информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
За кого нас держат?Портрет посетителя
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Tailscale окончательно забанила... 
 Прекращение работы антивируса Касперского... 
 Microsoft Authenticator теряет... 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
все доски
FAQ
IRC
новые сообщения
site updates
guestbook
beginners
sysadmin
programming
operating systems
theory
web building
software
hardware
networking
law
hacking
gadgets
job
dnet
humor
miscellaneous
scrap
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
[Win32] Расклад по полочкам внутри. Однако, это нечестно! ;-))) 13.09.02 07:33  Число просмотров: 4408
Автор: HandleX <Александр М.> Статус: The Elderman
Отредактировано 13.09.02 08:00  Количество правок: 1
<"чистая" ссылка>
Может, форуму ещё бабло за тебя на работе получать? Открываешь документацию и читаешь, там всё английским языком написано! ;-)))
Поставь 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 на форуме.
Удачи!
<programming> Поиск 






Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach