| File: | .build-ci/../keysd/src/import.c |
| Warning: | line 148, column 9 Potential leak of memory pointed to by 'copy' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | |||
| 2 | /* | |||
| 3 | * This file is part of nvme-cli. | |||
| 4 | * Copyright (c) 2026 Dell Technologies Inc. or its subsidiaries. | |||
| 5 | * | |||
| 6 | * Authors: Martin Belanger <martin.belanger@dell.com> | |||
| 7 | */ | |||
| 8 | ||||
| 9 | #include <errno(*__errno_location ()).h> | |||
| 10 | #include <stdio.h> | |||
| 11 | #include <stdlib.h> | |||
| 12 | #include <string.h> | |||
| 13 | ||||
| 14 | #include <ccan/str/str.h> | |||
| 15 | #include <daemon-util/log.h> | |||
| 16 | #include <nvme/config.h> | |||
| 17 | #include <nvme/crypto.h> | |||
| 18 | #include <nvme/fabrics.h> | |||
| 19 | #include <shared/cleanup-util.h> | |||
| 20 | #include <shared/string-util.h> | |||
| 21 | ||||
| 22 | #include "config.h" | |||
| 23 | #include "creds.h" | |||
| 24 | #include "import.h" | |||
| 25 | ||||
| 26 | struct import_ctx { | |||
| 27 | struct libnvme_global_ctx *ctx; | |||
| 28 | const char *creds_dir; | |||
| 29 | const struct keysd_config *cfg; | |||
| 30 | struct kmip_job *jobs; | |||
| 31 | size_t n_jobs; | |||
| 32 | char *default_hostnqn; // system identity, for entries without one | |||
| 33 | bool_Bool default_read; // default_hostnqn was looked up | |||
| 34 | char **done; // "<hostnqn> <subsysnqn>" already handled | |||
| 35 | size_t n_done; | |||
| 36 | }; | |||
| 37 | ||||
| 38 | /* Look up the system host NQN only when an entry needs it. */ | |||
| 39 | static const char *default_hostnqn(struct import_ctx *ic) | |||
| 40 | { | |||
| 41 | __cleanup_free__attribute__((cleanup(shr_freep))) char *hostid = NULL((void*)0); | |||
| 42 | int r; | |||
| 43 | ||||
| 44 | if (ic->default_read) | |||
| 45 | return ic->default_hostnqn; | |||
| 46 | ||||
| 47 | ic->default_read = true1; | |||
| 48 | r = libnvmf_host_get_ids(ic->ctx, NULL((void*)0), NULL((void*)0), &ic->default_hostnqn, | |||
| 49 | &hostid); | |||
| 50 | if (r < 0) | |||
| 51 | log_warn("no default host NQN: %s", strerror(-r))dmn_log_msg(DMN_LOG_WARN, "no default host NQN: %s", strerror (-r)); | |||
| 52 | ||||
| 53 | return ic->default_hostnqn; | |||
| 54 | } | |||
| 55 | ||||
| 56 | /* | |||
| 57 | * Every path of a subsystem is a connection of its own, with the same | |||
| 58 | * key. Return true the first time a (hostnqn, subsysnqn) pair is seen. | |||
| 59 | */ | |||
| 60 | static bool_Bool first_time(struct import_ctx *ic, const char *hostnqn, | |||
| 61 | const char *subsysnqn) | |||
| 62 | { | |||
| 63 | char *pair, **p; | |||
| 64 | size_t i; | |||
| 65 | ||||
| 66 | if (asprintf(&pair, "%s %s", hostnqn, subsysnqn) < 0) | |||
| 67 | return true1; | |||
| 68 | ||||
| 69 | for (i = 0; i < ic->n_done; i++) { | |||
| 70 | if (streq(ic->done[i], pair)(strcmp((ic->done[i]),(pair)) == 0)) { | |||
| 71 | free(pair); | |||
| 72 | return false0; | |||
| 73 | } | |||
| 74 | } | |||
| 75 | ||||
| 76 | p = realloc(ic->done, (ic->n_done + 1) * sizeof(*p)); | |||
| 77 | if (!p) { | |||
| 78 | free(pair); | |||
| 79 | return true1; | |||
| 80 | } | |||
| 81 | ic->done = p; | |||
| 82 | ic->done[ic->n_done++] = pair; | |||
| 83 | ||||
| 84 | return true1; | |||
| 85 | } | |||
| 86 | ||||
| 87 | static const char *param(const struct libnvmf_params *params, const char *key) | |||
| 88 | { | |||
| 89 | const char *value = libnvmf_params_get(params, key); | |||
| 90 | ||||
| 91 | return (value && *value) ? value : NULL((void*)0); | |||
| 92 | } | |||
| 93 | ||||
| 94 | /* A credential name is a file name in the credential directory. */ | |||
| 95 | static bool_Bool cred_name_valid(const char *name) | |||
| 96 | { | |||
| 97 | return name[0] != '.' && !strchr(name, '/')_Generic (0 ? (name) : (void *) 1, const void *: (const char * ) (strchr (name, '/')), default: strchr (name, '/')); | |||
| 98 | } | |||
| 99 | ||||
| 100 | /* | |||
| 101 | * Large enough for a PSK in the interchange format: a 48-byte key plus | |||
| 102 | * its CRC is 72 characters in base64, plus the 17-character framing. | |||
| 103 | */ | |||
| 104 | #define CRED_MAX128 128 | |||
| 105 | ||||
| 106 | static void free_secret(void *p, size_t len) | |||
| 107 | { | |||
| 108 | if (!p) | |||
| 109 | return; | |||
| 110 | explicit_bzero(p, len); | |||
| 111 | free(p); | |||
| 112 | } | |||
| 113 | ||||
| 114 | struct revoke_ctx { | |||
| 115 | const char *hostnqn; | |||
| 116 | const char *subsysnqn; | |||
| 117 | const char *keep; // identity of the key to keep | |||
| 118 | char **identities; | |||
| 119 | size_t n; | |||
| 120 | int err; | |||
| 121 | }; | |||
| 122 | ||||
| 123 | /* | |||
| 124 | * A PSK description is "NVMe<v><R|G><hmac> <hostnqn> <subsysnqn>", and | |||
| 125 | * version 1 adds " <digest>". Collect every other key for the same pair. | |||
| 126 | */ | |||
| 127 | static void collect_other_key(struct libnvme_global_ctx *ctx | |||
| 128 | __attribute__((unused)), | |||
| 129 | long keyring __attribute__((unused)), | |||
| 130 | long key __attribute__((unused)), | |||
| 131 | char *desc, int desc_len __attribute__((unused)), | |||
| 132 | void *data) | |||
| 133 | { | |||
| 134 | struct revoke_ctx *rc = data; | |||
| 135 | __cleanup_free__attribute__((cleanup(shr_freep))) char *copy = NULL((void*)0); | |||
| 136 | char *save, *host, *subsys, **p; | |||
| 137 | ||||
| 138 | if (rc->err || streq(desc, rc->keep)(strcmp((desc),(rc->keep)) == 0)) | |||
| ||||
| 139 | return; | |||
| 140 | ||||
| 141 | copy = strdup(desc); | |||
| 142 | if (!copy) { | |||
| 143 | rc->err = -ENOMEM12; | |||
| 144 | return; | |||
| 145 | } | |||
| 146 | if (!strtok_r(copy, " ", &save)) | |||
| 147 | return; | |||
| 148 | host = strtok_r(NULL((void*)0), " ", &save); | |||
| ||||
| 149 | subsys = strtok_r(NULL((void*)0), " ", &save); | |||
| 150 | if (!host || !subsys || !streq(host, rc->hostnqn)(strcmp((host),(rc->hostnqn)) == 0) || | |||
| 151 | !streq(subsys, rc->subsysnqn)(strcmp((subsys),(rc->subsysnqn)) == 0)) | |||
| 152 | return; | |||
| 153 | ||||
| 154 | p = realloc(rc->identities, (rc->n + 1) * sizeof(*p)); | |||
| 155 | if (!p) { | |||
| 156 | rc->err = -ENOMEM12; | |||
| 157 | return; | |||
| 158 | } | |||
| 159 | rc->identities = p; | |||
| 160 | rc->identities[rc->n] = strdup(desc); | |||
| 161 | if (!rc->identities[rc->n]) { | |||
| 162 | rc->err = -ENOMEM12; | |||
| 163 | return; | |||
| 164 | } | |||
| 165 | rc->n++; | |||
| 166 | } | |||
| 167 | ||||
| 168 | static void revoke_other_keys(struct libnvme_global_ctx *ctx, | |||
| 169 | const char *source, const char *keyring, | |||
| 170 | const char *hostnqn, const char *subsysnqn, | |||
| 171 | const char *keep) | |||
| 172 | { | |||
| 173 | struct revoke_ctx rc = { | |||
| 174 | .hostnqn = hostnqn, | |||
| 175 | .subsysnqn = subsysnqn, | |||
| 176 | .keep = keep, | |||
| 177 | }; | |||
| 178 | size_t i; | |||
| 179 | int r; | |||
| 180 | ||||
| 181 | // Revoke after the scan, not while it walks the keyring. | |||
| 182 | r = libnvmf_scan_tls_keys(ctx, keyring, collect_other_key, &rc); | |||
| 183 | log_dbg("scanned %d keys, %zu to revoke", r, rc.n)dmn_log_msg(DMN_LOG_DEBUG, "%s() - " "scanned %d keys, %zu to revoke" , __func__, r, rc.n); | |||
| 184 | if (r < 0 || rc.err) | |||
| 185 | log_err("%s: %s: cannot scan the keyring: %s", source,dmn_log_msg(DMN_LOG_ERR, "%s: %s: cannot scan the keyring: %s" , source, subsysnqn, strerror(-(r < 0 ? r : rc.err))) | |||
| 186 | subsysnqn, strerror(-(r < 0 ? r : rc.err)))dmn_log_msg(DMN_LOG_ERR, "%s: %s: cannot scan the keyring: %s" , source, subsysnqn, strerror(-(r < 0 ? r : rc.err))); | |||
| 187 | ||||
| 188 | for (i = 0; i < rc.n; i++) { | |||
| 189 | r = libnvmf_revoke_tls_key(ctx, keyring, "psk", | |||
| 190 | rc.identities[i]); | |||
| 191 | if (r < 0) | |||
| 192 | log_err("cannot revoke '%s': %s", rc.identities[i],dmn_log_msg(DMN_LOG_ERR, "cannot revoke '%s': %s", rc.identities [i], strerror(-r)) | |||
| 193 | strerror(-r))dmn_log_msg(DMN_LOG_ERR, "cannot revoke '%s': %s", rc.identities [i], strerror(-r)); | |||
| 194 | else | |||
| 195 | log_info("revoked '%s'", rc.identities[i])dmn_log_msg(DMN_LOG_INFO, "revoked '%s'", rc.identities[i]); | |||
| 196 | free(rc.identities[i]); | |||
| 197 | } | |||
| 198 | free(rc.identities); | |||
| 199 | } | |||
| 200 | ||||
| 201 | /* | |||
| 202 | * Put the PSK @encoded, in the interchange format, in @keyring for | |||
| 203 | * @hostnqn and @subsysnqn. @origin says where the PSK comes from, for the | |||
| 204 | * log. | |||
| 205 | */ | |||
| 206 | static int import_psk(struct import_ctx *ic, const char *source, | |||
| 207 | const char *keyring, const char *hostnqn, | |||
| 208 | const char *subsysnqn, const char *origin, | |||
| 209 | const char *encoded) | |||
| 210 | { | |||
| 211 | __cleanup_free__attribute__((cleanup(shr_freep))) char *identity = NULL((void*)0); | |||
| 212 | enum libnvmf_hmac_alg hmac; | |||
| 213 | unsigned char version; | |||
| 214 | unsigned char *psk = NULL((void*)0); | |||
| 215 | size_t psk_len = 0; | |||
| 216 | long keyring_id, key; | |||
| 217 | int r; | |||
| 218 | ||||
| 219 | r = libnvmf_import_tls_key_versioned(ic->ctx, encoded, &version, | |||
| 220 | &hmac, &psk_len, &psk); | |||
| 221 | if (r < 0) { | |||
| 222 | log_err("%s: %s: %s is not a valid PSK: %s", source,dmn_log_msg(DMN_LOG_ERR, "%s: %s: %s is not a valid PSK: %s", source, subsysnqn, origin, strerror(-r)) | |||
| 223 | subsysnqn, origin, strerror(-r))dmn_log_msg(DMN_LOG_ERR, "%s: %s: %s is not a valid PSK: %s", source, subsysnqn, origin, strerror(-r)); | |||
| 224 | return r; | |||
| 225 | } | |||
| 226 | ||||
| 227 | r = libnvmf_generate_tls_key_identity(ic->ctx, hostnqn, subsysnqn, | |||
| 228 | version, hmac, psk, psk_len, | |||
| 229 | &identity); | |||
| 230 | if (r < 0) { | |||
| 231 | log_err("%s: %s: cannot derive the PSK identity: %s", source,dmn_log_msg(DMN_LOG_ERR, "%s: %s: cannot derive the PSK identity: %s" , source, subsysnqn, strerror(-r)) | |||
| 232 | subsysnqn, strerror(-r))dmn_log_msg(DMN_LOG_ERR, "%s: %s: cannot derive the PSK identity: %s" , source, subsysnqn, strerror(-r)); | |||
| 233 | goto out; | |||
| 234 | } | |||
| 235 | ||||
| 236 | r = libnvmf_lookup_keyring(ic->ctx, keyring, &keyring_id); | |||
| 237 | if (!r) | |||
| 238 | r = libnvmf_set_keyring(ic->ctx, keyring_id); | |||
| 239 | if (r < 0) { | |||
| 240 | log_err("%s: %s: keyring '%s' not available: %s", source,dmn_log_msg(DMN_LOG_ERR, "%s: %s: keyring '%s' not available: %s" , source, subsysnqn, keyring ?: ".nvme", strerror(-r)) | |||
| 241 | subsysnqn, keyring ?: ".nvme", strerror(-r))dmn_log_msg(DMN_LOG_ERR, "%s: %s: keyring '%s' not available: %s" , source, subsysnqn, keyring ?: ".nvme", strerror(-r)); | |||
| 242 | goto out; | |||
| 243 | } | |||
| 244 | ||||
| 245 | // The identity ends with a digest of the PSK: same identity, same key. | |||
| 246 | r = libnvmf_lookup_key(ic->ctx, "psk", identity, &key); | |||
| 247 | if (!r) { | |||
| 248 | log_dbg("'%s' already present", identity)dmn_log_msg(DMN_LOG_DEBUG, "%s() - " "'%s' already present", __func__ , identity); | |||
| 249 | } else { | |||
| 250 | log_dbg("'%s' not found: %s", identity, strerror(-r))dmn_log_msg(DMN_LOG_DEBUG, "%s() - " "'%s' not found: %s", __func__ , identity, strerror(-r)); | |||
| 251 | r = libnvmf_insert_tls_key_versioned(ic->ctx, keyring, "psk", | |||
| 252 | hostnqn, subsysnqn, | |||
| 253 | version, hmac, psk, | |||
| 254 | psk_len, &key); | |||
| 255 | if (r < 0) { | |||
| 256 | log_err("%s: %s: cannot insert the PSK: %s", source,dmn_log_msg(DMN_LOG_ERR, "%s: %s: cannot insert the PSK: %s", source, subsysnqn, strerror(-r)) | |||
| 257 | subsysnqn, strerror(-r))dmn_log_msg(DMN_LOG_ERR, "%s: %s: cannot insert the PSK: %s", source, subsysnqn, strerror(-r)); | |||
| 258 | goto out; | |||
| 259 | } | |||
| 260 | log_info("imported '%s' from %s", identity, origin)dmn_log_msg(DMN_LOG_INFO, "imported '%s' from %s", identity, origin ); | |||
| 261 | } | |||
| 262 | ||||
| 263 | revoke_other_keys(ic->ctx, source, keyring, hostnqn, subsysnqn, | |||
| 264 | identity); | |||
| 265 | ||||
| 266 | out: | |||
| 267 | free_secret(psk, psk_len); | |||
| 268 | ||||
| 269 | return r; | |||
| 270 | } | |||
| 271 | ||||
| 272 | static int import_cred(struct import_ctx *ic, const char *source, | |||
| 273 | const char *keyring, const char *hostnqn, | |||
| 274 | const char *subsysnqn, const char *name) | |||
| 275 | { | |||
| 276 | __cleanup_free__attribute__((cleanup(shr_freep))) char *origin = NULL((void*)0); | |||
| 277 | __cleanup_free__attribute__((cleanup(shr_freep))) char *error = NULL((void*)0); | |||
| 278 | char encoded[CRED_MAX128 + 1]; | |||
| 279 | int r; | |||
| 280 | ||||
| 281 | if (!cred_name_valid(name)) { | |||
| 282 | log_err("%s: %s: invalid credential name '%s'", source,dmn_log_msg(DMN_LOG_ERR, "%s: %s: invalid credential name '%s'" , source, subsysnqn, name) | |||
| 283 | subsysnqn, name)dmn_log_msg(DMN_LOG_ERR, "%s: %s: invalid credential name '%s'" , source, subsysnqn, name); | |||
| 284 | return -EINVAL22; | |||
| 285 | } | |||
| 286 | ||||
| 287 | r = creds_decrypt(ic->creds_dir, name, encoded, sizeof(encoded), | |||
| 288 | &error); | |||
| 289 | if (r < 0) { | |||
| 290 | explicit_bzero(encoded, sizeof(encoded)); | |||
| 291 | log_err("%s: %s: cannot decrypt credential '%s': %s", source,dmn_log_msg(DMN_LOG_ERR, "%s: %s: cannot decrypt credential '%s': %s" , source, subsysnqn, name, error ?: strerror(-r)) | |||
| 292 | subsysnqn, name, error ?: strerror(-r))dmn_log_msg(DMN_LOG_ERR, "%s: %s: cannot decrypt credential '%s': %s" , source, subsysnqn, name, error ?: strerror(-r)); | |||
| 293 | return r; | |||
| 294 | } | |||
| 295 | ||||
| 296 | if (asprintf(&origin, "credential '%s'", name) < 0) | |||
| 297 | r = -ENOMEM12; | |||
| 298 | else | |||
| 299 | r = import_psk(ic, source, keyring, hostnqn, subsysnqn, origin, | |||
| 300 | encoded); | |||
| 301 | explicit_bzero(encoded, sizeof(encoded)); | |||
| 302 | ||||
| 303 | return r; | |||
| 304 | } | |||
| 305 | ||||
| 306 | static void free_job(struct kmip_job *job) | |||
| 307 | { | |||
| 308 | free(job->source); | |||
| 309 | free(job->keyring); | |||
| 310 | free(job->hostnqn); | |||
| 311 | free(job->subsysnqn); | |||
| 312 | free(job->name); | |||
| 313 | } | |||
| 314 | ||||
| 315 | /* Find the KMS of "kmip:<name>", or of "kmip" when there is only one. */ | |||
| 316 | static const struct keysd_kmip *find_kms(struct import_ctx *ic, | |||
| 317 | const char *source, const char *subsysnqn, const char *src) | |||
| 318 | { | |||
| 319 | const char *name = shr_startswith(src, "kmip:"); | |||
| 320 | const struct keysd_kmip *kms; | |||
| 321 | ||||
| 322 | if (!name) { | |||
| 323 | if (ic->cfg->nr_kmip == 1) | |||
| 324 | return &ic->cfg->kmip[0]; | |||
| 325 | if (ic->cfg->nr_kmip) | |||
| 326 | log_err("%s: %s: several KMSes: use tls-key-source = kmip:<name>",dmn_log_msg(DMN_LOG_ERR, "%s: %s: several KMSes: use tls-key-source = kmip:<name>" , source, subsysnqn) | |||
| 327 | source, subsysnqn)dmn_log_msg(DMN_LOG_ERR, "%s: %s: several KMSes: use tls-key-source = kmip:<name>" , source, subsysnqn); | |||
| 328 | else | |||
| 329 | log_err("%s: %s: tls-key-source is kmip but no KMS is configured, skipped",dmn_log_msg(DMN_LOG_ERR, "%s: %s: tls-key-source is kmip but no KMS is configured, skipped" , source, subsysnqn) | |||
| 330 | source, subsysnqn)dmn_log_msg(DMN_LOG_ERR, "%s: %s: tls-key-source is kmip but no KMS is configured, skipped" , source, subsysnqn); | |||
| 331 | return NULL((void*)0); | |||
| 332 | } | |||
| 333 | ||||
| 334 | kms = config_find_kmip(ic->cfg, name); | |||
| 335 | if (!kms) | |||
| 336 | log_err("%s: %s: KMS '%s' is not configured", source,dmn_log_msg(DMN_LOG_ERR, "%s: %s: KMS '%s' is not configured" , source, subsysnqn, name) | |||
| 337 | subsysnqn, name)dmn_log_msg(DMN_LOG_ERR, "%s: %s: KMS '%s' is not configured" , source, subsysnqn, name); | |||
| 338 | ||||
| 339 | return kms; | |||
| 340 | } | |||
| 341 | ||||
| 342 | /* Collect a key to get from a KMS. */ | |||
| 343 | static void add_kmip_job(struct import_ctx *ic, const char *source, | |||
| 344 | const char *keyring, const char *hostnqn, | |||
| 345 | const char *subsysnqn, const char *src, | |||
| 346 | const char *name) | |||
| 347 | { | |||
| 348 | const struct keysd_kmip *kms; | |||
| 349 | struct kmip_job *jobs, *job; | |||
| 350 | ||||
| 351 | #ifndef CONFIG_KMIP | |||
| 352 | log_warn("%s: %s: this build does not support tls-key-source '%s', skipped",dmn_log_msg(DMN_LOG_WARN, "%s: %s: this build does not support tls-key-source '%s', skipped" , source, subsysnqn, src) | |||
| 353 | source, subsysnqn, src)dmn_log_msg(DMN_LOG_WARN, "%s: %s: this build does not support tls-key-source '%s', skipped" , source, subsysnqn, src); | |||
| 354 | return; | |||
| 355 | #endif | |||
| 356 | ||||
| 357 | kms = find_kms(ic, source, subsysnqn, src); | |||
| 358 | if (!kms) | |||
| 359 | return; | |||
| 360 | ||||
| 361 | jobs = realloc(ic->jobs, (ic->n_jobs + 1) * sizeof(*jobs)); | |||
| 362 | if (!jobs) { | |||
| 363 | log_err("%s: %s: out of memory", source, subsysnqn)dmn_log_msg(DMN_LOG_ERR, "%s: %s: out of memory", source, subsysnqn ); | |||
| 364 | return; | |||
| 365 | } | |||
| 366 | ic->jobs = jobs; | |||
| 367 | ||||
| 368 | job = &ic->jobs[ic->n_jobs]; | |||
| 369 | job->kms = kms; | |||
| 370 | job->source = strdup(source); | |||
| 371 | job->keyring = shr_xstrdup(keyring); | |||
| 372 | job->hostnqn = strdup(hostnqn); | |||
| 373 | job->subsysnqn = strdup(subsysnqn); | |||
| 374 | job->name = strdup(name); | |||
| 375 | if (!job->source || (keyring && !job->keyring) || !job->hostnqn || | |||
| 376 | !job->subsysnqn || !job->name) { | |||
| 377 | log_err("%s: %s: out of memory", source, subsysnqn)dmn_log_msg(DMN_LOG_ERR, "%s: %s: out of memory", source, subsysnqn ); | |||
| 378 | free_job(job); | |||
| 379 | return; | |||
| 380 | } | |||
| 381 | ic->n_jobs++; | |||
| 382 | } | |||
| 383 | ||||
| 384 | int import_kmip_psk(struct import_ctx *ic, const struct kmip_job *job, | |||
| 385 | const char *encoded) | |||
| 386 | { | |||
| 387 | __cleanup_free__attribute__((cleanup(shr_freep))) char *origin = NULL((void*)0); | |||
| 388 | ||||
| 389 | if (asprintf(&origin, "KMS '%s', key '%s'", job->kms->name, | |||
| 390 | job->name) < 0) | |||
| 391 | return -ENOMEM12; | |||
| 392 | ||||
| 393 | return import_psk(ic, job->source, job->keyring, job->hostnqn, | |||
| 394 | job->subsysnqn, origin, encoded); | |||
| 395 | } | |||
| 396 | ||||
| 397 | static void import_conn(const struct libnvmf_config_conn *conn, | |||
| 398 | void *user_data) | |||
| 399 | { | |||
| 400 | struct import_ctx *ic = user_data; | |||
| 401 | const struct libnvmf_params *params; | |||
| 402 | const char *source, *src, *name, *hostnqn, *subsysnqn; | |||
| 403 | ||||
| 404 | params = libnvmf_config_conn_get_params(conn); | |||
| 405 | src = param(params, "tls-key-source"); | |||
| 406 | if (!src || streq(src, "inline")(strcmp((src),("inline")) == 0)) | |||
| 407 | return; | |||
| 408 | ||||
| 409 | source = libnvmf_config_conn_get_source(conn); | |||
| 410 | subsysnqn = libnvmf_config_conn_get_subsysnqn(conn); | |||
| 411 | hostnqn = libnvmf_config_conn_get_hostnqn(conn) ?: default_hostnqn(ic); | |||
| 412 | if (!hostnqn) { | |||
| 413 | log_warn("%s: %s: no host NQN, skipped", source, subsysnqn)dmn_log_msg(DMN_LOG_WARN, "%s: %s: no host NQN, skipped", source , subsysnqn); | |||
| 414 | return; | |||
| 415 | } | |||
| 416 | if (!first_time(ic, hostnqn, subsysnqn)) | |||
| 417 | return; | |||
| 418 | ||||
| 419 | name = param(params, "tls-key"); | |||
| 420 | if (!name) { | |||
| 421 | log_warn("%s: %s: tls-key-source is %s but tls-key is not set, skipped",dmn_log_msg(DMN_LOG_WARN, "%s: %s: tls-key-source is %s but tls-key is not set, skipped" , source, subsysnqn, src) | |||
| 422 | source, subsysnqn, src)dmn_log_msg(DMN_LOG_WARN, "%s: %s: tls-key-source is %s but tls-key is not set, skipped" , source, subsysnqn, src); | |||
| 423 | return; | |||
| 424 | } | |||
| 425 | ||||
| 426 | if (streq(src, "kmip")(strcmp((src),("kmip")) == 0) || shr_startswith(src, "kmip:")) | |||
| 427 | add_kmip_job(ic, source, param(params, "keyring"), hostnqn, | |||
| 428 | subsysnqn, src, name); | |||
| 429 | else if (streq(src, "systemd-creds")(strcmp((src),("systemd-creds")) == 0)) | |||
| 430 | import_cred(ic, source, param(params, "keyring"), hostnqn, | |||
| 431 | subsysnqn, name); | |||
| 432 | else | |||
| 433 | log_warn("%s: %s: tls-key-source '%s' is not supported, skipped",dmn_log_msg(DMN_LOG_WARN, "%s: %s: tls-key-source '%s' is not supported, skipped" , source, subsysnqn, src) | |||
| 434 | source, subsysnqn, src)dmn_log_msg(DMN_LOG_WARN, "%s: %s: tls-key-source '%s' is not supported, skipped" , source, subsysnqn, src); | |||
| 435 | } | |||
| 436 | ||||
| 437 | static void find_tls_key_source(const struct libnvmf_config_conn *conn, | |||
| 438 | void *user_data) | |||
| 439 | { | |||
| 440 | const char *src; | |||
| 441 | bool_Bool *found = user_data; | |||
| 442 | ||||
| 443 | src = param(libnvmf_config_conn_get_params(conn), "tls-key-source"); | |||
| 444 | if (src && !streq(src, "inline")(strcmp((src),("inline")) == 0)) | |||
| 445 | *found = true1; | |||
| 446 | } | |||
| 447 | ||||
| 448 | bool_Bool import_needed(struct libnvme_global_ctx *ctx, const char *fabrics_conf) | |||
| 449 | { | |||
| 450 | struct libnvmf_config *cfg; | |||
| 451 | bool_Bool found = false0; | |||
| 452 | int r; | |||
| 453 | ||||
| 454 | r = libnvmf_config_read(ctx, fabrics_conf, &cfg); | |||
| 455 | if (r < 0) { | |||
| 456 | log_err("cannot read the fabrics configuration: %s",dmn_log_msg(DMN_LOG_ERR, "cannot read the fabrics configuration: %s" , strerror(-r)) | |||
| 457 | strerror(-r))dmn_log_msg(DMN_LOG_ERR, "cannot read the fabrics configuration: %s" , strerror(-r)); | |||
| 458 | return false0; | |||
| 459 | } | |||
| 460 | ||||
| 461 | libnvmf_config_conn_for_each(cfg, find_tls_key_source, &found); | |||
| 462 | libnvmf_config_free(cfg); | |||
| 463 | ||||
| 464 | return found; | |||
| 465 | } | |||
| 466 | ||||
| 467 | struct import_ctx *import_new(struct libnvme_global_ctx *ctx, | |||
| 468 | const char *creds_dir, const struct keysd_config *cfg) | |||
| 469 | { | |||
| 470 | struct import_ctx *ic; | |||
| 471 | ||||
| 472 | ic = calloc(1, sizeof(*ic)); | |||
| 473 | if (!ic) | |||
| 474 | return NULL((void*)0); | |||
| 475 | ic->ctx = ctx; | |||
| 476 | ic->creds_dir = creds_dir; | |||
| 477 | ic->cfg = cfg; | |||
| 478 | ||||
| 479 | return ic; | |||
| 480 | } | |||
| 481 | ||||
| 482 | void import_free(struct import_ctx *ic) | |||
| 483 | { | |||
| 484 | size_t i; | |||
| 485 | ||||
| 486 | if (!ic) | |||
| 487 | return; | |||
| 488 | ||||
| 489 | for (i = 0; i < ic->n_jobs; i++) | |||
| 490 | free_job(&ic->jobs[i]); | |||
| 491 | free(ic->jobs); | |||
| 492 | for (i = 0; i < ic->n_done; i++) | |||
| 493 | free(ic->done[i]); | |||
| 494 | free(ic->done); | |||
| 495 | free(ic->default_hostnqn); | |||
| 496 | free(ic); | |||
| 497 | } | |||
| 498 | ||||
| 499 | void import_keys(struct import_ctx *ic, const char *fabrics_conf) | |||
| 500 | { | |||
| 501 | struct libnvmf_config *cfg; | |||
| 502 | int r; | |||
| 503 | ||||
| 504 | r = libnvmf_config_read(ic->ctx, fabrics_conf, &cfg); | |||
| 505 | if (r < 0) { | |||
| 506 | log_err("cannot read the fabrics configuration: %s",dmn_log_msg(DMN_LOG_ERR, "cannot read the fabrics configuration: %s" , strerror(-r)) | |||
| 507 | strerror(-r))dmn_log_msg(DMN_LOG_ERR, "cannot read the fabrics configuration: %s" , strerror(-r)); | |||
| 508 | return; | |||
| 509 | } | |||
| 510 | ||||
| 511 | libnvmf_config_conn_for_each(cfg, import_conn, ic); | |||
| 512 | libnvmf_config_free(cfg); | |||
| 513 | } | |||
| 514 | ||||
| 515 | size_t import_kmip_jobs(struct import_ctx *ic, const struct kmip_job **jobs) | |||
| 516 | { | |||
| 517 | *jobs = ic->jobs; | |||
| 518 | ||||
| 519 | return ic->n_jobs; | |||
| 520 | } |