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 NTStatus = 0xC0982001L; /* SMB non-specific error */
2440 *NTStatusp = NTStatus;
2441 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2444 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2445 unsigned char *classp)
2447 unsigned char class;
2448 unsigned short error;
2450 /* map CM_ERROR_* errors to SMB errors */
2451 if (code == CM_ERROR_NOSUCHCELL) {
2453 error = 3; /* bad path */
2455 else if (code == CM_ERROR_NOSUCHVOLUME) {
2457 error = 3; /* bad path */
2459 else if (code == CM_ERROR_TIMEDOUT) {
2461 error = 81; /* server is paused */
2463 else if (code == CM_ERROR_RETRY) {
2464 class = 2; /* shouldn't happen */
2467 else if (code == CM_ERROR_NOACCESS) {
2469 error = 4; /* bad access */
2471 else if (code == CM_ERROR_READONLY) {
2473 error = 19; /* read only */
2475 else if (code == CM_ERROR_NOSUCHFILE) {
2477 error = 2; /* ENOENT! */
2479 else if (code == CM_ERROR_NOSUCHPATH) {
2481 error = 3; /* Bad path */
2483 else if (code == CM_ERROR_TOOBIG) {
2485 error = 11; /* bad format */
2487 else if (code == CM_ERROR_INVAL) {
2488 class = 2; /* server non-specific error code */
2491 else if (code == CM_ERROR_BADFD) {
2493 error = 6; /* invalid file handle */
2495 else if (code == CM_ERROR_BADFDOP) {
2496 class = 1; /* invalid op on FD */
2499 else if (code == CM_ERROR_EXISTS) {
2501 error = 80; /* file already exists */
2503 else if (code == CM_ERROR_NOTEMPTY) {
2505 error = 5; /* delete directory not empty */
2507 else if (code == CM_ERROR_CROSSDEVLINK) {
2509 error = 17; /* EXDEV */
2511 else if (code == CM_ERROR_NOTDIR) {
2512 class = 1; /* bad path */
2515 else if (code == CM_ERROR_ISDIR) {
2516 class = 1; /* access denied; DOS doesn't have a good match */
2519 else if (code == CM_ERROR_BADOP) {
2523 else if (code == CM_ERROR_BADSHARENAME) {
2527 else if (code == CM_ERROR_NOIPC) {
2529 error = 4; /* bad access */
2531 else if (code == CM_ERROR_CLOCKSKEW) {
2532 class = 1; /* invalid function */
2535 else if (code == CM_ERROR_BADTID) {
2539 else if (code == CM_ERROR_USESTD) {
2543 else if (code == CM_ERROR_REMOTECONN) {
2547 else if (code == CM_ERROR_QUOTA) {
2548 if (vcp->flags & SMB_VCFLAG_USEV3) {
2550 error = 39; /* disk full */
2554 error = 5; /* access denied */
2557 else if (code == CM_ERROR_SPACE) {
2558 if (vcp->flags & SMB_VCFLAG_USEV3) {
2560 error = 39; /* disk full */
2564 error = 5; /* access denied */
2567 else if (code == CM_ERROR_PARTIALWRITE) {
2569 error = 39; /* disk full */
2571 else if (code == CM_ERROR_ATSYS) {
2573 error = 2; /* ENOENT */
2575 else if (code == CM_ERROR_WOULDBLOCK) {
2577 error = 33; /* lock conflict */
2579 else if (code == CM_ERROR_NOFILES) {
2581 error = 18; /* no files in search */
2583 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2585 error = 183; /* Samba uses this */
2587 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2588 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2590 error = 2; /* bad password */
2592 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2594 error = 3; /* bad path */
2603 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2606 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2608 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2609 return CM_ERROR_BADOP;
2612 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2614 unsigned short EchoCount, i;
2615 char *data, *outdata;
2618 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2620 for (i=1; i<=EchoCount; i++) {
2621 data = smb_GetSMBData(inp, &dataSize);
2622 smb_SetSMBParm(outp, 0, i);
2623 smb_SetSMBDataLength(outp, dataSize);
2624 outdata = smb_GetSMBData(outp, NULL);
2625 memcpy(outdata, data, dataSize);
2626 smb_SendPacket(vcp, outp);
2632 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2635 long count, minCount, finalCount;
2639 cm_user_t *userp = NULL;
2643 char *rawBuf = NULL;
2645 dos_ptr rawBuf = NULL;
2652 fd = smb_GetSMBParm(inp, 0);
2653 count = smb_GetSMBParm(inp, 3);
2654 minCount = smb_GetSMBParm(inp, 4);
2655 offset.HighPart = 0; /* too bad */
2656 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2658 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2659 fd, offset.LowPart, count);
2661 fidp = smb_FindFID(vcp, fd, 0);
2665 lock_ObtainMutex(&smb_RawBufLock);
2667 /* Get a raw buf, from head of list */
2668 rawBuf = smb_RawBufs;
2670 smb_RawBufs = *(char **)smb_RawBufs;
2672 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2675 lock_ReleaseMutex(&smb_RawBufLock);
2679 if (fidp->flags & SMB_FID_IOCTL)
2682 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2684 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2687 /* Give back raw buffer */
2688 lock_ObtainMutex(&smb_RawBufLock);
2690 *((char **) rawBuf) = smb_RawBufs;
2692 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2695 smb_RawBufs = rawBuf;
2696 lock_ReleaseMutex(&smb_RawBufLock);
2699 smb_ReleaseFID(fidp);
2703 userp = smb_GetUser(vcp, inp);
2706 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2708 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2709 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2710 userp, &finalCount, TRUE /* rawFlag */);
2717 cm_ReleaseUser(userp);
2720 smb_ReleaseFID(fidp);
2725 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2727 memset((char *)ncbp, 0, sizeof(NCB));
2729 ncbp->ncb_length = (unsigned short) finalCount;
2730 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2731 ncbp->ncb_lana_num = vcp->lana;
2732 ncbp->ncb_command = NCBSEND;
2733 ncbp->ncb_buffer = rawBuf;
2736 code = Netbios(ncbp);
2738 code = Netbios(ncbp, dos_ncb);
2741 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2744 /* Give back raw buffer */
2745 lock_ObtainMutex(&smb_RawBufLock);
2747 *((char **) rawBuf) = smb_RawBufs;
2749 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2752 smb_RawBufs = rawBuf;
2753 lock_ReleaseMutex(&smb_RawBufLock);
2759 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2761 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2766 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2768 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2773 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2780 int protoIndex; /* index we're using */
2785 char protocol_array[10][1024]; /* protocol signature of the client */
2786 int caps; /* capabilities */
2789 TIME_ZONE_INFORMATION tzi;
2791 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2795 DWORD now = GetCurrentTime();
2796 if (now - last_msg_time >= 30000
2797 && now - last_msg_time <= 90000) {
2799 "Setting dead_vcp %x", active_vcp);
2801 smb_ReleaseVC(dead_vcp);
2803 "Previous dead_vcp %x", dead_vcp);
2805 smb_HoldVC(active_vcp);
2806 dead_vcp = active_vcp;
2807 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2812 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2814 namep = smb_GetSMBData(inp, &dbytes);
2817 coreProtoIndex = -1; /* not found */
2820 while(namex < dbytes) {
2821 osi_Log1(smb_logp, "Protocol %s",
2822 osi_LogSaveString(smb_logp, namep+1));
2823 strcpy(protocol_array[tcounter], namep+1);
2825 /* namep points at the first protocol, or really, a 0x02
2826 * byte preceding the null-terminated ASCII name.
2828 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2829 coreProtoIndex = tcounter;
2831 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2832 v3ProtoIndex = tcounter;
2834 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2835 NTProtoIndex = tcounter;
2838 /* compute size of protocol entry */
2839 entryLength = strlen(namep+1);
2840 entryLength += 2; /* 0x02 bytes and null termination */
2842 /* advance over this protocol entry */
2843 namex += entryLength;
2844 namep += entryLength;
2845 tcounter++; /* which proto entry we're looking at */
2848 if (NTProtoIndex != -1) {
2849 protoIndex = NTProtoIndex;
2850 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2852 else if (v3ProtoIndex != -1) {
2853 protoIndex = v3ProtoIndex;
2854 vcp->flags |= SMB_VCFLAG_USEV3;
2856 else if (coreProtoIndex != -1) {
2857 protoIndex = coreProtoIndex;
2858 vcp->flags |= SMB_VCFLAG_USECORE;
2860 else protoIndex = -1;
2862 if (protoIndex == -1)
2863 return CM_ERROR_INVAL;
2864 else if (NTProtoIndex != -1) {
2865 smb_SetSMBParm(outp, 0, protoIndex);
2866 if (smb_authType != SMB_AUTH_NONE) {
2867 smb_SetSMBParmByte(outp, 1,
2868 NEGOTIATE_SECURITY_USER_LEVEL |
2869 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2871 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2873 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2874 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2875 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2876 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2877 /* The session key is not a well documented field however most clients
2878 * will echo back the session key to the server. Currently we are using
2879 * the same value for all sessions. We should generate a random value
2880 * and store it into the vcp
2882 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2883 smb_SetSMBParm(outp, 8, 1);
2885 * Tried changing the capabilities to support for W2K - defect 117695
2886 * Maybe something else needs to be changed here?
2890 smb_SetSMBParmLong(outp, 9, 0x43fd);
2892 smb_SetSMBParmLong(outp, 9, 0x251);
2895 * 32-bit error codes *
2900 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2902 NTNEGOTIATE_CAPABILITY_DFS |
2904 NTNEGOTIATE_CAPABILITY_NTFIND |
2905 NTNEGOTIATE_CAPABILITY_RAWMODE |
2906 NTNEGOTIATE_CAPABILITY_NTSMB;
2908 if ( smb_authType == SMB_AUTH_EXTENDED )
2909 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2911 smb_SetSMBParmLong(outp, 9, caps);
2913 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2914 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2915 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2917 GetTimeZoneInformation(&tzi);
2918 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2920 if (smb_authType == SMB_AUTH_NTLM) {
2921 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2922 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2923 /* paste in encryption key */
2924 datap = smb_GetSMBData(outp, NULL);
2925 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2926 /* and the faux domain name */
2927 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2928 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2932 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2934 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2936 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2938 datap = smb_GetSMBData(outp, NULL);
2939 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2942 datap += sizeof(smb_ServerGUID);
2943 memcpy(datap, secBlob, secBlobLength);
2947 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2948 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2951 else if (v3ProtoIndex != -1) {
2952 smb_SetSMBParm(outp, 0, protoIndex);
2954 /* NOTE: Extended authentication cannot be negotiated with v3
2955 * therefore we fail over to NTLM
2957 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2958 smb_SetSMBParm(outp, 1,
2959 NEGOTIATE_SECURITY_USER_LEVEL |
2960 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2962 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2964 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2965 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2966 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2967 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2968 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2969 smb_SetSMBParm(outp, 7, 1);
2971 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2972 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2973 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2975 GetTimeZoneInformation(&tzi);
2976 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2978 /* NOTE: Extended authentication cannot be negotiated with v3
2979 * therefore we fail over to NTLM
2981 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2982 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2983 smb_SetSMBParm(outp, 12, 0); /* resvd */
2984 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2985 datap = smb_GetSMBData(outp, NULL);
2986 /* paste in a new encryption key */
2987 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2988 /* and the faux domain name */
2989 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2991 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2992 smb_SetSMBParm(outp, 12, 0); /* resvd */
2993 smb_SetSMBDataLength(outp, 0);
2996 else if (coreProtoIndex != -1) { /* not really supported anymore */
2997 smb_SetSMBParm(outp, 0, protoIndex);
2998 smb_SetSMBDataLength(outp, 0);
3003 void smb_Daemon(void *parmp)
3005 afs_uint32 count = 0;
3007 while(smbShutdownFlag == 0) {
3011 if (smbShutdownFlag == 1)
3014 if ((count % 72) == 0) { /* every five minutes */
3016 time_t old_localZero = smb_localZero;
3018 /* Initialize smb_localZero */
3019 myTime.tm_isdst = -1; /* compute whether on DST or not */
3020 myTime.tm_year = 70;
3026 smb_localZero = mktime(&myTime);
3028 #ifndef USE_NUMERIC_TIME_CONV
3029 smb_CalculateNowTZ();
3030 #endif /* USE_NUMERIC_TIME_CONV */
3031 #ifdef AFS_FREELANCE
3032 if ( smb_localZero != old_localZero )
3033 cm_noteLocalMountPointChange();
3036 /* XXX GC dir search entries */
3040 void smb_WaitingLocksDaemon()
3042 smb_waitingLock_t *wL, *nwL;
3045 smb_packet_t *inp, *outp;
3049 while (smbShutdownFlag == 0) {
3050 lock_ObtainWrite(&smb_globalLock);
3051 nwL = smb_allWaitingLocks;
3053 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3063 lock_ObtainWrite(&smb_globalLock);
3065 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
3066 lock_ReleaseWrite(&smb_globalLock);
3067 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
3068 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
3069 if (code == CM_ERROR_WOULDBLOCK) {
3071 if (wL->timeRemaining != 0xffffffff
3072 && (wL->timeRemaining -= 1000) < 0)
3082 ncbp->ncb_length = inp->ncb_length;
3083 inp->spacep = cm_GetSpace();
3085 /* Remove waitingLock from list */
3086 lock_ObtainWrite(&smb_globalLock);
3087 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3089 lock_ReleaseWrite(&smb_globalLock);
3091 /* Resume packet processing */
3093 smb_SetSMBDataLength(outp, 0);
3094 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3095 outp->resumeCode = code;
3097 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3100 cm_FreeSpace(inp->spacep);
3101 smb_FreePacket(inp);
3102 smb_FreePacket(outp);
3106 } while (nwL && smbShutdownFlag == 0);
3111 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3113 osi_Log0(smb_logp, "SMB receive get disk attributes");
3115 smb_SetSMBParm(outp, 0, 32000);
3116 smb_SetSMBParm(outp, 1, 64);
3117 smb_SetSMBParm(outp, 2, 1024);
3118 smb_SetSMBParm(outp, 3, 30000);
3119 smb_SetSMBParm(outp, 4, 0);
3120 smb_SetSMBDataLength(outp, 0);
3124 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3128 unsigned short newTid;
3129 char shareName[256];
3137 osi_Log0(smb_logp, "SMB receive tree connect");
3139 /* parse input parameters */
3140 tp = smb_GetSMBData(inp, NULL);
3141 pathp = smb_ParseASCIIBlock(tp, &tp);
3142 if (smb_StoreAnsiFilenames)
3143 OemToChar(pathp,pathp);
3144 passwordp = smb_ParseASCIIBlock(tp, &tp);
3145 tp = strrchr(pathp, '\\');
3147 return CM_ERROR_BADSMB;
3148 strcpy(shareName, tp+1);
3150 userp = smb_GetUser(vcp, inp);
3152 lock_ObtainMutex(&vcp->mx);
3153 newTid = vcp->tidCounter++;
3154 lock_ReleaseMutex(&vcp->mx);
3156 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3157 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3158 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3160 smb_ReleaseUID(uidp);
3162 smb_ReleaseTID(tidp);
3163 return CM_ERROR_BADSHARENAME;
3165 lock_ObtainMutex(&tidp->mx);
3166 tidp->userp = userp;
3167 tidp->pathname = sharePath;
3168 lock_ReleaseMutex(&tidp->mx);
3169 smb_ReleaseTID(tidp);
3171 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3172 smb_SetSMBParm(rsp, 1, newTid);
3173 smb_SetSMBDataLength(rsp, 0);
3175 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3179 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3183 if (*inp++ != 0x1) return NULL;
3184 tlen = inp[0] + (inp[1]<<8);
3185 inp += 2; /* skip length field */
3188 *chainpp = inp + tlen;
3191 if (lengthp) *lengthp = tlen;
3196 /* set maskp to the mask part of the incoming path.
3197 * Mask is 11 bytes long (8.3 with the dot elided).
3198 * Returns true if succeeds with a valid name, otherwise it does
3199 * its best, but returns false.
3201 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3209 /* starts off valid */
3212 /* mask starts out all blanks */
3213 memset(maskp, ' ', 11);
3215 /* find last backslash, or use whole thing if there is none */
3216 tp = strrchr(pathp, '\\');
3217 if (!tp) tp = pathp;
3218 else tp++; /* skip slash */
3222 /* names starting with a dot are illegal */
3223 if (*tp == '.') valid8Dot3 = 0;
3227 if (tc == 0) return valid8Dot3;
3228 if (tc == '.' || tc == '"') break;
3229 if (i < 8) *up++ = tc;
3230 else valid8Dot3 = 0;
3233 /* if we get here, tp point after the dot */
3234 up = maskp+8; /* ext goes here */
3241 if (tc == '.' || tc == '"')
3244 /* copy extension if not too long */
3254 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3264 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3266 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3270 /* otherwise, we have a valid 8.3 name; see if we have a match,
3271 * treating '?' as a wildcard in maskp (but not in the file name).
3273 tp1 = umask; /* real name, in mask format */
3274 tp2 = maskp; /* mask, in mask format */
3275 for(i=0; i<11; i++) {
3276 tc1 = *tp1++; /* char from real name */
3277 tc2 = *tp2++; /* char from mask */
3278 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3279 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3282 if (tc2 == '?' && tc1 != ' ')
3289 /* we got a match */
3293 char *smb_FindMask(char *pathp)
3297 tp = strrchr(pathp, '\\'); /* find last slash */
3300 return tp+1; /* skip the slash */
3302 return pathp; /* no slash, return the entire path */
3305 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3307 unsigned char *pathp;
3309 unsigned char mask[11];
3310 unsigned char *statBlockp;
3311 unsigned char initStatBlock[21];
3314 osi_Log0(smb_logp, "SMB receive search volume");
3316 /* pull pathname and stat block out of request */
3317 tp = smb_GetSMBData(inp, NULL);
3318 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3319 osi_assert(pathp != NULL);
3320 if (smb_StoreAnsiFilenames)
3321 OemToChar(pathp,pathp);
3322 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3323 osi_assert(statBlockp != NULL);
3325 statBlockp = initStatBlock;
3329 /* for returning to caller */
3330 smb_Get8Dot3MaskFromPath(mask, pathp);
3332 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3333 tp = smb_GetSMBData(outp, NULL);
3335 *tp++ = 43; /* bytes in a dir entry */
3336 *tp++ = 0; /* high byte in counter */
3338 /* now marshall the dir entry, starting with the search status */
3339 *tp++ = statBlockp[0]; /* Reserved */
3340 memcpy(tp, mask, 11); tp += 11; /* FileName */
3342 /* now pass back server use info, with 1st byte non-zero */
3344 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3346 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3348 *tp++ = 0x8; /* attribute: volume */
3358 /* 4 byte file size */
3364 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3365 memset(tp, ' ', 13);
3368 /* set the length of the data part of the packet to 43 + 3, for the dir
3369 * entry plus the 5 and the length fields.
3371 smb_SetSMBDataLength(outp, 46);
3375 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3376 cm_user_t *userp, cm_req_t *reqp)
3384 smb_dirListPatch_t *patchp;
3385 smb_dirListPatch_t *npatchp;
3387 for (patchp = *dirPatchespp; patchp; patchp =
3388 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3390 dptr = patchp->dptr;
3392 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3394 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3395 *dptr++ = SMB_ATTR_HIDDEN;
3398 lock_ObtainMutex(&scp->mx);
3399 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3400 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3402 lock_ReleaseMutex(&scp->mx);
3403 cm_ReleaseSCache(scp);
3404 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3405 *dptr++ = SMB_ATTR_HIDDEN;
3409 attr = smb_Attributes(scp);
3410 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3411 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3412 attr |= SMB_ATTR_HIDDEN;
3416 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3419 shortTemp = (unsigned short) (dosTime & 0xffff);
3420 *((u_short *)dptr) = shortTemp;
3423 /* and copy out date */
3424 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3425 *((u_short *)dptr) = shortTemp;
3428 /* copy out file length */
3429 *((u_long *)dptr) = scp->length.LowPart;
3431 lock_ReleaseMutex(&scp->mx);
3432 cm_ReleaseSCache(scp);
3435 /* now free the patches */
3436 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3437 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3441 /* and mark the list as empty */
3442 *dirPatchespp = NULL;
3447 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3456 smb_dirListPatch_t *dirListPatchesp;
3457 smb_dirListPatch_t *curPatchp;
3461 osi_hyper_t dirLength;
3462 osi_hyper_t bufferOffset;
3463 osi_hyper_t curOffset;
3465 unsigned char *inCookiep;
3466 smb_dirSearch_t *dsp;
3470 unsigned long clientCookie;
3471 cm_pageHeader_t *pageHeaderp;
3472 cm_user_t *userp = NULL;
3479 long nextEntryCookie;
3480 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3481 char resByte; /* reserved byte from the cookie */
3482 char *op; /* output data ptr */
3483 char *origOp; /* original value of op */
3484 cm_space_t *spacep; /* for pathname buffer */
3495 maxCount = smb_GetSMBParm(inp, 0);
3497 dirListPatchesp = NULL;
3499 caseFold = CM_FLAG_CASEFOLD;
3501 tp = smb_GetSMBData(inp, NULL);
3502 pathp = smb_ParseASCIIBlock(tp, &tp);
3503 if (smb_StoreAnsiFilenames)
3504 OemToChar(pathp,pathp);
3505 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3507 /* bail out if request looks bad */
3508 if (!tp || !pathp) {
3509 return CM_ERROR_BADSMB;
3512 /* We can handle long names */
3513 if (vcp->flags & SMB_VCFLAG_USENT)
3514 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3516 /* make sure we got a whole search status */
3517 if (dataLength < 21) {
3518 nextCookie = 0; /* start at the beginning of the dir */
3521 attribute = smb_GetSMBParm(inp, 1);
3523 /* handle volume info in another function */
3524 if (attribute & 0x8)
3525 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3527 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3528 maxCount, osi_LogSaveString(smb_logp, pathp));
3530 if (*pathp == 0) { /* null pathp, treat as root dir */
3531 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3532 return CM_ERROR_NOFILES;
3536 dsp = smb_NewDirSearch(0);
3537 dsp->attribute = attribute;
3538 smb_Get8Dot3MaskFromPath(mask, pathp);
3539 memcpy(dsp->mask, mask, 11);
3541 /* track if this is likely to match a lot of entries */
3542 if (smb_IsStarMask(mask))
3547 /* pull the next cookie value out of the search status block */
3548 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3549 + (inCookiep[16]<<24);
3550 dsp = smb_FindDirSearch(inCookiep[12]);
3552 /* can't find dir search status; fatal error */
3553 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3554 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3555 return CM_ERROR_BADFD;
3557 attribute = dsp->attribute;
3558 resByte = inCookiep[0];
3560 /* copy out client cookie, in host byte order. Don't bother
3561 * interpreting it, since we're just passing it through, anyway.
3563 memcpy(&clientCookie, &inCookiep[17], 4);
3565 memcpy(mask, dsp->mask, 11);
3567 /* assume we're doing a star match if it has continued for more
3573 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3574 nextCookie, dsp->cookie, attribute);
3576 userp = smb_GetUser(vcp, inp);
3578 /* try to get the vnode for the path name next */
3579 lock_ObtainMutex(&dsp->mx);
3585 spacep = inp->spacep;
3586 smb_StripLastComponent(spacep->data, NULL, pathp);
3587 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3589 lock_ReleaseMutex(&dsp->mx);
3590 cm_ReleaseUser(userp);
3591 smb_DeleteDirSearch(dsp);
3592 smb_ReleaseDirSearch(dsp);
3593 return CM_ERROR_NOFILES;
3595 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3596 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3599 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3600 cm_ReleaseSCache(scp);
3601 lock_ReleaseMutex(&dsp->mx);
3602 cm_ReleaseUser(userp);
3603 smb_DeleteDirSearch(dsp);
3604 smb_ReleaseDirSearch(dsp);
3605 if ( WANTS_DFS_PATHNAMES(inp) )
3606 return CM_ERROR_PATH_NOT_COVERED;
3608 return CM_ERROR_BADSHARENAME;
3610 #endif /* DFS_SUPPORT */
3613 /* we need one hold for the entry we just stored into,
3614 * and one for our own processing. When we're done with this
3615 * function, we'll drop the one for our own processing.
3616 * We held it once from the namei call, and so we do another hold
3620 lock_ObtainMutex(&scp->mx);
3621 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3622 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3623 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3624 dsp->flags |= SMB_DIRSEARCH_BULKST;
3626 lock_ReleaseMutex(&scp->mx);
3629 lock_ReleaseMutex(&dsp->mx);
3631 cm_ReleaseUser(userp);
3632 smb_DeleteDirSearch(dsp);
3633 smb_ReleaseDirSearch(dsp);
3637 /* reserves space for parameter; we'll adjust it again later to the
3638 * real count of the # of entries we returned once we've actually
3639 * assembled the directory listing.
3641 smb_SetSMBParm(outp, 0, 0);
3643 /* get the directory size */
3644 lock_ObtainMutex(&scp->mx);
3645 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3646 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3648 lock_ReleaseMutex(&scp->mx);
3649 cm_ReleaseSCache(scp);
3650 cm_ReleaseUser(userp);
3651 smb_DeleteDirSearch(dsp);
3652 smb_ReleaseDirSearch(dsp);
3656 dirLength = scp->length;
3658 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3659 curOffset.HighPart = 0;
3660 curOffset.LowPart = nextCookie;
3661 origOp = op = smb_GetSMBData(outp, NULL);
3662 /* and write out the basic header */
3663 *op++ = 5; /* variable block */
3664 op += 2; /* skip vbl block length; we'll fill it in later */
3668 /* make sure that curOffset.LowPart doesn't point to the first
3669 * 32 bytes in the 2nd through last dir page, and that it doesn't
3670 * point at the first 13 32-byte chunks in the first dir page,
3671 * since those are dir and page headers, and don't contain useful
3674 temp = curOffset.LowPart & (2048-1);
3675 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3676 /* we're in the first page */
3677 if (temp < 13*32) temp = 13*32;
3680 /* we're in a later dir page */
3681 if (temp < 32) temp = 32;
3684 /* make sure the low order 5 bits are zero */
3687 /* now put temp bits back ito curOffset.LowPart */
3688 curOffset.LowPart &= ~(2048-1);
3689 curOffset.LowPart |= temp;
3691 /* check if we've returned all the names that will fit in the
3694 if (returnedNames >= maxCount) {
3695 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3696 returnedNames, maxCount);
3700 /* check if we've passed the dir's EOF */
3701 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3703 /* see if we can use the bufferp we have now; compute in which page
3704 * the current offset would be, and check whether that's the offset
3705 * of the buffer we have. If not, get the buffer.
3707 thyper.HighPart = curOffset.HighPart;
3708 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3709 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3712 buf_Release(bufferp);
3715 lock_ReleaseMutex(&scp->mx);
3716 lock_ObtainRead(&scp->bufCreateLock);
3717 code = buf_Get(scp, &thyper, &bufferp);
3718 lock_ReleaseRead(&scp->bufCreateLock);
3719 lock_ObtainMutex(&dsp->mx);
3721 /* now, if we're doing a star match, do bulk fetching of all of
3722 * the status info for files in the dir.
3725 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3726 lock_ObtainMutex(&scp->mx);
3727 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3728 LargeIntegerGreaterThanOrEqualTo(thyper,
3729 scp->bulkStatProgress)) {
3730 /* Don't bulk stat if risking timeout */
3731 int now = GetCurrentTime();
3732 if (now - req.startTime > 5000) {
3733 scp->bulkStatProgress = thyper;
3734 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3735 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3737 cm_TryBulkStat(scp, &thyper, userp, &req);
3740 lock_ObtainMutex(&scp->mx);
3742 lock_ReleaseMutex(&dsp->mx);
3744 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3748 bufferOffset = thyper;
3750 /* now get the data in the cache */
3752 code = cm_SyncOp(scp, bufferp, userp, &req,
3754 CM_SCACHESYNC_NEEDCALLBACK |
3755 CM_SCACHESYNC_READ);
3757 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3761 if (cm_HaveBuffer(scp, bufferp, 0)) {
3762 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3766 /* otherwise, load the buffer and try again */
3767 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3769 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3770 scp, bufferp, code);
3775 buf_Release(bufferp);
3779 } /* if (wrong buffer) ... */
3781 /* now we have the buffer containing the entry we're interested in; copy
3782 * it out if it represents a non-deleted entry.
3784 entryInDir = curOffset.LowPart & (2048-1);
3785 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3787 /* page header will help tell us which entries are free. Page header
3788 * can change more often than once per buffer, since AFS 3 dir page size
3789 * may be less than (but not more than a buffer package buffer.
3791 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3792 temp &= ~(2048 - 1); /* turn off intra-page bits */
3793 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3795 /* now determine which entry we're looking at in the page. If it is
3796 * free (there's a free bitmap at the start of the dir), we should
3797 * skip these 32 bytes.
3799 slotInPage = (entryInDir & 0x7e0) >> 5;
3800 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3801 /* this entry is free */
3802 numDirChunks = 1; /* only skip this guy */
3806 tp = bufferp->datap + entryInBuffer;
3807 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3809 /* while we're here, compute the next entry's location, too,
3810 * since we'll need it when writing out the cookie into the dir
3813 * XXXX Probably should do more sanity checking.
3815 numDirChunks = cm_NameEntries(dep->name, NULL);
3817 /* compute the offset of the cookie representing the next entry */
3818 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3820 /* Compute 8.3 name if necessary */
3821 actualName = dep->name;
3822 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3823 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3824 actualName = shortName;
3827 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3828 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3829 osi_LogSaveString(smb_logp, actualName));
3831 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3832 /* this is one of the entries to use: it is not deleted
3833 * and it matches the star pattern we're looking for.
3836 /* Eliminate entries that don't match requested
3839 /* no hidden files */
3840 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3841 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3845 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3847 /* We have already done the cm_TryBulkStat above */
3848 fid.cell = scp->fid.cell;
3849 fid.volume = scp->fid.volume;
3850 fid.vnode = ntohl(dep->fid.vnode);
3851 fid.unique = ntohl(dep->fid.unique);
3852 fileType = cm_FindFileType(&fid);
3853 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3854 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3856 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3857 fileType == CM_SCACHETYPE_DFSLINK ||
3858 fileType == CM_SCACHETYPE_INVALID)
3859 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3864 memcpy(op, mask, 11); op += 11;
3865 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3866 *op++ = nextEntryCookie & 0xff;
3867 *op++ = (nextEntryCookie>>8) & 0xff;
3868 *op++ = (nextEntryCookie>>16) & 0xff;
3869 *op++ = (nextEntryCookie>>24) & 0xff;
3870 memcpy(op, &clientCookie, 4); op += 4;
3872 /* now we emit the attribute. This is sort of tricky,
3873 * since we need to really stat the file to find out
3874 * what type of entry we've got. Right now, we're
3875 * copying out data from a buffer, while holding the
3876 * scp locked, so it isn't really convenient to stat
3877 * something now. We'll put in a place holder now,
3878 * and make a second pass before returning this to get
3879 * the real attributes. So, we just skip the data for
3880 * now, and adjust it later. We allocate a patch
3881 * record to make it easy to find this point later.
3882 * The replay will happen at a time when it is safe to
3883 * unlock the directory.
3885 curPatchp = malloc(sizeof(*curPatchp));
3886 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3887 curPatchp->dptr = op;
3888 curPatchp->fid.cell = scp->fid.cell;
3889 curPatchp->fid.volume = scp->fid.volume;
3890 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3891 curPatchp->fid.unique = ntohl(dep->fid.unique);
3893 /* do hidden attribute here since name won't be around when applying
3897 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3898 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3900 curPatchp->flags = 0;
3902 op += 9; /* skip attr, time, date and size */
3904 /* zero out name area. The spec says to pad with
3905 * spaces, but Samba doesn't, and neither do we.
3909 /* finally, we get to copy out the name; we know that
3910 * it fits in 8.3 or the pattern wouldn't match, but it
3911 * never hurts to be sure.
3913 strncpy(op, actualName, 13);
3914 if (smb_StoreAnsiFilenames)
3917 /* Uppercase if requested by client */
3918 if (!KNOWS_LONG_NAMES(inp))
3923 /* now, adjust the # of entries copied */
3925 } /* if we're including this name */
3928 /* and adjust curOffset to be where the new cookie is */
3929 thyper.HighPart = 0;
3930 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3931 curOffset = LargeIntegerAdd(thyper, curOffset);
3932 } /* while copying data for dir listing */
3934 /* release the mutex */
3935 lock_ReleaseMutex(&scp->mx);
3936 if (bufferp) buf_Release(bufferp);
3938 /* apply and free last set of patches; if not doing a star match, this
3939 * will be empty, but better safe (and freeing everything) than sorry.
3941 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3943 /* special return code for unsuccessful search */
3944 if (code == 0 && dataLength < 21 && returnedNames == 0)
3945 code = CM_ERROR_NOFILES;
3947 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3948 returnedNames, code);
3951 smb_DeleteDirSearch(dsp);
3952 smb_ReleaseDirSearch(dsp);
3953 cm_ReleaseSCache(scp);
3954 cm_ReleaseUser(userp);
3958 /* finalize the output buffer */
3959 smb_SetSMBParm(outp, 0, returnedNames);
3960 temp = (long) (op - origOp);
3961 smb_SetSMBDataLength(outp, temp);
3963 /* the data area is a variable block, which has a 5 (already there)
3964 * followed by the length of the # of data bytes. We now know this to
3965 * be "temp," although that includes the 3 bytes of vbl block header.
3966 * Deduct for them and fill in the length field.
3968 temp -= 3; /* deduct vbl block info */
3969 osi_assert(temp == (43 * returnedNames));
3970 origOp[1] = temp & 0xff;
3971 origOp[2] = (temp>>8) & 0xff;
3972 if (returnedNames == 0)
3973 smb_DeleteDirSearch(dsp);
3974 smb_ReleaseDirSearch(dsp);
3975 cm_ReleaseSCache(scp);
3976 cm_ReleaseUser(userp);
3980 /* verify that this is a valid path to a directory. I don't know why they
3981 * don't use the get file attributes call.
3983 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3987 cm_scache_t *rootScp;
3988 cm_scache_t *newScp;
3997 pathp = smb_GetSMBData(inp, NULL);
3998 pathp = smb_ParseASCIIBlock(pathp, NULL);
4000 return CM_ERROR_BADFD;
4001 if (smb_StoreAnsiFilenames)
4002 OemToChar(pathp,pathp);
4003 osi_Log1(smb_logp, "SMB receive check path %s",
4004 osi_LogSaveString(smb_logp, pathp));
4006 rootScp = cm_data.rootSCachep;
4008 userp = smb_GetUser(vcp, inp);
4010 caseFold = CM_FLAG_CASEFOLD;
4012 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4014 cm_ReleaseUser(userp);
4015 return CM_ERROR_NOSUCHPATH;
4017 code = cm_NameI(rootScp, pathp,
4018 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4019 userp, tidPathp, &req, &newScp);
4022 cm_ReleaseUser(userp);
4027 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4028 cm_ReleaseSCache(newScp);
4029 cm_ReleaseUser(userp);
4030 if ( WANTS_DFS_PATHNAMES(inp) )
4031 return CM_ERROR_PATH_NOT_COVERED;
4033 return CM_ERROR_BADSHARENAME;
4035 #endif /* DFS_SUPPORT */
4037 /* now lock the vnode with a callback; returns with newScp locked */
4038 lock_ObtainMutex(&newScp->mx);
4039 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4040 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4041 if (code && code != CM_ERROR_NOACCESS) {
4042 lock_ReleaseMutex(&newScp->mx);
4043 cm_ReleaseSCache(newScp);
4044 cm_ReleaseUser(userp);
4048 attrs = smb_Attributes(newScp);
4050 if (!(attrs & SMB_ATTR_DIRECTORY))
4051 code = CM_ERROR_NOTDIR;
4053 lock_ReleaseMutex(&newScp->mx);
4055 cm_ReleaseSCache(newScp);
4056 cm_ReleaseUser(userp);
4060 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4064 cm_scache_t *rootScp;
4065 unsigned short attribute;
4067 cm_scache_t *newScp;
4076 /* decode basic attributes we're passed */
4077 attribute = smb_GetSMBParm(inp, 0);
4078 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4080 pathp = smb_GetSMBData(inp, NULL);
4081 pathp = smb_ParseASCIIBlock(pathp, NULL);
4083 return CM_ERROR_BADSMB;
4084 if (smb_StoreAnsiFilenames)
4085 OemToChar(pathp,pathp);
4087 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4088 dosTime, attribute);
4090 rootScp = cm_data.rootSCachep;
4092 userp = smb_GetUser(vcp, inp);
4094 caseFold = CM_FLAG_CASEFOLD;
4096 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4098 cm_ReleaseUser(userp);
4099 return CM_ERROR_NOSUCHFILE;
4101 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4102 tidPathp, &req, &newScp);
4105 cm_ReleaseUser(userp);
4110 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4111 cm_ReleaseSCache(newScp);
4112 cm_ReleaseUser(userp);
4113 if ( WANTS_DFS_PATHNAMES(inp) )
4114 return CM_ERROR_PATH_NOT_COVERED;
4116 return CM_ERROR_BADSHARENAME;
4118 #endif /* DFS_SUPPORT */
4120 /* now lock the vnode with a callback; returns with newScp locked; we
4121 * need the current status to determine what the new status is, in some
4124 lock_ObtainMutex(&newScp->mx);
4125 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4126 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4128 lock_ReleaseMutex(&newScp->mx);
4129 cm_ReleaseSCache(newScp);
4130 cm_ReleaseUser(userp);
4134 /* Check for RO volume */
4135 if (newScp->flags & CM_SCACHEFLAG_RO) {
4136 lock_ReleaseMutex(&newScp->mx);
4137 cm_ReleaseSCache(newScp);
4138 cm_ReleaseUser(userp);
4139 return CM_ERROR_READONLY;
4142 /* prepare for setattr call */
4145 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4146 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4148 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4149 /* we're told to make a writable file read-only */
4150 attr.unixModeBits = newScp->unixModeBits & ~0222;
4151 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4153 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4154 /* we're told to make a read-only file writable */
4155 attr.unixModeBits = newScp->unixModeBits | 0222;
4156 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4158 lock_ReleaseMutex(&newScp->mx);
4160 /* now call setattr */
4162 code = cm_SetAttr(newScp, &attr, userp, &req);
4166 cm_ReleaseSCache(newScp);
4167 cm_ReleaseUser(userp);
4172 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4176 cm_scache_t *rootScp;
4177 cm_scache_t *newScp, *dscp;
4189 pathp = smb_GetSMBData(inp, NULL);
4190 pathp = smb_ParseASCIIBlock(pathp, NULL);
4192 return CM_ERROR_BADSMB;
4194 if (*pathp == 0) /* null path */
4197 if (smb_StoreAnsiFilenames)
4198 OemToChar(pathp,pathp);
4200 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4201 osi_LogSaveString(smb_logp, pathp));
4203 rootScp = cm_data.rootSCachep;
4205 userp = smb_GetUser(vcp, inp);
4207 /* we shouldn't need this for V3 requests, but we seem to */
4208 caseFold = CM_FLAG_CASEFOLD;
4210 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4212 cm_ReleaseUser(userp);
4213 return CM_ERROR_NOSUCHFILE;
4217 * XXX Strange hack XXX
4219 * As of Patch 5 (16 July 97), we are having the following problem:
4220 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4221 * requests to look up "desktop.ini" in all the subdirectories.
4222 * This can cause zillions of timeouts looking up non-existent cells
4223 * and volumes, especially in the top-level directory.
4225 * We have not found any way to avoid this or work around it except
4226 * to explicitly ignore the requests for mount points that haven't
4227 * yet been evaluated and for directories that haven't yet been
4230 * We should modify this hack to provide a fake desktop.ini file
4231 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4233 spacep = inp->spacep;
4234 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4235 #ifndef SPECIAL_FOLDERS
4236 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4237 code = cm_NameI(rootScp, spacep->data,
4238 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4239 userp, tidPathp, &req, &dscp);
4242 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4243 if ( WANTS_DFS_PATHNAMES(inp) )
4244 return CM_ERROR_PATH_NOT_COVERED;
4246 return CM_ERROR_BADSHARENAME;
4248 #endif /* DFS_SUPPORT */
4249 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4250 code = CM_ERROR_NOSUCHFILE;
4251 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4252 cm_buf_t *bp = buf_Find(dscp, &hzero);
4256 code = CM_ERROR_NOSUCHFILE;
4258 cm_ReleaseSCache(dscp);
4260 cm_ReleaseUser(userp);
4265 #endif /* SPECIAL_FOLDERS */
4267 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4268 tidPathp, &req, &newScp);
4270 cm_ReleaseUser(userp);
4275 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4276 cm_ReleaseSCache(newScp);
4277 cm_ReleaseUser(userp);
4278 if ( WANTS_DFS_PATHNAMES(inp) )
4279 return CM_ERROR_PATH_NOT_COVERED;
4281 return CM_ERROR_BADSHARENAME;
4283 #endif /* DFS_SUPPORT */
4285 /* now lock the vnode with a callback; returns with newScp locked */
4286 lock_ObtainMutex(&newScp->mx);
4287 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4288 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4290 lock_ReleaseMutex(&newScp->mx);
4291 cm_ReleaseSCache(newScp);
4292 cm_ReleaseUser(userp);
4297 /* use smb_Attributes instead. Also the fact that a file is
4298 * in a readonly volume doesn't mean it shojuld be marked as RO
4300 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4301 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4302 attrs = SMB_ATTR_DIRECTORY;
4305 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4306 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4308 attrs = smb_Attributes(newScp);
4311 smb_SetSMBParm(outp, 0, attrs);
4313 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4314 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4315 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4316 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4317 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4318 smb_SetSMBParm(outp, 5, 0);
4319 smb_SetSMBParm(outp, 6, 0);
4320 smb_SetSMBParm(outp, 7, 0);
4321 smb_SetSMBParm(outp, 8, 0);
4322 smb_SetSMBParm(outp, 9, 0);
4323 smb_SetSMBDataLength(outp, 0);
4324 lock_ReleaseMutex(&newScp->mx);
4326 cm_ReleaseSCache(newScp);
4327 cm_ReleaseUser(userp);
4332 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4336 osi_Log0(smb_logp, "SMB receive tree disconnect");
4338 /* find the tree and free it */
4339 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4341 lock_ObtainMutex(&tidp->mx);
4342 tidp->flags |= SMB_TIDFLAG_DELETE;
4343 lock_ReleaseMutex(&tidp->mx);
4344 smb_ReleaseTID(tidp);
4350 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4368 pathp = smb_GetSMBData(inp, NULL);
4369 pathp = smb_ParseASCIIBlock(pathp, NULL);
4370 if (smb_StoreAnsiFilenames)
4371 OemToChar(pathp,pathp);
4373 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4375 #ifdef DEBUG_VERBOSE
4379 hexpath = osi_HexifyString( pathp );
4380 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4385 share = smb_GetSMBParm(inp, 0);
4386 attribute = smb_GetSMBParm(inp, 1);
4388 spacep = inp->spacep;
4389 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4390 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4391 /* special case magic file name for receiving IOCTL requests
4392 * (since IOCTL calls themselves aren't getting through).
4394 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4395 smb_SetupIoctlFid(fidp, spacep);
4396 smb_SetSMBParm(outp, 0, fidp->fid);
4397 smb_SetSMBParm(outp, 1, 0); /* attrs */
4398 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4399 smb_SetSMBParm(outp, 3, 0);
4400 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4401 smb_SetSMBParm(outp, 5, 0x7fff);
4402 /* pass the open mode back */
4403 smb_SetSMBParm(outp, 6, (share & 0xf));
4404 smb_SetSMBDataLength(outp, 0);
4405 smb_ReleaseFID(fidp);
4409 userp = smb_GetUser(vcp, inp);
4411 caseFold = CM_FLAG_CASEFOLD;
4413 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4415 cm_ReleaseUser(userp);
4416 return CM_ERROR_NOSUCHPATH;
4418 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4419 tidPathp, &req, &scp);
4422 cm_ReleaseUser(userp);
4427 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4428 cm_ReleaseSCache(scp);
4429 cm_ReleaseUser(userp);
4430 if ( WANTS_DFS_PATHNAMES(inp) )
4431 return CM_ERROR_PATH_NOT_COVERED;
4433 return CM_ERROR_BADSHARENAME;
4435 #endif /* DFS_SUPPORT */
4437 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4439 cm_ReleaseSCache(scp);
4440 cm_ReleaseUser(userp);
4444 /* don't need callback to check file type, since file types never
4445 * change, and namei and cm_Lookup all stat the object at least once on
4446 * a successful return.
4448 if (scp->fileType != CM_SCACHETYPE_FILE) {
4449 cm_ReleaseSCache(scp);
4450 cm_ReleaseUser(userp);
4451 return CM_ERROR_ISDIR;
4454 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4457 /* save a pointer to the vnode */
4460 if ((share & 0xf) == 0)
4461 fidp->flags |= SMB_FID_OPENREAD;
4462 else if ((share & 0xf) == 1)
4463 fidp->flags |= SMB_FID_OPENWRITE;
4465 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4467 lock_ObtainMutex(&scp->mx);
4468 smb_SetSMBParm(outp, 0, fidp->fid);
4469 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4470 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4471 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4472 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4473 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4474 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4475 /* pass the open mode back; XXXX add access checks */
4476 smb_SetSMBParm(outp, 6, (share & 0xf));
4477 smb_SetSMBDataLength(outp, 0);
4478 lock_ReleaseMutex(&scp->mx);
4481 cm_Open(scp, 0, userp);
4483 /* send and free packet */
4484 smb_ReleaseFID(fidp);
4485 cm_ReleaseUser(userp);
4486 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4490 typedef struct smb_unlinkRock {
4495 char *maskp; /* pointer to the star pattern */
4500 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4503 smb_unlinkRock_t *rockp;
4511 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4512 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4513 caseFold |= CM_FLAG_8DOT3;
4515 matchName = dep->name;
4516 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4518 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4519 !cm_Is8Dot3(dep->name)) {
4520 cm_Gen8Dot3Name(dep, shortName, NULL);
4521 matchName = shortName;
4522 /* 8.3 matches are always case insensitive */
4523 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4526 osi_Log1(smb_logp, "Unlinking %s",
4527 osi_LogSaveString(smb_logp, matchName));
4528 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4529 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4530 smb_NotifyChange(FILE_ACTION_REMOVED,
4531 FILE_NOTIFY_CHANGE_FILE_NAME,
4532 dscp, dep->name, NULL, TRUE);
4536 /* If we made a case sensitive exact match, we might as well quit now. */
4537 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4538 code = CM_ERROR_STOPNOW;
4546 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4555 smb_unlinkRock_t rock;
4564 attribute = smb_GetSMBParm(inp, 0);
4566 tp = smb_GetSMBData(inp, NULL);
4567 pathp = smb_ParseASCIIBlock(tp, &tp);
4568 if (smb_StoreAnsiFilenames)
4569 OemToChar(pathp,pathp);
4571 osi_Log1(smb_logp, "SMB receive unlink %s",
4572 osi_LogSaveString(smb_logp, pathp));
4574 spacep = inp->spacep;
4575 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4577 userp = smb_GetUser(vcp, inp);
4579 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4581 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4583 cm_ReleaseUser(userp);
4584 return CM_ERROR_NOSUCHPATH;
4586 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4589 cm_ReleaseUser(userp);
4594 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4595 cm_ReleaseSCache(dscp);
4596 cm_ReleaseUser(userp);
4597 if ( WANTS_DFS_PATHNAMES(inp) )
4598 return CM_ERROR_PATH_NOT_COVERED;
4600 return CM_ERROR_BADSHARENAME;
4602 #endif /* DFS_SUPPORT */
4604 /* otherwise, scp points to the parent directory. */
4611 rock.maskp = smb_FindMask(pathp);
4612 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4615 thyper.HighPart = 0;
4621 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4622 * match. If that fails, we do a case insensitve match.
4624 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4625 !smb_IsStarMask(rock.maskp)) {
4626 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4629 thyper.HighPart = 0;
4630 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4635 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4637 if (code == CM_ERROR_STOPNOW)
4640 cm_ReleaseUser(userp);
4642 cm_ReleaseSCache(dscp);
4644 if (code == 0 && !rock.any)
4645 code = CM_ERROR_NOSUCHFILE;
4649 typedef struct smb_renameRock {
4650 cm_scache_t *odscp; /* old dir */
4651 cm_scache_t *ndscp; /* new dir */
4652 cm_user_t *userp; /* user */
4653 cm_req_t *reqp; /* request struct */
4654 smb_vc_t *vcp; /* virtual circuit */
4655 char *maskp; /* pointer to star pattern of old file name */
4656 int flags; /* tilde, casefold, etc */
4657 char *newNamep; /* ptr to the new file's name */
4660 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4663 smb_renameRock_t *rockp;
4668 rockp = (smb_renameRock_t *) vrockp;
4670 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4671 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4672 caseFold |= CM_FLAG_8DOT3;
4674 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4676 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4677 !cm_Is8Dot3(dep->name)) {
4678 cm_Gen8Dot3Name(dep, shortName, NULL);
4679 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4682 code = cm_Rename(rockp->odscp, dep->name,
4683 rockp->ndscp, rockp->newNamep, rockp->userp,
4685 /* if the call worked, stop doing the search now, since we
4686 * really only want to rename one file.
4689 code = CM_ERROR_STOPNOW;
4698 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4701 cm_space_t *spacep = NULL;
4702 smb_renameRock_t rock;
4703 cm_scache_t *oldDscp = NULL;
4704 cm_scache_t *newDscp = NULL;
4705 cm_scache_t *tmpscp= NULL;
4706 cm_scache_t *tmpscp2 = NULL;
4716 userp = smb_GetUser(vcp, inp);
4717 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4719 cm_ReleaseUser(userp);
4720 return CM_ERROR_NOSUCHPATH;
4724 spacep = inp->spacep;
4725 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4728 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4729 * what actually exists is foo/baz. I don't know why the code used to be
4730 * the way it was. 1/29/96
4732 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4734 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4736 * caseFold = CM_FLAG_CASEFOLD;
4738 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4739 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4740 userp, tidPathp, &req, &oldDscp);
4742 cm_ReleaseUser(userp);
4747 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4748 cm_ReleaseSCache(oldDscp);
4749 cm_ReleaseUser(userp);
4750 if ( WANTS_DFS_PATHNAMES(inp) )
4751 return CM_ERROR_PATH_NOT_COVERED;
4753 return CM_ERROR_BADSHARENAME;
4755 #endif /* DFS_SUPPORT */
4757 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4758 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4759 userp, tidPathp, &req, &newDscp);
4762 cm_ReleaseSCache(oldDscp);
4763 cm_ReleaseUser(userp);
4768 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4769 cm_ReleaseSCache(oldDscp);
4770 cm_ReleaseSCache(newDscp);
4771 cm_ReleaseUser(userp);
4772 if ( WANTS_DFS_PATHNAMES(inp) )
4773 return CM_ERROR_PATH_NOT_COVERED;
4775 return CM_ERROR_BADSHARENAME;
4777 #endif /* DFS_SUPPORT */
4780 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4781 * next, get the component names, and lower case them.
4784 /* handle the old name first */
4786 oldLastNamep = oldPathp;
4790 /* and handle the new name, too */
4792 newLastNamep = newPathp;
4796 /* TODO: The old name could be a wildcard. The new name must not be */
4798 /* do the vnode call */
4799 rock.odscp = oldDscp;
4800 rock.ndscp = newDscp;
4804 rock.maskp = oldLastNamep;
4805 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4806 rock.newNamep = newLastNamep;
4808 /* Check if the file already exists; if so return error */
4809 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4810 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4811 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4812 osi_LogSaveString(afsd_logp, newLastNamep));
4814 /* Check if the old and the new names differ only in case. If so return
4815 * success, else return CM_ERROR_EXISTS
4817 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4819 /* This would be a success only if the old file is *as same as* the new file */
4820 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4822 if (tmpscp == tmpscp2)
4825 code = CM_ERROR_EXISTS;
4826 cm_ReleaseSCache(tmpscp2);
4829 code = CM_ERROR_NOSUCHFILE;
4832 /* file exist, do not rename, also fixes move */
4833 osi_Log0(smb_logp, "Can't rename. Target already exists");
4834 code = CM_ERROR_EXISTS;
4838 cm_ReleaseSCache(tmpscp);
4839 cm_ReleaseSCache(newDscp);
4840 cm_ReleaseSCache(oldDscp);
4841 cm_ReleaseUser(userp);
4845 /* Now search the directory for the pattern, and do the appropriate rename when found */
4846 thyper.LowPart = 0; /* search dir from here */
4847 thyper.HighPart = 0;
4849 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4851 if (code == CM_ERROR_STOPNOW)
4854 code = CM_ERROR_NOSUCHFILE;
4856 /* Handle Change Notification */
4858 * Being lazy, not distinguishing between files and dirs in this
4859 * filter, since we'd have to do a lookup.
4861 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4862 if (oldDscp == newDscp) {
4863 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4864 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4865 filter, oldDscp, oldLastNamep,
4866 newLastNamep, TRUE);
4868 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4869 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4870 filter, oldDscp, oldLastNamep,
4872 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4873 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4874 filter, newDscp, newLastNamep,
4879 cm_ReleaseSCache(tmpscp);
4880 cm_ReleaseUser(userp);
4881 cm_ReleaseSCache(oldDscp);
4882 cm_ReleaseSCache(newDscp);
4887 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4890 cm_space_t *spacep = NULL;
4891 cm_scache_t *oldDscp = NULL;
4892 cm_scache_t *newDscp = NULL;
4893 cm_scache_t *tmpscp= NULL;
4894 cm_scache_t *tmpscp2 = NULL;
4895 cm_scache_t *sscp = NULL;
4904 userp = smb_GetUser(vcp, inp);
4906 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4908 cm_ReleaseUser(userp);
4909 return CM_ERROR_NOSUCHPATH;
4914 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4916 spacep = inp->spacep;
4917 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4919 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4920 userp, tidPathp, &req, &oldDscp);
4922 cm_ReleaseUser(userp);
4927 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4928 cm_ReleaseSCache(oldDscp);
4929 cm_ReleaseUser(userp);
4930 if ( WANTS_DFS_PATHNAMES(inp) )
4931 return CM_ERROR_PATH_NOT_COVERED;
4933 return CM_ERROR_BADSHARENAME;
4935 #endif /* DFS_SUPPORT */
4937 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4938 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4939 userp, tidPathp, &req, &newDscp);
4941 cm_ReleaseSCache(oldDscp);
4942 cm_ReleaseUser(userp);
4947 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4948 cm_ReleaseSCache(newDscp);
4949 cm_ReleaseSCache(oldDscp);
4950 cm_ReleaseUser(userp);
4951 if ( WANTS_DFS_PATHNAMES(inp) )
4952 return CM_ERROR_PATH_NOT_COVERED;
4954 return CM_ERROR_BADSHARENAME;
4956 #endif /* DFS_SUPPORT */
4958 /* Now, although we did two lookups for the two directories (because the same
4959 * directory can be referenced through different paths), we only allow hard links
4960 * within the same directory. */
4961 if (oldDscp != newDscp) {
4962 cm_ReleaseSCache(oldDscp);
4963 cm_ReleaseSCache(newDscp);
4964 cm_ReleaseUser(userp);
4965 return CM_ERROR_CROSSDEVLINK;
4968 /* handle the old name first */
4970 oldLastNamep = oldPathp;
4974 /* and handle the new name, too */
4976 newLastNamep = newPathp;
4980 /* now lookup the old name */
4981 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4982 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4984 cm_ReleaseSCache(oldDscp);
4985 cm_ReleaseSCache(newDscp);
4986 cm_ReleaseUser(userp);
4990 /* Check if the file already exists; if so return error */
4991 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4992 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4993 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4994 osi_LogSaveString(afsd_logp, newLastNamep));
4996 /* if the existing link is to the same file, then we return success */
4998 if(sscp == tmpscp) {
5001 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5002 code = CM_ERROR_EXISTS;
5007 cm_ReleaseSCache(tmpscp);
5008 cm_ReleaseSCache(sscp);
5009 cm_ReleaseSCache(newDscp);
5010 cm_ReleaseSCache(oldDscp);
5011 cm_ReleaseUser(userp);
5015 /* now create the hardlink */
5016 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5017 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5018 osi_Log1(smb_logp," Link returns %d", code);
5020 /* Handle Change Notification */
5022 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5023 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5024 smb_NotifyChange(FILE_ACTION_ADDED,
5025 filter, newDscp, newLastNamep,
5030 cm_ReleaseSCache(tmpscp);
5031 cm_ReleaseUser(userp);
5032 cm_ReleaseSCache(sscp);
5033 cm_ReleaseSCache(oldDscp);
5034 cm_ReleaseSCache(newDscp);
5039 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5045 tp = smb_GetSMBData(inp, NULL);
5046 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5047 if (smb_StoreAnsiFilenames)
5048 OemToChar(oldPathp,oldPathp);
5049 newPathp = smb_ParseASCIIBlock(tp, &tp);
5050 if (smb_StoreAnsiFilenames)
5051 OemToChar(newPathp,newPathp);
5053 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5054 osi_LogSaveString(smb_logp, oldPathp),
5055 osi_LogSaveString(smb_logp, newPathp));
5057 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5062 typedef struct smb_rmdirRock {
5066 char *maskp; /* pointer to the star pattern */
5071 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5074 smb_rmdirRock_t *rockp;
5079 rockp = (smb_rmdirRock_t *) vrockp;
5081 matchName = dep->name;
5082 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5083 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5085 match = (strcmp(matchName, rockp->maskp) == 0);
5087 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5088 !cm_Is8Dot3(dep->name)) {
5089 cm_Gen8Dot3Name(dep, shortName, NULL);
5090 matchName = shortName;
5091 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5094 osi_Log1(smb_logp, "Removing directory %s",
5095 osi_LogSaveString(smb_logp, matchName));
5096 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5097 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5098 smb_NotifyChange(FILE_ACTION_REMOVED,
5099 FILE_NOTIFY_CHANGE_DIR_NAME,
5100 dscp, dep->name, NULL, TRUE);
5109 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5117 smb_rmdirRock_t rock;
5126 tp = smb_GetSMBData(inp, NULL);
5127 pathp = smb_ParseASCIIBlock(tp, &tp);
5128 if (smb_StoreAnsiFilenames)
5129 OemToChar(pathp,pathp);
5131 spacep = inp->spacep;
5132 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5134 userp = smb_GetUser(vcp, inp);
5136 caseFold = CM_FLAG_CASEFOLD;
5138 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5140 cm_ReleaseUser(userp);
5141 return CM_ERROR_NOSUCHPATH;
5143 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5144 userp, tidPathp, &req, &dscp);
5147 cm_ReleaseUser(userp);
5152 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5153 cm_ReleaseSCache(dscp);
5154 cm_ReleaseUser(userp);
5155 if ( WANTS_DFS_PATHNAMES(inp) )
5156 return CM_ERROR_PATH_NOT_COVERED;
5158 return CM_ERROR_BADSHARENAME;
5160 #endif /* DFS_SUPPORT */
5162 /* otherwise, scp points to the parent directory. */
5169 rock.maskp = lastNamep;
5170 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5173 thyper.HighPart = 0;
5177 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5178 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5179 if (code == 0 && !rock.any) {
5181 thyper.HighPart = 0;
5182 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5183 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5186 cm_ReleaseUser(userp);
5188 cm_ReleaseSCache(dscp);
5190 if (code == 0 && !rock.any)
5191 code = CM_ERROR_NOSUCHFILE;
5195 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5205 fid = smb_GetSMBParm(inp, 0);
5207 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5209 fid = smb_ChainFID(fid, inp);
5210 fidp = smb_FindFID(vcp, fid, 0);
5211 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5213 smb_ReleaseFID(fidp);
5214 return CM_ERROR_BADFD;
5217 userp = smb_GetUser(vcp, inp);
5219 lock_ObtainMutex(&fidp->mx);
5220 if (fidp->flags & SMB_FID_OPENWRITE)
5221 code = cm_FSync(fidp->scp, userp, &req);
5224 lock_ReleaseMutex(&fidp->mx);
5226 smb_ReleaseFID(fidp);
5228 cm_ReleaseUser(userp);
5233 struct smb_FullNameRock {
5239 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5243 struct smb_FullNameRock *vrockp;
5245 vrockp = (struct smb_FullNameRock *)rockp;
5247 if (!cm_Is8Dot3(dep->name)) {
5248 cm_Gen8Dot3Name(dep, shortName, NULL);
5250 if (cm_stricmp(shortName, vrockp->name) == 0) {
5251 vrockp->fullName = strdup(dep->name);
5252 return CM_ERROR_STOPNOW;
5255 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5256 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5257 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5258 vrockp->fullName = strdup(dep->name);
5259 return CM_ERROR_STOPNOW;
5264 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5265 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5267 struct smb_FullNameRock rock;
5273 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5274 if (code == CM_ERROR_STOPNOW)
5275 *newPathp = rock.fullName;
5277 *newPathp = strdup(pathp);
5280 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5291 fid = smb_GetSMBParm(inp, 0);
5292 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5294 osi_Log1(smb_logp, "SMB close fid %d", fid);
5296 fid = smb_ChainFID(fid, inp);
5297 fidp = smb_FindFID(vcp, fid, 0);
5299 return CM_ERROR_BADFD;
5302 userp = smb_GetUser(vcp, inp);
5304 lock_ObtainMutex(&fidp->mx);
5306 /* Don't jump the gun on an async raw write */
5307 while (fidp->raw_writers) {
5308 lock_ReleaseMutex(&fidp->mx);
5309 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5310 lock_ObtainMutex(&fidp->mx);
5313 fidp->flags |= SMB_FID_DELETE;
5315 /* watch for ioctl closes, and read-only opens */
5316 if (fidp->scp != NULL &&
5317 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5318 == SMB_FID_OPENWRITE) {
5319 if (dosTime != 0 && dosTime != -1) {
5320 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5321 /* This fixes defect 10958 */
5322 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5323 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5325 code = cm_FSync(fidp->scp, userp, &req);
5330 if (fidp->flags & SMB_FID_DELONCLOSE) {
5331 cm_scache_t *dscp = fidp->NTopen_dscp;
5332 char *pathp = fidp->NTopen_pathp;
5335 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5336 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5337 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5338 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5339 smb_NotifyChange(FILE_ACTION_REMOVED,
5340 FILE_NOTIFY_CHANGE_DIR_NAME,
5341 dscp, fullPathp, NULL, TRUE);
5345 code = cm_Unlink(dscp, fullPathp, userp, &req);
5346 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5347 smb_NotifyChange(FILE_ACTION_REMOVED,
5348 FILE_NOTIFY_CHANGE_FILE_NAME,
5349 dscp, fullPathp, NULL, TRUE);
5353 lock_ReleaseMutex(&fidp->mx);
5355 if (fidp->flags & SMB_FID_NTOPEN) {
5356 cm_ReleaseSCache(fidp->NTopen_dscp);
5357 free(fidp->NTopen_pathp);
5359 if (fidp->NTopen_wholepathp)
5360 free(fidp->NTopen_wholepathp);
5362 smb_ReleaseFID(fidp);
5363 cm_ReleaseUser(userp);
5368 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5371 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5372 cm_user_t *userp, long *readp)
5374 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5375 cm_user_t *userp, long *readp, int dosflag)
5382 osi_hyper_t fileLength;
5384 osi_hyper_t lastByte;
5385 osi_hyper_t bufferOffset;
5386 long bufIndex, nbytes;
5396 lock_ObtainMutex(&fidp->mx);
5398 lock_ObtainMutex(&scp->mx);
5400 if (offset.HighPart == 0) {
5401 chunk = offset.LowPart >> cm_logChunkSize;
5402 if (chunk != fidp->curr_chunk) {
5403 fidp->prev_chunk = fidp->curr_chunk;
5404 fidp->curr_chunk = chunk;
5406 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5410 /* start by looking up the file's end */
5411 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5412 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5413 if (code) goto done;
5415 /* now we have the entry locked, look up the length */
5416 fileLength = scp->length;
5418 /* adjust count down so that it won't go past EOF */
5419 thyper.LowPart = count;
5420 thyper.HighPart = 0;
5421 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5423 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5424 /* we'd read past EOF, so just stop at fileLength bytes.
5425 * Start by computing how many bytes remain in the file.
5427 thyper = LargeIntegerSubtract(fileLength, offset);
5429 /* if we are past EOF, read 0 bytes */
5430 if (LargeIntegerLessThanZero(thyper))
5433 count = thyper.LowPart;
5438 /* now, copy the data one buffer at a time,
5439 * until we've filled the request packet
5442 /* if we've copied all the data requested, we're done */
5443 if (count <= 0) break;
5445 /* otherwise, load up a buffer of data */
5446 thyper.HighPart = offset.HighPart;
5447 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5448 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5451 buf_Release(bufferp);
5454 lock_ReleaseMutex(&scp->mx);
5456 lock_ObtainRead(&scp->bufCreateLock);
5457 code = buf_Get(scp, &thyper, &bufferp);
5458 lock_ReleaseRead(&scp->bufCreateLock);
5460 lock_ObtainMutex(&scp->mx);
5461 if (code) goto done;
5462 bufferOffset = thyper;
5464 /* now get the data in the cache */
5466 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5467 CM_SCACHESYNC_NEEDCALLBACK |
5468 CM_SCACHESYNC_READ);
5469 if (code) goto done;
5471 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5473 /* otherwise, load the buffer and try again */
5474 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5478 buf_Release(bufferp);
5482 } /* if (wrong buffer) ... */
5484 /* now we have the right buffer loaded. Copy out the
5485 * data from here to the user's buffer.
5487 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5489 /* and figure out how many bytes we want from this buffer */
5490 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5491 if (nbytes > count) nbytes = count; /* don't go past EOF */
5493 /* now copy the data */
5496 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5499 memcpy(op, bufferp->datap + bufIndex, nbytes);
5501 /* adjust counters, pointers, etc. */
5504 thyper.LowPart = nbytes;
5505 thyper.HighPart = 0;
5506 offset = LargeIntegerAdd(thyper, offset);
5510 lock_ReleaseMutex(&scp->mx);
5511 lock_ReleaseMutex(&fidp->mx);
5513 buf_Release(bufferp);
5515 if (code == 0 && sequential)
5516 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5522 * smb_WriteData -- common code for Write and Raw Write
5525 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5526 cm_user_t *userp, long *writtenp)
5528 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5529 cm_user_t *userp, long *writtenp, int dosflag)
5536 osi_hyper_t fileLength; /* file's length at start of write */
5537 osi_hyper_t minLength; /* don't read past this */
5538 long nbytes; /* # of bytes to transfer this iteration */
5540 osi_hyper_t thyper; /* hyper tmp variable */
5541 osi_hyper_t bufferOffset;
5542 long bufIndex; /* index in buffer where our data is */
5544 osi_hyper_t writeBackOffset;/* offset of region to write back when
5549 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5550 fidp->fid, offsetp->LowPart, count);
5560 lock_ObtainMutex(&fidp->mx);
5562 lock_ObtainMutex(&scp->mx);
5564 /* start by looking up the file's end */
5565 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5566 CM_SCACHESYNC_NEEDCALLBACK
5567 | CM_SCACHESYNC_SETSTATUS
5568 | CM_SCACHESYNC_GETSTATUS);
5572 /* make sure we have a writable FD */
5573 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5574 code = CM_ERROR_BADFDOP;
5578 /* now we have the entry locked, look up the length */
5579 fileLength = scp->length;
5580 minLength = fileLength;
5581 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5582 minLength = scp->serverLength;
5584 /* adjust file length if we extend past EOF */
5585 thyper.LowPart = count;
5586 thyper.HighPart = 0;
5587 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5588 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5589 /* we'd write past EOF, so extend the file */
5590 scp->mask |= CM_SCACHEMASK_LENGTH;
5591 scp->length = thyper;
5592 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5594 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5596 /* now, if the new position (thyper) and the old (offset) are in
5597 * different storeback windows, remember to store back the previous
5598 * storeback window when we're done with the write.
5600 if ((thyper.LowPart & (-cm_chunkSize)) !=
5601 (offset.LowPart & (-cm_chunkSize))) {
5602 /* they're different */
5604 writeBackOffset.HighPart = offset.HighPart;
5605 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5610 /* now, copy the data one buffer at a time, until we've filled the
5613 /* if we've copied all the data requested, we're done */
5617 /* handle over quota or out of space */
5618 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5619 *writtenp = written;
5620 code = CM_ERROR_QUOTA;
5624 /* otherwise, load up a buffer of data */
5625 thyper.HighPart = offset.HighPart;
5626 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5627 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5630 lock_ReleaseMutex(&bufferp->mx);
5631 buf_Release(bufferp);
5634 lock_ReleaseMutex(&scp->mx);
5636 lock_ObtainRead(&scp->bufCreateLock);
5637 code = buf_Get(scp, &thyper, &bufferp);
5638 lock_ReleaseRead(&scp->bufCreateLock);
5640 lock_ObtainMutex(&bufferp->mx);
5641 lock_ObtainMutex(&scp->mx);
5642 if (code) goto done;
5644 bufferOffset = thyper;
5646 /* now get the data in the cache */
5648 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5649 CM_SCACHESYNC_NEEDCALLBACK
5650 | CM_SCACHESYNC_WRITE
5651 | CM_SCACHESYNC_BUFLOCKED);
5655 /* If we're overwriting the entire buffer, or
5656 * if we're writing at or past EOF, mark the
5657 * buffer as current so we don't call
5658 * cm_GetBuffer. This skips the fetch from the
5659 * server in those cases where we're going to
5660 * obliterate all the data in the buffer anyway,
5661 * or in those cases where there is no useful
5662 * data at the server to start with.
5664 * Use minLength instead of scp->length, since
5665 * the latter has already been updated by this
5668 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5669 || LargeIntegerEqualTo(offset, bufferp->offset)
5670 && (count >= cm_data.buf_blockSize
5671 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5672 ConvertLongToLargeInteger(count)),
5674 if (count < cm_data.buf_blockSize
5675 && bufferp->dataVersion == -1)
5676 memset(bufferp->datap, 0,
5677 cm_data.buf_blockSize);
5678 bufferp->dataVersion = scp->dataVersion;
5681 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5683 /* otherwise, load the buffer and try again */
5684 lock_ReleaseMutex(&bufferp->mx);
5685 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5687 lock_ReleaseMutex(&scp->mx);
5688 lock_ObtainMutex(&bufferp->mx);
5689 lock_ObtainMutex(&scp->mx);
5693 lock_ReleaseMutex(&bufferp->mx);
5694 buf_Release(bufferp);
5698 } /* if (wrong buffer) ... */
5700 /* now we have the right buffer loaded. Copy out the
5701 * data from here to the user's buffer.
5703 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5705 /* and figure out how many bytes we want from this buffer */
5706 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5708 nbytes = count; /* don't go past end of request */
5710 /* now copy the data */
5713 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5716 memcpy(bufferp->datap + bufIndex, op, nbytes);
5717 buf_SetDirty(bufferp);
5719 /* and record the last writer */
5720 if (bufferp->userp != userp) {
5723 cm_ReleaseUser(bufferp->userp);
5724 bufferp->userp = userp;
5727 /* adjust counters, pointers, etc. */
5731 thyper.LowPart = nbytes;
5732 thyper.HighPart = 0;
5733 offset = LargeIntegerAdd(thyper, offset);
5737 lock_ReleaseMutex(&scp->mx);
5738 lock_ReleaseMutex(&fidp->mx);
5740 lock_ReleaseMutex(&bufferp->mx);
5741 buf_Release(bufferp);
5744 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5745 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5746 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5747 fidp->NTopen_dscp, fidp->NTopen_pathp,
5751 if (code == 0 && doWriteBack) {
5753 lock_ObtainMutex(&scp->mx);
5754 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5756 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5757 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5759 lock_ReleaseMutex(&scp->mx);
5760 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5761 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5764 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5765 fidp->fid, code, *writtenp);
5769 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5772 long count, written = 0, total_written = 0;
5777 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5779 int inDataBlockCount;
5781 fd = smb_GetSMBParm(inp, 0);
5782 count = smb_GetSMBParm(inp, 1);
5783 offset.HighPart = 0; /* too bad */
5784 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5786 op = smb_GetSMBData(inp, NULL);
5787 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5789 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5790 fd, offset.LowPart, count);
5792 fd = smb_ChainFID(fd, inp);
5793 fidp = smb_FindFID(vcp, fd, 0);
5795 return CM_ERROR_BADFD;
5798 if (fidp->flags & SMB_FID_IOCTL)
5799 return smb_IoctlWrite(fidp, vcp, inp, outp);
5801 userp = smb_GetUser(vcp, inp);
5803 /* special case: 0 bytes transferred means truncate to this position */
5809 truncAttr.mask = CM_ATTRMASK_LENGTH;
5810 truncAttr.length.LowPart = offset.LowPart;
5811 truncAttr.length.HighPart = 0;
5812 lock_ObtainMutex(&fidp->mx);
5813 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5814 lock_ReleaseMutex(&fidp->mx);
5815 smb_SetSMBParm(outp, 0, /* count */ 0);
5816 smb_SetSMBDataLength(outp, 0);
5817 fidp->flags |= SMB_FID_LENGTHSETDONE;
5822 * Work around bug in NT client
5824 * When copying a file, the NT client should first copy the data,
5825 * then copy the last write time. But sometimes the NT client does
5826 * these in the wrong order, so the data copies would inadvertently
5827 * cause the last write time to be overwritten. We try to detect this,
5828 * and don't set client mod time if we think that would go against the
5831 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5832 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5833 fidp->scp->clientModTime = time(NULL);
5837 while ( code == 0 && count > 0 ) {
5839 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5841 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5843 if (code == 0 && written == 0)
5844 code = CM_ERROR_PARTIALWRITE;
5846 offset.LowPart += written;
5848 total_written += written;
5852 /* set the packet data length to 3 bytes for the data block header,
5853 * plus the size of the data.
5855 smb_SetSMBParm(outp, 0, total_written);
5856 smb_SetSMBDataLength(outp, 0);
5859 smb_ReleaseFID(fidp);
5860 cm_ReleaseUser(userp);
5865 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5866 NCB *ncbp, raw_write_cont_t *rwcp)
5879 fd = smb_GetSMBParm(inp, 0);
5880 fidp = smb_FindFID(vcp, fd, 0);
5882 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5883 rwcp->offset.LowPart, rwcp->count);
5885 userp = smb_GetUser(vcp, inp);
5889 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5892 rawBuf = (dos_ptr) rwcp->buf;
5893 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5894 (unsigned char *) rawBuf, userp,
5898 if (rwcp->writeMode & 0x1) { /* synchronous */
5901 smb_FormatResponsePacket(vcp, inp, outp);
5902 op = (smb_t *) outp;
5903 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5904 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5905 smb_SetSMBDataLength(outp, 0);
5906 smb_SendPacket(vcp, outp);
5907 smb_FreePacket(outp);
5909 else { /* asynchronous */
5910 lock_ObtainMutex(&fidp->mx);
5911 fidp->raw_writers--;
5912 if (fidp->raw_writers == 0)
5913 thrd_SetEvent(fidp->raw_write_event);
5914 lock_ReleaseMutex(&fidp->mx);
5917 /* Give back raw buffer */
5918 lock_ObtainMutex(&smb_RawBufLock);
5920 *((char **)rawBuf) = smb_RawBufs;
5922 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5924 smb_RawBufs = rawBuf;
5925 lock_ReleaseMutex(&smb_RawBufLock);
5927 smb_ReleaseFID(fidp);
5928 cm_ReleaseUser(userp);
5931 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5936 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5939 long count, written = 0, total_written = 0;
5946 unsigned short writeMode;
5953 fd = smb_GetSMBParm(inp, 0);
5954 totalCount = smb_GetSMBParm(inp, 1);
5955 count = smb_GetSMBParm(inp, 10);
5956 offset.HighPart = 0; /* too bad */
5957 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5958 writeMode = smb_GetSMBParm(inp, 7);
5960 op = (char *) inp->data;
5961 op += smb_GetSMBParm(inp, 11);
5964 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5965 fd, offset.LowPart, count, writeMode);
5967 fd = smb_ChainFID(fd, inp);
5968 fidp = smb_FindFID(vcp, fd, 0);
5970 return CM_ERROR_BADFD;
5973 userp = smb_GetUser(vcp, inp);
5976 * Work around bug in NT client
5978 * When copying a file, the NT client should first copy the data,
5979 * then copy the last write time. But sometimes the NT client does
5980 * these in the wrong order, so the data copies would inadvertently
5981 * cause the last write time to be overwritten. We try to detect this,
5982 * and don't set client mod time if we think that would go against the
5985 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5986 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5987 fidp->scp->clientModTime = time(NULL);
5991 while ( code == 0 && count > 0 ) {
5993 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5995 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5997 if (code == 0 && written == 0)
5998 code = CM_ERROR_PARTIALWRITE;
6000 offset.LowPart += written;
6002 total_written += written;
6006 /* Get a raw buffer */
6009 lock_ObtainMutex(&smb_RawBufLock);
6011 /* Get a raw buf, from head of list */
6012 rawBuf = smb_RawBufs;
6014 smb_RawBufs = *(char **)smb_RawBufs;
6016 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6020 code = CM_ERROR_USESTD;
6022 lock_ReleaseMutex(&smb_RawBufLock);
6025 /* Don't allow a premature Close */
6026 if (code == 0 && (writeMode & 1) == 0) {
6027 lock_ObtainMutex(&fidp->mx);
6028 fidp->raw_writers++;
6029 thrd_ResetEvent(fidp->raw_write_event);
6030 lock_ReleaseMutex(&fidp->mx);
6033 smb_ReleaseFID(fidp);
6034 cm_ReleaseUser(userp);
6037 smb_SetSMBParm(outp, 0, total_written);
6038 smb_SetSMBDataLength(outp, 0);
6039 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6046 rwcp->offset.HighPart = 0;
6047 rwcp->offset.LowPart = offset.LowPart + count;
6048 rwcp->count = totalCount - count;
6049 rwcp->writeMode = writeMode;
6050 rwcp->alreadyWritten = total_written;
6052 /* set the packet data length to 3 bytes for the data block header,
6053 * plus the size of the data.
6055 smb_SetSMBParm(outp, 0, 0xffff);
6056 smb_SetSMBDataLength(outp, 0);
6061 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6064 long count, finalCount;
6071 fd = smb_GetSMBParm(inp, 0);
6072 count = smb_GetSMBParm(inp, 1);
6073 offset.HighPart = 0; /* too bad */
6074 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6076 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6077 fd, offset.LowPart, count);
6079 fd = smb_ChainFID(fd, inp);
6080 fidp = smb_FindFID(vcp, fd, 0);
6082 return CM_ERROR_BADFD;
6085 if (fidp->flags & SMB_FID_IOCTL) {
6086 return smb_IoctlRead(fidp, vcp, inp, outp);
6089 userp = smb_GetUser(vcp, inp);
6091 /* remember this for final results */
6092 smb_SetSMBParm(outp, 0, count);
6093 smb_SetSMBParm(outp, 1, 0);
6094 smb_SetSMBParm(outp, 2, 0);
6095 smb_SetSMBParm(outp, 3, 0);
6096 smb_SetSMBParm(outp, 4, 0);
6098 /* set the packet data length to 3 bytes for the data block header,
6099 * plus the size of the data.
6101 smb_SetSMBDataLength(outp, count+3);
6103 /* get op ptr after putting in the parms, since otherwise we don't
6104 * know where the data really is.
6106 op = smb_GetSMBData(outp, NULL);
6108 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6109 *op++ = 1; /* data block marker */
6110 *op++ = (unsigned char) (count & 0xff);
6111 *op++ = (unsigned char) ((count >> 8) & 0xff);
6114 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6116 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6119 /* fix some things up */
6120 smb_SetSMBParm(outp, 0, finalCount);
6121 smb_SetSMBDataLength(outp, finalCount+3);
6123 smb_ReleaseFID(fidp);
6125 cm_ReleaseUser(userp);
6129 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6136 cm_scache_t *dscp; /* dir we're dealing with */
6137 cm_scache_t *scp; /* file we're creating */
6139 int initialModeBits;
6149 /* compute initial mode bits based on read-only flag in attributes */
6150 initialModeBits = 0777;
6152 tp = smb_GetSMBData(inp, NULL);
6153 pathp = smb_ParseASCIIBlock(tp, &tp);
6154 if (smb_StoreAnsiFilenames)
6155 OemToChar(pathp,pathp);
6157 if (strcmp(pathp, "\\") == 0)
6158 return CM_ERROR_EXISTS;
6160 spacep = inp->spacep;
6161 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6163 userp = smb_GetUser(vcp, inp);
6165 caseFold = CM_FLAG_CASEFOLD;
6167 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6169 cm_ReleaseUser(userp);
6170 return CM_ERROR_NOSUCHPATH;
6173 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6174 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6175 userp, tidPathp, &req, &dscp);
6178 cm_ReleaseUser(userp);
6183 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6184 cm_ReleaseSCache(dscp);
6185 cm_ReleaseUser(userp);
6186 if ( WANTS_DFS_PATHNAMES(inp) )
6187 return CM_ERROR_PATH_NOT_COVERED;
6189 return CM_ERROR_BADSHARENAME;
6191 #endif /* DFS_SUPPORT */
6193 /* otherwise, scp points to the parent directory. Do a lookup, and
6194 * fail if we find it. Otherwise, we do the create.
6200 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6201 if (scp) cm_ReleaseSCache(scp);
6202 if (code != CM_ERROR_NOSUCHFILE) {
6203 if (code == 0) code = CM_ERROR_EXISTS;
6204 cm_ReleaseSCache(dscp);
6205 cm_ReleaseUser(userp);
6209 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6210 setAttr.clientModTime = time(NULL);
6211 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6212 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6213 smb_NotifyChange(FILE_ACTION_ADDED,
6214 FILE_NOTIFY_CHANGE_DIR_NAME,
6215 dscp, lastNamep, NULL, TRUE);
6217 /* we don't need this any longer */
6218 cm_ReleaseSCache(dscp);
6221 /* something went wrong creating or truncating the file */
6222 cm_ReleaseUser(userp);
6226 /* otherwise we succeeded */
6227 smb_SetSMBDataLength(outp, 0);
6228 cm_ReleaseUser(userp);
6233 BOOL smb_IsLegalFilename(char *filename)
6236 * Find the longest substring of filename that does not contain
6237 * any of the chars in illegalChars. If that substring is less
6238 * than the length of the whole string, then one or more of the
6239 * illegal chars is in filename.
6241 if (strcspn(filename, illegalChars) < strlen(filename))
6247 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6255 cm_scache_t *dscp; /* dir we're dealing with */
6256 cm_scache_t *scp; /* file we're creating */
6258 int initialModeBits;
6270 excl = (inp->inCom == 0x03)? 0 : 1;
6272 attributes = smb_GetSMBParm(inp, 0);
6273 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6275 /* compute initial mode bits based on read-only flag in attributes */
6276 initialModeBits = 0666;
6277 if (attributes & 1) initialModeBits &= ~0222;
6279 tp = smb_GetSMBData(inp, NULL);
6280 pathp = smb_ParseASCIIBlock(tp, &tp);
6281 if (smb_StoreAnsiFilenames)
6282 OemToChar(pathp,pathp);
6284 spacep = inp->spacep;
6285 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6287 userp = smb_GetUser(vcp, inp);
6289 caseFold = CM_FLAG_CASEFOLD;
6291 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6293 cm_ReleaseUser(userp);
6294 return CM_ERROR_NOSUCHPATH;
6296 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6297 userp, tidPathp, &req, &dscp);
6300 cm_ReleaseUser(userp);
6305 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6306 cm_ReleaseSCache(dscp);
6307 cm_ReleaseUser(userp);
6308 if ( WANTS_DFS_PATHNAMES(inp) )
6309 return CM_ERROR_PATH_NOT_COVERED;
6311 return CM_ERROR_BADSHARENAME;
6313 #endif /* DFS_SUPPORT */
6315 /* otherwise, scp points to the parent directory. Do a lookup, and
6316 * truncate the file if we find it, otherwise we create the file.
6323 if (!smb_IsLegalFilename(lastNamep))
6324 return CM_ERROR_BADNTFILENAME;
6326 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6327 #ifdef DEBUG_VERBOSE
6330 hexp = osi_HexifyString( lastNamep );
6331 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6336 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6337 if (code && code != CM_ERROR_NOSUCHFILE) {
6338 cm_ReleaseSCache(dscp);
6339 cm_ReleaseUser(userp);
6343 /* if we get here, if code is 0, the file exists and is represented by
6344 * scp. Otherwise, we have to create it.
6348 /* oops, file shouldn't be there */
6349 cm_ReleaseSCache(dscp);
6350 cm_ReleaseSCache(scp);
6351 cm_ReleaseUser(userp);
6352 return CM_ERROR_EXISTS;
6355 setAttr.mask = CM_ATTRMASK_LENGTH;
6356 setAttr.length.LowPart = 0;
6357 setAttr.length.HighPart = 0;
6358 code = cm_SetAttr(scp, &setAttr, userp, &req);
6361 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6362 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6363 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6365 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6366 smb_NotifyChange(FILE_ACTION_ADDED,
6367 FILE_NOTIFY_CHANGE_FILE_NAME,
6368 dscp, lastNamep, NULL, TRUE);
6369 if (!excl && code == CM_ERROR_EXISTS) {
6370 /* not an exclusive create, and someone else tried
6371 * creating it already, then we open it anyway. We
6372 * don't bother retrying after this, since if this next
6373 * fails, that means that the file was deleted after
6374 * we started this call.
6376 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6379 setAttr.mask = CM_ATTRMASK_LENGTH;
6380 setAttr.length.LowPart = 0;
6381 setAttr.length.HighPart = 0;
6382 code = cm_SetAttr(scp, &setAttr, userp, &req);
6387 /* we don't need this any longer */
6388 cm_ReleaseSCache(dscp);
6391 /* something went wrong creating or truncating the file */
6392 if (scp) cm_ReleaseSCache(scp);
6393 cm_ReleaseUser(userp);
6397 /* make sure we only open files */
6398 if (scp->fileType != CM_SCACHETYPE_FILE) {
6399 cm_ReleaseSCache(scp);
6400 cm_ReleaseUser(userp);
6401 return CM_ERROR_ISDIR;
6404 /* now all we have to do is open the file itself */
6405 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6408 /* save a pointer to the vnode */
6411 /* always create it open for read/write */
6412 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6414 smb_ReleaseFID(fidp);
6416 smb_SetSMBParm(outp, 0, fidp->fid);
6417 smb_SetSMBDataLength(outp, 0);
6419 cm_Open(scp, 0, userp);
6421 cm_ReleaseUser(userp);
6422 /* leave scp held since we put it in fidp->scp */
6426 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6439 fd = smb_GetSMBParm(inp, 0);
6440 whence = smb_GetSMBParm(inp, 1);
6441 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6443 /* try to find the file descriptor */
6444 fd = smb_ChainFID(fd, inp);
6445 fidp = smb_FindFID(vcp, fd, 0);
6446 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6447 return CM_ERROR_BADFD;
6450 userp = smb_GetUser(vcp, inp);
6452 lock_ObtainMutex(&fidp->mx);
6454 lock_ObtainMutex(&scp->mx);
6455 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6456 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6459 /* offset from current offset */
6460 offset += fidp->offset;
6462 else if (whence == 2) {
6463 /* offset from current EOF */
6464 offset += scp->length.LowPart;
6466 fidp->offset = offset;
6467 smb_SetSMBParm(outp, 0, offset & 0xffff);
6468 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6469 smb_SetSMBDataLength(outp, 0);
6471 lock_ReleaseMutex(&scp->mx);
6472 lock_ReleaseMutex(&fidp->mx);
6473 smb_ReleaseFID(fidp);
6474 cm_ReleaseUser(userp);
6478 /* dispatch all of the requests received in a packet. Due to chaining, this may
6479 * be more than one request.
6481 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6482 NCB *ncbp, raw_write_cont_t *rwcp)
6486 unsigned long code = 0;
6487 unsigned char *outWctp;
6488 int nparms; /* # of bytes of parameters */
6490 int nbytes; /* bytes of data, excluding count */
6493 unsigned short errCode;
6494 unsigned long NTStatus;
6496 unsigned char errClass;
6497 unsigned int oldGen;
6498 DWORD oldTime, newTime;
6500 /* get easy pointer to the data */
6501 smbp = (smb_t *) inp->data;
6503 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6504 /* setup the basic parms for the initial request in the packet */
6505 inp->inCom = smbp->com;
6506 inp->wctp = &smbp->wct;
6508 inp->ncb_length = ncbp->ncb_length;
6513 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6514 /* log it and discard it */
6519 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6520 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6522 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6523 1, ncbp->ncb_length, ptbuf, inp);
6524 DeregisterEventSource(h);
6526 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6531 /* We are an ongoing op */
6532 thrd_Increment(&ongoingOps);
6534 /* set up response packet for receiving output */
6535 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6536 smb_FormatResponsePacket(vcp, inp, outp);
6537 outWctp = outp->wctp;
6539 /* Remember session generation number and time */
6540 oldGen = sessionGen;
6541 oldTime = GetCurrentTime();
6543 while (inp->inCom != 0xff) {
6544 dp = &smb_dispatchTable[inp->inCom];
6546 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6547 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6548 code = outp->resumeCode;
6552 /* process each request in the packet; inCom, wctp and inCount
6553 * are already set up.
6555 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6558 /* now do the dispatch */
6559 /* start by formatting the response record a little, as a default */
6560 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6562 outWctp[1] = 0xff; /* no operation */
6563 outWctp[2] = 0; /* padding */
6568 /* not a chained request, this is a more reasonable default */
6569 outWctp[0] = 0; /* wct of zero */
6570 outWctp[1] = 0; /* and bcc (word) of zero */
6574 /* once set, stays set. Doesn't matter, since we never chain
6575 * "no response" calls.
6577 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6581 /* we have a recognized operation */
6583 if (inp->inCom == 0x1d)
6585 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6588 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%x lana %d lsn %d",(int)vcp,vcp->lana,vcp->lsn);
6589 osi_Log4(smb_logp,"Dispatch %s vcp 0x%x lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6590 code = (*(dp->procp)) (vcp, inp, outp);
6591 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",(code==0)?0:code-CM_ERROR_BASE);
6592 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);
6594 if ( code == CM_ERROR_BADSMB ||
6595 code == CM_ERROR_BADOP )
6597 #endif /* LOG_PACKET */
6600 if (oldGen != sessionGen) {
6605 newTime = GetCurrentTime();
6606 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6607 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6608 newTime - oldTime, ncbp->ncb_length);
6610 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6611 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6612 DeregisterEventSource(h);
6614 osi_Log1(smb_logp, "Pkt straddled session startup, "
6615 "ncb length %d", ncbp->ncb_length);
6619 /* bad opcode, fail the request, after displaying it */
6620 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6623 #endif /* LOG_PACKET */
6627 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6628 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6629 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6630 if (code == IDCANCEL)
6634 code = CM_ERROR_BADOP;
6637 /* catastrophic failure: log as much as possible */
6638 if (code == CM_ERROR_BADSMB) {
6645 "Invalid SMB, ncb_length %d",
6648 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6649 sprintf(s, "Invalid SMB message, length %d",
6652 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6653 1, ncbp->ncb_length, ptbuf, smbp);
6654 DeregisterEventSource(h);
6657 #endif /* LOG_PACKET */
6659 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6662 code = CM_ERROR_INVAL;
6665 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6666 thrd_Decrement(&ongoingOps);
6671 /* now, if we failed, turn the current response into an empty
6672 * one, and fill in the response packet's error code.
6675 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6676 smb_MapNTError(code, &NTStatus);
6677 outWctp = outp->wctp;
6678 smbp = (smb_t *) &outp->data;
6679 if (code != CM_ERROR_PARTIALWRITE
6680 && code != CM_ERROR_BUFFERTOOSMALL
6681 && code != CM_ERROR_GSSCONTINUE) {
6682 /* nuke wct and bcc. For a partial
6683 * write or an in-process authentication handshake,
6684 * assume they're OK.
6690 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6691 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6692 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6693 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6694 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6698 smb_MapCoreError(code, vcp, &errCode, &errClass);
6699 outWctp = outp->wctp;
6700 smbp = (smb_t *) &outp->data;
6701 if (code != CM_ERROR_PARTIALWRITE) {
6702 /* nuke wct and bcc. For a partial
6703 * write, assume they're OK.
6709 smbp->errLow = (unsigned char) (errCode & 0xff);
6710 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6711 smbp->rcls = errClass;
6714 } /* error occurred */
6716 /* if we're here, we've finished one request. Look to see if
6717 * this is a chained opcode. If it is, setup things to process
6718 * the chained request, and setup the output buffer to hold the
6719 * chained response. Start by finding the next input record.
6721 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6722 break; /* not a chained req */
6723 tp = inp->wctp; /* points to start of last request */
6724 /* in a chained request, the first two
6725 * parm fields are required, and are
6726 * AndXCommand/AndXReserved and
6728 if (tp[0] < 2) break;
6729 if (tp[1] == 0xff) break; /* no more chained opcodes */
6731 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6734 /* and now append the next output request to the end of this
6735 * last request. Begin by finding out where the last response
6736 * ends, since that's where we'll put our new response.
6738 outWctp = outp->wctp; /* ptr to out parameters */
6739 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6740 nparms = outWctp[0] << 1;
6741 tp = outWctp + nparms + 1; /* now points to bcc field */
6742 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6743 tp += 2 /* for the count itself */ + nbytes;
6744 /* tp now points to the new output record; go back and patch the
6745 * second parameter (off2) to point to the new record.
6747 temp = (unsigned int)tp - ((unsigned int) outp->data);
6748 outWctp[3] = (unsigned char) (temp & 0xff);
6749 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6750 outWctp[2] = 0; /* padding */
6751 outWctp[1] = inp->inCom; /* next opcode */
6753 /* finally, setup for the next iteration */
6756 } /* while loop over all requests in the packet */
6758 /* done logging out, turn off logging-out flag */
6759 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6760 vcp->justLoggedOut = NULL;
6763 free(loggedOutName);
6764 loggedOutName = NULL;
6765 smb_ReleaseUID(loggedOutUserp);
6766 loggedOutUserp = NULL;
6770 /* now send the output packet, and return */
6772 smb_SendPacket(vcp, outp);
6773 thrd_Decrement(&ongoingOps);
6775 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6776 if (active_vcp != vcp) {
6778 smb_ReleaseVC(active_vcp);
6780 "Replacing active_vcp %x with %x", active_vcp, vcp);
6785 last_msg_time = GetCurrentTime();
6786 } else if (active_vcp == vcp) {
6787 smb_ReleaseVC(active_vcp);
6795 /* Wait for Netbios() calls to return, and make the results available to server
6796 * threads. Note that server threads can't wait on the NCBevents array
6797 * themselves, because NCB events are manual-reset, and the servers would race
6798 * each other to reset them.
6800 void smb_ClientWaiter(void *parmp)
6805 while (smbShutdownFlag == 0) {
6806 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6808 if (code == WAIT_OBJECT_0)
6811 /* error checking */
6812 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6814 int abandonIdx = code - WAIT_ABANDONED_0;
6815 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6818 if (code == WAIT_IO_COMPLETION)
6820 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6824 if (code == WAIT_TIMEOUT)
6826 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6829 if (code == WAIT_FAILED)
6831 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6834 idx = code - WAIT_OBJECT_0;
6836 /* check idx range! */
6837 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6839 /* this is fatal - log as much as possible */
6840 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6844 thrd_ResetEvent(NCBevents[idx]);
6845 thrd_SetEvent(NCBreturns[0][idx]);
6851 * Try to have one NCBRECV request waiting for every live session. Not more
6852 * than one, because if there is more than one, it's hard to handle Write Raw.
6854 void smb_ServerWaiter(void *parmp)
6857 int idx_session, idx_NCB;
6863 while (smbShutdownFlag == 0) {
6865 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6867 if (code == WAIT_OBJECT_0)
6870 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6872 int abandonIdx = code - WAIT_ABANDONED_0;
6873 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6876 if (code == WAIT_IO_COMPLETION)
6878 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6882 if (code == WAIT_TIMEOUT)
6884 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6887 if (code == WAIT_FAILED)
6889 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6892 idx_session = code - WAIT_OBJECT_0;
6894 /* check idx range! */
6895 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6897 /* this is fatal - log as much as possible */
6898 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6904 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6906 if (code == WAIT_OBJECT_0) {
6907 if (smbShutdownFlag == 1)
6913 /* error checking */
6914 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6916 int abandonIdx = code - WAIT_ABANDONED_0;
6917 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6920 if (code == WAIT_IO_COMPLETION)
6922 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6926 if (code == WAIT_TIMEOUT)
6928 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6931 if (code == WAIT_FAILED)
6933 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6936 idx_NCB = code - WAIT_OBJECT_0;
6938 /* check idx range! */
6939 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6941 /* this is fatal - log as much as possible */
6942 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6946 /* Link them together */
6947 NCBsessions[idx_NCB] = idx_session;
6950 ncbp = NCBs[idx_NCB];
6951 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6952 ncbp->ncb_command = NCBRECV | ASYNCH;
6953 ncbp->ncb_lana_num = lanas[idx_session];
6955 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6956 ncbp->ncb_event = NCBevents[idx_NCB];
6957 ncbp->ncb_length = SMB_PACKETSIZE;
6960 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6961 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6962 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6963 ncbp->ncb_length = SMB_PACKETSIZE;
6964 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6965 Netbios(ncbp, dos_ncb);
6971 * The top level loop for handling SMB request messages. Each server thread
6972 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6973 * NCB and buffer for the incoming request are loaned to us.
6975 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6976 * to immediately send a request for the rest of the data. This must come
6977 * before any other traffic for that session, so we delay setting the session
6978 * event until that data has come in.
6980 void smb_Server(VOID *parmp)
6982 int myIdx = (int) parmp;
6986 smb_packet_t *outbufp;
6988 int idx_NCB, idx_session;
6990 smb_vc_t *vcp = NULL;
6996 rx_StartClientThread();
6999 outbufp = GetPacket();
7000 outbufp->ncbp = outncbp;
7003 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7006 /* terminate silently if shutdown flag is set */
7007 if (code == WAIT_OBJECT_0) {
7008 if (smbShutdownFlag == 1) {
7009 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7015 /* error checking */
7016 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7018 int abandonIdx = code - WAIT_ABANDONED_0;
7019 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7022 if (code == WAIT_IO_COMPLETION)
7024 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7028 if (code == WAIT_TIMEOUT)
7030 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7033 if (code == WAIT_FAILED)
7035 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7038 idx_NCB = code - WAIT_OBJECT_0;
7040 /* check idx range! */
7041 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7043 /* this is fatal - log as much as possible */
7044 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7048 ncbp = NCBs[idx_NCB];
7050 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7052 idx_session = NCBsessions[idx_NCB];
7053 rc = ncbp->ncb_retcode;
7055 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7058 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7061 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7064 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7067 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7070 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7073 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7076 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7079 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7082 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7085 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7088 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7091 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7094 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7097 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7100 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7103 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7106 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7109 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7112 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7115 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7118 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7121 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7124 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7127 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7130 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7133 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7136 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7139 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7142 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7145 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7148 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7151 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7154 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7157 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7160 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7163 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7166 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7169 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7179 /* Can this happen? Or is it just my UNIX paranoia? */
7180 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7185 /* Client closed session */
7186 dead_sessions[idx_session] = TRUE;
7189 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7190 /* Should also release vcp. [done] 2004-05-11 jaltman
7192 * sanity check that all TID's are gone.
7194 * TODO: check if we could use LSNs[idx_session] instead,
7195 * also cleanup after dead vcp
7198 if (dead_vcp == vcp)
7199 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7200 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7201 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7205 smb_ReleaseVC(dead_vcp);
7207 "Previous dead_vcp %x", dead_vcp);
7210 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7212 if (vcp->justLoggedOut) {
7214 loggedOutTime = vcp->logoffTime;
7215 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7216 loggedOutUserp = vcp->justLoggedOut;
7217 lock_ObtainWrite(&smb_rctLock);
7218 loggedOutUserp->refCount++;
7219 lock_ReleaseWrite(&smb_rctLock);
7225 /* Treat as transient error */
7232 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7233 sprintf(s, "SMB message incomplete, length %d",
7236 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7238 ncbp->ncb_length, ptbuf,
7240 DeregisterEventSource(h);
7243 "dispatch smb recv failed, message incomplete, ncb_length %d",
7246 "SMB message incomplete, "
7247 "length %d", ncbp->ncb_length);
7250 * We used to discard the packet.
7251 * Instead, try handling it normally.
7259 /* A weird error code. Log it, sleep, and
7261 if (vcp && vcp->errorCount++ > 3) {
7262 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7263 dead_sessions[idx_session] = TRUE;
7267 thrd_SetEvent(SessionEvents[idx_session]);
7272 /* Success, so now dispatch on all the data in the packet */
7274 smb_concurrentCalls++;
7275 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7276 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7280 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7282 * If at this point vcp is NULL (implies that packet was invalid)
7283 * then we are in big trouble. This means either :
7284 * a) we have the wrong NCB.
7285 * b) Netbios screwed up the call.
7286 * Obviously this implies that
7287 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7288 * lanas[idx_session] != ncbp->ncb_lana_num )
7289 * Either way, we can't do anything with this packet.
7290 * Log, sleep and resume.
7299 "LSNs[idx_session]=[%d],"
7300 "lanas[idx_session]=[%d],"
7301 "ncbp->ncb_lsn=[%d],"
7302 "ncbp->ncb_lana_num=[%d]",
7306 ncbp->ncb_lana_num);
7310 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7312 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7313 DeregisterEventSource(h);
7316 /* Also log in the trace log. */
7317 osi_Log4(smb_logp, "Server: BAD VCP!"
7318 "LSNs[idx_session]=[%d],"
7319 "lanas[idx_session]=[%d],"
7320 "ncbp->ncb_lsn=[%d],"
7321 "ncbp->ncb_lana_num=[%d]",
7325 ncbp->ncb_lana_num);
7327 /* thrd_Sleep(1000); Don't bother sleeping */
7328 thrd_SetEvent(SessionEvents[idx_session]);
7329 smb_concurrentCalls--;
7334 vcp->errorCount = 0;
7335 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7337 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7338 /* copy whole packet to virtual memory */
7339 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7341 bufp->dos_pkt / 16, bufp);*/
7343 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7345 smbp = (smb_t *)bufp->data;
7348 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7352 if (smbp->com == 0x1d) {
7353 /* Special handling for Write Raw */
7354 raw_write_cont_t rwc;
7355 EVENT_HANDLE rwevent;
7356 char eventName[MAX_PATH];
7358 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7359 if (rwc.code == 0) {
7360 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7361 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7362 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7363 ncbp->ncb_command = NCBRECV | ASYNCH;
7364 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7365 ncbp->ncb_lana_num = vcp->lana;
7366 ncbp->ncb_buffer = rwc.buf;
7367 ncbp->ncb_length = 65535;
7368 ncbp->ncb_event = rwevent;
7372 Netbios(ncbp, dos_ncb);
7374 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7375 thrd_CloseHandle(rwevent);
7377 thrd_SetEvent(SessionEvents[idx_session]);
7379 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7381 else if (smbp->com == 0xa0) {
7383 * Serialize the handling for NT Transact
7386 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7387 thrd_SetEvent(SessionEvents[idx_session]);
7389 thrd_SetEvent(SessionEvents[idx_session]);
7390 /* TODO: what else needs to be serialized? */
7391 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7393 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7395 __except( smb_ServerExceptionFilter() ) {
7399 smb_concurrentCalls--;
7402 thrd_SetEvent(NCBavails[idx_NCB]);
7409 * Exception filter for the server threads. If an exception occurs in the
7410 * dispatch routines, which is where exceptions are most common, then do a
7411 * force trace and give control to upstream exception handlers. Useful for
7414 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7415 DWORD smb_ServerExceptionFilter(void) {
7416 /* While this is not the best time to do a trace, if it succeeds, then
7417 * we have a trace (assuming tracing was enabled). Otherwise, this should
7418 * throw a second exception.
7423 ptbuf[0] = "Unhandled exception forcing trace";
7425 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7427 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7428 DeregisterEventSource(h);
7431 afsd_ForceTrace(TRUE);
7432 buf_ForceTrace(TRUE);
7433 return EXCEPTION_CONTINUE_SEARCH;
7438 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7439 * If the number of server threads is M, and the number of live sessions is
7440 * N, then the number of NCB's in use at any time either waiting for, or
7441 * holding, received messages is M + N, so that is how many NCB's get created.
7443 void InitNCBslot(int idx)
7445 struct smb_packet *bufp;
7446 EVENT_HANDLE retHandle;
7448 char eventName[MAX_PATH];
7450 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7452 NCBs[idx] = GetNCB();
7453 sprintf(eventName,"NCBavails[%d]", idx);
7454 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7455 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7456 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7458 sprintf(eventName,"NCBevents[%d]", idx);
7459 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7460 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7461 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7463 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7464 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7465 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7466 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7467 for (i=0; i<smb_NumServerThreads; i++)
7468 NCBreturns[i][idx] = retHandle;
7470 bufp->spacep = cm_GetSpace();
7474 /* listen for new connections */
7475 void smb_Listener(void *parmp)
7483 char rname[NCBNAMSZ+1];
7484 char cname[MAX_COMPUTERNAME_LENGTH+1];
7485 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7490 int lana = (int) parmp;
7494 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7497 /* retrieve computer name */
7498 GetComputerName(cname, &cnamelen);
7502 memset(ncbp, 0, sizeof(NCB));
7505 ncbp->ncb_command = NCBLISTEN;
7506 ncbp->ncb_rto = 0; /* No receive timeout */
7507 ncbp->ncb_sto = 0; /* No send timeout */
7509 /* pad out with spaces instead of null termination */
7510 len = strlen(smb_localNamep);
7511 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7512 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7514 strcpy(ncbp->ncb_callname, "*");
7515 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7517 ncbp->ncb_lana_num = lana;
7520 code = Netbios(ncbp);
7522 code = Netbios(ncbp, dos_ncb);
7531 /* terminate silently if shutdown flag is set */
7532 if (smbShutdownFlag == 1) {
7541 "NCBLISTEN lana=%d failed with code %d",
7542 ncbp->ncb_lana_num, code);
7544 "Client exiting due to network failure. Please restart client.\n");
7548 "Client exiting due to network failure. Please restart client.\n"
7549 "NCBLISTEN lana=%d failed with code %d",
7550 ncbp->ncb_lana_num, code);
7552 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7553 MB_OK|MB_SERVICE_NOTIFICATION);
7554 osi_assert(tbuffer);
7557 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7558 ncbp->ncb_lana_num, code);
7559 fprintf(stderr, "\nClient exiting due to network failure "
7560 "(possibly due to power-saving mode)\n");
7561 fprintf(stderr, "Please restart client.\n");
7562 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7566 /* check for remote conns */
7567 /* first get remote name and insert null terminator */
7568 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7569 for (i=NCBNAMSZ; i>0; i--) {
7570 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7576 /* compare with local name */
7578 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7579 flags |= SMB_VCFLAG_REMOTECONN;
7581 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7583 lock_ObtainMutex(&smb_ListenerLock);
7585 /* New generation */
7588 /* Log session startup */
7590 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7592 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7593 #endif /* NOTSERVICE */
7594 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7595 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7597 if (reportSessionStartups) {
7603 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7604 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7606 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7608 DeregisterEventSource(h);
7611 fprintf(stderr, "%s: New session %d starting from host %s\n",
7612 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7616 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7617 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7620 /* now ncbp->ncb_lsn is the connection ID */
7621 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7622 vcp->flags |= flags;
7623 strcpy(vcp->rname, rname);
7625 /* Allocate slot in session arrays */
7626 /* Re-use dead session if possible, otherwise add one more */
7627 /* But don't look at session[0], it is reserved */
7628 for (i = 1; i < numSessions; i++) {
7629 if (dead_sessions[i]) {
7630 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7631 dead_sessions[i] = FALSE;
7636 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7637 unsigned long code = CM_ERROR_ALLBUSY;
7638 smb_packet_t * outp = GetPacket();
7639 unsigned char *outWctp;
7644 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7645 unsigned long NTStatus;
7646 smb_MapNTError(code, &NTStatus);
7647 outWctp = outp->wctp;
7648 smbp = (smb_t *) &outp->data;
7652 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7653 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7654 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7655 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7656 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7658 unsigned short errCode;
7659 unsigned char errClass;
7660 smb_MapCoreError(code, vcp, &errCode, &errClass);
7661 outWctp = outp->wctp;
7662 smbp = (smb_t *) &outp->data;
7666 smbp->errLow = (unsigned char) (errCode & 0xff);
7667 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7668 smbp->rcls = errClass;
7670 smb_SendPacket(vcp, outp);
7671 smb_FreePacket(outp);
7673 /* assert that we do not exceed the maximum number of sessions or NCBs.
7674 * we should probably want to wait for a session to be freed in case
7677 osi_assert(i < Sessionmax - 1);
7678 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7680 LSNs[i] = ncbp->ncb_lsn;
7681 lanas[i] = ncbp->ncb_lana_num;
7683 if (i == numSessions) {
7684 /* Add new NCB for new session */
7685 char eventName[MAX_PATH];
7687 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7689 InitNCBslot(numNCBs);
7691 thrd_SetEvent(NCBavails[0]);
7692 thrd_SetEvent(NCBevents[0]);
7693 for (j = 0; j < smb_NumServerThreads; j++)
7694 thrd_SetEvent(NCBreturns[j][0]);
7695 /* Also add new session event */
7696 sprintf(eventName, "SessionEvents[%d]", i);
7697 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7698 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7699 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7701 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7702 thrd_SetEvent(SessionEvents[0]);
7704 thrd_SetEvent(SessionEvents[i]);
7711 lock_ReleaseMutex(&smb_ListenerLock);
7712 } /* dispatch while loop */
7715 /* initialize Netbios */
7716 void smb_NetbiosInit()
7722 int i, lana, code, l;
7724 int delname_tried=0;
7727 OSVERSIONINFO Version;
7729 /* Get the version of Windows */
7730 memset(&Version, 0x00, sizeof(Version));
7731 Version.dwOSVersionInfoSize = sizeof(Version);
7732 GetVersionEx(&Version);
7734 /* setup the NCB system */
7737 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7741 if (smb_LANadapter == -1) {
7742 ncbp->ncb_command = NCBENUM;
7743 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7744 ncbp->ncb_length = sizeof(lana_list);
7745 code = Netbios(ncbp);
7747 osi_Log1(smb_logp, "Netbios NCBENUM error code %d", code);
7748 osi_panic(s, __FILE__, __LINE__);
7752 lana_list.length = 1;
7753 lana_list.lana[0] = smb_LANadapter;
7756 for (i = 0; i < lana_list.length; i++) {
7757 /* reset the adaptor: in Win32, this is required for every process, and
7758 * acts as an init call, not as a real hardware reset.
7760 ncbp->ncb_command = NCBRESET;
7761 ncbp->ncb_callname[0] = 100;
7762 ncbp->ncb_callname[2] = 100;
7763 ncbp->ncb_lana_num = lana_list.lana[i];
7764 code = Netbios(ncbp);
7766 code = ncbp->ncb_retcode;
7768 osi_Log2(smb_logp, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7769 lana_list.lana[i] = 255; /* invalid lana */
7771 osi_Log1(smb_logp, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7775 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7776 we will just fake the LANA list */
7777 if (smb_LANadapter == -1) {
7778 for (i = 0; i < 8; i++)
7779 lana_list.lana[i] = i;
7780 lana_list.length = 8;
7783 lana_list.length = 1;
7784 lana_list.lana[0] = smb_LANadapter;
7788 /* and declare our name so we can receive connections */
7789 memset(ncbp, 0, sizeof(*ncbp));
7790 len=lstrlen(smb_localNamep);
7791 memset(smb_sharename,' ',NCBNAMSZ);
7792 memcpy(smb_sharename,smb_localNamep,len);
7793 osi_Log1(smb_logp, "lana_list.length %d", lana_list.length);
7795 /* Keep the name so we can unregister it later */
7796 for (l = 0; l < lana_list.length; l++) {
7797 lana = lana_list.lana[l];
7799 ncbp->ncb_command = NCBADDNAME;
7800 ncbp->ncb_lana_num = lana;
7801 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7803 code = Netbios(ncbp);
7805 code = Netbios(ncbp, dos_ncb);
7808 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7809 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7811 char name[NCBNAMSZ+1];
7813 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7814 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7817 if (code == 0) code = ncbp->ncb_retcode;
7819 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7821 /* we only use one LANA with djgpp */
7822 lana_list.lana[0] = lana;
7823 lana_list.length = 1;
7827 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7828 if (code == NRC_BRIDGE) { /* invalid LANA num */
7829 lana_list.lana[l] = 255;
7832 else if (code == NRC_DUPNAME) {
7833 osi_Log0(smb_logp, "Name already exists; try to delete it");
7834 memset(ncbp, 0, sizeof(*ncbp));
7835 ncbp->ncb_command = NCBDELNAME;
7836 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7837 ncbp->ncb_lana_num = lana;
7839 code = Netbios(ncbp);
7841 code = Netbios(ncbp, dos_ncb);
7844 code = ncbp->ncb_retcode;
7846 osi_Log2(smb_logp, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7848 if (code != 0 || delname_tried) {
7849 lana_list.lana[l] = 255;
7851 else if (code == 0) {
7852 if (!delname_tried) {
7860 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7861 lana_list.lana[l] = 255; /* invalid lana */
7862 osi_panic(s, __FILE__, __LINE__);
7866 lana_found = 1; /* at least one worked */
7873 osi_assert(lana_list.length >= 0);
7875 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
7878 /* we're done with the NCB now */
7882 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7899 EVENT_HANDLE retHandle;
7900 char eventName[MAX_PATH];
7903 smb_MBfunc = aMBfunc;
7907 smb_LANadapter = LANadapt;
7909 /* Initialize smb_localZero */
7910 myTime.tm_isdst = -1; /* compute whether on DST or not */
7911 myTime.tm_year = 70;
7917 smb_localZero = mktime(&myTime);
7919 #ifndef USE_NUMERIC_TIME_CONV
7920 /* Initialize kludge-GMT */
7921 smb_CalculateNowTZ();
7922 #endif /* USE_NUMERIC_TIME_CONV */
7923 #ifdef AFS_FREELANCE_CLIENT
7924 /* Make sure the root.afs volume has the correct time */
7925 cm_noteLocalMountPointChange();
7928 /* initialize the remote debugging log */
7931 /* remember the name */
7932 len = strlen(snamep);
7933 smb_localNamep = malloc(len+1);
7934 strcpy(smb_localNamep, snamep);
7935 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7937 /* and the global lock */
7938 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7939 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7941 /* Raw I/O data structures */
7942 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7944 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7946 /* 4 Raw I/O buffers */
7948 smb_RawBufs = calloc(65536,1);
7949 *((char **)smb_RawBufs) = NULL;
7950 for (i=0; i<3; i++) {
7951 char *rawBuf = calloc(65536,1);
7952 *((char **)rawBuf) = smb_RawBufs;
7953 smb_RawBufs = rawBuf;
7956 npar = 65536 >> 4; /* number of paragraphs */
7957 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7959 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7961 osi_panic("",__FILE__,__LINE__);
7964 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7967 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7969 _farpokel(_dos_ds, smb_RawBufs, NULL);
7970 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7971 npar = 65536 >> 4; /* number of paragraphs */
7972 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7974 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7976 osi_panic("",__FILE__,__LINE__);
7979 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7982 rawBuf = (seg * 16) + 0; /* DOS physical address */
7983 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7984 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7985 smb_RawBufs = rawBuf;
7989 /* global free lists */
7990 smb_ncbFreeListp = NULL;
7991 smb_packetFreeListp = NULL;
7995 /* Initialize listener and server structures */
7997 memset(dead_sessions, 0, sizeof(dead_sessions));
7998 sprintf(eventName, "SessionEvents[0]");
7999 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8000 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8001 afsi_log("Event Object Already Exists: %s", eventName);
8003 smb_NumServerThreads = nThreads;
8004 sprintf(eventName, "NCBavails[0]");
8005 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8006 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8007 afsi_log("Event Object Already Exists: %s", eventName);
8008 sprintf(eventName, "NCBevents[0]");
8009 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8010 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8011 afsi_log("Event Object Already Exists: %s", eventName);
8012 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8013 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8014 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8015 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8016 afsi_log("Event Object Already Exists: %s", eventName);
8017 for (i = 0; i < smb_NumServerThreads; i++) {
8018 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8019 NCBreturns[i][0] = retHandle;
8022 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8023 for (i = 0; i < smb_NumServerThreads; i++) {
8024 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8025 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8026 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8027 afsi_log("Event Object Already Exists: %s", eventName);
8030 numNCBs = smb_NumServerThreads + 1;
8032 /* Initialize dispatch table */
8033 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8034 /* Prepare the table for unknown operations */
8035 for(i=0; i<= SMB_NOPCODES; i++) {
8036 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8038 /* Fill in the ones we do know */
8039 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8040 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8041 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8042 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8043 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8044 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8045 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8046 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8047 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8048 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8049 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8050 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8051 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8052 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8053 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8054 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8055 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8056 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8057 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8058 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8059 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8060 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8061 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8062 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8063 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8064 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8065 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8066 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8067 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8068 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8069 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8070 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8071 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8072 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8073 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8074 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8075 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8076 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8077 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8078 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8079 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8080 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8081 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8082 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8083 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8084 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8085 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8086 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8087 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8088 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8089 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8090 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8091 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8092 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8093 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8094 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8095 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8096 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8097 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8098 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8099 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8100 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8101 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8102 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8103 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8104 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8105 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8106 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8107 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8108 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8109 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8110 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8112 /* setup tran 2 dispatch table */
8113 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8114 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8115 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8116 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8117 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8118 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8119 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8120 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8121 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8122 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8123 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8124 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8125 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8126 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8127 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8128 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8129 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8131 /* setup the rap dispatch table */
8132 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8133 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8134 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8135 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8136 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8140 /* if we are doing SMB authentication we have register outselves as a logon process */
8141 if (smb_authType != SMB_AUTH_NONE) {
8142 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8143 LSA_STRING afsProcessName;
8144 LSA_OPERATIONAL_MODE dummy; /*junk*/
8146 afsProcessName.Buffer = "OpenAFSClientDaemon";
8147 afsProcessName.Length = strlen(afsProcessName.Buffer);
8148 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8150 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8152 if (nts == STATUS_SUCCESS) {
8153 LSA_STRING packageName;
8154 /* we are registered. Find out the security package id */
8155 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8156 packageName.Length = strlen(packageName.Buffer);
8157 packageName.MaximumLength = packageName.Length + 1;
8158 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8159 if (nts == STATUS_SUCCESS) {
8161 * This code forces Windows to authenticate against the Logon Cache
8162 * first instead of attempting to authenticate against the Domain
8163 * Controller. When the Windows logon cache is enabled this improves
8164 * performance by removing the network access and works around a bug
8165 * seen at sites which are using a MIT Kerberos principal to login
8166 * to machines joined to a non-root domain in a multi-domain forest.
8168 PVOID pResponse = NULL;
8169 ULONG cbResponse = 0;
8170 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8172 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8173 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8174 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8175 OptionsRequest.DisableOptions = FALSE;
8177 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8180 sizeof(OptionsRequest),
8186 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8188 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8190 OutputDebugString(message);
8191 osi_Log2(smb_logp,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8194 OutputDebugString("MsV1_0SetProcessOption success");
8195 osi_Log0(smb_logp,"MsV1_0SetProcessOption success");
8197 /* END - code from Larry */
8199 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8200 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8201 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8203 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8205 /* something went wrong. We report the error and revert back to no authentication
8206 because we can't perform any auth requests without a successful lsa handle
8207 or sec package id. */
8208 afsi_log("Reverting to NO SMB AUTH");
8209 smb_authType = SMB_AUTH_NONE;
8212 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8214 /* something went wrong. We report the error and revert back to no authentication
8215 because we can't perform any auth requests without a successful lsa handle
8216 or sec package id. */
8217 afsi_log("Reverting to NO SMB AUTH");
8218 smb_authType = SMB_AUTH_NONE;
8222 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8223 * time prevents the failure of authentication when logged into Windows with an
8224 * external Kerberos principal mapped to a local account.
8226 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8227 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8228 * then the only option is NTLMSSP anyway; so just fallback.
8233 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8234 if (secBlobLength == 0) {
8235 smb_authType = SMB_AUTH_NTLM;
8236 afsi_log("Reverting to SMB AUTH NTLM");
8245 /* Now get ourselves a domain name. */
8246 /* For now we are using the local computer name as the domain name.
8247 * It is actually the domain for local logins, and we are acting as
8248 * a local SMB server.
8250 bufsize = sizeof(smb_ServerDomainName) - 1;
8251 GetComputerName(smb_ServerDomainName, &bufsize);
8252 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8253 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8256 /* Start listeners, waiters, servers, and daemons */
8258 for (i = 0; i < lana_list.length; i++) {
8259 if (lana_list.lana[i] == 255)
8261 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8262 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8263 osi_assert(phandle != NULL);
8264 thrd_CloseHandle(phandle);
8268 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8269 NULL, 0, &lpid, "smb_ClientWaiter");
8270 osi_assert(phandle != NULL);
8271 thrd_CloseHandle(phandle);
8274 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8275 NULL, 0, &lpid, "smb_ServerWaiter");
8276 osi_assert(phandle != NULL);
8277 thrd_CloseHandle(phandle);
8279 for (i=0; i<smb_NumServerThreads; i++) {
8280 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8281 (void *) i, 0, &lpid, "smb_Server");
8282 osi_assert(phandle != NULL);
8283 thrd_CloseHandle(phandle);
8286 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8287 NULL, 0, &lpid, "smb_Daemon");
8288 osi_assert(phandle != NULL);
8289 thrd_CloseHandle(phandle);
8291 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8292 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8293 osi_assert(phandle != NULL);
8294 thrd_CloseHandle(phandle);
8303 void smb_Shutdown(void)
8313 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8315 /* setup the NCB system */
8318 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8321 /* Block new sessions by setting shutdown flag */
8322 smbShutdownFlag = 1;
8324 /* Hang up all sessions */
8325 memset((char *)ncbp, 0, sizeof(NCB));
8326 for (i = 1; i < numSessions; i++)
8328 if (dead_sessions[i])
8331 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8332 ncbp->ncb_command = NCBHANGUP;
8333 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8334 ncbp->ncb_lsn = LSNs[i];
8336 code = Netbios(ncbp);
8338 code = Netbios(ncbp, dos_ncb);
8340 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8341 if (code == 0) code = ncbp->ncb_retcode;
8343 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8344 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8348 /* Trigger the shutdown of all SMB threads */
8349 for (i = 0; i < smb_NumServerThreads; i++)
8350 thrd_SetEvent(NCBreturns[i][0]);
8352 thrd_SetEvent(NCBevents[0]);
8353 thrd_SetEvent(SessionEvents[0]);
8354 thrd_SetEvent(NCBavails[0]);
8356 for (i = 0;i < smb_NumServerThreads; i++) {
8357 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8358 if (code == WAIT_OBJECT_0) {
8361 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8362 thrd_SetEvent(NCBreturns[i--][0]);
8366 /* Delete Netbios name */
8367 memset((char *)ncbp, 0, sizeof(NCB));
8368 for (i = 0; i < lana_list.length; i++) {
8369 if (lana_list.lana[i] == 255) continue;
8370 ncbp->ncb_command = NCBDELNAME;
8371 ncbp->ncb_lana_num = lana_list.lana[i];
8372 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8374 code = Netbios(ncbp);
8376 code = Netbios(ncbp, dos_ncb);
8379 code = ncbp->ncb_retcode;
8381 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8382 ncbp->ncb_lana_num, code);
8387 /* Release the reference counts held by the VCs */
8388 lock_ObtainWrite(&smb_rctLock);
8389 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8394 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8396 if (fidp->scp != NULL) {
8399 lock_ObtainMutex(&fidp->mx);
8400 if (fidp->scp != NULL) {
8403 cm_ReleaseSCache(scp);
8405 lock_ReleaseMutex(&fidp->mx);
8409 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8411 smb_ReleaseVCNoLock(tidp->vcp);
8413 cm_user_t *userp = tidp->userp;
8415 lock_ReleaseWrite(&smb_rctLock);
8416 cm_ReleaseUser(userp);
8417 lock_ObtainWrite(&smb_rctLock);
8421 lock_ReleaseWrite(&smb_rctLock);
8424 /* Get the UNC \\<servername>\<sharename> prefix. */
8425 char *smb_GetSharename()
8429 /* Make sure we have been properly initialized. */
8430 if (smb_localNamep == NULL)
8433 /* Allocate space for \\<servername>\<sharename>, plus the
8436 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8437 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8443 void smb_LogPacket(smb_packet_t *packet)
8446 unsigned length, paramlen, datalen, i, j;
8448 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8450 if (!packet) return;
8452 osi_Log0(smb_logp, "*** SMB packet dump ***");
8454 vp = (BYTE *) packet->data;
8456 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8457 length = paramlen + 2 + datalen;
8460 for (i=0;i < length; i+=16)
8462 memset( buf, ' ', 80 );
8467 buf[strlen(buf)] = ' ';
8469 cp = (BYTE*) buf + 7;
8471 for (j=0;j < 16 && (i+j)<length; j++)
8473 *(cp++) = hex[vp[i+j] >> 4];
8474 *(cp++) = hex[vp[i+j] & 0xf];
8484 for (j=0;j < 16 && (i+j)<length;j++)
8486 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8497 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8500 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8502 #endif /* LOG_PACKET */
8505 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8513 lock_ObtainRead(&smb_rctLock);
8515 sprintf(output, "begin dumping smb_vc_t\n");
8516 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8518 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8522 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8523 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8524 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8526 sprintf(output, "begin dumping smb_fid_t\n");
8527 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8529 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8531 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",
8532 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8533 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8534 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8535 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8538 sprintf(output, "done dumping smb_fid_t\n");
8539 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8542 sprintf(output, "done dumping smb_vc_t\n");
8543 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8546 lock_ReleaseRead(&smb_rctLock);