Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab_drsp_07.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
247.81 Кб
Скачать

2.8. Створення маркера обмеженого доступу

Маркером обмеженого доступу називається маркер доступу, який створюється з існуючого маркера доступу, але може мати в порівнянні з оригіналом наступні обмеження:

- деякі ідентифікатори безпеки, які в початковому маркері доступу використовувалися для перевірки дозволу доступу до об'єкту, що охоронявся, в обмежуючому маркері доступу використовуватимуться для перевірки заборони доступу до об'єкту. Тобто ідентифікатор безпеки, що має атрибут se_group_enabled в початковому маркері доступу, матиме атрибут se_group_use_for_deny_only в маркері обмеженого доступу;

- деякі привілеї можуть бути відмінені в маркері обмеженого доступу, хоча вони були дійсні в початковому маркері доступу;

- маркер обмеженого доступу може мати додаткові ідентифікатори безпеки, які використовуються для перевірки дозволу доступу суб'єкта, який представляється цим маркером доступу, до об'єкту, що охороняється; такі ідентифікатори безпеки називаються обмежуючими ідентифікаторами безпеки.

Тобто маркер обмеженого доступу має дві множини пов'язаних з ним ідентифікаторів безпеки. Одна множина ідентифікаторів безпеки наслідується від початкового маркера доступу, а друга — включає обмежуючі ідентифікатори безпеки, які додані в маркер обмеженого доступу при його створенні. Обмеження доступу до об'єкту, що охороняється, за допомогою маркера обмеженого доступу виконується за допомогою того, що система управління безпекою контролює доступ, використовуючи як ідентифікатори безпеки, успадковані маркером обмеженого доступу від початкового маркера, так і обмежуючі маркери, які були додані в маркер обмеженого доступу.

По суті, маркер оюмеженого доступу і визначається наявністю в ньому списку обмежуючих ідентифікаторів безпеки. Якщо цей список пустий, то маркер доступу не вважається за обмежений в доступі до об'єктів, що охороняються.

Маркери обмеженого доступу використовуються:

1) для створення нового процесу за допомогою виклику функції CreateProcessAsUser, який має обмежений контекст безпеки і може мати свій робочий стіл;

2) для обмеження контексту безпеки поточного процесу за допомогою виклику функції ImpersonateLoggedOnUser.

Для створення маркера обмеженого доступу використовується функція CreateRestrictedToken, яка має наступний прототип:

BOOL CreateRestrictedToken(

HANDLE ExistingTokenHandle, // дескриптор початкового маркера доступу

DWORD Flags, // прапор скидання привілеїв

DWORD DisableSidCount, // кількість заборонюючих SID

PSID_AND_ATTRIBUTES SidsToDisable, // масив заборонюючих SID

DWORD DeletePrivilegeCount, // кількість привілеїв, що відміняються

PLUID_AND_ATTRIBUTES PrivilegesToDelete, // масив привілеїв, що відміняються

DWORD RestrictedSidCount, // кількість обмежуючих SID

PSID_AND_ATTRIBUTES SidsToRestrict, // масив обмежуючих SID

PHANDLE NewTokenHandle // покажчик на дескриптор нового

// маркера доступу

);

В разі успішного завершення функція поверне ненульове значення, а в разі невдачі — FALSE. Код помилки в разі невдалого завершення функції можна отримати за допомогою виклику функції GetLastError. Параметри функції CreateRestrictedToken мають наступне призначення.

Параметр ExistingTokenHandle повинен містити дескриптор початкового маркера доступу, який може бути первинним або заміщаючим маркером доступу, а також маркером обмеженого доступу. Даний маркер має бути відкритий в режимі token_duplicate.

У параметрі Flags може бути встановлений прапор disable_max_privilege, який відміняє всі привілеї в маркері обмеженого доступу. Якщо цей прапор встановлений, то функція ігнорує параметри DeletePrivilegeCount і PrivilegesToDelete.

Параметр DisableSidCount повинен містити кількість заборонних ідентифікаторів безпеки в масиві, на який вказує наступний параметр SidsToDisable.

