xref: /spdk/lib/keyring/keyring.c (revision b4ba6cdf0ad14da86fe0ca1b53f6a3f7b09560de)
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 const char *
244 spdk_key_get_name(struct spdk_key *key)
245 {
246 	return key->name;
247 }
248 
249 int
250 spdk_key_get_key(struct spdk_key *key, void *buf, int len)
251 {
252 	struct spdk_keyring_module *module = key->module;
253 
254 	if (key->removed) {
255 		return -ENOKEY;
256 	}
257 
258 	return module->get_key(key, buf, len);
259 }
260 
261 void *
262 spdk_key_get_ctx(struct spdk_key *key)
263 {
264 	return key + 1;
265 }
266 
267 
268 struct spdk_keyring_module *
269 spdk_key_get_module(struct spdk_key *key)
270 {
271 	return key->module;
272 }
273 
274 void
275 spdk_keyring_write_config(struct spdk_json_write_ctx *w)
276 {
277 	struct spdk_keyring_module *module;
278 
279 	TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
280 		if (module->write_config != NULL) {
281 			module->write_config(w);
282 		}
283 	}
284 }
285 
286 void
287 spdk_keyring_for_each_key(struct spdk_keyring *keyring,
288 			  void *ctx, void (*fn)(void *ctx, struct spdk_key *key), uint32_t flags)
289 {
290 	struct spdk_key *key, *tmp;
291 
292 	assert(keyring == NULL);
293 	pthread_mutex_lock(&g_keyring.mutex);
294 	TAILQ_FOREACH_SAFE(key, &g_keyring.keys, tailq, tmp) {
295 		fn(ctx, key);
296 	}
297 
298 	if (flags & SPDK_KEYRING_FOR_EACH_ALL) {
299 		TAILQ_FOREACH_SAFE(key, &g_keyring.removed_keys, tailq, tmp) {
300 			fn(ctx, key);
301 		}
302 	}
303 	pthread_mutex_unlock(&g_keyring.mutex);
304 }
305 
306 void
307 spdk_keyring_register_module(struct spdk_keyring_module *module)
308 {
309 	TAILQ_INSERT_TAIL(&g_keyring.modules, module, tailq);
310 }
311 
312 void
313 keyring_dump_key_info(struct spdk_key *key, struct spdk_json_write_ctx *w)
314 {
315 	struct spdk_keyring_module *module = key->module;
316 
317 	spdk_json_write_named_string(w, "name", key->name);
318 	spdk_json_write_named_string(w, "module", module->name);
319 	spdk_json_write_named_bool(w, "removed", key->removed);
320 	spdk_json_write_named_bool(w, "probed", key->probed);
321 	spdk_json_write_named_int32(w, "refcnt", key->refcnt);
322 
323 	if (!key->removed && module->dump_info != NULL) {
324 		module->dump_info(key, w);
325 	}
326 }
327 
328 int
329 spdk_keyring_init(void)
330 {
331 	struct spdk_keyring_module *module, *tmp;
332 	pthread_mutexattr_t attr;
333 	int rc;
334 
335 	rc = pthread_mutexattr_init(&attr);
336 	if (rc != 0) {
337 		SPDK_ERRLOG("Failed to initialize mutex attr\n");
338 		return -rc;
339 	}
340 
341 	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
342 	if (rc != 0) {
343 		SPDK_ERRLOG("Failed to set mutex attr\n");
344 		pthread_mutexattr_destroy(&attr);
345 		return -rc;
346 	}
347 
348 	rc = pthread_mutex_init(&g_keyring.mutex, &attr);
349 	if (rc != 0) {
350 		SPDK_ERRLOG("Failed to initialize mutex\n");
351 		pthread_mutexattr_destroy(&attr);
352 		return -rc;
353 	}
354 
355 	pthread_mutexattr_destroy(&attr);
356 	TAILQ_FOREACH_SAFE(module, &g_keyring.modules, tailq, tmp) {
357 		if (module->init != NULL) {
358 			rc = module->init();
359 			if (rc != 0) {
360 				if (rc == -ENODEV) {
361 					SPDK_INFOLOG(keyring, "Skipping module %s\n", module->name);
362 					TAILQ_REMOVE(&g_keyring.modules, module, tailq);
363 					rc = 0;
364 					continue;
365 				}
366 
367 				SPDK_ERRLOG("Failed to initialize module %s: %s\n",
368 					    module->name, spdk_strerror(-rc));
369 				break;
370 			}
371 		}
372 
373 		SPDK_INFOLOG(keyring, "Initialized module %s\n", module->name);
374 	}
375 
376 	if (rc != 0) {
377 		TAILQ_FOREACH(tmp, &g_keyring.modules, tailq) {
378 			if (tmp == module) {
379 				break;
380 			}
381 			if (tmp->cleanup != NULL) {
382 				tmp->cleanup();
383 			}
384 		}
385 	}
386 
387 	return rc;
388 }
389 
390 void
391 spdk_keyring_cleanup(void)
392 {
393 	struct spdk_keyring_module *module;
394 	struct spdk_key *key;
395 
396 	while (!TAILQ_EMPTY(&g_keyring.keys)) {
397 		key = TAILQ_FIRST(&g_keyring.keys);
398 		keyring_remove_key(key);
399 	}
400 
401 	while (!TAILQ_EMPTY(&g_keyring.removed_keys)) {
402 		key = TAILQ_FIRST(&g_keyring.removed_keys);
403 		SPDK_WARNLOG("Key '%s' still has %d references\n", key->name, key->refcnt);
404 		key->refcnt = 0;
405 		TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
406 		keyring_free_key(key);
407 	}
408 
409 	TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
410 		if (module->cleanup != NULL) {
411 			module->cleanup();
412 		}
413 	}
414 }
415 
416 SPDK_LOG_REGISTER_COMPONENT(keyring)
417