xref: /spdk/module/keyring/linux/keyring.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2024 Intel Corporation. All rights reserved.
3  */
4 
5 #include <keyutils.h>
6 #include "keyring_linux.h"
7 #include "spdk/keyring.h"
8 #include "spdk/keyring_module.h"
9 #include "spdk/log.h"
10 #include "spdk/string.h"
11 #include "spdk/util.h"
12 
13 static struct keyring_linux_opts g_opts;
14 
15 struct linux_key {
16 	key_serial_t sn;
17 };
18 
19 static struct spdk_keyring_module g_keyring_linux;
20 
21 void
22 keyring_linux_get_opts(struct keyring_linux_opts *opts)
23 {
24 	memcpy(opts, &g_opts, sizeof(*opts));
25 }
26 
27 int
28 keyring_linux_set_opts(struct keyring_linux_opts *opts)
29 {
30 	g_opts.enable = opts->enable;
31 
32 	return 0;
33 }
34 
35 static int
36 linux_find_key(const char *name, key_serial_t *outsn)
37 {
38 	key_serial_t sn;
39 
40 	sn = request_key("user", name, NULL, KEY_SPEC_SESSION_KEYRING);
41 	if (sn < 0) {
42 		return -errno;
43 	}
44 
45 	if (outsn != NULL) {
46 		*outsn = sn;
47 	}
48 
49 	return 0;
50 }
51 
52 static int
53 linux_probe_key(const char *name)
54 {
55 	struct spdk_key_opts opts = {};
56 	int rc;
57 
58 	rc = linux_find_key(name, NULL);
59 	if (rc != 0) {
60 		return rc;
61 	}
62 
63 	opts.size = SPDK_SIZEOF(&opts, module);
64 	opts.name = name;
65 	opts.module = &g_keyring_linux;
66 
67 	return spdk_keyring_add_key(&opts);
68 }
69 
70 static int
71 linux_add_key(struct spdk_key *key, void *ctx)
72 {
73 	struct linux_key *lkey = spdk_key_get_ctx(key);
74 
75 	return linux_find_key(spdk_key_get_name(key), &lkey->sn);
76 }
77 
78 static void
79 linux_remove_key(struct spdk_key *key)
80 {
81 	/* no-op */
82 }
83 
84 static int
85 linux_get_key(struct spdk_key *key, void *buf, int len)
86 {
87 	struct linux_key *lkey = spdk_key_get_ctx(key);
88 	int rc, errsv;
89 
90 	rc = keyctl_read(lkey->sn, buf, len);
91 	if (rc < 0) {
92 		errsv = errno;
93 		SPDK_ERRLOG("Failed to read key '%s': %s\n", spdk_key_get_name(key),
94 			    spdk_strerror(errsv));
95 		return -errsv;
96 	}
97 
98 	if (rc > len) {
99 		SPDK_ERRLOG("Failed to read key '%s': buffer to small\n", spdk_key_get_name(key));
100 		return -ENOBUFS;
101 	}
102 
103 	return rc;
104 }
105 
106 static size_t
107 linux_get_ctx_size(void)
108 {
109 	return sizeof(struct linux_key);
110 }
111 
112 static void
113 linux_dump_info(struct spdk_key *key, struct spdk_json_write_ctx *w)
114 {
115 	struct linux_key *lkey = spdk_key_get_ctx(key);
116 
117 	spdk_json_write_named_uint32(w, "sn", lkey->sn);
118 }
119 
120 static void
121 linux_write_config(struct spdk_json_write_ctx *w)
122 {
123 	spdk_json_write_object_begin(w);
124 	spdk_json_write_named_string(w, "method", "keyring_linux_set_options");
125 	spdk_json_write_named_object_begin(w, "params");
126 	spdk_json_write_named_bool(w, "enable", g_opts.enable);
127 	spdk_json_write_object_end(w);
128 	spdk_json_write_object_end(w);
129 }
130 
131 static int
132 linux_init(void)
133 {
134 	return g_opts.enable ? 0 : -ENODEV;
135 }
136 
137 static struct spdk_keyring_module g_keyring_linux = {
138 	.name = "linux",
139 	.init = linux_init,
140 	.probe_key = linux_probe_key,
141 	.add_key = linux_add_key,
142 	.remove_key = linux_remove_key,
143 	.get_key = linux_get_key,
144 	.get_ctx_size = linux_get_ctx_size,
145 	.dump_info = linux_dump_info,
146 	.write_config = linux_write_config,
147 };
148 SPDK_KEYRING_REGISTER_MODULE(linux, &g_keyring_linux);
149