Лабораторная работа "Дискреционное управление доступом" - efanov/mephi GitHub Wiki

Содержание

Общие сведения

В ходе выполнения работы Вам потребуется обращаться к man(2) для получения информации о системных вызовах. Если при попытке открыть man(2) Вы получаете ошибки вроде следующей:

No manual entry for open in section 2

Установите man-страницы с помощью

sudo dnf install man-pages

Биты доступа

Описание битов доступа:

Бит доступа Файл Директория
r (чтение) Читать из файла Выводить содержимое директории (только имена файлов)
w (запись) Писать в файл Создавать, удалять, перемещать и переименовывать файлы в директории (также требуется x)
x (исполнение/поиск) Запускать файл на исполнение (файл является программой или сценарием) Читать метаданные файлов в директории (содержимое инодов). Использовать директорию в пути к файлу, переходить в директорию (cd), выводить содержимое директории в длинном формате (ls -l)
u+s (set-user-ID, SUID) Устанавливает эффективный идентификатор пользователя EUID процесса при исполнении файла равным иденти фикатору UID владельца файла Не используется
g+s (set-group-ID, SGID) Устанавливает эффек тивный идентификатор группы EGID процесса при исполнении файла равным идентификатору GID группы файла Устанавливает идентифика тор группы GID для файлов, создаваемых в директории, равным идентификатору группы директории GID (при создании файла, GID наследуется от директории, в которой создается файл)
o+t (sticky) Не используется Удалять или переименовывать файлы в директории может только владелец директории, или владелец файла, или процесс с привилегией CAP_FOWNER (также требуется w)

Чтобы запустить двоичный файл, достаточно только права на исполнение, а для запуска сценария необходимо наличие двух прав: на чтение и на исполнение.

Системные вызовы

Некоторые системные вызовы требуют указания или возвращают права доступа к файлу или тип файла.

Тип файла

Для описания типа файла используются следующие флаги, определённые в заголовочном файле sys/stat.h:

#define S_IFLNK  0120000
#define S_IFREG  0100000
#define S_IFBLK  0060000
#define S_IFDIR  0040000
#define S_IFCHR  0020000
#define S_IFIFO  0010000

Права доступа

Для описания прав доступа к файлу используются следующие флаги, определённые в заголовочном файле sys/stat.h:

#define S_ISUID  0004000
#define S_ISGID  0002000
#define S_ISVTX  0001000

#define S_IRWXU    00700
#define S_IRUSR    00400
#define S_IWUSR    00200
#define S_IXUSR    00100

#define S_IRWXG    00070
#define S_IRGRP    00040
#define S_IWGRP    00020
#define S_IXGRP    00010

#define S_IRWXO    00007
#define S_IROTH    00004
#define S_IWOTH    00002
#define S_IXOTH    00001

Флаги можно комбинировать между собой с помощью операции побитового ИЛИ |. Например, для создания файла может использоваться системный вызов open с перечислением указанных выше флагов для задания прав доступа к нему:

open("some_file", O_CREAT, S_IRWXU | S_IRGRP);

Обработка ошибок

Системные вызовы могут завершиться неудачей. Например, файл, к которому запрашивается доступ, не существует или для его открытия недостаточно прав. Для предотвращения непредсказуемого поведения программы в этих случаях необходимо исследовать результат выполнения системного вызова (вообще, любой функции). Чтобы понять, как обрабатывать результат системного вызова, необходимо прочитать его документацию в man(2).

Например, рассмотрим системный вызов access. В man(2) написано:

...

RETURN VALUE

       On success (all requested permissions granted, or mode is F_OK
       and the file exists), zero is returned.  On error (at least one
       bit in mode asked for a permission that is denied, or mode is
       F_OK and the file does not exist, or some other error occurred),
       -1 is returned, and errno is set to indicate the error.

...

Таким образом, выполнять системный вызов access следует, например, так:

if (-1 == access("some_file", F_OK))
{
    perror("access");
    exit(EXIT_FAILURE);
}

Конечно, действия при ошибке зависят от программы. В данном примере пользователю просто сообщается об ошибке, и выполнение порграммы прерывается с соответствующим кодом ошибки.

