REQUEST_KEY(2) | Вызовы системы управления ключами Linux | REQUEST_KEY(2) |
request_key - запрашивает ключ из системы управления ключами ядра
#include <sys/types.h> #include <keyutils.h>
key_serial_t request_key(const char *type, const char *description, const char *callout_info, key_serial_t dest_keyring);
В glibc нет обёрточной функции для данного системного вызова; смотрите ЗАМЕЧАНИЯ.
Системный вызов request_key() пытается найти ключ заданного type с описанием (именем), совпадающим с description. Если ключ найти невозможно, то ключ может быть создан. Если ключ найден или создан, то request_key() присоединяет его к связке ключей, чей идентификатор указан keyring, и возвращает серийный номер ключа.
Сначала request_key() выполняет рекурсивный поиск совпадающего ключа во всех связках ключей, присоединённых к вызвавшему процессу. Связки ключей просматриваются в следующем порядке: связки каждой нити, связки вызвавшего процесса и связки ключей сеанса.
Если request_key() вызван из программы, вызванной request_key() от имени какого-то другого процесс для генерации ключа, то в дальнейшем будет осуществлён поиск по связкам ключей этого другого процесса, используя для определения доступа его идентификатор пользователя, группы и дополнительных групп и контекста безопасности.
Поиск в дереве связок ключей выполняется сначала в ширину: искомые ключи в каждой связке проверяются на совпадение до рекурсивного перехода в дочерние связки ключей. Найдены могут быть только те ключи, которые разрешены вызывающему для поиска, и поиск может осуществляться только в разрешённых для поиска связках ключей.
Если ключ не найден и callout равно NULL, то вызов завершается ошибкой ENOKEY.
Если ключ не найден и callout не равно NULL, то ядро пытается вызвать пользовательскую программу для создания ключа. Подробности приведены ниже.
Серийный номер dest_keyring может задаваться серийным номером допустимой связки ключей, на которую у вызывающего есть права на запись, или же это может быть один из следующих специальных идентификаторов связок ключей:
Если dest_keyring равно 0 и создание ключа не выполнено, то дополнительных связей не появляется.
В противном случае, если dest_keyring равно 0 и создан новый ключ, то новый ключ будет прицеплен в связку ключей «по умолчанию». Более точно, когда ядро пытается определить в какую связку ключей должен быть прицеплен то только что созданный ключ, оно перебирает связки ключей начиная с со связки, установленной через keyctl(2) с операцией KEYCTL_SET_REQKEY_KEYRING и продолжает в порядке, показанном далее, пока не найдёт существующую связку ключей:
Если вызов keyctl(2) с операцией KEYCTL_SET_REQKEY_KEYRING установил KEY_REQKEY_DEFL_DEFAULT (или операция KEYCTL_SET_REQKEY_KEYRING не выполнялась), то ядро ищет связку ключей начиная с начала списка.
Если ядро не может найти ключ с соответствующим type и description, и callout не равно NULL, то ядро пытается вызвать программу из пользовательского пространства для создания ключа с заданными type и description. В этом случае выполняются следующие шаги:
Если какой-то из этих шагов завершается ошибкой, то вызвавшему request_key() возвращается ENOKEY и временно в связку ключей dest_keyring будет установлен отрицательно инициализированный ключ. Он устареет через несколько секунд, но пока этого не произойдёт все последующие вызовы request_key() будут завершаться ошибкой. Целью данного отрицательно инициализированного ключа является предотвращение повторяющихся запросов (возможно разными) процессами (они требуют затратных восходящих вызовов request-key(8)) для ключа, который невозможно (в данный момент) положительно инициализировать.
После инициализации ключа, ключ авторизации (KEY_SPEC_REQKEY_AUTH_KEY) отзывается и связка ключей назначения (KEY_SPEC_REQUESTOR_KEYRING) становится недоступной программе request-key(8).
Если ключ создан, то независимо от какой он — корректный или отрицательно инициализированный — вытеснит любой другой ключ с тем же типом и описанием из связки ключей dest_keyring.
При успешном выполнении request_key() возвращается серийный номер найденного или созданного ключа. При ошибке возвращается -1, а в errno содержится код ошибки.
Данный системный вызов впервые появился в Linux 2.6.10. Возможность инициализации ключей по запросу была добавлена в Linux 2.6.13.
Этот системный вызов является нестандартным расширением Linux.
В glibc нет обёрточной функции для этого системного вызова. Такая функция предоставляется пакетом libkeyutils. Для работы с функцией подключите библиотеку с помощью -lkeyutils.
В программе, представленной ниже, показано использование request_key(). Аргументы type, description и callout_info для системного вызова берутся из значений, переданных в аргументах командной строки. В качестве связки ключей назначения вызов использует связку ключей сеанса.
Чтобы показать работу программы сначала нужно создать подходящую запись в файле /etc/request-key.conf.
$ sudo sh # echo 'create user mtk:* * /bin/keyctl instantiate %k %c %S' \ > /etc/request-key.conf # exit
Эта запись говорит о том, что когда должен быть создан новый ключ «user» с префиксом «mtk:», задача должна выполняться посредством команды keyctl(1) с операцией instantiate. Аргументы, передаваемые операции instantiate: идентификатор неинициализированного ключа (%k); исходящие данные, переданные в вызов request_key() (%c); связка ключей сеанса (%S) запрашивающего (т. е., вызывающий request_key()). Описание значений % смотрите в request-key.conf(5).
Теперь запускаем программу и проверяем содержимое /proc/keys, чтобы удостовериться, что запрашиваемый ключ создан:
$ ./t_request_key user mtk:key1 "Payload data" $ grep '2dddaf50' /proc/keys 2dddaf50 I--Q--- 1 perm 3f010000 1000 1000 user mtk:key1: 12
Другой пример смотрите использования этой программы смотрите в keyctl(2).
/* t_request_key.c */ #include <sys/types.h> #include <keyutils.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { key_serial_t key; if (argc != 4) { fprintf(stderr, "Использование: %s тип описание callout-data\n", argv[0]); exit(EXIT_FAILURE); } key = request_key(argv[1], argv[2], argv[3], KEY_SPEC_SESSION_KEYRING); if (key == -1) { perror("request_key"); exit(EXIT_FAILURE); } printf("ID ключа = %lx\n", (long) key); exit(EXIT_SUCCESS); }
keyctl(1), add_key(2), keyctl(2), keyctl(3), capabilities(7), keyrings(7), keyutils(7), persistent-keyring(7), process-keyring(7), session-keyring(7), thread-keyring(7), user-keyring(7), user-session-keyring(7), request-key(8)
Файлы исходного кода ядра Documentation/security/keys/core.rst и Documentation/keys/request-key.rst (или, до Linux 4.13, файлы Documentation/security/keys.txt и Documentation/security/keys-request-key.txt).
2019-03-06 | Linux |