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