2012-02-15 6 views
6

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}" 
+0

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()'? –

+0

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

+0

¿Has intentado llamarlo explícitamente todavía? –

Respuesta

7

Un error que estás cometiendo es que estás pasando la globa de RTL l HInstance variable donde CoGetObject() espera un HWND en su lugar. Un identificador HINSTANCE no es un identificador HWND válido. Necesita utilizar un HWND real como Handle propiedad de un TForm, o bien especifique 0 para dejar que Elevation Moniker elija una ventana adecuada para usted.

En cuanto al valor de retorno ERROR_ELEVATION_REQUIRED, todo lo que puedo decir es que su registro COM es probable que esté incompleto en alguna parte.Por favor, muestre los detalles de registro completos que en realidad están siendo almacenados en el Registro (no lo que su código cree que está almacenando, lo que el Registro en realidad está almacenando).

CoInitializeSecurity() se debe llamar cuando el proceso del servidor comience a ejecutarse.

+0

Remy, gracias. He solucionado el problema con la variable 'HInstance'. Proporcioné los detalles de registro en la primera publicación. – AlexeyDaryin

+0

Ha creado un servidor COM de 32 bits que se ejecuta en un sistema operativo de 64 bits. ¿Has intentado crear una versión de 64 bits de tu servidor COM para que ya no se registre bajo el árbol 'Wow6432Node'? Aparte de eso, ¿ha intentado agregar el valor 'ROTFlags' a su registro? Consulte la sección 'Servidores elevados y registros ROT' del artículo. Por último, ¿su aplicación cliente se ejecuta en un nivel de integridad inferior? De ser así, consulte las secciones 'Permisos COM y Etiquetas de acceso obligatorio' y' CoCreateInstance and Integrity Levels' del artículo. –

+0

Agregué más detalles a mi publicación original. Traté de aplicar todos los consejos, sin embargo, el resultado no cambió. Todavía recibes 'ERROR_ELEVATION_REQUIRED'. – AlexeyDaryin

Cuestiones relacionadas