首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

跨使用者帳號的 DCOM 遠端呼叫完整設定指南:CoInitializeSecurity、CoCreateInstanceEx 與 CoSetProxyBlanket 實戰

     編輯:關於VC++

前言:DCOM 驗證核心三步驟

DCOM 依賴 RPC,遠端呼叫需通過驗證。客戶端與伺服器帳號不同時,必須顯式提供憑證。核心流程:

  1. 伺服器端:`CoInitializeSecurity` 設定存取權限
  2. 客戶端:`CoInitializeSecurity` + `CoCreateInstanceEx` (攜帶 `COAUTHIDENTITY`) 建立 Proxy
  3. 客戶端:`CoSetProxyBlanket` 為介面 Proxy 設定模擬等級與憑證

伺服器端設定 (或用 dcomcnfg.exe 圖形介面)


HRESULT hr = CoInitializeSecurity(
    NULL, -1, NULL, NULL,
    RPC_C_AUTHN_LEVEL_NONE,      // 驗證等級:無 (由客戶端決定)
    RPC_C_IMP_LEVEL_IDENTIFY,    // 模擬等級:識別
    NULL, EOAC_ACCESS_CONTROL, NULL); // 啟用存取控制
// 註冊類別工廠等後續步驟...

客戶端完整程式碼範例 (三種寫法)

範例 1:基本 CoCreateInstanceEx + CoSetProxyBlanket


HRESULT hr = CoInitialize(NULL);

MULTI_QI mqi = { &IID_ICRemoteTime, NULL, S_OK };
COAUTHIDENTITY authId = {0};
authId.User = L"Administrator";           // 遠端機器帳號
authId.UserLength = wcslen(authId.User);
authId.Domain = NULL;                     // 工作群組無網域
authId.DomainLength = 0;
authId.Password = L"password";            // 密碼
authId.PasswordLength = wcslen(authId.Password);
authId.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

COAUTHINFO authInfo = {0};
authInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT;
authInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE;
authInfo.pwszServerPrincName = NULL;
authInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
authInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
authInfo.pAuthIdentityData = &authId;
authInfo.dwCapabilities = EOAC_NONE;

COSERVERINFO si = {0};
si.pwszName = L"192.168.1.100"; // 伺服器 IP/名稱
si.pAuthInfo = &authInfo;

hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
    RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);

hr = CoCreateInstanceEx(CLSID_CRemoteTime, NULL, CLSCTX_REMOTE_SERVER, &si, 1, &mqi);
if (FAILED(hr) || FAILED(mqi.hr)) { /* 錯誤處理 */ }

ICRemoteTime* pRemote = (ICRemoteTime*)mqi.pItf;
// 使用 pRemote...
pRemote->Release();

範例 2:CComBSTR + 結構體初始化 (較現代)


HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
    RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);

COAUTHIDENTITY us = {0};
us.User = m_strName.AllocSysString(); // CString → BSTR
us.UserLength = wcslen(us.User);
us.Password = m_strPassword.AllocSysString();
us.PasswordLength = wcslen(us.Password);
us.Domain = m_strDomain.AllocSysString();
us.DomainLength = wcslen(us.Domain);
us.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

COAUTHINFO auth = {0};
auth.dwAuthnSvc = RPC_C_AUTHN_WINNT;
auth.dwAuthzSvc = RPC_C_AUTHZ_NONE;
auth.dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
auth.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
auth.pAuthIdentityData = &us;

COSERVERINFO si = {0};
si.pwszName = CComBSTR(strComputer).m_str; // CString → LPWSTR
si.pAuthInfo = m_bAccess ? &auth : NULL;

MULTI_QI mqi = { &__uuidof(IRemoteControl), NULL, S_OK };
hr = CoCreateInstanceEx(__uuidof(RemoteControl), NULL, CLSCTX_SERVER, &si, 1, &mqi);
if (SUCCEEDED(hr) && SUCCEEDED(mqi.hr)) {
    m_pIRemoteControl = (IRemoteControl*)mqi.pItf;
}

範例 3:查詢 IUnknown 後再 QI 目標介面


MULTI_QI mqi = { &IID_IUnknown, NULL, S_OK };
// ... 同範例 2 設定 si, auth ...
hr = CoCreateInstanceEx(__uuidof(RemoteControl), NULL, CLSCTX_SERVER, &si, 1, &mqi);
if (FAILED(hr) || FAILED(mqi.hr)) return;

IUnknown* pUnk = (IUnknown*)mqi.pItf;
IRemoteControl* pCtrl;
hr = pUnk->QueryInterface(__uuidof(IRemoteControl), (void**)&pCtrl);
pUnk->Release();
if (SUCCEEDED(hr)) {
    // 使用 pCtrl...
    pCtrl->Release();
}

關鍵參數對照表

參數常用值說明
RPC_C_AUTHN_WINNTNTLM 驗證Windows 整合驗證
RPC_C_AUTHN_LEVEL_CONNECT連線時驗證僅建立連線時驗證,不加密/簽章
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY封包完整性簽章防竄改
RPC_C_AUTHN_LEVEL_PKT_PRIVACY封包隱私加密傳輸 (最高安全)
RPC_C_IMP_LEVEL_IMPERSONATE模擬客戶端伺服器可用客戶端身分存取本機資源
RPC_C_IMP_LEVEL_DELEGATE委派伺服器可用客戶端身分存取**網路**資源 (需 Kerberos)
EOAC_NONE無額外能力
SEC_WINNT_AUTH_IDENTITY_UNICODEUnicode 憑證寬字元帳號/密碼

CoSetProxyBlanket 獨立呼叫 (若 CoCreateInstanceEx 未帶驗證)


COAUTHIDENTITY caid = { /* 同上填入 */ };
hr = CoSetProxyBlanket(pInterface,
    RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
    RPC_C_AUTHN_LEVEL_DEFAULT,
    RPC_C_IMP_LEVEL_IMPERSONATE,
    &caid, EOAC_NONE);

常見錯誤與排查

  1. 0x800706BA (RPC_S_SERVER_UNAVAILABLE):防火牆阻擋、DCOM 服務未啟動、IP 錯誤
  2. 0x80070005 (E_ACCESSDENIED):帳號/密碼錯誤、伺服器 `dcomcnfg` 未授權該使用者「啟動與啟用權限」/「存取權限」
  3. 0x80040154 (REGDB_E_CLASSNOTREG):遠端機未註冊元件、CLSID 錯誤、32/64 位元不符
  4. 密碼明文風險:程式碼中硬編碼密碼極不安全,建議:安全儲存、輸入提示、Kerberos/憑證驗證
  5. 32 位元客戶端呼叫 64 位元伺服器:需確認註冊表 `Wow6432Node`、代理/存根正確註冊

dcomcnfg.exe 圖形化設定 (伺服器端)

  1. 執行 `dcomcnfg` → 元件服務 → 電腦 → 我的電腦 → DCOM 設定
  2. 右鍵目標元件 → 內容 → **安全性** 分頁
  3. 「啟動與啟用權限」→ 編輯 → 加入使用者 → 勾選「本機啟動」、「遠端啟動」
  4. 「存取權限」→ 編輯 → 加入使用者 → 勾選「本機存取」、「遠端存取」
  5. 「身分識別」分頁 → 選「互動使用者」或「這個使用者」指定帳號
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved