错误说明

EACCES
用户无法修改密钥环。
EDQUOT
通过创建此密钥或将其链接到密钥环,将超出此用户的密钥配额。
EFAULT
类型,描述或callout_info之一指向进程的可访问地址空间之外。
EINTR
该请求被信号中断;参见signal(7)。
EINVAL
在类型或描述中指定的字符串大小(包括终止的空字节)超过了限制(分别为32个字节和4096个字节)。
EINVAL
在callout_info中指定的字符串(包括终止空字节)的大小超过了系统页面大小。
EKEYEXPIRED
找到了过期的密钥,但是无法获得替换密钥。
EKEYREJECTED
生成新密钥的尝试被拒绝。
EKEYREVOKED
找到了已吊销的钥匙,但是无法获得替代钥匙。
ENOKEY
找不到匹配的密钥。
ENOMEM
内存不足,无法创建密钥。
EPERM
类型参数以句点(aq.aq)开头。

说明

request_key()尝试查找具有与指定描述匹配的描述(名称)的给定类型的键。如果找不到这样的密钥,则可以选择创建该密钥。如果找到或创建了密钥,则request_key()会将其附加到在dest_keyring中指定了ID的密钥环上,并返回密钥的序列号。

request_key()首先在附加到调用过程的所有密钥环中递归搜索匹配的密钥。按以下顺序搜索密钥环:特定于线程的密钥环,特定于进程的密钥环,然后是会话密钥环。

如果从request_key()代表其他进程调用的程序中调用request_key()以生成密钥,则接下来将使用该另一个进程的用户ID,组ID,补充组ID搜索该另一个进程的密钥环。 ,并根据安全上下文确定访问权限。

密钥环树的搜索是广度优先的:在将任何子密钥环递归到其中之前,先检查每个搜索到的密钥环中的密钥是否匹配。仅找到呼叫者具有搜索许可的密钥,并且仅搜索呼叫者具有搜索许可的密钥环。

如果未找到键,且标注为NULL,则调用失败,错误为ENOKEY。

如果未找到密钥,并且标注不为NULL,则内核将尝试调用用户空间程序以实例化密钥。详细情况如下。

dest_keyring序列号可以是调用者对其具有写许可权的有效密钥环的序列号,也可以是以下特殊密钥环ID之一:

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))。
*
进程用户ID的会话密钥环(KEY_REQKEY_DEFL_USER_SESSION_KEYRING;请参阅user-session-keyring(7))。预计此密钥环将始终存在。
*
特定于UID的密钥环(KEY_REQKEY_DEFL_USER_KEYRING;参见user-keyring(7))。该密钥环也有望始终存在。

如果keyctl(2)KEYCTL_SET_REQKEY_KEYRING操作指定KEY_REQKEY_DEFL_DEFAULT(或者不执行KEYCTL_SET_REQKEY_KEYRING操作),则内核从列表的开头开始寻找密钥环。

Requesting user-space instantiation of a key

如果内核找不到与类型和描述匹配的键,并且标注不为NULL,则内核会尝试调用用户空间程序来实例化具有给定类型和描述的键。在这种情况下,执行以下步骤:

a)
内核使用请求的类型和描述创建一个未实例化的密钥U。
b)
The kernel creates an authorization key, V,

that refers to the key U and records the facts that the caller of
request_key()

is:

