Bug Summary

File:.build-ci/../plugins/keys/keys-plugin.c
Warning:line 1007, column 7
Opened stream never closed. Potential resource leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name keys-plugin.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I src -I ../src -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-09-23-073103-589-1 -x c ../plugins/keys/keys-plugin.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * This file is part of nvme-cli.
4 * Copyright (c) 2026 SUSE Software Solutions
5 *
6 * Authors: Daniel Wagner <dwagner@suse.de>
7 */
8
9#include <errno(*__errno_location ()).h>
10#include <stdio.h>
11#include <string.h>
12#include <sys/stat.h>
13
14#include <libnvme.h>
15
16#include <shared/base64-util.h>
17#include <shared/compiler-attributes-util.h>
18#include <shared/crc32-util.h>
19
20#include "cleanup.h"
21#include "global-ctx.h"
22#include "logging.h"
23#include "nvme-print.h"
24#include "plugin.h"
25
26static int read_key_value(const char *inline_value, char **out)
27{
28 char line[512];
29
30 if (inline_value) {
31 *out = strdup(inline_value);
32 return *out ? 0 : -ENOMEM12;
33 }
34
35 if (!fgets(line, sizeof(line), stdinstdin))
36 return -EINVAL22;
37 line[strcspn(line, "\n")] = '\0';
38
39 *out = strdup(line);
40 return *out ? 0 : -ENOMEM12;
41}
42
43static bool_Bool valid_kxchap_secret_len(unsigned int len)
44{
45 return len == 32 || len == 48 || len == 64;
46}
47
48static int gen_kxchap(int argc, char **argv, struct command *acmd, struct plugin *plugin)
49{
50 const char *desc =
51 "Generate a KX-HMAC-CHAP secret in the DHHC-1 representation, usable for\n"
52 "NVMe In-Band Authentication.";
53 const char *secret =
54 "Optional secret (in hexadecimal characters) to be placed in the representation.";
55 const char *secret_len = "Length of the secret (32, 48, or 64 bytes).";
56 const char *hmac =
57 "Hash function the consumer is to apply to the secret (0 = none, 1 = SHA-256, 2 = SHA-384, 3 = SHA-512).";
58
59 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
60 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *raw_secret = NULL((void*)0);
61 unsigned char key[68];
62 char encoded_key[128];
63 unsigned long crc = shr_crc32(0L, NULL((void*)0), 0);
64 int err = 0;
65
66 struct config {
67 char *secret;
68 unsigned int secret_len;
69 unsigned int hmac;
70 };
71
72 struct config cfg = {
73 .secret = NULL((void*)0),
74 .secret_len = 0,
75 .hmac = 0,
76 };
77
78 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"secret", 's', "STRING", CFG_STRING, &cfg.secret,
1, secret, 0, }, {"secret-length", 'l', "NUM", CFG_POSITIVE,
&cfg.secret_len, 1, secret_len, 0, }, {"hmac", 'm', "NUM"
, CFG_POSITIVE, &cfg.hmac, 1, hmac, 0, }, {"", 0, ((void*
)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0,
((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args
.verbose, 0, "Increase output verbosity", 0, }, {"quiet", 0, (
(void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
79 OPT_STR("secret", 's', &cfg.secret, secret),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"secret", 's', "STRING", CFG_STRING, &cfg.secret,
1, secret, 0, }, {"secret-length", 'l', "NUM", CFG_POSITIVE,
&cfg.secret_len, 1, secret_len, 0, }, {"hmac", 'm', "NUM"
, CFG_POSITIVE, &cfg.hmac, 1, hmac, 0, }, {"", 0, ((void*
)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0,
((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args
.verbose, 0, "Increase output verbosity", 0, }, {"quiet", 0, (
(void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
80 OPT_UINT("secret-length", 'l', &cfg.secret_len, secret_len),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"secret", 's', "STRING", CFG_STRING, &cfg.secret,
1, secret, 0, }, {"secret-length", 'l', "NUM", CFG_POSITIVE,
&cfg.secret_len, 1, secret_len, 0, }, {"hmac", 'm', "NUM"
, CFG_POSITIVE, &cfg.hmac, 1, hmac, 0, }, {"", 0, ((void*
)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0,
((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args
.verbose, 0, "Increase output verbosity", 0, }, {"quiet", 0, (
(void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
81 OPT_UINT("hmac", 'm', &cfg.hmac, hmac))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"secret", 's', "STRING", CFG_STRING, &cfg.secret,
1, secret, 0, }, {"secret-length", 'l', "NUM", CFG_POSITIVE,
&cfg.secret_len, 1, secret_len, 0, }, {"hmac", 'm', "NUM"
, CFG_POSITIVE, &cfg.hmac, 1, hmac, 0, }, {"", 0, ((void*
)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0,
((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args
.verbose, 0, "Increase output verbosity", 0, }, {"quiet", 0, (
(void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
82
83 err = parse_args(argc, argv, desc, opts);
84 if (err)
85 return err;
86
87 err = nvme_create_global_ctx(&ctx);
88 if (err)
89 return err;
90
91 if (cfg.hmac > 3) {
92 nvme_show_error("Invalid HMAC identifier %u", cfg.hmac)nvme_show_message(1, "Invalid HMAC identifier %u", cfg.hmac);
93 return -EINVAL22;
94 }
95 /*
96 * The hash identifier records the transform the consumer applies; it
97 * does not constrain the secret's own length, so accept all three
98 * with any identifier. A secret given as hex is the payload, so it
99 * takes an even number of characters and fixes the length; an
100 * explicit one may only confirm it. Only a secret generated here
101 * (none given, or from a pin) falls back to the digest size.
102 */
103 if (cfg.secret && strncmp(cfg.secret, "pin:", 4)) {
104 size_t len = strlen(cfg.secret);
105
106 if (len % 2) {
107 nvme_show_error("Secret has an odd number of hexadecimal characters (%zu)",nvme_show_message(1, "Secret has an odd number of hexadecimal characters (%zu)"
, len)
108 len)nvme_show_message(1, "Secret has an odd number of hexadecimal characters (%zu)"
, len)
;
109 return -EINVAL22;
110 }
111 if (cfg.secret_len && cfg.secret_len != len / 2) {
112 nvme_show_error("Secret length %u does not match the secret given (%zu bytes)",nvme_show_message(1, "Secret length %u does not match the secret given (%zu bytes)"
, cfg.secret_len, len / 2)
113 cfg.secret_len, len / 2)nvme_show_message(1, "Secret length %u does not match the secret given (%zu bytes)"
, cfg.secret_len, len / 2)
;
114 return -EINVAL22;
115 }
116 cfg.secret_len = len / 2;
117 } else if (!cfg.secret_len) {
118 switch (cfg.hmac) {
119 case 1:
120 cfg.secret_len = 32;
121 break;
122 case 2:
123 cfg.secret_len = 48;
124 break;
125 case 3:
126 cfg.secret_len = 64;
127 break;
128 default:
129 cfg.secret_len = 32;
130 break;
131 }
132 }
133 if (!valid_kxchap_secret_len(cfg.secret_len)) {
134 nvme_show_error("Invalid secret length %u", cfg.secret_len)nvme_show_message(1, "Invalid secret length %u", cfg.secret_len
)
;
135 return -EINVAL22;
136 }
137
138 err = libnvmf_create_raw_secret(ctx, cfg.secret, cfg.secret_len, &raw_secret);
139 if (err)
140 return err;
141
142 memcpy(key, raw_secret, cfg.secret_len);
143
144 crc = shr_crc32(crc, key, cfg.secret_len);
145 key[cfg.secret_len++] = crc & 0xff;
146 key[cfg.secret_len++] = (crc >> 8) & 0xff;
147 key[cfg.secret_len++] = (crc >> 16) & 0xff;
148 key[cfg.secret_len++] = (crc >> 24) & 0xff;
149
150 memset(encoded_key, 0, sizeof(encoded_key));
151 shr_base64_encode(key, cfg.secret_len, encoded_key);
152
153 nvme_show_result("DHHC-1:%02x:%s:", cfg.hmac, encoded_key)nvme_show_message(0, "DHHC-1:%02x:%s:", cfg.hmac, encoded_key
)
;
154 return 0;
155}
156
157static int validate_kxchap_key(const char *key, int *hmac_out,
158 unsigned char *decoded_key, int *decoded_len_out, uint32_t *crc_out)
159{
160 uint32_t crc = shr_crc32(0L, NULL((void*)0), 0);
161 uint32_t key_crc;
162 size_t len = strlen(key);
163 int decoded_len, hmac, err;
164
165 if (sscanf(key, "DHHC-1:%02x:%*s", &hmac) != 1) {
166 nvme_show_error("Invalid secret header '%s'", key)nvme_show_message(1, "Invalid secret header '%s'", key);
167 return -EINVAL22;
168 }
169 if (hmac > 3) {
170 nvme_show_error("Invalid HMAC identifier %d", hmac)nvme_show_message(1, "Invalid HMAC identifier %d", hmac);
171 return -EINVAL22;
172 }
173
174 /*
175 * The hash identifier selects the function used to transform the
176 * secret into a key; it does not constrain the length of the secret
177 * itself, so apply the same length check whichever one is selected.
178 * A 32, 48 or 64 byte secret plus a 4 byte CRC encodes to 48, 72 or
179 * 92 base64 characters, giving a total of 59, 83 or 103.
180 *
181 * This does not pin the length of the secret - the same number of
182 * base64 characters can carry three different byte counts - so the
183 * decoded length is still checked below. What it does do is bound
184 * the decode before it runs.
185 */
186 if (len != 59 && len != 83 && len != 103) {
187 nvme_show_error("Invalid DHHC-1 string length %zu", len)nvme_show_message(1, "Invalid DHHC-1 string length %zu", len);
188 return -EINVAL22;
189 }
190
191 if (key[len - 1] != ':') {
192 nvme_show_error("Invalid secret format (missing trailing ':')")nvme_show_message(1, "Invalid secret format (missing trailing ':')"
)
;
193 return -EINVAL22;
194 }
195
196 err = shr_base64_decode(key + 10, len - 11, decoded_key);
197 if (err < 0) {
198 nvme_show_error("Base64 decoding failed, error %d", err)nvme_show_message(1, "Base64 decoding failed, error %d", err);
199 return err;
200 }
201 decoded_len = err;
202 decoded_len -= 4;
203 if (!valid_kxchap_secret_len(decoded_len)) {
204 nvme_show_error("Invalid secret length %d", decoded_len)nvme_show_message(1, "Invalid secret length %d", decoded_len);
205 return -EINVAL22;
206 }
207 crc = shr_crc32(crc, decoded_key, decoded_len);
208 key_crc = ((uint32_t)decoded_key[decoded_len]) |
209 ((uint32_t)decoded_key[decoded_len + 1] << 8) |
210 ((uint32_t)decoded_key[decoded_len + 2] << 16) |
211 ((uint32_t)decoded_key[decoded_len + 3] << 24);
212 if (key_crc != crc) {
213 nvme_show_error("CRC mismatch (secret %08x, crc %08x)", key_crc, crc)nvme_show_message(1, "CRC mismatch (secret %08x, crc %08x)", key_crc
, crc)
;
214 return -EINVAL22;
215 }
216
217 *hmac_out = hmac;
218 *decoded_len_out = decoded_len;
219 *crc_out = crc;
220 return 0;
221}
222
223static int check_kxchap(int argc, char **argv, struct command *acmd, struct plugin *plugin)
224{
225 const char *desc =
226 "Check a KX-HMAC-CHAP host secret for usability for NVMe In-Band Authentication,\n"
227 "and, if --identity is given, check whether it is already loaded into a keyring.";
228 const char *keydata = "KX-HMAC-CHAP secret (in DHHC-1 interchange format) to be validated. Reads from stdin if not given.";
229 const char *keyring = "Keyring to check for an already loaded secret.";
230 const char *keytype = "Key type of the secret to look up.";
231 const char *identity = "Identity to look up in the keyring to check if the secret is already loaded.";
232
233 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
234 __cleanup_free__attribute__((cleanup(shr_freep))) char *key = NULL((void*)0);
235 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *stored = NULL((void*)0);
236 unsigned char decoded_key[128];
237 long keyring_id = 0, key_id = 0;
238 int decoded_len, hmac, err, stored_len;
239 uint32_t crc;
240 struct config {
241 char *keydata;
242 char *keyring;
243 char *keytype;
244 char *identity;
245 };
246
247 struct config cfg = {
248 .keydata = NULL((void*)0),
249 .keyring = ".nvme",
250 .keytype = "kxchap",
251 .identity = NULL((void*)0),
252 };
253
254 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keydata", 'd', "STRING", CFG_STRING, &cfg.keydata
, 1, keydata, 0, }, {"keyring", 'k', "STRING", CFG_STRING, &
cfg.keyring, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING
, &cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
255 OPT_STR("keydata", 'd', &cfg.keydata, keydata),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keydata", 'd', "STRING", CFG_STRING, &cfg.keydata
, 1, keydata, 0, }, {"keyring", 'k', "STRING", CFG_STRING, &
cfg.keyring, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING
, &cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
256 OPT_STR("keyring", 'k', &cfg.keyring, keyring),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keydata", 'd', "STRING", CFG_STRING, &cfg.keydata
, 1, keydata, 0, }, {"keyring", 'k', "STRING", CFG_STRING, &
cfg.keyring, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING
, &cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
257 OPT_STR("keytype", 't', &cfg.keytype, keytype),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keydata", 'd', "STRING", CFG_STRING, &cfg.keydata
, 1, keydata, 0, }, {"keyring", 'k', "STRING", CFG_STRING, &
cfg.keyring, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING
, &cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
258 OPT_STR("identity", 'i', &cfg.identity, identity))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keydata", 'd', "STRING", CFG_STRING, &cfg.keydata
, 1, keydata, 0, }, {"keyring", 'k', "STRING", CFG_STRING, &
cfg.keyring, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING
, &cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
259
260 err = parse_args(argc, argv, desc, opts);
261 if (err)
262 return err;
263
264 err = read_key_value(cfg.keydata, &key);
265 if (err) {
266 nvme_show_error("No secret data")nvme_show_message(1, "No secret data");
267 return err;
268 }
269
270 err = validate_kxchap_key(key, &hmac, decoded_key, &decoded_len, &crc);
271 if (err)
272 return err;
273
274 nvme_show_verbose_result("Secret is valid (HMAC %d, length %d, CRC %08x)", hmac, decoded_len, crc)nvme_show_verbose_message("Secret is valid (HMAC %d, length %d, CRC %08x)"
, hmac, decoded_len, crc)
;
275
276 if (!cfg.identity)
277 return 0;
278
279 err = nvme_create_global_ctx(&ctx);
280 if (err) {
281 nvme_show_error("Failed to create global context")nvme_show_message(1, "Failed to create global context");
282 return err;
283 }
284 libnvme_set_logging_level(ctx, log_level, false0, false0);
285
286 err = libnvmf_lookup_keyring(ctx, cfg.keyring, &keyring_id);
287 if (err) {
288 nvme_show_error("Failed to lookup keyring '%s', %s",nvme_show_message(1, "Failed to lookup keyring '%s', %s", cfg
.keyring, libnvme_strerror(-err))
289 cfg.keyring, libnvme_strerror(-err))nvme_show_message(1, "Failed to lookup keyring '%s', %s", cfg
.keyring, libnvme_strerror(-err))
;
290 return err;
291 }
292
293 err = libnvmf_set_keyring(ctx, keyring_id);
294 if (err) {
295 nvme_show_error("Failed to link keyring '%s', %s",nvme_show_message(1, "Failed to link keyring '%s', %s", cfg.keyring
, libnvme_strerror(-err))
296 cfg.keyring, libnvme_strerror(-err))nvme_show_message(1, "Failed to link keyring '%s', %s", cfg.keyring
, libnvme_strerror(-err))
;
297 return err;
298 }
299
300 err = libnvmf_lookup_key(ctx, cfg.keytype, cfg.identity, &key_id);
301 if (err) {
302 nvme_show_verbose_result("Secret is not loaded for identity '%s'", cfg.identity)nvme_show_verbose_message("Secret is not loaded for identity '%s'"
, cfg.identity)
;
303 return 0;
304 }
305
306 err = libnvmf_read_key(ctx, keyring_id, key_id, &stored_len, &stored);
307 if (err) {
308 nvme_show_error("Failed to read back loaded key, %s",nvme_show_message(1, "Failed to read back loaded key, %s", libnvme_strerror
(-err))
309 libnvme_strerror(-err))nvme_show_message(1, "Failed to read back loaded key, %s", libnvme_strerror
(-err))
;
310 return err;
311 }
312
313 if ((size_t)stored_len == strlen(key) && !memcmp(stored, key, stored_len))
314 nvme_show_verbose_result("Secret is loaded (serial %08x) and matches", (unsigned int)key_id)nvme_show_verbose_message("Secret is loaded (serial %08x) and matches"
, (unsigned int)key_id)
;
315 else
316 nvme_show_verbose_result("Secret is loaded (serial %08x) but differs", (unsigned int)key_id)nvme_show_verbose_message("Secret is loaded (serial %08x) but differs"
, (unsigned int)key_id)
;
317
318 return 0;
319}
320
321static int append_keyfile(struct libnvme_global_ctx *ctx, const char *keyring,
322 long id, const char *keyfile)
323{
324 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *key_data = NULL((void*)0);
325 __cleanup_free__attribute__((cleanup(shr_freep))) char *exported_key = NULL((void*)0);
326 __cleanup_free__attribute__((cleanup(shr_freep))) char *identity = NULL((void*)0);
327 __cleanup_file__attribute__((cleanup(shr_cleanup_file))) FILE *fd = NULL((void*)0);
328 int err, hmac, key_len;
329 mode_t old_umask;
330 long kr_id;
331 char type;
332
333 err = libnvmf_lookup_keyring(ctx, keyring, &kr_id);
334 if (err) {
335 nvme_show_error("Failed to lookup keyring '%s', %s",nvme_show_message(1, "Failed to lookup keyring '%s', %s", keyring
, libnvme_strerror(-err))
336 keyring, libnvme_strerror(-err))nvme_show_message(1, "Failed to lookup keyring '%s', %s", keyring
, libnvme_strerror(-err))
;
337 return err;
338 }
339
340 identity = libnvmf_describe_key_serial(ctx, id);
341 if (!identity) {
342 nvme_show_error("Failed to get identity info")nvme_show_message(1, "Failed to get identity info");
343 return -EINVAL22;
344 }
345
346 if (sscanf(identity, "NVMe%*1d%c%02d %*s", &type, &hmac) != 2) {
347 nvme_show_error("Failed to parse identity\n")nvme_show_message(1, "Failed to parse identity\n");
348 return -EINVAL22;
349 }
350
351 err = libnvmf_read_key(ctx, kr_id, id, &key_len, &key_data);
352 if (err) {
353 nvme_show_error("Failed to read back derived TLS PSK, %s",nvme_show_message(1, "Failed to read back derived TLS PSK, %s"
, libnvme_strerror(-err))
354 libnvme_strerror(-err))nvme_show_message(1, "Failed to read back derived TLS PSK, %s"
, libnvme_strerror(-err))
;
355 return err;
356 }
357
358 err = libnvmf_export_tls_key_versioned(ctx, 1, hmac, key_data,
359 key_len, &exported_key);
360 if (err) {
361 nvme_show_error("Failed to export key, %s",nvme_show_message(1, "Failed to export key, %s", libnvme_strerror
(-err))
362 libnvme_strerror(-err))nvme_show_message(1, "Failed to export key, %s", libnvme_strerror
(-err))
;
363 return err;
364 }
365
366 old_umask = umask(S_IRWXG((0400|0200|0100) >> 3) | S_IRWXO(((0400|0200|0100) >> 3) >> 3));
367
368 fd = fopen(keyfile, "a");
369 if (!fd) {
370 nvme_show_error("Failed to open '%s', %s",nvme_show_message(1, "Failed to open '%s', %s", keyfile, libnvme_strerror
((*__errno_location ())))
371 keyfile, libnvme_strerror(errno))nvme_show_message(1, "Failed to open '%s', %s", keyfile, libnvme_strerror
((*__errno_location ())))
;
372 err = -errno(*__errno_location ());
373 goto out;
374 }
375
376 /*
377 * The umask above only affects newly created files: an existing
378 * keyfile could already be more permissive, so restrict the mode of
379 * the file we actually opened, via its descriptor, before writing
380 * the key to it. Using the descriptor rather than the path avoids a
381 * rename/symlink race between checking and fixing up the mode.
382 */
383 if (fchmod(fileno(fd), 0600) < 0) {
384 nvme_show_error("Failed to restrict permissions on '%s', %s",nvme_show_message(1, "Failed to restrict permissions on '%s', %s"
, keyfile, libnvme_strerror((*__errno_location ())))
385 keyfile, libnvme_strerror(errno))nvme_show_message(1, "Failed to restrict permissions on '%s', %s"
, keyfile, libnvme_strerror((*__errno_location ())))
;
386 err = -errno(*__errno_location ());
387 goto out;
388 }
389
390 err = fprintf(fd, "%s %s\n", identity, exported_key);
391 if (err < 0) {
392 nvme_show_error("Failed to append key to '%s', %s",nvme_show_message(1, "Failed to append key to '%s', %s", keyfile
, libnvme_strerror((*__errno_location ())))
393 keyfile, libnvme_strerror(errno))nvme_show_message(1, "Failed to append key to '%s', %s", keyfile
, libnvme_strerror((*__errno_location ())))
;
394 err = -errno(*__errno_location ());
395 } else {
396 err = 0;
397 }
398
399out:
400 umask(old_umask);
401
402 return err;
403}
404
405static int do_insert_tls_key(struct libnvme_global_ctx *ctx, const char *keyring,
406 const char *keytype, const char *hostnqn, const char *subsysnqn,
407 int identity, int hmac, unsigned char *key_data, int key_len,
408 bool_Bool compat, const char *keyfile, long *tls_key)
409{
410 int err;
411
412 if (compat)
413 err = libnvmf_insert_tls_key_compat(ctx, keyring, keytype, hostnqn,
414 subsysnqn, identity, hmac, key_data, key_len, tls_key);
415 else
416 err = libnvmf_insert_tls_key_versioned(ctx, keyring, keytype, hostnqn,
417 subsysnqn, identity, hmac, key_data, key_len, tls_key);
418 if (err) {
419 nvme_show_error("Failed to insert key, %s", libnvme_strerror(-err))nvme_show_message(1, "Failed to insert key, %s", libnvme_strerror
(-err))
;
420 return err;
421 }
422 nvme_show_result("Inserted TLS PSK %08x", (unsigned int)*tls_key)nvme_show_message(0, "Inserted TLS PSK %08x", (unsigned int)*
tls_key)
;
423
424 if (keyfile) {
425 err = append_keyfile(ctx, keyring, *tls_key, keyfile);
426 if (err)
427 return err;
428 }
429
430 return 0;
431}
432
433static int gen_tls(int argc, char **argv, struct command *acmd, struct plugin *plugin)
434{
435 const char *desc = "Generate a TLS configured PSK in NVMe PSK Interchange format.";
436 const char *secret =
437 "Optional configured PSK (in hexadecimal characters) to be used.";
438 const char *hmac =
439 "Hash function for the retained PSK and for the cipher suite the TLS PSK is bound to (1 = SHA-256, 2 = SHA-384).";
440 const char *version = "TLS PSK identity version to use (0 = obsolete; 1 = TLS 1.3 with the PSK digest in the identity)";
441 const char *hostnqn = "Host NQN for the retained PSK and the TLS PSK identity.";
442 const char *subsysnqn = "Subsystem NQN for the TLS PSK identity.";
443 const char *keyring = "Keyring for the TLS PSK.";
444 const char *keytype = "Key type of the TLS PSK.";
445 const char *insert = "Additionally insert the TLS PSK into the keyring.";
446 const char *keyfile = "Append the identity of the TLS PSK, and the TLS PSK itself, to keyfile.";
447 const char *compat = "Use non-RFC 8446 compliant algorithm for deriving the retained PSK and the TLS PSK for older implementations.";
448
449 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
450 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *raw_secret = NULL((void*)0);
451 __cleanup_free__attribute__((cleanup(shr_freep))) char *encoded_key = NULL((void*)0);
452 __cleanup_free__attribute__((cleanup(shr_freep))) char *hnqn = NULL((void*)0);
453 int key_len = 32;
454 int err;
455 long tls_key;
456
457 struct config {
458 char *keyring;
459 char *keytype;
460 char *hostnqn;
461 char *subsysnqn;
462 char *secret;
463 char *keyfile;
464 unsigned char hmac;
465 unsigned char version;
466 bool_Bool insert;
467 bool_Bool compat;
468 };
469
470 struct config cfg = {
471 .keyring = ".nvme",
472 .keytype = "psk",
473 .hostnqn = NULL((void*)0),
474 .subsysnqn = NULL((void*)0),
475 .secret = NULL((void*)0),
476 .keyfile = NULL((void*)0),
477 .hmac = 1,
478 .version = 0,
479 .insert = false0,
480 .compat = false0,
481 };
482
483 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
484 OPT_STR("keyring", 'k', &cfg.keyring, keyring),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
485 OPT_STR("keytype", 't', &cfg.keytype, keytype),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
486 OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
487 OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
488 OPT_STR("secret", 's', &cfg.secret, secret),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
489 OPT_STR("keyfile", 'f', &cfg.keyfile, keyfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
490 OPT_BYTE("hmac", 'm', &cfg.hmac, hmac),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
491 OPT_BYTE("identity", 'I', &cfg.version, version),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
492 OPT_FLAG("insert", 'i', &cfg.insert, insert),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
493 OPT_FLAG("compat", 'C', &cfg.compat, compat))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"secret"
, 's', "STRING", CFG_STRING, &cfg.secret, 1, secret, 0, }
, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1,
keyfile, 0, }, {"hmac", 'm', "NUM", CFG_BYTE, &cfg.hmac,
1, hmac, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.version
, 1, version, 0, }, {"insert", 'i', ((void*)0), CFG_FLAG, &
cfg.insert, 0, insert, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
494
495 err = parse_args(argc, argv, desc, opts);
496 if (err)
497 return err;
498 if (cfg.hmac < 1 || cfg.hmac > 2) {
499 nvme_show_error("Invalid HMAC identifier %u", cfg.hmac)nvme_show_message(1, "Invalid HMAC identifier %u", cfg.hmac);
500 return -EINVAL22;
501 }
502 if (cfg.version > 1) {
503 nvme_show_error("Invalid TLS PSK identity version %u",nvme_show_message(1, "Invalid TLS PSK identity version %u", cfg
.version)
504 cfg.version)nvme_show_message(1, "Invalid TLS PSK identity version %u", cfg
.version)
;
505 return -EINVAL22;
506 }
507 if (cfg.insert) {
508 if (!cfg.subsysnqn) {
509 nvme_show_error("No subsystem NQN specified")nvme_show_message(1, "No subsystem NQN specified");
510 return -EINVAL22;
511 }
512 }
513 if (cfg.hmac == 2)
514 key_len = 48;
515
516 err = nvme_create_global_ctx(&ctx);
517 if (err)
518 return err;
519
520 err = libnvmf_create_raw_secret(ctx, cfg.secret, key_len, &raw_secret);
521 if (err)
522 return err;
523
524 err = libnvmf_export_tls_key(ctx, raw_secret, key_len, &encoded_key);
525 if (err) {
526 nvme_show_error("Failed to export key, %s", libnvme_strerror(-err))nvme_show_message(1, "Failed to export key, %s", libnvme_strerror
(-err))
;
527 return err;
528 }
529 nvme_show_result("%s", encoded_key)nvme_show_message(0, "%s", encoded_key);
530
531 if (cfg.insert) {
532 if (!cfg.hostnqn) {
533 err = libnvmf_host_get_ids(ctx, NULL((void*)0), NULL((void*)0), &hnqn, NULL((void*)0));
534 if (err)
535 return err;
536 cfg.hostnqn = hnqn;
537 }
538
539 err = do_insert_tls_key(ctx, cfg.keyring, cfg.keytype,
540 cfg.hostnqn, cfg.subsysnqn, cfg.version,
541 cfg.hmac, raw_secret, key_len, cfg.compat,
542 cfg.keyfile, &tls_key);
543 if (err)
544 return err;
545 }
546
547 return 0;
548}
549
550static int check_tls(int argc, char **argv, struct command *acmd, struct plugin *plugin)
551{
552 const char *desc =
553 "Check a TLS configured PSK for NVMe PSK Interchange format, and, if a\n"
554 "subsystem NQN is given, check whether the corresponding TLS PSK is\n"
555 "already loaded into a keyring.";
556 const char *keydata = "Configured PSK (in PSK Interchange format) to be validated. Reads from stdin if not given.";
557 const char *identity = "TLS PSK identity version to use (0 = obsolete; 1 = TLS 1.3 with the PSK digest in the identity)";
558 const char *hostnqn = "Host NQN for the TLS PSK identity.";
559 const char *subsysnqn = "Subsystem NQN for the TLS PSK identity. If not given, only the format is validated.";
560 const char *keyring = "Keyring to check for an already loaded TLS PSK.";
561 const char *keytype = "Key type of the TLS PSK to look up.";
562 const char *compat = "Use non-RFC 8446 compliant algorithm for deriving the TLS PSK identity for older implementations.";
563
564 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
565 __cleanup_free__attribute__((cleanup(shr_freep))) char *key_value = NULL((void*)0);
566 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *decoded_key = NULL((void*)0);
567 __cleanup_free__attribute__((cleanup(shr_freep))) char *hnqn = NULL((void*)0);
568 __cleanup_free__attribute__((cleanup(shr_freep))) char *tls_id = NULL((void*)0);
569 int decoded_len, err = 0;
570 enum libnvmf_hmac_alg hmac;
571 long keyring_id, key_id;
572 struct config {
573 char *keyring;
574 char *keytype;
575 char *hostnqn;
576 char *subsysnqn;
577 char *keydata;
578 unsigned char identity;
579 bool_Bool compat;
580 };
581
582 struct config cfg = {
583 .keyring = ".nvme",
584 .keytype = "psk",
585 .hostnqn = NULL((void*)0),
586 .subsysnqn = NULL((void*)0),
587 .keydata = NULL((void*)0),
588 .identity = 0,
589 .compat = false0,
590 };
591
592 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"identity", 'I', "NUM", CFG_BYTE, &cfg.identity, 1, identity
, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG, &cfg.compat
, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
593 OPT_STR("keyring", 'k', &cfg.keyring, keyring),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"identity", 'I', "NUM", CFG_BYTE, &cfg.identity, 1, identity
, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG, &cfg.compat
, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
594 OPT_STR("keytype", 't', &cfg.keytype, keytype),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"identity", 'I', "NUM", CFG_BYTE, &cfg.identity, 1, identity
, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG, &cfg.compat
, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
595 OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"identity", 'I', "NUM", CFG_BYTE, &cfg.identity, 1, identity
, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG, &cfg.compat
, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
596 OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"identity", 'I', "NUM", CFG_BYTE, &cfg.identity, 1, identity
, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG, &cfg.compat
, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
597 OPT_STR("keydata", 'd', &cfg.keydata, keydata),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"identity", 'I', "NUM", CFG_BYTE, &cfg.identity, 1, identity
, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG, &cfg.compat
, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
598 OPT_BYTE("identity", 'I', &cfg.identity, identity),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"identity", 'I', "NUM", CFG_BYTE, &cfg.identity, 1, identity
, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG, &cfg.compat
, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
599 OPT_FLAG("compat", 'C', &cfg.compat, compat))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"identity", 'I', "NUM", CFG_BYTE, &cfg.identity, 1, identity
, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG, &cfg.compat
, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
600
601 err = parse_args(argc, argv, desc, opts);
602 if (err)
603 return err;
604
605 if (cfg.identity > 1) {
606 nvme_show_error("Invalid TLS PSK identity version %u",nvme_show_message(1, "Invalid TLS PSK identity version %u", cfg
.identity)
607 cfg.identity)nvme_show_message(1, "Invalid TLS PSK identity version %u", cfg
.identity)
;
608 return -EINVAL22;
609 }
610
611 err = read_key_value(cfg.keydata, &key_value);
612 if (err) {
613 nvme_show_error("No key data")nvme_show_message(1, "No key data");
614 return err;
615 }
616
617 err = nvme_create_global_ctx(&ctx);
618 if (err) {
619 nvme_show_error("Failed to create global context")nvme_show_message(1, "Failed to create global context");
620 return err;
621 }
622 libnvme_set_logging_level(ctx, log_level, false0, false0);
623
624 err = libnvmf_import_tls_key(ctx, key_value, &decoded_len,
625 &hmac, &decoded_key);
626 if (err) {
627 nvme_show_error("Key decoding failed, %s", libnvme_strerror(-err))nvme_show_message(1, "Key decoding failed, %s", libnvme_strerror
(-err))
;
628 return err;
629 }
630 nvme_show_verbose_result("Configured PSK is valid (HMAC %u, length %d)", hmac, decoded_len)nvme_show_verbose_message("Configured PSK is valid (HMAC %u, length %d)"
, hmac, decoded_len)
;
631
632 if (!cfg.subsysnqn)
633 return 0;
634
635 if (!cfg.hostnqn) {
636 err = libnvmf_host_get_ids(ctx, NULL((void*)0), NULL((void*)0), &hnqn, NULL((void*)0));
637 if (err)
638 return err;
639 cfg.hostnqn = hnqn;
640 }
641
642 if (cfg.compat)
643 err = libnvmf_generate_tls_key_identity_compat(ctx,
644 cfg.hostnqn, cfg.subsysnqn, cfg.identity,
645 hmac, decoded_key, decoded_len, &tls_id);
646 else
647 err = libnvmf_generate_tls_key_identity(ctx,
648 cfg.hostnqn, cfg.subsysnqn, cfg.identity,
649 hmac, decoded_key, decoded_len, &tls_id);
650 if (err) {
651 nvme_show_error("Failed to generate identity, %s",nvme_show_message(1, "Failed to generate identity, %s", libnvme_strerror
(-err))
652 libnvme_strerror(-err))nvme_show_message(1, "Failed to generate identity, %s", libnvme_strerror
(-err))
;
653 return err;
654 }
655 nvme_show_result("%s", tls_id)nvme_show_message(0, "%s", tls_id);
656
657 err = libnvmf_lookup_keyring(ctx, cfg.keyring, &keyring_id);
658 if (err) {
659 nvme_show_error("Failed to lookup keyring '%s', %s",nvme_show_message(1, "Failed to lookup keyring '%s', %s", cfg
.keyring, libnvme_strerror(-err))
660 cfg.keyring, libnvme_strerror(-err))nvme_show_message(1, "Failed to lookup keyring '%s', %s", cfg
.keyring, libnvme_strerror(-err))
;
661 return err;
662 }
663
664 err = libnvmf_set_keyring(ctx, keyring_id);
665 if (err) {
666 nvme_show_error("Failed to link keyring '%s', %s",nvme_show_message(1, "Failed to link keyring '%s', %s", cfg.keyring
, libnvme_strerror(-err))
667 cfg.keyring, libnvme_strerror(-err))nvme_show_message(1, "Failed to link keyring '%s', %s", cfg.keyring
, libnvme_strerror(-err))
;
668 return err;
669 }
670
671 err = libnvmf_lookup_key(ctx, cfg.keytype, tls_id, &key_id);
672 if (err) {
673 nvme_show_verbose_result("TLS PSK is not loaded")nvme_show_verbose_message("TLS PSK is not loaded");
674 return 0;
675 }
676
677 nvme_show_verbose_result("TLS PSK is loaded (serial %08x)", (unsigned int)key_id)nvme_show_verbose_message("TLS PSK is loaded (serial %08x)", (
unsigned int)key_id)
;
678 return 0;
679}
680
681static int insert_tls(int argc, char **argv, struct command *acmd, struct plugin *plugin)
682{
683 const char *desc =
684 "Derive a TLS PSK from a configured PSK (in NVMe PSK Interchange\n"
685 "format) and insert it into a keyring.\n";
686 const char *keydata = "Configured PSK (in PSK Interchange format) to derive from. Reads from stdin if not given.";
687 const char *identity = "TLS PSK identity version to use (0 = obsolete; 1 = TLS 1.3 with the PSK digest in the identity)";
688 const char *hostnqn = "Host NQN for the retained PSK and the TLS PSK identity.";
689 const char *subsysnqn = "Subsystem NQN for the TLS PSK identity.";
690 const char *keyring = "Keyring for the TLS PSK.";
691 const char *keytype = "Key type of the TLS PSK.";
692 const char *keyfile = "Append the identity of the TLS PSK, and the TLS PSK itself, to keyfile.";
693 const char *compat = "Use non-RFC 8446 compliant algorithm for deriving the retained PSK and the TLS PSK for older implementations.";
694
695 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
696 __cleanup_free__attribute__((cleanup(shr_freep))) char *key_value = NULL((void*)0);
697 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *decoded_key = NULL((void*)0);
698 __cleanup_free__attribute__((cleanup(shr_freep))) char *hnqn = NULL((void*)0);
699 int decoded_len, err = 0;
700 enum libnvmf_hmac_alg hmac;
701 long tls_key;
702 struct config {
703 char *keyring;
704 char *keytype;
705 char *hostnqn;
706 char *subsysnqn;
707 char *keydata;
708 char *keyfile;
709 unsigned char identity;
710 bool_Bool compat;
711 };
712
713 struct config cfg = {
714 .keyring = ".nvme",
715 .keytype = "psk",
716 .hostnqn = NULL((void*)0),
717 .subsysnqn = NULL((void*)0),
718 .keydata = NULL((void*)0),
719 .keyfile = NULL((void*)0),
720 .identity = 0,
721 .compat = false0,
722 };
723
724 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
725 OPT_STR("keyring", 'k', &cfg.keyring, keyring),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
726 OPT_STR("keytype", 't', &cfg.keytype, keytype),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
727 OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
728 OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
729 OPT_STR("keydata", 'd', &cfg.keydata, keydata),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
730 OPT_STR("keyfile", 'f', &cfg.keyfile, keyfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
731 OPT_BYTE("identity", 'I', &cfg.identity, identity),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
732 OPT_FLAG("compat", 'C', &cfg.compat, compat))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"hostnqn", 'n', "STRING", CFG_STRING
, &cfg.hostnqn, 1, hostnqn, 0, }, {"subsysnqn", 'c', "STRING"
, CFG_STRING, &cfg.subsysnqn, 1, subsysnqn, 0, }, {"keydata"
, 'd', "STRING", CFG_STRING, &cfg.keydata, 1, keydata, 0,
}, {"keyfile", 'f', "STRING", CFG_STRING, &cfg.keyfile, 1
, keyfile, 0, }, {"identity", 'I', "NUM", CFG_BYTE, &cfg.
identity, 1, identity, 0, }, {"compat", 'C', ((void*)0), CFG_FLAG
, &cfg.compat, 0, compat, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
733
734 err = parse_args(argc, argv, desc, opts);
735 if (err)
736 return err;
737
738 if (!cfg.subsysnqn) {
739 nvme_show_error("Need to specify a subsystem NQN")nvme_show_message(1, "Need to specify a subsystem NQN");
740 return -EINVAL22;
741 }
742 if (cfg.identity > 1) {
743 nvme_show_error("Invalid TLS PSK identity version %u",nvme_show_message(1, "Invalid TLS PSK identity version %u", cfg
.identity)
744 cfg.identity)nvme_show_message(1, "Invalid TLS PSK identity version %u", cfg
.identity)
;
745 return -EINVAL22;
746 }
747
748 err = read_key_value(cfg.keydata, &key_value);
749 if (err) {
750 nvme_show_error("No key data")nvme_show_message(1, "No key data");
751 return err;
752 }
753
754 err = nvme_create_global_ctx(&ctx);
755 if (err) {
756 nvme_show_error("Failed to create global context")nvme_show_message(1, "Failed to create global context");
757 return err;
758 }
759 libnvme_set_logging_level(ctx, log_level, false0, false0);
760
761 err = libnvmf_import_tls_key(ctx, key_value, &decoded_len,
762 &hmac, &decoded_key);
763 if (err) {
764 nvme_show_error("Key decoding failed, %s", libnvme_strerror(-err))nvme_show_message(1, "Key decoding failed, %s", libnvme_strerror
(-err))
;
765 return err;
766 }
767
768 if (!cfg.hostnqn) {
769 err = libnvmf_host_get_ids(ctx, NULL((void*)0), NULL((void*)0), &hnqn, NULL((void*)0));
770 if (err)
771 return err;
772 cfg.hostnqn = hnqn;
773 }
774
775 return do_insert_tls_key(ctx, cfg.keyring, cfg.keytype, cfg.hostnqn,
776 cfg.subsysnqn, cfg.identity, hmac, decoded_key, decoded_len,
777 cfg.compat, cfg.keyfile, &tls_key);
778}
779
780static void __scan_tls_key(struct libnvme_global_ctx *ctx, long keyring_id,
781 long key_id, char *desc, int desc_len, void *data)
782{
783 FILE *fd = data;
784 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *key_data = NULL((void*)0);
785 __cleanup_free__attribute__((cleanup(shr_freep))) char *encoded_key = NULL((void*)0);
786 int key_len;
787 int hmac;
788 char type;
789 int err;
790
791 err = libnvmf_read_key(ctx, keyring_id, key_id, &key_len, &key_data);
792 if (err)
793 return;
794
795 if (sscanf(desc, "NVMe%*1d%c%02d %*s", &type, &hmac) != 2)
796 return;
797
798 err = libnvmf_export_tls_key_versioned(ctx, 1, hmac, key_data, key_len,
799 &encoded_key);
800 if (err)
801 return;
802 fprintf(fd, "%s %s\n", desc, encoded_key);
803}
804
805static int key_export(int argc, char **argv, struct command *acmd, struct plugin *plugin)
806{
807 const char *desc = "Export NVMeoF TLS PSKs from a keyring.\n";
808 const char *keyring = "Keyring to export the TLS PSKs from.";
809 const char *keyfile = "File to write the exported keys to (default: stdout).";
810
811 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
812 __cleanup_file__attribute__((cleanup(shr_cleanup_file))) FILE *fd = NULL((void*)0);
813 mode_t old_umask = 0;
814 int err = 0;
815
816 struct config {
817 char *keyring;
818 char *keyfile;
819 };
820
821 struct config cfg = {
822 .keyring = ".nvme",
823 .keyfile = NULL((void*)0),
824 };
825
826 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keyfile", 'f', "STRING", CFG_STRING, &
cfg.keyfile, 1, keyfile, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
827 OPT_STR("keyring", 'k', &cfg.keyring, keyring),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keyfile", 'f', "STRING", CFG_STRING, &
cfg.keyfile, 1, keyfile, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
828 OPT_STR("keyfile", 'f', &cfg.keyfile, keyfile))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keyfile", 'f', "STRING", CFG_STRING, &
cfg.keyfile, 1, keyfile, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
829
830 err = parse_args(argc, argv, desc, opts);
831 if (err)
832 return err;
833
834 err = nvme_create_global_ctx(&ctx);
835 if (err) {
836 nvme_show_error("Failed to create global context")nvme_show_message(1, "Failed to create global context");
837 return err;
838 }
839 libnvme_set_logging_level(ctx, log_level, false0, false0);
840
841 if (cfg.keyfile) {
842 old_umask = umask(0);
843
844 fd = fopen(cfg.keyfile, "w");
845 if (!fd) {
846 nvme_show_error("Cannot open keyfile %s, error %d",nvme_show_message(1, "Cannot open keyfile %s, error %d", cfg.
keyfile, (*__errno_location ()))
847 cfg.keyfile, errno)nvme_show_message(1, "Cannot open keyfile %s, error %d", cfg.
keyfile, (*__errno_location ()))
;
848 umask(old_umask);
849 return -errno(*__errno_location ());
850 }
851 } else {
852 fd = freopen(NULL((void*)0), "w", stdoutstdout);
853 }
854
855 err = libnvmf_scan_tls_keys(ctx, cfg.keyring, __scan_tls_key, fd);
856 if (err < 0) {
857 nvme_show_error("Export of TLS PSKs failed with '%s'",nvme_show_message(1, "Export of TLS PSKs failed with '%s'", libnvme_strerror
(-err))
858 libnvme_strerror(-err))nvme_show_message(1, "Export of TLS PSKs failed with '%s'", libnvme_strerror
(-err))
;
859 return err;
860 }
861
862 nvme_show_verbose_info("exporting to %s", cfg.keyfile)nvme_show_verbose_message("exporting to %s", cfg.keyfile);
863
864 if (cfg.keyfile) {
865 umask(old_umask);
866 chmod(cfg.keyfile, 0600);
867 }
868
869 return 0;
870}
871
872static bool_Bool is_kxchap_key(const char *key)
873{
874 return !strncmp(key, "DHHC-1:", 7);
875}
876
877static int import_one_key(struct libnvme_global_ctx *ctx, long keyring_id,
878 const char *identity, const char *key_str)
879{
880 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *psk = NULL((void*)0);
881 unsigned char decoded_key[128];
882 long key_serial;
883 int decoded_len, kxchap_hmac, err;
884 enum libnvmf_hmac_alg tls_hmac;
885 uint32_t crc;
886
887 if (is_kxchap_key(key_str)) {
888 err = validate_kxchap_key(key_str, &kxchap_hmac, decoded_key,
889 &decoded_len, &crc);
890 if (err)
891 return err;
892
893 return libnvmf_update_key(ctx, keyring_id, "kxchap", identity,
894 (unsigned char *)key_str, strlen(key_str),
895 &key_serial);
896 }
897
898 err = libnvmf_import_tls_key(ctx, key_str, &decoded_len, &tls_hmac, &psk);
899 if (err)
900 return err;
901
902 return libnvmf_update_key(ctx, keyring_id, "psk", identity, psk,
903 decoded_len, &key_serial);
904}
905
906static int import_key(struct libnvme_global_ctx *ctx, const char *keyring,
907 FILE *fd)
908{
909 long keyring_id;
910 char line[512];
911 char *key_str;
912 int linenum = 0;
913 int err;
914
915 err = libnvmf_lookup_keyring(ctx, keyring, &keyring_id);
916 if (err) {
917 nvme_show_error("Invalid keyring '%s'", keyring)nvme_show_message(1, "Invalid keyring '%s'", keyring);
918 return err;
919 }
920
921 while (fgets(line, sizeof(line), fd)) {
922 linenum++;
923 key_str = strrchr(line, ' ')_Generic (0 ? (line) : (void *) 1, const void *: (const char *
) (strrchr (line, ' ')), default: strrchr (line, ' '))
;
924 if (!key_str) {
925 nvme_show_error("Parse error in line %d",nvme_show_message(1, "Parse error in line %d", linenum)
926 linenum)nvme_show_message(1, "Parse error in line %d", linenum);
927 continue;
928 }
929 *key_str = '\0';
930 key_str++;
931 key_str[strcspn(key_str, "\n")] = 0;
932
933 err = import_one_key(ctx, keyring_id, line, key_str);
934 if (err)
935 nvme_show_error("Failed to import key in line %d, %s",nvme_show_message(1, "Failed to import key in line %d, %s", linenum
, libnvme_strerror(-err))
936 linenum, libnvme_strerror(-err))nvme_show_message(1, "Failed to import key in line %d, %s", linenum
, libnvme_strerror(-err))
;
937 }
938
939 return 0;
940}
941
942static int key_import(int argc, char **argv, struct command *acmd, struct plugin *plugin)
943{
944 const char *desc = "Import NVMeoF TLS PSKs and KX-HMAC-CHAP secrets into a keyring.\n";
945 const char *keyring = "Keyring to import the keys into.";
946 const char *keyfile = "File to read the keys from (default: stdin).";
947 const char *keydata = "Key to insert directly under --identity. Reads from stdin if not given.";
948 const char *identity = "Identity to store a single key under. If given, --keydata (or stdin) is read as a single key instead of a bulk <identity> <key> list.";
949
950 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
951 __cleanup_file__attribute__((cleanup(shr_cleanup_file))) FILE *fd = NULL((void*)0);
952 __cleanup_free__attribute__((cleanup(shr_freep))) char *key = NULL((void*)0);
953 long keyring_id;
954 int err = 0;
955
956 struct config {
957 char *keyring;
958 char *keyfile;
959 char *keydata;
960 char *identity;
961 };
962
963 struct config cfg = {
964 .keyring = ".nvme",
965 .keyfile = NULL((void*)0),
966 .keydata = NULL((void*)0),
967 .identity = NULL((void*)0),
968 };
969
970 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keyfile", 'f', "STRING", CFG_STRING, &
cfg.keyfile, 1, keyfile, 0, }, {"keydata", 'd', "STRING", CFG_STRING
, &cfg.keydata, 1, keydata, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
971 OPT_STR("keyring", 'k', &cfg.keyring, keyring),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keyfile", 'f', "STRING", CFG_STRING, &
cfg.keyfile, 1, keyfile, 0, }, {"keydata", 'd', "STRING", CFG_STRING
, &cfg.keydata, 1, keydata, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
972 OPT_STR("keyfile", 'f', &cfg.keyfile, keyfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keyfile", 'f', "STRING", CFG_STRING, &
cfg.keyfile, 1, keyfile, 0, }, {"keydata", 'd', "STRING", CFG_STRING
, &cfg.keydata, 1, keydata, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
973 OPT_STR("keydata", 'd', &cfg.keydata, keydata),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keyfile", 'f', "STRING", CFG_STRING, &
cfg.keyfile, 1, keyfile, 0, }, {"keydata", 'd', "STRING", CFG_STRING
, &cfg.keydata, 1, keydata, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
974 OPT_STR("identity", 'i', &cfg.identity, identity))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keyfile", 'f', "STRING", CFG_STRING, &
cfg.keyfile, 1, keyfile, 0, }, {"keydata", 'd', "STRING", CFG_STRING
, &cfg.keydata, 1, keydata, 0, }, {"identity", 'i', "STRING"
, CFG_STRING, &cfg.identity, 1, identity, 0, }, {"", 0, (
(void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options"
, 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &
nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"quiet"
, 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary", 0, },
{"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1
, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void
*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
975
976 err = parse_args(argc, argv, desc, opts);
977 if (err)
1
Assuming 'err' is 0
2
Taking false branch
978 return err;
979
980 err = nvme_create_global_ctx(&ctx);
981 if (err) {
3
Assuming 'err' is 0
4
Taking false branch
982 nvme_show_error("Failed to create global context")nvme_show_message(1, "Failed to create global context");
983 return err;
984 }
985 libnvme_set_logging_level(ctx, log_level, false0, false0);
986
987 if (!cfg.identity) {
5
Assuming field 'identity' is null
6
Taking true branch
988 if (cfg.keyfile) {
7
Assuming field 'keyfile' is non-null
8
Taking true branch
989 fd = fopen(cfg.keyfile, "r");
9
Stream opened here
10
Assuming that 'fopen' is successful
990 if (!fd
10.1
'fd' is non-null
) {
11
Taking false branch
991 int saved_errno = errno(*__errno_location ());
992
993 nvme_show_error("Cannot open keyfile %s, error %d",nvme_show_message(1, "Cannot open keyfile %s, error %d", cfg.
keyfile, saved_errno)
994 cfg.keyfile, saved_errno)nvme_show_message(1, "Cannot open keyfile %s, error %d", cfg.
keyfile, saved_errno)
;
995 return -saved_errno;
996 }
997 } else {
998 fd = freopen(NULL((void*)0), "r", stdinstdin);
999 if (!fd) {
1000 int saved_errno = errno(*__errno_location ());
1001
1002 nvme_show_error("Cannot reopen stdin, error %d", saved_errno)nvme_show_message(1, "Cannot reopen stdin, error %d", saved_errno
)
;
1003 return -saved_errno;
1004 }
1005 }
1006
1007 err = import_key(ctx, cfg.keyring, fd);
12
Opened stream never closed. Potential resource leak
1008 if (err) {
1009 nvme_show_error("Import of keys failed with '%s'",nvme_show_message(1, "Import of keys failed with '%s'", libnvme_strerror
(err))
1010 libnvme_strerror(err))nvme_show_message(1, "Import of keys failed with '%s'", libnvme_strerror
(err))
;
1011 return err;
1012 }
1013
1014 nvme_show_verbose_info("importing from %s", cfg.keyfile)nvme_show_verbose_message("importing from %s", cfg.keyfile);
1015 return 0;
1016 }
1017
1018 err = read_key_value(cfg.keydata, &key);
1019 if (err) {
1020 nvme_show_error("No key data")nvme_show_message(1, "No key data");
1021 return err;
1022 }
1023
1024 err = libnvmf_lookup_keyring(ctx, cfg.keyring, &keyring_id);
1025 if (err) {
1026 nvme_show_error("Failed to lookup keyring '%s', %s",nvme_show_message(1, "Failed to lookup keyring '%s', %s", cfg
.keyring, libnvme_strerror(-err))
1027 cfg.keyring, libnvme_strerror(-err))nvme_show_message(1, "Failed to lookup keyring '%s', %s", cfg
.keyring, libnvme_strerror(-err))
;
1028 return err;
1029 }
1030
1031 err = import_one_key(ctx, keyring_id, cfg.identity, key);
1032 if (err) {
1033 nvme_show_error("Failed to insert key, %s", libnvme_strerror(-err))nvme_show_message(1, "Failed to insert key, %s", libnvme_strerror
(-err))
;
1034 return err;
1035 }
1036
1037 nvme_show_result("Inserted key for identity '%s'", cfg.identity)nvme_show_message(0, "Inserted key for identity '%s'", cfg.identity
)
;
1038 return 0;
1039}
1040
1041static int key_revoke(int argc, char **argv, struct command *acmd, struct plugin *plugin)
1042{
1043 const char *desc = "Revoke an NVMeoF TLS PSK from a keyring.\n";
1044 const char *keyring = "Keyring to revoke the key from.";
1045 const char *keytype = "Key type of the key to revoke.";
1046 const char *identity = "Identity (description) of the key to revoke.";
1047
1048 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1049 int err = 0;
1050
1051 struct config {
1052 char *keyring;
1053 char *keytype;
1054 char *identity;
1055 };
1056
1057 struct config cfg = {
1058 .keyring = ".nvme",
1059 .keytype = "psk",
1060 .identity = NULL((void*)0),
1061 };
1062
1063 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING", CFG_STRING
, &cfg.identity, 1, identity, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
1064 OPT_STR("keyring", 'k', &cfg.keyring, keyring),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING", CFG_STRING
, &cfg.identity, 1, identity, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
1065 OPT_STR("keytype", 't', &cfg.keytype, keytype),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING", CFG_STRING
, &cfg.identity, 1, identity, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
1066 OPT_STR("identity", 'i', &cfg.identity, identity))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"keyring", 'k', "STRING", CFG_STRING, &cfg.keyring
, 1, keyring, 0, }, {"keytype", 't', "STRING", CFG_STRING, &
cfg.keytype, 1, keytype, 0, }, {"identity", 'i', "STRING", CFG_STRING
, &cfg.identity, 1, identity, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
1067
1068 err = parse_args(argc, argv, desc, opts);
1069 if (err)
1070 return err;
1071
1072 if (!cfg.identity) {
1073 nvme_show_error("Must specify --identity")nvme_show_message(1, "Must specify --identity");
1074 return -EINVAL22;
1075 }
1076
1077 err = nvme_create_global_ctx(&ctx);
1078 if (err) {
1079 nvme_show_error("Failed to create global context")nvme_show_message(1, "Failed to create global context");
1080 return err;
1081 }
1082 libnvme_set_logging_level(ctx, log_level, false0, false0);
1083
1084 err = libnvmf_revoke_tls_key(ctx, cfg.keyring, cfg.keytype, cfg.identity);
1085 if (err) {
1086 nvme_show_error("Failed to revoke key '%s'",nvme_show_message(1, "Failed to revoke key '%s'", libnvme_strerror
(err))
1087 libnvme_strerror(err))nvme_show_message(1, "Failed to revoke key '%s'", libnvme_strerror
(err))
;
1088 return err;
1089 }
1090
1091 nvme_show_verbose_info("revoking key")nvme_show_verbose_message("revoking key");
1092
1093 return 0;
1094}
1095
1096static struct command gen_kxchap_cmd = {
1097 .name = "gen-kxchap-secret",
1098 .help = "Generate NVMeoF KX-HMAC-CHAP host secret",
1099 .fn = gen_kxchap,
1100 .no_device = true1,
1101};
1102
1103static struct command check_kxchap_cmd = {
1104 .name = "check-kxchap-secret",
1105 .help = "Validate NVMeoF KX-HMAC-CHAP host secret format or check if loaded",
1106 .fn = check_kxchap,
1107 .no_device = true1,
1108};
1109
1110static struct command gen_tls_cmd = {
1111 .name = "gen-tls-psk",
1112 .help = "Generate NVMeoF TLS PSK",
1113 .fn = gen_tls,
1114 .no_device = true1,
1115};
1116
1117static struct command check_tls_cmd = {
1118 .name = "check-tls-psk",
1119 .help = "Validate NVMeoF TLS PSK format or check if loaded",
1120 .fn = check_tls,
1121 .no_device = true1,
1122};
1123
1124static struct command insert_tls_cmd = {
1125 .name = "insert-tls-psk",
1126 .help = "Insert NVMeoF TLS PSK into a keyring",
1127 .fn = insert_tls,
1128 .no_device = true1,
1129};
1130
1131static struct command key_import_cmd = {
1132 .name = "import",
1133 .help = "Import NVMeoF TLS PSKs and KX-HMAC-CHAP secrets into a keyring",
1134 .fn = key_import,
1135 .no_device = true1,
1136};
1137
1138static struct command key_export_cmd = {
1139 .name = "export",
1140 .help = "Export NVMeoF TLS PSKs from a keyring",
1141 .fn = key_export,
1142 .no_device = true1,
1143};
1144
1145static struct command key_revoke_cmd = {
1146 .name = "revoke",
1147 .help = "Revoke an NVMeoF TLS PSK from a keyring",
1148 .fn = key_revoke,
1149 .no_device = true1,
1150};
1151
1152static struct command *commands[] = {
1153 &gen_kxchap_cmd,
1154 &check_kxchap_cmd,
1155 &gen_tls_cmd,
1156 &check_tls_cmd,
1157 &insert_tls_cmd,
1158 &key_import_cmd,
1159 &key_export_cmd,
1160 &key_revoke_cmd,
1161 NULL((void*)0),
1162};
1163
1164static struct plugin plugin = {
1165 .name = "keys",
1166 .desc = "Manage NVMeoF KX-HMAC-CHAP secrets and TLS PSKs",
1167 .version = NVME_VERSION"3.1",
1168 .core = true1,
1169 .group = "Fabrics",
1170};
1171
1172static void __shr_constructor__attribute__((constructor)) register_plugin(void)
1173{
1174 plugin_add_group(&plugin, NULL((void*)0), commands);
1175 register_extension(&plugin);
1176}