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