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_waitingLockRequest_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 if (numVCs >= CM_SESSION_RESERVED) {
866 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
869 lock_ReleaseWrite(&smb_rctLock);
873 int smb_IsStarMask(char *maskp)
878 for(i=0; i<11; i++) {
880 if (tc == '?' || tc == '*' || tc == '>') return 1;
885 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
887 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
889 osi_assert(vcp->refCount-- != 0);
895 void smb_ReleaseVC(smb_vc_t *vcp)
897 lock_ObtainWrite(&smb_rctLock);
898 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
900 osi_assert(vcp->refCount-- != 0);
904 lock_ReleaseWrite(&smb_rctLock);
907 void smb_HoldVCNoLock(smb_vc_t *vcp)
910 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
913 void smb_HoldVC(smb_vc_t *vcp)
915 lock_ObtainWrite(&smb_rctLock);
917 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
918 lock_ReleaseWrite(&smb_rctLock);
921 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
925 lock_ObtainWrite(&smb_rctLock);
926 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
927 if (tid == tidp->tid) {
932 if (!tidp && (flags & SMB_FLAG_CREATE)) {
933 tidp = malloc(sizeof(*tidp));
934 memset(tidp, 0, sizeof(*tidp));
935 tidp->nextp = vcp->tidsp;
938 smb_HoldVCNoLock(vcp);
940 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
943 lock_ReleaseWrite(&smb_rctLock);
947 void smb_ReleaseTID(smb_tid_t *tidp)
954 lock_ObtainWrite(&smb_rctLock);
955 osi_assert(tidp->refCount-- > 0);
956 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
957 ltpp = &tidp->vcp->tidsp;
958 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
962 osi_assert(tp != NULL);
964 lock_FinalizeMutex(&tidp->mx);
965 userp = tidp->userp; /* remember to drop ref later */
967 smb_ReleaseVCNoLock(tidp->vcp);
970 lock_ReleaseWrite(&smb_rctLock);
972 cm_ReleaseUser(userp);
975 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
977 smb_user_t *uidp = NULL;
979 lock_ObtainWrite(&smb_rctLock);
980 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
981 if (uid == uidp->userID) {
983 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
984 (int)vcp, uidp->userID,
985 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
989 if (!uidp && (flags & SMB_FLAG_CREATE)) {
990 uidp = malloc(sizeof(*uidp));
991 memset(uidp, 0, sizeof(*uidp));
992 uidp->nextp = vcp->usersp;
995 smb_HoldVCNoLock(vcp);
997 lock_InitializeMutex(&uidp->mx, "user_t mutex");
999 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 : ""));
1001 lock_ReleaseWrite(&smb_rctLock);
1005 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1007 smb_username_t *unp= NULL;
1009 lock_ObtainWrite(&smb_rctLock);
1010 for(unp = usernamesp; unp; unp = unp->nextp) {
1011 if (stricmp(unp->name, usern) == 0 &&
1012 stricmp(unp->machine, machine) == 0) {
1017 if (!unp && (flags & SMB_FLAG_CREATE)) {
1018 unp = malloc(sizeof(*unp));
1019 memset(unp, 0, sizeof(*unp));
1021 unp->nextp = usernamesp;
1022 unp->name = strdup(usern);
1023 unp->machine = strdup(machine);
1025 lock_InitializeMutex(&unp->mx, "username_t mutex");
1027 lock_ReleaseWrite(&smb_rctLock);
1031 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1033 smb_user_t *uidp= NULL;
1035 lock_ObtainWrite(&smb_rctLock);
1036 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1039 if (stricmp(uidp->unp->name, usern) == 0) {
1041 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1046 lock_ReleaseWrite(&smb_rctLock);
1049 void smb_ReleaseUID(smb_user_t *uidp)
1056 lock_ObtainWrite(&smb_rctLock);
1057 osi_assert(uidp->refCount-- > 0);
1058 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1059 lupp = &uidp->vcp->usersp;
1060 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1064 osi_assert(up != NULL);
1066 lock_FinalizeMutex(&uidp->mx);
1068 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1069 uidp->unp->userp = NULL; /* after releasing the lock */
1071 smb_ReleaseVCNoLock(uidp->vcp);
1074 lock_ReleaseWrite(&smb_rctLock);
1076 cm_ReleaseUserVCRef(userp);
1077 cm_ReleaseUser(userp);
1082 /* retrieve a held reference to a user structure corresponding to an incoming
1084 * corresponding release function is cm_ReleaseUser.
1086 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1092 smbp = (smb_t *) inp;
1093 uidp = smb_FindUID(vcp, smbp->uid, 0);
1094 if ((!uidp) || (!uidp->unp))
1097 lock_ObtainMutex(&uidp->mx);
1098 up = uidp->unp->userp;
1100 lock_ReleaseMutex(&uidp->mx);
1102 smb_ReleaseUID(uidp);
1108 * Return a pointer to a pathname extracted from a TID structure. The
1109 * TID structure is not held; assume it won't go away.
1111 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1116 tidp = smb_FindTID(vcp, tid, 0);
1120 if (tidp->flags & SMB_TIDFLAG_IPC) {
1121 code = CM_ERROR_TIDIPC;
1122 /* tidp->pathname would be NULL, but that's fine */
1124 *treepath = tidp->pathname;
1125 smb_ReleaseTID(tidp);
1130 /* check to see if we have a chained fid, that is, a fid that comes from an
1131 * OpenAndX message that ran earlier in this packet. In this case, the fid
1132 * field in a read, for example, request, isn't set, since the value is
1133 * supposed to be inherited from the openAndX call.
1135 int smb_ChainFID(int fid, smb_packet_t *inp)
1137 if (inp->fid == 0 || inp->inCount == 0)
1143 /* are we a priv'd user? What does this mean on NT? */
1144 int smb_SUser(cm_user_t *userp)
1149 /* find a file ID. If we pass in 0 we select an unused File ID.
1150 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1151 * smb_fid_t data structure if desired File ID cannot be found.
1153 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1158 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1161 lock_ObtainWrite(&smb_rctLock);
1162 /* figure out if we need to allocate a new file ID */
1165 fid = vcp->fidCounter;
1169 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1170 if (fid == fidp->fid) {
1182 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1183 char eventName[MAX_PATH];
1185 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1186 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1187 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1188 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1189 thrd_CloseHandle(event);
1196 fidp = malloc(sizeof(*fidp));
1197 memset(fidp, 0, sizeof(*fidp));
1198 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1201 smb_HoldVCNoLock(vcp);
1202 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1204 fidp->curr_chunk = fidp->prev_chunk = -2;
1205 fidp->raw_write_event = event;
1207 vcp->fidCounter = fid+1;
1208 if (vcp->fidCounter == 0)
1209 vcp->fidCounter = 1;
1213 lock_ReleaseWrite(&smb_rctLock);
1217 void smb_ReleaseFID(smb_fid_t *fidp)
1220 smb_vc_t *vcp = NULL;
1221 smb_ioctl_t *ioctlp;
1227 lock_ObtainWrite(&smb_rctLock);
1228 osi_assert(fidp->refCount-- > 0);
1229 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1232 scp = fidp->scp; /* release after lock is released */
1235 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1236 thrd_CloseHandle(fidp->raw_write_event);
1238 /* and see if there is ioctl stuff to free */
1239 ioctlp = fidp->ioctlp;
1242 cm_FreeSpace(ioctlp->prefix);
1243 if (ioctlp->inAllocp)
1244 free(ioctlp->inAllocp);
1245 if (ioctlp->outAllocp)
1246 free(ioctlp->outAllocp);
1252 smb_ReleaseVCNoLock(vcp);
1254 lock_ReleaseWrite(&smb_rctLock);
1256 /* now release the scache structure */
1258 cm_ReleaseSCache(scp);
1262 * Case-insensitive search for one string in another;
1263 * used to find variable names in submount pathnames.
1265 static char *smb_stristr(char *str1, char *str2)
1269 for (cursor = str1; *cursor; cursor++)
1270 if (stricmp(cursor, str2) == 0)
1277 * Substitute a variable value for its name in a submount pathname. Variable
1278 * name has been identified by smb_stristr() and is in substr. Variable name
1279 * length (plus one) is in substr_size. Variable value is in newstr.
1281 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1286 strcpy(temp, substr + substr_size - 1);
1287 strcpy(substr, newstr);
1291 char VNUserName[] = "%USERNAME%";
1292 char VNLCUserName[] = "%LCUSERNAME%";
1293 char VNComputerName[] = "%COMPUTERNAME%";
1294 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1297 /* List available shares */
1298 int smb_ListShares()
1302 char shareBuf[4096];
1310 /*strcpy(shareNameList[num_shares], "all");
1311 strcpy(pathNameList[num_shares++], "/afs");*/
1312 fprintf(stderr, "The following shares are available:\n");
1313 fprintf(stderr, "Share Name (AFS Path)\n");
1314 fprintf(stderr, "---------------------\n");
1315 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1318 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1319 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1321 strcpy(sbmtpath, cm_confDir);
1323 strcat(sbmtpath, "/afsdsbmt.ini");
1324 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1325 shareBuf, sizeof(shareBuf),
1331 this_share = shareBuf;
1335 /*strcpy(shareNameList[num_shares], this_share);*/
1336 len = GetPrivateProfileString("AFS Submounts", this_share,
1343 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1346 if (*p == '\\') *p = '/'; /* change to / */
1350 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1351 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1354 while (*this_share != 0) this_share++; /* find next NUL */
1355 this_share++; /* skip past the NUL */
1356 } while (*this_share != 0); /* stop at final NUL */
1362 typedef struct smb_findShare_rock {
1366 } smb_findShare_rock_t;
1368 #define SMB_FINDSHARE_EXACT_MATCH 1
1369 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1371 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1375 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1376 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1377 if(!stricmp(dep->name, vrock->shareName))
1378 matchType = SMB_FINDSHARE_EXACT_MATCH;
1380 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1381 if(vrock->match) free(vrock->match);
1382 vrock->match = strdup(dep->name);
1383 vrock->matchType = matchType;
1385 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1386 return CM_ERROR_STOPNOW;
1392 /* find a shareName in the table of submounts */
1393 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1397 char pathName[1024];
1402 char sbmtpath[MAX_PATH];
1407 DWORD allSubmount = 1;
1409 /* if allSubmounts == 0, only return the //mountRoot/all share
1410 * if in fact it has been been created in the subMounts table.
1411 * This is to allow sites that want to restrict access to the
1414 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1415 0, KEY_QUERY_VALUE, &parmKey);
1416 if (code == ERROR_SUCCESS) {
1417 len = sizeof(allSubmount);
1418 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1419 (BYTE *) &allSubmount, &len);
1420 if (code != ERROR_SUCCESS) {
1423 RegCloseKey (parmKey);
1426 if (allSubmount && _stricmp(shareName, "all") == 0) {
1431 /* In case, the all share is disabled we need to still be able
1432 * to handle ioctl requests
1434 if (_stricmp(shareName, "ioctl$") == 0) {
1435 *pathNamep = strdup("/.__ioctl__");
1439 if (_stricmp(shareName, "IPC$") == 0 ||
1440 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1441 _stricmp(shareName, "DESKTOP.INI") == 0
1448 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1449 0, KEY_QUERY_VALUE, &parmKey);
1450 if (code == ERROR_SUCCESS) {
1451 len = sizeof(pathName);
1452 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1453 (BYTE *) pathName, &len);
1454 if (code != ERROR_SUCCESS)
1456 RegCloseKey (parmKey);
1461 strcpy(sbmtpath, cm_confDir);
1462 strcat(sbmtpath, "/afsdsbmt.ini");
1463 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1464 pathName, sizeof(pathName), sbmtpath);
1466 if (len != 0 && len != sizeof(pathName) - 1) {
1467 /* We can accept either unix or PC style AFS pathnames. Convert
1468 * Unix-style to PC style here for internal use.
1471 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1472 p += strlen(cm_mountRoot); /* skip mount path */
1475 if (*q == '/') *q = '\\'; /* change to \ */
1481 if (var = smb_stristr(p, VNUserName)) {
1482 if (uidp && uidp->unp)
1483 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1485 smb_subst(p, var, sizeof(VNUserName)," ");
1487 else if (var = smb_stristr(p, VNLCUserName))
1489 if (uidp && uidp->unp)
1490 strcpy(temp, uidp->unp->name);
1494 smb_subst(p, var, sizeof(VNLCUserName), temp);
1496 else if (var = smb_stristr(p, VNComputerName))
1498 sizeTemp = sizeof(temp);
1499 GetComputerName((LPTSTR)temp, &sizeTemp);
1500 smb_subst(p, var, sizeof(VNComputerName), temp);
1502 else if (var = smb_stristr(p, VNLCComputerName))
1504 sizeTemp = sizeof(temp);
1505 GetComputerName((LPTSTR)temp, &sizeTemp);
1507 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1512 *pathNamep = strdup(p);
1517 /* First lookup shareName in root.afs */
1519 smb_findShare_rock_t vrock;
1521 char * p = shareName;
1524 /* attempt to locate a partial match in root.afs. This is because
1525 when using the ANSI RAP calls, the share name is limited to 13 chars
1526 and hence is truncated. Of course we prefer exact matches. */
1528 thyper.HighPart = 0;
1531 vrock.shareName = shareName;
1533 vrock.matchType = 0;
1535 cm_HoldSCache(cm_data.rootSCachep);
1536 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1537 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1538 cm_ReleaseSCache(cm_data.rootSCachep);
1540 if (vrock.matchType) {
1541 sprintf(pathName,"/%s/",vrock.match);
1542 *pathNamep = strdup(strlwr(pathName));
1547 /* if we get here, there was no match for the share in root.afs */
1548 /* so try to create \\<netbiosName>\<cellname> */
1553 /* Get the full name for this cell */
1554 code = cm_SearchCellFile(p, temp, 0, 0);
1555 #ifdef AFS_AFSDB_ENV
1556 if (code && cm_dnsEnabled) {
1558 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1561 /* construct the path */
1563 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1564 *pathNamep = strdup(strlwr(pathName));
1573 /* Client-side offline caching policy types */
1574 #define CSC_POLICY_MANUAL 0
1575 #define CSC_POLICY_DOCUMENTS 1
1576 #define CSC_POLICY_PROGRAMS 2
1577 #define CSC_POLICY_DISABLE 3
1579 int smb_FindShareCSCPolicy(char *shareName)
1585 int retval = CSC_POLICY_MANUAL;
1587 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1588 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1591 REG_OPTION_NON_VOLATILE,
1597 len = sizeof(policy);
1598 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1600 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1602 else if (stricmp(policy, "documents") == 0)
1604 retval = CSC_POLICY_DOCUMENTS;
1606 else if (stricmp(policy, "programs") == 0)
1608 retval = CSC_POLICY_PROGRAMS;
1610 else if (stricmp(policy, "disable") == 0)
1612 retval = CSC_POLICY_DISABLE;
1615 RegCloseKey(hkCSCPolicy);
1619 /* find a dir search structure by cookie value, and return it held.
1620 * Must be called with smb_globalLock held.
1622 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1624 smb_dirSearch_t *dsp;
1626 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1627 if (dsp->cookie == cookie) {
1628 if (dsp != smb_firstDirSearchp) {
1629 /* move to head of LRU queue, too, if we're not already there */
1630 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1631 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1632 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1633 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1634 if (!smb_lastDirSearchp)
1635 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1637 lock_ObtainMutex(&dsp->mx);
1639 lock_ReleaseMutex(&dsp->mx);
1645 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1646 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1647 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1653 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1655 lock_ObtainWrite(&smb_globalLock);
1656 lock_ObtainMutex(&dsp->mx);
1657 dsp->flags |= SMB_DIRSEARCH_DELETE;
1658 if (dsp->scp != NULL) {
1659 lock_ObtainMutex(&dsp->scp->mx);
1660 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1661 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1662 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1663 dsp->scp->bulkStatProgress = hones;
1665 lock_ReleaseMutex(&dsp->scp->mx);
1667 lock_ReleaseMutex(&dsp->mx);
1668 lock_ReleaseWrite(&smb_globalLock);
1671 /* Must be called with the smb_globalLock held */
1672 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1674 cm_scache_t *scp = NULL;
1676 lock_ObtainMutex(&dsp->mx);
1677 osi_assert(dsp->refCount-- > 0);
1678 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1679 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1680 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1681 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1682 lock_ReleaseMutex(&dsp->mx);
1683 lock_FinalizeMutex(&dsp->mx);
1687 lock_ReleaseMutex(&dsp->mx);
1689 /* do this now to avoid spurious locking hierarchy creation */
1691 cm_ReleaseSCache(scp);
1694 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1696 lock_ObtainWrite(&smb_globalLock);
1697 smb_ReleaseDirSearchNoLock(dsp);
1698 lock_ReleaseWrite(&smb_globalLock);
1701 /* find a dir search structure by cookie value, and return it held */
1702 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1704 smb_dirSearch_t *dsp;
1706 lock_ObtainWrite(&smb_globalLock);
1707 dsp = smb_FindDirSearchNoLock(cookie);
1708 lock_ReleaseWrite(&smb_globalLock);
1712 /* GC some dir search entries, in the address space expected by the specific protocol.
1713 * Must be called with smb_globalLock held; release the lock temporarily.
1715 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1716 void smb_GCDirSearches(int isV3)
1718 smb_dirSearch_t *prevp;
1719 smb_dirSearch_t *tp;
1720 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1724 victimCount = 0; /* how many have we got so far */
1725 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1726 /* we'll move tp from queue, so
1729 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1730 /* if no one is using this guy, and we're either in the new protocol,
1731 * or we're in the old one and this is a small enough ID to be useful
1732 * to the old protocol, GC this guy.
1734 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1735 /* hold and delete */
1736 tp->flags |= SMB_DIRSEARCH_DELETE;
1737 victimsp[victimCount++] = tp;
1741 /* don't do more than this */
1742 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1746 /* now release them */
1747 for (i = 0; i < victimCount; i++) {
1748 smb_ReleaseDirSearchNoLock(victimsp[i]);
1752 /* function for allocating a dir search entry. We need these to remember enough context
1753 * since we don't get passed the path from call to call during a directory search.
1755 * Returns a held dir search structure, and bumps the reference count on the vnode,
1756 * since it saves a pointer to the vnode.
1758 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1760 smb_dirSearch_t *dsp;
1766 lock_ObtainWrite(&smb_globalLock);
1769 /* what's the biggest ID allowed in this version of the protocol */
1770 maxAllowed = isV3 ? 65535 : 255;
1771 if (smb_dirSearchCounter > maxAllowed)
1772 smb_dirSearchCounter = 1;
1774 start = smb_dirSearchCounter;
1777 /* twice so we have enough tries to find guys we GC after one pass;
1778 * 10 extra is just in case I mis-counted.
1780 if (++counter > 2*maxAllowed+10)
1781 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1783 if (smb_dirSearchCounter > maxAllowed) {
1784 smb_dirSearchCounter = 1;
1786 if (smb_dirSearchCounter == start) {
1788 smb_GCDirSearches(isV3);
1791 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1793 /* don't need to watch for refcount zero and deleted, since
1794 * we haven't dropped the global lock.
1796 lock_ObtainMutex(&dsp->mx);
1798 lock_ReleaseMutex(&dsp->mx);
1799 ++smb_dirSearchCounter;
1803 dsp = malloc(sizeof(*dsp));
1804 memset(dsp, 0, sizeof(*dsp));
1805 dsp->cookie = smb_dirSearchCounter;
1806 ++smb_dirSearchCounter;
1808 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1809 dsp->lastTime = osi_Time();
1810 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1811 if (!smb_lastDirSearchp)
1812 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1815 lock_ReleaseWrite(&smb_globalLock);
1819 static smb_packet_t *GetPacket(void)
1823 unsigned int npar, seg, tb_sel;
1826 lock_ObtainWrite(&smb_globalLock);
1827 tbp = smb_packetFreeListp;
1829 smb_packetFreeListp = tbp->nextp;
1830 lock_ReleaseWrite(&smb_globalLock);
1833 tbp = calloc(65540,1);
1835 tbp = malloc(sizeof(smb_packet_t));
1837 tbp->magic = SMB_PACKETMAGIC;
1840 tbp->resumeCode = 0;
1846 tbp->ncb_length = 0;
1851 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1854 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1856 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1858 osi_panic("",__FILE__,__LINE__);
1861 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1866 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1867 tbp->dos_pkt_sel = tb_sel;
1870 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1875 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1879 memcpy(tbp, pkt, sizeof(smb_packet_t));
1880 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1882 smb_HoldVC(tbp->vcp);
1886 static NCB *GetNCB(void)
1891 unsigned int npar, seg, tb_sel;
1894 lock_ObtainWrite(&smb_globalLock);
1895 tbp = smb_ncbFreeListp;
1897 smb_ncbFreeListp = tbp->nextp;
1898 lock_ReleaseWrite(&smb_globalLock);
1901 tbp = calloc(sizeof(*tbp),1);
1903 tbp = malloc(sizeof(*tbp));
1904 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1907 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1909 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1911 osi_panic("",__FILE__,__LINE__);
1913 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1918 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1919 tbp->dos_ncb_sel = tb_sel;
1921 tbp->magic = SMB_NCBMAGIC;
1924 osi_assert(tbp->magic == SMB_NCBMAGIC);
1926 memset(&tbp->ncb, 0, sizeof(NCB));
1929 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1934 void smb_FreePacket(smb_packet_t *tbp)
1936 smb_vc_t * vcp = NULL;
1937 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1939 lock_ObtainWrite(&smb_globalLock);
1940 tbp->nextp = smb_packetFreeListp;
1941 smb_packetFreeListp = tbp;
1942 tbp->magic = SMB_PACKETMAGIC;
1946 tbp->resumeCode = 0;
1952 tbp->ncb_length = 0;
1954 lock_ReleaseWrite(&smb_globalLock);
1960 static void FreeNCB(NCB *bufferp)
1964 tbp = (smb_ncb_t *) bufferp;
1965 osi_assert(tbp->magic == SMB_NCBMAGIC);
1967 lock_ObtainWrite(&smb_globalLock);
1968 tbp->nextp = smb_ncbFreeListp;
1969 smb_ncbFreeListp = tbp;
1970 lock_ReleaseWrite(&smb_globalLock);
1973 /* get a ptr to the data part of a packet, and its count */
1974 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1978 unsigned char *afterParmsp;
1980 parmBytes = *smbp->wctp << 1;
1981 afterParmsp = smbp->wctp + parmBytes + 1;
1983 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1984 if (nbytesp) *nbytesp = dataBytes;
1986 /* don't forget to skip the data byte count, since it follows
1987 * the parameters; that's where the "2" comes from below.
1989 return (unsigned char *) (afterParmsp + 2);
1992 /* must set all the returned parameters before playing around with the
1993 * data region, since the data region is located past the end of the
1994 * variable number of parameters.
1996 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1998 unsigned char *afterParmsp;
2000 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2002 *afterParmsp++ = dsize & 0xff;
2003 *afterParmsp = (dsize>>8) & 0xff;
2006 /* return the parm'th parameter in the smbp packet */
2007 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2010 unsigned char *parmDatap;
2012 parmCount = *smbp->wctp;
2014 if (parm >= parmCount) {
2019 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2021 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2022 parm, parmCount, smbp->ncb_length);
2025 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2026 1, smbp->ncb_length, ptbuf, smbp);
2027 DeregisterEventSource(h);
2029 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2030 parm, parmCount, smbp->ncb_length);
2031 osi_panic(s, __FILE__, __LINE__);
2033 parmDatap = smbp->wctp + (2*parm) + 1;
2035 return parmDatap[0] + (parmDatap[1] << 8);
2038 /* return the parm'th parameter in the smbp packet */
2039 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2042 unsigned char *parmDatap;
2044 parmCount = *smbp->wctp;
2046 if (parm * 2 + offset >= parmCount * 2) {
2051 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2053 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2054 parm, offset, parmCount, smbp->ncb_length);
2057 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2058 1, smbp->ncb_length, ptbuf, smbp);
2059 DeregisterEventSource(h);
2061 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2062 parm, offset, parmCount, smbp->ncb_length);
2063 osi_panic(s, __FILE__, __LINE__);
2065 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2067 return parmDatap[0] + (parmDatap[1] << 8);
2070 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2074 /* make sure we have enough slots */
2075 if (*smbp->wctp <= slot)
2076 *smbp->wctp = slot+1;
2078 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2079 *parmDatap++ = parmValue & 0xff;
2080 *parmDatap = (parmValue>>8) & 0xff;
2083 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2087 /* make sure we have enough slots */
2088 if (*smbp->wctp <= slot)
2089 *smbp->wctp = slot+2;
2091 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2092 *parmDatap++ = parmValue & 0xff;
2093 *parmDatap++ = (parmValue>>8) & 0xff;
2094 *parmDatap++ = (parmValue>>16) & 0xff;
2095 *parmDatap++ = (parmValue>>24) & 0xff;
2098 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2103 /* make sure we have enough slots */
2104 if (*smbp->wctp <= slot)
2105 *smbp->wctp = slot+4;
2107 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2109 *parmDatap++ = *parmValuep++;
2112 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2116 /* make sure we have enough slots */
2117 if (*smbp->wctp <= slot) {
2118 if (smbp->oddByte) {
2120 *smbp->wctp = slot+1;
2125 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2126 *parmDatap++ = parmValue & 0xff;
2129 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2133 lastSlashp = strrchr(inPathp, '\\');
2135 *lastComponentp = lastSlashp;
2138 if (inPathp == lastSlashp)
2140 *outPathp++ = *inPathp++;
2149 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2154 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2159 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2165 tlen = inp[0] + (inp[1]<<8);
2166 inp += 2; /* skip length field */
2169 *chainpp = inp + tlen;
2178 /* format a packet as a response */
2179 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2184 outp = (smb_t *) op;
2186 /* zero the basic structure through the smb_wct field, and zero the data
2187 * size field, assuming that wct stays zero; otherwise, you have to
2188 * explicitly set the data size field, too.
2190 inSmbp = (smb_t *) inp;
2191 memset(outp, 0, sizeof(smb_t)+2);
2197 outp->com = inSmbp->com;
2198 outp->tid = inSmbp->tid;
2199 outp->pid = inSmbp->pid;
2200 outp->uid = inSmbp->uid;
2201 outp->mid = inSmbp->mid;
2202 outp->res[0] = inSmbp->res[0];
2203 outp->res[1] = inSmbp->res[1];
2204 op->inCom = inSmbp->com;
2206 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2207 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2209 /* copy fields in generic packet area */
2210 op->wctp = &outp->wct;
2213 /* send a (probably response) packet; vcp tells us to whom to send it.
2214 * we compute the length by looking at wct and bcc fields.
2216 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2233 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2236 memset((char *)ncbp, 0, sizeof(NCB));
2238 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2239 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2240 extra += tp[0] + (tp[1]<<8);
2241 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2242 extra += 3; /* wct and length fields */
2244 ncbp->ncb_length = extra; /* bytes to send */
2245 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2246 ncbp->ncb_lana_num = vcp->lana;
2247 ncbp->ncb_command = NCBSEND; /* op means send data */
2249 ncbp->ncb_buffer = (char *) inp;/* packet */
2250 code = Netbios(ncbp);
2252 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2253 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2255 /* copy header information from virtual to DOS address space */
2256 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2257 code = Netbios(ncbp, dos_ncb);
2263 case 0x01: s = "llegal buffer length "; break;
2264 case 0x03: s = "illegal command "; break;
2265 case 0x05: s = "command timed out "; break;
2266 case 0x06: s = "message incomplete, issue another command"; break;
2267 case 0x07: s = "illegal buffer address "; break;
2268 case 0x08: s = "session number out of range "; break;
2269 case 0x09: s = "no resource available "; break;
2270 case 0x0a: s = "session closed "; break;
2271 case 0x0b: s = "command cancelled "; break;
2272 case 0x0d: s = "duplicate name "; break;
2273 case 0x0e: s = "name table full "; break;
2274 case 0x0f: s = "no deletions, name has active sessions "; break;
2275 case 0x11: s = "local session table full "; break;
2276 case 0x12: s = "remote session table full "; break;
2277 case 0x13: s = "illegal name number "; break;
2278 case 0x14: s = "no callname "; break;
2279 case 0x15: s = "cannot put * in NCB_NAME "; break;
2280 case 0x16: s = "name in use on remote adapter "; break;
2281 case 0x17: s = "name deleted "; break;
2282 case 0x18: s = "session ended abnormally "; break;
2283 case 0x19: s = "name conflict detected "; break;
2284 case 0x21: s = "interface busy, IRET before retrying "; break;
2285 case 0x22: s = "too many commands outstanding, retry later"; break;
2286 case 0x23: s = "ncb_lana_num field invalid "; break;
2287 case 0x24: s = "command completed while cancel occurring "; break;
2288 case 0x26: s = "command not valid to cancel "; break;
2289 case 0x30: s = "name defined by anther local process "; break;
2290 case 0x34: s = "environment undefined. RESET required "; break;
2291 case 0x35: s = "required OS resources exhausted "; break;
2292 case 0x36: s = "max number of applications exceeded "; break;
2293 case 0x37: s = "no saps available for netbios "; break;
2294 case 0x38: s = "requested resources are not available "; break;
2295 case 0x39: s = "invalid ncb address or length > segment "; break;
2296 case 0x3B: s = "invalid NCB DDID "; break;
2297 case 0x3C: s = "lock of user area failed "; break;
2298 case 0x3f: s = "NETBIOS not loaded "; break;
2299 case 0x40: s = "system error "; break;
2301 s = "unknown error";
2303 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2310 void smb_MapNTError(long code, unsigned long *NTStatusp)
2312 unsigned long NTStatus;
2314 /* map CM_ERROR_* errors to NT 32-bit status codes */
2315 /* NT Status codes are listed in ntstatus.h not winerror.h */
2316 if (code == CM_ERROR_NOSUCHCELL) {
2317 NTStatus = 0xC000000FL; /* No such file */
2319 else if (code == CM_ERROR_NOSUCHVOLUME) {
2320 NTStatus = 0xC000000FL; /* No such file */
2322 else if (code == CM_ERROR_TIMEDOUT) {
2324 NTStatus = 0xC00000CFL; /* Sharing Paused */
2326 NTStatus = 0x00000102L; /* Timeout */
2329 else if (code == CM_ERROR_RETRY) {
2330 NTStatus = 0xC000022DL; /* Retry */
2332 else if (code == CM_ERROR_NOACCESS) {
2333 NTStatus = 0xC0000022L; /* Access denied */
2335 else if (code == CM_ERROR_READONLY) {
2336 NTStatus = 0xC00000A2L; /* Write protected */
2338 else if (code == CM_ERROR_NOSUCHFILE) {
2339 NTStatus = 0xC000000FL; /* No such file */
2341 else if (code == CM_ERROR_NOSUCHPATH) {
2342 NTStatus = 0xC000003AL; /* Object path not found */
2344 else if (code == CM_ERROR_TOOBIG) {
2345 NTStatus = 0xC000007BL; /* Invalid image format */
2347 else if (code == CM_ERROR_INVAL) {
2348 NTStatus = 0xC000000DL; /* Invalid parameter */
2350 else if (code == CM_ERROR_BADFD) {
2351 NTStatus = 0xC0000008L; /* Invalid handle */
2353 else if (code == CM_ERROR_BADFDOP) {
2354 NTStatus = 0xC0000022L; /* Access denied */
2356 else if (code == CM_ERROR_EXISTS) {
2357 NTStatus = 0xC0000035L; /* Object name collision */
2359 else if (code == CM_ERROR_NOTEMPTY) {
2360 NTStatus = 0xC0000101L; /* Directory not empty */
2362 else if (code == CM_ERROR_CROSSDEVLINK) {
2363 NTStatus = 0xC00000D4L; /* Not same device */
2365 else if (code == CM_ERROR_NOTDIR) {
2366 NTStatus = 0xC0000103L; /* Not a directory */
2368 else if (code == CM_ERROR_ISDIR) {
2369 NTStatus = 0xC00000BAL; /* File is a directory */
2371 else if (code == CM_ERROR_BADOP) {
2373 /* I have no idea where this comes from */
2374 NTStatus = 0xC09820FFL; /* SMB no support */
2376 NTStatus = 0xC00000BBL; /* Not supported */
2377 #endif /* COMMENT */
2379 else if (code == CM_ERROR_BADSHARENAME) {
2380 NTStatus = 0xC00000CCL; /* Bad network name */
2382 else if (code == CM_ERROR_NOIPC) {
2384 NTStatus = 0xC0000022L; /* Access Denied */
2386 NTStatus = 0xC000013DL; /* Remote Resources */
2389 else if (code == CM_ERROR_CLOCKSKEW) {
2390 NTStatus = 0xC0000133L; /* Time difference at DC */
2392 else if (code == CM_ERROR_BADTID) {
2393 NTStatus = 0xC0982005L; /* SMB bad TID */
2395 else if (code == CM_ERROR_USESTD) {
2396 NTStatus = 0xC09820FBL; /* SMB use standard */
2398 else if (code == CM_ERROR_QUOTA) {
2400 NTStatus = 0xC0000044L; /* Quota exceeded */
2402 NTStatus = 0xC000007FL; /* Disk full */
2405 else if (code == CM_ERROR_SPACE) {
2406 NTStatus = 0xC000007FL; /* Disk full */
2408 else if (code == CM_ERROR_ATSYS) {
2409 NTStatus = 0xC0000033L; /* Object name invalid */
2411 else if (code == CM_ERROR_BADNTFILENAME) {
2412 NTStatus = 0xC0000033L; /* Object name invalid */
2414 else if (code == CM_ERROR_WOULDBLOCK) {
2415 NTStatus = 0xC0000055L; /* Lock not granted */
2417 else if (code == CM_ERROR_SHARING_VIOLATION) {
2418 NTStatus = 0xC0000043L; /* Sharing violation */
2420 else if (code == CM_ERROR_LOCK_CONFLICT) {
2421 NTStatus = 0xC0000054L; /* Lock conflict */
2423 else if (code == CM_ERROR_PARTIALWRITE) {
2424 NTStatus = 0xC000007FL; /* Disk full */
2426 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2427 NTStatus = 0xC0000023L; /* Buffer too small */
2429 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2430 NTStatus = 0xC0000035L; /* Object name collision */
2432 else if (code == CM_ERROR_BADPASSWORD) {
2433 NTStatus = 0xC000006DL; /* unknown username or bad password */
2435 else if (code == CM_ERROR_BADLOGONTYPE) {
2436 NTStatus = 0xC000015BL; /* logon type not granted */
2438 else if (code == CM_ERROR_GSSCONTINUE) {
2439 NTStatus = 0xC0000016L; /* more processing required */
2441 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2443 NTStatus = 0xC0000280L; /* reparse point not resolved */
2445 NTStatus = 0xC0000022L; /* Access Denied */
2448 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2449 NTStatus = 0xC0000257L; /* Path Not Covered */
2452 else if (code == CM_ERROR_ALLBUSY) {
2453 NTStatus = 0xC00000BFL; /* Network Busy */
2455 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2456 NTStatus = 0xC0000350L; /* Remote Host Down */
2459 /* we do not want to be telling the SMB/CIFS client that
2460 * the AFS Client Service is busy or down.
2462 else if (code == CM_ERROR_ALLBUSY ||
2463 code == CM_ERROR_ALLOFFLINE ||
2464 code == CM_ERROR_ALLDOWN) {
2465 NTStatus = 0xC00000BEL; /* Bad Network Path */
2468 else if (code == RXKADUNKNOWNKEY) {
2469 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2471 NTStatus = 0xC0982001L; /* SMB non-specific error */
2474 *NTStatusp = NTStatus;
2475 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2478 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2479 unsigned char *classp)
2481 unsigned char class;
2482 unsigned short error;
2484 /* map CM_ERROR_* errors to SMB errors */
2485 if (code == CM_ERROR_NOSUCHCELL) {
2487 error = 3; /* bad path */
2489 else if (code == CM_ERROR_NOSUCHVOLUME) {
2491 error = 3; /* bad path */
2493 else if (code == CM_ERROR_TIMEDOUT) {
2495 error = 81; /* server is paused */
2497 else if (code == CM_ERROR_RETRY) {
2498 class = 2; /* shouldn't happen */
2501 else if (code == CM_ERROR_NOACCESS) {
2503 error = 4; /* bad access */
2505 else if (code == CM_ERROR_READONLY) {
2507 error = 19; /* read only */
2509 else if (code == CM_ERROR_NOSUCHFILE) {
2511 error = 2; /* ENOENT! */
2513 else if (code == CM_ERROR_NOSUCHPATH) {
2515 error = 3; /* Bad path */
2517 else if (code == CM_ERROR_TOOBIG) {
2519 error = 11; /* bad format */
2521 else if (code == CM_ERROR_INVAL) {
2522 class = 2; /* server non-specific error code */
2525 else if (code == CM_ERROR_BADFD) {
2527 error = 6; /* invalid file handle */
2529 else if (code == CM_ERROR_BADFDOP) {
2530 class = 1; /* invalid op on FD */
2533 else if (code == CM_ERROR_EXISTS) {
2535 error = 80; /* file already exists */
2537 else if (code == CM_ERROR_NOTEMPTY) {
2539 error = 5; /* delete directory not empty */
2541 else if (code == CM_ERROR_CROSSDEVLINK) {
2543 error = 17; /* EXDEV */
2545 else if (code == CM_ERROR_NOTDIR) {
2546 class = 1; /* bad path */
2549 else if (code == CM_ERROR_ISDIR) {
2550 class = 1; /* access denied; DOS doesn't have a good match */
2553 else if (code == CM_ERROR_BADOP) {
2557 else if (code == CM_ERROR_BADSHARENAME) {
2561 else if (code == CM_ERROR_NOIPC) {
2563 error = 4; /* bad access */
2565 else if (code == CM_ERROR_CLOCKSKEW) {
2566 class = 1; /* invalid function */
2569 else if (code == CM_ERROR_BADTID) {
2573 else if (code == CM_ERROR_USESTD) {
2577 else if (code == CM_ERROR_REMOTECONN) {
2581 else if (code == CM_ERROR_QUOTA) {
2582 if (vcp->flags & SMB_VCFLAG_USEV3) {
2584 error = 39; /* disk full */
2588 error = 5; /* access denied */
2591 else if (code == CM_ERROR_SPACE) {
2592 if (vcp->flags & SMB_VCFLAG_USEV3) {
2594 error = 39; /* disk full */
2598 error = 5; /* access denied */
2601 else if (code == CM_ERROR_PARTIALWRITE) {
2603 error = 39; /* disk full */
2605 else if (code == CM_ERROR_ATSYS) {
2607 error = 2; /* ENOENT */
2609 else if (code == CM_ERROR_WOULDBLOCK) {
2611 error = 33; /* lock conflict */
2613 else if (code == CM_ERROR_LOCK_CONFLICT) {
2615 error = 33; /* lock conflict */
2617 else if (code == CM_ERROR_SHARING_VIOLATION) {
2619 error = 33; /* lock conflict */
2621 else if (code == CM_ERROR_NOFILES) {
2623 error = 18; /* no files in search */
2625 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2627 error = 183; /* Samba uses this */
2629 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2630 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2632 error = 2; /* bad password */
2634 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2636 error = 3; /* bad path */
2645 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2648 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2650 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2651 return CM_ERROR_BADOP;
2654 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2656 unsigned short EchoCount, i;
2657 char *data, *outdata;
2660 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2662 for (i=1; i<=EchoCount; i++) {
2663 data = smb_GetSMBData(inp, &dataSize);
2664 smb_SetSMBParm(outp, 0, i);
2665 smb_SetSMBDataLength(outp, dataSize);
2666 outdata = smb_GetSMBData(outp, NULL);
2667 memcpy(outdata, data, dataSize);
2668 smb_SendPacket(vcp, outp);
2674 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2677 long count, minCount, finalCount;
2682 cm_user_t *userp = NULL;
2686 char *rawBuf = NULL;
2688 dos_ptr rawBuf = NULL;
2695 fd = smb_GetSMBParm(inp, 0);
2696 count = smb_GetSMBParm(inp, 3);
2697 minCount = smb_GetSMBParm(inp, 4);
2698 offset.HighPart = 0; /* too bad */
2699 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2701 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2702 fd, offset.LowPart, count);
2704 fidp = smb_FindFID(vcp, fd, 0);
2708 pid = ((smb_t *) inp)->pid;
2710 LARGE_INTEGER LOffset, LLength;
2713 key = cm_GenerateKey(vcp->vcID, pid, fd);
2715 LOffset.HighPart = 0;
2716 LOffset.LowPart = offset.LowPart;
2717 LLength.HighPart = 0;
2718 LLength.LowPart = count;
2720 lock_ObtainMutex(&fidp->scp->mx);
2721 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2722 lock_ReleaseMutex(&fidp->scp->mx);
2728 lock_ObtainMutex(&smb_RawBufLock);
2730 /* Get a raw buf, from head of list */
2731 rawBuf = smb_RawBufs;
2733 smb_RawBufs = *(char **)smb_RawBufs;
2735 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2738 lock_ReleaseMutex(&smb_RawBufLock);
2742 if (fidp->flags & SMB_FID_IOCTL)
2745 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2747 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2750 /* Give back raw buffer */
2751 lock_ObtainMutex(&smb_RawBufLock);
2753 *((char **) rawBuf) = smb_RawBufs;
2755 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2758 smb_RawBufs = rawBuf;
2759 lock_ReleaseMutex(&smb_RawBufLock);
2762 smb_ReleaseFID(fidp);
2766 userp = smb_GetUser(vcp, inp);
2769 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2771 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2772 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2773 userp, &finalCount, TRUE /* rawFlag */);
2780 cm_ReleaseUser(userp);
2783 smb_ReleaseFID(fidp);
2788 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2790 memset((char *)ncbp, 0, sizeof(NCB));
2792 ncbp->ncb_length = (unsigned short) finalCount;
2793 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2794 ncbp->ncb_lana_num = vcp->lana;
2795 ncbp->ncb_command = NCBSEND;
2796 ncbp->ncb_buffer = rawBuf;
2799 code = Netbios(ncbp);
2801 code = Netbios(ncbp, dos_ncb);
2804 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2807 /* Give back raw buffer */
2808 lock_ObtainMutex(&smb_RawBufLock);
2810 *((char **) rawBuf) = smb_RawBufs;
2812 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2815 smb_RawBufs = rawBuf;
2816 lock_ReleaseMutex(&smb_RawBufLock);
2822 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2824 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2829 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2831 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2836 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2843 int protoIndex; /* index we're using */
2848 char protocol_array[10][1024]; /* protocol signature of the client */
2849 int caps; /* capabilities */
2852 TIME_ZONE_INFORMATION tzi;
2854 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2858 DWORD now = GetCurrentTime();
2859 if (now - last_msg_time >= 30000
2860 && now - last_msg_time <= 90000) {
2862 "Setting dead_vcp %x", active_vcp);
2864 smb_ReleaseVC(dead_vcp);
2866 "Previous dead_vcp %x", dead_vcp);
2868 smb_HoldVC(active_vcp);
2869 dead_vcp = active_vcp;
2870 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2875 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2877 namep = smb_GetSMBData(inp, &dbytes);
2880 coreProtoIndex = -1; /* not found */
2883 while(namex < dbytes) {
2884 osi_Log1(smb_logp, "Protocol %s",
2885 osi_LogSaveString(smb_logp, namep+1));
2886 strcpy(protocol_array[tcounter], namep+1);
2888 /* namep points at the first protocol, or really, a 0x02
2889 * byte preceding the null-terminated ASCII name.
2891 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2892 coreProtoIndex = tcounter;
2894 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2895 v3ProtoIndex = tcounter;
2897 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2898 NTProtoIndex = tcounter;
2901 /* compute size of protocol entry */
2902 entryLength = strlen(namep+1);
2903 entryLength += 2; /* 0x02 bytes and null termination */
2905 /* advance over this protocol entry */
2906 namex += entryLength;
2907 namep += entryLength;
2908 tcounter++; /* which proto entry we're looking at */
2911 if (NTProtoIndex != -1) {
2912 protoIndex = NTProtoIndex;
2913 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2915 else if (v3ProtoIndex != -1) {
2916 protoIndex = v3ProtoIndex;
2917 vcp->flags |= SMB_VCFLAG_USEV3;
2919 else if (coreProtoIndex != -1) {
2920 protoIndex = coreProtoIndex;
2921 vcp->flags |= SMB_VCFLAG_USECORE;
2923 else protoIndex = -1;
2925 if (protoIndex == -1)
2926 return CM_ERROR_INVAL;
2927 else if (NTProtoIndex != -1) {
2928 smb_SetSMBParm(outp, 0, protoIndex);
2929 if (smb_authType != SMB_AUTH_NONE) {
2930 smb_SetSMBParmByte(outp, 1,
2931 NEGOTIATE_SECURITY_USER_LEVEL |
2932 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2934 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2936 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2937 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2938 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2939 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2940 /* The session key is not a well documented field however most clients
2941 * will echo back the session key to the server. Currently we are using
2942 * the same value for all sessions. We should generate a random value
2943 * and store it into the vcp
2945 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2946 smb_SetSMBParm(outp, 8, 1);
2948 * Tried changing the capabilities to support for W2K - defect 117695
2949 * Maybe something else needs to be changed here?
2953 smb_SetSMBParmLong(outp, 9, 0x43fd);
2955 smb_SetSMBParmLong(outp, 9, 0x251);
2958 * 32-bit error codes *
2963 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2965 NTNEGOTIATE_CAPABILITY_DFS |
2967 NTNEGOTIATE_CAPABILITY_NTFIND |
2968 NTNEGOTIATE_CAPABILITY_RAWMODE |
2969 NTNEGOTIATE_CAPABILITY_NTSMB;
2971 if ( smb_authType == SMB_AUTH_EXTENDED )
2972 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2974 smb_SetSMBParmLong(outp, 9, caps);
2976 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2977 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2978 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2980 GetTimeZoneInformation(&tzi);
2981 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2983 if (smb_authType == SMB_AUTH_NTLM) {
2984 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2985 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2986 /* paste in encryption key */
2987 datap = smb_GetSMBData(outp, NULL);
2988 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2989 /* and the faux domain name */
2990 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2991 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2995 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2997 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2999 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3001 datap = smb_GetSMBData(outp, NULL);
3002 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3005 datap += sizeof(smb_ServerGUID);
3006 memcpy(datap, secBlob, secBlobLength);
3010 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3011 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3014 else if (v3ProtoIndex != -1) {
3015 smb_SetSMBParm(outp, 0, protoIndex);
3017 /* NOTE: Extended authentication cannot be negotiated with v3
3018 * therefore we fail over to NTLM
3020 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3021 smb_SetSMBParm(outp, 1,
3022 NEGOTIATE_SECURITY_USER_LEVEL |
3023 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3025 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3027 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3028 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3029 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3030 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3031 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3032 smb_SetSMBParm(outp, 7, 1);
3034 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3035 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3036 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3038 GetTimeZoneInformation(&tzi);
3039 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3041 /* NOTE: Extended authentication cannot be negotiated with v3
3042 * therefore we fail over to NTLM
3044 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3045 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3046 smb_SetSMBParm(outp, 12, 0); /* resvd */
3047 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3048 datap = smb_GetSMBData(outp, NULL);
3049 /* paste in a new encryption key */
3050 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3051 /* and the faux domain name */
3052 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3054 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3055 smb_SetSMBParm(outp, 12, 0); /* resvd */
3056 smb_SetSMBDataLength(outp, 0);
3059 else if (coreProtoIndex != -1) { /* not really supported anymore */
3060 smb_SetSMBParm(outp, 0, protoIndex);
3061 smb_SetSMBDataLength(outp, 0);
3066 void smb_Daemon(void *parmp)
3068 afs_uint32 count = 0;
3070 while(smbShutdownFlag == 0) {
3074 if (smbShutdownFlag == 1)
3077 if ((count % 72) == 0) { /* every five minutes */
3079 time_t old_localZero = smb_localZero;
3081 /* Initialize smb_localZero */
3082 myTime.tm_isdst = -1; /* compute whether on DST or not */
3083 myTime.tm_year = 70;
3089 smb_localZero = mktime(&myTime);
3091 #ifndef USE_NUMERIC_TIME_CONV
3092 smb_CalculateNowTZ();
3093 #endif /* USE_NUMERIC_TIME_CONV */
3094 #ifdef AFS_FREELANCE
3095 if ( smb_localZero != old_localZero )
3096 cm_noteLocalMountPointChange();
3099 /* XXX GC dir search entries */
3103 void smb_WaitingLocksDaemon()
3105 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3106 smb_waitingLock_t *wl, *wlNext;
3109 smb_packet_t *inp, *outp;
3113 while (smbShutdownFlag == 0) {
3114 lock_ObtainWrite(&smb_globalLock);
3115 nwlRequest = smb_allWaitingLocks;
3116 if (nwlRequest == NULL) {
3117 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3127 lock_ObtainWrite(&smb_globalLock);
3129 wlRequest = nwlRequest;
3130 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3131 lock_ReleaseWrite(&smb_globalLock);
3135 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3136 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3139 /* wl->state is either _DONE or _WAITING. _ERROR
3140 would no longer be on the queue. */
3141 code = cm_RetryLock( wl->lockp,
3142 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3145 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3146 } else if (code != CM_ERROR_WOULDBLOCK) {
3147 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3152 if (code == CM_ERROR_WOULDBLOCK) {
3155 if (wlRequest->timeRemaining != 0xffffffff
3156 && (wlRequest->timeRemaining -= 1000) < 0)
3168 scp = wlRequest->scp;
3172 lock_ObtainMutex(&scp->mx);
3174 for (wl = wlRequest->locks; wl; wl = wlNext) {
3175 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3177 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3178 wl->LLength, wl->key, NULL, &req);
3180 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3185 lock_ReleaseMutex(&scp->mx);
3188 for (wl = wlRequest->locks; wl; wl = wlNext) {
3189 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3190 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3195 vcp = wlRequest->vcp;
3196 inp = wlRequest->inp;
3197 outp = wlRequest->outp;
3199 ncbp->ncb_length = inp->ncb_length;
3200 inp->spacep = cm_GetSpace();
3202 /* Remove waitingLock from list */
3203 lock_ObtainWrite(&smb_globalLock);
3204 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3206 lock_ReleaseWrite(&smb_globalLock);
3208 /* Resume packet processing */
3210 smb_SetSMBDataLength(outp, 0);
3211 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3212 outp->resumeCode = code;
3214 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3217 cm_FreeSpace(inp->spacep);
3218 smb_FreePacket(inp);
3219 smb_FreePacket(outp);
3221 cm_ReleaseSCache(wlRequest->scp);
3224 } while (nwlRequest && smbShutdownFlag == 0);
3229 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3231 osi_Log0(smb_logp, "SMB receive get disk attributes");
3233 smb_SetSMBParm(outp, 0, 32000);
3234 smb_SetSMBParm(outp, 1, 64);
3235 smb_SetSMBParm(outp, 2, 1024);
3236 smb_SetSMBParm(outp, 3, 30000);
3237 smb_SetSMBParm(outp, 4, 0);
3238 smb_SetSMBDataLength(outp, 0);
3242 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3246 unsigned short newTid;
3247 char shareName[256];
3255 osi_Log0(smb_logp, "SMB receive tree connect");
3257 /* parse input parameters */
3258 tp = smb_GetSMBData(inp, NULL);
3259 pathp = smb_ParseASCIIBlock(tp, &tp);
3260 if (smb_StoreAnsiFilenames)
3261 OemToChar(pathp,pathp);
3262 passwordp = smb_ParseASCIIBlock(tp, &tp);
3263 tp = strrchr(pathp, '\\');
3265 return CM_ERROR_BADSMB;
3266 strcpy(shareName, tp+1);
3268 userp = smb_GetUser(vcp, inp);
3270 lock_ObtainMutex(&vcp->mx);
3271 newTid = vcp->tidCounter++;
3272 lock_ReleaseMutex(&vcp->mx);
3274 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3275 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3276 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3278 smb_ReleaseUID(uidp);
3280 smb_ReleaseTID(tidp);
3281 return CM_ERROR_BADSHARENAME;
3283 lock_ObtainMutex(&tidp->mx);
3284 tidp->userp = userp;
3285 tidp->pathname = sharePath;
3286 lock_ReleaseMutex(&tidp->mx);
3287 smb_ReleaseTID(tidp);
3289 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3290 smb_SetSMBParm(rsp, 1, newTid);
3291 smb_SetSMBDataLength(rsp, 0);
3293 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3297 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3301 if (*inp++ != 0x1) return NULL;
3302 tlen = inp[0] + (inp[1]<<8);
3303 inp += 2; /* skip length field */
3306 *chainpp = inp + tlen;
3309 if (lengthp) *lengthp = tlen;
3314 /* set maskp to the mask part of the incoming path.
3315 * Mask is 11 bytes long (8.3 with the dot elided).
3316 * Returns true if succeeds with a valid name, otherwise it does
3317 * its best, but returns false.
3319 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3327 /* starts off valid */
3330 /* mask starts out all blanks */
3331 memset(maskp, ' ', 11);
3333 /* find last backslash, or use whole thing if there is none */
3334 tp = strrchr(pathp, '\\');
3335 if (!tp) tp = pathp;
3336 else tp++; /* skip slash */
3340 /* names starting with a dot are illegal */
3341 if (*tp == '.') valid8Dot3 = 0;
3345 if (tc == 0) return valid8Dot3;
3346 if (tc == '.' || tc == '"') break;
3347 if (i < 8) *up++ = tc;
3348 else valid8Dot3 = 0;
3351 /* if we get here, tp point after the dot */
3352 up = maskp+8; /* ext goes here */
3359 if (tc == '.' || tc == '"')
3362 /* copy extension if not too long */
3372 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3382 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3384 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3388 /* otherwise, we have a valid 8.3 name; see if we have a match,
3389 * treating '?' as a wildcard in maskp (but not in the file name).
3391 tp1 = umask; /* real name, in mask format */
3392 tp2 = maskp; /* mask, in mask format */
3393 for(i=0; i<11; i++) {
3394 tc1 = *tp1++; /* char from real name */
3395 tc2 = *tp2++; /* char from mask */
3396 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3397 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3400 if (tc2 == '?' && tc1 != ' ')
3407 /* we got a match */
3411 char *smb_FindMask(char *pathp)
3415 tp = strrchr(pathp, '\\'); /* find last slash */
3418 return tp+1; /* skip the slash */
3420 return pathp; /* no slash, return the entire path */
3423 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3425 unsigned char *pathp;
3427 unsigned char mask[11];
3428 unsigned char *statBlockp;
3429 unsigned char initStatBlock[21];
3432 osi_Log0(smb_logp, "SMB receive search volume");
3434 /* pull pathname and stat block out of request */
3435 tp = smb_GetSMBData(inp, NULL);
3436 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3437 osi_assert(pathp != NULL);
3438 if (smb_StoreAnsiFilenames)
3439 OemToChar(pathp,pathp);
3440 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3441 osi_assert(statBlockp != NULL);
3443 statBlockp = initStatBlock;
3447 /* for returning to caller */
3448 smb_Get8Dot3MaskFromPath(mask, pathp);
3450 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3451 tp = smb_GetSMBData(outp, NULL);
3453 *tp++ = 43; /* bytes in a dir entry */
3454 *tp++ = 0; /* high byte in counter */
3456 /* now marshall the dir entry, starting with the search status */
3457 *tp++ = statBlockp[0]; /* Reserved */
3458 memcpy(tp, mask, 11); tp += 11; /* FileName */
3460 /* now pass back server use info, with 1st byte non-zero */
3462 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3464 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3466 *tp++ = 0x8; /* attribute: volume */
3476 /* 4 byte file size */
3482 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3483 memset(tp, ' ', 13);
3486 /* set the length of the data part of the packet to 43 + 3, for the dir
3487 * entry plus the 5 and the length fields.
3489 smb_SetSMBDataLength(outp, 46);
3493 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3494 cm_user_t *userp, cm_req_t *reqp)
3502 smb_dirListPatch_t *patchp;
3503 smb_dirListPatch_t *npatchp;
3505 for (patchp = *dirPatchespp; patchp; patchp =
3506 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3508 dptr = patchp->dptr;
3510 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3512 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3513 *dptr++ = SMB_ATTR_HIDDEN;
3516 lock_ObtainMutex(&scp->mx);
3517 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3518 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3520 lock_ReleaseMutex(&scp->mx);
3521 cm_ReleaseSCache(scp);
3522 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3523 *dptr++ = SMB_ATTR_HIDDEN;
3527 attr = smb_Attributes(scp);
3528 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3529 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3530 attr |= SMB_ATTR_HIDDEN;
3534 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3537 shortTemp = (unsigned short) (dosTime & 0xffff);
3538 *((u_short *)dptr) = shortTemp;
3541 /* and copy out date */
3542 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3543 *((u_short *)dptr) = shortTemp;
3546 /* copy out file length */
3547 *((u_long *)dptr) = scp->length.LowPart;
3549 lock_ReleaseMutex(&scp->mx);
3550 cm_ReleaseSCache(scp);
3553 /* now free the patches */
3554 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3555 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3559 /* and mark the list as empty */
3560 *dirPatchespp = NULL;
3565 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3574 smb_dirListPatch_t *dirListPatchesp;
3575 smb_dirListPatch_t *curPatchp;
3579 osi_hyper_t dirLength;
3580 osi_hyper_t bufferOffset;
3581 osi_hyper_t curOffset;
3583 unsigned char *inCookiep;
3584 smb_dirSearch_t *dsp;
3588 unsigned long clientCookie;
3589 cm_pageHeader_t *pageHeaderp;
3590 cm_user_t *userp = NULL;
3597 long nextEntryCookie;
3598 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3599 char resByte; /* reserved byte from the cookie */
3600 char *op; /* output data ptr */
3601 char *origOp; /* original value of op */
3602 cm_space_t *spacep; /* for pathname buffer */
3613 maxCount = smb_GetSMBParm(inp, 0);
3615 dirListPatchesp = NULL;
3617 caseFold = CM_FLAG_CASEFOLD;
3619 tp = smb_GetSMBData(inp, NULL);
3620 pathp = smb_ParseASCIIBlock(tp, &tp);
3621 if (smb_StoreAnsiFilenames)
3622 OemToChar(pathp,pathp);
3623 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3625 /* bail out if request looks bad */
3626 if (!tp || !pathp) {
3627 return CM_ERROR_BADSMB;
3630 /* We can handle long names */
3631 if (vcp->flags & SMB_VCFLAG_USENT)
3632 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3634 /* make sure we got a whole search status */
3635 if (dataLength < 21) {
3636 nextCookie = 0; /* start at the beginning of the dir */
3639 attribute = smb_GetSMBParm(inp, 1);
3641 /* handle volume info in another function */
3642 if (attribute & 0x8)
3643 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3645 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3646 maxCount, osi_LogSaveString(smb_logp, pathp));
3648 if (*pathp == 0) { /* null pathp, treat as root dir */
3649 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3650 return CM_ERROR_NOFILES;
3654 dsp = smb_NewDirSearch(0);
3655 dsp->attribute = attribute;
3656 smb_Get8Dot3MaskFromPath(mask, pathp);
3657 memcpy(dsp->mask, mask, 11);
3659 /* track if this is likely to match a lot of entries */
3660 if (smb_IsStarMask(mask))
3665 /* pull the next cookie value out of the search status block */
3666 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3667 + (inCookiep[16]<<24);
3668 dsp = smb_FindDirSearch(inCookiep[12]);
3670 /* can't find dir search status; fatal error */
3671 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3672 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3673 return CM_ERROR_BADFD;
3675 attribute = dsp->attribute;
3676 resByte = inCookiep[0];
3678 /* copy out client cookie, in host byte order. Don't bother
3679 * interpreting it, since we're just passing it through, anyway.
3681 memcpy(&clientCookie, &inCookiep[17], 4);
3683 memcpy(mask, dsp->mask, 11);
3685 /* assume we're doing a star match if it has continued for more
3691 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3692 nextCookie, dsp->cookie, attribute);
3694 userp = smb_GetUser(vcp, inp);
3696 /* try to get the vnode for the path name next */
3697 lock_ObtainMutex(&dsp->mx);
3703 spacep = inp->spacep;
3704 smb_StripLastComponent(spacep->data, NULL, pathp);
3705 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3707 lock_ReleaseMutex(&dsp->mx);
3708 cm_ReleaseUser(userp);
3709 smb_DeleteDirSearch(dsp);
3710 smb_ReleaseDirSearch(dsp);
3711 return CM_ERROR_NOFILES;
3713 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3714 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3717 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3718 cm_ReleaseSCache(scp);
3719 lock_ReleaseMutex(&dsp->mx);
3720 cm_ReleaseUser(userp);
3721 smb_DeleteDirSearch(dsp);
3722 smb_ReleaseDirSearch(dsp);
3723 if ( WANTS_DFS_PATHNAMES(inp) )
3724 return CM_ERROR_PATH_NOT_COVERED;
3726 return CM_ERROR_BADSHARENAME;
3728 #endif /* DFS_SUPPORT */
3731 /* we need one hold for the entry we just stored into,
3732 * and one for our own processing. When we're done with this
3733 * function, we'll drop the one for our own processing.
3734 * We held it once from the namei call, and so we do another hold
3738 lock_ObtainMutex(&scp->mx);
3739 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3740 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3741 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3742 dsp->flags |= SMB_DIRSEARCH_BULKST;
3744 lock_ReleaseMutex(&scp->mx);
3747 lock_ReleaseMutex(&dsp->mx);
3749 cm_ReleaseUser(userp);
3750 smb_DeleteDirSearch(dsp);
3751 smb_ReleaseDirSearch(dsp);
3755 /* reserves space for parameter; we'll adjust it again later to the
3756 * real count of the # of entries we returned once we've actually
3757 * assembled the directory listing.
3759 smb_SetSMBParm(outp, 0, 0);
3761 /* get the directory size */
3762 lock_ObtainMutex(&scp->mx);
3763 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3764 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3766 lock_ReleaseMutex(&scp->mx);
3767 cm_ReleaseSCache(scp);
3768 cm_ReleaseUser(userp);
3769 smb_DeleteDirSearch(dsp);
3770 smb_ReleaseDirSearch(dsp);
3774 dirLength = scp->length;
3776 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3777 curOffset.HighPart = 0;
3778 curOffset.LowPart = nextCookie;
3779 origOp = op = smb_GetSMBData(outp, NULL);
3780 /* and write out the basic header */
3781 *op++ = 5; /* variable block */
3782 op += 2; /* skip vbl block length; we'll fill it in later */
3786 /* make sure that curOffset.LowPart doesn't point to the first
3787 * 32 bytes in the 2nd through last dir page, and that it doesn't
3788 * point at the first 13 32-byte chunks in the first dir page,
3789 * since those are dir and page headers, and don't contain useful
3792 temp = curOffset.LowPart & (2048-1);
3793 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3794 /* we're in the first page */
3795 if (temp < 13*32) temp = 13*32;
3798 /* we're in a later dir page */
3799 if (temp < 32) temp = 32;
3802 /* make sure the low order 5 bits are zero */
3805 /* now put temp bits back ito curOffset.LowPart */
3806 curOffset.LowPart &= ~(2048-1);
3807 curOffset.LowPart |= temp;
3809 /* check if we've returned all the names that will fit in the
3812 if (returnedNames >= maxCount) {
3813 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3814 returnedNames, maxCount);
3818 /* check if we've passed the dir's EOF */
3819 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3821 /* see if we can use the bufferp we have now; compute in which page
3822 * the current offset would be, and check whether that's the offset
3823 * of the buffer we have. If not, get the buffer.
3825 thyper.HighPart = curOffset.HighPart;
3826 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3827 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3830 buf_Release(bufferp);
3833 lock_ReleaseMutex(&scp->mx);
3834 lock_ObtainRead(&scp->bufCreateLock);
3835 code = buf_Get(scp, &thyper, &bufferp);
3836 lock_ReleaseRead(&scp->bufCreateLock);
3837 lock_ObtainMutex(&dsp->mx);
3839 /* now, if we're doing a star match, do bulk fetching of all of
3840 * the status info for files in the dir.
3843 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3844 lock_ObtainMutex(&scp->mx);
3845 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3846 LargeIntegerGreaterThanOrEqualTo(thyper,
3847 scp->bulkStatProgress)) {
3848 /* Don't bulk stat if risking timeout */
3849 int now = GetCurrentTime();
3850 if (now - req.startTime > 5000) {
3851 scp->bulkStatProgress = thyper;
3852 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3853 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3855 cm_TryBulkStat(scp, &thyper, userp, &req);
3858 lock_ObtainMutex(&scp->mx);
3860 lock_ReleaseMutex(&dsp->mx);
3862 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3866 bufferOffset = thyper;
3868 /* now get the data in the cache */
3870 code = cm_SyncOp(scp, bufferp, userp, &req,
3872 CM_SCACHESYNC_NEEDCALLBACK |
3873 CM_SCACHESYNC_READ);
3875 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3879 if (cm_HaveBuffer(scp, bufferp, 0)) {
3880 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3884 /* otherwise, load the buffer and try again */
3885 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3887 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3888 scp, bufferp, code);
3893 buf_Release(bufferp);
3897 } /* if (wrong buffer) ... */
3899 /* now we have the buffer containing the entry we're interested in; copy
3900 * it out if it represents a non-deleted entry.
3902 entryInDir = curOffset.LowPart & (2048-1);
3903 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3905 /* page header will help tell us which entries are free. Page header
3906 * can change more often than once per buffer, since AFS 3 dir page size
3907 * may be less than (but not more than a buffer package buffer.
3909 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3910 temp &= ~(2048 - 1); /* turn off intra-page bits */
3911 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3913 /* now determine which entry we're looking at in the page. If it is
3914 * free (there's a free bitmap at the start of the dir), we should
3915 * skip these 32 bytes.
3917 slotInPage = (entryInDir & 0x7e0) >> 5;
3918 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3919 /* this entry is free */
3920 numDirChunks = 1; /* only skip this guy */
3924 tp = bufferp->datap + entryInBuffer;
3925 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3927 /* while we're here, compute the next entry's location, too,
3928 * since we'll need it when writing out the cookie into the dir
3931 * XXXX Probably should do more sanity checking.
3933 numDirChunks = cm_NameEntries(dep->name, NULL);
3935 /* compute the offset of the cookie representing the next entry */
3936 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3938 /* Compute 8.3 name if necessary */
3939 actualName = dep->name;
3940 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3941 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3942 actualName = shortName;
3945 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3946 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3947 osi_LogSaveString(smb_logp, actualName));
3949 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3950 /* this is one of the entries to use: it is not deleted
3951 * and it matches the star pattern we're looking for.
3954 /* Eliminate entries that don't match requested
3957 /* no hidden files */
3958 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3959 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3963 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3965 /* We have already done the cm_TryBulkStat above */
3966 fid.cell = scp->fid.cell;
3967 fid.volume = scp->fid.volume;
3968 fid.vnode = ntohl(dep->fid.vnode);
3969 fid.unique = ntohl(dep->fid.unique);
3970 fileType = cm_FindFileType(&fid);
3971 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3972 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3974 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3975 fileType == CM_SCACHETYPE_DFSLINK ||
3976 fileType == CM_SCACHETYPE_INVALID)
3977 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3982 memcpy(op, mask, 11); op += 11;
3983 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3984 *op++ = nextEntryCookie & 0xff;
3985 *op++ = (nextEntryCookie>>8) & 0xff;
3986 *op++ = (nextEntryCookie>>16) & 0xff;
3987 *op++ = (nextEntryCookie>>24) & 0xff;
3988 memcpy(op, &clientCookie, 4); op += 4;
3990 /* now we emit the attribute. This is sort of tricky,
3991 * since we need to really stat the file to find out
3992 * what type of entry we've got. Right now, we're
3993 * copying out data from a buffer, while holding the
3994 * scp locked, so it isn't really convenient to stat
3995 * something now. We'll put in a place holder now,
3996 * and make a second pass before returning this to get
3997 * the real attributes. So, we just skip the data for
3998 * now, and adjust it later. We allocate a patch
3999 * record to make it easy to find this point later.
4000 * The replay will happen at a time when it is safe to
4001 * unlock the directory.
4003 curPatchp = malloc(sizeof(*curPatchp));
4004 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4005 curPatchp->dptr = op;
4006 curPatchp->fid.cell = scp->fid.cell;
4007 curPatchp->fid.volume = scp->fid.volume;
4008 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4009 curPatchp->fid.unique = ntohl(dep->fid.unique);
4011 /* do hidden attribute here since name won't be around when applying
4015 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4016 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4018 curPatchp->flags = 0;
4020 op += 9; /* skip attr, time, date and size */
4022 /* zero out name area. The spec says to pad with
4023 * spaces, but Samba doesn't, and neither do we.
4027 /* finally, we get to copy out the name; we know that
4028 * it fits in 8.3 or the pattern wouldn't match, but it
4029 * never hurts to be sure.
4031 strncpy(op, actualName, 13);
4032 if (smb_StoreAnsiFilenames)
4035 /* Uppercase if requested by client */
4036 if (!KNOWS_LONG_NAMES(inp))
4041 /* now, adjust the # of entries copied */
4043 } /* if we're including this name */
4046 /* and adjust curOffset to be where the new cookie is */
4047 thyper.HighPart = 0;
4048 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4049 curOffset = LargeIntegerAdd(thyper, curOffset);
4050 } /* while copying data for dir listing */
4052 /* release the mutex */
4053 lock_ReleaseMutex(&scp->mx);
4054 if (bufferp) buf_Release(bufferp);
4056 /* apply and free last set of patches; if not doing a star match, this
4057 * will be empty, but better safe (and freeing everything) than sorry.
4059 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4061 /* special return code for unsuccessful search */
4062 if (code == 0 && dataLength < 21 && returnedNames == 0)
4063 code = CM_ERROR_NOFILES;
4065 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4066 returnedNames, code);
4069 smb_DeleteDirSearch(dsp);
4070 smb_ReleaseDirSearch(dsp);
4071 cm_ReleaseSCache(scp);
4072 cm_ReleaseUser(userp);
4076 /* finalize the output buffer */
4077 smb_SetSMBParm(outp, 0, returnedNames);
4078 temp = (long) (op - origOp);
4079 smb_SetSMBDataLength(outp, temp);
4081 /* the data area is a variable block, which has a 5 (already there)
4082 * followed by the length of the # of data bytes. We now know this to
4083 * be "temp," although that includes the 3 bytes of vbl block header.
4084 * Deduct for them and fill in the length field.
4086 temp -= 3; /* deduct vbl block info */
4087 osi_assert(temp == (43 * returnedNames));
4088 origOp[1] = temp & 0xff;
4089 origOp[2] = (temp>>8) & 0xff;
4090 if (returnedNames == 0)
4091 smb_DeleteDirSearch(dsp);
4092 smb_ReleaseDirSearch(dsp);
4093 cm_ReleaseSCache(scp);
4094 cm_ReleaseUser(userp);
4098 /* verify that this is a valid path to a directory. I don't know why they
4099 * don't use the get file attributes call.
4101 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4105 cm_scache_t *rootScp;
4106 cm_scache_t *newScp;
4115 pathp = smb_GetSMBData(inp, NULL);
4116 pathp = smb_ParseASCIIBlock(pathp, NULL);
4118 return CM_ERROR_BADFD;
4119 if (smb_StoreAnsiFilenames)
4120 OemToChar(pathp,pathp);
4121 osi_Log1(smb_logp, "SMB receive check path %s",
4122 osi_LogSaveString(smb_logp, pathp));
4124 rootScp = cm_data.rootSCachep;
4126 userp = smb_GetUser(vcp, inp);
4128 caseFold = CM_FLAG_CASEFOLD;
4130 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4132 cm_ReleaseUser(userp);
4133 return CM_ERROR_NOSUCHPATH;
4135 code = cm_NameI(rootScp, pathp,
4136 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4137 userp, tidPathp, &req, &newScp);
4140 cm_ReleaseUser(userp);
4145 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4146 cm_ReleaseSCache(newScp);
4147 cm_ReleaseUser(userp);
4148 if ( WANTS_DFS_PATHNAMES(inp) )
4149 return CM_ERROR_PATH_NOT_COVERED;
4151 return CM_ERROR_BADSHARENAME;
4153 #endif /* DFS_SUPPORT */
4155 /* now lock the vnode with a callback; returns with newScp locked */
4156 lock_ObtainMutex(&newScp->mx);
4157 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4158 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4159 if (code && code != CM_ERROR_NOACCESS) {
4160 lock_ReleaseMutex(&newScp->mx);
4161 cm_ReleaseSCache(newScp);
4162 cm_ReleaseUser(userp);
4166 attrs = smb_Attributes(newScp);
4168 if (!(attrs & SMB_ATTR_DIRECTORY))
4169 code = CM_ERROR_NOTDIR;
4171 lock_ReleaseMutex(&newScp->mx);
4173 cm_ReleaseSCache(newScp);
4174 cm_ReleaseUser(userp);
4178 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4182 cm_scache_t *rootScp;
4183 unsigned short attribute;
4185 cm_scache_t *newScp;
4194 /* decode basic attributes we're passed */
4195 attribute = smb_GetSMBParm(inp, 0);
4196 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4198 pathp = smb_GetSMBData(inp, NULL);
4199 pathp = smb_ParseASCIIBlock(pathp, NULL);
4201 return CM_ERROR_BADSMB;
4202 if (smb_StoreAnsiFilenames)
4203 OemToChar(pathp,pathp);
4205 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4206 dosTime, attribute);
4208 rootScp = cm_data.rootSCachep;
4210 userp = smb_GetUser(vcp, inp);
4212 caseFold = CM_FLAG_CASEFOLD;
4214 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4216 cm_ReleaseUser(userp);
4217 return CM_ERROR_NOSUCHFILE;
4219 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4220 tidPathp, &req, &newScp);
4223 cm_ReleaseUser(userp);
4228 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4229 cm_ReleaseSCache(newScp);
4230 cm_ReleaseUser(userp);
4231 if ( WANTS_DFS_PATHNAMES(inp) )
4232 return CM_ERROR_PATH_NOT_COVERED;
4234 return CM_ERROR_BADSHARENAME;
4236 #endif /* DFS_SUPPORT */
4238 /* now lock the vnode with a callback; returns with newScp locked; we
4239 * need the current status to determine what the new status is, in some
4242 lock_ObtainMutex(&newScp->mx);
4243 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4244 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4246 lock_ReleaseMutex(&newScp->mx);
4247 cm_ReleaseSCache(newScp);
4248 cm_ReleaseUser(userp);
4252 /* Check for RO volume */
4253 if (newScp->flags & CM_SCACHEFLAG_RO) {
4254 lock_ReleaseMutex(&newScp->mx);
4255 cm_ReleaseSCache(newScp);
4256 cm_ReleaseUser(userp);
4257 return CM_ERROR_READONLY;
4260 /* prepare for setattr call */
4263 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4264 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4266 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4267 /* we're told to make a writable file read-only */
4268 attr.unixModeBits = newScp->unixModeBits & ~0222;
4269 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4271 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4272 /* we're told to make a read-only file writable */
4273 attr.unixModeBits = newScp->unixModeBits | 0222;
4274 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4276 lock_ReleaseMutex(&newScp->mx);
4278 /* now call setattr */
4280 code = cm_SetAttr(newScp, &attr, userp, &req);
4284 cm_ReleaseSCache(newScp);
4285 cm_ReleaseUser(userp);
4290 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4294 cm_scache_t *rootScp;
4295 cm_scache_t *newScp, *dscp;
4307 pathp = smb_GetSMBData(inp, NULL);
4308 pathp = smb_ParseASCIIBlock(pathp, NULL);
4310 return CM_ERROR_BADSMB;
4312 if (*pathp == 0) /* null path */
4315 if (smb_StoreAnsiFilenames)
4316 OemToChar(pathp,pathp);
4318 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4319 osi_LogSaveString(smb_logp, pathp));
4321 rootScp = cm_data.rootSCachep;
4323 userp = smb_GetUser(vcp, inp);
4325 /* we shouldn't need this for V3 requests, but we seem to */
4326 caseFold = CM_FLAG_CASEFOLD;
4328 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4330 cm_ReleaseUser(userp);
4331 return CM_ERROR_NOSUCHFILE;
4335 * XXX Strange hack XXX
4337 * As of Patch 5 (16 July 97), we are having the following problem:
4338 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4339 * requests to look up "desktop.ini" in all the subdirectories.
4340 * This can cause zillions of timeouts looking up non-existent cells
4341 * and volumes, especially in the top-level directory.
4343 * We have not found any way to avoid this or work around it except
4344 * to explicitly ignore the requests for mount points that haven't
4345 * yet been evaluated and for directories that haven't yet been
4348 * We should modify this hack to provide a fake desktop.ini file
4349 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4351 spacep = inp->spacep;
4352 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4353 #ifndef SPECIAL_FOLDERS
4354 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4355 code = cm_NameI(rootScp, spacep->data,
4356 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4357 userp, tidPathp, &req, &dscp);
4360 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4361 if ( WANTS_DFS_PATHNAMES(inp) )
4362 return CM_ERROR_PATH_NOT_COVERED;
4364 return CM_ERROR_BADSHARENAME;
4366 #endif /* DFS_SUPPORT */
4367 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4368 code = CM_ERROR_NOSUCHFILE;
4369 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4370 cm_buf_t *bp = buf_Find(dscp, &hzero);
4374 code = CM_ERROR_NOSUCHFILE;
4376 cm_ReleaseSCache(dscp);
4378 cm_ReleaseUser(userp);
4383 #endif /* SPECIAL_FOLDERS */
4385 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4386 tidPathp, &req, &newScp);
4388 cm_ReleaseUser(userp);
4393 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4394 cm_ReleaseSCache(newScp);
4395 cm_ReleaseUser(userp);
4396 if ( WANTS_DFS_PATHNAMES(inp) )
4397 return CM_ERROR_PATH_NOT_COVERED;
4399 return CM_ERROR_BADSHARENAME;
4401 #endif /* DFS_SUPPORT */
4403 /* now lock the vnode with a callback; returns with newScp locked */
4404 lock_ObtainMutex(&newScp->mx);
4405 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4406 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4408 lock_ReleaseMutex(&newScp->mx);
4409 cm_ReleaseSCache(newScp);
4410 cm_ReleaseUser(userp);
4415 /* use smb_Attributes instead. Also the fact that a file is
4416 * in a readonly volume doesn't mean it shojuld be marked as RO
4418 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4419 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4420 attrs = SMB_ATTR_DIRECTORY;
4423 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4424 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4426 attrs = smb_Attributes(newScp);
4429 smb_SetSMBParm(outp, 0, attrs);
4431 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4432 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4433 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4434 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4435 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4436 smb_SetSMBParm(outp, 5, 0);
4437 smb_SetSMBParm(outp, 6, 0);
4438 smb_SetSMBParm(outp, 7, 0);
4439 smb_SetSMBParm(outp, 8, 0);
4440 smb_SetSMBParm(outp, 9, 0);
4441 smb_SetSMBDataLength(outp, 0);
4442 lock_ReleaseMutex(&newScp->mx);
4444 cm_ReleaseSCache(newScp);
4445 cm_ReleaseUser(userp);
4450 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4454 osi_Log0(smb_logp, "SMB receive tree disconnect");
4456 /* find the tree and free it */
4457 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4459 lock_ObtainMutex(&tidp->mx);
4460 tidp->flags |= SMB_TIDFLAG_DELETE;
4461 lock_ReleaseMutex(&tidp->mx);
4462 smb_ReleaseTID(tidp);
4468 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4486 pathp = smb_GetSMBData(inp, NULL);
4487 pathp = smb_ParseASCIIBlock(pathp, NULL);
4488 if (smb_StoreAnsiFilenames)
4489 OemToChar(pathp,pathp);
4491 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4493 #ifdef DEBUG_VERBOSE
4497 hexpath = osi_HexifyString( pathp );
4498 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4503 share = smb_GetSMBParm(inp, 0);
4504 attribute = smb_GetSMBParm(inp, 1);
4506 spacep = inp->spacep;
4507 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4508 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4509 /* special case magic file name for receiving IOCTL requests
4510 * (since IOCTL calls themselves aren't getting through).
4512 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4513 smb_SetupIoctlFid(fidp, spacep);
4514 smb_SetSMBParm(outp, 0, fidp->fid);
4515 smb_SetSMBParm(outp, 1, 0); /* attrs */
4516 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4517 smb_SetSMBParm(outp, 3, 0);
4518 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4519 smb_SetSMBParm(outp, 5, 0x7fff);
4520 /* pass the open mode back */
4521 smb_SetSMBParm(outp, 6, (share & 0xf));
4522 smb_SetSMBDataLength(outp, 0);
4523 smb_ReleaseFID(fidp);
4527 userp = smb_GetUser(vcp, inp);
4529 caseFold = CM_FLAG_CASEFOLD;
4531 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4533 cm_ReleaseUser(userp);
4534 return CM_ERROR_NOSUCHPATH;
4536 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4537 tidPathp, &req, &scp);
4540 cm_ReleaseUser(userp);
4545 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4546 cm_ReleaseSCache(scp);
4547 cm_ReleaseUser(userp);
4548 if ( WANTS_DFS_PATHNAMES(inp) )
4549 return CM_ERROR_PATH_NOT_COVERED;
4551 return CM_ERROR_BADSHARENAME;
4553 #endif /* DFS_SUPPORT */
4555 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4557 cm_ReleaseSCache(scp);
4558 cm_ReleaseUser(userp);
4562 /* don't need callback to check file type, since file types never
4563 * change, and namei and cm_Lookup all stat the object at least once on
4564 * a successful return.
4566 if (scp->fileType != CM_SCACHETYPE_FILE) {
4567 cm_ReleaseSCache(scp);
4568 cm_ReleaseUser(userp);
4569 return CM_ERROR_ISDIR;
4572 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4575 /* save a pointer to the vnode */
4578 if ((share & 0xf) == 0)
4579 fidp->flags |= SMB_FID_OPENREAD;
4580 else if ((share & 0xf) == 1)
4581 fidp->flags |= SMB_FID_OPENWRITE;
4583 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4585 lock_ObtainMutex(&scp->mx);
4586 smb_SetSMBParm(outp, 0, fidp->fid);
4587 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4588 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4589 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4590 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4591 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4592 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4593 /* pass the open mode back; XXXX add access checks */
4594 smb_SetSMBParm(outp, 6, (share & 0xf));
4595 smb_SetSMBDataLength(outp, 0);
4596 lock_ReleaseMutex(&scp->mx);
4599 cm_Open(scp, 0, userp);
4601 /* send and free packet */
4602 smb_ReleaseFID(fidp);
4603 cm_ReleaseUser(userp);
4604 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4608 typedef struct smb_unlinkRock {
4613 char *maskp; /* pointer to the star pattern */
4618 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4621 smb_unlinkRock_t *rockp;
4629 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4630 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4631 caseFold |= CM_FLAG_8DOT3;
4633 matchName = dep->name;
4634 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4636 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4637 !cm_Is8Dot3(dep->name)) {
4638 cm_Gen8Dot3Name(dep, shortName, NULL);
4639 matchName = shortName;
4640 /* 8.3 matches are always case insensitive */
4641 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4644 osi_Log1(smb_logp, "Unlinking %s",
4645 osi_LogSaveString(smb_logp, matchName));
4646 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4647 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4648 smb_NotifyChange(FILE_ACTION_REMOVED,
4649 FILE_NOTIFY_CHANGE_FILE_NAME,
4650 dscp, dep->name, NULL, TRUE);
4654 /* If we made a case sensitive exact match, we might as well quit now. */
4655 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4656 code = CM_ERROR_STOPNOW;
4664 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4673 smb_unlinkRock_t rock;
4682 attribute = smb_GetSMBParm(inp, 0);
4684 tp = smb_GetSMBData(inp, NULL);
4685 pathp = smb_ParseASCIIBlock(tp, &tp);
4686 if (smb_StoreAnsiFilenames)
4687 OemToChar(pathp,pathp);
4689 osi_Log1(smb_logp, "SMB receive unlink %s",
4690 osi_LogSaveString(smb_logp, pathp));
4692 spacep = inp->spacep;
4693 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4695 userp = smb_GetUser(vcp, inp);
4697 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4699 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4701 cm_ReleaseUser(userp);
4702 return CM_ERROR_NOSUCHPATH;
4704 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4707 cm_ReleaseUser(userp);
4712 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4713 cm_ReleaseSCache(dscp);
4714 cm_ReleaseUser(userp);
4715 if ( WANTS_DFS_PATHNAMES(inp) )
4716 return CM_ERROR_PATH_NOT_COVERED;
4718 return CM_ERROR_BADSHARENAME;
4720 #endif /* DFS_SUPPORT */
4722 /* otherwise, scp points to the parent directory. */
4729 rock.maskp = smb_FindMask(pathp);
4730 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4733 thyper.HighPart = 0;
4739 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4740 * match. If that fails, we do a case insensitve match.
4742 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4743 !smb_IsStarMask(rock.maskp)) {
4744 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4747 thyper.HighPart = 0;
4748 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4753 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4755 if (code == CM_ERROR_STOPNOW)
4758 cm_ReleaseUser(userp);
4760 cm_ReleaseSCache(dscp);
4762 if (code == 0 && !rock.any)
4763 code = CM_ERROR_NOSUCHFILE;
4767 typedef struct smb_renameRock {
4768 cm_scache_t *odscp; /* old dir */
4769 cm_scache_t *ndscp; /* new dir */
4770 cm_user_t *userp; /* user */
4771 cm_req_t *reqp; /* request struct */
4772 smb_vc_t *vcp; /* virtual circuit */
4773 char *maskp; /* pointer to star pattern of old file name */
4774 int flags; /* tilde, casefold, etc */
4775 char *newNamep; /* ptr to the new file's name */
4778 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4781 smb_renameRock_t *rockp;
4786 rockp = (smb_renameRock_t *) vrockp;
4788 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4789 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4790 caseFold |= CM_FLAG_8DOT3;
4792 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4794 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4795 !cm_Is8Dot3(dep->name)) {
4796 cm_Gen8Dot3Name(dep, shortName, NULL);
4797 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4800 code = cm_Rename(rockp->odscp, dep->name,
4801 rockp->ndscp, rockp->newNamep, rockp->userp,
4803 /* if the call worked, stop doing the search now, since we
4804 * really only want to rename one file.
4807 code = CM_ERROR_STOPNOW;
4816 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4819 cm_space_t *spacep = NULL;
4820 smb_renameRock_t rock;
4821 cm_scache_t *oldDscp = NULL;
4822 cm_scache_t *newDscp = NULL;
4823 cm_scache_t *tmpscp= NULL;
4824 cm_scache_t *tmpscp2 = NULL;
4834 userp = smb_GetUser(vcp, inp);
4835 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4837 cm_ReleaseUser(userp);
4838 return CM_ERROR_NOSUCHPATH;
4842 spacep = inp->spacep;
4843 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4845 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4846 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4847 userp, tidPathp, &req, &oldDscp);
4849 cm_ReleaseUser(userp);
4854 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4855 cm_ReleaseSCache(oldDscp);
4856 cm_ReleaseUser(userp);
4857 if ( WANTS_DFS_PATHNAMES(inp) )
4858 return CM_ERROR_PATH_NOT_COVERED;
4860 return CM_ERROR_BADSHARENAME;
4862 #endif /* DFS_SUPPORT */
4864 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4865 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4866 userp, tidPathp, &req, &newDscp);
4869 cm_ReleaseSCache(oldDscp);
4870 cm_ReleaseUser(userp);
4875 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4876 cm_ReleaseSCache(oldDscp);
4877 cm_ReleaseSCache(newDscp);
4878 cm_ReleaseUser(userp);
4879 if ( WANTS_DFS_PATHNAMES(inp) )
4880 return CM_ERROR_PATH_NOT_COVERED;
4882 return CM_ERROR_BADSHARENAME;
4884 #endif /* DFS_SUPPORT */
4887 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4888 * next, get the component names, and lower case them.
4891 /* handle the old name first */
4893 oldLastNamep = oldPathp;
4897 /* and handle the new name, too */
4899 newLastNamep = newPathp;
4903 /* TODO: The old name could be a wildcard. The new name must not be */
4905 /* do the vnode call */
4906 rock.odscp = oldDscp;
4907 rock.ndscp = newDscp;
4911 rock.maskp = oldLastNamep;
4912 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4913 rock.newNamep = newLastNamep;
4915 /* Check if the file already exists; if so return error */
4916 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4917 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4918 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4919 osi_LogSaveString(afsd_logp, newLastNamep));
4921 /* Check if the old and the new names differ only in case. If so return
4922 * success, else return CM_ERROR_EXISTS
4924 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4926 /* This would be a success only if the old file is *as same as* the new file */
4927 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4929 if (tmpscp == tmpscp2)
4932 code = CM_ERROR_EXISTS;
4933 cm_ReleaseSCache(tmpscp2);
4936 code = CM_ERROR_NOSUCHFILE;
4939 /* file exist, do not rename, also fixes move */
4940 osi_Log0(smb_logp, "Can't rename. Target already exists");
4941 code = CM_ERROR_EXISTS;
4945 cm_ReleaseSCache(tmpscp);
4946 cm_ReleaseSCache(newDscp);
4947 cm_ReleaseSCache(oldDscp);
4948 cm_ReleaseUser(userp);
4952 /* Now search the directory for the pattern, and do the appropriate rename when found */
4953 thyper.LowPart = 0; /* search dir from here */
4954 thyper.HighPart = 0;
4956 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4957 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
4959 if (code == CM_ERROR_STOPNOW)
4962 code = CM_ERROR_NOSUCHFILE;
4964 /* Handle Change Notification */
4966 * Being lazy, not distinguishing between files and dirs in this
4967 * filter, since we'd have to do a lookup.
4969 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4970 if (oldDscp == newDscp) {
4971 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4972 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4973 filter, oldDscp, oldLastNamep,
4974 newLastNamep, TRUE);
4976 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4977 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4978 filter, oldDscp, oldLastNamep,
4980 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4981 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4982 filter, newDscp, newLastNamep,
4987 cm_ReleaseSCache(tmpscp);
4988 cm_ReleaseUser(userp);
4989 cm_ReleaseSCache(oldDscp);
4990 cm_ReleaseSCache(newDscp);
4995 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4998 cm_space_t *spacep = NULL;
4999 cm_scache_t *oldDscp = NULL;
5000 cm_scache_t *newDscp = NULL;
5001 cm_scache_t *tmpscp= NULL;
5002 cm_scache_t *tmpscp2 = NULL;
5003 cm_scache_t *sscp = NULL;
5012 userp = smb_GetUser(vcp, inp);
5014 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5016 cm_ReleaseUser(userp);
5017 return CM_ERROR_NOSUCHPATH;
5022 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5024 spacep = inp->spacep;
5025 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5027 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5028 userp, tidPathp, &req, &oldDscp);
5030 cm_ReleaseUser(userp);
5035 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5036 cm_ReleaseSCache(oldDscp);
5037 cm_ReleaseUser(userp);
5038 if ( WANTS_DFS_PATHNAMES(inp) )
5039 return CM_ERROR_PATH_NOT_COVERED;
5041 return CM_ERROR_BADSHARENAME;
5043 #endif /* DFS_SUPPORT */
5045 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5046 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5047 userp, tidPathp, &req, &newDscp);
5049 cm_ReleaseSCache(oldDscp);
5050 cm_ReleaseUser(userp);
5055 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5056 cm_ReleaseSCache(newDscp);
5057 cm_ReleaseSCache(oldDscp);
5058 cm_ReleaseUser(userp);
5059 if ( WANTS_DFS_PATHNAMES(inp) )
5060 return CM_ERROR_PATH_NOT_COVERED;
5062 return CM_ERROR_BADSHARENAME;
5064 #endif /* DFS_SUPPORT */
5066 /* Now, although we did two lookups for the two directories (because the same
5067 * directory can be referenced through different paths), we only allow hard links
5068 * within the same directory. */
5069 if (oldDscp != newDscp) {
5070 cm_ReleaseSCache(oldDscp);
5071 cm_ReleaseSCache(newDscp);
5072 cm_ReleaseUser(userp);
5073 return CM_ERROR_CROSSDEVLINK;
5076 /* handle the old name first */
5078 oldLastNamep = oldPathp;
5082 /* and handle the new name, too */
5084 newLastNamep = newPathp;
5088 /* now lookup the old name */
5089 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5090 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5092 cm_ReleaseSCache(oldDscp);
5093 cm_ReleaseSCache(newDscp);
5094 cm_ReleaseUser(userp);
5098 /* Check if the file already exists; if so return error */
5099 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5100 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5101 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5102 osi_LogSaveString(afsd_logp, newLastNamep));
5104 /* if the existing link is to the same file, then we return success */
5106 if(sscp == tmpscp) {
5109 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5110 code = CM_ERROR_EXISTS;
5115 cm_ReleaseSCache(tmpscp);
5116 cm_ReleaseSCache(sscp);
5117 cm_ReleaseSCache(newDscp);
5118 cm_ReleaseSCache(oldDscp);
5119 cm_ReleaseUser(userp);
5123 /* now create the hardlink */
5124 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5125 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5126 osi_Log1(smb_logp," Link returns %d", code);
5128 /* Handle Change Notification */
5130 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5131 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5132 smb_NotifyChange(FILE_ACTION_ADDED,
5133 filter, newDscp, newLastNamep,
5138 cm_ReleaseSCache(tmpscp);
5139 cm_ReleaseUser(userp);
5140 cm_ReleaseSCache(sscp);
5141 cm_ReleaseSCache(oldDscp);
5142 cm_ReleaseSCache(newDscp);
5147 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5153 tp = smb_GetSMBData(inp, NULL);
5154 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5155 if (smb_StoreAnsiFilenames)
5156 OemToChar(oldPathp,oldPathp);
5157 newPathp = smb_ParseASCIIBlock(tp, &tp);
5158 if (smb_StoreAnsiFilenames)
5159 OemToChar(newPathp,newPathp);
5161 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5162 osi_LogSaveString(smb_logp, oldPathp),
5163 osi_LogSaveString(smb_logp, newPathp));
5165 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5170 typedef struct smb_rmdirRock {
5174 char *maskp; /* pointer to the star pattern */
5179 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5182 smb_rmdirRock_t *rockp;
5187 rockp = (smb_rmdirRock_t *) vrockp;
5189 matchName = dep->name;
5190 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5191 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5193 match = (strcmp(matchName, rockp->maskp) == 0);
5195 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5196 !cm_Is8Dot3(dep->name)) {
5197 cm_Gen8Dot3Name(dep, shortName, NULL);
5198 matchName = shortName;
5199 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5202 osi_Log1(smb_logp, "Removing directory %s",
5203 osi_LogSaveString(smb_logp, matchName));
5204 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5205 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5206 smb_NotifyChange(FILE_ACTION_REMOVED,
5207 FILE_NOTIFY_CHANGE_DIR_NAME,
5208 dscp, dep->name, NULL, TRUE);
5217 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5225 smb_rmdirRock_t rock;
5234 tp = smb_GetSMBData(inp, NULL);
5235 pathp = smb_ParseASCIIBlock(tp, &tp);
5236 if (smb_StoreAnsiFilenames)
5237 OemToChar(pathp,pathp);
5239 spacep = inp->spacep;
5240 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5242 userp = smb_GetUser(vcp, inp);
5244 caseFold = CM_FLAG_CASEFOLD;
5246 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5248 cm_ReleaseUser(userp);
5249 return CM_ERROR_NOSUCHPATH;
5251 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5252 userp, tidPathp, &req, &dscp);
5255 cm_ReleaseUser(userp);
5260 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5261 cm_ReleaseSCache(dscp);
5262 cm_ReleaseUser(userp);
5263 if ( WANTS_DFS_PATHNAMES(inp) )
5264 return CM_ERROR_PATH_NOT_COVERED;
5266 return CM_ERROR_BADSHARENAME;
5268 #endif /* DFS_SUPPORT */
5270 /* otherwise, scp points to the parent directory. */
5277 rock.maskp = lastNamep;
5278 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5281 thyper.HighPart = 0;
5285 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5286 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5287 if (code == 0 && !rock.any) {
5289 thyper.HighPart = 0;
5290 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5291 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5294 cm_ReleaseUser(userp);
5296 cm_ReleaseSCache(dscp);
5298 if (code == 0 && !rock.any)
5299 code = CM_ERROR_NOSUCHFILE;
5303 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5313 fid = smb_GetSMBParm(inp, 0);
5315 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5317 fid = smb_ChainFID(fid, inp);
5318 fidp = smb_FindFID(vcp, fid, 0);
5319 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5321 smb_ReleaseFID(fidp);
5322 return CM_ERROR_BADFD;
5325 userp = smb_GetUser(vcp, inp);
5327 lock_ObtainMutex(&fidp->mx);
5328 if (fidp->flags & SMB_FID_OPENWRITE)
5329 code = cm_FSync(fidp->scp, userp, &req);
5332 lock_ReleaseMutex(&fidp->mx);
5334 smb_ReleaseFID(fidp);
5336 cm_ReleaseUser(userp);
5341 struct smb_FullNameRock {
5347 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5351 struct smb_FullNameRock *vrockp;
5353 vrockp = (struct smb_FullNameRock *)rockp;
5355 if (!cm_Is8Dot3(dep->name)) {
5356 cm_Gen8Dot3Name(dep, shortName, NULL);
5358 if (cm_stricmp(shortName, vrockp->name) == 0) {
5359 vrockp->fullName = strdup(dep->name);
5360 return CM_ERROR_STOPNOW;
5363 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5364 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5365 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5366 vrockp->fullName = strdup(dep->name);
5367 return CM_ERROR_STOPNOW;
5372 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5373 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5375 struct smb_FullNameRock rock;
5381 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5382 if (code == CM_ERROR_STOPNOW)
5383 *newPathp = rock.fullName;
5385 *newPathp = strdup(pathp);
5388 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5399 fid = smb_GetSMBParm(inp, 0);
5400 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5402 osi_Log1(smb_logp, "SMB close fid %d", fid);
5404 fid = smb_ChainFID(fid, inp);
5405 fidp = smb_FindFID(vcp, fid, 0);
5407 return CM_ERROR_BADFD;
5410 userp = smb_GetUser(vcp, inp);
5412 lock_ObtainMutex(&fidp->mx);
5414 /* Don't jump the gun on an async raw write */
5415 while (fidp->raw_writers) {
5416 lock_ReleaseMutex(&fidp->mx);
5417 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5418 lock_ObtainMutex(&fidp->mx);
5421 fidp->flags |= SMB_FID_DELETE;
5423 /* watch for ioctl closes, and read-only opens */
5424 if (fidp->scp != NULL &&
5425 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5426 == SMB_FID_OPENWRITE) {
5427 if (dosTime != 0 && dosTime != -1) {
5428 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5429 /* This fixes defect 10958 */
5430 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5431 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5433 code = cm_FSync(fidp->scp, userp, &req);
5438 /* unlock any pending locks */
5439 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5440 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5446 pid = ((smb_t *) inp)->pid;
5447 key = cm_GenerateKey(vcp->vcID, pid, fid);
5450 lock_ObtainMutex(&scp->mx);
5452 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5453 CM_SCACHESYNC_NEEDCALLBACK
5454 | CM_SCACHESYNC_GETSTATUS
5455 | CM_SCACHESYNC_LOCK);
5458 osi_Log1(smb_logp, "smb CoreClose SyncOp failure code 0x%x", tcode);
5459 goto post_syncopdone;
5462 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5464 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5468 lock_ReleaseMutex(&scp->mx);
5469 cm_ReleaseSCache(scp);
5472 if (fidp->flags & SMB_FID_DELONCLOSE) {
5473 cm_scache_t *dscp = fidp->NTopen_dscp;
5474 char *pathp = fidp->NTopen_pathp;
5477 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5478 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5479 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5480 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5481 smb_NotifyChange(FILE_ACTION_REMOVED,
5482 FILE_NOTIFY_CHANGE_DIR_NAME,
5483 dscp, fullPathp, NULL, TRUE);
5487 code = cm_Unlink(dscp, fullPathp, userp, &req);
5488 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5489 smb_NotifyChange(FILE_ACTION_REMOVED,
5490 FILE_NOTIFY_CHANGE_FILE_NAME,
5491 dscp, fullPathp, NULL, TRUE);
5495 lock_ReleaseMutex(&fidp->mx);
5497 if (fidp->flags & SMB_FID_NTOPEN) {
5498 cm_ReleaseSCache(fidp->NTopen_dscp);
5499 free(fidp->NTopen_pathp);
5501 if (fidp->NTopen_wholepathp)
5502 free(fidp->NTopen_wholepathp);
5504 smb_ReleaseFID(fidp);
5505 cm_ReleaseUser(userp);
5510 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5513 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5514 cm_user_t *userp, long *readp)
5516 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5517 cm_user_t *userp, long *readp, int dosflag)
5524 osi_hyper_t fileLength;
5526 osi_hyper_t lastByte;
5527 osi_hyper_t bufferOffset;
5528 long bufIndex, nbytes;
5538 lock_ObtainMutex(&fidp->mx);
5540 lock_ObtainMutex(&scp->mx);
5542 if (offset.HighPart == 0) {
5543 chunk = offset.LowPart >> cm_logChunkSize;
5544 if (chunk != fidp->curr_chunk) {
5545 fidp->prev_chunk = fidp->curr_chunk;
5546 fidp->curr_chunk = chunk;
5548 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5552 /* start by looking up the file's end */
5553 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5554 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5555 if (code) goto done;
5557 /* now we have the entry locked, look up the length */
5558 fileLength = scp->length;
5560 /* adjust count down so that it won't go past EOF */
5561 thyper.LowPart = count;
5562 thyper.HighPart = 0;
5563 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5565 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5566 /* we'd read past EOF, so just stop at fileLength bytes.
5567 * Start by computing how many bytes remain in the file.
5569 thyper = LargeIntegerSubtract(fileLength, offset);
5571 /* if we are past EOF, read 0 bytes */
5572 if (LargeIntegerLessThanZero(thyper))
5575 count = thyper.LowPart;
5580 /* now, copy the data one buffer at a time,
5581 * until we've filled the request packet
5584 /* if we've copied all the data requested, we're done */
5585 if (count <= 0) break;
5587 /* otherwise, load up a buffer of data */
5588 thyper.HighPart = offset.HighPart;
5589 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5590 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5593 buf_Release(bufferp);
5596 lock_ReleaseMutex(&scp->mx);
5598 lock_ObtainRead(&scp->bufCreateLock);
5599 code = buf_Get(scp, &thyper, &bufferp);
5600 lock_ReleaseRead(&scp->bufCreateLock);
5602 lock_ObtainMutex(&scp->mx);
5603 if (code) goto done;
5604 bufferOffset = thyper;
5606 /* now get the data in the cache */
5608 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5609 CM_SCACHESYNC_NEEDCALLBACK |
5610 CM_SCACHESYNC_READ);
5611 if (code) goto done;
5613 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5615 /* otherwise, load the buffer and try again */
5616 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5620 buf_Release(bufferp);
5624 } /* if (wrong buffer) ... */
5626 /* now we have the right buffer loaded. Copy out the
5627 * data from here to the user's buffer.
5629 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5631 /* and figure out how many bytes we want from this buffer */
5632 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5633 if (nbytes > count) nbytes = count; /* don't go past EOF */
5635 /* now copy the data */
5638 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5641 memcpy(op, bufferp->datap + bufIndex, nbytes);
5643 /* adjust counters, pointers, etc. */
5646 thyper.LowPart = nbytes;
5647 thyper.HighPart = 0;
5648 offset = LargeIntegerAdd(thyper, offset);
5652 lock_ReleaseMutex(&scp->mx);
5653 lock_ReleaseMutex(&fidp->mx);
5655 buf_Release(bufferp);
5657 if (code == 0 && sequential)
5658 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5664 * smb_WriteData -- common code for Write and Raw Write
5667 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5668 cm_user_t *userp, long *writtenp)
5670 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5671 cm_user_t *userp, long *writtenp, int dosflag)
5678 osi_hyper_t fileLength; /* file's length at start of write */
5679 osi_hyper_t minLength; /* don't read past this */
5680 long nbytes; /* # of bytes to transfer this iteration */
5682 osi_hyper_t thyper; /* hyper tmp variable */
5683 osi_hyper_t bufferOffset;
5684 long bufIndex; /* index in buffer where our data is */
5686 osi_hyper_t writeBackOffset;/* offset of region to write back when
5691 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5692 fidp->fid, offsetp->LowPart, count);
5702 lock_ObtainMutex(&fidp->mx);
5704 lock_ObtainMutex(&scp->mx);
5706 /* start by looking up the file's end */
5707 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5708 CM_SCACHESYNC_NEEDCALLBACK
5709 | CM_SCACHESYNC_SETSTATUS
5710 | CM_SCACHESYNC_GETSTATUS);
5714 /* make sure we have a writable FD */
5715 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5716 code = CM_ERROR_BADFDOP;
5720 /* now we have the entry locked, look up the length */
5721 fileLength = scp->length;
5722 minLength = fileLength;
5723 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5724 minLength = scp->serverLength;
5726 /* adjust file length if we extend past EOF */
5727 thyper.LowPart = count;
5728 thyper.HighPart = 0;
5729 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5730 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5731 /* we'd write past EOF, so extend the file */
5732 scp->mask |= CM_SCACHEMASK_LENGTH;
5733 scp->length = thyper;
5734 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5736 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5738 /* now, if the new position (thyper) and the old (offset) are in
5739 * different storeback windows, remember to store back the previous
5740 * storeback window when we're done with the write.
5742 if ((thyper.LowPart & (-cm_chunkSize)) !=
5743 (offset.LowPart & (-cm_chunkSize))) {
5744 /* they're different */
5746 writeBackOffset.HighPart = offset.HighPart;
5747 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5752 /* now, copy the data one buffer at a time, until we've filled the
5755 /* if we've copied all the data requested, we're done */
5759 /* handle over quota or out of space */
5760 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5761 *writtenp = written;
5762 code = CM_ERROR_QUOTA;
5766 /* otherwise, load up a buffer of data */
5767 thyper.HighPart = offset.HighPart;
5768 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5769 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5772 lock_ReleaseMutex(&bufferp->mx);
5773 buf_Release(bufferp);
5776 lock_ReleaseMutex(&scp->mx);
5778 lock_ObtainRead(&scp->bufCreateLock);
5779 code = buf_Get(scp, &thyper, &bufferp);
5780 lock_ReleaseRead(&scp->bufCreateLock);
5782 lock_ObtainMutex(&bufferp->mx);
5783 lock_ObtainMutex(&scp->mx);
5784 if (code) goto done;
5786 bufferOffset = thyper;
5788 /* now get the data in the cache */
5790 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5791 CM_SCACHESYNC_NEEDCALLBACK
5792 | CM_SCACHESYNC_WRITE
5793 | CM_SCACHESYNC_BUFLOCKED);
5797 /* If we're overwriting the entire buffer, or
5798 * if we're writing at or past EOF, mark the
5799 * buffer as current so we don't call
5800 * cm_GetBuffer. This skips the fetch from the
5801 * server in those cases where we're going to
5802 * obliterate all the data in the buffer anyway,
5803 * or in those cases where there is no useful
5804 * data at the server to start with.
5806 * Use minLength instead of scp->length, since
5807 * the latter has already been updated by this
5810 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5811 || LargeIntegerEqualTo(offset, bufferp->offset)
5812 && (count >= cm_data.buf_blockSize
5813 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5814 ConvertLongToLargeInteger(count)),
5816 if (count < cm_data.buf_blockSize
5817 && bufferp->dataVersion == -1)
5818 memset(bufferp->datap, 0,
5819 cm_data.buf_blockSize);
5820 bufferp->dataVersion = scp->dataVersion;
5823 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5825 /* otherwise, load the buffer and try again */
5826 lock_ReleaseMutex(&bufferp->mx);
5827 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5829 lock_ReleaseMutex(&scp->mx);
5830 lock_ObtainMutex(&bufferp->mx);
5831 lock_ObtainMutex(&scp->mx);
5835 lock_ReleaseMutex(&bufferp->mx);
5836 buf_Release(bufferp);
5840 } /* if (wrong buffer) ... */
5842 /* now we have the right buffer loaded. Copy out the
5843 * data from here to the user's buffer.
5845 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5847 /* and figure out how many bytes we want from this buffer */
5848 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5850 nbytes = count; /* don't go past end of request */
5852 /* now copy the data */
5855 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5858 memcpy(bufferp->datap + bufIndex, op, nbytes);
5859 buf_SetDirty(bufferp);
5861 /* and record the last writer */
5862 if (bufferp->userp != userp) {
5865 cm_ReleaseUser(bufferp->userp);
5866 bufferp->userp = userp;
5869 /* adjust counters, pointers, etc. */
5873 thyper.LowPart = nbytes;
5874 thyper.HighPart = 0;
5875 offset = LargeIntegerAdd(thyper, offset);
5879 lock_ReleaseMutex(&scp->mx);
5880 lock_ReleaseMutex(&fidp->mx);
5882 lock_ReleaseMutex(&bufferp->mx);
5883 buf_Release(bufferp);
5886 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5887 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5888 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5889 fidp->NTopen_dscp, fidp->NTopen_pathp,
5893 if (code == 0 && doWriteBack) {
5895 lock_ObtainMutex(&scp->mx);
5896 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5898 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5899 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5901 lock_ReleaseMutex(&scp->mx);
5902 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5903 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5906 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5907 fidp->fid, code, *writtenp);
5911 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5914 long count, written = 0, total_written = 0;
5920 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5922 int inDataBlockCount;
5924 fd = smb_GetSMBParm(inp, 0);
5925 count = smb_GetSMBParm(inp, 1);
5926 offset.HighPart = 0; /* too bad */
5927 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5929 op = smb_GetSMBData(inp, NULL);
5930 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5932 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5933 fd, offset.LowPart, count);
5935 fd = smb_ChainFID(fd, inp);
5936 fidp = smb_FindFID(vcp, fd, 0);
5938 return CM_ERROR_BADFD;
5941 if (fidp->flags & SMB_FID_IOCTL)
5942 return smb_IoctlWrite(fidp, vcp, inp, outp);
5944 userp = smb_GetUser(vcp, inp);
5946 /* special case: 0 bytes transferred means truncate to this position */
5952 truncAttr.mask = CM_ATTRMASK_LENGTH;
5953 truncAttr.length.LowPart = offset.LowPart;
5954 truncAttr.length.HighPart = 0;
5955 lock_ObtainMutex(&fidp->mx);
5956 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5957 lock_ReleaseMutex(&fidp->mx);
5958 smb_SetSMBParm(outp, 0, /* count */ 0);
5959 smb_SetSMBDataLength(outp, 0);
5960 fidp->flags |= SMB_FID_LENGTHSETDONE;
5966 LARGE_INTEGER LOffset;
5967 LARGE_INTEGER LLength;
5969 pid = ((smb_t *) inp)->pid;
5970 key = cm_GenerateKey(vcp->vcID, pid, fd);
5972 LOffset.HighPart = offset.HighPart;
5973 LOffset.LowPart = offset.LowPart;
5974 LLength.HighPart = 0;
5975 LLength.LowPart = count;
5977 lock_ObtainMutex(&fidp->scp->mx);
5978 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5979 lock_ReleaseMutex(&fidp->scp->mx);
5986 * Work around bug in NT client
5988 * When copying a file, the NT client should first copy the data,
5989 * then copy the last write time. But sometimes the NT client does
5990 * these in the wrong order, so the data copies would inadvertently
5991 * cause the last write time to be overwritten. We try to detect this,
5992 * and don't set client mod time if we think that would go against the
5995 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5996 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5997 fidp->scp->clientModTime = time(NULL);
6001 while ( code == 0 && count > 0 ) {
6003 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6005 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6007 if (code == 0 && written == 0)
6008 code = CM_ERROR_PARTIALWRITE;
6010 offset.LowPart += written;
6012 total_written += written;
6016 /* set the packet data length to 3 bytes for the data block header,
6017 * plus the size of the data.
6019 smb_SetSMBParm(outp, 0, total_written);
6020 smb_SetSMBDataLength(outp, 0);
6023 smb_ReleaseFID(fidp);
6024 cm_ReleaseUser(userp);
6029 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6030 NCB *ncbp, raw_write_cont_t *rwcp)
6043 fd = smb_GetSMBParm(inp, 0);
6044 fidp = smb_FindFID(vcp, fd, 0);
6046 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6047 rwcp->offset.LowPart, rwcp->count);
6049 userp = smb_GetUser(vcp, inp);
6053 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6056 rawBuf = (dos_ptr) rwcp->buf;
6057 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6058 (unsigned char *) rawBuf, userp,
6062 if (rwcp->writeMode & 0x1) { /* synchronous */
6065 smb_FormatResponsePacket(vcp, inp, outp);
6066 op = (smb_t *) outp;
6067 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6068 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6069 smb_SetSMBDataLength(outp, 0);
6070 smb_SendPacket(vcp, outp);
6071 smb_FreePacket(outp);
6073 else { /* asynchronous */
6074 lock_ObtainMutex(&fidp->mx);
6075 fidp->raw_writers--;
6076 if (fidp->raw_writers == 0)
6077 thrd_SetEvent(fidp->raw_write_event);
6078 lock_ReleaseMutex(&fidp->mx);
6081 /* Give back raw buffer */
6082 lock_ObtainMutex(&smb_RawBufLock);
6084 *((char **)rawBuf) = smb_RawBufs;
6086 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6088 smb_RawBufs = rawBuf;
6089 lock_ReleaseMutex(&smb_RawBufLock);
6091 smb_ReleaseFID(fidp);
6092 cm_ReleaseUser(userp);
6095 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6100 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6103 long count, written = 0, total_written = 0;
6110 unsigned short writeMode;
6117 fd = smb_GetSMBParm(inp, 0);
6118 totalCount = smb_GetSMBParm(inp, 1);
6119 count = smb_GetSMBParm(inp, 10);
6120 offset.HighPart = 0; /* too bad */
6121 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6122 writeMode = smb_GetSMBParm(inp, 7);
6124 op = (char *) inp->data;
6125 op += smb_GetSMBParm(inp, 11);
6128 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6129 fd, offset.LowPart, count, writeMode);
6131 fd = smb_ChainFID(fd, inp);
6132 fidp = smb_FindFID(vcp, fd, 0);
6134 return CM_ERROR_BADFD;
6140 LARGE_INTEGER LOffset;
6141 LARGE_INTEGER LLength;
6143 pid = ((smb_t *) inp)->pid;
6144 key = cm_GenerateKey(vcp->vcID, pid, fd);
6146 LOffset.HighPart = offset.HighPart;
6147 LOffset.LowPart = offset.LowPart;
6148 LLength.HighPart = 0;
6149 LLength.LowPart = count;
6151 lock_ObtainMutex(&fidp->scp->mx);
6152 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6153 lock_ReleaseMutex(&fidp->scp->mx);
6156 smb_ReleaseFID(fidp);
6161 userp = smb_GetUser(vcp, inp);
6164 * Work around bug in NT client
6166 * When copying a file, the NT client should first copy the data,
6167 * then copy the last write time. But sometimes the NT client does
6168 * these in the wrong order, so the data copies would inadvertently
6169 * cause the last write time to be overwritten. We try to detect this,
6170 * and don't set client mod time if we think that would go against the
6173 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6174 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6175 fidp->scp->clientModTime = time(NULL);
6179 while ( code == 0 && count > 0 ) {
6181 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6183 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6185 if (code == 0 && written == 0)
6186 code = CM_ERROR_PARTIALWRITE;
6188 offset.LowPart += written;
6190 total_written += written;
6194 /* Get a raw buffer */
6197 lock_ObtainMutex(&smb_RawBufLock);
6199 /* Get a raw buf, from head of list */
6200 rawBuf = smb_RawBufs;
6202 smb_RawBufs = *(char **)smb_RawBufs;
6204 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6208 code = CM_ERROR_USESTD;
6210 lock_ReleaseMutex(&smb_RawBufLock);
6213 /* Don't allow a premature Close */
6214 if (code == 0 && (writeMode & 1) == 0) {
6215 lock_ObtainMutex(&fidp->mx);
6216 fidp->raw_writers++;
6217 thrd_ResetEvent(fidp->raw_write_event);
6218 lock_ReleaseMutex(&fidp->mx);
6221 smb_ReleaseFID(fidp);
6222 cm_ReleaseUser(userp);
6225 smb_SetSMBParm(outp, 0, total_written);
6226 smb_SetSMBDataLength(outp, 0);
6227 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6234 rwcp->offset.HighPart = 0;
6235 rwcp->offset.LowPart = offset.LowPart + count;
6236 rwcp->count = totalCount - count;
6237 rwcp->writeMode = writeMode;
6238 rwcp->alreadyWritten = total_written;
6240 /* set the packet data length to 3 bytes for the data block header,
6241 * plus the size of the data.
6243 smb_SetSMBParm(outp, 0, 0xffff);
6244 smb_SetSMBDataLength(outp, 0);
6249 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6252 long count, finalCount;
6260 fd = smb_GetSMBParm(inp, 0);
6261 count = smb_GetSMBParm(inp, 1);
6262 offset.HighPart = 0; /* too bad */
6263 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6265 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6266 fd, offset.LowPart, count);
6268 fd = smb_ChainFID(fd, inp);
6269 fidp = smb_FindFID(vcp, fd, 0);
6271 return CM_ERROR_BADFD;
6274 if (fidp->flags & SMB_FID_IOCTL) {
6275 return smb_IoctlRead(fidp, vcp, inp, outp);
6279 LARGE_INTEGER LOffset, LLength;
6282 pid = ((smb_t *) inp)->pid;
6283 key = cm_GenerateKey(vcp->vcID, pid, fd);
6285 LOffset.HighPart = 0;
6286 LOffset.LowPart = offset.LowPart;
6287 LLength.HighPart = 0;
6288 LLength.LowPart = count;
6290 lock_ObtainMutex(&fidp->scp->mx);
6291 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6292 lock_ReleaseMutex(&fidp->scp->mx);
6295 smb_ReleaseFID(fidp);
6299 userp = smb_GetUser(vcp, inp);
6301 /* remember this for final results */
6302 smb_SetSMBParm(outp, 0, count);
6303 smb_SetSMBParm(outp, 1, 0);
6304 smb_SetSMBParm(outp, 2, 0);
6305 smb_SetSMBParm(outp, 3, 0);
6306 smb_SetSMBParm(outp, 4, 0);
6308 /* set the packet data length to 3 bytes for the data block header,
6309 * plus the size of the data.
6311 smb_SetSMBDataLength(outp, count+3);
6313 /* get op ptr after putting in the parms, since otherwise we don't
6314 * know where the data really is.
6316 op = smb_GetSMBData(outp, NULL);
6318 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6319 *op++ = 1; /* data block marker */
6320 *op++ = (unsigned char) (count & 0xff);
6321 *op++ = (unsigned char) ((count >> 8) & 0xff);
6324 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6326 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6329 /* fix some things up */
6330 smb_SetSMBParm(outp, 0, finalCount);
6331 smb_SetSMBDataLength(outp, finalCount+3);
6333 smb_ReleaseFID(fidp);
6335 cm_ReleaseUser(userp);
6339 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6346 cm_scache_t *dscp; /* dir we're dealing with */
6347 cm_scache_t *scp; /* file we're creating */
6349 int initialModeBits;
6359 /* compute initial mode bits based on read-only flag in attributes */
6360 initialModeBits = 0777;
6362 tp = smb_GetSMBData(inp, NULL);
6363 pathp = smb_ParseASCIIBlock(tp, &tp);
6364 if (smb_StoreAnsiFilenames)
6365 OemToChar(pathp,pathp);
6367 if (strcmp(pathp, "\\") == 0)
6368 return CM_ERROR_EXISTS;
6370 spacep = inp->spacep;
6371 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6373 userp = smb_GetUser(vcp, inp);
6375 caseFold = CM_FLAG_CASEFOLD;
6377 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6379 cm_ReleaseUser(userp);
6380 return CM_ERROR_NOSUCHPATH;
6383 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6384 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6385 userp, tidPathp, &req, &dscp);
6388 cm_ReleaseUser(userp);
6393 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6394 cm_ReleaseSCache(dscp);
6395 cm_ReleaseUser(userp);
6396 if ( WANTS_DFS_PATHNAMES(inp) )
6397 return CM_ERROR_PATH_NOT_COVERED;
6399 return CM_ERROR_BADSHARENAME;
6401 #endif /* DFS_SUPPORT */
6403 /* otherwise, scp points to the parent directory. Do a lookup, and
6404 * fail if we find it. Otherwise, we do the create.
6410 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6411 if (scp) cm_ReleaseSCache(scp);
6412 if (code != CM_ERROR_NOSUCHFILE) {
6413 if (code == 0) code = CM_ERROR_EXISTS;
6414 cm_ReleaseSCache(dscp);
6415 cm_ReleaseUser(userp);
6419 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6420 setAttr.clientModTime = time(NULL);
6421 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6422 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6423 smb_NotifyChange(FILE_ACTION_ADDED,
6424 FILE_NOTIFY_CHANGE_DIR_NAME,
6425 dscp, lastNamep, NULL, TRUE);
6427 /* we don't need this any longer */
6428 cm_ReleaseSCache(dscp);
6431 /* something went wrong creating or truncating the file */
6432 cm_ReleaseUser(userp);
6436 /* otherwise we succeeded */
6437 smb_SetSMBDataLength(outp, 0);
6438 cm_ReleaseUser(userp);
6443 BOOL smb_IsLegalFilename(char *filename)
6446 * Find the longest substring of filename that does not contain
6447 * any of the chars in illegalChars. If that substring is less
6448 * than the length of the whole string, then one or more of the
6449 * illegal chars is in filename.
6451 if (strcspn(filename, illegalChars) < strlen(filename))
6457 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6465 cm_scache_t *dscp; /* dir we're dealing with */
6466 cm_scache_t *scp; /* file we're creating */
6468 int initialModeBits;
6480 excl = (inp->inCom == 0x03)? 0 : 1;
6482 attributes = smb_GetSMBParm(inp, 0);
6483 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6485 /* compute initial mode bits based on read-only flag in attributes */
6486 initialModeBits = 0666;
6487 if (attributes & 1) initialModeBits &= ~0222;
6489 tp = smb_GetSMBData(inp, NULL);
6490 pathp = smb_ParseASCIIBlock(tp, &tp);
6491 if (smb_StoreAnsiFilenames)
6492 OemToChar(pathp,pathp);
6494 spacep = inp->spacep;
6495 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6497 userp = smb_GetUser(vcp, inp);
6499 caseFold = CM_FLAG_CASEFOLD;
6501 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6503 cm_ReleaseUser(userp);
6504 return CM_ERROR_NOSUCHPATH;
6506 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6507 userp, tidPathp, &req, &dscp);
6510 cm_ReleaseUser(userp);
6515 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6516 cm_ReleaseSCache(dscp);
6517 cm_ReleaseUser(userp);
6518 if ( WANTS_DFS_PATHNAMES(inp) )
6519 return CM_ERROR_PATH_NOT_COVERED;
6521 return CM_ERROR_BADSHARENAME;
6523 #endif /* DFS_SUPPORT */
6525 /* otherwise, scp points to the parent directory. Do a lookup, and
6526 * truncate the file if we find it, otherwise we create the file.
6533 if (!smb_IsLegalFilename(lastNamep))
6534 return CM_ERROR_BADNTFILENAME;
6536 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6537 #ifdef DEBUG_VERBOSE
6540 hexp = osi_HexifyString( lastNamep );
6541 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6546 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6547 if (code && code != CM_ERROR_NOSUCHFILE) {
6548 cm_ReleaseSCache(dscp);
6549 cm_ReleaseUser(userp);
6553 /* if we get here, if code is 0, the file exists and is represented by
6554 * scp. Otherwise, we have to create it.
6558 /* oops, file shouldn't be there */
6559 cm_ReleaseSCache(dscp);
6560 cm_ReleaseSCache(scp);
6561 cm_ReleaseUser(userp);
6562 return CM_ERROR_EXISTS;
6565 setAttr.mask = CM_ATTRMASK_LENGTH;
6566 setAttr.length.LowPart = 0;
6567 setAttr.length.HighPart = 0;
6568 code = cm_SetAttr(scp, &setAttr, userp, &req);
6571 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6572 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6573 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6575 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6576 smb_NotifyChange(FILE_ACTION_ADDED,
6577 FILE_NOTIFY_CHANGE_FILE_NAME,
6578 dscp, lastNamep, NULL, TRUE);
6579 if (!excl && code == CM_ERROR_EXISTS) {
6580 /* not an exclusive create, and someone else tried
6581 * creating it already, then we open it anyway. We
6582 * don't bother retrying after this, since if this next
6583 * fails, that means that the file was deleted after
6584 * we started this call.
6586 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6589 setAttr.mask = CM_ATTRMASK_LENGTH;
6590 setAttr.length.LowPart = 0;
6591 setAttr.length.HighPart = 0;
6592 code = cm_SetAttr(scp, &setAttr, userp, &req);
6597 /* we don't need this any longer */
6598 cm_ReleaseSCache(dscp);
6601 /* something went wrong creating or truncating the file */
6602 if (scp) cm_ReleaseSCache(scp);
6603 cm_ReleaseUser(userp);
6607 /* make sure we only open files */
6608 if (scp->fileType != CM_SCACHETYPE_FILE) {
6609 cm_ReleaseSCache(scp);
6610 cm_ReleaseUser(userp);
6611 return CM_ERROR_ISDIR;
6614 /* now all we have to do is open the file itself */
6615 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6618 /* save a pointer to the vnode */
6621 /* always create it open for read/write */
6622 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6624 smb_ReleaseFID(fidp);
6626 smb_SetSMBParm(outp, 0, fidp->fid);
6627 smb_SetSMBDataLength(outp, 0);
6629 cm_Open(scp, 0, userp);
6631 cm_ReleaseUser(userp);
6632 /* leave scp held since we put it in fidp->scp */
6636 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6649 fd = smb_GetSMBParm(inp, 0);
6650 whence = smb_GetSMBParm(inp, 1);
6651 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6653 /* try to find the file descriptor */
6654 fd = smb_ChainFID(fd, inp);
6655 fidp = smb_FindFID(vcp, fd, 0);
6656 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6657 return CM_ERROR_BADFD;
6660 userp = smb_GetUser(vcp, inp);
6662 lock_ObtainMutex(&fidp->mx);
6664 lock_ObtainMutex(&scp->mx);
6665 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6666 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6669 /* offset from current offset */
6670 offset += fidp->offset;
6672 else if (whence == 2) {
6673 /* offset from current EOF */
6674 offset += scp->length.LowPart;
6676 fidp->offset = offset;
6677 smb_SetSMBParm(outp, 0, offset & 0xffff);
6678 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6679 smb_SetSMBDataLength(outp, 0);
6681 lock_ReleaseMutex(&scp->mx);
6682 lock_ReleaseMutex(&fidp->mx);
6683 smb_ReleaseFID(fidp);
6684 cm_ReleaseUser(userp);
6688 /* dispatch all of the requests received in a packet. Due to chaining, this may
6689 * be more than one request.
6691 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6692 NCB *ncbp, raw_write_cont_t *rwcp)
6696 unsigned long code = 0;
6697 unsigned char *outWctp;
6698 int nparms; /* # of bytes of parameters */
6700 int nbytes; /* bytes of data, excluding count */
6703 unsigned short errCode;
6704 unsigned long NTStatus;
6706 unsigned char errClass;
6707 unsigned int oldGen;
6708 DWORD oldTime, newTime;
6710 /* get easy pointer to the data */
6711 smbp = (smb_t *) inp->data;
6713 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6714 /* setup the basic parms for the initial request in the packet */
6715 inp->inCom = smbp->com;
6716 inp->wctp = &smbp->wct;
6718 inp->ncb_length = ncbp->ncb_length;
6723 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6724 /* log it and discard it */
6729 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6730 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6732 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6733 1, ncbp->ncb_length, ptbuf, inp);
6734 DeregisterEventSource(h);
6736 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6741 /* We are an ongoing op */
6742 thrd_Increment(&ongoingOps);
6744 /* set up response packet for receiving output */
6745 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6746 smb_FormatResponsePacket(vcp, inp, outp);
6747 outWctp = outp->wctp;
6749 /* Remember session generation number and time */
6750 oldGen = sessionGen;
6751 oldTime = GetCurrentTime();
6753 while (inp->inCom != 0xff) {
6754 dp = &smb_dispatchTable[inp->inCom];
6756 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6757 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6758 code = outp->resumeCode;
6762 /* process each request in the packet; inCom, wctp and inCount
6763 * are already set up.
6765 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6768 /* now do the dispatch */
6769 /* start by formatting the response record a little, as a default */
6770 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6772 outWctp[1] = 0xff; /* no operation */
6773 outWctp[2] = 0; /* padding */
6778 /* not a chained request, this is a more reasonable default */
6779 outWctp[0] = 0; /* wct of zero */
6780 outWctp[1] = 0; /* and bcc (word) of zero */
6784 /* once set, stays set. Doesn't matter, since we never chain
6785 * "no response" calls.
6787 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6791 /* we have a recognized operation */
6793 if (inp->inCom == 0x1d)
6795 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6798 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%x lana %d lsn %d",(int)vcp,vcp->lana,vcp->lsn);
6799 osi_Log4(smb_logp,"Dispatch %s vcp 0x%x lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6800 code = (*(dp->procp)) (vcp, inp, outp);
6801 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",code);
6802 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%x lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
6804 if ( code == CM_ERROR_BADSMB ||
6805 code == CM_ERROR_BADOP )
6807 #endif /* LOG_PACKET */
6810 if (oldGen != sessionGen) {
6815 newTime = GetCurrentTime();
6816 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6817 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6818 newTime - oldTime, ncbp->ncb_length);
6820 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6821 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6822 DeregisterEventSource(h);
6824 osi_Log1(smb_logp, "Pkt straddled session startup, "
6825 "ncb length %d", ncbp->ncb_length);
6829 /* bad opcode, fail the request, after displaying it */
6830 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6833 #endif /* LOG_PACKET */
6837 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6838 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6839 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6840 if (code == IDCANCEL)
6844 code = CM_ERROR_BADOP;
6847 /* catastrophic failure: log as much as possible */
6848 if (code == CM_ERROR_BADSMB) {
6855 "Invalid SMB, ncb_length %d",
6858 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6859 sprintf(s, "Invalid SMB message, length %d",
6862 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6863 1, ncbp->ncb_length, ptbuf, smbp);
6864 DeregisterEventSource(h);
6867 #endif /* LOG_PACKET */
6869 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6872 code = CM_ERROR_INVAL;
6875 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6876 thrd_Decrement(&ongoingOps);
6881 /* now, if we failed, turn the current response into an empty
6882 * one, and fill in the response packet's error code.
6885 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6886 smb_MapNTError(code, &NTStatus);
6887 outWctp = outp->wctp;
6888 smbp = (smb_t *) &outp->data;
6889 if (code != CM_ERROR_PARTIALWRITE
6890 && code != CM_ERROR_BUFFERTOOSMALL
6891 && code != CM_ERROR_GSSCONTINUE) {
6892 /* nuke wct and bcc. For a partial
6893 * write or an in-process authentication handshake,
6894 * assume they're OK.
6900 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6901 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6902 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6903 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6904 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6908 smb_MapCoreError(code, vcp, &errCode, &errClass);
6909 outWctp = outp->wctp;
6910 smbp = (smb_t *) &outp->data;
6911 if (code != CM_ERROR_PARTIALWRITE) {
6912 /* nuke wct and bcc. For a partial
6913 * write, assume they're OK.
6919 smbp->errLow = (unsigned char) (errCode & 0xff);
6920 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6921 smbp->rcls = errClass;
6924 } /* error occurred */
6926 /* if we're here, we've finished one request. Look to see if
6927 * this is a chained opcode. If it is, setup things to process
6928 * the chained request, and setup the output buffer to hold the
6929 * chained response. Start by finding the next input record.
6931 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6932 break; /* not a chained req */
6933 tp = inp->wctp; /* points to start of last request */
6934 /* in a chained request, the first two
6935 * parm fields are required, and are
6936 * AndXCommand/AndXReserved and
6938 if (tp[0] < 2) break;
6939 if (tp[1] == 0xff) break; /* no more chained opcodes */
6941 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6944 /* and now append the next output request to the end of this
6945 * last request. Begin by finding out where the last response
6946 * ends, since that's where we'll put our new response.
6948 outWctp = outp->wctp; /* ptr to out parameters */
6949 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6950 nparms = outWctp[0] << 1;
6951 tp = outWctp + nparms + 1; /* now points to bcc field */
6952 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6953 tp += 2 /* for the count itself */ + nbytes;
6954 /* tp now points to the new output record; go back and patch the
6955 * second parameter (off2) to point to the new record.
6957 temp = (unsigned int)tp - ((unsigned int) outp->data);
6958 outWctp[3] = (unsigned char) (temp & 0xff);
6959 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6960 outWctp[2] = 0; /* padding */
6961 outWctp[1] = inp->inCom; /* next opcode */
6963 /* finally, setup for the next iteration */
6966 } /* while loop over all requests in the packet */
6968 /* done logging out, turn off logging-out flag */
6969 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6970 vcp->justLoggedOut = NULL;
6973 free(loggedOutName);
6974 loggedOutName = NULL;
6975 smb_ReleaseUID(loggedOutUserp);
6976 loggedOutUserp = NULL;
6980 /* now send the output packet, and return */
6982 smb_SendPacket(vcp, outp);
6983 thrd_Decrement(&ongoingOps);
6985 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6986 if (active_vcp != vcp) {
6988 smb_ReleaseVC(active_vcp);
6990 "Replacing active_vcp %x with %x", active_vcp, vcp);
6995 last_msg_time = GetCurrentTime();
6996 } else if (active_vcp == vcp) {
6997 smb_ReleaseVC(active_vcp);
7005 /* Wait for Netbios() calls to return, and make the results available to server
7006 * threads. Note that server threads can't wait on the NCBevents array
7007 * themselves, because NCB events are manual-reset, and the servers would race
7008 * each other to reset them.
7010 void smb_ClientWaiter(void *parmp)
7015 while (smbShutdownFlag == 0) {
7016 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7018 if (code == WAIT_OBJECT_0)
7021 /* error checking */
7022 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7024 int abandonIdx = code - WAIT_ABANDONED_0;
7025 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7028 if (code == WAIT_IO_COMPLETION)
7030 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7034 if (code == WAIT_TIMEOUT)
7036 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7039 if (code == WAIT_FAILED)
7041 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7044 idx = code - WAIT_OBJECT_0;
7046 /* check idx range! */
7047 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7049 /* this is fatal - log as much as possible */
7050 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7054 thrd_ResetEvent(NCBevents[idx]);
7055 thrd_SetEvent(NCBreturns[0][idx]);
7061 * Try to have one NCBRECV request waiting for every live session. Not more
7062 * than one, because if there is more than one, it's hard to handle Write Raw.
7064 void smb_ServerWaiter(void *parmp)
7067 int idx_session, idx_NCB;
7073 while (smbShutdownFlag == 0) {
7075 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7077 if (code == WAIT_OBJECT_0)
7080 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7082 int abandonIdx = code - WAIT_ABANDONED_0;
7083 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7086 if (code == WAIT_IO_COMPLETION)
7088 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7092 if (code == WAIT_TIMEOUT)
7094 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7097 if (code == WAIT_FAILED)
7099 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7102 idx_session = code - WAIT_OBJECT_0;
7104 /* check idx range! */
7105 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7107 /* this is fatal - log as much as possible */
7108 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7114 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7116 if (code == WAIT_OBJECT_0) {
7117 if (smbShutdownFlag == 1)
7123 /* error checking */
7124 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7126 int abandonIdx = code - WAIT_ABANDONED_0;
7127 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7130 if (code == WAIT_IO_COMPLETION)
7132 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7136 if (code == WAIT_TIMEOUT)
7138 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7141 if (code == WAIT_FAILED)
7143 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7146 idx_NCB = code - WAIT_OBJECT_0;
7148 /* check idx range! */
7149 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7151 /* this is fatal - log as much as possible */
7152 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7156 /* Link them together */
7157 NCBsessions[idx_NCB] = idx_session;
7160 ncbp = NCBs[idx_NCB];
7161 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7162 ncbp->ncb_command = NCBRECV | ASYNCH;
7163 ncbp->ncb_lana_num = lanas[idx_session];
7165 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7166 ncbp->ncb_event = NCBevents[idx_NCB];
7167 ncbp->ncb_length = SMB_PACKETSIZE;
7170 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7171 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7172 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7173 ncbp->ncb_length = SMB_PACKETSIZE;
7174 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7175 Netbios(ncbp, dos_ncb);
7181 * The top level loop for handling SMB request messages. Each server thread
7182 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7183 * NCB and buffer for the incoming request are loaned to us.
7185 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7186 * to immediately send a request for the rest of the data. This must come
7187 * before any other traffic for that session, so we delay setting the session
7188 * event until that data has come in.
7190 void smb_Server(VOID *parmp)
7192 int myIdx = (int) parmp;
7196 smb_packet_t *outbufp;
7198 int idx_NCB, idx_session;
7200 smb_vc_t *vcp = NULL;
7206 rx_StartClientThread();
7209 outbufp = GetPacket();
7210 outbufp->ncbp = outncbp;
7213 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7216 /* terminate silently if shutdown flag is set */
7217 if (code == WAIT_OBJECT_0) {
7218 if (smbShutdownFlag == 1) {
7219 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7225 /* error checking */
7226 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7228 int abandonIdx = code - WAIT_ABANDONED_0;
7229 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7232 if (code == WAIT_IO_COMPLETION)
7234 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7238 if (code == WAIT_TIMEOUT)
7240 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7243 if (code == WAIT_FAILED)
7245 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7248 idx_NCB = code - WAIT_OBJECT_0;
7250 /* check idx range! */
7251 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7253 /* this is fatal - log as much as possible */
7254 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7258 ncbp = NCBs[idx_NCB];
7260 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7262 idx_session = NCBsessions[idx_NCB];
7263 rc = ncbp->ncb_retcode;
7265 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7268 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7271 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7274 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7277 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7280 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7283 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7286 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7289 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7292 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7295 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7298 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7301 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7304 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7307 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7310 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7313 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7316 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7319 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7322 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7325 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7328 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7331 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7334 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7337 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7340 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7343 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7346 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7349 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7352 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7355 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7358 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7361 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7364 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7367 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7370 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7373 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7376 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7379 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7389 /* Can this happen? Or is it just my UNIX paranoia? */
7390 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7395 /* Client closed session */
7396 dead_sessions[idx_session] = TRUE;
7399 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7400 /* Should also release vcp. [done] 2004-05-11 jaltman
7402 * sanity check that all TID's are gone.
7404 * TODO: check if we could use LSNs[idx_session] instead,
7405 * also cleanup after dead vcp
7408 if (dead_vcp == vcp)
7409 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7410 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7411 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7415 smb_ReleaseVC(dead_vcp);
7417 "Previous dead_vcp %x", dead_vcp);
7420 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7422 if (vcp->justLoggedOut) {
7424 loggedOutTime = vcp->logoffTime;
7425 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7426 loggedOutUserp = vcp->justLoggedOut;
7427 lock_ObtainWrite(&smb_rctLock);
7428 loggedOutUserp->refCount++;
7429 lock_ReleaseWrite(&smb_rctLock);
7435 /* Treat as transient error */
7442 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7443 sprintf(s, "SMB message incomplete, length %d",
7446 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7448 ncbp->ncb_length, ptbuf,
7450 DeregisterEventSource(h);
7453 "dispatch smb recv failed, message incomplete, ncb_length %d",
7456 "SMB message incomplete, "
7457 "length %d", ncbp->ncb_length);
7460 * We used to discard the packet.
7461 * Instead, try handling it normally.
7469 /* A weird error code. Log it, sleep, and
7471 if (vcp && vcp->errorCount++ > 3) {
7472 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7473 dead_sessions[idx_session] = TRUE;
7477 thrd_SetEvent(SessionEvents[idx_session]);
7482 /* Success, so now dispatch on all the data in the packet */
7484 smb_concurrentCalls++;
7485 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7486 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7490 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7492 * If at this point vcp is NULL (implies that packet was invalid)
7493 * then we are in big trouble. This means either :
7494 * a) we have the wrong NCB.
7495 * b) Netbios screwed up the call.
7496 * Obviously this implies that
7497 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7498 * lanas[idx_session] != ncbp->ncb_lana_num )
7499 * Either way, we can't do anything with this packet.
7500 * Log, sleep and resume.
7509 "LSNs[idx_session]=[%d],"
7510 "lanas[idx_session]=[%d],"
7511 "ncbp->ncb_lsn=[%d],"
7512 "ncbp->ncb_lana_num=[%d]",
7516 ncbp->ncb_lana_num);
7520 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7522 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7523 DeregisterEventSource(h);
7526 /* Also log in the trace log. */
7527 osi_Log4(smb_logp, "Server: BAD VCP!"
7528 "LSNs[idx_session]=[%d],"
7529 "lanas[idx_session]=[%d],"
7530 "ncbp->ncb_lsn=[%d],"
7531 "ncbp->ncb_lana_num=[%d]",
7535 ncbp->ncb_lana_num);
7537 /* thrd_Sleep(1000); Don't bother sleeping */
7538 thrd_SetEvent(SessionEvents[idx_session]);
7539 smb_concurrentCalls--;
7544 vcp->errorCount = 0;
7545 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7547 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7548 /* copy whole packet to virtual memory */
7549 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7551 bufp->dos_pkt / 16, bufp);*/
7553 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7555 smbp = (smb_t *)bufp->data;
7558 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7562 if (smbp->com == 0x1d) {
7563 /* Special handling for Write Raw */
7564 raw_write_cont_t rwc;
7565 EVENT_HANDLE rwevent;
7566 char eventName[MAX_PATH];
7568 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7569 if (rwc.code == 0) {
7570 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7571 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7572 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7573 ncbp->ncb_command = NCBRECV | ASYNCH;
7574 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7575 ncbp->ncb_lana_num = vcp->lana;
7576 ncbp->ncb_buffer = rwc.buf;
7577 ncbp->ncb_length = 65535;
7578 ncbp->ncb_event = rwevent;
7582 Netbios(ncbp, dos_ncb);
7584 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7585 thrd_CloseHandle(rwevent);
7587 thrd_SetEvent(SessionEvents[idx_session]);
7589 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7591 else if (smbp->com == 0xa0) {
7593 * Serialize the handling for NT Transact
7596 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7597 thrd_SetEvent(SessionEvents[idx_session]);
7599 thrd_SetEvent(SessionEvents[idx_session]);
7600 /* TODO: what else needs to be serialized? */
7601 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7603 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7605 __except( smb_ServerExceptionFilter() ) {
7609 smb_concurrentCalls--;
7612 thrd_SetEvent(NCBavails[idx_NCB]);
7619 * Exception filter for the server threads. If an exception occurs in the
7620 * dispatch routines, which is where exceptions are most common, then do a
7621 * force trace and give control to upstream exception handlers. Useful for
7624 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7625 DWORD smb_ServerExceptionFilter(void) {
7626 /* While this is not the best time to do a trace, if it succeeds, then
7627 * we have a trace (assuming tracing was enabled). Otherwise, this should
7628 * throw a second exception.
7633 ptbuf[0] = "Unhandled exception forcing trace";
7635 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7637 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7638 DeregisterEventSource(h);
7641 afsd_ForceTrace(TRUE);
7642 buf_ForceTrace(TRUE);
7643 return EXCEPTION_CONTINUE_SEARCH;
7648 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7649 * If the number of server threads is M, and the number of live sessions is
7650 * N, then the number of NCB's in use at any time either waiting for, or
7651 * holding, received messages is M + N, so that is how many NCB's get created.
7653 void InitNCBslot(int idx)
7655 struct smb_packet *bufp;
7656 EVENT_HANDLE retHandle;
7658 char eventName[MAX_PATH];
7660 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7662 NCBs[idx] = GetNCB();
7663 sprintf(eventName,"NCBavails[%d]", idx);
7664 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7665 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7666 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7668 sprintf(eventName,"NCBevents[%d]", idx);
7669 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7670 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7671 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7673 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7674 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7675 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7676 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7677 for (i=0; i<smb_NumServerThreads; i++)
7678 NCBreturns[i][idx] = retHandle;
7680 bufp->spacep = cm_GetSpace();
7684 /* listen for new connections */
7685 void smb_Listener(void *parmp)
7693 char rname[NCBNAMSZ+1];
7694 char cname[MAX_COMPUTERNAME_LENGTH+1];
7695 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7700 int lana = (int) parmp;
7704 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7707 /* retrieve computer name */
7708 GetComputerName(cname, &cnamelen);
7712 memset(ncbp, 0, sizeof(NCB));
7715 ncbp->ncb_command = NCBLISTEN;
7716 ncbp->ncb_rto = 0; /* No receive timeout */
7717 ncbp->ncb_sto = 0; /* No send timeout */
7719 /* pad out with spaces instead of null termination */
7720 len = strlen(smb_localNamep);
7721 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7722 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7724 strcpy(ncbp->ncb_callname, "*");
7725 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7727 ncbp->ncb_lana_num = lana;
7730 code = Netbios(ncbp);
7732 code = Netbios(ncbp, dos_ncb);
7741 /* terminate silently if shutdown flag is set */
7742 if (smbShutdownFlag == 1) {
7751 "NCBLISTEN lana=%d failed with code %d",
7752 ncbp->ncb_lana_num, code);
7754 "Client exiting due to network failure. Please restart client.\n");
7758 "Client exiting due to network failure. Please restart client.\n"
7759 "NCBLISTEN lana=%d failed with code %d",
7760 ncbp->ncb_lana_num, code);
7762 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7763 MB_OK|MB_SERVICE_NOTIFICATION);
7764 osi_assert(tbuffer);
7767 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7768 ncbp->ncb_lana_num, code);
7769 fprintf(stderr, "\nClient exiting due to network failure "
7770 "(possibly due to power-saving mode)\n");
7771 fprintf(stderr, "Please restart client.\n");
7772 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7776 /* check for remote conns */
7777 /* first get remote name and insert null terminator */
7778 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7779 for (i=NCBNAMSZ; i>0; i--) {
7780 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7786 /* compare with local name */
7788 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7789 flags |= SMB_VCFLAG_REMOTECONN;
7791 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7793 lock_ObtainMutex(&smb_ListenerLock);
7795 /* New generation */
7798 /* Log session startup */
7800 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7802 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7803 #endif /* NOTSERVICE */
7804 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7805 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7807 if (reportSessionStartups) {
7813 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7814 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7816 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7818 DeregisterEventSource(h);
7821 fprintf(stderr, "%s: New session %d starting from host %s\n",
7822 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7826 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7827 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7830 /* now ncbp->ncb_lsn is the connection ID */
7831 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7832 vcp->flags |= flags;
7833 strcpy(vcp->rname, rname);
7835 /* Allocate slot in session arrays */
7836 /* Re-use dead session if possible, otherwise add one more */
7837 /* But don't look at session[0], it is reserved */
7838 for (i = 1; i < numSessions; i++) {
7839 if (dead_sessions[i]) {
7840 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7841 dead_sessions[i] = FALSE;
7846 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7847 unsigned long code = CM_ERROR_ALLBUSY;
7848 smb_packet_t * outp = GetPacket();
7849 unsigned char *outWctp;
7854 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7855 unsigned long NTStatus;
7856 smb_MapNTError(code, &NTStatus);
7857 outWctp = outp->wctp;
7858 smbp = (smb_t *) &outp->data;
7862 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7863 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7864 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7865 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7866 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7868 unsigned short errCode;
7869 unsigned char errClass;
7870 smb_MapCoreError(code, vcp, &errCode, &errClass);
7871 outWctp = outp->wctp;
7872 smbp = (smb_t *) &outp->data;
7876 smbp->errLow = (unsigned char) (errCode & 0xff);
7877 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7878 smbp->rcls = errClass;
7880 smb_SendPacket(vcp, outp);
7881 smb_FreePacket(outp);
7883 /* assert that we do not exceed the maximum number of sessions or NCBs.
7884 * we should probably want to wait for a session to be freed in case
7887 osi_assert(i < Sessionmax - 1);
7888 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7890 LSNs[i] = ncbp->ncb_lsn;
7891 lanas[i] = ncbp->ncb_lana_num;
7893 if (i == numSessions) {
7894 /* Add new NCB for new session */
7895 char eventName[MAX_PATH];
7897 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7899 InitNCBslot(numNCBs);
7901 thrd_SetEvent(NCBavails[0]);
7902 thrd_SetEvent(NCBevents[0]);
7903 for (j = 0; j < smb_NumServerThreads; j++)
7904 thrd_SetEvent(NCBreturns[j][0]);
7905 /* Also add new session event */
7906 sprintf(eventName, "SessionEvents[%d]", i);
7907 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7908 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7909 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7911 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7912 thrd_SetEvent(SessionEvents[0]);
7914 thrd_SetEvent(SessionEvents[i]);
7921 lock_ReleaseMutex(&smb_ListenerLock);
7922 } /* dispatch while loop */
7925 /* initialize Netbios */
7926 void smb_NetbiosInit()
7932 int i, lana, code, l;
7934 int delname_tried=0;
7937 OSVERSIONINFO Version;
7939 /* Get the version of Windows */
7940 memset(&Version, 0x00, sizeof(Version));
7941 Version.dwOSVersionInfoSize = sizeof(Version);
7942 GetVersionEx(&Version);
7944 /* setup the NCB system */
7947 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7951 if (smb_LANadapter == -1) {
7952 ncbp->ncb_command = NCBENUM;
7953 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7954 ncbp->ncb_length = sizeof(lana_list);
7955 code = Netbios(ncbp);
7957 afsi_log("Netbios NCBENUM error code %d", code);
7958 osi_panic(s, __FILE__, __LINE__);
7962 lana_list.length = 1;
7963 lana_list.lana[0] = smb_LANadapter;
7966 for (i = 0; i < lana_list.length; i++) {
7967 /* reset the adaptor: in Win32, this is required for every process, and
7968 * acts as an init call, not as a real hardware reset.
7970 ncbp->ncb_command = NCBRESET;
7971 ncbp->ncb_callname[0] = 100;
7972 ncbp->ncb_callname[2] = 100;
7973 ncbp->ncb_lana_num = lana_list.lana[i];
7974 code = Netbios(ncbp);
7976 code = ncbp->ncb_retcode;
7978 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7979 lana_list.lana[i] = 255; /* invalid lana */
7981 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7985 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7986 we will just fake the LANA list */
7987 if (smb_LANadapter == -1) {
7988 for (i = 0; i < 8; i++)
7989 lana_list.lana[i] = i;
7990 lana_list.length = 8;
7993 lana_list.length = 1;
7994 lana_list.lana[0] = smb_LANadapter;
7998 /* and declare our name so we can receive connections */
7999 memset(ncbp, 0, sizeof(*ncbp));
8000 len=lstrlen(smb_localNamep);
8001 memset(smb_sharename,' ',NCBNAMSZ);
8002 memcpy(smb_sharename,smb_localNamep,len);
8003 afsi_log("lana_list.length %d", lana_list.length);
8005 /* Keep the name so we can unregister it later */
8006 for (l = 0; l < lana_list.length; l++) {
8007 lana = lana_list.lana[l];
8009 ncbp->ncb_command = NCBADDNAME;
8010 ncbp->ncb_lana_num = lana;
8011 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8013 code = Netbios(ncbp);
8015 code = Netbios(ncbp, dos_ncb);
8018 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8019 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8021 char name[NCBNAMSZ+1];
8023 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8024 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8027 if (code == 0) code = ncbp->ncb_retcode;
8029 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8031 /* we only use one LANA with djgpp */
8032 lana_list.lana[0] = lana;
8033 lana_list.length = 1;
8037 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8038 if (code == NRC_BRIDGE) { /* invalid LANA num */
8039 lana_list.lana[l] = 255;
8042 else if (code == NRC_DUPNAME) {
8043 afsi_log("Name already exists; try to delete it");
8044 memset(ncbp, 0, sizeof(*ncbp));
8045 ncbp->ncb_command = NCBDELNAME;
8046 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8047 ncbp->ncb_lana_num = lana;
8049 code = Netbios(ncbp);
8051 code = Netbios(ncbp, dos_ncb);
8054 code = ncbp->ncb_retcode;
8056 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8058 if (code != 0 || delname_tried) {
8059 lana_list.lana[l] = 255;
8061 else if (code == 0) {
8062 if (!delname_tried) {
8070 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8071 lana_list.lana[l] = 255; /* invalid lana */
8072 osi_panic(s, __FILE__, __LINE__);
8076 lana_found = 1; /* at least one worked */
8083 osi_assert(lana_list.length >= 0);
8085 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8088 /* we're done with the NCB now */
8092 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8109 EVENT_HANDLE retHandle;
8110 char eventName[MAX_PATH];
8113 smb_MBfunc = aMBfunc;
8117 smb_LANadapter = LANadapt;
8119 /* Initialize smb_localZero */
8120 myTime.tm_isdst = -1; /* compute whether on DST or not */
8121 myTime.tm_year = 70;
8127 smb_localZero = mktime(&myTime);
8129 #ifndef USE_NUMERIC_TIME_CONV
8130 /* Initialize kludge-GMT */
8131 smb_CalculateNowTZ();
8132 #endif /* USE_NUMERIC_TIME_CONV */
8133 #ifdef AFS_FREELANCE_CLIENT
8134 /* Make sure the root.afs volume has the correct time */
8135 cm_noteLocalMountPointChange();
8138 /* initialize the remote debugging log */
8141 /* remember the name */
8142 len = strlen(snamep);
8143 smb_localNamep = malloc(len+1);
8144 strcpy(smb_localNamep, snamep);
8145 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8147 /* and the global lock */
8148 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8149 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8151 /* Raw I/O data structures */
8152 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8154 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8156 /* 4 Raw I/O buffers */
8158 smb_RawBufs = calloc(65536,1);
8159 *((char **)smb_RawBufs) = NULL;
8160 for (i=0; i<3; i++) {
8161 char *rawBuf = calloc(65536,1);
8162 *((char **)rawBuf) = smb_RawBufs;
8163 smb_RawBufs = rawBuf;
8166 npar = 65536 >> 4; /* number of paragraphs */
8167 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8169 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8171 osi_panic("",__FILE__,__LINE__);
8174 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8177 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8179 _farpokel(_dos_ds, smb_RawBufs, NULL);
8180 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8181 npar = 65536 >> 4; /* number of paragraphs */
8182 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8184 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8186 osi_panic("",__FILE__,__LINE__);
8189 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8192 rawBuf = (seg * 16) + 0; /* DOS physical address */
8193 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8194 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8195 smb_RawBufs = rawBuf;
8199 /* global free lists */
8200 smb_ncbFreeListp = NULL;
8201 smb_packetFreeListp = NULL;
8205 /* Initialize listener and server structures */
8207 memset(dead_sessions, 0, sizeof(dead_sessions));
8208 sprintf(eventName, "SessionEvents[0]");
8209 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8210 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8211 afsi_log("Event Object Already Exists: %s", eventName);
8213 smb_NumServerThreads = nThreads;
8214 sprintf(eventName, "NCBavails[0]");
8215 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8216 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8217 afsi_log("Event Object Already Exists: %s", eventName);
8218 sprintf(eventName, "NCBevents[0]");
8219 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8220 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8221 afsi_log("Event Object Already Exists: %s", eventName);
8222 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8223 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8224 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8225 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8226 afsi_log("Event Object Already Exists: %s", eventName);
8227 for (i = 0; i < smb_NumServerThreads; i++) {
8228 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8229 NCBreturns[i][0] = retHandle;
8232 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8233 for (i = 0; i < smb_NumServerThreads; i++) {
8234 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8235 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8236 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8237 afsi_log("Event Object Already Exists: %s", eventName);
8240 numNCBs = smb_NumServerThreads + 1;
8242 /* Initialize dispatch table */
8243 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8244 /* Prepare the table for unknown operations */
8245 for(i=0; i<= SMB_NOPCODES; i++) {
8246 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8248 /* Fill in the ones we do know */
8249 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8250 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8251 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8252 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8253 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8254 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8255 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8256 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8257 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8258 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8259 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8260 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8261 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8262 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8263 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8264 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8265 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8266 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8267 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8268 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8269 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8270 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8271 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8272 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8273 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8274 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8275 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8276 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8277 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8278 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8279 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8280 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8281 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8282 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8283 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8284 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8285 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8286 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8287 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8288 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8289 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8290 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8291 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8292 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8293 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8294 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8295 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8296 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8297 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8298 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8299 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8300 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8301 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8302 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8303 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8304 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8305 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8306 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8307 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8308 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8309 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8310 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8311 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8312 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8313 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8314 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8315 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8316 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8317 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8318 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8319 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8320 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8322 /* setup tran 2 dispatch table */
8323 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8324 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8325 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8326 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8327 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8328 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8329 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8330 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8331 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8332 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8333 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8334 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8335 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8336 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8337 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8338 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8339 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8341 /* setup the rap dispatch table */
8342 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8343 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8344 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8345 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8346 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8350 /* if we are doing SMB authentication we have register outselves as a logon process */
8351 if (smb_authType != SMB_AUTH_NONE) {
8352 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8353 LSA_STRING afsProcessName;
8354 LSA_OPERATIONAL_MODE dummy; /*junk*/
8356 afsProcessName.Buffer = "OpenAFSClientDaemon";
8357 afsProcessName.Length = strlen(afsProcessName.Buffer);
8358 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8360 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8362 if (nts == STATUS_SUCCESS) {
8363 LSA_STRING packageName;
8364 /* we are registered. Find out the security package id */
8365 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8366 packageName.Length = strlen(packageName.Buffer);
8367 packageName.MaximumLength = packageName.Length + 1;
8368 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8369 if (nts == STATUS_SUCCESS) {
8371 * This code forces Windows to authenticate against the Logon Cache
8372 * first instead of attempting to authenticate against the Domain
8373 * Controller. When the Windows logon cache is enabled this improves
8374 * performance by removing the network access and works around a bug
8375 * seen at sites which are using a MIT Kerberos principal to login
8376 * to machines joined to a non-root domain in a multi-domain forest.
8378 PVOID pResponse = NULL;
8379 ULONG cbResponse = 0;
8380 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8382 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8383 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8384 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8385 OptionsRequest.DisableOptions = FALSE;
8387 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8390 sizeof(OptionsRequest),
8396 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8398 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8400 OutputDebugString(message);
8403 OutputDebugString("MsV1_0SetProcessOption success");
8404 afsi_log("MsV1_0SetProcessOption success");
8406 /* END - code from Larry */
8408 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8409 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8410 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8412 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8414 /* something went wrong. We report the error and revert back to no authentication
8415 because we can't perform any auth requests without a successful lsa handle
8416 or sec package id. */
8417 afsi_log("Reverting to NO SMB AUTH");
8418 smb_authType = SMB_AUTH_NONE;
8421 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8423 /* something went wrong. We report the error and revert back to no authentication
8424 because we can't perform any auth requests without a successful lsa handle
8425 or sec package id. */
8426 afsi_log("Reverting to NO SMB AUTH");
8427 smb_authType = SMB_AUTH_NONE;
8431 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8432 * time prevents the failure of authentication when logged into Windows with an
8433 * external Kerberos principal mapped to a local account.
8435 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8436 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8437 * then the only option is NTLMSSP anyway; so just fallback.
8442 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8443 if (secBlobLength == 0) {
8444 smb_authType = SMB_AUTH_NTLM;
8445 afsi_log("Reverting to SMB AUTH NTLM");
8454 /* Now get ourselves a domain name. */
8455 /* For now we are using the local computer name as the domain name.
8456 * It is actually the domain for local logins, and we are acting as
8457 * a local SMB server.
8459 bufsize = sizeof(smb_ServerDomainName) - 1;
8460 GetComputerName(smb_ServerDomainName, &bufsize);
8461 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8462 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8465 /* Start listeners, waiters, servers, and daemons */
8467 for (i = 0; i < lana_list.length; i++) {
8468 if (lana_list.lana[i] == 255)
8470 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8471 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8472 osi_assert(phandle != NULL);
8473 thrd_CloseHandle(phandle);
8477 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8478 NULL, 0, &lpid, "smb_ClientWaiter");
8479 osi_assert(phandle != NULL);
8480 thrd_CloseHandle(phandle);
8483 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8484 NULL, 0, &lpid, "smb_ServerWaiter");
8485 osi_assert(phandle != NULL);
8486 thrd_CloseHandle(phandle);
8488 for (i=0; i<smb_NumServerThreads; i++) {
8489 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8490 (void *) i, 0, &lpid, "smb_Server");
8491 osi_assert(phandle != NULL);
8492 thrd_CloseHandle(phandle);
8495 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8496 NULL, 0, &lpid, "smb_Daemon");
8497 osi_assert(phandle != NULL);
8498 thrd_CloseHandle(phandle);
8500 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8501 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8502 osi_assert(phandle != NULL);
8503 thrd_CloseHandle(phandle);
8512 void smb_Shutdown(void)
8522 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8524 /* setup the NCB system */
8527 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8530 /* Block new sessions by setting shutdown flag */
8531 smbShutdownFlag = 1;
8533 /* Hang up all sessions */
8534 memset((char *)ncbp, 0, sizeof(NCB));
8535 for (i = 1; i < numSessions; i++)
8537 if (dead_sessions[i])
8540 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8541 ncbp->ncb_command = NCBHANGUP;
8542 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8543 ncbp->ncb_lsn = LSNs[i];
8545 code = Netbios(ncbp);
8547 code = Netbios(ncbp, dos_ncb);
8549 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8550 if (code == 0) code = ncbp->ncb_retcode;
8552 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8553 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8557 /* Trigger the shutdown of all SMB threads */
8558 for (i = 0; i < smb_NumServerThreads; i++)
8559 thrd_SetEvent(NCBreturns[i][0]);
8561 thrd_SetEvent(NCBevents[0]);
8562 thrd_SetEvent(SessionEvents[0]);
8563 thrd_SetEvent(NCBavails[0]);
8565 for (i = 0;i < smb_NumServerThreads; i++) {
8566 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8567 if (code == WAIT_OBJECT_0) {
8570 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8571 thrd_SetEvent(NCBreturns[i--][0]);
8575 /* Delete Netbios name */
8576 memset((char *)ncbp, 0, sizeof(NCB));
8577 for (i = 0; i < lana_list.length; i++) {
8578 if (lana_list.lana[i] == 255) continue;
8579 ncbp->ncb_command = NCBDELNAME;
8580 ncbp->ncb_lana_num = lana_list.lana[i];
8581 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8583 code = Netbios(ncbp);
8585 code = Netbios(ncbp, dos_ncb);
8588 code = ncbp->ncb_retcode;
8590 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8591 ncbp->ncb_lana_num, code);
8596 /* Release the reference counts held by the VCs */
8597 lock_ObtainWrite(&smb_rctLock);
8598 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8603 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8605 if (fidp->scp != NULL) {
8608 lock_ObtainMutex(&fidp->mx);
8609 if (fidp->scp != NULL) {
8612 cm_ReleaseSCache(scp);
8614 lock_ReleaseMutex(&fidp->mx);
8618 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8620 smb_ReleaseVCNoLock(tidp->vcp);
8622 cm_user_t *userp = tidp->userp;
8624 lock_ReleaseWrite(&smb_rctLock);
8625 cm_ReleaseUser(userp);
8626 lock_ObtainWrite(&smb_rctLock);
8630 lock_ReleaseWrite(&smb_rctLock);
8633 /* Get the UNC \\<servername>\<sharename> prefix. */
8634 char *smb_GetSharename()
8638 /* Make sure we have been properly initialized. */
8639 if (smb_localNamep == NULL)
8642 /* Allocate space for \\<servername>\<sharename>, plus the
8645 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8646 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8652 void smb_LogPacket(smb_packet_t *packet)
8655 unsigned length, paramlen, datalen, i, j;
8657 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8659 if (!packet) return;
8661 osi_Log0(smb_logp, "*** SMB packet dump ***");
8663 vp = (BYTE *) packet->data;
8665 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8666 length = paramlen + 2 + datalen;
8669 for (i=0;i < length; i+=16)
8671 memset( buf, ' ', 80 );
8676 buf[strlen(buf)] = ' ';
8678 cp = (BYTE*) buf + 7;
8680 for (j=0;j < 16 && (i+j)<length; j++)
8682 *(cp++) = hex[vp[i+j] >> 4];
8683 *(cp++) = hex[vp[i+j] & 0xf];
8693 for (j=0;j < 16 && (i+j)<length;j++)
8695 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8706 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8709 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8711 #endif /* LOG_PACKET */
8714 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8722 lock_ObtainRead(&smb_rctLock);
8724 sprintf(output, "begin dumping smb_vc_t\n");
8725 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8727 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8731 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8732 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8733 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8735 sprintf(output, "begin dumping smb_fid_t\n");
8736 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8738 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8740 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",
8741 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8742 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8743 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8744 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8747 sprintf(output, "done dumping smb_fid_t\n");
8748 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8751 sprintf(output, "done dumping smb_vc_t\n");
8752 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8755 lock_ReleaseRead(&smb_rctLock);