(1)
实例化和保护密钥U的上下文,以及
(2)
可以满足关联密钥请求的上下文。
The authorization key is constructed as follows:
*
密钥类型为.request_key_auth。
*
密钥的UID和GID与请求进程的相应文件系统ID相同。
*
密钥向密钥所有者授予查看,读取和搜索权限,以及密钥用户的查看权限。
*
密钥的描述(名称)是一个十六进制字符串,代表要在请求程序中实例化的密钥的ID。
*
密钥的有效载荷来自callout_info中指定的数据。
*
在内部,内核还记录称为request_key()的进程的PID。
c)
内核创建一个进程,该进程执行带有新会话密钥环的用户空间服务,例如请求密钥(8),该会话密钥环包含指向授权密钥V的链接。
This program is supplied with the following command-line arguments:
[0]
字符串/ sbin / request-key。
[1]
字符串create(指示要创建密钥)。
[2]
要实例化的密钥的ID。
[3]
request_key()的调用者的文件系统UID。
[4]
request_key()的调用者的文件系统GID。
[5]
request_key()的调用者的线程密钥环的ID。如果尚未创建该密钥环,则该值为零。
[6]
request_key()的调用者的进程密钥环的ID。如果尚未创建该密钥环,则该值为零。
[7]
request_key()的调用者的会话密钥环的ID。
注意:每个作为键ID的命令行参数都以十进制编码(与/ proc / keys中显示的键ID不同,它们以十六进制值显示)。
d)
The program spawned in the previous step:
*
假定使用keyctl(2)KEYCTL_ASSUME_AUTHORITY操作(通常通过keyctl_assume_authority(3)函数)实例化密钥U的权限。
*
从授权密钥V的有效负载中获取标注数据(使用keyctl(2)KEYCTL_READ操作(或更常见的是使用keyctl_read(3)函数),其密钥ID值为KEY_SPEC_REQKEY_AUTH_KEY)。
*
实例化密钥(或执行另一个执行该任务的程序),指定有效负载和目标密钥环。 (可以使用特殊密钥ID KEY_SPEC_REQUESTOR_KEYRING访问请求者在调用request_key()时指定的目标密钥环。)使用keyctl(2)KEYCTL_INSTANTIATE操作(或更常见的是keyctl_instantiate(3)函数)来执行实例化。至此,request_key()调用完成,发出请求的程序可以继续执行。

如果这些步骤不成功,则将ENOKEY错误返回给request_key()的调用方,并且将在dest_keyring指定的密钥环中安装一个临时的,负实例化的密钥。这将在几秒钟后过期,但会导致随后对request_key()的调用失败,直到失败为止。此负实例化密钥的目的是防止(可能不同的)进程针对无法(当前)正实例化的密钥进行重复请求(需要昂贵的request-key(8)上调)。

实例化密钥后,将撤消授权密钥(KEY_SPEC_REQKEY_AUTH_KEY),并且不再可以从request-key(8)程序访问目标密钥环(KEY_SPEC_REQUESTOR_KEYRING)。

如果创建了密钥,则-(无论它是有效密钥还是负实例化的密钥)-都会从dest_keyring中指定的密钥环中替换具有相同类型和描述的任何其他密钥。

返回值

成功后,request_key()返回找到或导致创建的密钥的序列号。发生错误时,将返回-1并将errno设置为指示错误原因。

遵循规范

此系统调用是非标准的Linux扩展。

名称

request_key-向内核的密钥管理工具请求密钥

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/

另外参见

keyctl(1),add_key(2),keyctl(2),keyctl(3),功能(7),keyrings(7),keyutils(7),persistent-keyring(7),process-keyring(7),会话-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中) 。文本)。

备注

glibc中没有提供此系统调用的包装器。 libkeyutils软件包中提供了包装器。在该库中使用包装器时,请与-lkeyutils链接。

语法

#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包装器;请参阅注释。

版本

该系统调用首次出现在Linux 2.6.10中。 Linux 2.6.13中添加了根据请求实例化密钥的功能。

REQUEST_KEY - Linux手册页

Section: Linux Key Management Calls (2)
更新日期: 2020-06-09

示例

下面的程序演示了request_key()的用法。系统调用的类型,描述和callout_info参数取自命令行参数中提供的值。该呼叫将会话密钥环指定为目标密钥环。

为了演示该程序,我们首先在文件/etc/request-key.conf中创建一个合适的条目。

$ sudo sh
# echo 'create user mtk:* *   /bin/keyctl instantiate %k %c %S' \
          > /etc/request-key.conf
# exit

此项指定当必须实例化带有前缀" mtk:"的新"用户"键时,应通过keyctl(1)命令的实例化操作来执行该任务。提供给实例化操作的参数是:未实例化的键的ID(%k);提供给request_key()调用的标注数据(%c);以及请求者(即request_key()的调用者)的会话密钥环(%S)。有关这些%说明符的详细信息,请参见request-key.conf(5)。

然后,我们运行程序并检查/ proc / keys的内容,以验证请求的密钥已被实例化:

$ ./t_request_key user mtk:key1 "Payload data"
$ grep aq2dddaf50aq /proc/keys
2dddaf50 I--Q---  1 perm 3f010000  1000  1000 user  mtk:key1: 12

有关使用此程序的另一个示例,请参见keyctl(2)。

Program source

/* 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, "Usage: %s type description 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 %lx\n", (long) key);

    exit(EXIT_SUCCESS);
}
日期:2019-08-20 17:59:16 来源:oir作者:oir