Scroll to navigation

request_key(2) System Calls Manual request_key(2)

ИМЯ

request_key - запрашивает ключ из системы управления ключами ядра

БИБЛИОТЕКА

Linux Key Management Utilities (libkeyutils, -lkeyutils)

СИНТАКСИС

#include <keyutils.h>
key_serial_t request_key(const char *type, const char *description,
                         const char *_Nullable callout_info,
                         key_serial_t dest_keyring);

ОПИСАНИЕ

Системный вызов request_key() пытается найти ключ заданного type с описанием (именем), совпадающим с description. Если ключ найти невозможно, то ключ может быть создан. Если ключ найден или создан, то request_key() присоединяет его к связке ключей, чей идентификатор указан keyring, и возвращает серийный номер ключа.

Сначала request_key() выполняет рекурсивный поиск совпадающего ключа во всех связках ключей, присоединённых к вызвавшему процессу. Связки ключей просматриваются в следующем порядке: связки каждой нити, связки вызвавшего процесса и связки ключей сеанса.

Если request_key() вызван из программы, вызванной request_key() от имени какого-то другого процесс для генерации ключа, то в дальнейшем будет осуществлён поиск по связкам ключей этого другого процесса, используя для определения доступа его идентификатор пользователя, группы и дополнительных групп и контекста безопасности.

Поиск в дереве связок ключей выполняется сначала в ширину: искомые ключи в каждой связке проверяются на совпадение до рекурсивного перехода в дочерние связки ключей. Найдены могут быть только те ключи, которые разрешены вызывающему для поиска, и поиск может осуществляться только в разрешённых для поиска связках ключей.

Если ключ не найден и callout равно NULL, то вызов завершается ошибкой ENOKEY.

Если ключ не найден и callout не равно NULL, то ядро пытается вызвать пользовательскую программу для создания ключа. Подробности приведены ниже.

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

Связка ключей вызывающей нити (смотрите thread-keyring(7)).
Связка ключей вызывающего процесса (смотрите process-keyring(7)).
Связка ключей сеанса вызывающего (смотрите session-keyring(7)).
Связка ключей по UID вызывающего (смотрите user-keyring(7)).
Связка ключей по UID сеанса вызывающего (смотрите user-session-keyring(7)).

Если dest_keyring равно 0 и создание ключа не выполнено, то дополнительных связей не появляется.

В противном случае, если dest_keyring равно 0 и создан новый ключ, то новый ключ будет прицеплен в связку ключей «по умолчанию». Более точно, когда ядро пытается определить в какую связку ключей должен быть прицеплен то только что созданный ключ, оно перебирает связки ключей начиная с со связки, установленной через keyctl(2) с операцией KEYCTL_SET_REQKEY_KEYRING и продолжает в порядке, показанном далее, пока не найдёт существующую связку ключей:

Связка ключей запрашивающего (KEY_REQKEY_DEFL_REQUESTOR_KEYRING, начиная с Linux 2.6.29).
Связка ключей нити (KEY_REQKEY_DEFL_THREAD_KEYRING; смотрите thread-keyring(7)).
Связка ключей процесса (KEY_REQKEY_DEFL_PROCESS_KEYRING; смотрите process-keyring(7)).
Связка ключей сеанса (KEY_REQKEY_DEFL_SESSION_KEYRING; смотрите session-keyring(7)).
Связка ключей сеанса для идентификатора пользователя процесса (KEY_REQKEY_DEFL_USER_SESSION_KEYRING; смотрите user-session-keyring(7)). Ожидается, что эта связка ключей всегда существует.
Связка ключей для идентификатора пользователя процесса (KEY_REQKEY_DEFL_USER_KEYRING; смотрите user-keyring(7)). Ожидается, что эта связка ключей также всегда существует.

Если вызов keyctl(2) с операцией KEYCTL_SET_REQKEY_KEYRING установил KEY_REQKEY_DEFL_DEFAULT (или операция KEYCTL_SET_REQKEY_KEYRING не выполнялась), то ядро ищет связку ключей начиная с начала списка.

Запрос на создание ключа из пользовательского пространства

Если ядро не может найти ключ с соответствующим type и description, и callout не равно NULL, то ядро пытается вызвать программу из пользовательского пространства для создания ключа с заданными type и description. В этом случае выполняются следующие шаги:

