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 */
2469 NTStatus = 0xC0982001L; /* SMB non-specific error */
2472 *NTStatusp = NTStatus;
2473 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2476 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2477 unsigned char *classp)
2479 unsigned char class;
2480 unsigned short error;
2482 /* map CM_ERROR_* errors to SMB errors */
2483 if (code == CM_ERROR_NOSUCHCELL) {
2485 error = 3; /* bad path */
2487 else if (code == CM_ERROR_NOSUCHVOLUME) {
2489 error = 3; /* bad path */
2491 else if (code == CM_ERROR_TIMEDOUT) {
2493 error = 81; /* server is paused */
2495 else if (code == CM_ERROR_RETRY) {
2496 class = 2; /* shouldn't happen */
2499 else if (code == CM_ERROR_NOACCESS) {
2501 error = 4; /* bad access */
2503 else if (code == CM_ERROR_READONLY) {
2505 error = 19; /* read only */
2507 else if (code == CM_ERROR_NOSUCHFILE) {
2509 error = 2; /* ENOENT! */
2511 else if (code == CM_ERROR_NOSUCHPATH) {
2513 error = 3; /* Bad path */
2515 else if (code == CM_ERROR_TOOBIG) {
2517 error = 11; /* bad format */
2519 else if (code == CM_ERROR_INVAL) {
2520 class = 2; /* server non-specific error code */
2523 else if (code == CM_ERROR_BADFD) {
2525 error = 6; /* invalid file handle */
2527 else if (code == CM_ERROR_BADFDOP) {
2528 class = 1; /* invalid op on FD */
2531 else if (code == CM_ERROR_EXISTS) {
2533 error = 80; /* file already exists */
2535 else if (code == CM_ERROR_NOTEMPTY) {
2537 error = 5; /* delete directory not empty */
2539 else if (code == CM_ERROR_CROSSDEVLINK) {
2541 error = 17; /* EXDEV */
2543 else if (code == CM_ERROR_NOTDIR) {
2544 class = 1; /* bad path */
2547 else if (code == CM_ERROR_ISDIR) {
2548 class = 1; /* access denied; DOS doesn't have a good match */
2551 else if (code == CM_ERROR_BADOP) {
2555 else if (code == CM_ERROR_BADSHARENAME) {
2559 else if (code == CM_ERROR_NOIPC) {
2561 error = 4; /* bad access */
2563 else if (code == CM_ERROR_CLOCKSKEW) {
2564 class = 1; /* invalid function */
2567 else if (code == CM_ERROR_BADTID) {
2571 else if (code == CM_ERROR_USESTD) {
2575 else if (code == CM_ERROR_REMOTECONN) {
2579 else if (code == CM_ERROR_QUOTA) {
2580 if (vcp->flags & SMB_VCFLAG_USEV3) {
2582 error = 39; /* disk full */
2586 error = 5; /* access denied */
2589 else if (code == CM_ERROR_SPACE) {
2590 if (vcp->flags & SMB_VCFLAG_USEV3) {
2592 error = 39; /* disk full */
2596 error = 5; /* access denied */
2599 else if (code == CM_ERROR_PARTIALWRITE) {
2601 error = 39; /* disk full */
2603 else if (code == CM_ERROR_ATSYS) {
2605 error = 2; /* ENOENT */
2607 else if (code == CM_ERROR_WOULDBLOCK) {
2609 error = 33; /* lock conflict */
2611 else if (code == CM_ERROR_LOCK_CONFLICT) {
2613 error = 33; /* lock conflict */
2615 else if (code == CM_ERROR_SHARING_VIOLATION) {
2617 error = 33; /* lock conflict */
2619 else if (code == CM_ERROR_NOFILES) {
2621 error = 18; /* no files in search */
2623 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2625 error = 183; /* Samba uses this */
2627 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2628 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2630 error = 2; /* bad password */
2632 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2634 error = 3; /* bad path */
2643 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2646 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2648 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2649 return CM_ERROR_BADOP;
2652 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2654 unsigned short EchoCount, i;
2655 char *data, *outdata;
2658 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2660 for (i=1; i<=EchoCount; i++) {
2661 data = smb_GetSMBData(inp, &dataSize);
2662 smb_SetSMBParm(outp, 0, i);
2663 smb_SetSMBDataLength(outp, dataSize);
2664 outdata = smb_GetSMBData(outp, NULL);
2665 memcpy(outdata, data, dataSize);
2666 smb_SendPacket(vcp, outp);
2672 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2675 long count, minCount, finalCount;
2680 cm_user_t *userp = NULL;
2684 char *rawBuf = NULL;
2686 dos_ptr rawBuf = NULL;
2693 fd = smb_GetSMBParm(inp, 0);
2694 count = smb_GetSMBParm(inp, 3);
2695 minCount = smb_GetSMBParm(inp, 4);
2696 offset.HighPart = 0; /* too bad */
2697 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2699 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2700 fd, offset.LowPart, count);
2702 fidp = smb_FindFID(vcp, fd, 0);
2706 pid = ((smb_t *) inp)->pid;
2708 LARGE_INTEGER LOffset, LLength;
2711 key = cm_GenerateKey(vcp->vcID, pid, fd);
2713 LOffset.HighPart = 0;
2714 LOffset.LowPart = offset.LowPart;
2715 LLength.HighPart = 0;
2716 LLength.LowPart = count;
2718 lock_ObtainMutex(&fidp->scp->mx);
2719 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2720 lock_ReleaseMutex(&fidp->scp->mx);
2726 lock_ObtainMutex(&smb_RawBufLock);
2728 /* Get a raw buf, from head of list */
2729 rawBuf = smb_RawBufs;
2731 smb_RawBufs = *(char **)smb_RawBufs;
2733 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2736 lock_ReleaseMutex(&smb_RawBufLock);
2740 if (fidp->flags & SMB_FID_IOCTL)
2743 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2745 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2748 /* Give back raw buffer */
2749 lock_ObtainMutex(&smb_RawBufLock);
2751 *((char **) rawBuf) = smb_RawBufs;
2753 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2756 smb_RawBufs = rawBuf;
2757 lock_ReleaseMutex(&smb_RawBufLock);
2760 smb_ReleaseFID(fidp);
2764 userp = smb_GetUser(vcp, inp);
2767 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2769 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2770 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2771 userp, &finalCount, TRUE /* rawFlag */);
2778 cm_ReleaseUser(userp);
2781 smb_ReleaseFID(fidp);
2786 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2788 memset((char *)ncbp, 0, sizeof(NCB));
2790 ncbp->ncb_length = (unsigned short) finalCount;
2791 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2792 ncbp->ncb_lana_num = vcp->lana;
2793 ncbp->ncb_command = NCBSEND;
2794 ncbp->ncb_buffer = rawBuf;
2797 code = Netbios(ncbp);
2799 code = Netbios(ncbp, dos_ncb);
2802 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2805 /* Give back raw buffer */
2806 lock_ObtainMutex(&smb_RawBufLock);
2808 *((char **) rawBuf) = smb_RawBufs;
2810 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2813 smb_RawBufs = rawBuf;
2814 lock_ReleaseMutex(&smb_RawBufLock);
2820 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2822 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2827 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2829 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2834 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2841 int protoIndex; /* index we're using */
2846 char protocol_array[10][1024]; /* protocol signature of the client */
2847 int caps; /* capabilities */
2850 TIME_ZONE_INFORMATION tzi;
2852 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2856 DWORD now = GetCurrentTime();
2857 if (now - last_msg_time >= 30000
2858 && now - last_msg_time <= 90000) {
2860 "Setting dead_vcp %x", active_vcp);
2862 smb_ReleaseVC(dead_vcp);
2864 "Previous dead_vcp %x", dead_vcp);
2866 smb_HoldVC(active_vcp);
2867 dead_vcp = active_vcp;
2868 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2873 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2875 namep = smb_GetSMBData(inp, &dbytes);
2878 coreProtoIndex = -1; /* not found */
2881 while(namex < dbytes) {
2882 osi_Log1(smb_logp, "Protocol %s",
2883 osi_LogSaveString(smb_logp, namep+1));
2884 strcpy(protocol_array[tcounter], namep+1);
2886 /* namep points at the first protocol, or really, a 0x02
2887 * byte preceding the null-terminated ASCII name.
2889 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2890 coreProtoIndex = tcounter;
2892 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2893 v3ProtoIndex = tcounter;
2895 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2896 NTProtoIndex = tcounter;
2899 /* compute size of protocol entry */
2900 entryLength = strlen(namep+1);
2901 entryLength += 2; /* 0x02 bytes and null termination */
2903 /* advance over this protocol entry */
2904 namex += entryLength;
2905 namep += entryLength;
2906 tcounter++; /* which proto entry we're looking at */
2909 if (NTProtoIndex != -1) {
2910 protoIndex = NTProtoIndex;
2911 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2913 else if (v3ProtoIndex != -1) {
2914 protoIndex = v3ProtoIndex;
2915 vcp->flags |= SMB_VCFLAG_USEV3;
2917 else if (coreProtoIndex != -1) {
2918 protoIndex = coreProtoIndex;
2919 vcp->flags |= SMB_VCFLAG_USECORE;
2921 else protoIndex = -1;
2923 if (protoIndex == -1)
2924 return CM_ERROR_INVAL;
2925 else if (NTProtoIndex != -1) {
2926 smb_SetSMBParm(outp, 0, protoIndex);
2927 if (smb_authType != SMB_AUTH_NONE) {
2928 smb_SetSMBParmByte(outp, 1,
2929 NEGOTIATE_SECURITY_USER_LEVEL |
2930 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2932 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2934 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2935 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2936 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2937 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2938 /* The session key is not a well documented field however most clients
2939 * will echo back the session key to the server. Currently we are using
2940 * the same value for all sessions. We should generate a random value
2941 * and store it into the vcp
2943 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2944 smb_SetSMBParm(outp, 8, 1);
2946 * Tried changing the capabilities to support for W2K - defect 117695
2947 * Maybe something else needs to be changed here?
2951 smb_SetSMBParmLong(outp, 9, 0x43fd);
2953 smb_SetSMBParmLong(outp, 9, 0x251);
2956 * 32-bit error codes *
2961 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2963 NTNEGOTIATE_CAPABILITY_DFS |
2965 NTNEGOTIATE_CAPABILITY_NTFIND |
2966 NTNEGOTIATE_CAPABILITY_RAWMODE |
2967 NTNEGOTIATE_CAPABILITY_NTSMB;
2969 if ( smb_authType == SMB_AUTH_EXTENDED )
2970 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2972 smb_SetSMBParmLong(outp, 9, caps);
2974 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2975 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2976 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2978 GetTimeZoneInformation(&tzi);
2979 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2981 if (smb_authType == SMB_AUTH_NTLM) {
2982 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2983 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2984 /* paste in encryption key */
2985 datap = smb_GetSMBData(outp, NULL);
2986 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2987 /* and the faux domain name */
2988 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2989 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2993 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2995 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2997 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2999 datap = smb_GetSMBData(outp, NULL);
3000 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3003 datap += sizeof(smb_ServerGUID);
3004 memcpy(datap, secBlob, secBlobLength);
3008 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3009 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3012 else if (v3ProtoIndex != -1) {
3013 smb_SetSMBParm(outp, 0, protoIndex);
3015 /* NOTE: Extended authentication cannot be negotiated with v3
3016 * therefore we fail over to NTLM
3018 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3019 smb_SetSMBParm(outp, 1,
3020 NEGOTIATE_SECURITY_USER_LEVEL |
3021 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3023 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3025 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3026 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3027 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3028 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3029 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3030 smb_SetSMBParm(outp, 7, 1);
3032 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3033 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3034 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3036 GetTimeZoneInformation(&tzi);
3037 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3039 /* NOTE: Extended authentication cannot be negotiated with v3
3040 * therefore we fail over to NTLM
3042 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3043 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3044 smb_SetSMBParm(outp, 12, 0); /* resvd */
3045 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3046 datap = smb_GetSMBData(outp, NULL);
3047 /* paste in a new encryption key */
3048 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3049 /* and the faux domain name */
3050 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3052 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3053 smb_SetSMBParm(outp, 12, 0); /* resvd */
3054 smb_SetSMBDataLength(outp, 0);
3057 else if (coreProtoIndex != -1) { /* not really supported anymore */
3058 smb_SetSMBParm(outp, 0, protoIndex);
3059 smb_SetSMBDataLength(outp, 0);
3064 void smb_Daemon(void *parmp)
3066 afs_uint32 count = 0;
3068 while(smbShutdownFlag == 0) {
3072 if (smbShutdownFlag == 1)
3075 if ((count % 72) == 0) { /* every five minutes */
3077 time_t old_localZero = smb_localZero;
3079 /* Initialize smb_localZero */
3080 myTime.tm_isdst = -1; /* compute whether on DST or not */
3081 myTime.tm_year = 70;
3087 smb_localZero = mktime(&myTime);
3089 #ifndef USE_NUMERIC_TIME_CONV
3090 smb_CalculateNowTZ();
3091 #endif /* USE_NUMERIC_TIME_CONV */
3092 #ifdef AFS_FREELANCE
3093 if ( smb_localZero != old_localZero )
3094 cm_noteLocalMountPointChange();
3097 /* XXX GC dir search entries */
3101 void smb_WaitingLocksDaemon()
3103 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3104 smb_waitingLock_t *wl, *wlNext;
3107 smb_packet_t *inp, *outp;
3111 while (smbShutdownFlag == 0) {
3112 lock_ObtainWrite(&smb_globalLock);
3113 nwlRequest = smb_allWaitingLocks;
3114 if (nwlRequest == NULL) {
3115 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3125 lock_ObtainWrite(&smb_globalLock);
3127 wlRequest = nwlRequest;
3128 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3129 lock_ReleaseWrite(&smb_globalLock);
3133 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3134 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3137 /* wl->state is either _DONE or _WAITING. _ERROR
3138 would no longer be on the queue. */
3139 code = cm_RetryLock( wl->lockp,
3140 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3143 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3144 } else if (code != CM_ERROR_WOULDBLOCK) {
3145 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3150 if (code == CM_ERROR_WOULDBLOCK) {
3153 if (wlRequest->timeRemaining != 0xffffffff
3154 && (wlRequest->timeRemaining -= 1000) < 0)
3166 scp = wlRequest->scp;
3170 lock_ObtainMutex(&scp->mx);
3172 for (wl = wlRequest->locks; wl; wl = wlNext) {
3173 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3175 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3176 wl->LLength, wl->key, NULL, &req);
3178 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3183 lock_ReleaseMutex(&scp->mx);
3186 for (wl = wlRequest->locks; wl; wl = wlNext) {
3187 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3188 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3193 vcp = wlRequest->vcp;
3194 inp = wlRequest->inp;
3195 outp = wlRequest->outp;
3197 ncbp->ncb_length = inp->ncb_length;
3198 inp->spacep = cm_GetSpace();
3200 /* Remove waitingLock from list */
3201 lock_ObtainWrite(&smb_globalLock);
3202 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3204 lock_ReleaseWrite(&smb_globalLock);
3206 /* Resume packet processing */
3208 smb_SetSMBDataLength(outp, 0);
3209 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3210 outp->resumeCode = code;
3212 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3215 cm_FreeSpace(inp->spacep);
3216 smb_FreePacket(inp);
3217 smb_FreePacket(outp);
3219 cm_ReleaseSCache(wlRequest->scp);
3222 } while (nwlRequest && smbShutdownFlag == 0);
3227 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3229 osi_Log0(smb_logp, "SMB receive get disk attributes");
3231 smb_SetSMBParm(outp, 0, 32000);
3232 smb_SetSMBParm(outp, 1, 64);
3233 smb_SetSMBParm(outp, 2, 1024);
3234 smb_SetSMBParm(outp, 3, 30000);
3235 smb_SetSMBParm(outp, 4, 0);
3236 smb_SetSMBDataLength(outp, 0);
3240 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3244 unsigned short newTid;
3245 char shareName[256];
3253 osi_Log0(smb_logp, "SMB receive tree connect");
3255 /* parse input parameters */
3256 tp = smb_GetSMBData(inp, NULL);
3257 pathp = smb_ParseASCIIBlock(tp, &tp);
3258 if (smb_StoreAnsiFilenames)
3259 OemToChar(pathp,pathp);
3260 passwordp = smb_ParseASCIIBlock(tp, &tp);
3261 tp = strrchr(pathp, '\\');
3263 return CM_ERROR_BADSMB;
3264 strcpy(shareName, tp+1);
3266 userp = smb_GetUser(vcp, inp);
3268 lock_ObtainMutex(&vcp->mx);
3269 newTid = vcp->tidCounter++;
3270 lock_ReleaseMutex(&vcp->mx);
3272 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3273 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3274 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3276 smb_ReleaseUID(uidp);
3278 smb_ReleaseTID(tidp);
3279 return CM_ERROR_BADSHARENAME;
3281 lock_ObtainMutex(&tidp->mx);
3282 tidp->userp = userp;
3283 tidp->pathname = sharePath;
3284 lock_ReleaseMutex(&tidp->mx);
3285 smb_ReleaseTID(tidp);
3287 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3288 smb_SetSMBParm(rsp, 1, newTid);
3289 smb_SetSMBDataLength(rsp, 0);
3291 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3295 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3299 if (*inp++ != 0x1) return NULL;
3300 tlen = inp[0] + (inp[1]<<8);
3301 inp += 2; /* skip length field */
3304 *chainpp = inp + tlen;
3307 if (lengthp) *lengthp = tlen;
3312 /* set maskp to the mask part of the incoming path.
3313 * Mask is 11 bytes long (8.3 with the dot elided).
3314 * Returns true if succeeds with a valid name, otherwise it does
3315 * its best, but returns false.
3317 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3325 /* starts off valid */
3328 /* mask starts out all blanks */
3329 memset(maskp, ' ', 11);
3331 /* find last backslash, or use whole thing if there is none */
3332 tp = strrchr(pathp, '\\');
3333 if (!tp) tp = pathp;
3334 else tp++; /* skip slash */
3338 /* names starting with a dot are illegal */
3339 if (*tp == '.') valid8Dot3 = 0;
3343 if (tc == 0) return valid8Dot3;
3344 if (tc == '.' || tc == '"') break;
3345 if (i < 8) *up++ = tc;
3346 else valid8Dot3 = 0;
3349 /* if we get here, tp point after the dot */
3350 up = maskp+8; /* ext goes here */
3357 if (tc == '.' || tc == '"')
3360 /* copy extension if not too long */
3370 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3380 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3382 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3386 /* otherwise, we have a valid 8.3 name; see if we have a match,
3387 * treating '?' as a wildcard in maskp (but not in the file name).
3389 tp1 = umask; /* real name, in mask format */
3390 tp2 = maskp; /* mask, in mask format */
3391 for(i=0; i<11; i++) {
3392 tc1 = *tp1++; /* char from real name */
3393 tc2 = *tp2++; /* char from mask */
3394 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3395 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3398 if (tc2 == '?' && tc1 != ' ')
3405 /* we got a match */
3409 char *smb_FindMask(char *pathp)
3413 tp = strrchr(pathp, '\\'); /* find last slash */
3416 return tp+1; /* skip the slash */
3418 return pathp; /* no slash, return the entire path */
3421 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3423 unsigned char *pathp;
3425 unsigned char mask[11];
3426 unsigned char *statBlockp;
3427 unsigned char initStatBlock[21];
3430 osi_Log0(smb_logp, "SMB receive search volume");
3432 /* pull pathname and stat block out of request */
3433 tp = smb_GetSMBData(inp, NULL);
3434 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3435 osi_assert(pathp != NULL);
3436 if (smb_StoreAnsiFilenames)
3437 OemToChar(pathp,pathp);
3438 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3439 osi_assert(statBlockp != NULL);
3441 statBlockp = initStatBlock;
3445 /* for returning to caller */
3446 smb_Get8Dot3MaskFromPath(mask, pathp);
3448 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3449 tp = smb_GetSMBData(outp, NULL);
3451 *tp++ = 43; /* bytes in a dir entry */
3452 *tp++ = 0; /* high byte in counter */
3454 /* now marshall the dir entry, starting with the search status */
3455 *tp++ = statBlockp[0]; /* Reserved */
3456 memcpy(tp, mask, 11); tp += 11; /* FileName */
3458 /* now pass back server use info, with 1st byte non-zero */
3460 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3462 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3464 *tp++ = 0x8; /* attribute: volume */
3474 /* 4 byte file size */
3480 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3481 memset(tp, ' ', 13);
3484 /* set the length of the data part of the packet to 43 + 3, for the dir
3485 * entry plus the 5 and the length fields.
3487 smb_SetSMBDataLength(outp, 46);
3491 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3492 cm_user_t *userp, cm_req_t *reqp)
3500 smb_dirListPatch_t *patchp;
3501 smb_dirListPatch_t *npatchp;
3503 for (patchp = *dirPatchespp; patchp; patchp =
3504 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3506 dptr = patchp->dptr;
3508 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3510 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3511 *dptr++ = SMB_ATTR_HIDDEN;
3514 lock_ObtainMutex(&scp->mx);
3515 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3516 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3518 lock_ReleaseMutex(&scp->mx);
3519 cm_ReleaseSCache(scp);
3520 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3521 *dptr++ = SMB_ATTR_HIDDEN;
3525 attr = smb_Attributes(scp);
3526 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3527 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3528 attr |= SMB_ATTR_HIDDEN;
3532 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3535 shortTemp = (unsigned short) (dosTime & 0xffff);
3536 *((u_short *)dptr) = shortTemp;
3539 /* and copy out date */
3540 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3541 *((u_short *)dptr) = shortTemp;
3544 /* copy out file length */
3545 *((u_long *)dptr) = scp->length.LowPart;
3547 lock_ReleaseMutex(&scp->mx);
3548 cm_ReleaseSCache(scp);
3551 /* now free the patches */
3552 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3553 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3557 /* and mark the list as empty */
3558 *dirPatchespp = NULL;
3563 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3572 smb_dirListPatch_t *dirListPatchesp;
3573 smb_dirListPatch_t *curPatchp;
3577 osi_hyper_t dirLength;
3578 osi_hyper_t bufferOffset;
3579 osi_hyper_t curOffset;
3581 unsigned char *inCookiep;
3582 smb_dirSearch_t *dsp;
3586 unsigned long clientCookie;
3587 cm_pageHeader_t *pageHeaderp;
3588 cm_user_t *userp = NULL;
3595 long nextEntryCookie;
3596 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3597 char resByte; /* reserved byte from the cookie */
3598 char *op; /* output data ptr */
3599 char *origOp; /* original value of op */
3600 cm_space_t *spacep; /* for pathname buffer */
3611 maxCount = smb_GetSMBParm(inp, 0);
3613 dirListPatchesp = NULL;
3615 caseFold = CM_FLAG_CASEFOLD;
3617 tp = smb_GetSMBData(inp, NULL);
3618 pathp = smb_ParseASCIIBlock(tp, &tp);
3619 if (smb_StoreAnsiFilenames)
3620 OemToChar(pathp,pathp);
3621 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3623 /* bail out if request looks bad */
3624 if (!tp || !pathp) {
3625 return CM_ERROR_BADSMB;
3628 /* We can handle long names */
3629 if (vcp->flags & SMB_VCFLAG_USENT)
3630 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3632 /* make sure we got a whole search status */
3633 if (dataLength < 21) {
3634 nextCookie = 0; /* start at the beginning of the dir */
3637 attribute = smb_GetSMBParm(inp, 1);
3639 /* handle volume info in another function */
3640 if (attribute & 0x8)
3641 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3643 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3644 maxCount, osi_LogSaveString(smb_logp, pathp));
3646 if (*pathp == 0) { /* null pathp, treat as root dir */
3647 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3648 return CM_ERROR_NOFILES;
3652 dsp = smb_NewDirSearch(0);
3653 dsp->attribute = attribute;
3654 smb_Get8Dot3MaskFromPath(mask, pathp);
3655 memcpy(dsp->mask, mask, 11);
3657 /* track if this is likely to match a lot of entries */
3658 if (smb_IsStarMask(mask))
3663 /* pull the next cookie value out of the search status block */
3664 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3665 + (inCookiep[16]<<24);
3666 dsp = smb_FindDirSearch(inCookiep[12]);
3668 /* can't find dir search status; fatal error */
3669 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3670 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3671 return CM_ERROR_BADFD;
3673 attribute = dsp->attribute;
3674 resByte = inCookiep[0];
3676 /* copy out client cookie, in host byte order. Don't bother
3677 * interpreting it, since we're just passing it through, anyway.
3679 memcpy(&clientCookie, &inCookiep[17], 4);
3681 memcpy(mask, dsp->mask, 11);
3683 /* assume we're doing a star match if it has continued for more
3689 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3690 nextCookie, dsp->cookie, attribute);
3692 userp = smb_GetUser(vcp, inp);
3694 /* try to get the vnode for the path name next */
3695 lock_ObtainMutex(&dsp->mx);
3701 spacep = inp->spacep;
3702 smb_StripLastComponent(spacep->data, NULL, pathp);
3703 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3705 lock_ReleaseMutex(&dsp->mx);
3706 cm_ReleaseUser(userp);
3707 smb_DeleteDirSearch(dsp);
3708 smb_ReleaseDirSearch(dsp);
3709 return CM_ERROR_NOFILES;
3711 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3712 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3715 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3716 cm_ReleaseSCache(scp);
3717 lock_ReleaseMutex(&dsp->mx);
3718 cm_ReleaseUser(userp);
3719 smb_DeleteDirSearch(dsp);
3720 smb_ReleaseDirSearch(dsp);
3721 if ( WANTS_DFS_PATHNAMES(inp) )
3722 return CM_ERROR_PATH_NOT_COVERED;
3724 return CM_ERROR_BADSHARENAME;
3726 #endif /* DFS_SUPPORT */
3729 /* we need one hold for the entry we just stored into,
3730 * and one for our own processing. When we're done with this
3731 * function, we'll drop the one for our own processing.
3732 * We held it once from the namei call, and so we do another hold
3736 lock_ObtainMutex(&scp->mx);
3737 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3738 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3739 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3740 dsp->flags |= SMB_DIRSEARCH_BULKST;
3742 lock_ReleaseMutex(&scp->mx);
3745 lock_ReleaseMutex(&dsp->mx);
3747 cm_ReleaseUser(userp);
3748 smb_DeleteDirSearch(dsp);
3749 smb_ReleaseDirSearch(dsp);
3753 /* reserves space for parameter; we'll adjust it again later to the
3754 * real count of the # of entries we returned once we've actually
3755 * assembled the directory listing.
3757 smb_SetSMBParm(outp, 0, 0);
3759 /* get the directory size */
3760 lock_ObtainMutex(&scp->mx);
3761 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3762 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3764 lock_ReleaseMutex(&scp->mx);
3765 cm_ReleaseSCache(scp);
3766 cm_ReleaseUser(userp);
3767 smb_DeleteDirSearch(dsp);
3768 smb_ReleaseDirSearch(dsp);
3772 dirLength = scp->length;
3774 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3775 curOffset.HighPart = 0;
3776 curOffset.LowPart = nextCookie;
3777 origOp = op = smb_GetSMBData(outp, NULL);
3778 /* and write out the basic header */
3779 *op++ = 5; /* variable block */
3780 op += 2; /* skip vbl block length; we'll fill it in later */
3784 /* make sure that curOffset.LowPart doesn't point to the first
3785 * 32 bytes in the 2nd through last dir page, and that it doesn't
3786 * point at the first 13 32-byte chunks in the first dir page,
3787 * since those are dir and page headers, and don't contain useful
3790 temp = curOffset.LowPart & (2048-1);
3791 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3792 /* we're in the first page */
3793 if (temp < 13*32) temp = 13*32;
3796 /* we're in a later dir page */
3797 if (temp < 32) temp = 32;
3800 /* make sure the low order 5 bits are zero */
3803 /* now put temp bits back ito curOffset.LowPart */
3804 curOffset.LowPart &= ~(2048-1);
3805 curOffset.LowPart |= temp;
3807 /* check if we've returned all the names that will fit in the
3810 if (returnedNames >= maxCount) {
3811 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3812 returnedNames, maxCount);
3816 /* check if we've passed the dir's EOF */
3817 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3819 /* see if we can use the bufferp we have now; compute in which page
3820 * the current offset would be, and check whether that's the offset
3821 * of the buffer we have. If not, get the buffer.
3823 thyper.HighPart = curOffset.HighPart;
3824 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3825 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3828 buf_Release(bufferp);
3831 lock_ReleaseMutex(&scp->mx);
3832 lock_ObtainRead(&scp->bufCreateLock);
3833 code = buf_Get(scp, &thyper, &bufferp);
3834 lock_ReleaseRead(&scp->bufCreateLock);
3835 lock_ObtainMutex(&dsp->mx);
3837 /* now, if we're doing a star match, do bulk fetching of all of
3838 * the status info for files in the dir.
3841 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3842 lock_ObtainMutex(&scp->mx);
3843 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3844 LargeIntegerGreaterThanOrEqualTo(thyper,
3845 scp->bulkStatProgress)) {
3846 /* Don't bulk stat if risking timeout */
3847 int now = GetCurrentTime();
3848 if (now - req.startTime > 5000) {
3849 scp->bulkStatProgress = thyper;
3850 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3851 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3853 cm_TryBulkStat(scp, &thyper, userp, &req);
3856 lock_ObtainMutex(&scp->mx);
3858 lock_ReleaseMutex(&dsp->mx);
3860 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3864 bufferOffset = thyper;
3866 /* now get the data in the cache */
3868 code = cm_SyncOp(scp, bufferp, userp, &req,
3870 CM_SCACHESYNC_NEEDCALLBACK |
3871 CM_SCACHESYNC_READ);
3873 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3877 if (cm_HaveBuffer(scp, bufferp, 0)) {
3878 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3882 /* otherwise, load the buffer and try again */
3883 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3885 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3886 scp, bufferp, code);
3891 buf_Release(bufferp);
3895 } /* if (wrong buffer) ... */
3897 /* now we have the buffer containing the entry we're interested in; copy
3898 * it out if it represents a non-deleted entry.
3900 entryInDir = curOffset.LowPart & (2048-1);
3901 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3903 /* page header will help tell us which entries are free. Page header
3904 * can change more often than once per buffer, since AFS 3 dir page size
3905 * may be less than (but not more than a buffer package buffer.
3907 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3908 temp &= ~(2048 - 1); /* turn off intra-page bits */
3909 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3911 /* now determine which entry we're looking at in the page. If it is
3912 * free (there's a free bitmap at the start of the dir), we should
3913 * skip these 32 bytes.
3915 slotInPage = (entryInDir & 0x7e0) >> 5;
3916 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3917 /* this entry is free */
3918 numDirChunks = 1; /* only skip this guy */
3922 tp = bufferp->datap + entryInBuffer;
3923 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3925 /* while we're here, compute the next entry's location, too,
3926 * since we'll need it when writing out the cookie into the dir
3929 * XXXX Probably should do more sanity checking.
3931 numDirChunks = cm_NameEntries(dep->name, NULL);
3933 /* compute the offset of the cookie representing the next entry */
3934 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3936 /* Compute 8.3 name if necessary */
3937 actualName = dep->name;
3938 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3939 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3940 actualName = shortName;
3943 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3944 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3945 osi_LogSaveString(smb_logp, actualName));
3947 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3948 /* this is one of the entries to use: it is not deleted
3949 * and it matches the star pattern we're looking for.
3952 /* Eliminate entries that don't match requested
3955 /* no hidden files */
3956 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3957 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3961 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3963 /* We have already done the cm_TryBulkStat above */
3964 fid.cell = scp->fid.cell;
3965 fid.volume = scp->fid.volume;
3966 fid.vnode = ntohl(dep->fid.vnode);
3967 fid.unique = ntohl(dep->fid.unique);
3968 fileType = cm_FindFileType(&fid);
3969 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3970 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3972 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3973 fileType == CM_SCACHETYPE_DFSLINK ||
3974 fileType == CM_SCACHETYPE_INVALID)
3975 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3980 memcpy(op, mask, 11); op += 11;
3981 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3982 *op++ = nextEntryCookie & 0xff;
3983 *op++ = (nextEntryCookie>>8) & 0xff;
3984 *op++ = (nextEntryCookie>>16) & 0xff;
3985 *op++ = (nextEntryCookie>>24) & 0xff;
3986 memcpy(op, &clientCookie, 4); op += 4;
3988 /* now we emit the attribute. This is sort of tricky,
3989 * since we need to really stat the file to find out
3990 * what type of entry we've got. Right now, we're
3991 * copying out data from a buffer, while holding the
3992 * scp locked, so it isn't really convenient to stat
3993 * something now. We'll put in a place holder now,
3994 * and make a second pass before returning this to get
3995 * the real attributes. So, we just skip the data for
3996 * now, and adjust it later. We allocate a patch
3997 * record to make it easy to find this point later.
3998 * The replay will happen at a time when it is safe to
3999 * unlock the directory.
4001 curPatchp = malloc(sizeof(*curPatchp));
4002 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4003 curPatchp->dptr = op;
4004 curPatchp->fid.cell = scp->fid.cell;
4005 curPatchp->fid.volume = scp->fid.volume;
4006 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4007 curPatchp->fid.unique = ntohl(dep->fid.unique);
4009 /* do hidden attribute here since name won't be around when applying
4013 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4014 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4016 curPatchp->flags = 0;
4018 op += 9; /* skip attr, time, date and size */
4020 /* zero out name area. The spec says to pad with
4021 * spaces, but Samba doesn't, and neither do we.
4025 /* finally, we get to copy out the name; we know that
4026 * it fits in 8.3 or the pattern wouldn't match, but it
4027 * never hurts to be sure.
4029 strncpy(op, actualName, 13);
4030 if (smb_StoreAnsiFilenames)
4033 /* Uppercase if requested by client */
4034 if (!KNOWS_LONG_NAMES(inp))
4039 /* now, adjust the # of entries copied */
4041 } /* if we're including this name */
4044 /* and adjust curOffset to be where the new cookie is */
4045 thyper.HighPart = 0;
4046 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4047 curOffset = LargeIntegerAdd(thyper, curOffset);
4048 } /* while copying data for dir listing */
4050 /* release the mutex */
4051 lock_ReleaseMutex(&scp->mx);
4052 if (bufferp) buf_Release(bufferp);
4054 /* apply and free last set of patches; if not doing a star match, this
4055 * will be empty, but better safe (and freeing everything) than sorry.
4057 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4059 /* special return code for unsuccessful search */
4060 if (code == 0 && dataLength < 21 && returnedNames == 0)
4061 code = CM_ERROR_NOFILES;
4063 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4064 returnedNames, code);
4067 smb_DeleteDirSearch(dsp);
4068 smb_ReleaseDirSearch(dsp);
4069 cm_ReleaseSCache(scp);
4070 cm_ReleaseUser(userp);
4074 /* finalize the output buffer */
4075 smb_SetSMBParm(outp, 0, returnedNames);
4076 temp = (long) (op - origOp);
4077 smb_SetSMBDataLength(outp, temp);
4079 /* the data area is a variable block, which has a 5 (already there)
4080 * followed by the length of the # of data bytes. We now know this to
4081 * be "temp," although that includes the 3 bytes of vbl block header.
4082 * Deduct for them and fill in the length field.
4084 temp -= 3; /* deduct vbl block info */
4085 osi_assert(temp == (43 * returnedNames));
4086 origOp[1] = temp & 0xff;
4087 origOp[2] = (temp>>8) & 0xff;
4088 if (returnedNames == 0)
4089 smb_DeleteDirSearch(dsp);
4090 smb_ReleaseDirSearch(dsp);
4091 cm_ReleaseSCache(scp);
4092 cm_ReleaseUser(userp);
4096 /* verify that this is a valid path to a directory. I don't know why they
4097 * don't use the get file attributes call.
4099 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4103 cm_scache_t *rootScp;
4104 cm_scache_t *newScp;
4113 pathp = smb_GetSMBData(inp, NULL);
4114 pathp = smb_ParseASCIIBlock(pathp, NULL);
4116 return CM_ERROR_BADFD;
4117 if (smb_StoreAnsiFilenames)
4118 OemToChar(pathp,pathp);
4119 osi_Log1(smb_logp, "SMB receive check path %s",
4120 osi_LogSaveString(smb_logp, pathp));
4122 rootScp = cm_data.rootSCachep;
4124 userp = smb_GetUser(vcp, inp);
4126 caseFold = CM_FLAG_CASEFOLD;
4128 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4130 cm_ReleaseUser(userp);
4131 return CM_ERROR_NOSUCHPATH;
4133 code = cm_NameI(rootScp, pathp,
4134 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4135 userp, tidPathp, &req, &newScp);
4138 cm_ReleaseUser(userp);
4143 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4144 cm_ReleaseSCache(newScp);
4145 cm_ReleaseUser(userp);
4146 if ( WANTS_DFS_PATHNAMES(inp) )
4147 return CM_ERROR_PATH_NOT_COVERED;
4149 return CM_ERROR_BADSHARENAME;
4151 #endif /* DFS_SUPPORT */
4153 /* now lock the vnode with a callback; returns with newScp locked */
4154 lock_ObtainMutex(&newScp->mx);
4155 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4156 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4157 if (code && code != CM_ERROR_NOACCESS) {
4158 lock_ReleaseMutex(&newScp->mx);
4159 cm_ReleaseSCache(newScp);
4160 cm_ReleaseUser(userp);
4164 attrs = smb_Attributes(newScp);
4166 if (!(attrs & SMB_ATTR_DIRECTORY))
4167 code = CM_ERROR_NOTDIR;
4169 lock_ReleaseMutex(&newScp->mx);
4171 cm_ReleaseSCache(newScp);
4172 cm_ReleaseUser(userp);
4176 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4180 cm_scache_t *rootScp;
4181 unsigned short attribute;
4183 cm_scache_t *newScp;
4192 /* decode basic attributes we're passed */
4193 attribute = smb_GetSMBParm(inp, 0);
4194 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4196 pathp = smb_GetSMBData(inp, NULL);
4197 pathp = smb_ParseASCIIBlock(pathp, NULL);
4199 return CM_ERROR_BADSMB;
4200 if (smb_StoreAnsiFilenames)
4201 OemToChar(pathp,pathp);
4203 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4204 dosTime, attribute);
4206 rootScp = cm_data.rootSCachep;
4208 userp = smb_GetUser(vcp, inp);
4210 caseFold = CM_FLAG_CASEFOLD;
4212 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4214 cm_ReleaseUser(userp);
4215 return CM_ERROR_NOSUCHFILE;
4217 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4218 tidPathp, &req, &newScp);
4221 cm_ReleaseUser(userp);
4226 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4227 cm_ReleaseSCache(newScp);
4228 cm_ReleaseUser(userp);
4229 if ( WANTS_DFS_PATHNAMES(inp) )
4230 return CM_ERROR_PATH_NOT_COVERED;
4232 return CM_ERROR_BADSHARENAME;
4234 #endif /* DFS_SUPPORT */
4236 /* now lock the vnode with a callback; returns with newScp locked; we
4237 * need the current status to determine what the new status is, in some
4240 lock_ObtainMutex(&newScp->mx);
4241 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4242 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4244 lock_ReleaseMutex(&newScp->mx);
4245 cm_ReleaseSCache(newScp);
4246 cm_ReleaseUser(userp);
4250 /* Check for RO volume */
4251 if (newScp->flags & CM_SCACHEFLAG_RO) {
4252 lock_ReleaseMutex(&newScp->mx);
4253 cm_ReleaseSCache(newScp);
4254 cm_ReleaseUser(userp);
4255 return CM_ERROR_READONLY;
4258 /* prepare for setattr call */
4261 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4262 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4264 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4265 /* we're told to make a writable file read-only */
4266 attr.unixModeBits = newScp->unixModeBits & ~0222;
4267 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4269 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4270 /* we're told to make a read-only file writable */
4271 attr.unixModeBits = newScp->unixModeBits | 0222;
4272 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4274 lock_ReleaseMutex(&newScp->mx);
4276 /* now call setattr */
4278 code = cm_SetAttr(newScp, &attr, userp, &req);
4282 cm_ReleaseSCache(newScp);
4283 cm_ReleaseUser(userp);
4288 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4292 cm_scache_t *rootScp;
4293 cm_scache_t *newScp, *dscp;
4305 pathp = smb_GetSMBData(inp, NULL);
4306 pathp = smb_ParseASCIIBlock(pathp, NULL);
4308 return CM_ERROR_BADSMB;
4310 if (*pathp == 0) /* null path */
4313 if (smb_StoreAnsiFilenames)
4314 OemToChar(pathp,pathp);
4316 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4317 osi_LogSaveString(smb_logp, pathp));
4319 rootScp = cm_data.rootSCachep;
4321 userp = smb_GetUser(vcp, inp);
4323 /* we shouldn't need this for V3 requests, but we seem to */
4324 caseFold = CM_FLAG_CASEFOLD;
4326 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4328 cm_ReleaseUser(userp);
4329 return CM_ERROR_NOSUCHFILE;
4333 * XXX Strange hack XXX
4335 * As of Patch 5 (16 July 97), we are having the following problem:
4336 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4337 * requests to look up "desktop.ini" in all the subdirectories.
4338 * This can cause zillions of timeouts looking up non-existent cells
4339 * and volumes, especially in the top-level directory.
4341 * We have not found any way to avoid this or work around it except
4342 * to explicitly ignore the requests for mount points that haven't
4343 * yet been evaluated and for directories that haven't yet been
4346 * We should modify this hack to provide a fake desktop.ini file
4347 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4349 spacep = inp->spacep;
4350 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4351 #ifndef SPECIAL_FOLDERS
4352 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4353 code = cm_NameI(rootScp, spacep->data,
4354 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4355 userp, tidPathp, &req, &dscp);
4358 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4359 if ( WANTS_DFS_PATHNAMES(inp) )
4360 return CM_ERROR_PATH_NOT_COVERED;
4362 return CM_ERROR_BADSHARENAME;
4364 #endif /* DFS_SUPPORT */
4365 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4366 code = CM_ERROR_NOSUCHFILE;
4367 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4368 cm_buf_t *bp = buf_Find(dscp, &hzero);
4372 code = CM_ERROR_NOSUCHFILE;
4374 cm_ReleaseSCache(dscp);
4376 cm_ReleaseUser(userp);
4381 #endif /* SPECIAL_FOLDERS */
4383 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4384 tidPathp, &req, &newScp);
4386 cm_ReleaseUser(userp);
4391 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4392 cm_ReleaseSCache(newScp);
4393 cm_ReleaseUser(userp);
4394 if ( WANTS_DFS_PATHNAMES(inp) )
4395 return CM_ERROR_PATH_NOT_COVERED;
4397 return CM_ERROR_BADSHARENAME;
4399 #endif /* DFS_SUPPORT */
4401 /* now lock the vnode with a callback; returns with newScp locked */
4402 lock_ObtainMutex(&newScp->mx);
4403 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4404 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4406 lock_ReleaseMutex(&newScp->mx);
4407 cm_ReleaseSCache(newScp);
4408 cm_ReleaseUser(userp);
4413 /* use smb_Attributes instead. Also the fact that a file is
4414 * in a readonly volume doesn't mean it shojuld be marked as RO
4416 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4417 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4418 attrs = SMB_ATTR_DIRECTORY;
4421 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4422 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4424 attrs = smb_Attributes(newScp);
4427 smb_SetSMBParm(outp, 0, attrs);
4429 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4430 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4431 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4432 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4433 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4434 smb_SetSMBParm(outp, 5, 0);
4435 smb_SetSMBParm(outp, 6, 0);
4436 smb_SetSMBParm(outp, 7, 0);
4437 smb_SetSMBParm(outp, 8, 0);
4438 smb_SetSMBParm(outp, 9, 0);
4439 smb_SetSMBDataLength(outp, 0);
4440 lock_ReleaseMutex(&newScp->mx);
4442 cm_ReleaseSCache(newScp);
4443 cm_ReleaseUser(userp);
4448 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4452 osi_Log0(smb_logp, "SMB receive tree disconnect");
4454 /* find the tree and free it */
4455 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4457 lock_ObtainMutex(&tidp->mx);
4458 tidp->flags |= SMB_TIDFLAG_DELETE;
4459 lock_ReleaseMutex(&tidp->mx);
4460 smb_ReleaseTID(tidp);
4466 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4484 pathp = smb_GetSMBData(inp, NULL);
4485 pathp = smb_ParseASCIIBlock(pathp, NULL);
4486 if (smb_StoreAnsiFilenames)
4487 OemToChar(pathp,pathp);
4489 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4491 #ifdef DEBUG_VERBOSE
4495 hexpath = osi_HexifyString( pathp );
4496 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4501 share = smb_GetSMBParm(inp, 0);
4502 attribute = smb_GetSMBParm(inp, 1);
4504 spacep = inp->spacep;
4505 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4506 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4507 /* special case magic file name for receiving IOCTL requests
4508 * (since IOCTL calls themselves aren't getting through).
4510 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4511 smb_SetupIoctlFid(fidp, spacep);
4512 smb_SetSMBParm(outp, 0, fidp->fid);
4513 smb_SetSMBParm(outp, 1, 0); /* attrs */
4514 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4515 smb_SetSMBParm(outp, 3, 0);
4516 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4517 smb_SetSMBParm(outp, 5, 0x7fff);
4518 /* pass the open mode back */
4519 smb_SetSMBParm(outp, 6, (share & 0xf));
4520 smb_SetSMBDataLength(outp, 0);
4521 smb_ReleaseFID(fidp);
4525 userp = smb_GetUser(vcp, inp);
4527 caseFold = CM_FLAG_CASEFOLD;
4529 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4531 cm_ReleaseUser(userp);
4532 return CM_ERROR_NOSUCHPATH;
4534 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4535 tidPathp, &req, &scp);
4538 cm_ReleaseUser(userp);
4543 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4544 cm_ReleaseSCache(scp);
4545 cm_ReleaseUser(userp);
4546 if ( WANTS_DFS_PATHNAMES(inp) )
4547 return CM_ERROR_PATH_NOT_COVERED;
4549 return CM_ERROR_BADSHARENAME;
4551 #endif /* DFS_SUPPORT */
4553 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4555 cm_ReleaseSCache(scp);
4556 cm_ReleaseUser(userp);
4560 /* don't need callback to check file type, since file types never
4561 * change, and namei and cm_Lookup all stat the object at least once on
4562 * a successful return.
4564 if (scp->fileType != CM_SCACHETYPE_FILE) {
4565 cm_ReleaseSCache(scp);
4566 cm_ReleaseUser(userp);
4567 return CM_ERROR_ISDIR;
4570 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4573 /* save a pointer to the vnode */
4576 if ((share & 0xf) == 0)
4577 fidp->flags |= SMB_FID_OPENREAD;
4578 else if ((share & 0xf) == 1)
4579 fidp->flags |= SMB_FID_OPENWRITE;
4581 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4583 lock_ObtainMutex(&scp->mx);
4584 smb_SetSMBParm(outp, 0, fidp->fid);
4585 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4586 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4587 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4588 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4589 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4590 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4591 /* pass the open mode back; XXXX add access checks */
4592 smb_SetSMBParm(outp, 6, (share & 0xf));
4593 smb_SetSMBDataLength(outp, 0);
4594 lock_ReleaseMutex(&scp->mx);
4597 cm_Open(scp, 0, userp);
4599 /* send and free packet */
4600 smb_ReleaseFID(fidp);
4601 cm_ReleaseUser(userp);
4602 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4606 typedef struct smb_unlinkRock {
4611 char *maskp; /* pointer to the star pattern */
4616 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4619 smb_unlinkRock_t *rockp;
4627 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4628 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4629 caseFold |= CM_FLAG_8DOT3;
4631 matchName = dep->name;
4632 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4634 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4635 !cm_Is8Dot3(dep->name)) {
4636 cm_Gen8Dot3Name(dep, shortName, NULL);
4637 matchName = shortName;
4638 /* 8.3 matches are always case insensitive */
4639 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4642 osi_Log1(smb_logp, "Unlinking %s",
4643 osi_LogSaveString(smb_logp, matchName));
4644 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4645 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4646 smb_NotifyChange(FILE_ACTION_REMOVED,
4647 FILE_NOTIFY_CHANGE_FILE_NAME,
4648 dscp, dep->name, NULL, TRUE);
4652 /* If we made a case sensitive exact match, we might as well quit now. */
4653 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4654 code = CM_ERROR_STOPNOW;
4662 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4671 smb_unlinkRock_t rock;
4680 attribute = smb_GetSMBParm(inp, 0);
4682 tp = smb_GetSMBData(inp, NULL);
4683 pathp = smb_ParseASCIIBlock(tp, &tp);
4684 if (smb_StoreAnsiFilenames)
4685 OemToChar(pathp,pathp);
4687 osi_Log1(smb_logp, "SMB receive unlink %s",
4688 osi_LogSaveString(smb_logp, pathp));
4690 spacep = inp->spacep;
4691 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4693 userp = smb_GetUser(vcp, inp);
4695 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4697 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4699 cm_ReleaseUser(userp);
4700 return CM_ERROR_NOSUCHPATH;
4702 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4705 cm_ReleaseUser(userp);
4710 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4711 cm_ReleaseSCache(dscp);
4712 cm_ReleaseUser(userp);
4713 if ( WANTS_DFS_PATHNAMES(inp) )
4714 return CM_ERROR_PATH_NOT_COVERED;
4716 return CM_ERROR_BADSHARENAME;
4718 #endif /* DFS_SUPPORT */
4720 /* otherwise, scp points to the parent directory. */
4727 rock.maskp = smb_FindMask(pathp);
4728 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4731 thyper.HighPart = 0;
4737 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4738 * match. If that fails, we do a case insensitve match.
4740 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4741 !smb_IsStarMask(rock.maskp)) {
4742 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4745 thyper.HighPart = 0;
4746 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4751 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4753 if (code == CM_ERROR_STOPNOW)
4756 cm_ReleaseUser(userp);
4758 cm_ReleaseSCache(dscp);
4760 if (code == 0 && !rock.any)
4761 code = CM_ERROR_NOSUCHFILE;
4765 typedef struct smb_renameRock {
4766 cm_scache_t *odscp; /* old dir */
4767 cm_scache_t *ndscp; /* new dir */
4768 cm_user_t *userp; /* user */
4769 cm_req_t *reqp; /* request struct */
4770 smb_vc_t *vcp; /* virtual circuit */
4771 char *maskp; /* pointer to star pattern of old file name */
4772 int flags; /* tilde, casefold, etc */
4773 char *newNamep; /* ptr to the new file's name */
4776 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4779 smb_renameRock_t *rockp;
4784 rockp = (smb_renameRock_t *) vrockp;
4786 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4787 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4788 caseFold |= CM_FLAG_8DOT3;
4790 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4792 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4793 !cm_Is8Dot3(dep->name)) {
4794 cm_Gen8Dot3Name(dep, shortName, NULL);
4795 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4798 code = cm_Rename(rockp->odscp, dep->name,
4799 rockp->ndscp, rockp->newNamep, rockp->userp,
4801 /* if the call worked, stop doing the search now, since we
4802 * really only want to rename one file.
4805 code = CM_ERROR_STOPNOW;
4814 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4817 cm_space_t *spacep = NULL;
4818 smb_renameRock_t rock;
4819 cm_scache_t *oldDscp = NULL;
4820 cm_scache_t *newDscp = NULL;
4821 cm_scache_t *tmpscp= NULL;
4822 cm_scache_t *tmpscp2 = NULL;
4832 userp = smb_GetUser(vcp, inp);
4833 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4835 cm_ReleaseUser(userp);
4836 return CM_ERROR_NOSUCHPATH;
4840 spacep = inp->spacep;
4841 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4843 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4844 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4845 userp, tidPathp, &req, &oldDscp);
4847 cm_ReleaseUser(userp);
4852 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4853 cm_ReleaseSCache(oldDscp);
4854 cm_ReleaseUser(userp);
4855 if ( WANTS_DFS_PATHNAMES(inp) )
4856 return CM_ERROR_PATH_NOT_COVERED;
4858 return CM_ERROR_BADSHARENAME;
4860 #endif /* DFS_SUPPORT */
4862 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4863 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4864 userp, tidPathp, &req, &newDscp);
4867 cm_ReleaseSCache(oldDscp);
4868 cm_ReleaseUser(userp);
4873 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4874 cm_ReleaseSCache(oldDscp);
4875 cm_ReleaseSCache(newDscp);
4876 cm_ReleaseUser(userp);
4877 if ( WANTS_DFS_PATHNAMES(inp) )
4878 return CM_ERROR_PATH_NOT_COVERED;
4880 return CM_ERROR_BADSHARENAME;
4882 #endif /* DFS_SUPPORT */
4885 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4886 * next, get the component names, and lower case them.
4889 /* handle the old name first */
4891 oldLastNamep = oldPathp;
4895 /* and handle the new name, too */
4897 newLastNamep = newPathp;
4901 /* TODO: The old name could be a wildcard. The new name must not be */
4903 /* do the vnode call */
4904 rock.odscp = oldDscp;
4905 rock.ndscp = newDscp;
4909 rock.maskp = oldLastNamep;
4910 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4911 rock.newNamep = newLastNamep;
4913 /* Check if the file already exists; if so return error */
4914 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4915 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4916 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4917 osi_LogSaveString(afsd_logp, newLastNamep));
4919 /* Check if the old and the new names differ only in case. If so return
4920 * success, else return CM_ERROR_EXISTS
4922 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4924 /* This would be a success only if the old file is *as same as* the new file */
4925 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4927 if (tmpscp == tmpscp2)
4930 code = CM_ERROR_EXISTS;
4931 cm_ReleaseSCache(tmpscp2);
4934 code = CM_ERROR_NOSUCHFILE;
4937 /* file exist, do not rename, also fixes move */
4938 osi_Log0(smb_logp, "Can't rename. Target already exists");
4939 code = CM_ERROR_EXISTS;
4943 cm_ReleaseSCache(tmpscp);
4944 cm_ReleaseSCache(newDscp);
4945 cm_ReleaseSCache(oldDscp);
4946 cm_ReleaseUser(userp);
4950 /* Now search the directory for the pattern, and do the appropriate rename when found */
4951 thyper.LowPart = 0; /* search dir from here */
4952 thyper.HighPart = 0;
4954 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4955 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
4957 if (code == CM_ERROR_STOPNOW)
4960 code = CM_ERROR_NOSUCHFILE;
4962 /* Handle Change Notification */
4964 * Being lazy, not distinguishing between files and dirs in this
4965 * filter, since we'd have to do a lookup.
4967 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4968 if (oldDscp == newDscp) {
4969 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4970 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4971 filter, oldDscp, oldLastNamep,
4972 newLastNamep, TRUE);
4974 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4975 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4976 filter, oldDscp, oldLastNamep,
4978 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4979 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4980 filter, newDscp, newLastNamep,
4985 cm_ReleaseSCache(tmpscp);
4986 cm_ReleaseUser(userp);
4987 cm_ReleaseSCache(oldDscp);
4988 cm_ReleaseSCache(newDscp);
4993 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4996 cm_space_t *spacep = NULL;
4997 cm_scache_t *oldDscp = NULL;
4998 cm_scache_t *newDscp = NULL;
4999 cm_scache_t *tmpscp= NULL;
5000 cm_scache_t *tmpscp2 = NULL;
5001 cm_scache_t *sscp = NULL;
5010 userp = smb_GetUser(vcp, inp);
5012 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5014 cm_ReleaseUser(userp);
5015 return CM_ERROR_NOSUCHPATH;
5020 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5022 spacep = inp->spacep;
5023 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5025 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5026 userp, tidPathp, &req, &oldDscp);
5028 cm_ReleaseUser(userp);
5033 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5034 cm_ReleaseSCache(oldDscp);
5035 cm_ReleaseUser(userp);
5036 if ( WANTS_DFS_PATHNAMES(inp) )
5037 return CM_ERROR_PATH_NOT_COVERED;
5039 return CM_ERROR_BADSHARENAME;
5041 #endif /* DFS_SUPPORT */
5043 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5044 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5045 userp, tidPathp, &req, &newDscp);
5047 cm_ReleaseSCache(oldDscp);
5048 cm_ReleaseUser(userp);
5053 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5054 cm_ReleaseSCache(newDscp);
5055 cm_ReleaseSCache(oldDscp);
5056 cm_ReleaseUser(userp);
5057 if ( WANTS_DFS_PATHNAMES(inp) )
5058 return CM_ERROR_PATH_NOT_COVERED;
5060 return CM_ERROR_BADSHARENAME;
5062 #endif /* DFS_SUPPORT */
5064 /* Now, although we did two lookups for the two directories (because the same
5065 * directory can be referenced through different paths), we only allow hard links
5066 * within the same directory. */
5067 if (oldDscp != newDscp) {
5068 cm_ReleaseSCache(oldDscp);
5069 cm_ReleaseSCache(newDscp);
5070 cm_ReleaseUser(userp);
5071 return CM_ERROR_CROSSDEVLINK;
5074 /* handle the old name first */
5076 oldLastNamep = oldPathp;
5080 /* and handle the new name, too */
5082 newLastNamep = newPathp;
5086 /* now lookup the old name */
5087 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5088 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5090 cm_ReleaseSCache(oldDscp);
5091 cm_ReleaseSCache(newDscp);
5092 cm_ReleaseUser(userp);
5096 /* Check if the file already exists; if so return error */
5097 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5098 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5099 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5100 osi_LogSaveString(afsd_logp, newLastNamep));
5102 /* if the existing link is to the same file, then we return success */
5104 if(sscp == tmpscp) {
5107 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5108 code = CM_ERROR_EXISTS;
5113 cm_ReleaseSCache(tmpscp);
5114 cm_ReleaseSCache(sscp);
5115 cm_ReleaseSCache(newDscp);
5116 cm_ReleaseSCache(oldDscp);
5117 cm_ReleaseUser(userp);
5121 /* now create the hardlink */
5122 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5123 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5124 osi_Log1(smb_logp," Link returns %d", code);
5126 /* Handle Change Notification */
5128 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5129 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5130 smb_NotifyChange(FILE_ACTION_ADDED,
5131 filter, newDscp, newLastNamep,
5136 cm_ReleaseSCache(tmpscp);
5137 cm_ReleaseUser(userp);
5138 cm_ReleaseSCache(sscp);
5139 cm_ReleaseSCache(oldDscp);
5140 cm_ReleaseSCache(newDscp);
5145 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5151 tp = smb_GetSMBData(inp, NULL);
5152 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5153 if (smb_StoreAnsiFilenames)
5154 OemToChar(oldPathp,oldPathp);
5155 newPathp = smb_ParseASCIIBlock(tp, &tp);
5156 if (smb_StoreAnsiFilenames)
5157 OemToChar(newPathp,newPathp);
5159 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5160 osi_LogSaveString(smb_logp, oldPathp),
5161 osi_LogSaveString(smb_logp, newPathp));
5163 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5168 typedef struct smb_rmdirRock {
5172 char *maskp; /* pointer to the star pattern */
5177 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5180 smb_rmdirRock_t *rockp;
5185 rockp = (smb_rmdirRock_t *) vrockp;
5187 matchName = dep->name;
5188 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5189 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5191 match = (strcmp(matchName, rockp->maskp) == 0);
5193 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5194 !cm_Is8Dot3(dep->name)) {
5195 cm_Gen8Dot3Name(dep, shortName, NULL);
5196 matchName = shortName;
5197 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5200 osi_Log1(smb_logp, "Removing directory %s",
5201 osi_LogSaveString(smb_logp, matchName));
5202 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5203 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5204 smb_NotifyChange(FILE_ACTION_REMOVED,
5205 FILE_NOTIFY_CHANGE_DIR_NAME,
5206 dscp, dep->name, NULL, TRUE);
5215 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5223 smb_rmdirRock_t rock;
5232 tp = smb_GetSMBData(inp, NULL);
5233 pathp = smb_ParseASCIIBlock(tp, &tp);
5234 if (smb_StoreAnsiFilenames)
5235 OemToChar(pathp,pathp);
5237 spacep = inp->spacep;
5238 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5240 userp = smb_GetUser(vcp, inp);
5242 caseFold = CM_FLAG_CASEFOLD;
5244 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5246 cm_ReleaseUser(userp);
5247 return CM_ERROR_NOSUCHPATH;
5249 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5250 userp, tidPathp, &req, &dscp);
5253 cm_ReleaseUser(userp);
5258 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5259 cm_ReleaseSCache(dscp);
5260 cm_ReleaseUser(userp);
5261 if ( WANTS_DFS_PATHNAMES(inp) )
5262 return CM_ERROR_PATH_NOT_COVERED;
5264 return CM_ERROR_BADSHARENAME;
5266 #endif /* DFS_SUPPORT */
5268 /* otherwise, scp points to the parent directory. */
5275 rock.maskp = lastNamep;
5276 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5279 thyper.HighPart = 0;
5283 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5284 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5285 if (code == 0 && !rock.any) {
5287 thyper.HighPart = 0;
5288 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5289 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5292 cm_ReleaseUser(userp);
5294 cm_ReleaseSCache(dscp);
5296 if (code == 0 && !rock.any)
5297 code = CM_ERROR_NOSUCHFILE;
5301 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5311 fid = smb_GetSMBParm(inp, 0);
5313 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5315 fid = smb_ChainFID(fid, inp);
5316 fidp = smb_FindFID(vcp, fid, 0);
5317 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5319 smb_ReleaseFID(fidp);
5320 return CM_ERROR_BADFD;
5323 userp = smb_GetUser(vcp, inp);
5325 lock_ObtainMutex(&fidp->mx);
5326 if (fidp->flags & SMB_FID_OPENWRITE)
5327 code = cm_FSync(fidp->scp, userp, &req);
5330 lock_ReleaseMutex(&fidp->mx);
5332 smb_ReleaseFID(fidp);
5334 cm_ReleaseUser(userp);
5339 struct smb_FullNameRock {
5345 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5349 struct smb_FullNameRock *vrockp;
5351 vrockp = (struct smb_FullNameRock *)rockp;
5353 if (!cm_Is8Dot3(dep->name)) {
5354 cm_Gen8Dot3Name(dep, shortName, NULL);
5356 if (cm_stricmp(shortName, vrockp->name) == 0) {
5357 vrockp->fullName = strdup(dep->name);
5358 return CM_ERROR_STOPNOW;
5361 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5362 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5363 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5364 vrockp->fullName = strdup(dep->name);
5365 return CM_ERROR_STOPNOW;
5370 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5371 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5373 struct smb_FullNameRock rock;
5379 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5380 if (code == CM_ERROR_STOPNOW)
5381 *newPathp = rock.fullName;
5383 *newPathp = strdup(pathp);
5386 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5397 fid = smb_GetSMBParm(inp, 0);
5398 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5400 osi_Log1(smb_logp, "SMB close fid %d", fid);
5402 fid = smb_ChainFID(fid, inp);
5403 fidp = smb_FindFID(vcp, fid, 0);
5405 return CM_ERROR_BADFD;
5408 userp = smb_GetUser(vcp, inp);
5410 lock_ObtainMutex(&fidp->mx);
5412 /* Don't jump the gun on an async raw write */
5413 while (fidp->raw_writers) {
5414 lock_ReleaseMutex(&fidp->mx);
5415 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5416 lock_ObtainMutex(&fidp->mx);
5419 fidp->flags |= SMB_FID_DELETE;
5421 /* watch for ioctl closes, and read-only opens */
5422 if (fidp->scp != NULL &&
5423 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5424 == SMB_FID_OPENWRITE) {
5425 if (dosTime != 0 && dosTime != -1) {
5426 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5427 /* This fixes defect 10958 */
5428 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5429 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5431 code = cm_FSync(fidp->scp, userp, &req);
5436 /* unlock any pending locks */
5437 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5438 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5444 pid = ((smb_t *) inp)->pid;
5445 key = cm_GenerateKey(vcp->vcID, pid, fid);
5448 lock_ObtainMutex(&scp->mx);
5450 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5451 CM_SCACHESYNC_NEEDCALLBACK
5452 | CM_SCACHESYNC_GETSTATUS
5453 | CM_SCACHESYNC_LOCK);
5456 osi_Log1(smb_logp, "smb CoreClose SyncOp failure code 0x%x", tcode);
5457 goto post_syncopdone;
5460 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5462 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5466 lock_ReleaseMutex(&scp->mx);
5467 cm_ReleaseSCache(scp);
5470 if (fidp->flags & SMB_FID_DELONCLOSE) {
5471 cm_scache_t *dscp = fidp->NTopen_dscp;
5472 char *pathp = fidp->NTopen_pathp;
5475 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5476 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5477 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5478 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5479 smb_NotifyChange(FILE_ACTION_REMOVED,
5480 FILE_NOTIFY_CHANGE_DIR_NAME,
5481 dscp, fullPathp, NULL, TRUE);
5485 code = cm_Unlink(dscp, fullPathp, userp, &req);
5486 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5487 smb_NotifyChange(FILE_ACTION_REMOVED,
5488 FILE_NOTIFY_CHANGE_FILE_NAME,
5489 dscp, fullPathp, NULL, TRUE);
5493 lock_ReleaseMutex(&fidp->mx);
5495 if (fidp->flags & SMB_FID_NTOPEN) {
5496 cm_ReleaseSCache(fidp->NTopen_dscp);
5497 free(fidp->NTopen_pathp);
5499 if (fidp->NTopen_wholepathp)
5500 free(fidp->NTopen_wholepathp);
5502 smb_ReleaseFID(fidp);
5503 cm_ReleaseUser(userp);
5508 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5511 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5512 cm_user_t *userp, long *readp)
5514 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5515 cm_user_t *userp, long *readp, int dosflag)
5522 osi_hyper_t fileLength;
5524 osi_hyper_t lastByte;
5525 osi_hyper_t bufferOffset;
5526 long bufIndex, nbytes;
5536 lock_ObtainMutex(&fidp->mx);
5538 lock_ObtainMutex(&scp->mx);
5540 if (offset.HighPart == 0) {
5541 chunk = offset.LowPart >> cm_logChunkSize;
5542 if (chunk != fidp->curr_chunk) {
5543 fidp->prev_chunk = fidp->curr_chunk;
5544 fidp->curr_chunk = chunk;
5546 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5550 /* start by looking up the file's end */
5551 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5552 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5553 if (code) goto done;
5555 /* now we have the entry locked, look up the length */
5556 fileLength = scp->length;
5558 /* adjust count down so that it won't go past EOF */
5559 thyper.LowPart = count;
5560 thyper.HighPart = 0;
5561 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5563 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5564 /* we'd read past EOF, so just stop at fileLength bytes.
5565 * Start by computing how many bytes remain in the file.
5567 thyper = LargeIntegerSubtract(fileLength, offset);
5569 /* if we are past EOF, read 0 bytes */
5570 if (LargeIntegerLessThanZero(thyper))
5573 count = thyper.LowPart;
5578 /* now, copy the data one buffer at a time,
5579 * until we've filled the request packet
5582 /* if we've copied all the data requested, we're done */
5583 if (count <= 0) break;
5585 /* otherwise, load up a buffer of data */
5586 thyper.HighPart = offset.HighPart;
5587 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5588 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5591 buf_Release(bufferp);
5594 lock_ReleaseMutex(&scp->mx);
5596 lock_ObtainRead(&scp->bufCreateLock);
5597 code = buf_Get(scp, &thyper, &bufferp);
5598 lock_ReleaseRead(&scp->bufCreateLock);
5600 lock_ObtainMutex(&scp->mx);
5601 if (code) goto done;
5602 bufferOffset = thyper;
5604 /* now get the data in the cache */
5606 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5607 CM_SCACHESYNC_NEEDCALLBACK |
5608 CM_SCACHESYNC_READ);
5609 if (code) goto done;
5611 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5613 /* otherwise, load the buffer and try again */
5614 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5618 buf_Release(bufferp);
5622 } /* if (wrong buffer) ... */
5624 /* now we have the right buffer loaded. Copy out the
5625 * data from here to the user's buffer.
5627 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5629 /* and figure out how many bytes we want from this buffer */
5630 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5631 if (nbytes > count) nbytes = count; /* don't go past EOF */
5633 /* now copy the data */
5636 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5639 memcpy(op, bufferp->datap + bufIndex, nbytes);
5641 /* adjust counters, pointers, etc. */
5644 thyper.LowPart = nbytes;
5645 thyper.HighPart = 0;
5646 offset = LargeIntegerAdd(thyper, offset);
5650 lock_ReleaseMutex(&scp->mx);
5651 lock_ReleaseMutex(&fidp->mx);
5653 buf_Release(bufferp);
5655 if (code == 0 && sequential)
5656 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5662 * smb_WriteData -- common code for Write and Raw Write
5665 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5666 cm_user_t *userp, long *writtenp)
5668 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5669 cm_user_t *userp, long *writtenp, int dosflag)
5676 osi_hyper_t fileLength; /* file's length at start of write */
5677 osi_hyper_t minLength; /* don't read past this */
5678 long nbytes; /* # of bytes to transfer this iteration */
5680 osi_hyper_t thyper; /* hyper tmp variable */
5681 osi_hyper_t bufferOffset;
5682 long bufIndex; /* index in buffer where our data is */
5684 osi_hyper_t writeBackOffset;/* offset of region to write back when
5689 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5690 fidp->fid, offsetp->LowPart, count);
5700 lock_ObtainMutex(&fidp->mx);
5702 lock_ObtainMutex(&scp->mx);
5704 /* start by looking up the file's end */
5705 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5706 CM_SCACHESYNC_NEEDCALLBACK
5707 | CM_SCACHESYNC_SETSTATUS
5708 | CM_SCACHESYNC_GETSTATUS);
5712 /* make sure we have a writable FD */
5713 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5714 code = CM_ERROR_BADFDOP;
5718 /* now we have the entry locked, look up the length */
5719 fileLength = scp->length;
5720 minLength = fileLength;
5721 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5722 minLength = scp->serverLength;
5724 /* adjust file length if we extend past EOF */
5725 thyper.LowPart = count;
5726 thyper.HighPart = 0;
5727 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5728 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5729 /* we'd write past EOF, so extend the file */
5730 scp->mask |= CM_SCACHEMASK_LENGTH;
5731 scp->length = thyper;
5732 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5734 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5736 /* now, if the new position (thyper) and the old (offset) are in
5737 * different storeback windows, remember to store back the previous
5738 * storeback window when we're done with the write.
5740 if ((thyper.LowPart & (-cm_chunkSize)) !=
5741 (offset.LowPart & (-cm_chunkSize))) {
5742 /* they're different */
5744 writeBackOffset.HighPart = offset.HighPart;
5745 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5750 /* now, copy the data one buffer at a time, until we've filled the
5753 /* if we've copied all the data requested, we're done */
5757 /* handle over quota or out of space */
5758 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5759 *writtenp = written;
5760 code = CM_ERROR_QUOTA;
5764 /* otherwise, load up a buffer of data */
5765 thyper.HighPart = offset.HighPart;
5766 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5767 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5770 lock_ReleaseMutex(&bufferp->mx);
5771 buf_Release(bufferp);
5774 lock_ReleaseMutex(&scp->mx);
5776 lock_ObtainRead(&scp->bufCreateLock);
5777 code = buf_Get(scp, &thyper, &bufferp);
5778 lock_ReleaseRead(&scp->bufCreateLock);
5780 lock_ObtainMutex(&bufferp->mx);
5781 lock_ObtainMutex(&scp->mx);
5782 if (code) goto done;
5784 bufferOffset = thyper;
5786 /* now get the data in the cache */
5788 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5789 CM_SCACHESYNC_NEEDCALLBACK
5790 | CM_SCACHESYNC_WRITE
5791 | CM_SCACHESYNC_BUFLOCKED);
5795 /* If we're overwriting the entire buffer, or
5796 * if we're writing at or past EOF, mark the
5797 * buffer as current so we don't call
5798 * cm_GetBuffer. This skips the fetch from the
5799 * server in those cases where we're going to
5800 * obliterate all the data in the buffer anyway,
5801 * or in those cases where there is no useful
5802 * data at the server to start with.
5804 * Use minLength instead of scp->length, since
5805 * the latter has already been updated by this
5808 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5809 || LargeIntegerEqualTo(offset, bufferp->offset)
5810 && (count >= cm_data.buf_blockSize
5811 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5812 ConvertLongToLargeInteger(count)),
5814 if (count < cm_data.buf_blockSize
5815 && bufferp->dataVersion == -1)
5816 memset(bufferp->datap, 0,
5817 cm_data.buf_blockSize);
5818 bufferp->dataVersion = scp->dataVersion;
5821 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5823 /* otherwise, load the buffer and try again */
5824 lock_ReleaseMutex(&bufferp->mx);
5825 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5827 lock_ReleaseMutex(&scp->mx);
5828 lock_ObtainMutex(&bufferp->mx);
5829 lock_ObtainMutex(&scp->mx);
5833 lock_ReleaseMutex(&bufferp->mx);
5834 buf_Release(bufferp);
5838 } /* if (wrong buffer) ... */
5840 /* now we have the right buffer loaded. Copy out the
5841 * data from here to the user's buffer.
5843 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5845 /* and figure out how many bytes we want from this buffer */
5846 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5848 nbytes = count; /* don't go past end of request */
5850 /* now copy the data */
5853 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5856 memcpy(bufferp->datap + bufIndex, op, nbytes);
5857 buf_SetDirty(bufferp);
5859 /* and record the last writer */
5860 if (bufferp->userp != userp) {
5863 cm_ReleaseUser(bufferp->userp);
5864 bufferp->userp = userp;
5867 /* adjust counters, pointers, etc. */
5871 thyper.LowPart = nbytes;
5872 thyper.HighPart = 0;
5873 offset = LargeIntegerAdd(thyper, offset);
5877 lock_ReleaseMutex(&scp->mx);
5878 lock_ReleaseMutex(&fidp->mx);
5880 lock_ReleaseMutex(&bufferp->mx);
5881 buf_Release(bufferp);
5884 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5885 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5886 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5887 fidp->NTopen_dscp, fidp->NTopen_pathp,
5891 if (code == 0 && doWriteBack) {
5893 lock_ObtainMutex(&scp->mx);
5894 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5896 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5897 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5899 lock_ReleaseMutex(&scp->mx);
5900 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5901 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5904 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5905 fidp->fid, code, *writtenp);
5909 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5912 long count, written = 0, total_written = 0;
5918 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5920 int inDataBlockCount;
5922 fd = smb_GetSMBParm(inp, 0);
5923 count = smb_GetSMBParm(inp, 1);
5924 offset.HighPart = 0; /* too bad */
5925 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5927 op = smb_GetSMBData(inp, NULL);
5928 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5930 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5931 fd, offset.LowPart, count);
5933 fd = smb_ChainFID(fd, inp);
5934 fidp = smb_FindFID(vcp, fd, 0);
5936 return CM_ERROR_BADFD;
5939 if (fidp->flags & SMB_FID_IOCTL)
5940 return smb_IoctlWrite(fidp, vcp, inp, outp);
5942 userp = smb_GetUser(vcp, inp);
5944 /* special case: 0 bytes transferred means truncate to this position */
5950 truncAttr.mask = CM_ATTRMASK_LENGTH;
5951 truncAttr.length.LowPart = offset.LowPart;
5952 truncAttr.length.HighPart = 0;
5953 lock_ObtainMutex(&fidp->mx);
5954 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5955 lock_ReleaseMutex(&fidp->mx);
5956 smb_SetSMBParm(outp, 0, /* count */ 0);
5957 smb_SetSMBDataLength(outp, 0);
5958 fidp->flags |= SMB_FID_LENGTHSETDONE;
5964 LARGE_INTEGER LOffset;
5965 LARGE_INTEGER LLength;
5967 pid = ((smb_t *) inp)->pid;
5968 key = cm_GenerateKey(vcp->vcID, pid, fd);
5970 LOffset.HighPart = offset.HighPart;
5971 LOffset.LowPart = offset.LowPart;
5972 LLength.HighPart = 0;
5973 LLength.LowPart = count;
5975 lock_ObtainMutex(&fidp->scp->mx);
5976 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5977 lock_ReleaseMutex(&fidp->scp->mx);
5984 * Work around bug in NT client
5986 * When copying a file, the NT client should first copy the data,
5987 * then copy the last write time. But sometimes the NT client does
5988 * these in the wrong order, so the data copies would inadvertently
5989 * cause the last write time to be overwritten. We try to detect this,
5990 * and don't set client mod time if we think that would go against the
5993 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5994 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5995 fidp->scp->clientModTime = time(NULL);
5999 while ( code == 0 && count > 0 ) {
6001 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6003 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6005 if (code == 0 && written == 0)
6006 code = CM_ERROR_PARTIALWRITE;
6008 offset.LowPart += written;
6010 total_written += written;
6014 /* set the packet data length to 3 bytes for the data block header,
6015 * plus the size of the data.
6017 smb_SetSMBParm(outp, 0, total_written);
6018 smb_SetSMBDataLength(outp, 0);
6021 smb_ReleaseFID(fidp);
6022 cm_ReleaseUser(userp);
6027 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6028 NCB *ncbp, raw_write_cont_t *rwcp)
6041 fd = smb_GetSMBParm(inp, 0);
6042 fidp = smb_FindFID(vcp, fd, 0);
6044 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6045 rwcp->offset.LowPart, rwcp->count);
6047 userp = smb_GetUser(vcp, inp);
6051 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6054 rawBuf = (dos_ptr) rwcp->buf;
6055 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6056 (unsigned char *) rawBuf, userp,
6060 if (rwcp->writeMode & 0x1) { /* synchronous */
6063 smb_FormatResponsePacket(vcp, inp, outp);
6064 op = (smb_t *) outp;
6065 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6066 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6067 smb_SetSMBDataLength(outp, 0);
6068 smb_SendPacket(vcp, outp);
6069 smb_FreePacket(outp);
6071 else { /* asynchronous */
6072 lock_ObtainMutex(&fidp->mx);
6073 fidp->raw_writers--;
6074 if (fidp->raw_writers == 0)
6075 thrd_SetEvent(fidp->raw_write_event);
6076 lock_ReleaseMutex(&fidp->mx);
6079 /* Give back raw buffer */
6080 lock_ObtainMutex(&smb_RawBufLock);
6082 *((char **)rawBuf) = smb_RawBufs;
6084 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6086 smb_RawBufs = rawBuf;
6087 lock_ReleaseMutex(&smb_RawBufLock);
6089 smb_ReleaseFID(fidp);
6090 cm_ReleaseUser(userp);
6093 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6098 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6101 long count, written = 0, total_written = 0;
6108 unsigned short writeMode;
6115 fd = smb_GetSMBParm(inp, 0);
6116 totalCount = smb_GetSMBParm(inp, 1);
6117 count = smb_GetSMBParm(inp, 10);
6118 offset.HighPart = 0; /* too bad */
6119 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6120 writeMode = smb_GetSMBParm(inp, 7);
6122 op = (char *) inp->data;
6123 op += smb_GetSMBParm(inp, 11);
6126 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6127 fd, offset.LowPart, count, writeMode);
6129 fd = smb_ChainFID(fd, inp);
6130 fidp = smb_FindFID(vcp, fd, 0);
6132 return CM_ERROR_BADFD;
6138 LARGE_INTEGER LOffset;
6139 LARGE_INTEGER LLength;
6141 pid = ((smb_t *) inp)->pid;
6142 key = cm_GenerateKey(vcp->vcID, pid, fd);
6144 LOffset.HighPart = offset.HighPart;
6145 LOffset.LowPart = offset.LowPart;
6146 LLength.HighPart = 0;
6147 LLength.LowPart = count;
6149 lock_ObtainMutex(&fidp->scp->mx);
6150 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6151 lock_ReleaseMutex(&fidp->scp->mx);
6154 smb_ReleaseFID(fidp);
6159 userp = smb_GetUser(vcp, inp);
6162 * Work around bug in NT client
6164 * When copying a file, the NT client should first copy the data,
6165 * then copy the last write time. But sometimes the NT client does
6166 * these in the wrong order, so the data copies would inadvertently
6167 * cause the last write time to be overwritten. We try to detect this,
6168 * and don't set client mod time if we think that would go against the
6171 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6172 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6173 fidp->scp->clientModTime = time(NULL);
6177 while ( code == 0 && count > 0 ) {
6179 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6181 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6183 if (code == 0 && written == 0)
6184 code = CM_ERROR_PARTIALWRITE;
6186 offset.LowPart += written;
6188 total_written += written;
6192 /* Get a raw buffer */
6195 lock_ObtainMutex(&smb_RawBufLock);
6197 /* Get a raw buf, from head of list */
6198 rawBuf = smb_RawBufs;
6200 smb_RawBufs = *(char **)smb_RawBufs;
6202 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6206 code = CM_ERROR_USESTD;
6208 lock_ReleaseMutex(&smb_RawBufLock);
6211 /* Don't allow a premature Close */
6212 if (code == 0 && (writeMode & 1) == 0) {
6213 lock_ObtainMutex(&fidp->mx);
6214 fidp->raw_writers++;
6215 thrd_ResetEvent(fidp->raw_write_event);
6216 lock_ReleaseMutex(&fidp->mx);
6219 smb_ReleaseFID(fidp);
6220 cm_ReleaseUser(userp);
6223 smb_SetSMBParm(outp, 0, total_written);
6224 smb_SetSMBDataLength(outp, 0);
6225 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6232 rwcp->offset.HighPart = 0;
6233 rwcp->offset.LowPart = offset.LowPart + count;
6234 rwcp->count = totalCount - count;
6235 rwcp->writeMode = writeMode;
6236 rwcp->alreadyWritten = total_written;
6238 /* set the packet data length to 3 bytes for the data block header,
6239 * plus the size of the data.
6241 smb_SetSMBParm(outp, 0, 0xffff);
6242 smb_SetSMBDataLength(outp, 0);
6247 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6250 long count, finalCount;
6258 fd = smb_GetSMBParm(inp, 0);
6259 count = smb_GetSMBParm(inp, 1);
6260 offset.HighPart = 0; /* too bad */
6261 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6263 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6264 fd, offset.LowPart, count);
6266 fd = smb_ChainFID(fd, inp);
6267 fidp = smb_FindFID(vcp, fd, 0);
6269 return CM_ERROR_BADFD;
6272 if (fidp->flags & SMB_FID_IOCTL) {
6273 return smb_IoctlRead(fidp, vcp, inp, outp);
6277 LARGE_INTEGER LOffset, LLength;
6280 pid = ((smb_t *) inp)->pid;
6281 key = cm_GenerateKey(vcp->vcID, pid, fd);
6283 LOffset.HighPart = 0;
6284 LOffset.LowPart = offset.LowPart;
6285 LLength.HighPart = 0;
6286 LLength.LowPart = count;
6288 lock_ObtainMutex(&fidp->scp->mx);
6289 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6290 lock_ReleaseMutex(&fidp->scp->mx);
6293 smb_ReleaseFID(fidp);
6297 userp = smb_GetUser(vcp, inp);
6299 /* remember this for final results */
6300 smb_SetSMBParm(outp, 0, count);
6301 smb_SetSMBParm(outp, 1, 0);
6302 smb_SetSMBParm(outp, 2, 0);
6303 smb_SetSMBParm(outp, 3, 0);
6304 smb_SetSMBParm(outp, 4, 0);
6306 /* set the packet data length to 3 bytes for the data block header,
6307 * plus the size of the data.
6309 smb_SetSMBDataLength(outp, count+3);
6311 /* get op ptr after putting in the parms, since otherwise we don't
6312 * know where the data really is.
6314 op = smb_GetSMBData(outp, NULL);
6316 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6317 *op++ = 1; /* data block marker */
6318 *op++ = (unsigned char) (count & 0xff);
6319 *op++ = (unsigned char) ((count >> 8) & 0xff);
6322 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6324 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6327 /* fix some things up */
6328 smb_SetSMBParm(outp, 0, finalCount);
6329 smb_SetSMBDataLength(outp, finalCount+3);
6331 smb_ReleaseFID(fidp);
6333 cm_ReleaseUser(userp);
6337 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6344 cm_scache_t *dscp; /* dir we're dealing with */
6345 cm_scache_t *scp; /* file we're creating */
6347 int initialModeBits;
6357 /* compute initial mode bits based on read-only flag in attributes */
6358 initialModeBits = 0777;
6360 tp = smb_GetSMBData(inp, NULL);
6361 pathp = smb_ParseASCIIBlock(tp, &tp);
6362 if (smb_StoreAnsiFilenames)
6363 OemToChar(pathp,pathp);
6365 if (strcmp(pathp, "\\") == 0)
6366 return CM_ERROR_EXISTS;
6368 spacep = inp->spacep;
6369 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6371 userp = smb_GetUser(vcp, inp);
6373 caseFold = CM_FLAG_CASEFOLD;
6375 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6377 cm_ReleaseUser(userp);
6378 return CM_ERROR_NOSUCHPATH;
6381 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6382 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6383 userp, tidPathp, &req, &dscp);
6386 cm_ReleaseUser(userp);
6391 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6392 cm_ReleaseSCache(dscp);
6393 cm_ReleaseUser(userp);
6394 if ( WANTS_DFS_PATHNAMES(inp) )
6395 return CM_ERROR_PATH_NOT_COVERED;
6397 return CM_ERROR_BADSHARENAME;
6399 #endif /* DFS_SUPPORT */
6401 /* otherwise, scp points to the parent directory. Do a lookup, and
6402 * fail if we find it. Otherwise, we do the create.
6408 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6409 if (scp) cm_ReleaseSCache(scp);
6410 if (code != CM_ERROR_NOSUCHFILE) {
6411 if (code == 0) code = CM_ERROR_EXISTS;
6412 cm_ReleaseSCache(dscp);
6413 cm_ReleaseUser(userp);
6417 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6418 setAttr.clientModTime = time(NULL);
6419 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6420 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6421 smb_NotifyChange(FILE_ACTION_ADDED,
6422 FILE_NOTIFY_CHANGE_DIR_NAME,
6423 dscp, lastNamep, NULL, TRUE);
6425 /* we don't need this any longer */
6426 cm_ReleaseSCache(dscp);
6429 /* something went wrong creating or truncating the file */
6430 cm_ReleaseUser(userp);
6434 /* otherwise we succeeded */
6435 smb_SetSMBDataLength(outp, 0);
6436 cm_ReleaseUser(userp);
6441 BOOL smb_IsLegalFilename(char *filename)
6444 * Find the longest substring of filename that does not contain
6445 * any of the chars in illegalChars. If that substring is less
6446 * than the length of the whole string, then one or more of the
6447 * illegal chars is in filename.
6449 if (strcspn(filename, illegalChars) < strlen(filename))
6455 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6463 cm_scache_t *dscp; /* dir we're dealing with */
6464 cm_scache_t *scp; /* file we're creating */
6466 int initialModeBits;
6478 excl = (inp->inCom == 0x03)? 0 : 1;
6480 attributes = smb_GetSMBParm(inp, 0);
6481 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6483 /* compute initial mode bits based on read-only flag in attributes */
6484 initialModeBits = 0666;
6485 if (attributes & 1) initialModeBits &= ~0222;
6487 tp = smb_GetSMBData(inp, NULL);
6488 pathp = smb_ParseASCIIBlock(tp, &tp);
6489 if (smb_StoreAnsiFilenames)
6490 OemToChar(pathp,pathp);
6492 spacep = inp->spacep;
6493 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6495 userp = smb_GetUser(vcp, inp);
6497 caseFold = CM_FLAG_CASEFOLD;
6499 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6501 cm_ReleaseUser(userp);
6502 return CM_ERROR_NOSUCHPATH;
6504 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6505 userp, tidPathp, &req, &dscp);
6508 cm_ReleaseUser(userp);
6513 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6514 cm_ReleaseSCache(dscp);
6515 cm_ReleaseUser(userp);
6516 if ( WANTS_DFS_PATHNAMES(inp) )
6517 return CM_ERROR_PATH_NOT_COVERED;
6519 return CM_ERROR_BADSHARENAME;
6521 #endif /* DFS_SUPPORT */
6523 /* otherwise, scp points to the parent directory. Do a lookup, and
6524 * truncate the file if we find it, otherwise we create the file.
6531 if (!smb_IsLegalFilename(lastNamep))
6532 return CM_ERROR_BADNTFILENAME;
6534 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6535 #ifdef DEBUG_VERBOSE
6538 hexp = osi_HexifyString( lastNamep );
6539 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6544 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6545 if (code && code != CM_ERROR_NOSUCHFILE) {
6546 cm_ReleaseSCache(dscp);
6547 cm_ReleaseUser(userp);
6551 /* if we get here, if code is 0, the file exists and is represented by
6552 * scp. Otherwise, we have to create it.
6556 /* oops, file shouldn't be there */
6557 cm_ReleaseSCache(dscp);
6558 cm_ReleaseSCache(scp);
6559 cm_ReleaseUser(userp);
6560 return CM_ERROR_EXISTS;
6563 setAttr.mask = CM_ATTRMASK_LENGTH;
6564 setAttr.length.LowPart = 0;
6565 setAttr.length.HighPart = 0;
6566 code = cm_SetAttr(scp, &setAttr, userp, &req);
6569 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6570 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6571 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6573 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6574 smb_NotifyChange(FILE_ACTION_ADDED,
6575 FILE_NOTIFY_CHANGE_FILE_NAME,
6576 dscp, lastNamep, NULL, TRUE);
6577 if (!excl && code == CM_ERROR_EXISTS) {
6578 /* not an exclusive create, and someone else tried
6579 * creating it already, then we open it anyway. We
6580 * don't bother retrying after this, since if this next
6581 * fails, that means that the file was deleted after
6582 * we started this call.
6584 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6587 setAttr.mask = CM_ATTRMASK_LENGTH;
6588 setAttr.length.LowPart = 0;
6589 setAttr.length.HighPart = 0;
6590 code = cm_SetAttr(scp, &setAttr, userp, &req);
6595 /* we don't need this any longer */
6596 cm_ReleaseSCache(dscp);
6599 /* something went wrong creating or truncating the file */
6600 if (scp) cm_ReleaseSCache(scp);
6601 cm_ReleaseUser(userp);
6605 /* make sure we only open files */
6606 if (scp->fileType != CM_SCACHETYPE_FILE) {
6607 cm_ReleaseSCache(scp);
6608 cm_ReleaseUser(userp);
6609 return CM_ERROR_ISDIR;
6612 /* now all we have to do is open the file itself */
6613 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6616 /* save a pointer to the vnode */
6619 /* always create it open for read/write */
6620 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6622 smb_ReleaseFID(fidp);
6624 smb_SetSMBParm(outp, 0, fidp->fid);
6625 smb_SetSMBDataLength(outp, 0);
6627 cm_Open(scp, 0, userp);
6629 cm_ReleaseUser(userp);
6630 /* leave scp held since we put it in fidp->scp */
6634 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6647 fd = smb_GetSMBParm(inp, 0);
6648 whence = smb_GetSMBParm(inp, 1);
6649 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6651 /* try to find the file descriptor */
6652 fd = smb_ChainFID(fd, inp);
6653 fidp = smb_FindFID(vcp, fd, 0);
6654 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6655 return CM_ERROR_BADFD;
6658 userp = smb_GetUser(vcp, inp);
6660 lock_ObtainMutex(&fidp->mx);
6662 lock_ObtainMutex(&scp->mx);
6663 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6664 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6667 /* offset from current offset */
6668 offset += fidp->offset;
6670 else if (whence == 2) {
6671 /* offset from current EOF */
6672 offset += scp->length.LowPart;
6674 fidp->offset = offset;
6675 smb_SetSMBParm(outp, 0, offset & 0xffff);
6676 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6677 smb_SetSMBDataLength(outp, 0);
6679 lock_ReleaseMutex(&scp->mx);
6680 lock_ReleaseMutex(&fidp->mx);
6681 smb_ReleaseFID(fidp);
6682 cm_ReleaseUser(userp);
6686 /* dispatch all of the requests received in a packet. Due to chaining, this may
6687 * be more than one request.
6689 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6690 NCB *ncbp, raw_write_cont_t *rwcp)
6694 unsigned long code = 0;
6695 unsigned char *outWctp;
6696 int nparms; /* # of bytes of parameters */
6698 int nbytes; /* bytes of data, excluding count */
6701 unsigned short errCode;
6702 unsigned long NTStatus;
6704 unsigned char errClass;
6705 unsigned int oldGen;
6706 DWORD oldTime, newTime;
6708 /* get easy pointer to the data */
6709 smbp = (smb_t *) inp->data;
6711 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6712 /* setup the basic parms for the initial request in the packet */
6713 inp->inCom = smbp->com;
6714 inp->wctp = &smbp->wct;
6716 inp->ncb_length = ncbp->ncb_length;
6721 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6722 /* log it and discard it */
6727 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6728 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6730 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6731 1, ncbp->ncb_length, ptbuf, inp);
6732 DeregisterEventSource(h);
6734 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6739 /* We are an ongoing op */
6740 thrd_Increment(&ongoingOps);
6742 /* set up response packet for receiving output */
6743 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6744 smb_FormatResponsePacket(vcp, inp, outp);
6745 outWctp = outp->wctp;
6747 /* Remember session generation number and time */
6748 oldGen = sessionGen;
6749 oldTime = GetCurrentTime();
6751 while (inp->inCom != 0xff) {
6752 dp = &smb_dispatchTable[inp->inCom];
6754 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6755 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6756 code = outp->resumeCode;
6760 /* process each request in the packet; inCom, wctp and inCount
6761 * are already set up.
6763 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6766 /* now do the dispatch */
6767 /* start by formatting the response record a little, as a default */
6768 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6770 outWctp[1] = 0xff; /* no operation */
6771 outWctp[2] = 0; /* padding */
6776 /* not a chained request, this is a more reasonable default */
6777 outWctp[0] = 0; /* wct of zero */
6778 outWctp[1] = 0; /* and bcc (word) of zero */
6782 /* once set, stays set. Doesn't matter, since we never chain
6783 * "no response" calls.
6785 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6789 /* we have a recognized operation */
6791 if (inp->inCom == 0x1d)
6793 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6796 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%x lana %d lsn %d",(int)vcp,vcp->lana,vcp->lsn);
6797 osi_Log4(smb_logp,"Dispatch %s vcp 0x%x lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6798 code = (*(dp->procp)) (vcp, inp, outp);
6799 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",(code==0)?0:code-CM_ERROR_BASE);
6800 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%x lana %d lsn %d",(code==0)?0:code-CM_ERROR_BASE,vcp,vcp->lana,vcp->lsn);
6802 if ( code == CM_ERROR_BADSMB ||
6803 code == CM_ERROR_BADOP )
6805 #endif /* LOG_PACKET */
6808 if (oldGen != sessionGen) {
6813 newTime = GetCurrentTime();
6814 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6815 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6816 newTime - oldTime, ncbp->ncb_length);
6818 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6819 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6820 DeregisterEventSource(h);
6822 osi_Log1(smb_logp, "Pkt straddled session startup, "
6823 "ncb length %d", ncbp->ncb_length);
6827 /* bad opcode, fail the request, after displaying it */
6828 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6831 #endif /* LOG_PACKET */
6835 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6836 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6837 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6838 if (code == IDCANCEL)
6842 code = CM_ERROR_BADOP;
6845 /* catastrophic failure: log as much as possible */
6846 if (code == CM_ERROR_BADSMB) {
6853 "Invalid SMB, ncb_length %d",
6856 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6857 sprintf(s, "Invalid SMB message, length %d",
6860 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6861 1, ncbp->ncb_length, ptbuf, smbp);
6862 DeregisterEventSource(h);
6865 #endif /* LOG_PACKET */
6867 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6870 code = CM_ERROR_INVAL;
6873 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6874 thrd_Decrement(&ongoingOps);
6879 /* now, if we failed, turn the current response into an empty
6880 * one, and fill in the response packet's error code.
6883 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6884 smb_MapNTError(code, &NTStatus);
6885 outWctp = outp->wctp;
6886 smbp = (smb_t *) &outp->data;
6887 if (code != CM_ERROR_PARTIALWRITE
6888 && code != CM_ERROR_BUFFERTOOSMALL
6889 && code != CM_ERROR_GSSCONTINUE) {
6890 /* nuke wct and bcc. For a partial
6891 * write or an in-process authentication handshake,
6892 * assume they're OK.
6898 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6899 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6900 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6901 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6902 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6906 smb_MapCoreError(code, vcp, &errCode, &errClass);
6907 outWctp = outp->wctp;
6908 smbp = (smb_t *) &outp->data;
6909 if (code != CM_ERROR_PARTIALWRITE) {
6910 /* nuke wct and bcc. For a partial
6911 * write, assume they're OK.
6917 smbp->errLow = (unsigned char) (errCode & 0xff);
6918 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6919 smbp->rcls = errClass;
6922 } /* error occurred */
6924 /* if we're here, we've finished one request. Look to see if
6925 * this is a chained opcode. If it is, setup things to process
6926 * the chained request, and setup the output buffer to hold the
6927 * chained response. Start by finding the next input record.
6929 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6930 break; /* not a chained req */
6931 tp = inp->wctp; /* points to start of last request */
6932 /* in a chained request, the first two
6933 * parm fields are required, and are
6934 * AndXCommand/AndXReserved and
6936 if (tp[0] < 2) break;
6937 if (tp[1] == 0xff) break; /* no more chained opcodes */
6939 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6942 /* and now append the next output request to the end of this
6943 * last request. Begin by finding out where the last response
6944 * ends, since that's where we'll put our new response.
6946 outWctp = outp->wctp; /* ptr to out parameters */
6947 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6948 nparms = outWctp[0] << 1;
6949 tp = outWctp + nparms + 1; /* now points to bcc field */
6950 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6951 tp += 2 /* for the count itself */ + nbytes;
6952 /* tp now points to the new output record; go back and patch the
6953 * second parameter (off2) to point to the new record.
6955 temp = (unsigned int)tp - ((unsigned int) outp->data);
6956 outWctp[3] = (unsigned char) (temp & 0xff);
6957 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6958 outWctp[2] = 0; /* padding */
6959 outWctp[1] = inp->inCom; /* next opcode */
6961 /* finally, setup for the next iteration */
6964 } /* while loop over all requests in the packet */
6966 /* done logging out, turn off logging-out flag */
6967 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6968 vcp->justLoggedOut = NULL;
6971 free(loggedOutName);
6972 loggedOutName = NULL;
6973 smb_ReleaseUID(loggedOutUserp);
6974 loggedOutUserp = NULL;
6978 /* now send the output packet, and return */
6980 smb_SendPacket(vcp, outp);
6981 thrd_Decrement(&ongoingOps);
6983 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6984 if (active_vcp != vcp) {
6986 smb_ReleaseVC(active_vcp);
6988 "Replacing active_vcp %x with %x", active_vcp, vcp);
6993 last_msg_time = GetCurrentTime();
6994 } else if (active_vcp == vcp) {
6995 smb_ReleaseVC(active_vcp);
7003 /* Wait for Netbios() calls to return, and make the results available to server
7004 * threads. Note that server threads can't wait on the NCBevents array
7005 * themselves, because NCB events are manual-reset, and the servers would race
7006 * each other to reset them.
7008 void smb_ClientWaiter(void *parmp)
7013 while (smbShutdownFlag == 0) {
7014 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7016 if (code == WAIT_OBJECT_0)
7019 /* error checking */
7020 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7022 int abandonIdx = code - WAIT_ABANDONED_0;
7023 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7026 if (code == WAIT_IO_COMPLETION)
7028 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7032 if (code == WAIT_TIMEOUT)
7034 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7037 if (code == WAIT_FAILED)
7039 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7042 idx = code - WAIT_OBJECT_0;
7044 /* check idx range! */
7045 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7047 /* this is fatal - log as much as possible */
7048 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7052 thrd_ResetEvent(NCBevents[idx]);
7053 thrd_SetEvent(NCBreturns[0][idx]);
7059 * Try to have one NCBRECV request waiting for every live session. Not more
7060 * than one, because if there is more than one, it's hard to handle Write Raw.
7062 void smb_ServerWaiter(void *parmp)
7065 int idx_session, idx_NCB;
7071 while (smbShutdownFlag == 0) {
7073 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7075 if (code == WAIT_OBJECT_0)
7078 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7080 int abandonIdx = code - WAIT_ABANDONED_0;
7081 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7084 if (code == WAIT_IO_COMPLETION)
7086 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7090 if (code == WAIT_TIMEOUT)
7092 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7095 if (code == WAIT_FAILED)
7097 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7100 idx_session = code - WAIT_OBJECT_0;
7102 /* check idx range! */
7103 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7105 /* this is fatal - log as much as possible */
7106 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7112 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7114 if (code == WAIT_OBJECT_0) {
7115 if (smbShutdownFlag == 1)
7121 /* error checking */
7122 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7124 int abandonIdx = code - WAIT_ABANDONED_0;
7125 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7128 if (code == WAIT_IO_COMPLETION)
7130 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7134 if (code == WAIT_TIMEOUT)
7136 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7139 if (code == WAIT_FAILED)
7141 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7144 idx_NCB = code - WAIT_OBJECT_0;
7146 /* check idx range! */
7147 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7149 /* this is fatal - log as much as possible */
7150 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7154 /* Link them together */
7155 NCBsessions[idx_NCB] = idx_session;
7158 ncbp = NCBs[idx_NCB];
7159 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7160 ncbp->ncb_command = NCBRECV | ASYNCH;
7161 ncbp->ncb_lana_num = lanas[idx_session];
7163 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7164 ncbp->ncb_event = NCBevents[idx_NCB];
7165 ncbp->ncb_length = SMB_PACKETSIZE;
7168 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7169 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7170 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7171 ncbp->ncb_length = SMB_PACKETSIZE;
7172 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7173 Netbios(ncbp, dos_ncb);
7179 * The top level loop for handling SMB request messages. Each server thread
7180 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7181 * NCB and buffer for the incoming request are loaned to us.
7183 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7184 * to immediately send a request for the rest of the data. This must come
7185 * before any other traffic for that session, so we delay setting the session
7186 * event until that data has come in.
7188 void smb_Server(VOID *parmp)
7190 int myIdx = (int) parmp;
7194 smb_packet_t *outbufp;
7196 int idx_NCB, idx_session;
7198 smb_vc_t *vcp = NULL;
7204 rx_StartClientThread();
7207 outbufp = GetPacket();
7208 outbufp->ncbp = outncbp;
7211 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7214 /* terminate silently if shutdown flag is set */
7215 if (code == WAIT_OBJECT_0) {
7216 if (smbShutdownFlag == 1) {
7217 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7223 /* error checking */
7224 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7226 int abandonIdx = code - WAIT_ABANDONED_0;
7227 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7230 if (code == WAIT_IO_COMPLETION)
7232 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7236 if (code == WAIT_TIMEOUT)
7238 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7241 if (code == WAIT_FAILED)
7243 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7246 idx_NCB = code - WAIT_OBJECT_0;
7248 /* check idx range! */
7249 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7251 /* this is fatal - log as much as possible */
7252 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7256 ncbp = NCBs[idx_NCB];
7258 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7260 idx_session = NCBsessions[idx_NCB];
7261 rc = ncbp->ncb_retcode;
7263 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7266 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7269 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7272 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7275 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7278 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7281 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7284 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7287 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7290 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7293 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7296 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7299 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7302 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7305 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7308 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7311 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7314 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7317 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7320 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7323 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7326 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7329 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7332 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7335 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7338 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7341 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7344 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7347 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7350 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7353 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7356 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7359 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7362 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7365 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7368 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7371 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7374 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7377 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7387 /* Can this happen? Or is it just my UNIX paranoia? */
7388 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7393 /* Client closed session */
7394 dead_sessions[idx_session] = TRUE;
7397 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7398 /* Should also release vcp. [done] 2004-05-11 jaltman
7400 * sanity check that all TID's are gone.
7402 * TODO: check if we could use LSNs[idx_session] instead,
7403 * also cleanup after dead vcp
7406 if (dead_vcp == vcp)
7407 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7408 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7409 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7413 smb_ReleaseVC(dead_vcp);
7415 "Previous dead_vcp %x", dead_vcp);
7418 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7420 if (vcp->justLoggedOut) {
7422 loggedOutTime = vcp->logoffTime;
7423 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7424 loggedOutUserp = vcp->justLoggedOut;
7425 lock_ObtainWrite(&smb_rctLock);
7426 loggedOutUserp->refCount++;
7427 lock_ReleaseWrite(&smb_rctLock);
7433 /* Treat as transient error */
7440 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7441 sprintf(s, "SMB message incomplete, length %d",
7444 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7446 ncbp->ncb_length, ptbuf,
7448 DeregisterEventSource(h);
7451 "dispatch smb recv failed, message incomplete, ncb_length %d",
7454 "SMB message incomplete, "
7455 "length %d", ncbp->ncb_length);
7458 * We used to discard the packet.
7459 * Instead, try handling it normally.
7467 /* A weird error code. Log it, sleep, and
7469 if (vcp && vcp->errorCount++ > 3) {
7470 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7471 dead_sessions[idx_session] = TRUE;
7475 thrd_SetEvent(SessionEvents[idx_session]);
7480 /* Success, so now dispatch on all the data in the packet */
7482 smb_concurrentCalls++;
7483 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7484 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7488 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7490 * If at this point vcp is NULL (implies that packet was invalid)
7491 * then we are in big trouble. This means either :
7492 * a) we have the wrong NCB.
7493 * b) Netbios screwed up the call.
7494 * Obviously this implies that
7495 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7496 * lanas[idx_session] != ncbp->ncb_lana_num )
7497 * Either way, we can't do anything with this packet.
7498 * Log, sleep and resume.
7507 "LSNs[idx_session]=[%d],"
7508 "lanas[idx_session]=[%d],"
7509 "ncbp->ncb_lsn=[%d],"
7510 "ncbp->ncb_lana_num=[%d]",
7514 ncbp->ncb_lana_num);
7518 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7520 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7521 DeregisterEventSource(h);
7524 /* Also log in the trace log. */
7525 osi_Log4(smb_logp, "Server: BAD VCP!"
7526 "LSNs[idx_session]=[%d],"
7527 "lanas[idx_session]=[%d],"
7528 "ncbp->ncb_lsn=[%d],"
7529 "ncbp->ncb_lana_num=[%d]",
7533 ncbp->ncb_lana_num);
7535 /* thrd_Sleep(1000); Don't bother sleeping */
7536 thrd_SetEvent(SessionEvents[idx_session]);
7537 smb_concurrentCalls--;
7542 vcp->errorCount = 0;
7543 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7545 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7546 /* copy whole packet to virtual memory */
7547 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7549 bufp->dos_pkt / 16, bufp);*/
7551 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7553 smbp = (smb_t *)bufp->data;
7556 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7560 if (smbp->com == 0x1d) {
7561 /* Special handling for Write Raw */
7562 raw_write_cont_t rwc;
7563 EVENT_HANDLE rwevent;
7564 char eventName[MAX_PATH];
7566 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7567 if (rwc.code == 0) {
7568 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7569 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7570 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7571 ncbp->ncb_command = NCBRECV | ASYNCH;
7572 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7573 ncbp->ncb_lana_num = vcp->lana;
7574 ncbp->ncb_buffer = rwc.buf;
7575 ncbp->ncb_length = 65535;
7576 ncbp->ncb_event = rwevent;
7580 Netbios(ncbp, dos_ncb);
7582 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7583 thrd_CloseHandle(rwevent);
7585 thrd_SetEvent(SessionEvents[idx_session]);
7587 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7589 else if (smbp->com == 0xa0) {
7591 * Serialize the handling for NT Transact
7594 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7595 thrd_SetEvent(SessionEvents[idx_session]);
7597 thrd_SetEvent(SessionEvents[idx_session]);
7598 /* TODO: what else needs to be serialized? */
7599 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7601 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7603 __except( smb_ServerExceptionFilter() ) {
7607 smb_concurrentCalls--;
7610 thrd_SetEvent(NCBavails[idx_NCB]);
7617 * Exception filter for the server threads. If an exception occurs in the
7618 * dispatch routines, which is where exceptions are most common, then do a
7619 * force trace and give control to upstream exception handlers. Useful for
7622 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7623 DWORD smb_ServerExceptionFilter(void) {
7624 /* While this is not the best time to do a trace, if it succeeds, then
7625 * we have a trace (assuming tracing was enabled). Otherwise, this should
7626 * throw a second exception.
7631 ptbuf[0] = "Unhandled exception forcing trace";
7633 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7635 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7636 DeregisterEventSource(h);
7639 afsd_ForceTrace(TRUE);
7640 buf_ForceTrace(TRUE);
7641 return EXCEPTION_CONTINUE_SEARCH;
7646 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7647 * If the number of server threads is M, and the number of live sessions is
7648 * N, then the number of NCB's in use at any time either waiting for, or
7649 * holding, received messages is M + N, so that is how many NCB's get created.
7651 void InitNCBslot(int idx)
7653 struct smb_packet *bufp;
7654 EVENT_HANDLE retHandle;
7656 char eventName[MAX_PATH];
7658 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7660 NCBs[idx] = GetNCB();
7661 sprintf(eventName,"NCBavails[%d]", idx);
7662 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7663 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7664 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7666 sprintf(eventName,"NCBevents[%d]", idx);
7667 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7668 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7669 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7671 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7672 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7673 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7674 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7675 for (i=0; i<smb_NumServerThreads; i++)
7676 NCBreturns[i][idx] = retHandle;
7678 bufp->spacep = cm_GetSpace();
7682 /* listen for new connections */
7683 void smb_Listener(void *parmp)
7691 char rname[NCBNAMSZ+1];
7692 char cname[MAX_COMPUTERNAME_LENGTH+1];
7693 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7698 int lana = (int) parmp;
7702 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7705 /* retrieve computer name */
7706 GetComputerName(cname, &cnamelen);
7710 memset(ncbp, 0, sizeof(NCB));
7713 ncbp->ncb_command = NCBLISTEN;
7714 ncbp->ncb_rto = 0; /* No receive timeout */
7715 ncbp->ncb_sto = 0; /* No send timeout */
7717 /* pad out with spaces instead of null termination */
7718 len = strlen(smb_localNamep);
7719 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7720 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7722 strcpy(ncbp->ncb_callname, "*");
7723 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7725 ncbp->ncb_lana_num = lana;
7728 code = Netbios(ncbp);
7730 code = Netbios(ncbp, dos_ncb);
7739 /* terminate silently if shutdown flag is set */
7740 if (smbShutdownFlag == 1) {
7749 "NCBLISTEN lana=%d failed with code %d",
7750 ncbp->ncb_lana_num, code);
7752 "Client exiting due to network failure. Please restart client.\n");
7756 "Client exiting due to network failure. Please restart client.\n"
7757 "NCBLISTEN lana=%d failed with code %d",
7758 ncbp->ncb_lana_num, code);
7760 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7761 MB_OK|MB_SERVICE_NOTIFICATION);
7762 osi_assert(tbuffer);
7765 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7766 ncbp->ncb_lana_num, code);
7767 fprintf(stderr, "\nClient exiting due to network failure "
7768 "(possibly due to power-saving mode)\n");
7769 fprintf(stderr, "Please restart client.\n");
7770 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7774 /* check for remote conns */
7775 /* first get remote name and insert null terminator */
7776 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7777 for (i=NCBNAMSZ; i>0; i--) {
7778 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7784 /* compare with local name */
7786 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7787 flags |= SMB_VCFLAG_REMOTECONN;
7789 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7791 lock_ObtainMutex(&smb_ListenerLock);
7793 /* New generation */
7796 /* Log session startup */
7798 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7800 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7801 #endif /* NOTSERVICE */
7802 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7803 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7805 if (reportSessionStartups) {
7811 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7812 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7814 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7816 DeregisterEventSource(h);
7819 fprintf(stderr, "%s: New session %d starting from host %s\n",
7820 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7824 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7825 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7828 /* now ncbp->ncb_lsn is the connection ID */
7829 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7830 vcp->flags |= flags;
7831 strcpy(vcp->rname, rname);
7833 /* Allocate slot in session arrays */
7834 /* Re-use dead session if possible, otherwise add one more */
7835 /* But don't look at session[0], it is reserved */
7836 for (i = 1; i < numSessions; i++) {
7837 if (dead_sessions[i]) {
7838 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7839 dead_sessions[i] = FALSE;
7844 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7845 unsigned long code = CM_ERROR_ALLBUSY;
7846 smb_packet_t * outp = GetPacket();
7847 unsigned char *outWctp;
7852 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7853 unsigned long NTStatus;
7854 smb_MapNTError(code, &NTStatus);
7855 outWctp = outp->wctp;
7856 smbp = (smb_t *) &outp->data;
7860 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7861 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7862 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7863 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7864 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7866 unsigned short errCode;
7867 unsigned char errClass;
7868 smb_MapCoreError(code, vcp, &errCode, &errClass);
7869 outWctp = outp->wctp;
7870 smbp = (smb_t *) &outp->data;
7874 smbp->errLow = (unsigned char) (errCode & 0xff);
7875 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7876 smbp->rcls = errClass;
7878 smb_SendPacket(vcp, outp);
7879 smb_FreePacket(outp);
7881 /* assert that we do not exceed the maximum number of sessions or NCBs.
7882 * we should probably want to wait for a session to be freed in case
7885 osi_assert(i < Sessionmax - 1);
7886 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7888 LSNs[i] = ncbp->ncb_lsn;
7889 lanas[i] = ncbp->ncb_lana_num;
7891 if (i == numSessions) {
7892 /* Add new NCB for new session */
7893 char eventName[MAX_PATH];
7895 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7897 InitNCBslot(numNCBs);
7899 thrd_SetEvent(NCBavails[0]);
7900 thrd_SetEvent(NCBevents[0]);
7901 for (j = 0; j < smb_NumServerThreads; j++)
7902 thrd_SetEvent(NCBreturns[j][0]);
7903 /* Also add new session event */
7904 sprintf(eventName, "SessionEvents[%d]", i);
7905 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7906 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7907 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7909 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7910 thrd_SetEvent(SessionEvents[0]);
7912 thrd_SetEvent(SessionEvents[i]);
7919 lock_ReleaseMutex(&smb_ListenerLock);
7920 } /* dispatch while loop */
7923 /* initialize Netbios */
7924 void smb_NetbiosInit()
7930 int i, lana, code, l;
7932 int delname_tried=0;
7935 OSVERSIONINFO Version;
7937 /* Get the version of Windows */
7938 memset(&Version, 0x00, sizeof(Version));
7939 Version.dwOSVersionInfoSize = sizeof(Version);
7940 GetVersionEx(&Version);
7942 /* setup the NCB system */
7945 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7949 if (smb_LANadapter == -1) {
7950 ncbp->ncb_command = NCBENUM;
7951 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7952 ncbp->ncb_length = sizeof(lana_list);
7953 code = Netbios(ncbp);
7955 afsi_log("Netbios NCBENUM error code %d", code);
7956 osi_panic(s, __FILE__, __LINE__);
7960 lana_list.length = 1;
7961 lana_list.lana[0] = smb_LANadapter;
7964 for (i = 0; i < lana_list.length; i++) {
7965 /* reset the adaptor: in Win32, this is required for every process, and
7966 * acts as an init call, not as a real hardware reset.
7968 ncbp->ncb_command = NCBRESET;
7969 ncbp->ncb_callname[0] = 100;
7970 ncbp->ncb_callname[2] = 100;
7971 ncbp->ncb_lana_num = lana_list.lana[i];
7972 code = Netbios(ncbp);
7974 code = ncbp->ncb_retcode;
7976 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7977 lana_list.lana[i] = 255; /* invalid lana */
7979 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7983 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7984 we will just fake the LANA list */
7985 if (smb_LANadapter == -1) {
7986 for (i = 0; i < 8; i++)
7987 lana_list.lana[i] = i;
7988 lana_list.length = 8;
7991 lana_list.length = 1;
7992 lana_list.lana[0] = smb_LANadapter;
7996 /* and declare our name so we can receive connections */
7997 memset(ncbp, 0, sizeof(*ncbp));
7998 len=lstrlen(smb_localNamep);
7999 memset(smb_sharename,' ',NCBNAMSZ);
8000 memcpy(smb_sharename,smb_localNamep,len);
8001 afsi_log("lana_list.length %d", lana_list.length);
8003 /* Keep the name so we can unregister it later */
8004 for (l = 0; l < lana_list.length; l++) {
8005 lana = lana_list.lana[l];
8007 ncbp->ncb_command = NCBADDNAME;
8008 ncbp->ncb_lana_num = lana;
8009 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8011 code = Netbios(ncbp);
8013 code = Netbios(ncbp, dos_ncb);
8016 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8017 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8019 char name[NCBNAMSZ+1];
8021 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8022 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8025 if (code == 0) code = ncbp->ncb_retcode;
8027 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8029 /* we only use one LANA with djgpp */
8030 lana_list.lana[0] = lana;
8031 lana_list.length = 1;
8035 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8036 if (code == NRC_BRIDGE) { /* invalid LANA num */
8037 lana_list.lana[l] = 255;
8040 else if (code == NRC_DUPNAME) {
8041 afsi_log("Name already exists; try to delete it");
8042 memset(ncbp, 0, sizeof(*ncbp));
8043 ncbp->ncb_command = NCBDELNAME;
8044 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8045 ncbp->ncb_lana_num = lana;
8047 code = Netbios(ncbp);
8049 code = Netbios(ncbp, dos_ncb);
8052 code = ncbp->ncb_retcode;
8054 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8056 if (code != 0 || delname_tried) {
8057 lana_list.lana[l] = 255;
8059 else if (code == 0) {
8060 if (!delname_tried) {
8068 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8069 lana_list.lana[l] = 255; /* invalid lana */
8070 osi_panic(s, __FILE__, __LINE__);
8074 lana_found = 1; /* at least one worked */
8081 osi_assert(lana_list.length >= 0);
8083 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8086 /* we're done with the NCB now */
8090 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8107 EVENT_HANDLE retHandle;
8108 char eventName[MAX_PATH];
8111 smb_MBfunc = aMBfunc;
8115 smb_LANadapter = LANadapt;
8117 /* Initialize smb_localZero */
8118 myTime.tm_isdst = -1; /* compute whether on DST or not */
8119 myTime.tm_year = 70;
8125 smb_localZero = mktime(&myTime);
8127 #ifndef USE_NUMERIC_TIME_CONV
8128 /* Initialize kludge-GMT */
8129 smb_CalculateNowTZ();
8130 #endif /* USE_NUMERIC_TIME_CONV */
8131 #ifdef AFS_FREELANCE_CLIENT
8132 /* Make sure the root.afs volume has the correct time */
8133 cm_noteLocalMountPointChange();
8136 /* initialize the remote debugging log */
8139 /* remember the name */
8140 len = strlen(snamep);
8141 smb_localNamep = malloc(len+1);
8142 strcpy(smb_localNamep, snamep);
8143 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8145 /* and the global lock */
8146 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8147 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8149 /* Raw I/O data structures */
8150 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8152 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8154 /* 4 Raw I/O buffers */
8156 smb_RawBufs = calloc(65536,1);
8157 *((char **)smb_RawBufs) = NULL;
8158 for (i=0; i<3; i++) {
8159 char *rawBuf = calloc(65536,1);
8160 *((char **)rawBuf) = smb_RawBufs;
8161 smb_RawBufs = rawBuf;
8164 npar = 65536 >> 4; /* number of paragraphs */
8165 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8167 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8169 osi_panic("",__FILE__,__LINE__);
8172 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8175 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8177 _farpokel(_dos_ds, smb_RawBufs, NULL);
8178 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8179 npar = 65536 >> 4; /* number of paragraphs */
8180 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8182 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8184 osi_panic("",__FILE__,__LINE__);
8187 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8190 rawBuf = (seg * 16) + 0; /* DOS physical address */
8191 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8192 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8193 smb_RawBufs = rawBuf;
8197 /* global free lists */
8198 smb_ncbFreeListp = NULL;
8199 smb_packetFreeListp = NULL;
8203 /* Initialize listener and server structures */
8205 memset(dead_sessions, 0, sizeof(dead_sessions));
8206 sprintf(eventName, "SessionEvents[0]");
8207 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8208 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8209 afsi_log("Event Object Already Exists: %s", eventName);
8211 smb_NumServerThreads = nThreads;
8212 sprintf(eventName, "NCBavails[0]");
8213 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8214 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8215 afsi_log("Event Object Already Exists: %s", eventName);
8216 sprintf(eventName, "NCBevents[0]");
8217 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8218 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8219 afsi_log("Event Object Already Exists: %s", eventName);
8220 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8221 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8222 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8223 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8224 afsi_log("Event Object Already Exists: %s", eventName);
8225 for (i = 0; i < smb_NumServerThreads; i++) {
8226 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8227 NCBreturns[i][0] = retHandle;
8230 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8231 for (i = 0; i < smb_NumServerThreads; i++) {
8232 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8233 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8234 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8235 afsi_log("Event Object Already Exists: %s", eventName);
8238 numNCBs = smb_NumServerThreads + 1;
8240 /* Initialize dispatch table */
8241 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8242 /* Prepare the table for unknown operations */
8243 for(i=0; i<= SMB_NOPCODES; i++) {
8244 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8246 /* Fill in the ones we do know */
8247 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8248 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8249 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8250 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8251 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8252 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8253 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8254 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8255 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8256 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8257 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8258 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8259 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8260 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8261 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8262 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8263 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8264 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8265 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8266 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8267 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8268 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8269 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8270 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8271 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8272 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8273 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8274 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8275 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8276 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8277 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8278 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8279 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8280 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8281 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8282 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8283 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8284 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8285 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8286 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8287 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8288 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8289 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8290 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8291 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8292 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8293 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8294 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8295 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8296 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8297 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8298 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8299 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8300 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8301 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8302 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8303 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8304 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8305 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8306 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8307 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8308 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8309 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8310 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8311 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8312 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8313 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8314 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8315 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8316 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8317 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8318 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8320 /* setup tran 2 dispatch table */
8321 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8322 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8323 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8324 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8325 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8326 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8327 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8328 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8329 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8330 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8331 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8332 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8333 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8334 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8335 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8336 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8337 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8339 /* setup the rap dispatch table */
8340 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8341 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8342 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8343 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8344 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8348 /* if we are doing SMB authentication we have register outselves as a logon process */
8349 if (smb_authType != SMB_AUTH_NONE) {
8350 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8351 LSA_STRING afsProcessName;
8352 LSA_OPERATIONAL_MODE dummy; /*junk*/
8354 afsProcessName.Buffer = "OpenAFSClientDaemon";
8355 afsProcessName.Length = strlen(afsProcessName.Buffer);
8356 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8358 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8360 if (nts == STATUS_SUCCESS) {
8361 LSA_STRING packageName;
8362 /* we are registered. Find out the security package id */
8363 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8364 packageName.Length = strlen(packageName.Buffer);
8365 packageName.MaximumLength = packageName.Length + 1;
8366 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8367 if (nts == STATUS_SUCCESS) {
8369 * This code forces Windows to authenticate against the Logon Cache
8370 * first instead of attempting to authenticate against the Domain
8371 * Controller. When the Windows logon cache is enabled this improves
8372 * performance by removing the network access and works around a bug
8373 * seen at sites which are using a MIT Kerberos principal to login
8374 * to machines joined to a non-root domain in a multi-domain forest.
8376 PVOID pResponse = NULL;
8377 ULONG cbResponse = 0;
8378 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8380 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8381 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8382 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8383 OptionsRequest.DisableOptions = FALSE;
8385 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8388 sizeof(OptionsRequest),
8394 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8396 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8398 OutputDebugString(message);
8401 OutputDebugString("MsV1_0SetProcessOption success");
8402 afsi_log("MsV1_0SetProcessOption success");
8404 /* END - code from Larry */
8406 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8407 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8408 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8410 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8412 /* something went wrong. We report the error and revert back to no authentication
8413 because we can't perform any auth requests without a successful lsa handle
8414 or sec package id. */
8415 afsi_log("Reverting to NO SMB AUTH");
8416 smb_authType = SMB_AUTH_NONE;
8419 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8421 /* something went wrong. We report the error and revert back to no authentication
8422 because we can't perform any auth requests without a successful lsa handle
8423 or sec package id. */
8424 afsi_log("Reverting to NO SMB AUTH");
8425 smb_authType = SMB_AUTH_NONE;
8429 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8430 * time prevents the failure of authentication when logged into Windows with an
8431 * external Kerberos principal mapped to a local account.
8433 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8434 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8435 * then the only option is NTLMSSP anyway; so just fallback.
8440 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8441 if (secBlobLength == 0) {
8442 smb_authType = SMB_AUTH_NTLM;
8443 afsi_log("Reverting to SMB AUTH NTLM");
8452 /* Now get ourselves a domain name. */
8453 /* For now we are using the local computer name as the domain name.
8454 * It is actually the domain for local logins, and we are acting as
8455 * a local SMB server.
8457 bufsize = sizeof(smb_ServerDomainName) - 1;
8458 GetComputerName(smb_ServerDomainName, &bufsize);
8459 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8460 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8463 /* Start listeners, waiters, servers, and daemons */
8465 for (i = 0; i < lana_list.length; i++) {
8466 if (lana_list.lana[i] == 255)
8468 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8469 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8470 osi_assert(phandle != NULL);
8471 thrd_CloseHandle(phandle);
8475 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8476 NULL, 0, &lpid, "smb_ClientWaiter");
8477 osi_assert(phandle != NULL);
8478 thrd_CloseHandle(phandle);
8481 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8482 NULL, 0, &lpid, "smb_ServerWaiter");
8483 osi_assert(phandle != NULL);
8484 thrd_CloseHandle(phandle);
8486 for (i=0; i<smb_NumServerThreads; i++) {
8487 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8488 (void *) i, 0, &lpid, "smb_Server");
8489 osi_assert(phandle != NULL);
8490 thrd_CloseHandle(phandle);
8493 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8494 NULL, 0, &lpid, "smb_Daemon");
8495 osi_assert(phandle != NULL);
8496 thrd_CloseHandle(phandle);
8498 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8499 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8500 osi_assert(phandle != NULL);
8501 thrd_CloseHandle(phandle);
8510 void smb_Shutdown(void)
8520 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8522 /* setup the NCB system */
8525 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8528 /* Block new sessions by setting shutdown flag */
8529 smbShutdownFlag = 1;
8531 /* Hang up all sessions */
8532 memset((char *)ncbp, 0, sizeof(NCB));
8533 for (i = 1; i < numSessions; i++)
8535 if (dead_sessions[i])
8538 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8539 ncbp->ncb_command = NCBHANGUP;
8540 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8541 ncbp->ncb_lsn = LSNs[i];
8543 code = Netbios(ncbp);
8545 code = Netbios(ncbp, dos_ncb);
8547 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8548 if (code == 0) code = ncbp->ncb_retcode;
8550 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8551 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8555 /* Trigger the shutdown of all SMB threads */
8556 for (i = 0; i < smb_NumServerThreads; i++)
8557 thrd_SetEvent(NCBreturns[i][0]);
8559 thrd_SetEvent(NCBevents[0]);
8560 thrd_SetEvent(SessionEvents[0]);
8561 thrd_SetEvent(NCBavails[0]);
8563 for (i = 0;i < smb_NumServerThreads; i++) {
8564 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8565 if (code == WAIT_OBJECT_0) {
8568 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8569 thrd_SetEvent(NCBreturns[i--][0]);
8573 /* Delete Netbios name */
8574 memset((char *)ncbp, 0, sizeof(NCB));
8575 for (i = 0; i < lana_list.length; i++) {
8576 if (lana_list.lana[i] == 255) continue;
8577 ncbp->ncb_command = NCBDELNAME;
8578 ncbp->ncb_lana_num = lana_list.lana[i];
8579 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8581 code = Netbios(ncbp);
8583 code = Netbios(ncbp, dos_ncb);
8586 code = ncbp->ncb_retcode;
8588 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8589 ncbp->ncb_lana_num, code);
8594 /* Release the reference counts held by the VCs */
8595 lock_ObtainWrite(&smb_rctLock);
8596 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8601 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8603 if (fidp->scp != NULL) {
8606 lock_ObtainMutex(&fidp->mx);
8607 if (fidp->scp != NULL) {
8610 cm_ReleaseSCache(scp);
8612 lock_ReleaseMutex(&fidp->mx);
8616 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8618 smb_ReleaseVCNoLock(tidp->vcp);
8620 cm_user_t *userp = tidp->userp;
8622 lock_ReleaseWrite(&smb_rctLock);
8623 cm_ReleaseUser(userp);
8624 lock_ObtainWrite(&smb_rctLock);
8628 lock_ReleaseWrite(&smb_rctLock);
8631 /* Get the UNC \\<servername>\<sharename> prefix. */
8632 char *smb_GetSharename()
8636 /* Make sure we have been properly initialized. */
8637 if (smb_localNamep == NULL)
8640 /* Allocate space for \\<servername>\<sharename>, plus the
8643 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8644 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8650 void smb_LogPacket(smb_packet_t *packet)
8653 unsigned length, paramlen, datalen, i, j;
8655 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8657 if (!packet) return;
8659 osi_Log0(smb_logp, "*** SMB packet dump ***");
8661 vp = (BYTE *) packet->data;
8663 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8664 length = paramlen + 2 + datalen;
8667 for (i=0;i < length; i+=16)
8669 memset( buf, ' ', 80 );
8674 buf[strlen(buf)] = ' ';
8676 cp = (BYTE*) buf + 7;
8678 for (j=0;j < 16 && (i+j)<length; j++)
8680 *(cp++) = hex[vp[i+j] >> 4];
8681 *(cp++) = hex[vp[i+j] & 0xf];
8691 for (j=0;j < 16 && (i+j)<length;j++)
8693 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8704 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8707 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8709 #endif /* LOG_PACKET */
8712 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8720 lock_ObtainRead(&smb_rctLock);
8722 sprintf(output, "begin dumping smb_vc_t\n");
8723 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8725 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8729 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8730 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8731 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8733 sprintf(output, "begin dumping smb_fid_t\n");
8734 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8736 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8738 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",
8739 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8740 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8741 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8742 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8745 sprintf(output, "done dumping smb_fid_t\n");
8746 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8749 sprintf(output, "done dumping smb_vc_t\n");
8750 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8753 lock_ReleaseRead(&smb_rctLock);