Provided by: manpages-ru-dev_4.19.0-7_all bug

ИМЯ

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

LIBRARY

       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 может задаваться серийным номером допустимой связки ключей, на
       которую у вызывающего есть права на запись, или  же  это  может  быть  один  из  следующих
       специальных идентификаторов связок ключей:

       KEY_SPEC_THREAD_KEYRING
              Связка ключей вызывающей нити (смотрите thread-keyring(7)).

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

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

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

       KEY_SPEC_USER_SESSION_KEYRING
              Связка ключей по 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.

ОШИБКИ

       EACCES Изменение связки ключей пользователю недоступно.

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

       EFAULT Значение  type,  description  или  callout_info  указывают вне доступного адресного
              пространства процесса.

       EINTR  Запрос был прерван сигналом; смотрите signal(7).

       EINVAL Размер строки (включая конечный  байт  null),  заданной  в  type  или  description,
              превышает ограничение (32 байта и 4096 байт, соответственно).

       EINVAL Размер  строки  (включая  конечный  байт  null), заданной в callout_info, превышает
              размер системной страницы.

       EKEYEXPIRED
              Найден просроченный ключ, и замена не может быть получена.

       EKEYREJECTED
              Попытка генерации нового ключа была отвергнута.

       EKEYREVOKED
              Найден отозванный ключ, и замена не может быть получена.

       ENOKEY Искомый ключ не найден.

       ENOMEM Недостаточно памяти для создания ключа.

       EPERM  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 версии 3 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ или более позднюю, чтобы
       узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

       Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте
       электронное письмо на ⟨man-pages-ru-talks@lists.sourceforge.net⟩.