c++ (WMI)IWbemServices::Release()在连接到远程计算机时引发“拒绝访问”异常

xcitsw88  于 2023-06-07  发布在  其他
关注(0)|答案(1)|浏览(736)

在C++中,我找不到一种方法来适当地终止与远程服务器的WMI会话。任何释放IWbemServices指针的尝试都会引发异常;到服务器的TCP连接一直保持建立状态,直到进程退出(在最后一次CoUninitialize调用后它是打开的)。连接到本地计算机时不会出现此问题(引发异常)。
我看过一个类似的问题,问here,但微软的解决方案(检索IUnknown指针并首先释放它)没有解决这个问题。
下面是代码(为了可读性,省略了错误检查):

HRESULT hRes = S_OK;

IWbemLocator* pWbemLocator = NULL;
IWbemServices* pWbemServices = NULL;

// these three pointers are already initialized...
PWCHAR wcUser; // L"theuser"
PWCHAR wcPass; // L"thepassword"
PWCHAR wcAuth; // L"ntlmdomain:THEDOMAIN"

std::wstring wstrNsPath = L"\\\\remoteserver\\ROOT\\CIMV2";

hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);

hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pWbemLocator);

// this returns S_OK :)
hRes = pWbemLocator->ConnectServer((BSTR)wstrNsPath.c_str(),
        (BSTR)wcUser,
        (BSTR)wcPass,
        NULL,
        WBEM_FLAG_CONNECT_USE_MAX_WAIT,
        (BSTR)wcAuth,
        NULL,
        &pWbemServices);

hRes = CoSetProxyBlanket(pWbemServices,
        RPC_C_AUTHN_DEFAULT,
        RPC_C_AUTHZ_DEFAULT,
        COLE_DEFAULT_PRINCIPAL,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        RPC_C_AUTHN_LEVEL_DEFAULT,
        NULL, // domain info already specified in 'wcAuth'
        EOAC_NONE);

// do some queries..

// cleanup
pWbemServices->Release(); // on remote sessions, this throws an exception
pWbemLocator->Release();
CoUninitialize();

异常显示在调试输出(Visual Studio)中:

onecore\com\combase\dcomrem\call.cxx(1234)\combase.dll!0000ABCDEFABCDEF: (caller: 0000FEDCBAFEDCBA) ReturnHr(1) tid(4321) 80070005 Access is denied.

这是预期的行为吗?一旦会话被释放,客户端和服务器之间的连接是否不应该被终止?
我尝试遵循MSDN的建议,并在上面代码中的CoSetProxyBlanket()调用之后添加了以下内容。这并没有改变什么。

IUnknown* pUnknown = NULL;
pWbemServices->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknown);
if (pUnknown)
{
    hRes = CoSetProxyBlanket(pUnknown,
        RPC_C_AUTHN_DEFAULT,
        RPC_C_AUTHZ_DEFAULT,
        COLE_DEFAULT_PRINCIPAL,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        RPC_C_AUTHN_LEVEL_DEFAULT,
        NULL,
        EOAC_NONE);
    pUnknown->Release();
}

任何建议都非常感谢!

EDIT因此,在捕获会话数据包后,使用pAuthInfo == NULL设置代理安全性似乎会导致由客户端计算机的当前登录用户发出请求。它忽略了我在调用ConnectServer时提供的凭据。我知道COAUTHIDENTITY结构允许您将正确的凭据传递给CoSetProxyBlanket,但我希望避免将域作为单独的变量输入。换句话说,当向远程服务器发出请求时,是否有一种方法可以使用wcAuth提取此信息?如果是这样,我如何区分本地与远程请求?

下面是Wireshark的输出,它让我相信这就是问题所在(参见数据包1617):

No.     Time        Source      Destination Protocol Length Info
1615    162.221354  [CLIENT_IP] [SERVER_IP] DCERPC  174 Alter_context: call_id: 8, Fragment: Single, 1 context items: IRemUnknown2 V0.0 (32bit NDR), NTLMSSP_NEGOTIATE
1616    162.228517  [SERVER_IP] [CLIENT_IP] DCERPC  366 Alter_context_resp: call_id: 8, Fragment: Single, max_xmit: 5840 max_recv: 5840, 1 results: Acceptance, NTLMSSP_CHALLENGE
1617    162.229396  [CLIENT_IP] [SERVER_IP] DCERPC  612 AUTH3: call_id: 8, Fragment: Single, NTLMSSP_AUTH, User: .\[client_user]
1618    162.229495  [CLIENT_IP] [SERVER_IP] IRemUnknown2    182 RemRelease request Cnt=1 Refs=5-0
1619    162.235567  [SERVER_IP] [CLIENT_IP] TCP  60 49669 → 59905 [ACK] Seq=1606 Ack=4339 Win=64768 Len=0
1620    162.235567  [SERVER_IP] [CLIENT_IP] DCERPC  86  Fault: call_id: 8, Fragment: Single, Ctx: 0, status: nca_s_fault_access_denied
blpfk2vs

blpfk2vs1#

我能够解决这个问题。如果未使用当前登录的用户令牌,则必须将CoSetProxyBlanketpAuthInfo参数指定为有效的COAUTHIDENITY结构指针。IWbemLocator::ConnectServer的文档实际上指出,最好的做法是在strUser参数中包含域...如果这样做,则必须将权限字符串作为NULL传递。
需要注意的一点是,如果ConnectServer成功,您不必为确保正确性而疯狂地清理用户名字符串;登录要么有效要么无效(并中断/抛出异常,这取决于您如何处理错误)。换句话说,只需搜索字符串中的域分隔符('\\''@'),并将它们适当地拆分为域名和用户名。

相关问题