Как работает олицетворение в DCOM? - PullRequest
14 голосов
/ 25 мая 2011

У меня есть клиентские и серверные приложения DCOM, которые используют маршаллер автоматизации OLE. Они отлично работают при запуске на одном компьютере, но когда сервер находится на другом компьютере, не в том же домене, я получаю E_ACCESSDENIED (0x80070005).

Сервер ПК настроен с помощью dcomcnfg, чтобы предоставить полный доступ к любому объекту DCOM пользователю, чей логин и пароль я указываю на клиенте. ServerApp и его библиотека типов зарегистрированы на сервере ПК.

Библиотека типов также зарегистрирована на клиентском ПК. Я указываю имя сервера непосредственно в ClientApp, поэтому, насколько я понимаю, на клиентском ПК не требуется настройка dcomcnfg.

CreateInstanceEx () с именем сервера, логином, доменом и паролем работает нормально. Он возвращает IUnknown и одновременно запускает ServerApp на серверном ПК.

Но когда я пытаюсь выполнить QueryInterface () для интерфейса, поддерживаемого сервером, я получаю E_ACCESSDENIED.

Анализируя журнал событий безопасности, у меня есть две записи:

Во-первых, успешный вход в сеть пользователем, чьи учетные данные я указал в ClientApp. Это происходит, когда я вызываю CreateInstanceEx ().

Далее, неудачная попытка входа в систему пользователем, под которым я вошел на клиентский ПК . Поскольку два ПК не находятся в домене, этот пользователь неизвестен серверу ПК.

Теперь, зачем, черт возьми, ЭТОТ пользователь заходил на сервер, особенно когда я вызываю QueryInterface всех вещей?

Изучая параметры CreateInterfaceEx, кажется, что происходит какой-то механизм олицетворения. Но неясно, кто кого подражает. Там задействовано ТРИ пользователя:

  1. Пользователь, под которым ServerApp работает на ПК сервера (как настроено в dcomcnfg).

  2. Пользователь, чьи учетные данные ClientApp указывает при подключении.

  3. Пользователь, чьи учетные данные ClientApp работает на клиентском ПК.

Независимо от того, как вы смотрите на это, если № 3 вовлечен, это слишком много для одного пользователя. Если DCOM все равно будет идентифицировать / выдавать себя за № 3 на серверном ПК, зачем мне указывать # 2 учетные данные? До какой точки?

Было бы логично, чтобы DCOM выдавал себя за №2, потому что именно это я и указал в качестве своих учетных данных. Но почему тогда вторая попытка входа?

Может кто-нибудь объяснить, как работает олицетворение, , а также, если есть способ просто проигнорировать его и запустить как пользователь, указанный в dcomcnfg?

Ответы [ 2 ]

13 голосов
/ 25 мая 2011

Отвечая на мой собственный вопрос.После долгих исследований выяснилось, что DCOM имеет ДВА различных случая идентификации :

  1. Авторизация для создания объекта (CoCreateInstanceEx)
  2. Авторизация для вызовов методов.

По неизвестным причинам # 2 не наследует настройки # 1.По умолчанию он использует учетные данные клиентского процесса, и, следовательно, странные имена входа.

Существует два способа указать учетные данные для # 2.Первый CoSetProxyBlanket .Он устанавливает учетные данные только для указанного прокси-сервера (marshaller-unmarshaller):

CoCreateInstanceEx(IID_IObject1, /*login, pass*/, obj1); //Success!
//Logged in and recevied IObject1 proxy in obj1

obj1->DoSomething();
//IObject1 proxy in obj1 now tries to login under process credentials.
//Failure! E_ACCESSDENIED

CoSetProxyBlanket(obj1, /*login, pass*/); //Success!
//IObject1 proxy is now authorized.

obj1->DoSomething(); //Success!
obj1->QueryInterface(IID_IObject2, obj2); //Success!

obj2->DoSomethingElse(); //Failure!
//This different proxy for IObject2 have not yet been authorized.

CoSetProxyBlanket(obj2, /*login, pass*/);
//etc.

Важно отметить, что хотя CoCreateInstanceEx требует, чтобы уровень олицетворения был как минимум IMPERSONATE, CoSetProxyBlanket, похоже, не работает ни с чем, кроме IDENTIFY.

Другой вариант - использовать CoInitializeSecurity для установки учетных данных по умолчанию для всего процесса.Тогда вам не нужно вызывать CoSetProxyBlanket на каждом прокси:

CoInitializeSecurity(/* login, pass */);
CoCreateInstanceEx(IID_IUnknown, /*login, pass*/, obj); //Success!
obj->DoSomething(); //Success!

При использовании CoInitializeSecurity на клиенте вы также должны указать asAuthSvc , хотя MSDN говорит, что вы этого не делаете.

Недостаток этого метода, очевидно, состоит в том, что если у вас есть несколько объектов DCOM с разных компьютеров, вам нужно будет указать все учетные данные в этом вызове, и они, вероятно, будут проверяться на каждом компьютере каждый раз.Вы открываете другой прокси.

Это также не надежно, когда вы работаете из DLL (что если процесс имеет другую безопасность по умолчанию?).Так что, вероятно, лучше реализовать оболочку QueryInterface, которую CoSetsProxyBlanket, прежде чем возвращать после каждого вызова.

0 голосов
/ 02 февраля 2018

Для тех, кто работает в Delphi, есть одна небольшая заметка, которая может сэкономить много вашего времени. После выполнения операции obj as ISomeInterface необходимо вызвать CoSetProxyBlanket для нового экземпляра. Это может быть не очень очевидно, но все мы знаем, что оператор as вызывает метод QueryInterface, и он может возвращать новый экземпляр.

...