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) {
2317 NTStatus = 0xC00000CFL; /* Sharing Paused */
2319 NTStatus = 0x00000102L; /* Timeout */
2322 else if (code == CM_ERROR_RETRY) {
2323 NTStatus = 0xC000022DL; /* Retry */
2325 else if (code == CM_ERROR_NOACCESS) {
2326 NTStatus = 0xC0000022L; /* Access denied */
2328 else if (code == CM_ERROR_READONLY) {
2329 NTStatus = 0xC00000A2L; /* Write protected */
2331 else if (code == CM_ERROR_NOSUCHFILE) {
2332 NTStatus = 0xC000000FL; /* No such file */
2334 else if (code == CM_ERROR_NOSUCHPATH) {
2335 NTStatus = 0xC000003AL; /* Object path not found */
2337 else if (code == CM_ERROR_TOOBIG) {
2338 NTStatus = 0xC000007BL; /* Invalid image format */
2340 else if (code == CM_ERROR_INVAL) {
2341 NTStatus = 0xC000000DL; /* Invalid parameter */
2343 else if (code == CM_ERROR_BADFD) {
2344 NTStatus = 0xC0000008L; /* Invalid handle */
2346 else if (code == CM_ERROR_BADFDOP) {
2347 NTStatus = 0xC0000022L; /* Access denied */
2349 else if (code == CM_ERROR_EXISTS) {
2350 NTStatus = 0xC0000035L; /* Object name collision */
2352 else if (code == CM_ERROR_NOTEMPTY) {
2353 NTStatus = 0xC0000101L; /* Directory not empty */
2355 else if (code == CM_ERROR_CROSSDEVLINK) {
2356 NTStatus = 0xC00000D4L; /* Not same device */
2358 else if (code == CM_ERROR_NOTDIR) {
2359 NTStatus = 0xC0000103L; /* Not a directory */
2361 else if (code == CM_ERROR_ISDIR) {
2362 NTStatus = 0xC00000BAL; /* File is a directory */
2364 else if (code == CM_ERROR_BADOP) {
2366 /* I have no idea where this comes from */
2367 NTStatus = 0xC09820FFL; /* SMB no support */
2369 NTStatus = 0xC00000BBL; /* Not supported */
2370 #endif /* COMMENT */
2372 else if (code == CM_ERROR_BADSHARENAME) {
2373 NTStatus = 0xC00000CCL; /* Bad network name */
2375 else if (code == CM_ERROR_NOIPC) {
2377 NTStatus = 0xC0000022L; /* Access Denied */
2379 NTStatus = 0xC000013DL; /* Remote Resources */
2382 else if (code == CM_ERROR_CLOCKSKEW) {
2383 NTStatus = 0xC0000133L; /* Time difference at DC */
2385 else if (code == CM_ERROR_BADTID) {
2386 NTStatus = 0xC0982005L; /* SMB bad TID */
2388 else if (code == CM_ERROR_USESTD) {
2389 NTStatus = 0xC09820FBL; /* SMB use standard */
2391 else if (code == CM_ERROR_QUOTA) {
2393 NTStatus = 0xC0000044L; /* Quota exceeded */
2395 NTStatus = 0xC000007FL; /* Disk full */
2398 else if (code == CM_ERROR_SPACE) {
2399 NTStatus = 0xC000007FL; /* Disk full */
2401 else if (code == CM_ERROR_ATSYS) {
2402 NTStatus = 0xC0000033L; /* Object name invalid */
2404 else if (code == CM_ERROR_BADNTFILENAME) {
2405 NTStatus = 0xC0000033L; /* Object name invalid */
2407 else if (code == CM_ERROR_WOULDBLOCK) {
2408 NTStatus = 0xC0000055L; /* Lock not granted */
2410 else if (code == CM_ERROR_PARTIALWRITE) {
2411 NTStatus = 0xC000007FL; /* Disk full */
2413 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2414 NTStatus = 0xC0000023L; /* Buffer too small */
2416 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2417 NTStatus = 0xC0000035L; /* Object name collision */
2419 else if (code == CM_ERROR_BADPASSWORD) {
2420 NTStatus = 0xC000006DL; /* unknown username or bad password */
2422 else if (code == CM_ERROR_BADLOGONTYPE) {
2423 NTStatus = 0xC000015BL; /* logon type not granted */
2425 else if (code == CM_ERROR_GSSCONTINUE) {
2426 NTStatus = 0xC0000016L; /* more processing required */
2428 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2430 NTStatus = 0xC0000280L; /* reparse point not resolved */
2432 NTStatus = 0xC0000022L; /* Access Denied */
2435 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2436 NTStatus = 0xC0000257L; /* Path Not Covered */
2439 else if (code == CM_ERROR_ALLBUSY) {
2440 NTStatus = 0xC00000BFL; /* Network Busy */
2442 else if (code == CM_ERROR_ALLOFFLINE) {
2443 NTStatus = 0xC0000350L; /* Remote Host Down */
2446 /* we do not want to be telling the SMB/CIFS client that
2447 * the AFS Client Service is busy or down.
2449 else if (code == CM_ERROR_ALLBUSY ||
2450 code == CM_ERROR_ALLOFFLINE) {
2451 NTStatus = 0xC00000BEL; /* Bad Network Path */
2455 NTStatus = 0xC0982001L; /* SMB non-specific error */
2458 *NTStatusp = NTStatus;
2459 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2462 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2463 unsigned char *classp)
2465 unsigned char class;
2466 unsigned short error;
2468 /* map CM_ERROR_* errors to SMB errors */
2469 if (code == CM_ERROR_NOSUCHCELL) {
2471 error = 3; /* bad path */
2473 else if (code == CM_ERROR_NOSUCHVOLUME) {
2475 error = 3; /* bad path */
2477 else if (code == CM_ERROR_TIMEDOUT) {
2479 error = 81; /* server is paused */
2481 else if (code == CM_ERROR_RETRY) {
2482 class = 2; /* shouldn't happen */
2485 else if (code == CM_ERROR_NOACCESS) {
2487 error = 4; /* bad access */
2489 else if (code == CM_ERROR_READONLY) {
2491 error = 19; /* read only */
2493 else if (code == CM_ERROR_NOSUCHFILE) {
2495 error = 2; /* ENOENT! */
2497 else if (code == CM_ERROR_NOSUCHPATH) {
2499 error = 3; /* Bad path */
2501 else if (code == CM_ERROR_TOOBIG) {
2503 error = 11; /* bad format */
2505 else if (code == CM_ERROR_INVAL) {
2506 class = 2; /* server non-specific error code */
2509 else if (code == CM_ERROR_BADFD) {
2511 error = 6; /* invalid file handle */
2513 else if (code == CM_ERROR_BADFDOP) {
2514 class = 1; /* invalid op on FD */
2517 else if (code == CM_ERROR_EXISTS) {
2519 error = 80; /* file already exists */
2521 else if (code == CM_ERROR_NOTEMPTY) {
2523 error = 5; /* delete directory not empty */
2525 else if (code == CM_ERROR_CROSSDEVLINK) {
2527 error = 17; /* EXDEV */
2529 else if (code == CM_ERROR_NOTDIR) {
2530 class = 1; /* bad path */
2533 else if (code == CM_ERROR_ISDIR) {
2534 class = 1; /* access denied; DOS doesn't have a good match */
2537 else if (code == CM_ERROR_BADOP) {
2541 else if (code == CM_ERROR_BADSHARENAME) {
2545 else if (code == CM_ERROR_NOIPC) {
2547 error = 4; /* bad access */
2549 else if (code == CM_ERROR_CLOCKSKEW) {
2550 class = 1; /* invalid function */
2553 else if (code == CM_ERROR_BADTID) {
2557 else if (code == CM_ERROR_USESTD) {
2561 else if (code == CM_ERROR_REMOTECONN) {
2565 else if (code == CM_ERROR_QUOTA) {
2566 if (vcp->flags & SMB_VCFLAG_USEV3) {
2568 error = 39; /* disk full */
2572 error = 5; /* access denied */
2575 else if (code == CM_ERROR_SPACE) {
2576 if (vcp->flags & SMB_VCFLAG_USEV3) {
2578 error = 39; /* disk full */
2582 error = 5; /* access denied */
2585 else if (code == CM_ERROR_PARTIALWRITE) {
2587 error = 39; /* disk full */
2589 else if (code == CM_ERROR_ATSYS) {
2591 error = 2; /* ENOENT */
2593 else if (code == CM_ERROR_WOULDBLOCK) {
2595 error = 33; /* lock conflict */
2597 else if (code == CM_ERROR_NOFILES) {
2599 error = 18; /* no files in search */
2601 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2603 error = 183; /* Samba uses this */
2605 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2606 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2608 error = 2; /* bad password */
2610 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2612 error = 3; /* bad path */
2621 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2624 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2626 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2627 return CM_ERROR_BADOP;
2630 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2632 unsigned short EchoCount, i;
2633 char *data, *outdata;
2636 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2638 for (i=1; i<=EchoCount; i++) {
2639 data = smb_GetSMBData(inp, &dataSize);
2640 smb_SetSMBParm(outp, 0, i);
2641 smb_SetSMBDataLength(outp, dataSize);
2642 outdata = smb_GetSMBData(outp, NULL);
2643 memcpy(outdata, data, dataSize);
2644 smb_SendPacket(vcp, outp);
2650 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2653 long count, minCount, finalCount;
2657 cm_user_t *userp = NULL;
2661 char *rawBuf = NULL;
2663 dos_ptr rawBuf = NULL;
2670 fd = smb_GetSMBParm(inp, 0);
2671 count = smb_GetSMBParm(inp, 3);
2672 minCount = smb_GetSMBParm(inp, 4);
2673 offset.HighPart = 0; /* too bad */
2674 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2676 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2677 fd, offset.LowPart, count);
2679 fidp = smb_FindFID(vcp, fd, 0);
2683 lock_ObtainMutex(&smb_RawBufLock);
2685 /* Get a raw buf, from head of list */
2686 rawBuf = smb_RawBufs;
2688 smb_RawBufs = *(char **)smb_RawBufs;
2690 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2693 lock_ReleaseMutex(&smb_RawBufLock);
2697 if (fidp->flags & SMB_FID_IOCTL)
2700 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2702 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2705 /* Give back raw buffer */
2706 lock_ObtainMutex(&smb_RawBufLock);
2708 *((char **) rawBuf) = smb_RawBufs;
2710 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2713 smb_RawBufs = rawBuf;
2714 lock_ReleaseMutex(&smb_RawBufLock);
2717 smb_ReleaseFID(fidp);
2721 userp = smb_GetUser(vcp, inp);
2724 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2726 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2727 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2728 userp, &finalCount, TRUE /* rawFlag */);
2735 cm_ReleaseUser(userp);
2738 smb_ReleaseFID(fidp);
2743 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2745 memset((char *)ncbp, 0, sizeof(NCB));
2747 ncbp->ncb_length = (unsigned short) finalCount;
2748 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2749 ncbp->ncb_lana_num = vcp->lana;
2750 ncbp->ncb_command = NCBSEND;
2751 ncbp->ncb_buffer = rawBuf;
2754 code = Netbios(ncbp);
2756 code = Netbios(ncbp, dos_ncb);
2759 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2762 /* Give back raw buffer */
2763 lock_ObtainMutex(&smb_RawBufLock);
2765 *((char **) rawBuf) = smb_RawBufs;
2767 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2770 smb_RawBufs = rawBuf;
2771 lock_ReleaseMutex(&smb_RawBufLock);
2777 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2779 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2784 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2786 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2791 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2798 int protoIndex; /* index we're using */
2803 char protocol_array[10][1024]; /* protocol signature of the client */
2804 int caps; /* capabilities */
2807 TIME_ZONE_INFORMATION tzi;
2809 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2813 DWORD now = GetCurrentTime();
2814 if (now - last_msg_time >= 30000
2815 && now - last_msg_time <= 90000) {
2817 "Setting dead_vcp %x", active_vcp);
2819 smb_ReleaseVC(dead_vcp);
2821 "Previous dead_vcp %x", dead_vcp);
2823 smb_HoldVC(active_vcp);
2824 dead_vcp = active_vcp;
2825 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2830 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2832 namep = smb_GetSMBData(inp, &dbytes);
2835 coreProtoIndex = -1; /* not found */
2838 while(namex < dbytes) {
2839 osi_Log1(smb_logp, "Protocol %s",
2840 osi_LogSaveString(smb_logp, namep+1));
2841 strcpy(protocol_array[tcounter], namep+1);
2843 /* namep points at the first protocol, or really, a 0x02
2844 * byte preceding the null-terminated ASCII name.
2846 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2847 coreProtoIndex = tcounter;
2849 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2850 v3ProtoIndex = tcounter;
2852 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2853 NTProtoIndex = tcounter;
2856 /* compute size of protocol entry */
2857 entryLength = strlen(namep+1);
2858 entryLength += 2; /* 0x02 bytes and null termination */
2860 /* advance over this protocol entry */
2861 namex += entryLength;
2862 namep += entryLength;
2863 tcounter++; /* which proto entry we're looking at */
2866 if (NTProtoIndex != -1) {
2867 protoIndex = NTProtoIndex;
2868 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2870 else if (v3ProtoIndex != -1) {
2871 protoIndex = v3ProtoIndex;
2872 vcp->flags |= SMB_VCFLAG_USEV3;
2874 else if (coreProtoIndex != -1) {
2875 protoIndex = coreProtoIndex;
2876 vcp->flags |= SMB_VCFLAG_USECORE;
2878 else protoIndex = -1;
2880 if (protoIndex == -1)
2881 return CM_ERROR_INVAL;
2882 else if (NTProtoIndex != -1) {
2883 smb_SetSMBParm(outp, 0, protoIndex);
2884 if (smb_authType != SMB_AUTH_NONE) {
2885 smb_SetSMBParmByte(outp, 1,
2886 NEGOTIATE_SECURITY_USER_LEVEL |
2887 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2889 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2891 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2892 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2893 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2894 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2895 /* The session key is not a well documented field however most clients
2896 * will echo back the session key to the server. Currently we are using
2897 * the same value for all sessions. We should generate a random value
2898 * and store it into the vcp
2900 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2901 smb_SetSMBParm(outp, 8, 1);
2903 * Tried changing the capabilities to support for W2K - defect 117695
2904 * Maybe something else needs to be changed here?
2908 smb_SetSMBParmLong(outp, 9, 0x43fd);
2910 smb_SetSMBParmLong(outp, 9, 0x251);
2913 * 32-bit error codes *
2918 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2920 NTNEGOTIATE_CAPABILITY_DFS |
2922 NTNEGOTIATE_CAPABILITY_NTFIND |
2923 NTNEGOTIATE_CAPABILITY_RAWMODE |
2924 NTNEGOTIATE_CAPABILITY_NTSMB;
2926 if ( smb_authType == SMB_AUTH_EXTENDED )
2927 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2929 smb_SetSMBParmLong(outp, 9, caps);
2931 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2932 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2933 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2935 GetTimeZoneInformation(&tzi);
2936 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2938 if (smb_authType == SMB_AUTH_NTLM) {
2939 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2940 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2941 /* paste in encryption key */
2942 datap = smb_GetSMBData(outp, NULL);
2943 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2944 /* and the faux domain name */
2945 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2946 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2950 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2952 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2954 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2956 datap = smb_GetSMBData(outp, NULL);
2957 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2960 datap += sizeof(smb_ServerGUID);
2961 memcpy(datap, secBlob, secBlobLength);
2965 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2966 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2969 else if (v3ProtoIndex != -1) {
2970 smb_SetSMBParm(outp, 0, protoIndex);
2972 /* NOTE: Extended authentication cannot be negotiated with v3
2973 * therefore we fail over to NTLM
2975 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2976 smb_SetSMBParm(outp, 1,
2977 NEGOTIATE_SECURITY_USER_LEVEL |
2978 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2980 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2982 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2983 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2984 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2985 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2986 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2987 smb_SetSMBParm(outp, 7, 1);
2989 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2990 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2991 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2993 GetTimeZoneInformation(&tzi);
2994 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2996 /* NOTE: Extended authentication cannot be negotiated with v3
2997 * therefore we fail over to NTLM
2999 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3000 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3001 smb_SetSMBParm(outp, 12, 0); /* resvd */
3002 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3003 datap = smb_GetSMBData(outp, NULL);
3004 /* paste in a new encryption key */
3005 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3006 /* and the faux domain name */
3007 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3009 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3010 smb_SetSMBParm(outp, 12, 0); /* resvd */
3011 smb_SetSMBDataLength(outp, 0);
3014 else if (coreProtoIndex != -1) { /* not really supported anymore */
3015 smb_SetSMBParm(outp, 0, protoIndex);
3016 smb_SetSMBDataLength(outp, 0);
3021 void smb_Daemon(void *parmp)
3023 afs_uint32 count = 0;
3025 while(smbShutdownFlag == 0) {
3029 if (smbShutdownFlag == 1)
3032 if ((count % 72) == 0) { /* every five minutes */
3034 time_t old_localZero = smb_localZero;
3036 /* Initialize smb_localZero */
3037 myTime.tm_isdst = -1; /* compute whether on DST or not */
3038 myTime.tm_year = 70;
3044 smb_localZero = mktime(&myTime);
3046 #ifndef USE_NUMERIC_TIME_CONV
3047 smb_CalculateNowTZ();
3048 #endif /* USE_NUMERIC_TIME_CONV */
3049 #ifdef AFS_FREELANCE
3050 if ( smb_localZero != old_localZero )
3051 cm_noteLocalMountPointChange();
3054 /* XXX GC dir search entries */
3058 void smb_WaitingLocksDaemon()
3060 smb_waitingLock_t *wL, *nwL;
3063 smb_packet_t *inp, *outp;
3067 while (smbShutdownFlag == 0) {
3068 lock_ObtainWrite(&smb_globalLock);
3069 nwL = smb_allWaitingLocks;
3071 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3081 lock_ObtainWrite(&smb_globalLock);
3083 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
3084 lock_ReleaseWrite(&smb_globalLock);
3085 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
3086 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
3087 if (code == CM_ERROR_WOULDBLOCK) {
3089 if (wL->timeRemaining != 0xffffffff
3090 && (wL->timeRemaining -= 1000) < 0)
3100 ncbp->ncb_length = inp->ncb_length;
3101 inp->spacep = cm_GetSpace();
3103 /* Remove waitingLock from list */
3104 lock_ObtainWrite(&smb_globalLock);
3105 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3107 lock_ReleaseWrite(&smb_globalLock);
3109 /* Resume packet processing */
3111 smb_SetSMBDataLength(outp, 0);
3112 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3113 outp->resumeCode = code;
3115 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3118 cm_FreeSpace(inp->spacep);
3119 smb_FreePacket(inp);
3120 smb_FreePacket(outp);
3124 } while (nwL && smbShutdownFlag == 0);
3129 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3131 osi_Log0(smb_logp, "SMB receive get disk attributes");
3133 smb_SetSMBParm(outp, 0, 32000);
3134 smb_SetSMBParm(outp, 1, 64);
3135 smb_SetSMBParm(outp, 2, 1024);
3136 smb_SetSMBParm(outp, 3, 30000);
3137 smb_SetSMBParm(outp, 4, 0);
3138 smb_SetSMBDataLength(outp, 0);
3142 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3146 unsigned short newTid;
3147 char shareName[256];
3155 osi_Log0(smb_logp, "SMB receive tree connect");
3157 /* parse input parameters */
3158 tp = smb_GetSMBData(inp, NULL);
3159 pathp = smb_ParseASCIIBlock(tp, &tp);
3160 if (smb_StoreAnsiFilenames)
3161 OemToChar(pathp,pathp);
3162 passwordp = smb_ParseASCIIBlock(tp, &tp);
3163 tp = strrchr(pathp, '\\');
3165 return CM_ERROR_BADSMB;
3166 strcpy(shareName, tp+1);
3168 userp = smb_GetUser(vcp, inp);
3170 lock_ObtainMutex(&vcp->mx);
3171 newTid = vcp->tidCounter++;
3172 lock_ReleaseMutex(&vcp->mx);
3174 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3175 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3176 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3178 smb_ReleaseUID(uidp);
3180 smb_ReleaseTID(tidp);
3181 return CM_ERROR_BADSHARENAME;
3183 lock_ObtainMutex(&tidp->mx);
3184 tidp->userp = userp;
3185 tidp->pathname = sharePath;
3186 lock_ReleaseMutex(&tidp->mx);
3187 smb_ReleaseTID(tidp);
3189 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3190 smb_SetSMBParm(rsp, 1, newTid);
3191 smb_SetSMBDataLength(rsp, 0);
3193 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3197 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3201 if (*inp++ != 0x1) return NULL;
3202 tlen = inp[0] + (inp[1]<<8);
3203 inp += 2; /* skip length field */
3206 *chainpp = inp + tlen;
3209 if (lengthp) *lengthp = tlen;
3214 /* set maskp to the mask part of the incoming path.
3215 * Mask is 11 bytes long (8.3 with the dot elided).
3216 * Returns true if succeeds with a valid name, otherwise it does
3217 * its best, but returns false.
3219 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3227 /* starts off valid */
3230 /* mask starts out all blanks */
3231 memset(maskp, ' ', 11);
3233 /* find last backslash, or use whole thing if there is none */
3234 tp = strrchr(pathp, '\\');
3235 if (!tp) tp = pathp;
3236 else tp++; /* skip slash */
3240 /* names starting with a dot are illegal */
3241 if (*tp == '.') valid8Dot3 = 0;
3245 if (tc == 0) return valid8Dot3;
3246 if (tc == '.' || tc == '"') break;
3247 if (i < 8) *up++ = tc;
3248 else valid8Dot3 = 0;
3251 /* if we get here, tp point after the dot */
3252 up = maskp+8; /* ext goes here */
3259 if (tc == '.' || tc == '"')
3262 /* copy extension if not too long */
3272 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3282 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3284 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3288 /* otherwise, we have a valid 8.3 name; see if we have a match,
3289 * treating '?' as a wildcard in maskp (but not in the file name).
3291 tp1 = umask; /* real name, in mask format */
3292 tp2 = maskp; /* mask, in mask format */
3293 for(i=0; i<11; i++) {
3294 tc1 = *tp1++; /* char from real name */
3295 tc2 = *tp2++; /* char from mask */
3296 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3297 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3300 if (tc2 == '?' && tc1 != ' ')
3307 /* we got a match */
3311 char *smb_FindMask(char *pathp)
3315 tp = strrchr(pathp, '\\'); /* find last slash */
3318 return tp+1; /* skip the slash */
3320 return pathp; /* no slash, return the entire path */
3323 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3325 unsigned char *pathp;
3327 unsigned char mask[11];
3328 unsigned char *statBlockp;
3329 unsigned char initStatBlock[21];
3332 osi_Log0(smb_logp, "SMB receive search volume");
3334 /* pull pathname and stat block out of request */
3335 tp = smb_GetSMBData(inp, NULL);
3336 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3337 osi_assert(pathp != NULL);
3338 if (smb_StoreAnsiFilenames)
3339 OemToChar(pathp,pathp);
3340 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3341 osi_assert(statBlockp != NULL);
3343 statBlockp = initStatBlock;
3347 /* for returning to caller */
3348 smb_Get8Dot3MaskFromPath(mask, pathp);
3350 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3351 tp = smb_GetSMBData(outp, NULL);
3353 *tp++ = 43; /* bytes in a dir entry */
3354 *tp++ = 0; /* high byte in counter */
3356 /* now marshall the dir entry, starting with the search status */
3357 *tp++ = statBlockp[0]; /* Reserved */
3358 memcpy(tp, mask, 11); tp += 11; /* FileName */
3360 /* now pass back server use info, with 1st byte non-zero */
3362 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3364 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3366 *tp++ = 0x8; /* attribute: volume */
3376 /* 4 byte file size */
3382 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3383 memset(tp, ' ', 13);
3386 /* set the length of the data part of the packet to 43 + 3, for the dir
3387 * entry plus the 5 and the length fields.
3389 smb_SetSMBDataLength(outp, 46);
3393 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3394 cm_user_t *userp, cm_req_t *reqp)
3402 smb_dirListPatch_t *patchp;
3403 smb_dirListPatch_t *npatchp;
3405 for (patchp = *dirPatchespp; patchp; patchp =
3406 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3408 dptr = patchp->dptr;
3410 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3412 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3413 *dptr++ = SMB_ATTR_HIDDEN;
3416 lock_ObtainMutex(&scp->mx);
3417 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3418 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3420 lock_ReleaseMutex(&scp->mx);
3421 cm_ReleaseSCache(scp);
3422 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3423 *dptr++ = SMB_ATTR_HIDDEN;
3427 attr = smb_Attributes(scp);
3428 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3429 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3430 attr |= SMB_ATTR_HIDDEN;
3434 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3437 shortTemp = (unsigned short) (dosTime & 0xffff);
3438 *((u_short *)dptr) = shortTemp;
3441 /* and copy out date */
3442 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3443 *((u_short *)dptr) = shortTemp;
3446 /* copy out file length */
3447 *((u_long *)dptr) = scp->length.LowPart;
3449 lock_ReleaseMutex(&scp->mx);
3450 cm_ReleaseSCache(scp);
3453 /* now free the patches */
3454 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3455 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3459 /* and mark the list as empty */
3460 *dirPatchespp = NULL;
3465 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3474 smb_dirListPatch_t *dirListPatchesp;
3475 smb_dirListPatch_t *curPatchp;
3479 osi_hyper_t dirLength;
3480 osi_hyper_t bufferOffset;
3481 osi_hyper_t curOffset;
3483 unsigned char *inCookiep;
3484 smb_dirSearch_t *dsp;
3488 unsigned long clientCookie;
3489 cm_pageHeader_t *pageHeaderp;
3490 cm_user_t *userp = NULL;
3497 long nextEntryCookie;
3498 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3499 char resByte; /* reserved byte from the cookie */
3500 char *op; /* output data ptr */
3501 char *origOp; /* original value of op */
3502 cm_space_t *spacep; /* for pathname buffer */
3513 maxCount = smb_GetSMBParm(inp, 0);
3515 dirListPatchesp = NULL;
3517 caseFold = CM_FLAG_CASEFOLD;
3519 tp = smb_GetSMBData(inp, NULL);
3520 pathp = smb_ParseASCIIBlock(tp, &tp);
3521 if (smb_StoreAnsiFilenames)
3522 OemToChar(pathp,pathp);
3523 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3525 /* bail out if request looks bad */
3526 if (!tp || !pathp) {
3527 return CM_ERROR_BADSMB;
3530 /* We can handle long names */
3531 if (vcp->flags & SMB_VCFLAG_USENT)
3532 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3534 /* make sure we got a whole search status */
3535 if (dataLength < 21) {
3536 nextCookie = 0; /* start at the beginning of the dir */
3539 attribute = smb_GetSMBParm(inp, 1);
3541 /* handle volume info in another function */
3542 if (attribute & 0x8)
3543 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3545 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3546 maxCount, osi_LogSaveString(smb_logp, pathp));
3548 if (*pathp == 0) { /* null pathp, treat as root dir */
3549 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3550 return CM_ERROR_NOFILES;
3554 dsp = smb_NewDirSearch(0);
3555 dsp->attribute = attribute;
3556 smb_Get8Dot3MaskFromPath(mask, pathp);
3557 memcpy(dsp->mask, mask, 11);
3559 /* track if this is likely to match a lot of entries */
3560 if (smb_IsStarMask(mask))
3565 /* pull the next cookie value out of the search status block */
3566 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3567 + (inCookiep[16]<<24);
3568 dsp = smb_FindDirSearch(inCookiep[12]);
3570 /* can't find dir search status; fatal error */
3571 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3572 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3573 return CM_ERROR_BADFD;
3575 attribute = dsp->attribute;
3576 resByte = inCookiep[0];
3578 /* copy out client cookie, in host byte order. Don't bother
3579 * interpreting it, since we're just passing it through, anyway.
3581 memcpy(&clientCookie, &inCookiep[17], 4);
3583 memcpy(mask, dsp->mask, 11);
3585 /* assume we're doing a star match if it has continued for more
3591 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3592 nextCookie, dsp->cookie, attribute);
3594 userp = smb_GetUser(vcp, inp);
3596 /* try to get the vnode for the path name next */
3597 lock_ObtainMutex(&dsp->mx);
3603 spacep = inp->spacep;
3604 smb_StripLastComponent(spacep->data, NULL, pathp);
3605 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3607 lock_ReleaseMutex(&dsp->mx);
3608 cm_ReleaseUser(userp);
3609 smb_DeleteDirSearch(dsp);
3610 smb_ReleaseDirSearch(dsp);
3611 return CM_ERROR_NOFILES;
3613 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3614 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3617 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3618 cm_ReleaseSCache(scp);
3619 lock_ReleaseMutex(&dsp->mx);
3620 cm_ReleaseUser(userp);
3621 smb_DeleteDirSearch(dsp);
3622 smb_ReleaseDirSearch(dsp);
3623 if ( WANTS_DFS_PATHNAMES(inp) )
3624 return CM_ERROR_PATH_NOT_COVERED;
3626 return CM_ERROR_BADSHARENAME;
3628 #endif /* DFS_SUPPORT */
3631 /* we need one hold for the entry we just stored into,
3632 * and one for our own processing. When we're done with this
3633 * function, we'll drop the one for our own processing.
3634 * We held it once from the namei call, and so we do another hold
3638 lock_ObtainMutex(&scp->mx);
3639 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3640 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3641 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3642 dsp->flags |= SMB_DIRSEARCH_BULKST;
3644 lock_ReleaseMutex(&scp->mx);
3647 lock_ReleaseMutex(&dsp->mx);
3649 cm_ReleaseUser(userp);
3650 smb_DeleteDirSearch(dsp);
3651 smb_ReleaseDirSearch(dsp);
3655 /* reserves space for parameter; we'll adjust it again later to the
3656 * real count of the # of entries we returned once we've actually
3657 * assembled the directory listing.
3659 smb_SetSMBParm(outp, 0, 0);
3661 /* get the directory size */
3662 lock_ObtainMutex(&scp->mx);
3663 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3664 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3666 lock_ReleaseMutex(&scp->mx);
3667 cm_ReleaseSCache(scp);
3668 cm_ReleaseUser(userp);
3669 smb_DeleteDirSearch(dsp);
3670 smb_ReleaseDirSearch(dsp);
3674 dirLength = scp->length;
3676 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3677 curOffset.HighPart = 0;
3678 curOffset.LowPart = nextCookie;
3679 origOp = op = smb_GetSMBData(outp, NULL);
3680 /* and write out the basic header */
3681 *op++ = 5; /* variable block */
3682 op += 2; /* skip vbl block length; we'll fill it in later */
3686 /* make sure that curOffset.LowPart doesn't point to the first
3687 * 32 bytes in the 2nd through last dir page, and that it doesn't
3688 * point at the first 13 32-byte chunks in the first dir page,
3689 * since those are dir and page headers, and don't contain useful
3692 temp = curOffset.LowPart & (2048-1);
3693 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3694 /* we're in the first page */
3695 if (temp < 13*32) temp = 13*32;
3698 /* we're in a later dir page */
3699 if (temp < 32) temp = 32;
3702 /* make sure the low order 5 bits are zero */
3705 /* now put temp bits back ito curOffset.LowPart */
3706 curOffset.LowPart &= ~(2048-1);
3707 curOffset.LowPart |= temp;
3709 /* check if we've returned all the names that will fit in the
3712 if (returnedNames >= maxCount) {
3713 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3714 returnedNames, maxCount);
3718 /* check if we've passed the dir's EOF */
3719 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3721 /* see if we can use the bufferp we have now; compute in which page
3722 * the current offset would be, and check whether that's the offset
3723 * of the buffer we have. If not, get the buffer.
3725 thyper.HighPart = curOffset.HighPart;
3726 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3727 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3730 buf_Release(bufferp);
3733 lock_ReleaseMutex(&scp->mx);
3734 lock_ObtainRead(&scp->bufCreateLock);
3735 code = buf_Get(scp, &thyper, &bufferp);
3736 lock_ReleaseRead(&scp->bufCreateLock);
3737 lock_ObtainMutex(&dsp->mx);
3739 /* now, if we're doing a star match, do bulk fetching of all of
3740 * the status info for files in the dir.
3743 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3744 lock_ObtainMutex(&scp->mx);
3745 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3746 LargeIntegerGreaterThanOrEqualTo(thyper,
3747 scp->bulkStatProgress)) {
3748 /* Don't bulk stat if risking timeout */
3749 int now = GetCurrentTime();
3750 if (now - req.startTime > 5000) {
3751 scp->bulkStatProgress = thyper;
3752 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3753 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3755 cm_TryBulkStat(scp, &thyper, userp, &req);
3758 lock_ObtainMutex(&scp->mx);
3760 lock_ReleaseMutex(&dsp->mx);
3762 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3766 bufferOffset = thyper;
3768 /* now get the data in the cache */
3770 code = cm_SyncOp(scp, bufferp, userp, &req,
3772 CM_SCACHESYNC_NEEDCALLBACK |
3773 CM_SCACHESYNC_READ);
3775 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3779 if (cm_HaveBuffer(scp, bufferp, 0)) {
3780 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3784 /* otherwise, load the buffer and try again */
3785 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3787 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3788 scp, bufferp, code);
3793 buf_Release(bufferp);
3797 } /* if (wrong buffer) ... */
3799 /* now we have the buffer containing the entry we're interested in; copy
3800 * it out if it represents a non-deleted entry.
3802 entryInDir = curOffset.LowPart & (2048-1);
3803 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3805 /* page header will help tell us which entries are free. Page header
3806 * can change more often than once per buffer, since AFS 3 dir page size
3807 * may be less than (but not more than a buffer package buffer.
3809 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3810 temp &= ~(2048 - 1); /* turn off intra-page bits */
3811 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3813 /* now determine which entry we're looking at in the page. If it is
3814 * free (there's a free bitmap at the start of the dir), we should
3815 * skip these 32 bytes.
3817 slotInPage = (entryInDir & 0x7e0) >> 5;
3818 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3819 /* this entry is free */
3820 numDirChunks = 1; /* only skip this guy */
3824 tp = bufferp->datap + entryInBuffer;
3825 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3827 /* while we're here, compute the next entry's location, too,
3828 * since we'll need it when writing out the cookie into the dir
3831 * XXXX Probably should do more sanity checking.
3833 numDirChunks = cm_NameEntries(dep->name, NULL);
3835 /* compute the offset of the cookie representing the next entry */
3836 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3838 /* Compute 8.3 name if necessary */
3839 actualName = dep->name;
3840 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3841 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3842 actualName = shortName;
3845 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3846 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3847 osi_LogSaveString(smb_logp, actualName));
3849 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3850 /* this is one of the entries to use: it is not deleted
3851 * and it matches the star pattern we're looking for.
3854 /* Eliminate entries that don't match requested
3857 /* no hidden files */
3858 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3859 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3863 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3865 /* We have already done the cm_TryBulkStat above */
3866 fid.cell = scp->fid.cell;
3867 fid.volume = scp->fid.volume;
3868 fid.vnode = ntohl(dep->fid.vnode);
3869 fid.unique = ntohl(dep->fid.unique);
3870 fileType = cm_FindFileType(&fid);
3871 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3872 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3874 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3875 fileType == CM_SCACHETYPE_DFSLINK ||
3876 fileType == CM_SCACHETYPE_INVALID)
3877 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3882 memcpy(op, mask, 11); op += 11;
3883 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3884 *op++ = nextEntryCookie & 0xff;
3885 *op++ = (nextEntryCookie>>8) & 0xff;
3886 *op++ = (nextEntryCookie>>16) & 0xff;
3887 *op++ = (nextEntryCookie>>24) & 0xff;
3888 memcpy(op, &clientCookie, 4); op += 4;
3890 /* now we emit the attribute. This is sort of tricky,
3891 * since we need to really stat the file to find out
3892 * what type of entry we've got. Right now, we're
3893 * copying out data from a buffer, while holding the
3894 * scp locked, so it isn't really convenient to stat
3895 * something now. We'll put in a place holder now,
3896 * and make a second pass before returning this to get
3897 * the real attributes. So, we just skip the data for
3898 * now, and adjust it later. We allocate a patch
3899 * record to make it easy to find this point later.
3900 * The replay will happen at a time when it is safe to
3901 * unlock the directory.
3903 curPatchp = malloc(sizeof(*curPatchp));
3904 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3905 curPatchp->dptr = op;
3906 curPatchp->fid.cell = scp->fid.cell;
3907 curPatchp->fid.volume = scp->fid.volume;
3908 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3909 curPatchp->fid.unique = ntohl(dep->fid.unique);
3911 /* do hidden attribute here since name won't be around when applying
3915 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3916 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3918 curPatchp->flags = 0;
3920 op += 9; /* skip attr, time, date and size */
3922 /* zero out name area. The spec says to pad with
3923 * spaces, but Samba doesn't, and neither do we.
3927 /* finally, we get to copy out the name; we know that
3928 * it fits in 8.3 or the pattern wouldn't match, but it
3929 * never hurts to be sure.
3931 strncpy(op, actualName, 13);
3932 if (smb_StoreAnsiFilenames)
3935 /* Uppercase if requested by client */
3936 if (!KNOWS_LONG_NAMES(inp))
3941 /* now, adjust the # of entries copied */
3943 } /* if we're including this name */
3946 /* and adjust curOffset to be where the new cookie is */
3947 thyper.HighPart = 0;
3948 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3949 curOffset = LargeIntegerAdd(thyper, curOffset);
3950 } /* while copying data for dir listing */
3952 /* release the mutex */
3953 lock_ReleaseMutex(&scp->mx);
3954 if (bufferp) buf_Release(bufferp);
3956 /* apply and free last set of patches; if not doing a star match, this
3957 * will be empty, but better safe (and freeing everything) than sorry.
3959 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3961 /* special return code for unsuccessful search */
3962 if (code == 0 && dataLength < 21 && returnedNames == 0)
3963 code = CM_ERROR_NOFILES;
3965 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3966 returnedNames, code);
3969 smb_DeleteDirSearch(dsp);
3970 smb_ReleaseDirSearch(dsp);
3971 cm_ReleaseSCache(scp);
3972 cm_ReleaseUser(userp);
3976 /* finalize the output buffer */
3977 smb_SetSMBParm(outp, 0, returnedNames);
3978 temp = (long) (op - origOp);
3979 smb_SetSMBDataLength(outp, temp);
3981 /* the data area is a variable block, which has a 5 (already there)
3982 * followed by the length of the # of data bytes. We now know this to
3983 * be "temp," although that includes the 3 bytes of vbl block header.
3984 * Deduct for them and fill in the length field.
3986 temp -= 3; /* deduct vbl block info */
3987 osi_assert(temp == (43 * returnedNames));
3988 origOp[1] = temp & 0xff;
3989 origOp[2] = (temp>>8) & 0xff;
3990 if (returnedNames == 0)
3991 smb_DeleteDirSearch(dsp);
3992 smb_ReleaseDirSearch(dsp);
3993 cm_ReleaseSCache(scp);
3994 cm_ReleaseUser(userp);
3998 /* verify that this is a valid path to a directory. I don't know why they
3999 * don't use the get file attributes call.
4001 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4005 cm_scache_t *rootScp;
4006 cm_scache_t *newScp;
4015 pathp = smb_GetSMBData(inp, NULL);
4016 pathp = smb_ParseASCIIBlock(pathp, NULL);
4018 return CM_ERROR_BADFD;
4019 if (smb_StoreAnsiFilenames)
4020 OemToChar(pathp,pathp);
4021 osi_Log1(smb_logp, "SMB receive check path %s",
4022 osi_LogSaveString(smb_logp, pathp));
4024 rootScp = cm_data.rootSCachep;
4026 userp = smb_GetUser(vcp, inp);
4028 caseFold = CM_FLAG_CASEFOLD;
4030 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4032 cm_ReleaseUser(userp);
4033 return CM_ERROR_NOSUCHPATH;
4035 code = cm_NameI(rootScp, pathp,
4036 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4037 userp, tidPathp, &req, &newScp);
4040 cm_ReleaseUser(userp);
4045 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4046 cm_ReleaseSCache(newScp);
4047 cm_ReleaseUser(userp);
4048 if ( WANTS_DFS_PATHNAMES(inp) )
4049 return CM_ERROR_PATH_NOT_COVERED;
4051 return CM_ERROR_BADSHARENAME;
4053 #endif /* DFS_SUPPORT */
4055 /* now lock the vnode with a callback; returns with newScp locked */
4056 lock_ObtainMutex(&newScp->mx);
4057 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4058 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4059 if (code && code != CM_ERROR_NOACCESS) {
4060 lock_ReleaseMutex(&newScp->mx);
4061 cm_ReleaseSCache(newScp);
4062 cm_ReleaseUser(userp);
4066 attrs = smb_Attributes(newScp);
4068 if (!(attrs & SMB_ATTR_DIRECTORY))
4069 code = CM_ERROR_NOTDIR;
4071 lock_ReleaseMutex(&newScp->mx);
4073 cm_ReleaseSCache(newScp);
4074 cm_ReleaseUser(userp);
4078 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4082 cm_scache_t *rootScp;
4083 unsigned short attribute;
4085 cm_scache_t *newScp;
4094 /* decode basic attributes we're passed */
4095 attribute = smb_GetSMBParm(inp, 0);
4096 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4098 pathp = smb_GetSMBData(inp, NULL);
4099 pathp = smb_ParseASCIIBlock(pathp, NULL);
4101 return CM_ERROR_BADSMB;
4102 if (smb_StoreAnsiFilenames)
4103 OemToChar(pathp,pathp);
4105 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4106 dosTime, attribute);
4108 rootScp = cm_data.rootSCachep;
4110 userp = smb_GetUser(vcp, inp);
4112 caseFold = CM_FLAG_CASEFOLD;
4114 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4116 cm_ReleaseUser(userp);
4117 return CM_ERROR_NOSUCHFILE;
4119 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4120 tidPathp, &req, &newScp);
4123 cm_ReleaseUser(userp);
4128 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4129 cm_ReleaseSCache(newScp);
4130 cm_ReleaseUser(userp);
4131 if ( WANTS_DFS_PATHNAMES(inp) )
4132 return CM_ERROR_PATH_NOT_COVERED;
4134 return CM_ERROR_BADSHARENAME;
4136 #endif /* DFS_SUPPORT */
4138 /* now lock the vnode with a callback; returns with newScp locked; we
4139 * need the current status to determine what the new status is, in some
4142 lock_ObtainMutex(&newScp->mx);
4143 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4144 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4146 lock_ReleaseMutex(&newScp->mx);
4147 cm_ReleaseSCache(newScp);
4148 cm_ReleaseUser(userp);
4152 /* Check for RO volume */
4153 if (newScp->flags & CM_SCACHEFLAG_RO) {
4154 lock_ReleaseMutex(&newScp->mx);
4155 cm_ReleaseSCache(newScp);
4156 cm_ReleaseUser(userp);
4157 return CM_ERROR_READONLY;
4160 /* prepare for setattr call */
4163 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4164 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4166 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4167 /* we're told to make a writable file read-only */
4168 attr.unixModeBits = newScp->unixModeBits & ~0222;
4169 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4171 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4172 /* we're told to make a read-only file writable */
4173 attr.unixModeBits = newScp->unixModeBits | 0222;
4174 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4176 lock_ReleaseMutex(&newScp->mx);
4178 /* now call setattr */
4180 code = cm_SetAttr(newScp, &attr, userp, &req);
4184 cm_ReleaseSCache(newScp);
4185 cm_ReleaseUser(userp);
4190 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4194 cm_scache_t *rootScp;
4195 cm_scache_t *newScp, *dscp;
4207 pathp = smb_GetSMBData(inp, NULL);
4208 pathp = smb_ParseASCIIBlock(pathp, NULL);
4210 return CM_ERROR_BADSMB;
4212 if (*pathp == 0) /* null path */
4215 if (smb_StoreAnsiFilenames)
4216 OemToChar(pathp,pathp);
4218 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4219 osi_LogSaveString(smb_logp, pathp));
4221 rootScp = cm_data.rootSCachep;
4223 userp = smb_GetUser(vcp, inp);
4225 /* we shouldn't need this for V3 requests, but we seem to */
4226 caseFold = CM_FLAG_CASEFOLD;
4228 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4230 cm_ReleaseUser(userp);
4231 return CM_ERROR_NOSUCHFILE;
4235 * XXX Strange hack XXX
4237 * As of Patch 5 (16 July 97), we are having the following problem:
4238 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4239 * requests to look up "desktop.ini" in all the subdirectories.
4240 * This can cause zillions of timeouts looking up non-existent cells
4241 * and volumes, especially in the top-level directory.
4243 * We have not found any way to avoid this or work around it except
4244 * to explicitly ignore the requests for mount points that haven't
4245 * yet been evaluated and for directories that haven't yet been
4248 * We should modify this hack to provide a fake desktop.ini file
4249 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4251 spacep = inp->spacep;
4252 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4253 #ifndef SPECIAL_FOLDERS
4254 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4255 code = cm_NameI(rootScp, spacep->data,
4256 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4257 userp, tidPathp, &req, &dscp);
4260 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4261 if ( WANTS_DFS_PATHNAMES(inp) )
4262 return CM_ERROR_PATH_NOT_COVERED;
4264 return CM_ERROR_BADSHARENAME;
4266 #endif /* DFS_SUPPORT */
4267 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4268 code = CM_ERROR_NOSUCHFILE;
4269 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4270 cm_buf_t *bp = buf_Find(dscp, &hzero);
4274 code = CM_ERROR_NOSUCHFILE;
4276 cm_ReleaseSCache(dscp);
4278 cm_ReleaseUser(userp);
4283 #endif /* SPECIAL_FOLDERS */
4285 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4286 tidPathp, &req, &newScp);
4288 cm_ReleaseUser(userp);
4293 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4294 cm_ReleaseSCache(newScp);
4295 cm_ReleaseUser(userp);
4296 if ( WANTS_DFS_PATHNAMES(inp) )
4297 return CM_ERROR_PATH_NOT_COVERED;
4299 return CM_ERROR_BADSHARENAME;
4301 #endif /* DFS_SUPPORT */
4303 /* now lock the vnode with a callback; returns with newScp locked */
4304 lock_ObtainMutex(&newScp->mx);
4305 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4306 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4308 lock_ReleaseMutex(&newScp->mx);
4309 cm_ReleaseSCache(newScp);
4310 cm_ReleaseUser(userp);
4315 /* use smb_Attributes instead. Also the fact that a file is
4316 * in a readonly volume doesn't mean it shojuld be marked as RO
4318 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4319 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4320 attrs = SMB_ATTR_DIRECTORY;
4323 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4324 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4326 attrs = smb_Attributes(newScp);
4329 smb_SetSMBParm(outp, 0, attrs);
4331 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4332 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4333 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4334 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4335 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4336 smb_SetSMBParm(outp, 5, 0);
4337 smb_SetSMBParm(outp, 6, 0);
4338 smb_SetSMBParm(outp, 7, 0);
4339 smb_SetSMBParm(outp, 8, 0);
4340 smb_SetSMBParm(outp, 9, 0);
4341 smb_SetSMBDataLength(outp, 0);
4342 lock_ReleaseMutex(&newScp->mx);
4344 cm_ReleaseSCache(newScp);
4345 cm_ReleaseUser(userp);
4350 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4354 osi_Log0(smb_logp, "SMB receive tree disconnect");
4356 /* find the tree and free it */
4357 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4359 lock_ObtainMutex(&tidp->mx);
4360 tidp->flags |= SMB_TIDFLAG_DELETE;
4361 lock_ReleaseMutex(&tidp->mx);
4362 smb_ReleaseTID(tidp);
4368 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4386 pathp = smb_GetSMBData(inp, NULL);
4387 pathp = smb_ParseASCIIBlock(pathp, NULL);
4388 if (smb_StoreAnsiFilenames)
4389 OemToChar(pathp,pathp);
4391 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4393 #ifdef DEBUG_VERBOSE
4397 hexpath = osi_HexifyString( pathp );
4398 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4403 share = smb_GetSMBParm(inp, 0);
4404 attribute = smb_GetSMBParm(inp, 1);
4406 spacep = inp->spacep;
4407 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4408 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4409 /* special case magic file name for receiving IOCTL requests
4410 * (since IOCTL calls themselves aren't getting through).
4412 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4413 smb_SetupIoctlFid(fidp, spacep);
4414 smb_SetSMBParm(outp, 0, fidp->fid);
4415 smb_SetSMBParm(outp, 1, 0); /* attrs */
4416 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4417 smb_SetSMBParm(outp, 3, 0);
4418 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4419 smb_SetSMBParm(outp, 5, 0x7fff);
4420 /* pass the open mode back */
4421 smb_SetSMBParm(outp, 6, (share & 0xf));
4422 smb_SetSMBDataLength(outp, 0);
4423 smb_ReleaseFID(fidp);
4427 userp = smb_GetUser(vcp, inp);
4429 caseFold = CM_FLAG_CASEFOLD;
4431 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4433 cm_ReleaseUser(userp);
4434 return CM_ERROR_NOSUCHPATH;
4436 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4437 tidPathp, &req, &scp);
4440 cm_ReleaseUser(userp);
4445 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4446 cm_ReleaseSCache(scp);
4447 cm_ReleaseUser(userp);
4448 if ( WANTS_DFS_PATHNAMES(inp) )
4449 return CM_ERROR_PATH_NOT_COVERED;
4451 return CM_ERROR_BADSHARENAME;
4453 #endif /* DFS_SUPPORT */
4455 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4457 cm_ReleaseSCache(scp);
4458 cm_ReleaseUser(userp);
4462 /* don't need callback to check file type, since file types never
4463 * change, and namei and cm_Lookup all stat the object at least once on
4464 * a successful return.
4466 if (scp->fileType != CM_SCACHETYPE_FILE) {
4467 cm_ReleaseSCache(scp);
4468 cm_ReleaseUser(userp);
4469 return CM_ERROR_ISDIR;
4472 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4475 /* save a pointer to the vnode */
4478 if ((share & 0xf) == 0)
4479 fidp->flags |= SMB_FID_OPENREAD;
4480 else if ((share & 0xf) == 1)
4481 fidp->flags |= SMB_FID_OPENWRITE;
4483 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4485 lock_ObtainMutex(&scp->mx);
4486 smb_SetSMBParm(outp, 0, fidp->fid);
4487 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4488 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4489 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4490 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4491 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4492 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4493 /* pass the open mode back; XXXX add access checks */
4494 smb_SetSMBParm(outp, 6, (share & 0xf));
4495 smb_SetSMBDataLength(outp, 0);
4496 lock_ReleaseMutex(&scp->mx);
4499 cm_Open(scp, 0, userp);
4501 /* send and free packet */
4502 smb_ReleaseFID(fidp);
4503 cm_ReleaseUser(userp);
4504 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4508 typedef struct smb_unlinkRock {
4513 char *maskp; /* pointer to the star pattern */
4518 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4521 smb_unlinkRock_t *rockp;
4529 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4530 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4531 caseFold |= CM_FLAG_8DOT3;
4533 matchName = dep->name;
4534 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4536 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4537 !cm_Is8Dot3(dep->name)) {
4538 cm_Gen8Dot3Name(dep, shortName, NULL);
4539 matchName = shortName;
4540 /* 8.3 matches are always case insensitive */
4541 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4544 osi_Log1(smb_logp, "Unlinking %s",
4545 osi_LogSaveString(smb_logp, matchName));
4546 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4547 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4548 smb_NotifyChange(FILE_ACTION_REMOVED,
4549 FILE_NOTIFY_CHANGE_FILE_NAME,
4550 dscp, dep->name, NULL, TRUE);
4554 /* If we made a case sensitive exact match, we might as well quit now. */
4555 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4556 code = CM_ERROR_STOPNOW;
4564 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4573 smb_unlinkRock_t rock;
4582 attribute = smb_GetSMBParm(inp, 0);
4584 tp = smb_GetSMBData(inp, NULL);
4585 pathp = smb_ParseASCIIBlock(tp, &tp);
4586 if (smb_StoreAnsiFilenames)
4587 OemToChar(pathp,pathp);
4589 osi_Log1(smb_logp, "SMB receive unlink %s",
4590 osi_LogSaveString(smb_logp, pathp));
4592 spacep = inp->spacep;
4593 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4595 userp = smb_GetUser(vcp, inp);
4597 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4599 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4601 cm_ReleaseUser(userp);
4602 return CM_ERROR_NOSUCHPATH;
4604 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4607 cm_ReleaseUser(userp);
4612 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4613 cm_ReleaseSCache(dscp);
4614 cm_ReleaseUser(userp);
4615 if ( WANTS_DFS_PATHNAMES(inp) )
4616 return CM_ERROR_PATH_NOT_COVERED;
4618 return CM_ERROR_BADSHARENAME;
4620 #endif /* DFS_SUPPORT */
4622 /* otherwise, scp points to the parent directory. */
4629 rock.maskp = smb_FindMask(pathp);
4630 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4633 thyper.HighPart = 0;
4639 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4640 * match. If that fails, we do a case insensitve match.
4642 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4643 !smb_IsStarMask(rock.maskp)) {
4644 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4647 thyper.HighPart = 0;
4648 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4653 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4655 if (code == CM_ERROR_STOPNOW)
4658 cm_ReleaseUser(userp);
4660 cm_ReleaseSCache(dscp);
4662 if (code == 0 && !rock.any)
4663 code = CM_ERROR_NOSUCHFILE;
4667 typedef struct smb_renameRock {
4668 cm_scache_t *odscp; /* old dir */
4669 cm_scache_t *ndscp; /* new dir */
4670 cm_user_t *userp; /* user */
4671 cm_req_t *reqp; /* request struct */
4672 smb_vc_t *vcp; /* virtual circuit */
4673 char *maskp; /* pointer to star pattern of old file name */
4674 int flags; /* tilde, casefold, etc */
4675 char *newNamep; /* ptr to the new file's name */
4678 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4681 smb_renameRock_t *rockp;
4686 rockp = (smb_renameRock_t *) vrockp;
4688 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4689 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4690 caseFold |= CM_FLAG_8DOT3;
4692 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4694 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4695 !cm_Is8Dot3(dep->name)) {
4696 cm_Gen8Dot3Name(dep, shortName, NULL);
4697 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4700 code = cm_Rename(rockp->odscp, dep->name,
4701 rockp->ndscp, rockp->newNamep, rockp->userp,
4703 /* if the call worked, stop doing the search now, since we
4704 * really only want to rename one file.
4707 code = CM_ERROR_STOPNOW;
4716 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4719 cm_space_t *spacep = NULL;
4720 smb_renameRock_t rock;
4721 cm_scache_t *oldDscp = NULL;
4722 cm_scache_t *newDscp = NULL;
4723 cm_scache_t *tmpscp= NULL;
4724 cm_scache_t *tmpscp2 = NULL;
4734 userp = smb_GetUser(vcp, inp);
4735 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4737 cm_ReleaseUser(userp);
4738 return CM_ERROR_NOSUCHPATH;
4742 spacep = inp->spacep;
4743 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4746 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4747 * what actually exists is foo/baz. I don't know why the code used to be
4748 * the way it was. 1/29/96
4750 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4752 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4754 * caseFold = CM_FLAG_CASEFOLD;
4756 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4757 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4758 userp, tidPathp, &req, &oldDscp);
4760 cm_ReleaseUser(userp);
4765 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4766 cm_ReleaseSCache(oldDscp);
4767 cm_ReleaseUser(userp);
4768 if ( WANTS_DFS_PATHNAMES(inp) )
4769 return CM_ERROR_PATH_NOT_COVERED;
4771 return CM_ERROR_BADSHARENAME;
4773 #endif /* DFS_SUPPORT */
4775 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4776 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4777 userp, tidPathp, &req, &newDscp);
4780 cm_ReleaseSCache(oldDscp);
4781 cm_ReleaseUser(userp);
4786 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4787 cm_ReleaseSCache(oldDscp);
4788 cm_ReleaseSCache(newDscp);
4789 cm_ReleaseUser(userp);
4790 if ( WANTS_DFS_PATHNAMES(inp) )
4791 return CM_ERROR_PATH_NOT_COVERED;
4793 return CM_ERROR_BADSHARENAME;
4795 #endif /* DFS_SUPPORT */
4798 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4799 * next, get the component names, and lower case them.
4802 /* handle the old name first */
4804 oldLastNamep = oldPathp;
4808 /* and handle the new name, too */
4810 newLastNamep = newPathp;
4814 /* TODO: The old name could be a wildcard. The new name must not be */
4816 /* do the vnode call */
4817 rock.odscp = oldDscp;
4818 rock.ndscp = newDscp;
4822 rock.maskp = oldLastNamep;
4823 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4824 rock.newNamep = newLastNamep;
4826 /* Check if the file already exists; if so return error */
4827 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4828 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4829 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4830 osi_LogSaveString(afsd_logp, newLastNamep));
4832 /* Check if the old and the new names differ only in case. If so return
4833 * success, else return CM_ERROR_EXISTS
4835 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4837 /* This would be a success only if the old file is *as same as* the new file */
4838 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4840 if (tmpscp == tmpscp2)
4843 code = CM_ERROR_EXISTS;
4844 cm_ReleaseSCache(tmpscp2);
4847 code = CM_ERROR_NOSUCHFILE;
4850 /* file exist, do not rename, also fixes move */
4851 osi_Log0(smb_logp, "Can't rename. Target already exists");
4852 code = CM_ERROR_EXISTS;
4856 cm_ReleaseSCache(tmpscp);
4857 cm_ReleaseSCache(newDscp);
4858 cm_ReleaseSCache(oldDscp);
4859 cm_ReleaseUser(userp);
4863 /* Now search the directory for the pattern, and do the appropriate rename when found */
4864 thyper.LowPart = 0; /* search dir from here */
4865 thyper.HighPart = 0;
4867 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4869 if (code == CM_ERROR_STOPNOW)
4872 code = CM_ERROR_NOSUCHFILE;
4874 /* Handle Change Notification */
4876 * Being lazy, not distinguishing between files and dirs in this
4877 * filter, since we'd have to do a lookup.
4879 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4880 if (oldDscp == newDscp) {
4881 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4882 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4883 filter, oldDscp, oldLastNamep,
4884 newLastNamep, TRUE);
4886 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4887 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4888 filter, oldDscp, oldLastNamep,
4890 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4891 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4892 filter, newDscp, newLastNamep,
4897 cm_ReleaseSCache(tmpscp);
4898 cm_ReleaseUser(userp);
4899 cm_ReleaseSCache(oldDscp);
4900 cm_ReleaseSCache(newDscp);
4905 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4908 cm_space_t *spacep = NULL;
4909 cm_scache_t *oldDscp = NULL;
4910 cm_scache_t *newDscp = NULL;
4911 cm_scache_t *tmpscp= NULL;
4912 cm_scache_t *tmpscp2 = NULL;
4913 cm_scache_t *sscp = NULL;
4922 userp = smb_GetUser(vcp, inp);
4924 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4926 cm_ReleaseUser(userp);
4927 return CM_ERROR_NOSUCHPATH;
4932 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4934 spacep = inp->spacep;
4935 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4937 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4938 userp, tidPathp, &req, &oldDscp);
4940 cm_ReleaseUser(userp);
4945 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4946 cm_ReleaseSCache(oldDscp);
4947 cm_ReleaseUser(userp);
4948 if ( WANTS_DFS_PATHNAMES(inp) )
4949 return CM_ERROR_PATH_NOT_COVERED;
4951 return CM_ERROR_BADSHARENAME;
4953 #endif /* DFS_SUPPORT */
4955 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4956 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4957 userp, tidPathp, &req, &newDscp);
4959 cm_ReleaseSCache(oldDscp);
4960 cm_ReleaseUser(userp);
4965 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4966 cm_ReleaseSCache(newDscp);
4967 cm_ReleaseSCache(oldDscp);
4968 cm_ReleaseUser(userp);
4969 if ( WANTS_DFS_PATHNAMES(inp) )
4970 return CM_ERROR_PATH_NOT_COVERED;
4972 return CM_ERROR_BADSHARENAME;
4974 #endif /* DFS_SUPPORT */
4976 /* Now, although we did two lookups for the two directories (because the same
4977 * directory can be referenced through different paths), we only allow hard links
4978 * within the same directory. */
4979 if (oldDscp != newDscp) {
4980 cm_ReleaseSCache(oldDscp);
4981 cm_ReleaseSCache(newDscp);
4982 cm_ReleaseUser(userp);
4983 return CM_ERROR_CROSSDEVLINK;
4986 /* handle the old name first */
4988 oldLastNamep = oldPathp;
4992 /* and handle the new name, too */
4994 newLastNamep = newPathp;
4998 /* now lookup the old name */
4999 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5000 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5002 cm_ReleaseSCache(oldDscp);
5003 cm_ReleaseSCache(newDscp);
5004 cm_ReleaseUser(userp);
5008 /* Check if the file already exists; if so return error */
5009 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5010 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5011 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5012 osi_LogSaveString(afsd_logp, newLastNamep));
5014 /* if the existing link is to the same file, then we return success */
5016 if(sscp == tmpscp) {
5019 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5020 code = CM_ERROR_EXISTS;
5025 cm_ReleaseSCache(tmpscp);
5026 cm_ReleaseSCache(sscp);
5027 cm_ReleaseSCache(newDscp);
5028 cm_ReleaseSCache(oldDscp);
5029 cm_ReleaseUser(userp);
5033 /* now create the hardlink */
5034 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5035 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5036 osi_Log1(smb_logp," Link returns %d", code);
5038 /* Handle Change Notification */
5040 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5041 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5042 smb_NotifyChange(FILE_ACTION_ADDED,
5043 filter, newDscp, newLastNamep,
5048 cm_ReleaseSCache(tmpscp);
5049 cm_ReleaseUser(userp);
5050 cm_ReleaseSCache(sscp);
5051 cm_ReleaseSCache(oldDscp);
5052 cm_ReleaseSCache(newDscp);
5057 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5063 tp = smb_GetSMBData(inp, NULL);
5064 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5065 if (smb_StoreAnsiFilenames)
5066 OemToChar(oldPathp,oldPathp);
5067 newPathp = smb_ParseASCIIBlock(tp, &tp);
5068 if (smb_StoreAnsiFilenames)
5069 OemToChar(newPathp,newPathp);
5071 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5072 osi_LogSaveString(smb_logp, oldPathp),
5073 osi_LogSaveString(smb_logp, newPathp));
5075 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5080 typedef struct smb_rmdirRock {
5084 char *maskp; /* pointer to the star pattern */
5089 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5092 smb_rmdirRock_t *rockp;
5097 rockp = (smb_rmdirRock_t *) vrockp;
5099 matchName = dep->name;
5100 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5101 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5103 match = (strcmp(matchName, rockp->maskp) == 0);
5105 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5106 !cm_Is8Dot3(dep->name)) {
5107 cm_Gen8Dot3Name(dep, shortName, NULL);
5108 matchName = shortName;
5109 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5112 osi_Log1(smb_logp, "Removing directory %s",
5113 osi_LogSaveString(smb_logp, matchName));
5114 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5115 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5116 smb_NotifyChange(FILE_ACTION_REMOVED,
5117 FILE_NOTIFY_CHANGE_DIR_NAME,
5118 dscp, dep->name, NULL, TRUE);
5127 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5135 smb_rmdirRock_t rock;
5144 tp = smb_GetSMBData(inp, NULL);
5145 pathp = smb_ParseASCIIBlock(tp, &tp);
5146 if (smb_StoreAnsiFilenames)
5147 OemToChar(pathp,pathp);
5149 spacep = inp->spacep;
5150 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5152 userp = smb_GetUser(vcp, inp);
5154 caseFold = CM_FLAG_CASEFOLD;
5156 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5158 cm_ReleaseUser(userp);
5159 return CM_ERROR_NOSUCHPATH;
5161 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5162 userp, tidPathp, &req, &dscp);
5165 cm_ReleaseUser(userp);
5170 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5171 cm_ReleaseSCache(dscp);
5172 cm_ReleaseUser(userp);
5173 if ( WANTS_DFS_PATHNAMES(inp) )
5174 return CM_ERROR_PATH_NOT_COVERED;
5176 return CM_ERROR_BADSHARENAME;
5178 #endif /* DFS_SUPPORT */
5180 /* otherwise, scp points to the parent directory. */
5187 rock.maskp = lastNamep;
5188 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5191 thyper.HighPart = 0;
5195 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5196 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5197 if (code == 0 && !rock.any) {
5199 thyper.HighPart = 0;
5200 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5201 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5204 cm_ReleaseUser(userp);
5206 cm_ReleaseSCache(dscp);
5208 if (code == 0 && !rock.any)
5209 code = CM_ERROR_NOSUCHFILE;
5213 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5223 fid = smb_GetSMBParm(inp, 0);
5225 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5227 fid = smb_ChainFID(fid, inp);
5228 fidp = smb_FindFID(vcp, fid, 0);
5229 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5231 smb_ReleaseFID(fidp);
5232 return CM_ERROR_BADFD;
5235 userp = smb_GetUser(vcp, inp);
5237 lock_ObtainMutex(&fidp->mx);
5238 if (fidp->flags & SMB_FID_OPENWRITE)
5239 code = cm_FSync(fidp->scp, userp, &req);
5242 lock_ReleaseMutex(&fidp->mx);
5244 smb_ReleaseFID(fidp);
5246 cm_ReleaseUser(userp);
5251 struct smb_FullNameRock {
5257 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5261 struct smb_FullNameRock *vrockp;
5263 vrockp = (struct smb_FullNameRock *)rockp;
5265 if (!cm_Is8Dot3(dep->name)) {
5266 cm_Gen8Dot3Name(dep, shortName, NULL);
5268 if (cm_stricmp(shortName, vrockp->name) == 0) {
5269 vrockp->fullName = strdup(dep->name);
5270 return CM_ERROR_STOPNOW;
5273 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5274 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5275 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5276 vrockp->fullName = strdup(dep->name);
5277 return CM_ERROR_STOPNOW;
5282 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5283 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5285 struct smb_FullNameRock rock;
5291 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5292 if (code == CM_ERROR_STOPNOW)
5293 *newPathp = rock.fullName;
5295 *newPathp = strdup(pathp);
5298 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5309 fid = smb_GetSMBParm(inp, 0);
5310 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5312 osi_Log1(smb_logp, "SMB close fid %d", fid);
5314 fid = smb_ChainFID(fid, inp);
5315 fidp = smb_FindFID(vcp, fid, 0);
5317 return CM_ERROR_BADFD;
5320 userp = smb_GetUser(vcp, inp);
5322 lock_ObtainMutex(&fidp->mx);
5324 /* Don't jump the gun on an async raw write */
5325 while (fidp->raw_writers) {
5326 lock_ReleaseMutex(&fidp->mx);
5327 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5328 lock_ObtainMutex(&fidp->mx);
5331 fidp->flags |= SMB_FID_DELETE;
5333 /* watch for ioctl closes, and read-only opens */
5334 if (fidp->scp != NULL &&
5335 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5336 == SMB_FID_OPENWRITE) {
5337 if (dosTime != 0 && dosTime != -1) {
5338 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5339 /* This fixes defect 10958 */
5340 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5341 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5343 code = cm_FSync(fidp->scp, userp, &req);
5348 if (fidp->flags & SMB_FID_DELONCLOSE) {
5349 cm_scache_t *dscp = fidp->NTopen_dscp;
5350 char *pathp = fidp->NTopen_pathp;
5353 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5354 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5355 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5356 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5357 smb_NotifyChange(FILE_ACTION_REMOVED,
5358 FILE_NOTIFY_CHANGE_DIR_NAME,
5359 dscp, fullPathp, NULL, TRUE);
5363 code = cm_Unlink(dscp, fullPathp, userp, &req);
5364 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5365 smb_NotifyChange(FILE_ACTION_REMOVED,
5366 FILE_NOTIFY_CHANGE_FILE_NAME,
5367 dscp, fullPathp, NULL, TRUE);
5371 lock_ReleaseMutex(&fidp->mx);
5373 if (fidp->flags & SMB_FID_NTOPEN) {
5374 cm_ReleaseSCache(fidp->NTopen_dscp);
5375 free(fidp->NTopen_pathp);
5377 if (fidp->NTopen_wholepathp)
5378 free(fidp->NTopen_wholepathp);
5380 smb_ReleaseFID(fidp);
5381 cm_ReleaseUser(userp);
5386 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5389 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5390 cm_user_t *userp, long *readp)
5392 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5393 cm_user_t *userp, long *readp, int dosflag)
5400 osi_hyper_t fileLength;
5402 osi_hyper_t lastByte;
5403 osi_hyper_t bufferOffset;
5404 long bufIndex, nbytes;
5414 lock_ObtainMutex(&fidp->mx);
5416 lock_ObtainMutex(&scp->mx);
5418 if (offset.HighPart == 0) {
5419 chunk = offset.LowPart >> cm_logChunkSize;
5420 if (chunk != fidp->curr_chunk) {
5421 fidp->prev_chunk = fidp->curr_chunk;
5422 fidp->curr_chunk = chunk;
5424 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5428 /* start by looking up the file's end */
5429 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5430 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5431 if (code) goto done;
5433 /* now we have the entry locked, look up the length */
5434 fileLength = scp->length;
5436 /* adjust count down so that it won't go past EOF */
5437 thyper.LowPart = count;
5438 thyper.HighPart = 0;
5439 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5441 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5442 /* we'd read past EOF, so just stop at fileLength bytes.
5443 * Start by computing how many bytes remain in the file.
5445 thyper = LargeIntegerSubtract(fileLength, offset);
5447 /* if we are past EOF, read 0 bytes */
5448 if (LargeIntegerLessThanZero(thyper))
5451 count = thyper.LowPart;
5456 /* now, copy the data one buffer at a time,
5457 * until we've filled the request packet
5460 /* if we've copied all the data requested, we're done */
5461 if (count <= 0) break;
5463 /* otherwise, load up a buffer of data */
5464 thyper.HighPart = offset.HighPart;
5465 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5466 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5469 buf_Release(bufferp);
5472 lock_ReleaseMutex(&scp->mx);
5474 lock_ObtainRead(&scp->bufCreateLock);
5475 code = buf_Get(scp, &thyper, &bufferp);
5476 lock_ReleaseRead(&scp->bufCreateLock);
5478 lock_ObtainMutex(&scp->mx);
5479 if (code) goto done;
5480 bufferOffset = thyper;
5482 /* now get the data in the cache */
5484 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5485 CM_SCACHESYNC_NEEDCALLBACK |
5486 CM_SCACHESYNC_READ);
5487 if (code) goto done;
5489 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5491 /* otherwise, load the buffer and try again */
5492 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5496 buf_Release(bufferp);
5500 } /* if (wrong buffer) ... */
5502 /* now we have the right buffer loaded. Copy out the
5503 * data from here to the user's buffer.
5505 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5507 /* and figure out how many bytes we want from this buffer */
5508 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5509 if (nbytes > count) nbytes = count; /* don't go past EOF */
5511 /* now copy the data */
5514 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5517 memcpy(op, bufferp->datap + bufIndex, nbytes);
5519 /* adjust counters, pointers, etc. */
5522 thyper.LowPart = nbytes;
5523 thyper.HighPart = 0;
5524 offset = LargeIntegerAdd(thyper, offset);
5528 lock_ReleaseMutex(&scp->mx);
5529 lock_ReleaseMutex(&fidp->mx);
5531 buf_Release(bufferp);
5533 if (code == 0 && sequential)
5534 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5540 * smb_WriteData -- common code for Write and Raw Write
5543 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5544 cm_user_t *userp, long *writtenp)
5546 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5547 cm_user_t *userp, long *writtenp, int dosflag)
5554 osi_hyper_t fileLength; /* file's length at start of write */
5555 osi_hyper_t minLength; /* don't read past this */
5556 long nbytes; /* # of bytes to transfer this iteration */
5558 osi_hyper_t thyper; /* hyper tmp variable */
5559 osi_hyper_t bufferOffset;
5560 long bufIndex; /* index in buffer where our data is */
5562 osi_hyper_t writeBackOffset;/* offset of region to write back when
5567 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5568 fidp->fid, offsetp->LowPart, count);
5578 lock_ObtainMutex(&fidp->mx);
5580 lock_ObtainMutex(&scp->mx);
5582 /* start by looking up the file's end */
5583 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5584 CM_SCACHESYNC_NEEDCALLBACK
5585 | CM_SCACHESYNC_SETSTATUS
5586 | CM_SCACHESYNC_GETSTATUS);
5590 /* make sure we have a writable FD */
5591 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5592 code = CM_ERROR_BADFDOP;
5596 /* now we have the entry locked, look up the length */
5597 fileLength = scp->length;
5598 minLength = fileLength;
5599 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5600 minLength = scp->serverLength;
5602 /* adjust file length if we extend past EOF */
5603 thyper.LowPart = count;
5604 thyper.HighPart = 0;
5605 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5606 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5607 /* we'd write past EOF, so extend the file */
5608 scp->mask |= CM_SCACHEMASK_LENGTH;
5609 scp->length = thyper;
5610 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5612 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5614 /* now, if the new position (thyper) and the old (offset) are in
5615 * different storeback windows, remember to store back the previous
5616 * storeback window when we're done with the write.
5618 if ((thyper.LowPart & (-cm_chunkSize)) !=
5619 (offset.LowPart & (-cm_chunkSize))) {
5620 /* they're different */
5622 writeBackOffset.HighPart = offset.HighPart;
5623 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5628 /* now, copy the data one buffer at a time, until we've filled the
5631 /* if we've copied all the data requested, we're done */
5635 /* handle over quota or out of space */
5636 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5637 *writtenp = written;
5638 code = CM_ERROR_QUOTA;
5642 /* otherwise, load up a buffer of data */
5643 thyper.HighPart = offset.HighPart;
5644 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5645 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5648 lock_ReleaseMutex(&bufferp->mx);
5649 buf_Release(bufferp);
5652 lock_ReleaseMutex(&scp->mx);
5654 lock_ObtainRead(&scp->bufCreateLock);
5655 code = buf_Get(scp, &thyper, &bufferp);
5656 lock_ReleaseRead(&scp->bufCreateLock);
5658 lock_ObtainMutex(&bufferp->mx);
5659 lock_ObtainMutex(&scp->mx);
5660 if (code) goto done;
5662 bufferOffset = thyper;
5664 /* now get the data in the cache */
5666 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5667 CM_SCACHESYNC_NEEDCALLBACK
5668 | CM_SCACHESYNC_WRITE
5669 | CM_SCACHESYNC_BUFLOCKED);
5673 /* If we're overwriting the entire buffer, or
5674 * if we're writing at or past EOF, mark the
5675 * buffer as current so we don't call
5676 * cm_GetBuffer. This skips the fetch from the
5677 * server in those cases where we're going to
5678 * obliterate all the data in the buffer anyway,
5679 * or in those cases where there is no useful
5680 * data at the server to start with.
5682 * Use minLength instead of scp->length, since
5683 * the latter has already been updated by this
5686 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5687 || LargeIntegerEqualTo(offset, bufferp->offset)
5688 && (count >= cm_data.buf_blockSize
5689 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5690 ConvertLongToLargeInteger(count)),
5692 if (count < cm_data.buf_blockSize
5693 && bufferp->dataVersion == -1)
5694 memset(bufferp->datap, 0,
5695 cm_data.buf_blockSize);
5696 bufferp->dataVersion = scp->dataVersion;
5699 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5701 /* otherwise, load the buffer and try again */
5702 lock_ReleaseMutex(&bufferp->mx);
5703 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5705 lock_ReleaseMutex(&scp->mx);
5706 lock_ObtainMutex(&bufferp->mx);
5707 lock_ObtainMutex(&scp->mx);
5711 lock_ReleaseMutex(&bufferp->mx);
5712 buf_Release(bufferp);
5716 } /* if (wrong buffer) ... */
5718 /* now we have the right buffer loaded. Copy out the
5719 * data from here to the user's buffer.
5721 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5723 /* and figure out how many bytes we want from this buffer */
5724 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5726 nbytes = count; /* don't go past end of request */
5728 /* now copy the data */
5731 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5734 memcpy(bufferp->datap + bufIndex, op, nbytes);
5735 buf_SetDirty(bufferp);
5737 /* and record the last writer */
5738 if (bufferp->userp != userp) {
5741 cm_ReleaseUser(bufferp->userp);
5742 bufferp->userp = userp;
5745 /* adjust counters, pointers, etc. */
5749 thyper.LowPart = nbytes;
5750 thyper.HighPart = 0;
5751 offset = LargeIntegerAdd(thyper, offset);
5755 lock_ReleaseMutex(&scp->mx);
5756 lock_ReleaseMutex(&fidp->mx);
5758 lock_ReleaseMutex(&bufferp->mx);
5759 buf_Release(bufferp);
5762 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5763 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5764 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5765 fidp->NTopen_dscp, fidp->NTopen_pathp,
5769 if (code == 0 && doWriteBack) {
5771 lock_ObtainMutex(&scp->mx);
5772 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5774 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5775 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5777 lock_ReleaseMutex(&scp->mx);
5778 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5779 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5782 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5783 fidp->fid, code, *writtenp);
5787 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5790 long count, written = 0, total_written = 0;
5795 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5797 int inDataBlockCount;
5799 fd = smb_GetSMBParm(inp, 0);
5800 count = smb_GetSMBParm(inp, 1);
5801 offset.HighPart = 0; /* too bad */
5802 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5804 op = smb_GetSMBData(inp, NULL);
5805 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5807 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5808 fd, offset.LowPart, count);
5810 fd = smb_ChainFID(fd, inp);
5811 fidp = smb_FindFID(vcp, fd, 0);
5813 return CM_ERROR_BADFD;
5816 if (fidp->flags & SMB_FID_IOCTL)
5817 return smb_IoctlWrite(fidp, vcp, inp, outp);
5819 userp = smb_GetUser(vcp, inp);
5821 /* special case: 0 bytes transferred means truncate to this position */
5827 truncAttr.mask = CM_ATTRMASK_LENGTH;
5828 truncAttr.length.LowPart = offset.LowPart;
5829 truncAttr.length.HighPart = 0;
5830 lock_ObtainMutex(&fidp->mx);
5831 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5832 lock_ReleaseMutex(&fidp->mx);
5833 smb_SetSMBParm(outp, 0, /* count */ 0);
5834 smb_SetSMBDataLength(outp, 0);
5835 fidp->flags |= SMB_FID_LENGTHSETDONE;
5840 * Work around bug in NT client
5842 * When copying a file, the NT client should first copy the data,
5843 * then copy the last write time. But sometimes the NT client does
5844 * these in the wrong order, so the data copies would inadvertently
5845 * cause the last write time to be overwritten. We try to detect this,
5846 * and don't set client mod time if we think that would go against the
5849 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5850 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5851 fidp->scp->clientModTime = time(NULL);
5855 while ( code == 0 && count > 0 ) {
5857 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5859 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5861 if (code == 0 && written == 0)
5862 code = CM_ERROR_PARTIALWRITE;
5864 offset.LowPart += written;
5866 total_written += written;
5870 /* set the packet data length to 3 bytes for the data block header,
5871 * plus the size of the data.
5873 smb_SetSMBParm(outp, 0, total_written);
5874 smb_SetSMBDataLength(outp, 0);
5877 smb_ReleaseFID(fidp);
5878 cm_ReleaseUser(userp);
5883 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5884 NCB *ncbp, raw_write_cont_t *rwcp)
5897 fd = smb_GetSMBParm(inp, 0);
5898 fidp = smb_FindFID(vcp, fd, 0);
5900 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5901 rwcp->offset.LowPart, rwcp->count);
5903 userp = smb_GetUser(vcp, inp);
5907 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5910 rawBuf = (dos_ptr) rwcp->buf;
5911 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5912 (unsigned char *) rawBuf, userp,
5916 if (rwcp->writeMode & 0x1) { /* synchronous */
5919 smb_FormatResponsePacket(vcp, inp, outp);
5920 op = (smb_t *) outp;
5921 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5922 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5923 smb_SetSMBDataLength(outp, 0);
5924 smb_SendPacket(vcp, outp);
5925 smb_FreePacket(outp);
5927 else { /* asynchronous */
5928 lock_ObtainMutex(&fidp->mx);
5929 fidp->raw_writers--;
5930 if (fidp->raw_writers == 0)
5931 thrd_SetEvent(fidp->raw_write_event);
5932 lock_ReleaseMutex(&fidp->mx);
5935 /* Give back raw buffer */
5936 lock_ObtainMutex(&smb_RawBufLock);
5938 *((char **)rawBuf) = smb_RawBufs;
5940 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5942 smb_RawBufs = rawBuf;
5943 lock_ReleaseMutex(&smb_RawBufLock);
5945 smb_ReleaseFID(fidp);
5946 cm_ReleaseUser(userp);
5949 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5954 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5957 long count, written = 0, total_written = 0;
5964 unsigned short writeMode;
5971 fd = smb_GetSMBParm(inp, 0);
5972 totalCount = smb_GetSMBParm(inp, 1);
5973 count = smb_GetSMBParm(inp, 10);
5974 offset.HighPart = 0; /* too bad */
5975 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5976 writeMode = smb_GetSMBParm(inp, 7);
5978 op = (char *) inp->data;
5979 op += smb_GetSMBParm(inp, 11);
5982 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5983 fd, offset.LowPart, count, writeMode);
5985 fd = smb_ChainFID(fd, inp);
5986 fidp = smb_FindFID(vcp, fd, 0);
5988 return CM_ERROR_BADFD;
5991 userp = smb_GetUser(vcp, inp);
5994 * Work around bug in NT client
5996 * When copying a file, the NT client should first copy the data,
5997 * then copy the last write time. But sometimes the NT client does
5998 * these in the wrong order, so the data copies would inadvertently
5999 * cause the last write time to be overwritten. We try to detect this,
6000 * and don't set client mod time if we think that would go against the
6003 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6004 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6005 fidp->scp->clientModTime = time(NULL);
6009 while ( code == 0 && count > 0 ) {
6011 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6013 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6015 if (code == 0 && written == 0)
6016 code = CM_ERROR_PARTIALWRITE;
6018 offset.LowPart += written;
6020 total_written += written;
6024 /* Get a raw buffer */
6027 lock_ObtainMutex(&smb_RawBufLock);
6029 /* Get a raw buf, from head of list */
6030 rawBuf = smb_RawBufs;
6032 smb_RawBufs = *(char **)smb_RawBufs;
6034 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6038 code = CM_ERROR_USESTD;
6040 lock_ReleaseMutex(&smb_RawBufLock);
6043 /* Don't allow a premature Close */
6044 if (code == 0 && (writeMode & 1) == 0) {
6045 lock_ObtainMutex(&fidp->mx);
6046 fidp->raw_writers++;
6047 thrd_ResetEvent(fidp->raw_write_event);
6048 lock_ReleaseMutex(&fidp->mx);
6051 smb_ReleaseFID(fidp);
6052 cm_ReleaseUser(userp);
6055 smb_SetSMBParm(outp, 0, total_written);
6056 smb_SetSMBDataLength(outp, 0);
6057 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6064 rwcp->offset.HighPart = 0;
6065 rwcp->offset.LowPart = offset.LowPart + count;
6066 rwcp->count = totalCount - count;
6067 rwcp->writeMode = writeMode;
6068 rwcp->alreadyWritten = total_written;
6070 /* set the packet data length to 3 bytes for the data block header,
6071 * plus the size of the data.
6073 smb_SetSMBParm(outp, 0, 0xffff);
6074 smb_SetSMBDataLength(outp, 0);
6079 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6082 long count, finalCount;
6089 fd = smb_GetSMBParm(inp, 0);
6090 count = smb_GetSMBParm(inp, 1);
6091 offset.HighPart = 0; /* too bad */
6092 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6094 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6095 fd, offset.LowPart, count);
6097 fd = smb_ChainFID(fd, inp);
6098 fidp = smb_FindFID(vcp, fd, 0);
6100 return CM_ERROR_BADFD;
6103 if (fidp->flags & SMB_FID_IOCTL) {
6104 return smb_IoctlRead(fidp, vcp, inp, outp);
6107 userp = smb_GetUser(vcp, inp);
6109 /* remember this for final results */
6110 smb_SetSMBParm(outp, 0, count);
6111 smb_SetSMBParm(outp, 1, 0);
6112 smb_SetSMBParm(outp, 2, 0);
6113 smb_SetSMBParm(outp, 3, 0);
6114 smb_SetSMBParm(outp, 4, 0);
6116 /* set the packet data length to 3 bytes for the data block header,
6117 * plus the size of the data.
6119 smb_SetSMBDataLength(outp, count+3);
6121 /* get op ptr after putting in the parms, since otherwise we don't
6122 * know where the data really is.
6124 op = smb_GetSMBData(outp, NULL);
6126 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6127 *op++ = 1; /* data block marker */
6128 *op++ = (unsigned char) (count & 0xff);
6129 *op++ = (unsigned char) ((count >> 8) & 0xff);
6132 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6134 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6137 /* fix some things up */
6138 smb_SetSMBParm(outp, 0, finalCount);
6139 smb_SetSMBDataLength(outp, finalCount+3);
6141 smb_ReleaseFID(fidp);
6143 cm_ReleaseUser(userp);
6147 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6154 cm_scache_t *dscp; /* dir we're dealing with */
6155 cm_scache_t *scp; /* file we're creating */
6157 int initialModeBits;
6167 /* compute initial mode bits based on read-only flag in attributes */
6168 initialModeBits = 0777;
6170 tp = smb_GetSMBData(inp, NULL);
6171 pathp = smb_ParseASCIIBlock(tp, &tp);
6172 if (smb_StoreAnsiFilenames)
6173 OemToChar(pathp,pathp);
6175 if (strcmp(pathp, "\\") == 0)
6176 return CM_ERROR_EXISTS;
6178 spacep = inp->spacep;
6179 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6181 userp = smb_GetUser(vcp, inp);
6183 caseFold = CM_FLAG_CASEFOLD;
6185 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6187 cm_ReleaseUser(userp);
6188 return CM_ERROR_NOSUCHPATH;
6191 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6192 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6193 userp, tidPathp, &req, &dscp);
6196 cm_ReleaseUser(userp);
6201 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6202 cm_ReleaseSCache(dscp);
6203 cm_ReleaseUser(userp);
6204 if ( WANTS_DFS_PATHNAMES(inp) )
6205 return CM_ERROR_PATH_NOT_COVERED;
6207 return CM_ERROR_BADSHARENAME;
6209 #endif /* DFS_SUPPORT */
6211 /* otherwise, scp points to the parent directory. Do a lookup, and
6212 * fail if we find it. Otherwise, we do the create.
6218 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6219 if (scp) cm_ReleaseSCache(scp);
6220 if (code != CM_ERROR_NOSUCHFILE) {
6221 if (code == 0) code = CM_ERROR_EXISTS;
6222 cm_ReleaseSCache(dscp);
6223 cm_ReleaseUser(userp);
6227 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6228 setAttr.clientModTime = time(NULL);
6229 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6230 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6231 smb_NotifyChange(FILE_ACTION_ADDED,
6232 FILE_NOTIFY_CHANGE_DIR_NAME,
6233 dscp, lastNamep, NULL, TRUE);
6235 /* we don't need this any longer */
6236 cm_ReleaseSCache(dscp);
6239 /* something went wrong creating or truncating the file */
6240 cm_ReleaseUser(userp);
6244 /* otherwise we succeeded */
6245 smb_SetSMBDataLength(outp, 0);
6246 cm_ReleaseUser(userp);
6251 BOOL smb_IsLegalFilename(char *filename)
6254 * Find the longest substring of filename that does not contain
6255 * any of the chars in illegalChars. If that substring is less
6256 * than the length of the whole string, then one or more of the
6257 * illegal chars is in filename.
6259 if (strcspn(filename, illegalChars) < strlen(filename))
6265 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6273 cm_scache_t *dscp; /* dir we're dealing with */
6274 cm_scache_t *scp; /* file we're creating */
6276 int initialModeBits;
6288 excl = (inp->inCom == 0x03)? 0 : 1;
6290 attributes = smb_GetSMBParm(inp, 0);
6291 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6293 /* compute initial mode bits based on read-only flag in attributes */
6294 initialModeBits = 0666;
6295 if (attributes & 1) initialModeBits &= ~0222;
6297 tp = smb_GetSMBData(inp, NULL);
6298 pathp = smb_ParseASCIIBlock(tp, &tp);
6299 if (smb_StoreAnsiFilenames)
6300 OemToChar(pathp,pathp);
6302 spacep = inp->spacep;
6303 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6305 userp = smb_GetUser(vcp, inp);
6307 caseFold = CM_FLAG_CASEFOLD;
6309 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6311 cm_ReleaseUser(userp);
6312 return CM_ERROR_NOSUCHPATH;
6314 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6315 userp, tidPathp, &req, &dscp);
6318 cm_ReleaseUser(userp);
6323 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6324 cm_ReleaseSCache(dscp);
6325 cm_ReleaseUser(userp);
6326 if ( WANTS_DFS_PATHNAMES(inp) )
6327 return CM_ERROR_PATH_NOT_COVERED;
6329 return CM_ERROR_BADSHARENAME;
6331 #endif /* DFS_SUPPORT */
6333 /* otherwise, scp points to the parent directory. Do a lookup, and
6334 * truncate the file if we find it, otherwise we create the file.
6341 if (!smb_IsLegalFilename(lastNamep))
6342 return CM_ERROR_BADNTFILENAME;
6344 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6345 #ifdef DEBUG_VERBOSE
6348 hexp = osi_HexifyString( lastNamep );
6349 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6354 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6355 if (code && code != CM_ERROR_NOSUCHFILE) {
6356 cm_ReleaseSCache(dscp);
6357 cm_ReleaseUser(userp);
6361 /* if we get here, if code is 0, the file exists and is represented by
6362 * scp. Otherwise, we have to create it.
6366 /* oops, file shouldn't be there */
6367 cm_ReleaseSCache(dscp);
6368 cm_ReleaseSCache(scp);
6369 cm_ReleaseUser(userp);
6370 return CM_ERROR_EXISTS;
6373 setAttr.mask = CM_ATTRMASK_LENGTH;
6374 setAttr.length.LowPart = 0;
6375 setAttr.length.HighPart = 0;
6376 code = cm_SetAttr(scp, &setAttr, userp, &req);
6379 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6380 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6381 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6383 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6384 smb_NotifyChange(FILE_ACTION_ADDED,
6385 FILE_NOTIFY_CHANGE_FILE_NAME,
6386 dscp, lastNamep, NULL, TRUE);
6387 if (!excl && code == CM_ERROR_EXISTS) {
6388 /* not an exclusive create, and someone else tried
6389 * creating it already, then we open it anyway. We
6390 * don't bother retrying after this, since if this next
6391 * fails, that means that the file was deleted after
6392 * we started this call.
6394 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6397 setAttr.mask = CM_ATTRMASK_LENGTH;
6398 setAttr.length.LowPart = 0;
6399 setAttr.length.HighPart = 0;
6400 code = cm_SetAttr(scp, &setAttr, userp, &req);
6405 /* we don't need this any longer */
6406 cm_ReleaseSCache(dscp);
6409 /* something went wrong creating or truncating the file */
6410 if (scp) cm_ReleaseSCache(scp);
6411 cm_ReleaseUser(userp);
6415 /* make sure we only open files */
6416 if (scp->fileType != CM_SCACHETYPE_FILE) {
6417 cm_ReleaseSCache(scp);
6418 cm_ReleaseUser(userp);
6419 return CM_ERROR_ISDIR;
6422 /* now all we have to do is open the file itself */
6423 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6426 /* save a pointer to the vnode */
6429 /* always create it open for read/write */
6430 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6432 smb_ReleaseFID(fidp);
6434 smb_SetSMBParm(outp, 0, fidp->fid);
6435 smb_SetSMBDataLength(outp, 0);
6437 cm_Open(scp, 0, userp);
6439 cm_ReleaseUser(userp);
6440 /* leave scp held since we put it in fidp->scp */
6444 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6457 fd = smb_GetSMBParm(inp, 0);
6458 whence = smb_GetSMBParm(inp, 1);
6459 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6461 /* try to find the file descriptor */
6462 fd = smb_ChainFID(fd, inp);
6463 fidp = smb_FindFID(vcp, fd, 0);
6464 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6465 return CM_ERROR_BADFD;
6468 userp = smb_GetUser(vcp, inp);
6470 lock_ObtainMutex(&fidp->mx);
6472 lock_ObtainMutex(&scp->mx);
6473 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6474 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6477 /* offset from current offset */
6478 offset += fidp->offset;
6480 else if (whence == 2) {
6481 /* offset from current EOF */
6482 offset += scp->length.LowPart;
6484 fidp->offset = offset;
6485 smb_SetSMBParm(outp, 0, offset & 0xffff);
6486 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6487 smb_SetSMBDataLength(outp, 0);
6489 lock_ReleaseMutex(&scp->mx);
6490 lock_ReleaseMutex(&fidp->mx);
6491 smb_ReleaseFID(fidp);
6492 cm_ReleaseUser(userp);
6496 /* dispatch all of the requests received in a packet. Due to chaining, this may
6497 * be more than one request.
6499 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6500 NCB *ncbp, raw_write_cont_t *rwcp)
6504 unsigned long code = 0;
6505 unsigned char *outWctp;
6506 int nparms; /* # of bytes of parameters */
6508 int nbytes; /* bytes of data, excluding count */
6511 unsigned short errCode;
6512 unsigned long NTStatus;
6514 unsigned char errClass;
6515 unsigned int oldGen;
6516 DWORD oldTime, newTime;
6518 /* get easy pointer to the data */
6519 smbp = (smb_t *) inp->data;
6521 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6522 /* setup the basic parms for the initial request in the packet */
6523 inp->inCom = smbp->com;
6524 inp->wctp = &smbp->wct;
6526 inp->ncb_length = ncbp->ncb_length;
6531 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6532 /* log it and discard it */
6537 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6538 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6540 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6541 1, ncbp->ncb_length, ptbuf, inp);
6542 DeregisterEventSource(h);
6544 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6549 /* We are an ongoing op */
6550 thrd_Increment(&ongoingOps);
6552 /* set up response packet for receiving output */
6553 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6554 smb_FormatResponsePacket(vcp, inp, outp);
6555 outWctp = outp->wctp;
6557 /* Remember session generation number and time */
6558 oldGen = sessionGen;
6559 oldTime = GetCurrentTime();
6561 while (inp->inCom != 0xff) {
6562 dp = &smb_dispatchTable[inp->inCom];
6564 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6565 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6566 code = outp->resumeCode;
6570 /* process each request in the packet; inCom, wctp and inCount
6571 * are already set up.
6573 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6576 /* now do the dispatch */
6577 /* start by formatting the response record a little, as a default */
6578 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6580 outWctp[1] = 0xff; /* no operation */
6581 outWctp[2] = 0; /* padding */
6586 /* not a chained request, this is a more reasonable default */
6587 outWctp[0] = 0; /* wct of zero */
6588 outWctp[1] = 0; /* and bcc (word) of zero */
6592 /* once set, stays set. Doesn't matter, since we never chain
6593 * "no response" calls.
6595 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6599 /* we have a recognized operation */
6601 if (inp->inCom == 0x1d)
6603 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6606 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%x lana %d lsn %d",(int)vcp,vcp->lana,vcp->lsn);
6607 osi_Log4(smb_logp,"Dispatch %s vcp 0x%x lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6608 code = (*(dp->procp)) (vcp, inp, outp);
6609 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",(code==0)?0:code-CM_ERROR_BASE);
6610 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);
6612 if ( code == CM_ERROR_BADSMB ||
6613 code == CM_ERROR_BADOP )
6615 #endif /* LOG_PACKET */
6618 if (oldGen != sessionGen) {
6623 newTime = GetCurrentTime();
6624 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6625 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6626 newTime - oldTime, ncbp->ncb_length);
6628 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6629 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6630 DeregisterEventSource(h);
6632 osi_Log1(smb_logp, "Pkt straddled session startup, "
6633 "ncb length %d", ncbp->ncb_length);
6637 /* bad opcode, fail the request, after displaying it */
6638 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6641 #endif /* LOG_PACKET */
6645 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6646 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6647 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6648 if (code == IDCANCEL)
6652 code = CM_ERROR_BADOP;
6655 /* catastrophic failure: log as much as possible */
6656 if (code == CM_ERROR_BADSMB) {
6663 "Invalid SMB, ncb_length %d",
6666 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6667 sprintf(s, "Invalid SMB message, length %d",
6670 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6671 1, ncbp->ncb_length, ptbuf, smbp);
6672 DeregisterEventSource(h);
6675 #endif /* LOG_PACKET */
6677 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6680 code = CM_ERROR_INVAL;
6683 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6684 thrd_Decrement(&ongoingOps);
6689 /* now, if we failed, turn the current response into an empty
6690 * one, and fill in the response packet's error code.
6693 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6694 smb_MapNTError(code, &NTStatus);
6695 outWctp = outp->wctp;
6696 smbp = (smb_t *) &outp->data;
6697 if (code != CM_ERROR_PARTIALWRITE
6698 && code != CM_ERROR_BUFFERTOOSMALL
6699 && code != CM_ERROR_GSSCONTINUE) {
6700 /* nuke wct and bcc. For a partial
6701 * write or an in-process authentication handshake,
6702 * assume they're OK.
6708 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6709 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6710 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6711 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6712 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6716 smb_MapCoreError(code, vcp, &errCode, &errClass);
6717 outWctp = outp->wctp;
6718 smbp = (smb_t *) &outp->data;
6719 if (code != CM_ERROR_PARTIALWRITE) {
6720 /* nuke wct and bcc. For a partial
6721 * write, assume they're OK.
6727 smbp->errLow = (unsigned char) (errCode & 0xff);
6728 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6729 smbp->rcls = errClass;
6732 } /* error occurred */
6734 /* if we're here, we've finished one request. Look to see if
6735 * this is a chained opcode. If it is, setup things to process
6736 * the chained request, and setup the output buffer to hold the
6737 * chained response. Start by finding the next input record.
6739 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6740 break; /* not a chained req */
6741 tp = inp->wctp; /* points to start of last request */
6742 /* in a chained request, the first two
6743 * parm fields are required, and are
6744 * AndXCommand/AndXReserved and
6746 if (tp[0] < 2) break;
6747 if (tp[1] == 0xff) break; /* no more chained opcodes */
6749 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6752 /* and now append the next output request to the end of this
6753 * last request. Begin by finding out where the last response
6754 * ends, since that's where we'll put our new response.
6756 outWctp = outp->wctp; /* ptr to out parameters */
6757 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6758 nparms = outWctp[0] << 1;
6759 tp = outWctp + nparms + 1; /* now points to bcc field */
6760 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6761 tp += 2 /* for the count itself */ + nbytes;
6762 /* tp now points to the new output record; go back and patch the
6763 * second parameter (off2) to point to the new record.
6765 temp = (unsigned int)tp - ((unsigned int) outp->data);
6766 outWctp[3] = (unsigned char) (temp & 0xff);
6767 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6768 outWctp[2] = 0; /* padding */
6769 outWctp[1] = inp->inCom; /* next opcode */
6771 /* finally, setup for the next iteration */
6774 } /* while loop over all requests in the packet */
6776 /* done logging out, turn off logging-out flag */
6777 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6778 vcp->justLoggedOut = NULL;
6781 free(loggedOutName);
6782 loggedOutName = NULL;
6783 smb_ReleaseUID(loggedOutUserp);
6784 loggedOutUserp = NULL;
6788 /* now send the output packet, and return */
6790 smb_SendPacket(vcp, outp);
6791 thrd_Decrement(&ongoingOps);
6793 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6794 if (active_vcp != vcp) {
6796 smb_ReleaseVC(active_vcp);
6798 "Replacing active_vcp %x with %x", active_vcp, vcp);
6803 last_msg_time = GetCurrentTime();
6804 } else if (active_vcp == vcp) {
6805 smb_ReleaseVC(active_vcp);
6813 /* Wait for Netbios() calls to return, and make the results available to server
6814 * threads. Note that server threads can't wait on the NCBevents array
6815 * themselves, because NCB events are manual-reset, and the servers would race
6816 * each other to reset them.
6818 void smb_ClientWaiter(void *parmp)
6823 while (smbShutdownFlag == 0) {
6824 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6826 if (code == WAIT_OBJECT_0)
6829 /* error checking */
6830 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6832 int abandonIdx = code - WAIT_ABANDONED_0;
6833 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6836 if (code == WAIT_IO_COMPLETION)
6838 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6842 if (code == WAIT_TIMEOUT)
6844 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6847 if (code == WAIT_FAILED)
6849 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6852 idx = code - WAIT_OBJECT_0;
6854 /* check idx range! */
6855 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6857 /* this is fatal - log as much as possible */
6858 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6862 thrd_ResetEvent(NCBevents[idx]);
6863 thrd_SetEvent(NCBreturns[0][idx]);
6869 * Try to have one NCBRECV request waiting for every live session. Not more
6870 * than one, because if there is more than one, it's hard to handle Write Raw.
6872 void smb_ServerWaiter(void *parmp)
6875 int idx_session, idx_NCB;
6881 while (smbShutdownFlag == 0) {
6883 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6885 if (code == WAIT_OBJECT_0)
6888 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6890 int abandonIdx = code - WAIT_ABANDONED_0;
6891 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6894 if (code == WAIT_IO_COMPLETION)
6896 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6900 if (code == WAIT_TIMEOUT)
6902 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6905 if (code == WAIT_FAILED)
6907 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6910 idx_session = code - WAIT_OBJECT_0;
6912 /* check idx range! */
6913 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6915 /* this is fatal - log as much as possible */
6916 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6922 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6924 if (code == WAIT_OBJECT_0) {
6925 if (smbShutdownFlag == 1)
6931 /* error checking */
6932 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6934 int abandonIdx = code - WAIT_ABANDONED_0;
6935 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6938 if (code == WAIT_IO_COMPLETION)
6940 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6944 if (code == WAIT_TIMEOUT)
6946 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6949 if (code == WAIT_FAILED)
6951 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6954 idx_NCB = code - WAIT_OBJECT_0;
6956 /* check idx range! */
6957 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6959 /* this is fatal - log as much as possible */
6960 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6964 /* Link them together */
6965 NCBsessions[idx_NCB] = idx_session;
6968 ncbp = NCBs[idx_NCB];
6969 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6970 ncbp->ncb_command = NCBRECV | ASYNCH;
6971 ncbp->ncb_lana_num = lanas[idx_session];
6973 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6974 ncbp->ncb_event = NCBevents[idx_NCB];
6975 ncbp->ncb_length = SMB_PACKETSIZE;
6978 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6979 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6980 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6981 ncbp->ncb_length = SMB_PACKETSIZE;
6982 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6983 Netbios(ncbp, dos_ncb);
6989 * The top level loop for handling SMB request messages. Each server thread
6990 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6991 * NCB and buffer for the incoming request are loaned to us.
6993 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6994 * to immediately send a request for the rest of the data. This must come
6995 * before any other traffic for that session, so we delay setting the session
6996 * event until that data has come in.
6998 void smb_Server(VOID *parmp)
7000 int myIdx = (int) parmp;
7004 smb_packet_t *outbufp;
7006 int idx_NCB, idx_session;
7008 smb_vc_t *vcp = NULL;
7014 rx_StartClientThread();
7017 outbufp = GetPacket();
7018 outbufp->ncbp = outncbp;
7021 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7024 /* terminate silently if shutdown flag is set */
7025 if (code == WAIT_OBJECT_0) {
7026 if (smbShutdownFlag == 1) {
7027 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7033 /* error checking */
7034 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7036 int abandonIdx = code - WAIT_ABANDONED_0;
7037 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7040 if (code == WAIT_IO_COMPLETION)
7042 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7046 if (code == WAIT_TIMEOUT)
7048 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7051 if (code == WAIT_FAILED)
7053 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7056 idx_NCB = code - WAIT_OBJECT_0;
7058 /* check idx range! */
7059 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7061 /* this is fatal - log as much as possible */
7062 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7066 ncbp = NCBs[idx_NCB];
7068 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7070 idx_session = NCBsessions[idx_NCB];
7071 rc = ncbp->ncb_retcode;
7073 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7076 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7079 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7082 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7085 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7088 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7091 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7094 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7097 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7100 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7103 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7106 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7109 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7112 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7115 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7118 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7121 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7124 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7127 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7130 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7133 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7136 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7139 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7142 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7145 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7148 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7151 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7154 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7157 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7160 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7163 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7166 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7169 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7172 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7175 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7178 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7181 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7184 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7187 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7197 /* Can this happen? Or is it just my UNIX paranoia? */
7198 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7203 /* Client closed session */
7204 dead_sessions[idx_session] = TRUE;
7207 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7208 /* Should also release vcp. [done] 2004-05-11 jaltman
7210 * sanity check that all TID's are gone.
7212 * TODO: check if we could use LSNs[idx_session] instead,
7213 * also cleanup after dead vcp
7216 if (dead_vcp == vcp)
7217 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7218 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7219 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7223 smb_ReleaseVC(dead_vcp);
7225 "Previous dead_vcp %x", dead_vcp);
7228 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7230 if (vcp->justLoggedOut) {
7232 loggedOutTime = vcp->logoffTime;
7233 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7234 loggedOutUserp = vcp->justLoggedOut;
7235 lock_ObtainWrite(&smb_rctLock);
7236 loggedOutUserp->refCount++;
7237 lock_ReleaseWrite(&smb_rctLock);
7243 /* Treat as transient error */
7250 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7251 sprintf(s, "SMB message incomplete, length %d",
7254 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7256 ncbp->ncb_length, ptbuf,
7258 DeregisterEventSource(h);
7261 "dispatch smb recv failed, message incomplete, ncb_length %d",
7264 "SMB message incomplete, "
7265 "length %d", ncbp->ncb_length);
7268 * We used to discard the packet.
7269 * Instead, try handling it normally.
7277 /* A weird error code. Log it, sleep, and
7279 if (vcp && vcp->errorCount++ > 3) {
7280 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7281 dead_sessions[idx_session] = TRUE;
7285 thrd_SetEvent(SessionEvents[idx_session]);
7290 /* Success, so now dispatch on all the data in the packet */
7292 smb_concurrentCalls++;
7293 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7294 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7298 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7300 * If at this point vcp is NULL (implies that packet was invalid)
7301 * then we are in big trouble. This means either :
7302 * a) we have the wrong NCB.
7303 * b) Netbios screwed up the call.
7304 * Obviously this implies that
7305 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7306 * lanas[idx_session] != ncbp->ncb_lana_num )
7307 * Either way, we can't do anything with this packet.
7308 * Log, sleep and resume.
7317 "LSNs[idx_session]=[%d],"
7318 "lanas[idx_session]=[%d],"
7319 "ncbp->ncb_lsn=[%d],"
7320 "ncbp->ncb_lana_num=[%d]",
7324 ncbp->ncb_lana_num);
7328 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7330 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7331 DeregisterEventSource(h);
7334 /* Also log in the trace log. */
7335 osi_Log4(smb_logp, "Server: BAD VCP!"
7336 "LSNs[idx_session]=[%d],"
7337 "lanas[idx_session]=[%d],"
7338 "ncbp->ncb_lsn=[%d],"
7339 "ncbp->ncb_lana_num=[%d]",
7343 ncbp->ncb_lana_num);
7345 /* thrd_Sleep(1000); Don't bother sleeping */
7346 thrd_SetEvent(SessionEvents[idx_session]);
7347 smb_concurrentCalls--;
7352 vcp->errorCount = 0;
7353 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7355 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7356 /* copy whole packet to virtual memory */
7357 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7359 bufp->dos_pkt / 16, bufp);*/
7361 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7363 smbp = (smb_t *)bufp->data;
7366 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7370 if (smbp->com == 0x1d) {
7371 /* Special handling for Write Raw */
7372 raw_write_cont_t rwc;
7373 EVENT_HANDLE rwevent;
7374 char eventName[MAX_PATH];
7376 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7377 if (rwc.code == 0) {
7378 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7379 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7380 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7381 ncbp->ncb_command = NCBRECV | ASYNCH;
7382 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7383 ncbp->ncb_lana_num = vcp->lana;
7384 ncbp->ncb_buffer = rwc.buf;
7385 ncbp->ncb_length = 65535;
7386 ncbp->ncb_event = rwevent;
7390 Netbios(ncbp, dos_ncb);
7392 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7393 thrd_CloseHandle(rwevent);
7395 thrd_SetEvent(SessionEvents[idx_session]);
7397 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7399 else if (smbp->com == 0xa0) {
7401 * Serialize the handling for NT Transact
7404 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7405 thrd_SetEvent(SessionEvents[idx_session]);
7407 thrd_SetEvent(SessionEvents[idx_session]);
7408 /* TODO: what else needs to be serialized? */
7409 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7411 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7413 __except( smb_ServerExceptionFilter() ) {
7417 smb_concurrentCalls--;
7420 thrd_SetEvent(NCBavails[idx_NCB]);
7427 * Exception filter for the server threads. If an exception occurs in the
7428 * dispatch routines, which is where exceptions are most common, then do a
7429 * force trace and give control to upstream exception handlers. Useful for
7432 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7433 DWORD smb_ServerExceptionFilter(void) {
7434 /* While this is not the best time to do a trace, if it succeeds, then
7435 * we have a trace (assuming tracing was enabled). Otherwise, this should
7436 * throw a second exception.
7441 ptbuf[0] = "Unhandled exception forcing trace";
7443 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7445 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7446 DeregisterEventSource(h);
7449 afsd_ForceTrace(TRUE);
7450 buf_ForceTrace(TRUE);
7451 return EXCEPTION_CONTINUE_SEARCH;
7456 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7457 * If the number of server threads is M, and the number of live sessions is
7458 * N, then the number of NCB's in use at any time either waiting for, or
7459 * holding, received messages is M + N, so that is how many NCB's get created.
7461 void InitNCBslot(int idx)
7463 struct smb_packet *bufp;
7464 EVENT_HANDLE retHandle;
7466 char eventName[MAX_PATH];
7468 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7470 NCBs[idx] = GetNCB();
7471 sprintf(eventName,"NCBavails[%d]", idx);
7472 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7473 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7474 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7476 sprintf(eventName,"NCBevents[%d]", idx);
7477 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7478 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7479 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7481 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7482 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7483 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7484 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7485 for (i=0; i<smb_NumServerThreads; i++)
7486 NCBreturns[i][idx] = retHandle;
7488 bufp->spacep = cm_GetSpace();
7492 /* listen for new connections */
7493 void smb_Listener(void *parmp)
7501 char rname[NCBNAMSZ+1];
7502 char cname[MAX_COMPUTERNAME_LENGTH+1];
7503 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7508 int lana = (int) parmp;
7512 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7515 /* retrieve computer name */
7516 GetComputerName(cname, &cnamelen);
7520 memset(ncbp, 0, sizeof(NCB));
7523 ncbp->ncb_command = NCBLISTEN;
7524 ncbp->ncb_rto = 0; /* No receive timeout */
7525 ncbp->ncb_sto = 0; /* No send timeout */
7527 /* pad out with spaces instead of null termination */
7528 len = strlen(smb_localNamep);
7529 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7530 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7532 strcpy(ncbp->ncb_callname, "*");
7533 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7535 ncbp->ncb_lana_num = lana;
7538 code = Netbios(ncbp);
7540 code = Netbios(ncbp, dos_ncb);
7549 /* terminate silently if shutdown flag is set */
7550 if (smbShutdownFlag == 1) {
7559 "NCBLISTEN lana=%d failed with code %d",
7560 ncbp->ncb_lana_num, code);
7562 "Client exiting due to network failure. Please restart client.\n");
7566 "Client exiting due to network failure. Please restart client.\n"
7567 "NCBLISTEN lana=%d failed with code %d",
7568 ncbp->ncb_lana_num, code);
7570 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7571 MB_OK|MB_SERVICE_NOTIFICATION);
7572 osi_assert(tbuffer);
7575 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7576 ncbp->ncb_lana_num, code);
7577 fprintf(stderr, "\nClient exiting due to network failure "
7578 "(possibly due to power-saving mode)\n");
7579 fprintf(stderr, "Please restart client.\n");
7580 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7584 /* check for remote conns */
7585 /* first get remote name and insert null terminator */
7586 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7587 for (i=NCBNAMSZ; i>0; i--) {
7588 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7594 /* compare with local name */
7596 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7597 flags |= SMB_VCFLAG_REMOTECONN;
7599 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7601 lock_ObtainMutex(&smb_ListenerLock);
7603 /* New generation */
7606 /* Log session startup */
7608 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7610 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7611 #endif /* NOTSERVICE */
7612 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7613 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7615 if (reportSessionStartups) {
7621 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7622 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7624 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7626 DeregisterEventSource(h);
7629 fprintf(stderr, "%s: New session %d starting from host %s\n",
7630 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7634 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7635 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7638 /* now ncbp->ncb_lsn is the connection ID */
7639 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7640 vcp->flags |= flags;
7641 strcpy(vcp->rname, rname);
7643 /* Allocate slot in session arrays */
7644 /* Re-use dead session if possible, otherwise add one more */
7645 /* But don't look at session[0], it is reserved */
7646 for (i = 1; i < numSessions; i++) {
7647 if (dead_sessions[i]) {
7648 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7649 dead_sessions[i] = FALSE;
7654 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7655 unsigned long code = CM_ERROR_ALLBUSY;
7656 smb_packet_t * outp = GetPacket();
7657 unsigned char *outWctp;
7662 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7663 unsigned long NTStatus;
7664 smb_MapNTError(code, &NTStatus);
7665 outWctp = outp->wctp;
7666 smbp = (smb_t *) &outp->data;
7670 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7671 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7672 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7673 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7674 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7676 unsigned short errCode;
7677 unsigned char errClass;
7678 smb_MapCoreError(code, vcp, &errCode, &errClass);
7679 outWctp = outp->wctp;
7680 smbp = (smb_t *) &outp->data;
7684 smbp->errLow = (unsigned char) (errCode & 0xff);
7685 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7686 smbp->rcls = errClass;
7688 smb_SendPacket(vcp, outp);
7689 smb_FreePacket(outp);
7691 /* assert that we do not exceed the maximum number of sessions or NCBs.
7692 * we should probably want to wait for a session to be freed in case
7695 osi_assert(i < Sessionmax - 1);
7696 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7698 LSNs[i] = ncbp->ncb_lsn;
7699 lanas[i] = ncbp->ncb_lana_num;
7701 if (i == numSessions) {
7702 /* Add new NCB for new session */
7703 char eventName[MAX_PATH];
7705 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7707 InitNCBslot(numNCBs);
7709 thrd_SetEvent(NCBavails[0]);
7710 thrd_SetEvent(NCBevents[0]);
7711 for (j = 0; j < smb_NumServerThreads; j++)
7712 thrd_SetEvent(NCBreturns[j][0]);
7713 /* Also add new session event */
7714 sprintf(eventName, "SessionEvents[%d]", i);
7715 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7716 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7717 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7719 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7720 thrd_SetEvent(SessionEvents[0]);
7722 thrd_SetEvent(SessionEvents[i]);
7729 lock_ReleaseMutex(&smb_ListenerLock);
7730 } /* dispatch while loop */
7733 /* initialize Netbios */
7734 void smb_NetbiosInit()
7740 int i, lana, code, l;
7742 int delname_tried=0;
7745 OSVERSIONINFO Version;
7747 /* Get the version of Windows */
7748 memset(&Version, 0x00, sizeof(Version));
7749 Version.dwOSVersionInfoSize = sizeof(Version);
7750 GetVersionEx(&Version);
7752 /* setup the NCB system */
7755 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7759 if (smb_LANadapter == -1) {
7760 ncbp->ncb_command = NCBENUM;
7761 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7762 ncbp->ncb_length = sizeof(lana_list);
7763 code = Netbios(ncbp);
7765 afsi_log("Netbios NCBENUM error code %d", code);
7766 osi_panic(s, __FILE__, __LINE__);
7770 lana_list.length = 1;
7771 lana_list.lana[0] = smb_LANadapter;
7774 for (i = 0; i < lana_list.length; i++) {
7775 /* reset the adaptor: in Win32, this is required for every process, and
7776 * acts as an init call, not as a real hardware reset.
7778 ncbp->ncb_command = NCBRESET;
7779 ncbp->ncb_callname[0] = 100;
7780 ncbp->ncb_callname[2] = 100;
7781 ncbp->ncb_lana_num = lana_list.lana[i];
7782 code = Netbios(ncbp);
7784 code = ncbp->ncb_retcode;
7786 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7787 lana_list.lana[i] = 255; /* invalid lana */
7789 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7793 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7794 we will just fake the LANA list */
7795 if (smb_LANadapter == -1) {
7796 for (i = 0; i < 8; i++)
7797 lana_list.lana[i] = i;
7798 lana_list.length = 8;
7801 lana_list.length = 1;
7802 lana_list.lana[0] = smb_LANadapter;
7806 /* and declare our name so we can receive connections */
7807 memset(ncbp, 0, sizeof(*ncbp));
7808 len=lstrlen(smb_localNamep);
7809 memset(smb_sharename,' ',NCBNAMSZ);
7810 memcpy(smb_sharename,smb_localNamep,len);
7811 afsi_log("lana_list.length %d", lana_list.length);
7813 /* Keep the name so we can unregister it later */
7814 for (l = 0; l < lana_list.length; l++) {
7815 lana = lana_list.lana[l];
7817 ncbp->ncb_command = NCBADDNAME;
7818 ncbp->ncb_lana_num = lana;
7819 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7821 code = Netbios(ncbp);
7823 code = Netbios(ncbp, dos_ncb);
7826 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7827 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7829 char name[NCBNAMSZ+1];
7831 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7832 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
7835 if (code == 0) code = ncbp->ncb_retcode;
7837 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
7839 /* we only use one LANA with djgpp */
7840 lana_list.lana[0] = lana;
7841 lana_list.length = 1;
7845 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
7846 if (code == NRC_BRIDGE) { /* invalid LANA num */
7847 lana_list.lana[l] = 255;
7850 else if (code == NRC_DUPNAME) {
7851 afsi_log("Name already exists; try to delete it");
7852 memset(ncbp, 0, sizeof(*ncbp));
7853 ncbp->ncb_command = NCBDELNAME;
7854 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7855 ncbp->ncb_lana_num = lana;
7857 code = Netbios(ncbp);
7859 code = Netbios(ncbp, dos_ncb);
7862 code = ncbp->ncb_retcode;
7864 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7866 if (code != 0 || delname_tried) {
7867 lana_list.lana[l] = 255;
7869 else if (code == 0) {
7870 if (!delname_tried) {
7878 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
7879 lana_list.lana[l] = 255; /* invalid lana */
7880 osi_panic(s, __FILE__, __LINE__);
7884 lana_found = 1; /* at least one worked */
7891 osi_assert(lana_list.length >= 0);
7893 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
7896 /* we're done with the NCB now */
7900 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7917 EVENT_HANDLE retHandle;
7918 char eventName[MAX_PATH];
7921 smb_MBfunc = aMBfunc;
7925 smb_LANadapter = LANadapt;
7927 /* Initialize smb_localZero */
7928 myTime.tm_isdst = -1; /* compute whether on DST or not */
7929 myTime.tm_year = 70;
7935 smb_localZero = mktime(&myTime);
7937 #ifndef USE_NUMERIC_TIME_CONV
7938 /* Initialize kludge-GMT */
7939 smb_CalculateNowTZ();
7940 #endif /* USE_NUMERIC_TIME_CONV */
7941 #ifdef AFS_FREELANCE_CLIENT
7942 /* Make sure the root.afs volume has the correct time */
7943 cm_noteLocalMountPointChange();
7946 /* initialize the remote debugging log */
7949 /* remember the name */
7950 len = strlen(snamep);
7951 smb_localNamep = malloc(len+1);
7952 strcpy(smb_localNamep, snamep);
7953 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7955 /* and the global lock */
7956 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7957 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7959 /* Raw I/O data structures */
7960 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7962 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7964 /* 4 Raw I/O buffers */
7966 smb_RawBufs = calloc(65536,1);
7967 *((char **)smb_RawBufs) = NULL;
7968 for (i=0; i<3; i++) {
7969 char *rawBuf = calloc(65536,1);
7970 *((char **)rawBuf) = smb_RawBufs;
7971 smb_RawBufs = rawBuf;
7974 npar = 65536 >> 4; /* number of paragraphs */
7975 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7977 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7979 osi_panic("",__FILE__,__LINE__);
7982 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7985 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7987 _farpokel(_dos_ds, smb_RawBufs, NULL);
7988 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7989 npar = 65536 >> 4; /* number of paragraphs */
7990 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7992 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7994 osi_panic("",__FILE__,__LINE__);
7997 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8000 rawBuf = (seg * 16) + 0; /* DOS physical address */
8001 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8002 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8003 smb_RawBufs = rawBuf;
8007 /* global free lists */
8008 smb_ncbFreeListp = NULL;
8009 smb_packetFreeListp = NULL;
8013 /* Initialize listener and server structures */
8015 memset(dead_sessions, 0, sizeof(dead_sessions));
8016 sprintf(eventName, "SessionEvents[0]");
8017 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8018 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8019 afsi_log("Event Object Already Exists: %s", eventName);
8021 smb_NumServerThreads = nThreads;
8022 sprintf(eventName, "NCBavails[0]");
8023 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8024 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8025 afsi_log("Event Object Already Exists: %s", eventName);
8026 sprintf(eventName, "NCBevents[0]");
8027 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8028 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8029 afsi_log("Event Object Already Exists: %s", eventName);
8030 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8031 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8032 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8033 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8034 afsi_log("Event Object Already Exists: %s", eventName);
8035 for (i = 0; i < smb_NumServerThreads; i++) {
8036 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8037 NCBreturns[i][0] = retHandle;
8040 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8041 for (i = 0; i < smb_NumServerThreads; i++) {
8042 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8043 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8044 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8045 afsi_log("Event Object Already Exists: %s", eventName);
8048 numNCBs = smb_NumServerThreads + 1;
8050 /* Initialize dispatch table */
8051 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8052 /* Prepare the table for unknown operations */
8053 for(i=0; i<= SMB_NOPCODES; i++) {
8054 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8056 /* Fill in the ones we do know */
8057 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8058 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8059 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8060 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8061 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8062 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8063 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8064 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8065 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8066 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8067 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8068 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8069 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8070 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8071 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8072 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8073 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8074 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8075 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8076 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8077 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8078 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8079 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8080 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8081 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8082 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8083 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8084 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8085 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8086 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8087 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8088 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8089 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8090 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8091 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8092 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8093 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8094 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8095 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8096 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8097 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8098 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8099 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8100 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8101 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8102 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8103 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8104 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8105 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8106 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8107 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8108 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8109 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8110 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8111 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8112 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8113 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8114 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8115 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8116 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8117 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8118 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8119 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8120 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8121 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8122 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8123 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8124 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8125 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8126 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8127 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8128 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8130 /* setup tran 2 dispatch table */
8131 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8132 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8133 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8134 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8135 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8136 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8137 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8138 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8139 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8140 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8141 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8142 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8143 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8144 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8145 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8146 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8147 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8149 /* setup the rap dispatch table */
8150 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8151 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8152 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8153 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8154 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8158 /* if we are doing SMB authentication we have register outselves as a logon process */
8159 if (smb_authType != SMB_AUTH_NONE) {
8160 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8161 LSA_STRING afsProcessName;
8162 LSA_OPERATIONAL_MODE dummy; /*junk*/
8164 afsProcessName.Buffer = "OpenAFSClientDaemon";
8165 afsProcessName.Length = strlen(afsProcessName.Buffer);
8166 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8168 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8170 if (nts == STATUS_SUCCESS) {
8171 LSA_STRING packageName;
8172 /* we are registered. Find out the security package id */
8173 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8174 packageName.Length = strlen(packageName.Buffer);
8175 packageName.MaximumLength = packageName.Length + 1;
8176 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8177 if (nts == STATUS_SUCCESS) {
8179 * This code forces Windows to authenticate against the Logon Cache
8180 * first instead of attempting to authenticate against the Domain
8181 * Controller. When the Windows logon cache is enabled this improves
8182 * performance by removing the network access and works around a bug
8183 * seen at sites which are using a MIT Kerberos principal to login
8184 * to machines joined to a non-root domain in a multi-domain forest.
8186 PVOID pResponse = NULL;
8187 ULONG cbResponse = 0;
8188 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8190 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8191 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8192 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8193 OptionsRequest.DisableOptions = FALSE;
8195 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8198 sizeof(OptionsRequest),
8204 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8206 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8208 OutputDebugString(message);
8211 OutputDebugString("MsV1_0SetProcessOption success");
8212 afsi_log("MsV1_0SetProcessOption success");
8214 /* END - code from Larry */
8216 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8217 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8218 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8220 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8222 /* something went wrong. We report the error and revert back to no authentication
8223 because we can't perform any auth requests without a successful lsa handle
8224 or sec package id. */
8225 afsi_log("Reverting to NO SMB AUTH");
8226 smb_authType = SMB_AUTH_NONE;
8229 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8231 /* something went wrong. We report the error and revert back to no authentication
8232 because we can't perform any auth requests without a successful lsa handle
8233 or sec package id. */
8234 afsi_log("Reverting to NO SMB AUTH");
8235 smb_authType = SMB_AUTH_NONE;
8239 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8240 * time prevents the failure of authentication when logged into Windows with an
8241 * external Kerberos principal mapped to a local account.
8243 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8244 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8245 * then the only option is NTLMSSP anyway; so just fallback.
8250 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8251 if (secBlobLength == 0) {
8252 smb_authType = SMB_AUTH_NTLM;
8253 afsi_log("Reverting to SMB AUTH NTLM");
8262 /* Now get ourselves a domain name. */
8263 /* For now we are using the local computer name as the domain name.
8264 * It is actually the domain for local logins, and we are acting as
8265 * a local SMB server.
8267 bufsize = sizeof(smb_ServerDomainName) - 1;
8268 GetComputerName(smb_ServerDomainName, &bufsize);
8269 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8270 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8273 /* Start listeners, waiters, servers, and daemons */
8275 for (i = 0; i < lana_list.length; i++) {
8276 if (lana_list.lana[i] == 255)
8278 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8279 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8280 osi_assert(phandle != NULL);
8281 thrd_CloseHandle(phandle);
8285 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8286 NULL, 0, &lpid, "smb_ClientWaiter");
8287 osi_assert(phandle != NULL);
8288 thrd_CloseHandle(phandle);
8291 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8292 NULL, 0, &lpid, "smb_ServerWaiter");
8293 osi_assert(phandle != NULL);
8294 thrd_CloseHandle(phandle);
8296 for (i=0; i<smb_NumServerThreads; i++) {
8297 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8298 (void *) i, 0, &lpid, "smb_Server");
8299 osi_assert(phandle != NULL);
8300 thrd_CloseHandle(phandle);
8303 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8304 NULL, 0, &lpid, "smb_Daemon");
8305 osi_assert(phandle != NULL);
8306 thrd_CloseHandle(phandle);
8308 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8309 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8310 osi_assert(phandle != NULL);
8311 thrd_CloseHandle(phandle);
8320 void smb_Shutdown(void)
8330 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8332 /* setup the NCB system */
8335 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8338 /* Block new sessions by setting shutdown flag */
8339 smbShutdownFlag = 1;
8341 /* Hang up all sessions */
8342 memset((char *)ncbp, 0, sizeof(NCB));
8343 for (i = 1; i < numSessions; i++)
8345 if (dead_sessions[i])
8348 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8349 ncbp->ncb_command = NCBHANGUP;
8350 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8351 ncbp->ncb_lsn = LSNs[i];
8353 code = Netbios(ncbp);
8355 code = Netbios(ncbp, dos_ncb);
8357 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8358 if (code == 0) code = ncbp->ncb_retcode;
8360 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8361 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8365 /* Trigger the shutdown of all SMB threads */
8366 for (i = 0; i < smb_NumServerThreads; i++)
8367 thrd_SetEvent(NCBreturns[i][0]);
8369 thrd_SetEvent(NCBevents[0]);
8370 thrd_SetEvent(SessionEvents[0]);
8371 thrd_SetEvent(NCBavails[0]);
8373 for (i = 0;i < smb_NumServerThreads; i++) {
8374 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8375 if (code == WAIT_OBJECT_0) {
8378 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8379 thrd_SetEvent(NCBreturns[i--][0]);
8383 /* Delete Netbios name */
8384 memset((char *)ncbp, 0, sizeof(NCB));
8385 for (i = 0; i < lana_list.length; i++) {
8386 if (lana_list.lana[i] == 255) continue;
8387 ncbp->ncb_command = NCBDELNAME;
8388 ncbp->ncb_lana_num = lana_list.lana[i];
8389 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8391 code = Netbios(ncbp);
8393 code = Netbios(ncbp, dos_ncb);
8396 code = ncbp->ncb_retcode;
8398 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8399 ncbp->ncb_lana_num, code);
8404 /* Release the reference counts held by the VCs */
8405 lock_ObtainWrite(&smb_rctLock);
8406 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8411 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8413 if (fidp->scp != NULL) {
8416 lock_ObtainMutex(&fidp->mx);
8417 if (fidp->scp != NULL) {
8420 cm_ReleaseSCache(scp);
8422 lock_ReleaseMutex(&fidp->mx);
8426 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8428 smb_ReleaseVCNoLock(tidp->vcp);
8430 cm_user_t *userp = tidp->userp;
8432 lock_ReleaseWrite(&smb_rctLock);
8433 cm_ReleaseUser(userp);
8434 lock_ObtainWrite(&smb_rctLock);
8438 lock_ReleaseWrite(&smb_rctLock);
8441 /* Get the UNC \\<servername>\<sharename> prefix. */
8442 char *smb_GetSharename()
8446 /* Make sure we have been properly initialized. */
8447 if (smb_localNamep == NULL)
8450 /* Allocate space for \\<servername>\<sharename>, plus the
8453 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8454 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8460 void smb_LogPacket(smb_packet_t *packet)
8463 unsigned length, paramlen, datalen, i, j;
8465 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8467 if (!packet) return;
8469 osi_Log0(smb_logp, "*** SMB packet dump ***");
8471 vp = (BYTE *) packet->data;
8473 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8474 length = paramlen + 2 + datalen;
8477 for (i=0;i < length; i+=16)
8479 memset( buf, ' ', 80 );
8484 buf[strlen(buf)] = ' ';
8486 cp = (BYTE*) buf + 7;
8488 for (j=0;j < 16 && (i+j)<length; j++)
8490 *(cp++) = hex[vp[i+j] >> 4];
8491 *(cp++) = hex[vp[i+j] & 0xf];
8501 for (j=0;j < 16 && (i+j)<length;j++)
8503 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8514 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8517 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8519 #endif /* LOG_PACKET */
8522 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8530 lock_ObtainRead(&smb_rctLock);
8532 sprintf(output, "begin dumping smb_vc_t\n");
8533 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8535 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8539 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8540 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8541 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8543 sprintf(output, "begin dumping smb_fid_t\n");
8544 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8546 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8548 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",
8549 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8550 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8551 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8552 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8555 sprintf(output, "done dumping smb_fid_t\n");
8556 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8559 sprintf(output, "done dumping smb_vc_t\n");
8560 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8563 lock_ReleaseRead(&smb_rctLock);