Прогон программы создания новой учетной записи

Для иллюстрации рассмотрим несложную программу, задача которой - создать новую учетную запись для пользователя "ExpUser".

#ifndef UNICODE

#define UNICODE

#endif

#include <stdio.h>

#include <windows.h>

#include <lm.h>

BOOL CreateUser(PWSTR pszName, PWSTR pszPassword) {

USER_INFO_1 ui = {0};

NET_API_STATUS nStatus;

ui.usri1_name = pszName; // имя пользователя

ui.usri1_password = pszPassword; // пароль пользователя

ui.usri1_priv = USER_PRIV_USER; // обычный пользователь

nStatus = NetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);

return (nStatus == NERR_Success);

}

void main() {

if(!CreateUser(L"ExpUser", L"123"))

printf("A system error has occurred");

}

Результат работы программы - создание нового пользователя - можно проконтролировать при помощи апплета панели управления "Локальные пользователи". После создания пользователя целесообразно наделить его минимальным набором прав, например, правом входа в систему. Самое разумное - включить пользователя в какую-либо группу, например, в группу обычных пользователей. В этом случае вновь созданный пользователь получит привилегии члена данной группы. Это можно сделать при помощи того же апплета. О том, как обеспечить пользователя необходимыми привилегиями программным образом, будет рассказано ниже.

Для удаления учетной записи пользователя используется функция NetUserDel.

Идентификатор безопасности SID

Структура идентификатора безопасности

SID пользователя (и группы) является уникальным внутренним идентификатором и представляют собой структуру переменной длины с коротким заголовком, за которым следует длинное случайное число. Это числовое значение формируется из ряда параметров, причем утверждается [6], что вероятность появления двух одинаковых SID практически равна нулю. В частности, если удалить пользователя в системе, а затем создать его под тем же именем, то SID вновь созданного пользователя будет уже другим.

Узнать свой идентификатор безопасности пользователь легко может при помощи утилит whoami или getsid из ресурсов Windows. Например, так:

> whoami /user /sid

При помощи команды whoami /all можно получить всю информацию из маркера доступа процесса, см. следующие разделы.

Поскольку структура SID имеет переменную длину, для копирования SID и преобразования его в текстовую форму и обратно рекомендуется прибегать к специальным функциям CopySID, ConvertSidToStringSid и ConvertStringSidToSid.

Чтобы получить бинарное значение SID по имени пользователя, нужно использовать функцию LookupAccountName. Обратная задача может быть решена при помощи функции LookupAccountSid.

Прогон программы получения идентификатора безопасности

В качестве иллюстрации рассмотрим несложную программу, задача которой - получение значения Sid для текущей учетной записи и преобразования его в текстовую форму.

#define _WIN32_WINNT 0x0500

#define UNICODE

#ifdef UNICODE

#define _UNICODE

#endif

#include <windows.h>

#include <stdio.h>

#include <sddl.h>

void main(void){

wchar_t UserName[256];

int MaxUserNameLength = 256;

SID Sid[1024];

PSID pSid;

LPTSTR StringSid;

DWORD SidSize=1024;

SID_NAME_USE SidType;

LPTSTR DomainName=NULL;

DWORD DomainNameSize=16; // длина имени домена

HANDLE hHeap;

hHeap = GetProcessHeap();

pSid = &Sid[0];

GetUserName(UserName, &MaxUserNameLength); // получаем имя пользователя

DomainName = (LPTSTR)HeapAlloc(hHeap,0,DomainNameSize * sizeof(TCHAR));

LookupAccountName(

NULL, // локальный компьютер

UserName, pSid, &SidSize, DomainName,&DomainNameSize,&SidType);

if (!ConvertSidToStringSid(pSid, &StringSid)) /* память для строки выделяет сама функция */

printf("Convert SID to string SID failed.");

wprintf(L"StringSid %s\n", StringSid);

LocalFree(StringSid);

HeapFree(hHeap,0,DomainName);

}

