|
|
//+---------------------------------------------------------------------------
//
// 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; }
|