1485 lines
34 KiB
C++
1485 lines
34 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
main.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This is the main routine for the Internet Services suite.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David Treadwell (davidtr) 7-27-93
|
|||
|
|
|||
|
Revision History:
|
|||
|
Murali Krishnan ( Muralik) 16-Nov-1994 Added Gopher service
|
|||
|
Murali Krishnan ( Muralik) 3-July-1995 Removed non-internet info + trims
|
|||
|
Sophia Chung (sophiac) 09-Oct-1995 Splitted internet services into
|
|||
|
access and info services
|
|||
|
Murali Krishnan ( Muralik) 20-Feb-1996 Enabled to run on NT Workstation
|
|||
|
Emily Kruglick ( EmilyK) 14-Jun-2000 Moved file from iis 5 tree to iis 6.
|
|||
|
Removed all Win95 support.
|
|||
|
Added support for WAS controlling W3SVC.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
//
|
|||
|
// INCLUDES
|
|||
|
//
|
|||
|
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#include <windows.h>
|
|||
|
#include <winsvc.h> // Service control APIs
|
|||
|
#include <rpc.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <inetsvcs.h>
|
|||
|
#include <iis64.h>
|
|||
|
#include "waslaunch.hxx"
|
|||
|
|
|||
|
#include "inetimsg.h"
|
|||
|
#include "iisadmin.hxx"
|
|||
|
#include <objbase.h>
|
|||
|
#include "regconst.h"
|
|||
|
|
|||
|
//
|
|||
|
// Modifications to this name should also be made in tsunami.hxx
|
|||
|
//
|
|||
|
|
|||
|
#define INETA_W3ONLY_NO_AUTH TEXT("W3OnlyNoAuth")
|
|||
|
|
|||
|
//
|
|||
|
// Functions used to start/stop the RPC server
|
|||
|
//
|
|||
|
|
|||
|
typedef DWORD ( *PFN_INETINFO_START_RPC_SERVER) ( VOID );
|
|||
|
typedef DWORD ( *PFN_INETINFO_STOP_RPC_SERVER) ( VOID );
|
|||
|
|
|||
|
//
|
|||
|
// Local function used by the above to load and invoke a service DLL.
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
InetinfoStartService (
|
|||
|
IN DWORD argc,
|
|||
|
IN LPSTR argv[]
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
StartDispatchTable(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Functions used to preload dlls into the inetinfo process
|
|||
|
//
|
|||
|
|
|||
|
BOOL
|
|||
|
LoadPreloadDlls(
|
|||
|
HMODULE * * ppPreloadDllHandles
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
UnloadPreloadDlls(
|
|||
|
HMODULE * * ppPreloadDllHandles
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Used if the services Dll or entry point can't be found
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
AbortService(
|
|||
|
LPSTR ServiceName,
|
|||
|
DWORD Error
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Dispatch table for all services. Passed to NetServiceStartCtrlDispatcher.
|
|||
|
//
|
|||
|
// Add new service entries here and in the DLL name list.
|
|||
|
// Also add an entry in the following table InetServiceDllTable
|
|||
|
//
|
|||
|
|
|||
|
SERVICE_TABLE_ENTRY InetServiceDispatchTable[] = {
|
|||
|
{ "GopherSvc", InetinfoStartService },
|
|||
|
{ "MSFtpSvc", InetinfoStartService },
|
|||
|
{ "W3Svc", InetinfoStartService },
|
|||
|
{ "IISADMIN", InetinfoStartService },
|
|||
|
{ NULL, NULL },
|
|||
|
};
|
|||
|
|
|||
|
SERVICE_TABLE_ENTRY W3ServiceDispatchTable[] = {
|
|||
|
{ "W3Svc", InetinfoStartService },
|
|||
|
{ NULL, NULL },
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// DLL names for all services.
|
|||
|
// (should correspond exactly with above InetServiceDispatchTable)
|
|||
|
//
|
|||
|
|
|||
|
struct SERVICE_DLL_TABLE_ENTRY {
|
|||
|
|
|||
|
LPSTR lpServiceName;
|
|||
|
LPSTR lpDllName;
|
|||
|
CRITICAL_SECTION csLoadLock;
|
|||
|
} InetServiceDllTable[] = {
|
|||
|
{ "GopherSvc", "gopherd.dll" },
|
|||
|
{ "MSFtpSvc", "ftpsvc2.dll" },
|
|||
|
{ "W3Svc", "w3svc.dll" },
|
|||
|
{ "IISADMIN", "iisadmin.dll" },
|
|||
|
{ NULL, NULL }
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// Global parameter data passed to each service.
|
|||
|
//
|
|||
|
|
|||
|
TCPSVCS_GLOBAL_DATA InetinfoGlobalData;
|
|||
|
|
|||
|
#include <initguid.h>
|
|||
|
DEFINE_GUID(IisExeGuid,
|
|||
|
0x784d8901, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e);
|
|||
|
#ifndef _NO_TRACING_
|
|||
|
#include "dbgutil.h"
|
|||
|
#include "pudebug.h"
|
|||
|
DECLARE_DEBUG_PRINTS_OBJECT()
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// A global variable that remembers that we'll refuse to start.
|
|||
|
//
|
|||
|
|
|||
|
BOOL RefuseStartup = FALSE;
|
|||
|
BOOL g_fRunAsExe = FALSE;
|
|||
|
BOOL g_fW3svcNoAuth = FALSE;
|
|||
|
BOOL g_fOleInitialized = TRUE;
|
|||
|
|
|||
|
DWORD __cdecl
|
|||
|
main(
|
|||
|
IN DWORD argc,
|
|||
|
IN LPSTR argv[]
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the main routine for the LANMan services. It starts up the
|
|||
|
main thread that is going to handle the control requests from the
|
|||
|
service controller.
|
|||
|
|
|||
|
It basically sets up the ControlDispatcher and, on return, exits
|
|||
|
from this main thread. The call to NetServiceStartCtrlDispatcher
|
|||
|
does not return until all services have terminated, and this process
|
|||
|
can go away.
|
|||
|
|
|||
|
The ControlDispatcher thread will start/stop/pause/continue any
|
|||
|
services. If a service is to be started, it will create a thread
|
|||
|
and then call the main routine of that service. The "main routine"
|
|||
|
for each service is actually an intermediate function implemented in
|
|||
|
this module that loads the DLL containing the server being started
|
|||
|
and calls its entry point.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
HMODULE dllHandle = NULL;
|
|||
|
HINSTANCE hRpcRef = NULL;
|
|||
|
HMODULE * pPreloadDllHandles = NULL;
|
|||
|
DWORD dwIndex;
|
|||
|
struct SERVICE_DLL_TABLE_ENTRY * pEntry;
|
|||
|
DWORD err = ERROR_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize OLE
|
|||
|
//
|
|||
|
|
|||
|
#ifndef _NO_TRACING_
|
|||
|
HRESULT hr;
|
|||
|
|
|||
|
CREATE_DEBUG_PRINT_OBJECT("Inetinfo.exe");
|
|||
|
// CREATE_INITIALIZE_DEBUG();
|
|||
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED );
|
|||
|
#else
|
|||
|
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED );
|
|||
|
#endif
|
|||
|
if ( FAILED(hr)) {
|
|||
|
if ( hr != E_INVALIDARG ) {
|
|||
|
IIS_PRINTF((buff,"CoInitialize failed with %x\n",hr));
|
|||
|
g_fOleInitialized = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize Global Data.
|
|||
|
//
|
|||
|
//
|
|||
|
// Use the rpcref library, so that multiple services can
|
|||
|
// independently "start" the rpc server
|
|||
|
//
|
|||
|
|
|||
|
hRpcRef = LoadLibrary("rpcref.dll");
|
|||
|
|
|||
|
if ( hRpcRef != NULL )
|
|||
|
{
|
|||
|
InetinfoGlobalData.StartRpcServerListen =
|
|||
|
(PFN_INETINFO_START_RPC_SERVER)
|
|||
|
GetProcAddress(hRpcRef,"InetinfoStartRpcServerListen");
|
|||
|
|
|||
|
InetinfoGlobalData.StopRpcServerListen =
|
|||
|
(PFN_INETINFO_STOP_RPC_SERVER)
|
|||
|
GetProcAddress(hRpcRef,"InetinfoStopRpcServerListen");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Error %d loading rpcref.dll\n",
|
|||
|
GetLastError() ));
|
|||
|
#ifndef _NO_TRACING_
|
|||
|
DELETE_DEBUG_PRINT_OBJECT();
|
|||
|
// DELETE_INITIALIZE_DEBUG()
|
|||
|
#endif
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize service entry locks
|
|||
|
//
|
|||
|
|
|||
|
for ( dwIndex = 0 ; ; dwIndex++ )
|
|||
|
{
|
|||
|
pEntry = &( InetServiceDllTable[ dwIndex ] );
|
|||
|
if ( pEntry->lpServiceName == NULL )
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
InitializeCriticalSection( &( pEntry->csLoadLock ) );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Disable hard-error popups.
|
|||
|
//
|
|||
|
|
|||
|
SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX );
|
|||
|
|
|||
|
//
|
|||
|
// Preload Dlls specified in the registry
|
|||
|
//
|
|||
|
|
|||
|
if ( !LoadPreloadDlls( &pPreloadDllHandles ) )
|
|||
|
{
|
|||
|
IIS_PRINTF(( buff, "Error pre-loading DLLs\n" ));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if ( (argc > 2) && !_stricmp( argv[1], "-e" ))
|
|||
|
{
|
|||
|
PCHAR pszName = argv[2];
|
|||
|
HANDLE hAsExeEvent;
|
|||
|
HANDLE hStartW3svc = NULL;
|
|||
|
PIISADMIN_SERVICE_DLL_EXEENTRY IisAdminExeEntry = NULL;
|
|||
|
PIISADMIN_SERVICE_DLL_EXEEXIT IisAdminExeExit = NULL;
|
|||
|
BOOL IsIisAdmin = TRUE;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Create a named event. The common internet services code attempts
|
|||
|
// to create a semaphore with the same name, if it fails then the
|
|||
|
// service is being run as an exe
|
|||
|
//
|
|||
|
|
|||
|
g_fRunAsExe = TRUE;
|
|||
|
|
|||
|
hAsExeEvent = CreateEvent( NULL,
|
|||
|
FALSE,
|
|||
|
FALSE,
|
|||
|
IIS_AS_EXE_OBJECT_NAME);
|
|||
|
|
|||
|
err = GetLastError();
|
|||
|
if ( hAsExeEvent == NULL ) {
|
|||
|
|
|||
|
IIS_PRINTF((buff,"Cannot create %s event. err %d\n",
|
|||
|
IIS_AS_EXE_OBJECT_NAME, err));
|
|||
|
goto Finished;
|
|||
|
}
|
|||
|
|
|||
|
if ( err != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
CloseHandle(hAsExeEvent);
|
|||
|
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Error %d in CreateEvent[%s]\n",
|
|||
|
err, IIS_AS_EXE_OBJECT_NAME));
|
|||
|
|
|||
|
goto Finished;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// All services are dependent on IISADMIN
|
|||
|
// so if it's not IISADMIN call it
|
|||
|
//
|
|||
|
|
|||
|
if ( (_stricmp(IISADMIN_NAME, pszName) != 0) ) {
|
|||
|
|
|||
|
//
|
|||
|
// Not IISADMIN
|
|||
|
//
|
|||
|
|
|||
|
IsIisAdmin = FALSE;
|
|||
|
|
|||
|
dllHandle = LoadLibrary(IISADMIN_NAME);
|
|||
|
|
|||
|
if ( dllHandle == NULL ) {
|
|||
|
|
|||
|
err = GetLastError();
|
|||
|
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Failed to load DLL %s: %ld\n",
|
|||
|
IISADMIN_NAME, err));
|
|||
|
goto Finished;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the service's main entry point. This
|
|||
|
// entry point has a well-known name.
|
|||
|
//
|
|||
|
|
|||
|
IisAdminExeEntry = (PIISADMIN_SERVICE_DLL_EXEENTRY)GetProcAddress(
|
|||
|
dllHandle,
|
|||
|
IISADMIN_EXEENTRY_STRING
|
|||
|
);
|
|||
|
|
|||
|
if (IisAdminExeEntry == NULL ) {
|
|||
|
err = GetLastError();
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Can't find entry %s in DLL %s: %ld\n",
|
|||
|
IISADMIN_EXEENTRY_STRING, IISADMIN_NAME, err));
|
|||
|
goto Finished;
|
|||
|
}
|
|||
|
|
|||
|
IisAdminExeExit = (PIISADMIN_SERVICE_DLL_EXEEXIT)GetProcAddress(
|
|||
|
dllHandle,
|
|||
|
IISADMIN_EXEEXIT_STRING
|
|||
|
);
|
|||
|
|
|||
|
if (IisAdminExeExit == NULL ) {
|
|||
|
err = GetLastError();
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Can't find entry %s in DLL %s: %ld\n",
|
|||
|
IISADMIN_EXEEXIT_STRING, IISADMIN_NAME, err);
|
|||
|
);
|
|||
|
goto Finished;
|
|||
|
}
|
|||
|
|
|||
|
if (!IisAdminExeEntry( TRUE, FALSE, TRUE)) {
|
|||
|
IIS_PRINTF((buff,"IISadmin init failed\n"));
|
|||
|
err = 1;
|
|||
|
goto Finished;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Offset argv so that the first entry points to the dll name to
|
|||
|
// load
|
|||
|
//
|
|||
|
|
|||
|
IIS_PRINTF((buff,"Starting %s\n", pszName));
|
|||
|
InetinfoStartService( 1, &argv[2] );
|
|||
|
|
|||
|
if (!IsIisAdmin) {
|
|||
|
IisAdminExeExit();
|
|||
|
}
|
|||
|
|
|||
|
if ( hStartW3svc != NULL ) {
|
|||
|
CloseHandle( hStartW3svc );
|
|||
|
}
|
|||
|
CloseHandle( hAsExeEvent );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
StartDispatchTable( );
|
|||
|
}
|
|||
|
|
|||
|
DBGPRINTF((
|
|||
|
DBG_CONTEXT,
|
|||
|
"Finishing main CTC = %d \n",
|
|||
|
GetTickCount()
|
|||
|
));
|
|||
|
|
|||
|
Finished:
|
|||
|
|
|||
|
//
|
|||
|
// Unload pre-loaded Dlls
|
|||
|
//
|
|||
|
|
|||
|
UnloadPreloadDlls( &pPreloadDllHandles );
|
|||
|
|
|||
|
//
|
|||
|
// Cleanup OLE
|
|||
|
//
|
|||
|
|
|||
|
if ( g_fOleInitialized ) {
|
|||
|
CoUninitialize();
|
|||
|
g_fOleInitialized = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the admin service dll
|
|||
|
// Note: this must happen after CoUninitialize or it causes
|
|||
|
// a crash on Win95
|
|||
|
//
|
|||
|
|
|||
|
if (dllHandle != NULL) {
|
|||
|
FreeLibrary( dllHandle );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if ( hRpcRef != NULL ) {
|
|||
|
FreeLibrary( hRpcRef );
|
|||
|
hRpcRef = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Terminate service entry locks
|
|||
|
//
|
|||
|
|
|||
|
for ( dwIndex = 0 ; ; dwIndex++ )
|
|||
|
{
|
|||
|
pEntry = &( InetServiceDllTable[ dwIndex ] );
|
|||
|
if ( pEntry->lpServiceName == NULL )
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
DeleteCriticalSection( &( pEntry->csLoadLock ) );
|
|||
|
}
|
|||
|
|
|||
|
IIS_PRINTF((buff,"Exiting inetinfo.exe\n"));
|
|||
|
#ifndef _NO_TRACING_
|
|||
|
DELETE_DEBUG_PRINT_OBJECT();
|
|||
|
// DELETE_INITIALIZE_DEBUG()
|
|||
|
#endif
|
|||
|
|
|||
|
DBGPRINTF((
|
|||
|
DBG_CONTEXT,
|
|||
|
"Exiting main CTC = %d \n",
|
|||
|
GetTickCount()
|
|||
|
));
|
|||
|
|
|||
|
return err;
|
|||
|
|
|||
|
} // main
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
FindEntryFromDispatchTable(
|
|||
|
IN LPSTR pszService
|
|||
|
)
|
|||
|
{
|
|||
|
SERVICE_TABLE_ENTRY * pService;
|
|||
|
|
|||
|
for(pService = InetServiceDispatchTable;
|
|||
|
pService->lpServiceName != NULL;
|
|||
|
pService++) {
|
|||
|
|
|||
|
if ( !lstrcmpi( pService->lpServiceName, pszService)) {
|
|||
|
|
|||
|
return DIFF(pService - InetServiceDispatchTable);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We have not found the entry. Set error and return
|
|||
|
//
|
|||
|
|
|||
|
SetLastError( ERROR_INVALID_PARAMETER);
|
|||
|
return 0xFFFFFFFF;
|
|||
|
|
|||
|
} // FindEntryFromDispatchTable()
|
|||
|
|
|||
|
BOOL
|
|||
|
GetDLLNameForDispatchEntryService(
|
|||
|
IN LPSTR pszService,
|
|||
|
IN OUT CHAR * pszDllName,
|
|||
|
IN DWORD cbDllName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
If the image name is not in the static dispatch table, then it might be
|
|||
|
in the registry under the value "IISDllName" under the key for the
|
|||
|
service. This routine reads the registry for the setting (if existing).
|
|||
|
|
|||
|
This code allows the exchange folks to install their service DLLs in a
|
|||
|
location other than "%systemroot%\inetsrv".
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pszService - Service name
|
|||
|
pszDllName - Filled with image name
|
|||
|
cbDllName - Size of buffer pointed to by pszDllName
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful, else FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HKEY hkey = NULL, hkeyService = NULL;
|
|||
|
DWORD err;
|
|||
|
DWORD valType;
|
|||
|
DWORD nBytes;
|
|||
|
BOOL ret = FALSE;
|
|||
|
|
|||
|
err = RegOpenKeyEx(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
REGISTRY_SERVICES_KEY_A,
|
|||
|
0,
|
|||
|
KEY_READ,
|
|||
|
&hkeyService
|
|||
|
);
|
|||
|
|
|||
|
if (err != ERROR_SUCCESS) {
|
|||
|
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Failed to open service key: %ld\n", err));
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
err = RegOpenKeyEx(
|
|||
|
hkeyService,
|
|||
|
pszService,
|
|||
|
0,
|
|||
|
KEY_READ,
|
|||
|
&hkey
|
|||
|
);
|
|||
|
|
|||
|
if (err != ERROR_SUCCESS) {
|
|||
|
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Failed to open service key for %s: %ld\n",
|
|||
|
pszService, err));
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
nBytes = cbDllName;
|
|||
|
|
|||
|
err = RegQueryValueEx(
|
|||
|
hkey,
|
|||
|
REGISTRY_VALUE_IISSERVICE_DLL_PATH_NAME_A,
|
|||
|
NULL,
|
|||
|
&valType,
|
|||
|
(LPBYTE)pszDllName,
|
|||
|
&nBytes);
|
|||
|
|
|||
|
if ( err == ERROR_SUCCESS &&
|
|||
|
( valType == REG_SZ || valType == REG_EXPAND_SZ ) )
|
|||
|
{
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Service Dll is %s", pszDllName));
|
|||
|
|
|||
|
ret = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if (hkey != NULL) {
|
|||
|
RegCloseKey( hkey );
|
|||
|
}
|
|||
|
|
|||
|
if (hkeyService != NULL) {
|
|||
|
RegCloseKey( hkeyService );
|
|||
|
}
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
InetinfoStartService (
|
|||
|
IN DWORD argc,
|
|||
|
IN LPSTR argv[]
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine loads the DLL that contains a service and calls its
|
|||
|
main routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DllName - name of the DLL
|
|||
|
|
|||
|
argc, argv - Passed through to the service
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HMODULE dllHandle;
|
|||
|
PINETSVCS_SERVICE_DLL_ENTRY serviceEntry;
|
|||
|
BOOL ok;
|
|||
|
DWORD Error;
|
|||
|
CHAR tmpDllName[MAX_PATH+1];
|
|||
|
LPSTR DllName;
|
|||
|
DWORD dwIndex;
|
|||
|
|
|||
|
//
|
|||
|
// If we need to refuse to start services, do so.
|
|||
|
//
|
|||
|
|
|||
|
if ( RefuseStartup ) {
|
|||
|
AbortService(argv[0], ERROR_INVALID_PARAMETER);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find the Dll Name for requested service
|
|||
|
//
|
|||
|
|
|||
|
dwIndex = FindEntryFromDispatchTable( argv[0] );
|
|||
|
if ( dwIndex == 0xFFFFFFFF ) {
|
|||
|
|
|||
|
if ( GetDLLNameForDispatchEntryService( argv[0],
|
|||
|
tmpDllName,
|
|||
|
sizeof( tmpDllName ) ) ) {
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Service %s has path set in registry. Assuming %s\n",
|
|||
|
argv[0],
|
|||
|
tmpDllName));
|
|||
|
DllName = tmpDllName;
|
|||
|
}
|
|||
|
else if ( strlen(argv[0]) < (MAX_PATH-4) ) {
|
|||
|
strcpy(tmpDllName, argv[0]);
|
|||
|
strcat(tmpDllName, ".dll");
|
|||
|
|
|||
|
IIS_PRINTF((buff,"Service %s not on primary list. Assuming %s\n",
|
|||
|
argv[0], tmpDllName));
|
|||
|
DllName = tmpDllName;
|
|||
|
} else {
|
|||
|
Error = ERROR_INSUFFICIENT_BUFFER;
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Failed To Find Dll For %s : %ld\n",
|
|||
|
argv[0], Error));
|
|||
|
AbortService( argv[0], Error);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DllName = InetServiceDllTable[ dwIndex ].lpDllName;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Load the DLL that contains the service.
|
|||
|
//
|
|||
|
|
|||
|
if ( dwIndex != 0xFFFFFFFF )
|
|||
|
{
|
|||
|
EnterCriticalSection( &( InetServiceDllTable[ dwIndex ].csLoadLock ) );
|
|||
|
}
|
|||
|
|
|||
|
dllHandle = LoadLibraryEx( DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
|
|||
|
if ( dllHandle == NULL ) {
|
|||
|
Error = GetLastError();
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Failed to load DLL %s: %ld\n",
|
|||
|
DllName, Error));
|
|||
|
AbortService(argv[0], Error);
|
|||
|
goto Finished;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the service's main entry point. This
|
|||
|
// entry point has a well-known name.
|
|||
|
//
|
|||
|
|
|||
|
serviceEntry = (PINETSVCS_SERVICE_DLL_ENTRY)GetProcAddress(
|
|||
|
dllHandle,
|
|||
|
INETSVCS_ENTRY_POINT_STRING
|
|||
|
);
|
|||
|
|
|||
|
if ( serviceEntry == NULL ) {
|
|||
|
Error = GetLastError();
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Can't find entry %s in DLL %s: %ld\n",
|
|||
|
INETSVCS_ENTRY_POINT_STRING, DllName, Error));
|
|||
|
AbortService(argv[0], Error);
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Call the service's main entry point. This call doesn't return
|
|||
|
// until the service exits.
|
|||
|
//
|
|||
|
|
|||
|
serviceEntry( argc, argv, &InetinfoGlobalData );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// wait for the control dispatcher routine to return. This
|
|||
|
// works around a problem where simptcp was crashing because the
|
|||
|
// FreeLibrary() was happenning before the control routine returned.
|
|||
|
//
|
|||
|
|
|||
|
Sleep( 500 );
|
|||
|
|
|||
|
//
|
|||
|
// Unload the DLL.
|
|||
|
//
|
|||
|
|
|||
|
ok = FreeLibrary( dllHandle );
|
|||
|
if ( !ok ) {
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"INETSVCS: Can't unload DLL %s: %ld\n",
|
|||
|
DllName, GetLastError()));
|
|||
|
}
|
|||
|
|
|||
|
Finished:
|
|||
|
if ( dwIndex != 0xFFFFFFFF )
|
|||
|
{
|
|||
|
LeaveCriticalSection( &( InetServiceDllTable[ dwIndex ].csLoadLock ) );
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // InetinfoStartService
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DummyCtrlHandler(
|
|||
|
DWORD Opcode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is a dummy control handler which is only used if we can't load
|
|||
|
a services DLL entry point. Then we need this so we can send the
|
|||
|
status back to the service controller saying we are stopped, and why.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
OpCode - Ignored
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return;
|
|||
|
|
|||
|
} // DummyCtrlHandler
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AbortService(
|
|||
|
LPSTR ServiceName,
|
|||
|
DWORD Error)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is called if we can't load the entry point for a service. It
|
|||
|
gets a handle so it can call SetServiceStatus saying we are stopped
|
|||
|
and why.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServiceName - the name of the service that couldn't be started
|
|||
|
Error - the reason it couldn't be started
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SERVICE_STATUS_HANDLE GenericServiceStatusHandle;
|
|||
|
SERVICE_STATUS GenericServiceStatus;
|
|||
|
|
|||
|
if (!g_fRunAsExe) {
|
|||
|
GenericServiceStatus.dwServiceType = SERVICE_WIN32;
|
|||
|
GenericServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
|||
|
GenericServiceStatus.dwControlsAccepted = SERVICE_CONTROL_STOP;
|
|||
|
GenericServiceStatus.dwCheckPoint = 0;
|
|||
|
GenericServiceStatus.dwWaitHint = 0;
|
|||
|
GenericServiceStatus.dwWin32ExitCode = Error;
|
|||
|
GenericServiceStatus.dwServiceSpecificExitCode = 0;
|
|||
|
|
|||
|
GenericServiceStatusHandle = RegisterServiceCtrlHandler(
|
|||
|
ServiceName,
|
|||
|
DummyCtrlHandler);
|
|||
|
|
|||
|
if (GenericServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {
|
|||
|
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"[Inetinfo]RegisterServiceCtrlHandler[%s] failed %d\n",
|
|||
|
ServiceName, GetLastError()));
|
|||
|
|
|||
|
} else if (!SetServiceStatus (GenericServiceStatusHandle,
|
|||
|
&GenericServiceStatus)) {
|
|||
|
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"[Inetinfo]SetServiceStatus[%s] error %ld\n",
|
|||
|
ServiceName, GetLastError()));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
};
|
|||
|
|
|||
|
VOID
|
|||
|
StartDispatchTable(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the dispatch table to use. It uses the default if
|
|||
|
the DispatchEntries value key does not exist
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to the dispatch table to use.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LPSERVICE_TABLE_ENTRY dispatchTable = InetServiceDispatchTable;
|
|||
|
LPSERVICE_TABLE_ENTRY tableEntry = NULL;
|
|||
|
|
|||
|
LPBYTE buffer;
|
|||
|
HKEY hKey = NULL;
|
|||
|
|
|||
|
DWORD i;
|
|||
|
DWORD err;
|
|||
|
DWORD valType;
|
|||
|
DWORD nBytes = 0;
|
|||
|
DWORD nEntries = 0;
|
|||
|
PCHAR entry;
|
|||
|
BOOL IsIisAdmin = TRUE;
|
|||
|
HMODULE dllHandle;
|
|||
|
PIISADMIN_SERVICE_DLL_EXEENTRY IisAdminExeEntry = NULL;
|
|||
|
PIISADMIN_SERVICE_DLL_EXEEXIT IisAdminExeExit = NULL;
|
|||
|
DWORD dwW3svcNoAuth;
|
|||
|
|
|||
|
//
|
|||
|
// See if need to augment the dispatcher table
|
|||
|
//
|
|||
|
|
|||
|
err = RegOpenKeyEx(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
REGISTRY_KEY_INETINFO_PARAMETERS_A,
|
|||
|
0,
|
|||
|
KEY_READ,
|
|||
|
&hKey
|
|||
|
);
|
|||
|
|
|||
|
if ( err != ERROR_SUCCESS ) {
|
|||
|
hKey = NULL;
|
|||
|
goto start_dispatch;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// See if mono service
|
|||
|
//
|
|||
|
|
|||
|
nBytes = sizeof(dwW3svcNoAuth);
|
|||
|
if ( RegQueryValueEx(
|
|||
|
hKey,
|
|||
|
INETA_W3ONLY_NO_AUTH,
|
|||
|
NULL,
|
|||
|
&valType,
|
|||
|
(LPBYTE)&dwW3svcNoAuth,
|
|||
|
&nBytes
|
|||
|
) == ERROR_SUCCESS && valType == REG_DWORD ) {
|
|||
|
g_fW3svcNoAuth = !!dwW3svcNoAuth;
|
|||
|
}
|
|||
|
|
|||
|
if ( g_fW3svcNoAuth ) {
|
|||
|
|
|||
|
dllHandle = LoadLibrary(IISADMIN_NAME);
|
|||
|
|
|||
|
if ( dllHandle == NULL ) {
|
|||
|
|
|||
|
err = GetLastError();
|
|||
|
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Failed to load DLL %s: %ld\n",
|
|||
|
IISADMIN_NAME, err));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the service's main entry point. This
|
|||
|
// entry point has a well-known name.
|
|||
|
//
|
|||
|
|
|||
|
IisAdminExeEntry = (PIISADMIN_SERVICE_DLL_EXEENTRY)GetProcAddress(
|
|||
|
dllHandle,
|
|||
|
IISADMIN_EXEENTRY_STRING
|
|||
|
);
|
|||
|
|
|||
|
if (IisAdminExeEntry == NULL ) {
|
|||
|
err = GetLastError();
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Can't find entry %s in DLL %s: %ld\n",
|
|||
|
IISADMIN_EXEENTRY_STRING, IISADMIN_NAME, err));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
IisAdminExeExit = (PIISADMIN_SERVICE_DLL_EXEEXIT)GetProcAddress(
|
|||
|
dllHandle,
|
|||
|
IISADMIN_EXEEXIT_STRING
|
|||
|
);
|
|||
|
|
|||
|
if (IisAdminExeExit == NULL ) {
|
|||
|
err = GetLastError();
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Can't find entry %s in DLL %s: %ld\n",
|
|||
|
IISADMIN_EXEEXIT_STRING, IISADMIN_NAME, err);
|
|||
|
);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (!IisAdminExeEntry( FALSE, TRUE, TRUE )) {
|
|||
|
IIS_PRINTF((buff,"IISadmin init failed\n"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
IsIisAdmin = FALSE;
|
|||
|
|
|||
|
dispatchTable = W3ServiceDispatchTable;
|
|||
|
|
|||
|
goto start_dispatch;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// See if the value exists and get the size of the buffer needed
|
|||
|
//
|
|||
|
|
|||
|
nBytes = 0;
|
|||
|
err = RegQueryValueEx(
|
|||
|
hKey,
|
|||
|
REGISTRY_VALUE_INETINFO_DISPATCH_ENTRIES_A,
|
|||
|
NULL,
|
|||
|
&valType,
|
|||
|
NULL,
|
|||
|
&nBytes
|
|||
|
);
|
|||
|
|
|||
|
if ( (err != ERROR_SUCCESS) || (nBytes <= sizeof(CHAR)) ) {
|
|||
|
goto start_dispatch;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate nBytes to query the buffer
|
|||
|
//
|
|||
|
|
|||
|
buffer = (LPBYTE)LocalAlloc(0, nBytes);
|
|||
|
if ( buffer == NULL ) {
|
|||
|
goto start_dispatch;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the values
|
|||
|
//
|
|||
|
|
|||
|
err = RegQueryValueEx(
|
|||
|
hKey,
|
|||
|
REGISTRY_VALUE_INETINFO_DISPATCH_ENTRIES_A,
|
|||
|
NULL,
|
|||
|
&valType,
|
|||
|
buffer,
|
|||
|
&nBytes
|
|||
|
);
|
|||
|
|
|||
|
if ( (err != ERROR_SUCCESS) || (valType != REG_MULTI_SZ) ) {
|
|||
|
LocalFree(buffer);
|
|||
|
goto start_dispatch;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list and see how many entries we have. Remove the list
|
|||
|
// terminator from the byte count
|
|||
|
//
|
|||
|
|
|||
|
nBytes -= sizeof(CHAR);
|
|||
|
for ( i = 0, entry = (PCHAR)buffer;
|
|||
|
i < nBytes;
|
|||
|
i += sizeof(CHAR) ) {
|
|||
|
|
|||
|
if ( *entry++ == '\0' ) {
|
|||
|
nEntries++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( nEntries == 0 ) {
|
|||
|
LocalFree(buffer);
|
|||
|
goto start_dispatch;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add the number of entries in the default list (including the NULL entry)
|
|||
|
//
|
|||
|
|
|||
|
nEntries += sizeof(InetServiceDispatchTable) / sizeof(SERVICE_TABLE_ENTRY);
|
|||
|
|
|||
|
//
|
|||
|
// Now we need to allocate the new dispatch table
|
|||
|
//
|
|||
|
|
|||
|
tableEntry = (LPSERVICE_TABLE_ENTRY)
|
|||
|
LocalAlloc(0, nEntries * sizeof(SERVICE_TABLE_ENTRY));
|
|||
|
|
|||
|
if ( tableEntry == NULL ) {
|
|||
|
LocalFree(buffer);
|
|||
|
goto start_dispatch;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// set the dispatch table pointer to the new table
|
|||
|
//
|
|||
|
|
|||
|
dispatchTable = tableEntry;
|
|||
|
|
|||
|
//
|
|||
|
// Populate the table starting with the defaults
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; InetServiceDispatchTable[i].lpServiceName != NULL; i++ ) {
|
|||
|
|
|||
|
tableEntry->lpServiceName =
|
|||
|
InetServiceDispatchTable[i].lpServiceName;
|
|||
|
tableEntry->lpServiceProc =
|
|||
|
InetServiceDispatchTable[i].lpServiceProc;
|
|||
|
tableEntry++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now let's add the ones specified in the registry
|
|||
|
//
|
|||
|
|
|||
|
entry = (PCHAR)buffer;
|
|||
|
|
|||
|
tableEntry->lpServiceName = entry;
|
|||
|
tableEntry->lpServiceProc = InetinfoStartService;
|
|||
|
tableEntry++;
|
|||
|
|
|||
|
//
|
|||
|
// Skip the first char and the last NULL terminator.
|
|||
|
// This is needed because we already added the first one.
|
|||
|
//
|
|||
|
|
|||
|
for ( i = 2*sizeof(CHAR); i < nBytes; i += sizeof(CHAR) ) {
|
|||
|
|
|||
|
if ( *entry++ == '\0' ) {
|
|||
|
tableEntry->lpServiceName = entry;
|
|||
|
tableEntry->lpServiceProc = InetinfoStartService;
|
|||
|
tableEntry++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// setup sentinel entry
|
|||
|
//
|
|||
|
|
|||
|
tableEntry->lpServiceName = NULL;
|
|||
|
tableEntry->lpServiceProc = NULL;
|
|||
|
|
|||
|
start_dispatch:
|
|||
|
|
|||
|
if ( hKey != NULL ) {
|
|||
|
RegCloseKey(hKey);
|
|||
|
}
|
|||
|
|
|||
|
W3SVCLauncher* pLauncher = new W3SVCLauncher();
|
|||
|
if (pLauncher==NULL)
|
|||
|
{
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Can not launch the W3SVC launching class %lu\n",
|
|||
|
GetLastError()));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pLauncher->StartListening();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Call StartServiceCtrlDispatcher to set up the control interface.
|
|||
|
// The API won't return until all services have been terminated. At that
|
|||
|
// point, we just exit.
|
|||
|
//
|
|||
|
|
|||
|
if (! StartServiceCtrlDispatcher (
|
|||
|
dispatchTable
|
|||
|
)) {
|
|||
|
//
|
|||
|
// Log an event for failing to start control dispatcher
|
|||
|
//
|
|||
|
|
|||
|
IIS_PRINTF((buff,
|
|||
|
"Inetinfo: Failed to start control dispatcher %lu\n",
|
|||
|
GetLastError()));
|
|||
|
}
|
|||
|
|
|||
|
DBGPRINTF((
|
|||
|
DBG_CONTEXT,
|
|||
|
"All services have shutdown CTC = %d \n",
|
|||
|
GetTickCount()
|
|||
|
));
|
|||
|
|
|||
|
if (pLauncher)
|
|||
|
{
|
|||
|
pLauncher->StopListening();
|
|||
|
|
|||
|
delete pLauncher;
|
|||
|
pLauncher = NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DBGPRINTF((
|
|||
|
DBG_CONTEXT,
|
|||
|
"Completed all W3SVC new code CTC = %d \n",
|
|||
|
GetTickCount()
|
|||
|
));
|
|||
|
|
|||
|
// Now that we have returned from the StartServiceCtrlDispatcher it means
|
|||
|
// that even IISAdmin has shutdown. This means that W3svc is no longer running
|
|||
|
// and that we do not need to keep listening for WAS to tell us to start W3WP.
|
|||
|
// Therefore we need to single the thread to complete so that inetinfo.exe shutsdown
|
|||
|
// correctly.
|
|||
|
|
|||
|
//
|
|||
|
// free table if allocated
|
|||
|
//
|
|||
|
|
|||
|
if ( dispatchTable != InetServiceDispatchTable &&
|
|||
|
dispatchTable != W3ServiceDispatchTable ) {
|
|||
|
LocalFree( dispatchTable );
|
|||
|
LocalFree( buffer );
|
|||
|
}
|
|||
|
|
|||
|
if (!IsIisAdmin) {
|
|||
|
IisAdminExeExit();
|
|||
|
FreeLibrary( dllHandle );
|
|||
|
}
|
|||
|
|
|||
|
DBGPRINTF((
|
|||
|
DBG_CONTEXT,
|
|||
|
"Exiting StartDispatchTable CTC = %d \n",
|
|||
|
GetTickCount()
|
|||
|
));
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // StartDispatchTable
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
LoadPreloadDlls(
|
|||
|
HMODULE * * ppPreloadDllHandles
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Force pre-loading of any DLLs listed in the associated registry key.
|
|||
|
This is to support DLLs that have code which must run before other parts
|
|||
|
of inetinfo start.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
On input, an (uninitialized) pointer to an array of module handles. This
|
|||
|
array is allocated, filled out, and returned to the caller by this
|
|||
|
function. The caller must eventually call UnloadPreloadDlls on this array
|
|||
|
in order to close the handles and release the memory.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE on success, FALSE on failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL bSuccess = TRUE;
|
|||
|
HKEY hKey = NULL;
|
|||
|
DWORD err;
|
|||
|
DWORD cbBufferLen;
|
|||
|
DWORD valType;
|
|||
|
LPBYTE pbBuffer = NULL;
|
|||
|
DWORD i;
|
|||
|
PCHAR pszTemp = NULL;
|
|||
|
DWORD nEntries;
|
|||
|
PCHAR pszEntry = NULL;
|
|||
|
DWORD curEntry;
|
|||
|
|
|||
|
|
|||
|
*ppPreloadDllHandles = NULL;
|
|||
|
|
|||
|
|
|||
|
err = RegOpenKeyEx(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
REGISTRY_KEY_INETINFO_PARAMETERS_A,
|
|||
|
0,
|
|||
|
KEY_QUERY_VALUE,
|
|||
|
&hKey
|
|||
|
);
|
|||
|
|
|||
|
if ( err != ERROR_SUCCESS ) {
|
|||
|
// Note: not considered an error if the key is not there
|
|||
|
|
|||
|
hKey = NULL;
|
|||
|
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// See if the value exists and get the size of the buffer needed
|
|||
|
//
|
|||
|
|
|||
|
cbBufferLen = 0;
|
|||
|
|
|||
|
err = RegQueryValueEx(
|
|||
|
hKey,
|
|||
|
REGISTRY_VALUE_INETINFO_PRELOAD_DLLS_A,
|
|||
|
NULL,
|
|||
|
&valType,
|
|||
|
NULL,
|
|||
|
&cbBufferLen
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Check for no value or an empty value (double null terminated).
|
|||
|
//
|
|||
|
if ( ( err != ERROR_SUCCESS ) || ( cbBufferLen <= 2 * sizeof(CHAR) ) )
|
|||
|
{
|
|||
|
// Note: not considered an error if the value is not there
|
|||
|
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate cbBufferLen in order to fetch the data
|
|||
|
//
|
|||
|
|
|||
|
pbBuffer = (LPBYTE)LocalAlloc(
|
|||
|
0,
|
|||
|
cbBufferLen
|
|||
|
);
|
|||
|
|
|||
|
if ( pbBuffer == NULL )
|
|||
|
{
|
|||
|
bSuccess = FALSE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the values
|
|||
|
//
|
|||
|
|
|||
|
err = RegQueryValueEx(
|
|||
|
hKey,
|
|||
|
REGISTRY_VALUE_INETINFO_PRELOAD_DLLS_A,
|
|||
|
NULL,
|
|||
|
&valType,
|
|||
|
pbBuffer,
|
|||
|
&cbBufferLen
|
|||
|
);
|
|||
|
|
|||
|
if ( ( err != ERROR_SUCCESS ) || ( valType != REG_MULTI_SZ ) )
|
|||
|
{
|
|||
|
bSuccess = FALSE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list and see how many entries we have. Ignore the list
|
|||
|
// terminator in the last byte of the buffer.
|
|||
|
//
|
|||
|
|
|||
|
nEntries = 0;
|
|||
|
pszTemp = (PCHAR)pbBuffer;
|
|||
|
|
|||
|
for ( i = 0; i < ( cbBufferLen - sizeof(CHAR) ) ; i += sizeof(CHAR) )
|
|||
|
{
|
|||
|
if ( *pszTemp == '\0' )
|
|||
|
{
|
|||
|
nEntries++;
|
|||
|
}
|
|||
|
|
|||
|
pszTemp++;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the array of handles, with room for a sentinel entry
|
|||
|
//
|
|||
|
|
|||
|
*ppPreloadDllHandles = (HMODULE *)LocalAlloc(
|
|||
|
0,
|
|||
|
( nEntries + 1 ) * sizeof(HMODULE)
|
|||
|
);
|
|||
|
|
|||
|
if ( *ppPreloadDllHandles == NULL )
|
|||
|
{
|
|||
|
bSuccess = FALSE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now attempt to load each DLL, and save the handle in the array
|
|||
|
//
|
|||
|
|
|||
|
pszTemp = (PCHAR)pbBuffer;
|
|||
|
pszEntry = (PCHAR)pbBuffer;
|
|||
|
curEntry = 0;
|
|||
|
|
|||
|
for ( i = 0; i < ( cbBufferLen - sizeof(CHAR) ) ; i += sizeof(CHAR) )
|
|||
|
{
|
|||
|
if ( *pszTemp == '\0' )
|
|||
|
{
|
|||
|
//
|
|||
|
// We've hit the end of one of the SZs in the Multi-SZ;
|
|||
|
// Load the DLL
|
|||
|
//
|
|||
|
|
|||
|
(*ppPreloadDllHandles)[curEntry] = LoadLibrary( pszEntry );
|
|||
|
|
|||
|
if ( (*ppPreloadDllHandles)[curEntry] == NULL )
|
|||
|
{
|
|||
|
IIS_PRINTF(( buff, "Preloading FAILED for DLL: %s\n", pszEntry ));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IIS_PRINTF(( buff, "Preloaded DLL: %s\n", pszEntry ));
|
|||
|
|
|||
|
// Only move to the next slot if we got a valid handle
|
|||
|
curEntry++;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Set the next entry pointer past the current null char
|
|||
|
pszEntry = pszTemp + sizeof(CHAR);
|
|||
|
}
|
|||
|
|
|||
|
pszTemp++;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Put in a sentinel at the end of the array
|
|||
|
|
|||
|
(*ppPreloadDllHandles)[curEntry] = NULL;
|
|||
|
|
|||
|
|
|||
|
Exit:
|
|||
|
|
|||
|
if ( hKey != NULL )
|
|||
|
{
|
|||
|
RegCloseKey( hKey );
|
|||
|
}
|
|||
|
|
|||
|
if ( pbBuffer != NULL )
|
|||
|
{
|
|||
|
LocalFree( pbBuffer );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return bSuccess;
|
|||
|
|
|||
|
} // LoadPreloadDlls
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
UnloadPreloadDlls(
|
|||
|
HMODULE * * ppPreloadDllHandles
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Unload any DLLs which were preloaded by LoadPreloadDlls.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pointer to an array of module handles. Each handle will be freed,
|
|||
|
and then the memory of the array will be LocalFree()ed by this function.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HMODULE * pHandleArray = *ppPreloadDllHandles;
|
|||
|
|
|||
|
if ( pHandleArray != NULL )
|
|||
|
{
|
|||
|
|
|||
|
IIS_PRINTF(( buff, "Unloading Preloaded DLLs\n" ));
|
|||
|
|
|||
|
|
|||
|
while ( *pHandleArray != NULL )
|
|||
|
{
|
|||
|
FreeLibrary( *pHandleArray );
|
|||
|
|
|||
|
pHandleArray++;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LocalFree( *ppPreloadDllHandles );
|
|||
|
|
|||
|
*ppPreloadDllHandles = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // UnloadPreloadDlls
|
|||
|
|
|||
|
|
|||
|
|