2011-05-25 72 views
13

我有一個使用OLE自動編組器的DCOM客戶端和服務器應用程序。它們在同一臺PC上運行時工作良好,但當服務器位於不同的PC上,而不在同一個域中時,我得到E_ACCESSDENIED(0x80070005)。DCOM中的模擬如何工作?

服務器PC使用dcomcnfg進行配置,以便將所有DCOM對象的訪問權授予其客戶端上指定的登錄名和密碼的用戶。 ServerApp及其類型庫在服務器PC上註冊。

類型庫也在客戶端PC上註冊。我直接在ClientApp中指定服務器名稱,因此就我所知,客戶端PC上不需要配置dcomcnfg。

CreateInstanceEx()與服務器名稱,登錄,域和密碼工作正常。它返回IUnknown,同時在服務器PC上啓動ServerApp。

但是當我嘗試QueryInterface()爲服務器支持的接口時,我得到E_ACCESSDENIED。

分析安全事件日誌,我有兩個記錄有:

首先,其憑據我ClientApp指定用戶一個成功的網絡登錄。當我調用CreateInstanceEx()時會發生這種情況。

接下來,登錄失敗的用戶登錄客戶端PC。由於兩臺PC不在一個域中,因此服務器PC不知道該用戶。

現在,爲什麼這個用戶會登錄到服務器,特別是當我調用QueryInterface的所有東西?

研究CreateInterfaceEx參數,它似乎有某種模擬機制正在進行。但是誰扮演誰並不清楚。有包括三個用戶憑證:在其下ServerApp服務器PC上運行(如在DCOMCNFG配置)

  1. 用戶。

  2. ClientApp在連接時指定其憑據的用戶。

  3. ClientApp在客戶端PC上運行其憑據的用戶。

無論你如何看待它,如果涉及#3,它就是一個用戶太多。如果DCOM無論如何要在服務器PC上識別/模擬#3,爲什麼我需要指定#2的憑據?到什麼點?

對於DCOM來說,模擬#2似乎是合乎邏輯的,因爲這是我明確指定的憑據。但爲什麼第二次登錄嘗試呢?

有人能解釋一下模仿是如何工作的,以及是否有辦法忽略它並以dcomcnfg中指定的用戶身份運行?

回答

12

回答我自己的問題。多摸索很明顯,DCOM有兩種不同的標識情況

  1. 授權對象創建(CoCreateInstanceEx)
  2. 授權方法調用。

由於未知原因,#2不會繼承#1設置。默認情況下,它使用客戶端進程的憑據,因此使用奇怪的登錄。

有兩種方式指定#2的憑據。首先是CoSetProxyBlanket。它僅用於設置指定代理(編組,解組)的憑據:

CoCreateInstanceEx(IID_IObject1, /*login, pass*/, obj1); //Success! 
//Logged in and recevied IObject1 proxy in obj1 

obj1->DoSomething(); 
//IObject1 proxy in obj1 now tries to login under process credentials. 
//Failure! E_ACCESSDENIED 

CoSetProxyBlanket(obj1, /*login, pass*/); //Success! 
//IObject1 proxy is now authorized. 

obj1->DoSomething(); //Success! 
obj1->QueryInterface(IID_IObject2, obj2); //Success! 

obj2->DoSomethingElse(); //Failure! 
//This different proxy for IObject2 have not yet been authorized. 

CoSetProxyBlanket(obj2, /*login, pass*/); 
//etc. 

重要的是要注意,雖然CoCreateInstanceEx需要模擬級別至少IMPERSONATE,CoSetProxyBlanket似乎並沒有在除了IDENTIFY什麼工作是很重要的。

另一種選擇是使用CoInitializeSecurity爲整個過程設置默認憑證。然後,你不必調用CoSetProxyBlanket每個代理:

CoInitializeSecurity(/* login, pass */); 
CoCreateInstanceEx(IID_IUnknown, /*login, pass*/, obj); //Success! 
obj->DoSomething(); //Success! 

當你在客戶端上使用CoInitializeSecurity指定asAuthSvc過,即使MSDN說,你不知道。

這種方法的缺點顯然是,如果你有來自不同PC的幾個DCOM對象,你將不得不指定在這個調用中的所有憑據,並且這些可能會在每次打開時針對每臺計算機進行嘗試一個不同的代理。

當你從一個DLL運行時(如果一個進程具有不同的默認安全性呢?),這也是不可靠的。因此,最好在每次調用返回之前實現一個CoSetsProxyBlanket的QueryInterface包裝器。

0

對於那些在德爾福工作的人來說,有一點可以節省大量時間。在您完成obj as ISomeInterface操作後,您必須爲新實例調用CoSetProxyBlanket。這可能不是很明顯,但我們只知道as運算符調用了QueryInterface方法,並且它可以返回新的實例。