Задания

Биты доступа

Просмотр битов доступа и принадлежности файла

Права доступа и принадлежность файла можно просмотреть с помощью команд ls -l, stat. Например:

ls -l /etc/passwd
# Вывод:
# -rw-r--r--. 1 root root 1047 Oct  3 17:53 /etc/passwd

stat /etc/passwd
# Вывод:
#   File: /etc/passwd
#   Size: 1047            Blocks: 8          IO Block: 4096   regular file
# Device: fd00h/64768d    Inode: 33965265    Links: 1
# Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
# Context: system_u:object_r:passwd_file_t:s0
# Access: 2023-10-03 17:53:54.820289385 +0300
# Modify: 2023-10-03 17:53:54.675292727 +0300
# Change: 2023-10-03 17:53:54.688292428 +0300
#  Birth: 2023-10-03 17:53:54.675292727 +0300

Изучите права доступа программы passwd. Объясните их смысл.

Изменение прав доступа к файлам

Для изменения прав доступа к файлу используется системный вызов chmod. Этот вызов возможно выполнять как в Bash, так и напрямую в C. Рассмотрим оба варианта.

В командах ниже предполагается, что в системе существуют два пользователя: ivan (включен в /etc/sudoers) и polina (не включена в /etc/sudoers). Команды выполняются от лица пользователя ivan.

Создадим файл с секретом и сделаем его доступным на чтение только владельцу:

touch file
echo "This is a secret!" > file
chmod 600 file

Попробуем вывести содержимое файла сначала от лица пользователя ivan, а затем — от лица пользователя polina:

cat file
# Вывод:
# This is a secret!

sudo -u polina cat file
# Вывод:
# cat: file: Permission denied

Теперь сделайте так, чтобы polina смогла прочитать содержимое файла file.

Создадим директорию с файлом в ней:

mkdir dir
touch dir/file
echo "File content." > dir/file

Сделайте так, чтобы файл dir/file мог прочитать только тот, кто знает о его существовании.

Задачи

Решите следующие задачи от имени обычного пользователя (не root).

  1. Перейдите в домашний каталог.
  2. Создайте каталог test и перейдите в него.
  3. Создайте файл file, определите его права доступа.
  4. Запретите любые действия с файлом file.
  5. Попробуйте записать строку "test" в файл file. В доступе должно быть отказано.
  6. Попробуйте прочитать файл file. В доступе должно быть отказано.
  7. Измените права доступа для file так, чтобы только текущий пользователь мог осуществлять в него запись. Команда ls -l должна показывать права --w-------.
  8. Запишите строку "test" в файл file. Попробуйте прочитать содержимое файла — в доступе должно быть отказано.
  9. Разрешите группе текущего пользователя читать содержимое файла. Группа текущего пользователя обычно совпадает с именем пользователя. Команда ls -l должна показывать права --w-r-----.
  10. Попробуйте прочитать содержимое файла file. В доступе должно быть отказано.
  11. Разрешите текущему пользователю читать содержимое файла file. Команда ls -l должна показывать права -rw-r-----.
  12. Попробуйте прочитать содержимое файла file — должна появиться ранее добавленная туда строка "test".
  13. Создайте каталог dir. Создайте в этом каталоге файл new_file, запишите в него текст "file 2".
  14. Просмотрите содержимое каталога dir. Должен появиться файл new_file.
  15. Измените права доступа на каталог dir так, чтобы пользователи не имели права на исполнение (x). Попробуйте просмотреть содержимое файла new_file в каталоге dir. В доступе должно быть отказано. Попробуйте удалить этот файл — в доступе также должно быть отказано.
  16. Попробуйте изменить владельца файла file на root. Изменить группу владельца на root. В обоих операциях должно быть отказано — обычный пользователь не может изменить владельца файла.
  17. При помощи команды umask задайте такую маску, чтобы при создании файла никто не имел к нему никакого доступа, кроме владельца. При создании нового файла (команда touch file1) права доступа данного файла будут следующими: -rw-------.
  18. При помощи команды umask задайте такую маску, чтобы при создании файла все имели к данному файлу полный доступ. При создании нового файла (команда touch file2) права доступа данного файла будут следующими: -rw-rw-rw-.
  19. Откройте второе окно с терминалом и выполните вход от имени системного администратора (root):
    su
  20. От имени системного администратора измените владельца файла file на root. Измените права доступа так, чтобы только владелец мог прочитать файл. По окончании изменений выйдите из сеанса root, выполнив команду exit.
  21. Попробуйте прочитать файл file от имени обычного пользователя (не root!). В доступе должно быть отказано.
  22. От имени системного администратора измените права доступа на файл так, чтобы группа могла прочитать данный файл. По окончании изменений выйдите из сеанса root, выполнив команду exit.
  23. Попробуйте прочитать файл file от имени обычного пользователя. Доступ должен быть разрешён.

