/*++ Copyright (c) 1991 Microsoft Corporation Module Name: svcsrv.c Abstract: This module contains routines for supporting the server APIs in the server service, SrvNetServerDiskEnum, and SrvNetServerSetInfo. Author: David Treadwell (davidtr) 31-Jan-1991 Revision History: --*/ #include "precomp.h" #include "svcsrv.tmh" #pragma hdrstop // // Forward declarations. // LARGE_INTEGER SecondsToTime ( IN ULONG Seconds, IN BOOLEAN MakeNegative ); LARGE_INTEGER MinutesToTime ( IN ULONG Seconds, IN BOOLEAN MakeNegative ); ULONG MultipleOfProcessors ( IN ULONG value ); BOOL IsSuiteVersion( IN USHORT Version ); #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, SrvNetServerDiskEnum ) #pragma alloc_text( PAGE, SrvNetServerSetInfo ) #pragma alloc_text( PAGE, SecondsToTime ) #pragma alloc_text( PAGE, MinutesToTime ) #pragma alloc_text( PAGE, MultipleOfProcessors ) #pragma alloc_text( PAGE, IsSuiteVersion ) #endif #define IsWebBlade() IsSuiteVersion(VER_SUITE_BLADE) #define IsPersonal() IsSuiteVersion(VER_SUITE_PERSONAL) #define IsEmbedded() IsSuiteVersion(VER_SUITE_EMBEDDEDNT) BOOL IsSuiteVersion(USHORT Version) { OSVERSIONINFOEX Osvi; DWORD TypeMask; DWORDLONG ConditionMask; memset(&Osvi, 0, sizeof(OSVERSIONINFOEX)); Osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); Osvi.wSuiteMask = Version; TypeMask = VER_SUITENAME; ConditionMask = 0; VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_OR); return(NT_SUCCESS(RtlVerifyVersionInfo(&Osvi, TypeMask, ConditionMask))); } NTSTATUS SrvNetServerDiskEnum ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Buffer, IN ULONG BufferLength ) { PAGED_CODE( ); Srp, Buffer, BufferLength; return STATUS_NOT_IMPLEMENTED; } // SrvNetServerDiskEnum NTSTATUS SrvNetServerSetInfo ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Buffer, IN ULONG BufferLength ) /*++ Routine Description: This routine processes the NetServerSetInfo API in the server FSD. Arguments: Srp - a pointer to the server request packet that contains all the information necessary to satisfy the request. This includes: INPUT: None. OUTPUT: None. Buffer - a pointer to a SERVER_INFO_102, followed immediately by a SERVER_INFO_599 structure, followed by a SERVER_INFO_559a structure. All information is always reset in this routine; the server service also tracks this data, so when it gets a NetServerSetInfo it overwrites the appropriate fields and sends all the data. BufferLength - total length of this buffer. Return Value: NTSTATUS - result of operation to return to the server service. --*/ { NTSTATUS status = STATUS_INVALID_PARAMETER; PSERVER_INFO_102 sv102; PSERVER_INFO_599 sv599; PSERVER_INFO_598 sv598; LARGE_INTEGER scavengerTimeout; LARGE_INTEGER alerterTimeout; ULONG ipxdisc; LARGE_INTEGER li; ULONG bufferOffset; ULONG keTimeIncrement; PAGED_CODE( ); // // Make sure that the input buffer length is correct. // if ( BufferLength < sizeof(SERVER_INFO_102) + sizeof(SERVER_INFO_599) + sizeof(SERVER_INFO_598) ) { return status; } // // Set up buffer pointers as appropriate. The SERVER_INFO_599 // structure must immediately follow the SERVER_INFO_102 structure // in the buffer. // sv102 = Buffer; sv599 = (PSERVER_INFO_599)(sv102 + 1); sv598 = (PSERVER_INFO_598)(sv599 + 1); if( sv599->sv599_scavtimeout == 0 ) { // This will cause a divide by zero later on return STATUS_INVALID_PARAMETER; } // // store the time increment count // keTimeIncrement = KeQueryTimeIncrement(); // // Grab the lock that protects configuration changes. // ACQUIRE_LOCK( &SrvConfigurationLock ); // // Set all configuration information in the server. // try { SrvMaxUsers = sv102->sv102_users; // // The autodisconnect timeout must be converted from minutes to NT // time, which has a base of 100s of nanoseconds. If the specified // value is negative (top bit set), set the timeout to 0, indicating // that no autodisconnect should be done. If the specified value is // 0, meaning to autodisconnect immediately, set the timeout to a // small value, but not 0. // if ( (sv102->sv102_disc & 0x80000000) == 0 ) { if ( sv102->sv102_disc != 0 ) { SrvAutodisconnectTimeout.QuadPart = Int32x32To64( sv102->sv102_disc, 10*1000*1000*60 ); } else { SrvAutodisconnectTimeout.QuadPart = 1; } } else { SrvAutodisconnectTimeout.QuadPart = 0; } SrvInitialSessionTableSize = (USHORT)sv599->sv599_initsesstable; SrvInitialTreeTableSize = (USHORT)sv599->sv599_initconntable; SrvInitialFileTableSize = (USHORT)sv599->sv599_initfiletable; SrvInitialSearchTableSize = (USHORT)sv599->sv599_initsearchtable; SrvMaxFileTableSize = (USHORT)sv599->sv599_sessopens; SrvMaxNumberVcs = sv599->sv599_sessvcs; SrvMaxSearchTableSize = (USHORT)sv599->sv599_opensearch; SrvReceiveBufferLength = sv599->sv599_sizreqbuf; SrvReceiveBufferSize = (SrvReceiveBufferLength + SrvCacheLineSize) & ~SrvCacheLineSize; SrvReceiveMdlSize = (ULONG)(MmSizeOfMdl( (PVOID)(PAGE_SIZE-1), SrvReceiveBufferSize ) + 7) & ~7; SrvMaxMdlSize = (ULONG)(MmSizeOfMdl( (PVOID)(PAGE_SIZE-1), MAX_PARTIAL_BUFFER_SIZE ) + 7) & ~7; SrvInitialReceiveWorkItemCount = sv599->sv599_initworkitems; SrvMaxReceiveWorkItemCount = sv599->sv599_maxworkitems; SrvInitialRawModeWorkItemCount = sv599->sv599_rawworkitems; SrvReceiveIrpStackSize = (CCHAR)sv599->sv599_irpstacksize; SrvReceiveIrpSize = (IoSizeOfIrp( SrvReceiveIrpStackSize ) + 7) & ~7; SrvMaxSessionTableSize = (USHORT)sv599->sv599_sessusers; SrvMaxTreeTableSize = (USHORT)sv599->sv599_sessconns; SrvMaxPagedPoolUsage = sv599->sv599_maxpagedmemoryusage; SrvMaxNonPagedPoolUsage = sv599->sv599_maxnonpagedmemoryusage; SrvEnableSoftCompatibility = (BOOLEAN)sv599->sv599_enablesoftcompat; SrvEnableForcedLogoff = (BOOLEAN)sv599->sv599_enableforcedlogoff; SrvCoreSearchTimeout = sv599->sv599_maxkeepsearch; SrvSearchMaxTimeout = SecondsToTime( SrvCoreSearchTimeout, FALSE ); SrvScavengerTimeoutInSeconds = sv599->sv599_scavtimeout; scavengerTimeout = SecondsToTime( SrvScavengerTimeoutInSeconds, FALSE ); SrvMaxMpxCount = (USHORT)sv599->sv599_maxmpxct; SrvWaitForOplockBreakTime = SecondsToTime( sv599->sv599_oplockbreakwait, FALSE ); SrvWaitForOplockBreakRequestTime = SecondsToTime( sv599->sv599_oplockbreakresponsewait, FALSE ); SrvMinReceiveQueueLength = sv599->sv599_minrcvqueue; SrvMinFreeWorkItemsBlockingIo = sv599->sv599_minfreeworkitems; SrvXsSectionSize.QuadPart = sv599->sv599_xactmemsize; SrvThreadPriority = (KPRIORITY)sv599->sv599_threadpriority; SrvEnableOplockForceClose = (BOOLEAN)sv599->sv599_enableoplockforceclose; SrvEnableFcbOpens = (BOOLEAN)sv599->sv599_enablefcbopens; SrvEnableRawMode = (BOOLEAN)sv599->sv599_enableraw; SrvFreeConnectionMinimum = sv599->sv599_minfreeconnections; SrvFreeConnectionMaximum = sv599->sv599_maxfreeconnections; // // Max work item idle time is in ticks // li = SecondsToTime( sv599->sv599_maxworkitemidletime, FALSE ); li.QuadPart /= keTimeIncrement; if ( li.HighPart != 0 ) { li.LowPart = 0xffffffff; } SrvWorkItemMaxIdleTime = li.LowPart; // // Oplocks should not be enabled if SrvMaxMpxCount == 1 // if ( SrvMaxMpxCount > 1 ) { SrvEnableOplocks = (BOOLEAN)sv599->sv599_enableoplocks; } else { SrvEnableOplocks = FALSE; } SrvProductTypeServer = MmIsThisAnNtAsSystem( ); SrvServerSize = sv598->sv598_serversize; SrvMaxRawModeWorkItemCount = sv598->sv598_maxrawworkitems; SrvMaxThreadsPerQueue = sv598->sv598_maxthreadsperqueue; ipxdisc = sv598->sv598_connectionlessautodisc; SrvConnectionNoSessionsTimeout = sv598->sv598_ConnectionNoSessionsTimeout; SrvRemoveDuplicateSearches = (BOOLEAN)sv598->sv598_removeduplicatesearches; SrvMaxOpenSearches = sv598->sv598_maxglobalopensearch; SrvSharingViolationRetryCount = sv598->sv598_sharingviolationretries; SrvSharingViolationDelay.QuadPart = Int32x32To64( sv598->sv598_sharingviolationdelay, -1*10*1000 ); SrvLockViolationDelay = sv598->sv598_lockviolationdelay; SrvLockViolationOffset = sv598->sv598_lockviolationoffset; SrvCachedOpenLimit = sv598->sv598_cachedopenlimit; SrvMdlReadSwitchover = sv598->sv598_mdlreadswitchover; SrvEnableWfW311DirectIpx = (BOOLEAN)sv598->sv598_enablewfw311directipx; SrvRestrictNullSessionAccess = (BOOLEAN)sv598->sv598_restrictnullsessaccess; SrvQueueCalc = SecondsToTime( sv598->sv598_queuesamplesecs, FALSE ); SrvPreferredAffinity = sv598->sv598_preferredaffinity; SrvOtherQueueAffinity = sv598->sv598_otherqueueaffinity; SrvBalanceCount = sv598->sv598_balancecount; SrvMaxFreeRfcbs = sv598->sv598_maxfreerfcbs; SrvMaxFreeMfcbs = sv598->sv598_maxfreemfcbs; SrvMaxPagedPoolChunkSize = sv598->sv598_maxpagedpoolchunksize; SrvMaxCachedDirectory = sv598->sv598_cacheddirectorylimit; SrvMaxCopyLength = sv598->sv598_maxcopylength; SrvMinClientBufferSize = sv598->sv598_minclientbuffersize; SrvMinClientBufferSize &= ~03; SrvSmbSecuritySignaturesEnabled = (sv598->sv598_enablesecuritysignature != FALSE); SrvSmbSecuritySignaturesRequired = (sv598->sv598_requiresecuritysignature != FALSE); SrvEnableW9xSecuritySignatures = (sv598->sv598_enableW9xsecuritysignature != FALSE); ServerGuid = sv598->sv598_serverguid; SrvEnforceLogoffTimes = (sv598->sv598_enforcekerberosreauthentication != FALSE); SrvDisableDoSChecking = (sv598->sv598_disabledos != FALSE); SrvDisableStrictNameChecking = (sv598->sv598_disablestrictnamechecking != FALSE); SrvFreeDiskSpaceCeiling = sv598->sv598_lowdiskspaceminimum; // // Make sure the settings are consistent! // if( SrvSmbSecuritySignaturesEnabled == FALSE ) { SrvSmbSecuritySignaturesRequired = FALSE; } SrvMaxNonPagedPoolChunkSize = SrvMaxPagedPoolChunkSize; SrvLockViolationDelayRelative.QuadPart = Int32x32To64( sv598->sv598_lockviolationdelay, -1*10*1000 ); // // Convert the idle thread timeout from seconds to ticks // SrvIdleThreadTimeOut = Int32x32To64( sv598->sv598_IdleThreadTimeOut, -1*10*1000*1000 ); // // Calculate switchover number for mpx // bufferOffset = (sizeof(SMB_HEADER) + sizeof(RESP_READ_MPX) - 1 + 3) & ~3; if ( SrvMdlReadSwitchover > (SrvReceiveBufferLength - bufferOffset) ) { SrvMpxMdlReadSwitchover = SrvReceiveBufferLength - bufferOffset; } else { SrvMpxMdlReadSwitchover = SrvMdlReadSwitchover; } // // The IPX autodisconnect timeout must be converted from minutes to // ticks. If 0 is specified, use 15 minutes. // if ( ipxdisc == 0 ) { ipxdisc = 15; } li.QuadPart = Int32x32To64( ipxdisc, 10*1000*1000*60 ); li.QuadPart /= keTimeIncrement; if ( li.HighPart != 0 ) { li.LowPart = 0xffffffff; } SrvIpxAutodisconnectTimeout = li.LowPart; // // The "idle connection without sessions" timeout must be converted from // minutes to ticks. // li.QuadPart = Int32x32To64( SrvConnectionNoSessionsTimeout, 10*1000*1000*60 ); li.QuadPart /= keTimeIncrement; if( li.HighPart != 0 ) { li.LowPart = 0xffffffff; } SrvConnectionNoSessionsTimeout = li.LowPart; // // Event logging and alerting information. // alerterTimeout = MinutesToTime( sv599->sv599_alertschedule, FALSE ); SrvAlertMinutes = sv599->sv599_alertschedule; SrvErrorRecord.ErrorThreshold = sv599->sv599_errorthreshold; SrvNetworkErrorRecord.ErrorThreshold = sv599->sv599_networkerrorthreshold; SrvFreeDiskSpaceThreshold = sv599->sv599_diskspacethreshold; SrvCaptureScavengerTimeout( &scavengerTimeout, &alerterTimeout ); // // Link Speed Parameters // SrvMaxLinkDelay = SecondsToTime( sv599->sv599_maxlinkdelay, FALSE ); SrvMinLinkThroughput.QuadPart = sv599->sv599_minlinkthroughput; SrvLinkInfoValidTime = SecondsToTime ( sv599->sv599_linkinfovalidtime, FALSE ); SrvScavengerUpdateQosCount = sv599->sv599_scavqosinfoupdatetime / sv599->sv599_scavtimeout; // // Override parameters that cannot be set on WinNT (vs. NTAS). // // We override the parameters passed by the service in case somebody // figures out the FSCTL that changes parameters. We also override // in the service in order to keep the service's view consistent // with the server's. If you make any changes here, also make them // in srvsvc\server\registry.c. // // // For Embedded systems, just take the registry value. They do their own // validation of settings. // if( !IsEmbedded() ) { if ( !SrvProductTypeServer ) { // // On WinNT, the maximum value of certain parameters is fixed at // build time. These include: concurrent users, SMB buffers, // #define MINIMIZE(_param,_max) _param = MIN( _param, _max ); MINIMIZE( SrvMaxUsers, MAX_USERS_WKSTA ); MINIMIZE( SrvMaxReceiveWorkItemCount, MAX_MAXWORKITEMS_WKSTA ); MINIMIZE( SrvMaxThreadsPerQueue, MAX_THREADS_WKSTA ); if( IsPersonal() ) { MINIMIZE( SrvMaxUsers, MAX_USERS_PERSONAL ); } // // On WinNT, we do not cache the following: // SrvCachedOpenLimit = 0; // don't cache close'd files SrvMaxCachedDirectory = 0; // don't cache directory names SrvMaxFreeRfcbs = 0; // don't cache free'd RFCB structs SrvMaxFreeMfcbs = 0; // don't cache free'd NONPAGED_MFCB structs } if( IsWebBlade() ) { MINIMIZE( SrvMaxUsers, MAX_USERS_WEB_BLADE ); MINIMIZE( SrvMaxReceiveWorkItemCount, MAX_MAXWORKITEMS_WKSTA ); MINIMIZE( SrvMaxThreadsPerQueue, MAX_THREADS_WKSTA ); } } if( (SrvMaxUsers < UINT_MAX) && (SrvMaxUsers > 0) ) { // Increment by 1 to allow the "emergency admin" user. Essentially, the final user // to connect must be an administrator in case something is going wrong, such as DoS SrvMaxUsers += 1; } // // The following items are generally per-processor. Ensure they // are a multiple of the number of processors in the system. // SrvMaxReceiveWorkItemCount = MultipleOfProcessors( SrvMaxReceiveWorkItemCount ); SrvInitialReceiveWorkItemCount = MultipleOfProcessors( SrvInitialReceiveWorkItemCount ); SrvMinReceiveQueueLength = MultipleOfProcessors( SrvMinReceiveQueueLength ); SrvMaxRawModeWorkItemCount = MultipleOfProcessors( SrvMaxRawModeWorkItemCount ); SrvInitialRawModeWorkItemCount = MultipleOfProcessors( SrvInitialRawModeWorkItemCount ); status = STATUS_SUCCESS; } except( EXCEPTION_EXECUTE_HANDLER ) { status = GetExceptionCode(); } RELEASE_LOCK( &SrvConfigurationLock ); return status; } // SrvNetServerSetInfo LARGE_INTEGER SecondsToTime ( IN ULONG Seconds, IN BOOLEAN MakeNegative ) /*++ Routine Description: This routine converts a time interval specified in seconds to the NT time base in 100s on nanoseconds. Arguments: Seconds - the interval in seconds. MakeNegative - if TRUE, the time returned is a negative, i.e. relative time. Return Value: LARGE_INTEGER - the interval in NT time. --*/ { LARGE_INTEGER ntTime; PAGED_CODE( ); if ( MakeNegative ) { ntTime.QuadPart = Int32x32To64( Seconds, -1*10*1000*1000 ); } else { ntTime.QuadPart = Int32x32To64( Seconds, 1*10*1000*1000 ); } return ntTime; } // SecondsToTime LARGE_INTEGER MinutesToTime ( IN ULONG Minutes, IN BOOLEAN MakeNegative ) /*++ Routine Description: This routine converts a time interval specified in minutes to the NT time base in 100s on nanoseconds. Arguments: Minutes - the interval in minutes. MakeNegative - if TRUE, the time returned is a negative, i.e. relative time. Return Value: LARGE_INTEGER - the interval in NT time. --*/ { PAGED_CODE( ); return SecondsToTime( 60*Minutes, MakeNegative ); } // MinutesToTime ULONG MultipleOfProcessors( IN ULONG value ) /*++ Routine Description: This routine ensures the passed in value is a multiple of the number of processors in the system. The value will be adjusted upward if necessary. Arguments: value - the value to be adjusted Return Value: the adjusted value --*/ { value += SrvNumberOfProcessors - 1; value /= SrvNumberOfProcessors; value *= SrvNumberOfProcessors; return value; }