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) {
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 NTStatus = 0xC00000BEL; /* Bad Network Path */
2468 NTStatus = 0xC0982001L; /* SMB non-specific error */
2471 *NTStatusp = NTStatus;
2472 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2475 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2476 unsigned char *classp)
2478 unsigned char class;
2479 unsigned short error;
2481 /* map CM_ERROR_* errors to SMB errors */
2482 if (code == CM_ERROR_NOSUCHCELL) {
2484 error = 3; /* bad path */
2486 else if (code == CM_ERROR_NOSUCHVOLUME) {
2488 error = 3; /* bad path */
2490 else if (code == CM_ERROR_TIMEDOUT) {
2492 error = 81; /* server is paused */
2494 else if (code == CM_ERROR_RETRY) {
2495 class = 2; /* shouldn't happen */
2498 else if (code == CM_ERROR_NOACCESS) {
2500 error = 4; /* bad access */
2502 else if (code == CM_ERROR_READONLY) {
2504 error = 19; /* read only */
2506 else if (code == CM_ERROR_NOSUCHFILE) {
2508 error = 2; /* ENOENT! */
2510 else if (code == CM_ERROR_NOSUCHPATH) {
2512 error = 3; /* Bad path */
2514 else if (code == CM_ERROR_TOOBIG) {
2516 error = 11; /* bad format */
2518 else if (code == CM_ERROR_INVAL) {
2519 class = 2; /* server non-specific error code */
2522 else if (code == CM_ERROR_BADFD) {
2524 error = 6; /* invalid file handle */
2526 else if (code == CM_ERROR_BADFDOP) {
2527 class = 1; /* invalid op on FD */
2530 else if (code == CM_ERROR_EXISTS) {
2532 error = 80; /* file already exists */
2534 else if (code == CM_ERROR_NOTEMPTY) {
2536 error = 5; /* delete directory not empty */
2538 else if (code == CM_ERROR_CROSSDEVLINK) {
2540 error = 17; /* EXDEV */
2542 else if (code == CM_ERROR_NOTDIR) {
2543 class = 1; /* bad path */
2546 else if (code == CM_ERROR_ISDIR) {
2547 class = 1; /* access denied; DOS doesn't have a good match */
2550 else if (code == CM_ERROR_BADOP) {
2554 else if (code == CM_ERROR_BADSHARENAME) {
2558 else if (code == CM_ERROR_NOIPC) {
2560 error = 4; /* bad access */
2562 else if (code == CM_ERROR_CLOCKSKEW) {
2563 class = 1; /* invalid function */
2566 else if (code == CM_ERROR_BADTID) {
2570 else if (code == CM_ERROR_USESTD) {
2574 else if (code == CM_ERROR_REMOTECONN) {
2578 else if (code == CM_ERROR_QUOTA) {
2579 if (vcp->flags & SMB_VCFLAG_USEV3) {
2581 error = 39; /* disk full */
2585 error = 5; /* access denied */
2588 else if (code == CM_ERROR_SPACE) {
2589 if (vcp->flags & SMB_VCFLAG_USEV3) {
2591 error = 39; /* disk full */
2595 error = 5; /* access denied */
2598 else if (code == CM_ERROR_PARTIALWRITE) {
2600 error = 39; /* disk full */
2602 else if (code == CM_ERROR_ATSYS) {
2604 error = 2; /* ENOENT */
2606 else if (code == CM_ERROR_WOULDBLOCK) {
2608 error = 33; /* lock conflict */
2610 else if (code == CM_ERROR_LOCK_CONFLICT) {
2612 error = 33; /* lock conflict */
2614 else if (code == CM_ERROR_SHARING_VIOLATION) {
2616 error = 33; /* lock conflict */
2618 else if (code == CM_ERROR_NOFILES) {
2620 error = 18; /* no files in search */
2622 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2624 error = 183; /* Samba uses this */
2626 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2627 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2629 error = 2; /* bad password */
2631 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2633 error = 3; /* bad path */
2642 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2645 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2647 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2648 return CM_ERROR_BADOP;
2651 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2653 unsigned short EchoCount, i;
2654 char *data, *outdata;
2657 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2659 for (i=1; i<=EchoCount; i++) {
2660 data = smb_GetSMBData(inp, &dataSize);
2661 smb_SetSMBParm(outp, 0, i);
2662 smb_SetSMBDataLength(outp, dataSize);
2663 outdata = smb_GetSMBData(outp, NULL);
2664 memcpy(outdata, data, dataSize);
2665 smb_SendPacket(vcp, outp);
2671 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2674 long count, minCount, finalCount;
2679 cm_user_t *userp = NULL;
2683 char *rawBuf = NULL;
2685 dos_ptr rawBuf = NULL;
2692 fd = smb_GetSMBParm(inp, 0);
2693 count = smb_GetSMBParm(inp, 3);
2694 minCount = smb_GetSMBParm(inp, 4);
2695 offset.HighPart = 0; /* too bad */
2696 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2698 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2699 fd, offset.LowPart, count);
2701 fidp = smb_FindFID(vcp, fd, 0);
2705 pid = ((smb_t *) inp)->pid;
2707 LARGE_INTEGER LOffset, LLength;
2710 key = cm_GenerateKey(vcp->vcID, pid, fd);
2712 LOffset.HighPart = 0;
2713 LOffset.LowPart = offset.LowPart;
2714 LLength.HighPart = 0;
2715 LLength.LowPart = count;
2717 lock_ObtainMutex(&fidp->scp->mx);
2718 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2719 lock_ReleaseMutex(&fidp->scp->mx);
2725 lock_ObtainMutex(&smb_RawBufLock);
2727 /* Get a raw buf, from head of list */
2728 rawBuf = smb_RawBufs;
2730 smb_RawBufs = *(char **)smb_RawBufs;
2732 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2735 lock_ReleaseMutex(&smb_RawBufLock);
2739 if (fidp->flags & SMB_FID_IOCTL)
2742 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2744 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2747 /* Give back raw buffer */
2748 lock_ObtainMutex(&smb_RawBufLock);
2750 *((char **) rawBuf) = smb_RawBufs;
2752 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2755 smb_RawBufs = rawBuf;
2756 lock_ReleaseMutex(&smb_RawBufLock);
2759 smb_ReleaseFID(fidp);
2763 userp = smb_GetUser(vcp, inp);
2766 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2768 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2769 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2770 userp, &finalCount, TRUE /* rawFlag */);
2777 cm_ReleaseUser(userp);
2780 smb_ReleaseFID(fidp);
2785 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2787 memset((char *)ncbp, 0, sizeof(NCB));
2789 ncbp->ncb_length = (unsigned short) finalCount;
2790 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2791 ncbp->ncb_lana_num = vcp->lana;
2792 ncbp->ncb_command = NCBSEND;
2793 ncbp->ncb_buffer = rawBuf;
2796 code = Netbios(ncbp);
2798 code = Netbios(ncbp, dos_ncb);
2801 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2804 /* Give back raw buffer */
2805 lock_ObtainMutex(&smb_RawBufLock);
2807 *((char **) rawBuf) = smb_RawBufs;
2809 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2812 smb_RawBufs = rawBuf;
2813 lock_ReleaseMutex(&smb_RawBufLock);
2819 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2821 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2826 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2828 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2833 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2840 int protoIndex; /* index we're using */
2845 char protocol_array[10][1024]; /* protocol signature of the client */
2846 int caps; /* capabilities */
2849 TIME_ZONE_INFORMATION tzi;
2851 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2855 DWORD now = GetCurrentTime();
2856 if (now - last_msg_time >= 30000
2857 && now - last_msg_time <= 90000) {
2859 "Setting dead_vcp %x", active_vcp);
2861 smb_ReleaseVC(dead_vcp);
2863 "Previous dead_vcp %x", dead_vcp);
2865 smb_HoldVC(active_vcp);
2866 dead_vcp = active_vcp;
2867 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2872 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2874 namep = smb_GetSMBData(inp, &dbytes);
2877 coreProtoIndex = -1; /* not found */
2880 while(namex < dbytes) {
2881 osi_Log1(smb_logp, "Protocol %s",
2882 osi_LogSaveString(smb_logp, namep+1));
2883 strcpy(protocol_array[tcounter], namep+1);
2885 /* namep points at the first protocol, or really, a 0x02
2886 * byte preceding the null-terminated ASCII name.
2888 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2889 coreProtoIndex = tcounter;
2891 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2892 v3ProtoIndex = tcounter;
2894 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2895 NTProtoIndex = tcounter;
2898 /* compute size of protocol entry */
2899 entryLength = strlen(namep+1);
2900 entryLength += 2; /* 0x02 bytes and null termination */
2902 /* advance over this protocol entry */
2903 namex += entryLength;
2904 namep += entryLength;
2905 tcounter++; /* which proto entry we're looking at */
2908 if (NTProtoIndex != -1) {
2909 protoIndex = NTProtoIndex;
2910 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2912 else if (v3ProtoIndex != -1) {
2913 protoIndex = v3ProtoIndex;
2914 vcp->flags |= SMB_VCFLAG_USEV3;
2916 else if (coreProtoIndex != -1) {
2917 protoIndex = coreProtoIndex;
2918 vcp->flags |= SMB_VCFLAG_USECORE;
2920 else protoIndex = -1;
2922 if (protoIndex == -1)
2923 return CM_ERROR_INVAL;
2924 else if (NTProtoIndex != -1) {
2925 smb_SetSMBParm(outp, 0, protoIndex);
2926 if (smb_authType != SMB_AUTH_NONE) {
2927 smb_SetSMBParmByte(outp, 1,
2928 NEGOTIATE_SECURITY_USER_LEVEL |
2929 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2931 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2933 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2934 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2935 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2936 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2937 /* The session key is not a well documented field however most clients
2938 * will echo back the session key to the server. Currently we are using
2939 * the same value for all sessions. We should generate a random value
2940 * and store it into the vcp
2942 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2943 smb_SetSMBParm(outp, 8, 1);
2945 * Tried changing the capabilities to support for W2K - defect 117695
2946 * Maybe something else needs to be changed here?
2950 smb_SetSMBParmLong(outp, 9, 0x43fd);
2952 smb_SetSMBParmLong(outp, 9, 0x251);
2955 * 32-bit error codes *
2960 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2962 NTNEGOTIATE_CAPABILITY_DFS |
2964 NTNEGOTIATE_CAPABILITY_NTFIND |
2965 NTNEGOTIATE_CAPABILITY_RAWMODE |
2966 NTNEGOTIATE_CAPABILITY_NTSMB;
2968 if ( smb_authType == SMB_AUTH_EXTENDED )
2969 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2971 smb_SetSMBParmLong(outp, 9, caps);
2973 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2974 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2975 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2977 GetTimeZoneInformation(&tzi);
2978 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2980 if (smb_authType == SMB_AUTH_NTLM) {
2981 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2982 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2983 /* paste in encryption key */
2984 datap = smb_GetSMBData(outp, NULL);
2985 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2986 /* and the faux domain name */
2987 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2988 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2992 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2994 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2996 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2998 datap = smb_GetSMBData(outp, NULL);
2999 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3002 datap += sizeof(smb_ServerGUID);
3003 memcpy(datap, secBlob, secBlobLength);
3007 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3008 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3011 else if (v3ProtoIndex != -1) {
3012 smb_SetSMBParm(outp, 0, protoIndex);
3014 /* NOTE: Extended authentication cannot be negotiated with v3
3015 * therefore we fail over to NTLM
3017 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3018 smb_SetSMBParm(outp, 1,
3019 NEGOTIATE_SECURITY_USER_LEVEL |
3020 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3022 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3024 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3025 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3026 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3027 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3028 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3029 smb_SetSMBParm(outp, 7, 1);
3031 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3032 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3033 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3035 GetTimeZoneInformation(&tzi);
3036 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3038 /* NOTE: Extended authentication cannot be negotiated with v3
3039 * therefore we fail over to NTLM
3041 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3042 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3043 smb_SetSMBParm(outp, 12, 0); /* resvd */
3044 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3045 datap = smb_GetSMBData(outp, NULL);
3046 /* paste in a new encryption key */
3047 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3048 /* and the faux domain name */
3049 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3051 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3052 smb_SetSMBParm(outp, 12, 0); /* resvd */
3053 smb_SetSMBDataLength(outp, 0);
3056 else if (coreProtoIndex != -1) { /* not really supported anymore */
3057 smb_SetSMBParm(outp, 0, protoIndex);
3058 smb_SetSMBDataLength(outp, 0);
3063 void smb_Daemon(void *parmp)
3065 afs_uint32 count = 0;
3067 while(smbShutdownFlag == 0) {
3071 if (smbShutdownFlag == 1)
3074 if ((count % 72) == 0) { /* every five minutes */
3076 time_t old_localZero = smb_localZero;
3078 /* Initialize smb_localZero */
3079 myTime.tm_isdst = -1; /* compute whether on DST or not */
3080 myTime.tm_year = 70;
3086 smb_localZero = mktime(&myTime);
3088 #ifndef USE_NUMERIC_TIME_CONV
3089 smb_CalculateNowTZ();
3090 #endif /* USE_NUMERIC_TIME_CONV */
3091 #ifdef AFS_FREELANCE
3092 if ( smb_localZero != old_localZero )
3093 cm_noteLocalMountPointChange();
3096 /* XXX GC dir search entries */
3100 void smb_WaitingLocksDaemon()
3102 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3103 smb_waitingLock_t *wl, *wlNext;
3106 smb_packet_t *inp, *outp;
3110 while (smbShutdownFlag == 0) {
3111 lock_ObtainWrite(&smb_globalLock);
3112 nwlRequest = smb_allWaitingLocks;
3113 if (nwlRequest == NULL) {
3114 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3124 lock_ObtainWrite(&smb_globalLock);
3126 wlRequest = nwlRequest;
3127 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3128 lock_ReleaseWrite(&smb_globalLock);
3132 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3133 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3136 /* wl->state is either _DONE or _WAITING. _ERROR
3137 would no longer be on the queue. */
3138 code = cm_RetryLock( wl->lockp,
3139 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3142 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3143 } else if (code != CM_ERROR_WOULDBLOCK) {
3144 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3149 if (code == CM_ERROR_WOULDBLOCK) {
3152 if (wlRequest->timeRemaining != 0xffffffff
3153 && (wlRequest->timeRemaining -= 1000) < 0)
3165 scp = wlRequest->scp;
3169 lock_ObtainMutex(&scp->mx);
3171 for (wl = wlRequest->locks; wl; wl = wlNext) {
3172 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3174 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3175 wl->LLength, wl->key, NULL, &req);
3177 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3182 lock_ReleaseMutex(&scp->mx);
3185 for (wl = wlRequest->locks; wl; wl = wlNext) {
3186 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3187 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3192 vcp = wlRequest->vcp;
3193 inp = wlRequest->inp;
3194 outp = wlRequest->outp;
3196 ncbp->ncb_length = inp->ncb_length;
3197 inp->spacep = cm_GetSpace();
3199 /* Remove waitingLock from list */
3200 lock_ObtainWrite(&smb_globalLock);
3201 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3203 lock_ReleaseWrite(&smb_globalLock);
3205 /* Resume packet processing */
3207 smb_SetSMBDataLength(outp, 0);
3208 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3209 outp->resumeCode = code;
3211 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3214 cm_FreeSpace(inp->spacep);
3215 smb_FreePacket(inp);
3216 smb_FreePacket(outp);
3218 cm_ReleaseSCache(wlRequest->scp);
3221 } while (nwlRequest && smbShutdownFlag == 0);
3226 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3228 osi_Log0(smb_logp, "SMB receive get disk attributes");
3230 smb_SetSMBParm(outp, 0, 32000);
3231 smb_SetSMBParm(outp, 1, 64);
3232 smb_SetSMBParm(outp, 2, 1024);
3233 smb_SetSMBParm(outp, 3, 30000);
3234 smb_SetSMBParm(outp, 4, 0);
3235 smb_SetSMBDataLength(outp, 0);
3239 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3243 unsigned short newTid;
3244 char shareName[256];
3252 osi_Log0(smb_logp, "SMB receive tree connect");
3254 /* parse input parameters */
3255 tp = smb_GetSMBData(inp, NULL);
3256 pathp = smb_ParseASCIIBlock(tp, &tp);
3257 if (smb_StoreAnsiFilenames)
3258 OemToChar(pathp,pathp);
3259 passwordp = smb_ParseASCIIBlock(tp, &tp);
3260 tp = strrchr(pathp, '\\');
3262 return CM_ERROR_BADSMB;
3263 strcpy(shareName, tp+1);
3265 userp = smb_GetUser(vcp, inp);
3267 lock_ObtainMutex(&vcp->mx);
3268 newTid = vcp->tidCounter++;
3269 lock_ReleaseMutex(&vcp->mx);
3271 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3272 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3273 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3275 smb_ReleaseUID(uidp);
3277 smb_ReleaseTID(tidp);
3278 return CM_ERROR_BADSHARENAME;
3280 lock_ObtainMutex(&tidp->mx);
3281 tidp->userp = userp;
3282 tidp->pathname = sharePath;
3283 lock_ReleaseMutex(&tidp->mx);
3284 smb_ReleaseTID(tidp);
3286 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3287 smb_SetSMBParm(rsp, 1, newTid);
3288 smb_SetSMBDataLength(rsp, 0);
3290 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3294 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3298 if (*inp++ != 0x1) return NULL;
3299 tlen = inp[0] + (inp[1]<<8);
3300 inp += 2; /* skip length field */
3303 *chainpp = inp + tlen;
3306 if (lengthp) *lengthp = tlen;
3311 /* set maskp to the mask part of the incoming path.
3312 * Mask is 11 bytes long (8.3 with the dot elided).
3313 * Returns true if succeeds with a valid name, otherwise it does
3314 * its best, but returns false.
3316 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3324 /* starts off valid */
3327 /* mask starts out all blanks */
3328 memset(maskp, ' ', 11);
3330 /* find last backslash, or use whole thing if there is none */
3331 tp = strrchr(pathp, '\\');
3332 if (!tp) tp = pathp;
3333 else tp++; /* skip slash */
3337 /* names starting with a dot are illegal */
3338 if (*tp == '.') valid8Dot3 = 0;
3342 if (tc == 0) return valid8Dot3;
3343 if (tc == '.' || tc == '"') break;
3344 if (i < 8) *up++ = tc;
3345 else valid8Dot3 = 0;
3348 /* if we get here, tp point after the dot */
3349 up = maskp+8; /* ext goes here */
3356 if (tc == '.' || tc == '"')
3359 /* copy extension if not too long */
3369 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3379 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3381 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3385 /* otherwise, we have a valid 8.3 name; see if we have a match,
3386 * treating '?' as a wildcard in maskp (but not in the file name).
3388 tp1 = umask; /* real name, in mask format */
3389 tp2 = maskp; /* mask, in mask format */
3390 for(i=0; i<11; i++) {
3391 tc1 = *tp1++; /* char from real name */
3392 tc2 = *tp2++; /* char from mask */
3393 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3394 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3397 if (tc2 == '?' && tc1 != ' ')
3404 /* we got a match */
3408 char *smb_FindMask(char *pathp)
3412 tp = strrchr(pathp, '\\'); /* find last slash */
3415 return tp+1; /* skip the slash */
3417 return pathp; /* no slash, return the entire path */
3420 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3422 unsigned char *pathp;
3424 unsigned char mask[11];
3425 unsigned char *statBlockp;
3426 unsigned char initStatBlock[21];
3429 osi_Log0(smb_logp, "SMB receive search volume");
3431 /* pull pathname and stat block out of request */
3432 tp = smb_GetSMBData(inp, NULL);
3433 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3434 osi_assert(pathp != NULL);
3435 if (smb_StoreAnsiFilenames)
3436 OemToChar(pathp,pathp);
3437 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3438 osi_assert(statBlockp != NULL);
3440 statBlockp = initStatBlock;
3444 /* for returning to caller */
3445 smb_Get8Dot3MaskFromPath(mask, pathp);
3447 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3448 tp = smb_GetSMBData(outp, NULL);
3450 *tp++ = 43; /* bytes in a dir entry */
3451 *tp++ = 0; /* high byte in counter */
3453 /* now marshall the dir entry, starting with the search status */
3454 *tp++ = statBlockp[0]; /* Reserved */
3455 memcpy(tp, mask, 11); tp += 11; /* FileName */
3457 /* now pass back server use info, with 1st byte non-zero */
3459 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3461 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3463 *tp++ = 0x8; /* attribute: volume */
3473 /* 4 byte file size */
3479 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3480 memset(tp, ' ', 13);
3483 /* set the length of the data part of the packet to 43 + 3, for the dir
3484 * entry plus the 5 and the length fields.
3486 smb_SetSMBDataLength(outp, 46);
3490 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3491 cm_user_t *userp, cm_req_t *reqp)
3499 smb_dirListPatch_t *patchp;
3500 smb_dirListPatch_t *npatchp;
3502 for (patchp = *dirPatchespp; patchp; patchp =
3503 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3505 dptr = patchp->dptr;
3507 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3509 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3510 *dptr++ = SMB_ATTR_HIDDEN;
3513 lock_ObtainMutex(&scp->mx);
3514 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3515 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3517 lock_ReleaseMutex(&scp->mx);
3518 cm_ReleaseSCache(scp);
3519 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3520 *dptr++ = SMB_ATTR_HIDDEN;
3524 attr = smb_Attributes(scp);
3525 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3526 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3527 attr |= SMB_ATTR_HIDDEN;
3531 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3534 shortTemp = (unsigned short) (dosTime & 0xffff);
3535 *((u_short *)dptr) = shortTemp;
3538 /* and copy out date */
3539 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3540 *((u_short *)dptr) = shortTemp;
3543 /* copy out file length */
3544 *((u_long *)dptr) = scp->length.LowPart;
3546 lock_ReleaseMutex(&scp->mx);
3547 cm_ReleaseSCache(scp);
3550 /* now free the patches */
3551 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3552 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3556 /* and mark the list as empty */
3557 *dirPatchespp = NULL;
3562 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3571 smb_dirListPatch_t *dirListPatchesp;
3572 smb_dirListPatch_t *curPatchp;
3576 osi_hyper_t dirLength;
3577 osi_hyper_t bufferOffset;
3578 osi_hyper_t curOffset;
3580 unsigned char *inCookiep;
3581 smb_dirSearch_t *dsp;
3585 unsigned long clientCookie;
3586 cm_pageHeader_t *pageHeaderp;
3587 cm_user_t *userp = NULL;
3594 long nextEntryCookie;
3595 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3596 char resByte; /* reserved byte from the cookie */
3597 char *op; /* output data ptr */
3598 char *origOp; /* original value of op */
3599 cm_space_t *spacep; /* for pathname buffer */
3610 maxCount = smb_GetSMBParm(inp, 0);
3612 dirListPatchesp = NULL;
3614 caseFold = CM_FLAG_CASEFOLD;
3616 tp = smb_GetSMBData(inp, NULL);
3617 pathp = smb_ParseASCIIBlock(tp, &tp);
3618 if (smb_StoreAnsiFilenames)
3619 OemToChar(pathp,pathp);
3620 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3622 /* bail out if request looks bad */
3623 if (!tp || !pathp) {
3624 return CM_ERROR_BADSMB;
3627 /* We can handle long names */
3628 if (vcp->flags & SMB_VCFLAG_USENT)
3629 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3631 /* make sure we got a whole search status */
3632 if (dataLength < 21) {
3633 nextCookie = 0; /* start at the beginning of the dir */
3636 attribute = smb_GetSMBParm(inp, 1);
3638 /* handle volume info in another function */
3639 if (attribute & 0x8)
3640 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3642 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3643 maxCount, osi_LogSaveString(smb_logp, pathp));
3645 if (*pathp == 0) { /* null pathp, treat as root dir */
3646 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3647 return CM_ERROR_NOFILES;
3651 dsp = smb_NewDirSearch(0);
3652 dsp->attribute = attribute;
3653 smb_Get8Dot3MaskFromPath(mask, pathp);
3654 memcpy(dsp->mask, mask, 11);
3656 /* track if this is likely to match a lot of entries */
3657 if (smb_IsStarMask(mask))
3662 /* pull the next cookie value out of the search status block */
3663 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3664 + (inCookiep[16]<<24);
3665 dsp = smb_FindDirSearch(inCookiep[12]);
3667 /* can't find dir search status; fatal error */
3668 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3669 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3670 return CM_ERROR_BADFD;
3672 attribute = dsp->attribute;
3673 resByte = inCookiep[0];
3675 /* copy out client cookie, in host byte order. Don't bother
3676 * interpreting it, since we're just passing it through, anyway.
3678 memcpy(&clientCookie, &inCookiep[17], 4);
3680 memcpy(mask, dsp->mask, 11);
3682 /* assume we're doing a star match if it has continued for more
3688 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3689 nextCookie, dsp->cookie, attribute);
3691 userp = smb_GetUser(vcp, inp);
3693 /* try to get the vnode for the path name next */
3694 lock_ObtainMutex(&dsp->mx);
3700 spacep = inp->spacep;
3701 smb_StripLastComponent(spacep->data, NULL, pathp);
3702 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3704 lock_ReleaseMutex(&dsp->mx);
3705 cm_ReleaseUser(userp);
3706 smb_DeleteDirSearch(dsp);
3707 smb_ReleaseDirSearch(dsp);
3708 return CM_ERROR_NOFILES;
3710 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3711 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3714 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3715 cm_ReleaseSCache(scp);
3716 lock_ReleaseMutex(&dsp->mx);
3717 cm_ReleaseUser(userp);
3718 smb_DeleteDirSearch(dsp);
3719 smb_ReleaseDirSearch(dsp);
3720 if ( WANTS_DFS_PATHNAMES(inp) )
3721 return CM_ERROR_PATH_NOT_COVERED;
3723 return CM_ERROR_BADSHARENAME;
3725 #endif /* DFS_SUPPORT */
3728 /* we need one hold for the entry we just stored into,
3729 * and one for our own processing. When we're done with this
3730 * function, we'll drop the one for our own processing.
3731 * We held it once from the namei call, and so we do another hold
3735 lock_ObtainMutex(&scp->mx);
3736 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3737 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3738 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3739 dsp->flags |= SMB_DIRSEARCH_BULKST;
3741 lock_ReleaseMutex(&scp->mx);
3744 lock_ReleaseMutex(&dsp->mx);
3746 cm_ReleaseUser(userp);
3747 smb_DeleteDirSearch(dsp);
3748 smb_ReleaseDirSearch(dsp);
3752 /* reserves space for parameter; we'll adjust it again later to the
3753 * real count of the # of entries we returned once we've actually
3754 * assembled the directory listing.
3756 smb_SetSMBParm(outp, 0, 0);
3758 /* get the directory size */
3759 lock_ObtainMutex(&scp->mx);
3760 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3761 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3763 lock_ReleaseMutex(&scp->mx);
3764 cm_ReleaseSCache(scp);
3765 cm_ReleaseUser(userp);
3766 smb_DeleteDirSearch(dsp);
3767 smb_ReleaseDirSearch(dsp);
3771 dirLength = scp->length;
3773 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3774 curOffset.HighPart = 0;
3775 curOffset.LowPart = nextCookie;
3776 origOp = op = smb_GetSMBData(outp, NULL);
3777 /* and write out the basic header */
3778 *op++ = 5; /* variable block */
3779 op += 2; /* skip vbl block length; we'll fill it in later */
3783 /* make sure that curOffset.LowPart doesn't point to the first
3784 * 32 bytes in the 2nd through last dir page, and that it doesn't
3785 * point at the first 13 32-byte chunks in the first dir page,
3786 * since those are dir and page headers, and don't contain useful
3789 temp = curOffset.LowPart & (2048-1);
3790 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3791 /* we're in the first page */
3792 if (temp < 13*32) temp = 13*32;
3795 /* we're in a later dir page */
3796 if (temp < 32) temp = 32;
3799 /* make sure the low order 5 bits are zero */
3802 /* now put temp bits back ito curOffset.LowPart */
3803 curOffset.LowPart &= ~(2048-1);
3804 curOffset.LowPart |= temp;
3806 /* check if we've returned all the names that will fit in the
3809 if (returnedNames >= maxCount) {
3810 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3811 returnedNames, maxCount);
3815 /* check if we've passed the dir's EOF */
3816 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3818 /* see if we can use the bufferp we have now; compute in which page
3819 * the current offset would be, and check whether that's the offset
3820 * of the buffer we have. If not, get the buffer.
3822 thyper.HighPart = curOffset.HighPart;
3823 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3824 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3827 buf_Release(bufferp);
3830 lock_ReleaseMutex(&scp->mx);
3831 lock_ObtainRead(&scp->bufCreateLock);
3832 code = buf_Get(scp, &thyper, &bufferp);
3833 lock_ReleaseRead(&scp->bufCreateLock);
3834 lock_ObtainMutex(&dsp->mx);
3836 /* now, if we're doing a star match, do bulk fetching of all of
3837 * the status info for files in the dir.
3840 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3841 lock_ObtainMutex(&scp->mx);
3842 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3843 LargeIntegerGreaterThanOrEqualTo(thyper,
3844 scp->bulkStatProgress)) {
3845 /* Don't bulk stat if risking timeout */
3846 int now = GetCurrentTime();
3847 if (now - req.startTime > 5000) {
3848 scp->bulkStatProgress = thyper;
3849 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3850 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3852 cm_TryBulkStat(scp, &thyper, userp, &req);
3855 lock_ObtainMutex(&scp->mx);
3857 lock_ReleaseMutex(&dsp->mx);
3859 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3863 bufferOffset = thyper;
3865 /* now get the data in the cache */
3867 code = cm_SyncOp(scp, bufferp, userp, &req,
3869 CM_SCACHESYNC_NEEDCALLBACK |
3870 CM_SCACHESYNC_READ);
3872 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3876 if (cm_HaveBuffer(scp, bufferp, 0)) {
3877 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3881 /* otherwise, load the buffer and try again */
3882 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3884 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3885 scp, bufferp, code);
3890 buf_Release(bufferp);
3894 } /* if (wrong buffer) ... */
3896 /* now we have the buffer containing the entry we're interested in; copy
3897 * it out if it represents a non-deleted entry.
3899 entryInDir = curOffset.LowPart & (2048-1);
3900 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3902 /* page header will help tell us which entries are free. Page header
3903 * can change more often than once per buffer, since AFS 3 dir page size
3904 * may be less than (but not more than a buffer package buffer.
3906 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3907 temp &= ~(2048 - 1); /* turn off intra-page bits */
3908 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3910 /* now determine which entry we're looking at in the page. If it is
3911 * free (there's a free bitmap at the start of the dir), we should
3912 * skip these 32 bytes.
3914 slotInPage = (entryInDir & 0x7e0) >> 5;
3915 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3916 /* this entry is free */
3917 numDirChunks = 1; /* only skip this guy */
3921 tp = bufferp->datap + entryInBuffer;
3922 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3924 /* while we're here, compute the next entry's location, too,
3925 * since we'll need it when writing out the cookie into the dir
3928 * XXXX Probably should do more sanity checking.
3930 numDirChunks = cm_NameEntries(dep->name, NULL);
3932 /* compute the offset of the cookie representing the next entry */
3933 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3935 /* Compute 8.3 name if necessary */
3936 actualName = dep->name;
3937 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3938 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3939 actualName = shortName;
3942 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3943 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3944 osi_LogSaveString(smb_logp, actualName));
3946 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3947 /* this is one of the entries to use: it is not deleted
3948 * and it matches the star pattern we're looking for.
3951 /* Eliminate entries that don't match requested
3954 /* no hidden files */
3955 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3956 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3960 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3962 /* We have already done the cm_TryBulkStat above */
3963 fid.cell = scp->fid.cell;
3964 fid.volume = scp->fid.volume;
3965 fid.vnode = ntohl(dep->fid.vnode);
3966 fid.unique = ntohl(dep->fid.unique);
3967 fileType = cm_FindFileType(&fid);
3968 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3969 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3971 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3972 fileType == CM_SCACHETYPE_DFSLINK ||
3973 fileType == CM_SCACHETYPE_INVALID)
3974 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3979 memcpy(op, mask, 11); op += 11;
3980 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3981 *op++ = nextEntryCookie & 0xff;
3982 *op++ = (nextEntryCookie>>8) & 0xff;
3983 *op++ = (nextEntryCookie>>16) & 0xff;
3984 *op++ = (nextEntryCookie>>24) & 0xff;
3985 memcpy(op, &clientCookie, 4); op += 4;
3987 /* now we emit the attribute. This is sort of tricky,
3988 * since we need to really stat the file to find out
3989 * what type of entry we've got. Right now, we're
3990 * copying out data from a buffer, while holding the
3991 * scp locked, so it isn't really convenient to stat
3992 * something now. We'll put in a place holder now,
3993 * and make a second pass before returning this to get
3994 * the real attributes. So, we just skip the data for
3995 * now, and adjust it later. We allocate a patch
3996 * record to make it easy to find this point later.
3997 * The replay will happen at a time when it is safe to
3998 * unlock the directory.
4000 curPatchp = malloc(sizeof(*curPatchp));
4001 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4002 curPatchp->dptr = op;
4003 curPatchp->fid.cell = scp->fid.cell;
4004 curPatchp->fid.volume = scp->fid.volume;
4005 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4006 curPatchp->fid.unique = ntohl(dep->fid.unique);
4008 /* do hidden attribute here since name won't be around when applying
4012 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4013 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4015 curPatchp->flags = 0;
4017 op += 9; /* skip attr, time, date and size */
4019 /* zero out name area. The spec says to pad with
4020 * spaces, but Samba doesn't, and neither do we.
4024 /* finally, we get to copy out the name; we know that
4025 * it fits in 8.3 or the pattern wouldn't match, but it
4026 * never hurts to be sure.
4028 strncpy(op, actualName, 13);
4029 if (smb_StoreAnsiFilenames)
4032 /* Uppercase if requested by client */
4033 if (!KNOWS_LONG_NAMES(inp))
4038 /* now, adjust the # of entries copied */
4040 } /* if we're including this name */
4043 /* and adjust curOffset to be where the new cookie is */
4044 thyper.HighPart = 0;
4045 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4046 curOffset = LargeIntegerAdd(thyper, curOffset);
4047 } /* while copying data for dir listing */
4049 /* release the mutex */
4050 lock_ReleaseMutex(&scp->mx);
4051 if (bufferp) buf_Release(bufferp);
4053 /* apply and free last set of patches; if not doing a star match, this
4054 * will be empty, but better safe (and freeing everything) than sorry.
4056 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4058 /* special return code for unsuccessful search */
4059 if (code == 0 && dataLength < 21 && returnedNames == 0)
4060 code = CM_ERROR_NOFILES;
4062 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4063 returnedNames, code);
4066 smb_DeleteDirSearch(dsp);
4067 smb_ReleaseDirSearch(dsp);
4068 cm_ReleaseSCache(scp);
4069 cm_ReleaseUser(userp);
4073 /* finalize the output buffer */
4074 smb_SetSMBParm(outp, 0, returnedNames);
4075 temp = (long) (op - origOp);
4076 smb_SetSMBDataLength(outp, temp);
4078 /* the data area is a variable block, which has a 5 (already there)
4079 * followed by the length of the # of data bytes. We now know this to
4080 * be "temp," although that includes the 3 bytes of vbl block header.
4081 * Deduct for them and fill in the length field.
4083 temp -= 3; /* deduct vbl block info */
4084 osi_assert(temp == (43 * returnedNames));
4085 origOp[1] = temp & 0xff;
4086 origOp[2] = (temp>>8) & 0xff;
4087 if (returnedNames == 0)
4088 smb_DeleteDirSearch(dsp);
4089 smb_ReleaseDirSearch(dsp);
4090 cm_ReleaseSCache(scp);
4091 cm_ReleaseUser(userp);
4095 /* verify that this is a valid path to a directory. I don't know why they
4096 * don't use the get file attributes call.
4098 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4102 cm_scache_t *rootScp;
4103 cm_scache_t *newScp;
4112 pathp = smb_GetSMBData(inp, NULL);
4113 pathp = smb_ParseASCIIBlock(pathp, NULL);
4115 return CM_ERROR_BADFD;
4116 if (smb_StoreAnsiFilenames)
4117 OemToChar(pathp,pathp);
4118 osi_Log1(smb_logp, "SMB receive check path %s",
4119 osi_LogSaveString(smb_logp, pathp));
4121 rootScp = cm_data.rootSCachep;
4123 userp = smb_GetUser(vcp, inp);
4125 caseFold = CM_FLAG_CASEFOLD;
4127 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4129 cm_ReleaseUser(userp);
4130 return CM_ERROR_NOSUCHPATH;
4132 code = cm_NameI(rootScp, pathp,
4133 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4134 userp, tidPathp, &req, &newScp);
4137 cm_ReleaseUser(userp);
4142 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4143 cm_ReleaseSCache(newScp);
4144 cm_ReleaseUser(userp);
4145 if ( WANTS_DFS_PATHNAMES(inp) )
4146 return CM_ERROR_PATH_NOT_COVERED;
4148 return CM_ERROR_BADSHARENAME;
4150 #endif /* DFS_SUPPORT */
4152 /* now lock the vnode with a callback; returns with newScp locked */
4153 lock_ObtainMutex(&newScp->mx);
4154 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4155 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4156 if (code && code != CM_ERROR_NOACCESS) {
4157 lock_ReleaseMutex(&newScp->mx);
4158 cm_ReleaseSCache(newScp);
4159 cm_ReleaseUser(userp);
4163 attrs = smb_Attributes(newScp);
4165 if (!(attrs & SMB_ATTR_DIRECTORY))
4166 code = CM_ERROR_NOTDIR;
4168 lock_ReleaseMutex(&newScp->mx);
4170 cm_ReleaseSCache(newScp);
4171 cm_ReleaseUser(userp);
4175 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4179 cm_scache_t *rootScp;
4180 unsigned short attribute;
4182 cm_scache_t *newScp;
4191 /* decode basic attributes we're passed */
4192 attribute = smb_GetSMBParm(inp, 0);
4193 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4195 pathp = smb_GetSMBData(inp, NULL);
4196 pathp = smb_ParseASCIIBlock(pathp, NULL);
4198 return CM_ERROR_BADSMB;
4199 if (smb_StoreAnsiFilenames)
4200 OemToChar(pathp,pathp);
4202 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4203 dosTime, attribute);
4205 rootScp = cm_data.rootSCachep;
4207 userp = smb_GetUser(vcp, inp);
4209 caseFold = CM_FLAG_CASEFOLD;
4211 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4213 cm_ReleaseUser(userp);
4214 return CM_ERROR_NOSUCHFILE;
4216 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4217 tidPathp, &req, &newScp);
4220 cm_ReleaseUser(userp);
4225 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4226 cm_ReleaseSCache(newScp);
4227 cm_ReleaseUser(userp);
4228 if ( WANTS_DFS_PATHNAMES(inp) )
4229 return CM_ERROR_PATH_NOT_COVERED;
4231 return CM_ERROR_BADSHARENAME;
4233 #endif /* DFS_SUPPORT */
4235 /* now lock the vnode with a callback; returns with newScp locked; we
4236 * need the current status to determine what the new status is, in some
4239 lock_ObtainMutex(&newScp->mx);
4240 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4241 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4243 lock_ReleaseMutex(&newScp->mx);
4244 cm_ReleaseSCache(newScp);
4245 cm_ReleaseUser(userp);
4249 /* Check for RO volume */
4250 if (newScp->flags & CM_SCACHEFLAG_RO) {
4251 lock_ReleaseMutex(&newScp->mx);
4252 cm_ReleaseSCache(newScp);
4253 cm_ReleaseUser(userp);
4254 return CM_ERROR_READONLY;
4257 /* prepare for setattr call */
4260 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4261 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4263 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4264 /* we're told to make a writable file read-only */
4265 attr.unixModeBits = newScp->unixModeBits & ~0222;
4266 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4268 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4269 /* we're told to make a read-only file writable */
4270 attr.unixModeBits = newScp->unixModeBits | 0222;
4271 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4273 lock_ReleaseMutex(&newScp->mx);
4275 /* now call setattr */
4277 code = cm_SetAttr(newScp, &attr, userp, &req);
4281 cm_ReleaseSCache(newScp);
4282 cm_ReleaseUser(userp);
4287 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4291 cm_scache_t *rootScp;
4292 cm_scache_t *newScp, *dscp;
4304 pathp = smb_GetSMBData(inp, NULL);
4305 pathp = smb_ParseASCIIBlock(pathp, NULL);
4307 return CM_ERROR_BADSMB;
4309 if (*pathp == 0) /* null path */
4312 if (smb_StoreAnsiFilenames)
4313 OemToChar(pathp,pathp);
4315 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4316 osi_LogSaveString(smb_logp, pathp));
4318 rootScp = cm_data.rootSCachep;
4320 userp = smb_GetUser(vcp, inp);
4322 /* we shouldn't need this for V3 requests, but we seem to */
4323 caseFold = CM_FLAG_CASEFOLD;
4325 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4327 cm_ReleaseUser(userp);
4328 return CM_ERROR_NOSUCHFILE;
4332 * XXX Strange hack XXX
4334 * As of Patch 5 (16 July 97), we are having the following problem:
4335 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4336 * requests to look up "desktop.ini" in all the subdirectories.
4337 * This can cause zillions of timeouts looking up non-existent cells
4338 * and volumes, especially in the top-level directory.
4340 * We have not found any way to avoid this or work around it except
4341 * to explicitly ignore the requests for mount points that haven't
4342 * yet been evaluated and for directories that haven't yet been
4345 * We should modify this hack to provide a fake desktop.ini file
4346 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4348 spacep = inp->spacep;
4349 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4350 #ifndef SPECIAL_FOLDERS
4351 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4352 code = cm_NameI(rootScp, spacep->data,
4353 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4354 userp, tidPathp, &req, &dscp);
4357 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4358 if ( WANTS_DFS_PATHNAMES(inp) )
4359 return CM_ERROR_PATH_NOT_COVERED;
4361 return CM_ERROR_BADSHARENAME;
4363 #endif /* DFS_SUPPORT */
4364 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4365 code = CM_ERROR_NOSUCHFILE;
4366 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4367 cm_buf_t *bp = buf_Find(dscp, &hzero);
4371 code = CM_ERROR_NOSUCHFILE;
4373 cm_ReleaseSCache(dscp);
4375 cm_ReleaseUser(userp);
4380 #endif /* SPECIAL_FOLDERS */
4382 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4383 tidPathp, &req, &newScp);
4385 cm_ReleaseUser(userp);
4390 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4391 cm_ReleaseSCache(newScp);
4392 cm_ReleaseUser(userp);
4393 if ( WANTS_DFS_PATHNAMES(inp) )
4394 return CM_ERROR_PATH_NOT_COVERED;
4396 return CM_ERROR_BADSHARENAME;
4398 #endif /* DFS_SUPPORT */
4400 /* now lock the vnode with a callback; returns with newScp locked */
4401 lock_ObtainMutex(&newScp->mx);
4402 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4403 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4405 lock_ReleaseMutex(&newScp->mx);
4406 cm_ReleaseSCache(newScp);
4407 cm_ReleaseUser(userp);
4412 /* use smb_Attributes instead. Also the fact that a file is
4413 * in a readonly volume doesn't mean it shojuld be marked as RO
4415 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4416 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4417 attrs = SMB_ATTR_DIRECTORY;
4420 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4421 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4423 attrs = smb_Attributes(newScp);
4426 smb_SetSMBParm(outp, 0, attrs);
4428 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4429 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4430 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4431 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4432 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4433 smb_SetSMBParm(outp, 5, 0);
4434 smb_SetSMBParm(outp, 6, 0);
4435 smb_SetSMBParm(outp, 7, 0);
4436 smb_SetSMBParm(outp, 8, 0);
4437 smb_SetSMBParm(outp, 9, 0);
4438 smb_SetSMBDataLength(outp, 0);
4439 lock_ReleaseMutex(&newScp->mx);
4441 cm_ReleaseSCache(newScp);
4442 cm_ReleaseUser(userp);
4447 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4451 osi_Log0(smb_logp, "SMB receive tree disconnect");
4453 /* find the tree and free it */
4454 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4456 lock_ObtainMutex(&tidp->mx);
4457 tidp->flags |= SMB_TIDFLAG_DELETE;
4458 lock_ReleaseMutex(&tidp->mx);
4459 smb_ReleaseTID(tidp);
4465 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4483 pathp = smb_GetSMBData(inp, NULL);
4484 pathp = smb_ParseASCIIBlock(pathp, NULL);
4485 if (smb_StoreAnsiFilenames)
4486 OemToChar(pathp,pathp);
4488 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4490 #ifdef DEBUG_VERBOSE
4494 hexpath = osi_HexifyString( pathp );
4495 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4500 share = smb_GetSMBParm(inp, 0);
4501 attribute = smb_GetSMBParm(inp, 1);
4503 spacep = inp->spacep;
4504 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4505 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4506 /* special case magic file name for receiving IOCTL requests
4507 * (since IOCTL calls themselves aren't getting through).
4509 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4510 smb_SetupIoctlFid(fidp, spacep);
4511 smb_SetSMBParm(outp, 0, fidp->fid);
4512 smb_SetSMBParm(outp, 1, 0); /* attrs */
4513 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4514 smb_SetSMBParm(outp, 3, 0);
4515 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4516 smb_SetSMBParm(outp, 5, 0x7fff);
4517 /* pass the open mode back */
4518 smb_SetSMBParm(outp, 6, (share & 0xf));
4519 smb_SetSMBDataLength(outp, 0);
4520 smb_ReleaseFID(fidp);
4524 userp = smb_GetUser(vcp, inp);
4526 caseFold = CM_FLAG_CASEFOLD;
4528 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4530 cm_ReleaseUser(userp);
4531 return CM_ERROR_NOSUCHPATH;
4533 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4534 tidPathp, &req, &scp);
4537 cm_ReleaseUser(userp);
4542 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4543 cm_ReleaseSCache(scp);
4544 cm_ReleaseUser(userp);
4545 if ( WANTS_DFS_PATHNAMES(inp) )
4546 return CM_ERROR_PATH_NOT_COVERED;
4548 return CM_ERROR_BADSHARENAME;
4550 #endif /* DFS_SUPPORT */
4552 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4554 cm_ReleaseSCache(scp);
4555 cm_ReleaseUser(userp);
4559 /* don't need callback to check file type, since file types never
4560 * change, and namei and cm_Lookup all stat the object at least once on
4561 * a successful return.
4563 if (scp->fileType != CM_SCACHETYPE_FILE) {
4564 cm_ReleaseSCache(scp);
4565 cm_ReleaseUser(userp);
4566 return CM_ERROR_ISDIR;
4569 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4572 /* save a pointer to the vnode */
4575 if ((share & 0xf) == 0)
4576 fidp->flags |= SMB_FID_OPENREAD;
4577 else if ((share & 0xf) == 1)
4578 fidp->flags |= SMB_FID_OPENWRITE;
4580 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4582 lock_ObtainMutex(&scp->mx);
4583 smb_SetSMBParm(outp, 0, fidp->fid);
4584 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4585 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4586 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4587 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4588 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4589 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4590 /* pass the open mode back; XXXX add access checks */
4591 smb_SetSMBParm(outp, 6, (share & 0xf));
4592 smb_SetSMBDataLength(outp, 0);
4593 lock_ReleaseMutex(&scp->mx);
4596 cm_Open(scp, 0, userp);
4598 /* send and free packet */
4599 smb_ReleaseFID(fidp);
4600 cm_ReleaseUser(userp);
4601 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4605 typedef struct smb_unlinkRock {
4610 char *maskp; /* pointer to the star pattern */
4615 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4618 smb_unlinkRock_t *rockp;
4626 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4627 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4628 caseFold |= CM_FLAG_8DOT3;
4630 matchName = dep->name;
4631 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4633 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4634 !cm_Is8Dot3(dep->name)) {
4635 cm_Gen8Dot3Name(dep, shortName, NULL);
4636 matchName = shortName;
4637 /* 8.3 matches are always case insensitive */
4638 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4641 osi_Log1(smb_logp, "Unlinking %s",
4642 osi_LogSaveString(smb_logp, matchName));
4643 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4644 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4645 smb_NotifyChange(FILE_ACTION_REMOVED,
4646 FILE_NOTIFY_CHANGE_FILE_NAME,
4647 dscp, dep->name, NULL, TRUE);
4651 /* If we made a case sensitive exact match, we might as well quit now. */
4652 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4653 code = CM_ERROR_STOPNOW;
4661 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4670 smb_unlinkRock_t rock;
4679 attribute = smb_GetSMBParm(inp, 0);
4681 tp = smb_GetSMBData(inp, NULL);
4682 pathp = smb_ParseASCIIBlock(tp, &tp);
4683 if (smb_StoreAnsiFilenames)
4684 OemToChar(pathp,pathp);
4686 osi_Log1(smb_logp, "SMB receive unlink %s",
4687 osi_LogSaveString(smb_logp, pathp));
4689 spacep = inp->spacep;
4690 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4692 userp = smb_GetUser(vcp, inp);
4694 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4696 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4698 cm_ReleaseUser(userp);
4699 return CM_ERROR_NOSUCHPATH;
4701 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4704 cm_ReleaseUser(userp);
4709 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4710 cm_ReleaseSCache(dscp);
4711 cm_ReleaseUser(userp);
4712 if ( WANTS_DFS_PATHNAMES(inp) )
4713 return CM_ERROR_PATH_NOT_COVERED;
4715 return CM_ERROR_BADSHARENAME;
4717 #endif /* DFS_SUPPORT */
4719 /* otherwise, scp points to the parent directory. */
4726 rock.maskp = smb_FindMask(pathp);
4727 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4730 thyper.HighPart = 0;
4736 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4737 * match. If that fails, we do a case insensitve match.
4739 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4740 !smb_IsStarMask(rock.maskp)) {
4741 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4744 thyper.HighPart = 0;
4745 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4750 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4752 if (code == CM_ERROR_STOPNOW)
4755 cm_ReleaseUser(userp);
4757 cm_ReleaseSCache(dscp);
4759 if (code == 0 && !rock.any)
4760 code = CM_ERROR_NOSUCHFILE;
4764 typedef struct smb_renameRock {
4765 cm_scache_t *odscp; /* old dir */
4766 cm_scache_t *ndscp; /* new dir */
4767 cm_user_t *userp; /* user */
4768 cm_req_t *reqp; /* request struct */
4769 smb_vc_t *vcp; /* virtual circuit */
4770 char *maskp; /* pointer to star pattern of old file name */
4771 int flags; /* tilde, casefold, etc */
4772 char *newNamep; /* ptr to the new file's name */
4775 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4778 smb_renameRock_t *rockp;
4783 rockp = (smb_renameRock_t *) vrockp;
4785 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4786 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4787 caseFold |= CM_FLAG_8DOT3;
4789 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4791 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4792 !cm_Is8Dot3(dep->name)) {
4793 cm_Gen8Dot3Name(dep, shortName, NULL);
4794 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4797 code = cm_Rename(rockp->odscp, dep->name,
4798 rockp->ndscp, rockp->newNamep, rockp->userp,
4800 /* if the call worked, stop doing the search now, since we
4801 * really only want to rename one file.
4804 code = CM_ERROR_STOPNOW;
4813 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4816 cm_space_t *spacep = NULL;
4817 smb_renameRock_t rock;
4818 cm_scache_t *oldDscp = NULL;
4819 cm_scache_t *newDscp = NULL;
4820 cm_scache_t *tmpscp= NULL;
4821 cm_scache_t *tmpscp2 = NULL;
4831 userp = smb_GetUser(vcp, inp);
4832 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4834 cm_ReleaseUser(userp);
4835 return CM_ERROR_NOSUCHPATH;
4839 spacep = inp->spacep;
4840 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4843 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4844 * what actually exists is foo/baz. I don't know why the code used to be
4845 * the way it was. 1/29/96
4847 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4849 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4851 * caseFold = CM_FLAG_CASEFOLD;
4853 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4854 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4855 userp, tidPathp, &req, &oldDscp);
4857 cm_ReleaseUser(userp);
4862 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4863 cm_ReleaseSCache(oldDscp);
4864 cm_ReleaseUser(userp);
4865 if ( WANTS_DFS_PATHNAMES(inp) )
4866 return CM_ERROR_PATH_NOT_COVERED;
4868 return CM_ERROR_BADSHARENAME;
4870 #endif /* DFS_SUPPORT */
4872 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4873 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4874 userp, tidPathp, &req, &newDscp);
4877 cm_ReleaseSCache(oldDscp);
4878 cm_ReleaseUser(userp);
4883 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4884 cm_ReleaseSCache(oldDscp);
4885 cm_ReleaseSCache(newDscp);
4886 cm_ReleaseUser(userp);
4887 if ( WANTS_DFS_PATHNAMES(inp) )
4888 return CM_ERROR_PATH_NOT_COVERED;
4890 return CM_ERROR_BADSHARENAME;
4892 #endif /* DFS_SUPPORT */
4895 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4896 * next, get the component names, and lower case them.
4899 /* handle the old name first */
4901 oldLastNamep = oldPathp;
4905 /* and handle the new name, too */
4907 newLastNamep = newPathp;
4911 /* TODO: The old name could be a wildcard. The new name must not be */
4913 /* do the vnode call */
4914 rock.odscp = oldDscp;
4915 rock.ndscp = newDscp;
4919 rock.maskp = oldLastNamep;
4920 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4921 rock.newNamep = newLastNamep;
4923 /* Check if the file already exists; if so return error */
4924 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4925 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4926 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4927 osi_LogSaveString(afsd_logp, newLastNamep));
4929 /* Check if the old and the new names differ only in case. If so return
4930 * success, else return CM_ERROR_EXISTS
4932 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4934 /* This would be a success only if the old file is *as same as* the new file */
4935 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4937 if (tmpscp == tmpscp2)
4940 code = CM_ERROR_EXISTS;
4941 cm_ReleaseSCache(tmpscp2);
4944 code = CM_ERROR_NOSUCHFILE;
4947 /* file exist, do not rename, also fixes move */
4948 osi_Log0(smb_logp, "Can't rename. Target already exists");
4949 code = CM_ERROR_EXISTS;
4953 cm_ReleaseSCache(tmpscp);
4954 cm_ReleaseSCache(newDscp);
4955 cm_ReleaseSCache(oldDscp);
4956 cm_ReleaseUser(userp);
4960 /* Now search the directory for the pattern, and do the appropriate rename when found */
4961 thyper.LowPart = 0; /* search dir from here */
4962 thyper.HighPart = 0;
4964 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4966 if (code == CM_ERROR_STOPNOW)
4969 code = CM_ERROR_NOSUCHFILE;
4971 /* Handle Change Notification */
4973 * Being lazy, not distinguishing between files and dirs in this
4974 * filter, since we'd have to do a lookup.
4976 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4977 if (oldDscp == newDscp) {
4978 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4979 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4980 filter, oldDscp, oldLastNamep,
4981 newLastNamep, TRUE);
4983 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4984 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4985 filter, oldDscp, oldLastNamep,
4987 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4988 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4989 filter, newDscp, newLastNamep,
4994 cm_ReleaseSCache(tmpscp);
4995 cm_ReleaseUser(userp);
4996 cm_ReleaseSCache(oldDscp);
4997 cm_ReleaseSCache(newDscp);
5002 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5005 cm_space_t *spacep = NULL;
5006 cm_scache_t *oldDscp = NULL;
5007 cm_scache_t *newDscp = NULL;
5008 cm_scache_t *tmpscp= NULL;
5009 cm_scache_t *tmpscp2 = NULL;
5010 cm_scache_t *sscp = NULL;
5019 userp = smb_GetUser(vcp, inp);
5021 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5023 cm_ReleaseUser(userp);
5024 return CM_ERROR_NOSUCHPATH;
5029 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5031 spacep = inp->spacep;
5032 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5034 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5035 userp, tidPathp, &req, &oldDscp);
5037 cm_ReleaseUser(userp);
5042 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5043 cm_ReleaseSCache(oldDscp);
5044 cm_ReleaseUser(userp);
5045 if ( WANTS_DFS_PATHNAMES(inp) )
5046 return CM_ERROR_PATH_NOT_COVERED;
5048 return CM_ERROR_BADSHARENAME;
5050 #endif /* DFS_SUPPORT */
5052 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5053 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5054 userp, tidPathp, &req, &newDscp);
5056 cm_ReleaseSCache(oldDscp);
5057 cm_ReleaseUser(userp);
5062 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5063 cm_ReleaseSCache(newDscp);
5064 cm_ReleaseSCache(oldDscp);
5065 cm_ReleaseUser(userp);
5066 if ( WANTS_DFS_PATHNAMES(inp) )
5067 return CM_ERROR_PATH_NOT_COVERED;
5069 return CM_ERROR_BADSHARENAME;
5071 #endif /* DFS_SUPPORT */
5073 /* Now, although we did two lookups for the two directories (because the same
5074 * directory can be referenced through different paths), we only allow hard links
5075 * within the same directory. */
5076 if (oldDscp != newDscp) {
5077 cm_ReleaseSCache(oldDscp);
5078 cm_ReleaseSCache(newDscp);
5079 cm_ReleaseUser(userp);
5080 return CM_ERROR_CROSSDEVLINK;
5083 /* handle the old name first */
5085 oldLastNamep = oldPathp;
5089 /* and handle the new name, too */
5091 newLastNamep = newPathp;
5095 /* now lookup the old name */
5096 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5097 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5099 cm_ReleaseSCache(oldDscp);
5100 cm_ReleaseSCache(newDscp);
5101 cm_ReleaseUser(userp);
5105 /* Check if the file already exists; if so return error */
5106 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5107 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5108 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5109 osi_LogSaveString(afsd_logp, newLastNamep));
5111 /* if the existing link is to the same file, then we return success */
5113 if(sscp == tmpscp) {
5116 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5117 code = CM_ERROR_EXISTS;
5122 cm_ReleaseSCache(tmpscp);
5123 cm_ReleaseSCache(sscp);
5124 cm_ReleaseSCache(newDscp);
5125 cm_ReleaseSCache(oldDscp);
5126 cm_ReleaseUser(userp);
5130 /* now create the hardlink */
5131 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5132 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5133 osi_Log1(smb_logp," Link returns %d", code);
5135 /* Handle Change Notification */
5137 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5138 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5139 smb_NotifyChange(FILE_ACTION_ADDED,
5140 filter, newDscp, newLastNamep,
5145 cm_ReleaseSCache(tmpscp);
5146 cm_ReleaseUser(userp);
5147 cm_ReleaseSCache(sscp);
5148 cm_ReleaseSCache(oldDscp);
5149 cm_ReleaseSCache(newDscp);
5154 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5160 tp = smb_GetSMBData(inp, NULL);
5161 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5162 if (smb_StoreAnsiFilenames)
5163 OemToChar(oldPathp,oldPathp);
5164 newPathp = smb_ParseASCIIBlock(tp, &tp);
5165 if (smb_StoreAnsiFilenames)
5166 OemToChar(newPathp,newPathp);
5168 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5169 osi_LogSaveString(smb_logp, oldPathp),
5170 osi_LogSaveString(smb_logp, newPathp));
5172 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5177 typedef struct smb_rmdirRock {
5181 char *maskp; /* pointer to the star pattern */
5186 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5189 smb_rmdirRock_t *rockp;
5194 rockp = (smb_rmdirRock_t *) vrockp;
5196 matchName = dep->name;
5197 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5198 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5200 match = (strcmp(matchName, rockp->maskp) == 0);
5202 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5203 !cm_Is8Dot3(dep->name)) {
5204 cm_Gen8Dot3Name(dep, shortName, NULL);
5205 matchName = shortName;
5206 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5209 osi_Log1(smb_logp, "Removing directory %s",
5210 osi_LogSaveString(smb_logp, matchName));
5211 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5212 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5213 smb_NotifyChange(FILE_ACTION_REMOVED,
5214 FILE_NOTIFY_CHANGE_DIR_NAME,
5215 dscp, dep->name, NULL, TRUE);
5224 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5232 smb_rmdirRock_t rock;
5241 tp = smb_GetSMBData(inp, NULL);
5242 pathp = smb_ParseASCIIBlock(tp, &tp);
5243 if (smb_StoreAnsiFilenames)
5244 OemToChar(pathp,pathp);
5246 spacep = inp->spacep;
5247 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5249 userp = smb_GetUser(vcp, inp);
5251 caseFold = CM_FLAG_CASEFOLD;
5253 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5255 cm_ReleaseUser(userp);
5256 return CM_ERROR_NOSUCHPATH;
5258 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5259 userp, tidPathp, &req, &dscp);
5262 cm_ReleaseUser(userp);
5267 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5268 cm_ReleaseSCache(dscp);
5269 cm_ReleaseUser(userp);
5270 if ( WANTS_DFS_PATHNAMES(inp) )
5271 return CM_ERROR_PATH_NOT_COVERED;
5273 return CM_ERROR_BADSHARENAME;
5275 #endif /* DFS_SUPPORT */
5277 /* otherwise, scp points to the parent directory. */
5284 rock.maskp = lastNamep;
5285 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5288 thyper.HighPart = 0;
5292 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5293 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5294 if (code == 0 && !rock.any) {
5296 thyper.HighPart = 0;
5297 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5298 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5301 cm_ReleaseUser(userp);
5303 cm_ReleaseSCache(dscp);
5305 if (code == 0 && !rock.any)
5306 code = CM_ERROR_NOSUCHFILE;
5310 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5320 fid = smb_GetSMBParm(inp, 0);
5322 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5324 fid = smb_ChainFID(fid, inp);
5325 fidp = smb_FindFID(vcp, fid, 0);
5326 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5328 smb_ReleaseFID(fidp);
5329 return CM_ERROR_BADFD;
5332 userp = smb_GetUser(vcp, inp);
5334 lock_ObtainMutex(&fidp->mx);
5335 if (fidp->flags & SMB_FID_OPENWRITE)
5336 code = cm_FSync(fidp->scp, userp, &req);
5339 lock_ReleaseMutex(&fidp->mx);
5341 smb_ReleaseFID(fidp);
5343 cm_ReleaseUser(userp);
5348 struct smb_FullNameRock {
5354 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5358 struct smb_FullNameRock *vrockp;
5360 vrockp = (struct smb_FullNameRock *)rockp;
5362 if (!cm_Is8Dot3(dep->name)) {
5363 cm_Gen8Dot3Name(dep, shortName, NULL);
5365 if (cm_stricmp(shortName, vrockp->name) == 0) {
5366 vrockp->fullName = strdup(dep->name);
5367 return CM_ERROR_STOPNOW;
5370 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5371 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5372 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5373 vrockp->fullName = strdup(dep->name);
5374 return CM_ERROR_STOPNOW;
5379 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5380 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5382 struct smb_FullNameRock rock;
5388 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5389 if (code == CM_ERROR_STOPNOW)
5390 *newPathp = rock.fullName;
5392 *newPathp = strdup(pathp);
5395 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5406 fid = smb_GetSMBParm(inp, 0);
5407 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5409 osi_Log1(smb_logp, "SMB close fid %d", fid);
5411 fid = smb_ChainFID(fid, inp);
5412 fidp = smb_FindFID(vcp, fid, 0);
5414 return CM_ERROR_BADFD;
5417 userp = smb_GetUser(vcp, inp);
5419 lock_ObtainMutex(&fidp->mx);
5421 /* Don't jump the gun on an async raw write */
5422 while (fidp->raw_writers) {
5423 lock_ReleaseMutex(&fidp->mx);
5424 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5425 lock_ObtainMutex(&fidp->mx);
5428 fidp->flags |= SMB_FID_DELETE;
5430 /* watch for ioctl closes, and read-only opens */
5431 if (fidp->scp != NULL &&
5432 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5433 == SMB_FID_OPENWRITE) {
5434 if (dosTime != 0 && dosTime != -1) {
5435 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5436 /* This fixes defect 10958 */
5437 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5438 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5440 code = cm_FSync(fidp->scp, userp, &req);
5445 /* unlock any pending locks */
5446 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5447 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5453 pid = ((smb_t *) inp)->pid;
5454 key = cm_GenerateKey(vcp->vcID, pid, fid);
5457 lock_ObtainMutex(&scp->mx);
5459 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5460 CM_SCACHESYNC_NEEDCALLBACK
5461 | CM_SCACHESYNC_GETSTATUS
5462 | CM_SCACHESYNC_LOCK);
5465 osi_Log1(smb_logp, "smb CoreClose SyncOp failure code 0x%x", tcode);
5466 goto post_syncopdone;
5469 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5471 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5475 lock_ReleaseMutex(&scp->mx);
5476 cm_ReleaseSCache(scp);
5479 if (fidp->flags & SMB_FID_DELONCLOSE) {
5480 cm_scache_t *dscp = fidp->NTopen_dscp;
5481 char *pathp = fidp->NTopen_pathp;
5484 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5485 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5486 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5487 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5488 smb_NotifyChange(FILE_ACTION_REMOVED,
5489 FILE_NOTIFY_CHANGE_DIR_NAME,
5490 dscp, fullPathp, NULL, TRUE);
5494 code = cm_Unlink(dscp, fullPathp, userp, &req);
5495 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5496 smb_NotifyChange(FILE_ACTION_REMOVED,
5497 FILE_NOTIFY_CHANGE_FILE_NAME,
5498 dscp, fullPathp, NULL, TRUE);
5502 lock_ReleaseMutex(&fidp->mx);
5504 if (fidp->flags & SMB_FID_NTOPEN) {
5505 cm_ReleaseSCache(fidp->NTopen_dscp);
5506 free(fidp->NTopen_pathp);
5508 if (fidp->NTopen_wholepathp)
5509 free(fidp->NTopen_wholepathp);
5511 smb_ReleaseFID(fidp);
5512 cm_ReleaseUser(userp);
5517 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5520 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5521 cm_user_t *userp, long *readp)
5523 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5524 cm_user_t *userp, long *readp, int dosflag)
5531 osi_hyper_t fileLength;
5533 osi_hyper_t lastByte;
5534 osi_hyper_t bufferOffset;
5535 long bufIndex, nbytes;
5545 lock_ObtainMutex(&fidp->mx);
5547 lock_ObtainMutex(&scp->mx);
5549 if (offset.HighPart == 0) {
5550 chunk = offset.LowPart >> cm_logChunkSize;
5551 if (chunk != fidp->curr_chunk) {
5552 fidp->prev_chunk = fidp->curr_chunk;
5553 fidp->curr_chunk = chunk;
5555 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5559 /* start by looking up the file's end */
5560 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5561 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5562 if (code) goto done;
5564 /* now we have the entry locked, look up the length */
5565 fileLength = scp->length;
5567 /* adjust count down so that it won't go past EOF */
5568 thyper.LowPart = count;
5569 thyper.HighPart = 0;
5570 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5572 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5573 /* we'd read past EOF, so just stop at fileLength bytes.
5574 * Start by computing how many bytes remain in the file.
5576 thyper = LargeIntegerSubtract(fileLength, offset);
5578 /* if we are past EOF, read 0 bytes */
5579 if (LargeIntegerLessThanZero(thyper))
5582 count = thyper.LowPart;
5587 /* now, copy the data one buffer at a time,
5588 * until we've filled the request packet
5591 /* if we've copied all the data requested, we're done */
5592 if (count <= 0) break;
5594 /* otherwise, load up a buffer of data */
5595 thyper.HighPart = offset.HighPart;
5596 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5597 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5600 buf_Release(bufferp);
5603 lock_ReleaseMutex(&scp->mx);
5605 lock_ObtainRead(&scp->bufCreateLock);
5606 code = buf_Get(scp, &thyper, &bufferp);
5607 lock_ReleaseRead(&scp->bufCreateLock);
5609 lock_ObtainMutex(&scp->mx);
5610 if (code) goto done;
5611 bufferOffset = thyper;
5613 /* now get the data in the cache */
5615 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5616 CM_SCACHESYNC_NEEDCALLBACK |
5617 CM_SCACHESYNC_READ);
5618 if (code) goto done;
5620 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5622 /* otherwise, load the buffer and try again */
5623 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5627 buf_Release(bufferp);
5631 } /* if (wrong buffer) ... */
5633 /* now we have the right buffer loaded. Copy out the
5634 * data from here to the user's buffer.
5636 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5638 /* and figure out how many bytes we want from this buffer */
5639 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5640 if (nbytes > count) nbytes = count; /* don't go past EOF */
5642 /* now copy the data */
5645 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5648 memcpy(op, bufferp->datap + bufIndex, nbytes);
5650 /* adjust counters, pointers, etc. */
5653 thyper.LowPart = nbytes;
5654 thyper.HighPart = 0;
5655 offset = LargeIntegerAdd(thyper, offset);
5659 lock_ReleaseMutex(&scp->mx);
5660 lock_ReleaseMutex(&fidp->mx);
5662 buf_Release(bufferp);
5664 if (code == 0 && sequential)
5665 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5671 * smb_WriteData -- common code for Write and Raw Write
5674 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5675 cm_user_t *userp, long *writtenp)
5677 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5678 cm_user_t *userp, long *writtenp, int dosflag)
5685 osi_hyper_t fileLength; /* file's length at start of write */
5686 osi_hyper_t minLength; /* don't read past this */
5687 long nbytes; /* # of bytes to transfer this iteration */
5689 osi_hyper_t thyper; /* hyper tmp variable */
5690 osi_hyper_t bufferOffset;
5691 long bufIndex; /* index in buffer where our data is */
5693 osi_hyper_t writeBackOffset;/* offset of region to write back when
5698 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5699 fidp->fid, offsetp->LowPart, count);
5709 lock_ObtainMutex(&fidp->mx);
5711 lock_ObtainMutex(&scp->mx);
5713 /* start by looking up the file's end */
5714 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5715 CM_SCACHESYNC_NEEDCALLBACK
5716 | CM_SCACHESYNC_SETSTATUS
5717 | CM_SCACHESYNC_GETSTATUS);
5721 /* make sure we have a writable FD */
5722 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5723 code = CM_ERROR_BADFDOP;
5727 /* now we have the entry locked, look up the length */
5728 fileLength = scp->length;
5729 minLength = fileLength;
5730 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5731 minLength = scp->serverLength;
5733 /* adjust file length if we extend past EOF */
5734 thyper.LowPart = count;
5735 thyper.HighPart = 0;
5736 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5737 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5738 /* we'd write past EOF, so extend the file */
5739 scp->mask |= CM_SCACHEMASK_LENGTH;
5740 scp->length = thyper;
5741 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5743 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5745 /* now, if the new position (thyper) and the old (offset) are in
5746 * different storeback windows, remember to store back the previous
5747 * storeback window when we're done with the write.
5749 if ((thyper.LowPart & (-cm_chunkSize)) !=
5750 (offset.LowPart & (-cm_chunkSize))) {
5751 /* they're different */
5753 writeBackOffset.HighPart = offset.HighPart;
5754 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5759 /* now, copy the data one buffer at a time, until we've filled the
5762 /* if we've copied all the data requested, we're done */
5766 /* handle over quota or out of space */
5767 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5768 *writtenp = written;
5769 code = CM_ERROR_QUOTA;
5773 /* otherwise, load up a buffer of data */
5774 thyper.HighPart = offset.HighPart;
5775 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5776 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5779 lock_ReleaseMutex(&bufferp->mx);
5780 buf_Release(bufferp);
5783 lock_ReleaseMutex(&scp->mx);
5785 lock_ObtainRead(&scp->bufCreateLock);
5786 code = buf_Get(scp, &thyper, &bufferp);
5787 lock_ReleaseRead(&scp->bufCreateLock);
5789 lock_ObtainMutex(&bufferp->mx);
5790 lock_ObtainMutex(&scp->mx);
5791 if (code) goto done;
5793 bufferOffset = thyper;
5795 /* now get the data in the cache */
5797 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5798 CM_SCACHESYNC_NEEDCALLBACK
5799 | CM_SCACHESYNC_WRITE
5800 | CM_SCACHESYNC_BUFLOCKED);
5804 /* If we're overwriting the entire buffer, or
5805 * if we're writing at or past EOF, mark the
5806 * buffer as current so we don't call
5807 * cm_GetBuffer. This skips the fetch from the
5808 * server in those cases where we're going to
5809 * obliterate all the data in the buffer anyway,
5810 * or in those cases where there is no useful
5811 * data at the server to start with.
5813 * Use minLength instead of scp->length, since
5814 * the latter has already been updated by this
5817 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5818 || LargeIntegerEqualTo(offset, bufferp->offset)
5819 && (count >= cm_data.buf_blockSize
5820 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5821 ConvertLongToLargeInteger(count)),
5823 if (count < cm_data.buf_blockSize
5824 && bufferp->dataVersion == -1)
5825 memset(bufferp->datap, 0,
5826 cm_data.buf_blockSize);
5827 bufferp->dataVersion = scp->dataVersion;
5830 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5832 /* otherwise, load the buffer and try again */
5833 lock_ReleaseMutex(&bufferp->mx);
5834 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5836 lock_ReleaseMutex(&scp->mx);
5837 lock_ObtainMutex(&bufferp->mx);
5838 lock_ObtainMutex(&scp->mx);
5842 lock_ReleaseMutex(&bufferp->mx);
5843 buf_Release(bufferp);
5847 } /* if (wrong buffer) ... */
5849 /* now we have the right buffer loaded. Copy out the
5850 * data from here to the user's buffer.
5852 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5854 /* and figure out how many bytes we want from this buffer */
5855 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5857 nbytes = count; /* don't go past end of request */
5859 /* now copy the data */
5862 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5865 memcpy(bufferp->datap + bufIndex, op, nbytes);
5866 buf_SetDirty(bufferp);
5868 /* and record the last writer */
5869 if (bufferp->userp != userp) {
5872 cm_ReleaseUser(bufferp->userp);
5873 bufferp->userp = userp;
5876 /* adjust counters, pointers, etc. */
5880 thyper.LowPart = nbytes;
5881 thyper.HighPart = 0;
5882 offset = LargeIntegerAdd(thyper, offset);
5886 lock_ReleaseMutex(&scp->mx);
5887 lock_ReleaseMutex(&fidp->mx);
5889 lock_ReleaseMutex(&bufferp->mx);
5890 buf_Release(bufferp);
5893 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5894 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5895 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5896 fidp->NTopen_dscp, fidp->NTopen_pathp,
5900 if (code == 0 && doWriteBack) {
5902 lock_ObtainMutex(&scp->mx);
5903 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5905 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5906 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5908 lock_ReleaseMutex(&scp->mx);
5909 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5910 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5913 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5914 fidp->fid, code, *writtenp);
5918 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5921 long count, written = 0, total_written = 0;
5927 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5929 int inDataBlockCount;
5931 fd = smb_GetSMBParm(inp, 0);
5932 count = smb_GetSMBParm(inp, 1);
5933 offset.HighPart = 0; /* too bad */
5934 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5936 op = smb_GetSMBData(inp, NULL);
5937 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5939 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5940 fd, offset.LowPart, count);
5942 fd = smb_ChainFID(fd, inp);
5943 fidp = smb_FindFID(vcp, fd, 0);
5945 return CM_ERROR_BADFD;
5948 if (fidp->flags & SMB_FID_IOCTL)
5949 return smb_IoctlWrite(fidp, vcp, inp, outp);
5951 userp = smb_GetUser(vcp, inp);
5953 /* special case: 0 bytes transferred means truncate to this position */
5959 truncAttr.mask = CM_ATTRMASK_LENGTH;
5960 truncAttr.length.LowPart = offset.LowPart;
5961 truncAttr.length.HighPart = 0;
5962 lock_ObtainMutex(&fidp->mx);
5963 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5964 lock_ReleaseMutex(&fidp->mx);
5965 smb_SetSMBParm(outp, 0, /* count */ 0);
5966 smb_SetSMBDataLength(outp, 0);
5967 fidp->flags |= SMB_FID_LENGTHSETDONE;
5973 LARGE_INTEGER LOffset;
5974 LARGE_INTEGER LLength;
5976 pid = ((smb_t *) inp)->pid;
5977 key = cm_GenerateKey(vcp->vcID, pid, fd);
5979 LOffset.HighPart = offset.HighPart;
5980 LOffset.LowPart = offset.LowPart;
5981 LLength.HighPart = 0;
5982 LLength.LowPart = count;
5984 lock_ObtainMutex(&fidp->scp->mx);
5985 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5986 lock_ReleaseMutex(&fidp->scp->mx);
5993 * Work around bug in NT client
5995 * When copying a file, the NT client should first copy the data,
5996 * then copy the last write time. But sometimes the NT client does
5997 * these in the wrong order, so the data copies would inadvertently
5998 * cause the last write time to be overwritten. We try to detect this,
5999 * and don't set client mod time if we think that would go against the
6002 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6003 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6004 fidp->scp->clientModTime = time(NULL);
6008 while ( code == 0 && count > 0 ) {
6010 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6012 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6014 if (code == 0 && written == 0)
6015 code = CM_ERROR_PARTIALWRITE;
6017 offset.LowPart += written;
6019 total_written += written;
6023 /* set the packet data length to 3 bytes for the data block header,
6024 * plus the size of the data.
6026 smb_SetSMBParm(outp, 0, total_written);
6027 smb_SetSMBDataLength(outp, 0);
6030 smb_ReleaseFID(fidp);
6031 cm_ReleaseUser(userp);
6036 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6037 NCB *ncbp, raw_write_cont_t *rwcp)
6050 fd = smb_GetSMBParm(inp, 0);
6051 fidp = smb_FindFID(vcp, fd, 0);
6053 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6054 rwcp->offset.LowPart, rwcp->count);
6056 userp = smb_GetUser(vcp, inp);
6060 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6063 rawBuf = (dos_ptr) rwcp->buf;
6064 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6065 (unsigned char *) rawBuf, userp,
6069 if (rwcp->writeMode & 0x1) { /* synchronous */
6072 smb_FormatResponsePacket(vcp, inp, outp);
6073 op = (smb_t *) outp;
6074 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6075 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6076 smb_SetSMBDataLength(outp, 0);
6077 smb_SendPacket(vcp, outp);
6078 smb_FreePacket(outp);
6080 else { /* asynchronous */
6081 lock_ObtainMutex(&fidp->mx);
6082 fidp->raw_writers--;
6083 if (fidp->raw_writers == 0)
6084 thrd_SetEvent(fidp->raw_write_event);
6085 lock_ReleaseMutex(&fidp->mx);
6088 /* Give back raw buffer */
6089 lock_ObtainMutex(&smb_RawBufLock);
6091 *((char **)rawBuf) = smb_RawBufs;
6093 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6095 smb_RawBufs = rawBuf;
6096 lock_ReleaseMutex(&smb_RawBufLock);
6098 smb_ReleaseFID(fidp);
6099 cm_ReleaseUser(userp);
6102 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6107 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6110 long count, written = 0, total_written = 0;
6117 unsigned short writeMode;
6124 fd = smb_GetSMBParm(inp, 0);
6125 totalCount = smb_GetSMBParm(inp, 1);
6126 count = smb_GetSMBParm(inp, 10);
6127 offset.HighPart = 0; /* too bad */
6128 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6129 writeMode = smb_GetSMBParm(inp, 7);
6131 op = (char *) inp->data;
6132 op += smb_GetSMBParm(inp, 11);
6135 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6136 fd, offset.LowPart, count, writeMode);
6138 fd = smb_ChainFID(fd, inp);
6139 fidp = smb_FindFID(vcp, fd, 0);
6141 return CM_ERROR_BADFD;
6147 LARGE_INTEGER LOffset;
6148 LARGE_INTEGER LLength;
6150 pid = ((smb_t *) inp)->pid;
6151 key = cm_GenerateKey(vcp->vcID, pid, fd);
6153 LOffset.HighPart = offset.HighPart;
6154 LOffset.LowPart = offset.LowPart;
6155 LLength.HighPart = 0;
6156 LLength.LowPart = count;
6158 lock_ObtainMutex(&fidp->scp->mx);
6159 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6160 lock_ReleaseMutex(&fidp->scp->mx);
6163 smb_ReleaseFID(fidp);
6168 userp = smb_GetUser(vcp, inp);
6171 * Work around bug in NT client
6173 * When copying a file, the NT client should first copy the data,
6174 * then copy the last write time. But sometimes the NT client does
6175 * these in the wrong order, so the data copies would inadvertently
6176 * cause the last write time to be overwritten. We try to detect this,
6177 * and don't set client mod time if we think that would go against the
6180 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6181 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6182 fidp->scp->clientModTime = time(NULL);
6186 while ( code == 0 && count > 0 ) {
6188 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6190 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6192 if (code == 0 && written == 0)
6193 code = CM_ERROR_PARTIALWRITE;
6195 offset.LowPart += written;
6197 total_written += written;
6201 /* Get a raw buffer */
6204 lock_ObtainMutex(&smb_RawBufLock);
6206 /* Get a raw buf, from head of list */
6207 rawBuf = smb_RawBufs;
6209 smb_RawBufs = *(char **)smb_RawBufs;
6211 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6215 code = CM_ERROR_USESTD;
6217 lock_ReleaseMutex(&smb_RawBufLock);
6220 /* Don't allow a premature Close */
6221 if (code == 0 && (writeMode & 1) == 0) {
6222 lock_ObtainMutex(&fidp->mx);
6223 fidp->raw_writers++;
6224 thrd_ResetEvent(fidp->raw_write_event);
6225 lock_ReleaseMutex(&fidp->mx);
6228 smb_ReleaseFID(fidp);
6229 cm_ReleaseUser(userp);
6232 smb_SetSMBParm(outp, 0, total_written);
6233 smb_SetSMBDataLength(outp, 0);
6234 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6241 rwcp->offset.HighPart = 0;
6242 rwcp->offset.LowPart = offset.LowPart + count;
6243 rwcp->count = totalCount - count;
6244 rwcp->writeMode = writeMode;
6245 rwcp->alreadyWritten = total_written;
6247 /* set the packet data length to 3 bytes for the data block header,
6248 * plus the size of the data.
6250 smb_SetSMBParm(outp, 0, 0xffff);
6251 smb_SetSMBDataLength(outp, 0);
6256 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6259 long count, finalCount;
6267 fd = smb_GetSMBParm(inp, 0);
6268 count = smb_GetSMBParm(inp, 1);
6269 offset.HighPart = 0; /* too bad */
6270 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6272 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6273 fd, offset.LowPart, count);
6275 fd = smb_ChainFID(fd, inp);
6276 fidp = smb_FindFID(vcp, fd, 0);
6278 return CM_ERROR_BADFD;
6281 if (fidp->flags & SMB_FID_IOCTL) {
6282 return smb_IoctlRead(fidp, vcp, inp, outp);
6286 LARGE_INTEGER LOffset, LLength;
6289 pid = ((smb_t *) inp)->pid;
6290 key = cm_GenerateKey(vcp->vcID, pid, fd);
6292 LOffset.HighPart = 0;
6293 LOffset.LowPart = offset.LowPart;
6294 LLength.HighPart = 0;
6295 LLength.LowPart = count;
6297 lock_ObtainMutex(&fidp->scp->mx);
6298 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6299 lock_ReleaseMutex(&fidp->scp->mx);
6302 smb_ReleaseFID(fidp);
6306 userp = smb_GetUser(vcp, inp);
6308 /* remember this for final results */
6309 smb_SetSMBParm(outp, 0, count);
6310 smb_SetSMBParm(outp, 1, 0);
6311 smb_SetSMBParm(outp, 2, 0);
6312 smb_SetSMBParm(outp, 3, 0);
6313 smb_SetSMBParm(outp, 4, 0);
6315 /* set the packet data length to 3 bytes for the data block header,
6316 * plus the size of the data.
6318 smb_SetSMBDataLength(outp, count+3);
6320 /* get op ptr after putting in the parms, since otherwise we don't
6321 * know where the data really is.
6323 op = smb_GetSMBData(outp, NULL);
6325 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6326 *op++ = 1; /* data block marker */
6327 *op++ = (unsigned char) (count & 0xff);
6328 *op++ = (unsigned char) ((count >> 8) & 0xff);
6331 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6333 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6336 /* fix some things up */
6337 smb_SetSMBParm(outp, 0, finalCount);
6338 smb_SetSMBDataLength(outp, finalCount+3);
6340 smb_ReleaseFID(fidp);
6342 cm_ReleaseUser(userp);
6346 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6353 cm_scache_t *dscp; /* dir we're dealing with */
6354 cm_scache_t *scp; /* file we're creating */
6356 int initialModeBits;
6366 /* compute initial mode bits based on read-only flag in attributes */
6367 initialModeBits = 0777;
6369 tp = smb_GetSMBData(inp, NULL);
6370 pathp = smb_ParseASCIIBlock(tp, &tp);
6371 if (smb_StoreAnsiFilenames)
6372 OemToChar(pathp,pathp);
6374 if (strcmp(pathp, "\\") == 0)
6375 return CM_ERROR_EXISTS;
6377 spacep = inp->spacep;
6378 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6380 userp = smb_GetUser(vcp, inp);
6382 caseFold = CM_FLAG_CASEFOLD;
6384 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6386 cm_ReleaseUser(userp);
6387 return CM_ERROR_NOSUCHPATH;
6390 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6391 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6392 userp, tidPathp, &req, &dscp);
6395 cm_ReleaseUser(userp);
6400 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6401 cm_ReleaseSCache(dscp);
6402 cm_ReleaseUser(userp);
6403 if ( WANTS_DFS_PATHNAMES(inp) )
6404 return CM_ERROR_PATH_NOT_COVERED;
6406 return CM_ERROR_BADSHARENAME;
6408 #endif /* DFS_SUPPORT */
6410 /* otherwise, scp points to the parent directory. Do a lookup, and
6411 * fail if we find it. Otherwise, we do the create.
6417 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6418 if (scp) cm_ReleaseSCache(scp);
6419 if (code != CM_ERROR_NOSUCHFILE) {
6420 if (code == 0) code = CM_ERROR_EXISTS;
6421 cm_ReleaseSCache(dscp);
6422 cm_ReleaseUser(userp);
6426 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6427 setAttr.clientModTime = time(NULL);
6428 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6429 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6430 smb_NotifyChange(FILE_ACTION_ADDED,
6431 FILE_NOTIFY_CHANGE_DIR_NAME,
6432 dscp, lastNamep, NULL, TRUE);
6434 /* we don't need this any longer */
6435 cm_ReleaseSCache(dscp);
6438 /* something went wrong creating or truncating the file */
6439 cm_ReleaseUser(userp);
6443 /* otherwise we succeeded */
6444 smb_SetSMBDataLength(outp, 0);
6445 cm_ReleaseUser(userp);
6450 BOOL smb_IsLegalFilename(char *filename)
6453 * Find the longest substring of filename that does not contain
6454 * any of the chars in illegalChars. If that substring is less
6455 * than the length of the whole string, then one or more of the
6456 * illegal chars is in filename.
6458 if (strcspn(filename, illegalChars) < strlen(filename))
6464 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6472 cm_scache_t *dscp; /* dir we're dealing with */
6473 cm_scache_t *scp; /* file we're creating */
6475 int initialModeBits;
6487 excl = (inp->inCom == 0x03)? 0 : 1;
6489 attributes = smb_GetSMBParm(inp, 0);
6490 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6492 /* compute initial mode bits based on read-only flag in attributes */
6493 initialModeBits = 0666;
6494 if (attributes & 1) initialModeBits &= ~0222;
6496 tp = smb_GetSMBData(inp, NULL);
6497 pathp = smb_ParseASCIIBlock(tp, &tp);
6498 if (smb_StoreAnsiFilenames)
6499 OemToChar(pathp,pathp);
6501 spacep = inp->spacep;
6502 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6504 userp = smb_GetUser(vcp, inp);
6506 caseFold = CM_FLAG_CASEFOLD;
6508 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6510 cm_ReleaseUser(userp);
6511 return CM_ERROR_NOSUCHPATH;
6513 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6514 userp, tidPathp, &req, &dscp);
6517 cm_ReleaseUser(userp);
6522 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6523 cm_ReleaseSCache(dscp);
6524 cm_ReleaseUser(userp);
6525 if ( WANTS_DFS_PATHNAMES(inp) )
6526 return CM_ERROR_PATH_NOT_COVERED;
6528 return CM_ERROR_BADSHARENAME;
6530 #endif /* DFS_SUPPORT */
6532 /* otherwise, scp points to the parent directory. Do a lookup, and
6533 * truncate the file if we find it, otherwise we create the file.
6540 if (!smb_IsLegalFilename(lastNamep))
6541 return CM_ERROR_BADNTFILENAME;
6543 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6544 #ifdef DEBUG_VERBOSE
6547 hexp = osi_HexifyString( lastNamep );
6548 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6553 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6554 if (code && code != CM_ERROR_NOSUCHFILE) {
6555 cm_ReleaseSCache(dscp);
6556 cm_ReleaseUser(userp);
6560 /* if we get here, if code is 0, the file exists and is represented by
6561 * scp. Otherwise, we have to create it.
6565 /* oops, file shouldn't be there */
6566 cm_ReleaseSCache(dscp);
6567 cm_ReleaseSCache(scp);
6568 cm_ReleaseUser(userp);
6569 return CM_ERROR_EXISTS;
6572 setAttr.mask = CM_ATTRMASK_LENGTH;
6573 setAttr.length.LowPart = 0;
6574 setAttr.length.HighPart = 0;
6575 code = cm_SetAttr(scp, &setAttr, userp, &req);
6578 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6579 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6580 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6582 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6583 smb_NotifyChange(FILE_ACTION_ADDED,
6584 FILE_NOTIFY_CHANGE_FILE_NAME,
6585 dscp, lastNamep, NULL, TRUE);
6586 if (!excl && code == CM_ERROR_EXISTS) {
6587 /* not an exclusive create, and someone else tried
6588 * creating it already, then we open it anyway. We
6589 * don't bother retrying after this, since if this next
6590 * fails, that means that the file was deleted after
6591 * we started this call.
6593 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6596 setAttr.mask = CM_ATTRMASK_LENGTH;
6597 setAttr.length.LowPart = 0;
6598 setAttr.length.HighPart = 0;
6599 code = cm_SetAttr(scp, &setAttr, userp, &req);
6604 /* we don't need this any longer */
6605 cm_ReleaseSCache(dscp);
6608 /* something went wrong creating or truncating the file */
6609 if (scp) cm_ReleaseSCache(scp);
6610 cm_ReleaseUser(userp);
6614 /* make sure we only open files */
6615 if (scp->fileType != CM_SCACHETYPE_FILE) {
6616 cm_ReleaseSCache(scp);
6617 cm_ReleaseUser(userp);
6618 return CM_ERROR_ISDIR;
6621 /* now all we have to do is open the file itself */
6622 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6625 /* save a pointer to the vnode */
6628 /* always create it open for read/write */
6629 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6631 smb_ReleaseFID(fidp);
6633 smb_SetSMBParm(outp, 0, fidp->fid);
6634 smb_SetSMBDataLength(outp, 0);
6636 cm_Open(scp, 0, userp);
6638 cm_ReleaseUser(userp);
6639 /* leave scp held since we put it in fidp->scp */
6643 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6656 fd = smb_GetSMBParm(inp, 0);
6657 whence = smb_GetSMBParm(inp, 1);
6658 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6660 /* try to find the file descriptor */
6661 fd = smb_ChainFID(fd, inp);
6662 fidp = smb_FindFID(vcp, fd, 0);
6663 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6664 return CM_ERROR_BADFD;
6667 userp = smb_GetUser(vcp, inp);
6669 lock_ObtainMutex(&fidp->mx);
6671 lock_ObtainMutex(&scp->mx);
6672 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6673 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6676 /* offset from current offset */
6677 offset += fidp->offset;
6679 else if (whence == 2) {
6680 /* offset from current EOF */
6681 offset += scp->length.LowPart;
6683 fidp->offset = offset;
6684 smb_SetSMBParm(outp, 0, offset & 0xffff);
6685 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6686 smb_SetSMBDataLength(outp, 0);
6688 lock_ReleaseMutex(&scp->mx);
6689 lock_ReleaseMutex(&fidp->mx);
6690 smb_ReleaseFID(fidp);
6691 cm_ReleaseUser(userp);
6695 /* dispatch all of the requests received in a packet. Due to chaining, this may
6696 * be more than one request.
6698 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6699 NCB *ncbp, raw_write_cont_t *rwcp)
6703 unsigned long code = 0;
6704 unsigned char *outWctp;
6705 int nparms; /* # of bytes of parameters */
6707 int nbytes; /* bytes of data, excluding count */
6710 unsigned short errCode;
6711 unsigned long NTStatus;
6713 unsigned char errClass;
6714 unsigned int oldGen;
6715 DWORD oldTime, newTime;
6717 /* get easy pointer to the data */
6718 smbp = (smb_t *) inp->data;
6720 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6721 /* setup the basic parms for the initial request in the packet */
6722 inp->inCom = smbp->com;
6723 inp->wctp = &smbp->wct;
6725 inp->ncb_length = ncbp->ncb_length;
6730 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6731 /* log it and discard it */
6736 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6737 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6739 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6740 1, ncbp->ncb_length, ptbuf, inp);
6741 DeregisterEventSource(h);
6743 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6748 /* We are an ongoing op */
6749 thrd_Increment(&ongoingOps);
6751 /* set up response packet for receiving output */
6752 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6753 smb_FormatResponsePacket(vcp, inp, outp);
6754 outWctp = outp->wctp;
6756 /* Remember session generation number and time */
6757 oldGen = sessionGen;
6758 oldTime = GetCurrentTime();
6760 while (inp->inCom != 0xff) {
6761 dp = &smb_dispatchTable[inp->inCom];
6763 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6764 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6765 code = outp->resumeCode;
6769 /* process each request in the packet; inCom, wctp and inCount
6770 * are already set up.
6772 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6775 /* now do the dispatch */
6776 /* start by formatting the response record a little, as a default */
6777 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6779 outWctp[1] = 0xff; /* no operation */
6780 outWctp[2] = 0; /* padding */
6785 /* not a chained request, this is a more reasonable default */
6786 outWctp[0] = 0; /* wct of zero */
6787 outWctp[1] = 0; /* and bcc (word) of zero */
6791 /* once set, stays set. Doesn't matter, since we never chain
6792 * "no response" calls.
6794 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6798 /* we have a recognized operation */
6800 if (inp->inCom == 0x1d)
6802 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6805 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%x lana %d lsn %d",(int)vcp,vcp->lana,vcp->lsn);
6806 osi_Log4(smb_logp,"Dispatch %s vcp 0x%x lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6807 code = (*(dp->procp)) (vcp, inp, outp);
6808 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",(code==0)?0:code-CM_ERROR_BASE);
6809 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);
6811 if ( code == CM_ERROR_BADSMB ||
6812 code == CM_ERROR_BADOP )
6814 #endif /* LOG_PACKET */
6817 if (oldGen != sessionGen) {
6822 newTime = GetCurrentTime();
6823 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6824 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6825 newTime - oldTime, ncbp->ncb_length);
6827 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6828 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6829 DeregisterEventSource(h);
6831 osi_Log1(smb_logp, "Pkt straddled session startup, "
6832 "ncb length %d", ncbp->ncb_length);
6836 /* bad opcode, fail the request, after displaying it */
6837 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6840 #endif /* LOG_PACKET */
6844 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6845 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6846 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6847 if (code == IDCANCEL)
6851 code = CM_ERROR_BADOP;
6854 /* catastrophic failure: log as much as possible */
6855 if (code == CM_ERROR_BADSMB) {
6862 "Invalid SMB, ncb_length %d",
6865 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6866 sprintf(s, "Invalid SMB message, length %d",
6869 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6870 1, ncbp->ncb_length, ptbuf, smbp);
6871 DeregisterEventSource(h);
6874 #endif /* LOG_PACKET */
6876 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6879 code = CM_ERROR_INVAL;
6882 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6883 thrd_Decrement(&ongoingOps);
6888 /* now, if we failed, turn the current response into an empty
6889 * one, and fill in the response packet's error code.
6892 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6893 smb_MapNTError(code, &NTStatus);
6894 outWctp = outp->wctp;
6895 smbp = (smb_t *) &outp->data;
6896 if (code != CM_ERROR_PARTIALWRITE
6897 && code != CM_ERROR_BUFFERTOOSMALL
6898 && code != CM_ERROR_GSSCONTINUE) {
6899 /* nuke wct and bcc. For a partial
6900 * write or an in-process authentication handshake,
6901 * assume they're OK.
6907 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6908 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6909 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6910 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6911 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6915 smb_MapCoreError(code, vcp, &errCode, &errClass);
6916 outWctp = outp->wctp;
6917 smbp = (smb_t *) &outp->data;
6918 if (code != CM_ERROR_PARTIALWRITE) {
6919 /* nuke wct and bcc. For a partial
6920 * write, assume they're OK.
6926 smbp->errLow = (unsigned char) (errCode & 0xff);
6927 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6928 smbp->rcls = errClass;
6931 } /* error occurred */
6933 /* if we're here, we've finished one request. Look to see if
6934 * this is a chained opcode. If it is, setup things to process
6935 * the chained request, and setup the output buffer to hold the
6936 * chained response. Start by finding the next input record.
6938 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6939 break; /* not a chained req */
6940 tp = inp->wctp; /* points to start of last request */
6941 /* in a chained request, the first two
6942 * parm fields are required, and are
6943 * AndXCommand/AndXReserved and
6945 if (tp[0] < 2) break;
6946 if (tp[1] == 0xff) break; /* no more chained opcodes */
6948 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6951 /* and now append the next output request to the end of this
6952 * last request. Begin by finding out where the last response
6953 * ends, since that's where we'll put our new response.
6955 outWctp = outp->wctp; /* ptr to out parameters */
6956 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6957 nparms = outWctp[0] << 1;
6958 tp = outWctp + nparms + 1; /* now points to bcc field */
6959 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6960 tp += 2 /* for the count itself */ + nbytes;
6961 /* tp now points to the new output record; go back and patch the
6962 * second parameter (off2) to point to the new record.
6964 temp = (unsigned int)tp - ((unsigned int) outp->data);
6965 outWctp[3] = (unsigned char) (temp & 0xff);
6966 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6967 outWctp[2] = 0; /* padding */
6968 outWctp[1] = inp->inCom; /* next opcode */
6970 /* finally, setup for the next iteration */
6973 } /* while loop over all requests in the packet */
6975 /* done logging out, turn off logging-out flag */
6976 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6977 vcp->justLoggedOut = NULL;
6980 free(loggedOutName);
6981 loggedOutName = NULL;
6982 smb_ReleaseUID(loggedOutUserp);
6983 loggedOutUserp = NULL;
6987 /* now send the output packet, and return */
6989 smb_SendPacket(vcp, outp);
6990 thrd_Decrement(&ongoingOps);
6992 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6993 if (active_vcp != vcp) {
6995 smb_ReleaseVC(active_vcp);
6997 "Replacing active_vcp %x with %x", active_vcp, vcp);
7002 last_msg_time = GetCurrentTime();
7003 } else if (active_vcp == vcp) {
7004 smb_ReleaseVC(active_vcp);
7012 /* Wait for Netbios() calls to return, and make the results available to server
7013 * threads. Note that server threads can't wait on the NCBevents array
7014 * themselves, because NCB events are manual-reset, and the servers would race
7015 * each other to reset them.
7017 void smb_ClientWaiter(void *parmp)
7022 while (smbShutdownFlag == 0) {
7023 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7025 if (code == WAIT_OBJECT_0)
7028 /* error checking */
7029 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7031 int abandonIdx = code - WAIT_ABANDONED_0;
7032 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7035 if (code == WAIT_IO_COMPLETION)
7037 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7041 if (code == WAIT_TIMEOUT)
7043 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7046 if (code == WAIT_FAILED)
7048 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7051 idx = code - WAIT_OBJECT_0;
7053 /* check idx range! */
7054 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7056 /* this is fatal - log as much as possible */
7057 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7061 thrd_ResetEvent(NCBevents[idx]);
7062 thrd_SetEvent(NCBreturns[0][idx]);
7068 * Try to have one NCBRECV request waiting for every live session. Not more
7069 * than one, because if there is more than one, it's hard to handle Write Raw.
7071 void smb_ServerWaiter(void *parmp)
7074 int idx_session, idx_NCB;
7080 while (smbShutdownFlag == 0) {
7082 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7084 if (code == WAIT_OBJECT_0)
7087 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7089 int abandonIdx = code - WAIT_ABANDONED_0;
7090 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7093 if (code == WAIT_IO_COMPLETION)
7095 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7099 if (code == WAIT_TIMEOUT)
7101 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7104 if (code == WAIT_FAILED)
7106 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7109 idx_session = code - WAIT_OBJECT_0;
7111 /* check idx range! */
7112 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7114 /* this is fatal - log as much as possible */
7115 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7121 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7123 if (code == WAIT_OBJECT_0) {
7124 if (smbShutdownFlag == 1)
7130 /* error checking */
7131 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7133 int abandonIdx = code - WAIT_ABANDONED_0;
7134 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7137 if (code == WAIT_IO_COMPLETION)
7139 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7143 if (code == WAIT_TIMEOUT)
7145 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7148 if (code == WAIT_FAILED)
7150 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7153 idx_NCB = code - WAIT_OBJECT_0;
7155 /* check idx range! */
7156 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7158 /* this is fatal - log as much as possible */
7159 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7163 /* Link them together */
7164 NCBsessions[idx_NCB] = idx_session;
7167 ncbp = NCBs[idx_NCB];
7168 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7169 ncbp->ncb_command = NCBRECV | ASYNCH;
7170 ncbp->ncb_lana_num = lanas[idx_session];
7172 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7173 ncbp->ncb_event = NCBevents[idx_NCB];
7174 ncbp->ncb_length = SMB_PACKETSIZE;
7177 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7178 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7179 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7180 ncbp->ncb_length = SMB_PACKETSIZE;
7181 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7182 Netbios(ncbp, dos_ncb);
7188 * The top level loop for handling SMB request messages. Each server thread
7189 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7190 * NCB and buffer for the incoming request are loaned to us.
7192 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7193 * to immediately send a request for the rest of the data. This must come
7194 * before any other traffic for that session, so we delay setting the session
7195 * event until that data has come in.
7197 void smb_Server(VOID *parmp)
7199 int myIdx = (int) parmp;
7203 smb_packet_t *outbufp;
7205 int idx_NCB, idx_session;
7207 smb_vc_t *vcp = NULL;
7213 rx_StartClientThread();
7216 outbufp = GetPacket();
7217 outbufp->ncbp = outncbp;
7220 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7223 /* terminate silently if shutdown flag is set */
7224 if (code == WAIT_OBJECT_0) {
7225 if (smbShutdownFlag == 1) {
7226 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7232 /* error checking */
7233 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7235 int abandonIdx = code - WAIT_ABANDONED_0;
7236 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7239 if (code == WAIT_IO_COMPLETION)
7241 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7245 if (code == WAIT_TIMEOUT)
7247 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7250 if (code == WAIT_FAILED)
7252 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7255 idx_NCB = code - WAIT_OBJECT_0;
7257 /* check idx range! */
7258 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7260 /* this is fatal - log as much as possible */
7261 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7265 ncbp = NCBs[idx_NCB];
7267 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7269 idx_session = NCBsessions[idx_NCB];
7270 rc = ncbp->ncb_retcode;
7272 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7275 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7278 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7281 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7284 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7287 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7290 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7293 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7296 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7299 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7302 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7305 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7308 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7311 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7314 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7317 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7320 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7323 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7326 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7329 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7332 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7335 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7338 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7341 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7344 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7347 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7350 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7353 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7356 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7359 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7362 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7365 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7368 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7371 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7374 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7377 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7380 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7383 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7386 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7396 /* Can this happen? Or is it just my UNIX paranoia? */
7397 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7402 /* Client closed session */
7403 dead_sessions[idx_session] = TRUE;
7406 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7407 /* Should also release vcp. [done] 2004-05-11 jaltman
7409 * sanity check that all TID's are gone.
7411 * TODO: check if we could use LSNs[idx_session] instead,
7412 * also cleanup after dead vcp
7415 if (dead_vcp == vcp)
7416 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7417 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7418 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7422 smb_ReleaseVC(dead_vcp);
7424 "Previous dead_vcp %x", dead_vcp);
7427 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7429 if (vcp->justLoggedOut) {
7431 loggedOutTime = vcp->logoffTime;
7432 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7433 loggedOutUserp = vcp->justLoggedOut;
7434 lock_ObtainWrite(&smb_rctLock);
7435 loggedOutUserp->refCount++;
7436 lock_ReleaseWrite(&smb_rctLock);
7442 /* Treat as transient error */
7449 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7450 sprintf(s, "SMB message incomplete, length %d",
7453 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7455 ncbp->ncb_length, ptbuf,
7457 DeregisterEventSource(h);
7460 "dispatch smb recv failed, message incomplete, ncb_length %d",
7463 "SMB message incomplete, "
7464 "length %d", ncbp->ncb_length);
7467 * We used to discard the packet.
7468 * Instead, try handling it normally.
7476 /* A weird error code. Log it, sleep, and
7478 if (vcp && vcp->errorCount++ > 3) {
7479 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7480 dead_sessions[idx_session] = TRUE;
7484 thrd_SetEvent(SessionEvents[idx_session]);
7489 /* Success, so now dispatch on all the data in the packet */
7491 smb_concurrentCalls++;
7492 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7493 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7497 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7499 * If at this point vcp is NULL (implies that packet was invalid)
7500 * then we are in big trouble. This means either :
7501 * a) we have the wrong NCB.
7502 * b) Netbios screwed up the call.
7503 * Obviously this implies that
7504 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7505 * lanas[idx_session] != ncbp->ncb_lana_num )
7506 * Either way, we can't do anything with this packet.
7507 * Log, sleep and resume.
7516 "LSNs[idx_session]=[%d],"
7517 "lanas[idx_session]=[%d],"
7518 "ncbp->ncb_lsn=[%d],"
7519 "ncbp->ncb_lana_num=[%d]",
7523 ncbp->ncb_lana_num);
7527 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7529 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7530 DeregisterEventSource(h);
7533 /* Also log in the trace log. */
7534 osi_Log4(smb_logp, "Server: BAD VCP!"
7535 "LSNs[idx_session]=[%d],"
7536 "lanas[idx_session]=[%d],"
7537 "ncbp->ncb_lsn=[%d],"
7538 "ncbp->ncb_lana_num=[%d]",
7542 ncbp->ncb_lana_num);
7544 /* thrd_Sleep(1000); Don't bother sleeping */
7545 thrd_SetEvent(SessionEvents[idx_session]);
7546 smb_concurrentCalls--;
7551 vcp->errorCount = 0;
7552 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7554 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7555 /* copy whole packet to virtual memory */
7556 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7558 bufp->dos_pkt / 16, bufp);*/
7560 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7562 smbp = (smb_t *)bufp->data;
7565 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7569 if (smbp->com == 0x1d) {
7570 /* Special handling for Write Raw */
7571 raw_write_cont_t rwc;
7572 EVENT_HANDLE rwevent;
7573 char eventName[MAX_PATH];
7575 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7576 if (rwc.code == 0) {
7577 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7578 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7579 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7580 ncbp->ncb_command = NCBRECV | ASYNCH;
7581 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7582 ncbp->ncb_lana_num = vcp->lana;
7583 ncbp->ncb_buffer = rwc.buf;
7584 ncbp->ncb_length = 65535;
7585 ncbp->ncb_event = rwevent;
7589 Netbios(ncbp, dos_ncb);
7591 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7592 thrd_CloseHandle(rwevent);
7594 thrd_SetEvent(SessionEvents[idx_session]);
7596 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7598 else if (smbp->com == 0xa0) {
7600 * Serialize the handling for NT Transact
7603 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7604 thrd_SetEvent(SessionEvents[idx_session]);
7606 thrd_SetEvent(SessionEvents[idx_session]);
7607 /* TODO: what else needs to be serialized? */
7608 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7610 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7612 __except( smb_ServerExceptionFilter() ) {
7616 smb_concurrentCalls--;
7619 thrd_SetEvent(NCBavails[idx_NCB]);
7626 * Exception filter for the server threads. If an exception occurs in the
7627 * dispatch routines, which is where exceptions are most common, then do a
7628 * force trace and give control to upstream exception handlers. Useful for
7631 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7632 DWORD smb_ServerExceptionFilter(void) {
7633 /* While this is not the best time to do a trace, if it succeeds, then
7634 * we have a trace (assuming tracing was enabled). Otherwise, this should
7635 * throw a second exception.
7640 ptbuf[0] = "Unhandled exception forcing trace";
7642 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7644 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7645 DeregisterEventSource(h);
7648 afsd_ForceTrace(TRUE);
7649 buf_ForceTrace(TRUE);
7650 return EXCEPTION_CONTINUE_SEARCH;
7655 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7656 * If the number of server threads is M, and the number of live sessions is
7657 * N, then the number of NCB's in use at any time either waiting for, or
7658 * holding, received messages is M + N, so that is how many NCB's get created.
7660 void InitNCBslot(int idx)
7662 struct smb_packet *bufp;
7663 EVENT_HANDLE retHandle;
7665 char eventName[MAX_PATH];
7667 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7669 NCBs[idx] = GetNCB();
7670 sprintf(eventName,"NCBavails[%d]", idx);
7671 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7672 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7673 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7675 sprintf(eventName,"NCBevents[%d]", idx);
7676 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7677 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7678 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7680 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7681 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7682 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7683 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7684 for (i=0; i<smb_NumServerThreads; i++)
7685 NCBreturns[i][idx] = retHandle;
7687 bufp->spacep = cm_GetSpace();
7691 /* listen for new connections */
7692 void smb_Listener(void *parmp)
7700 char rname[NCBNAMSZ+1];
7701 char cname[MAX_COMPUTERNAME_LENGTH+1];
7702 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7707 int lana = (int) parmp;
7711 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7714 /* retrieve computer name */
7715 GetComputerName(cname, &cnamelen);
7719 memset(ncbp, 0, sizeof(NCB));
7722 ncbp->ncb_command = NCBLISTEN;
7723 ncbp->ncb_rto = 0; /* No receive timeout */
7724 ncbp->ncb_sto = 0; /* No send timeout */
7726 /* pad out with spaces instead of null termination */
7727 len = strlen(smb_localNamep);
7728 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7729 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7731 strcpy(ncbp->ncb_callname, "*");
7732 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7734 ncbp->ncb_lana_num = lana;
7737 code = Netbios(ncbp);
7739 code = Netbios(ncbp, dos_ncb);
7748 /* terminate silently if shutdown flag is set */
7749 if (smbShutdownFlag == 1) {
7758 "NCBLISTEN lana=%d failed with code %d",
7759 ncbp->ncb_lana_num, code);
7761 "Client exiting due to network failure. Please restart client.\n");
7765 "Client exiting due to network failure. Please restart client.\n"
7766 "NCBLISTEN lana=%d failed with code %d",
7767 ncbp->ncb_lana_num, code);
7769 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7770 MB_OK|MB_SERVICE_NOTIFICATION);
7771 osi_assert(tbuffer);
7774 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7775 ncbp->ncb_lana_num, code);
7776 fprintf(stderr, "\nClient exiting due to network failure "
7777 "(possibly due to power-saving mode)\n");
7778 fprintf(stderr, "Please restart client.\n");
7779 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7783 /* check for remote conns */
7784 /* first get remote name and insert null terminator */
7785 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7786 for (i=NCBNAMSZ; i>0; i--) {
7787 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7793 /* compare with local name */
7795 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7796 flags |= SMB_VCFLAG_REMOTECONN;
7798 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7800 lock_ObtainMutex(&smb_ListenerLock);
7802 /* New generation */
7805 /* Log session startup */
7807 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7809 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7810 #endif /* NOTSERVICE */
7811 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7812 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7814 if (reportSessionStartups) {
7820 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7821 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7823 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7825 DeregisterEventSource(h);
7828 fprintf(stderr, "%s: New session %d starting from host %s\n",
7829 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7833 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7834 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7837 /* now ncbp->ncb_lsn is the connection ID */
7838 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7839 vcp->flags |= flags;
7840 strcpy(vcp->rname, rname);
7842 /* Allocate slot in session arrays */
7843 /* Re-use dead session if possible, otherwise add one more */
7844 /* But don't look at session[0], it is reserved */
7845 for (i = 1; i < numSessions; i++) {
7846 if (dead_sessions[i]) {
7847 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7848 dead_sessions[i] = FALSE;
7853 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7854 unsigned long code = CM_ERROR_ALLBUSY;
7855 smb_packet_t * outp = GetPacket();
7856 unsigned char *outWctp;
7861 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7862 unsigned long NTStatus;
7863 smb_MapNTError(code, &NTStatus);
7864 outWctp = outp->wctp;
7865 smbp = (smb_t *) &outp->data;
7869 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7870 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7871 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7872 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7873 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7875 unsigned short errCode;
7876 unsigned char errClass;
7877 smb_MapCoreError(code, vcp, &errCode, &errClass);
7878 outWctp = outp->wctp;
7879 smbp = (smb_t *) &outp->data;
7883 smbp->errLow = (unsigned char) (errCode & 0xff);
7884 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7885 smbp->rcls = errClass;
7887 smb_SendPacket(vcp, outp);
7888 smb_FreePacket(outp);
7890 /* assert that we do not exceed the maximum number of sessions or NCBs.
7891 * we should probably want to wait for a session to be freed in case
7894 osi_assert(i < Sessionmax - 1);
7895 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7897 LSNs[i] = ncbp->ncb_lsn;
7898 lanas[i] = ncbp->ncb_lana_num;
7900 if (i == numSessions) {
7901 /* Add new NCB for new session */
7902 char eventName[MAX_PATH];
7904 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7906 InitNCBslot(numNCBs);
7908 thrd_SetEvent(NCBavails[0]);
7909 thrd_SetEvent(NCBevents[0]);
7910 for (j = 0; j < smb_NumServerThreads; j++)
7911 thrd_SetEvent(NCBreturns[j][0]);
7912 /* Also add new session event */
7913 sprintf(eventName, "SessionEvents[%d]", i);
7914 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7915 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7916 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7918 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7919 thrd_SetEvent(SessionEvents[0]);
7921 thrd_SetEvent(SessionEvents[i]);
7928 lock_ReleaseMutex(&smb_ListenerLock);
7929 } /* dispatch while loop */
7932 /* initialize Netbios */
7933 void smb_NetbiosInit()
7939 int i, lana, code, l;
7941 int delname_tried=0;
7944 OSVERSIONINFO Version;
7946 /* Get the version of Windows */
7947 memset(&Version, 0x00, sizeof(Version));
7948 Version.dwOSVersionInfoSize = sizeof(Version);
7949 GetVersionEx(&Version);
7951 /* setup the NCB system */
7954 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7958 if (smb_LANadapter == -1) {
7959 ncbp->ncb_command = NCBENUM;
7960 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7961 ncbp->ncb_length = sizeof(lana_list);
7962 code = Netbios(ncbp);
7964 afsi_log("Netbios NCBENUM error code %d", code);
7965 osi_panic(s, __FILE__, __LINE__);
7969 lana_list.length = 1;
7970 lana_list.lana[0] = smb_LANadapter;
7973 for (i = 0; i < lana_list.length; i++) {
7974 /* reset the adaptor: in Win32, this is required for every process, and
7975 * acts as an init call, not as a real hardware reset.
7977 ncbp->ncb_command = NCBRESET;
7978 ncbp->ncb_callname[0] = 100;
7979 ncbp->ncb_callname[2] = 100;
7980 ncbp->ncb_lana_num = lana_list.lana[i];
7981 code = Netbios(ncbp);
7983 code = ncbp->ncb_retcode;
7985 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7986 lana_list.lana[i] = 255; /* invalid lana */
7988 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7992 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7993 we will just fake the LANA list */
7994 if (smb_LANadapter == -1) {
7995 for (i = 0; i < 8; i++)
7996 lana_list.lana[i] = i;
7997 lana_list.length = 8;
8000 lana_list.length = 1;
8001 lana_list.lana[0] = smb_LANadapter;
8005 /* and declare our name so we can receive connections */
8006 memset(ncbp, 0, sizeof(*ncbp));
8007 len=lstrlen(smb_localNamep);
8008 memset(smb_sharename,' ',NCBNAMSZ);
8009 memcpy(smb_sharename,smb_localNamep,len);
8010 afsi_log("lana_list.length %d", lana_list.length);
8012 /* Keep the name so we can unregister it later */
8013 for (l = 0; l < lana_list.length; l++) {
8014 lana = lana_list.lana[l];
8016 ncbp->ncb_command = NCBADDNAME;
8017 ncbp->ncb_lana_num = lana;
8018 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8020 code = Netbios(ncbp);
8022 code = Netbios(ncbp, dos_ncb);
8025 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8026 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8028 char name[NCBNAMSZ+1];
8030 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8031 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8034 if (code == 0) code = ncbp->ncb_retcode;
8036 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8038 /* we only use one LANA with djgpp */
8039 lana_list.lana[0] = lana;
8040 lana_list.length = 1;
8044 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8045 if (code == NRC_BRIDGE) { /* invalid LANA num */
8046 lana_list.lana[l] = 255;
8049 else if (code == NRC_DUPNAME) {
8050 afsi_log("Name already exists; try to delete it");
8051 memset(ncbp, 0, sizeof(*ncbp));
8052 ncbp->ncb_command = NCBDELNAME;
8053 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8054 ncbp->ncb_lana_num = lana;
8056 code = Netbios(ncbp);
8058 code = Netbios(ncbp, dos_ncb);
8061 code = ncbp->ncb_retcode;
8063 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8065 if (code != 0 || delname_tried) {
8066 lana_list.lana[l] = 255;
8068 else if (code == 0) {
8069 if (!delname_tried) {
8077 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8078 lana_list.lana[l] = 255; /* invalid lana */
8079 osi_panic(s, __FILE__, __LINE__);
8083 lana_found = 1; /* at least one worked */
8090 osi_assert(lana_list.length >= 0);
8092 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8095 /* we're done with the NCB now */
8099 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8116 EVENT_HANDLE retHandle;
8117 char eventName[MAX_PATH];
8120 smb_MBfunc = aMBfunc;
8124 smb_LANadapter = LANadapt;
8126 /* Initialize smb_localZero */
8127 myTime.tm_isdst = -1; /* compute whether on DST or not */
8128 myTime.tm_year = 70;
8134 smb_localZero = mktime(&myTime);
8136 #ifndef USE_NUMERIC_TIME_CONV
8137 /* Initialize kludge-GMT */
8138 smb_CalculateNowTZ();
8139 #endif /* USE_NUMERIC_TIME_CONV */
8140 #ifdef AFS_FREELANCE_CLIENT
8141 /* Make sure the root.afs volume has the correct time */
8142 cm_noteLocalMountPointChange();
8145 /* initialize the remote debugging log */
8148 /* remember the name */
8149 len = strlen(snamep);
8150 smb_localNamep = malloc(len+1);
8151 strcpy(smb_localNamep, snamep);
8152 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8154 /* and the global lock */
8155 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8156 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8158 /* Raw I/O data structures */
8159 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8161 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8163 /* 4 Raw I/O buffers */
8165 smb_RawBufs = calloc(65536,1);
8166 *((char **)smb_RawBufs) = NULL;
8167 for (i=0; i<3; i++) {
8168 char *rawBuf = calloc(65536,1);
8169 *((char **)rawBuf) = smb_RawBufs;
8170 smb_RawBufs = rawBuf;
8173 npar = 65536 >> 4; /* number of paragraphs */
8174 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8176 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8178 osi_panic("",__FILE__,__LINE__);
8181 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8184 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8186 _farpokel(_dos_ds, smb_RawBufs, NULL);
8187 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8188 npar = 65536 >> 4; /* number of paragraphs */
8189 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8191 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8193 osi_panic("",__FILE__,__LINE__);
8196 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8199 rawBuf = (seg * 16) + 0; /* DOS physical address */
8200 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8201 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8202 smb_RawBufs = rawBuf;
8206 /* global free lists */
8207 smb_ncbFreeListp = NULL;
8208 smb_packetFreeListp = NULL;
8212 /* Initialize listener and server structures */
8214 memset(dead_sessions, 0, sizeof(dead_sessions));
8215 sprintf(eventName, "SessionEvents[0]");
8216 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8217 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8218 afsi_log("Event Object Already Exists: %s", eventName);
8220 smb_NumServerThreads = nThreads;
8221 sprintf(eventName, "NCBavails[0]");
8222 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8223 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8224 afsi_log("Event Object Already Exists: %s", eventName);
8225 sprintf(eventName, "NCBevents[0]");
8226 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8227 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8228 afsi_log("Event Object Already Exists: %s", eventName);
8229 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8230 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8231 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8232 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8233 afsi_log("Event Object Already Exists: %s", eventName);
8234 for (i = 0; i < smb_NumServerThreads; i++) {
8235 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8236 NCBreturns[i][0] = retHandle;
8239 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8240 for (i = 0; i < smb_NumServerThreads; i++) {
8241 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8242 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8243 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8244 afsi_log("Event Object Already Exists: %s", eventName);
8247 numNCBs = smb_NumServerThreads + 1;
8249 /* Initialize dispatch table */
8250 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8251 /* Prepare the table for unknown operations */
8252 for(i=0; i<= SMB_NOPCODES; i++) {
8253 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8255 /* Fill in the ones we do know */
8256 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8257 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8258 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8259 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8260 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8261 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8262 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8263 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8264 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8265 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8266 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8267 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8268 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8269 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8270 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8271 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8272 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8273 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8274 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8275 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8276 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8277 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8278 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8279 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8280 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8281 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8282 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8283 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8284 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8285 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8286 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8287 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8288 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8289 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8290 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8291 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8292 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8293 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8294 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8295 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8296 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8297 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8298 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8299 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8300 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8301 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8302 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8303 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8304 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8305 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8306 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8307 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8308 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8309 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8310 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8311 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8312 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8313 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8314 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8315 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8316 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8317 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8318 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8319 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8320 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8321 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8322 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8323 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8324 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8325 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8326 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8327 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8329 /* setup tran 2 dispatch table */
8330 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8331 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8332 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8333 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8334 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8335 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8336 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8337 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8338 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8339 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8340 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8341 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8342 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8343 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8344 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8345 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8346 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8348 /* setup the rap dispatch table */
8349 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8350 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8351 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8352 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8353 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8357 /* if we are doing SMB authentication we have register outselves as a logon process */
8358 if (smb_authType != SMB_AUTH_NONE) {
8359 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8360 LSA_STRING afsProcessName;
8361 LSA_OPERATIONAL_MODE dummy; /*junk*/
8363 afsProcessName.Buffer = "OpenAFSClientDaemon";
8364 afsProcessName.Length = strlen(afsProcessName.Buffer);
8365 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8367 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8369 if (nts == STATUS_SUCCESS) {
8370 LSA_STRING packageName;
8371 /* we are registered. Find out the security package id */
8372 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8373 packageName.Length = strlen(packageName.Buffer);
8374 packageName.MaximumLength = packageName.Length + 1;
8375 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8376 if (nts == STATUS_SUCCESS) {
8378 * This code forces Windows to authenticate against the Logon Cache
8379 * first instead of attempting to authenticate against the Domain
8380 * Controller. When the Windows logon cache is enabled this improves
8381 * performance by removing the network access and works around a bug
8382 * seen at sites which are using a MIT Kerberos principal to login
8383 * to machines joined to a non-root domain in a multi-domain forest.
8385 PVOID pResponse = NULL;
8386 ULONG cbResponse = 0;
8387 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8389 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8390 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8391 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8392 OptionsRequest.DisableOptions = FALSE;
8394 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8397 sizeof(OptionsRequest),
8403 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8405 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8407 OutputDebugString(message);
8410 OutputDebugString("MsV1_0SetProcessOption success");
8411 afsi_log("MsV1_0SetProcessOption success");
8413 /* END - code from Larry */
8415 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8416 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8417 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8419 afsi_log("Can't determine security package name for NTLM!! 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;
8428 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8430 /* something went wrong. We report the error and revert back to no authentication
8431 because we can't perform any auth requests without a successful lsa handle
8432 or sec package id. */
8433 afsi_log("Reverting to NO SMB AUTH");
8434 smb_authType = SMB_AUTH_NONE;
8438 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8439 * time prevents the failure of authentication when logged into Windows with an
8440 * external Kerberos principal mapped to a local account.
8442 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8443 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8444 * then the only option is NTLMSSP anyway; so just fallback.
8449 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8450 if (secBlobLength == 0) {
8451 smb_authType = SMB_AUTH_NTLM;
8452 afsi_log("Reverting to SMB AUTH NTLM");
8461 /* Now get ourselves a domain name. */
8462 /* For now we are using the local computer name as the domain name.
8463 * It is actually the domain for local logins, and we are acting as
8464 * a local SMB server.
8466 bufsize = sizeof(smb_ServerDomainName) - 1;
8467 GetComputerName(smb_ServerDomainName, &bufsize);
8468 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8469 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8472 /* Start listeners, waiters, servers, and daemons */
8474 for (i = 0; i < lana_list.length; i++) {
8475 if (lana_list.lana[i] == 255)
8477 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8478 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8479 osi_assert(phandle != NULL);
8480 thrd_CloseHandle(phandle);
8484 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8485 NULL, 0, &lpid, "smb_ClientWaiter");
8486 osi_assert(phandle != NULL);
8487 thrd_CloseHandle(phandle);
8490 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8491 NULL, 0, &lpid, "smb_ServerWaiter");
8492 osi_assert(phandle != NULL);
8493 thrd_CloseHandle(phandle);
8495 for (i=0; i<smb_NumServerThreads; i++) {
8496 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8497 (void *) i, 0, &lpid, "smb_Server");
8498 osi_assert(phandle != NULL);
8499 thrd_CloseHandle(phandle);
8502 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8503 NULL, 0, &lpid, "smb_Daemon");
8504 osi_assert(phandle != NULL);
8505 thrd_CloseHandle(phandle);
8507 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8508 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8509 osi_assert(phandle != NULL);
8510 thrd_CloseHandle(phandle);
8519 void smb_Shutdown(void)
8529 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8531 /* setup the NCB system */
8534 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8537 /* Block new sessions by setting shutdown flag */
8538 smbShutdownFlag = 1;
8540 /* Hang up all sessions */
8541 memset((char *)ncbp, 0, sizeof(NCB));
8542 for (i = 1; i < numSessions; i++)
8544 if (dead_sessions[i])
8547 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8548 ncbp->ncb_command = NCBHANGUP;
8549 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8550 ncbp->ncb_lsn = LSNs[i];
8552 code = Netbios(ncbp);
8554 code = Netbios(ncbp, dos_ncb);
8556 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8557 if (code == 0) code = ncbp->ncb_retcode;
8559 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8560 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8564 /* Trigger the shutdown of all SMB threads */
8565 for (i = 0; i < smb_NumServerThreads; i++)
8566 thrd_SetEvent(NCBreturns[i][0]);
8568 thrd_SetEvent(NCBevents[0]);
8569 thrd_SetEvent(SessionEvents[0]);
8570 thrd_SetEvent(NCBavails[0]);
8572 for (i = 0;i < smb_NumServerThreads; i++) {
8573 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8574 if (code == WAIT_OBJECT_0) {
8577 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8578 thrd_SetEvent(NCBreturns[i--][0]);
8582 /* Delete Netbios name */
8583 memset((char *)ncbp, 0, sizeof(NCB));
8584 for (i = 0; i < lana_list.length; i++) {
8585 if (lana_list.lana[i] == 255) continue;
8586 ncbp->ncb_command = NCBDELNAME;
8587 ncbp->ncb_lana_num = lana_list.lana[i];
8588 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8590 code = Netbios(ncbp);
8592 code = Netbios(ncbp, dos_ncb);
8595 code = ncbp->ncb_retcode;
8597 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8598 ncbp->ncb_lana_num, code);
8603 /* Release the reference counts held by the VCs */
8604 lock_ObtainWrite(&smb_rctLock);
8605 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8610 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8612 if (fidp->scp != NULL) {
8615 lock_ObtainMutex(&fidp->mx);
8616 if (fidp->scp != NULL) {
8619 cm_ReleaseSCache(scp);
8621 lock_ReleaseMutex(&fidp->mx);
8625 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8627 smb_ReleaseVCNoLock(tidp->vcp);
8629 cm_user_t *userp = tidp->userp;
8631 lock_ReleaseWrite(&smb_rctLock);
8632 cm_ReleaseUser(userp);
8633 lock_ObtainWrite(&smb_rctLock);
8637 lock_ReleaseWrite(&smb_rctLock);
8640 /* Get the UNC \\<servername>\<sharename> prefix. */
8641 char *smb_GetSharename()
8645 /* Make sure we have been properly initialized. */
8646 if (smb_localNamep == NULL)
8649 /* Allocate space for \\<servername>\<sharename>, plus the
8652 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8653 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8659 void smb_LogPacket(smb_packet_t *packet)
8662 unsigned length, paramlen, datalen, i, j;
8664 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8666 if (!packet) return;
8668 osi_Log0(smb_logp, "*** SMB packet dump ***");
8670 vp = (BYTE *) packet->data;
8672 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8673 length = paramlen + 2 + datalen;
8676 for (i=0;i < length; i+=16)
8678 memset( buf, ' ', 80 );
8683 buf[strlen(buf)] = ' ';
8685 cp = (BYTE*) buf + 7;
8687 for (j=0;j < 16 && (i+j)<length; j++)
8689 *(cp++) = hex[vp[i+j] >> 4];
8690 *(cp++) = hex[vp[i+j] & 0xf];
8700 for (j=0;j < 16 && (i+j)<length;j++)
8702 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8713 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8716 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8718 #endif /* LOG_PACKET */
8721 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8729 lock_ObtainRead(&smb_rctLock);
8731 sprintf(output, "begin dumping smb_vc_t\n");
8732 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8734 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8738 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8739 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8740 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8742 sprintf(output, "begin dumping smb_fid_t\n");
8743 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8745 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8747 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",
8748 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8749 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8750 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8751 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8754 sprintf(output, "done dumping smb_fid_t\n");
8755 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8758 sprintf(output, "done dumping smb_vc_t\n");
8759 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8762 lock_ReleaseRead(&smb_rctLock);