适用于 WMI 的 IWbemLocator::ConnectServer 的主要任务之一是返回指向 IWbemServices 代理的 指针。 通过 IWbemServices 代理,可以访问 WMI 基础结构的功能。 但是,指向 IWbemServices 代理的指针具有客户端应用程序进程的标识,而不是 IWbemServices 进程的标识。 因此,如果尝试使用指针访问 IWbemServices ,则可以接收访问被拒绝的代码,例如 E_ACCESSDENIED。 为避免出现访问被拒绝错误,您必须通过调用 CoSetProxyBlanket 接口来设置新指针的标识。
提供程序可以在命名空间上设置安全性,以便除非在与该命名空间的连接中使用数据包隐私(PktPrivacy),否则不会返回任何数据。 这可确保数据在跨网络时进行加密。 如果尝试设置较低的身份验证级别,将收到拒绝访问的消息。 有关详细信息,请参阅 设置命名空间安全描述符。
有关在脚本中设置身份验证的详细信息,请参阅 使用 VBScript 设置默认进程安全级别。
在远程 IUnknown 接口上设置安全性
在某些情况下,需要的不仅仅是指向代理的指针,而是对服务器的更多访问权限。 有时,可能需要与代理的 IUnknown 接口建立安全连接。 使用 IUnknown,可以查询远程系统以获取接口和其他必要技术。
当代理位于远程计算机上时,服务器会将代理的 IUnknown 接口的所有调用委托给 IUnknown 接口。 例如,如果在代理上调用 QueryInterface ,并且请求的接口不是代理的一部分,代理会将调用发送到远程服务器。 反过来,远程服务器会检查适当的接口支持。 如果服务器确实支持该接口,COM 会将新代理封送回客户端,以便应用程序可以使用新接口。
如果客户端对远程服务器没有访问权限,但使用的是用户凭据,则会出现问题。 在这种情况下,任何尝试访问远程服务器上的 QueryInterface 都失败。 代理的最终版本也会失败,因为当前用户无权访问远程服务器。 出现这种情况的症状是客户端应用程序在最终代理释放失败之前会出现一到两秒的时滞。 失败的原因是 COM 尝试使用当前用户的默认安全设置访问远程服务器,这不包括允许首先访问服务器的已修改凭据。 有关详细信息,请参阅 在 IWbemServices 和其他代理上设置安全性。
若要避免连接失败,请使用 CoSetProxyBlanket 在从 IUnknown 返回的指针上显式设置安全身份验证。 使用 CoSetProxyBlanket,可以确保远程服务器接收正确的身份验证标识。
下面的代码示例演示如何使用 CoSetProxyBlanket 访问远程 IUnknown 接口。
SEC_WINNT_AUTH_IDENTITY_W* pAuthIdentity =
new SEC_WINNT_AUTH_IDENTITY_W;
ZeroMemory(pAuthIdentity, sizeof(SEC_WINNT_AUTH_IDENTITY_W));
pAuthIdentity->User = new WCHAR[32];
StringCbCopyW(pAuthIdentity->User,sizeof(L"MyUser"),L"MyUser");
pAuthIdentity->UserLength = wcslen(pAuthIdentity->User);
pAuthIdentity->Domain = new WCHAR[32];
StringCbCopyW(pAuthIdentity->Domain,sizeof(L"MyDomain"),L"MyDomain");
pAuthIdentity->DomainLength = wcslen(pAuthIdentity->Domain);
pAuthIdentity->Password = new WCHAR[32];
pAuthIdentity->Password[0] = NULL;
pAuthIdentity->PasswordLength = wcslen( pAuthIdentity->Password);
pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
IWbemServices* pWbemServices = 0;
// Set proxy security
hr = CoSetProxyBlanket(pWbemServices,
RPC_C_AUTHN_DEFAULT,
RPC_C_AUTHZ_NONE,
COLE_DEFAULT_PRINCIPAL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
pAuthIdentity,
EOAC_NONE
);
if (FAILED(hr))
{
cout << "Count not set proxy blanket. Error code = 0x"
<< hex << hr << endl;
pWbemServices->Release();
return 1;
}
// Set IUnknown security
IUnknown* pUnk = NULL;
pWbemServices->QueryInterface(IID_IUnknown, (void**) &pUnk);
hr = CoSetProxyBlanket(pUnk,
RPC_C_AUTHN_DEFAULT,
RPC_C_AUTHZ_NONE,
COLE_DEFAULT_PRINCIPAL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
pAuthIdentity,
EOAC_NONE
);
if (FAILED(hr))
{
cout << "Count not set proxy blanket. Error code = 0x"
<< hex << hr << endl;
pUnk->Release();
pWbemServices->Release();
delete [] pAuthIdentity->User;
delete [] pAuthIdentity->Domain;
delete [] pAuthIdentity->Password;
delete pAuthIdentity;
return 1;
}
// cleanup IUnknown
pUnk->Release();
//
// Perform a bunch of operations
//
// Cleanup
pWbemServices->Release();
delete [] pAuthIdentity->User;
delete [] pAuthIdentity->Domain;
delete [] pAuthIdentity->Password;
delete pAuthIdentity;
注释
在代理的 IUnknown 接口上设置安全性时,COM 将创建一个代理副本,该副本在调用 CoUninitialize 之前无法释放。
相关主题