windows-nt/Source/XPSP1/NT/net/mmc/remrras/server/remrras.cpp
2020-09-26 16:20:57 +08:00

391 lines
9.6 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: REMRRAS.CPP
//
//----------------------------------------------------------------------------
// Note: Proxy/Stub Information
// To build a separate proxy/stub DLL,
// run nmake -f remrrasps.mk in the project directory.
#include "stdafx.h"
#include <iaccess.h> // IAccessControl
#include "resource.h"
#include "initguid.h"
#include "remras.h"
#include "ncutil.h"
#include "atlapp.h"
#include "atltmp.h"
//nclude "remrras_i.c"
#include "RemCfg.h"
#include <statreg.h>
#include <statreg.cpp>
#include <atlimpl.cpp>
HRESULT CommitIPInfo();
void RestartRouter();
DWORD WaitForServiceToStop(SC_HANDLE hService);
LONG CExeModule::Unlock()
{
LONG l = CComModule::Unlock();
if (l == 0)
{
#if _WIN32_WINNT >= 0x0400
if (CoSuspendClassObjects() == S_OK)
PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
#else
PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
#endif
}
return l;
}
CExeModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_RemoteRouterConfig, CRemCfg)
END_OBJECT_MAP()
LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
{
while (*p1 != NULL)
{
LPCTSTR p = p2;
while (*p != NULL)
{
if (*p1 == *p++)
return p1+1;
}
p1++;
}
return NULL;
}
DWORD g_dwTraceHandle = 0;
extern BOOL s_fWriteIPConfig;
extern BOOL s_fRestartRouter;
HRESULT GrantAdministratorsGroupAccess()
{
TCHAR szBuffer[1024];
IAccessControl* pAccessControl = NULL;
HRESULT hr = CoCreateInstance(CLSID_DCOMAccessControl, NULL, CLSCTX_INPROC_SERVER,
IID_IAccessControl, (void**)&pAccessControl);
if(FAILED(hr))
goto Error;
// Setup the property list. We use the NULL property because we are
// trying to adjust the security of the object itself
ACTRL_ACCESSW access;
ACTRL_PROPERTY_ENTRYW propEntry;
access.cEntries = 1;
access.pPropertyAccessList = &propEntry;
ACTRL_ACCESS_ENTRY_LISTW entryList;
propEntry.lpProperty = NULL;
propEntry.pAccessEntryList = &entryList;
propEntry.fListFlags = 0;
// Setup the access control list for the default property
ACTRL_ACCESS_ENTRYW entry;
entryList.cEntries = 1;
entryList.pAccessList = &entry;
// Setup the access control entry
entry.fAccessFlags = ACTRL_ACCESS_ALLOWED;
entry.Access = COM_RIGHTS_EXECUTE;
entry.ProvSpecificAccess = 0;
entry.Inheritance = NO_INHERITANCE;
entry.lpInheritProperty = NULL;
// NT requires the system account to have access (for launching)
entry.Trustee.pMultipleTrustee = NULL;
entry.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
entry.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
entry.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
::LoadString(NULL, IDS_NT_AUTHORITY_ADMINISTRATORS, szBuffer,
256);
entry.Trustee.ptstrName = szBuffer;
hr = pAccessControl->GrantAccessRights(&access);
if(FAILED(hr))
{
#ifdef __PRIVATE_DEBUG
TCHAR msg[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, msg, 1024, 0);
MessageBox(NULL,msg, L"Error", MB_OK);
#endif
goto Error;
}
hr = CoInitializeSecurity(pAccessControl, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IDENTIFY,
NULL, EOAC_ACCESS_CONTROL, NULL);
Error:
if(pAccessControl)
pAccessControl->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
//
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
{
lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
HRESULT hRes = CoInitialize(NULL);
hRes = GrantAdministratorsGroupAccess();
// If you are running on NT 4.0 or higher you can use the following call
// instead to make the EXE free threaded.
// This means that calls come in on a random RPC thread
// HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
_ASSERTE(SUCCEEDED(hRes));
_Module.Init(ObjectMap, hInstance);
_Module.dwThreadID = GetCurrentThreadId();
TCHAR szTokens[] = _T("-/");
int nRet = 0;
BOOL bRun = TRUE;
s_fWriteIPConfig = FALSE;
s_fRestartRouter = FALSE;
LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
while (lpszToken != NULL)
{
if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
{
_Module.UpdateRegistryFromResource(IDR_Remrras, FALSE);
nRet = _Module.UnregisterServer();
bRun = FALSE;
break;
}
if (lstrcmpi(lpszToken, _T("RegServer"))==0)
{
_Module.UpdateRegistryFromResource(IDR_Remrras, TRUE);
nRet = _Module.RegisterServer(TRUE);
bRun = FALSE;
break;
}
if (lstrcmpi(lpszToken, _T("Restart")) == 0)
{
RestartRouter();
bRun = FALSE;
nRet = 0;
break;
}
lpszToken = FindOneOf(lpszToken, szTokens);
}
if (bRun)
{
g_dwTraceHandle = TraceRegister(_T("remrras"));
TraceSz("Entering remrras.exe");
hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE);
_ASSERTE(SUCCEEDED(hRes));
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
DispatchMessage(&msg);
_Module.RevokeClassObjects();
// At this point, check the global flag to see if there is work
// to be done.
if (s_fWriteIPConfig)
{
TraceSz("The IP Configuration is being changed.");
CoUninitialize();
CoInitialize(NULL);
CommitIPInfo();
}
if (s_fRestartRouter)
{
// There's no point in doing any kind of error code
RestartRouter();
}
TraceSz("Exiting remrras.exe\n");
TraceDeregister(g_dwTraceHandle);
}
CoUninitialize();
return nRet;
}
static DWORD s_dwTickBegin = 0;
static DWORD s_dwLastCheckPoint = -1;
static DWORD s_dwWaitPeriod = 18000;
void RestartRouter()
{
DWORD dwErr = ERROR_SUCCESS;
SC_HANDLE hScManager = 0;
SC_HANDLE hService = 0;
//
// Open the SCManager so that we can try to stop the service
//
hScManager = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hScManager == NULL)
dwErr = ::GetLastError();
if (hScManager && (dwErr == ERROR_SUCCESS))
{
hService = ::OpenService(hScManager,
_T("RemoteAccess"),
SERVICE_STOP | SERVICE_START |
SERVICE_QUERY_STATUS);
if (hService == NULL)
dwErr = ::GetLastError();
}
if (hService && (dwErr == ERROR_SUCCESS))
{
SERVICE_STATUS serviceStatus;
// Stop the RemoteAccess Service
if (::ControlService(hService, SERVICE_CONTROL_STOP,
&serviceStatus))
{
// We are now stopping the service, we need to wait
// the proper amount of time
s_dwTickBegin = GetTickCount();
// get the wait period
::ZeroMemory(&serviceStatus, sizeof(serviceStatus));
if (QueryServiceStatus(hService, &serviceStatus))
s_dwWaitPeriod = serviceStatus.dwWaitHint;
dwErr = WaitForServiceToStop(hService);
}
else
{
dwErr = ::GetLastError();
// Is the service already stopped?
if (dwErr == ERROR_SERVICE_NOT_ACTIVE)
{
dwErr = ERROR_SUCCESS;
}
}
}
if (hService && (dwErr == ERROR_SUCCESS))
{
SERVICE_STATUS serviceStatus;
// Start the RemoteAccess Service
::StartService(hService, NULL, NULL);
}
if (hService)
::CloseServiceHandle(hService);
if (hScManager)
::CloseServiceHandle(hScManager);
}
BOOL CheckForError(SERVICE_STATUS * pServiceStats)
{
BOOL fError = FALSE;
DWORD dwTickCurrent = GetTickCount();
if (pServiceStats->dwCheckPoint == 0)
{
// the service is in some state, not pending anything.
// before calling this function the code should check to see if
// the service is in the correct state. This means it is in
// some unexpected state.
fError = TRUE;
}
else
if ((dwTickCurrent - s_dwTickBegin) > s_dwWaitPeriod)
{
// ok to check the dwCheckPoint field to see if
// everything is going ok
if (s_dwLastCheckPoint == -1)
{
s_dwLastCheckPoint = pServiceStats->dwCheckPoint;
}
else
{
if (s_dwLastCheckPoint >= pServiceStats->dwCheckPoint)
{
fError = TRUE;
}
}
s_dwLastCheckPoint = pServiceStats->dwCheckPoint;
s_dwTickBegin = dwTickCurrent;
s_dwWaitPeriod = pServiceStats->dwWaitHint;
}
return fError;
}
DWORD WaitForServiceToStop(SC_HANDLE hService)
{
SERVICE_STATUS serviceStatus;
DWORD dwErr = ERROR_SUCCESS;
do
{
::ZeroMemory(&serviceStatus, sizeof(serviceStatus));
if (!QueryServiceStatus(hService, &serviceStatus))
{
dwErr = ::GetLastError();
break;
}
// If the dwCheckpoint value is 0, then there is no start/stop/pause
// or continue action pending (in which case we can exit no matter
// what happened).
if (serviceStatus.dwCurrentState == SERVICE_STOPPED)
break;
if (CheckForError(&serviceStatus))
{
// Something failed. Report an error.
if (serviceStatus.dwWin32ExitCode)
dwErr = serviceStatus.dwWin32ExitCode;
else
dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
break;
}
// Now we sleep
Sleep(5000);
}
while (TRUE);
return dwErr;
}