Ограничение доступа, права пользователей… Эти слова звучат сладкой музыкой для любого системного администратора, который заботится о безопасности сети, равно как и для пользователя, который следит за конфиденциальностью своей информации. К счастью, в операционных системах Windows NT и Windows 2000 реализованы специальные средства, позволяющие решать многие проблемы защиты информации.

Какие же механизмы включаются, когда мы выбираем пункт меню «Безопасность» из диалогового окна свойств файла? В данной статье я постараюсь ответить на этот вопрос. В качестве примера возьмем технологии получения списка логических дисковых разделов, локальных разделяемых ресурсов, а также рассмотрим две удобные утилиты, одна из которых входит в поставку NT, а вторая - в Resource Kit.

В операционной системe NT существует понятие «защищенный объект» (securable object). Это объект, доступ к которому контролируется и ограничивается операционной системой. В семействе операционных систем производства Microsoft лишь NT и Windows 2000 обеспечивают подобный сервис. К таким объектам относятся: файлы и каталоги файловой системы NTFS; каналы (pipes); процессы и потоки (Process and threads); файлы, спроецированные в память (mapped files); маркеры доступа (access tokens); объекты управления окнами (Window-management objects); разделы реестра (registry keys); службы Win32 (services); принтеры (Printers); разделенные сетевые ресурсы (Network shares); объекты синхронизации процессов (Interprocess synchronization objects - events, mutexes, semaphores, waitable timers); задачи (Job objects).

В модели ограничения доступа Win32 существует два базовых понятия:

Access tokens - маркеры доступа (МД), содержащие информацию о пользователе;

Security descriptors - описатели защиты, содержащие информацию о правах тех или иных учетных записей на доступ к объекту.

При регистрации пользователя в системе после успешной проверки имени и пароля создается маркер доступа. Для каждого процесса, выполняемого далее в контексте этого пользователя, создается копия МД. Маркер доступа содержит множество идентификаторов защиты (security identifiers, SID), определяющих учетные записи пользователя и тех групп, в которые он входит. Кроме того, МД содержит список привилегий (privilege) - прав на доступ к тем или иным объектам, предоставляемых той или иной учетной записи. С помощью этой информации операционная система определяет возможности доступа пользователя к ресурсам.

При создании защищенного объекта ОС присваивает ему описатель защиты (security descriptor, SD) - той защиты, которая имеется у пользователя, создающего объект, или же той, что задана по умолчанию. Приложения Win32 могут использовать функции API как для получения, так и для изменения информации о доступе к объектам.

Security descriptor содержит информацию о владельце объекта, а также может включать следующие списки контроля доступа Access-Contol List (ACL):

Discretionary access-control list (DACL) - разграничительные списки контроля доступа, в которых содержатся пользователи и группы с соответствующими правами на доступ к объекту;

System access-control list (SACL) - системные списки контроля доступа, которые определяют, как осуществляется аудит попыток доступа к объекту.

Список контроля доступа содержит список записей контроля доступа (access-control entries, ACEs). Каждая запись содержит набор битовых флагов и идентификатор SID попечителя (trustee) - пользователя или группы, к которой эти права применены.

Остановимся на упомянутых объектах более подробно.

Security Descriptor

Эти объекты содержат информацию о безопасности, соотнесенную с тем или иным защищенным объектом. Физически этот объект представляет собой структуру SECURITY_DESCRIPTOR, описанную в файле Windows.h:

typedef struct _SECURITY_DESCRIPTOR {
 BYTE Revision;
 BYTE Sbz1;
 SECURITY_DESCRIPTOR_CONTROL Control;
 PSID Owner;
 PSID Group;
 PACL Sacl;
 PACL Dacl;
} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;

Структура SECURITY_DESCRIPTOR используется для доступа к информации о безопасности объектов. Но изменять поля непосредственно в данной структуре невозможно. Для этого необходимо использовать специальные функции (например, SetSecurityDescriptorOwner(…)). Кроме того, Win32 API предоставляет интерфейс для создания и инициализации описателя SD для новых объектов.

Access token

