Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2324 lines
61 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name :
tsvcinfo.cxx
Abstract:
Defines the functions for TCP services Info class.
This module is intended to capture the common scheduler
code for the tcp services ( especially internet services)
which involves the Service Controller dispatch functions.
Also this class provides an interface for common dll of servers.
Author:
Murali R. Krishnan ( MuraliK ) 15-Nov-1994
Project:
Internet Servers Common DLL
Functions Exported:
TSVC_INFO::TSVC_INFO()
TSVC_INFO::~TSVC_INFO()
TSVC_INFO::StartServiceOperation()
TSVC_INFO::InitializeConnections()
TSVC_INFO::CleanupConnections()
TSVC_INFO::InitializeSockets()
TSVC_INFO::CleanupSockets()
TSVC_INFO::Print()
Revision History:
MuraliK 08-March-1995 Added InitializeConnections and
CleanupConnections member functions to TSVC_INFO.
--*/
/************************************************************
* Include Headers
************************************************************/
# include "tcpdllp.hxx"
# include <rpc.h>
# include "tsunami.hxx"
# include "tsvcinfo.hxx"
# include "inetreg.h"
# include "apiutil.h"
extern MIME_MAP * g_pMimeMap;
/************************************************************
* Symbolic Constants
************************************************************/
//
// Default Max length to which queue of pending connections may grow
//
# define CP_DEFAULT_MAX_BACKLOG_ENTRIES ( 25)
# define LISTEN_BACKLOG_A "ListenBacklog"
# define MAX_ADDRESSES_SUPPORTED ( 20)
#define SIZEOF_IP_SEC_LIST( IPList ) (sizeof(INET_INFO_IP_SEC_LIST) + \
(IPList)->cEntries * \
sizeof(INET_INFO_IP_SEC_ENTRY))
//
// This is the key RNR places the service information
//
#define WINSOCK_SERV_PROV_KEY \
"System\\CurrentControlSet\\Control\\ServiceProvider\\ServiceTypes\\"
/************************************************************
* Local Functions
************************************************************/
static BOOL
RegisterServiceForAdvertising(IN LPCTSTR pszServiceName,
IN LPGUID lpServiceGuid,
IN SOCKET *pSockets,
IN DWORD nSockets);
static int
GetValidListenAddresses( IN LPCTSTR pszServiceName,
IN LPGUID lpServiceGuid,
IN PCSADDR_INFO pcsAddrInfo,
IN OUT LPDWORD lpcbAddrInfo );
#ifdef CHICAGO
BOOL g_fIgnoreSC = TRUE;
#else
BOOL g_fIgnoreSC = FALSE;
#endif
/************************************************************
* Functions
************************************************************/
TSVC_INFO::TSVC_INFO(
IN LPCTSTR lpszServiceName,
IN CHAR * lpszModuleName,
IN CHAR * lpszRegParamKey,
IN WCHAR * lpszAnonPasswordSecretName,
IN WCHAR * lpszVirtualRootsSecretName,
IN DWORD dwServiceId,
IN PFN_SERVICE_SPECIFIC_INITIALIZE pfnInitialize,
IN PFN_SERVICE_SPECIFIC_CLEANUP pfnCleanup
)
/*++
Desrcription:
Contructor for TSVC_INFO class.
This constructs a new service info object for the service specified.
Arguments:
lpszServiceName
name of the service to be created.
dwServiceId
DWORD containing the bitflag id for service.
lpszModuleName
name of the module for loading string resources.
lpszRegParamKey
fully qualified name of the registry key that contains the
common service data for this server
lpszAnonPasswordSecretName
The name of the LSA secret the anonymous password is stored under
lpszVirtualRootsSecretName
The name of the LSA secret the virtual root passwords are stored
under
pfnInitialize
pointer to function to be called for initialization of
service specific data
pfnCleanup
pointer to function to be called for cleanup of service
specific data
On success it initializes all the members of the object,
inserts itself to the global list of service info objects and
returns with success.
Note:
The caller of this function should check the validity by
invoking the member function IsValid() after constructing
this object.
--*/
:
ISVC_INFO( dwServiceId, lpszServiceName, lpszModuleName, lpszRegParamKey),
m_fValid ( FALSE ),
m_fNoIPAccessChecks ( FALSE ),
m_ipaDenyList ( ),
m_ipaGrantList ( ),
m_tsCache ( dwServiceId ),
m_pchAnonUserName ( NULL ),
m_pchLogFileDirectory ( NULL ),
m_pMimeMap ( g_pMimeMap),
m_pchLogFileName ( NULL ),
m_fSocketsInitialized ( 0 ),
m_dwLogonMethod ( INETA_DEF_LOGON_METHOD ),
m_pchDefaultLogonDomain( NULL )
{
DBG_ASSERT( pfnInitialize != NULL &&
pfnCleanup != NULL);
DBG_ASSERT( lpszAnonPasswordSecretName != NULL );
DBG_ASSERT( lpszVirtualRootsSecretName != NULL );
//
// Initialize the service status structure.
//
m_svcStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
m_svcStatus.dwCurrentState = SERVICE_STOPPED;
m_svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_PAUSE_CONTINUE
| SERVICE_ACCEPT_SHUTDOWN;
m_svcStatus.dwWin32ExitCode = NO_ERROR;
m_svcStatus.dwServiceSpecificExitCode = NO_ERROR;
m_svcStatus.dwCheckPoint = 0;
m_svcStatus.dwWaitHint = 0;
//
// Initialize Call back functions
//
m_pfnInitialize = pfnInitialize;
m_pfnCleanup = pfnCleanup;
m_hShutdownEvent= NULL;
m_pchAnonPasswordSecretName = lpszAnonPasswordSecretName;
m_pchVirtualRootsSecretName = lpszVirtualRootsSecretName;
m_achAnonUserPwd[0] = '\0';
//
// Initialize the cache stuff. Can't call during InitializeServiceInfo
// because it creates threads but it's safe to call multiple times.
//
// They are unitialized in process detach which currently never gets called
//
m_fValid = Tsunami_Initialize() &&
InitializeCacheScavenger();
return;
} // TSVC_INFO::TSVC_INFO()
TSVC_INFO::~TSVC_INFO( VOID)
/*++
Description:
Cleanup the TsvcInfo object. If the service is not already
terminated, it terminates the service before cleanup.
Arguments:
None
Returns:
None
--*/
{
if ( m_hShutdownEvent != NULL) {
CloseHandle( m_hShutdownEvent);
}
} // TSVC_INFO::~TSVC_INFO()
DWORD
TSVC_INFO::StartServiceOperation(
IN PFN_SERVICE_CTRL_HANDLER pfnCtrlHandler
)
/*++
Description:
Starts the operation of service instantiated in the given
Service Info Object.
Arguments:
pfnCtrlHandler
pointer to a callback function for handling dispatch of
service controller requests. A separate function is required
since Service Controller call back function does not send
context information.
Returns:
NO_ERROR on success and Win32 error code if any failure.
--*/
{
DWORD err;
DWORD cbBuffer;
BOOL fInitCalled = FALSE;
if ( !IsValid()) {
//
// Not successfully initialized.
//
return ( ERROR_INVALID_FUNCTION);
}
if ( !g_fIgnoreSC ) {
m_hsvcStatus = RegisterServiceCtrlHandler(
QueryServiceName(),
pfnCtrlHandler
);
} else {
m_hsvcStatus = 1;
}
//
// Register the Control Handler routine.
//
if( m_hsvcStatus == NULL_SERVICE_STATUS_HANDLE )
{
err = GetLastError();
DBGPRINTF( ( DBG_CONTEXT,
"cannot connect to register ctrl handler, error %lu\n",
err )
);
goto Cleanup;
}
//
// Update the service status.
//
err = UpdateServiceStatus( SERVICE_START_PENDING,
NO_ERROR,
1,
SERVICE_START_WAIT_HINT );
if( err != NO_ERROR )
{
DBGPRINTF( ( DBG_CONTEXT,
"StartServiceOperation(): cannot update service status,"
" error %lu\n",
err )
);
goto Cleanup;
}
//
// Initialize the service common components
//
if ( !ReadParamsFromRegistry( FC_INET_INFO_ALL ) ||
!InitializeNTSecurity()
) {
err = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
"Initilization of service common stuff failed with %d\n",
err));
goto Cleanup;
}
//
// Initialize the various service specific components.
//
err = ( *m_pfnInitialize)( this);
fInitCalled = TRUE;
if( err != NO_ERROR ) {
DBGPRINTF( ( DBG_CONTEXT,
" Initialization of service failed with %d\n",
err));
goto Cleanup;
}
#ifndef CHICAGO
//
// Create shutdown event.
//
m_hShutdownEvent = CreateEvent( NULL, // lpsaSecurity
TRUE, // fManualReset
FALSE, // fInitialState
NULL ); // lpszEventName
if( m_hShutdownEvent == NULL )
{
err = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
"InitializeService(): Cannot create shutdown event,"
" error %lu\n",
err )
);
goto Cleanup;
}
//
// Update the service status.
//
err = UpdateServiceStatus( SERVICE_RUNNING,
NO_ERROR,
0,
0 );
if( err != NO_ERROR )
{
DBGPRINTF( ( DBG_CONTEXT, "cannot update service status, error %lu\n",
err )
);
goto Cleanup;
}
//
// Wait for the shutdown event.
//
DBGPRINTF( ( DBG_CONTEXT, " Waiting for ShutDown Event ...\n"));
err = WaitForSingleObject( m_hShutdownEvent,
INFINITE );
if ( err != WAIT_OBJECT_0) {
//
// Error. Unable to wait for single object.
//
DBGPRINTF( ( DBG_CONTEXT,
"Wait for single object failed with Error %lu\n",
err )
);
}
//
// Stop time. Tell the Service Controller that we're stopping,
// then terminate the various service components.
//
UpdateServiceStatus( SERVICE_STOP_PENDING,
0,
1,
SERVICE_STOP_WAIT_HINT );
//
// Destroy the shutdown event.
//
if( m_hShutdownEvent != NULL ) {
if ( ! CloseHandle( m_hShutdownEvent ) ) {
err = GetLastError();
}
m_hShutdownEvent = NULL;
}
#else // CHICAGO
// Start ATQ main thread
// AtqMasterLoop();
//
// Update the service status.
//
err = UpdateServiceStatus( SERVICE_RUNNING,
NO_ERROR,
0,
0 );
if( err != NO_ERROR )
{
DBGPRINTF( ( DBG_CONTEXT, "cannot update service status, error %lu\n",
err )
);
goto Cleanup;
}
return TRUE;
#endif // CHICAGO
Cleanup:
if ( fInitCalled) {
//
// Cleanup partially initialized modules
//
DWORD err1 = ( *m_pfnCleanup)( this);
if ( err1 != NO_ERROR) {
//
// Compound errors possible
//
if ( err != NO_ERROR) {
DBGPRINTF( ( DBG_CONTEXT,
" Error %d occured during cleanup of service %s\n",
err1, QueryServiceName()));
}
}
}
TsRemoveVirtualRoots( GetTsvcCache() );
TerminateNTSecurity();
TerminateCommonParams();
TerminateIPSecurity();
TerminateLogging();
//
// If we managed to actually connect to the Service Controller,
// then tell it that we're stopped.
//
if( m_hsvcStatus != NULL_SERVICE_STATUS_HANDLE )
{
UpdateServiceStatus( SERVICE_STOPPED,
err,
0,
0 );
}
return ( err);
} // TSVC_INFO::StartServiceOperation()
DWORD
TSVC_INFO::UpdateServiceStatus(
IN DWORD dwState,
IN DWORD dwWin32ExitCode,
IN DWORD dwCheckPoint,
IN DWORD dwWaitHint )
/*++
Description:
Updates the local copy status of service controller status
and reports it to the service controller.
Arguments:
dwState - New service state.
dwWin32ExitCode - Service exit code.
dwCheckPoint - Check point for lengthy state transitions.
dwWaitHint - Wait hint for lengthy state transitions.
Returns:
NO_ERROR on success and returns Win32 error if failure.
On success the status is reported to service controller.
--*/
{
m_svcStatus.dwCurrentState = dwState;
m_svcStatus.dwWin32ExitCode = dwWin32ExitCode;
m_svcStatus.dwCheckPoint = dwCheckPoint;
m_svcStatus.dwWaitHint = dwWaitHint;
if ( !g_fIgnoreSC ) {
return ReportServiceStatus();
} else {
return ( NO_ERROR);
}
} // TSVC_INFO::UpdateServiceStatus()
DWORD
TSVC_INFO::ReportServiceStatus( VOID)
/*++
Description:
Wraps the call to SetServiceStatus() function.
Prints the service status data if need be
Arguments:
None
Returns:
NO_ERROR if successful. other Win32 error code on failure.
If successfull the new status has been reported to the service
controller.
--*/
{
DWORD err = NO_ERROR;
IF_DEBUG( DLL_SERVICE_INFO) {
DBGPRINTF(( DBG_CONTEXT, "dwServiceType = %08lX\n",
m_svcStatus.dwServiceType ));
DBGPRINTF(( DBG_CONTEXT, "dwCurrentState = %08lX\n",
m_svcStatus.dwCurrentState ));
DBGPRINTF(( DBG_CONTEXT, "dwControlsAccepted = %08lX\n",
m_svcStatus.dwControlsAccepted ));
DBGPRINTF(( DBG_CONTEXT, "dwWin32ExitCode = %08lX\n",
m_svcStatus.dwWin32ExitCode ));
DBGPRINTF(( DBG_CONTEXT, "dwServiceSpecificExitCode = %08lX\n",
m_svcStatus.dwServiceSpecificExitCode ));
DBGPRINTF(( DBG_CONTEXT, "dwCheckPoint = %08lX\n",
m_svcStatus.dwCheckPoint ));
DBGPRINTF(( DBG_CONTEXT, "dwWaitHint = %08lX\n",
m_svcStatus.dwWaitHint ));
}
if ( !g_fIgnoreSC ) {
DBGPRINTF(( DBG_CONTEXT,
" Setting Service Status for %s to %d\n",
QueryServiceName(), m_svcStatus.dwCurrentState)
);
if( !SetServiceStatus( m_hsvcStatus, &m_svcStatus ) ) {
err = GetLastError();
}
} else {
err = NO_ERROR;
}
return err;
} // TSVC_INFO::ReportServiceStatus()
VOID
TSVC_INFO::ServiceCtrlHandler ( IN DWORD dwOpCode)
/*++
Description:
This function received control requests from the service controller.
It runs in the context of service controller's dispatcher thread and
performs the requested function.
( Note: Avoid time consuming operations in this function.)
Arguments:
dwOpCode
indicates the requested operation. This should be
one of the SERVICE_CONTROL_* manifests.
Returns:
None. If successful, then the state of the service might be changed.
Note:
if an operation ( especially SERVICE_CONTROL_STOP) is very lengthy,
then this routine should report a STOP_PENDING status and create
a worker thread to do the dirty work. The worker thread would then
perform the necessary work and for reporting timely wait hints and
final SERVICE_STOPPED status.
History:
KeithMo 07-March-1993 Created
MuraliK 15-Nov-1994 Generalized it for all services.
--*/
{
//
// Interpret the opcode.
//
switch( dwOpCode )
{
case SERVICE_CONTROL_INTERROGATE :
InterrogateService();
break;
case SERVICE_CONTROL_STOP :
StopService();
break;
case SERVICE_CONTROL_PAUSE :
PauseService();
break;
case SERVICE_CONTROL_CONTINUE :
ContinueService();
break;
case SERVICE_CONTROL_SHUTDOWN :
ShutdownService();
break;
default :
DBGPRINTF(( DBG_CONTEXT, "Unrecognized Service Opcode %lu\n",
dwOpCode ));
break;
}
//
// Report the current service status back to the Service
// Controller. The workers called to implement the OpCodes
// should set the m_svcStatus.dwCurrentState field if
// the service status changed.
//
ReportServiceStatus();
} // TSVC_INFO::ServiceCtrlHandler()
VOID
TSVC_INFO::InterrogateService( VOID )
/*++
Description:
This function interrogates with the service status.
Actually, nothing needs to be done here; the
status is always updated after a service control.
We have this function here to provide useful
debug info.
HISTORY:
KeithMo 07-Mar-1993 Created.
MuraliK 15-Nov-1994 Ported to Tcpsvcs.dll
--*/
{
IF_DEBUG( DLL_SERVICE_INFO) {
DBGPRINTF(( DBG_CONTEXT, "Interrogating service status for %s\n",
QueryServiceName())
);
}
return;
} // TSVC_INFO::InterrogateService()
VOID
TSVC_INFO::StopService( VOID )
/*++
Description:
Stops the service. If the stop cannot be performed in a
timely manner, a worker thread needs to be created to do the
original cleanup work.
Returns:
None. If successful, then the service will be stopped.
The final action of this function is signal the handle for
shutdown event. This will release the main thread which does
necessary cleanup work.
--*/
{
IF_DEBUG( DLL_SERVICE_INFO) {
DBGPRINTF(( DBG_CONTEXT,
"stopping service %s\n",
QueryServiceName())
);
}
m_svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
m_svcStatus.dwCheckPoint = 0;
DBG_REQUIRE( SetEvent( m_hShutdownEvent ));
return;
} // TSVC_INFO::StopService()
VOID
TSVC_INFO::PauseService( VOID )
/*++
Description:
This function pauses the service. When the service is paused,
no new user sessions are to be accepted, but existing connections
are not effected.
This function must update the SERVICE_STATUS::dwCurrentState
field before returning.
Returns:
None. If successful the service is paused.
--*/
{
IF_DEBUG( DLL_SERVICE_INFO) {
DBGPRINTF(( DBG_CONTEXT, "pausing service %s\n",
QueryServiceName())
);
}
m_svcStatus.dwCurrentState = SERVICE_PAUSED;
return;
} // TSVC_INFO::PauseService()
VOID
TSVC_INFO::ContinueService( VOID )
/*++
Description:
This function restarts ( continues) a paused service. This
will return the service to the running state.
This function must update the m_svcStatus.dwCurrentState
field to running mode before returning.
Returns:
None. If successful then the service is running.
--*/
{
IF_DEBUG( DLL_SERVICE_INFO) {
DBGPRINTF(( DBG_CONTEXT, "continuing service %s\n",
QueryServiceName())
);
}
m_svcStatus.dwCurrentState = SERVICE_RUNNING;
return;
} // TSVC_INFO::ContinueService()
VOID
TSVC_INFO::ShutdownService( VOID )
/*++
Description:
This function performs the shutdown on a service.
This is called during system shutdown.
This function is time constrained. The service controller gives a
maximum of 20 seconds for shutdown for all active services.
Only timely operations should be performed in this function.
Returns:
None. If successful, the service is shutdown.
--*/
{
IF_DEBUG( DLL_SERVICE_INFO) {
DBGPRINTF(( DBG_CONTEXT, "shutting down service %s\n",
QueryServiceName())
);
}
m_svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
m_svcStatus.dwCheckPoint = 0;
#ifndef CHICAGO
DBG_REQUIRE( SetEvent( m_hShutdownEvent ));
#else
//
// Stop time. Tell the Service Controller that we're stopping,
// then terminate the various service components.
//
//
// Stop time. Tell the Service Controller that we're stopping,
// then terminate the various service components.
//
UpdateServiceStatus( SERVICE_STOP_PENDING,
0,
1,
SERVICE_STOP_WAIT_HINT );
DWORD err = ( *m_pfnCleanup)( this);
TsRemoveVirtualRoots( GetTsvcCache() );
TerminateNTSecurity();
TerminateCommonParams();
TerminateIPSecurity();
TerminateLogging();
UpdateServiceStatus( SERVICE_STOPPED,
err,
0,
0 );
#endif // CHICAGO
return;
} // TSVC_INFO::ShutdownService()
BOOL
TSVC_INFO::InitializeConnections(
IN PFN_CONNECT_CALLBACK pfnConnect,
IN ATQ_COMPLETION pfnConnectEx,
IN ATQ_COMPLETION pfnIOCompletion,
IN USHORT AdditionalPort,
IN DWORD cbAcceptExReceiveBuffer,
IN const CHAR * pszServiceDBName OPTIONAL
)
/*++
This function initializes the TS_XPORT_CONNECTIONS object and starts off
the connection thread. There is one connection object per protocol.
Each connection object maintains a listening socket bound to the protcol
for which the object was created. Each object also has its own
connection thread that awaits for accepting and dispatching new
connections.
This function queries using RNR API to find what protocols need to be
supported for a given service. Then it creates Connection objects and
creates listen socket, and starts off the connection thread.
Arguments:
pfnConnect pointer to function used as call back when a new connection
is established. Used only if AcceptEx is not available.
pfnConnectEx - Used if AcceptEx is available
pfnIOCompletion - IO Completion routine to use, only used if AcceptEx
is available.
AdditionalPort - Allows listenning on an additional TCP port (like the
SSL port for example). Specify as zero to not listen on any
additional ports.
cbAcceptExReceiveBuffer - count of bytes of data to be allocated for
receive buffer for use with AcceptEx.
pszServiceDBName - The optional name to look up in the etc\services file
that will override the port in the RNR stuff
Returns:
TRUE on successfully establishing connections.
FALSE if there is any failure in establishing the connections.
If there is any error in starting the connections, or if only a partial
list of protocol connections are established or threads started,
this function returns FALSE. No cleanup of partial information is done.
The caller should call CleanupConnections to clean the state of the
object.
--*/
{
BOOL fReturn = FALSE;
//
// We fix the size of the array. This can be a problem for scalability!
//
CSADDR_INFO rgcsAddrInfo[ MAX_ADDRESSES_SUPPORTED];
DWORD cbAddrInfo;
LPCTSTR pszServiceName = QueryServiceName();
int nAddresses;
GUID guidService;
HKEY hkey;
struct sockaddr_in sockaddrLocal;
struct sockaddr_in sockaddrRemote;
#ifndef CHICAGO
//
// Obtain the GUID for the service before proceeding
//
//
// NOTE: Type casting is done to char *, since the RNR APIs
// dont like constants ! :(
//
if ( GetTypeByName( (LPTSTR) pszServiceName, &guidService ) != 0) {
DBG_CODE(
DWORD dwError = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
" GetTypeByName failed, error %u\n",
dwError));
SetLastError( dwError);
);
return (FALSE);
}
cbAddrInfo = sizeof( rgcsAddrInfo);
nAddresses = GetValidListenAddresses(pszServiceName,
&guidService,
rgcsAddrInfo,
&cbAddrInfo );
IF_DEBUG( DLL_CONNECTION) {
DBGPRINTF( ( DBG_CONTEXT,
" GetValidListenAddresses( %s, %08x, %08x)"
" returns nProtocols = %d; cbAddrInfo = %d\n",
pszServiceName,
rgcsAddrInfo,
&cbAddrInfo,
nAddresses,
cbAddrInfo));
}
#else
nAddresses = 0;
//
// We don't have RnR APIs on Windows9x yet, not clear when we will
// have. For test purposes fill out address structures manually with
// hard coded constants for HTTP port information
//
{
rgcsAddrInfo[nAddresses].iProtocol = IPPROTO_TCP;
rgcsAddrInfo[nAddresses].iSocketType = SOCK_STREAM;
rgcsAddrInfo[nAddresses].LocalAddr.lpSockaddr =
(struct sockaddr *) &sockaddrLocal;
rgcsAddrInfo[nAddresses].LocalAddr.iSockaddrLength =
sizeof(sockaddrLocal);
memset( &sockaddrLocal, 0, sizeof(sockaddrLocal));
sockaddrLocal.sin_family = AF_INET;
sockaddrLocal.sin_port = htons( 80 );
rgcsAddrInfo[nAddresses].RemoteAddr.lpSockaddr =
(struct sockaddr *) &sockaddrRemote;
rgcsAddrInfo[nAddresses].RemoteAddr.iSockaddrLength =
sizeof(sockaddrRemote);
memset( &sockaddrRemote, 0, sizeof(sockaddrRemote));
sockaddrRemote.sin_family = AF_INET;
sockaddrRemote.sin_port = 0;
nAddresses++;
}
#endif
//
// Check to see if we need to override the RNR port number with the
// etc\services port number. Note we only do this for TCP currently
//
if ( pszServiceDBName )
{
int i;
LPSERVENT pservent;
for ( i = 0; i < nAddresses; i++ )
{
struct sockaddr_in * psockaddr =
(struct sockaddr_in *) rgcsAddrInfo[i].LocalAddr.lpSockaddr;
if ( rgcsAddrInfo[i].iProtocol == IPPROTO_TCP &&
rgcsAddrInfo[i].iSocketType == SOCK_STREAM &&
psockaddr->sin_family == AF_INET )
{
pservent = getservbyname( pszServiceDBName, "tcp" );
if ( !pservent )
{
DBGPRINTF(( DBG_CONTEXT,
" getservbyname failed, error %d\n",
GetLastError() ));
break;
}
psockaddr->sin_port = pservent->s_port;
break;
}
}
}
//
// If we've been supplied an SSL port, add the additional address to
// the end of the list
//
if ( AdditionalPort != 0 &&
nAddresses > 0 && nAddresses < (MAX_ADDRESSES_SUPPORTED - 1) )
{
//
// Append the specified additional port to listen on
//
rgcsAddrInfo[nAddresses].iProtocol = IPPROTO_TCP;
rgcsAddrInfo[nAddresses].iSocketType = SOCK_STREAM;
rgcsAddrInfo[nAddresses].LocalAddr.lpSockaddr =
(struct sockaddr *) &sockaddrLocal;
rgcsAddrInfo[nAddresses].LocalAddr.iSockaddrLength =
sizeof(sockaddrLocal);
memset( &sockaddrLocal, 0, sizeof(sockaddrLocal));
sockaddrLocal.sin_family = AF_INET;
sockaddrLocal.sin_port = htons( AdditionalPort );
rgcsAddrInfo[nAddresses].RemoteAddr.lpSockaddr =
(struct sockaddr *) &sockaddrRemote;
rgcsAddrInfo[nAddresses].RemoteAddr.iSockaddrLength =
sizeof(sockaddrRemote);
memset( &sockaddrRemote, 0, sizeof(sockaddrRemote));
sockaddrRemote.sin_family = AF_INET;
sockaddrRemote.sin_port = 0;
nAddresses++;
}
if ( nAddresses > 0) {
DWORD nConnEstablished = 0;
DWORD nThreads = 0;
DWORD nListenBacklog = CP_DEFAULT_MAX_BACKLOG_ENTRIES;
SOCKET rgSockets[MAX_ADDRESSES_SUPPORTED];
DWORD nListenSockets = MAX_ADDRESSES_SUPPORTED;
HINSTANCE hWsock32;
BOOL fUseAcceptEx;
//
// Use AcceptEx for listen processing if the entry point is available
// in the local winsock
//
#ifndef CHICAGO
fUseAcceptEx = AtqGetInfo( AtqUseAcceptEx );
#else
fUseAcceptEx = FALSE;
#endif
//
// Get the listen backlog parameter, supply the default if the
// key or value doesn't exist
//
if ( !RegOpenKeyEx( HKEY_LOCAL_MACHINE,
INET_INFO_PARAMETERS_KEY,
0,
KEY_READ,
&hkey )) {
nListenBacklog = ReadRegistryDword( hkey,
LISTEN_BACKLOG_A,
CP_DEFAULT_MAX_BACKLOG_ENTRIES);
RegCloseKey( hkey );
}
fReturn =( m_tsConnections.
EstablishListenConnections(pszServiceName,
rgcsAddrInfo,
nAddresses,
&nConnEstablished,
nListenBacklog,
fUseAcceptEx )
&& (nConnEstablished <= MAX_ADDRESSES_SUPPORTED)
&& m_tsConnections.GetListenSockets(rgSockets,
&nListenSockets)
&& ( nConnEstablished == nListenSockets)
&& RegisterServiceForAdvertising( pszServiceName,
&guidService,
rgSockets,
nConnEstablished)
);
IF_DEBUG( DLL_CONNECTION) {
DBGPRINTF( ( DBG_CONTEXT,
" EstablishListenSockets or"
" RegisterServiceForAdvertising"
" for Service %s returns %d."
" Number of Connections established = %d\n",
pszServiceName, fReturn,
nConnEstablished));
}
DBG_ASSERT( pfnConnect != NULL);
fReturn = ( fReturn &&
m_tsConnections.StartListenPumps( pfnConnect,
pfnConnectEx,
pfnIOCompletion,
cbAcceptExReceiveBuffer,
QueryRegParamKey(),
&nThreads)
);
IF_DEBUG( DLL_CONNECTION) {
DBGPRINTF( ( DBG_CONTEXT,
" StartListenPumps( %08x) returns %d."
" Number of Threads = %d\n",
pfnConnect, fReturn,
nThreads));
}
}
DBG_CODE(m_tsConnections.Print());
return ( fReturn);
} // TSVC_INFO::InitializeConnections()
BOOL
TSVC_INFO::CleanupConnections( VOID)
/*++
Description:
This function cleans up the active connection threads. It notifies
the connection thread to stop and then it cleans up the connection
objects ( freeing memory used up).
Returns:
TRUE on success and FALSE if there is any failure.
Use GetLastError() to obtain detailed error code.
--*/
{
IF_DEBUG( DLL_CONNECTION) {
DBGPRINTF( ( DBG_CONTEXT,
" Cleaning up %d connections \n",
m_tsConnections.QueryNumTransports())
);
}
return ( m_tsConnections.StopListenPumps() &&
m_tsConnections.Cleanup());
} // TSVC_INFO::CleanupConnections()
# define MAX_SOCKETS ( 20)
inline BOOL IsConnectionOriented( IN PPROTOCOL_INFO pProtocolInfo)
{
return ( ( pProtocolInfo->dwServiceFlags & XP_CONNECTIONLESS) == 0);
} // IsConnectionOriented()
inline BOOL IsReliable( IN PPROTOCOL_INFO pProtocolInfo)
/*++
This should be a protocol which delivers all packets and in order in which
they are sent.
--*/
{
return ( ( pProtocolInfo->dwServiceFlags & XP_GUARANTEED_DELIVERY) &&
( pProtocolInfo->dwServiceFlags & XP_GUARANTEED_ORDER) &&
IsConnectionOriented( pProtocolInfo));
} // IsReliable()
static int
GetValidListenAddresses( IN LPCTSTR pszServiceName,
IN LPGUID lpServiceGuid,
IN PCSADDR_INFO pcsAddrInfo,
IN OUT LPDWORD lpcbAddrInfo )
/*++
This function obtains the list of valid listen addresses for the service
specified. It uses the RNR API set to enumerate the list of protocols
installed in a machine and queries using GetAddressByName() to obtain
the list of valid addresses that can be used for establishing a listen
socket.
Arguments:
pszServiceName pointer to null-terminated string containing service name.
lpServiceGuid pointer to GUID for the service.
pcsAddrInfo pointer to an array of CSADDR_INFO structures which
on successful return contains the address information.
lpcbAddInfo pointer to a DWORD containing the count of bytes
available under pcsAddrInfo. When this function is
called, it contains the number of bytes pointed to by
pcsAddrInfo. On return contains the number of
bytes required.
Returns:
count of valid CSADDR_INFO structures found for the given service to
establish a listen socket.
On error returns a value <= 0.
--*/
{
int nAddresses = 0; // assume a safe value == failure.
DWORD cbBuffer;
int cProtocols;
PPROTOCOL_INFO pProtocolInfo;
int rgProtocols[ MAX_SOCKETS + 1];
int * pProtocol;
int i;
BUFFER buff;
#define ENUM_PROTO_BUFF_SIZE 49152
//
// First Look up the protocols installed on this machine. The
// EnumProtocols() API returns about all the windows sockets protocols
// loaded on this machine. We will use this information to identify the
// protocols which provide the necessary semantics.
//
if ( !buff.Resize( ENUM_PROTO_BUFF_SIZE )) {
return 0;
}
cbBuffer = buff.QuerySize();
cProtocols = EnumProtocols( NULL, buff.QueryPtr(), &cbBuffer);
if ( cProtocols < 0) {
return 0;
}
//
// Walk through the available protocols and pick out the ones that
// support the desired characteristics.
//
for( pProtocolInfo = (PPROTOCOL_INFO ) buff.QueryPtr(),
pProtocol = rgProtocols,
i = 0;
( i < cProtocols &&
( pProtocol < rgProtocols + MAX_SOCKETS));
pProtocolInfo++, i++ ) {
if ( IsReliable( pProtocolInfo)) {
//
// This protocol matches our requirement of being reliable.
// Make a note of the protocol.
//
IF_DEBUG( DLL_SERVICE_INFO) {
DBGPRINTF( ( DBG_CONTEXT,
" Protocol %d ( %s) matches condition\n",
pProtocolInfo->iProtocol,
pProtocolInfo->lpProtocol));
}
*pProtocol++ = pProtocolInfo->iProtocol;
}
} // for() : Protocol filter ()
IF_DEBUG( DLL_SERVICE_INFO) {
DBGPRINTF( ( DBG_CONTEXT, " Filtering yields %d of %d protocols. \n",
( pProtocol - rgProtocols), cProtocols));
}
// terminate the protocols array.
*pProtocol = 0;
cProtocols = ( pProtocol - rgProtocols);
//
// Make sure we found at least one acceptable protocol.
// If there is no protocol on this machine, which suit our condition,
// this function fails.
//
if ( cProtocols > 0) {
//
// Use GetAddressByName() to get addresses for chosen protocols.
// We restrict the scope of the search to those protocols of interest
// by passing the protocols array we generated. The function
// returns socket addresses only for the protocols we can support.
//
nAddresses = GetAddressByName(
NS_DEFAULT, // lpszNameSpace
lpServiceGuid,
(char *) pszServiceName,
rgProtocols,
RES_SERVICE | RES_FIND_MULTIPLE,
NULL, // lpServiceAsyncInfo
(PVOID )pcsAddrInfo,
lpcbAddrInfo,
NULL, // lpAliasBuffer
NULL // lpdwAliasBufferLen
);
IF_DEBUG( DLL_SERVICE_INFO) {
// take a copy of error code and set it back, to avoid lost errors
DWORD dwError = GetLastError();
DBGPRINTF( ( DBG_CONTEXT,
" GetAddressByName() returned %d."
" Bytes Written=%d. Error = %ld\n",
nAddresses, *lpcbAddrInfo,
( nAddresses <= 0) ? dwError: NO_ERROR));
if ( nAddresses <= 0) { SetLastError( dwError); }
}
}
return ( nAddresses);
} // GetValidListenAddress()
static BOOL
RegisterServiceForAdvertising(
IN LPCTSTR pszServiceName,
IN LPGUID lpServiceGuid,
IN SOCKET *pSockets,
IN DWORD nSockets)
/*++
This function registers a service for the purpose of advertising.
By registering using RnR apis, we advertise the fact that this particular
service is running on the protocols designated. Hence RnR compliant
clients can get access to the same.
Arguments:
pszService name of the service
lpServiceGuid pointer to GUID for the service.
pSockets pointer to an array of sockets whose address needs to be
advertised.
nSockets number of sockets in the array.
Returns:
TRUE on success and FALSE if there is any failure.
Use GetLastError() for further details on failure.
--*/
{
BOOL fReturn = TRUE;
BYTE * pbAddressBuffer;
DWORD cbAddressBuffer;
DWORD nSuccessCount = 0;
INT err;
SERVICE_INFO serviceInfo;
SERVICE_ADDRESSES * pServiceAddress;
DBG_ASSERT( pszServiceName && lpServiceGuid && pSockets);
/*++
Advertising service involves following steps:
1. Set up a service info structure.
2. Allocate memory for service addresses for as many sockets need to
be advertised.
3. Fill in the information containing the socket addresses
4. Execute call for advertising the service (use SetService( REGISTER)).
--*/
//
// Alloc space for SERVICE_ADDRESSES and n-1 SERVICE_ADDRESS structures.
//
pServiceAddress = ( ( SERVICE_ADDRESSES *)
TCP_ALLOC( sizeof( SERVICE_ADDRESSES) +
(nSockets -1)*sizeof(SERVICE_ADDRESS)
)
);
// Alloc space for SOCKADDR addresses returned.
cbAddressBuffer = nSockets * sizeof(SOCKADDR);
pbAddressBuffer = (BYTE *) TCP_ALLOC(cbAddressBuffer);
if ( pServiceAddress == NULL || pbAddressBuffer == NULL) {
if ( pServiceAddress != NULL) { TCP_FREE( pServiceAddress); }
if ( pbAddressBuffer != NULL) { TCP_FREE( pbAddressBuffer); }
SetLastError( ERROR_NOT_ENOUGH_MEMORY);
return (FALSE);
}
//
// set up service info structure.
// Here the interesting fields are lpServiceType, lpServiceName,
// and lpServiceAddress fields.
//
serviceInfo.lpServiceType = lpServiceGuid ;
// surprisingly enough! RNR structures dont like constants
serviceInfo.lpServiceName = (LPTSTR ) pszServiceName ;
// do we need better comment ? NYI
serviceInfo.lpComment = "Microsoft Internet Services";
serviceInfo.lpLocale = NULL;
serviceInfo.lpMachineName = NULL ;
serviceInfo.dwVersion = 1;
serviceInfo.dwDisplayHint = 0;
serviceInfo.dwTime = 0;
serviceInfo.lpServiceAddress = pServiceAddress;
serviceInfo.ServiceSpecificInfo.cbSize = 0 ;
serviceInfo.ServiceSpecificInfo.pBlobData = NULL ;
//
// For each socket, get its local association and store the same.
//
PSOCKADDR pSockAddr = (PSOCKADDR ) pbAddressBuffer;
for (DWORD i = 0; i < nSockets; i++)
{
int size = (int) cbAddressBuffer;
//
// Call getsockname() to get the local association for the socket.
//
if ( (err = getsockname( pSockets[i], pSockAddr, &size))
== SOCKET_ERROR) {
continue ;
}
//
// Now setup the Addressing information for this socket.
// Only the dwAddressType, dwAddressLength and lpAddress
// is of any interest in this example.
//
pServiceAddress->Addresses[i].dwAddressType = pSockAddr->sa_family;
pServiceAddress->Addresses[i].dwAddressFlags = 0;
pServiceAddress->Addresses[i].dwAddressLength = size ;
pServiceAddress->Addresses[i].dwPrincipalLength= 0 ;
pServiceAddress->Addresses[i].lpAddress = (LPBYTE) pSockAddr;
pServiceAddress->Addresses[i].lpPrincipal = NULL ;
//
// Advance pointer and adjust buffer size. Assumes that
// the structures are aligned. Unaligned accesses !! NYI
//
cbAddressBuffer -= size;
pSockAddr = (PSOCKADDR) ((BYTE*)pSockAddr + size);
nSuccessCount++ ;
}
pServiceAddress->dwAddressCount = nSuccessCount;
//
// If we got at least one address, go ahead and advertise it.
//
if (nSuccessCount > 0) {
DWORD dwStatusFlags;
err = SetService(
NS_DEFAULT, // for all default name spaces
SERVICE_REGISTER, // we want to register (advertise)
0, // no flags specified
&serviceInfo, // SERVICE_INFO structure
NULL, // no async support yet
&dwStatusFlags) ; // returns status flags
IF_DEBUG( DLL_CONNECTION ) {
DBGPRINTF(( DBG_CONTEXT, " SetService(%s, NS_DEFAULT, Register)"
" nAddresses = %d/%d, returns Status = %08x,"
" err = %d\n",
pszServiceName, nSuccessCount, nSockets,
dwStatusFlags, err));
}
} else {
SetLastError( ERROR_INVALID_PARAMETER);
fReturn = FALSE;
}
TCP_FREE( pbAddressBuffer);
TCP_FREE( pServiceAddress);
return ( fReturn);
} // RegisterServiceForAdvertising()
DWORD
TSVC_INFO::InitializeSockets( VOID )
/*++
Initializes Socket access.
It is responsible for connecting to WinSock.
Returns:
NO_ERROR on success
Otherwise returns a Win32 error code.
Limitations:
This is for a single thread and not mult-thread safe.
This function should be called after initializing globals.
--*/
{
DWORD dwError = NO_ERROR;
WSADATA wsaData;
INT serr;
//
// Connect to WinSock
//
serr = WSAStartup( MAKEWORD( 1, 1), & wsaData);
if( serr != 0 ) {
SetServiceSpecificExitCode( ( DWORD) serr);
dwError = ( ERROR_SERVICE_SPECIFIC_ERROR);
}
m_fSocketsInitialized = ( dwError == NO_ERROR) ? 1: 0;
return ( dwError);
} // TSVC_INFO::InitializeSockets()
DWORD
TSVC_INFO::CleanupSockets( VOID)
/*++
Cleansup the static information of sockets
Returns:
0 if no errors,
non-zero error code for any socket errors
Limitations:
This is for a single thread and not mult-thread safe.
This function should be called after initializing globals.
Note:
This function should be called after shutting down all
active socket connections.
--*/
{
DWORD dwError = NO_ERROR;
if ( m_fSocketsInitialized ) {
INT serr = WSACleanup();
if ( serr != 0) {
SetServiceSpecificExitCode( ( DWORD) serr);
dwError = ( ERROR_SERVICE_SPECIFIC_ERROR);
}
}
m_fSocketsInitialized = ( dwError == NO_ERROR) ? 1 : 0;
return (dwError);
} // TSVC_INFO::CleanupSockets()
BOOL
TSVC_INFO::GetConfiguration( IN OUT PVOID pConfig)
/*++
This function copies the current configuration for a service (TSVC_INFO)
into the given RPC object pConfig.
In case of any failures, it deallocates any memory block that was
allocated during the process of copy by this function alone.
Arguments:
pConfig - pointer to RPC configuration object for a service.
Returns:
TRUE for success and FALSE for any errors.
--*/
{
BOOL fReturn;
LPINET_INFO_CONFIG_INFO pInfoConfig;
fReturn = ISVC_INFO::GetConfiguration( pConfig);
if ( !fReturn) {
return ( FALSE);
}
pInfoConfig = (LPINET_INFO_CONFIG_INFO) pConfig;
LockThisForRead();
//
// Get always retrieves all of the parameters except for the anonymous
// password, which is retrieved as a secret
//
pInfoConfig->FieldControl |=
(FC_INET_INFO_PUBLISHING_SVCS_ALL & ~FC_INET_INFO_ANON_PASSWORD);
pInfoConfig->fLogAnonymous = QueryLogAnonymous();
pInfoConfig->fLogNonAnonymous = QueryLogNonAnonymous();
pInfoConfig->dwAuthentication = QueryAuthentication();
pInfoConfig->sPort = QueryPort();
memset( pInfoConfig->szAnonPassword,
0,
sizeof( pInfoConfig->szAnonPassword ));
//
// Copy the IP security info
//
if ( !m_ipaDenyList.IsEmpty() )
{
pInfoConfig->DenyIPList =
(LPINET_INFO_IP_SEC_LIST)
MIDL_user_allocate( m_ipaDenyList.QueryIPListSize());
if ( !pInfoConfig->DenyIPList )
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
fReturn = FALSE;
goto Exit;
}
m_ipaDenyList.CopyIPList( pInfoConfig->DenyIPList);
}
else
{
pInfoConfig->DenyIPList = NULL;
}
if ( !m_ipaGrantList.IsEmpty() )
{
pInfoConfig->GrantIPList =
(LPINET_INFO_IP_SEC_LIST)
MIDL_user_allocate( m_ipaGrantList.QueryIPListSize());
if ( !pInfoConfig->GrantIPList )
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
fReturn = FALSE;
goto Exit;
}
m_ipaGrantList.CopyIPList( pInfoConfig->GrantIPList);
}
else
{
pInfoConfig->GrantIPList = NULL;
}
//
// Copy the virtual root info, note a NULL VirtualRoots is not
// valid as it is for IP security. This should be the last
// allocated item for the pConfig structure
//
pInfoConfig->VirtualRoots = TsGetRPCVirtualRoots( GetTsvcCache() );
//
// Copy the strings
//
if ( !pInfoConfig->VirtualRoots ||
!ConvertStringToRpc(&pInfoConfig->lpszAnonUserName,
QueryAnonUserName())
) {
fReturn = FALSE;
}
Exit:
if ( !fReturn ) {
if ( pInfoConfig->DenyIPList ) {
MIDL_user_free( pInfoConfig->DenyIPList );
pInfoConfig->DenyIPList = NULL;
}
if ( pInfoConfig->GrantIPList ) {
MIDL_user_free( pInfoConfig->GrantIPList );
pInfoConfig->GrantIPList = NULL;
}
//
// FreeRpcString checks for NULL pointer
//
FreeRpcString( pInfoConfig->lpszAnonUserName );
// JohnL wrote the code for Virtual roots and it is not freed on
// errors. NYI.
}
UnlockThis();
return (fReturn);
} // TSVC_INFO::GetConfiguration()
BOOL
TSVC_INFO::ReadParamsFromRegistry(
IN FIELD_CONTROL fc
)
/*++
Description
Reads the service common items from the registry
Arguments:
fc - Items to read
Note:
--*/
{
BOOL fRet;
DWORD err;
HKEY hkey = NULL;
IF_DEBUG( DLL_RPC) {
DBGPRINTF(( DBG_CONTEXT,
"TSVC_INFO::ReadParamsFromRegistry() Entered\n"));
}
// Complete reading parameters for ISVC_INFO object first.
fRet = ISVC_INFO::ReadParamsFromRegistry(fc);
if ( !fRet) {
IF_DEBUG( DLL_RPC) {
err = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
" TSVC_INFO::ReadParamsFromRegistry() ==> Error =%u\n",
err));
SetLastError( err);
}
}
// Open registry and read parameters for TSVC_INFO object itself.
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
QueryRegParamKey(),
0,
KEY_ALL_ACCESS,
&hkey );
if ( err )
{
DBGPRINTF(( DBG_CONTEXT,
"[ReadParamsFromRegistry] RegOpenKeyEx returned error %d\n",
err ));
SetLastError( err );
return FALSE;
}
LockThisForWrite();
//
// Read the specified values from the registry
//
if ( IsFieldSet( fc, FC_INET_INFO_LOG_ANONYMOUS ))
{
m_fLogAnonymous = ReadRegistryDword( hkey,
INETA_LOG_ANONYMOUS,
INETA_DEF_LOG_ANONYMOUS );
}
if ( IsFieldSet( fc, FC_INET_INFO_LOG_NONANONYMOUS ))
{
m_fLogNonAnonymous = ReadRegistryDword( hkey,
INETA_LOG_NONANONYMOUS,
INETA_DEF_LOG_NONANONYMOUS );
}
if ( IsFieldSet( fc, FC_INET_INFO_AUTHENTICATION ))
{
m_dwAuthentication = ReadRegistryDword( hkey,
INETA_AUTHENTICATION,
INETA_DEF_AUTHENTICATION );
}
if ( IsFieldSet( fc, FC_INET_INFO_PORT_NUMBER ))
{
CHAR achServProvKey[MAX_PATH+1];
HKEY hkeyServProv;
short port;
//
// Get the port directly out of the RNR service provider key
//
strcpy( achServProvKey, WINSOCK_SERV_PROV_KEY );
strcat( achServProvKey, QueryServiceName() );
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
achServProvKey,
0,
KEY_ALL_ACCESS,
&hkeyServProv );
if ( err )
{
DBGPRINTF(( DBG_CONTEXT,
"[ReadParamsFromRegistry()] RegOpenKeyEx for"
" service provider key returned %d\n",
err ));
SetLastError( err );
goto Exit;
}
port = (USHORT) ReadRegistryDword( hkeyServProv,
"TcpPort",
0 );
RegCloseKey( hkeyServProv );
m_sPort = port;
}
//
// String fields
//
if ( fRet && IsFieldSet( fc, FC_INET_INFO_ANON_USER_NAME ))
{
fRet = ReadRegString( hkey,
&m_pchAnonUserName,
INETA_ANON_USER_NAME,
INETA_DEF_ANON_USER_NAME);
}
//
// Always re-read the anonymous user password
//
if ( fRet )
{
fRet = TsGetAnonymousPassword( m_achAnonUserPwd,
this );
}
//
// Other fields
//
if ( fRet && IsFieldSet( fc, FC_INET_INFO_SITE_SECURITY ))
fRet = InitializeIPSecurity();
if ( fRet && IsFieldSet( fc, FC_INET_INFO_VIRTUAL_ROOTS ))
{
fRet = TsReadVirtualRoots( GetTsvcCache(),
hkey,
this );
}
// no UI for these settings : read them always
m_dwLogonMethod = ReadRegistryDword( hkey,
INETA_LOGON_METHOD,
INETA_DEF_LOGON_METHOD );
switch ( m_dwLogonMethod )
{
case INETA_LOGM_BATCH:
m_dwLogonMethod = LOGON32_LOGON_BATCH;
break;
case INETA_LOGM_NETWORK:
m_dwLogonMethod = LOGON32_LOGON_NETWORK;
break;
default:
case INETA_LOGM_INTERACTIVE:
m_dwLogonMethod = LOGON32_LOGON_INTERACTIVE;
break;
}
ReadRegString( hkey,
&m_pchDefaultLogonDomain,
INETA_DEFAULT_LOGON_DOMAIN,
INETA_DEF_DEFAULT_LOGON_DOMAIN );
Exit:
UnlockThis();
if ( hkey )
RegCloseKey( hkey );
if ( !fRet )
{
IF_DEBUG (ERROR) {
err = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
"[ReadParamsFromRegistry()] Leaving with Error = %d\n",
err));
SetLastError( err);
}
}
return fRet;
} // TSVC_INFO::ReadParamsFromRegistry()
VOID
TSVC_INFO::TerminateCommonParams(
VOID
)
{
//
// Just need to free the registry strings
//
if ( m_pchLogFileDirectory )
TCP_FREE( m_pchLogFileDirectory );
if ( m_pchLogFileName )
TCP_FREE( m_pchLogFileName );
if ( m_pchAnonUserName )
TCP_FREE( m_pchAnonUserName );
if ( m_pchDefaultLogonDomain )
TCP_FREE( m_pchDefaultLogonDomain );
} // TSVC_INFO::TerminateCommonParams();
BOOL
TSVC_INFO::SetConfiguration(
IN PVOID pConfig
)
/*++
Description
Writes the service common items to the registry
Arguments:
pConfig - Admin items to write to the registry
Note:
We don't need to lock "this" object because we only write to the registry
The anonymous password is set as a secret from the client side
--*/
{
BOOL fRet;
LPINET_INFO_CONFIG_INFO pInfoConfig;
FIELD_CONTROL fcConfig;
DWORD err;
HKEY hkey = NULL;
fRet = ISVC_INFO::SetConfiguration( pConfig);
if ( !fRet) {
IF_DEBUG( ERROR) {
err = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
"TSVC_INFO::SetConfiguration() failed."
" Error = %u\n",
err));
SetLastError( err);
}
return (FALSE);
}
pInfoConfig = (LPINET_INFO_CONFIG_INFO) pConfig;
fcConfig = pInfoConfig->FieldControl;
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
QueryRegParamKey(),
0,
KEY_ALL_ACCESS,
&hkey );
if ( err )
{
DBGPRINTF(( DBG_CONTEXT,
"[SetConfiguration()] RegOpenKeyEx returns error %d\n",
err ));
SetLastError( err );
return FALSE;
}
if ( !err && IsFieldSet( fcConfig, FC_INET_INFO_AUTHENTICATION ))
{
err = WriteRegistryDword( hkey,
INETA_AUTHENTICATION,
pInfoConfig->dwAuthentication );
}
if ( !err && IsFieldSet( fcConfig, FC_INET_INFO_PORT_NUMBER ))
{
CHAR achServProvKey[MAX_PATH+1];
HKEY hkeyServProv;
//
// Set the port directory in the RNR service provider key
//
strcpy( achServProvKey, WINSOCK_SERV_PROV_KEY );
strcat( achServProvKey, QueryServiceName() );
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
achServProvKey,
0,
KEY_ALL_ACCESS,
&hkeyServProv );
if ( !err )
{
err = WriteRegistryDword( hkeyServProv,
"TcpPort",
(USHORT) pInfoConfig->sPort);
RegCloseKey( hkeyServProv );
}
else
{
DBGPRINTF(( DBG_CONTEXT,
"[SetConfiguration()] RegOpenKeyEx for"
" service provider key returned %d\n",
err ));
}
}
//
// Write the strings
//
if ( !err && IsFieldSet( fcConfig, FC_INET_INFO_ANON_USER_NAME ))
{
err = RegSetValueExW( hkey,
INETA_ANON_USER_NAME_W,
0,
REG_SZ,
(BYTE *) pInfoConfig->lpszAnonUserName,
(wcslen( pInfoConfig->lpszAnonUserName ) + 1) *
sizeof( WCHAR ));
}
//
// Write other fields
//
if ( !err && IsFieldSet( fcConfig, FC_INET_INFO_SITE_SECURITY ))
{
if ( !SetIPSecurity( hkey,
pInfoConfig ))
{
DBGPRINTF(( DBG_CONTEXT,
"[SetConfiguration] SetIPSecurity returns"
" error %d\n",
GetLastError()));
err = GetLastError();
}
}
if ( !err && IsFieldSet( fcConfig, FC_INET_INFO_VIRTUAL_ROOTS ))
{
if ( !TsSetVirtualRootsW( GetTsvcCache(),
hkey,
pInfoConfig ))
{
err = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
"[SetConfiguration()]SetVirtualRoots "
" returns error %d\n",
err));
}
}
if ( hkey ) {
RegCloseKey( hkey );
}
if ( err ) {
IF_DEBUG( ERROR) {
DBGPRINTF(( DBG_CONTEXT,
"TSVC_INFO::SetConfiguration() ==> Error = %u\n",
err));
}
SetLastError( err );
fRet = FALSE;
}
return fRet;
} // TSVC_INFO::SetConfiguration()
# if DBG
VOID
TSVC_INFO::Print( VOID) const
{
ISVC_INFO::Print();
DBGPRINTF( ( DBG_CONTEXT,
" Printing TSVC_INFO object ( %08x) \n"
" Valid = %u. SocketsInitFlag = %u\n"
" ServiceStatusHandle = %08x. ShutDownEvent = %08x\n"
" MimeMap = %08x\n"
" InitFunction = %08x. CleanupFunction = %08x.\n"
,
this,
m_fValid, m_fSocketsInitialized,
m_hsvcStatus, m_hShutdownEvent,
m_pMimeMap
));
DBGPRINTF(( DBG_CONTEXT,
" Server Admin Params: \n"
" Authentication = %u. Port = %d.\n"
" Log Anon = %u. Log NonAnon = %u.\n"
" AnonUserName = %s.\n"
" Anon Password SecretName = %ws. VirtualRoots Secret = %ws\n"
,
m_dwAuthentication, m_sPort,
m_fLogAnonymous, m_fLogNonAnonymous,
m_pchAnonUserName,
m_pchAnonPasswordSecretName,
m_pchVirtualRootsSecretName
));
m_ipaGrantList.Print( "Grant List");
m_ipaDenyList.Print( "Deny List");
m_tsConnections.Print();
return;
} // TSVC_INFO::Print()
# endif // DBG
/************************ End of File ***********************/