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 time_t diff_t = unixTime - smb_localZero;
797 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
798 osi_assert(diff_t < _UI32_MAX);
800 *dosUTimep = (afs_uint32)diff_t;
803 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
806 *unixTimep = dosTime + smb_localZero;
808 /* dosTime seems to be already adjusted for GMT */
809 *unixTimep = dosTime;
813 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
817 lock_ObtainWrite(&smb_rctLock);
818 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
819 if (lsn == vcp->lsn && lana == vcp->lana) {
820 smb_HoldVCNoLock(vcp);
824 if (!vcp && (flags & SMB_FLAG_CREATE)) {
825 vcp = malloc(sizeof(*vcp));
826 memset(vcp, 0, sizeof(*vcp));
827 vcp->vcID = numVCs++;
831 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
832 vcp->nextp = smb_allVCsp;
834 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
839 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
840 /* We must obtain a challenge for extended auth
841 * in case the client negotiates smb v3
843 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
844 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
845 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
846 ULONG lsaRespSize = 0;
848 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
850 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
857 if (nts != STATUS_SUCCESS)
858 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
859 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
860 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
862 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
863 LsaFreeReturnBuffer(lsaResp);
866 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
868 if (numVCs >= CM_SESSION_RESERVED) {
870 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
873 lock_ReleaseWrite(&smb_rctLock);
877 int smb_IsStarMask(char *maskp)
882 for(i=0; i<11; i++) {
884 if (tc == '?' || tc == '*' || tc == '>') return 1;
889 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
891 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
893 osi_assert(vcp->refCount-- != 0);
899 void smb_ReleaseVC(smb_vc_t *vcp)
901 lock_ObtainWrite(&smb_rctLock);
902 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
904 osi_assert(vcp->refCount-- != 0);
908 lock_ReleaseWrite(&smb_rctLock);
911 void smb_HoldVCNoLock(smb_vc_t *vcp)
914 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
917 void smb_HoldVC(smb_vc_t *vcp)
919 lock_ObtainWrite(&smb_rctLock);
921 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
922 lock_ReleaseWrite(&smb_rctLock);
925 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
929 lock_ObtainWrite(&smb_rctLock);
930 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
931 if (tid == tidp->tid) {
936 if (!tidp && (flags & SMB_FLAG_CREATE)) {
937 tidp = malloc(sizeof(*tidp));
938 memset(tidp, 0, sizeof(*tidp));
939 tidp->nextp = vcp->tidsp;
942 smb_HoldVCNoLock(vcp);
944 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
947 lock_ReleaseWrite(&smb_rctLock);
951 void smb_ReleaseTID(smb_tid_t *tidp)
958 lock_ObtainWrite(&smb_rctLock);
959 osi_assert(tidp->refCount-- > 0);
960 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
961 ltpp = &tidp->vcp->tidsp;
962 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
966 osi_assert(tp != NULL);
968 lock_FinalizeMutex(&tidp->mx);
969 userp = tidp->userp; /* remember to drop ref later */
971 smb_ReleaseVCNoLock(tidp->vcp);
974 lock_ReleaseWrite(&smb_rctLock);
976 cm_ReleaseUser(userp);
979 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
981 smb_user_t *uidp = NULL;
983 lock_ObtainWrite(&smb_rctLock);
984 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
985 if (uid == uidp->userID) {
987 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
989 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
993 if (!uidp && (flags & SMB_FLAG_CREATE)) {
994 uidp = malloc(sizeof(*uidp));
995 memset(uidp, 0, sizeof(*uidp));
996 uidp->nextp = vcp->usersp;
999 smb_HoldVCNoLock(vcp);
1001 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1003 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1005 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1007 lock_ReleaseWrite(&smb_rctLock);
1011 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1013 smb_username_t *unp= NULL;
1015 lock_ObtainWrite(&smb_rctLock);
1016 for(unp = usernamesp; unp; unp = unp->nextp) {
1017 if (stricmp(unp->name, usern) == 0 &&
1018 stricmp(unp->machine, machine) == 0) {
1023 if (!unp && (flags & SMB_FLAG_CREATE)) {
1024 unp = malloc(sizeof(*unp));
1025 memset(unp, 0, sizeof(*unp));
1027 unp->nextp = usernamesp;
1028 unp->name = strdup(usern);
1029 unp->machine = strdup(machine);
1031 lock_InitializeMutex(&unp->mx, "username_t mutex");
1033 lock_ReleaseWrite(&smb_rctLock);
1037 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1039 smb_user_t *uidp= NULL;
1041 lock_ObtainWrite(&smb_rctLock);
1042 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1045 if (stricmp(uidp->unp->name, usern) == 0) {
1047 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1048 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1053 lock_ReleaseWrite(&smb_rctLock);
1056 void smb_ReleaseUID(smb_user_t *uidp)
1063 lock_ObtainWrite(&smb_rctLock);
1064 osi_assert(uidp->refCount-- > 0);
1065 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1066 lupp = &uidp->vcp->usersp;
1067 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1071 osi_assert(up != NULL);
1073 lock_FinalizeMutex(&uidp->mx);
1075 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1076 uidp->unp->userp = NULL; /* after releasing the lock */
1078 smb_ReleaseVCNoLock(uidp->vcp);
1081 lock_ReleaseWrite(&smb_rctLock);
1083 cm_ReleaseUserVCRef(userp);
1084 cm_ReleaseUser(userp);
1089 /* retrieve a held reference to a user structure corresponding to an incoming
1091 * corresponding release function is cm_ReleaseUser.
1093 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1099 smbp = (smb_t *) inp;
1100 uidp = smb_FindUID(vcp, smbp->uid, 0);
1101 if ((!uidp) || (!uidp->unp))
1104 lock_ObtainMutex(&uidp->mx);
1105 up = uidp->unp->userp;
1107 lock_ReleaseMutex(&uidp->mx);
1109 smb_ReleaseUID(uidp);
1115 * Return a pointer to a pathname extracted from a TID structure. The
1116 * TID structure is not held; assume it won't go away.
1118 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1123 tidp = smb_FindTID(vcp, tid, 0);
1127 if (tidp->flags & SMB_TIDFLAG_IPC) {
1128 code = CM_ERROR_TIDIPC;
1129 /* tidp->pathname would be NULL, but that's fine */
1131 *treepath = tidp->pathname;
1132 smb_ReleaseTID(tidp);
1137 /* check to see if we have a chained fid, that is, a fid that comes from an
1138 * OpenAndX message that ran earlier in this packet. In this case, the fid
1139 * field in a read, for example, request, isn't set, since the value is
1140 * supposed to be inherited from the openAndX call.
1142 int smb_ChainFID(int fid, smb_packet_t *inp)
1144 if (inp->fid == 0 || inp->inCount == 0)
1150 /* are we a priv'd user? What does this mean on NT? */
1151 int smb_SUser(cm_user_t *userp)
1156 /* find a file ID. If we pass in 0 we select an unused File ID.
1157 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1158 * smb_fid_t data structure if desired File ID cannot be found.
1160 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1165 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1168 lock_ObtainWrite(&smb_rctLock);
1169 /* figure out if we need to allocate a new file ID */
1172 fid = vcp->fidCounter;
1176 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1177 if (fid == fidp->fid) {
1189 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1190 char eventName[MAX_PATH];
1192 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1193 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1194 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1195 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1196 thrd_CloseHandle(event);
1203 fidp = malloc(sizeof(*fidp));
1204 memset(fidp, 0, sizeof(*fidp));
1205 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1208 smb_HoldVCNoLock(vcp);
1209 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1211 fidp->curr_chunk = fidp->prev_chunk = -2;
1212 fidp->raw_write_event = event;
1214 vcp->fidCounter = fid+1;
1215 if (vcp->fidCounter == 0)
1216 vcp->fidCounter = 1;
1220 lock_ReleaseWrite(&smb_rctLock);
1224 void smb_ReleaseFID(smb_fid_t *fidp)
1227 smb_vc_t *vcp = NULL;
1228 smb_ioctl_t *ioctlp;
1234 lock_ObtainWrite(&smb_rctLock);
1235 osi_assert(fidp->refCount-- > 0);
1236 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1239 scp = fidp->scp; /* release after lock is released */
1242 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1243 thrd_CloseHandle(fidp->raw_write_event);
1245 /* and see if there is ioctl stuff to free */
1246 ioctlp = fidp->ioctlp;
1249 cm_FreeSpace(ioctlp->prefix);
1250 if (ioctlp->inAllocp)
1251 free(ioctlp->inAllocp);
1252 if (ioctlp->outAllocp)
1253 free(ioctlp->outAllocp);
1259 smb_ReleaseVCNoLock(vcp);
1261 lock_ReleaseWrite(&smb_rctLock);
1263 /* now release the scache structure */
1265 cm_ReleaseSCache(scp);
1269 * Case-insensitive search for one string in another;
1270 * used to find variable names in submount pathnames.
1272 static char *smb_stristr(char *str1, char *str2)
1276 for (cursor = str1; *cursor; cursor++)
1277 if (stricmp(cursor, str2) == 0)
1284 * Substitute a variable value for its name in a submount pathname. Variable
1285 * name has been identified by smb_stristr() and is in substr. Variable name
1286 * length (plus one) is in substr_size. Variable value is in newstr.
1288 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1293 strcpy(temp, substr + substr_size - 1);
1294 strcpy(substr, newstr);
1298 char VNUserName[] = "%USERNAME%";
1299 char VNLCUserName[] = "%LCUSERNAME%";
1300 char VNComputerName[] = "%COMPUTERNAME%";
1301 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1304 /* List available shares */
1305 int smb_ListShares()
1309 char shareBuf[4096];
1317 /*strcpy(shareNameList[num_shares], "all");
1318 strcpy(pathNameList[num_shares++], "/afs");*/
1319 fprintf(stderr, "The following shares are available:\n");
1320 fprintf(stderr, "Share Name (AFS Path)\n");
1321 fprintf(stderr, "---------------------\n");
1322 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1325 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1326 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1328 strcpy(sbmtpath, cm_confDir);
1330 strcat(sbmtpath, "/afsdsbmt.ini");
1331 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1332 shareBuf, sizeof(shareBuf),
1338 this_share = shareBuf;
1342 /*strcpy(shareNameList[num_shares], this_share);*/
1343 len = GetPrivateProfileString("AFS Submounts", this_share,
1350 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1353 if (*p == '\\') *p = '/'; /* change to / */
1357 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1358 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1361 while (*this_share != 0) this_share++; /* find next NUL */
1362 this_share++; /* skip past the NUL */
1363 } while (*this_share != 0); /* stop at final NUL */
1369 typedef struct smb_findShare_rock {
1373 } smb_findShare_rock_t;
1375 #define SMB_FINDSHARE_EXACT_MATCH 1
1376 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1378 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1382 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1383 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1384 if(!stricmp(dep->name, vrock->shareName))
1385 matchType = SMB_FINDSHARE_EXACT_MATCH;
1387 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1388 if(vrock->match) free(vrock->match);
1389 vrock->match = strdup(dep->name);
1390 vrock->matchType = matchType;
1392 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1393 return CM_ERROR_STOPNOW;
1399 /* find a shareName in the table of submounts */
1400 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1404 char pathName[1024];
1409 char sbmtpath[MAX_PATH];
1414 DWORD allSubmount = 1;
1416 /* if allSubmounts == 0, only return the //mountRoot/all share
1417 * if in fact it has been been created in the subMounts table.
1418 * This is to allow sites that want to restrict access to the
1421 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1422 0, KEY_QUERY_VALUE, &parmKey);
1423 if (code == ERROR_SUCCESS) {
1424 len = sizeof(allSubmount);
1425 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1426 (BYTE *) &allSubmount, &len);
1427 if (code != ERROR_SUCCESS) {
1430 RegCloseKey (parmKey);
1433 if (allSubmount && _stricmp(shareName, "all") == 0) {
1438 /* In case, the all share is disabled we need to still be able
1439 * to handle ioctl requests
1441 if (_stricmp(shareName, "ioctl$") == 0) {
1442 *pathNamep = strdup("/.__ioctl__");
1446 if (_stricmp(shareName, "IPC$") == 0 ||
1447 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1448 _stricmp(shareName, "DESKTOP.INI") == 0
1455 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1456 0, KEY_QUERY_VALUE, &parmKey);
1457 if (code == ERROR_SUCCESS) {
1458 len = sizeof(pathName);
1459 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1460 (BYTE *) pathName, &len);
1461 if (code != ERROR_SUCCESS)
1463 RegCloseKey (parmKey);
1468 strcpy(sbmtpath, cm_confDir);
1469 strcat(sbmtpath, "/afsdsbmt.ini");
1470 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1471 pathName, sizeof(pathName), sbmtpath);
1473 if (len != 0 && len != sizeof(pathName) - 1) {
1474 /* We can accept either unix or PC style AFS pathnames. Convert
1475 * Unix-style to PC style here for internal use.
1478 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1479 p += strlen(cm_mountRoot); /* skip mount path */
1482 if (*q == '/') *q = '\\'; /* change to \ */
1488 if (var = smb_stristr(p, VNUserName)) {
1489 if (uidp && uidp->unp)
1490 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1492 smb_subst(p, var, sizeof(VNUserName)," ");
1494 else if (var = smb_stristr(p, VNLCUserName))
1496 if (uidp && uidp->unp)
1497 strcpy(temp, uidp->unp->name);
1501 smb_subst(p, var, sizeof(VNLCUserName), temp);
1503 else if (var = smb_stristr(p, VNComputerName))
1505 sizeTemp = sizeof(temp);
1506 GetComputerName((LPTSTR)temp, &sizeTemp);
1507 smb_subst(p, var, sizeof(VNComputerName), temp);
1509 else if (var = smb_stristr(p, VNLCComputerName))
1511 sizeTemp = sizeof(temp);
1512 GetComputerName((LPTSTR)temp, &sizeTemp);
1514 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1519 *pathNamep = strdup(p);
1524 /* First lookup shareName in root.afs */
1526 smb_findShare_rock_t vrock;
1528 char * p = shareName;
1531 /* attempt to locate a partial match in root.afs. This is because
1532 when using the ANSI RAP calls, the share name is limited to 13 chars
1533 and hence is truncated. Of course we prefer exact matches. */
1535 thyper.HighPart = 0;
1538 vrock.shareName = shareName;
1540 vrock.matchType = 0;
1542 cm_HoldSCache(cm_data.rootSCachep);
1543 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1544 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1545 cm_ReleaseSCache(cm_data.rootSCachep);
1547 if (vrock.matchType) {
1548 sprintf(pathName,"/%s/",vrock.match);
1549 *pathNamep = strdup(strlwr(pathName));
1554 /* if we get here, there was no match for the share in root.afs */
1555 /* so try to create \\<netbiosName>\<cellname> */
1560 /* Get the full name for this cell */
1561 code = cm_SearchCellFile(p, temp, 0, 0);
1562 #ifdef AFS_AFSDB_ENV
1563 if (code && cm_dnsEnabled) {
1565 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1568 /* construct the path */
1570 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1571 *pathNamep = strdup(strlwr(pathName));
1580 /* Client-side offline caching policy types */
1581 #define CSC_POLICY_MANUAL 0
1582 #define CSC_POLICY_DOCUMENTS 1
1583 #define CSC_POLICY_PROGRAMS 2
1584 #define CSC_POLICY_DISABLE 3
1586 int smb_FindShareCSCPolicy(char *shareName)
1592 int retval = CSC_POLICY_MANUAL;
1594 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1595 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1598 REG_OPTION_NON_VOLATILE,
1604 len = sizeof(policy);
1605 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1607 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1609 else if (stricmp(policy, "documents") == 0)
1611 retval = CSC_POLICY_DOCUMENTS;
1613 else if (stricmp(policy, "programs") == 0)
1615 retval = CSC_POLICY_PROGRAMS;
1617 else if (stricmp(policy, "disable") == 0)
1619 retval = CSC_POLICY_DISABLE;
1622 RegCloseKey(hkCSCPolicy);
1626 /* find a dir search structure by cookie value, and return it held.
1627 * Must be called with smb_globalLock held.
1629 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1631 smb_dirSearch_t *dsp;
1633 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1634 if (dsp->cookie == cookie) {
1635 if (dsp != smb_firstDirSearchp) {
1636 /* move to head of LRU queue, too, if we're not already there */
1637 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1638 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1639 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1640 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1641 if (!smb_lastDirSearchp)
1642 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1644 lock_ObtainMutex(&dsp->mx);
1646 lock_ReleaseMutex(&dsp->mx);
1652 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1653 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1654 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1660 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1662 lock_ObtainWrite(&smb_globalLock);
1663 lock_ObtainMutex(&dsp->mx);
1664 dsp->flags |= SMB_DIRSEARCH_DELETE;
1665 if (dsp->scp != NULL) {
1666 lock_ObtainMutex(&dsp->scp->mx);
1667 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1668 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1669 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1670 dsp->scp->bulkStatProgress = hones;
1672 lock_ReleaseMutex(&dsp->scp->mx);
1674 lock_ReleaseMutex(&dsp->mx);
1675 lock_ReleaseWrite(&smb_globalLock);
1678 /* Must be called with the smb_globalLock held */
1679 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1681 cm_scache_t *scp = NULL;
1683 lock_ObtainMutex(&dsp->mx);
1684 osi_assert(dsp->refCount-- > 0);
1685 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1686 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1687 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1688 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1689 lock_ReleaseMutex(&dsp->mx);
1690 lock_FinalizeMutex(&dsp->mx);
1694 lock_ReleaseMutex(&dsp->mx);
1696 /* do this now to avoid spurious locking hierarchy creation */
1698 cm_ReleaseSCache(scp);
1701 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1703 lock_ObtainWrite(&smb_globalLock);
1704 smb_ReleaseDirSearchNoLock(dsp);
1705 lock_ReleaseWrite(&smb_globalLock);
1708 /* find a dir search structure by cookie value, and return it held */
1709 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1711 smb_dirSearch_t *dsp;
1713 lock_ObtainWrite(&smb_globalLock);
1714 dsp = smb_FindDirSearchNoLock(cookie);
1715 lock_ReleaseWrite(&smb_globalLock);
1719 /* GC some dir search entries, in the address space expected by the specific protocol.
1720 * Must be called with smb_globalLock held; release the lock temporarily.
1722 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1723 void smb_GCDirSearches(int isV3)
1725 smb_dirSearch_t *prevp;
1726 smb_dirSearch_t *tp;
1727 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1731 victimCount = 0; /* how many have we got so far */
1732 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1733 /* we'll move tp from queue, so
1736 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1737 /* if no one is using this guy, and we're either in the new protocol,
1738 * or we're in the old one and this is a small enough ID to be useful
1739 * to the old protocol, GC this guy.
1741 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1742 /* hold and delete */
1743 tp->flags |= SMB_DIRSEARCH_DELETE;
1744 victimsp[victimCount++] = tp;
1748 /* don't do more than this */
1749 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1753 /* now release them */
1754 for (i = 0; i < victimCount; i++) {
1755 smb_ReleaseDirSearchNoLock(victimsp[i]);
1759 /* function for allocating a dir search entry. We need these to remember enough context
1760 * since we don't get passed the path from call to call during a directory search.
1762 * Returns a held dir search structure, and bumps the reference count on the vnode,
1763 * since it saves a pointer to the vnode.
1765 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1767 smb_dirSearch_t *dsp;
1773 lock_ObtainWrite(&smb_globalLock);
1776 /* what's the biggest ID allowed in this version of the protocol */
1777 maxAllowed = isV3 ? 65535 : 255;
1778 if (smb_dirSearchCounter > maxAllowed)
1779 smb_dirSearchCounter = 1;
1781 start = smb_dirSearchCounter;
1784 /* twice so we have enough tries to find guys we GC after one pass;
1785 * 10 extra is just in case I mis-counted.
1787 if (++counter > 2*maxAllowed+10)
1788 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1790 if (smb_dirSearchCounter > maxAllowed) {
1791 smb_dirSearchCounter = 1;
1793 if (smb_dirSearchCounter == start) {
1795 smb_GCDirSearches(isV3);
1798 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1800 /* don't need to watch for refcount zero and deleted, since
1801 * we haven't dropped the global lock.
1803 lock_ObtainMutex(&dsp->mx);
1805 lock_ReleaseMutex(&dsp->mx);
1806 ++smb_dirSearchCounter;
1810 dsp = malloc(sizeof(*dsp));
1811 memset(dsp, 0, sizeof(*dsp));
1812 dsp->cookie = smb_dirSearchCounter;
1813 ++smb_dirSearchCounter;
1815 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1816 dsp->lastTime = osi_Time();
1817 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1818 if (!smb_lastDirSearchp)
1819 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1822 lock_ReleaseWrite(&smb_globalLock);
1826 static smb_packet_t *GetPacket(void)
1830 unsigned int npar, seg, tb_sel;
1833 lock_ObtainWrite(&smb_globalLock);
1834 tbp = smb_packetFreeListp;
1836 smb_packetFreeListp = tbp->nextp;
1837 lock_ReleaseWrite(&smb_globalLock);
1840 tbp = calloc(65540,1);
1842 tbp = malloc(sizeof(smb_packet_t));
1844 tbp->magic = SMB_PACKETMAGIC;
1847 tbp->resumeCode = 0;
1853 tbp->ncb_length = 0;
1858 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1861 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1863 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1865 osi_panic("",__FILE__,__LINE__);
1868 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1873 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1874 tbp->dos_pkt_sel = tb_sel;
1877 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1882 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1886 memcpy(tbp, pkt, sizeof(smb_packet_t));
1887 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
1889 smb_HoldVC(tbp->vcp);
1893 static NCB *GetNCB(void)
1898 unsigned int npar, seg, tb_sel;
1901 lock_ObtainWrite(&smb_globalLock);
1902 tbp = smb_ncbFreeListp;
1904 smb_ncbFreeListp = tbp->nextp;
1905 lock_ReleaseWrite(&smb_globalLock);
1908 tbp = calloc(sizeof(*tbp),1);
1910 tbp = malloc(sizeof(*tbp));
1911 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1914 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1916 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1918 osi_panic("",__FILE__,__LINE__);
1920 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1925 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1926 tbp->dos_ncb_sel = tb_sel;
1928 tbp->magic = SMB_NCBMAGIC;
1931 osi_assert(tbp->magic == SMB_NCBMAGIC);
1933 memset(&tbp->ncb, 0, sizeof(NCB));
1936 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1941 void smb_FreePacket(smb_packet_t *tbp)
1943 smb_vc_t * vcp = NULL;
1944 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1946 lock_ObtainWrite(&smb_globalLock);
1947 tbp->nextp = smb_packetFreeListp;
1948 smb_packetFreeListp = tbp;
1949 tbp->magic = SMB_PACKETMAGIC;
1953 tbp->resumeCode = 0;
1959 tbp->ncb_length = 0;
1961 lock_ReleaseWrite(&smb_globalLock);
1967 static void FreeNCB(NCB *bufferp)
1971 tbp = (smb_ncb_t *) bufferp;
1972 osi_assert(tbp->magic == SMB_NCBMAGIC);
1974 lock_ObtainWrite(&smb_globalLock);
1975 tbp->nextp = smb_ncbFreeListp;
1976 smb_ncbFreeListp = tbp;
1977 lock_ReleaseWrite(&smb_globalLock);
1980 /* get a ptr to the data part of a packet, and its count */
1981 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1985 unsigned char *afterParmsp;
1987 parmBytes = *smbp->wctp << 1;
1988 afterParmsp = smbp->wctp + parmBytes + 1;
1990 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1991 if (nbytesp) *nbytesp = dataBytes;
1993 /* don't forget to skip the data byte count, since it follows
1994 * the parameters; that's where the "2" comes from below.
1996 return (unsigned char *) (afterParmsp + 2);
1999 /* must set all the returned parameters before playing around with the
2000 * data region, since the data region is located past the end of the
2001 * variable number of parameters.
2003 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2005 unsigned char *afterParmsp;
2007 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2009 *afterParmsp++ = dsize & 0xff;
2010 *afterParmsp = (dsize>>8) & 0xff;
2013 /* return the parm'th parameter in the smbp packet */
2014 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2017 unsigned char *parmDatap;
2019 parmCount = *smbp->wctp;
2021 if (parm >= parmCount) {
2024 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2025 parm, parmCount, smbp->ncb_length);
2026 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2027 parm, parmCount, smbp->ncb_length);
2029 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2030 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2032 osi_panic(s, __FILE__, __LINE__);
2034 parmDatap = smbp->wctp + (2*parm) + 1;
2036 return parmDatap[0] + (parmDatap[1] << 8);
2039 /* return the parm'th parameter in the smbp packet */
2040 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2043 unsigned char *parmDatap;
2045 parmCount = *smbp->wctp;
2047 if (parm * 2 + offset >= parmCount * 2) {
2050 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2051 parm, offset, parmCount, smbp->ncb_length);
2053 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2054 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2056 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2057 parm, offset, parmCount, smbp->ncb_length);
2058 osi_panic(s, __FILE__, __LINE__);
2060 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2062 return parmDatap[0] + (parmDatap[1] << 8);
2065 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2069 /* make sure we have enough slots */
2070 if (*smbp->wctp <= slot)
2071 *smbp->wctp = slot+1;
2073 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2074 *parmDatap++ = parmValue & 0xff;
2075 *parmDatap = (parmValue>>8) & 0xff;
2078 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2082 /* make sure we have enough slots */
2083 if (*smbp->wctp <= slot)
2084 *smbp->wctp = slot+2;
2086 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2087 *parmDatap++ = parmValue & 0xff;
2088 *parmDatap++ = (parmValue>>8) & 0xff;
2089 *parmDatap++ = (parmValue>>16) & 0xff;
2090 *parmDatap++ = (parmValue>>24) & 0xff;
2093 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2098 /* make sure we have enough slots */
2099 if (*smbp->wctp <= slot)
2100 *smbp->wctp = slot+4;
2102 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2104 *parmDatap++ = *parmValuep++;
2107 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2111 /* make sure we have enough slots */
2112 if (*smbp->wctp <= slot) {
2113 if (smbp->oddByte) {
2115 *smbp->wctp = slot+1;
2120 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2121 *parmDatap++ = parmValue & 0xff;
2124 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2128 lastSlashp = strrchr(inPathp, '\\');
2130 *lastComponentp = lastSlashp;
2133 if (inPathp == lastSlashp)
2135 *outPathp++ = *inPathp++;
2144 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2149 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2154 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2160 tlen = inp[0] + (inp[1]<<8);
2161 inp += 2; /* skip length field */
2164 *chainpp = inp + tlen;
2173 /* format a packet as a response */
2174 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2179 outp = (smb_t *) op;
2181 /* zero the basic structure through the smb_wct field, and zero the data
2182 * size field, assuming that wct stays zero; otherwise, you have to
2183 * explicitly set the data size field, too.
2185 inSmbp = (smb_t *) inp;
2186 memset(outp, 0, sizeof(smb_t)+2);
2192 outp->com = inSmbp->com;
2193 outp->tid = inSmbp->tid;
2194 outp->pid = inSmbp->pid;
2195 outp->uid = inSmbp->uid;
2196 outp->mid = inSmbp->mid;
2197 outp->res[0] = inSmbp->res[0];
2198 outp->res[1] = inSmbp->res[1];
2199 op->inCom = inSmbp->com;
2201 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2202 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2204 /* copy fields in generic packet area */
2205 op->wctp = &outp->wct;
2208 /* send a (probably response) packet; vcp tells us to whom to send it.
2209 * we compute the length by looking at wct and bcc fields.
2211 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2228 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2231 memset((char *)ncbp, 0, sizeof(NCB));
2233 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2234 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2235 extra += tp[0] + (tp[1]<<8);
2236 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2237 extra += 3; /* wct and length fields */
2239 ncbp->ncb_length = extra; /* bytes to send */
2240 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2241 ncbp->ncb_lana_num = vcp->lana;
2242 ncbp->ncb_command = NCBSEND; /* op means send data */
2244 ncbp->ncb_buffer = (char *) inp;/* packet */
2245 code = Netbios(ncbp);
2247 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2248 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2250 /* copy header information from virtual to DOS address space */
2251 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2252 code = Netbios(ncbp, dos_ncb);
2258 case 0x01: s = "llegal buffer length "; break;
2259 case 0x03: s = "illegal command "; break;
2260 case 0x05: s = "command timed out "; break;
2261 case 0x06: s = "message incomplete, issue another command"; break;
2262 case 0x07: s = "illegal buffer address "; break;
2263 case 0x08: s = "session number out of range "; break;
2264 case 0x09: s = "no resource available "; break;
2265 case 0x0a: s = "session closed "; break;
2266 case 0x0b: s = "command cancelled "; break;
2267 case 0x0d: s = "duplicate name "; break;
2268 case 0x0e: s = "name table full "; break;
2269 case 0x0f: s = "no deletions, name has active sessions "; break;
2270 case 0x11: s = "local session table full "; break;
2271 case 0x12: s = "remote session table full "; break;
2272 case 0x13: s = "illegal name number "; break;
2273 case 0x14: s = "no callname "; break;
2274 case 0x15: s = "cannot put * in NCB_NAME "; break;
2275 case 0x16: s = "name in use on remote adapter "; break;
2276 case 0x17: s = "name deleted "; break;
2277 case 0x18: s = "session ended abnormally "; break;
2278 case 0x19: s = "name conflict detected "; break;
2279 case 0x21: s = "interface busy, IRET before retrying "; break;
2280 case 0x22: s = "too many commands outstanding, retry later"; break;
2281 case 0x23: s = "ncb_lana_num field invalid "; break;
2282 case 0x24: s = "command completed while cancel occurring "; break;
2283 case 0x26: s = "command not valid to cancel "; break;
2284 case 0x30: s = "name defined by anther local process "; break;
2285 case 0x34: s = "environment undefined. RESET required "; break;
2286 case 0x35: s = "required OS resources exhausted "; break;
2287 case 0x36: s = "max number of applications exceeded "; break;
2288 case 0x37: s = "no saps available for netbios "; break;
2289 case 0x38: s = "requested resources are not available "; break;
2290 case 0x39: s = "invalid ncb address or length > segment "; break;
2291 case 0x3B: s = "invalid NCB DDID "; break;
2292 case 0x3C: s = "lock of user area failed "; break;
2293 case 0x3f: s = "NETBIOS not loaded "; break;
2294 case 0x40: s = "system error "; break;
2296 s = "unknown error";
2298 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2305 void smb_MapNTError(long code, unsigned long *NTStatusp)
2307 unsigned long NTStatus;
2309 /* map CM_ERROR_* errors to NT 32-bit status codes */
2310 /* NT Status codes are listed in ntstatus.h not winerror.h */
2311 if (code == CM_ERROR_NOSUCHCELL) {
2312 NTStatus = 0xC000000FL; /* No such file */
2314 else if (code == CM_ERROR_NOSUCHVOLUME) {
2315 NTStatus = 0xC000000FL; /* No such file */
2317 else if (code == CM_ERROR_TIMEDOUT) {
2319 NTStatus = 0xC00000CFL; /* Sharing Paused */
2321 NTStatus = 0x00000102L; /* Timeout */
2324 else if (code == CM_ERROR_RETRY) {
2325 NTStatus = 0xC000022DL; /* Retry */
2327 else if (code == CM_ERROR_NOACCESS) {
2328 NTStatus = 0xC0000022L; /* Access denied */
2330 else if (code == CM_ERROR_READONLY) {
2331 NTStatus = 0xC00000A2L; /* Write protected */
2333 else if (code == CM_ERROR_NOSUCHFILE) {
2334 NTStatus = 0xC000000FL; /* No such file */
2336 else if (code == CM_ERROR_NOSUCHPATH) {
2337 NTStatus = 0xC000003AL; /* Object path not found */
2339 else if (code == CM_ERROR_TOOBIG) {
2340 NTStatus = 0xC000007BL; /* Invalid image format */
2342 else if (code == CM_ERROR_INVAL) {
2343 NTStatus = 0xC000000DL; /* Invalid parameter */
2345 else if (code == CM_ERROR_BADFD) {
2346 NTStatus = 0xC0000008L; /* Invalid handle */
2348 else if (code == CM_ERROR_BADFDOP) {
2349 NTStatus = 0xC0000022L; /* Access denied */
2351 else if (code == CM_ERROR_EXISTS) {
2352 NTStatus = 0xC0000035L; /* Object name collision */
2354 else if (code == CM_ERROR_NOTEMPTY) {
2355 NTStatus = 0xC0000101L; /* Directory not empty */
2357 else if (code == CM_ERROR_CROSSDEVLINK) {
2358 NTStatus = 0xC00000D4L; /* Not same device */
2360 else if (code == CM_ERROR_NOTDIR) {
2361 NTStatus = 0xC0000103L; /* Not a directory */
2363 else if (code == CM_ERROR_ISDIR) {
2364 NTStatus = 0xC00000BAL; /* File is a directory */
2366 else if (code == CM_ERROR_BADOP) {
2368 /* I have no idea where this comes from */
2369 NTStatus = 0xC09820FFL; /* SMB no support */
2371 NTStatus = 0xC00000BBL; /* Not supported */
2372 #endif /* COMMENT */
2374 else if (code == CM_ERROR_BADSHARENAME) {
2375 NTStatus = 0xC00000CCL; /* Bad network name */
2377 else if (code == CM_ERROR_NOIPC) {
2379 NTStatus = 0xC0000022L; /* Access Denied */
2381 NTStatus = 0xC000013DL; /* Remote Resources */
2384 else if (code == CM_ERROR_CLOCKSKEW) {
2385 NTStatus = 0xC0000133L; /* Time difference at DC */
2387 else if (code == CM_ERROR_BADTID) {
2388 NTStatus = 0xC0982005L; /* SMB bad TID */
2390 else if (code == CM_ERROR_USESTD) {
2391 NTStatus = 0xC09820FBL; /* SMB use standard */
2393 else if (code == CM_ERROR_QUOTA) {
2395 NTStatus = 0xC0000044L; /* Quota exceeded */
2397 NTStatus = 0xC000007FL; /* Disk full */
2400 else if (code == CM_ERROR_SPACE) {
2401 NTStatus = 0xC000007FL; /* Disk full */
2403 else if (code == CM_ERROR_ATSYS) {
2404 NTStatus = 0xC0000033L; /* Object name invalid */
2406 else if (code == CM_ERROR_BADNTFILENAME) {
2407 NTStatus = 0xC0000033L; /* Object name invalid */
2409 else if (code == CM_ERROR_WOULDBLOCK) {
2410 NTStatus = 0xC0000055L; /* Lock not granted */
2412 else if (code == CM_ERROR_SHARING_VIOLATION) {
2413 NTStatus = 0xC0000043L; /* Sharing violation */
2415 else if (code == CM_ERROR_LOCK_CONFLICT) {
2416 NTStatus = 0xC0000054L; /* Lock conflict */
2418 else if (code == CM_ERROR_PARTIALWRITE) {
2419 NTStatus = 0xC000007FL; /* Disk full */
2421 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2422 NTStatus = 0xC0000023L; /* Buffer too small */
2424 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2425 NTStatus = 0xC0000035L; /* Object name collision */
2427 else if (code == CM_ERROR_BADPASSWORD) {
2428 NTStatus = 0xC000006DL; /* unknown username or bad password */
2430 else if (code == CM_ERROR_BADLOGONTYPE) {
2431 NTStatus = 0xC000015BL; /* logon type not granted */
2433 else if (code == CM_ERROR_GSSCONTINUE) {
2434 NTStatus = 0xC0000016L; /* more processing required */
2436 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2438 NTStatus = 0xC0000280L; /* reparse point not resolved */
2440 NTStatus = 0xC0000022L; /* Access Denied */
2443 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2444 NTStatus = 0xC0000257L; /* Path Not Covered */
2447 else if (code == CM_ERROR_ALLBUSY) {
2448 NTStatus = 0xC00000BFL; /* Network Busy */
2450 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2451 NTStatus = 0xC0000350L; /* Remote Host Down */
2454 /* we do not want to be telling the SMB/CIFS client that
2455 * the AFS Client Service is busy or down.
2457 else if (code == CM_ERROR_ALLBUSY ||
2458 code == CM_ERROR_ALLOFFLINE ||
2459 code == CM_ERROR_ALLDOWN) {
2460 NTStatus = 0xC00000BEL; /* Bad Network Path */
2463 else if (code == RXKADUNKNOWNKEY) {
2464 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2466 NTStatus = 0xC0982001L; /* SMB non-specific error */
2469 *NTStatusp = NTStatus;
2470 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2473 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2474 unsigned char *classp)
2476 unsigned char class;
2477 unsigned short error;
2479 /* map CM_ERROR_* errors to SMB errors */
2480 if (code == CM_ERROR_NOSUCHCELL) {
2482 error = 3; /* bad path */
2484 else if (code == CM_ERROR_NOSUCHVOLUME) {
2486 error = 3; /* bad path */
2488 else if (code == CM_ERROR_TIMEDOUT) {
2490 error = 81; /* server is paused */
2492 else if (code == CM_ERROR_RETRY) {
2493 class = 2; /* shouldn't happen */
2496 else if (code == CM_ERROR_NOACCESS) {
2498 error = 4; /* bad access */
2500 else if (code == CM_ERROR_READONLY) {
2502 error = 19; /* read only */
2504 else if (code == CM_ERROR_NOSUCHFILE) {
2506 error = 2; /* ENOENT! */
2508 else if (code == CM_ERROR_NOSUCHPATH) {
2510 error = 3; /* Bad path */
2512 else if (code == CM_ERROR_TOOBIG) {
2514 error = 11; /* bad format */
2516 else if (code == CM_ERROR_INVAL) {
2517 class = 2; /* server non-specific error code */
2520 else if (code == CM_ERROR_BADFD) {
2522 error = 6; /* invalid file handle */
2524 else if (code == CM_ERROR_BADFDOP) {
2525 class = 1; /* invalid op on FD */
2528 else if (code == CM_ERROR_EXISTS) {
2530 error = 80; /* file already exists */
2532 else if (code == CM_ERROR_NOTEMPTY) {
2534 error = 5; /* delete directory not empty */
2536 else if (code == CM_ERROR_CROSSDEVLINK) {
2538 error = 17; /* EXDEV */
2540 else if (code == CM_ERROR_NOTDIR) {
2541 class = 1; /* bad path */
2544 else if (code == CM_ERROR_ISDIR) {
2545 class = 1; /* access denied; DOS doesn't have a good match */
2548 else if (code == CM_ERROR_BADOP) {
2552 else if (code == CM_ERROR_BADSHARENAME) {
2556 else if (code == CM_ERROR_NOIPC) {
2558 error = 4; /* bad access */
2560 else if (code == CM_ERROR_CLOCKSKEW) {
2561 class = 1; /* invalid function */
2564 else if (code == CM_ERROR_BADTID) {
2568 else if (code == CM_ERROR_USESTD) {
2572 else if (code == CM_ERROR_REMOTECONN) {
2576 else if (code == CM_ERROR_QUOTA) {
2577 if (vcp->flags & SMB_VCFLAG_USEV3) {
2579 error = 39; /* disk full */
2583 error = 5; /* access denied */
2586 else if (code == CM_ERROR_SPACE) {
2587 if (vcp->flags & SMB_VCFLAG_USEV3) {
2589 error = 39; /* disk full */
2593 error = 5; /* access denied */
2596 else if (code == CM_ERROR_PARTIALWRITE) {
2598 error = 39; /* disk full */
2600 else if (code == CM_ERROR_ATSYS) {
2602 error = 2; /* ENOENT */
2604 else if (code == CM_ERROR_WOULDBLOCK) {
2606 error = 33; /* lock conflict */
2608 else if (code == CM_ERROR_LOCK_CONFLICT) {
2610 error = 33; /* lock conflict */
2612 else if (code == CM_ERROR_SHARING_VIOLATION) {
2614 error = 33; /* lock conflict */
2616 else if (code == CM_ERROR_NOFILES) {
2618 error = 18; /* no files in search */
2620 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2622 error = 183; /* Samba uses this */
2624 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2625 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2627 error = 2; /* bad password */
2629 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2631 error = 3; /* bad path */
2640 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2643 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2645 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2646 return CM_ERROR_BADOP;
2649 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2651 unsigned short EchoCount, i;
2652 char *data, *outdata;
2655 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2657 for (i=1; i<=EchoCount; i++) {
2658 data = smb_GetSMBData(inp, &dataSize);
2659 smb_SetSMBParm(outp, 0, i);
2660 smb_SetSMBDataLength(outp, dataSize);
2661 outdata = smb_GetSMBData(outp, NULL);
2662 memcpy(outdata, data, dataSize);
2663 smb_SendPacket(vcp, outp);
2669 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2672 long count, minCount, finalCount;
2677 cm_user_t *userp = NULL;
2681 char *rawBuf = NULL;
2683 dos_ptr rawBuf = NULL;
2690 fd = smb_GetSMBParm(inp, 0);
2691 count = smb_GetSMBParm(inp, 3);
2692 minCount = smb_GetSMBParm(inp, 4);
2693 offset.HighPart = 0; /* too bad */
2694 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2696 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2697 fd, offset.LowPart, count);
2699 fidp = smb_FindFID(vcp, fd, 0);
2703 pid = ((smb_t *) inp)->pid;
2705 LARGE_INTEGER LOffset, LLength;
2708 key = cm_GenerateKey(vcp->vcID, pid, fd);
2710 LOffset.HighPart = 0;
2711 LOffset.LowPart = offset.LowPart;
2712 LLength.HighPart = 0;
2713 LLength.LowPart = count;
2715 lock_ObtainMutex(&fidp->scp->mx);
2716 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2717 lock_ReleaseMutex(&fidp->scp->mx);
2723 lock_ObtainMutex(&smb_RawBufLock);
2725 /* Get a raw buf, from head of list */
2726 rawBuf = smb_RawBufs;
2728 smb_RawBufs = *(char **)smb_RawBufs;
2730 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2733 lock_ReleaseMutex(&smb_RawBufLock);
2737 if (fidp->flags & SMB_FID_IOCTL)
2740 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2742 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2745 /* Give back raw buffer */
2746 lock_ObtainMutex(&smb_RawBufLock);
2748 *((char **) rawBuf) = smb_RawBufs;
2750 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2753 smb_RawBufs = rawBuf;
2754 lock_ReleaseMutex(&smb_RawBufLock);
2757 smb_ReleaseFID(fidp);
2761 userp = smb_GetUser(vcp, inp);
2764 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2766 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2767 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2768 userp, &finalCount, TRUE /* rawFlag */);
2775 cm_ReleaseUser(userp);
2778 smb_ReleaseFID(fidp);
2783 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2785 memset((char *)ncbp, 0, sizeof(NCB));
2787 ncbp->ncb_length = (unsigned short) finalCount;
2788 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2789 ncbp->ncb_lana_num = vcp->lana;
2790 ncbp->ncb_command = NCBSEND;
2791 ncbp->ncb_buffer = rawBuf;
2794 code = Netbios(ncbp);
2796 code = Netbios(ncbp, dos_ncb);
2799 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2802 /* Give back raw buffer */
2803 lock_ObtainMutex(&smb_RawBufLock);
2805 *((char **) rawBuf) = smb_RawBufs;
2807 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2810 smb_RawBufs = rawBuf;
2811 lock_ReleaseMutex(&smb_RawBufLock);
2817 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2819 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2824 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2826 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2831 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2838 int protoIndex; /* index we're using */
2843 char protocol_array[10][1024]; /* protocol signature of the client */
2844 int caps; /* capabilities */
2847 TIME_ZONE_INFORMATION tzi;
2849 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2853 DWORD now = GetCurrentTime();
2854 if (now - last_msg_time >= 30000
2855 && now - last_msg_time <= 90000) {
2857 "Setting dead_vcp %x", active_vcp);
2859 smb_ReleaseVC(dead_vcp);
2861 "Previous dead_vcp %x", dead_vcp);
2863 smb_HoldVC(active_vcp);
2864 dead_vcp = active_vcp;
2865 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2870 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2872 namep = smb_GetSMBData(inp, &dbytes);
2875 coreProtoIndex = -1; /* not found */
2878 while(namex < dbytes) {
2879 osi_Log1(smb_logp, "Protocol %s",
2880 osi_LogSaveString(smb_logp, namep+1));
2881 strcpy(protocol_array[tcounter], namep+1);
2883 /* namep points at the first protocol, or really, a 0x02
2884 * byte preceding the null-terminated ASCII name.
2886 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2887 coreProtoIndex = tcounter;
2889 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2890 v3ProtoIndex = tcounter;
2892 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2893 NTProtoIndex = tcounter;
2896 /* compute size of protocol entry */
2897 entryLength = (int)strlen(namep+1);
2898 entryLength += 2; /* 0x02 bytes and null termination */
2900 /* advance over this protocol entry */
2901 namex += entryLength;
2902 namep += entryLength;
2903 tcounter++; /* which proto entry we're looking at */
2906 if (NTProtoIndex != -1) {
2907 protoIndex = NTProtoIndex;
2908 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2910 else if (v3ProtoIndex != -1) {
2911 protoIndex = v3ProtoIndex;
2912 vcp->flags |= SMB_VCFLAG_USEV3;
2914 else if (coreProtoIndex != -1) {
2915 protoIndex = coreProtoIndex;
2916 vcp->flags |= SMB_VCFLAG_USECORE;
2918 else protoIndex = -1;
2920 if (protoIndex == -1)
2921 return CM_ERROR_INVAL;
2922 else if (NTProtoIndex != -1) {
2923 smb_SetSMBParm(outp, 0, protoIndex);
2924 if (smb_authType != SMB_AUTH_NONE) {
2925 smb_SetSMBParmByte(outp, 1,
2926 NEGOTIATE_SECURITY_USER_LEVEL |
2927 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2929 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2931 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2932 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2933 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2934 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2935 /* The session key is not a well documented field however most clients
2936 * will echo back the session key to the server. Currently we are using
2937 * the same value for all sessions. We should generate a random value
2938 * and store it into the vcp
2940 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2941 smb_SetSMBParm(outp, 8, 1);
2943 * Tried changing the capabilities to support for W2K - defect 117695
2944 * Maybe something else needs to be changed here?
2948 smb_SetSMBParmLong(outp, 9, 0x43fd);
2950 smb_SetSMBParmLong(outp, 9, 0x251);
2953 * 32-bit error codes *
2958 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2960 NTNEGOTIATE_CAPABILITY_DFS |
2962 NTNEGOTIATE_CAPABILITY_NTFIND |
2963 NTNEGOTIATE_CAPABILITY_RAWMODE |
2964 NTNEGOTIATE_CAPABILITY_NTSMB;
2966 if ( smb_authType == SMB_AUTH_EXTENDED )
2967 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2969 smb_SetSMBParmLong(outp, 9, caps);
2971 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2972 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2973 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2975 GetTimeZoneInformation(&tzi);
2976 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2978 if (smb_authType == SMB_AUTH_NTLM) {
2979 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2980 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2981 /* paste in encryption key */
2982 datap = smb_GetSMBData(outp, NULL);
2983 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2984 /* and the faux domain name */
2985 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2986 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2990 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2992 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2994 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2996 datap = smb_GetSMBData(outp, NULL);
2997 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3000 datap += sizeof(smb_ServerGUID);
3001 memcpy(datap, secBlob, secBlobLength);
3005 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3006 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3009 else if (v3ProtoIndex != -1) {
3010 smb_SetSMBParm(outp, 0, protoIndex);
3012 /* NOTE: Extended authentication cannot be negotiated with v3
3013 * therefore we fail over to NTLM
3015 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3016 smb_SetSMBParm(outp, 1,
3017 NEGOTIATE_SECURITY_USER_LEVEL |
3018 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3020 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3022 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3023 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3024 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3025 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3026 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3027 smb_SetSMBParm(outp, 7, 1);
3029 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3030 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3031 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3033 GetTimeZoneInformation(&tzi);
3034 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3036 /* NOTE: Extended authentication cannot be negotiated with v3
3037 * therefore we fail over to NTLM
3039 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3040 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3041 smb_SetSMBParm(outp, 12, 0); /* resvd */
3042 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3043 datap = smb_GetSMBData(outp, NULL);
3044 /* paste in a new encryption key */
3045 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3046 /* and the faux domain name */
3047 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3049 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3050 smb_SetSMBParm(outp, 12, 0); /* resvd */
3051 smb_SetSMBDataLength(outp, 0);
3054 else if (coreProtoIndex != -1) { /* not really supported anymore */
3055 smb_SetSMBParm(outp, 0, protoIndex);
3056 smb_SetSMBDataLength(outp, 0);
3061 void smb_Daemon(void *parmp)
3063 afs_uint32 count = 0;
3065 while(smbShutdownFlag == 0) {
3069 if (smbShutdownFlag == 1)
3072 if ((count % 72) == 0) { /* every five minutes */
3074 time_t old_localZero = smb_localZero;
3076 /* Initialize smb_localZero */
3077 myTime.tm_isdst = -1; /* compute whether on DST or not */
3078 myTime.tm_year = 70;
3084 smb_localZero = mktime(&myTime);
3086 #ifndef USE_NUMERIC_TIME_CONV
3087 smb_CalculateNowTZ();
3088 #endif /* USE_NUMERIC_TIME_CONV */
3089 #ifdef AFS_FREELANCE
3090 if ( smb_localZero != old_localZero )
3091 cm_noteLocalMountPointChange();
3094 /* XXX GC dir search entries */
3098 void smb_WaitingLocksDaemon()
3100 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3101 smb_waitingLock_t *wl, *wlNext;
3104 smb_packet_t *inp, *outp;
3108 while (smbShutdownFlag == 0) {
3109 lock_ObtainWrite(&smb_globalLock);
3110 nwlRequest = smb_allWaitingLocks;
3111 if (nwlRequest == NULL) {
3112 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3122 lock_ObtainWrite(&smb_globalLock);
3124 wlRequest = nwlRequest;
3125 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3126 lock_ReleaseWrite(&smb_globalLock);
3130 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3131 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3134 /* wl->state is either _DONE or _WAITING. _ERROR
3135 would no longer be on the queue. */
3136 code = cm_RetryLock( wl->lockp,
3137 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3140 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3141 } else if (code != CM_ERROR_WOULDBLOCK) {
3142 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3147 if (code == CM_ERROR_WOULDBLOCK) {
3150 if (wlRequest->timeRemaining != 0xffffffff
3151 && (wlRequest->timeRemaining -= 1000) < 0)
3163 scp = wlRequest->scp;
3167 lock_ObtainMutex(&scp->mx);
3169 for (wl = wlRequest->locks; wl; wl = wlNext) {
3170 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3172 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3173 wl->LLength, wl->key, NULL, &req);
3175 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3180 lock_ReleaseMutex(&scp->mx);
3183 for (wl = wlRequest->locks; wl; wl = wlNext) {
3184 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3185 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3190 vcp = wlRequest->vcp;
3191 inp = wlRequest->inp;
3192 outp = wlRequest->outp;
3194 ncbp->ncb_length = inp->ncb_length;
3195 inp->spacep = cm_GetSpace();
3197 /* Remove waitingLock from list */
3198 lock_ObtainWrite(&smb_globalLock);
3199 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3201 lock_ReleaseWrite(&smb_globalLock);
3203 /* Resume packet processing */
3205 smb_SetSMBDataLength(outp, 0);
3206 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3207 outp->resumeCode = code;
3209 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3212 cm_FreeSpace(inp->spacep);
3213 smb_FreePacket(inp);
3214 smb_FreePacket(outp);
3216 cm_ReleaseSCache(wlRequest->scp);
3219 } while (nwlRequest && smbShutdownFlag == 0);
3224 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3226 osi_Log0(smb_logp, "SMB receive get disk attributes");
3228 smb_SetSMBParm(outp, 0, 32000);
3229 smb_SetSMBParm(outp, 1, 64);
3230 smb_SetSMBParm(outp, 2, 1024);
3231 smb_SetSMBParm(outp, 3, 30000);
3232 smb_SetSMBParm(outp, 4, 0);
3233 smb_SetSMBDataLength(outp, 0);
3237 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3241 unsigned short newTid;
3242 char shareName[256];
3250 osi_Log0(smb_logp, "SMB receive tree connect");
3252 /* parse input parameters */
3253 tp = smb_GetSMBData(inp, NULL);
3254 pathp = smb_ParseASCIIBlock(tp, &tp);
3255 if (smb_StoreAnsiFilenames)
3256 OemToChar(pathp,pathp);
3257 passwordp = smb_ParseASCIIBlock(tp, &tp);
3258 tp = strrchr(pathp, '\\');
3260 return CM_ERROR_BADSMB;
3261 strcpy(shareName, tp+1);
3263 userp = smb_GetUser(vcp, inp);
3265 lock_ObtainMutex(&vcp->mx);
3266 newTid = vcp->tidCounter++;
3267 lock_ReleaseMutex(&vcp->mx);
3269 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3270 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3271 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3273 smb_ReleaseUID(uidp);
3275 smb_ReleaseTID(tidp);
3276 return CM_ERROR_BADSHARENAME;
3278 lock_ObtainMutex(&tidp->mx);
3279 tidp->userp = userp;
3280 tidp->pathname = sharePath;
3281 lock_ReleaseMutex(&tidp->mx);
3282 smb_ReleaseTID(tidp);
3284 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3285 smb_SetSMBParm(rsp, 1, newTid);
3286 smb_SetSMBDataLength(rsp, 0);
3288 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3292 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3296 if (*inp++ != 0x1) return NULL;
3297 tlen = inp[0] + (inp[1]<<8);
3298 inp += 2; /* skip length field */
3301 *chainpp = inp + tlen;
3304 if (lengthp) *lengthp = tlen;
3309 /* set maskp to the mask part of the incoming path.
3310 * Mask is 11 bytes long (8.3 with the dot elided).
3311 * Returns true if succeeds with a valid name, otherwise it does
3312 * its best, but returns false.
3314 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3322 /* starts off valid */
3325 /* mask starts out all blanks */
3326 memset(maskp, ' ', 11);
3328 /* find last backslash, or use whole thing if there is none */
3329 tp = strrchr(pathp, '\\');
3330 if (!tp) tp = pathp;
3331 else tp++; /* skip slash */
3335 /* names starting with a dot are illegal */
3336 if (*tp == '.') valid8Dot3 = 0;
3340 if (tc == 0) return valid8Dot3;
3341 if (tc == '.' || tc == '"') break;
3342 if (i < 8) *up++ = tc;
3343 else valid8Dot3 = 0;
3346 /* if we get here, tp point after the dot */
3347 up = maskp+8; /* ext goes here */
3354 if (tc == '.' || tc == '"')
3357 /* copy extension if not too long */
3367 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3377 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3379 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3383 /* otherwise, we have a valid 8.3 name; see if we have a match,
3384 * treating '?' as a wildcard in maskp (but not in the file name).
3386 tp1 = umask; /* real name, in mask format */
3387 tp2 = maskp; /* mask, in mask format */
3388 for(i=0; i<11; i++) {
3389 tc1 = *tp1++; /* char from real name */
3390 tc2 = *tp2++; /* char from mask */
3391 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3392 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3395 if (tc2 == '?' && tc1 != ' ')
3402 /* we got a match */
3406 char *smb_FindMask(char *pathp)
3410 tp = strrchr(pathp, '\\'); /* find last slash */
3413 return tp+1; /* skip the slash */
3415 return pathp; /* no slash, return the entire path */
3418 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3420 unsigned char *pathp;
3422 unsigned char mask[11];
3423 unsigned char *statBlockp;
3424 unsigned char initStatBlock[21];
3427 osi_Log0(smb_logp, "SMB receive search volume");
3429 /* pull pathname and stat block out of request */
3430 tp = smb_GetSMBData(inp, NULL);
3431 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3432 osi_assert(pathp != NULL);
3433 if (smb_StoreAnsiFilenames)
3434 OemToChar(pathp,pathp);
3435 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3436 osi_assert(statBlockp != NULL);
3438 statBlockp = initStatBlock;
3442 /* for returning to caller */
3443 smb_Get8Dot3MaskFromPath(mask, pathp);
3445 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3446 tp = smb_GetSMBData(outp, NULL);
3448 *tp++ = 43; /* bytes in a dir entry */
3449 *tp++ = 0; /* high byte in counter */
3451 /* now marshall the dir entry, starting with the search status */
3452 *tp++ = statBlockp[0]; /* Reserved */
3453 memcpy(tp, mask, 11); tp += 11; /* FileName */
3455 /* now pass back server use info, with 1st byte non-zero */
3457 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3459 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3461 *tp++ = 0x8; /* attribute: volume */
3471 /* 4 byte file size */
3477 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3478 memset(tp, ' ', 13);
3481 /* set the length of the data part of the packet to 43 + 3, for the dir
3482 * entry plus the 5 and the length fields.
3484 smb_SetSMBDataLength(outp, 46);
3488 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3489 cm_user_t *userp, cm_req_t *reqp)
3497 smb_dirListPatch_t *patchp;
3498 smb_dirListPatch_t *npatchp;
3500 for (patchp = *dirPatchespp; patchp; patchp =
3501 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3503 dptr = patchp->dptr;
3505 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3507 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3508 *dptr++ = SMB_ATTR_HIDDEN;
3511 lock_ObtainMutex(&scp->mx);
3512 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3513 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3515 lock_ReleaseMutex(&scp->mx);
3516 cm_ReleaseSCache(scp);
3517 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3518 *dptr++ = SMB_ATTR_HIDDEN;
3522 attr = smb_Attributes(scp);
3523 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3524 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3525 attr |= SMB_ATTR_HIDDEN;
3529 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3532 shortTemp = (unsigned short) (dosTime & 0xffff);
3533 *((u_short *)dptr) = shortTemp;
3536 /* and copy out date */
3537 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3538 *((u_short *)dptr) = shortTemp;
3541 /* copy out file length */
3542 *((u_long *)dptr) = scp->length.LowPart;
3544 lock_ReleaseMutex(&scp->mx);
3545 cm_ReleaseSCache(scp);
3548 /* now free the patches */
3549 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3550 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3554 /* and mark the list as empty */
3555 *dirPatchespp = NULL;
3560 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3569 smb_dirListPatch_t *dirListPatchesp;
3570 smb_dirListPatch_t *curPatchp;
3574 osi_hyper_t dirLength;
3575 osi_hyper_t bufferOffset;
3576 osi_hyper_t curOffset;
3578 unsigned char *inCookiep;
3579 smb_dirSearch_t *dsp;
3583 unsigned long clientCookie;
3584 cm_pageHeader_t *pageHeaderp;
3585 cm_user_t *userp = NULL;
3592 long nextEntryCookie;
3593 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3594 char resByte; /* reserved byte from the cookie */
3595 char *op; /* output data ptr */
3596 char *origOp; /* original value of op */
3597 cm_space_t *spacep; /* for pathname buffer */
3608 maxCount = smb_GetSMBParm(inp, 0);
3610 dirListPatchesp = NULL;
3612 caseFold = CM_FLAG_CASEFOLD;
3614 tp = smb_GetSMBData(inp, NULL);
3615 pathp = smb_ParseASCIIBlock(tp, &tp);
3616 if (smb_StoreAnsiFilenames)
3617 OemToChar(pathp,pathp);
3618 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3620 /* bail out if request looks bad */
3621 if (!tp || !pathp) {
3622 return CM_ERROR_BADSMB;
3625 /* We can handle long names */
3626 if (vcp->flags & SMB_VCFLAG_USENT)
3627 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3629 /* make sure we got a whole search status */
3630 if (dataLength < 21) {
3631 nextCookie = 0; /* start at the beginning of the dir */
3634 attribute = smb_GetSMBParm(inp, 1);
3636 /* handle volume info in another function */
3637 if (attribute & 0x8)
3638 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3640 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3641 maxCount, osi_LogSaveString(smb_logp, pathp));
3643 if (*pathp == 0) { /* null pathp, treat as root dir */
3644 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3645 return CM_ERROR_NOFILES;
3649 dsp = smb_NewDirSearch(0);
3650 dsp->attribute = attribute;
3651 smb_Get8Dot3MaskFromPath(mask, pathp);
3652 memcpy(dsp->mask, mask, 11);
3654 /* track if this is likely to match a lot of entries */
3655 if (smb_IsStarMask(mask))
3660 /* pull the next cookie value out of the search status block */
3661 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3662 + (inCookiep[16]<<24);
3663 dsp = smb_FindDirSearch(inCookiep[12]);
3665 /* can't find dir search status; fatal error */
3666 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3667 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3668 return CM_ERROR_BADFD;
3670 attribute = dsp->attribute;
3671 resByte = inCookiep[0];
3673 /* copy out client cookie, in host byte order. Don't bother
3674 * interpreting it, since we're just passing it through, anyway.
3676 memcpy(&clientCookie, &inCookiep[17], 4);
3678 memcpy(mask, dsp->mask, 11);
3680 /* assume we're doing a star match if it has continued for more
3686 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3687 nextCookie, dsp->cookie, attribute);
3689 userp = smb_GetUser(vcp, inp);
3691 /* try to get the vnode for the path name next */
3692 lock_ObtainMutex(&dsp->mx);
3698 spacep = inp->spacep;
3699 smb_StripLastComponent(spacep->data, NULL, pathp);
3700 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3702 lock_ReleaseMutex(&dsp->mx);
3703 cm_ReleaseUser(userp);
3704 smb_DeleteDirSearch(dsp);
3705 smb_ReleaseDirSearch(dsp);
3706 return CM_ERROR_NOFILES;
3708 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3709 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3712 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3713 cm_ReleaseSCache(scp);
3714 lock_ReleaseMutex(&dsp->mx);
3715 cm_ReleaseUser(userp);
3716 smb_DeleteDirSearch(dsp);
3717 smb_ReleaseDirSearch(dsp);
3718 if ( WANTS_DFS_PATHNAMES(inp) )
3719 return CM_ERROR_PATH_NOT_COVERED;
3721 return CM_ERROR_BADSHARENAME;
3723 #endif /* DFS_SUPPORT */
3726 /* we need one hold for the entry we just stored into,
3727 * and one for our own processing. When we're done with this
3728 * function, we'll drop the one for our own processing.
3729 * We held it once from the namei call, and so we do another hold
3733 lock_ObtainMutex(&scp->mx);
3734 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3735 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3736 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3737 dsp->flags |= SMB_DIRSEARCH_BULKST;
3739 lock_ReleaseMutex(&scp->mx);
3742 lock_ReleaseMutex(&dsp->mx);
3744 cm_ReleaseUser(userp);
3745 smb_DeleteDirSearch(dsp);
3746 smb_ReleaseDirSearch(dsp);
3750 /* reserves space for parameter; we'll adjust it again later to the
3751 * real count of the # of entries we returned once we've actually
3752 * assembled the directory listing.
3754 smb_SetSMBParm(outp, 0, 0);
3756 /* get the directory size */
3757 lock_ObtainMutex(&scp->mx);
3758 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3759 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3761 lock_ReleaseMutex(&scp->mx);
3762 cm_ReleaseSCache(scp);
3763 cm_ReleaseUser(userp);
3764 smb_DeleteDirSearch(dsp);
3765 smb_ReleaseDirSearch(dsp);
3769 dirLength = scp->length;
3771 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3772 curOffset.HighPart = 0;
3773 curOffset.LowPart = nextCookie;
3774 origOp = op = smb_GetSMBData(outp, NULL);
3775 /* and write out the basic header */
3776 *op++ = 5; /* variable block */
3777 op += 2; /* skip vbl block length; we'll fill it in later */
3781 /* make sure that curOffset.LowPart doesn't point to the first
3782 * 32 bytes in the 2nd through last dir page, and that it doesn't
3783 * point at the first 13 32-byte chunks in the first dir page,
3784 * since those are dir and page headers, and don't contain useful
3787 temp = curOffset.LowPart & (2048-1);
3788 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3789 /* we're in the first page */
3790 if (temp < 13*32) temp = 13*32;
3793 /* we're in a later dir page */
3794 if (temp < 32) temp = 32;
3797 /* make sure the low order 5 bits are zero */
3800 /* now put temp bits back ito curOffset.LowPart */
3801 curOffset.LowPart &= ~(2048-1);
3802 curOffset.LowPart |= temp;
3804 /* check if we've returned all the names that will fit in the
3807 if (returnedNames >= maxCount) {
3808 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3809 returnedNames, maxCount);
3813 /* check if we've passed the dir's EOF */
3814 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3816 /* see if we can use the bufferp we have now; compute in which page
3817 * the current offset would be, and check whether that's the offset
3818 * of the buffer we have. If not, get the buffer.
3820 thyper.HighPart = curOffset.HighPart;
3821 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3822 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3825 buf_Release(bufferp);
3828 lock_ReleaseMutex(&scp->mx);
3829 lock_ObtainRead(&scp->bufCreateLock);
3830 code = buf_Get(scp, &thyper, &bufferp);
3831 lock_ReleaseRead(&scp->bufCreateLock);
3832 lock_ObtainMutex(&dsp->mx);
3834 /* now, if we're doing a star match, do bulk fetching of all of
3835 * the status info for files in the dir.
3838 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3839 lock_ObtainMutex(&scp->mx);
3840 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3841 LargeIntegerGreaterThanOrEqualTo(thyper,
3842 scp->bulkStatProgress)) {
3843 /* Don't bulk stat if risking timeout */
3844 int now = GetCurrentTime();
3845 if (now - req.startTime > 5000) {
3846 scp->bulkStatProgress = thyper;
3847 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3848 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3850 cm_TryBulkStat(scp, &thyper, userp, &req);
3853 lock_ObtainMutex(&scp->mx);
3855 lock_ReleaseMutex(&dsp->mx);
3857 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3861 bufferOffset = thyper;
3863 /* now get the data in the cache */
3865 code = cm_SyncOp(scp, bufferp, userp, &req,
3867 CM_SCACHESYNC_NEEDCALLBACK |
3868 CM_SCACHESYNC_READ);
3870 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3874 if (cm_HaveBuffer(scp, bufferp, 0)) {
3875 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3879 /* otherwise, load the buffer and try again */
3880 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3882 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3883 scp, bufferp, code);
3888 buf_Release(bufferp);
3892 } /* if (wrong buffer) ... */
3894 /* now we have the buffer containing the entry we're interested in; copy
3895 * it out if it represents a non-deleted entry.
3897 entryInDir = curOffset.LowPart & (2048-1);
3898 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3900 /* page header will help tell us which entries are free. Page header
3901 * can change more often than once per buffer, since AFS 3 dir page size
3902 * may be less than (but not more than a buffer package buffer.
3904 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3905 temp &= ~(2048 - 1); /* turn off intra-page bits */
3906 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3908 /* now determine which entry we're looking at in the page. If it is
3909 * free (there's a free bitmap at the start of the dir), we should
3910 * skip these 32 bytes.
3912 slotInPage = (entryInDir & 0x7e0) >> 5;
3913 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3914 /* this entry is free */
3915 numDirChunks = 1; /* only skip this guy */
3919 tp = bufferp->datap + entryInBuffer;
3920 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3922 /* while we're here, compute the next entry's location, too,
3923 * since we'll need it when writing out the cookie into the dir
3926 * XXXX Probably should do more sanity checking.
3928 numDirChunks = cm_NameEntries(dep->name, NULL);
3930 /* compute the offset of the cookie representing the next entry */
3931 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3933 /* Compute 8.3 name if necessary */
3934 actualName = dep->name;
3935 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3936 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3937 actualName = shortName;
3940 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3941 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3942 osi_LogSaveString(smb_logp, actualName));
3944 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3945 /* this is one of the entries to use: it is not deleted
3946 * and it matches the star pattern we're looking for.
3949 /* Eliminate entries that don't match requested
3952 /* no hidden files */
3953 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3954 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3958 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3960 /* We have already done the cm_TryBulkStat above */
3961 fid.cell = scp->fid.cell;
3962 fid.volume = scp->fid.volume;
3963 fid.vnode = ntohl(dep->fid.vnode);
3964 fid.unique = ntohl(dep->fid.unique);
3965 fileType = cm_FindFileType(&fid);
3966 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3967 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3969 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3970 fileType == CM_SCACHETYPE_DFSLINK ||
3971 fileType == CM_SCACHETYPE_INVALID)
3972 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3977 memcpy(op, mask, 11); op += 11;
3978 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3979 *op++ = (char)(nextEntryCookie & 0xff);
3980 *op++ = (char)((nextEntryCookie>>8) & 0xff);
3981 *op++ = (char)((nextEntryCookie>>16) & 0xff);
3982 *op++ = (char)((nextEntryCookie>>24) & 0xff);
3983 memcpy(op, &clientCookie, 4); op += 4;
3985 /* now we emit the attribute. This is sort of tricky,
3986 * since we need to really stat the file to find out
3987 * what type of entry we've got. Right now, we're
3988 * copying out data from a buffer, while holding the
3989 * scp locked, so it isn't really convenient to stat
3990 * something now. We'll put in a place holder now,
3991 * and make a second pass before returning this to get
3992 * the real attributes. So, we just skip the data for
3993 * now, and adjust it later. We allocate a patch
3994 * record to make it easy to find this point later.
3995 * The replay will happen at a time when it is safe to
3996 * unlock the directory.
3998 curPatchp = malloc(sizeof(*curPatchp));
3999 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4000 curPatchp->dptr = op;
4001 curPatchp->fid.cell = scp->fid.cell;
4002 curPatchp->fid.volume = scp->fid.volume;
4003 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4004 curPatchp->fid.unique = ntohl(dep->fid.unique);
4006 /* do hidden attribute here since name won't be around when applying
4010 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4011 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4013 curPatchp->flags = 0;
4015 op += 9; /* skip attr, time, date and size */
4017 /* zero out name area. The spec says to pad with
4018 * spaces, but Samba doesn't, and neither do we.
4022 /* finally, we get to copy out the name; we know that
4023 * it fits in 8.3 or the pattern wouldn't match, but it
4024 * never hurts to be sure.
4026 strncpy(op, actualName, 13);
4027 if (smb_StoreAnsiFilenames)
4030 /* Uppercase if requested by client */
4031 if (!KNOWS_LONG_NAMES(inp))
4036 /* now, adjust the # of entries copied */
4038 } /* if we're including this name */
4041 /* and adjust curOffset to be where the new cookie is */
4042 thyper.HighPart = 0;
4043 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4044 curOffset = LargeIntegerAdd(thyper, curOffset);
4045 } /* while copying data for dir listing */
4047 /* release the mutex */
4048 lock_ReleaseMutex(&scp->mx);
4049 if (bufferp) buf_Release(bufferp);
4051 /* apply and free last set of patches; if not doing a star match, this
4052 * will be empty, but better safe (and freeing everything) than sorry.
4054 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4056 /* special return code for unsuccessful search */
4057 if (code == 0 && dataLength < 21 && returnedNames == 0)
4058 code = CM_ERROR_NOFILES;
4060 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4061 returnedNames, code);
4064 smb_DeleteDirSearch(dsp);
4065 smb_ReleaseDirSearch(dsp);
4066 cm_ReleaseSCache(scp);
4067 cm_ReleaseUser(userp);
4071 /* finalize the output buffer */
4072 smb_SetSMBParm(outp, 0, returnedNames);
4073 temp = (long) (op - origOp);
4074 smb_SetSMBDataLength(outp, temp);
4076 /* the data area is a variable block, which has a 5 (already there)
4077 * followed by the length of the # of data bytes. We now know this to
4078 * be "temp," although that includes the 3 bytes of vbl block header.
4079 * Deduct for them and fill in the length field.
4081 temp -= 3; /* deduct vbl block info */
4082 osi_assert(temp == (43 * returnedNames));
4083 origOp[1] = (char)(temp & 0xff);
4084 origOp[2] = (char)((temp>>8) & 0xff);
4085 if (returnedNames == 0)
4086 smb_DeleteDirSearch(dsp);
4087 smb_ReleaseDirSearch(dsp);
4088 cm_ReleaseSCache(scp);
4089 cm_ReleaseUser(userp);
4093 /* verify that this is a valid path to a directory. I don't know why they
4094 * don't use the get file attributes call.
4096 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4100 cm_scache_t *rootScp;
4101 cm_scache_t *newScp;
4110 pathp = smb_GetSMBData(inp, NULL);
4111 pathp = smb_ParseASCIIBlock(pathp, NULL);
4113 return CM_ERROR_BADFD;
4114 if (smb_StoreAnsiFilenames)
4115 OemToChar(pathp,pathp);
4116 osi_Log1(smb_logp, "SMB receive check path %s",
4117 osi_LogSaveString(smb_logp, pathp));
4119 rootScp = cm_data.rootSCachep;
4121 userp = smb_GetUser(vcp, inp);
4123 caseFold = CM_FLAG_CASEFOLD;
4125 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4127 cm_ReleaseUser(userp);
4128 return CM_ERROR_NOSUCHPATH;
4130 code = cm_NameI(rootScp, pathp,
4131 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4132 userp, tidPathp, &req, &newScp);
4135 cm_ReleaseUser(userp);
4140 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4141 cm_ReleaseSCache(newScp);
4142 cm_ReleaseUser(userp);
4143 if ( WANTS_DFS_PATHNAMES(inp) )
4144 return CM_ERROR_PATH_NOT_COVERED;
4146 return CM_ERROR_BADSHARENAME;
4148 #endif /* DFS_SUPPORT */
4150 /* now lock the vnode with a callback; returns with newScp locked */
4151 lock_ObtainMutex(&newScp->mx);
4152 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4153 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4154 if (code && code != CM_ERROR_NOACCESS) {
4155 lock_ReleaseMutex(&newScp->mx);
4156 cm_ReleaseSCache(newScp);
4157 cm_ReleaseUser(userp);
4161 attrs = smb_Attributes(newScp);
4163 if (!(attrs & SMB_ATTR_DIRECTORY))
4164 code = CM_ERROR_NOTDIR;
4166 lock_ReleaseMutex(&newScp->mx);
4168 cm_ReleaseSCache(newScp);
4169 cm_ReleaseUser(userp);
4173 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4177 cm_scache_t *rootScp;
4178 unsigned short attribute;
4180 cm_scache_t *newScp;
4189 /* decode basic attributes we're passed */
4190 attribute = smb_GetSMBParm(inp, 0);
4191 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4193 pathp = smb_GetSMBData(inp, NULL);
4194 pathp = smb_ParseASCIIBlock(pathp, NULL);
4196 return CM_ERROR_BADSMB;
4197 if (smb_StoreAnsiFilenames)
4198 OemToChar(pathp,pathp);
4200 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4201 dosTime, attribute);
4203 rootScp = cm_data.rootSCachep;
4205 userp = smb_GetUser(vcp, inp);
4207 caseFold = CM_FLAG_CASEFOLD;
4209 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4211 cm_ReleaseUser(userp);
4212 return CM_ERROR_NOSUCHFILE;
4214 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4215 tidPathp, &req, &newScp);
4218 cm_ReleaseUser(userp);
4223 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4224 cm_ReleaseSCache(newScp);
4225 cm_ReleaseUser(userp);
4226 if ( WANTS_DFS_PATHNAMES(inp) )
4227 return CM_ERROR_PATH_NOT_COVERED;
4229 return CM_ERROR_BADSHARENAME;
4231 #endif /* DFS_SUPPORT */
4233 /* now lock the vnode with a callback; returns with newScp locked; we
4234 * need the current status to determine what the new status is, in some
4237 lock_ObtainMutex(&newScp->mx);
4238 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4239 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4241 lock_ReleaseMutex(&newScp->mx);
4242 cm_ReleaseSCache(newScp);
4243 cm_ReleaseUser(userp);
4247 /* Check for RO volume */
4248 if (newScp->flags & CM_SCACHEFLAG_RO) {
4249 lock_ReleaseMutex(&newScp->mx);
4250 cm_ReleaseSCache(newScp);
4251 cm_ReleaseUser(userp);
4252 return CM_ERROR_READONLY;
4255 /* prepare for setattr call */
4258 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4259 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4261 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4262 /* we're told to make a writable file read-only */
4263 attr.unixModeBits = newScp->unixModeBits & ~0222;
4264 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4266 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4267 /* we're told to make a read-only file writable */
4268 attr.unixModeBits = newScp->unixModeBits | 0222;
4269 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4271 lock_ReleaseMutex(&newScp->mx);
4273 /* now call setattr */
4275 code = cm_SetAttr(newScp, &attr, userp, &req);
4279 cm_ReleaseSCache(newScp);
4280 cm_ReleaseUser(userp);
4285 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4289 cm_scache_t *rootScp;
4290 cm_scache_t *newScp, *dscp;
4302 pathp = smb_GetSMBData(inp, NULL);
4303 pathp = smb_ParseASCIIBlock(pathp, NULL);
4305 return CM_ERROR_BADSMB;
4307 if (*pathp == 0) /* null path */
4310 if (smb_StoreAnsiFilenames)
4311 OemToChar(pathp,pathp);
4313 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4314 osi_LogSaveString(smb_logp, pathp));
4316 rootScp = cm_data.rootSCachep;
4318 userp = smb_GetUser(vcp, inp);
4320 /* we shouldn't need this for V3 requests, but we seem to */
4321 caseFold = CM_FLAG_CASEFOLD;
4323 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4325 cm_ReleaseUser(userp);
4326 return CM_ERROR_NOSUCHFILE;
4330 * XXX Strange hack XXX
4332 * As of Patch 5 (16 July 97), we are having the following problem:
4333 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4334 * requests to look up "desktop.ini" in all the subdirectories.
4335 * This can cause zillions of timeouts looking up non-existent cells
4336 * and volumes, especially in the top-level directory.
4338 * We have not found any way to avoid this or work around it except
4339 * to explicitly ignore the requests for mount points that haven't
4340 * yet been evaluated and for directories that haven't yet been
4343 * We should modify this hack to provide a fake desktop.ini file
4344 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4346 spacep = inp->spacep;
4347 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4348 #ifndef SPECIAL_FOLDERS
4349 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4350 code = cm_NameI(rootScp, spacep->data,
4351 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4352 userp, tidPathp, &req, &dscp);
4355 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4356 if ( WANTS_DFS_PATHNAMES(inp) )
4357 return CM_ERROR_PATH_NOT_COVERED;
4359 return CM_ERROR_BADSHARENAME;
4361 #endif /* DFS_SUPPORT */
4362 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4363 code = CM_ERROR_NOSUCHFILE;
4364 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4365 cm_buf_t *bp = buf_Find(dscp, &hzero);
4369 code = CM_ERROR_NOSUCHFILE;
4371 cm_ReleaseSCache(dscp);
4373 cm_ReleaseUser(userp);
4378 #endif /* SPECIAL_FOLDERS */
4380 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4381 tidPathp, &req, &newScp);
4383 cm_ReleaseUser(userp);
4388 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4389 cm_ReleaseSCache(newScp);
4390 cm_ReleaseUser(userp);
4391 if ( WANTS_DFS_PATHNAMES(inp) )
4392 return CM_ERROR_PATH_NOT_COVERED;
4394 return CM_ERROR_BADSHARENAME;
4396 #endif /* DFS_SUPPORT */
4398 /* now lock the vnode with a callback; returns with newScp locked */
4399 lock_ObtainMutex(&newScp->mx);
4400 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4401 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4403 lock_ReleaseMutex(&newScp->mx);
4404 cm_ReleaseSCache(newScp);
4405 cm_ReleaseUser(userp);
4410 /* use smb_Attributes instead. Also the fact that a file is
4411 * in a readonly volume doesn't mean it shojuld be marked as RO
4413 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4414 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4415 attrs = SMB_ATTR_DIRECTORY;
4418 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4419 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4421 attrs = smb_Attributes(newScp);
4424 smb_SetSMBParm(outp, 0, attrs);
4426 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4427 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4428 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4429 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4430 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4431 smb_SetSMBParm(outp, 5, 0);
4432 smb_SetSMBParm(outp, 6, 0);
4433 smb_SetSMBParm(outp, 7, 0);
4434 smb_SetSMBParm(outp, 8, 0);
4435 smb_SetSMBParm(outp, 9, 0);
4436 smb_SetSMBDataLength(outp, 0);
4437 lock_ReleaseMutex(&newScp->mx);
4439 cm_ReleaseSCache(newScp);
4440 cm_ReleaseUser(userp);
4445 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4449 osi_Log0(smb_logp, "SMB receive tree disconnect");
4451 /* find the tree and free it */
4452 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4454 lock_ObtainMutex(&tidp->mx);
4455 tidp->flags |= SMB_TIDFLAG_DELETE;
4456 lock_ReleaseMutex(&tidp->mx);
4457 smb_ReleaseTID(tidp);
4463 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4481 pathp = smb_GetSMBData(inp, NULL);
4482 pathp = smb_ParseASCIIBlock(pathp, NULL);
4483 if (smb_StoreAnsiFilenames)
4484 OemToChar(pathp,pathp);
4486 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4488 #ifdef DEBUG_VERBOSE
4492 hexpath = osi_HexifyString( pathp );
4493 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4498 share = smb_GetSMBParm(inp, 0);
4499 attribute = smb_GetSMBParm(inp, 1);
4501 spacep = inp->spacep;
4502 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4503 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4504 /* special case magic file name for receiving IOCTL requests
4505 * (since IOCTL calls themselves aren't getting through).
4507 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4508 smb_SetupIoctlFid(fidp, spacep);
4509 smb_SetSMBParm(outp, 0, fidp->fid);
4510 smb_SetSMBParm(outp, 1, 0); /* attrs */
4511 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4512 smb_SetSMBParm(outp, 3, 0);
4513 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4514 smb_SetSMBParm(outp, 5, 0x7fff);
4515 /* pass the open mode back */
4516 smb_SetSMBParm(outp, 6, (share & 0xf));
4517 smb_SetSMBDataLength(outp, 0);
4518 smb_ReleaseFID(fidp);
4522 userp = smb_GetUser(vcp, inp);
4524 caseFold = CM_FLAG_CASEFOLD;
4526 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4528 cm_ReleaseUser(userp);
4529 return CM_ERROR_NOSUCHPATH;
4531 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4532 tidPathp, &req, &scp);
4535 cm_ReleaseUser(userp);
4540 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4541 cm_ReleaseSCache(scp);
4542 cm_ReleaseUser(userp);
4543 if ( WANTS_DFS_PATHNAMES(inp) )
4544 return CM_ERROR_PATH_NOT_COVERED;
4546 return CM_ERROR_BADSHARENAME;
4548 #endif /* DFS_SUPPORT */
4550 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4552 cm_ReleaseSCache(scp);
4553 cm_ReleaseUser(userp);
4557 /* don't need callback to check file type, since file types never
4558 * change, and namei and cm_Lookup all stat the object at least once on
4559 * a successful return.
4561 if (scp->fileType != CM_SCACHETYPE_FILE) {
4562 cm_ReleaseSCache(scp);
4563 cm_ReleaseUser(userp);
4564 return CM_ERROR_ISDIR;
4567 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4570 /* save a pointer to the vnode */
4573 if ((share & 0xf) == 0)
4574 fidp->flags |= SMB_FID_OPENREAD;
4575 else if ((share & 0xf) == 1)
4576 fidp->flags |= SMB_FID_OPENWRITE;
4578 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4580 lock_ObtainMutex(&scp->mx);
4581 smb_SetSMBParm(outp, 0, fidp->fid);
4582 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4583 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4584 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4585 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4586 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4587 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4588 /* pass the open mode back; XXXX add access checks */
4589 smb_SetSMBParm(outp, 6, (share & 0xf));
4590 smb_SetSMBDataLength(outp, 0);
4591 lock_ReleaseMutex(&scp->mx);
4594 cm_Open(scp, 0, userp);
4596 /* send and free packet */
4597 smb_ReleaseFID(fidp);
4598 cm_ReleaseUser(userp);
4599 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4603 typedef struct smb_unlinkRock {
4608 char *maskp; /* pointer to the star pattern */
4613 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4616 smb_unlinkRock_t *rockp;
4624 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4625 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4626 caseFold |= CM_FLAG_8DOT3;
4628 matchName = dep->name;
4629 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4631 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4632 !cm_Is8Dot3(dep->name)) {
4633 cm_Gen8Dot3Name(dep, shortName, NULL);
4634 matchName = shortName;
4635 /* 8.3 matches are always case insensitive */
4636 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4639 osi_Log1(smb_logp, "Unlinking %s",
4640 osi_LogSaveString(smb_logp, matchName));
4641 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4642 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4643 smb_NotifyChange(FILE_ACTION_REMOVED,
4644 FILE_NOTIFY_CHANGE_FILE_NAME,
4645 dscp, dep->name, NULL, TRUE);
4649 /* If we made a case sensitive exact match, we might as well quit now. */
4650 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4651 code = CM_ERROR_STOPNOW;
4659 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4668 smb_unlinkRock_t rock;
4677 attribute = smb_GetSMBParm(inp, 0);
4679 tp = smb_GetSMBData(inp, NULL);
4680 pathp = smb_ParseASCIIBlock(tp, &tp);
4681 if (smb_StoreAnsiFilenames)
4682 OemToChar(pathp,pathp);
4684 osi_Log1(smb_logp, "SMB receive unlink %s",
4685 osi_LogSaveString(smb_logp, pathp));
4687 spacep = inp->spacep;
4688 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4690 userp = smb_GetUser(vcp, inp);
4692 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4694 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4696 cm_ReleaseUser(userp);
4697 return CM_ERROR_NOSUCHPATH;
4699 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4702 cm_ReleaseUser(userp);
4707 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4708 cm_ReleaseSCache(dscp);
4709 cm_ReleaseUser(userp);
4710 if ( WANTS_DFS_PATHNAMES(inp) )
4711 return CM_ERROR_PATH_NOT_COVERED;
4713 return CM_ERROR_BADSHARENAME;
4715 #endif /* DFS_SUPPORT */
4717 /* otherwise, scp points to the parent directory. */
4724 rock.maskp = smb_FindMask(pathp);
4725 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4728 thyper.HighPart = 0;
4734 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4735 * match. If that fails, we do a case insensitve match.
4737 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4738 !smb_IsStarMask(rock.maskp)) {
4739 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4742 thyper.HighPart = 0;
4743 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4748 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4750 if (code == CM_ERROR_STOPNOW)
4753 cm_ReleaseUser(userp);
4755 cm_ReleaseSCache(dscp);
4757 if (code == 0 && !rock.any)
4758 code = CM_ERROR_NOSUCHFILE;
4762 typedef struct smb_renameRock {
4763 cm_scache_t *odscp; /* old dir */
4764 cm_scache_t *ndscp; /* new dir */
4765 cm_user_t *userp; /* user */
4766 cm_req_t *reqp; /* request struct */
4767 smb_vc_t *vcp; /* virtual circuit */
4768 char *maskp; /* pointer to star pattern of old file name */
4769 int flags; /* tilde, casefold, etc */
4770 char *newNamep; /* ptr to the new file's name */
4773 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4776 smb_renameRock_t *rockp;
4781 rockp = (smb_renameRock_t *) vrockp;
4783 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4784 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4785 caseFold |= CM_FLAG_8DOT3;
4787 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4789 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4790 !cm_Is8Dot3(dep->name)) {
4791 cm_Gen8Dot3Name(dep, shortName, NULL);
4792 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4795 code = cm_Rename(rockp->odscp, dep->name,
4796 rockp->ndscp, rockp->newNamep, rockp->userp,
4798 /* if the call worked, stop doing the search now, since we
4799 * really only want to rename one file.
4802 code = CM_ERROR_STOPNOW;
4811 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4814 cm_space_t *spacep = NULL;
4815 smb_renameRock_t rock;
4816 cm_scache_t *oldDscp = NULL;
4817 cm_scache_t *newDscp = NULL;
4818 cm_scache_t *tmpscp= NULL;
4819 cm_scache_t *tmpscp2 = NULL;
4829 userp = smb_GetUser(vcp, inp);
4830 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4832 cm_ReleaseUser(userp);
4833 return CM_ERROR_NOSUCHPATH;
4837 spacep = inp->spacep;
4838 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4840 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4841 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4842 userp, tidPathp, &req, &oldDscp);
4844 cm_ReleaseUser(userp);
4849 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4850 cm_ReleaseSCache(oldDscp);
4851 cm_ReleaseUser(userp);
4852 if ( WANTS_DFS_PATHNAMES(inp) )
4853 return CM_ERROR_PATH_NOT_COVERED;
4855 return CM_ERROR_BADSHARENAME;
4857 #endif /* DFS_SUPPORT */
4859 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4860 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4861 userp, tidPathp, &req, &newDscp);
4864 cm_ReleaseSCache(oldDscp);
4865 cm_ReleaseUser(userp);
4870 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4871 cm_ReleaseSCache(oldDscp);
4872 cm_ReleaseSCache(newDscp);
4873 cm_ReleaseUser(userp);
4874 if ( WANTS_DFS_PATHNAMES(inp) )
4875 return CM_ERROR_PATH_NOT_COVERED;
4877 return CM_ERROR_BADSHARENAME;
4879 #endif /* DFS_SUPPORT */
4882 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4883 * next, get the component names, and lower case them.
4886 /* handle the old name first */
4888 oldLastNamep = oldPathp;
4892 /* and handle the new name, too */
4894 newLastNamep = newPathp;
4898 /* TODO: The old name could be a wildcard. The new name must not be */
4900 /* do the vnode call */
4901 rock.odscp = oldDscp;
4902 rock.ndscp = newDscp;
4906 rock.maskp = oldLastNamep;
4907 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4908 rock.newNamep = newLastNamep;
4910 /* Check if the file already exists; if so return error */
4911 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4912 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4913 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4914 osi_LogSaveString(afsd_logp, newLastNamep));
4916 /* Check if the old and the new names differ only in case. If so return
4917 * success, else return CM_ERROR_EXISTS
4919 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4921 /* This would be a success only if the old file is *as same as* the new file */
4922 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4924 if (tmpscp == tmpscp2)
4927 code = CM_ERROR_EXISTS;
4928 cm_ReleaseSCache(tmpscp2);
4931 code = CM_ERROR_NOSUCHFILE;
4934 /* file exist, do not rename, also fixes move */
4935 osi_Log0(smb_logp, "Can't rename. Target already exists");
4936 code = CM_ERROR_EXISTS;
4940 cm_ReleaseSCache(tmpscp);
4941 cm_ReleaseSCache(newDscp);
4942 cm_ReleaseSCache(oldDscp);
4943 cm_ReleaseUser(userp);
4947 /* Now search the directory for the pattern, and do the appropriate rename when found */
4948 thyper.LowPart = 0; /* search dir from here */
4949 thyper.HighPart = 0;
4951 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4952 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
4954 if (code == CM_ERROR_STOPNOW)
4957 code = CM_ERROR_NOSUCHFILE;
4959 /* Handle Change Notification */
4961 * Being lazy, not distinguishing between files and dirs in this
4962 * filter, since we'd have to do a lookup.
4964 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4965 if (oldDscp == newDscp) {
4966 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4967 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4968 filter, oldDscp, oldLastNamep,
4969 newLastNamep, TRUE);
4971 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4972 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4973 filter, oldDscp, oldLastNamep,
4975 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4976 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4977 filter, newDscp, newLastNamep,
4982 cm_ReleaseSCache(tmpscp);
4983 cm_ReleaseUser(userp);
4984 cm_ReleaseSCache(oldDscp);
4985 cm_ReleaseSCache(newDscp);
4990 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4993 cm_space_t *spacep = NULL;
4994 cm_scache_t *oldDscp = NULL;
4995 cm_scache_t *newDscp = NULL;
4996 cm_scache_t *tmpscp= NULL;
4997 cm_scache_t *tmpscp2 = NULL;
4998 cm_scache_t *sscp = NULL;
5007 userp = smb_GetUser(vcp, inp);
5009 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5011 cm_ReleaseUser(userp);
5012 return CM_ERROR_NOSUCHPATH;
5017 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5019 spacep = inp->spacep;
5020 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5022 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5023 userp, tidPathp, &req, &oldDscp);
5025 cm_ReleaseUser(userp);
5030 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5031 cm_ReleaseSCache(oldDscp);
5032 cm_ReleaseUser(userp);
5033 if ( WANTS_DFS_PATHNAMES(inp) )
5034 return CM_ERROR_PATH_NOT_COVERED;
5036 return CM_ERROR_BADSHARENAME;
5038 #endif /* DFS_SUPPORT */
5040 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5041 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5042 userp, tidPathp, &req, &newDscp);
5044 cm_ReleaseSCache(oldDscp);
5045 cm_ReleaseUser(userp);
5050 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5051 cm_ReleaseSCache(newDscp);
5052 cm_ReleaseSCache(oldDscp);
5053 cm_ReleaseUser(userp);
5054 if ( WANTS_DFS_PATHNAMES(inp) )
5055 return CM_ERROR_PATH_NOT_COVERED;
5057 return CM_ERROR_BADSHARENAME;
5059 #endif /* DFS_SUPPORT */
5061 /* Now, although we did two lookups for the two directories (because the same
5062 * directory can be referenced through different paths), we only allow hard links
5063 * within the same directory. */
5064 if (oldDscp != newDscp) {
5065 cm_ReleaseSCache(oldDscp);
5066 cm_ReleaseSCache(newDscp);
5067 cm_ReleaseUser(userp);
5068 return CM_ERROR_CROSSDEVLINK;
5071 /* handle the old name first */
5073 oldLastNamep = oldPathp;
5077 /* and handle the new name, too */
5079 newLastNamep = newPathp;
5083 /* now lookup the old name */
5084 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5085 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5087 cm_ReleaseSCache(oldDscp);
5088 cm_ReleaseSCache(newDscp);
5089 cm_ReleaseUser(userp);
5093 /* Check if the file already exists; if so return error */
5094 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5095 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5096 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5097 osi_LogSaveString(afsd_logp, newLastNamep));
5099 /* if the existing link is to the same file, then we return success */
5101 if(sscp == tmpscp) {
5104 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5105 code = CM_ERROR_EXISTS;
5110 cm_ReleaseSCache(tmpscp);
5111 cm_ReleaseSCache(sscp);
5112 cm_ReleaseSCache(newDscp);
5113 cm_ReleaseSCache(oldDscp);
5114 cm_ReleaseUser(userp);
5118 /* now create the hardlink */
5119 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5120 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5121 osi_Log1(smb_logp," Link returns %d", code);
5123 /* Handle Change Notification */
5125 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5126 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5127 smb_NotifyChange(FILE_ACTION_ADDED,
5128 filter, newDscp, newLastNamep,
5133 cm_ReleaseSCache(tmpscp);
5134 cm_ReleaseUser(userp);
5135 cm_ReleaseSCache(sscp);
5136 cm_ReleaseSCache(oldDscp);
5137 cm_ReleaseSCache(newDscp);
5142 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5148 tp = smb_GetSMBData(inp, NULL);
5149 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5150 if (smb_StoreAnsiFilenames)
5151 OemToChar(oldPathp,oldPathp);
5152 newPathp = smb_ParseASCIIBlock(tp, &tp);
5153 if (smb_StoreAnsiFilenames)
5154 OemToChar(newPathp,newPathp);
5156 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5157 osi_LogSaveString(smb_logp, oldPathp),
5158 osi_LogSaveString(smb_logp, newPathp));
5160 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5165 typedef struct smb_rmdirRock {
5169 char *maskp; /* pointer to the star pattern */
5174 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5177 smb_rmdirRock_t *rockp;
5182 rockp = (smb_rmdirRock_t *) vrockp;
5184 matchName = dep->name;
5185 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5186 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5188 match = (strcmp(matchName, rockp->maskp) == 0);
5190 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5191 !cm_Is8Dot3(dep->name)) {
5192 cm_Gen8Dot3Name(dep, shortName, NULL);
5193 matchName = shortName;
5194 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5197 osi_Log1(smb_logp, "Removing directory %s",
5198 osi_LogSaveString(smb_logp, matchName));
5199 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5200 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5201 smb_NotifyChange(FILE_ACTION_REMOVED,
5202 FILE_NOTIFY_CHANGE_DIR_NAME,
5203 dscp, dep->name, NULL, TRUE);
5212 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5220 smb_rmdirRock_t rock;
5229 tp = smb_GetSMBData(inp, NULL);
5230 pathp = smb_ParseASCIIBlock(tp, &tp);
5231 if (smb_StoreAnsiFilenames)
5232 OemToChar(pathp,pathp);
5234 spacep = inp->spacep;
5235 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5237 userp = smb_GetUser(vcp, inp);
5239 caseFold = CM_FLAG_CASEFOLD;
5241 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5243 cm_ReleaseUser(userp);
5244 return CM_ERROR_NOSUCHPATH;
5246 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5247 userp, tidPathp, &req, &dscp);
5250 cm_ReleaseUser(userp);
5255 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5256 cm_ReleaseSCache(dscp);
5257 cm_ReleaseUser(userp);
5258 if ( WANTS_DFS_PATHNAMES(inp) )
5259 return CM_ERROR_PATH_NOT_COVERED;
5261 return CM_ERROR_BADSHARENAME;
5263 #endif /* DFS_SUPPORT */
5265 /* otherwise, scp points to the parent directory. */
5272 rock.maskp = lastNamep;
5273 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5276 thyper.HighPart = 0;
5280 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5281 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5282 if (code == 0 && !rock.any) {
5284 thyper.HighPart = 0;
5285 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5286 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5289 cm_ReleaseUser(userp);
5291 cm_ReleaseSCache(dscp);
5293 if (code == 0 && !rock.any)
5294 code = CM_ERROR_NOSUCHFILE;
5298 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5308 fid = smb_GetSMBParm(inp, 0);
5310 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5312 fid = smb_ChainFID(fid, inp);
5313 fidp = smb_FindFID(vcp, fid, 0);
5314 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5316 smb_ReleaseFID(fidp);
5317 return CM_ERROR_BADFD;
5320 userp = smb_GetUser(vcp, inp);
5322 lock_ObtainMutex(&fidp->mx);
5323 if (fidp->flags & SMB_FID_OPENWRITE)
5324 code = cm_FSync(fidp->scp, userp, &req);
5327 lock_ReleaseMutex(&fidp->mx);
5329 smb_ReleaseFID(fidp);
5331 cm_ReleaseUser(userp);
5336 struct smb_FullNameRock {
5342 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5346 struct smb_FullNameRock *vrockp;
5348 vrockp = (struct smb_FullNameRock *)rockp;
5350 if (!cm_Is8Dot3(dep->name)) {
5351 cm_Gen8Dot3Name(dep, shortName, NULL);
5353 if (cm_stricmp(shortName, vrockp->name) == 0) {
5354 vrockp->fullName = strdup(dep->name);
5355 return CM_ERROR_STOPNOW;
5358 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5359 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5360 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5361 vrockp->fullName = strdup(dep->name);
5362 return CM_ERROR_STOPNOW;
5367 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5368 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5370 struct smb_FullNameRock rock;
5376 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5377 if (code == CM_ERROR_STOPNOW)
5378 *newPathp = rock.fullName;
5380 *newPathp = strdup(pathp);
5383 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5394 fid = smb_GetSMBParm(inp, 0);
5395 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5397 osi_Log1(smb_logp, "SMB close fid %d", fid);
5399 fid = smb_ChainFID(fid, inp);
5400 fidp = smb_FindFID(vcp, fid, 0);
5402 return CM_ERROR_BADFD;
5405 userp = smb_GetUser(vcp, inp);
5407 lock_ObtainMutex(&fidp->mx);
5409 /* Don't jump the gun on an async raw write */
5410 while (fidp->raw_writers) {
5411 lock_ReleaseMutex(&fidp->mx);
5412 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5413 lock_ObtainMutex(&fidp->mx);
5416 fidp->flags |= SMB_FID_DELETE;
5418 /* watch for ioctl closes, and read-only opens */
5419 if (fidp->scp != NULL &&
5420 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5421 == SMB_FID_OPENWRITE) {
5422 if (dosTime != 0 && dosTime != -1) {
5423 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5424 /* This fixes defect 10958 */
5425 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5426 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5428 code = cm_FSync(fidp->scp, userp, &req);
5433 /* unlock any pending locks */
5434 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5435 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5441 pid = ((smb_t *) inp)->pid;
5442 key = cm_GenerateKey(vcp->vcID, pid, fid);
5445 lock_ObtainMutex(&scp->mx);
5447 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5448 CM_SCACHESYNC_NEEDCALLBACK
5449 | CM_SCACHESYNC_GETSTATUS
5450 | CM_SCACHESYNC_LOCK);
5453 osi_Log1(smb_logp, "smb CoreClose SyncOp failure code 0x%x", tcode);
5454 goto post_syncopdone;
5457 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5459 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5463 lock_ReleaseMutex(&scp->mx);
5464 cm_ReleaseSCache(scp);
5467 if (fidp->flags & SMB_FID_DELONCLOSE) {
5468 cm_scache_t *dscp = fidp->NTopen_dscp;
5469 char *pathp = fidp->NTopen_pathp;
5472 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5473 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5474 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5475 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5476 smb_NotifyChange(FILE_ACTION_REMOVED,
5477 FILE_NOTIFY_CHANGE_DIR_NAME,
5478 dscp, fullPathp, NULL, TRUE);
5482 code = cm_Unlink(dscp, fullPathp, userp, &req);
5483 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5484 smb_NotifyChange(FILE_ACTION_REMOVED,
5485 FILE_NOTIFY_CHANGE_FILE_NAME,
5486 dscp, fullPathp, NULL, TRUE);
5490 lock_ReleaseMutex(&fidp->mx);
5492 if (fidp->flags & SMB_FID_NTOPEN) {
5493 cm_ReleaseSCache(fidp->NTopen_dscp);
5494 free(fidp->NTopen_pathp);
5496 if (fidp->NTopen_wholepathp)
5497 free(fidp->NTopen_wholepathp);
5499 smb_ReleaseFID(fidp);
5500 cm_ReleaseUser(userp);
5505 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5508 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5509 cm_user_t *userp, long *readp)
5511 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5512 cm_user_t *userp, long *readp, int dosflag)
5519 osi_hyper_t fileLength;
5521 osi_hyper_t lastByte;
5522 osi_hyper_t bufferOffset;
5523 long bufIndex, nbytes;
5533 lock_ObtainMutex(&fidp->mx);
5535 lock_ObtainMutex(&scp->mx);
5537 if (offset.HighPart == 0) {
5538 chunk = offset.LowPart >> cm_logChunkSize;
5539 if (chunk != fidp->curr_chunk) {
5540 fidp->prev_chunk = fidp->curr_chunk;
5541 fidp->curr_chunk = chunk;
5543 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5547 /* start by looking up the file's end */
5548 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5549 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5550 if (code) goto done;
5552 /* now we have the entry locked, look up the length */
5553 fileLength = scp->length;
5555 /* adjust count down so that it won't go past EOF */
5556 thyper.LowPart = count;
5557 thyper.HighPart = 0;
5558 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5560 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5561 /* we'd read past EOF, so just stop at fileLength bytes.
5562 * Start by computing how many bytes remain in the file.
5564 thyper = LargeIntegerSubtract(fileLength, offset);
5566 /* if we are past EOF, read 0 bytes */
5567 if (LargeIntegerLessThanZero(thyper))
5570 count = thyper.LowPart;
5575 /* now, copy the data one buffer at a time,
5576 * until we've filled the request packet
5579 /* if we've copied all the data requested, we're done */
5580 if (count <= 0) break;
5582 /* otherwise, load up a buffer of data */
5583 thyper.HighPart = offset.HighPart;
5584 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5585 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5588 buf_Release(bufferp);
5591 lock_ReleaseMutex(&scp->mx);
5593 lock_ObtainRead(&scp->bufCreateLock);
5594 code = buf_Get(scp, &thyper, &bufferp);
5595 lock_ReleaseRead(&scp->bufCreateLock);
5597 lock_ObtainMutex(&scp->mx);
5598 if (code) goto done;
5599 bufferOffset = thyper;
5601 /* now get the data in the cache */
5603 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5604 CM_SCACHESYNC_NEEDCALLBACK |
5605 CM_SCACHESYNC_READ);
5606 if (code) goto done;
5608 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5610 /* otherwise, load the buffer and try again */
5611 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5615 buf_Release(bufferp);
5619 } /* if (wrong buffer) ... */
5621 /* now we have the right buffer loaded. Copy out the
5622 * data from here to the user's buffer.
5624 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5626 /* and figure out how many bytes we want from this buffer */
5627 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5628 if (nbytes > count) nbytes = count; /* don't go past EOF */
5630 /* now copy the data */
5633 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5636 memcpy(op, bufferp->datap + bufIndex, nbytes);
5638 /* adjust counters, pointers, etc. */
5641 thyper.LowPart = nbytes;
5642 thyper.HighPart = 0;
5643 offset = LargeIntegerAdd(thyper, offset);
5647 lock_ReleaseMutex(&scp->mx);
5648 lock_ReleaseMutex(&fidp->mx);
5650 buf_Release(bufferp);
5652 if (code == 0 && sequential)
5653 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5659 * smb_WriteData -- common code for Write and Raw Write
5662 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5663 cm_user_t *userp, long *writtenp)
5665 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5666 cm_user_t *userp, long *writtenp, int dosflag)
5673 osi_hyper_t fileLength; /* file's length at start of write */
5674 osi_hyper_t minLength; /* don't read past this */
5675 long nbytes; /* # of bytes to transfer this iteration */
5677 osi_hyper_t thyper; /* hyper tmp variable */
5678 osi_hyper_t bufferOffset;
5679 long bufIndex; /* index in buffer where our data is */
5681 osi_hyper_t writeBackOffset;/* offset of region to write back when
5686 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5687 fidp->fid, offsetp->LowPart, count);
5697 lock_ObtainMutex(&fidp->mx);
5699 lock_ObtainMutex(&scp->mx);
5701 /* start by looking up the file's end */
5702 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5703 CM_SCACHESYNC_NEEDCALLBACK
5704 | CM_SCACHESYNC_SETSTATUS
5705 | CM_SCACHESYNC_GETSTATUS);
5709 /* make sure we have a writable FD */
5710 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5711 code = CM_ERROR_BADFDOP;
5715 /* now we have the entry locked, look up the length */
5716 fileLength = scp->length;
5717 minLength = fileLength;
5718 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5719 minLength = scp->serverLength;
5721 /* adjust file length if we extend past EOF */
5722 thyper.LowPart = count;
5723 thyper.HighPart = 0;
5724 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5725 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5726 /* we'd write past EOF, so extend the file */
5727 scp->mask |= CM_SCACHEMASK_LENGTH;
5728 scp->length = thyper;
5729 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5731 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5733 /* now, if the new position (thyper) and the old (offset) are in
5734 * different storeback windows, remember to store back the previous
5735 * storeback window when we're done with the write.
5737 if ((thyper.LowPart & (-cm_chunkSize)) !=
5738 (offset.LowPart & (-cm_chunkSize))) {
5739 /* they're different */
5741 writeBackOffset.HighPart = offset.HighPart;
5742 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5747 /* now, copy the data one buffer at a time, until we've filled the
5750 /* if we've copied all the data requested, we're done */
5754 /* handle over quota or out of space */
5755 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5756 *writtenp = written;
5757 code = CM_ERROR_QUOTA;
5761 /* otherwise, load up a buffer of data */
5762 thyper.HighPart = offset.HighPart;
5763 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5764 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5767 lock_ReleaseMutex(&bufferp->mx);
5768 buf_Release(bufferp);
5771 lock_ReleaseMutex(&scp->mx);
5773 lock_ObtainRead(&scp->bufCreateLock);
5774 code = buf_Get(scp, &thyper, &bufferp);
5775 lock_ReleaseRead(&scp->bufCreateLock);
5777 lock_ObtainMutex(&bufferp->mx);
5778 lock_ObtainMutex(&scp->mx);
5779 if (code) goto done;
5781 bufferOffset = thyper;
5783 /* now get the data in the cache */
5785 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5786 CM_SCACHESYNC_NEEDCALLBACK
5787 | CM_SCACHESYNC_WRITE
5788 | CM_SCACHESYNC_BUFLOCKED);
5792 /* If we're overwriting the entire buffer, or
5793 * if we're writing at or past EOF, mark the
5794 * buffer as current so we don't call
5795 * cm_GetBuffer. This skips the fetch from the
5796 * server in those cases where we're going to
5797 * obliterate all the data in the buffer anyway,
5798 * or in those cases where there is no useful
5799 * data at the server to start with.
5801 * Use minLength instead of scp->length, since
5802 * the latter has already been updated by this
5805 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5806 || LargeIntegerEqualTo(offset, bufferp->offset)
5807 && (count >= cm_data.buf_blockSize
5808 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5809 ConvertLongToLargeInteger(count)),
5811 if (count < cm_data.buf_blockSize
5812 && bufferp->dataVersion == -1)
5813 memset(bufferp->datap, 0,
5814 cm_data.buf_blockSize);
5815 bufferp->dataVersion = scp->dataVersion;
5818 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5820 /* otherwise, load the buffer and try again */
5821 lock_ReleaseMutex(&bufferp->mx);
5822 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5824 lock_ReleaseMutex(&scp->mx);
5825 lock_ObtainMutex(&bufferp->mx);
5826 lock_ObtainMutex(&scp->mx);
5830 lock_ReleaseMutex(&bufferp->mx);
5831 buf_Release(bufferp);
5835 } /* if (wrong buffer) ... */
5837 /* now we have the right buffer loaded. Copy out the
5838 * data from here to the user's buffer.
5840 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5842 /* and figure out how many bytes we want from this buffer */
5843 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5845 nbytes = count; /* don't go past end of request */
5847 /* now copy the data */
5850 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5853 memcpy(bufferp->datap + bufIndex, op, nbytes);
5854 buf_SetDirty(bufferp);
5856 /* and record the last writer */
5857 if (bufferp->userp != userp) {
5860 cm_ReleaseUser(bufferp->userp);
5861 bufferp->userp = userp;
5864 /* adjust counters, pointers, etc. */
5868 thyper.LowPart = nbytes;
5869 thyper.HighPart = 0;
5870 offset = LargeIntegerAdd(thyper, offset);
5874 lock_ReleaseMutex(&scp->mx);
5875 lock_ReleaseMutex(&fidp->mx);
5877 lock_ReleaseMutex(&bufferp->mx);
5878 buf_Release(bufferp);
5881 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5882 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5883 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5884 fidp->NTopen_dscp, fidp->NTopen_pathp,
5888 if (code == 0 && doWriteBack) {
5890 lock_ObtainMutex(&scp->mx);
5891 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5893 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5894 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5896 lock_ReleaseMutex(&scp->mx);
5897 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5898 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5901 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5902 fidp->fid, code, *writtenp);
5906 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5909 long count, written = 0, total_written = 0;
5915 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5917 int inDataBlockCount;
5919 fd = smb_GetSMBParm(inp, 0);
5920 count = smb_GetSMBParm(inp, 1);
5921 offset.HighPart = 0; /* too bad */
5922 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5924 op = smb_GetSMBData(inp, NULL);
5925 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5927 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5928 fd, offset.LowPart, count);
5930 fd = smb_ChainFID(fd, inp);
5931 fidp = smb_FindFID(vcp, fd, 0);
5933 return CM_ERROR_BADFD;
5936 if (fidp->flags & SMB_FID_IOCTL)
5937 return smb_IoctlWrite(fidp, vcp, inp, outp);
5939 userp = smb_GetUser(vcp, inp);
5941 /* special case: 0 bytes transferred means truncate to this position */
5947 truncAttr.mask = CM_ATTRMASK_LENGTH;
5948 truncAttr.length.LowPart = offset.LowPart;
5949 truncAttr.length.HighPart = 0;
5950 lock_ObtainMutex(&fidp->mx);
5951 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5952 lock_ReleaseMutex(&fidp->mx);
5953 smb_SetSMBParm(outp, 0, /* count */ 0);
5954 smb_SetSMBDataLength(outp, 0);
5955 fidp->flags |= SMB_FID_LENGTHSETDONE;
5961 LARGE_INTEGER LOffset;
5962 LARGE_INTEGER LLength;
5964 pid = ((smb_t *) inp)->pid;
5965 key = cm_GenerateKey(vcp->vcID, pid, fd);
5967 LOffset.HighPart = offset.HighPart;
5968 LOffset.LowPart = offset.LowPart;
5969 LLength.HighPart = 0;
5970 LLength.LowPart = count;
5972 lock_ObtainMutex(&fidp->scp->mx);
5973 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5974 lock_ReleaseMutex(&fidp->scp->mx);
5981 * Work around bug in NT client
5983 * When copying a file, the NT client should first copy the data,
5984 * then copy the last write time. But sometimes the NT client does
5985 * these in the wrong order, so the data copies would inadvertently
5986 * cause the last write time to be overwritten. We try to detect this,
5987 * and don't set client mod time if we think that would go against the
5990 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5991 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5992 fidp->scp->clientModTime = time(NULL);
5996 while ( code == 0 && count > 0 ) {
5998 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6000 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6002 if (code == 0 && written == 0)
6003 code = CM_ERROR_PARTIALWRITE;
6005 offset.LowPart += written;
6007 total_written += written;
6011 /* set the packet data length to 3 bytes for the data block header,
6012 * plus the size of the data.
6014 smb_SetSMBParm(outp, 0, total_written);
6015 smb_SetSMBDataLength(outp, 0);
6018 smb_ReleaseFID(fidp);
6019 cm_ReleaseUser(userp);
6024 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6025 NCB *ncbp, raw_write_cont_t *rwcp)
6038 fd = smb_GetSMBParm(inp, 0);
6039 fidp = smb_FindFID(vcp, fd, 0);
6041 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6042 rwcp->offset.LowPart, rwcp->count);
6044 userp = smb_GetUser(vcp, inp);
6048 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6051 rawBuf = (dos_ptr) rwcp->buf;
6052 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6053 (unsigned char *) rawBuf, userp,
6057 if (rwcp->writeMode & 0x1) { /* synchronous */
6060 smb_FormatResponsePacket(vcp, inp, outp);
6061 op = (smb_t *) outp;
6062 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6063 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6064 smb_SetSMBDataLength(outp, 0);
6065 smb_SendPacket(vcp, outp);
6066 smb_FreePacket(outp);
6068 else { /* asynchronous */
6069 lock_ObtainMutex(&fidp->mx);
6070 fidp->raw_writers--;
6071 if (fidp->raw_writers == 0)
6072 thrd_SetEvent(fidp->raw_write_event);
6073 lock_ReleaseMutex(&fidp->mx);
6076 /* Give back raw buffer */
6077 lock_ObtainMutex(&smb_RawBufLock);
6079 *((char **)rawBuf) = smb_RawBufs;
6081 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6083 smb_RawBufs = rawBuf;
6084 lock_ReleaseMutex(&smb_RawBufLock);
6086 smb_ReleaseFID(fidp);
6087 cm_ReleaseUser(userp);
6090 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6095 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6098 long count, written = 0, total_written = 0;
6105 unsigned short writeMode;
6112 fd = smb_GetSMBParm(inp, 0);
6113 totalCount = smb_GetSMBParm(inp, 1);
6114 count = smb_GetSMBParm(inp, 10);
6115 offset.HighPart = 0; /* too bad */
6116 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6117 writeMode = smb_GetSMBParm(inp, 7);
6119 op = (char *) inp->data;
6120 op += smb_GetSMBParm(inp, 11);
6123 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6124 fd, offset.LowPart, count, writeMode);
6126 fd = smb_ChainFID(fd, inp);
6127 fidp = smb_FindFID(vcp, fd, 0);
6129 return CM_ERROR_BADFD;
6135 LARGE_INTEGER LOffset;
6136 LARGE_INTEGER LLength;
6138 pid = ((smb_t *) inp)->pid;
6139 key = cm_GenerateKey(vcp->vcID, pid, fd);
6141 LOffset.HighPart = offset.HighPart;
6142 LOffset.LowPart = offset.LowPart;
6143 LLength.HighPart = 0;
6144 LLength.LowPart = count;
6146 lock_ObtainMutex(&fidp->scp->mx);
6147 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6148 lock_ReleaseMutex(&fidp->scp->mx);
6151 smb_ReleaseFID(fidp);
6156 userp = smb_GetUser(vcp, inp);
6159 * Work around bug in NT client
6161 * When copying a file, the NT client should first copy the data,
6162 * then copy the last write time. But sometimes the NT client does
6163 * these in the wrong order, so the data copies would inadvertently
6164 * cause the last write time to be overwritten. We try to detect this,
6165 * and don't set client mod time if we think that would go against the
6168 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6169 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6170 fidp->scp->clientModTime = time(NULL);
6174 while ( code == 0 && count > 0 ) {
6176 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6178 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6180 if (code == 0 && written == 0)
6181 code = CM_ERROR_PARTIALWRITE;
6183 offset.LowPart += written;
6185 total_written += written;
6189 /* Get a raw buffer */
6192 lock_ObtainMutex(&smb_RawBufLock);
6194 /* Get a raw buf, from head of list */
6195 rawBuf = smb_RawBufs;
6197 smb_RawBufs = *(char **)smb_RawBufs;
6199 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6203 code = CM_ERROR_USESTD;
6205 lock_ReleaseMutex(&smb_RawBufLock);
6208 /* Don't allow a premature Close */
6209 if (code == 0 && (writeMode & 1) == 0) {
6210 lock_ObtainMutex(&fidp->mx);
6211 fidp->raw_writers++;
6212 thrd_ResetEvent(fidp->raw_write_event);
6213 lock_ReleaseMutex(&fidp->mx);
6216 smb_ReleaseFID(fidp);
6217 cm_ReleaseUser(userp);
6220 smb_SetSMBParm(outp, 0, total_written);
6221 smb_SetSMBDataLength(outp, 0);
6222 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6229 rwcp->offset.HighPart = 0;
6230 rwcp->offset.LowPart = offset.LowPart + count;
6231 rwcp->count = totalCount - count;
6232 rwcp->writeMode = writeMode;
6233 rwcp->alreadyWritten = total_written;
6235 /* set the packet data length to 3 bytes for the data block header,
6236 * plus the size of the data.
6238 smb_SetSMBParm(outp, 0, 0xffff);
6239 smb_SetSMBDataLength(outp, 0);
6244 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6247 long count, finalCount;
6255 fd = smb_GetSMBParm(inp, 0);
6256 count = smb_GetSMBParm(inp, 1);
6257 offset.HighPart = 0; /* too bad */
6258 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6260 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6261 fd, offset.LowPart, count);
6263 fd = smb_ChainFID(fd, inp);
6264 fidp = smb_FindFID(vcp, fd, 0);
6266 return CM_ERROR_BADFD;
6269 if (fidp->flags & SMB_FID_IOCTL) {
6270 return smb_IoctlRead(fidp, vcp, inp, outp);
6274 LARGE_INTEGER LOffset, LLength;
6277 pid = ((smb_t *) inp)->pid;
6278 key = cm_GenerateKey(vcp->vcID, pid, fd);
6280 LOffset.HighPart = 0;
6281 LOffset.LowPart = offset.LowPart;
6282 LLength.HighPart = 0;
6283 LLength.LowPart = count;
6285 lock_ObtainMutex(&fidp->scp->mx);
6286 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6287 lock_ReleaseMutex(&fidp->scp->mx);
6290 smb_ReleaseFID(fidp);
6294 userp = smb_GetUser(vcp, inp);
6296 /* remember this for final results */
6297 smb_SetSMBParm(outp, 0, count);
6298 smb_SetSMBParm(outp, 1, 0);
6299 smb_SetSMBParm(outp, 2, 0);
6300 smb_SetSMBParm(outp, 3, 0);
6301 smb_SetSMBParm(outp, 4, 0);
6303 /* set the packet data length to 3 bytes for the data block header,
6304 * plus the size of the data.
6306 smb_SetSMBDataLength(outp, count+3);
6308 /* get op ptr after putting in the parms, since otherwise we don't
6309 * know where the data really is.
6311 op = smb_GetSMBData(outp, NULL);
6313 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6314 *op++ = 1; /* data block marker */
6315 *op++ = (unsigned char) (count & 0xff);
6316 *op++ = (unsigned char) ((count >> 8) & 0xff);
6319 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6321 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6324 /* fix some things up */
6325 smb_SetSMBParm(outp, 0, finalCount);
6326 smb_SetSMBDataLength(outp, finalCount+3);
6328 smb_ReleaseFID(fidp);
6330 cm_ReleaseUser(userp);
6334 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6341 cm_scache_t *dscp; /* dir we're dealing with */
6342 cm_scache_t *scp; /* file we're creating */
6344 int initialModeBits;
6354 /* compute initial mode bits based on read-only flag in attributes */
6355 initialModeBits = 0777;
6357 tp = smb_GetSMBData(inp, NULL);
6358 pathp = smb_ParseASCIIBlock(tp, &tp);
6359 if (smb_StoreAnsiFilenames)
6360 OemToChar(pathp,pathp);
6362 if (strcmp(pathp, "\\") == 0)
6363 return CM_ERROR_EXISTS;
6365 spacep = inp->spacep;
6366 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6368 userp = smb_GetUser(vcp, inp);
6370 caseFold = CM_FLAG_CASEFOLD;
6372 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6374 cm_ReleaseUser(userp);
6375 return CM_ERROR_NOSUCHPATH;
6378 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6379 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6380 userp, tidPathp, &req, &dscp);
6383 cm_ReleaseUser(userp);
6388 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6389 cm_ReleaseSCache(dscp);
6390 cm_ReleaseUser(userp);
6391 if ( WANTS_DFS_PATHNAMES(inp) )
6392 return CM_ERROR_PATH_NOT_COVERED;
6394 return CM_ERROR_BADSHARENAME;
6396 #endif /* DFS_SUPPORT */
6398 /* otherwise, scp points to the parent directory. Do a lookup, and
6399 * fail if we find it. Otherwise, we do the create.
6405 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6406 if (scp) cm_ReleaseSCache(scp);
6407 if (code != CM_ERROR_NOSUCHFILE) {
6408 if (code == 0) code = CM_ERROR_EXISTS;
6409 cm_ReleaseSCache(dscp);
6410 cm_ReleaseUser(userp);
6414 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6415 setAttr.clientModTime = time(NULL);
6416 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6417 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6418 smb_NotifyChange(FILE_ACTION_ADDED,
6419 FILE_NOTIFY_CHANGE_DIR_NAME,
6420 dscp, lastNamep, NULL, TRUE);
6422 /* we don't need this any longer */
6423 cm_ReleaseSCache(dscp);
6426 /* something went wrong creating or truncating the file */
6427 cm_ReleaseUser(userp);
6431 /* otherwise we succeeded */
6432 smb_SetSMBDataLength(outp, 0);
6433 cm_ReleaseUser(userp);
6438 BOOL smb_IsLegalFilename(char *filename)
6441 * Find the longest substring of filename that does not contain
6442 * any of the chars in illegalChars. If that substring is less
6443 * than the length of the whole string, then one or more of the
6444 * illegal chars is in filename.
6446 if (strcspn(filename, illegalChars) < strlen(filename))
6452 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6460 cm_scache_t *dscp; /* dir we're dealing with */
6461 cm_scache_t *scp; /* file we're creating */
6463 int initialModeBits;
6475 excl = (inp->inCom == 0x03)? 0 : 1;
6477 attributes = smb_GetSMBParm(inp, 0);
6478 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6480 /* compute initial mode bits based on read-only flag in attributes */
6481 initialModeBits = 0666;
6482 if (attributes & 1) initialModeBits &= ~0222;
6484 tp = smb_GetSMBData(inp, NULL);
6485 pathp = smb_ParseASCIIBlock(tp, &tp);
6486 if (smb_StoreAnsiFilenames)
6487 OemToChar(pathp,pathp);
6489 spacep = inp->spacep;
6490 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6492 userp = smb_GetUser(vcp, inp);
6494 caseFold = CM_FLAG_CASEFOLD;
6496 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6498 cm_ReleaseUser(userp);
6499 return CM_ERROR_NOSUCHPATH;
6501 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6502 userp, tidPathp, &req, &dscp);
6505 cm_ReleaseUser(userp);
6510 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6511 cm_ReleaseSCache(dscp);
6512 cm_ReleaseUser(userp);
6513 if ( WANTS_DFS_PATHNAMES(inp) )
6514 return CM_ERROR_PATH_NOT_COVERED;
6516 return CM_ERROR_BADSHARENAME;
6518 #endif /* DFS_SUPPORT */
6520 /* otherwise, scp points to the parent directory. Do a lookup, and
6521 * truncate the file if we find it, otherwise we create the file.
6528 if (!smb_IsLegalFilename(lastNamep))
6529 return CM_ERROR_BADNTFILENAME;
6531 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6532 #ifdef DEBUG_VERBOSE
6535 hexp = osi_HexifyString( lastNamep );
6536 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6541 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6542 if (code && code != CM_ERROR_NOSUCHFILE) {
6543 cm_ReleaseSCache(dscp);
6544 cm_ReleaseUser(userp);
6548 /* if we get here, if code is 0, the file exists and is represented by
6549 * scp. Otherwise, we have to create it.
6553 /* oops, file shouldn't be there */
6554 cm_ReleaseSCache(dscp);
6555 cm_ReleaseSCache(scp);
6556 cm_ReleaseUser(userp);
6557 return CM_ERROR_EXISTS;
6560 setAttr.mask = CM_ATTRMASK_LENGTH;
6561 setAttr.length.LowPart = 0;
6562 setAttr.length.HighPart = 0;
6563 code = cm_SetAttr(scp, &setAttr, userp, &req);
6566 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6567 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6568 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6570 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6571 smb_NotifyChange(FILE_ACTION_ADDED,
6572 FILE_NOTIFY_CHANGE_FILE_NAME,
6573 dscp, lastNamep, NULL, TRUE);
6574 if (!excl && code == CM_ERROR_EXISTS) {
6575 /* not an exclusive create, and someone else tried
6576 * creating it already, then we open it anyway. We
6577 * don't bother retrying after this, since if this next
6578 * fails, that means that the file was deleted after
6579 * we started this call.
6581 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6584 setAttr.mask = CM_ATTRMASK_LENGTH;
6585 setAttr.length.LowPart = 0;
6586 setAttr.length.HighPart = 0;
6587 code = cm_SetAttr(scp, &setAttr, userp, &req);
6592 /* we don't need this any longer */
6593 cm_ReleaseSCache(dscp);
6596 /* something went wrong creating or truncating the file */
6597 if (scp) cm_ReleaseSCache(scp);
6598 cm_ReleaseUser(userp);
6602 /* make sure we only open files */
6603 if (scp->fileType != CM_SCACHETYPE_FILE) {
6604 cm_ReleaseSCache(scp);
6605 cm_ReleaseUser(userp);
6606 return CM_ERROR_ISDIR;
6609 /* now all we have to do is open the file itself */
6610 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6613 /* save a pointer to the vnode */
6616 /* always create it open for read/write */
6617 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6619 smb_ReleaseFID(fidp);
6621 smb_SetSMBParm(outp, 0, fidp->fid);
6622 smb_SetSMBDataLength(outp, 0);
6624 cm_Open(scp, 0, userp);
6626 cm_ReleaseUser(userp);
6627 /* leave scp held since we put it in fidp->scp */
6631 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6644 fd = smb_GetSMBParm(inp, 0);
6645 whence = smb_GetSMBParm(inp, 1);
6646 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6648 /* try to find the file descriptor */
6649 fd = smb_ChainFID(fd, inp);
6650 fidp = smb_FindFID(vcp, fd, 0);
6651 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6652 return CM_ERROR_BADFD;
6655 userp = smb_GetUser(vcp, inp);
6657 lock_ObtainMutex(&fidp->mx);
6659 lock_ObtainMutex(&scp->mx);
6660 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6661 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6664 /* offset from current offset */
6665 offset += fidp->offset;
6667 else if (whence == 2) {
6668 /* offset from current EOF */
6669 offset += scp->length.LowPart;
6671 fidp->offset = offset;
6672 smb_SetSMBParm(outp, 0, offset & 0xffff);
6673 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6674 smb_SetSMBDataLength(outp, 0);
6676 lock_ReleaseMutex(&scp->mx);
6677 lock_ReleaseMutex(&fidp->mx);
6678 smb_ReleaseFID(fidp);
6679 cm_ReleaseUser(userp);
6683 /* dispatch all of the requests received in a packet. Due to chaining, this may
6684 * be more than one request.
6686 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6687 NCB *ncbp, raw_write_cont_t *rwcp)
6691 unsigned long code = 0;
6692 unsigned char *outWctp;
6693 int nparms; /* # of bytes of parameters */
6695 int nbytes; /* bytes of data, excluding count */
6698 unsigned short errCode;
6699 unsigned long NTStatus;
6701 unsigned char errClass;
6702 unsigned int oldGen;
6703 DWORD oldTime, newTime;
6705 /* get easy pointer to the data */
6706 smbp = (smb_t *) inp->data;
6708 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6709 /* setup the basic parms for the initial request in the packet */
6710 inp->inCom = smbp->com;
6711 inp->wctp = &smbp->wct;
6713 inp->ncb_length = ncbp->ncb_length;
6718 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6719 /* log it and discard it */
6721 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
6722 __FILE__, __LINE__, ncbp->ncb_length);
6724 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6728 /* We are an ongoing op */
6729 thrd_Increment(&ongoingOps);
6731 /* set up response packet for receiving output */
6732 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6733 smb_FormatResponsePacket(vcp, inp, outp);
6734 outWctp = outp->wctp;
6736 /* Remember session generation number and time */
6737 oldGen = sessionGen;
6738 oldTime = GetCurrentTime();
6740 while (inp->inCom != 0xff) {
6741 dp = &smb_dispatchTable[inp->inCom];
6743 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6744 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6745 code = outp->resumeCode;
6749 /* process each request in the packet; inCom, wctp and inCount
6750 * are already set up.
6752 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6755 /* now do the dispatch */
6756 /* start by formatting the response record a little, as a default */
6757 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6759 outWctp[1] = 0xff; /* no operation */
6760 outWctp[2] = 0; /* padding */
6765 /* not a chained request, this is a more reasonable default */
6766 outWctp[0] = 0; /* wct of zero */
6767 outWctp[1] = 0; /* and bcc (word) of zero */
6771 /* once set, stays set. Doesn't matter, since we never chain
6772 * "no response" calls.
6774 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6778 /* we have a recognized operation */
6780 if (inp->inCom == 0x1d)
6782 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6785 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6786 code = (*(dp->procp)) (vcp, inp, outp);
6787 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
6789 if ( code == CM_ERROR_BADSMB ||
6790 code == CM_ERROR_BADOP )
6792 #endif /* LOG_PACKET */
6795 if (oldGen != sessionGen) {
6796 newTime = GetCurrentTime();
6798 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
6799 newTime - oldTime, ncbp->ncb_length);
6801 osi_Log2(smb_logp, "Pkt straddled session startup, "
6802 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
6806 /* bad opcode, fail the request, after displaying it */
6807 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6810 #endif /* LOG_PACKET */
6814 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6815 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6816 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6817 if (code == IDCANCEL)
6821 code = CM_ERROR_BADOP;
6824 /* catastrophic failure: log as much as possible */
6825 if (code == CM_ERROR_BADSMB) {
6827 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
6832 #endif /* LOG_PACKET */
6833 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6836 code = CM_ERROR_INVAL;
6839 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6840 thrd_Decrement(&ongoingOps);
6845 /* now, if we failed, turn the current response into an empty
6846 * one, and fill in the response packet's error code.
6849 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6850 smb_MapNTError(code, &NTStatus);
6851 outWctp = outp->wctp;
6852 smbp = (smb_t *) &outp->data;
6853 if (code != CM_ERROR_PARTIALWRITE
6854 && code != CM_ERROR_BUFFERTOOSMALL
6855 && code != CM_ERROR_GSSCONTINUE) {
6856 /* nuke wct and bcc. For a partial
6857 * write or an in-process authentication handshake,
6858 * assume they're OK.
6864 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6865 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6866 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6867 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6868 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6872 smb_MapCoreError(code, vcp, &errCode, &errClass);
6873 outWctp = outp->wctp;
6874 smbp = (smb_t *) &outp->data;
6875 if (code != CM_ERROR_PARTIALWRITE) {
6876 /* nuke wct and bcc. For a partial
6877 * write, assume they're OK.
6883 smbp->errLow = (unsigned char) (errCode & 0xff);
6884 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6885 smbp->rcls = errClass;
6888 } /* error occurred */
6890 /* if we're here, we've finished one request. Look to see if
6891 * this is a chained opcode. If it is, setup things to process
6892 * the chained request, and setup the output buffer to hold the
6893 * chained response. Start by finding the next input record.
6895 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6896 break; /* not a chained req */
6897 tp = inp->wctp; /* points to start of last request */
6898 /* in a chained request, the first two
6899 * parm fields are required, and are
6900 * AndXCommand/AndXReserved and
6902 if (tp[0] < 2) break;
6903 if (tp[1] == 0xff) break; /* no more chained opcodes */
6905 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6908 /* and now append the next output request to the end of this
6909 * last request. Begin by finding out where the last response
6910 * ends, since that's where we'll put our new response.
6912 outWctp = outp->wctp; /* ptr to out parameters */
6913 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6914 nparms = outWctp[0] << 1;
6915 tp = outWctp + nparms + 1; /* now points to bcc field */
6916 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6917 tp += 2 /* for the count itself */ + nbytes;
6918 /* tp now points to the new output record; go back and patch the
6919 * second parameter (off2) to point to the new record.
6921 temp = (unsigned int)(tp - outp->data);
6922 outWctp[3] = (unsigned char) (temp & 0xff);
6923 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6924 outWctp[2] = 0; /* padding */
6925 outWctp[1] = inp->inCom; /* next opcode */
6927 /* finally, setup for the next iteration */
6930 } /* while loop over all requests in the packet */
6932 /* done logging out, turn off logging-out flag */
6933 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6934 vcp->justLoggedOut = NULL;
6937 free(loggedOutName);
6938 loggedOutName = NULL;
6939 smb_ReleaseUID(loggedOutUserp);
6940 loggedOutUserp = NULL;
6944 /* now send the output packet, and return */
6946 smb_SendPacket(vcp, outp);
6947 thrd_Decrement(&ongoingOps);
6949 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6950 if (active_vcp != vcp) {
6952 smb_ReleaseVC(active_vcp);
6954 "Replacing active_vcp %x with %x", active_vcp, vcp);
6959 last_msg_time = GetCurrentTime();
6960 } else if (active_vcp == vcp) {
6961 smb_ReleaseVC(active_vcp);
6969 /* Wait for Netbios() calls to return, and make the results available to server
6970 * threads. Note that server threads can't wait on the NCBevents array
6971 * themselves, because NCB events are manual-reset, and the servers would race
6972 * each other to reset them.
6974 void smb_ClientWaiter(void *parmp)
6979 while (smbShutdownFlag == 0) {
6980 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6982 if (code == WAIT_OBJECT_0)
6985 /* error checking */
6986 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6988 int abandonIdx = code - WAIT_ABANDONED_0;
6989 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6992 if (code == WAIT_IO_COMPLETION)
6994 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6998 if (code == WAIT_TIMEOUT)
7000 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7003 if (code == WAIT_FAILED)
7005 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7008 idx = code - WAIT_OBJECT_0;
7010 /* check idx range! */
7011 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7013 /* this is fatal - log as much as possible */
7014 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7018 thrd_ResetEvent(NCBevents[idx]);
7019 thrd_SetEvent(NCBreturns[0][idx]);
7025 * Try to have one NCBRECV request waiting for every live session. Not more
7026 * than one, because if there is more than one, it's hard to handle Write Raw.
7028 void smb_ServerWaiter(void *parmp)
7031 int idx_session, idx_NCB;
7037 while (smbShutdownFlag == 0) {
7039 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7041 if (code == WAIT_OBJECT_0)
7044 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7046 int abandonIdx = code - WAIT_ABANDONED_0;
7047 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7050 if (code == WAIT_IO_COMPLETION)
7052 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7056 if (code == WAIT_TIMEOUT)
7058 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7061 if (code == WAIT_FAILED)
7063 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7066 idx_session = code - WAIT_OBJECT_0;
7068 /* check idx range! */
7069 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7071 /* this is fatal - log as much as possible */
7072 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7078 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7080 if (code == WAIT_OBJECT_0) {
7081 if (smbShutdownFlag == 1)
7087 /* error checking */
7088 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7090 int abandonIdx = code - WAIT_ABANDONED_0;
7091 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7094 if (code == WAIT_IO_COMPLETION)
7096 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7100 if (code == WAIT_TIMEOUT)
7102 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7105 if (code == WAIT_FAILED)
7107 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7110 idx_NCB = code - WAIT_OBJECT_0;
7112 /* check idx range! */
7113 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7115 /* this is fatal - log as much as possible */
7116 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7120 /* Link them together */
7121 NCBsessions[idx_NCB] = idx_session;
7124 ncbp = NCBs[idx_NCB];
7125 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7126 ncbp->ncb_command = NCBRECV | ASYNCH;
7127 ncbp->ncb_lana_num = lanas[idx_session];
7129 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7130 ncbp->ncb_event = NCBevents[idx_NCB];
7131 ncbp->ncb_length = SMB_PACKETSIZE;
7134 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7135 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7136 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7137 ncbp->ncb_length = SMB_PACKETSIZE;
7138 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7139 Netbios(ncbp, dos_ncb);
7145 * The top level loop for handling SMB request messages. Each server thread
7146 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7147 * NCB and buffer for the incoming request are loaned to us.
7149 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7150 * to immediately send a request for the rest of the data. This must come
7151 * before any other traffic for that session, so we delay setting the session
7152 * event until that data has come in.
7154 void smb_Server(VOID *parmp)
7156 INT_PTR myIdx = (INT_PTR) parmp;
7160 smb_packet_t *outbufp;
7162 int idx_NCB, idx_session;
7164 smb_vc_t *vcp = NULL;
7170 rx_StartClientThread();
7173 outbufp = GetPacket();
7174 outbufp->ncbp = outncbp;
7177 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7180 /* terminate silently if shutdown flag is set */
7181 if (code == WAIT_OBJECT_0) {
7182 if (smbShutdownFlag == 1) {
7183 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7189 /* error checking */
7190 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7192 int abandonIdx = code - WAIT_ABANDONED_0;
7193 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7196 if (code == WAIT_IO_COMPLETION)
7198 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7202 if (code == WAIT_TIMEOUT)
7204 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7207 if (code == WAIT_FAILED)
7209 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7212 idx_NCB = code - WAIT_OBJECT_0;
7214 /* check idx range! */
7215 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7217 /* this is fatal - log as much as possible */
7218 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7222 ncbp = NCBs[idx_NCB];
7224 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7226 idx_session = NCBsessions[idx_NCB];
7227 rc = ncbp->ncb_retcode;
7229 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7232 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7235 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7238 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7241 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7244 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7247 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7250 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7253 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7256 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7259 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7262 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7265 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7268 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7271 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7274 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7277 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7280 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7283 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7286 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7289 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7292 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7295 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7298 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7301 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7304 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7307 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7310 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7313 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7316 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7319 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7322 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7325 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7328 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7331 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7334 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7337 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7340 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7343 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7353 /* Can this happen? Or is it just my UNIX paranoia? */
7354 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7359 /* Client closed session */
7360 dead_sessions[idx_session] = TRUE;
7363 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7364 /* Should also release vcp. [done] 2004-05-11 jaltman
7366 * sanity check that all TID's are gone.
7368 * TODO: check if we could use LSNs[idx_session] instead,
7369 * also cleanup after dead vcp
7372 if (dead_vcp == vcp)
7373 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7374 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7375 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7379 smb_ReleaseVC(dead_vcp);
7381 "Previous dead_vcp %x", dead_vcp);
7384 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7386 if (vcp->justLoggedOut) {
7388 loggedOutTime = vcp->logoffTime;
7389 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7390 loggedOutUserp = vcp->justLoggedOut;
7391 lock_ObtainWrite(&smb_rctLock);
7392 loggedOutUserp->refCount++;
7393 lock_ReleaseWrite(&smb_rctLock);
7399 /* Treat as transient error */
7402 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7406 "dispatch smb recv failed, message incomplete, ncb_length %d",
7409 "SMB message incomplete, "
7410 "length %d", ncbp->ncb_length);
7413 * We used to discard the packet.
7414 * Instead, try handling it normally.
7422 /* A weird error code. Log it, sleep, and
7424 if (vcp && vcp->errorCount++ > 3) {
7425 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7426 dead_sessions[idx_session] = TRUE;
7430 thrd_SetEvent(SessionEvents[idx_session]);
7435 /* Success, so now dispatch on all the data in the packet */
7437 smb_concurrentCalls++;
7438 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7439 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7443 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7445 * If at this point vcp is NULL (implies that packet was invalid)
7446 * then we are in big trouble. This means either :
7447 * a) we have the wrong NCB.
7448 * b) Netbios screwed up the call.
7449 * Obviously this implies that
7450 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7451 * lanas[idx_session] != ncbp->ncb_lana_num )
7452 * Either way, we can't do anything with this packet.
7453 * Log, sleep and resume.
7456 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7460 ncbp->ncb_lana_num);
7462 /* Also log in the trace log. */
7463 osi_Log4(smb_logp, "Server: BAD VCP!"
7464 "LSNs[idx_session]=[%d],"
7465 "lanas[idx_session]=[%d],"
7466 "ncbp->ncb_lsn=[%d],"
7467 "ncbp->ncb_lana_num=[%d]",
7471 ncbp->ncb_lana_num);
7473 /* thrd_Sleep(1000); Don't bother sleeping */
7474 thrd_SetEvent(SessionEvents[idx_session]);
7475 smb_concurrentCalls--;
7480 vcp->errorCount = 0;
7481 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7483 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7484 /* copy whole packet to virtual memory */
7485 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7487 bufp->dos_pkt / 16, bufp);*/
7489 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7491 smbp = (smb_t *)bufp->data;
7494 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7498 if (smbp->com == 0x1d) {
7499 /* Special handling for Write Raw */
7500 raw_write_cont_t rwc;
7501 EVENT_HANDLE rwevent;
7502 char eventName[MAX_PATH];
7504 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7505 if (rwc.code == 0) {
7506 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7507 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7508 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7509 ncbp->ncb_command = NCBRECV | ASYNCH;
7510 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7511 ncbp->ncb_lana_num = vcp->lana;
7512 ncbp->ncb_buffer = rwc.buf;
7513 ncbp->ncb_length = 65535;
7514 ncbp->ncb_event = rwevent;
7518 Netbios(ncbp, dos_ncb);
7520 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7521 thrd_CloseHandle(rwevent);
7523 thrd_SetEvent(SessionEvents[idx_session]);
7525 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7527 else if (smbp->com == 0xa0) {
7529 * Serialize the handling for NT Transact
7532 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7533 thrd_SetEvent(SessionEvents[idx_session]);
7535 thrd_SetEvent(SessionEvents[idx_session]);
7536 /* TODO: what else needs to be serialized? */
7537 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7539 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7541 __except( smb_ServerExceptionFilter() ) {
7545 smb_concurrentCalls--;
7548 thrd_SetEvent(NCBavails[idx_NCB]);
7555 * Exception filter for the server threads. If an exception occurs in the
7556 * dispatch routines, which is where exceptions are most common, then do a
7557 * force trace and give control to upstream exception handlers. Useful for
7560 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7561 DWORD smb_ServerExceptionFilter(void) {
7562 /* While this is not the best time to do a trace, if it succeeds, then
7563 * we have a trace (assuming tracing was enabled). Otherwise, this should
7564 * throw a second exception.
7566 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7567 afsd_ForceTrace(TRUE);
7568 buf_ForceTrace(TRUE);
7569 return EXCEPTION_CONTINUE_SEARCH;
7574 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7575 * If the number of server threads is M, and the number of live sessions is
7576 * N, then the number of NCB's in use at any time either waiting for, or
7577 * holding, received messages is M + N, so that is how many NCB's get created.
7579 void InitNCBslot(int idx)
7581 struct smb_packet *bufp;
7582 EVENT_HANDLE retHandle;
7584 char eventName[MAX_PATH];
7586 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7588 NCBs[idx] = GetNCB();
7589 sprintf(eventName,"NCBavails[%d]", idx);
7590 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7591 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7592 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7594 sprintf(eventName,"NCBevents[%d]", idx);
7595 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7596 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7597 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7599 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7600 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7601 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7602 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7603 for (i=0; i<smb_NumServerThreads; i++)
7604 NCBreturns[i][idx] = retHandle;
7606 bufp->spacep = cm_GetSpace();
7610 /* listen for new connections */
7611 void smb_Listener(void *parmp)
7619 char rname[NCBNAMSZ+1];
7620 char cname[MAX_COMPUTERNAME_LENGTH+1];
7621 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7626 INT_PTR lana = (INT_PTR) parmp;
7630 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7633 /* retrieve computer name */
7634 GetComputerName(cname, &cnamelen);
7638 memset(ncbp, 0, sizeof(NCB));
7641 ncbp->ncb_command = NCBLISTEN;
7642 ncbp->ncb_rto = 0; /* No receive timeout */
7643 ncbp->ncb_sto = 0; /* No send timeout */
7645 /* pad out with spaces instead of null termination */
7646 len = (long)strlen(smb_localNamep);
7647 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7648 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7650 strcpy(ncbp->ncb_callname, "*");
7651 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7653 ncbp->ncb_lana_num = (UCHAR)lana;
7656 code = Netbios(ncbp);
7658 code = Netbios(ncbp, dos_ncb);
7667 /* terminate silently if shutdown flag is set */
7668 if (smbShutdownFlag == 1) {
7677 "NCBLISTEN lana=%d failed with code %d",
7678 ncbp->ncb_lana_num, code);
7680 "Client exiting due to network failure. Please restart client.\n");
7684 "Client exiting due to network failure. Please restart client.\n"
7685 "NCBLISTEN lana=%d failed with code %d",
7686 ncbp->ncb_lana_num, code);
7688 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7689 MB_OK|MB_SERVICE_NOTIFICATION);
7690 osi_assert(tbuffer);
7693 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7694 ncbp->ncb_lana_num, code);
7695 fprintf(stderr, "\nClient exiting due to network failure "
7696 "(possibly due to power-saving mode)\n");
7697 fprintf(stderr, "Please restart client.\n");
7698 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7702 /* check for remote conns */
7703 /* first get remote name and insert null terminator */
7704 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7705 for (i=NCBNAMSZ; i>0; i--) {
7706 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7712 /* compare with local name */
7714 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7715 flags |= SMB_VCFLAG_REMOTECONN;
7717 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7719 lock_ObtainMutex(&smb_ListenerLock);
7721 /* New generation */
7724 /* Log session startup */
7726 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7728 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7729 #endif /* NOTSERVICE */
7730 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7731 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7733 if (reportSessionStartups) {
7735 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7738 fprintf(stderr, "%s: New session %d starting from host %s\n",
7739 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7743 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7744 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7747 /* now ncbp->ncb_lsn is the connection ID */
7748 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7749 vcp->flags |= flags;
7750 strcpy(vcp->rname, rname);
7752 /* Allocate slot in session arrays */
7753 /* Re-use dead session if possible, otherwise add one more */
7754 /* But don't look at session[0], it is reserved */
7755 for (i = 1; i < numSessions; i++) {
7756 if (dead_sessions[i]) {
7757 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7758 dead_sessions[i] = FALSE;
7763 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7764 unsigned long code = CM_ERROR_ALLBUSY;
7765 smb_packet_t * outp = GetPacket();
7766 unsigned char *outWctp;
7771 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7772 unsigned long NTStatus;
7773 smb_MapNTError(code, &NTStatus);
7774 outWctp = outp->wctp;
7775 smbp = (smb_t *) &outp->data;
7779 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7780 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7781 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7782 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7783 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7785 unsigned short errCode;
7786 unsigned char errClass;
7787 smb_MapCoreError(code, vcp, &errCode, &errClass);
7788 outWctp = outp->wctp;
7789 smbp = (smb_t *) &outp->data;
7793 smbp->errLow = (unsigned char) (errCode & 0xff);
7794 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7795 smbp->rcls = errClass;
7797 smb_SendPacket(vcp, outp);
7798 smb_FreePacket(outp);
7800 /* assert that we do not exceed the maximum number of sessions or NCBs.
7801 * we should probably want to wait for a session to be freed in case
7804 osi_assert(i < Sessionmax - 1);
7805 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7807 LSNs[i] = ncbp->ncb_lsn;
7808 lanas[i] = ncbp->ncb_lana_num;
7810 if (i == numSessions) {
7811 /* Add new NCB for new session */
7812 char eventName[MAX_PATH];
7814 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7816 InitNCBslot(numNCBs);
7818 thrd_SetEvent(NCBavails[0]);
7819 thrd_SetEvent(NCBevents[0]);
7820 for (j = 0; j < smb_NumServerThreads; j++)
7821 thrd_SetEvent(NCBreturns[j][0]);
7822 /* Also add new session event */
7823 sprintf(eventName, "SessionEvents[%d]", i);
7824 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7825 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7826 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7828 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7829 thrd_SetEvent(SessionEvents[0]);
7831 thrd_SetEvent(SessionEvents[i]);
7838 lock_ReleaseMutex(&smb_ListenerLock);
7839 } /* dispatch while loop */
7842 /* initialize Netbios */
7843 void smb_NetbiosInit()
7849 int i, lana, code, l;
7851 int delname_tried=0;
7854 OSVERSIONINFO Version;
7856 /* Get the version of Windows */
7857 memset(&Version, 0x00, sizeof(Version));
7858 Version.dwOSVersionInfoSize = sizeof(Version);
7859 GetVersionEx(&Version);
7861 /* setup the NCB system */
7864 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7868 if (smb_LANadapter == -1) {
7869 ncbp->ncb_command = NCBENUM;
7870 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7871 ncbp->ncb_length = sizeof(lana_list);
7872 code = Netbios(ncbp);
7874 afsi_log("Netbios NCBENUM error code %d", code);
7875 osi_panic(s, __FILE__, __LINE__);
7879 lana_list.length = 1;
7880 lana_list.lana[0] = smb_LANadapter;
7883 for (i = 0; i < lana_list.length; i++) {
7884 /* reset the adaptor: in Win32, this is required for every process, and
7885 * acts as an init call, not as a real hardware reset.
7887 ncbp->ncb_command = NCBRESET;
7888 ncbp->ncb_callname[0] = 100;
7889 ncbp->ncb_callname[2] = 100;
7890 ncbp->ncb_lana_num = lana_list.lana[i];
7891 code = Netbios(ncbp);
7893 code = ncbp->ncb_retcode;
7895 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7896 lana_list.lana[i] = 255; /* invalid lana */
7898 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7902 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7903 we will just fake the LANA list */
7904 if (smb_LANadapter == -1) {
7905 for (i = 0; i < 8; i++)
7906 lana_list.lana[i] = i;
7907 lana_list.length = 8;
7910 lana_list.length = 1;
7911 lana_list.lana[0] = smb_LANadapter;
7915 /* and declare our name so we can receive connections */
7916 memset(ncbp, 0, sizeof(*ncbp));
7917 len=lstrlen(smb_localNamep);
7918 memset(smb_sharename,' ',NCBNAMSZ);
7919 memcpy(smb_sharename,smb_localNamep,len);
7920 afsi_log("lana_list.length %d", lana_list.length);
7922 /* Keep the name so we can unregister it later */
7923 for (l = 0; l < lana_list.length; l++) {
7924 lana = lana_list.lana[l];
7926 ncbp->ncb_command = NCBADDNAME;
7927 ncbp->ncb_lana_num = lana;
7928 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7930 code = Netbios(ncbp);
7932 code = Netbios(ncbp, dos_ncb);
7935 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7936 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7938 char name[NCBNAMSZ+1];
7940 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7941 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
7944 if (code == 0) code = ncbp->ncb_retcode;
7946 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
7948 /* we only use one LANA with djgpp */
7949 lana_list.lana[0] = lana;
7950 lana_list.length = 1;
7954 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
7955 if (code == NRC_BRIDGE) { /* invalid LANA num */
7956 lana_list.lana[l] = 255;
7959 else if (code == NRC_DUPNAME) {
7960 afsi_log("Name already exists; try to delete it");
7961 memset(ncbp, 0, sizeof(*ncbp));
7962 ncbp->ncb_command = NCBDELNAME;
7963 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7964 ncbp->ncb_lana_num = lana;
7966 code = Netbios(ncbp);
7968 code = Netbios(ncbp, dos_ncb);
7971 code = ncbp->ncb_retcode;
7973 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7975 if (code != 0 || delname_tried) {
7976 lana_list.lana[l] = 255;
7978 else if (code == 0) {
7979 if (!delname_tried) {
7987 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
7988 lana_list.lana[l] = 255; /* invalid lana */
7989 osi_panic(s, __FILE__, __LINE__);
7993 lana_found = 1; /* at least one worked */
8000 osi_assert(lana_list.length >= 0);
8002 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8005 /* we're done with the NCB now */
8009 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8026 EVENT_HANDLE retHandle;
8027 char eventName[MAX_PATH];
8030 smb_MBfunc = aMBfunc;
8034 smb_LANadapter = LANadapt;
8036 /* Initialize smb_localZero */
8037 myTime.tm_isdst = -1; /* compute whether on DST or not */
8038 myTime.tm_year = 70;
8044 smb_localZero = mktime(&myTime);
8046 #ifndef USE_NUMERIC_TIME_CONV
8047 /* Initialize kludge-GMT */
8048 smb_CalculateNowTZ();
8049 #endif /* USE_NUMERIC_TIME_CONV */
8050 #ifdef AFS_FREELANCE_CLIENT
8051 /* Make sure the root.afs volume has the correct time */
8052 cm_noteLocalMountPointChange();
8055 /* initialize the remote debugging log */
8058 /* remember the name */
8059 len = (int)strlen(snamep);
8060 smb_localNamep = malloc(len+1);
8061 strcpy(smb_localNamep, snamep);
8062 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8064 /* and the global lock */
8065 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8066 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8068 /* Raw I/O data structures */
8069 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8071 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8073 /* 4 Raw I/O buffers */
8075 smb_RawBufs = calloc(65536,1);
8076 *((char **)smb_RawBufs) = NULL;
8077 for (i=0; i<3; i++) {
8078 char *rawBuf = calloc(65536,1);
8079 *((char **)rawBuf) = smb_RawBufs;
8080 smb_RawBufs = rawBuf;
8083 npar = 65536 >> 4; /* number of paragraphs */
8084 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8086 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8088 osi_panic("",__FILE__,__LINE__);
8091 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8094 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8096 _farpokel(_dos_ds, smb_RawBufs, NULL);
8097 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8098 npar = 65536 >> 4; /* number of paragraphs */
8099 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8101 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8103 osi_panic("",__FILE__,__LINE__);
8106 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8109 rawBuf = (seg * 16) + 0; /* DOS physical address */
8110 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8111 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8112 smb_RawBufs = rawBuf;
8116 /* global free lists */
8117 smb_ncbFreeListp = NULL;
8118 smb_packetFreeListp = NULL;
8122 /* Initialize listener and server structures */
8124 memset(dead_sessions, 0, sizeof(dead_sessions));
8125 sprintf(eventName, "SessionEvents[0]");
8126 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8127 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8128 afsi_log("Event Object Already Exists: %s", eventName);
8130 smb_NumServerThreads = nThreads;
8131 sprintf(eventName, "NCBavails[0]");
8132 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8133 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8134 afsi_log("Event Object Already Exists: %s", eventName);
8135 sprintf(eventName, "NCBevents[0]");
8136 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8137 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8138 afsi_log("Event Object Already Exists: %s", eventName);
8139 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8140 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8141 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8142 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8143 afsi_log("Event Object Already Exists: %s", eventName);
8144 for (i = 0; i < smb_NumServerThreads; i++) {
8145 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8146 NCBreturns[i][0] = retHandle;
8149 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8150 for (i = 0; i < smb_NumServerThreads; i++) {
8151 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8152 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8153 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8154 afsi_log("Event Object Already Exists: %s", eventName);
8155 InitNCBslot((int)(i+1));
8157 numNCBs = smb_NumServerThreads + 1;
8159 /* Initialize dispatch table */
8160 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8161 /* Prepare the table for unknown operations */
8162 for(i=0; i<= SMB_NOPCODES; i++) {
8163 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8165 /* Fill in the ones we do know */
8166 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8167 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8168 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8169 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8170 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8171 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8172 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8173 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8174 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8175 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8176 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8177 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8178 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8179 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8180 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8181 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8182 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8183 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8184 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8185 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8186 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8187 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8188 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8189 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8190 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8191 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8192 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8193 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8194 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8195 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8196 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8197 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8198 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8199 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8200 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8201 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8202 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8203 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8204 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8205 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8206 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8207 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8208 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8209 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8210 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8211 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8212 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8213 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8214 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8215 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8216 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8217 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8218 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8219 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8220 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8221 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8222 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8223 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8224 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8225 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8226 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8227 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8228 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8229 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8230 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8231 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8232 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8233 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8234 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8235 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8236 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8237 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8239 /* setup tran 2 dispatch table */
8240 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8241 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8242 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8243 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8244 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8245 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8246 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8247 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8248 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8249 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8250 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8251 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8252 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8253 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8254 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8255 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8256 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8258 /* setup the rap dispatch table */
8259 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8260 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8261 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8262 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8263 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8267 /* if we are doing SMB authentication we have register outselves as a logon process */
8268 if (smb_authType != SMB_AUTH_NONE) {
8269 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8270 LSA_STRING afsProcessName;
8271 LSA_OPERATIONAL_MODE dummy; /*junk*/
8273 afsProcessName.Buffer = "OpenAFSClientDaemon";
8274 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8275 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8277 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8279 if (nts == STATUS_SUCCESS) {
8280 LSA_STRING packageName;
8281 /* we are registered. Find out the security package id */
8282 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8283 packageName.Length = (USHORT)strlen(packageName.Buffer);
8284 packageName.MaximumLength = packageName.Length + 1;
8285 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8286 if (nts == STATUS_SUCCESS) {
8288 * This code forces Windows to authenticate against the Logon Cache
8289 * first instead of attempting to authenticate against the Domain
8290 * Controller. When the Windows logon cache is enabled this improves
8291 * performance by removing the network access and works around a bug
8292 * seen at sites which are using a MIT Kerberos principal to login
8293 * to machines joined to a non-root domain in a multi-domain forest.
8295 PVOID pResponse = NULL;
8296 ULONG cbResponse = 0;
8297 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8299 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8300 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8301 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8302 OptionsRequest.DisableOptions = FALSE;
8304 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8307 sizeof(OptionsRequest),
8313 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8315 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8317 OutputDebugString(message);
8320 OutputDebugString("MsV1_0SetProcessOption success");
8321 afsi_log("MsV1_0SetProcessOption success");
8323 /* END - code from Larry */
8325 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8326 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8327 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8329 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8331 /* something went wrong. We report the error and revert back to no authentication
8332 because we can't perform any auth requests without a successful lsa handle
8333 or sec package id. */
8334 afsi_log("Reverting to NO SMB AUTH");
8335 smb_authType = SMB_AUTH_NONE;
8338 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8340 /* something went wrong. We report the error and revert back to no authentication
8341 because we can't perform any auth requests without a successful lsa handle
8342 or sec package id. */
8343 afsi_log("Reverting to NO SMB AUTH");
8344 smb_authType = SMB_AUTH_NONE;
8348 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8349 * time prevents the failure of authentication when logged into Windows with an
8350 * external Kerberos principal mapped to a local account.
8352 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8353 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8354 * then the only option is NTLMSSP anyway; so just fallback.
8359 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8360 if (secBlobLength == 0) {
8361 smb_authType = SMB_AUTH_NTLM;
8362 afsi_log("Reverting to SMB AUTH NTLM");
8371 /* Now get ourselves a domain name. */
8372 /* For now we are using the local computer name as the domain name.
8373 * It is actually the domain for local logins, and we are acting as
8374 * a local SMB server.
8376 bufsize = sizeof(smb_ServerDomainName) - 1;
8377 GetComputerName(smb_ServerDomainName, &bufsize);
8378 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8379 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8382 /* Start listeners, waiters, servers, and daemons */
8384 for (i = 0; i < lana_list.length; i++) {
8385 if (lana_list.lana[i] == 255)
8387 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8388 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8389 osi_assert(phandle != NULL);
8390 thrd_CloseHandle(phandle);
8394 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8395 NULL, 0, &lpid, "smb_ClientWaiter");
8396 osi_assert(phandle != NULL);
8397 thrd_CloseHandle(phandle);
8400 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8401 NULL, 0, &lpid, "smb_ServerWaiter");
8402 osi_assert(phandle != NULL);
8403 thrd_CloseHandle(phandle);
8405 for (i=0; i<smb_NumServerThreads; i++) {
8406 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8407 (void *) i, 0, &lpid, "smb_Server");
8408 osi_assert(phandle != NULL);
8409 thrd_CloseHandle(phandle);
8412 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8413 NULL, 0, &lpid, "smb_Daemon");
8414 osi_assert(phandle != NULL);
8415 thrd_CloseHandle(phandle);
8417 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8418 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8419 osi_assert(phandle != NULL);
8420 thrd_CloseHandle(phandle);
8429 void smb_Shutdown(void)
8439 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8441 /* setup the NCB system */
8444 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8447 /* Block new sessions by setting shutdown flag */
8448 smbShutdownFlag = 1;
8450 /* Hang up all sessions */
8451 memset((char *)ncbp, 0, sizeof(NCB));
8452 for (i = 1; i < numSessions; i++)
8454 if (dead_sessions[i])
8457 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8458 ncbp->ncb_command = NCBHANGUP;
8459 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8460 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8462 code = Netbios(ncbp);
8464 code = Netbios(ncbp, dos_ncb);
8466 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8467 if (code == 0) code = ncbp->ncb_retcode;
8469 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8470 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8474 /* Trigger the shutdown of all SMB threads */
8475 for (i = 0; i < smb_NumServerThreads; i++)
8476 thrd_SetEvent(NCBreturns[i][0]);
8478 thrd_SetEvent(NCBevents[0]);
8479 thrd_SetEvent(SessionEvents[0]);
8480 thrd_SetEvent(NCBavails[0]);
8482 for (i = 0;i < smb_NumServerThreads; i++) {
8483 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8484 if (code == WAIT_OBJECT_0) {
8487 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8488 thrd_SetEvent(NCBreturns[i--][0]);
8492 /* Delete Netbios name */
8493 memset((char *)ncbp, 0, sizeof(NCB));
8494 for (i = 0; i < lana_list.length; i++) {
8495 if (lana_list.lana[i] == 255) continue;
8496 ncbp->ncb_command = NCBDELNAME;
8497 ncbp->ncb_lana_num = lana_list.lana[i];
8498 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8500 code = Netbios(ncbp);
8502 code = Netbios(ncbp, dos_ncb);
8505 code = ncbp->ncb_retcode;
8507 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8508 ncbp->ncb_lana_num, code);
8513 /* Release the reference counts held by the VCs */
8514 lock_ObtainWrite(&smb_rctLock);
8515 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8520 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8522 if (fidp->scp != NULL) {
8525 lock_ObtainMutex(&fidp->mx);
8526 if (fidp->scp != NULL) {
8529 cm_ReleaseSCache(scp);
8531 lock_ReleaseMutex(&fidp->mx);
8535 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8537 smb_ReleaseVCNoLock(tidp->vcp);
8539 cm_user_t *userp = tidp->userp;
8541 lock_ReleaseWrite(&smb_rctLock);
8542 cm_ReleaseUser(userp);
8543 lock_ObtainWrite(&smb_rctLock);
8547 lock_ReleaseWrite(&smb_rctLock);
8550 /* Get the UNC \\<servername>\<sharename> prefix. */
8551 char *smb_GetSharename()
8555 /* Make sure we have been properly initialized. */
8556 if (smb_localNamep == NULL)
8559 /* Allocate space for \\<servername>\<sharename>, plus the
8562 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8563 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8569 void smb_LogPacket(smb_packet_t *packet)
8572 unsigned length, paramlen, datalen, i, j;
8574 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8576 if (!packet) return;
8578 osi_Log0(smb_logp, "*** SMB packet dump ***");
8580 vp = (BYTE *) packet->data;
8582 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8583 length = paramlen + 2 + datalen;
8586 for (i=0;i < length; i+=16)
8588 memset( buf, ' ', 80 );
8593 buf[strlen(buf)] = ' ';
8595 cp = (BYTE*) buf + 7;
8597 for (j=0;j < 16 && (i+j)<length; j++)
8599 *(cp++) = hex[vp[i+j] >> 4];
8600 *(cp++) = hex[vp[i+j] & 0xf];
8610 for (j=0;j < 16 && (i+j)<length;j++)
8612 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8623 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8626 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8628 #endif /* LOG_PACKET */
8631 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8639 lock_ObtainRead(&smb_rctLock);
8641 sprintf(output, "begin dumping smb_vc_t\n");
8642 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8644 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8648 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8649 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8650 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8652 sprintf(output, "begin dumping smb_fid_t\n");
8653 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8655 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8657 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8658 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8659 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8660 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8661 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8664 sprintf(output, "done dumping smb_fid_t\n");
8665 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8668 sprintf(output, "done dumping smb_vc_t\n");
8669 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8672 lock_ReleaseRead(&smb_rctLock);