Access token (маркер доступа) - это объект операционной системы, который описывает контекст ограничения доступа к процессу или потоку. Он содержит привилегии, соответствующие учетной записи пользователя, ассоциированного с процессом или потоком. Маркер доступа создается после успешной идентификации пользователя в системе. После этого каждый процесс, который так или иначе запускается данным пользователем, сопровождается копией его маркера.

Идентификатор защиты SID

Уникальный параметр переменной длины, определяющий учетную запись (account) и хранящийся в базе данных системы безопасности Windows NT, - вот что такое SID. В начале каждого сеанса, как только пользователь идентифицирован в системе, его SID извлекается из БД и помещается в маркер доступа. Далее это значение используется операционной системой при всех действиях пользователя с защищенными объектами.

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

NULL - S-1-0-0 - SID группы, в которую не входят пользователи. Используется лишь тогда, когда SID неизвестен;

World - S-1-1-0 - группа, включающая в себя всех пользователей;

Local - S-1-2-0 - пользователи, имеющие непосредственный, физический доступ к системе;

Creator Owner ID - S-1-3-0 - SID, которым заменяется SID пользователя, создавшего объект. Этот SID используется для унаследованных записей ACE (см. ниже);

Creator Group ID - S-1-3-1 - значение, заменяющее SID основной группы, к которой принадлежит пользователь, создавший объект. Этот SID, как и предыдущий, используется для унаследованных записей ACE.

Список управления доступом ACL

ACL представлен структурой, описанной в Windows.h:

typedef struct _ACL { 
 BYTE AclRevision; 
 BYTE Sbz1; 
 WORD AclSize; 
 WORD AceCount; 
 WORD Sbz2; 
} ACL;

Для Windows NT версий 3.5, 3.51, 4.0 определено максимальное число записей управления доступом, задаваемых списком управления доступом (см. статью Q166348 в базе знаний Microsoft). Оно равно 1820.

Запись управления доступом ACE

Система ограничения доступа Windows NT/2000 использует несколько типов записей ACE, которые перечислены в Таблице 1, содержащей, кроме того, и названия соответствующих этим типам структур данных.

Вполне вероятно, что в следующих версиях операционной системы появятся новые типы ACE, да и из приведенных в Таблице 1 некоторые поддерживаются только Windows 2000. Для того чтобы унифицировать процедуру анализа структур ACE, разработчики включили во все структуры _ACE одинаковую последовательность полей, которая отображается в структуре ACE_HEADER:

typedef struct _ACE_HEADER { 
 BYTE AceType; 
 BYTE AceFlags; 
 WORD AceSize; 
} ACE_HEADER; 
typedef ACE_HEADER *PACE_HEADER;

Первое поле AceType определяет тип структуры. Очевидно, что указатель на любую структуру _ACE можно преобразовать в указатель на ACE_HEAER, получить тип ACE, после чего этот указатель преобразовать в указатель на соответствующую полученному типу структуру данных. Замечу, что такой прием широко используется в различных API продуктов Microsoft.

Теперь мы имеем общее представление о том, как устроена система безопасности объектов Windows NT. Попробуем применить эти сведения на практике и написать небольшую программу. В качестве примера используется программа, позволяющая выбрать один или несколько разделов диска, которые будут отсканированы, после чего на основе собранной информации будет создан командный файл, устанавливающий права на объекты выбранного раздела. В сценарий также включается список локальных разделяемых ресурсов с правами доступа к ним. После запуска сценария создаются разделяемые ресурсы, восстанавливаются права доступа к ним и параметры безопасности для объектов файловой системы. Ниже я расскажу лишь о ключевых моментах проекта, относящихся, впрочем, не только к API системы безопасности. Полный текст программы можно найти на http://members.xoom.com/alex_ep/NTSec/sec.zip, а соответствующий дистрибутив, в который входят дополнительные модули и файл справки - на сайте http://members.xoom.com/alex_ep/NTSec/RTPermScan.zip.

Список разделов дисковых устройств

