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