Параметр SidsToDisable повинен вказувати на масив структур типу sid_and_attributes, кожна з яких містить заборонюючий ідентифікатор безпеки, для якого буде встановлений режим se_group_use_for_deny_only в маркері обмеженого доступу. Відзначимо, що ці заборонюючі ідентифікатори мають бути пов'язані з початковим маркером доступу. Функція ігнорує ідентифікатори безпеки, які не пов'язані з початковим маркером доступу. Функція також ігнорує атрибути ідентифікатора безпеки, які встановлені в полі Attributes структури sid_and_attributes. Якщо функція не змінює атрибути дескрипторів безпеки, які пов'язані з початковим маркером доступу, то в цьому параметрі можна встановити значення NULL.

Параметр DeletePrivilegeCount повинен містити кількість привілеїв, що відміняються, в масиві, на який вказує наступний параметр PrivilegesToDelete.

Параметр PrivilegesToDelete повинен вказувати на масив структур типу luid_and_attributes, кожна з яких містить локальний ідентифікатор привілею, який має бути відмінений в маркері обмеженого доступу. Функція ігнорує всі привілеї, які не входять в початковий маркер доступу. Функція також ігнорує атрибути привілеїв, які встановлені в полі Attributes структури типа LUID_AND_ATTRIBUTES.

Якщо функція не відміняє привілею початкового маркера доступу, то в цьому параметрі можна встановити значення NULL.

Параметр RestrictedSidCount повинен містити кількість обмежуючих ідентифікаторів в масиві, на який вказуєє наступний параметр SidsToRestrict.

Параметр SidsToRestrict повинен вказувати на масив структур типу sid_and_attributes, кожна з яких містить обмежуючий ідентифікатор безпеки, який буде пов'язаний з новим маркером обмеженого доступу. Обмежуючі ідентифікатори безпеки не пов'язані з початковим маркером доступу і використовуються тільки для перевірки дозволу доступу маркера обмеженого доступу до об'єкту, що охороняється.

Поле Attributes структури sid_and_attributes повинне містити нульове значення для кожного обмежуючого маркера доступу. Якщо функція не пов'язує з маркером обмеженого доступу обмежуючих ідентифікаторів безпеки, то в цьому параметрі можна встановити значення NULL.

Якщо початковим маркером доступу є маркер обмеженого доступу, то з новим маркером обмеженого доступу будуть зв'язані тільки ті обмежуючі ідентифікатори безпеки, які одночасно пов'язані з початковим маркером обмеженого доступу і знаходяться в масиві, на який вказує параметр SidsToRestrict.

Параметр NewTokenHandle повинен містити адресу змінної типу HANDLE, в яку функція запише дескриптор створеного маркера обмеженого доступу. Створений маркер доступу має той же тип, що і початковий маркер доступу, тобто може бути первинним або заміщаючим маркером доступу. Крім того, для нового маркера доступу встановлені ті ж режими доступу, що і для початкового маркера доступу.

Для перевірки чи є заданий маркер доступу маркером обмеженого доступу використовується функція IsTokenRestricted, яка має наступний прототип:

BOOL IsTokenRestricted(

HANDLE TokenHandie // дескриптор маркера доступу

);

Єдиний параметр цієї функції повинен містити дескриптор маркера доступу, який піддається перевірці на обмеження по доступу до об'єктів, що охороняються. Якщо маркер доступу, який міститься в параметрі TokenHandle, містить список обмежуючих ідентифікаторів безпеки, то функція поверне ненульове значення, інакше — FALSE. Код помилки в разі невдалого завершення функції можна отримати за допомогою виклику функції GetLastError.

У лістингу 7.3.7 (Додаток А) приведена програма, в якій за допомогою функції CreateRestrictedToken створюється маркер обмеженого доступу. Після цього цей маркер перевіряється функцією IsTokenRestricted на обмеженість.

Контрольні запитання

  1. Що таке контроль доступу до ресурсів?

  2. Що таке ідентифікатор привілеїв?

  3. Опишіть структуру маркера доступу?