На Листинге 1 показано, как получить список логических дисков. Для этого используется функция Win-API NetServerDiskEnum. Ее первый параметр определяет сетевое имя компьютера, список накопителей которого нас интересует. Если этот параметр NULL, то берется локальный компьютер. Список дисковых накопителей возвращается в параметре lpBuf. Он имеет вид последовательности из 3 байт. Каждая последовательность содержит букву - символ диска, двоеточие и разделитель NULL. Количество прочитанных накопителей возвращается в параметре dwReded, а общее количество дисков - в dwTotal. После обработки буфер lpBuf необходимо освободить вызовом функции NetApi-BufferFree(lpBuf).

В коде Листинга 1 вызывается написанная мной функция GetParti-tionTypeEx. Она получает параметры дискового накопителя, возвращает наименование файловой системы, на нем установленной, и проверяет, поддерживает ли файловая система контроль ограничения доступа (cм. Листинг 2).

В Win32 API для получения информации о дисковом разделе используется функция

BOOL GetVolumeInformation( LPCTSTR
lpRootPathName, LPTSTR lpVolumeNameBuf-fer,
 ВWORD nVolumeNameSize, LPDWORD
 lpVolumeSerialNumber, LPDWORD
 lpMaximumComponent-Length, LPDWORD
 lpFileSystem-Flags, LPTSTR lpFileSystemName-
Buffer, DWORD nFileSystem-NameSize ).

Ее параметры описаны в Таблице 2. Чуть подробнее рассмотрим параметр lpFileSystemFlags. Это набор битовых флагов. Среди прочих определен флаг FS_PERSISTENT_ACLS. Наличие этого флага означает, что папки и файлы раздела являются охраняемыми объектами. Перед тем как получать списки ACE для того или иного объекта, неплохо убедиться, что файловая система их поддерживает. Теперь мы знаем, как это делается.

Более подробное описание данной функции можно найти в MSDN по адресу: http://msdn.microsoft.com/library/psdk/winbase/fsys_6wfi.htm.

Список записей управления доступом для защищенных объектов

Итак, несложная операция просмотра всех объектов файловой системы и выяснения их свойств завершена. Пора обратиться к основному вопросу статьи - созданию механизма получения списков пользовательских прав на доступ к объектам. Как я уже отмечал выше, информация о правах доступа к объекту передается через DACL. Здесь рассматриваются лишь именованные объекты операционной системы, но функции работы с объектами, не имеющими уникального символьного идентификатора, например с потоками, ничем не отличаются от описанных ниже.

Чтобы получить структуру ACL для именованного объекта, нужно задействовать функцию GetNmedSe-curityInfo. Среди прочих значений она возвращает указатели на DACL и SACL. Нас интересует первый из них. Теперь у нас есть вся информация для создания списка ACE. Функция GetAce позволяет пройти по всему списку заголовков ACE_HEADER, соответствующих ACL. Этой функции передаются три параметра. Первый - указатель на ACL, второй - порядковый номер ACE, указатель на который возвращается в третьем параметре (cм. Листинг 3).

Список разделяемых ресурсов и прав для них

Последний вопрос, который я хочу подробно рассмотреть, касается получения списка локальных ресурсов общего доступа (shares) и прав доступа к ним. Процедура получения прав на объекты идентична описанной процедуре получения прав на доступ к файловым объектам. Поэтому реализующий ее код включен в код процедуры, представленной в Листинге 4, и отдельно не обсуждается. Это характерно для API системы безопасности, которая предоставляет обобщенный интерфейс ко всем защищенным объектам. Действительно, с точки зрения системы ограничения доступа Windows разделяемый ресурс - такой же именованный объект, как, например, и файл. Поэтому алгоритмы работы с ними одни и те же.

Список разделяемых ресурсов предоставляется функцией

Win32 API NET_API_STATUS 
NetShareEnum( LPWSTR servername, DWORD level, LPBYTE *
bufptr, DWORD prefmaxlen, DWORD entriesread, LPDWORD
 totalentries, LPDWORD resume_handle )

возвращающей в параметре bufptr указатель на массив структур, который нужно освободить вызовом функции NetBufferFree. Подробное описание этой функции можно найти по адресу: http://msdn.microsoft.com/library/psdk/network/ntlmapi2_4l2l.htm.

Для получения SD ресурса используется функция

NET_API_STATUS NetShareGetInfo( LPWSTR 
servername, LPWSTR netname, DWORD level,
 LPBYTE *bufptr ),

