He creado un servidor COM local que requiere elevación y debe crearse una instancia desde un proceso no elevado.COM Elevation Moniker no puede elevar el servidor en Vista/Windows 7
Utilizando MSDN's article on the COM elevation moniker, configuré la clase del servidor siguiendo los requisitos especificados. El servidor se registró correctamente en la colmena HKLM.
El ejemplo de código:
procedure CoCreateInstanceAsAdmin(const Handle: HWND;
const ClassID, IID: TGuid; PInterface: PPointer);
var
rBindOpts: TBindOpts3;
sMonikerName: WideString;
iRes: HRESULT;
begin
ZeroMemory(@rBindOpts, Sizeof(TBindOpts3));
rBindOpts.cbStruct := Sizeof(TBindOpts3);
rBindOpts.hwnd := Handle;
rBindOpts.dwClassContext := CLSCTX_LOCAL_SERVER;
sMonikerName := 'Elevation:Administrator!new:' + GUIDToString(ClassID);
iRes := CoGetObject(PWideChar(sMonikerName), @rBindOpts, IID, PInterface);
OleCheck(iRes);
end;
class function CoIMyServer.Create: IMyServer;
begin
CoCreateInstanceAsAdmin(HInstance, CLASS_IMyServer, IMyServer, @Result);
end;
Cuando se trata de CoGetObject(PWideChar(sMonikerName), @rBindOpts, IID, PInterface)
me sale la pantalla UAC y confirme que ejecuta el servidor como administrador. Sin embargo, OleCheck(iRes)
devuelve: "La operación solicitada requiere elevación".
De that article He leído acerca de "Elevación sobre el hombro (OTS)".
¿Es esta la única forma de que mi instancia de servidor esté disponible para el proceso no elevado? Si es así, ¿cuándo se debe llamar al CoInitializeSecurity
en el servidor?
detalles de registro completos
HKLM\SOFTWARE\Wow6432Node\Classes\CLSID
{MyServer CLSID}
(Default) = IMyServer Object
LocalizedString = @C:\Program Files (x86)\MyServer\MyServer.exe,-15500
Elevation
Enabled = 0x000001 (1)
LocalServer32
(Default) = C:\PROGRA~2\MyServer\MYSERVER.EXE
ProgID
(Default) = uMyServer.IMyServer
TypeLib
(Default) = {TypeLib GUID}
Version
(Default) = 1.0
HKLM\SOFTWARE\Wow6432Node\Classes\Interface
{GUID of IID_IMyServer}
(Default) = IMyServer
ProxyStubClsid32
(Default) = {Some GUID}
TypeLib
(Default) = {TypeLib GUID}
Version = 1.0
anteriormente son las únicas entradas que existen en mi registro después de registrar el servidor.
detalles adicionales
tratado sin éxito de llamar CoInitializeSecurity()
implícitamente + configuración de permisos de almuerzo como se aconseja utilizar el siguiente código:
function GetSecurityDescriptor(const lpszSDDL: LPWSTR; out pSD: PSecurityDescriptor): Boolean;
begin
Result := ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1,
pSD, nil);
end;
function GetLaunchActPermissionsWithIL(out pSD: PSecurityDescriptor): Boolean;
var
lpszSDDL: LPWSTR;
begin
// Allow World Local Launch/Activation permissions. Label the SD for LOW IL Execute UP
lpszSDDL := 'O:BAG:BAD:(A;;0xb;;;WD)S:(ML;;NX;;;LW)';
Result := GetSecurityDescriptor(lpszSDDL, pSD);
end;
function GetAccessPermissionsForLUAServer(out pSD: PSecurityDescriptor): Boolean;
var
lpszSDDL: LPWSTR;
begin
// Local call permissions to IU, SY
lpszSDDL := 'O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)';
Result := GetSecurityDescriptor(lpszSDDL, pSD);
end;
function SetAccessPermissions(hAppKey: HKEY; pSD: PSECURITY_DESCRIPTOR): Boolean;
var
dwLen: DWORD;
iRes: LONG;
begin
dwLen := GetSecurityDescriptorLength(pSD);
iRes := RegSetValueExA(hAppKey, 'AccessPermission', 0, REG_BINARY, pSD, dwLen);
Result := iRes = ERROR_SUCCESS;
end;
function SetLaunchActPermissions(hAppKey: HKEY; pSD: PSECURITY_DESCRIPTOR): Boolean;
var
dwLen: DWORD;
iRes: LONG;
begin
dwLen := GetSecurityDescriptorLength(pSD);
iRes := RegSetValueExA(hAppKey, 'LaunchPermission', 0, REG_BINARY, pSD, dwLen);
Result := iRes = ERROR_SUCCESS;
end;
procedure Initialize;
var
pSD: PSecurityDescriptor;
sSubKey: WideString;
hAppKey: HKEY;
begin
sSubKey := 'AppID\{GUID}';
RegOpenKeyW(HKEY_CLASSES_ROOT, PWideChar(sSubKey), hAppKey);
if GetAccessPermissionsForLUAServer(pSD) then
if not SetAccessPermissions(hAppKey, pSD) then
raise Exception.Create(Format('Access permissions aren''t set. System error: %d',
[GetLastError()]));
pSD := nil;
if GetLaunchActPermissionsWithIL(pSD) then
if not SetLaunchActPermissions(hAppKey, pSD) then
raise Exception.Create(Format('Launch permissions aren''t set. System error: %d',
[GetLastError()]));
end;
initialization
TAutoObjectFactory.Create(ComServer, TMyServer, Class_IMyServer,
ciMultiInstance, tmApartment);
Initialize;
Como AppID GUID He intentado utilizar tanto el mismo GUID CLSID de mi interfaz de servidor y un nuevo GUID generado: el resultado fue el mismo. AccessPermission
y LaunchPermission
valores aparecieron en el lugar especificado después del registro del servidor.
También probamos:
- Especificación
ROTFlags = 1
en el AppId clave - Construyendo el servidor como aplicación de 64 bits
claves de registro/valores adicionales que he creado manualmente:
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\MyServer.exe]
@="MyServer"
"AppID"="{My GUID}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{My GUID}]
@="MyServer"
"ROTFlags"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{My GUID}]
@="MyServer Object"
"AppID"="{My GUID}"
Realmente no debería estar escribiendo en 'HKEY_CLASSES_ROOT' directamente. Está bien para leer, pero para escribir debe usar 'HKEY_LOCAL_MACHINE \ Software \ Classes' en su lugar. MSDN dice eso. Aparte de eso, ¿dónde y cómo se llama 'CoInitializeSecurity()'? –
Ok sobre la clave de registro. Solucionado eso. De acuerdo con la sección "Over-The-Shoulder (OTS) Elevation", se llama implícitamente a CoInitializeSecurity() '(consulte el ejemplo con el código' SetAccessPermissions') y nunca lo llamé yo mismo. – AlexeyDaryin
¿Has intentado llamarlo explícitamente todavía? –