463 lines
12 KiB
C++
463 lines
12 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997-2001.
|
|
//
|
|
// File: S V C M A I N . C P P
|
|
//
|
|
// Contents: Service main for netman.dll
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: shaunco 3 Apr 1998
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
#include <dbt.h>
|
|
#include "nmbase.h"
|
|
#include "nminit.h"
|
|
#include "nmres.h"
|
|
#include "eapolfunc.h"
|
|
|
|
#include "wsdpsvc.h"
|
|
|
|
#undef EAPOL_LINKED
|
|
|
|
// Includes for COM objects needed in the following object map.
|
|
//
|
|
|
|
// Connection Manager
|
|
//
|
|
#include "..\conman\conman.h"
|
|
#include "..\conman\conman2.h"
|
|
#include "..\conman\enum.h"
|
|
|
|
// Connection Class Managers
|
|
//
|
|
#include "..\conman\conmani.h"
|
|
#include "..\conman\conmanl.h"
|
|
#include "..\conman\conmansa.h"
|
|
#include "..\conman\conmanw.h"
|
|
#include "..\conman\enumi.h"
|
|
#include "..\conman\enuml.h"
|
|
#include "..\conman\enumsa.h"
|
|
#include "..\conman\enumw.h"
|
|
|
|
// Connection Objects
|
|
//
|
|
#include "dialup.h"
|
|
#include "inbound.h"
|
|
#include "lan.h"
|
|
#include "saconob.h"
|
|
|
|
// Install queue
|
|
//
|
|
#include "ncqueue.h"
|
|
|
|
// Home networking support
|
|
//
|
|
#include "nmhnet.h"
|
|
|
|
// NetGroupPolicies
|
|
#include "nmpolicy.h"
|
|
|
|
#define INITGUID
|
|
DEFINE_GUID(CLSID_InternetConnectionBeaconService,0x04df613a,0x5610,0x11d4,0x9e,0xc8,0x00,0xb0,0xd0,0x22,0xdd,0x1f);
|
|
// TODO Remove this when we have proper idl
|
|
|
|
CServiceModule _Module;
|
|
|
|
BEGIN_OBJECT_MAP(ObjectMap)
|
|
|
|
// Connection Manager
|
|
//
|
|
OBJECT_ENTRY(CLSID_ConnectionManager, CConnectionManager)
|
|
OBJECT_ENTRY(CLSID_ConnectionManagerEnumConnection, CConnectionManagerEnumConnection)
|
|
|
|
|
|
// Connection Manager2
|
|
OBJECT_ENTRY(CLSID_ConnectionManager2, CConnectionManager2)
|
|
|
|
// Connection Class Managers
|
|
//
|
|
OBJECT_ENTRY(CLSID_InboundConnectionManager, CInboundConnectionManager)
|
|
OBJECT_ENTRY(CLSID_InboundConnectionManagerEnumConnection, CInboundConnectionManagerEnumConnection)
|
|
OBJECT_ENTRY(CLSID_LanConnectionManager, CLanConnectionManager)
|
|
OBJECT_ENTRY(CLSID_LanConnectionManagerEnumConnection, CLanConnectionManagerEnumConnection)
|
|
OBJECT_ENTRY(CLSID_WanConnectionManager, CWanConnectionManager)
|
|
OBJECT_ENTRY(CLSID_WanConnectionManagerEnumConnection, CWanConnectionManagerEnumConnection)
|
|
OBJECT_ENTRY(CLSID_SharedAccessConnectionManager, CSharedAccessConnectionManager)
|
|
OBJECT_ENTRY(CLSID_SharedAccessConnectionManagerEnumConnection, CSharedAccessConnectionManagerEnumConnection)
|
|
|
|
// Connection Objects
|
|
//
|
|
OBJECT_ENTRY(CLSID_DialupConnection, CDialupConnection)
|
|
OBJECT_ENTRY(CLSID_InboundConnection, CInboundConnection)
|
|
OBJECT_ENTRY(CLSID_LanConnection, CLanConnection)
|
|
OBJECT_ENTRY(CLSID_SharedAccessConnection, CSharedAccessConnection)
|
|
|
|
// Install queue
|
|
//
|
|
OBJECT_ENTRY(CLSID_InstallQueue, CInstallQueue)
|
|
|
|
// Home networking support
|
|
//
|
|
OBJECT_ENTRY(CLSID_NetConnectionHNetUtil, CNetConnectionHNetUtil)
|
|
|
|
// NetGroupPolicies
|
|
OBJECT_ENTRY(CLSID_NetGroupPolicies, CNetMachinePolicies)
|
|
|
|
END_OBJECT_MAP()
|
|
|
|
|
|
VOID
|
|
CServiceModule::DllProcessAttach (
|
|
HINSTANCE hinst)
|
|
{
|
|
CComModule::Init (ObjectMap, hinst);
|
|
}
|
|
|
|
VOID
|
|
CServiceModule::DllProcessDetach (
|
|
VOID)
|
|
{
|
|
CComModule::Term ();
|
|
}
|
|
|
|
DWORD
|
|
CServiceModule::DwHandler (
|
|
DWORD dwControl,
|
|
DWORD dwEventType,
|
|
PVOID pEventData,
|
|
PVOID pContext)
|
|
{
|
|
if (SERVICE_CONTROL_STOP == dwControl)
|
|
{
|
|
HRESULT hr;
|
|
|
|
TraceTag (ttidConman, "Received SERVICE_CONTROL_STOP request");
|
|
|
|
SetServiceStatus (SERVICE_STOP_PENDING);
|
|
|
|
hr = ServiceShutdown();
|
|
}
|
|
|
|
else if (SERVICE_CONTROL_INTERROGATE == dwControl)
|
|
{
|
|
TraceTag (ttidConman, "Received SERVICE_CONTROL_INTERROGATE request");
|
|
UpdateServiceStatus (FALSE);
|
|
}
|
|
|
|
else if ((SERVICE_CONTROL_DEVICEEVENT == dwControl) && pEventData)
|
|
{
|
|
DEV_BROADCAST_DEVICEINTERFACE* pInfo =
|
|
(DEV_BROADCAST_DEVICEINTERFACE*)pEventData;
|
|
|
|
if (DBT_DEVTYP_DEVICEINTERFACE == pInfo->dbcc_devicetype)
|
|
{
|
|
if (DBT_DEVICEARRIVAL == dwEventType)
|
|
{
|
|
TraceTag (ttidConman, "Device arrival: [%S]",
|
|
pInfo->dbcc_name);
|
|
|
|
LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
|
|
}
|
|
else if (DBT_DEVICEREMOVECOMPLETE == dwEventType)
|
|
{
|
|
GUID guidAdapter = GUID_NULL;
|
|
WCHAR szGuid[MAX_PATH];
|
|
WCHAR szTempName[MAX_PATH];
|
|
WCHAR* szFindGuid;
|
|
|
|
TraceTag (ttidConman, "Device removed: [%S]",
|
|
pInfo->dbcc_name);
|
|
|
|
szFindGuid = wcsrchr(pInfo->dbcc_name, L'{');
|
|
if (szFindGuid)
|
|
{
|
|
wcscpy(szGuid, szFindGuid);
|
|
IIDFromString(szGuid, &guidAdapter);
|
|
}
|
|
|
|
if (!IsEqualGUID(guidAdapter, GUID_NULL))
|
|
{
|
|
CONMAN_EVENT* pEvent;
|
|
|
|
pEvent = new CONMAN_EVENT;
|
|
|
|
if (pEvent)
|
|
{
|
|
pEvent->ConnectionManager = CONMAN_LAN;
|
|
pEvent->guidId = guidAdapter;
|
|
pEvent->Type = CONNECTION_STATUS_CHANGE;
|
|
pEvent->Status = NCS_DISCONNECTED;
|
|
|
|
if (!QueueUserWorkItemInThread(LanEventWorkItem, reinterpret_cast<LPVOID>(pEvent), EVENTMGR_CONMAN))
|
|
{
|
|
FreeConmanEvent(pEvent);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef EAPOL_LINKED
|
|
TraceTag (ttidConman, "Calling EAPOL ElDeviceNotificationHandler");
|
|
|
|
DWORD dwRetCode = NO_ERROR;
|
|
|
|
if ((dwRetCode = ElDeviceNotificationHandler (
|
|
pEventData, dwEventType)) != NO_ERROR)
|
|
{
|
|
TraceTag (ttidConman, "ElDeviceNotificationHandler failed with error %ld",
|
|
dwRetCode);
|
|
}
|
|
|
|
TraceTag (ttidConman, "EAPOL ElDeviceNotificationHandler completed");
|
|
#endif
|
|
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
VOID
|
|
CServiceModule::SetServiceStatus(DWORD dwState)
|
|
{
|
|
m_status.dwCurrentState = dwState;
|
|
m_status.dwCheckPoint = 0;
|
|
if (!::SetServiceStatus (m_hStatus, &m_status))
|
|
{
|
|
TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
|
|
"CServiceModule::SetServiceStatus");
|
|
}
|
|
}
|
|
|
|
VOID CServiceModule::UpdateServiceStatus (
|
|
BOOL fUpdateCheckpoint /* = TRUE */)
|
|
{
|
|
if (fUpdateCheckpoint)
|
|
{
|
|
m_status.dwCheckPoint++;
|
|
}
|
|
|
|
if (!::SetServiceStatus (m_hStatus, &m_status))
|
|
{
|
|
TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
|
|
"CServiceModule::UpdateServiceStatus");
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CServiceModule::Run()
|
|
{
|
|
HRESULT hr = CoInitializeEx (NULL,
|
|
COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CServiceModule::Run: "
|
|
"CoInitializeEx failed");
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TraceTag (ttidConman, "Calling RegisterClassObjects...");
|
|
|
|
// Create the event to sychronize registering our class objects
|
|
// with the connection manager which attempts to CoCreate
|
|
// objects which are also registered here. I've seen cases
|
|
// where the connection manager will be off and running before
|
|
// this completes causing CoCreateInstance to fail.
|
|
// The connection manager will wait on this event before
|
|
// executing CoCreateInstance.
|
|
//
|
|
HANDLE hEvent;
|
|
hr = HrNmCreateClassObjectRegistrationEvent (&hEvent);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _Module.RegisterClassObjects (
|
|
CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
|
|
REGCLS_MULTIPLEUSE);
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CServiceModule::Run: "
|
|
"_Module.RegisterClassObjects failed");
|
|
|
|
// Signal the event and close it. If this delete's the
|
|
// event, so be it. It's purpose is served as all
|
|
// class objects have been registered.
|
|
//
|
|
SetEvent (hEvent);
|
|
CloseHandle (hEvent);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ServiceStartup();
|
|
}
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
CServiceModule::ServiceMain (
|
|
DWORD argc,
|
|
PWSTR argv[])
|
|
{
|
|
// Reset the version era for RAS phonebook entry modifications.
|
|
//
|
|
g_lRasEntryModifiedVersionEra = 0;
|
|
|
|
m_fRasmanReferenced = FALSE;
|
|
|
|
m_dwThreadID = GetCurrentThreadId ();
|
|
|
|
ZeroMemory (&m_status, sizeof(m_status));
|
|
m_status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
|
|
m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
|
|
|
// Register the service control handler.
|
|
//
|
|
m_hStatus = RegisterServiceCtrlHandlerEx (
|
|
L"netman",
|
|
_DwHandler,
|
|
NULL);
|
|
|
|
if (m_hStatus)
|
|
{
|
|
SetServiceStatus (SERVICE_START_PENDING);
|
|
|
|
// When the Run function returns, the service is running.
|
|
// We now handle shutdown from ServiceShutdown when our DwHandler
|
|
// is called and is passed SERVICE_CONTROL_STOP as the dwControl
|
|
// parameter. This allows us to terminate our message pump thread
|
|
// which effectively reduces us to 0 threads that we own.
|
|
Run ();
|
|
}
|
|
else
|
|
{
|
|
TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
|
|
"CServiceModule::ServiceMain - RegisterServiceCtrlHandler failed");
|
|
}
|
|
}
|
|
|
|
// static
|
|
DWORD
|
|
WINAPI
|
|
CServiceModule::_DwHandler (
|
|
DWORD dwControl,
|
|
DWORD dwEventType,
|
|
PVOID pEventData,
|
|
PVOID pContext)
|
|
{
|
|
return _Module.DwHandler (dwControl, dwEventType, pEventData, pContext);
|
|
}
|
|
|
|
VOID
|
|
CServiceModule::ReferenceRasman (
|
|
RASREFTYPE RefType)
|
|
{
|
|
BOOL fRef = (REF_REFERENCE == RefType);
|
|
|
|
if (REF_INITIALIZE == RefType)
|
|
{
|
|
Assert (!fRef);
|
|
|
|
// RasInitialize implicitly references rasman.
|
|
//
|
|
RasInitialize ();
|
|
}
|
|
// If we need to reference and we're not already,
|
|
// or we need unreference and we're referenced, do the appropriate thing.
|
|
// (This is logical xor. Quite different than bitwise xor when
|
|
// the two arguments don't neccesarily have the same value for TRUE.)
|
|
//
|
|
else if ((fRef && !m_fRasmanReferenced) ||
|
|
(!fRef && m_fRasmanReferenced))
|
|
{
|
|
RasReferenceRasman (fRef);
|
|
|
|
m_fRasmanReferenced = fRef;
|
|
}
|
|
}
|
|
|
|
HRESULT CServiceModule::ServiceStartup()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
#ifdef EAPOL_LINKED
|
|
//
|
|
// Start EAPOL
|
|
//
|
|
|
|
TraceTag (ttidConman, "Starting EAPOL");
|
|
|
|
EAPOLServiceMain ( argc, NULL);
|
|
|
|
TraceTag (ttidConman, "EAPOL started successfully");
|
|
#endif
|
|
|
|
StartWsdpService (); // Starts WSDP service on DTC/AdvServer build/
|
|
// no-op otherwise
|
|
|
|
InitializeHNetSupport();
|
|
|
|
SetServiceStatus (SERVICE_RUNNING);
|
|
TraceTag (ttidConman, "Netman is now running...");
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CServiceModule::ServiceShutdown()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = UninitializeEventHandler();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CleanupHNetSupport();
|
|
|
|
StopWsdpService (); // Stops WSDP service if necessary
|
|
|
|
// We must synchronize with the install queue's thread otherwise
|
|
// RevokeClassObjects will kill the InstallQueue object and
|
|
// CoUninitialize will free the NetCfg module before the thread
|
|
// is finished.
|
|
//
|
|
WaitForInstallQueueToExit();
|
|
|
|
_Module.RevokeClassObjects ();
|
|
|
|
// Unreference rasman now that our service is about to stop.
|
|
//
|
|
_Module.ReferenceRasman (REF_UNREFERENCE);
|
|
|
|
#ifdef EAPOL_LINKED
|
|
TraceTag (ttidConman, "Stopping EAPOL");
|
|
|
|
EAPOLCleanUp (NO_ERROR);
|
|
|
|
TraceTag (ttidConman, "EAPOL stopped successfully");
|
|
#endif
|
|
|
|
SetServiceStatus(SERVICE_STOPPED);
|
|
}
|
|
CoUninitialize();
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
SetServiceStatus(SERVICE_RUNNING);
|
|
}
|
|
|
|
return hr;
|
|
}
|