Шестой параметр функции CoInitializeSecurity, dwImpLevel применяется для импортируемых объектных ссылок. Величина, определенная для этого параметра, устанавливает уровень заимствования прав (impersonation level), используемый для всех объектных ссылок, которые возвращаются функцией CoUnmarshalInterface. Уровень заимствования прав позволяет одному процессу заимствовать атрибуты защиты у другого процесса и отражает степень доверия, которое клиент испытывает к серверу. Этот параметр должен принимать одно из следующих четырех значений, характеризующих уровень заимствования прав:
enum {
// hide credentials of caller from object
// скрываем от объекта полномочия вызывающей программы
RPC_C_IMP_LEVEL_ANONYMOUS = 1,
// allow object to query credentials of caller
// разрешаем объекту запрашивать полномочия вызывающей программы
RPC_C_IMP_LEVEL_IDENTIFY = 2,
// allow use of caller's credentials up to one-hop away
// разрешаем использовать полномочия вызывающей
// программы не далее одной сетевой передачи
RPC_C_IMP_LEVEL_IMPERSONATE = 3,
// allow use of caller's credentials across multiple hops
// разрешаем использовать полномочия вызывающей
// программы в течение нескольких сетевых передач
RPC_C_IMP_LEVEL_DELEGATE = 4
};
Уровень RPC_C_IMP_LEVEL_ANONYMOUS не позволяет реализации объекта обнаружить идентификатор безопасности вызывающей программы[3]. Уровень доверия RPC_C_IMP_LEVEL_IDENTIFY указывает, что реализация объекта может программно определить идентификатор защиты вызывающей программы. Уровень доверия RPC_C_IMP_LEVEL_IMPERSONATE указывает, что сервер может не только определить идентификатор защиты вызывающей программы, но также выполнить операции на уровне операционной системы с использованием полномочий вызывающей программы. На этом уровне доверия объекты могут использовать полномочия вызывающей программы, но имеют доступ только к локальным ресурсам[4]. В противоположность этому, уровень доверия RPC_C_IMP_LEVEL_DELEGATE разрешает серверу доступ как к локальным, так и к удаленным ресурсам с использованием полномочий вызывающей программы. Этот уровень доверия не поддерживается протоколом аутентификации NTLM, но поддерживается протоколом аутентификации Kerberos.
Восьмой параметр функции CoInitializeSecurity, dwCapabilities применим к импортируемым и к экспортируемым объектным ссылкам. Этот параметр является битовой маской, которая может состоять из нуля или более следующих битов:
typedef enum tagEOLE_AUTHENTICATION_CAPABILITIES {
EOAC_NONE = 0х0,
EOAC_MUTUAL_AUTH = 0х1,
// These are only valid for CoInitializeSecurity
// только эти допустимы для CoInitializeSecurity
EOAC_SECURE_REFS = 0х2,
EOAC_ACCESS_CONTROL = 0х4,
EOAC_APPID = 0х8
} EOLE_AUTHENTICATION_CAPABILITIES;
Взаимная аутентификация (EOAC_MUTUAL_AUTH) под NTLM не поддерживается. Она используется для проверки того, что сервер исполняется как ожидаемый принципал. Ссылки защиты (EOAC_MUTUAL_AUTH) указывают, что распределенные вызовы подсчета ссылок COM будут аутентифицироваться для гарантии того, что никакие вражеские агенты не могут испортить счетчик ссылок, используемый OR и администраторами заглушек для управления жизненным циклом. EOAC_ACCESS_CONTROL и EOAC_APPID используются для управления семантикой первого параметра функции CoInitializeSecurity и будут обсуждаться далее в этой главе.
Как было установлено ранее в этом разделе, CoInitializeSecurity вызывается один раз на процесс, явно или неявно. Приложения, желающие вызвать CoInitializeSecurity явно, должны делать это после первого вызова CoInitializeEx, но перед «первым интересным вызовом COM» (first interesting COM call). Фраза «первый интересный вызов COM» относится к любой API-функции, которой может понадобиться OXID. Сюда относятся CoMarshalInterface и CoUnmarshalInterface, а также любые API-вызовы, неявно вызывающие эти функции. Поскольку вызовы CoRegisterClassObject связывают объекты класса с апартаментами, то CoInitializeSecurity должна быть вызвана до регистрации объектов класса. API-функции активации (например, CoCreateInstanceEx) являются любопытным исключением. Активация API-функций для определенных внутренних классов, которые являются частью COM API (например, глобальная интерфейсная таблица, COM-объект контроля доступа по умолчанию) может быть произведена до вызова CoInitializeSecurity. Тем не менее, функция CoInitializeSecurity должна быть вызвана раньше, чем любые активационные вызовы, которые фактически консультируются с реестром и загружают другие DLL или контактируют с другими серверами. Если приложение не вызывает функцию CoInitializeSecurity явно, то COM вызовет ее неявно в качестве первого интересного вызова COM.
Когда COM вызывает функцию CoInitializeSecurity неявно, она читает значения большинства параметров из реестра. Некоторые из этих параметров содержатся в реестровом ключе, общем для всей машины, в то время как остальные записаны под специфическим AppID данного приложения. Чтобы извлечь AppID приложения, COM ищет имя файла процесса приложения под ключом реестра
HKEY_CLASSES_ROOT\AppID
Если COM находит здесь имя файла, она извлекает AppID из именованной величины AppID:
[HKCR\AppID\ServerOfTheApes.exe]
AppID="{27EE6A4D-DF65-11d0-8C5F-0080C73925BA}"
Если никакого соответствия не существует, то COM считает, что приложение не имеет в реестре специфических установок по защите.
Неявные вызовы CoInitializeSecurity находят первый параметр, pSecDesc, путем поиска сериализованного (приведенного в последовательную форму) дескриптора защиты NT SECURITY_DESCRIPTOR в следующей именованной величине:
[HKCR\AppID\{27EE6A4D-DF65-11d0-8C5F-0080C73925BA}]
AccessPermission=<serialized NT security descriptor>
Если эта именованная величина не найдена, то COM ищет общий для всей машины элемент:
[HKEY_LOCAL_MACHINE\Software\Microsoft\OLE]
DefaultAccessPermission=<serialized NT security descriptor>
Оба этих элемента реестра могут быть легко изменены при помощи DCOMCNFG.ЕХЕ. Если не найден ни один из этих элементов реестра, то COM создаст дескриптор защиты (security descriptor), предоставляющий доступ принципалу только вызывающей программы и встроенной учетной записи SYSTEM. COM использует этот дескриптор защиты, чтобы при помощи Win32 API-функции AccessCheck предоставить или запретить доступ к объектам, экспортированным из данного процесса.
3 Во время написания данного текста оба SSP – NTLM и Kerberos – молча принимали это значение, но в действительности повышали его до RPC_C_IMP_LEVEL_IDENTIFY, если имело место соединение с удаленной машиной.
4 Формально уровень RPC_C_IMP_LEVEL_IMPERSONATE разрешает сохранять полномочия вызывающей программы не более чем в течение одной сетевой передачи. Это эффективно ограничивает доступ для удаленных объектов ресурсами только локальной машины объекта.