Программа

Реализуйте программу chmod на языке C с использованием системных вызовов. Вызов программы должен происходить следующим образом:

chmod <number> <file>

Например,

chmod 0644 some_file

Проверьте пользовательский ввод, обработайте ошибки и выведите их в случае возникновения.

Подсказка Для конвертации строки в число можно воспользоваться функцией strtoul (string to unsigned long).

Атрибуты файла

Следующий блок команд выполняется от лица суперпользователя root. Ниже файлу f_append_only устанавливаются атрибуты, позволяющие только дописывать содержимое в конец файла. Подробности в man chattr.

echo abc > f_append_only

echo 123456 > f_append_only

ls -l f_append_only
# Вывод:
# -rw-r--r--. 1 root root 4 Oct 10 19:00 f_append_only

cat f_append_only
# Вывод:
# 123456

chattr +a f_append_only

lsattr f_append_only
# Вывод:
# -----a-------------- f_append_only

Попробуйте изменить/перезаписать файл. Объясните результаты. В каких сценариях это может быть полезно?

Сделайте так, чтобы этот файл нельзя было изменять, переименовывать и удалять, а также чтобы нельзя было создавать на него ссылки и открывать его для записи.

Программа

Напишите программу trigatime на языке C, которая добавляет флаг A (у файла не обновляется время последнего доступа, поле atime инода), если в атрибутах файла он не указан, и убирает этот флаг, если он указан. Пример работы программы:

touch file

lsattr file
# Вывод:
# ---------------------- file

trigatime file

lsattr file
# Вывод:
# -------A-------------- file

trigatime file

lsattr file
# Вывод:
# ---------------------- file
Подсказка Следует использовать системный вызов ioctl. Необходимые константы (например, FS_IOC_GETFLAGS) расположены в заголовочном файле linux/fs.h.

ACL

Для вывода ACL предназначена команда getfacl:

getfacl /etc/passwd
# Вывод:
# getfacl: Removing leading '/' from absolute path names
# # file: etc/passwd
# # owner: root
# # group: root
# user::rw-
# group::r--
# other::r--

Для установки ACL предназначена команда setfacl:

touch file

chmod 600 file

setfacl -m u:polina:r file

ls -l file
# Вывод:
# -rw-r-----+ 1    ivan    ivan 14 Oct  5 18:01 file

getfacl file
# Вывод:
# # file: file
# # owner: ivan
# # group: ivan
# user::rw-
# user:polina:r--
# group::---
# mask::r--
# other::---

Перейдите в директорию /tmp. Создайте папку и сделайте так, чтобы polina по-умолчанию могла изменять содержимое всех создаваемых в ней файлов.

Допуск

  1. Объясните все биты прав доступа в выводе ls -l.
  2. Какая команда используется для изменения прав доступа к файлу?
  3. Кто может изменять права доступа к файлам?
  4. Для чего нужен ACL?
  5. Как устанавливать атрибуты файла?
  6. Может ли пользователь root игнорировать атрибуты файла при работе с ним?

Порядок защиты работы

Для защиты работы необходимо показать написанные программы chmod, trigatime и ответить на вопросы по теме работы.

⚠️ **GitHub.com Fallback** ⚠️