(1)
Ядро создаёт неинициализированный ключ U с запрошенными type и description.
(2)
Ядро создаёт ключ авторизации V, который ссылается на ключ U и сохраняются данные вызывающего request_key():
(2.1)
контекст, в котором ключ U должен быть создан и защищён и
(2.2)
контекст, из которого запросы связанного ключа могут быть проведены.
Ключ авторизации создаётся со следующими свойствами:
Тип ключа — ".request_key_auth".
UID и GID ключа совпадают с ID в файловой системе для запрашивающего процесса.
Ключ даёт права на просмотр, чтение и поиск на ключ-владелец, а также право просмотра для ключа пользователя.
Описание (имя) ключа представляет собой Шестнадцатеричную строку идентификатора ключа, который будет создан в запрашивающей программе.
Полезные данные ключа берутся из данных callout_info.
Внутри ядра также сохраняется PID процесса, который был вызван request_key().
(3)
Ядро создаёт процесс, который запускает службу пользовательского пространства, такую как request-key(8), с новой связкой ключей сеанса с прицепленным ключом авторизации V.
Данной программе передаются следующие аргументы командной строки:
[0]
Строка "/sbin/request-key".
[1]
Строка "create" (показывающая, что ключ будет создан).
[2]
Идентификатор ключа, который будет создан.
[3]
UID (в файловой системе) вызывающего request_key().
[4]
GID (в файловой системе) вызывающего request_key().
[5]
Идентификатор связки ключей нити вызывающего request_key(). Может быть ноль, если связка ключей не создана.
[6]
Идентификатор связки ключей процесса вызывающего request_key(). Может быть ноль, если связка ключей не создана.
[7]
Идентификатор связки ключей сеанса вызывающего request_key().
Замечание: каждый аргумент командной строки, обозначающий идентификатор ключа, кодируется десятичным числом (в отличие от идентификаторов ключе, показанных в /proc/keys, которые выдаются в виде шестнадцатеричных значений).
(4)
Программа, порождённая на предыдущем шаге:
Принимает полномочия на создание ключа U с помощью keyctl(2) с операцией KEYCTL_ASSUME_AUTHORITY (обычно, с помощью функции keyctl_assume_authority(3)).
Получает исходящие данные (callout data) из полезной нагрузки ключа авторизации V (с помощью keyctl(2) с операцией KEYCTL_READ (или, чаще всего, с помощью функции keyctl_read(3)) с значением идентификатора ключа KEY_SPEC_REQKEY_AUTH_KEY.
Создаёт ключ (или выполняет другую программу, которая делает эту работу), с заданной полезной нагрузкой и связкой ключей назначения (связка ключей назначения та, которую запрашивающий указал при вызове request_key(), и которая быть доступна через специальный идентификатор ключа KEY_SPEC_REQUESTOR_KEYRING). Создание выполняется с помощью keyctl() с операцией KEYCTL_INSTANTIATE (или, чаще всего, с помощью функции keyctl_instantiate(3)). На этот момент вызов request_key() завершается и запрашивающая программа может продолжать выполнение.

Если какой-то из этих шагов завершается ошибкой, то вызвавшему request_key() возвращается ENOKEY и временно в связку ключей dest_keyring будет установлен отрицательно инициализированный ключ. Он устареет через несколько секунд, но пока этого не произойдёт все последующие вызовы request_key() будут завершаться ошибкой. Целью данного отрицательно инициализированного ключа является предотвращение повторяющихся запросов (возможно разными) процессами (они требуют затратных восходящих вызовов request-key(8)) для ключа, который невозможно (в данный момент) положительно инициализировать.

После инициализации ключа, ключ авторизации (KEY_SPEC_REQKEY_AUTH_KEY) отзывается и связка ключей назначения (KEY_SPEC_REQUESTOR_KEYRING) становится недоступной программе request-key(8).

If a key is created, then—regardless of whether it is a valid key or a negatively instantiated key—it will displace any other key with the same type and description from the keyring specified in dest_keyring.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

On success, request_key() returns the serial number of the key it found or caused to be created. On error, -1 is returned and errno is set to indicate the error.

ОШИБКИ

Изменение связки ключей пользователю недоступно.
Квота на ключи для данного пользователя была бы превышена, если бы этот ключ создался или был бы прицеплен в связку ключей.
Значение type, description или callout_info указывают вне доступного адресного пространства процесса.
Запрос был прерван сигналом; смотрите signal(7).
Размер строки (включая конечный байт null), заданной в type или description, превышает ограничение (32 байта и 4096 байт, соответственно).
Размер строки (включая конечный байт null), заданной в callout_info, превышает размер системной страницы.
Найден просроченный ключ, и замена не может быть получена.
Попытка генерации нового ключа была отвергнута.
Найден отозванный ключ, и замена не может быть получена.
Искомый ключ не найден.
Недостаточно памяти для создания ключа.
The type argument started with a period ('.').

ВЕРСИИ

Данный системный вызов впервые появился в Linux 2.6.10. Возможность инициализации ключей по запросу была добавлена в Linux 2.6.13.

СТАНДАРТЫ

Этот системный вызов является нестандартным расширением Linux.

ПРИМЕРЫ

В программе, представленной ниже, показано использование 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 <keyutils.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.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("Key ID is %jx\n", (uintmax_t) 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).

ПЕРЕВОД

Русский перевод этой страницы руководства разработал(и) aereiae <aereiae@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Katrin Kutepova <blackkatelv@gmail.com>, Lockal <lockalsash@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Баринов Владимир и Иван Павлов <pavia00@gmail.com>

Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.

5 февраля 2023 г. Справочные страницы Linux 6.03