Выбрать главу

Когда SCM решает, что должен быть запущен новый серверный процесс, он пытается получить дескриптор защиты NT SECURITY_DESCRIPTOR, описывающий, каким пользователям разрешено запускать серверный процесс. В первую очередь SCM проверяет AppID класса для явной установки прав запуска. Эта установка приходит в форме сериализованного дескриптора защиты NT, который хранится в именованной величине LaunchPermission AppID:

[HKCR\AppID\{27EE6A4D-DF65-1d0-8C5F-0080C73925BA}]

LaunchPermission=<serialized NT security descriptor>

Если эта именованная величина отсутствует, SCM пытается прочитать общие для всей машины права запуска из такой именованной величины:

[HKEY_LOCAL_MACHINE\Software\Microsoft\OLE]

DefaultLaunchPermission=<serialized NT security descriptor>

Обе эти установки могут быть модифицированы с помощью DCOMCNFG.EXE. Если не найден ни один из этих ключей реестра, то COM запретит запуск кому бы то ни было. Если же SECURITY_DESCRIPTOR найден, SCM проверяет идентификатор защиты активизирующей вызывающей программы (формально называемой активизатором – actiuator) по списку разграничительного контроля доступа DACL (Discretionary Access Control List), имеющемуся в дескрипторе, чтобы определить, имеет ли активизатор полномочия на запуск сервера. Если активизатор не имеет необходимых полномочий, то следует отказ на активационный вызов с HRESULT E_ACCESSDENIED, и никаких процессов не запускается. В случае успешной проверки SCM запускает серверный процесс и продолжает выполнение активационного запроса.

Права запуска определяют только, какие пользователи могут или не могут начинать серверные процессы во время активации. Эта проверка всегда выполняется SCM на основе информации, записанной в реестре. Права доступа определяют, какие пользователи могут действительно связываться с объектами серверного процесса. Эта проверка осуществляется библиотекой COM при каждом запросе на установку соединения, приходящем от клиента. Для контроля установок прав доступа к процессу разработчики могут использовать API-функцию CoIntializeSecurity.

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

[HKCR\AppIO\{27EE6A4D-DF65-11d0-8C5F-0080C73925BA}]

AccessPermission=<serialized NT security descriptor>

Ранее объяснялось, что если этот элемент реестра отсутствует, то COM ищет установку по умолчанию для всей машины, а если она также отсутствует, то создается новый список контроля доступа, который включает только принципала серверных процессов и встроенной учетной записи SYSTEM.

Приложения, явно вызывающие CoInitializeSecurity, могут вручную контролировать, каким вызывающим программам разрешен доступ к объектам, экспортируемым данным процессом. По умолчанию первый параметр CoIntializeSecurity принимает указатель на SECURITY_DESCRIPTOR NT. Если вызывающая программа передает в качестве этого параметра нулевой указатель, то COM не будет осуществлять никакого контроля входящих вызовов. Это разрешает вызовы от любого аутентифицированного принципала защиты. Если и клиент, и сервер укажут RPC_C_AUTHN_LEVEL_NONE, то COM разрешит вызовы от кого угодно, независимо от его аутентификации. Если же в вызывающей программе имеется легальный указатель на дескриптор защиты, то COM с помощью DACL этого дескриптора защиты определит, каким вызывающим программам разрешен доступ к объектам процесса. Заголовки SDK определяют так называемый флаг прав (COM_RIGHTS_EXECUTE), который используется при создании DACL для явного разрешения или запрета пользователям на связь с объектами процесса.

Хотя и допускается использовать API-функции Win32 для создания SECURITY_DESCRIPTOR с целью передачи его в CoInitializeSecurity, этот способ контроля доступа к объектам процесса не является предпочтительным, в основном по причине темной природы API-функций защиты Win32. Для упрощения программирования в COM контроля доступа в реализации COM для Windows NT 4.0 Service Pack 2 разработчикам разрешено указывать тот объект COM, который будет использоваться для выполнения проверки доступа при установке новых соединений. Этот объект регистрируется библиотекой COM во время выполнения CoInitializeSecurity и должен реализовать интерфейс IAccessControclass="underline"

[object, uuid(EEDD23EO-8410-11CE-A1C3-08002B2B8D8F)]

interface IAccessControl : IUnknown {

// add access allowed rights for a list of users

// добавляем разрешенные права доступа для списка пользователей

HRESULT GrantAccessRights([in] PACTRL_ACCESSW pAccessList);

// explicitly set the access rights for a list of users

// явно устанавливаем права доступа для списка пользователей

HRESULT SetAccessRights([in] PACTRL_ACCESSW pAccessList

// users+rights

// пользователи + Права

);

// set the owner/group IDs of the descriptor

// устанавливаем идентификаторы владельца/группы для дескриптора

HRESULT Set0wner(

[in] PTRUSTEEW pOwner, // owner ID

// ID владельца

[in] PTRUSTEEW pGroup // group ID

// ID группы

);

// remove access rights for a list of users

// удаляем права доступа для списка пользователей

HRESULT RevokeAccessRights(

[in] LPWSTR lpProperty, // not used

// не используется

[in] ULONG cTrustees, // how many users

// сколько имеется пользователей

[in, size_is(cTrustees)] TRUSTEEW prgTrustees[] // users

// пользователи

);

// get list of users and their rights

// получаем список пользователей и их прав

HRESULT GetAllAccessRights(

[in] LPWSTR lpProperty, // not used

// не используется

[out] PACTRL_ACCESSW *ppAccessList, // users+rights

// пользователи + права

[out] PTRUSTEEW *ppOwner, // owner ID

// ID владельца

[out] PTRUSTEEW *ppGroup // group ID

// ID группы

);

// called by COM to allow/deny access to an object

// вызывается COM для разрешения/запрета доступа к объекту

HRESULT IsAccessAllowed(

[in] PTRUSTEEW pTrustee, // caller's ID

// ID вызывающей программы

[in] LPWSTR lpProperty, // not used

// не используется

[in] ACCESS_RIGHTS Rights, // COM_RIGHTS_EXECUTE

[out] BOOL *pbAllowed // yes/no!

// да/нет!

);

}

Этот интерфейс предназначен для того, чтобы разработчики могли создавать объекты контроля доступа на основе статических таблиц данных, преобразующих имена принципалов в права доступа. Интерфейс основывается на новом Windows NT 4.0 API защиты на базе опекуна (trustee), то есть пользователя, обладающего правами доступа к объекту. Основным типом данных, используемым этим API, является TRUSTEE:

typedef struct _TRUSTEE_W {

struct _TRUSTEE_W *pMultipleTrustee;

MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;

TRUSTEE_FORM TrusteeForm;

TRUSTEE_TYPE TrusteeType;

switch_is(TrusteeForm)]

union {

[case(TRUSTEE_IS_NAME)]

LPWSTR ptstrName;

[case(TRUSTEE_IS_SID)]

SID *pSid;

};

} TRUSTEE_W, *PTRUSTEE_W, TRUSTEEW, *PTRUSTEEW;

Этот тип данных используется для описания принципала защиты. Первые два параметра, pMultipleTrustee и MultipleTrusteeOperation, позволяют вызывающей программе отличать настоящие регистрационные имена (logins – логины) от попыток заимствования прав. Пятый параметр, ptstrName/pSid, содержит либо идентификатор защиты NT (security identifier – SID), либо текстовое имя учетной записи, подлежащее идентификации. При этом третий параметр, TrusteeForm, указывает, какой именно член объединения (union member) используется. Четвертый параметр, TrusteeType, указывает, является ли данный принципал учетной записью пользователя или группы.