Вызов QueryInterface с индивидуальной идентификацией

Выпуск:

Я успешно вызываю CoSetProxyBlanket на прокси (если это правильный термин для него), а затем вызываю QueryInterface на том же прокси, но я получаю результат 0x80070005 («Отказано в доступе»). Однако, если я сначала позвоню CoInitializeSecurity (чего я пытаюсь избежать) с теми же учетными данными, то вызов будет успешным.

Вопрос:

Как я могу успешно получить нужный мне интерфейс, не вызывая CoInitializeSecurity? Из того, что я понимаю, процесс может вызывать этот метод только один раз, поэтому он не совместим с созданием DLL и обычно может быть заменен вызовами CoSetProxyBlanket.

Подробности:

Я экспериментирую с созданием своего собственного клиента OPC, который может взаимодействовать с компьютерами, работающими в разных доменах. без соответствующие учетные записи пользователей.

Сначала я создаю идентификационную структуру с доменом, именем пользователя и паролем, которые действительны на сервере:

COAUTHINFO      authInfo;
COAUTHIDENTITY  authIdentity;

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.pAuthInfo = &authInfo;

Тогда я могу позвонить CoCreateInstanceEx с помощью этой информации сервера получить дескриптор (m_IOPCServer) на мой OPC-сервер (IID_IOPCServer).

После получения дескриптора я обнаружил, что необходимо еще раз установить дополнительные разрешения (см. Как работает олицетворение в DCOM?) с этим вызовом:

hr = CoSetProxyBlanket(m_IOPCServer, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
&authIdentity, EOAC_NONE);

После этого я могу успешно получить дескриптор группы товаров OPC:

hr = m_IOPCServer->AddGroup(L"", FALSE, reqUptRate, clientHandle,
NULL, NULL, lcid, &m_hServerGroup, &revisedUptRate,
IID_IOPCItemMgt,(LPUNKNOWN*)&m_IOPCItemMgt);

Тем не менее, когда я пытаюсь использовать этот код:

hr = m_IOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);

Результат 0x80070005 («Доступ запрещен»). Это имеет место, даже если я успешно вызываю CoSetProxyBlanket для m_IOPCItemMgt. Однако если я сначала вызову CoInitializeSecurity, то вызов завершится успешно.

Я считаю, что проблема, связанная с Как работает олицетворение в DCOM? в том смысле, что функция QueryInterface является формой создания объекта, поэтому она не использует ту же защиту, что и другие вызовы методов, такие как AddGroup. Однако в справке Microsoft QueryInterface, согласно примечаниям для разработчика, это звучит так, как будто QueryInterface не должен проверять списки ACL, а при возвращаемых значениях отказ в доступе не упоминается как возможность. Я не думаю, что эта проблема связана с конкретной реализацией, потому что я пробовал свой код на некоторых известных коммерческих серверах OPC (например, Matrikon Simulation Server), а также на OpenOP Light, который не обеспечивает никакой дополнительной безопасности.

Я предполагаю, что мне нужно найти способ повторить эту команду

hr = m_IOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);

но сделайте так, также поставляя authIdentity, Это возможно? Это можно сделать с помощью CoCreateInstanceEx или CoGetClassObject или какого-либо другого COM-вызова?

1

Решение

Не вдаваясь в подробности: CoInitializeSecurity всегда вызывается как минимум один раз для каждого процесса. Это может быть сделано неявно или явно. Если ваш код не выполняет явный вызов, среда выполнения DCOM сделает это за вас с параметрами, заполненными из реестра. Вы можете попытаться настроить соответствующие значения реестра, чтобы заставить DCOm использовать значения, подобные тем, которые использовались в вашем явном вызове. Раздел реестра, в котором хранятся эти значения: «HKEY_LOCAL_MACHINE \ SOFTWARE \ Classes \ AppID {AppID_GUID}». Этот ключ описан здесь:https://msdn.microsoft.com/en-us/library/windows/desktop/ms693736(v=vs.85).aspx

1

Другие решения

Вы должны позвонить CoSetProxyBlanket на каждом новом экземпляре COM-объекта, поэтому в вашем случае вы должны вызывать его даже для m_IOPCItemMgt,

0

По вопросам рекламы [email protected]