2025-11-28 00:35:46 +09:00

270 lines
7.7 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// ElevationManager.cpp
// -Implements functionality for elevation including using
// the elevation moniker and setting a button shield icon.
//
#include "stdafx.h"
#include "ElevationManager.h"
#include "..\RegisterServer\RegisterServer.h"
#include "..\RegisterServer\RegisterServer_i.c"
//
// FUNCTION: ElevationManager(__out hr *)
//
// PURPOSE: Constructor for elevation manager. Calls CoInitializeEx.
//
// COMMENTS:
// Calling code should check the out parameter for Failure and cancel
// further operation on class.
//
ElevationManager::ElevationManager(__out HRESULT * hr)
{
CInitHR = CoInitializeEx(NULL, COINIT_MULTITHREADED);
*hr = CInitHR;
}
ElevationManager::~ElevationManager(void)
{
if(SUCCEEDED(CInitHR))
CoUninitialize();
}
//
// FUNCTION: private RegisterAsDll(const TCHAR *, HWND, BOOL)
//
// PURPOSE: Creates an instance of the specified IID in an elevated process.
//
// COMMENTS:
// tszFileName - The filename to be registered
// hwndMain - The handle to the main window.
// fRegister - TRUE: register server.
// - FALSE: unregister server.
//
// Uses CoCreateInstanceAsAdmin to load the IDllRegister Interface in an elevated process.
//
// Succeeds if registration is successful, fails otherwise.
// Over The Shoulder (OTS) elevation will succeed in CoCreateInstanceAsAdmin with the correct credentials, but fail
// with E_ACCESSDENIED if the registry key 'AppId/{CLSID}/AccessPermission' is not correctly set to allow the
// Interactive user. (See Register.cpp function SetOTSRegValue)
//
HRESULT ElevationManager::RegisterAsDll(const TCHAR * tszFileName, HWND hwndMain, BOOL fRegister){
HRESULT hr;
IDllRegister * pDllRegister = NULL;
TCHAR *tszFullFileName = NULL;
BSTR bstrFileName = NULL;
int bufLen = GetFullPathName(tszFileName, 0, NULL, NULL);
tszFullFileName = (TCHAR *)malloc(sizeof(TCHAR) * bufLen);
if(!tszFullFileName){
hr = E_OUTOFMEMORY;
goto cleanup;
}
if(!GetFullPathName(tszFileName, bufLen, tszFullFileName, NULL)){
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
hr = CoCreateInstanceAsAdmin(hwndMain, CLSID_RegistrationClass, IID_IDllRegister, (void **) &pDllRegister);
if(FAILED(hr)){
goto cleanup;
}
bstrFileName = SysAllocString(tszFullFileName);
if(!bstrFileName){
hr = E_OUTOFMEMORY;
goto cleanup;
}
if(fRegister)
hr = pDllRegister->RegisterDll(bstrFileName);
else
hr = pDllRegister->UnRegisterDll(bstrFileName);
cleanup:
free(tszFullFileName);
SysFreeString(bstrFileName);
if(pDllRegister)
pDllRegister->Release();
pDllRegister=NULL;
return hr;
}
//
// FUNCTION: private CoCreateInstanceAsAdmin(HWND, REFCLSID, REFIID, __out void**)
//
// PURPOSE: Creates an instance of the specified IID in an elevated process us the COM Elevation Moniker.
//
// COMMENTS:
// hwndMain - The Window associated with this call.
// rclsid - CLSID associated with the data and code that will be used to create the object.
// riid - Reference to the identifier of the interface to be used to communicate with the object.
// ppv - [out] Address of pointer variable that receives the interface pointer requested in riid.
// Upon successful return, *ppv contains the requested interface pointer.
// Upon failure, *ppv contains NULL.
//
// Fails if: -User declines Elevation
// -{CLSID}/Elevation/Enabled != 1 (See Register.cpp)
// -{CLSID}/LocalizedString not set or invalid (See Register.cpp)
//
HRESULT ElevationManager::CoCreateInstanceAsAdmin(HWND hwndMain, __in REFCLSID rclsid, __in REFIID riid, __deref_out void ** ppv)
{
BIND_OPTS3 bo;
WCHAR wszCLSID[CLSIDSize];
WCHAR wszMonikerName[MonikerSize+CLSIDSize];
StringFromGUID2(rclsid, wszCLSID, ARRAYSIZE(wszCLSID));
HRESULT hr = StringCchPrintf(wszMonikerName, ARRAYSIZE(wszMonikerName), MonikerName, wszCLSID);
if (FAILED(hr))
return hr;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.hwnd = hwndMain;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
hr = CoGetObject(wszMonikerName, &bo, riid, ppv);
return hr;
}
//
// FUNCTION: private RegisterAsExe(const TCHAR *, HWND, BOOL)
//
// PURPOSE: Registers the file provided as an executable.
//
// COMMENTS:
// tszFileName - The file to be registered.
// hwndMain - The Window associated with this call.
// fRegister - TRUE: Register server
// FALSE: Unregister server.
//
// This function does not get an elevated instance of the server, instead the server is responsible
// to elevate the executable using shell execute.
//
HRESULT ElevationManager::RegisterAsExe(const TCHAR * tszFileName, HWND hwndMain, BOOL fRegister){
HRESULT hr;
IExeRegister * pExeRegister = NULL;
BSTR bstrFileName = NULL;
hr = CoCreateInstance(CLSID_RegistrationClass, NULL, CLSCTX_INPROC, IID_IExeRegister, (void **) &pExeRegister);
if(FAILED(hr))
goto cleanup;
bstrFileName = SysAllocString(tszFileName);
if(!bstrFileName){
hr = E_OUTOFMEMORY;
goto cleanup;
};
if(fRegister)
hr = pExeRegister->RegisterExe(bstrFileName, hwndMain);
else
hr = pExeRegister->UnregisterExe(bstrFileName, hwndMain);
cleanup:
SysFreeString(bstrFileName);
if(pExeRegister)
pExeRegister->Release();
pExeRegister = NULL;
return hr;
}
//
// FUNCTION: SetButtonShield(HWND)
//
// PURPOSE: Places the Shield Icon on the button referenced by hwnd.
//
// COMMENTS:
// hwndButton - handle to the button that should recieve the shield icon.
// This call is in it's own function here for clarity.
// An application must be manifested to use comctl32.dll version 6 to gain this functionality:
// In VS, add to ProjectProperties->Linker->Manifest File->Additional Manifest Dependencies:
// "type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"
//
LRESULT ElevationManager::SetButtonShield(HWND hwndButton){
return Button_SetElevationRequiredState(hwndButton, TRUE);
}
//
// FUNCTION: UnregisterServer(const TCHAR *, HWND)
//
// PURPOSE: Public entry point to Unregister the server provided.
//
// COMMENTS:
// tszFileName - The server to unregister.
// hwndMain - the window associated with this call.
//
// Filename can be an exe or a library image.
//
HRESULT ElevationManager::UnRegisterServer(const TCHAR * tszFileName, HWND hwndMain){
BOOL isExe = IsFileExe(tszFileName);
if(isExe)
return RegisterAsExe(tszFileName, hwndMain, FALSE);
else
return RegisterAsDll(tszFileName, hwndMain, FALSE);
}
//
// FUNCTION: RegisterServer(const TCHAR *, HWND)
//
// PURPOSE: Public entry point to register the server provided.
//
// COMMENTS:
// tszFileName - The server to register.
// hwndMain - the window associated with this call.
//
// Filename can be an exe or a library image.
//
HRESULT ElevationManager::RegisterServer(const TCHAR * tszFileName, HWND hwndMain){
BOOL isExe = IsFileExe(tszFileName);
if(isExe)
return RegisterAsExe(tszFileName, hwndMain, TRUE);
else
return RegisterAsDll(tszFileName, hwndMain, TRUE);
}
//
// FUNCTION: private IsFileExe(const TCHAR *)
//
// PURPOSE: Checks the file extension of the given file for '.exe'
// COMMENTS:
// tszFileName - The file name to check.
// Returns - TRUE if file is EXE, FALSE Otherwise.
BOOL ElevationManager::IsFileExe(const TCHAR * tszFileName){
size_t len = _tcslen(tszFileName);
size_t min = 5;
const TCHAR * tszTemp = NULL;
if(len < min)
return FALSE;
tszTemp = tszFileName + (len - 4);
if(_tcscmp(tszTemp, _T(".exe"))==0)
return TRUE;
return FALSE;
}