Может, форуму ещё бабло за тебя на работе получать? Открываешь документацию и читаешь, там всё английским языком написано! ;-)))
Поставь MSDN, бездна информации, которая заставить тебя задумываться и хохотать, хохотать и задумываться не одну неделю ;-)))
Я с Security под Delphi работаю, это вам не интерфейсы юзать (Не в обиду коё-кому будет сказано, это шутка такая ;-))), а Low-Level Security API.
Итак, Security Descriptor (SD). Это структура в памяти компьютера, которая хранит в себе информацию о том, что может делать с объектом (которому принадлежит этот SD) тот или иной пользователь.
Вот её описание:
typedef struct _SECURITY_DESCRIPTOR {
BYTE Revision;
BYTE Sbz1;
SECURITY_DESCRIPTOR_CONTROL Control;
PSID Owner;
PSID Group;
PACL Sacl;
PACL Dacl;
} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
typedef PVOID PSECURITY_DESCRIPTOR;
---
Revision — признак, по которому мелкософт определяет степень "древности" дескриптора. Дело в том, что времена меняются, и степень "навороченности" дескриптора должна меняться вместе с ним. В настоящее время равен 1. Редко кому прийдётся менять этот байт, поскольку мелкософт говорит, что вааще, не правьте SD руками, а правьте его с помощью функций API. В частности, функция InitializeSecurityDescriptor инициализирует свежий, с пылу-с жару пустой SD ;-) И ещё одно маленькое отступление. Если прочитать про InitializeSecurityDescriptor, то можно встретить странные слова про какие-то там Absolute и Self-Relative форматы SD. Можно заметить, что многие поля в структуре SD — это указатели другие структуры, к примеру, DACL (о нём чуть попозже). Так вот, в Absolute SD все эти указатели "настоящие", т.е. указывают на реальный адрес памяти, откуда начинается та или иная структура. А в Self-Relative SD эти указатели являются смещениями от начала самого SD, и для того, чтобы вычислить реальный адрес, надо к адресу начала SD прибавить это смещение. Придуман сей механизм как раз для того, чтобы Self-Relative SD можно было бы без лишних телодвижений сбросить в какое-нибудь хранилище (к примеру, в файл), а потом безболезненно его оттуда считать и выдать на-гора клиенту. В частности, в файловой системе NTFS эти дескрипторы для каждого файла/каталога хранятся именно в этом формате где-то в её недрах, и когда вы вызываете GetFileSecurity, он вам выдаётся примерно таким же макаром. Более того, мелкософт пишет, что практически все SD, возвращаемые с помощью функций API, имеют формат Self-Relative, а когда вы толкаете SD системе, то он должен быть Absolute. Но на практике, система практически во всех случаях адекватно воспринимает Self-Relative SD, а если нет, то вы обязательно узнаете об этом, вызвав GetLastError ;-) Тут резонен следующий вопрос: а как сама система узнаёт, какого типа SD вы ей впихнули? Смотреть ниже ;-)
Sbz1 — хрен знает что это такое ;-) Возможно, это размер SD. Повторяю, не пытайтесь заполнять поля SD вручную.
Control — это поле содержит кучу битовых флагов, определяющие свойства SD и его частей. К примеру флаг SE_DACL_PRESENT говорит о том, что в этом SD заполнено поле DACL, а флаг SE_SELF_RELATIVE — угадайте — да, конечно, именно о том, что это есть Self-Relative SD. Работают с этими флагами с помощью функций GetSecurityDescriptorControl и операциями чтения бита по маске ;-), в частности, перелопатив MSDN, можно заметить, что нет функции типа SetSecurityDescriptorControl, из чего делаем вывод, что юзверю НЕТ нужды править эти флаги. И ещё одно отступление. Казалось бы что проще — прочитать какое-то долбанное поле типа DWORD в структуре? Для чего нужна функция GetSecurityDescriptorControl? Опять же, мелкософт не гарантирует, что следующие поколения SD будут иметь это поле по этому смещению, и вообще, будет ли оно. А функция API будет жить и здравствовать в следующих поколениях OS. Хотя, я почти уверен, что если бы Microsoft кардинальным образом изменила структуру SD и оставила нормально работающие функции API, то всё равно половина trhird-party софта перестала бы работать корректно с Security, поскольку слишком велик соблазн обратится по типу MySD.Control, чем вызывать какие-то Security API ;-))
Owner — это указатель на SID создателя-владельца защищаемого объекта. SID — это по-английски означает Security Identifyer, и отвечает он на вопрос "кто это?" ;-) То есть SID однозначно определяет пользователя или группу. После того, как в NT был создан пользователь или группа, тон он/она получают уникальный SID. Но про SID — это уже offtopic, тема эта достаточно интригующая и обширная ;-) Итог: когда вы в Проводнике WinNT совершаете акт вандализма под названием "Take Ownership", то этому полю присваивается именно ваш SID ;-) Читается/устанавливается это поле с помощью функций GetSecurityDescriptorOwner и SetSecurityDescriptorOwner.
Group — гм-м-м. Это крайне пространное поле полностью называется Primary Group. Вообще, в мелкософт его завели из-за навязанной ей правительством США совместимостью со стандартом POSIX. Это поле играет некоторую роль при создании нового защищённого объекта, и, соответственно Primary Group SID к нему. Об этом можно прочитать в Базе Глюков мелкософт по этому ID: Q126629. Я так нихрена и не понял ;-)))) Читается/устанавливается это поле с помощью функций GetSecurityDescriptorGroup и SetSecurityDescriptorGroup.
SACL — вот пошли действительно серьёзные вешщи :-) Это — Великий и Ужасный System Access Control List. В переводе означает, что это есть Системный Список Контроля Доступа. Занимается он тем, что хранит в себе информацию о том, когда надо "стучать" про то, что кто-то там что-то делает с защищённым объектом. В Журнал Безопасности NT информация попадает именно в зависимости от того, что находится в SACL. SACL есть структура, формат её такой:
typedef struct _ACL {
BYTE AclRevision;
BYTE Sbz1;
WORD AclSize;
WORD AceCount;
WORD Sbz2;
} ACL;
typedef ACL *PACL;
---
Но опять же, знание этой структуры нужно нам только теоретически, посколько очень рекомендуется работать с ней только с помощью API. В этой структуре самое важное это список так называемых ACE. ACE — это Access Control Entry, и они тоже суть структуры. Бывают они разные, но для SACL это будет SYSTEM_AUDIT_ACE.
typedef struct _SYSTEM_AUDIT_ACE {
ACE_HEADER Header;
ACCESS_MASK Mask;
DWORD SidStart;
} SYSTEM_AUDIT_ACE;
typedef struct _ACE_HEADER {
BYTE AceType;
BYTE AceFlags;
WORD AceSize;
} ACE_HEADER;
typedef ACE_HEADER *PACE_HEADER;
---
В этой структуре хранится чаще всего SID юзверя и тип события, при котором наступает Audit Event. То есть если SID Васи Пупкина "канает" (почему "канает" а не равен? Да потому что может быть указан SID группы, к примеру, которой принадлежит юзверь и тогда его SID "канает". Есть особые функция API, которая проверяет эквивалентность одного SID другому — EqualPrefixSid и EqualSid), и тип доступа к объекту, который запросил Вася, "проходит" по полю Mask, и тип Ace (он указан в поле AceFlags SUCCESSFUL_ACCESS_ACE_FLAG и FAILED_ACCESS_ACE_FLAG) соответствует успешности получения доступа к объекту, то это событие записывается в системный журнал безопасности. Читается\устанавливается поле SACL при помощи функций GetSecurityDescriptorSacl и SetSecurityDescriptorSacl.
DACL — ну наконец, добрались... Это, пожалуй самая "вкусная" часть SD. В переводе с аглицкого "discretionary access-control list" будет что-то вроде "списка разделения доступа". Именно в зависимости от того, что находится в DACL, процесс пользователя может получить доступ к объекту, или получить отказ. Структура DACL такая же, что и у SACL, только Ace'ы другие. Чаще всего это структуры ACCESS_ALLOWED_ACE и ACCESS_DENIED_ACE.
typedef struct _ACCESS_ALLOWED_ACE {
ACE_HEADER Header;
ACCESS_MASK Mask;
DWORD SidStart;
} ACCESS_ALLOWED_ACE;
typedef struct _ACCESS_DENIED_ACE {
ACE_HEADER Header;
ACCESS_MASK Mask;
DWORD SidStart;
} ACCESS_DENIED_ACE;
---
Можно увидеть, что они совершенно одинаковы. Может возникнуть вопрос: а как узнать что это за конкретный ACE, на который мы получили указатель? Эта информация хранится в структуре ACE_HEADER, которая одинаково присутствует у всех типов ACE. Там в полях AceType и AceFlags мы всё и узнаем ;-)
Итак, как работает DACL. Предположим, Вася Пупкин вызывает функцию CreateFile в которой говорит, что нужно открыть C:\ntldr с флагом GENERIC_WRITE ;-)
Система в конце концов начнёт проверку доступа. Состоит он в переборе сперва всех Ace в DACL, которые суть ACCESS_DENIED_ACE. Если SID Васи Пупкина проканает и тип запрошенного доступа (GENERIC_WRITE) тоже будет в поле Mask у Ace'а, то система тут же обломит Васю с доступом. После чего система начнёт проверять все ACCESS_ALLOWED_ACE на предмет того, канает ли его SID и запрошенный тип доступа в поле Mask. И если канает хотя бы в одном Ace, то разрешает доступ. Ну а если не канает до конца перебора, то в доступе отказывает. Функций для работы с DACL много — InitializeAcl, GetExplicitEntriesFromAcl, GetAclInformation, GetAce, AddAccessAllowedAce, AddAccessDeniedAce, AddAce и прочая, и прочая, есть где развернуться ;-)
Ну вот, в общем то и хватит для общего развития ;-) Вернёмся же к нашим баранам. Было необходимо сохранить для файла его SD, чтобы впоследствии в случае краха этот SD восстановить заново. Для этого нужно для файла вызвать функцию GetFileSecurity, получить SD для файла. Причём, при вызове тебе нужно указывать в поле RequestedInformation флаги OWNER_SECURITY_INFORMATION, GROUP_SECURITY_INFORMATION, DACL_SECURITY_INFORMATION и SACL_SECURITY_INFORMATION. Надеюсь, после всего вышеизложенного, уже понятно почему. Потом, после вызова GetSecurityDescriptorLength спокойно заталкиваем наш многострадальный SD в хранилище, поскольку он имеет формат Self-Relative. Ну, я думаю обратная операция уже будет понятна, особенно если вспомнить о существовании приятной во всех отношениях функции SetFileSecurity ;-)
Написание сего текста заняло где-то час моего времени, который ты тоже мог бы спокойно и с пользой потратить сидя в поисковике. Просто я надеюсь, что эти мои перлы снизят количество вопросов и недоразумений по Security API на форуме.
Удачи!
|