Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (c) 2024 Intel Corporation. All rights reserved.
3 : */
4 :
5 : #include "keyring_internal.h"
6 : #include "spdk/keyring.h"
7 : #include "spdk/keyring_module.h"
8 : #include "spdk/log.h"
9 : #include "spdk/queue.h"
10 : #include "spdk/string.h"
11 :
12 : struct spdk_key {
13 : char *name;
14 : int refcnt;
15 : bool removed;
16 : bool probed;
17 : struct spdk_keyring_module *module;
18 : TAILQ_ENTRY(spdk_key) tailq;
19 : };
20 :
21 : struct spdk_keyring {
22 : pthread_mutex_t mutex;
23 : TAILQ_HEAD(, spdk_keyring_module) modules;
24 : TAILQ_HEAD(, spdk_key) keys;
25 : TAILQ_HEAD(, spdk_key) removed_keys;
26 : };
27 :
28 : static struct spdk_keyring g_keyring = {
29 : .keys = TAILQ_HEAD_INITIALIZER(g_keyring.keys),
30 : .removed_keys = TAILQ_HEAD_INITIALIZER(g_keyring.removed_keys),
31 : .modules = TAILQ_HEAD_INITIALIZER(g_keyring.modules),
32 : };
33 :
34 : static const char *
35 40 : keyring_get_key_name(const char *name)
36 : {
37 40 : const char *keyname;
38 :
39 : /* Both "key0" and ":key0" refer to "key0" in the global keyring */
40 40 : keyname = strstr(name, ":");
41 40 : if (keyname == NULL) {
42 36 : return name;
43 : }
44 :
45 4 : return keyname + 1;
46 40 : }
47 :
48 : static struct spdk_key *
49 33 : keyring_find_key(const char *name)
50 : {
51 33 : struct spdk_key *key;
52 :
53 33 : TAILQ_FOREACH(key, &g_keyring.keys, tailq) {
54 20 : if (strcmp(keyring_get_key_name(key->name),
55 20 : keyring_get_key_name(name)) == 0) {
56 20 : return key;
57 : }
58 0 : }
59 :
60 13 : return NULL;
61 33 : }
62 :
63 : static void
64 4 : keyring_free_key(struct spdk_key *key)
65 : {
66 4 : assert(key->refcnt == 0);
67 :
68 4 : free(key->name);
69 4 : free(key);
70 4 : }
71 :
72 : static int
73 15 : keyring_put_key(struct spdk_key *key)
74 : {
75 15 : assert(key->refcnt > 0);
76 15 : key->refcnt--;
77 :
78 15 : if (key->refcnt == 0) {
79 3 : assert(key->removed);
80 3 : TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
81 3 : keyring_free_key(key);
82 :
83 3 : return 0;
84 : }
85 :
86 12 : return key->refcnt;
87 15 : }
88 :
89 : int
90 7 : spdk_keyring_add_key(const struct spdk_key_opts *opts)
91 : {
92 7 : struct spdk_key *key = NULL;
93 7 : struct spdk_keyring_module *module = opts->module;
94 7 : const char *keyname;
95 7 : int rc = 0;
96 :
97 : /* For now, only global keyring is supported */
98 7 : keyname = strstr(opts->name, ":");
99 7 : if (keyname != NULL && keyname != opts->name) {
100 0 : SPDK_ERRLOG("Couldn't add key '%s' to the keyring: keyring doesn't exist\n",
101 : opts->name);
102 0 : return -EINVAL;
103 : }
104 :
105 7 : pthread_mutex_lock(&g_keyring.mutex);
106 7 : if (keyring_find_key(opts->name) != NULL) {
107 2 : SPDK_ERRLOG("Key '%s' already exists\n", opts->name);
108 2 : rc = -EEXIST;
109 2 : goto out;
110 : }
111 :
112 5 : key = calloc(1, sizeof(*key) + module->get_ctx_size());
113 5 : if (key == NULL) {
114 0 : rc = -ENOMEM;
115 0 : goto out;
116 : }
117 :
118 5 : key->name = strdup(opts->name);
119 5 : if (key->name == NULL) {
120 0 : rc = -ENOMEM;
121 0 : goto out;
122 : }
123 :
124 5 : rc = module->add_key(key, opts->ctx);
125 5 : if (rc != 0) {
126 1 : SPDK_ERRLOG("Failed to add key '%s' to the keyring\n", opts->name);
127 1 : goto out;
128 : }
129 :
130 4 : key->module = module;
131 4 : key->refcnt = 1;
132 4 : TAILQ_INSERT_TAIL(&g_keyring.keys, key, tailq);
133 : out:
134 7 : pthread_mutex_unlock(&g_keyring.mutex);
135 7 : if (rc != 0 && key != NULL) {
136 1 : keyring_free_key(key);
137 1 : }
138 :
139 7 : return rc;
140 7 : }
141 :
142 : static void
143 4 : keyring_remove_key(struct spdk_key *key)
144 : {
145 4 : assert(!key->removed);
146 4 : key->removed = true;
147 4 : key->module->remove_key(key);
148 4 : TAILQ_REMOVE(&g_keyring.keys, key, tailq);
149 4 : TAILQ_INSERT_TAIL(&g_keyring.removed_keys, key, tailq);
150 4 : keyring_put_key(key);
151 4 : }
152 :
153 : int
154 7 : spdk_keyring_remove_key(const char *name, struct spdk_keyring_module *module)
155 : {
156 7 : struct spdk_key *key;
157 7 : int rc = 0;
158 :
159 7 : pthread_mutex_lock(&g_keyring.mutex);
160 7 : key = keyring_find_key(name);
161 7 : if (key == NULL) {
162 2 : SPDK_ERRLOG("Key '%s' does not exist\n", name);
163 2 : rc = -ENOKEY;
164 2 : goto out;
165 : }
166 :
167 5 : if (key->module != module) {
168 1 : SPDK_ERRLOG("Key '%s' is not owned by module '%s'\n", name, module->name);
169 1 : rc = -EINVAL;
170 1 : goto out;
171 : }
172 :
173 4 : keyring_remove_key(key);
174 : out:
175 7 : pthread_mutex_unlock(&g_keyring.mutex);
176 14 : return rc;
177 7 : }
178 :
179 : static struct spdk_key *
180 6 : keyring_probe_key(const char *name)
181 : {
182 6 : struct spdk_keyring_module *module;
183 6 : struct spdk_key *key = NULL;
184 6 : int rc;
185 :
186 12 : TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
187 6 : if (module->probe_key == NULL) {
188 6 : continue;
189 : }
190 :
191 0 : rc = module->probe_key(name);
192 0 : if (rc == 0) {
193 0 : key = keyring_find_key(name);
194 0 : if (key == NULL) {
195 0 : SPDK_ERRLOG("Successfully probed key '%s' using module '%s', but "
196 : "the key is unavailable\n", name, module->name);
197 0 : return NULL;
198 : }
199 :
200 0 : key->probed = true;
201 0 : break;
202 0 : } else if (rc != -ENOKEY) {
203 : /* The module is aware of the key but couldn't instantiate it */
204 0 : assert(keyring_find_key(name) == NULL);
205 0 : SPDK_ERRLOG("Failed to probe key '%s' using module '%s': %s\n",
206 : name, module->name, spdk_strerror(-rc));
207 0 : break;
208 : }
209 0 : }
210 :
211 6 : return key;
212 6 : }
213 :
214 : struct spdk_key *
215 19 : spdk_keyring_get_key(const char *name)
216 : {
217 19 : struct spdk_key *key;
218 :
219 19 : pthread_mutex_lock(&g_keyring.mutex);
220 19 : key = keyring_find_key(name);
221 19 : if (key == NULL) {
222 6 : key = keyring_probe_key(name);
223 6 : if (key == NULL) {
224 6 : goto out;
225 : }
226 0 : }
227 :
228 13 : key->refcnt++;
229 : out:
230 19 : pthread_mutex_unlock(&g_keyring.mutex);
231 :
232 38 : return key;
233 19 : }
234 :
235 : void
236 11 : spdk_keyring_put_key(struct spdk_key *key)
237 : {
238 11 : int refcnt;
239 :
240 11 : if (key == NULL) {
241 0 : return;
242 : }
243 :
244 11 : pthread_mutex_lock(&g_keyring.mutex);
245 11 : refcnt = keyring_put_key(key);
246 11 : if (refcnt == 1 && key->probed && !key->removed) {
247 0 : keyring_remove_key(key);
248 0 : }
249 11 : pthread_mutex_unlock(&g_keyring.mutex);
250 11 : }
251 :
252 : struct spdk_key *
253 0 : spdk_key_dup(struct spdk_key *key)
254 : {
255 0 : pthread_mutex_lock(&g_keyring.mutex);
256 0 : key->refcnt++;
257 0 : pthread_mutex_unlock(&g_keyring.mutex);
258 :
259 0 : return key;
260 : }
261 :
262 : const char *
263 9 : spdk_key_get_name(struct spdk_key *key)
264 : {
265 9 : return key->name;
266 : }
267 :
268 : int
269 3 : spdk_key_get_key(struct spdk_key *key, void *buf, int len)
270 : {
271 3 : struct spdk_keyring_module *module = key->module;
272 :
273 3 : if (key->removed) {
274 1 : return -ENOKEY;
275 : }
276 :
277 2 : return module->get_key(key, buf, len);
278 3 : }
279 :
280 : void *
281 11 : spdk_key_get_ctx(struct spdk_key *key)
282 : {
283 11 : return key + 1;
284 : }
285 :
286 :
287 : struct spdk_keyring_module *
288 0 : spdk_key_get_module(struct spdk_key *key)
289 : {
290 0 : return key->module;
291 : }
292 :
293 : void
294 0 : spdk_keyring_write_config(struct spdk_json_write_ctx *w)
295 : {
296 0 : struct spdk_keyring_module *module;
297 :
298 0 : TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
299 0 : if (module->write_config != NULL) {
300 0 : module->write_config(w);
301 0 : }
302 0 : }
303 0 : }
304 :
305 : void
306 0 : spdk_keyring_for_each_key(struct spdk_keyring *keyring,
307 : void *ctx, void (*fn)(void *ctx, struct spdk_key *key), uint32_t flags)
308 : {
309 0 : struct spdk_key *key, *tmp;
310 :
311 0 : assert(keyring == NULL);
312 0 : pthread_mutex_lock(&g_keyring.mutex);
313 0 : TAILQ_FOREACH_SAFE(key, &g_keyring.keys, tailq, tmp) {
314 0 : fn(ctx, key);
315 0 : }
316 :
317 0 : if (flags & SPDK_KEYRING_FOR_EACH_ALL) {
318 0 : TAILQ_FOREACH_SAFE(key, &g_keyring.removed_keys, tailq, tmp) {
319 0 : fn(ctx, key);
320 0 : }
321 0 : }
322 0 : pthread_mutex_unlock(&g_keyring.mutex);
323 0 : }
324 :
325 : void
326 1 : spdk_keyring_register_module(struct spdk_keyring_module *module)
327 : {
328 1 : TAILQ_INSERT_TAIL(&g_keyring.modules, module, tailq);
329 1 : }
330 :
331 : void
332 0 : keyring_dump_key_info(struct spdk_key *key, struct spdk_json_write_ctx *w)
333 : {
334 0 : struct spdk_keyring_module *module = key->module;
335 :
336 0 : spdk_json_write_named_string(w, "name", key->name);
337 0 : spdk_json_write_named_string(w, "module", module->name);
338 0 : spdk_json_write_named_bool(w, "removed", key->removed);
339 0 : spdk_json_write_named_bool(w, "probed", key->probed);
340 0 : spdk_json_write_named_int32(w, "refcnt", key->refcnt);
341 :
342 0 : if (!key->removed && module->dump_info != NULL) {
343 0 : module->dump_info(key, w);
344 0 : }
345 0 : }
346 :
347 : int
348 0 : spdk_keyring_init(void)
349 : {
350 0 : struct spdk_keyring_module *module, *tmp;
351 0 : pthread_mutexattr_t attr;
352 0 : int rc;
353 :
354 0 : rc = pthread_mutexattr_init(&attr);
355 0 : if (rc != 0) {
356 0 : SPDK_ERRLOG("Failed to initialize mutex attr\n");
357 0 : return -rc;
358 : }
359 :
360 0 : rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
361 0 : if (rc != 0) {
362 0 : SPDK_ERRLOG("Failed to set mutex attr\n");
363 0 : pthread_mutexattr_destroy(&attr);
364 0 : return -rc;
365 : }
366 :
367 0 : rc = pthread_mutex_init(&g_keyring.mutex, &attr);
368 0 : if (rc != 0) {
369 0 : SPDK_ERRLOG("Failed to initialize mutex\n");
370 0 : pthread_mutexattr_destroy(&attr);
371 0 : return -rc;
372 : }
373 :
374 0 : pthread_mutexattr_destroy(&attr);
375 0 : TAILQ_FOREACH_SAFE(module, &g_keyring.modules, tailq, tmp) {
376 0 : if (module->init != NULL) {
377 0 : rc = module->init();
378 0 : if (rc != 0) {
379 0 : if (rc == -ENODEV) {
380 0 : SPDK_INFOLOG(keyring, "Skipping module %s\n", module->name);
381 0 : TAILQ_REMOVE(&g_keyring.modules, module, tailq);
382 0 : rc = 0;
383 0 : continue;
384 : }
385 :
386 0 : SPDK_ERRLOG("Failed to initialize module %s: %s\n",
387 : module->name, spdk_strerror(-rc));
388 0 : break;
389 : }
390 0 : }
391 :
392 0 : SPDK_INFOLOG(keyring, "Initialized module %s\n", module->name);
393 0 : }
394 :
395 0 : if (rc != 0) {
396 0 : TAILQ_FOREACH(tmp, &g_keyring.modules, tailq) {
397 0 : if (tmp == module) {
398 0 : break;
399 : }
400 0 : if (tmp->cleanup != NULL) {
401 0 : tmp->cleanup();
402 0 : }
403 0 : }
404 0 : }
405 :
406 0 : return rc;
407 0 : }
408 :
409 : void
410 0 : spdk_keyring_cleanup(void)
411 : {
412 0 : struct spdk_keyring_module *module;
413 0 : struct spdk_key *key;
414 :
415 0 : while (!TAILQ_EMPTY(&g_keyring.keys)) {
416 0 : key = TAILQ_FIRST(&g_keyring.keys);
417 0 : keyring_remove_key(key);
418 : }
419 :
420 0 : while (!TAILQ_EMPTY(&g_keyring.removed_keys)) {
421 0 : key = TAILQ_FIRST(&g_keyring.removed_keys);
422 0 : SPDK_WARNLOG("Key '%s' still has %d references\n", key->name, key->refcnt);
423 0 : key->refcnt = 0;
424 0 : TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
425 0 : keyring_free_key(key);
426 : }
427 :
428 0 : TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
429 0 : if (module->cleanup != NULL) {
430 0 : module->cleanup();
431 0 : }
432 0 : }
433 0 : }
434 :
435 1 : SPDK_LOG_REGISTER_COMPONENT(keyring)
|