Завдання на самостійну роботу: ознайомитись з теоретичними відомостями, виконати на комп’ютері завдання і підготувати звіт по роботи.

К.т.н., доцент О. Є. Коваленко

Додаток А. Лістинги програм.

Лістинг 7.3.1. Ініціалізація локального ідентифікатора

#include <windows.h>

#include <stdio.h>

int main()

{

LUID luId; // локальний ідентифікатор

DWORD dwRetCode; // код повернення

// розподіляємо локальний унікальний ідентифікатор

if (!AllocateLocallyUniqueId(

&luId)) // адреса локального ідентифікатора

{

dwRetCode = GetLastError();

perror("Lookup privilege value failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// роздруковуємо LUID

printf("Locally unique identifier.\n");

printf("\tHigh part: %x, Low part: %x\n", luId.HighPart, luId.LowPart);

return 0;

}

Лістинг 7.3.2. Визначення локального ідентифікатора і імені привілею

#include <windows.h>

#include <stdio.h>

int main()

{

LUID luId; // локальний ідентифікатор для привілею

DWORD dwLength = 0; // довжина імені привілею

LPTSTR lpPrivName = NULL; // адреса імені привілею

DWORD dwRetCode; // код повернення

// визначуваний локальний ідентифікатор привілею

if (!LookupPrivilegeValue(

NULL, // шукаємо привілеї на локальній машині

SE_DEBUG_NAME, // привілей виконувати відладку процесу

&luId)) // адреса локального ідентифікатора привілею

{

dwRetCode = GetLastError();

perror("Lookup privilege value failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// роздруковуємо LUID

printf("Luid of SE_DEBUG_NAME privilege. ");

printf("High part: %x, Low part: %x\n", luId.HighPart, luId.LowPart);

// визначаємо довжину імені привілею

if (!LookupPrivilegeName(

NULL, // локальна машина

&luId, // адреса локального унікального ідентифікатора

lpPrivName, // адреса імені привілею

&dwLength)) // адреса довжини буфера

{

dwRetCode = GetLastError();

if (dwRetCode != ERROR_INSUFFICIENT_BUFFER)

{

perror("Lookup privilege name failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// захоплюємо пам'ять для імені привілею

lpPrivName = new CHAR[dwLength + 1];

}

// визначаємо ім'я привілею

if (!LookupPrivilegeName(

NULL, // локальна машина

&luId, // адреса локального унікального ідентифікатора

lpPrivName, // адреса імені привілею

&dwLength)) // адреса довжини буфера

{

dwRetCode = GetLastError();

perror("Lookup privilege name failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// роздруковуємо ім'я привілею

printf("Name of the Luid: %s\n", lpPrivName);

delete[] lpPrivName;

return 0;

}

Лістинг 7.3.3. Визначення зручного для відображення імені привілею

#include <windows.h>

#include <stdio.h>

int main()

{

LPTSTR lpPrivDisplayName = NULL; // адреса імені привілею для відображення

DWORD dwLength = 0; // довжина імені привілею

DWORD dwLangId; // ідентифікатор мови

DWORD dwRetCode; // код повернення

// визначаємо довжину імені привілею для відображення

if (!LookupPrivilegeDisplayName (

NULL, // локальна машина

SE_SHUTDOWN_NAME, // ім'я привілею

lpPrivDisplayName, // адреса для імені привілею

&dwLength, // адреса довжини буфера

&dwLangId)) // адреса ідентифікатора мови

{

dwRetCode = GetLastError();

if (dwRetCode != ERROR_INSUFFICIENT_BUFFER)

{

perror("Lookup privilege display name failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// захоплюємо пам'ять для імені привілею

lpPrivDisplayName = new char[dwLength + 1];

}

// визначаємо ім'я привілею для відображення

if (!LookupPrivilegeDisplayName (

NULL, // локальна машина

SE_SHUTDOWN_NAME, // ім'я привілею

lpPrivDisplayName, // адреса для імені привілею

&dwLength, // адреса довжини буфера

&dwLangId)) // адреса ідентифікатора мови

{

dwRetCode = GetLastError();

perror("Lookup privilege display name failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// роздруковуємо ім'я привілею і ідентифікатор мови

printf("Display name of the privilege SE_SHUTDOWN_NAME:\n\t%s\n", lpPrivDisplayName);

printf("Language identifier: %x\n", dwLangId);

delete[] lpPrivDisplayName;

return 0;

}

Лістинг 7.3.4. Визначення джерела маркера доступу

#include <windows.h>

#include <stdio.h>

int main()

{

HANDLE hProcess; // дескриптор процесу

HANDLE hTokenHandle; // дескриптор маркера доступу

TOKEN_SOURCE ts; // джерело маркера доступу

DWORD dwRetLength; // довжина буфера, що повертається

DWORD dwRetCode; // код повернення

// отримуємо дескриптор процесу

hProcess = GetCurrentProcess();

// відкриваємо маркер доступу процесу

if (!OpenProcessToken(

hProcess, // дескриптор процесу

TOKEN_QUERY_SOURCE, // доступ до джерела маркера

&hTokenHandle)) // дескриптор маркера

{

dwRetCode = GetLastError();

printf( "Open process token failed: %u\n", dwRetCode);

return dwRetCode;

}

// отримуємо джерело маркера доступу

if (!GetTokenInformation(

hTokenHandle, // дескриптор маркера доступу

TokenSource, // отримуємо джерело маркера доступу

&ts, // адреса буфера для джерела

sizeof(ts), // розмір буфера

&dwRetLength)) // необхідний розмір буфера в разі невдачі

{

dwRetCode = GetLastError();

printf( "Get token information failed: %u\n", dwRetCode);

return dwRetCode;

}

// роздруковуємо джерело маркера доступу

printf("Source name: ");

for (int i = 0; i < TOKEN_SOURCE_LENGTH; ++i)

putchar(ts.SourceName[i]);

putchar('\n');

printf("Source identifier: %X %X\n", ts.SourceIdentifier.HighPart,

ts.SourceIdentifier.LowPart);

CloseHandle(hTokenHandle);

return 0;

}

Лістинг 7.3.5. Визначення привілеїв маркера доступу

#include <windows.h>

#include <stdio.h>

int main()

{

HANDLE hProcessToken; // дескриптор маркера доступу

PTOKEN_PRIVILEGES lpTokenPrivileges = NULL;

LPTSTR lpPrivName = NULL; // адреса імені привілею

LPTSTR lpPrivDisplayName = NULL; // адреса імені привілею для

// відображення

DWORD dwLangId;

DWORD dwLength;

DWORD dwRetCode; // код повернення

if (!OpenProcessToken(

GetCurrentProcess(), // дескриптор процесу

TOKEN_QUERY, // читання інформації з маркера доступу

&hProcessToken )) // дескриптор маркера доступу

{

dwRetCode = GetLastError();

perror("Set security descriptor owner failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// отримуємо довжину буфера для привілеїв

if (!GetTokenInformation(

hProcessToken, // дескриптор маркера доступу

TokenPrivileges, // отримуємо привілеї

lpTokenPrivileges, // адреса буфера

0, // довжина буфера

&dwLength)) // необхідна довжина

{

dwRetCode = GetLastError();

if (dwRetCode != ERROR_INSUFFICIENT_BUFFER)

{

perror("Get token information for length failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// захоплюємо пам'ять для імені привілею

lpTokenPrivileges = (TOKEN_PRIVILEGES*)new char[dwLength];

}

// отримуємо привілеї маркера доступу

if (!GetTokenInformation(

hProcessToken, // дескриптор маркера доступу

TokenPrivileges, // отримуємо привілеї

lpTokenPrivileges, // адреса буфера

dwLength, // довжина буфера

&dwLength)) // необхідна довжина

{

dwRetCode = GetLastError();

perror("Get token information failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// роздруковуємо привілеї

printf( "User privileges: \n" );

for( unsigned i = 0; i < lpTokenPrivileges->PrivilegeCount; ++i)

{

// друкуємо стан привілею

if ((lpTokenPrivileges->Privileges[i].Attributes &

SE_PRIVILEGE_ENABLED) == SE_PRIVILEGE_ENABLED)

printf("SE_PRIVILEGE_ENABLED:\n");

if ((lpTokenPrivileges->Privileges[i].Attributes &

SE_PRIVILEGE_ENABLED_BY_DEFAULT) ==

SE_PRIVILEGE_ENABLED_BY_DEFAULT)

printf("SE_PRIVILEGE_ENABLED_BY_DEFAULT:\n");

if ((lpTokenPrivileges->Privileges[i].Attributes &

SE_PRIVILEGE_USED_FOR_ACCESS) == SE_PRIVILEGE_USED_FOR_ACCESS)

printf("SE_PRIVILEGE_USED_FOR_ACCESS:\n");

if (!lpTokenPrivileges->Privileges[i].Attributes)

printf("The privilege is disabled:\n");

// визначаємо довжину імені привілею

dwLength = 0;

if (!LookupPrivilegeName(

NULL, // локальна машина

&(lpTokenPrivileges->Privileges[i].Luid), // адреса LUID

lpPrivName, // адреса імені привілею

&dwLength)) // адреса довжини буфера

{

dwRetCode = GetLastError();

if (dwRetCode != ERROR_INSUFFICIENT_BUFFER)

{

perror("Lookup privilege name for length failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// захоплюємо пам'ять для імені привілею

lpPrivName = new char[dwLength + 1];

}

// визначаємо ім'я привілею

if (!LookupPrivilegeName(

NULL, // локальна машина

&(lpTokenPrivileges->Privileges[i].Luid), // адреса LUID

lpPrivName, // адреса імені привілею

&dwLength)) // адреса довжини буфера

{

dwRetCode = GetLastError();

perror("Lookup privilege name failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// визначаємо довжину імені привілею для відображення

dwLength = 0;

if (!LookupPrivilegeDisplayName (

NULL, // локальна машина

lpPrivName, // ім'я привілею

lpPrivDisplayName, // адреса для імені привілею

&dwLength, // адреса довжини буфера

&dwLangId)) // адреса ідентифікатора мови

{

dwRetCode = GetLastError();

if (dwRetCode != ERROR_INSUFFICIENT_BUFFER)

{

perror("Lookup privilege display name for length failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// захоплюємо пам'ять для імені привілею

lpPrivDisplayName = new char[dwLength + 1];

}

// визначаємо ім'я привілею для відображення

if (!LookupPrivilegeDisplayName (

NULL, // локальна машина

lpPrivName, // ім'я привілею

lpPrivDisplayName, // адреса для імені привілею

&dwLength, // адреса довжини буфера

&dwLangId)) // адреса ідентифікатора мови

{

dwRetCode = GetLastError();

perror("Lookup privilege display name failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// роздруковуємо ім'я привілею і ідентифікатор мови

printf("\t%s\n", lpPrivDisplayName);

// звільняємо пам'ять

delete[] lpPrivName;

delete[] lpPrivDisplayName;

lpPrivName = NULL;

lpPrivDisplayName = NULL;

}

CloseHandle(hProcessToken);

return 0;

}

Лістинг 7.3.6. Створення списку DACL об'єкту за умовчанням

#define _WIN32_WINNT 0x0500

#include <windows.h>

#include <stdio.h>

#include <lm.h>

#include <sddl.h>

int main()

{

HANDLE hMutex; // дескриптор м’ютекса

HANDLE hProcess; // дескриптор процесу

HANDLE hTokenHandle; // дескриптор маркера доступу

ACL *lpDacl; // покажчик на список доступу

void *lpAce = NULL; // покажчик на елемент списку

BOOL bDaclPresent; // ознака присутності списку DACL

BOOL bDaclDefaulted; // ознака списку DACL за умовчанням

char chUserName[UNLEN]; // ім'я користувача

DWORD dwLengthOfDomainName = 0; // довжина імені домена

DWORD dwLengthOfSid = 0; // довжина дозволяючого SID

DWORD dwDaclLength = 0; // довжина списку доступу

DWORD dwRetLength = 0; // довжина буфера, що повертається

SID *lpSid = NULL; // покажчик на дозволяючий SID

LPTSTR lpDomainName = NULL; // покажчик на ім’я домен

SID_NAME_USE typeOfSid; // тип облікового запису

PSECURITY_DESCRIPTOR lpSd = NULL; // покажчик на SD

DWORD dwLengthOfSd = 0; // довжина дескриптора безпеки

LPTSTR StringSid; // покажчик на рядок SID

DWORD dwRetCode; // код повернення

// отримуємо дескриптор процесу

hProcess = GetCurrentProcess();

// відкриваємо маркер доступу процесу

if (!OpenProcessToken(

hProcess, // дескриптор процесу

TOKEN_QUERY | // отримуємо інформацію з маркера доступу

TOKEN_ADJUST_DEFAULT, // і змінюємо список DACL маркера доступу

&hTokenHandle)) // дескриптор маркера

{

dwRetCode = GetLastError();

printf( "Open process token failed: %u\n", dwRetCode);

return dwRetCode;

}

// вводимо ім'я користувача, якому дозволимо доступ до каталога

printf("Input а user name: ");

gets(chUserName);

// визначаємо довжину SID користувача

if (!LookupAccountName(

NULL, // шукаємо ім'я на локальному комп'ютері

chUserName, // ім'я користувача

NULL, // визначуваний довжину SID

&dwLengthOfSid, // довжина SID

NULL, // визначуване ім'я домена

&dwLengthOfDomainName, // довжина імені домена

&typeOfSid)) // тип облікового запису

{

dwRetCode = GetLastError();

if (dwRetCode == ERROR_INSUFFICIENT_BUFFER)

{

// розподіляємо пам'ять для SID і імені домена

lpSid = (SID*) new char[dwLengthOfSid];

lpDomainName = (LPTSTR) new char[dwLengthOfDomainName];

}

else

{

// виходимо з програми

printf("Lookup account name failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

}

// визначувані SID і ім'я домена користувача

if(!LookupAccountName(

NULL, // шукаємо ім'я на локальному комп'ютері

chUserName, // ім'я користувача

lpSid, // покажчик на SID

&dwLengthOfSid, // довжина SID

lpDomainName, // покажчик на ім’я домен

&dwLengthOfDomainName, // довжина імені домена

&typeOfSid)) // тип облікового запису

{

dwRetCode = GetLastError();

printf("Lookup account name failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// перетворення SID в рядок

if (!ConvertSidToStringSid(

lpSid

&StringSid))

{

dwRetCode = GetLastError();

printf("Convert sid to string sid failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// печатем SID

printf("%s\n",StringSid);

LocalFree(StringSid);

// визначаємо довжину списку DACL

dwDaclLength = sizeof(ACL)

+ sizeof(ACCESS_ALLOWED_ACE)

- sizeof(DWORD)+ dwLengthOfSid;

// розподіляємо пам'ять під DACL

lpDacl = (ACL*)new char[dwDaclLength];

// ініціалізація списку DACL

if (!InitializeAcl(

lpDacl, // адреса DACL

dwDaclLength, // довжина DACL

ACL_REVISION)) // версія DACL

{

dwRetCode = GetLastError();

printf("Lookup account name failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// додаємо дозволяючий елемент в список DACL

if (!AddAccessAllowedAce(

lpDacl, // адреса DACL

ACL_REVISION, // версія DACL

GENERIC_ALL, // дозволяємо всі родові права доступу

lpSid)) // адреса SID

{

dwRetCode = GetLastError();

perror("Add access allowed ACE failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// встановлюємо новий DACL за умовчанням в маркер доступу

if (!SetTokenInformation(

hTokenHandle, // дескриптор маркера доступу

TokenDefaultDacl, // встановлюємо список DACL

&lpDacl, // адреса буфера з новим списком DACL

dwDaclLength)) // розмір буфера

{

dwRetCode = GetLastError();

printf( "Set token information failed: %u\n", dwRetCode);

return dwRetCode;

}

// створюємо м’ютекс

hMutex = CreateMutex(NULL, FALSE, "DemoMutex");

if (hMutex == NULL)

{

dwRetCode = GetLastError();

perror("Create mutex failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

printf("The mutex is created.\n");

// звільняємо пам'ять

delete[] lpSid;

delete[] lpDomainName;

delete[] lpDacl;

// тепер перевіряємо список DACL м’ютекса

// визначаємо необхідну довжину буфера

if (!GetKernelObjectSecurity(

hMutex, // дескриптор м’ютекса

DACL_SECURITY_INFORMATION, // одержуємо список DACL м’ютекса

lpSd, // адреса SD

0, // визначаємо довжину буфера

&dwLengthOfSd)) // необхідна довжина буфера

{

dwRetCode = GetLastError();

if (dwRetCode == ERROR_INSUFFICIENT_BUFFER)

// розподіляємо пам'ять для буфера

lpSd = (SECURITY_DESCRIPTOR*) new char[dwLengthOfSd];

else

{

// виходимо з програми

printf("Get kernel object security failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

}

// читаємо ідентифікатор безпеки м’ютекса

if (!GetKernelObjectSecurity(

hMutex, // дескриптор м’ютекса

DACL_SECURITY_INFORMATION, // одержуємо список DACL м’ютекса

lpSd, // адреса SD

dwLengthOfSd, // довжина буфера

&dwLengthOfSd)) // необхідна довжина буфера

{

dwRetCode = GetLastError();

printf("Get kernel object security failed.\n");

printf("The last error code: %u\n", dwRetCode);

return dwRetCode;

}

// одержуємо список DACL з дескриптора безпеки

if (!GetSecurityDescriptorDacl(

lpSd, // адреса дескриптора безпеки

&bDaclPresent, // ознака присутності списку DACL

&lpDacl, // адреса покажчика на DACL

&bDaclDefaulted)) // ознака списку DACL за умовчанням

{

dwRetCode = GetLastError();

printf("Get security descriptor DACL failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// перевіряємо, чи є DACL

if (!bDaclPresent)

{

printf("Dacl is not present.\n");

return 0;

}

else

printf("Dacl is present.\n");

// перевіряємо, чи встановлений DACL користувачем

if (bDaclDefaulted == SE_DACL_DEFAULTED)

printf("Dacl is defaulted.\n");

else

printf("Dacl is not defaulted.\n");

// друкуємо кількість елементів

printf("Ace count: %u\n", lpDacl->AceCount);

// одержуємо елементи списку DACL

for (unsigned i = 0; i < lpDacl->AceCount; ++i)

{

if (!GetAce(

lpDacl, // адреса DACL

i, // індекс елементу

&lpAce)) // покажчик на елемент списку

{

dwRetCode = GetLastError();

printf("Get ACE failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// виводимо на друк тип елементу і SID

if (((ACE_HEADER*)lpAce)->AceType == ACCESS_ALLOWED_ACE_TYPE)

{

printf("ACCESS_ALLOWED_ACE_TYPE\n");

// перетворюємо SID в рядок

if (!ConvertSidToStringSid(

&((ACCESS_ALLOWED_ACE*)lpAce)->SidStart,

&StringSid))

{

dwRetCode = GetLastError();

printf("Convert sid to string sid failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// друкуємо SID

printf("%s\n",StringSid);

LocalFree(StringSid);

}

}

// звільняємо пам'ять

delete[] lpSd;

CloseHandle(hMutex);

CloseHandle(hTokenHandle);

return 0;

}

Лістинг 7.3.7. Створення і перевірка маркера обмеженого доступу

#include <windows.h>

#include <stdio.h>

#include <lm.h>

int main()

{

HANDLE hProcess; // дескриптор процесу

HANDLE hToken; // дескриптор маркера доступу

HANDLE hRestrict; // дескриптор обмежуючого маркера доступу

char chUserName[UNLEN]; // ім'я користувача

DWORD dwLengthOfUserName = UNLEN; // довжина імені облікового запису

DWORD dwLengthOfSID = 0; // довжина SID

DWORD dwLengthOfDomainName = 0; // довжина імені домена

SID *lpSid = NULL; // покажчик на SID

LPTSTR lpDomainName = NULL; // покажчик на ім’я домен

SID_NAME_USE type_of_SID; // тип облікового запису

SID_AND_ATTRIBUTES RestrictingSid; // обмежуючий SID

DWORD dwRetCode; // код повернення

// отримуємо дескриптор процесу

hProcess = GetCurrentProcess();

// отримуємо маркер доступу процесу

if (!OpenProcessToken(

hProcess, // дескриптор процесу

TOKEN_ALL_ACCESS, // повний доступ до маркера доступу

&hToken)) // дескриптор маркера

{

dwRetCode = GetLastError();

printf( "Open process token failed: %u\n", dwRetCode);

return dwRetCode;

}

printf("Input а user name: ");

gets(chUserName); // вводимо ім'я користувача

// визначаємо довжину SID користувача

if (!LookupAccountName(

NULL, // шукаємо ім'я на локальному комп'ютері

chUserName, // ім'я користувача

NULL, // визначаємо довжину SID

&dwLengthOfSID, // довжина SID

NULL, // визначаємо ім'я домена

&dwLengthOfDomainName, // довжина імені домена

&type_of_SID)) // тип облікового запису

{

dwRetCode = GetLastError();

if (dwRetCode == ERROR_INSUFFICIENT_BUFFER)

{

// розподіляємо пам'ять для SID і імені домена

lpSid = (SID*) new char[dwLengthOfSID];

lpDomainName = (LPTSTR) new wchar_t[dwLengthOfDomainName];

}

else

{

// виходимо з програми

printf("Lookup account name failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

}

// визначаємо SID і ім'я домена користувача

if(!LookupAccountName(

NULL, // шукаємо ім'я на локальному комп'ютері

chUserName, // ім'я користувача

lpSid, // покажчик на SID

&dwLengthOfSID, // довжина SID

lpDomainName, // покажчик на ім’я домен

&dwLengthOfDomainName, // довжина імені домена

&type_of_SID)) // тип облікового запису

{

dwRetCode = GetLastError();

printf("Lookup account name failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// ініціалізуємо обмежуючий SID

RestrictingSid.Sid = lpSid;

RestrictingSid.Attributes = 0;

// створюємо обмежуючий маркер доступу

if (!CreateRestrictedToken(

hToken, // дескриптор початкового маркера доступу

0, // привілею не змінюємо

0, NULL, // прапор SE_GROUP_USE_FOR_DENY_ONLY не встановлюємо

0, NULL, // привілею не видаляємо

1, // один обмежуючий SID

&RestrictingSid, // адреса обмежуючого SID

&hRestrict)) // адреса обмежуючого маркера доступу

{

dwRetCode = GetLastError();

printf("Create restricted token failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// перевіряємо заміщення маркера доступу

if (IsTokenRestricted(hRestrict))

printf("The restricted token is created.\n");

else

{

dwRetCode = GetLastError();

printf("Is Token Restricted failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// заміщаємо контекст безпеки потоку

if (!ImpersonateLoggedOnUser(hRestrict))

{

dwRetCode = GetLastError();

printf("Impersonate logged on user failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

// тут робимо якусь роботу

printf("Some work is done.\n");

// повертаємо початковий контекст

if (!RevertToSelf())

{

dwRetCode = GetLastError();

printf("Revert to self failed.\n");

printf("Error code: %d\n", dwRetCode);

return dwRetCode;

}

CloseHandle(hToken);

return 0;

}

36

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]