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