В качестве примера приведем упрощенную версию утилиты cp(1) , копирующую один файл в другой с использованием отображения файла в память.
#include
#include
#include
#include
#include
main(int argc, char *argv[]) {
int fd_src, fd_dst;
caddr_t addr_src, addr_dst;
struct stat filestat;
/* Первый аргумент - исходный файл, второй - целевой */
fd_dst=open(argv[2], O_RDWR | O_CREAT);
/* Определим размер исходного файла */
fstat(fd_src, &filestat);
/* Сделаем размер целевого файла равным исходному */
lseek(fd_dst, filestat.st_size - 1, SEEK_SET);
/* Зададим отображение */
addr_src=mmap((caddr_t)0, filestat.st_size,
PROT_READ, MAP_SHARED, fd_src, 0);
addr_dst=mmap((caddr_t)0, filestat.st_size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd_dst, 0);
/* Копируем области памяти */
memcpy(addr_dst, addr_src, filestat.st_size);
exit(0);
}
Поскольку, как обсуждалось выше, с помощью вызова mmap(2 ) нельзя изменить размер файла, это было сделано с помощью вызова lseek(2) с последующей записью одного байта так, что размер целевого файла стал равным размеру исходного. При этом в целевом файле образуется "дыра", которая, к счастью, сразу же заполняется содержимым копируемого файла.
Владелец-пользователь и владелец-группа файла могут быть изменены с помощью системных вызовов chown(2) , fchown(2) и lchown(2) :
#include
#include
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fildes, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
Все три вызова работают одинаково за исключением ситуации, когда адресуемый файл является символической связью. В последнем случае вызов lchown(2) действует на сам файл — символическую связь, а не на целевой файл (т.е. не следует символической связи). В функциях chown(2) и lchown(2) файл адресуется по имени, а в fchown(2) — по файловому дескриптору. Если значение owner
или group
установлено равным -1, соответствующий владелец файла не изменяется.
В версиях BSD UNIX только суперпользователь может изменить владение файлом. Это ограничение призвано, в первую очередь, не допустить "скрытие" файлов под именем другого пользователя, например, при установке квотирования ресурсов файловой системы. Владельца-группу можно изменить только для файлов, которыми вы владеете, причем им может стать одна из групп, членом которой вы являетесь. Эти же ограничения определены и стандартом POSIX.1.
В системах ветви System V эти ограничения являются конфигурируемыми, и в общем случае в UNIX System V пользователь может изменить владельца собственных файлов.
В случае успешного изменения владельцев файла биты SUID и SGID сбрасываются, если процесс, вызвавший chown(2 ) не обладает правами суперпользователя.
Как уже обсуждалось в предыдущей главе, каждый процесс имеет четыре пользовательских идентификатора — UID, GID, EUID и EGID. В то время как UID и GID определяют реального владельца процесса, EUID и EGID определяют права доступа процесса к файлам в процессе выполнения. В общем случае реальные и эффективные идентификаторы эквивалентны. Это значит, что процесс имеет те же привилегии, что и пользователь, запустивший его. Однако, как уже обсуждалось выше, возникают ситуации, когда процесс должен получить дополнительные привилегии, чаще всего — привилегии суперпользователя. Это достигается установкой битов SUID и SGID. Примером такого процесса может служить утилита passwd(1) , изменяющая пароль пользователя.
Права доступа к файлу могут быть изменены с помощью системных вызовов chmod(2) и fchmod(2) :
#include
#include
int chmod(const char *path, mode_t mode);
int fchmod(int fildes, mode_t mode);
Значение аргумента mode определяет устанавливаемые права доступа и дополнительные атрибуты (такие как SUID, SGID и Sticky bit), и создается путем логического объединения различных флагов, представленных в табл. 2.14. Вторая колонка таблицы содержит восьмеричные значения для девяти битов прав доступа (чтение, запись и выполнение для трех классов доступа) и трех битов дополнительных атрибутов.
Таблица 2.14. Флаги аргумента mode
Флаг |
Биты |
Значение |
S_ISUID |
04000 |
Установить бит SUID |
S_ISGID |
020#0 |
Установить бит SGID, если # равно 7, 5, 3 или 1. Установить обязательное блокирование файла, если # равно 6, 4, 2 или 0 |
S_ISVTX |
01000 |
Установить Sticky bit |
S_IRWXU |
00700 |
Установить право на чтение, запись и выполнение для владельца-пользователя |
S_IRUSR |
00400 |
Установить право на чтение для владельца-пользователя |
S_IWUSR |
00200 |
Установить право на запись для владельца-пользователя |
S_IXUSR |
00100 |
Установить право на выполнение для владельца-пользователя |
S_IRWXG |
00070 |
Установить право на чтение, запись и выполнение для владельца-группы |
S_IRGRP |
00040 |
Установить право на чтение для владельца-группы |
S_IWGRP |
00020 |
Установить право на запись для владельца-группы |
S_IXGRP |
00010 |
Установить право на выполнение для владельца-группы |
S_IRWXO |
00007 |
Установить право на чтение, запись и выполнение для остальных пользователей |
S_IROTH |
00004 |
Установить право на чтение для остальных пользователей |
S_IWOTH |
00002 |
Установить право на запись для остальных пользователей |
S_IXOTH |
00001 |
Установить право на выполнение для остальных пользователей |
Некоторые флаги, представленные в таблице, уже являются объединением нескольких флагов. Так, например, флаг S_RWXU
эквивалентен S_IRUSR | S_IWUSR | S_IXUSR
. Значение флага S_ISGID зависит от того, установлено или нет право на выполнение для группы (S_IXGRP). В первом случае, он будет означать установку SGID, а во втором — обязательное блокирование файла.
Читать дальше