2012-02-15 22 views
6

Ho creato un server COM locale che richiede l'elevazione e deve essere istanziato da all'interno di un processo non elevato.Moniker di elevazione COM non riesce ad elevare il server in Vista/Windows 7

Utilizzando MSDN's article on the COM elevation moniker, ho configurato la classe del server in base ai requisiti specificati. Il server è stato registrato con successo nell'hive HKLM.

L'esempio di codice:

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; 

Quando si tratta di CoGetObject(PWideChar(sMonikerName), @rBindOpts, IID, PInterface) ottengo lo schermo UAC e confermare in esecuzione il server come amministratore. Tuttavia, OleCheck(iRes) restituisce: "L'operazione richiesta richiede l'elevazione" errore.

Da that article Ho letto di "Altezza sopra la spalla (OTS)".

È questo l'unico modo per ottenere la mia istanza del server disponibile per il processo non elevato? In tal caso, quando deve essere chiamato CoInitializeSecurity sul server?


completi dettagli di registrazione

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 

Sopra sono le uniche voci che esistono nel mio registro dopo la registrazione del server.


Ulteriori dettagli

provato senza successo chiamando CoInitializeSecurity() implicitamente + impostando le autorizzazioni di pranzo come consigliato utilizzando il seguente codice:

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; 

Come AppID GUID Ho cercato di usare sia lo stesso CLSID GUID della mia interfaccia server e un nuovo GUID generato: il risultato è stato lo stesso. I valori AccessPermission e LaunchPermission sono stati visualizzati nel luogo specificato dopo la registrazione del server.

cercato anche:

  • Specificando ROTFlags = 1 nel AppId chiave
  • Costruire il server come un'applicazione a 64 bit

Ulteriori chiavi di registro/valori che ho creato 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

Non dovresti scrivere direttamente a "HKEY_CLASSES_ROOT' direttamente. Va bene per la lettura, ma per scrivere dovresti usare 'HKEY_LOCAL_MACHINE \ Software \ Classes'. MSDN dice tanto. A parte questo, dove e come si chiama 'CoInitializeSecurity()'? –

+0

OK sulla chiave di registro. Risolto il problema. Secondo la sezione "Over-the-Shoulder (OTS) Elevation" 'CoInitializeSecurity()' è chiamato implicitamente (si veda l'esempio con il codice 'SetAccessPermissions') e quindi non l'ho mai chiamato da solo. – AlexeyDaryin

+0

Hai provato a chiamarlo in modo esplicito ancora? –

risposta

7

Un errore che stai facendo è che stai passando il globa della RTL l variabile HInstance dove CoGetObject() si aspetta invece un HWND. Un handle HINSTANCE non è un handle valido HWND. È necessario utilizzare uno HWND effettivo, ad esempio la proprietà Handle di un TForm, oppure specificare 0 per consentire al Moniker di elevazione di scegliere una finestra adatta a te.

Per quanto riguarda il valore di ritorno ERROR_ELEVATION_REQUIRED, tutto quello che posso dire è che la registrazione COM è probabilmente incompleta da qualche parte.Si prega di mostrare i dettagli completi della registrazione che vengono effettivamente memorizzati nel Registro di sistema (non ciò che il vostro codice pensa che stia memorizzando - ciò che il Registro sta effettivamente memorizzando).

CoInitializeSecurity() deve essere chiamato quando il processo del server inizia a funzionare.

+0

Remy, grazie. Ho risolto il problema con la variabile 'HInstance'. Ho fornito i dettagli della registrazione nel primo post. – AlexeyDaryin

+0

È stato creato un server COM a 32 bit in esecuzione su un sistema operativo a 64 bit. Hai provato a creare una versione a 64 bit del tuo server COM in modo che non venga più registrata sotto l'albero 'Wow6432Node'? A parte questo, hai provato ad aggiungere il valore 'ROTFlags' alla tua registrazione? Vedere la sezione "Elevated Servers and ROT Registrations" dell'articolo. Infine, la tua app client è in esecuzione a un livello di integrità inferiore? In tal caso, consultare le sezioni "Autorizzazioni COM e Etichette di accesso obbligatorio" e "CoCreateInstance and Integrity Levels" dell'articolo. –

+0

Ho aggiunto altri dettagli al mio post originale. Ho provato ad applicare tutti i consigli, tuttavia il risultato non è cambiato. Ancora ricevendo "ERROR_ELEVATION_REQUIRED". – AlexeyDaryin