В приведенной программе вначале формируются параметры вызова функции LookupAccountName. В частности, имя текущей учетной записи возвращает функция GetUserName(). Кроме того, необходимо выделить память для имени домена. Результирующее значение SID можно сравнить с тем, которое выдает утилита Whoami.exe.

Объекты. Дескриптор защиты

В ОС Windows все типы объектов защищены одинаковым образом. С каждым объектом связан дескриптор защиты (security descriptor). Дескриптор защиты описывается структурой типа SECURITY_DESCRIPTOR и инициализируется функцией InitializeSecurityDescriptor.

Связь объекта с дескриптором происходит в момент создания объекта. Например, один из аргументов функции CreateFile - указатель на структуру SECURITY_ATTRIBUTES, которая содержит указатель на дескриптор защиты.

Дескриптор защиты (см. рис. 13.1) содержит SID владельца объекта, SID групп для данного объекта и два указателя на списки DACL (Discretionary ACL) и SACL (System ACL) контроля доступа. DACL и SACL содержат разрешающие и запрещающие доступ списки пользователей и групп, а также списки пользователей, чьи попытки доступа к данному объекту подлежат аудиту.

Структура каждого ACL списка проста. Это набор записей ACE (Access Control Entry), каждая запись содержит SID и перечень прав, предоставленных субъекту с этим SID.

Прогон программы создания новой учетной записи - student2.ru

Рис. 13.1. Структура дескриптора защиты для файла

В списке ACL есть записи ACE двух типов - разрешающие и запрещающие доступ. Разрешающая запись содержит SID пользователя или группы и битовый массив (access mask), определяющий набор операций, которые процессы, запускаемые этим пользователем, могут выполнять с данным объектом. Запрещающая запись действует аналогично, но в этом случае процесс не может выполнять перечисленные операции. Битовый массив или маска доступа состоит из 32 битов и обычно формируется программным образом из предопределенных констант, которые описаны в файлах-заголовках компилятора (главным образом в файле WinNT.h).

На примере, изображенном на рис. 13.1, владелец файла Александр имеет право на все операции с данным файлом, всем остальным обычно дается только право на чтение, а Павлу запрещены все операции. Таким образом, список DACL описывает все права доступа к объекту. Если этого списка нет, то все пользователи имеют все права; если этот список существует, но он пустой, права имеет только его владелец.

Кроме списка DACL дескриптор защиты включает также список SACL, который имеет такую же структуру, что и DACL, то есть состоит из таких же ACE записей, только вместо операций, регламентирующих доступ к объекту, в нем перечислены операции, подлежащие аудиту. В примере на рис. 13.1 операции с файлом процессов, запускаемых Сергеем, описанные в соответствующем битовом массиве будут регистрироваться в системном журнале.

Для установки прав доступа к файлу, находящемуся на NTFS разделе диска, нужно выбрать вкладку "Безопасность" апплета "Свойства", который возникает в Windows Explorer при нажатии на ярлык файла правой кнопкой мыши.

Итак, дескриптор защиты имеет достаточно сложную структуру и его формирование выглядит непростой задачей. К счастью, в Windows есть стандартный механизм, назначающий доступ к объектам "по умолчанию", если приложение не позаботилось создать его явно. В таких случаях говорят, что объекту назначена стандартная защита. Примером может служить создание файла при помощи функции CreateFile, где параметру-указателю на структуру SECURITY_ATTRIBUTES присвоено значение NULL. Некоторые объекты используют только стандартную защиту (мьютексы, события, семафоры).

Субъекты хранят информацию о стандартной защите, которая будет назначена создаваемым объектам, в своем маркере доступа (см. следующий раздел). Разумеется, в ОС Windows есть все необходимые средства для настройки стандартной защиты, в частности, списка DACL "по умолчанию", в маркере доступа субъекта.

Основной источник информации о защите объекта - Win32-функция GetSecurityInfo, тогда как настройка защиты объекта может быть осуществлена при помощи функции SetSecurityInfo.

Наши рекомендации