описание которой находится по адресу: http://msdn.microsoft.com/library/psdk/network/ntlmapi2_18bz.htm. В параметре level передается необходимый уровень детализации информации. В соответствии с этим параметром в параметре bufptr возвращается указатель на ту или иную структуру. Уровню детализации 502 соответствует структура SHARE_INFO_502, описанная в файле Lmshare.h:

typedef struct _SHARE_INFO_502 {
 LPWSTR shi502_netname;
 DWORD shi502_type;
 LPWSTR shi502_remark;
 DWORD shi502_permissions;
 DWORD shi502_max_uses;
 DWORD shi502_current_uses;
 LPWSTR shi502_path;
 LPWSTR shi502_passwd;
 DWORD shi502_reserved;
 PSECURITY_DESCRIPTOR shi502_security_descriptor;
} SHARE_INFO_502, *PSHARE_INFO_502, *LPSHARE_INFO_502;

Для получения списка ACE используется поле shi502_security_descriptor, содержащее необходимый Security Descriptor.

Восстановление параметров безопасности

Результатом работы утилиты, которую можно загрузить по указанному адресу, является командный файл. Прекрасно, скажете вы, а что дальше? Вообще говоря, наш файл состоит из двух частей: в первой создаются и устанавливаются права доступа к разделяемым файлам и каталогам, а во второй выясняются параметры безопасности для объектов файловой системы. Для работы с разделяемыми ресурсами из командной строки в Microsoft WindowsNT (R) Resource Kit есть небольшая программа - RMTSHARE.EXE. Сценарий создан с использованием этой программы.

Параметры команды такие:

Rmtshare.exe 
serversharename=drive:path
 [/USERS:number | /UNLIMITED]
    [/REMARK:"text"]
    [/GRANT [user[:perm][ /GRANT
 user[:perm]]]]
    [/REMOVE user]

Для просмотра и установки параметров доступа к объектам NTFS используется утилита cacls.exe, входящая в WinNT.

Cacls.exe filename [/T][/E][/C][/G 
user:perm][/R user [...]][/P user:perm
 [...]] [/D user [...]]

Filename - без других параметров выводит на экран список пользователей и их прав на доступ к объекту Filename.

/T - изменяет список записей управления доступом к объекту, а если это папка, то ко всем вложенным папкам.

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

/C - позволяет продолжить работу в случае ошибки отказа в доступе.

/G user:perm - устанавливает для пользователя, определяемого параметром user, права на доступ к объекту, определяемые параметром perm:

N - нет; R - чтение; W - запись; C - изменение; F - полный контроль.

/R user - удаляет для указанного пользователя права на доступ к объекту.

/P user:perm - изменяет для указанного в параметре user пользователя права на доступ к объекту, которые описываются параметром perm и могут быть следующими:

N - нет; R - чтение; W - запись; C - изменение; F - полный контроль.

/D user - запрещает применять пользователю доступ к указанному объекту.

Утилита позволяет применять маски, например *.*, в именах файлов и папок, а также указывать в одной команде несколько пользователей. В Knowledge Base описан метод использования утилиты cacls.exe для изменения прав доступа не только пользователей, но и групп к объектам файловой системы. В этом случае синтаксис сохраняется, но имена групп берутся в кавычки (Q162786).

Active Directory и доступ к информации о безопасности

В Windows 2000 реализована новая служба качественно меняющая, кроме всего прочего, и механизмы работы с объектами файловой системы. Это Active Directory. Программный интерфейс к ней называется Active Directory Service Interfaces (ADSI). ADSI представляет собой набор COM-объектов, обеспечивающий программный интерфейс к функциям службы Active Directory. Базовые объекты системы безопасности (ACL, SID, ACE и т. д.) в ADSI те же, что и описанные выше. Существенные изменения коснулись лишь механизмов манипуляции с ними. Подробнее об ADSI я планирую рассказать в следующей статье.

Александр ЭПШТЕЙН - разработчик коммерческого и свободно распространяемого ПО для Windows и UNIX. Начальник отдела разработки ПО компании «КиберПлат.КОМ». С ним можно связаться по адресу: alex_ep@hotmail.com.