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>
29 #include <rx/rx_prototypes.h>
32 #include <WINNT\afsreg.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 time_t smb_LogoffTransferTimeout;
54 int smb_StoreAnsiFilenames = 0;
56 DWORD last_msg_time = 0;
60 unsigned int sessionGen = 0;
62 extern void afsi_log(char *pattern, ...);
63 extern HANDLE afsi_file;
65 osi_hyper_t hzero = {0, 0};
66 osi_hyper_t hones = {0xFFFFFFFF, -1};
69 osi_rwlock_t smb_globalLock;
70 osi_rwlock_t smb_rctLock;
71 osi_mutex_t smb_ListenerLock;
74 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 int smb_NumServerThreads;
87 int numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCBmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 DWORD NCBsessions[NCBmax];
104 struct smb_packet *bufs[NCBmax];
106 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[Sessionmax];
108 unsigned short LSNs[Sessionmax];
109 int lanas[Sessionmax];
110 BOOL dead_sessions[Sessionmax];
114 osi_mutex_t smb_RawBufLock;
116 #define SMB_RAW_BUFS 4
118 int smb_RawBufSel[SMB_RAW_BUFS];
123 #define SMB_MASKFLAG_TILDE 1
124 #define SMB_MASKFLAG_CASEFOLD 2
126 #define RAWTIMEOUT INFINITE
129 typedef struct raw_write_cont {
142 /* dir search stuff */
143 long smb_dirSearchCounter = 1;
144 smb_dirSearch_t *smb_firstDirSearchp;
145 smb_dirSearch_t *smb_lastDirSearchp;
147 /* hide dot files? */
148 int smb_hideDotFiles;
150 /* global state about V3 protocols */
151 int smb_useV3; /* try to negotiate V3 */
154 static showErrors = 1;
155 /* MessageBox or something like it */
156 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
160 * Time in Unix format of midnight, 1/1/1970 local time.
161 * When added to dosUTime, gives Unix (AFS) time.
163 time_t smb_localZero = 0;
165 #define USE_NUMERIC_TIME_CONV 1
167 #ifndef USE_NUMERIC_TIME_CONV
168 /* Time difference for converting to kludge-GMT */
169 afs_uint32 smb_NowTZ;
170 #endif /* USE_NUMERIC_TIME_CONV */
172 char *smb_localNamep = NULL;
174 smb_vc_t *smb_allVCsp;
176 smb_username_t *usernamesp = NULL;
178 smb_waitingLock_t *smb_allWaitingLocks;
181 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
182 NCB *ncbp, raw_write_cont_t *rwcp);
183 void smb_NetbiosInit();
185 #ifndef AFS_WIN95_ENV
186 DWORD smb_ServerExceptionFilter(void);
189 extern char cm_HostName[];
190 extern char cm_confDir[];
194 #define LPTSTR char *
195 #define GetComputerName(str, sizep) \
196 strcpy((str), cm_HostName); \
197 *(sizep) = strlen(cm_HostName)
201 void smb_LogPacket(smb_packet_t *packet);
202 #endif /* LOG_PACKET */
204 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
205 int smb_ServerDomainNameLength = 0;
206 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
207 int smb_ServerOSLength = sizeof(smb_ServerOS);
208 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
209 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
211 /* Faux server GUID. This is never checked. */
212 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
214 char * myCrt_Dispatch(int i)
219 return "(00)ReceiveCoreMakeDir";
221 return "(01)ReceiveCoreRemoveDir";
223 return "(02)ReceiveCoreOpen";
225 return "(03)ReceiveCoreCreate";
227 return "(04)ReceiveCoreClose";
229 return "(05)ReceiveCoreFlush";
231 return "(06)ReceiveCoreUnlink";
233 return "(07)ReceiveCoreRename";
235 return "(08)ReceiveCoreGetFileAttributes";
237 return "(09)ReceiveCoreSetFileAttributes";
239 return "(0a)ReceiveCoreRead";
241 return "(0b)ReceiveCoreWrite";
243 return "(0c)ReceiveCoreLockRecord";
245 return "(0d)ReceiveCoreUnlockRecord";
247 return "(0e)SendCoreBadOp";
249 return "(0f)ReceiveCoreCreate";
251 return "(10)ReceiveCoreCheckPath";
253 return "(11)SendCoreBadOp";
255 return "(12)ReceiveCoreSeek";
257 return "(1a)ReceiveCoreReadRaw";
259 return "(1d)ReceiveCoreWriteRawDummy";
261 return "(22)ReceiveV3SetAttributes";
263 return "(23)ReceiveV3GetAttributes";
265 return "(24)ReceiveV3LockingX";
267 return "(25)ReceiveV3Trans";
269 return "(26)ReceiveV3Trans[aux]";
271 return "(29)SendCoreBadOp";
273 return "(2b)ReceiveCoreEcho";
275 return "(2d)ReceiveV3OpenX";
277 return "(2e)ReceiveV3ReadX";
279 return "(32)ReceiveV3Tran2A";
281 return "(33)ReceiveV3Tran2A[aux]";
283 return "(34)ReceiveV3FindClose";
285 return "(35)ReceiveV3FindNotifyClose";
287 return "(70)ReceiveCoreTreeConnect";
289 return "(71)ReceiveCoreTreeDisconnect";
291 return "(72)ReceiveNegotiate";
293 return "(73)ReceiveV3SessionSetupX";
295 return "(74)ReceiveV3UserLogoffX";
297 return "(75)ReceiveV3TreeConnectX";
299 return "(80)ReceiveCoreGetDiskAttributes";
301 return "(81)ReceiveCoreSearchDir";
305 return "(83)FindUnique";
307 return "(84)FindClose";
309 return "(A0)ReceiveNTTransact";
311 return "(A2)ReceiveNTCreateX";
313 return "(A4)ReceiveNTCancel";
315 return "(A5)ReceiveNTRename";
317 return "(C0)OpenPrintFile";
319 return "(C1)WritePrintFile";
321 return "(C2)ClosePrintFile";
323 return "(C3)GetPrintQueue";
325 return "(D8)ReadBulk";
327 return "(D9)WriteBulk";
329 return "(DA)WriteBulkData";
331 return "unknown SMB op";
335 char * myCrt_2Dispatch(int i)
340 return "unknown SMB op-2";
342 return "S(00)CreateFile";
344 return "S(01)FindFirst";
346 return "S(02)FindNext"; /* FindNext */
348 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
352 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
354 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
356 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
358 return "S(08)??_ReceiveTran2SetFileInfo";
360 return "S(09)??_ReceiveTran2FSCTL";
362 return "S(0a)_ReceiveTran2IOCTL";
364 return "S(0b)_ReceiveTran2FindNotifyFirst";
366 return "S(0c)_ReceiveTran2FindNotifyNext";
368 return "S(0d)_ReceiveTran2CreateDirectory";
370 return "S(0e)_ReceiveTran2SessionSetup";
372 return "S(10)_ReceiveTran2GetDfsReferral";
374 return "S(11)_ReceiveTran2ReportDfsInconsistency";
378 char * myCrt_RapDispatch(int i)
383 return "unknown RAP OP";
385 return "RAP(0)NetShareEnum";
387 return "RAP(1)NetShareGetInfo";
389 return "RAP(13)NetServerGetInfo";
391 return "RAP(63)NetWkStaGetInfo";
395 /* scache must be locked */
396 unsigned int smb_Attributes(cm_scache_t *scp)
400 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
401 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
402 scp->fileType == CM_SCACHETYPE_INVALID)
404 attrs = SMB_ATTR_DIRECTORY;
405 #ifdef SPECIAL_FOLDERS
406 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
407 #endif /* SPECIAL_FOLDERS */
408 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
409 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
414 * We used to mark a file RO if it was in an RO volume, but that
415 * turns out to be impolitic in NT. See defect 10007.
418 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
419 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
421 if ((scp->unixModeBits & 0222) == 0)
422 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
428 /* Check if the named file/dir is a dotfile/dotdir */
429 /* String pointed to by lastComp can have leading slashes, but otherwise should have
430 no other patch components */
431 unsigned int smb_IsDotFile(char *lastComp) {
434 /* skip over slashes */
435 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
440 /* nulls, curdir and parent dir doesn't count */
446 if(*(s+1) == '.' && !*(s + 2))
453 static int ExtractBits(WORD bits, short start, short len)
460 num = bits << (16 - end);
461 num = num >> ((16 - end) + start);
467 void ShowUnixTime(char *FuncName, time_t unixTime)
472 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
474 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
475 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
477 int day, month, year, sec, min, hour;
480 day = ExtractBits(wDate, 0, 5);
481 month = ExtractBits(wDate, 5, 4);
482 year = ExtractBits(wDate, 9, 7) + 1980;
484 sec = ExtractBits(wTime, 0, 5);
485 min = ExtractBits(wTime, 5, 6);
486 hour = ExtractBits(wTime, 11, 5);
488 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
489 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
495 /* Determine if we are observing daylight savings time */
496 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
498 TIME_ZONE_INFORMATION timeZoneInformation;
499 SYSTEMTIME utc, local, localDST;
501 /* Get the time zone info. NT uses this to calc if we are in DST. */
502 GetTimeZoneInformation(&timeZoneInformation);
504 /* Return the daylight bias */
505 *pDstBias = timeZoneInformation.DaylightBias;
507 /* Return the bias */
508 *pBias = timeZoneInformation.Bias;
510 /* Now determine if DST is being observed */
512 /* Get the UTC (GMT) time */
515 /* Convert UTC time to local time using the time zone info. If we are
516 observing DST, the calculated local time will include this.
518 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
520 /* Set the daylight bias to 0. The daylight bias is the amount of change
521 * in time that we use for daylight savings time. By setting this to 0
522 * we cause there to be no change in time during daylight savings time.
524 timeZoneInformation.DaylightBias = 0;
526 /* Convert the utc time to local time again, but this time without any
527 adjustment for daylight savings time.
529 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
531 /* If the two times are different, then it means that the localDST that
532 we calculated includes the daylight bias, and therefore we are
533 observing daylight savings time.
535 *pDST = localDST.wHour != local.wHour;
538 /* Determine if we are observing daylight savings time */
539 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
545 *pDstBias = -60; /* where can this be different? */
551 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
553 BOOL dst; /* Will be TRUE if observing DST */
554 LONG dstBias; /* Offset from local time if observing DST */
555 LONG bias; /* Offset from GMT for local time */
558 * This function will adjust the last write time to compensate
559 * for two bugs in the smb client:
561 * 1) During Daylight Savings Time, the LastWriteTime is ahead
562 * in time by the DaylightBias (ignoring the sign - the
563 * DaylightBias is always stored as a negative number). If
564 * the DaylightBias is -60, then the LastWriteTime will be
565 * ahead by 60 minutes.
567 * 2) If the local time zone is a positive offset from GMT, then
568 * the LastWriteTime will be the correct local time plus the
569 * Bias (ignoring the sign - a positive offset from GMT is
570 * always stored as a negative Bias). If the Bias is -120,
571 * then the LastWriteTime will be ahead by 120 minutes.
573 * These bugs can occur at the same time.
576 GetTimeZoneInfo(&dst, &dstBias, &bias);
578 /* First adjust for DST */
580 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
582 /* Now adjust for a positive offset from GMT (a negative bias). */
584 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
587 #ifndef USE_NUMERIC_TIME_CONV
589 * Calculate the difference (in seconds) between local time and GMT.
590 * This enables us to convert file times to kludge-GMT.
596 struct tm gmt_tm, local_tm;
597 int days, hours, minutes, seconds;
600 gmt_tm = *(gmtime(&t));
601 local_tm = *(localtime(&t));
603 days = local_tm.tm_yday - gmt_tm.tm_yday;
604 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
605 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
606 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
610 #endif /* USE_NUMERIC_TIME_CONV */
613 #ifdef USE_NUMERIC_TIME_CONV
614 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
616 // Note that LONGLONG is a 64-bit value
619 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
620 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
621 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
624 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
629 time_t ersatz_unixTime;
632 * Must use kludge-GMT instead of real GMT.
633 * kludge-GMT is computed by adding time zone difference to localtime.
636 * ltp = gmtime(&unixTime);
638 ersatz_unixTime = unixTime - smb_NowTZ;
639 ltp = localtime(&ersatz_unixTime);
641 /* if we fail, make up something */
644 localJunk.tm_year = 89 - 20;
645 localJunk.tm_mon = 4;
646 localJunk.tm_mday = 12;
647 localJunk.tm_hour = 0;
648 localJunk.tm_min = 0;
649 localJunk.tm_sec = 0;
652 stm.wYear = ltp->tm_year + 1900;
653 stm.wMonth = ltp->tm_mon + 1;
654 stm.wDayOfWeek = ltp->tm_wday;
655 stm.wDay = ltp->tm_mday;
656 stm.wHour = ltp->tm_hour;
657 stm.wMinute = ltp->tm_min;
658 stm.wSecond = ltp->tm_sec;
659 stm.wMilliseconds = 0;
661 SystemTimeToFileTime(&stm, largeTimep);
663 #endif /* USE_NUMERIC_TIME_CONV */
665 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
667 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
668 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
669 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
671 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
673 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
674 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
676 *ft = LargeIntegerMultiplyByLong(*ft, 60);
677 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
680 ut = ConvertLongToLargeInteger(unixTime);
681 ut = LargeIntegerMultiplyByLong(ut, 10000000);
682 *ft = LargeIntegerAdd(*ft, ut);
687 #ifdef USE_NUMERIC_TIME_CONV
688 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
690 // Note that LONGLONG is a 64-bit value
693 ll = largeTimep->dwHighDateTime;
695 ll += largeTimep->dwLowDateTime;
697 ll -= 116444736000000000;
700 *unixTimep = (DWORD)ll;
702 #else /* USE_NUMERIC_TIME_CONV */
703 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
709 FileTimeToSystemTime(largeTimep, &stm);
711 lt.tm_year = stm.wYear - 1900;
712 lt.tm_mon = stm.wMonth - 1;
713 lt.tm_wday = stm.wDayOfWeek;
714 lt.tm_mday = stm.wDay;
715 lt.tm_hour = stm.wHour;
716 lt.tm_min = stm.wMinute;
717 lt.tm_sec = stm.wSecond;
720 save_timezone = _timezone;
721 _timezone += smb_NowTZ;
722 *unixTimep = mktime(<);
723 _timezone = save_timezone;
725 #endif /* USE_NUMERIC_TIME_CONV */
727 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
729 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
730 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
731 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
735 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
736 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
737 a = LargeIntegerMultiplyByLong(a, 60);
738 a = LargeIntegerMultiplyByLong(a, 10000000);
740 /* subtract it from ft */
741 a = LargeIntegerSubtract(*ft, a);
743 /* divide down to seconds */
744 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
748 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
756 ltp = localtime((time_t*) &t);
758 /* if we fail, make up something */
761 localJunk.tm_year = 89 - 20;
762 localJunk.tm_mon = 4;
763 localJunk.tm_mday = 12;
764 localJunk.tm_hour = 0;
765 localJunk.tm_min = 0;
766 localJunk.tm_sec = 0;
769 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
770 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
771 *searchTimep = (dosDate<<16) | dosTime;
774 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
776 unsigned short dosDate;
777 unsigned short dosTime;
780 dosDate = (unsigned short) (searchTime & 0xffff);
781 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
783 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
784 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
785 localTm.tm_mday = (dosDate) & 0x1f;
786 localTm.tm_hour = (dosTime>>11) & 0x1f;
787 localTm.tm_min = (dosTime >> 5) & 0x3f;
788 localTm.tm_sec = (dosTime & 0x1f) * 2;
789 localTm.tm_isdst = -1; /* compute whether DST in effect */
791 *unixTimep = mktime(&localTm);
794 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
796 *dosUTimep = unixTime - smb_localZero;
799 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
802 *unixTimep = dosTime + smb_localZero;
804 /* dosTime seems to be already adjusted for GMT */
805 *unixTimep = dosTime;
809 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
813 lock_ObtainWrite(&smb_rctLock);
814 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
815 if (lsn == vcp->lsn && lana == vcp->lana) {
816 smb_HoldVCNoLock(vcp);
820 if (!vcp && (flags & SMB_FLAG_CREATE)) {
821 vcp = malloc(sizeof(*vcp));
822 memset(vcp, 0, sizeof(*vcp));
823 vcp->vcID = numVCs++;
827 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
828 vcp->nextp = smb_allVCsp;
830 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
835 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
836 /* We must obtain a challenge for extended auth
837 * in case the client negotiates smb v3
839 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
840 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
841 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
842 ULONG lsaRespSize = 0;
844 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
846 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
853 if (nts != STATUS_SUCCESS)
854 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
855 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
856 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
858 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
859 LsaFreeReturnBuffer(lsaResp);
862 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
864 lock_ReleaseWrite(&smb_rctLock);
868 int smb_IsStarMask(char *maskp)
873 for(i=0; i<11; i++) {
875 if (tc == '?' || tc == '*' || tc == '>') return 1;
880 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
882 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
884 osi_assert(vcp->refCount-- != 0);
890 void smb_ReleaseVC(smb_vc_t *vcp)
892 lock_ObtainWrite(&smb_rctLock);
893 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
895 osi_assert(vcp->refCount-- != 0);
899 lock_ReleaseWrite(&smb_rctLock);
902 void smb_HoldVCNoLock(smb_vc_t *vcp)
905 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
908 void smb_HoldVC(smb_vc_t *vcp)
910 lock_ObtainWrite(&smb_rctLock);
912 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
913 lock_ReleaseWrite(&smb_rctLock);
916 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
920 lock_ObtainWrite(&smb_rctLock);
921 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
922 if (tid == tidp->tid) {
927 if (!tidp && (flags & SMB_FLAG_CREATE)) {
928 tidp = malloc(sizeof(*tidp));
929 memset(tidp, 0, sizeof(*tidp));
930 tidp->nextp = vcp->tidsp;
933 smb_HoldVCNoLock(vcp);
935 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
938 lock_ReleaseWrite(&smb_rctLock);
942 void smb_ReleaseTID(smb_tid_t *tidp)
949 lock_ObtainWrite(&smb_rctLock);
950 osi_assert(tidp->refCount-- > 0);
951 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
952 ltpp = &tidp->vcp->tidsp;
953 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
957 osi_assert(tp != NULL);
959 lock_FinalizeMutex(&tidp->mx);
960 userp = tidp->userp; /* remember to drop ref later */
962 smb_ReleaseVCNoLock(tidp->vcp);
965 lock_ReleaseWrite(&smb_rctLock);
967 cm_ReleaseUser(userp);
970 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
972 smb_user_t *uidp = NULL;
974 lock_ObtainWrite(&smb_rctLock);
975 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
976 if (uid == uidp->userID) {
978 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
979 (int)vcp, uidp->userID,
980 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
984 if (!uidp && (flags & SMB_FLAG_CREATE)) {
985 uidp = malloc(sizeof(*uidp));
986 memset(uidp, 0, sizeof(*uidp));
987 uidp->nextp = vcp->usersp;
990 smb_HoldVCNoLock(vcp);
992 lock_InitializeMutex(&uidp->mx, "user_t mutex");
994 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 : ""));
996 lock_ReleaseWrite(&smb_rctLock);
1000 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1002 smb_username_t *unp= NULL;
1004 lock_ObtainWrite(&smb_rctLock);
1005 for(unp = usernamesp; unp; unp = unp->nextp) {
1006 if (stricmp(unp->name, usern) == 0 &&
1007 stricmp(unp->machine, machine) == 0) {
1012 if (!unp && (flags & SMB_FLAG_CREATE)) {
1013 unp = malloc(sizeof(*unp));
1014 memset(unp, 0, sizeof(*unp));
1016 unp->nextp = usernamesp;
1017 unp->name = strdup(usern);
1018 unp->machine = strdup(machine);
1020 lock_InitializeMutex(&unp->mx, "username_t mutex");
1022 lock_ReleaseWrite(&smb_rctLock);
1026 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1028 smb_user_t *uidp= NULL;
1030 lock_ObtainWrite(&smb_rctLock);
1031 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1034 if (stricmp(uidp->unp->name, usern) == 0) {
1036 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1041 lock_ReleaseWrite(&smb_rctLock);
1044 void smb_ReleaseUID(smb_user_t *uidp)
1051 lock_ObtainWrite(&smb_rctLock);
1052 osi_assert(uidp->refCount-- > 0);
1053 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1054 lupp = &uidp->vcp->usersp;
1055 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1059 osi_assert(up != NULL);
1061 lock_FinalizeMutex(&uidp->mx);
1063 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1064 uidp->unp->userp = NULL; /* after releasing the lock */
1066 smb_ReleaseVCNoLock(uidp->vcp);
1069 lock_ReleaseWrite(&smb_rctLock);
1071 cm_ReleaseUserVCRef(userp);
1072 cm_ReleaseUser(userp);
1077 /* retrieve a held reference to a user structure corresponding to an incoming
1079 * corresponding release function is cm_ReleaseUser.
1081 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1087 smbp = (smb_t *) inp;
1088 uidp = smb_FindUID(vcp, smbp->uid, 0);
1089 if ((!uidp) || (!uidp->unp))
1092 lock_ObtainMutex(&uidp->mx);
1093 up = uidp->unp->userp;
1095 lock_ReleaseMutex(&uidp->mx);
1097 smb_ReleaseUID(uidp);
1103 * Return a pointer to a pathname extracted from a TID structure. The
1104 * TID structure is not held; assume it won't go away.
1106 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1111 tidp = smb_FindTID(vcp, tid, 0);
1115 if (tidp->flags & SMB_TIDFLAG_IPC) {
1116 code = CM_ERROR_TIDIPC;
1117 /* tidp->pathname would be NULL, but that's fine */
1119 *treepath = tidp->pathname;
1120 smb_ReleaseTID(tidp);
1125 /* check to see if we have a chained fid, that is, a fid that comes from an
1126 * OpenAndX message that ran earlier in this packet. In this case, the fid
1127 * field in a read, for example, request, isn't set, since the value is
1128 * supposed to be inherited from the openAndX call.
1130 int smb_ChainFID(int fid, smb_packet_t *inp)
1132 if (inp->fid == 0 || inp->inCount == 0)
1138 /* are we a priv'd user? What does this mean on NT? */
1139 int smb_SUser(cm_user_t *userp)
1144 /* find a file ID. If we pass in 0 we select an used File ID.
1145 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1146 * smb_fid_t data structure if desired File ID cannot be found.
1148 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1153 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1156 lock_ObtainWrite(&smb_rctLock);
1157 /* figure out if we need to allocate a new file ID */
1160 fid = vcp->fidCounter;
1164 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1165 if (fid == fidp->fid) {
1176 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1177 char eventName[MAX_PATH];
1179 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1180 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1181 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1182 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1183 thrd_CloseHandle(event);
1190 fidp = malloc(sizeof(*fidp));
1191 memset(fidp, 0, sizeof(*fidp));
1192 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1195 smb_HoldVCNoLock(vcp);
1196 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1198 fidp->curr_chunk = fidp->prev_chunk = -2;
1199 fidp->raw_write_event = event;
1201 vcp->fidCounter = fid+1;
1202 if (vcp->fidCounter == 0)
1203 vcp->fidCounter = 1;
1206 lock_ReleaseWrite(&smb_rctLock);
1210 void smb_ReleaseFID(smb_fid_t *fidp)
1213 smb_vc_t *vcp = NULL;
1214 smb_ioctl_t *ioctlp;
1220 lock_ObtainWrite(&smb_rctLock);
1221 osi_assert(fidp->refCount-- > 0);
1222 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1225 scp = fidp->scp; /* release after lock is released */
1228 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1229 thrd_CloseHandle(fidp->raw_write_event);
1231 /* and see if there is ioctl stuff to free */
1232 ioctlp = fidp->ioctlp;
1235 cm_FreeSpace(ioctlp->prefix);
1236 if (ioctlp->inAllocp)
1237 free(ioctlp->inAllocp);
1238 if (ioctlp->outAllocp)
1239 free(ioctlp->outAllocp);
1245 smb_ReleaseVCNoLock(vcp);
1247 lock_ReleaseWrite(&smb_rctLock);
1249 /* now release the scache structure */
1251 cm_ReleaseSCache(scp);
1255 * Case-insensitive search for one string in another;
1256 * used to find variable names in submount pathnames.
1258 static char *smb_stristr(char *str1, char *str2)
1262 for (cursor = str1; *cursor; cursor++)
1263 if (stricmp(cursor, str2) == 0)
1270 * Substitute a variable value for its name in a submount pathname. Variable
1271 * name has been identified by smb_stristr() and is in substr. Variable name
1272 * length (plus one) is in substr_size. Variable value is in newstr.
1274 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1279 strcpy(temp, substr + substr_size - 1);
1280 strcpy(substr, newstr);
1284 char VNUserName[] = "%USERNAME%";
1285 char VNLCUserName[] = "%LCUSERNAME%";
1286 char VNComputerName[] = "%COMPUTERNAME%";
1287 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1290 /* List available shares */
1291 int smb_ListShares()
1295 char shareBuf[4096];
1303 /*strcpy(shareNameList[num_shares], "all");
1304 strcpy(pathNameList[num_shares++], "/afs");*/
1305 fprintf(stderr, "The following shares are available:\n");
1306 fprintf(stderr, "Share Name (AFS Path)\n");
1307 fprintf(stderr, "---------------------\n");
1308 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1311 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1312 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1314 strcpy(sbmtpath, cm_confDir);
1316 strcat(sbmtpath, "/afsdsbmt.ini");
1317 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1318 shareBuf, sizeof(shareBuf),
1324 this_share = shareBuf;
1328 /*strcpy(shareNameList[num_shares], this_share);*/
1329 len = GetPrivateProfileString("AFS Submounts", this_share,
1336 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1339 if (*p == '\\') *p = '/'; /* change to / */
1343 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1344 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1347 while (*this_share != 0) this_share++; /* find next NUL */
1348 this_share++; /* skip past the NUL */
1349 } while (*this_share != 0); /* stop at final NUL */
1355 typedef struct smb_findShare_rock {
1359 } smb_findShare_rock_t;
1361 #define SMB_FINDSHARE_EXACT_MATCH 1
1362 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1364 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1368 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1369 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1370 if(!stricmp(dep->name, vrock->shareName))
1371 matchType = SMB_FINDSHARE_EXACT_MATCH;
1373 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1374 if(vrock->match) free(vrock->match);
1375 vrock->match = strdup(dep->name);
1376 vrock->matchType = matchType;
1378 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1379 return CM_ERROR_STOPNOW;
1385 /* find a shareName in the table of submounts */
1386 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1390 char pathName[1024];
1395 char sbmtpath[MAX_PATH];
1400 DWORD allSubmount = 1;
1402 /* if allSubmounts == 0, only return the //mountRoot/all share
1403 * if in fact it has been been created in the subMounts table.
1404 * This is to allow sites that want to restrict access to the
1407 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1408 0, KEY_QUERY_VALUE, &parmKey);
1409 if (code == ERROR_SUCCESS) {
1410 len = sizeof(allSubmount);
1411 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1412 (BYTE *) &allSubmount, &len);
1413 if (code != ERROR_SUCCESS) {
1416 RegCloseKey (parmKey);
1419 if (allSubmount && _stricmp(shareName, "all") == 0) {
1424 /* In case, the all share is disabled we need to still be able
1425 * to handle ioctl requests
1427 if (_stricmp(shareName, "ioctl$") == 0) {
1428 *pathNamep = strdup("/.__ioctl__");
1432 if (_stricmp(shareName, "IPC$") == 0 ||
1433 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1434 _stricmp(shareName, "DESKTOP.INI") == 0
1441 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1442 0, KEY_QUERY_VALUE, &parmKey);
1443 if (code == ERROR_SUCCESS) {
1444 len = sizeof(pathName);
1445 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1446 (BYTE *) pathName, &len);
1447 if (code != ERROR_SUCCESS)
1449 RegCloseKey (parmKey);
1454 strcpy(sbmtpath, cm_confDir);
1455 strcat(sbmtpath, "/afsdsbmt.ini");
1456 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1457 pathName, sizeof(pathName), sbmtpath);
1459 if (len != 0 && len != sizeof(pathName) - 1) {
1460 /* We can accept either unix or PC style AFS pathnames. Convert
1461 * Unix-style to PC style here for internal use.
1464 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1465 p += strlen(cm_mountRoot); /* skip mount path */
1468 if (*q == '/') *q = '\\'; /* change to \ */
1474 if (var = smb_stristr(p, VNUserName)) {
1475 if (uidp && uidp->unp)
1476 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1478 smb_subst(p, var, sizeof(VNUserName)," ");
1480 else if (var = smb_stristr(p, VNLCUserName))
1482 if (uidp && uidp->unp)
1483 strcpy(temp, uidp->unp->name);
1487 smb_subst(p, var, sizeof(VNLCUserName), temp);
1489 else if (var = smb_stristr(p, VNComputerName))
1491 sizeTemp = sizeof(temp);
1492 GetComputerName((LPTSTR)temp, &sizeTemp);
1493 smb_subst(p, var, sizeof(VNComputerName), temp);
1495 else if (var = smb_stristr(p, VNLCComputerName))
1497 sizeTemp = sizeof(temp);
1498 GetComputerName((LPTSTR)temp, &sizeTemp);
1500 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1505 *pathNamep = strdup(p);
1510 /* First lookup shareName in root.afs */
1512 smb_findShare_rock_t vrock;
1514 char * p = shareName;
1517 /* attempt to locate a partial match in root.afs. This is because
1518 when using the ANSI RAP calls, the share name is limited to 13 chars
1519 and hence is truncated. Of course we prefer exact matches. */
1521 thyper.HighPart = 0;
1524 vrock.shareName = shareName;
1526 vrock.matchType = 0;
1528 cm_HoldSCache(cm_data.rootSCachep);
1529 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1530 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1531 cm_ReleaseSCache(cm_data.rootSCachep);
1533 if (vrock.matchType) {
1534 sprintf(pathName,"/%s/",vrock.match);
1535 *pathNamep = strdup(strlwr(pathName));
1540 /* if we get here, there was no match for the share in root.afs */
1541 /* so try to create \\<netbiosName>\<cellname> */
1546 /* Get the full name for this cell */
1547 code = cm_SearchCellFile(p, temp, 0, 0);
1548 #ifdef AFS_AFSDB_ENV
1549 if (code && cm_dnsEnabled) {
1551 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1554 /* construct the path */
1556 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1557 *pathNamep = strdup(strlwr(pathName));
1566 /* Client-side offline caching policy types */
1567 #define CSC_POLICY_MANUAL 0
1568 #define CSC_POLICY_DOCUMENTS 1
1569 #define CSC_POLICY_PROGRAMS 2
1570 #define CSC_POLICY_DISABLE 3
1572 int smb_FindShareCSCPolicy(char *shareName)
1578 int retval = CSC_POLICY_MANUAL;
1580 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1581 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1584 REG_OPTION_NON_VOLATILE,
1590 len = sizeof(policy);
1591 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1593 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1595 else if (stricmp(policy, "documents") == 0)
1597 retval = CSC_POLICY_DOCUMENTS;
1599 else if (stricmp(policy, "programs") == 0)
1601 retval = CSC_POLICY_PROGRAMS;
1603 else if (stricmp(policy, "disable") == 0)
1605 retval = CSC_POLICY_DISABLE;
1608 RegCloseKey(hkCSCPolicy);
1612 /* find a dir search structure by cookie value, and return it held.
1613 * Must be called with smb_globalLock held.
1615 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1617 smb_dirSearch_t *dsp;
1619 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1620 if (dsp->cookie == cookie) {
1621 if (dsp != smb_firstDirSearchp) {
1622 /* move to head of LRU queue, too, if we're not already there */
1623 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1624 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1625 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1626 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1627 if (!smb_lastDirSearchp)
1628 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1630 lock_ObtainMutex(&dsp->mx);
1632 lock_ReleaseMutex(&dsp->mx);
1638 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1639 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1640 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1646 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1648 lock_ObtainWrite(&smb_globalLock);
1649 lock_ObtainMutex(&dsp->mx);
1650 dsp->flags |= SMB_DIRSEARCH_DELETE;
1651 if (dsp->scp != NULL) {
1652 lock_ObtainMutex(&dsp->scp->mx);
1653 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1654 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1655 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1656 dsp->scp->bulkStatProgress = hones;
1658 lock_ReleaseMutex(&dsp->scp->mx);
1660 lock_ReleaseMutex(&dsp->mx);
1661 lock_ReleaseWrite(&smb_globalLock);
1664 /* Must be called with the smb_globalLock held */
1665 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1667 cm_scache_t *scp = NULL;
1669 lock_ObtainMutex(&dsp->mx);
1670 osi_assert(dsp->refCount-- > 0);
1671 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1672 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1673 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1674 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1675 lock_ReleaseMutex(&dsp->mx);
1676 lock_FinalizeMutex(&dsp->mx);
1680 lock_ReleaseMutex(&dsp->mx);
1682 /* do this now to avoid spurious locking hierarchy creation */
1684 cm_ReleaseSCache(scp);
1687 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1689 lock_ObtainWrite(&smb_globalLock);
1690 smb_ReleaseDirSearchNoLock(dsp);
1691 lock_ReleaseWrite(&smb_globalLock);
1694 /* find a dir search structure by cookie value, and return it held */
1695 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1697 smb_dirSearch_t *dsp;
1699 lock_ObtainWrite(&smb_globalLock);
1700 dsp = smb_FindDirSearchNoLock(cookie);
1701 lock_ReleaseWrite(&smb_globalLock);
1705 /* GC some dir search entries, in the address space expected by the specific protocol.
1706 * Must be called with smb_globalLock held; release the lock temporarily.
1708 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1709 void smb_GCDirSearches(int isV3)
1711 smb_dirSearch_t *prevp;
1712 smb_dirSearch_t *tp;
1713 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1717 victimCount = 0; /* how many have we got so far */
1718 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1719 /* we'll move tp from queue, so
1722 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1723 /* if no one is using this guy, and we're either in the new protocol,
1724 * or we're in the old one and this is a small enough ID to be useful
1725 * to the old protocol, GC this guy.
1727 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1728 /* hold and delete */
1729 tp->flags |= SMB_DIRSEARCH_DELETE;
1730 victimsp[victimCount++] = tp;
1734 /* don't do more than this */
1735 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1739 /* now release them */
1740 for (i = 0; i < victimCount; i++) {
1741 smb_ReleaseDirSearchNoLock(victimsp[i]);
1745 /* function for allocating a dir search entry. We need these to remember enough context
1746 * since we don't get passed the path from call to call during a directory search.
1748 * Returns a held dir search structure, and bumps the reference count on the vnode,
1749 * since it saves a pointer to the vnode.
1751 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1753 smb_dirSearch_t *dsp;
1759 lock_ObtainWrite(&smb_globalLock);
1762 /* what's the biggest ID allowed in this version of the protocol */
1763 maxAllowed = isV3 ? 65535 : 255;
1764 if (smb_dirSearchCounter > maxAllowed)
1765 smb_dirSearchCounter = 1;
1767 start = smb_dirSearchCounter;
1770 /* twice so we have enough tries to find guys we GC after one pass;
1771 * 10 extra is just in case I mis-counted.
1773 if (++counter > 2*maxAllowed+10)
1774 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1776 if (smb_dirSearchCounter > maxAllowed) {
1777 smb_dirSearchCounter = 1;
1779 if (smb_dirSearchCounter == start) {
1781 smb_GCDirSearches(isV3);
1784 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1786 /* don't need to watch for refcount zero and deleted, since
1787 * we haven't dropped the global lock.
1789 lock_ObtainMutex(&dsp->mx);
1791 lock_ReleaseMutex(&dsp->mx);
1792 ++smb_dirSearchCounter;
1796 dsp = malloc(sizeof(*dsp));
1797 memset(dsp, 0, sizeof(*dsp));
1798 dsp->cookie = smb_dirSearchCounter;
1799 ++smb_dirSearchCounter;
1801 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1802 dsp->lastTime = osi_Time();
1803 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1804 if (!smb_lastDirSearchp)
1805 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1808 lock_ReleaseWrite(&smb_globalLock);
1812 static smb_packet_t *GetPacket(void)
1816 unsigned int npar, seg, tb_sel;
1819 lock_ObtainWrite(&smb_globalLock);
1820 tbp = smb_packetFreeListp;
1822 smb_packetFreeListp = tbp->nextp;
1823 lock_ReleaseWrite(&smb_globalLock);
1826 tbp = calloc(65540,1);
1828 tbp = malloc(sizeof(smb_packet_t));
1830 tbp->magic = SMB_PACKETMAGIC;
1833 tbp->resumeCode = 0;
1839 tbp->ncb_length = 0;
1844 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1847 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1849 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1851 osi_panic("",__FILE__,__LINE__);
1854 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1859 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1860 tbp->dos_pkt_sel = tb_sel;
1863 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1868 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1872 memcpy(tbp, pkt, sizeof(smb_packet_t));
1873 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1875 smb_HoldVC(tbp->vcp);
1879 static NCB *GetNCB(void)
1884 unsigned int npar, seg, tb_sel;
1887 lock_ObtainWrite(&smb_globalLock);
1888 tbp = smb_ncbFreeListp;
1890 smb_ncbFreeListp = tbp->nextp;
1891 lock_ReleaseWrite(&smb_globalLock);
1894 tbp = calloc(sizeof(*tbp),1);
1896 tbp = malloc(sizeof(*tbp));
1897 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1900 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1902 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1904 osi_panic("",__FILE__,__LINE__);
1906 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1911 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1912 tbp->dos_ncb_sel = tb_sel;
1914 tbp->magic = SMB_NCBMAGIC;
1917 osi_assert(tbp->magic == SMB_NCBMAGIC);
1919 memset(&tbp->ncb, 0, sizeof(NCB));
1922 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1927 void smb_FreePacket(smb_packet_t *tbp)
1929 smb_vc_t * vcp = NULL;
1930 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1932 lock_ObtainWrite(&smb_globalLock);
1933 tbp->nextp = smb_packetFreeListp;
1934 smb_packetFreeListp = tbp;
1935 tbp->magic = SMB_PACKETMAGIC;
1939 tbp->resumeCode = 0;
1945 tbp->ncb_length = 0;
1947 lock_ReleaseWrite(&smb_globalLock);
1953 static void FreeNCB(NCB *bufferp)
1957 tbp = (smb_ncb_t *) bufferp;
1958 osi_assert(tbp->magic == SMB_NCBMAGIC);
1960 lock_ObtainWrite(&smb_globalLock);
1961 tbp->nextp = smb_ncbFreeListp;
1962 smb_ncbFreeListp = tbp;
1963 lock_ReleaseWrite(&smb_globalLock);
1966 /* get a ptr to the data part of a packet, and its count */
1967 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1971 unsigned char *afterParmsp;
1973 parmBytes = *smbp->wctp << 1;
1974 afterParmsp = smbp->wctp + parmBytes + 1;
1976 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1977 if (nbytesp) *nbytesp = dataBytes;
1979 /* don't forget to skip the data byte count, since it follows
1980 * the parameters; that's where the "2" comes from below.
1982 return (unsigned char *) (afterParmsp + 2);
1985 /* must set all the returned parameters before playing around with the
1986 * data region, since the data region is located past the end of the
1987 * variable number of parameters.
1989 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1991 unsigned char *afterParmsp;
1993 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1995 *afterParmsp++ = dsize & 0xff;
1996 *afterParmsp = (dsize>>8) & 0xff;
1999 /* return the parm'th parameter in the smbp packet */
2000 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2003 unsigned char *parmDatap;
2005 parmCount = *smbp->wctp;
2007 if (parm >= parmCount) {
2012 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2014 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2015 parm, parmCount, smbp->ncb_length);
2018 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2019 1, smbp->ncb_length, ptbuf, smbp);
2020 DeregisterEventSource(h);
2022 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2023 parm, parmCount, smbp->ncb_length);
2024 osi_panic(s, __FILE__, __LINE__);
2026 parmDatap = smbp->wctp + (2*parm) + 1;
2028 return parmDatap[0] + (parmDatap[1] << 8);
2031 /* return the parm'th parameter in the smbp packet */
2032 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2035 unsigned char *parmDatap;
2037 parmCount = *smbp->wctp;
2039 if (parm * 2 + offset >= parmCount * 2) {
2044 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2046 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2047 parm, offset, parmCount, smbp->ncb_length);
2050 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2051 1, smbp->ncb_length, ptbuf, smbp);
2052 DeregisterEventSource(h);
2054 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2055 parm, offset, parmCount, smbp->ncb_length);
2056 osi_panic(s, __FILE__, __LINE__);
2058 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2060 return parmDatap[0] + (parmDatap[1] << 8);
2063 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2067 /* make sure we have enough slots */
2068 if (*smbp->wctp <= slot)
2069 *smbp->wctp = slot+1;
2071 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2072 *parmDatap++ = parmValue & 0xff;
2073 *parmDatap = (parmValue>>8) & 0xff;
2076 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2080 /* make sure we have enough slots */
2081 if (*smbp->wctp <= slot)
2082 *smbp->wctp = slot+2;
2084 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2085 *parmDatap++ = parmValue & 0xff;
2086 *parmDatap++ = (parmValue>>8) & 0xff;
2087 *parmDatap++ = (parmValue>>16) & 0xff;
2088 *parmDatap++ = (parmValue>>24) & 0xff;
2091 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2096 /* make sure we have enough slots */
2097 if (*smbp->wctp <= slot)
2098 *smbp->wctp = slot+4;
2100 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2102 *parmDatap++ = *parmValuep++;
2105 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2109 /* make sure we have enough slots */
2110 if (*smbp->wctp <= slot) {
2111 if (smbp->oddByte) {
2113 *smbp->wctp = slot+1;
2118 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2119 *parmDatap++ = parmValue & 0xff;
2122 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2126 lastSlashp = strrchr(inPathp, '\\');
2128 *lastComponentp = lastSlashp;
2131 if (inPathp == lastSlashp)
2133 *outPathp++ = *inPathp++;
2142 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2147 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2152 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2158 tlen = inp[0] + (inp[1]<<8);
2159 inp += 2; /* skip length field */
2162 *chainpp = inp + tlen;
2171 /* format a packet as a response */
2172 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2177 outp = (smb_t *) op;
2179 /* zero the basic structure through the smb_wct field, and zero the data
2180 * size field, assuming that wct stays zero; otherwise, you have to
2181 * explicitly set the data size field, too.
2183 inSmbp = (smb_t *) inp;
2184 memset(outp, 0, sizeof(smb_t)+2);
2190 outp->com = inSmbp->com;
2191 outp->tid = inSmbp->tid;
2192 outp->pid = inSmbp->pid;
2193 outp->uid = inSmbp->uid;
2194 outp->mid = inSmbp->mid;
2195 outp->res[0] = inSmbp->res[0];
2196 outp->res[1] = inSmbp->res[1];
2197 op->inCom = inSmbp->com;
2199 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2200 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2202 /* copy fields in generic packet area */
2203 op->wctp = &outp->wct;
2206 /* send a (probably response) packet; vcp tells us to whom to send it.
2207 * we compute the length by looking at wct and bcc fields.
2209 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2226 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2229 memset((char *)ncbp, 0, sizeof(NCB));
2231 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2232 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2233 extra += tp[0] + (tp[1]<<8);
2234 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2235 extra += 3; /* wct and length fields */
2237 ncbp->ncb_length = extra; /* bytes to send */
2238 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2239 ncbp->ncb_lana_num = vcp->lana;
2240 ncbp->ncb_command = NCBSEND; /* op means send data */
2242 ncbp->ncb_buffer = (char *) inp;/* packet */
2243 code = Netbios(ncbp);
2245 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2246 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2248 /* copy header information from virtual to DOS address space */
2249 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2250 code = Netbios(ncbp, dos_ncb);
2256 case 0x01: s = "llegal buffer length "; break;
2257 case 0x03: s = "illegal command "; break;
2258 case 0x05: s = "command timed out "; break;
2259 case 0x06: s = "message incomplete, issue another command"; break;
2260 case 0x07: s = "illegal buffer address "; break;
2261 case 0x08: s = "session number out of range "; break;
2262 case 0x09: s = "no resource available "; break;
2263 case 0x0a: s = "session closed "; break;
2264 case 0x0b: s = "command cancelled "; break;
2265 case 0x0d: s = "duplicate name "; break;
2266 case 0x0e: s = "name table full "; break;
2267 case 0x0f: s = "no deletions, name has active sessions "; break;
2268 case 0x11: s = "local session table full "; break;
2269 case 0x12: s = "remote session table full "; break;
2270 case 0x13: s = "illegal name number "; break;
2271 case 0x14: s = "no callname "; break;
2272 case 0x15: s = "cannot put * in NCB_NAME "; break;
2273 case 0x16: s = "name in use on remote adapter "; break;
2274 case 0x17: s = "name deleted "; break;
2275 case 0x18: s = "session ended abnormally "; break;
2276 case 0x19: s = "name conflict detected "; break;
2277 case 0x21: s = "interface busy, IRET before retrying "; break;
2278 case 0x22: s = "too many commands outstanding, retry later"; break;
2279 case 0x23: s = "ncb_lana_num field invalid "; break;
2280 case 0x24: s = "command completed while cancel occurring "; break;
2281 case 0x26: s = "command not valid to cancel "; break;
2282 case 0x30: s = "name defined by anther local process "; break;
2283 case 0x34: s = "environment undefined. RESET required "; break;
2284 case 0x35: s = "required OS resources exhausted "; break;
2285 case 0x36: s = "max number of applications exceeded "; break;
2286 case 0x37: s = "no saps available for netbios "; break;
2287 case 0x38: s = "requested resources are not available "; break;
2288 case 0x39: s = "invalid ncb address or length > segment "; break;
2289 case 0x3B: s = "invalid NCB DDID "; break;
2290 case 0x3C: s = "lock of user area failed "; break;
2291 case 0x3f: s = "NETBIOS not loaded "; break;
2292 case 0x40: s = "system error "; break;
2294 s = "unknown error";
2296 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2303 void smb_MapNTError(long code, unsigned long *NTStatusp)
2305 unsigned long NTStatus;
2307 /* map CM_ERROR_* errors to NT 32-bit status codes */
2308 /* NT Status codes are listed in ntstatus.h not winerror.h */
2309 if (code == CM_ERROR_NOSUCHCELL) {
2310 NTStatus = 0xC000000FL; /* No such file */
2312 else if (code == CM_ERROR_NOSUCHVOLUME) {
2313 NTStatus = 0xC000000FL; /* No such file */
2315 else if (code == CM_ERROR_TIMEDOUT) {
2316 NTStatus = 0xC00000CFL; /* Sharing Paused */
2318 else if (code == CM_ERROR_RETRY) {
2319 NTStatus = 0xC000022DL; /* Retry */
2321 else if (code == CM_ERROR_NOACCESS) {
2322 NTStatus = 0xC0000022L; /* Access denied */
2324 else if (code == CM_ERROR_READONLY) {
2325 NTStatus = 0xC00000A2L; /* Write protected */
2327 else if (code == CM_ERROR_NOSUCHFILE) {
2328 NTStatus = 0xC000000FL; /* No such file */
2330 else if (code == CM_ERROR_NOSUCHPATH) {
2331 NTStatus = 0xC000003AL; /* Object path not found */
2333 else if (code == CM_ERROR_TOOBIG) {
2334 NTStatus = 0xC000007BL; /* Invalid image format */
2336 else if (code == CM_ERROR_INVAL) {
2337 NTStatus = 0xC000000DL; /* Invalid parameter */
2339 else if (code == CM_ERROR_BADFD) {
2340 NTStatus = 0xC0000008L; /* Invalid handle */
2342 else if (code == CM_ERROR_BADFDOP) {
2343 NTStatus = 0xC0000022L; /* Access denied */
2345 else if (code == CM_ERROR_EXISTS) {
2346 NTStatus = 0xC0000035L; /* Object name collision */
2348 else if (code == CM_ERROR_NOTEMPTY) {
2349 NTStatus = 0xC0000101L; /* Directory not empty */
2351 else if (code == CM_ERROR_CROSSDEVLINK) {
2352 NTStatus = 0xC00000D4L; /* Not same device */
2354 else if (code == CM_ERROR_NOTDIR) {
2355 NTStatus = 0xC0000103L; /* Not a directory */
2357 else if (code == CM_ERROR_ISDIR) {
2358 NTStatus = 0xC00000BAL; /* File is a directory */
2360 else if (code == CM_ERROR_BADOP) {
2362 /* I have no idea where this comes from */
2363 NTStatus = 0xC09820FFL; /* SMB no support */
2365 NTStatus = 0xC00000BBL; /* Not supported */
2366 #endif /* COMMENT */
2368 else if (code == CM_ERROR_BADSHARENAME) {
2369 NTStatus = 0xC00000CCL; /* Bad network name */
2371 else if (code == CM_ERROR_NOIPC) {
2373 NTStatus = 0xC0000022L; /* Access Denied */
2375 NTStatus = 0xC000013DL; /* Remote Resources */
2378 else if (code == CM_ERROR_CLOCKSKEW) {
2379 NTStatus = 0xC0000133L; /* Time difference at DC */
2381 else if (code == CM_ERROR_BADTID) {
2382 NTStatus = 0xC0982005L; /* SMB bad TID */
2384 else if (code == CM_ERROR_USESTD) {
2385 NTStatus = 0xC09820FBL; /* SMB use standard */
2387 else if (code == CM_ERROR_QUOTA) {
2389 NTStatus = 0xC0000044L; /* Quota exceeded */
2391 NTStatus = 0xC000007FL; /* Disk full */
2394 else if (code == CM_ERROR_SPACE) {
2395 NTStatus = 0xC000007FL; /* Disk full */
2397 else if (code == CM_ERROR_ATSYS) {
2398 NTStatus = 0xC0000033L; /* Object name invalid */
2400 else if (code == CM_ERROR_BADNTFILENAME) {
2401 NTStatus = 0xC0000033L; /* Object name invalid */
2403 else if (code == CM_ERROR_WOULDBLOCK) {
2404 NTStatus = 0xC0000055L; /* Lock not granted */
2406 else if (code == CM_ERROR_PARTIALWRITE) {
2407 NTStatus = 0xC000007FL; /* Disk full */
2409 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2410 NTStatus = 0xC0000023L; /* Buffer too small */
2412 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2413 NTStatus = 0xC0000035L; /* Object name collision */
2415 else if (code == CM_ERROR_BADPASSWORD) {
2416 NTStatus = 0xC000006DL; /* unknown username or bad password */
2418 else if (code == CM_ERROR_BADLOGONTYPE) {
2419 NTStatus = 0xC000015BL; /* logon type not granted */
2421 else if (code == CM_ERROR_GSSCONTINUE) {
2422 NTStatus = 0xC0000016L; /* more processing required */
2424 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2426 NTStatus = 0xC0000280L; /* reparse point not resolved */
2428 NTStatus = 0xC0000022L; /* Access Denied */
2431 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2432 NTStatus = 0xC0000257L; /* Path Not Covered */
2434 else if (code == CM_ERROR_ALLBUSY) {
2435 NTStatus = 0xC00000BFL; /* Network Busy */
2437 else if (code == CM_ERROR_ALLOFFLINE) {
2438 NTStatus = 0xC0000350L; /* Remote Host Down */
2441 NTStatus = 0xC0982001L; /* SMB non-specific error */
2444 *NTStatusp = NTStatus;
2445 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2448 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2449 unsigned char *classp)
2451 unsigned char class;
2452 unsigned short error;
2454 /* map CM_ERROR_* errors to SMB errors */
2455 if (code == CM_ERROR_NOSUCHCELL) {
2457 error = 3; /* bad path */
2459 else if (code == CM_ERROR_NOSUCHVOLUME) {
2461 error = 3; /* bad path */
2463 else if (code == CM_ERROR_TIMEDOUT) {
2465 error = 81; /* server is paused */
2467 else if (code == CM_ERROR_RETRY) {
2468 class = 2; /* shouldn't happen */
2471 else if (code == CM_ERROR_NOACCESS) {
2473 error = 4; /* bad access */
2475 else if (code == CM_ERROR_READONLY) {
2477 error = 19; /* read only */
2479 else if (code == CM_ERROR_NOSUCHFILE) {
2481 error = 2; /* ENOENT! */
2483 else if (code == CM_ERROR_NOSUCHPATH) {
2485 error = 3; /* Bad path */
2487 else if (code == CM_ERROR_TOOBIG) {
2489 error = 11; /* bad format */
2491 else if (code == CM_ERROR_INVAL) {
2492 class = 2; /* server non-specific error code */
2495 else if (code == CM_ERROR_BADFD) {
2497 error = 6; /* invalid file handle */
2499 else if (code == CM_ERROR_BADFDOP) {
2500 class = 1; /* invalid op on FD */
2503 else if (code == CM_ERROR_EXISTS) {
2505 error = 80; /* file already exists */
2507 else if (code == CM_ERROR_NOTEMPTY) {
2509 error = 5; /* delete directory not empty */
2511 else if (code == CM_ERROR_CROSSDEVLINK) {
2513 error = 17; /* EXDEV */
2515 else if (code == CM_ERROR_NOTDIR) {
2516 class = 1; /* bad path */
2519 else if (code == CM_ERROR_ISDIR) {
2520 class = 1; /* access denied; DOS doesn't have a good match */
2523 else if (code == CM_ERROR_BADOP) {
2527 else if (code == CM_ERROR_BADSHARENAME) {
2531 else if (code == CM_ERROR_NOIPC) {
2533 error = 4; /* bad access */
2535 else if (code == CM_ERROR_CLOCKSKEW) {
2536 class = 1; /* invalid function */
2539 else if (code == CM_ERROR_BADTID) {
2543 else if (code == CM_ERROR_USESTD) {
2547 else if (code == CM_ERROR_REMOTECONN) {
2551 else if (code == CM_ERROR_QUOTA) {
2552 if (vcp->flags & SMB_VCFLAG_USEV3) {
2554 error = 39; /* disk full */
2558 error = 5; /* access denied */
2561 else if (code == CM_ERROR_SPACE) {
2562 if (vcp->flags & SMB_VCFLAG_USEV3) {
2564 error = 39; /* disk full */
2568 error = 5; /* access denied */
2571 else if (code == CM_ERROR_PARTIALWRITE) {
2573 error = 39; /* disk full */
2575 else if (code == CM_ERROR_ATSYS) {
2577 error = 2; /* ENOENT */
2579 else if (code == CM_ERROR_WOULDBLOCK) {
2581 error = 33; /* lock conflict */
2583 else if (code == CM_ERROR_NOFILES) {
2585 error = 18; /* no files in search */
2587 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2589 error = 183; /* Samba uses this */
2591 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2592 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2594 error = 2; /* bad password */
2596 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2598 error = 3; /* bad path */
2607 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2610 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2612 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2613 return CM_ERROR_BADOP;
2616 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2618 unsigned short EchoCount, i;
2619 char *data, *outdata;
2622 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2624 for (i=1; i<=EchoCount; i++) {
2625 data = smb_GetSMBData(inp, &dataSize);
2626 smb_SetSMBParm(outp, 0, i);
2627 smb_SetSMBDataLength(outp, dataSize);
2628 outdata = smb_GetSMBData(outp, NULL);
2629 memcpy(outdata, data, dataSize);
2630 smb_SendPacket(vcp, outp);
2636 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2639 long count, minCount, finalCount;
2643 cm_user_t *userp = NULL;
2647 char *rawBuf = NULL;
2649 dos_ptr rawBuf = NULL;
2656 fd = smb_GetSMBParm(inp, 0);
2657 count = smb_GetSMBParm(inp, 3);
2658 minCount = smb_GetSMBParm(inp, 4);
2659 offset.HighPart = 0; /* too bad */
2660 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2662 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2663 fd, offset.LowPart, count);
2665 fidp = smb_FindFID(vcp, fd, 0);
2669 lock_ObtainMutex(&smb_RawBufLock);
2671 /* Get a raw buf, from head of list */
2672 rawBuf = smb_RawBufs;
2674 smb_RawBufs = *(char **)smb_RawBufs;
2676 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2679 lock_ReleaseMutex(&smb_RawBufLock);
2683 if (fidp->flags & SMB_FID_IOCTL)
2686 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2688 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2691 /* Give back raw buffer */
2692 lock_ObtainMutex(&smb_RawBufLock);
2694 *((char **) rawBuf) = smb_RawBufs;
2696 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2699 smb_RawBufs = rawBuf;
2700 lock_ReleaseMutex(&smb_RawBufLock);
2703 smb_ReleaseFID(fidp);
2707 userp = smb_GetUser(vcp, inp);
2710 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2712 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2713 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2714 userp, &finalCount, TRUE /* rawFlag */);
2721 cm_ReleaseUser(userp);
2724 smb_ReleaseFID(fidp);
2729 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2731 memset((char *)ncbp, 0, sizeof(NCB));
2733 ncbp->ncb_length = (unsigned short) finalCount;
2734 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2735 ncbp->ncb_lana_num = vcp->lana;
2736 ncbp->ncb_command = NCBSEND;
2737 ncbp->ncb_buffer = rawBuf;
2740 code = Netbios(ncbp);
2742 code = Netbios(ncbp, dos_ncb);
2745 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2748 /* Give back raw buffer */
2749 lock_ObtainMutex(&smb_RawBufLock);
2751 *((char **) rawBuf) = smb_RawBufs;
2753 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2756 smb_RawBufs = rawBuf;
2757 lock_ReleaseMutex(&smb_RawBufLock);
2763 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2765 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2770 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2772 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2777 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2784 int protoIndex; /* index we're using */
2789 char protocol_array[10][1024]; /* protocol signature of the client */
2790 int caps; /* capabilities */
2793 TIME_ZONE_INFORMATION tzi;
2795 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2799 DWORD now = GetCurrentTime();
2800 if (now - last_msg_time >= 30000
2801 && now - last_msg_time <= 90000) {
2803 "Setting dead_vcp %x", active_vcp);
2805 smb_ReleaseVC(dead_vcp);
2807 "Previous dead_vcp %x", dead_vcp);
2809 smb_HoldVC(active_vcp);
2810 dead_vcp = active_vcp;
2811 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2816 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2818 namep = smb_GetSMBData(inp, &dbytes);
2821 coreProtoIndex = -1; /* not found */
2824 while(namex < dbytes) {
2825 osi_Log1(smb_logp, "Protocol %s",
2826 osi_LogSaveString(smb_logp, namep+1));
2827 strcpy(protocol_array[tcounter], namep+1);
2829 /* namep points at the first protocol, or really, a 0x02
2830 * byte preceding the null-terminated ASCII name.
2832 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2833 coreProtoIndex = tcounter;
2835 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2836 v3ProtoIndex = tcounter;
2838 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2839 NTProtoIndex = tcounter;
2842 /* compute size of protocol entry */
2843 entryLength = strlen(namep+1);
2844 entryLength += 2; /* 0x02 bytes and null termination */
2846 /* advance over this protocol entry */
2847 namex += entryLength;
2848 namep += entryLength;
2849 tcounter++; /* which proto entry we're looking at */
2852 if (NTProtoIndex != -1) {
2853 protoIndex = NTProtoIndex;
2854 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2856 else if (v3ProtoIndex != -1) {
2857 protoIndex = v3ProtoIndex;
2858 vcp->flags |= SMB_VCFLAG_USEV3;
2860 else if (coreProtoIndex != -1) {
2861 protoIndex = coreProtoIndex;
2862 vcp->flags |= SMB_VCFLAG_USECORE;
2864 else protoIndex = -1;
2866 if (protoIndex == -1)
2867 return CM_ERROR_INVAL;
2868 else if (NTProtoIndex != -1) {
2869 smb_SetSMBParm(outp, 0, protoIndex);
2870 if (smb_authType != SMB_AUTH_NONE) {
2871 smb_SetSMBParmByte(outp, 1,
2872 NEGOTIATE_SECURITY_USER_LEVEL |
2873 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2875 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2877 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2878 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2879 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2880 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2881 /* The session key is not a well documented field however most clients
2882 * will echo back the session key to the server. Currently we are using
2883 * the same value for all sessions. We should generate a random value
2884 * and store it into the vcp
2886 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2887 smb_SetSMBParm(outp, 8, 1);
2889 * Tried changing the capabilities to support for W2K - defect 117695
2890 * Maybe something else needs to be changed here?
2894 smb_SetSMBParmLong(outp, 9, 0x43fd);
2896 smb_SetSMBParmLong(outp, 9, 0x251);
2899 * 32-bit error codes *
2904 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2906 NTNEGOTIATE_CAPABILITY_DFS |
2908 NTNEGOTIATE_CAPABILITY_NTFIND |
2909 NTNEGOTIATE_CAPABILITY_RAWMODE |
2910 NTNEGOTIATE_CAPABILITY_NTSMB;
2912 if ( smb_authType == SMB_AUTH_EXTENDED )
2913 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2915 smb_SetSMBParmLong(outp, 9, caps);
2917 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2918 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2919 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2921 GetTimeZoneInformation(&tzi);
2922 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2924 if (smb_authType == SMB_AUTH_NTLM) {
2925 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2926 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2927 /* paste in encryption key */
2928 datap = smb_GetSMBData(outp, NULL);
2929 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2930 /* and the faux domain name */
2931 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2932 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2936 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2938 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2940 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2942 datap = smb_GetSMBData(outp, NULL);
2943 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2946 datap += sizeof(smb_ServerGUID);
2947 memcpy(datap, secBlob, secBlobLength);
2951 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2952 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2955 else if (v3ProtoIndex != -1) {
2956 smb_SetSMBParm(outp, 0, protoIndex);
2958 /* NOTE: Extended authentication cannot be negotiated with v3
2959 * therefore we fail over to NTLM
2961 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2962 smb_SetSMBParm(outp, 1,
2963 NEGOTIATE_SECURITY_USER_LEVEL |
2964 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2966 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2968 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2969 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2970 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2971 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2972 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2973 smb_SetSMBParm(outp, 7, 1);
2975 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2976 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2977 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2979 GetTimeZoneInformation(&tzi);
2980 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2982 /* NOTE: Extended authentication cannot be negotiated with v3
2983 * therefore we fail over to NTLM
2985 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2986 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2987 smb_SetSMBParm(outp, 12, 0); /* resvd */
2988 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2989 datap = smb_GetSMBData(outp, NULL);
2990 /* paste in a new encryption key */
2991 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2992 /* and the faux domain name */
2993 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2995 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2996 smb_SetSMBParm(outp, 12, 0); /* resvd */
2997 smb_SetSMBDataLength(outp, 0);
3000 else if (coreProtoIndex != -1) { /* not really supported anymore */
3001 smb_SetSMBParm(outp, 0, protoIndex);
3002 smb_SetSMBDataLength(outp, 0);
3007 void smb_Daemon(void *parmp)
3009 afs_uint32 count = 0;
3011 while(smbShutdownFlag == 0) {
3015 if (smbShutdownFlag == 1)
3018 if ((count % 72) == 0) { /* every five minutes */
3020 time_t old_localZero = smb_localZero;
3022 /* Initialize smb_localZero */
3023 myTime.tm_isdst = -1; /* compute whether on DST or not */
3024 myTime.tm_year = 70;
3030 smb_localZero = mktime(&myTime);
3032 #ifndef USE_NUMERIC_TIME_CONV
3033 smb_CalculateNowTZ();
3034 #endif /* USE_NUMERIC_TIME_CONV */
3035 #ifdef AFS_FREELANCE
3036 if ( smb_localZero != old_localZero )
3037 cm_noteLocalMountPointChange();
3040 /* XXX GC dir search entries */
3044 void smb_WaitingLocksDaemon()
3046 smb_waitingLock_t *wL, *nwL;
3049 smb_packet_t *inp, *outp;
3053 while (smbShutdownFlag == 0) {
3054 lock_ObtainWrite(&smb_globalLock);
3055 nwL = smb_allWaitingLocks;
3057 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3067 lock_ObtainWrite(&smb_globalLock);
3069 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
3070 lock_ReleaseWrite(&smb_globalLock);
3071 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
3072 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
3073 if (code == CM_ERROR_WOULDBLOCK) {
3075 if (wL->timeRemaining != 0xffffffff
3076 && (wL->timeRemaining -= 1000) < 0)
3086 ncbp->ncb_length = inp->ncb_length;
3087 inp->spacep = cm_GetSpace();
3089 /* Remove waitingLock from list */
3090 lock_ObtainWrite(&smb_globalLock);
3091 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3093 lock_ReleaseWrite(&smb_globalLock);
3095 /* Resume packet processing */
3097 smb_SetSMBDataLength(outp, 0);
3098 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3099 outp->resumeCode = code;
3101 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3104 cm_FreeSpace(inp->spacep);
3105 smb_FreePacket(inp);
3106 smb_FreePacket(outp);
3110 } while (nwL && smbShutdownFlag == 0);
3115 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3117 osi_Log0(smb_logp, "SMB receive get disk attributes");
3119 smb_SetSMBParm(outp, 0, 32000);
3120 smb_SetSMBParm(outp, 1, 64);
3121 smb_SetSMBParm(outp, 2, 1024);
3122 smb_SetSMBParm(outp, 3, 30000);
3123 smb_SetSMBParm(outp, 4, 0);
3124 smb_SetSMBDataLength(outp, 0);
3128 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3132 unsigned short newTid;
3133 char shareName[256];
3141 osi_Log0(smb_logp, "SMB receive tree connect");
3143 /* parse input parameters */
3144 tp = smb_GetSMBData(inp, NULL);
3145 pathp = smb_ParseASCIIBlock(tp, &tp);
3146 if (smb_StoreAnsiFilenames)
3147 OemToChar(pathp,pathp);
3148 passwordp = smb_ParseASCIIBlock(tp, &tp);
3149 tp = strrchr(pathp, '\\');
3151 return CM_ERROR_BADSMB;
3152 strcpy(shareName, tp+1);
3154 userp = smb_GetUser(vcp, inp);
3156 lock_ObtainMutex(&vcp->mx);
3157 newTid = vcp->tidCounter++;
3158 lock_ReleaseMutex(&vcp->mx);
3160 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3161 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3162 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3164 smb_ReleaseUID(uidp);
3166 smb_ReleaseTID(tidp);
3167 return CM_ERROR_BADSHARENAME;
3169 lock_ObtainMutex(&tidp->mx);
3170 tidp->userp = userp;
3171 tidp->pathname = sharePath;
3172 lock_ReleaseMutex(&tidp->mx);
3173 smb_ReleaseTID(tidp);
3175 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3176 smb_SetSMBParm(rsp, 1, newTid);
3177 smb_SetSMBDataLength(rsp, 0);
3179 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3183 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3187 if (*inp++ != 0x1) return NULL;
3188 tlen = inp[0] + (inp[1]<<8);
3189 inp += 2; /* skip length field */
3192 *chainpp = inp + tlen;
3195 if (lengthp) *lengthp = tlen;
3200 /* set maskp to the mask part of the incoming path.
3201 * Mask is 11 bytes long (8.3 with the dot elided).
3202 * Returns true if succeeds with a valid name, otherwise it does
3203 * its best, but returns false.
3205 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3213 /* starts off valid */
3216 /* mask starts out all blanks */
3217 memset(maskp, ' ', 11);
3219 /* find last backslash, or use whole thing if there is none */
3220 tp = strrchr(pathp, '\\');
3221 if (!tp) tp = pathp;
3222 else tp++; /* skip slash */
3226 /* names starting with a dot are illegal */
3227 if (*tp == '.') valid8Dot3 = 0;
3231 if (tc == 0) return valid8Dot3;
3232 if (tc == '.' || tc == '"') break;
3233 if (i < 8) *up++ = tc;
3234 else valid8Dot3 = 0;
3237 /* if we get here, tp point after the dot */
3238 up = maskp+8; /* ext goes here */
3245 if (tc == '.' || tc == '"')
3248 /* copy extension if not too long */
3258 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3268 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3270 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3274 /* otherwise, we have a valid 8.3 name; see if we have a match,
3275 * treating '?' as a wildcard in maskp (but not in the file name).
3277 tp1 = umask; /* real name, in mask format */
3278 tp2 = maskp; /* mask, in mask format */
3279 for(i=0; i<11; i++) {
3280 tc1 = *tp1++; /* char from real name */
3281 tc2 = *tp2++; /* char from mask */
3282 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3283 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3286 if (tc2 == '?' && tc1 != ' ')
3293 /* we got a match */
3297 char *smb_FindMask(char *pathp)
3301 tp = strrchr(pathp, '\\'); /* find last slash */
3304 return tp+1; /* skip the slash */
3306 return pathp; /* no slash, return the entire path */
3309 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3311 unsigned char *pathp;
3313 unsigned char mask[11];
3314 unsigned char *statBlockp;
3315 unsigned char initStatBlock[21];
3318 osi_Log0(smb_logp, "SMB receive search volume");
3320 /* pull pathname and stat block out of request */
3321 tp = smb_GetSMBData(inp, NULL);
3322 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3323 osi_assert(pathp != NULL);
3324 if (smb_StoreAnsiFilenames)
3325 OemToChar(pathp,pathp);
3326 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3327 osi_assert(statBlockp != NULL);
3329 statBlockp = initStatBlock;
3333 /* for returning to caller */
3334 smb_Get8Dot3MaskFromPath(mask, pathp);
3336 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3337 tp = smb_GetSMBData(outp, NULL);
3339 *tp++ = 43; /* bytes in a dir entry */
3340 *tp++ = 0; /* high byte in counter */
3342 /* now marshall the dir entry, starting with the search status */
3343 *tp++ = statBlockp[0]; /* Reserved */
3344 memcpy(tp, mask, 11); tp += 11; /* FileName */
3346 /* now pass back server use info, with 1st byte non-zero */
3348 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3350 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3352 *tp++ = 0x8; /* attribute: volume */
3362 /* 4 byte file size */
3368 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3369 memset(tp, ' ', 13);
3372 /* set the length of the data part of the packet to 43 + 3, for the dir
3373 * entry plus the 5 and the length fields.
3375 smb_SetSMBDataLength(outp, 46);
3379 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3380 cm_user_t *userp, cm_req_t *reqp)
3388 smb_dirListPatch_t *patchp;
3389 smb_dirListPatch_t *npatchp;
3391 for (patchp = *dirPatchespp; patchp; patchp =
3392 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3394 dptr = patchp->dptr;
3396 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3398 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3399 *dptr++ = SMB_ATTR_HIDDEN;
3402 lock_ObtainMutex(&scp->mx);
3403 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3404 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3406 lock_ReleaseMutex(&scp->mx);
3407 cm_ReleaseSCache(scp);
3408 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3409 *dptr++ = SMB_ATTR_HIDDEN;
3413 attr = smb_Attributes(scp);
3414 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3415 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3416 attr |= SMB_ATTR_HIDDEN;
3420 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3423 shortTemp = (unsigned short) (dosTime & 0xffff);
3424 *((u_short *)dptr) = shortTemp;
3427 /* and copy out date */
3428 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3429 *((u_short *)dptr) = shortTemp;
3432 /* copy out file length */
3433 *((u_long *)dptr) = scp->length.LowPart;
3435 lock_ReleaseMutex(&scp->mx);
3436 cm_ReleaseSCache(scp);
3439 /* now free the patches */
3440 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3441 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3445 /* and mark the list as empty */
3446 *dirPatchespp = NULL;
3451 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3460 smb_dirListPatch_t *dirListPatchesp;
3461 smb_dirListPatch_t *curPatchp;
3465 osi_hyper_t dirLength;
3466 osi_hyper_t bufferOffset;
3467 osi_hyper_t curOffset;
3469 unsigned char *inCookiep;
3470 smb_dirSearch_t *dsp;
3474 unsigned long clientCookie;
3475 cm_pageHeader_t *pageHeaderp;
3476 cm_user_t *userp = NULL;
3483 long nextEntryCookie;
3484 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3485 char resByte; /* reserved byte from the cookie */
3486 char *op; /* output data ptr */
3487 char *origOp; /* original value of op */
3488 cm_space_t *spacep; /* for pathname buffer */
3499 maxCount = smb_GetSMBParm(inp, 0);
3501 dirListPatchesp = NULL;
3503 caseFold = CM_FLAG_CASEFOLD;
3505 tp = smb_GetSMBData(inp, NULL);
3506 pathp = smb_ParseASCIIBlock(tp, &tp);
3507 if (smb_StoreAnsiFilenames)
3508 OemToChar(pathp,pathp);
3509 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3511 /* bail out if request looks bad */
3512 if (!tp || !pathp) {
3513 return CM_ERROR_BADSMB;
3516 /* We can handle long names */
3517 if (vcp->flags & SMB_VCFLAG_USENT)
3518 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3520 /* make sure we got a whole search status */
3521 if (dataLength < 21) {
3522 nextCookie = 0; /* start at the beginning of the dir */
3525 attribute = smb_GetSMBParm(inp, 1);
3527 /* handle volume info in another function */
3528 if (attribute & 0x8)
3529 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3531 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3532 maxCount, osi_LogSaveString(smb_logp, pathp));
3534 if (*pathp == 0) { /* null pathp, treat as root dir */
3535 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3536 return CM_ERROR_NOFILES;
3540 dsp = smb_NewDirSearch(0);
3541 dsp->attribute = attribute;
3542 smb_Get8Dot3MaskFromPath(mask, pathp);
3543 memcpy(dsp->mask, mask, 11);
3545 /* track if this is likely to match a lot of entries */
3546 if (smb_IsStarMask(mask))
3551 /* pull the next cookie value out of the search status block */
3552 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3553 + (inCookiep[16]<<24);
3554 dsp = smb_FindDirSearch(inCookiep[12]);
3556 /* can't find dir search status; fatal error */
3557 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3558 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3559 return CM_ERROR_BADFD;
3561 attribute = dsp->attribute;
3562 resByte = inCookiep[0];
3564 /* copy out client cookie, in host byte order. Don't bother
3565 * interpreting it, since we're just passing it through, anyway.
3567 memcpy(&clientCookie, &inCookiep[17], 4);
3569 memcpy(mask, dsp->mask, 11);
3571 /* assume we're doing a star match if it has continued for more
3577 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3578 nextCookie, dsp->cookie, attribute);
3580 userp = smb_GetUser(vcp, inp);
3582 /* try to get the vnode for the path name next */
3583 lock_ObtainMutex(&dsp->mx);
3589 spacep = inp->spacep;
3590 smb_StripLastComponent(spacep->data, NULL, pathp);
3591 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3593 lock_ReleaseMutex(&dsp->mx);
3594 cm_ReleaseUser(userp);
3595 smb_DeleteDirSearch(dsp);
3596 smb_ReleaseDirSearch(dsp);
3597 return CM_ERROR_NOFILES;
3599 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3600 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3603 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3604 cm_ReleaseSCache(scp);
3605 lock_ReleaseMutex(&dsp->mx);
3606 cm_ReleaseUser(userp);
3607 smb_DeleteDirSearch(dsp);
3608 smb_ReleaseDirSearch(dsp);
3609 if ( WANTS_DFS_PATHNAMES(inp) )
3610 return CM_ERROR_PATH_NOT_COVERED;
3612 return CM_ERROR_BADSHARENAME;
3614 #endif /* DFS_SUPPORT */
3617 /* we need one hold for the entry we just stored into,
3618 * and one for our own processing. When we're done with this
3619 * function, we'll drop the one for our own processing.
3620 * We held it once from the namei call, and so we do another hold
3624 lock_ObtainMutex(&scp->mx);
3625 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3626 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3627 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3628 dsp->flags |= SMB_DIRSEARCH_BULKST;
3630 lock_ReleaseMutex(&scp->mx);
3633 lock_ReleaseMutex(&dsp->mx);
3635 cm_ReleaseUser(userp);
3636 smb_DeleteDirSearch(dsp);
3637 smb_ReleaseDirSearch(dsp);
3641 /* reserves space for parameter; we'll adjust it again later to the
3642 * real count of the # of entries we returned once we've actually
3643 * assembled the directory listing.
3645 smb_SetSMBParm(outp, 0, 0);
3647 /* get the directory size */
3648 lock_ObtainMutex(&scp->mx);
3649 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3650 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3652 lock_ReleaseMutex(&scp->mx);
3653 cm_ReleaseSCache(scp);
3654 cm_ReleaseUser(userp);
3655 smb_DeleteDirSearch(dsp);
3656 smb_ReleaseDirSearch(dsp);
3660 dirLength = scp->length;
3662 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3663 curOffset.HighPart = 0;
3664 curOffset.LowPart = nextCookie;
3665 origOp = op = smb_GetSMBData(outp, NULL);
3666 /* and write out the basic header */
3667 *op++ = 5; /* variable block */
3668 op += 2; /* skip vbl block length; we'll fill it in later */
3672 /* make sure that curOffset.LowPart doesn't point to the first
3673 * 32 bytes in the 2nd through last dir page, and that it doesn't
3674 * point at the first 13 32-byte chunks in the first dir page,
3675 * since those are dir and page headers, and don't contain useful
3678 temp = curOffset.LowPart & (2048-1);
3679 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3680 /* we're in the first page */
3681 if (temp < 13*32) temp = 13*32;
3684 /* we're in a later dir page */
3685 if (temp < 32) temp = 32;
3688 /* make sure the low order 5 bits are zero */
3691 /* now put temp bits back ito curOffset.LowPart */
3692 curOffset.LowPart &= ~(2048-1);
3693 curOffset.LowPart |= temp;
3695 /* check if we've returned all the names that will fit in the
3698 if (returnedNames >= maxCount) {
3699 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3700 returnedNames, maxCount);
3704 /* check if we've passed the dir's EOF */
3705 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3707 /* see if we can use the bufferp we have now; compute in which page
3708 * the current offset would be, and check whether that's the offset
3709 * of the buffer we have. If not, get the buffer.
3711 thyper.HighPart = curOffset.HighPart;
3712 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3713 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3716 buf_Release(bufferp);
3719 lock_ReleaseMutex(&scp->mx);
3720 lock_ObtainRead(&scp->bufCreateLock);
3721 code = buf_Get(scp, &thyper, &bufferp);
3722 lock_ReleaseRead(&scp->bufCreateLock);
3723 lock_ObtainMutex(&dsp->mx);
3725 /* now, if we're doing a star match, do bulk fetching of all of
3726 * the status info for files in the dir.
3729 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3730 lock_ObtainMutex(&scp->mx);
3731 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3732 LargeIntegerGreaterThanOrEqualTo(thyper,
3733 scp->bulkStatProgress)) {
3734 /* Don't bulk stat if risking timeout */
3735 int now = GetCurrentTime();
3736 if (now - req.startTime > 5000) {
3737 scp->bulkStatProgress = thyper;
3738 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3739 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3741 cm_TryBulkStat(scp, &thyper, userp, &req);
3744 lock_ObtainMutex(&scp->mx);
3746 lock_ReleaseMutex(&dsp->mx);
3748 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3752 bufferOffset = thyper;
3754 /* now get the data in the cache */
3756 code = cm_SyncOp(scp, bufferp, userp, &req,
3758 CM_SCACHESYNC_NEEDCALLBACK |
3759 CM_SCACHESYNC_READ);
3761 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3765 if (cm_HaveBuffer(scp, bufferp, 0)) {
3766 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3770 /* otherwise, load the buffer and try again */
3771 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3773 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3774 scp, bufferp, code);
3779 buf_Release(bufferp);
3783 } /* if (wrong buffer) ... */
3785 /* now we have the buffer containing the entry we're interested in; copy
3786 * it out if it represents a non-deleted entry.
3788 entryInDir = curOffset.LowPart & (2048-1);
3789 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3791 /* page header will help tell us which entries are free. Page header
3792 * can change more often than once per buffer, since AFS 3 dir page size
3793 * may be less than (but not more than a buffer package buffer.
3795 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3796 temp &= ~(2048 - 1); /* turn off intra-page bits */
3797 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3799 /* now determine which entry we're looking at in the page. If it is
3800 * free (there's a free bitmap at the start of the dir), we should
3801 * skip these 32 bytes.
3803 slotInPage = (entryInDir & 0x7e0) >> 5;
3804 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3805 /* this entry is free */
3806 numDirChunks = 1; /* only skip this guy */
3810 tp = bufferp->datap + entryInBuffer;
3811 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3813 /* while we're here, compute the next entry's location, too,
3814 * since we'll need it when writing out the cookie into the dir
3817 * XXXX Probably should do more sanity checking.
3819 numDirChunks = cm_NameEntries(dep->name, NULL);
3821 /* compute the offset of the cookie representing the next entry */
3822 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3824 /* Compute 8.3 name if necessary */
3825 actualName = dep->name;
3826 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3827 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3828 actualName = shortName;
3831 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3832 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3833 osi_LogSaveString(smb_logp, actualName));
3835 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3836 /* this is one of the entries to use: it is not deleted
3837 * and it matches the star pattern we're looking for.
3840 /* Eliminate entries that don't match requested
3843 /* no hidden files */
3844 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3845 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3849 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3851 /* We have already done the cm_TryBulkStat above */
3852 fid.cell = scp->fid.cell;
3853 fid.volume = scp->fid.volume;
3854 fid.vnode = ntohl(dep->fid.vnode);
3855 fid.unique = ntohl(dep->fid.unique);
3856 fileType = cm_FindFileType(&fid);
3857 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3858 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3860 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3861 fileType == CM_SCACHETYPE_DFSLINK ||
3862 fileType == CM_SCACHETYPE_INVALID)
3863 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3868 memcpy(op, mask, 11); op += 11;
3869 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3870 *op++ = nextEntryCookie & 0xff;
3871 *op++ = (nextEntryCookie>>8) & 0xff;
3872 *op++ = (nextEntryCookie>>16) & 0xff;
3873 *op++ = (nextEntryCookie>>24) & 0xff;
3874 memcpy(op, &clientCookie, 4); op += 4;
3876 /* now we emit the attribute. This is sort of tricky,
3877 * since we need to really stat the file to find out
3878 * what type of entry we've got. Right now, we're
3879 * copying out data from a buffer, while holding the
3880 * scp locked, so it isn't really convenient to stat
3881 * something now. We'll put in a place holder now,
3882 * and make a second pass before returning this to get
3883 * the real attributes. So, we just skip the data for
3884 * now, and adjust it later. We allocate a patch
3885 * record to make it easy to find this point later.
3886 * The replay will happen at a time when it is safe to
3887 * unlock the directory.
3889 curPatchp = malloc(sizeof(*curPatchp));
3890 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3891 curPatchp->dptr = op;
3892 curPatchp->fid.cell = scp->fid.cell;
3893 curPatchp->fid.volume = scp->fid.volume;
3894 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3895 curPatchp->fid.unique = ntohl(dep->fid.unique);
3897 /* do hidden attribute here since name won't be around when applying
3901 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3902 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3904 curPatchp->flags = 0;
3906 op += 9; /* skip attr, time, date and size */
3908 /* zero out name area. The spec says to pad with
3909 * spaces, but Samba doesn't, and neither do we.
3913 /* finally, we get to copy out the name; we know that
3914 * it fits in 8.3 or the pattern wouldn't match, but it
3915 * never hurts to be sure.
3917 strncpy(op, actualName, 13);
3918 if (smb_StoreAnsiFilenames)
3921 /* Uppercase if requested by client */
3922 if (!KNOWS_LONG_NAMES(inp))
3927 /* now, adjust the # of entries copied */
3929 } /* if we're including this name */
3932 /* and adjust curOffset to be where the new cookie is */
3933 thyper.HighPart = 0;
3934 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3935 curOffset = LargeIntegerAdd(thyper, curOffset);
3936 } /* while copying data for dir listing */
3938 /* release the mutex */
3939 lock_ReleaseMutex(&scp->mx);
3940 if (bufferp) buf_Release(bufferp);
3942 /* apply and free last set of patches; if not doing a star match, this
3943 * will be empty, but better safe (and freeing everything) than sorry.
3945 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3947 /* special return code for unsuccessful search */
3948 if (code == 0 && dataLength < 21 && returnedNames == 0)
3949 code = CM_ERROR_NOFILES;
3951 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3952 returnedNames, code);
3955 smb_DeleteDirSearch(dsp);
3956 smb_ReleaseDirSearch(dsp);
3957 cm_ReleaseSCache(scp);
3958 cm_ReleaseUser(userp);
3962 /* finalize the output buffer */
3963 smb_SetSMBParm(outp, 0, returnedNames);
3964 temp = (long) (op - origOp);
3965 smb_SetSMBDataLength(outp, temp);
3967 /* the data area is a variable block, which has a 5 (already there)
3968 * followed by the length of the # of data bytes. We now know this to
3969 * be "temp," although that includes the 3 bytes of vbl block header.
3970 * Deduct for them and fill in the length field.
3972 temp -= 3; /* deduct vbl block info */
3973 osi_assert(temp == (43 * returnedNames));
3974 origOp[1] = temp & 0xff;
3975 origOp[2] = (temp>>8) & 0xff;
3976 if (returnedNames == 0)
3977 smb_DeleteDirSearch(dsp);
3978 smb_ReleaseDirSearch(dsp);
3979 cm_ReleaseSCache(scp);
3980 cm_ReleaseUser(userp);
3984 /* verify that this is a valid path to a directory. I don't know why they
3985 * don't use the get file attributes call.
3987 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3991 cm_scache_t *rootScp;
3992 cm_scache_t *newScp;
4001 pathp = smb_GetSMBData(inp, NULL);
4002 pathp = smb_ParseASCIIBlock(pathp, NULL);
4004 return CM_ERROR_BADFD;
4005 if (smb_StoreAnsiFilenames)
4006 OemToChar(pathp,pathp);
4007 osi_Log1(smb_logp, "SMB receive check path %s",
4008 osi_LogSaveString(smb_logp, pathp));
4010 rootScp = cm_data.rootSCachep;
4012 userp = smb_GetUser(vcp, inp);
4014 caseFold = CM_FLAG_CASEFOLD;
4016 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4018 cm_ReleaseUser(userp);
4019 return CM_ERROR_NOSUCHPATH;
4021 code = cm_NameI(rootScp, pathp,
4022 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4023 userp, tidPathp, &req, &newScp);
4026 cm_ReleaseUser(userp);
4031 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4032 cm_ReleaseSCache(newScp);
4033 cm_ReleaseUser(userp);
4034 if ( WANTS_DFS_PATHNAMES(inp) )
4035 return CM_ERROR_PATH_NOT_COVERED;
4037 return CM_ERROR_BADSHARENAME;
4039 #endif /* DFS_SUPPORT */
4041 /* now lock the vnode with a callback; returns with newScp locked */
4042 lock_ObtainMutex(&newScp->mx);
4043 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4044 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4045 if (code && code != CM_ERROR_NOACCESS) {
4046 lock_ReleaseMutex(&newScp->mx);
4047 cm_ReleaseSCache(newScp);
4048 cm_ReleaseUser(userp);
4052 attrs = smb_Attributes(newScp);
4054 if (!(attrs & SMB_ATTR_DIRECTORY))
4055 code = CM_ERROR_NOTDIR;
4057 lock_ReleaseMutex(&newScp->mx);
4059 cm_ReleaseSCache(newScp);
4060 cm_ReleaseUser(userp);
4064 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4068 cm_scache_t *rootScp;
4069 unsigned short attribute;
4071 cm_scache_t *newScp;
4080 /* decode basic attributes we're passed */
4081 attribute = smb_GetSMBParm(inp, 0);
4082 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4084 pathp = smb_GetSMBData(inp, NULL);
4085 pathp = smb_ParseASCIIBlock(pathp, NULL);
4087 return CM_ERROR_BADSMB;
4088 if (smb_StoreAnsiFilenames)
4089 OemToChar(pathp,pathp);
4091 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4092 dosTime, attribute);
4094 rootScp = cm_data.rootSCachep;
4096 userp = smb_GetUser(vcp, inp);
4098 caseFold = CM_FLAG_CASEFOLD;
4100 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4102 cm_ReleaseUser(userp);
4103 return CM_ERROR_NOSUCHFILE;
4105 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4106 tidPathp, &req, &newScp);
4109 cm_ReleaseUser(userp);
4114 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4115 cm_ReleaseSCache(newScp);
4116 cm_ReleaseUser(userp);
4117 if ( WANTS_DFS_PATHNAMES(inp) )
4118 return CM_ERROR_PATH_NOT_COVERED;
4120 return CM_ERROR_BADSHARENAME;
4122 #endif /* DFS_SUPPORT */
4124 /* now lock the vnode with a callback; returns with newScp locked; we
4125 * need the current status to determine what the new status is, in some
4128 lock_ObtainMutex(&newScp->mx);
4129 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4130 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4132 lock_ReleaseMutex(&newScp->mx);
4133 cm_ReleaseSCache(newScp);
4134 cm_ReleaseUser(userp);
4138 /* Check for RO volume */
4139 if (newScp->flags & CM_SCACHEFLAG_RO) {
4140 lock_ReleaseMutex(&newScp->mx);
4141 cm_ReleaseSCache(newScp);
4142 cm_ReleaseUser(userp);
4143 return CM_ERROR_READONLY;
4146 /* prepare for setattr call */
4149 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4150 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4152 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4153 /* we're told to make a writable file read-only */
4154 attr.unixModeBits = newScp->unixModeBits & ~0222;
4155 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4157 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4158 /* we're told to make a read-only file writable */
4159 attr.unixModeBits = newScp->unixModeBits | 0222;
4160 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4162 lock_ReleaseMutex(&newScp->mx);
4164 /* now call setattr */
4166 code = cm_SetAttr(newScp, &attr, userp, &req);
4170 cm_ReleaseSCache(newScp);
4171 cm_ReleaseUser(userp);
4176 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4180 cm_scache_t *rootScp;
4181 cm_scache_t *newScp, *dscp;
4193 pathp = smb_GetSMBData(inp, NULL);
4194 pathp = smb_ParseASCIIBlock(pathp, NULL);
4196 return CM_ERROR_BADSMB;
4198 if (*pathp == 0) /* null path */
4201 if (smb_StoreAnsiFilenames)
4202 OemToChar(pathp,pathp);
4204 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4205 osi_LogSaveString(smb_logp, pathp));
4207 rootScp = cm_data.rootSCachep;
4209 userp = smb_GetUser(vcp, inp);
4211 /* we shouldn't need this for V3 requests, but we seem to */
4212 caseFold = CM_FLAG_CASEFOLD;
4214 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4216 cm_ReleaseUser(userp);
4217 return CM_ERROR_NOSUCHFILE;
4221 * XXX Strange hack XXX
4223 * As of Patch 5 (16 July 97), we are having the following problem:
4224 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4225 * requests to look up "desktop.ini" in all the subdirectories.
4226 * This can cause zillions of timeouts looking up non-existent cells
4227 * and volumes, especially in the top-level directory.
4229 * We have not found any way to avoid this or work around it except
4230 * to explicitly ignore the requests for mount points that haven't
4231 * yet been evaluated and for directories that haven't yet been
4234 * We should modify this hack to provide a fake desktop.ini file
4235 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4237 spacep = inp->spacep;
4238 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4239 #ifndef SPECIAL_FOLDERS
4240 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4241 code = cm_NameI(rootScp, spacep->data,
4242 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4243 userp, tidPathp, &req, &dscp);
4246 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4247 if ( WANTS_DFS_PATHNAMES(inp) )
4248 return CM_ERROR_PATH_NOT_COVERED;
4250 return CM_ERROR_BADSHARENAME;
4252 #endif /* DFS_SUPPORT */
4253 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4254 code = CM_ERROR_NOSUCHFILE;
4255 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4256 cm_buf_t *bp = buf_Find(dscp, &hzero);
4260 code = CM_ERROR_NOSUCHFILE;
4262 cm_ReleaseSCache(dscp);
4264 cm_ReleaseUser(userp);
4269 #endif /* SPECIAL_FOLDERS */
4271 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4272 tidPathp, &req, &newScp);
4274 cm_ReleaseUser(userp);
4279 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4280 cm_ReleaseSCache(newScp);
4281 cm_ReleaseUser(userp);
4282 if ( WANTS_DFS_PATHNAMES(inp) )
4283 return CM_ERROR_PATH_NOT_COVERED;
4285 return CM_ERROR_BADSHARENAME;
4287 #endif /* DFS_SUPPORT */
4289 /* now lock the vnode with a callback; returns with newScp locked */
4290 lock_ObtainMutex(&newScp->mx);
4291 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4292 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4294 lock_ReleaseMutex(&newScp->mx);
4295 cm_ReleaseSCache(newScp);
4296 cm_ReleaseUser(userp);
4301 /* use smb_Attributes instead. Also the fact that a file is
4302 * in a readonly volume doesn't mean it shojuld be marked as RO
4304 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4305 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4306 attrs = SMB_ATTR_DIRECTORY;
4309 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4310 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4312 attrs = smb_Attributes(newScp);
4315 smb_SetSMBParm(outp, 0, attrs);
4317 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4318 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4319 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4320 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4321 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4322 smb_SetSMBParm(outp, 5, 0);
4323 smb_SetSMBParm(outp, 6, 0);
4324 smb_SetSMBParm(outp, 7, 0);
4325 smb_SetSMBParm(outp, 8, 0);
4326 smb_SetSMBParm(outp, 9, 0);
4327 smb_SetSMBDataLength(outp, 0);
4328 lock_ReleaseMutex(&newScp->mx);
4330 cm_ReleaseSCache(newScp);
4331 cm_ReleaseUser(userp);
4336 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4340 osi_Log0(smb_logp, "SMB receive tree disconnect");
4342 /* find the tree and free it */
4343 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4345 lock_ObtainMutex(&tidp->mx);
4346 tidp->flags |= SMB_TIDFLAG_DELETE;
4347 lock_ReleaseMutex(&tidp->mx);
4348 smb_ReleaseTID(tidp);
4354 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4372 pathp = smb_GetSMBData(inp, NULL);
4373 pathp = smb_ParseASCIIBlock(pathp, NULL);
4374 if (smb_StoreAnsiFilenames)
4375 OemToChar(pathp,pathp);
4377 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4379 #ifdef DEBUG_VERBOSE
4383 hexpath = osi_HexifyString( pathp );
4384 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4389 share = smb_GetSMBParm(inp, 0);
4390 attribute = smb_GetSMBParm(inp, 1);
4392 spacep = inp->spacep;
4393 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4394 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4395 /* special case magic file name for receiving IOCTL requests
4396 * (since IOCTL calls themselves aren't getting through).
4398 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4399 smb_SetupIoctlFid(fidp, spacep);
4400 smb_SetSMBParm(outp, 0, fidp->fid);
4401 smb_SetSMBParm(outp, 1, 0); /* attrs */
4402 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4403 smb_SetSMBParm(outp, 3, 0);
4404 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4405 smb_SetSMBParm(outp, 5, 0x7fff);
4406 /* pass the open mode back */
4407 smb_SetSMBParm(outp, 6, (share & 0xf));
4408 smb_SetSMBDataLength(outp, 0);
4409 smb_ReleaseFID(fidp);
4413 userp = smb_GetUser(vcp, inp);
4415 caseFold = CM_FLAG_CASEFOLD;
4417 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4419 cm_ReleaseUser(userp);
4420 return CM_ERROR_NOSUCHPATH;
4422 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4423 tidPathp, &req, &scp);
4426 cm_ReleaseUser(userp);
4431 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4432 cm_ReleaseSCache(scp);
4433 cm_ReleaseUser(userp);
4434 if ( WANTS_DFS_PATHNAMES(inp) )
4435 return CM_ERROR_PATH_NOT_COVERED;
4437 return CM_ERROR_BADSHARENAME;
4439 #endif /* DFS_SUPPORT */
4441 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4443 cm_ReleaseSCache(scp);
4444 cm_ReleaseUser(userp);
4448 /* don't need callback to check file type, since file types never
4449 * change, and namei and cm_Lookup all stat the object at least once on
4450 * a successful return.
4452 if (scp->fileType != CM_SCACHETYPE_FILE) {
4453 cm_ReleaseSCache(scp);
4454 cm_ReleaseUser(userp);
4455 return CM_ERROR_ISDIR;
4458 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4461 /* save a pointer to the vnode */
4464 if ((share & 0xf) == 0)
4465 fidp->flags |= SMB_FID_OPENREAD;
4466 else if ((share & 0xf) == 1)
4467 fidp->flags |= SMB_FID_OPENWRITE;
4469 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4471 lock_ObtainMutex(&scp->mx);
4472 smb_SetSMBParm(outp, 0, fidp->fid);
4473 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4474 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4475 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4476 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4477 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4478 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4479 /* pass the open mode back; XXXX add access checks */
4480 smb_SetSMBParm(outp, 6, (share & 0xf));
4481 smb_SetSMBDataLength(outp, 0);
4482 lock_ReleaseMutex(&scp->mx);
4485 cm_Open(scp, 0, userp);
4487 /* send and free packet */
4488 smb_ReleaseFID(fidp);
4489 cm_ReleaseUser(userp);
4490 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4494 typedef struct smb_unlinkRock {
4499 char *maskp; /* pointer to the star pattern */
4504 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4507 smb_unlinkRock_t *rockp;
4515 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4516 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4517 caseFold |= CM_FLAG_8DOT3;
4519 matchName = dep->name;
4520 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4522 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4523 !cm_Is8Dot3(dep->name)) {
4524 cm_Gen8Dot3Name(dep, shortName, NULL);
4525 matchName = shortName;
4526 /* 8.3 matches are always case insensitive */
4527 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4530 osi_Log1(smb_logp, "Unlinking %s",
4531 osi_LogSaveString(smb_logp, matchName));
4532 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4533 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4534 smb_NotifyChange(FILE_ACTION_REMOVED,
4535 FILE_NOTIFY_CHANGE_FILE_NAME,
4536 dscp, dep->name, NULL, TRUE);
4540 /* If we made a case sensitive exact match, we might as well quit now. */
4541 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4542 code = CM_ERROR_STOPNOW;
4550 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4559 smb_unlinkRock_t rock;
4568 attribute = smb_GetSMBParm(inp, 0);
4570 tp = smb_GetSMBData(inp, NULL);
4571 pathp = smb_ParseASCIIBlock(tp, &tp);
4572 if (smb_StoreAnsiFilenames)
4573 OemToChar(pathp,pathp);
4575 osi_Log1(smb_logp, "SMB receive unlink %s",
4576 osi_LogSaveString(smb_logp, pathp));
4578 spacep = inp->spacep;
4579 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4581 userp = smb_GetUser(vcp, inp);
4583 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4585 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4587 cm_ReleaseUser(userp);
4588 return CM_ERROR_NOSUCHPATH;
4590 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4593 cm_ReleaseUser(userp);
4598 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4599 cm_ReleaseSCache(dscp);
4600 cm_ReleaseUser(userp);
4601 if ( WANTS_DFS_PATHNAMES(inp) )
4602 return CM_ERROR_PATH_NOT_COVERED;
4604 return CM_ERROR_BADSHARENAME;
4606 #endif /* DFS_SUPPORT */
4608 /* otherwise, scp points to the parent directory. */
4615 rock.maskp = smb_FindMask(pathp);
4616 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4619 thyper.HighPart = 0;
4625 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4626 * match. If that fails, we do a case insensitve match.
4628 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4629 !smb_IsStarMask(rock.maskp)) {
4630 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4633 thyper.HighPart = 0;
4634 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4639 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4641 if (code == CM_ERROR_STOPNOW)
4644 cm_ReleaseUser(userp);
4646 cm_ReleaseSCache(dscp);
4648 if (code == 0 && !rock.any)
4649 code = CM_ERROR_NOSUCHFILE;
4653 typedef struct smb_renameRock {
4654 cm_scache_t *odscp; /* old dir */
4655 cm_scache_t *ndscp; /* new dir */
4656 cm_user_t *userp; /* user */
4657 cm_req_t *reqp; /* request struct */
4658 smb_vc_t *vcp; /* virtual circuit */
4659 char *maskp; /* pointer to star pattern of old file name */
4660 int flags; /* tilde, casefold, etc */
4661 char *newNamep; /* ptr to the new file's name */
4664 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4667 smb_renameRock_t *rockp;
4672 rockp = (smb_renameRock_t *) vrockp;
4674 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4675 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4676 caseFold |= CM_FLAG_8DOT3;
4678 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4680 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4681 !cm_Is8Dot3(dep->name)) {
4682 cm_Gen8Dot3Name(dep, shortName, NULL);
4683 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4686 code = cm_Rename(rockp->odscp, dep->name,
4687 rockp->ndscp, rockp->newNamep, rockp->userp,
4689 /* if the call worked, stop doing the search now, since we
4690 * really only want to rename one file.
4693 code = CM_ERROR_STOPNOW;
4702 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4705 cm_space_t *spacep = NULL;
4706 smb_renameRock_t rock;
4707 cm_scache_t *oldDscp = NULL;
4708 cm_scache_t *newDscp = NULL;
4709 cm_scache_t *tmpscp= NULL;
4710 cm_scache_t *tmpscp2 = NULL;
4720 userp = smb_GetUser(vcp, inp);
4721 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4723 cm_ReleaseUser(userp);
4724 return CM_ERROR_NOSUCHPATH;
4728 spacep = inp->spacep;
4729 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4732 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4733 * what actually exists is foo/baz. I don't know why the code used to be
4734 * the way it was. 1/29/96
4736 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4738 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4740 * caseFold = CM_FLAG_CASEFOLD;
4742 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4743 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4744 userp, tidPathp, &req, &oldDscp);
4746 cm_ReleaseUser(userp);
4751 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4752 cm_ReleaseSCache(oldDscp);
4753 cm_ReleaseUser(userp);
4754 if ( WANTS_DFS_PATHNAMES(inp) )
4755 return CM_ERROR_PATH_NOT_COVERED;
4757 return CM_ERROR_BADSHARENAME;
4759 #endif /* DFS_SUPPORT */
4761 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4762 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4763 userp, tidPathp, &req, &newDscp);
4766 cm_ReleaseSCache(oldDscp);
4767 cm_ReleaseUser(userp);
4772 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4773 cm_ReleaseSCache(oldDscp);
4774 cm_ReleaseSCache(newDscp);
4775 cm_ReleaseUser(userp);
4776 if ( WANTS_DFS_PATHNAMES(inp) )
4777 return CM_ERROR_PATH_NOT_COVERED;
4779 return CM_ERROR_BADSHARENAME;
4781 #endif /* DFS_SUPPORT */
4784 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4785 * next, get the component names, and lower case them.
4788 /* handle the old name first */
4790 oldLastNamep = oldPathp;
4794 /* and handle the new name, too */
4796 newLastNamep = newPathp;
4800 /* TODO: The old name could be a wildcard. The new name must not be */
4802 /* do the vnode call */
4803 rock.odscp = oldDscp;
4804 rock.ndscp = newDscp;
4808 rock.maskp = oldLastNamep;
4809 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4810 rock.newNamep = newLastNamep;
4812 /* Check if the file already exists; if so return error */
4813 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4814 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4815 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4816 osi_LogSaveString(afsd_logp, newLastNamep));
4818 /* Check if the old and the new names differ only in case. If so return
4819 * success, else return CM_ERROR_EXISTS
4821 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4823 /* This would be a success only if the old file is *as same as* the new file */
4824 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4826 if (tmpscp == tmpscp2)
4829 code = CM_ERROR_EXISTS;
4830 cm_ReleaseSCache(tmpscp2);
4833 code = CM_ERROR_NOSUCHFILE;
4836 /* file exist, do not rename, also fixes move */
4837 osi_Log0(smb_logp, "Can't rename. Target already exists");
4838 code = CM_ERROR_EXISTS;
4842 cm_ReleaseSCache(tmpscp);
4843 cm_ReleaseSCache(newDscp);
4844 cm_ReleaseSCache(oldDscp);
4845 cm_ReleaseUser(userp);
4849 /* Now search the directory for the pattern, and do the appropriate rename when found */
4850 thyper.LowPart = 0; /* search dir from here */
4851 thyper.HighPart = 0;
4853 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4855 if (code == CM_ERROR_STOPNOW)
4858 code = CM_ERROR_NOSUCHFILE;
4860 /* Handle Change Notification */
4862 * Being lazy, not distinguishing between files and dirs in this
4863 * filter, since we'd have to do a lookup.
4865 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4866 if (oldDscp == newDscp) {
4867 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4868 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4869 filter, oldDscp, oldLastNamep,
4870 newLastNamep, TRUE);
4872 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4873 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4874 filter, oldDscp, oldLastNamep,
4876 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4877 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4878 filter, newDscp, newLastNamep,
4883 cm_ReleaseSCache(tmpscp);
4884 cm_ReleaseUser(userp);
4885 cm_ReleaseSCache(oldDscp);
4886 cm_ReleaseSCache(newDscp);
4891 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4894 cm_space_t *spacep = NULL;
4895 cm_scache_t *oldDscp = NULL;
4896 cm_scache_t *newDscp = NULL;
4897 cm_scache_t *tmpscp= NULL;
4898 cm_scache_t *tmpscp2 = NULL;
4899 cm_scache_t *sscp = NULL;
4908 userp = smb_GetUser(vcp, inp);
4910 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4912 cm_ReleaseUser(userp);
4913 return CM_ERROR_NOSUCHPATH;
4918 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4920 spacep = inp->spacep;
4921 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4923 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4924 userp, tidPathp, &req, &oldDscp);
4926 cm_ReleaseUser(userp);
4931 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4932 cm_ReleaseSCache(oldDscp);
4933 cm_ReleaseUser(userp);
4934 if ( WANTS_DFS_PATHNAMES(inp) )
4935 return CM_ERROR_PATH_NOT_COVERED;
4937 return CM_ERROR_BADSHARENAME;
4939 #endif /* DFS_SUPPORT */
4941 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4942 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4943 userp, tidPathp, &req, &newDscp);
4945 cm_ReleaseSCache(oldDscp);
4946 cm_ReleaseUser(userp);
4951 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4952 cm_ReleaseSCache(newDscp);
4953 cm_ReleaseSCache(oldDscp);
4954 cm_ReleaseUser(userp);
4955 if ( WANTS_DFS_PATHNAMES(inp) )
4956 return CM_ERROR_PATH_NOT_COVERED;
4958 return CM_ERROR_BADSHARENAME;
4960 #endif /* DFS_SUPPORT */
4962 /* Now, although we did two lookups for the two directories (because the same
4963 * directory can be referenced through different paths), we only allow hard links
4964 * within the same directory. */
4965 if (oldDscp != newDscp) {
4966 cm_ReleaseSCache(oldDscp);
4967 cm_ReleaseSCache(newDscp);
4968 cm_ReleaseUser(userp);
4969 return CM_ERROR_CROSSDEVLINK;
4972 /* handle the old name first */
4974 oldLastNamep = oldPathp;
4978 /* and handle the new name, too */
4980 newLastNamep = newPathp;
4984 /* now lookup the old name */
4985 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4986 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4988 cm_ReleaseSCache(oldDscp);
4989 cm_ReleaseSCache(newDscp);
4990 cm_ReleaseUser(userp);
4994 /* Check if the file already exists; if so return error */
4995 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4996 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4997 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4998 osi_LogSaveString(afsd_logp, newLastNamep));
5000 /* if the existing link is to the same file, then we return success */
5002 if(sscp == tmpscp) {
5005 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5006 code = CM_ERROR_EXISTS;
5011 cm_ReleaseSCache(tmpscp);
5012 cm_ReleaseSCache(sscp);
5013 cm_ReleaseSCache(newDscp);
5014 cm_ReleaseSCache(oldDscp);
5015 cm_ReleaseUser(userp);
5019 /* now create the hardlink */
5020 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5021 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5022 osi_Log1(smb_logp," Link returns %d", code);
5024 /* Handle Change Notification */
5026 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5027 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5028 smb_NotifyChange(FILE_ACTION_ADDED,
5029 filter, newDscp, newLastNamep,
5034 cm_ReleaseSCache(tmpscp);
5035 cm_ReleaseUser(userp);
5036 cm_ReleaseSCache(sscp);
5037 cm_ReleaseSCache(oldDscp);
5038 cm_ReleaseSCache(newDscp);
5043 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5049 tp = smb_GetSMBData(inp, NULL);
5050 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5051 if (smb_StoreAnsiFilenames)
5052 OemToChar(oldPathp,oldPathp);
5053 newPathp = smb_ParseASCIIBlock(tp, &tp);
5054 if (smb_StoreAnsiFilenames)
5055 OemToChar(newPathp,newPathp);
5057 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5058 osi_LogSaveString(smb_logp, oldPathp),
5059 osi_LogSaveString(smb_logp, newPathp));
5061 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5066 typedef struct smb_rmdirRock {
5070 char *maskp; /* pointer to the star pattern */
5075 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5078 smb_rmdirRock_t *rockp;
5083 rockp = (smb_rmdirRock_t *) vrockp;
5085 matchName = dep->name;
5086 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5087 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5089 match = (strcmp(matchName, rockp->maskp) == 0);
5091 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5092 !cm_Is8Dot3(dep->name)) {
5093 cm_Gen8Dot3Name(dep, shortName, NULL);
5094 matchName = shortName;
5095 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5098 osi_Log1(smb_logp, "Removing directory %s",
5099 osi_LogSaveString(smb_logp, matchName));
5100 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5101 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5102 smb_NotifyChange(FILE_ACTION_REMOVED,
5103 FILE_NOTIFY_CHANGE_DIR_NAME,
5104 dscp, dep->name, NULL, TRUE);
5113 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5121 smb_rmdirRock_t rock;
5130 tp = smb_GetSMBData(inp, NULL);
5131 pathp = smb_ParseASCIIBlock(tp, &tp);
5132 if (smb_StoreAnsiFilenames)
5133 OemToChar(pathp,pathp);
5135 spacep = inp->spacep;
5136 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5138 userp = smb_GetUser(vcp, inp);
5140 caseFold = CM_FLAG_CASEFOLD;
5142 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5144 cm_ReleaseUser(userp);
5145 return CM_ERROR_NOSUCHPATH;
5147 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5148 userp, tidPathp, &req, &dscp);
5151 cm_ReleaseUser(userp);
5156 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5157 cm_ReleaseSCache(dscp);
5158 cm_ReleaseUser(userp);
5159 if ( WANTS_DFS_PATHNAMES(inp) )
5160 return CM_ERROR_PATH_NOT_COVERED;
5162 return CM_ERROR_BADSHARENAME;
5164 #endif /* DFS_SUPPORT */
5166 /* otherwise, scp points to the parent directory. */
5173 rock.maskp = lastNamep;
5174 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5177 thyper.HighPart = 0;
5181 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5182 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5183 if (code == 0 && !rock.any) {
5185 thyper.HighPart = 0;
5186 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5187 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5190 cm_ReleaseUser(userp);
5192 cm_ReleaseSCache(dscp);
5194 if (code == 0 && !rock.any)
5195 code = CM_ERROR_NOSUCHFILE;
5199 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5209 fid = smb_GetSMBParm(inp, 0);
5211 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5213 fid = smb_ChainFID(fid, inp);
5214 fidp = smb_FindFID(vcp, fid, 0);
5215 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5217 smb_ReleaseFID(fidp);
5218 return CM_ERROR_BADFD;
5221 userp = smb_GetUser(vcp, inp);
5223 lock_ObtainMutex(&fidp->mx);
5224 if (fidp->flags & SMB_FID_OPENWRITE)
5225 code = cm_FSync(fidp->scp, userp, &req);
5228 lock_ReleaseMutex(&fidp->mx);
5230 smb_ReleaseFID(fidp);
5232 cm_ReleaseUser(userp);
5237 struct smb_FullNameRock {
5243 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5247 struct smb_FullNameRock *vrockp;
5249 vrockp = (struct smb_FullNameRock *)rockp;
5251 if (!cm_Is8Dot3(dep->name)) {
5252 cm_Gen8Dot3Name(dep, shortName, NULL);
5254 if (cm_stricmp(shortName, vrockp->name) == 0) {
5255 vrockp->fullName = strdup(dep->name);
5256 return CM_ERROR_STOPNOW;
5259 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5260 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5261 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5262 vrockp->fullName = strdup(dep->name);
5263 return CM_ERROR_STOPNOW;
5268 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5269 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5271 struct smb_FullNameRock rock;
5277 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5278 if (code == CM_ERROR_STOPNOW)
5279 *newPathp = rock.fullName;
5281 *newPathp = strdup(pathp);
5284 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5295 fid = smb_GetSMBParm(inp, 0);
5296 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5298 osi_Log1(smb_logp, "SMB close fid %d", fid);
5300 fid = smb_ChainFID(fid, inp);
5301 fidp = smb_FindFID(vcp, fid, 0);
5303 return CM_ERROR_BADFD;
5306 userp = smb_GetUser(vcp, inp);
5308 lock_ObtainMutex(&fidp->mx);
5310 /* Don't jump the gun on an async raw write */
5311 while (fidp->raw_writers) {
5312 lock_ReleaseMutex(&fidp->mx);
5313 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5314 lock_ObtainMutex(&fidp->mx);
5317 fidp->flags |= SMB_FID_DELETE;
5319 /* watch for ioctl closes, and read-only opens */
5320 if (fidp->scp != NULL &&
5321 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5322 == SMB_FID_OPENWRITE) {
5323 if (dosTime != 0 && dosTime != -1) {
5324 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5325 /* This fixes defect 10958 */
5326 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5327 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5329 code = cm_FSync(fidp->scp, userp, &req);
5334 if (fidp->flags & SMB_FID_DELONCLOSE) {
5335 cm_scache_t *dscp = fidp->NTopen_dscp;
5336 char *pathp = fidp->NTopen_pathp;
5339 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5340 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5341 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5342 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5343 smb_NotifyChange(FILE_ACTION_REMOVED,
5344 FILE_NOTIFY_CHANGE_DIR_NAME,
5345 dscp, fullPathp, NULL, TRUE);
5349 code = cm_Unlink(dscp, fullPathp, userp, &req);
5350 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5351 smb_NotifyChange(FILE_ACTION_REMOVED,
5352 FILE_NOTIFY_CHANGE_FILE_NAME,
5353 dscp, fullPathp, NULL, TRUE);
5357 lock_ReleaseMutex(&fidp->mx);
5359 if (fidp->flags & SMB_FID_NTOPEN) {
5360 cm_ReleaseSCache(fidp->NTopen_dscp);
5361 free(fidp->NTopen_pathp);
5363 if (fidp->NTopen_wholepathp)
5364 free(fidp->NTopen_wholepathp);
5366 smb_ReleaseFID(fidp);
5367 cm_ReleaseUser(userp);
5372 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5375 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5376 cm_user_t *userp, long *readp)
5378 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5379 cm_user_t *userp, long *readp, int dosflag)
5386 osi_hyper_t fileLength;
5388 osi_hyper_t lastByte;
5389 osi_hyper_t bufferOffset;
5390 long bufIndex, nbytes;
5400 lock_ObtainMutex(&fidp->mx);
5402 lock_ObtainMutex(&scp->mx);
5404 if (offset.HighPart == 0) {
5405 chunk = offset.LowPart >> cm_logChunkSize;
5406 if (chunk != fidp->curr_chunk) {
5407 fidp->prev_chunk = fidp->curr_chunk;
5408 fidp->curr_chunk = chunk;
5410 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5414 /* start by looking up the file's end */
5415 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5416 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5417 if (code) goto done;
5419 /* now we have the entry locked, look up the length */
5420 fileLength = scp->length;
5422 /* adjust count down so that it won't go past EOF */
5423 thyper.LowPart = count;
5424 thyper.HighPart = 0;
5425 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5427 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5428 /* we'd read past EOF, so just stop at fileLength bytes.
5429 * Start by computing how many bytes remain in the file.
5431 thyper = LargeIntegerSubtract(fileLength, offset);
5433 /* if we are past EOF, read 0 bytes */
5434 if (LargeIntegerLessThanZero(thyper))
5437 count = thyper.LowPart;
5442 /* now, copy the data one buffer at a time,
5443 * until we've filled the request packet
5446 /* if we've copied all the data requested, we're done */
5447 if (count <= 0) break;
5449 /* otherwise, load up a buffer of data */
5450 thyper.HighPart = offset.HighPart;
5451 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5452 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5455 buf_Release(bufferp);
5458 lock_ReleaseMutex(&scp->mx);
5460 lock_ObtainRead(&scp->bufCreateLock);
5461 code = buf_Get(scp, &thyper, &bufferp);
5462 lock_ReleaseRead(&scp->bufCreateLock);
5464 lock_ObtainMutex(&scp->mx);
5465 if (code) goto done;
5466 bufferOffset = thyper;
5468 /* now get the data in the cache */
5470 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5471 CM_SCACHESYNC_NEEDCALLBACK |
5472 CM_SCACHESYNC_READ);
5473 if (code) goto done;
5475 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5477 /* otherwise, load the buffer and try again */
5478 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5482 buf_Release(bufferp);
5486 } /* if (wrong buffer) ... */
5488 /* now we have the right buffer loaded. Copy out the
5489 * data from here to the user's buffer.
5491 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5493 /* and figure out how many bytes we want from this buffer */
5494 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5495 if (nbytes > count) nbytes = count; /* don't go past EOF */
5497 /* now copy the data */
5500 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5503 memcpy(op, bufferp->datap + bufIndex, nbytes);
5505 /* adjust counters, pointers, etc. */
5508 thyper.LowPart = nbytes;
5509 thyper.HighPart = 0;
5510 offset = LargeIntegerAdd(thyper, offset);
5514 lock_ReleaseMutex(&scp->mx);
5515 lock_ReleaseMutex(&fidp->mx);
5517 buf_Release(bufferp);
5519 if (code == 0 && sequential)
5520 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5526 * smb_WriteData -- common code for Write and Raw Write
5529 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5530 cm_user_t *userp, long *writtenp)
5532 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5533 cm_user_t *userp, long *writtenp, int dosflag)
5540 osi_hyper_t fileLength; /* file's length at start of write */
5541 osi_hyper_t minLength; /* don't read past this */
5542 long nbytes; /* # of bytes to transfer this iteration */
5544 osi_hyper_t thyper; /* hyper tmp variable */
5545 osi_hyper_t bufferOffset;
5546 long bufIndex; /* index in buffer where our data is */
5548 osi_hyper_t writeBackOffset;/* offset of region to write back when
5553 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5554 fidp->fid, offsetp->LowPart, count);
5564 lock_ObtainMutex(&fidp->mx);
5566 lock_ObtainMutex(&scp->mx);
5568 /* start by looking up the file's end */
5569 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5570 CM_SCACHESYNC_NEEDCALLBACK
5571 | CM_SCACHESYNC_SETSTATUS
5572 | CM_SCACHESYNC_GETSTATUS);
5576 /* make sure we have a writable FD */
5577 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5578 code = CM_ERROR_BADFDOP;
5582 /* now we have the entry locked, look up the length */
5583 fileLength = scp->length;
5584 minLength = fileLength;
5585 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5586 minLength = scp->serverLength;
5588 /* adjust file length if we extend past EOF */
5589 thyper.LowPart = count;
5590 thyper.HighPart = 0;
5591 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5592 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5593 /* we'd write past EOF, so extend the file */
5594 scp->mask |= CM_SCACHEMASK_LENGTH;
5595 scp->length = thyper;
5596 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5598 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5600 /* now, if the new position (thyper) and the old (offset) are in
5601 * different storeback windows, remember to store back the previous
5602 * storeback window when we're done with the write.
5604 if ((thyper.LowPart & (-cm_chunkSize)) !=
5605 (offset.LowPart & (-cm_chunkSize))) {
5606 /* they're different */
5608 writeBackOffset.HighPart = offset.HighPart;
5609 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5614 /* now, copy the data one buffer at a time, until we've filled the
5617 /* if we've copied all the data requested, we're done */
5621 /* handle over quota or out of space */
5622 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5623 *writtenp = written;
5624 code = CM_ERROR_QUOTA;
5628 /* otherwise, load up a buffer of data */
5629 thyper.HighPart = offset.HighPart;
5630 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5631 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5634 lock_ReleaseMutex(&bufferp->mx);
5635 buf_Release(bufferp);
5638 lock_ReleaseMutex(&scp->mx);
5640 lock_ObtainRead(&scp->bufCreateLock);
5641 code = buf_Get(scp, &thyper, &bufferp);
5642 lock_ReleaseRead(&scp->bufCreateLock);
5644 lock_ObtainMutex(&bufferp->mx);
5645 lock_ObtainMutex(&scp->mx);
5646 if (code) goto done;
5648 bufferOffset = thyper;
5650 /* now get the data in the cache */
5652 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5653 CM_SCACHESYNC_NEEDCALLBACK
5654 | CM_SCACHESYNC_WRITE
5655 | CM_SCACHESYNC_BUFLOCKED);
5659 /* If we're overwriting the entire buffer, or
5660 * if we're writing at or past EOF, mark the
5661 * buffer as current so we don't call
5662 * cm_GetBuffer. This skips the fetch from the
5663 * server in those cases where we're going to
5664 * obliterate all the data in the buffer anyway,
5665 * or in those cases where there is no useful
5666 * data at the server to start with.
5668 * Use minLength instead of scp->length, since
5669 * the latter has already been updated by this
5672 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5673 || LargeIntegerEqualTo(offset, bufferp->offset)
5674 && (count >= cm_data.buf_blockSize
5675 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5676 ConvertLongToLargeInteger(count)),
5678 if (count < cm_data.buf_blockSize
5679 && bufferp->dataVersion == -1)
5680 memset(bufferp->datap, 0,
5681 cm_data.buf_blockSize);
5682 bufferp->dataVersion = scp->dataVersion;
5685 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5687 /* otherwise, load the buffer and try again */
5688 lock_ReleaseMutex(&bufferp->mx);
5689 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5691 lock_ReleaseMutex(&scp->mx);
5692 lock_ObtainMutex(&bufferp->mx);
5693 lock_ObtainMutex(&scp->mx);
5697 lock_ReleaseMutex(&bufferp->mx);
5698 buf_Release(bufferp);
5702 } /* if (wrong buffer) ... */
5704 /* now we have the right buffer loaded. Copy out the
5705 * data from here to the user's buffer.
5707 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5709 /* and figure out how many bytes we want from this buffer */
5710 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5712 nbytes = count; /* don't go past end of request */
5714 /* now copy the data */
5717 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5720 memcpy(bufferp->datap + bufIndex, op, nbytes);
5721 buf_SetDirty(bufferp);
5723 /* and record the last writer */
5724 if (bufferp->userp != userp) {
5727 cm_ReleaseUser(bufferp->userp);
5728 bufferp->userp = userp;
5731 /* adjust counters, pointers, etc. */
5735 thyper.LowPart = nbytes;
5736 thyper.HighPart = 0;
5737 offset = LargeIntegerAdd(thyper, offset);
5741 lock_ReleaseMutex(&scp->mx);
5742 lock_ReleaseMutex(&fidp->mx);
5744 lock_ReleaseMutex(&bufferp->mx);
5745 buf_Release(bufferp);
5748 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5749 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5750 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5751 fidp->NTopen_dscp, fidp->NTopen_pathp,
5755 if (code == 0 && doWriteBack) {
5757 lock_ObtainMutex(&scp->mx);
5758 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5760 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5761 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5763 lock_ReleaseMutex(&scp->mx);
5764 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5765 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5768 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5769 fidp->fid, code, *writtenp);
5773 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5776 long count, written = 0, total_written = 0;
5781 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5783 int inDataBlockCount;
5785 fd = smb_GetSMBParm(inp, 0);
5786 count = smb_GetSMBParm(inp, 1);
5787 offset.HighPart = 0; /* too bad */
5788 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5790 op = smb_GetSMBData(inp, NULL);
5791 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5793 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5794 fd, offset.LowPart, count);
5796 fd = smb_ChainFID(fd, inp);
5797 fidp = smb_FindFID(vcp, fd, 0);
5799 return CM_ERROR_BADFD;
5802 if (fidp->flags & SMB_FID_IOCTL)
5803 return smb_IoctlWrite(fidp, vcp, inp, outp);
5805 userp = smb_GetUser(vcp, inp);
5807 /* special case: 0 bytes transferred means truncate to this position */
5813 truncAttr.mask = CM_ATTRMASK_LENGTH;
5814 truncAttr.length.LowPart = offset.LowPart;
5815 truncAttr.length.HighPart = 0;
5816 lock_ObtainMutex(&fidp->mx);
5817 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5818 lock_ReleaseMutex(&fidp->mx);
5819 smb_SetSMBParm(outp, 0, /* count */ 0);
5820 smb_SetSMBDataLength(outp, 0);
5821 fidp->flags |= SMB_FID_LENGTHSETDONE;
5826 * Work around bug in NT client
5828 * When copying a file, the NT client should first copy the data,
5829 * then copy the last write time. But sometimes the NT client does
5830 * these in the wrong order, so the data copies would inadvertently
5831 * cause the last write time to be overwritten. We try to detect this,
5832 * and don't set client mod time if we think that would go against the
5835 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5836 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5837 fidp->scp->clientModTime = time(NULL);
5841 while ( code == 0 && count > 0 ) {
5843 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5845 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5847 if (code == 0 && written == 0)
5848 code = CM_ERROR_PARTIALWRITE;
5850 offset.LowPart += written;
5852 total_written += written;
5856 /* set the packet data length to 3 bytes for the data block header,
5857 * plus the size of the data.
5859 smb_SetSMBParm(outp, 0, total_written);
5860 smb_SetSMBDataLength(outp, 0);
5863 smb_ReleaseFID(fidp);
5864 cm_ReleaseUser(userp);
5869 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5870 NCB *ncbp, raw_write_cont_t *rwcp)
5883 fd = smb_GetSMBParm(inp, 0);
5884 fidp = smb_FindFID(vcp, fd, 0);
5886 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5887 rwcp->offset.LowPart, rwcp->count);
5889 userp = smb_GetUser(vcp, inp);
5893 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5896 rawBuf = (dos_ptr) rwcp->buf;
5897 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5898 (unsigned char *) rawBuf, userp,
5902 if (rwcp->writeMode & 0x1) { /* synchronous */
5905 smb_FormatResponsePacket(vcp, inp, outp);
5906 op = (smb_t *) outp;
5907 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5908 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5909 smb_SetSMBDataLength(outp, 0);
5910 smb_SendPacket(vcp, outp);
5911 smb_FreePacket(outp);
5913 else { /* asynchronous */
5914 lock_ObtainMutex(&fidp->mx);
5915 fidp->raw_writers--;
5916 if (fidp->raw_writers == 0)
5917 thrd_SetEvent(fidp->raw_write_event);
5918 lock_ReleaseMutex(&fidp->mx);
5921 /* Give back raw buffer */
5922 lock_ObtainMutex(&smb_RawBufLock);
5924 *((char **)rawBuf) = smb_RawBufs;
5926 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5928 smb_RawBufs = rawBuf;
5929 lock_ReleaseMutex(&smb_RawBufLock);
5931 smb_ReleaseFID(fidp);
5932 cm_ReleaseUser(userp);
5935 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5940 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5943 long count, written = 0, total_written = 0;
5950 unsigned short writeMode;
5957 fd = smb_GetSMBParm(inp, 0);
5958 totalCount = smb_GetSMBParm(inp, 1);
5959 count = smb_GetSMBParm(inp, 10);
5960 offset.HighPart = 0; /* too bad */
5961 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5962 writeMode = smb_GetSMBParm(inp, 7);
5964 op = (char *) inp->data;
5965 op += smb_GetSMBParm(inp, 11);
5968 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5969 fd, offset.LowPart, count, writeMode);
5971 fd = smb_ChainFID(fd, inp);
5972 fidp = smb_FindFID(vcp, fd, 0);
5974 return CM_ERROR_BADFD;
5977 userp = smb_GetUser(vcp, inp);
5980 * Work around bug in NT client
5982 * When copying a file, the NT client should first copy the data,
5983 * then copy the last write time. But sometimes the NT client does
5984 * these in the wrong order, so the data copies would inadvertently
5985 * cause the last write time to be overwritten. We try to detect this,
5986 * and don't set client mod time if we think that would go against the
5989 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5990 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5991 fidp->scp->clientModTime = time(NULL);
5995 while ( code == 0 && count > 0 ) {
5997 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5999 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6001 if (code == 0 && written == 0)
6002 code = CM_ERROR_PARTIALWRITE;
6004 offset.LowPart += written;
6006 total_written += written;
6010 /* Get a raw buffer */
6013 lock_ObtainMutex(&smb_RawBufLock);
6015 /* Get a raw buf, from head of list */
6016 rawBuf = smb_RawBufs;
6018 smb_RawBufs = *(char **)smb_RawBufs;
6020 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6024 code = CM_ERROR_USESTD;
6026 lock_ReleaseMutex(&smb_RawBufLock);
6029 /* Don't allow a premature Close */
6030 if (code == 0 && (writeMode & 1) == 0) {
6031 lock_ObtainMutex(&fidp->mx);
6032 fidp->raw_writers++;
6033 thrd_ResetEvent(fidp->raw_write_event);
6034 lock_ReleaseMutex(&fidp->mx);
6037 smb_ReleaseFID(fidp);
6038 cm_ReleaseUser(userp);
6041 smb_SetSMBParm(outp, 0, total_written);
6042 smb_SetSMBDataLength(outp, 0);
6043 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6050 rwcp->offset.HighPart = 0;
6051 rwcp->offset.LowPart = offset.LowPart + count;
6052 rwcp->count = totalCount - count;
6053 rwcp->writeMode = writeMode;
6054 rwcp->alreadyWritten = total_written;
6056 /* set the packet data length to 3 bytes for the data block header,
6057 * plus the size of the data.
6059 smb_SetSMBParm(outp, 0, 0xffff);
6060 smb_SetSMBDataLength(outp, 0);
6065 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6068 long count, finalCount;
6075 fd = smb_GetSMBParm(inp, 0);
6076 count = smb_GetSMBParm(inp, 1);
6077 offset.HighPart = 0; /* too bad */
6078 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6080 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6081 fd, offset.LowPart, count);
6083 fd = smb_ChainFID(fd, inp);
6084 fidp = smb_FindFID(vcp, fd, 0);
6086 return CM_ERROR_BADFD;
6089 if (fidp->flags & SMB_FID_IOCTL) {
6090 return smb_IoctlRead(fidp, vcp, inp, outp);
6093 userp = smb_GetUser(vcp, inp);
6095 /* remember this for final results */
6096 smb_SetSMBParm(outp, 0, count);
6097 smb_SetSMBParm(outp, 1, 0);
6098 smb_SetSMBParm(outp, 2, 0);
6099 smb_SetSMBParm(outp, 3, 0);
6100 smb_SetSMBParm(outp, 4, 0);
6102 /* set the packet data length to 3 bytes for the data block header,
6103 * plus the size of the data.
6105 smb_SetSMBDataLength(outp, count+3);
6107 /* get op ptr after putting in the parms, since otherwise we don't
6108 * know where the data really is.
6110 op = smb_GetSMBData(outp, NULL);
6112 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6113 *op++ = 1; /* data block marker */
6114 *op++ = (unsigned char) (count & 0xff);
6115 *op++ = (unsigned char) ((count >> 8) & 0xff);
6118 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6120 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6123 /* fix some things up */
6124 smb_SetSMBParm(outp, 0, finalCount);
6125 smb_SetSMBDataLength(outp, finalCount+3);
6127 smb_ReleaseFID(fidp);
6129 cm_ReleaseUser(userp);
6133 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6140 cm_scache_t *dscp; /* dir we're dealing with */
6141 cm_scache_t *scp; /* file we're creating */
6143 int initialModeBits;
6153 /* compute initial mode bits based on read-only flag in attributes */
6154 initialModeBits = 0777;
6156 tp = smb_GetSMBData(inp, NULL);
6157 pathp = smb_ParseASCIIBlock(tp, &tp);
6158 if (smb_StoreAnsiFilenames)
6159 OemToChar(pathp,pathp);
6161 if (strcmp(pathp, "\\") == 0)
6162 return CM_ERROR_EXISTS;
6164 spacep = inp->spacep;
6165 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6167 userp = smb_GetUser(vcp, inp);
6169 caseFold = CM_FLAG_CASEFOLD;
6171 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6173 cm_ReleaseUser(userp);
6174 return CM_ERROR_NOSUCHPATH;
6177 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6178 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6179 userp, tidPathp, &req, &dscp);
6182 cm_ReleaseUser(userp);
6187 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6188 cm_ReleaseSCache(dscp);
6189 cm_ReleaseUser(userp);
6190 if ( WANTS_DFS_PATHNAMES(inp) )
6191 return CM_ERROR_PATH_NOT_COVERED;
6193 return CM_ERROR_BADSHARENAME;
6195 #endif /* DFS_SUPPORT */
6197 /* otherwise, scp points to the parent directory. Do a lookup, and
6198 * fail if we find it. Otherwise, we do the create.
6204 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6205 if (scp) cm_ReleaseSCache(scp);
6206 if (code != CM_ERROR_NOSUCHFILE) {
6207 if (code == 0) code = CM_ERROR_EXISTS;
6208 cm_ReleaseSCache(dscp);
6209 cm_ReleaseUser(userp);
6213 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6214 setAttr.clientModTime = time(NULL);
6215 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6216 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6217 smb_NotifyChange(FILE_ACTION_ADDED,
6218 FILE_NOTIFY_CHANGE_DIR_NAME,
6219 dscp, lastNamep, NULL, TRUE);
6221 /* we don't need this any longer */
6222 cm_ReleaseSCache(dscp);
6225 /* something went wrong creating or truncating the file */
6226 cm_ReleaseUser(userp);
6230 /* otherwise we succeeded */
6231 smb_SetSMBDataLength(outp, 0);
6232 cm_ReleaseUser(userp);
6237 BOOL smb_IsLegalFilename(char *filename)
6240 * Find the longest substring of filename that does not contain
6241 * any of the chars in illegalChars. If that substring is less
6242 * than the length of the whole string, then one or more of the
6243 * illegal chars is in filename.
6245 if (strcspn(filename, illegalChars) < strlen(filename))
6251 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6259 cm_scache_t *dscp; /* dir we're dealing with */
6260 cm_scache_t *scp; /* file we're creating */
6262 int initialModeBits;
6274 excl = (inp->inCom == 0x03)? 0 : 1;
6276 attributes = smb_GetSMBParm(inp, 0);
6277 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6279 /* compute initial mode bits based on read-only flag in attributes */
6280 initialModeBits = 0666;
6281 if (attributes & 1) initialModeBits &= ~0222;
6283 tp = smb_GetSMBData(inp, NULL);
6284 pathp = smb_ParseASCIIBlock(tp, &tp);
6285 if (smb_StoreAnsiFilenames)
6286 OemToChar(pathp,pathp);
6288 spacep = inp->spacep;
6289 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6291 userp = smb_GetUser(vcp, inp);
6293 caseFold = CM_FLAG_CASEFOLD;
6295 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6297 cm_ReleaseUser(userp);
6298 return CM_ERROR_NOSUCHPATH;
6300 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6301 userp, tidPathp, &req, &dscp);
6304 cm_ReleaseUser(userp);
6309 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6310 cm_ReleaseSCache(dscp);
6311 cm_ReleaseUser(userp);
6312 if ( WANTS_DFS_PATHNAMES(inp) )
6313 return CM_ERROR_PATH_NOT_COVERED;
6315 return CM_ERROR_BADSHARENAME;
6317 #endif /* DFS_SUPPORT */
6319 /* otherwise, scp points to the parent directory. Do a lookup, and
6320 * truncate the file if we find it, otherwise we create the file.
6327 if (!smb_IsLegalFilename(lastNamep))
6328 return CM_ERROR_BADNTFILENAME;
6330 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6331 #ifdef DEBUG_VERBOSE
6334 hexp = osi_HexifyString( lastNamep );
6335 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6340 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6341 if (code && code != CM_ERROR_NOSUCHFILE) {
6342 cm_ReleaseSCache(dscp);
6343 cm_ReleaseUser(userp);
6347 /* if we get here, if code is 0, the file exists and is represented by
6348 * scp. Otherwise, we have to create it.
6352 /* oops, file shouldn't be there */
6353 cm_ReleaseSCache(dscp);
6354 cm_ReleaseSCache(scp);
6355 cm_ReleaseUser(userp);
6356 return CM_ERROR_EXISTS;
6359 setAttr.mask = CM_ATTRMASK_LENGTH;
6360 setAttr.length.LowPart = 0;
6361 setAttr.length.HighPart = 0;
6362 code = cm_SetAttr(scp, &setAttr, userp, &req);
6365 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6366 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6367 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6369 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6370 smb_NotifyChange(FILE_ACTION_ADDED,
6371 FILE_NOTIFY_CHANGE_FILE_NAME,
6372 dscp, lastNamep, NULL, TRUE);
6373 if (!excl && code == CM_ERROR_EXISTS) {
6374 /* not an exclusive create, and someone else tried
6375 * creating it already, then we open it anyway. We
6376 * don't bother retrying after this, since if this next
6377 * fails, that means that the file was deleted after
6378 * we started this call.
6380 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6383 setAttr.mask = CM_ATTRMASK_LENGTH;
6384 setAttr.length.LowPart = 0;
6385 setAttr.length.HighPart = 0;
6386 code = cm_SetAttr(scp, &setAttr, userp, &req);
6391 /* we don't need this any longer */
6392 cm_ReleaseSCache(dscp);
6395 /* something went wrong creating or truncating the file */
6396 if (scp) cm_ReleaseSCache(scp);
6397 cm_ReleaseUser(userp);
6401 /* make sure we only open files */
6402 if (scp->fileType != CM_SCACHETYPE_FILE) {
6403 cm_ReleaseSCache(scp);
6404 cm_ReleaseUser(userp);
6405 return CM_ERROR_ISDIR;
6408 /* now all we have to do is open the file itself */
6409 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6412 /* save a pointer to the vnode */
6415 /* always create it open for read/write */
6416 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6418 smb_ReleaseFID(fidp);
6420 smb_SetSMBParm(outp, 0, fidp->fid);
6421 smb_SetSMBDataLength(outp, 0);
6423 cm_Open(scp, 0, userp);
6425 cm_ReleaseUser(userp);
6426 /* leave scp held since we put it in fidp->scp */
6430 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6443 fd = smb_GetSMBParm(inp, 0);
6444 whence = smb_GetSMBParm(inp, 1);
6445 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6447 /* try to find the file descriptor */
6448 fd = smb_ChainFID(fd, inp);
6449 fidp = smb_FindFID(vcp, fd, 0);
6450 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6451 return CM_ERROR_BADFD;
6454 userp = smb_GetUser(vcp, inp);
6456 lock_ObtainMutex(&fidp->mx);
6458 lock_ObtainMutex(&scp->mx);
6459 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6460 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6463 /* offset from current offset */
6464 offset += fidp->offset;
6466 else if (whence == 2) {
6467 /* offset from current EOF */
6468 offset += scp->length.LowPart;
6470 fidp->offset = offset;
6471 smb_SetSMBParm(outp, 0, offset & 0xffff);
6472 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6473 smb_SetSMBDataLength(outp, 0);
6475 lock_ReleaseMutex(&scp->mx);
6476 lock_ReleaseMutex(&fidp->mx);
6477 smb_ReleaseFID(fidp);
6478 cm_ReleaseUser(userp);
6482 /* dispatch all of the requests received in a packet. Due to chaining, this may
6483 * be more than one request.
6485 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6486 NCB *ncbp, raw_write_cont_t *rwcp)
6490 unsigned long code = 0;
6491 unsigned char *outWctp;
6492 int nparms; /* # of bytes of parameters */
6494 int nbytes; /* bytes of data, excluding count */
6497 unsigned short errCode;
6498 unsigned long NTStatus;
6500 unsigned char errClass;
6501 unsigned int oldGen;
6502 DWORD oldTime, newTime;
6504 /* get easy pointer to the data */
6505 smbp = (smb_t *) inp->data;
6507 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6508 /* setup the basic parms for the initial request in the packet */
6509 inp->inCom = smbp->com;
6510 inp->wctp = &smbp->wct;
6512 inp->ncb_length = ncbp->ncb_length;
6517 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6518 /* log it and discard it */
6523 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6524 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6526 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6527 1, ncbp->ncb_length, ptbuf, inp);
6528 DeregisterEventSource(h);
6530 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6535 /* We are an ongoing op */
6536 thrd_Increment(&ongoingOps);
6538 /* set up response packet for receiving output */
6539 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6540 smb_FormatResponsePacket(vcp, inp, outp);
6541 outWctp = outp->wctp;
6543 /* Remember session generation number and time */
6544 oldGen = sessionGen;
6545 oldTime = GetCurrentTime();
6547 while (inp->inCom != 0xff) {
6548 dp = &smb_dispatchTable[inp->inCom];
6550 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6551 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6552 code = outp->resumeCode;
6556 /* process each request in the packet; inCom, wctp and inCount
6557 * are already set up.
6559 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6562 /* now do the dispatch */
6563 /* start by formatting the response record a little, as a default */
6564 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6566 outWctp[1] = 0xff; /* no operation */
6567 outWctp[2] = 0; /* padding */
6572 /* not a chained request, this is a more reasonable default */
6573 outWctp[0] = 0; /* wct of zero */
6574 outWctp[1] = 0; /* and bcc (word) of zero */
6578 /* once set, stays set. Doesn't matter, since we never chain
6579 * "no response" calls.
6581 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6585 /* we have a recognized operation */
6587 if (inp->inCom == 0x1d)
6589 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6592 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%x lana %d lsn %d",(int)vcp,vcp->lana,vcp->lsn);
6593 osi_Log4(smb_logp,"Dispatch %s vcp 0x%x lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6594 code = (*(dp->procp)) (vcp, inp, outp);
6595 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",(code==0)?0:code-CM_ERROR_BASE);
6596 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);
6598 if ( code == CM_ERROR_BADSMB ||
6599 code == CM_ERROR_BADOP )
6601 #endif /* LOG_PACKET */
6604 if (oldGen != sessionGen) {
6609 newTime = GetCurrentTime();
6610 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6611 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6612 newTime - oldTime, ncbp->ncb_length);
6614 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6615 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6616 DeregisterEventSource(h);
6618 osi_Log1(smb_logp, "Pkt straddled session startup, "
6619 "ncb length %d", ncbp->ncb_length);
6623 /* bad opcode, fail the request, after displaying it */
6624 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6627 #endif /* LOG_PACKET */
6631 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6632 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6633 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6634 if (code == IDCANCEL)
6638 code = CM_ERROR_BADOP;
6641 /* catastrophic failure: log as much as possible */
6642 if (code == CM_ERROR_BADSMB) {
6649 "Invalid SMB, ncb_length %d",
6652 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6653 sprintf(s, "Invalid SMB message, length %d",
6656 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6657 1, ncbp->ncb_length, ptbuf, smbp);
6658 DeregisterEventSource(h);
6661 #endif /* LOG_PACKET */
6663 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6666 code = CM_ERROR_INVAL;
6669 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6670 thrd_Decrement(&ongoingOps);
6675 /* now, if we failed, turn the current response into an empty
6676 * one, and fill in the response packet's error code.
6679 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6680 smb_MapNTError(code, &NTStatus);
6681 outWctp = outp->wctp;
6682 smbp = (smb_t *) &outp->data;
6683 if (code != CM_ERROR_PARTIALWRITE
6684 && code != CM_ERROR_BUFFERTOOSMALL
6685 && code != CM_ERROR_GSSCONTINUE) {
6686 /* nuke wct and bcc. For a partial
6687 * write or an in-process authentication handshake,
6688 * assume they're OK.
6694 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6695 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6696 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6697 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6698 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6702 smb_MapCoreError(code, vcp, &errCode, &errClass);
6703 outWctp = outp->wctp;
6704 smbp = (smb_t *) &outp->data;
6705 if (code != CM_ERROR_PARTIALWRITE) {
6706 /* nuke wct and bcc. For a partial
6707 * write, assume they're OK.
6713 smbp->errLow = (unsigned char) (errCode & 0xff);
6714 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6715 smbp->rcls = errClass;
6718 } /* error occurred */
6720 /* if we're here, we've finished one request. Look to see if
6721 * this is a chained opcode. If it is, setup things to process
6722 * the chained request, and setup the output buffer to hold the
6723 * chained response. Start by finding the next input record.
6725 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6726 break; /* not a chained req */
6727 tp = inp->wctp; /* points to start of last request */
6728 /* in a chained request, the first two
6729 * parm fields are required, and are
6730 * AndXCommand/AndXReserved and
6732 if (tp[0] < 2) break;
6733 if (tp[1] == 0xff) break; /* no more chained opcodes */
6735 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6738 /* and now append the next output request to the end of this
6739 * last request. Begin by finding out where the last response
6740 * ends, since that's where we'll put our new response.
6742 outWctp = outp->wctp; /* ptr to out parameters */
6743 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6744 nparms = outWctp[0] << 1;
6745 tp = outWctp + nparms + 1; /* now points to bcc field */
6746 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6747 tp += 2 /* for the count itself */ + nbytes;
6748 /* tp now points to the new output record; go back and patch the
6749 * second parameter (off2) to point to the new record.
6751 temp = (unsigned int)tp - ((unsigned int) outp->data);
6752 outWctp[3] = (unsigned char) (temp & 0xff);
6753 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6754 outWctp[2] = 0; /* padding */
6755 outWctp[1] = inp->inCom; /* next opcode */
6757 /* finally, setup for the next iteration */
6760 } /* while loop over all requests in the packet */
6762 /* done logging out, turn off logging-out flag */
6763 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6764 vcp->justLoggedOut = NULL;
6767 free(loggedOutName);
6768 loggedOutName = NULL;
6769 smb_ReleaseUID(loggedOutUserp);
6770 loggedOutUserp = NULL;
6774 /* now send the output packet, and return */
6776 smb_SendPacket(vcp, outp);
6777 thrd_Decrement(&ongoingOps);
6779 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6780 if (active_vcp != vcp) {
6782 smb_ReleaseVC(active_vcp);
6784 "Replacing active_vcp %x with %x", active_vcp, vcp);
6789 last_msg_time = GetCurrentTime();
6790 } else if (active_vcp == vcp) {
6791 smb_ReleaseVC(active_vcp);
6799 /* Wait for Netbios() calls to return, and make the results available to server
6800 * threads. Note that server threads can't wait on the NCBevents array
6801 * themselves, because NCB events are manual-reset, and the servers would race
6802 * each other to reset them.
6804 void smb_ClientWaiter(void *parmp)
6809 while (smbShutdownFlag == 0) {
6810 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6812 if (code == WAIT_OBJECT_0)
6815 /* error checking */
6816 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6818 int abandonIdx = code - WAIT_ABANDONED_0;
6819 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6822 if (code == WAIT_IO_COMPLETION)
6824 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6828 if (code == WAIT_TIMEOUT)
6830 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6833 if (code == WAIT_FAILED)
6835 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6838 idx = code - WAIT_OBJECT_0;
6840 /* check idx range! */
6841 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6843 /* this is fatal - log as much as possible */
6844 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6848 thrd_ResetEvent(NCBevents[idx]);
6849 thrd_SetEvent(NCBreturns[0][idx]);
6855 * Try to have one NCBRECV request waiting for every live session. Not more
6856 * than one, because if there is more than one, it's hard to handle Write Raw.
6858 void smb_ServerWaiter(void *parmp)
6861 int idx_session, idx_NCB;
6867 while (smbShutdownFlag == 0) {
6869 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6871 if (code == WAIT_OBJECT_0)
6874 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6876 int abandonIdx = code - WAIT_ABANDONED_0;
6877 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6880 if (code == WAIT_IO_COMPLETION)
6882 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6886 if (code == WAIT_TIMEOUT)
6888 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6891 if (code == WAIT_FAILED)
6893 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6896 idx_session = code - WAIT_OBJECT_0;
6898 /* check idx range! */
6899 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6901 /* this is fatal - log as much as possible */
6902 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6908 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6910 if (code == WAIT_OBJECT_0) {
6911 if (smbShutdownFlag == 1)
6917 /* error checking */
6918 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6920 int abandonIdx = code - WAIT_ABANDONED_0;
6921 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6924 if (code == WAIT_IO_COMPLETION)
6926 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6930 if (code == WAIT_TIMEOUT)
6932 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6935 if (code == WAIT_FAILED)
6937 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6940 idx_NCB = code - WAIT_OBJECT_0;
6942 /* check idx range! */
6943 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6945 /* this is fatal - log as much as possible */
6946 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6950 /* Link them together */
6951 NCBsessions[idx_NCB] = idx_session;
6954 ncbp = NCBs[idx_NCB];
6955 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6956 ncbp->ncb_command = NCBRECV | ASYNCH;
6957 ncbp->ncb_lana_num = lanas[idx_session];
6959 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6960 ncbp->ncb_event = NCBevents[idx_NCB];
6961 ncbp->ncb_length = SMB_PACKETSIZE;
6964 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6965 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6966 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6967 ncbp->ncb_length = SMB_PACKETSIZE;
6968 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6969 Netbios(ncbp, dos_ncb);
6975 * The top level loop for handling SMB request messages. Each server thread
6976 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6977 * NCB and buffer for the incoming request are loaned to us.
6979 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6980 * to immediately send a request for the rest of the data. This must come
6981 * before any other traffic for that session, so we delay setting the session
6982 * event until that data has come in.
6984 void smb_Server(VOID *parmp)
6986 int myIdx = (int) parmp;
6990 smb_packet_t *outbufp;
6992 int idx_NCB, idx_session;
6994 smb_vc_t *vcp = NULL;
7000 rx_StartClientThread();
7003 outbufp = GetPacket();
7004 outbufp->ncbp = outncbp;
7007 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7010 /* terminate silently if shutdown flag is set */
7011 if (code == WAIT_OBJECT_0) {
7012 if (smbShutdownFlag == 1) {
7013 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7019 /* error checking */
7020 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7022 int abandonIdx = code - WAIT_ABANDONED_0;
7023 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7026 if (code == WAIT_IO_COMPLETION)
7028 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7032 if (code == WAIT_TIMEOUT)
7034 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7037 if (code == WAIT_FAILED)
7039 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7042 idx_NCB = code - WAIT_OBJECT_0;
7044 /* check idx range! */
7045 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7047 /* this is fatal - log as much as possible */
7048 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7052 ncbp = NCBs[idx_NCB];
7054 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7056 idx_session = NCBsessions[idx_NCB];
7057 rc = ncbp->ncb_retcode;
7059 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7062 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7065 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7068 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7071 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7074 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7077 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7080 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7083 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7086 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7089 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7092 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7095 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7098 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7101 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7104 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7107 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7110 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7113 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7116 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7119 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7122 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7125 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7128 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7131 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7134 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7137 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7140 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7143 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7146 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7149 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7152 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7155 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7158 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7161 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7164 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7167 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7170 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7173 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7183 /* Can this happen? Or is it just my UNIX paranoia? */
7184 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7189 /* Client closed session */
7190 dead_sessions[idx_session] = TRUE;
7193 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7194 /* Should also release vcp. [done] 2004-05-11 jaltman
7196 * sanity check that all TID's are gone.
7198 * TODO: check if we could use LSNs[idx_session] instead,
7199 * also cleanup after dead vcp
7202 if (dead_vcp == vcp)
7203 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7204 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7205 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7209 smb_ReleaseVC(dead_vcp);
7211 "Previous dead_vcp %x", dead_vcp);
7214 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7216 if (vcp->justLoggedOut) {
7218 loggedOutTime = vcp->logoffTime;
7219 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7220 loggedOutUserp = vcp->justLoggedOut;
7221 lock_ObtainWrite(&smb_rctLock);
7222 loggedOutUserp->refCount++;
7223 lock_ReleaseWrite(&smb_rctLock);
7229 /* Treat as transient error */
7236 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7237 sprintf(s, "SMB message incomplete, length %d",
7240 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7242 ncbp->ncb_length, ptbuf,
7244 DeregisterEventSource(h);
7247 "dispatch smb recv failed, message incomplete, ncb_length %d",
7250 "SMB message incomplete, "
7251 "length %d", ncbp->ncb_length);
7254 * We used to discard the packet.
7255 * Instead, try handling it normally.
7263 /* A weird error code. Log it, sleep, and
7265 if (vcp && vcp->errorCount++ > 3) {
7266 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7267 dead_sessions[idx_session] = TRUE;
7271 thrd_SetEvent(SessionEvents[idx_session]);
7276 /* Success, so now dispatch on all the data in the packet */
7278 smb_concurrentCalls++;
7279 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7280 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7284 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7286 * If at this point vcp is NULL (implies that packet was invalid)
7287 * then we are in big trouble. This means either :
7288 * a) we have the wrong NCB.
7289 * b) Netbios screwed up the call.
7290 * Obviously this implies that
7291 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7292 * lanas[idx_session] != ncbp->ncb_lana_num )
7293 * Either way, we can't do anything with this packet.
7294 * Log, sleep and resume.
7303 "LSNs[idx_session]=[%d],"
7304 "lanas[idx_session]=[%d],"
7305 "ncbp->ncb_lsn=[%d],"
7306 "ncbp->ncb_lana_num=[%d]",
7310 ncbp->ncb_lana_num);
7314 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7316 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7317 DeregisterEventSource(h);
7320 /* Also log in the trace log. */
7321 osi_Log4(smb_logp, "Server: BAD VCP!"
7322 "LSNs[idx_session]=[%d],"
7323 "lanas[idx_session]=[%d],"
7324 "ncbp->ncb_lsn=[%d],"
7325 "ncbp->ncb_lana_num=[%d]",
7329 ncbp->ncb_lana_num);
7331 /* thrd_Sleep(1000); Don't bother sleeping */
7332 thrd_SetEvent(SessionEvents[idx_session]);
7333 smb_concurrentCalls--;
7338 vcp->errorCount = 0;
7339 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7341 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7342 /* copy whole packet to virtual memory */
7343 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7345 bufp->dos_pkt / 16, bufp);*/
7347 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7349 smbp = (smb_t *)bufp->data;
7352 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7356 if (smbp->com == 0x1d) {
7357 /* Special handling for Write Raw */
7358 raw_write_cont_t rwc;
7359 EVENT_HANDLE rwevent;
7360 char eventName[MAX_PATH];
7362 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7363 if (rwc.code == 0) {
7364 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7365 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7366 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7367 ncbp->ncb_command = NCBRECV | ASYNCH;
7368 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7369 ncbp->ncb_lana_num = vcp->lana;
7370 ncbp->ncb_buffer = rwc.buf;
7371 ncbp->ncb_length = 65535;
7372 ncbp->ncb_event = rwevent;
7376 Netbios(ncbp, dos_ncb);
7378 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7379 thrd_CloseHandle(rwevent);
7381 thrd_SetEvent(SessionEvents[idx_session]);
7383 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7385 else if (smbp->com == 0xa0) {
7387 * Serialize the handling for NT Transact
7390 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7391 thrd_SetEvent(SessionEvents[idx_session]);
7393 thrd_SetEvent(SessionEvents[idx_session]);
7394 /* TODO: what else needs to be serialized? */
7395 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7397 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7399 __except( smb_ServerExceptionFilter() ) {
7403 smb_concurrentCalls--;
7406 thrd_SetEvent(NCBavails[idx_NCB]);
7413 * Exception filter for the server threads. If an exception occurs in the
7414 * dispatch routines, which is where exceptions are most common, then do a
7415 * force trace and give control to upstream exception handlers. Useful for
7418 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7419 DWORD smb_ServerExceptionFilter(void) {
7420 /* While this is not the best time to do a trace, if it succeeds, then
7421 * we have a trace (assuming tracing was enabled). Otherwise, this should
7422 * throw a second exception.
7427 ptbuf[0] = "Unhandled exception forcing trace";
7429 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7431 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7432 DeregisterEventSource(h);
7435 afsd_ForceTrace(TRUE);
7436 buf_ForceTrace(TRUE);
7437 return EXCEPTION_CONTINUE_SEARCH;
7442 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7443 * If the number of server threads is M, and the number of live sessions is
7444 * N, then the number of NCB's in use at any time either waiting for, or
7445 * holding, received messages is M + N, so that is how many NCB's get created.
7447 void InitNCBslot(int idx)
7449 struct smb_packet *bufp;
7450 EVENT_HANDLE retHandle;
7452 char eventName[MAX_PATH];
7454 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7456 NCBs[idx] = GetNCB();
7457 sprintf(eventName,"NCBavails[%d]", idx);
7458 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7459 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7460 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7462 sprintf(eventName,"NCBevents[%d]", idx);
7463 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7464 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7465 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7467 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7468 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7469 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7470 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7471 for (i=0; i<smb_NumServerThreads; i++)
7472 NCBreturns[i][idx] = retHandle;
7474 bufp->spacep = cm_GetSpace();
7478 /* listen for new connections */
7479 void smb_Listener(void *parmp)
7487 char rname[NCBNAMSZ+1];
7488 char cname[MAX_COMPUTERNAME_LENGTH+1];
7489 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7494 int lana = (int) parmp;
7498 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7501 /* retrieve computer name */
7502 GetComputerName(cname, &cnamelen);
7506 memset(ncbp, 0, sizeof(NCB));
7509 ncbp->ncb_command = NCBLISTEN;
7510 ncbp->ncb_rto = 0; /* No receive timeout */
7511 ncbp->ncb_sto = 0; /* No send timeout */
7513 /* pad out with spaces instead of null termination */
7514 len = strlen(smb_localNamep);
7515 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7516 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7518 strcpy(ncbp->ncb_callname, "*");
7519 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7521 ncbp->ncb_lana_num = lana;
7524 code = Netbios(ncbp);
7526 code = Netbios(ncbp, dos_ncb);
7535 /* terminate silently if shutdown flag is set */
7536 if (smbShutdownFlag == 1) {
7545 "NCBLISTEN lana=%d failed with code %d",
7546 ncbp->ncb_lana_num, code);
7548 "Client exiting due to network failure. Please restart client.\n");
7552 "Client exiting due to network failure. Please restart client.\n"
7553 "NCBLISTEN lana=%d failed with code %d",
7554 ncbp->ncb_lana_num, code);
7556 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7557 MB_OK|MB_SERVICE_NOTIFICATION);
7558 osi_assert(tbuffer);
7561 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7562 ncbp->ncb_lana_num, code);
7563 fprintf(stderr, "\nClient exiting due to network failure "
7564 "(possibly due to power-saving mode)\n");
7565 fprintf(stderr, "Please restart client.\n");
7566 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7570 /* check for remote conns */
7571 /* first get remote name and insert null terminator */
7572 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7573 for (i=NCBNAMSZ; i>0; i--) {
7574 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7580 /* compare with local name */
7582 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7583 flags |= SMB_VCFLAG_REMOTECONN;
7585 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7587 lock_ObtainMutex(&smb_ListenerLock);
7589 /* New generation */
7592 /* Log session startup */
7594 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7596 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7597 #endif /* NOTSERVICE */
7598 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7599 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7601 if (reportSessionStartups) {
7607 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7608 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7610 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7612 DeregisterEventSource(h);
7615 fprintf(stderr, "%s: New session %d starting from host %s\n",
7616 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7620 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7621 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7624 /* now ncbp->ncb_lsn is the connection ID */
7625 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7626 vcp->flags |= flags;
7627 strcpy(vcp->rname, rname);
7629 /* Allocate slot in session arrays */
7630 /* Re-use dead session if possible, otherwise add one more */
7631 /* But don't look at session[0], it is reserved */
7632 for (i = 1; i < numSessions; i++) {
7633 if (dead_sessions[i]) {
7634 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7635 dead_sessions[i] = FALSE;
7640 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7641 unsigned long code = CM_ERROR_ALLBUSY;
7642 smb_packet_t * outp = GetPacket();
7643 unsigned char *outWctp;
7648 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7649 unsigned long NTStatus;
7650 smb_MapNTError(code, &NTStatus);
7651 outWctp = outp->wctp;
7652 smbp = (smb_t *) &outp->data;
7656 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7657 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7658 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7659 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7660 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7662 unsigned short errCode;
7663 unsigned char errClass;
7664 smb_MapCoreError(code, vcp, &errCode, &errClass);
7665 outWctp = outp->wctp;
7666 smbp = (smb_t *) &outp->data;
7670 smbp->errLow = (unsigned char) (errCode & 0xff);
7671 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7672 smbp->rcls = errClass;
7674 smb_SendPacket(vcp, outp);
7675 smb_FreePacket(outp);
7677 /* assert that we do not exceed the maximum number of sessions or NCBs.
7678 * we should probably want to wait for a session to be freed in case
7681 osi_assert(i < Sessionmax - 1);
7682 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7684 LSNs[i] = ncbp->ncb_lsn;
7685 lanas[i] = ncbp->ncb_lana_num;
7687 if (i == numSessions) {
7688 /* Add new NCB for new session */
7689 char eventName[MAX_PATH];
7691 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7693 InitNCBslot(numNCBs);
7695 thrd_SetEvent(NCBavails[0]);
7696 thrd_SetEvent(NCBevents[0]);
7697 for (j = 0; j < smb_NumServerThreads; j++)
7698 thrd_SetEvent(NCBreturns[j][0]);
7699 /* Also add new session event */
7700 sprintf(eventName, "SessionEvents[%d]", i);
7701 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7702 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7703 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7705 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7706 thrd_SetEvent(SessionEvents[0]);
7708 thrd_SetEvent(SessionEvents[i]);
7715 lock_ReleaseMutex(&smb_ListenerLock);
7716 } /* dispatch while loop */
7719 /* initialize Netbios */
7720 void smb_NetbiosInit()
7726 int i, lana, code, l;
7728 int delname_tried=0;
7731 OSVERSIONINFO Version;
7733 /* Get the version of Windows */
7734 memset(&Version, 0x00, sizeof(Version));
7735 Version.dwOSVersionInfoSize = sizeof(Version);
7736 GetVersionEx(&Version);
7738 /* setup the NCB system */
7741 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7745 if (smb_LANadapter == -1) {
7746 ncbp->ncb_command = NCBENUM;
7747 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7748 ncbp->ncb_length = sizeof(lana_list);
7749 code = Netbios(ncbp);
7751 osi_Log1(smb_logp, "Netbios NCBENUM error code %d", code);
7752 osi_panic(s, __FILE__, __LINE__);
7756 lana_list.length = 1;
7757 lana_list.lana[0] = smb_LANadapter;
7760 for (i = 0; i < lana_list.length; i++) {
7761 /* reset the adaptor: in Win32, this is required for every process, and
7762 * acts as an init call, not as a real hardware reset.
7764 ncbp->ncb_command = NCBRESET;
7765 ncbp->ncb_callname[0] = 100;
7766 ncbp->ncb_callname[2] = 100;
7767 ncbp->ncb_lana_num = lana_list.lana[i];
7768 code = Netbios(ncbp);
7770 code = ncbp->ncb_retcode;
7772 osi_Log2(smb_logp, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7773 lana_list.lana[i] = 255; /* invalid lana */
7775 osi_Log1(smb_logp, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7779 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7780 we will just fake the LANA list */
7781 if (smb_LANadapter == -1) {
7782 for (i = 0; i < 8; i++)
7783 lana_list.lana[i] = i;
7784 lana_list.length = 8;
7787 lana_list.length = 1;
7788 lana_list.lana[0] = smb_LANadapter;
7792 /* and declare our name so we can receive connections */
7793 memset(ncbp, 0, sizeof(*ncbp));
7794 len=lstrlen(smb_localNamep);
7795 memset(smb_sharename,' ',NCBNAMSZ);
7796 memcpy(smb_sharename,smb_localNamep,len);
7797 osi_Log1(smb_logp, "lana_list.length %d", lana_list.length);
7799 /* Keep the name so we can unregister it later */
7800 for (l = 0; l < lana_list.length; l++) {
7801 lana = lana_list.lana[l];
7803 ncbp->ncb_command = NCBADDNAME;
7804 ncbp->ncb_lana_num = lana;
7805 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7807 code = Netbios(ncbp);
7809 code = Netbios(ncbp, dos_ncb);
7812 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7813 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7815 char name[NCBNAMSZ+1];
7817 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7818 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7821 if (code == 0) code = ncbp->ncb_retcode;
7823 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7825 /* we only use one LANA with djgpp */
7826 lana_list.lana[0] = lana;
7827 lana_list.length = 1;
7831 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7832 if (code == NRC_BRIDGE) { /* invalid LANA num */
7833 lana_list.lana[l] = 255;
7836 else if (code == NRC_DUPNAME) {
7837 osi_Log0(smb_logp, "Name already exists; try to delete it");
7838 memset(ncbp, 0, sizeof(*ncbp));
7839 ncbp->ncb_command = NCBDELNAME;
7840 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7841 ncbp->ncb_lana_num = lana;
7843 code = Netbios(ncbp);
7845 code = Netbios(ncbp, dos_ncb);
7848 code = ncbp->ncb_retcode;
7850 osi_Log2(smb_logp, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7852 if (code != 0 || delname_tried) {
7853 lana_list.lana[l] = 255;
7855 else if (code == 0) {
7856 if (!delname_tried) {
7864 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7865 lana_list.lana[l] = 255; /* invalid lana */
7866 osi_panic(s, __FILE__, __LINE__);
7870 lana_found = 1; /* at least one worked */
7877 osi_assert(lana_list.length >= 0);
7879 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
7882 /* we're done with the NCB now */
7886 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7903 EVENT_HANDLE retHandle;
7904 char eventName[MAX_PATH];
7907 smb_MBfunc = aMBfunc;
7911 smb_LANadapter = LANadapt;
7913 /* Initialize smb_localZero */
7914 myTime.tm_isdst = -1; /* compute whether on DST or not */
7915 myTime.tm_year = 70;
7921 smb_localZero = mktime(&myTime);
7923 #ifndef USE_NUMERIC_TIME_CONV
7924 /* Initialize kludge-GMT */
7925 smb_CalculateNowTZ();
7926 #endif /* USE_NUMERIC_TIME_CONV */
7927 #ifdef AFS_FREELANCE_CLIENT
7928 /* Make sure the root.afs volume has the correct time */
7929 cm_noteLocalMountPointChange();
7932 /* initialize the remote debugging log */
7935 /* remember the name */
7936 len = strlen(snamep);
7937 smb_localNamep = malloc(len+1);
7938 strcpy(smb_localNamep, snamep);
7939 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7941 /* and the global lock */
7942 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7943 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7945 /* Raw I/O data structures */
7946 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7948 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7950 /* 4 Raw I/O buffers */
7952 smb_RawBufs = calloc(65536,1);
7953 *((char **)smb_RawBufs) = NULL;
7954 for (i=0; i<3; i++) {
7955 char *rawBuf = calloc(65536,1);
7956 *((char **)rawBuf) = smb_RawBufs;
7957 smb_RawBufs = rawBuf;
7960 npar = 65536 >> 4; /* number of paragraphs */
7961 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7963 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7965 osi_panic("",__FILE__,__LINE__);
7968 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7971 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7973 _farpokel(_dos_ds, smb_RawBufs, NULL);
7974 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7975 npar = 65536 >> 4; /* number of paragraphs */
7976 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7978 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7980 osi_panic("",__FILE__,__LINE__);
7983 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7986 rawBuf = (seg * 16) + 0; /* DOS physical address */
7987 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7988 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7989 smb_RawBufs = rawBuf;
7993 /* global free lists */
7994 smb_ncbFreeListp = NULL;
7995 smb_packetFreeListp = NULL;
7999 /* Initialize listener and server structures */
8001 memset(dead_sessions, 0, sizeof(dead_sessions));
8002 sprintf(eventName, "SessionEvents[0]");
8003 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8004 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8005 afsi_log("Event Object Already Exists: %s", eventName);
8007 smb_NumServerThreads = nThreads;
8008 sprintf(eventName, "NCBavails[0]");
8009 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8010 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8011 afsi_log("Event Object Already Exists: %s", eventName);
8012 sprintf(eventName, "NCBevents[0]");
8013 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8014 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8015 afsi_log("Event Object Already Exists: %s", eventName);
8016 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8017 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8018 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8019 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8020 afsi_log("Event Object Already Exists: %s", eventName);
8021 for (i = 0; i < smb_NumServerThreads; i++) {
8022 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8023 NCBreturns[i][0] = retHandle;
8026 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8027 for (i = 0; i < smb_NumServerThreads; i++) {
8028 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8029 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8030 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8031 afsi_log("Event Object Already Exists: %s", eventName);
8034 numNCBs = smb_NumServerThreads + 1;
8036 /* Initialize dispatch table */
8037 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8038 /* Prepare the table for unknown operations */
8039 for(i=0; i<= SMB_NOPCODES; i++) {
8040 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8042 /* Fill in the ones we do know */
8043 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8044 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8045 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8046 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8047 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8048 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8049 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8050 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8051 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8052 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8053 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8054 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8055 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8056 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8057 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8058 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8059 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8060 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8061 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8062 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8063 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8064 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8065 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8066 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8067 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8068 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8069 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8070 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8071 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8072 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8073 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8074 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8075 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8076 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8077 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8078 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8079 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8080 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8081 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8082 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8083 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8084 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8085 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8086 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8087 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8088 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8089 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8090 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8091 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8092 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8093 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8094 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8095 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8096 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8097 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8098 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8099 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8100 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8101 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8102 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8103 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8104 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8105 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8106 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8107 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8108 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8109 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8110 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8111 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8112 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8113 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8114 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8116 /* setup tran 2 dispatch table */
8117 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8118 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8119 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8120 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8121 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8122 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8123 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8124 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8125 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8126 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8127 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8128 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8129 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8130 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8131 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8132 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8133 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8135 /* setup the rap dispatch table */
8136 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8137 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8138 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8139 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8140 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8144 /* if we are doing SMB authentication we have register outselves as a logon process */
8145 if (smb_authType != SMB_AUTH_NONE) {
8146 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8147 LSA_STRING afsProcessName;
8148 LSA_OPERATIONAL_MODE dummy; /*junk*/
8150 afsProcessName.Buffer = "OpenAFSClientDaemon";
8151 afsProcessName.Length = strlen(afsProcessName.Buffer);
8152 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8154 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8156 if (nts == STATUS_SUCCESS) {
8157 LSA_STRING packageName;
8158 /* we are registered. Find out the security package id */
8159 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8160 packageName.Length = strlen(packageName.Buffer);
8161 packageName.MaximumLength = packageName.Length + 1;
8162 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8163 if (nts == STATUS_SUCCESS) {
8165 * This code forces Windows to authenticate against the Logon Cache
8166 * first instead of attempting to authenticate against the Domain
8167 * Controller. When the Windows logon cache is enabled this improves
8168 * performance by removing the network access and works around a bug
8169 * seen at sites which are using a MIT Kerberos principal to login
8170 * to machines joined to a non-root domain in a multi-domain forest.
8172 PVOID pResponse = NULL;
8173 ULONG cbResponse = 0;
8174 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8176 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8177 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8178 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8179 OptionsRequest.DisableOptions = FALSE;
8181 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8184 sizeof(OptionsRequest),
8190 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8192 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8194 OutputDebugString(message);
8195 osi_Log2(smb_logp,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8198 OutputDebugString("MsV1_0SetProcessOption success");
8199 osi_Log0(smb_logp,"MsV1_0SetProcessOption success");
8201 /* END - code from Larry */
8203 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8204 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8205 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8207 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8209 /* something went wrong. We report the error and revert back to no authentication
8210 because we can't perform any auth requests without a successful lsa handle
8211 or sec package id. */
8212 afsi_log("Reverting to NO SMB AUTH");
8213 smb_authType = SMB_AUTH_NONE;
8216 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8218 /* something went wrong. We report the error and revert back to no authentication
8219 because we can't perform any auth requests without a successful lsa handle
8220 or sec package id. */
8221 afsi_log("Reverting to NO SMB AUTH");
8222 smb_authType = SMB_AUTH_NONE;
8226 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8227 * time prevents the failure of authentication when logged into Windows with an
8228 * external Kerberos principal mapped to a local account.
8230 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8231 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8232 * then the only option is NTLMSSP anyway; so just fallback.
8237 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8238 if (secBlobLength == 0) {
8239 smb_authType = SMB_AUTH_NTLM;
8240 afsi_log("Reverting to SMB AUTH NTLM");
8249 /* Now get ourselves a domain name. */
8250 /* For now we are using the local computer name as the domain name.
8251 * It is actually the domain for local logins, and we are acting as
8252 * a local SMB server.
8254 bufsize = sizeof(smb_ServerDomainName) - 1;
8255 GetComputerName(smb_ServerDomainName, &bufsize);
8256 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8257 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8260 /* Start listeners, waiters, servers, and daemons */
8262 for (i = 0; i < lana_list.length; i++) {
8263 if (lana_list.lana[i] == 255)
8265 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8266 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8267 osi_assert(phandle != NULL);
8268 thrd_CloseHandle(phandle);
8272 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8273 NULL, 0, &lpid, "smb_ClientWaiter");
8274 osi_assert(phandle != NULL);
8275 thrd_CloseHandle(phandle);
8278 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8279 NULL, 0, &lpid, "smb_ServerWaiter");
8280 osi_assert(phandle != NULL);
8281 thrd_CloseHandle(phandle);
8283 for (i=0; i<smb_NumServerThreads; i++) {
8284 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8285 (void *) i, 0, &lpid, "smb_Server");
8286 osi_assert(phandle != NULL);
8287 thrd_CloseHandle(phandle);
8290 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8291 NULL, 0, &lpid, "smb_Daemon");
8292 osi_assert(phandle != NULL);
8293 thrd_CloseHandle(phandle);
8295 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8296 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8297 osi_assert(phandle != NULL);
8298 thrd_CloseHandle(phandle);
8307 void smb_Shutdown(void)
8317 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8319 /* setup the NCB system */
8322 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8325 /* Block new sessions by setting shutdown flag */
8326 smbShutdownFlag = 1;
8328 /* Hang up all sessions */
8329 memset((char *)ncbp, 0, sizeof(NCB));
8330 for (i = 1; i < numSessions; i++)
8332 if (dead_sessions[i])
8335 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8336 ncbp->ncb_command = NCBHANGUP;
8337 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8338 ncbp->ncb_lsn = LSNs[i];
8340 code = Netbios(ncbp);
8342 code = Netbios(ncbp, dos_ncb);
8344 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8345 if (code == 0) code = ncbp->ncb_retcode;
8347 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8348 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8352 /* Trigger the shutdown of all SMB threads */
8353 for (i = 0; i < smb_NumServerThreads; i++)
8354 thrd_SetEvent(NCBreturns[i][0]);
8356 thrd_SetEvent(NCBevents[0]);
8357 thrd_SetEvent(SessionEvents[0]);
8358 thrd_SetEvent(NCBavails[0]);
8360 for (i = 0;i < smb_NumServerThreads; i++) {
8361 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8362 if (code == WAIT_OBJECT_0) {
8365 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8366 thrd_SetEvent(NCBreturns[i--][0]);
8370 /* Delete Netbios name */
8371 memset((char *)ncbp, 0, sizeof(NCB));
8372 for (i = 0; i < lana_list.length; i++) {
8373 if (lana_list.lana[i] == 255) continue;
8374 ncbp->ncb_command = NCBDELNAME;
8375 ncbp->ncb_lana_num = lana_list.lana[i];
8376 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8378 code = Netbios(ncbp);
8380 code = Netbios(ncbp, dos_ncb);
8383 code = ncbp->ncb_retcode;
8385 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8386 ncbp->ncb_lana_num, code);
8391 /* Release the reference counts held by the VCs */
8392 lock_ObtainWrite(&smb_rctLock);
8393 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8398 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8400 if (fidp->scp != NULL) {
8403 lock_ObtainMutex(&fidp->mx);
8404 if (fidp->scp != NULL) {
8407 cm_ReleaseSCache(scp);
8409 lock_ReleaseMutex(&fidp->mx);
8413 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8415 smb_ReleaseVCNoLock(tidp->vcp);
8417 cm_user_t *userp = tidp->userp;
8419 lock_ReleaseWrite(&smb_rctLock);
8420 cm_ReleaseUser(userp);
8421 lock_ObtainWrite(&smb_rctLock);
8425 lock_ReleaseWrite(&smb_rctLock);
8428 /* Get the UNC \\<servername>\<sharename> prefix. */
8429 char *smb_GetSharename()
8433 /* Make sure we have been properly initialized. */
8434 if (smb_localNamep == NULL)
8437 /* Allocate space for \\<servername>\<sharename>, plus the
8440 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8441 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8447 void smb_LogPacket(smb_packet_t *packet)
8450 unsigned length, paramlen, datalen, i, j;
8452 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8454 if (!packet) return;
8456 osi_Log0(smb_logp, "*** SMB packet dump ***");
8458 vp = (BYTE *) packet->data;
8460 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8461 length = paramlen + 2 + datalen;
8464 for (i=0;i < length; i+=16)
8466 memset( buf, ' ', 80 );
8471 buf[strlen(buf)] = ' ';
8473 cp = (BYTE*) buf + 7;
8475 for (j=0;j < 16 && (i+j)<length; j++)
8477 *(cp++) = hex[vp[i+j] >> 4];
8478 *(cp++) = hex[vp[i+j] & 0xf];
8488 for (j=0;j < 16 && (i+j)<length;j++)
8490 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8501 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8504 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8506 #endif /* LOG_PACKET */
8509 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8517 lock_ObtainRead(&smb_rctLock);
8519 sprintf(output, "begin dumping smb_vc_t\n");
8520 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8522 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8526 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8527 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8528 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8530 sprintf(output, "begin dumping smb_fid_t\n");
8531 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8533 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8535 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",
8536 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8537 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8538 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8539 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8542 sprintf(output, "done dumping smb_fid_t\n");
8543 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8546 sprintf(output, "done dumping smb_vc_t\n");
8547 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8550 lock_ReleaseRead(&smb_rctLock);