Последняя редакция: 31.07.07

Идентификаторы учетных записей в Windows 2000 / XP / 2003 / VISTA

Эта небольшая статья посвящена одной из структур данных операционной системы, с которой связаны операции управления учетными записями, контроля доступа, аудита и другие функции безопасности Windows. Эта структура носит имя SID (Security Identifier).

Согласно описанию из Platform SDK, SID - это структура данных переменной длины, которая идентифицирует учетную запись пользователя, группы или компьютера. Каждой учетной записи ставится в соответствие уникальный идентификатор, SID, в момент создания учетной записи. Система оперирует с SID'ами учетных записей, а не их именами.

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

Уникальность SIDа обеспечивается его образованием из двух полей: AUTHORITY и SUBAUTHORITY. Первое поле имеет фиксированную длину и определяет класс учетной записи, второе поле имеет переменную длину и идентифицирует учетную запись внутри класса. Поле SUBAUTHORITY может иметь нулевую длину, в этом случает SID идентифицирует класс учетных записей.

В Platform SDK структура SID определяется следующим образом:

typedef struct _SID {
   BYTE  Revision;
   BYTE  SubAuthorityCount;
   SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
   DWORD SubAuthority[1];
} SID, *PISID;
Revision - версия SID. Это поле должно быть равно константе SDK SID_REVISION (1).
SubAuthorityCount - количество слов (DWORD'ов) в поле SubAuthority.
IdentifierAuthority - поле AUTHORITY.
SubAuthority - поле SUBATHORITY.

Согласно описанию структуры SID, AUTHORITY представляется как структура SID_IDENTIFIER_AUTHORITY, определенная в Platform SDK следующим образом:

typedef struct _SID_IDENTIFIER_AUTHORITY {
    BYTE  Value[6];
} SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY;
Таким образом, AUTHORITY представляется последовательностью из 6 байт. В Platform SDK определены константы для инициализации значения SID AUTHORITY при построении или анализе SID:

#define SECURITY_NULL_SID_AUTHORITY         {0,0,0,0,0,0}
#define SECURITY_WORLD_SID_AUTHORITY        {0,0,0,0,0,1}
#define SECURITY_LOCAL_SID_AUTHORITY        {0,0,0,0,0,2}
#define SECURITY_CREATOR_SID_AUTHORITY      {0,0,0,0,0,3}
#define SECURITY_NON_UNIQUE_AUTHORITY       {0,0,0,0,0,4}
#define SECURITY_NT_AUTHORITY               {0,0,0,0,0,5}
#define SECURITY_RESOURCE_MANAGER_AUTHORITY {0,0,0,0,0,9}
Кроме того, существует ещё один, недокументированный в Platform SDK AUTHORITY:

#define SECURITY_INTERNET_AUTHORITY         {0,0,0,0,0,7}
Эти константы можно использовать, например, при инициализации объявленного экземпляра структуры:

SomeFunction()
{
	SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
}


SUBAUTHORITY - поле, переменной длины, состоящее из слов (DWORD'ов), количество которых хранится в структуре SID. Объявление поля в структуре как:

  DWORD SubAuthority[1];
позволяет обращаться к любому DWORD'у в SubAuthority, не прибегая к приведению указателей. Но при этом размер структуры SID без SUBAUTHORITY должен вычисляться как

(sizeof(SID) - sizeof(DWORD))
т.к. в структуре объявлен один DWORD поля SUBAUTHORITY.

Ранее отмечалось, что минимальная длина SUBAUTHORITY - 0 слов. Максимальная длина определяется константой Platform SDK SID_MAX_SUB_AUTHORITIES (15).

Максимальный размер (в байтах), необходимый для хранения SID, можно вычислить следующим образом:

((sizeof(SID) - sizeof(DWORD)) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES)
Если известно количество слов в SUBAUTHORITY, то размер SID можно вычислить следующим образом:

((sizeof(SID) - sizeof(DWORD)) + sizeof(DWORD)*SubAuthorityCount)


Для отображения бинарных данных SID'ов, их можно представлять в виде строки следующего формата:

S-R-I-s-s...
где: S - неизменный идентификатор строкового представления SID;
R - SID_REVISION (1);
I - значение SID AUTHORITY;
s - значения слов поля SUBAUTHORITY. В строковом представлении каждая s соответствует одному DWORD'у из SUBATHORITY

SID группы "Администраторы" для локального компьютера в виде строки выглядит следующим образом: S-1-5-32-544
В этой записи:
1 - SID_REVISION;
5 - значение AUTHORITY (соответствует SECURITY_NT_AUTHORITY);
32 - значение первого слова SUBAUTHORITY;
544 - значение второго слова SUBAUTHORITY.
Количество слов в SUBAUTHORITY - 2.

SID учетной записи "ВСЕ" ("Everyone") в виде строки выглядит следующим образом: S-1-1-0
В этой записи:
1 - SID_REVISION;
1 - значение AUTHORITY (соответствует SECURITY_WORLD_SID_AUTHORITY);
0 - значение первого слова SUBAUTHORITY.
Количество слов в SUBAUTHORITY - 1.

SID учетной записи "Псевдодомен NT" ("NT Pseudo Domain") в виде строки выглядит следующим образом: S-1-5
В этой записи:
1 - SID_REVISION;
5 - значение AUTHORITY (соответствует SECURITY_NT_AUTHORITY);
Количество слов в SUBAUTHORITY - 0.

SID некоторого пользователя локального компьютера в виде строки может выглядеть следующим образом: S-1-5-21-789336058-484763869-725345543-1003
В этой записи:
1 - SID_REVISION;
5 - значение AUTHORITY (соответствует SECURITY_NT_AUTHORITY);
21 - значение первого слова SUBAUTHORITY;
789336058 - значение второго слова SUBAUTHORITY;
484763869 - значение третьего слова SUBAUTHORITY;
725345543 - значение четвертого слова SUBAUTHORITY;
1003 - значение пятого слова SUBAUTHORITY.
Количество слов в SUBAUTHORITY - 5.



В системе существует специальный SID для обозначения идентификатора сессии (logon SID). Этот SID можно использовать в списках контролях доступа для контроля доступа к объектам пользователей, интерактивно работающих в системе в текущий момент. SID идентификатора сессии существует, пока пользователь не вышел из системы. При каждом новом входе в систему генерируется другой logon SID. Права доступа для Logon SID установлены на оконную станцию WinSta0, отображающую окна пользовательских программ во время его сеанса работы в системе. При запуске графической программы от имени другого пользователя, следует добавлять права доступа на оконную станцию для Logon SID'а этого пользователя, для того, чтобы окна программы могли отображаться. Эти действия выполняются при запуске процесса от имени другого пользователя функцией CreateProcessAsUser.

Знание структуры SID позволяет выявить список встроенных учетных записей Windows. Для получения списка следует в цикле заполнить поля структуры SID и попытаться получить имя учетной записи, для которой был заполнен SID (с помощью LookupAccountName, возвращающей имя учетной записи по SID). Список полученных таким образом встроенных учетных записей в разных Windows приведен в таблице.

Встроенные учетные записи Windows


SID	 Имя                              2000   XP  2003 VISTA

S-1-0-0	 NULL SID                           -    +    +    +

S-1-1-0	 Все
         Everyone                           +    +    +    +

S-1-2-0	 ЛОКАЛЬНЫЕ
         LOCAL                              +    +    +    +

S-1-3-0	 СОЗДАТЕЛЬ-ВЛАДЕЛЕЦ
         CREATOR OWNER                      +    +    +    +

S-1-3-1	 ГРУППА-СОЗДАТЕЛЬ
         CREATOR GROUP                      +    +    +    +

S-1-3-2	 СОЗДАТЕЛЬ-ВЛАДЕЛЕЦ СЕРВЕР
         CREATOR OWNER SERVER               +    +    +    +

S-1-3-3	 ГРУППА-СОЗДАТЕЛЬ СЕРВЕР
         CREATOR GROUP SERVER               +    +    +    +

S-1-5	 Псевдодомен NT
         NT Pseudo Domain                   +    +    +    +

S-1-5-1	 УДАЛЕННЫЙ ДОСТУП
         DIALUP                             +    +    +    +

S-1-5-2	 СЕТЬ
         NETWORK                            +    +    +    +

S-1-5-3	 ПАКЕТНЫЕ ФАЙЛЫ
         BATCH                              +    +    +    +

S-1-5-4	 ИНТЕРАКТИВНЫЕ 
         INTERACTIVE                        +    +    +    +

S-1-5-6	 СЛУЖБА
         SERVICE                            +    +    +    +

S-1-5-7	 АНОНИМНЫЙ ВХОД
         ANONYMOUS LOGON                    +    +    +    +

S-1-5-8	 PROXY                              +    +    +    +

S-1-5-9	 КОНТРОЛЛЕРЫ ДОМЕНА ПРЕДПРИЯТИЯ 
         ENTERPRISE DOMAIN CONTROLLERS      +    +    +    +

S-1-5-10 SELF                               +    +    +    +

S-1-5-11 Прошедшие проверку
         Authenticated Users                +    +    +    +

S-1-5-12 ОГРАНИЧЕННЫЕ
         RESTRICTED                         +    +    +    +

S-1-5-13 ПОЛЬЗОВАТЕЛЬ СЕРВЕРА ТЕРМИНАЛОВ
         TERMINAL SERVER USER               +    +    +    +

S-1-5-14 REMOTE INTERACTIVE LOGON           -    +    +    +

S-1-5-15 Данная организация
         This Organization                  -    -    +    +

S-1-5-17 IUSR                               -    -    -    +

S-1-5-18 SYSTEM                             +    +    +    +

S-1-5-19 LOCAL SERVICE                      -    +    +    +

S-1-5-20 NETWORK SERVICE                    -    +    +    +

S-1-5-22 КОНТРОЛЛЕРЫ ДОМЕНА ПРЕДПРИЯТИЯ, 
         ДОСТУПНЫЕ ТОЛЬКО ДЛЯ ЧТЕНИЯ ДЛЯ 
         БЕТА ВЕРСИИ                        -    -    -    +

S-1-7    Internet$                          +    +    +    +

S-1-16   Обязательная метка                 -    -    -    +

S-1-16-0 Ненадежный обязательный уровень    -    -    -    +



Для управления SID программисты Microsoft предусмотрели несколько функций (см. таблицу).

Функции для управления SID'ами


Назначение             Функция из ntdll.dll          Функция из advapi32.dll
                       (недокументирована в PSDK)    (документирована в PSDK)

Выделяет память и 
инициализирует SID     RtlAllocateAndInitializeSid   AllocateAndInitializeSid

Переводит SID в 
строковую форму 
представления          RtlConvertSidToUnicodeString  ConvertSidToStringSid

Копирует SID           RtlCopySid                    CopySid

Сравнивает два SID'а 
без учета последнего 
слова в SUBATHORITY    RtlEqualPrefixSid             EqualPrefixSid

Сравнивает два SID'а   RtlEqualSid                   EqualSid

Освобождает память, 
выделенную при инициа-
лизации SID'а соответ-
ствующей функцией      RtlFreeSid                    FreeSid

Возвращает значение 
AUTHORITY для SID      RtlIdentifierAuthoritySid     GetSidIdentifierAuthority

Инициализирует SID     RtlInitializeSid              InitializeSid

Вычисляет необходимый 
размер памяти для 
хранения SID           RtlLengthRequiredSid          GetSidLengthRequired

Возвращает размер SID  RtlLengthSid                  GetLengthSid

Возвращает количество 
слов в SUBATHORITY     RtlSubAuthorityCountSid       GetSidSubAuthorityCount

Возвращает все слова
SUBATHORITY            RtlSubAuthoritySid            GetSidSubAuthority

Проверяет SID на 
корректность           RtlValidSid                   IsValidSid

Переводит SID из 
строковой формы пред-
ставления в бинарную                                 ConvertStringSidToSid

Создает SID встроенной 
учетной записи                                       CreateWellKnownSid

Проверяет, является ли 
указанный SID иденти-
фикатором встроенной 
учетной записи                                       IsWellKnownSid

Сравнивает два SID'а 
и выявляет, принадлежат 
ли учетные записи с 
этими SID'ами одному 
домену                                               EqualDomainSid


При написании этой статьи были замечены некоторые особенности в работе функций по управлению SID'ами.
Например, функция IsValidSid проверяет поле Revision не полностью, а только младшие четыре байта и считает верными SID'ы с установленными в поле Revision значениями такими как 0x41, 0xF1 и т.д. При этом функция ConvertSidToStringSid переводит в строку только SID'ы с "правильным" Revision, равным 0x01.
Функция ConvertSidToStringSid некорректно переводит в строковую форму SID'ы, содержащие ненулевые значения в первых двух байтах AUTHORITY. Например, для двух SID'ов с пустым SUBAUTHORITY и AUTHORITY равным {0,1,0,0,0,0} для первого SID'а, {0,0,0,0,0,10} - для второго SID'а, строка, возвращенная функцией, будет одинакова: "S-1-10".
AddAccessAllowedAce позволяет добавить в DACL запись с неверным SID (в SID неверным является поле Revision, равное например, 0x41). Но установить SECURITY DESCRIPTOR с таким DACL на объект невозможно (функция установки прав доступа возвращает ошибку, указывая на неверный формат данных). Но AddAccessAllowedAce запрещает создавать записи контроля доступа с SID, если в Revision неверны 4 младших бита (например, Revision равен 0x0F).


Ссылки:
Access Control Overview
Basic Access Control Functions




Размещение статьи на других сайтах - только с разрешения автора
Запрещено использование исходного кода с этого сайта в коммерческом ПО с закрытым кодом
Вопросы по материалам статьи можно задать по почте: ntinside [at] yandex.ru

Copyright (C) Fur, 2007
Хостинг от uCoz