如何使用 COAUTHIDENTITY 在 CoCreateInstanceEx 中正确模拟另一个用户?
Posted
技术标签:
【中文标题】如何使用 COAUTHIDENTITY 在 CoCreateInstanceEx 中正确模拟另一个用户?【英文标题】:How do I properly impersonate another user in CoCreateInstanceEx using COAUTHIDENTITY? 【发布时间】:2012-06-11 20:34:25 【问题描述】:我目前正在开发一个 MFC 应用程序,该应用程序需要从另一个系统上运行的 COM 对象中检索数据。当两个系统都运行 Windows XP 并且手动设置相同的用户帐户(即两个系统上的用户名和密码相同,没有域)时,我们已经拥有相同的数据交换机制并得到完全支持。问题是我正在尝试设置它,以便我可以从另一台设置了相同用户帐户但在公司域用户帐户下登录的计算机访问同一个 DCOM 系统。
现在,如果我使用 Run As 手动运行我的应用程序并指定备用用户,它就可以工作,但我正在寻找更好的解决方案。当我在 CoCreateInstanceEx 中为 COSERVERINFO 设置 COAUTHIDENTITY 时,我指定了备用帐户的用户名和密码,但这似乎不起作用。我在域条目中尝试了各种方法 - 本地计算机、远程计算机的计算机名称,并将其留空 - 但似乎没有任何帮助。
我尝试在服务器计算机上编辑对象的 DCOM 权限,以允许对所有人帐户的完全访问权限,但这似乎没有帮助,而且我无法找到任何有意义的错误消息来说明实际情况错误的。如果我可以在服务器计算机上获得某种日志消息以确切了解使用 Run As 运行它时遇到的凭据,这可能会有所帮助。有人有什么想法吗?或者,当您从非域帐户建立 DCOM 连接时,也许知道系统对域使用什么(有些事情暗示使用了计算机名称,但在我尝试时不起作用)。
代码如下:
COAUTHINFO AuthInfo;
COAUTHIDENTITY AuthIdentity;
COSERVERINFO ServerInfo;
MULTI_QI Results;
AuthIdentity.Domain = (unsigned short *) w_domain;
AuthIdentity.DomainLength = wcslen( w_domain);
AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
AuthIdentity.Password = (unsigned short *) w_password;
AuthIdentity.PasswordLength = wcslen(w_password);
AuthIdentity.User = (unsigned short *) w_username;
AuthIdentity.UserLength = wcslen(w_username);
AuthInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_CALL;
AuthInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT;
AuthInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE;
AuthInfo.dwCapabilities = EOAC_NONE;
AuthInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
AuthInfo.pAuthIdentityData = &AuthIdentity;
AuthInfo.pwszServerPrincName = NULL;
ServerInfo.dwReserved1 = 0;
ServerInfo.dwReserved2 = 0;
ServerInfo.pAuthInfo = &AuthInfo;
ServerInfo.pwszName = w_nodename;
Results.pIID = &_uuidof(_DS_SessionContext);
Results.pItf = NULL;
Results.hr = 0;
hr = CoCreateInstanceEx(clsid, NULL, CLSCTX_ALL, &ServerInfo, (ULONG) 1, &Results);
if(FAILED(hr))
m_Error.Format("(0x%x) CoCreateInstanceEx for _DS_DataFrame failed.",hr);
m_Error2.Format("Make sure computer IP address is correct and connected.");
CoUninitialize();
UpdateData(false);
UpdateWindow();
return false;
pSession = (_DS_SessionContext *)Results.pItf;
hr = pSession->raw_DS_GetVersion(&DSStatus, &version);
if(FAILED(hr))
m_Error.Format("(0x%x)GetVersion",hr);
CoUninitialize();
UpdateData(false);
UpdateWindow();
return false;
【问题讨论】:
【参考方案1】:啊,我想通了。事实证明,在 DCOM 中,创建实例并在其上调用函数不会自动使用相同的安全毯。传递给 CoCreateInstanceEx 的 COSERVERINFO 中的身份验证信息仅适用于创建实例,当我稍后在该实例上调用函数时,它会失败,因为我正在使用应用程序的凭据调用这些函数。
要正确地做到这一点,在实例上调用函数之前,我必须先调用(为清楚起见省略了错误处理):
hr = CoSetProxyBlanket(Results.pItf, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE, &AuthIdentity, EOAC_NONE);
这会将用于调用实例的安全毯设置为与创建实例相同的安全毯,因此一切正常。
【讨论】:
亲爱的梅森,你拯救了我的一天!我希望我能多次投票。以上是关于如何使用 COAUTHIDENTITY 在 CoCreateInstanceEx 中正确模拟另一个用户?的主要内容,如果未能解决你的问题,请参考以下文章
Ubuntu18.04 nvim + coc.nvim + ccls环境配置