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 34 : keyring_get_key_name(const char *name)
36 : {
37 : const char *keyname;
38 :
39 : /* Both "key0" and ":key0" refer to "key0" in the global keyring */
40 34 : keyname = strstr(name, ":");
41 34 : if (keyname == NULL) {
42 31 : return name;
43 : }
44 :
45 3 : return keyname + 1;
46 : }
47 :
48 : static struct spdk_key *
49 30 : keyring_find_key(const char *name)
50 : {
51 : struct spdk_key *key;
52 :
53 30 : TAILQ_FOREACH(key, &g_keyring.keys, tailq) {
54 17 : if (strcmp(keyring_get_key_name(key->name),
55 : keyring_get_key_name(name)) == 0) {
56 17 : return key;
57 : }
58 : }
59 :
60 13 : return NULL;
61 : }
62 :
63 : static void
64 5 : keyring_free_key(struct spdk_key *key)
65 : {
66 5 : assert(key->refcnt == 0);
67 :
68 5 : free(key->name);
69 5 : free(key);
70 5 : }
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 4 : assert(key->removed);
80 4 : TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
81 4 : keyring_free_key(key);
82 :
83 4 : return 0;
84 : }
85 :
86 11 : return key->refcnt;
87 : }
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 : 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 7 : out:
134 7 : pthread_mutex_unlock(&g_keyring.mutex);
135 7 : if (rc != 0 && key != NULL) {
136 1 : keyring_free_key(key);
137 : }
138 :
139 7 : return rc;
140 : }
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 : void
154 6 : spdk_keyring_remove_key(const char *name)
155 : {
156 : struct spdk_key *key;
157 :
158 6 : pthread_mutex_lock(&g_keyring.mutex);
159 6 : key = keyring_find_key(name);
160 6 : if (key == NULL) {
161 2 : SPDK_WARNLOG("Key '%s' does not exist\n", name);
162 2 : goto out;
163 : }
164 :
165 4 : keyring_remove_key(key);
166 6 : out:
167 6 : pthread_mutex_unlock(&g_keyring.mutex);
168 6 : }
169 :
170 : static struct spdk_key *
171 6 : keyring_probe_key(const char *name)
172 : {
173 : struct spdk_keyring_module *module;
174 6 : struct spdk_key *key = NULL;
175 : int rc;
176 :
177 12 : TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
178 6 : if (module->probe_key == NULL) {
179 6 : continue;
180 : }
181 :
182 0 : rc = module->probe_key(name);
183 0 : if (rc == 0) {
184 0 : key = keyring_find_key(name);
185 0 : if (key == NULL) {
186 0 : SPDK_ERRLOG("Successfully probed key '%s' using module '%s', but "
187 : "the key is unavailable\n", name, module->name);
188 0 : return NULL;
189 : }
190 :
191 0 : key->probed = true;
192 0 : break;
193 0 : } else if (rc != -ENOKEY) {
194 : /* The module is aware of the key but couldn't instantiate it */
195 0 : assert(keyring_find_key(name) == NULL);
196 0 : SPDK_ERRLOG("Failed to probe key '%s' using module '%s': %s\n",
197 : name, module->name, spdk_strerror(-rc));
198 0 : break;
199 : }
200 : }
201 :
202 6 : return key;
203 : }
204 :
205 : struct spdk_key *
206 17 : spdk_keyring_get_key(const char *name)
207 : {
208 : struct spdk_key *key;
209 :
210 17 : pthread_mutex_lock(&g_keyring.mutex);
211 17 : key = keyring_find_key(name);
212 17 : if (key == NULL) {
213 6 : key = keyring_probe_key(name);
214 6 : if (key == NULL) {
215 6 : goto out;
216 : }
217 : }
218 :
219 11 : key->refcnt++;
220 17 : out:
221 17 : pthread_mutex_unlock(&g_keyring.mutex);
222 :
223 17 : return key;
224 : }
225 :
226 : void
227 11 : spdk_keyring_put_key(struct spdk_key *key)
228 : {
229 : int refcnt;
230 :
231 11 : if (key == NULL) {
232 0 : return;
233 : }
234 :
235 11 : pthread_mutex_lock(&g_keyring.mutex);
236 11 : refcnt = keyring_put_key(key);
237 11 : if (refcnt == 1 && key->probed && !key->removed) {
238 0 : keyring_remove_key(key);
239 : }
240 11 : pthread_mutex_unlock(&g_keyring.mutex);
241 : }
242 :
243 : struct spdk_key *
244 0 : spdk_key_dup(struct spdk_key *key)
245 : {
246 0 : pthread_mutex_lock(&g_keyring.mutex);
247 0 : key->refcnt++;
248 0 : pthread_mutex_unlock(&g_keyring.mutex);
249 :
250 0 : return key;
251 : }
252 :
253 : const char *
254 9 : spdk_key_get_name(struct spdk_key *key)
255 : {
256 9 : return key->name;
257 : }
258 :
259 : int
260 3 : spdk_key_get_key(struct spdk_key *key, void *buf, int len)
261 : {
262 3 : struct spdk_keyring_module *module = key->module;
263 :
264 3 : if (key->removed) {
265 1 : return -ENOKEY;
266 : }
267 :
268 2 : return module->get_key(key, buf, len);
269 : }
270 :
271 : void *
272 11 : spdk_key_get_ctx(struct spdk_key *key)
273 : {
274 11 : return key + 1;
275 : }
276 :
277 :
278 : struct spdk_keyring_module *
279 0 : spdk_key_get_module(struct spdk_key *key)
280 : {
281 0 : return key->module;
282 : }
283 :
284 : void
285 0 : spdk_keyring_write_config(struct spdk_json_write_ctx *w)
286 : {
287 : struct spdk_keyring_module *module;
288 :
289 0 : TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
290 0 : if (module->write_config != NULL) {
291 0 : module->write_config(w);
292 : }
293 : }
294 0 : }
295 :
296 : void
297 0 : spdk_keyring_for_each_key(struct spdk_keyring *keyring,
298 : void *ctx, void (*fn)(void *ctx, struct spdk_key *key), uint32_t flags)
299 : {
300 : struct spdk_key *key, *tmp;
301 :
302 0 : assert(keyring == NULL);
303 0 : pthread_mutex_lock(&g_keyring.mutex);
304 0 : TAILQ_FOREACH_SAFE(key, &g_keyring.keys, tailq, tmp) {
305 0 : fn(ctx, key);
306 : }
307 :
308 0 : if (flags & SPDK_KEYRING_FOR_EACH_ALL) {
309 0 : TAILQ_FOREACH_SAFE(key, &g_keyring.removed_keys, tailq, tmp) {
310 0 : fn(ctx, key);
311 : }
312 : }
313 0 : pthread_mutex_unlock(&g_keyring.mutex);
314 0 : }
315 :
316 : void
317 1 : spdk_keyring_register_module(struct spdk_keyring_module *module)
318 : {
319 1 : TAILQ_INSERT_TAIL(&g_keyring.modules, module, tailq);
320 1 : }
321 :
322 : void
323 0 : keyring_dump_key_info(struct spdk_key *key, struct spdk_json_write_ctx *w)
324 : {
325 0 : struct spdk_keyring_module *module = key->module;
326 :
327 0 : spdk_json_write_named_string(w, "name", key->name);
328 0 : spdk_json_write_named_string(w, "module", module->name);
329 0 : spdk_json_write_named_bool(w, "removed", key->removed);
330 0 : spdk_json_write_named_bool(w, "probed", key->probed);
331 0 : spdk_json_write_named_int32(w, "refcnt", key->refcnt);
332 :
333 0 : if (!key->removed && module->dump_info != NULL) {
334 0 : module->dump_info(key, w);
335 : }
336 0 : }
337 :
338 : int
339 0 : spdk_keyring_init(void)
340 : {
341 : struct spdk_keyring_module *module, *tmp;
342 0 : pthread_mutexattr_t attr;
343 : int rc;
344 :
345 0 : rc = pthread_mutexattr_init(&attr);
346 0 : if (rc != 0) {
347 0 : SPDK_ERRLOG("Failed to initialize mutex attr\n");
348 0 : return -rc;
349 : }
350 :
351 0 : rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
352 0 : if (rc != 0) {
353 0 : SPDK_ERRLOG("Failed to set mutex attr\n");
354 0 : pthread_mutexattr_destroy(&attr);
355 0 : return -rc;
356 : }
357 :
358 0 : rc = pthread_mutex_init(&g_keyring.mutex, &attr);
359 0 : if (rc != 0) {
360 0 : SPDK_ERRLOG("Failed to initialize mutex\n");
361 0 : pthread_mutexattr_destroy(&attr);
362 0 : return -rc;
363 : }
364 :
365 0 : pthread_mutexattr_destroy(&attr);
366 0 : TAILQ_FOREACH_SAFE(module, &g_keyring.modules, tailq, tmp) {
367 0 : if (module->init != NULL) {
368 0 : rc = module->init();
369 0 : if (rc != 0) {
370 0 : if (rc == -ENODEV) {
371 0 : SPDK_INFOLOG(keyring, "Skipping module %s\n", module->name);
372 0 : TAILQ_REMOVE(&g_keyring.modules, module, tailq);
373 0 : rc = 0;
374 0 : continue;
375 : }
376 :
377 0 : SPDK_ERRLOG("Failed to initialize module %s: %s\n",
378 : module->name, spdk_strerror(-rc));
379 0 : break;
380 : }
381 : }
382 :
383 0 : SPDK_INFOLOG(keyring, "Initialized module %s\n", module->name);
384 : }
385 :
386 0 : if (rc != 0) {
387 0 : TAILQ_FOREACH(tmp, &g_keyring.modules, tailq) {
388 0 : if (tmp == module) {
389 0 : break;
390 : }
391 0 : if (tmp->cleanup != NULL) {
392 0 : tmp->cleanup();
393 : }
394 : }
395 : }
396 :
397 0 : return rc;
398 : }
399 :
400 : void
401 0 : spdk_keyring_cleanup(void)
402 : {
403 : struct spdk_keyring_module *module;
404 : struct spdk_key *key;
405 :
406 0 : while (!TAILQ_EMPTY(&g_keyring.keys)) {
407 0 : key = TAILQ_FIRST(&g_keyring.keys);
408 0 : keyring_remove_key(key);
409 : }
410 :
411 0 : while (!TAILQ_EMPTY(&g_keyring.removed_keys)) {
412 0 : key = TAILQ_FIRST(&g_keyring.removed_keys);
413 0 : SPDK_WARNLOG("Key '%s' still has %d references\n", key->name, key->refcnt);
414 0 : key->refcnt = 0;
415 0 : TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
416 0 : keyring_free_key(key);
417 : }
418 :
419 0 : TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
420 0 : if (module->cleanup != NULL) {
421 0 : module->cleanup();
422 : }
423 : }
424 0 : }
425 :
426 1 : SPDK_LOG_REGISTER_COMPONENT(keyring)
|