]>
Commit | Line | Data |
---|---|---|
8710a681 LP |
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | ||
3 | #include <getopt.h> | |
4 | ||
5 | #include "ask-password-api.h" | |
6 | #include "cryptenroll-fido2.h" | |
d2fafc42 | 7 | #include "cryptenroll-list.h" |
8710a681 LP |
8 | #include "cryptenroll-password.h" |
9 | #include "cryptenroll-pkcs11.h" | |
10 | #include "cryptenroll-recovery.h" | |
5e521624 | 11 | #include "cryptenroll-tpm2.h" |
d2fafc42 LP |
12 | #include "cryptenroll-wipe.h" |
13 | #include "cryptenroll.h" | |
8710a681 LP |
14 | #include "cryptsetup-util.h" |
15 | #include "escape.h" | |
16 | #include "libfido2-util.h" | |
17 | #include "main-func.h" | |
18 | #include "memory-util.h" | |
614b022c | 19 | #include "parse-argument.h" |
5e521624 | 20 | #include "parse-util.h" |
8710a681 LP |
21 | #include "path-util.h" |
22 | #include "pkcs11-util.h" | |
23 | #include "pretty-print.h" | |
d2fafc42 | 24 | #include "string-table.h" |
8710a681 LP |
25 | #include "strv.h" |
26 | #include "terminal-util.h" | |
5e521624 | 27 | #include "tpm2-util.h" |
8710a681 | 28 | |
8710a681 LP |
29 | static EnrollType arg_enroll_type = _ENROLL_TYPE_INVALID; |
30 | static char *arg_pkcs11_token_uri = NULL; | |
31 | static char *arg_fido2_device = NULL; | |
32 | static char *arg_tpm2_device = NULL; | |
5e521624 | 33 | static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; |
8710a681 | 34 | static char *arg_node = NULL; |
d2fafc42 LP |
35 | static int *arg_wipe_slots = NULL; |
36 | static size_t arg_n_wipe_slots = 0; | |
37 | static WipeScope arg_wipe_slots_scope = WIPE_EXPLICIT; | |
38 | static unsigned arg_wipe_slots_mask = 0; /* Bitmask of (1U << EnrollType), for wiping all slots of specific types */ | |
06f08719 | 39 | static Fido2EnrollFlags arg_fido2_lock_with = FIDO2ENROLL_PIN | FIDO2ENROLL_UP; |
d2fafc42 LP |
40 | |
41 | assert_cc(sizeof(arg_wipe_slots_mask) * 8 >= _ENROLL_TYPE_MAX); | |
8710a681 LP |
42 | |
43 | STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri, freep); | |
44 | STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep); | |
45 | STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); | |
46 | STATIC_DESTRUCTOR_REGISTER(arg_node, freep); | |
47 | ||
d2fafc42 LP |
48 | static bool wipe_requested(void) { |
49 | return arg_n_wipe_slots > 0 || | |
50 | arg_wipe_slots_scope != WIPE_EXPLICIT || | |
51 | arg_wipe_slots_mask != 0; | |
52 | } | |
53 | ||
54 | static const char* const enroll_type_table[_ENROLL_TYPE_MAX] = { | |
55 | [ENROLL_PASSWORD] = "password", | |
56 | [ENROLL_RECOVERY] = "recovery", | |
57 | [ENROLL_PKCS11] = "pkcs11", | |
58 | [ENROLL_FIDO2] = "fido2", | |
59 | [ENROLL_TPM2] = "tpm2", | |
60 | }; | |
61 | ||
62 | DEFINE_STRING_TABLE_LOOKUP(enroll_type, EnrollType); | |
63 | ||
64 | static const char *const luks2_token_type_table[_ENROLL_TYPE_MAX] = { | |
65 | /* ENROLL_PASSWORD has no entry here, as slots of this type do not have a token in the LUKS2 header */ | |
66 | [ENROLL_RECOVERY] = "systemd-recovery", | |
67 | [ENROLL_PKCS11] = "systemd-pkcs11", | |
68 | [ENROLL_FIDO2] = "systemd-fido2", | |
69 | [ENROLL_TPM2] = "systemd-tpm2", | |
70 | }; | |
71 | ||
72 | DEFINE_STRING_TABLE_LOOKUP(luks2_token_type, EnrollType); | |
73 | ||
8710a681 LP |
74 | static int help(void) { |
75 | _cleanup_free_ char *link = NULL; | |
76 | int r; | |
77 | ||
78 | r = terminal_urlify_man("systemd-cryptenroll", "1", &link); | |
79 | if (r < 0) | |
80 | return log_oom(); | |
81 | ||
82 | printf("%s [OPTIONS...] BLOCK-DEVICE\n" | |
83 | "\n%sEnroll a security token or authentication credential to a LUKS volume.%s\n\n" | |
84 | " -h --help Show this help\n" | |
85 | " --version Show package version\n" | |
86 | " --password Enroll a user-supplied password\n" | |
87 | " --recovery-key Enroll a recovery key\n" | |
88 | " --pkcs11-token-uri=URI\n" | |
89 | " Specify PKCS#11 security token URI\n" | |
90 | " --fido2-device=PATH\n" | |
91 | " Enroll a FIDO2-HMAC security token\n" | |
cde2f860 LB |
92 | " --fido2-with-client-pin=BOOL\n" |
93 | " Whether to require entering a PIN to unlock the volume\n" | |
06f08719 LB |
94 | " --fido2-with-user-presence=BOOL\n" |
95 | " Whether to require user presence to unlock the volume\n" | |
5e521624 LP |
96 | " --tpm2-device=PATH\n" |
97 | " Enroll a TPM2 device\n" | |
98 | " --tpm2-pcrs=PCR1,PCR2,PCR3,…\n" | |
45861042 | 99 | " Specify TPM2 PCRs to seal against\n" |
d2fafc42 LP |
100 | " --wipe-slot=SLOT1,SLOT2,…\n" |
101 | " Wipe specified slots\n" | |
bc556335 DDM |
102 | "\nSee the %s for details.\n", |
103 | program_invocation_short_name, | |
104 | ansi_highlight(), | |
105 | ansi_normal(), | |
106 | link); | |
8710a681 LP |
107 | |
108 | return 0; | |
109 | } | |
110 | ||
111 | static int parse_argv(int argc, char *argv[]) { | |
112 | ||
113 | enum { | |
114 | ARG_VERSION = 0x100, | |
115 | ARG_PASSWORD, | |
116 | ARG_RECOVERY_KEY, | |
117 | ARG_PKCS11_TOKEN_URI, | |
118 | ARG_FIDO2_DEVICE, | |
5e521624 LP |
119 | ARG_TPM2_DEVICE, |
120 | ARG_TPM2_PCRS, | |
d2fafc42 | 121 | ARG_WIPE_SLOT, |
cde2f860 | 122 | ARG_FIDO2_WITH_PIN, |
06f08719 | 123 | ARG_FIDO2_WITH_UP, |
8710a681 LP |
124 | }; |
125 | ||
126 | static const struct option options[] = { | |
cde2f860 LB |
127 | { "help", no_argument, NULL, 'h' }, |
128 | { "version", no_argument, NULL, ARG_VERSION }, | |
129 | { "password", no_argument, NULL, ARG_PASSWORD }, | |
130 | { "recovery-key", no_argument, NULL, ARG_RECOVERY_KEY }, | |
131 | { "pkcs11-token-uri", required_argument, NULL, ARG_PKCS11_TOKEN_URI }, | |
132 | { "fido2-device", required_argument, NULL, ARG_FIDO2_DEVICE }, | |
133 | { "fido2-with-client-pin", required_argument, NULL, ARG_FIDO2_WITH_PIN }, | |
06f08719 | 134 | { "fido2-with-user-presence", required_argument, NULL, ARG_FIDO2_WITH_UP }, |
cde2f860 LB |
135 | { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE }, |
136 | { "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS }, | |
137 | { "wipe-slot", required_argument, NULL, ARG_WIPE_SLOT }, | |
8710a681 LP |
138 | {} |
139 | }; | |
140 | ||
141 | int c, r; | |
142 | ||
143 | assert(argc >= 0); | |
144 | assert(argv); | |
145 | ||
146 | while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { | |
147 | ||
148 | switch (c) { | |
149 | ||
150 | case 'h': | |
151 | return help(); | |
152 | ||
153 | case ARG_VERSION: | |
154 | return version(); | |
155 | ||
cde2f860 LB |
156 | case ARG_FIDO2_WITH_PIN: { |
157 | bool lock_with_pin; | |
158 | ||
159 | r = parse_boolean_argument("--fido2-with-client-pin=", optarg, &lock_with_pin); | |
160 | if (r < 0) | |
161 | return r; | |
162 | ||
163 | SET_FLAG(arg_fido2_lock_with, FIDO2ENROLL_PIN, lock_with_pin); | |
164 | ||
165 | break; | |
166 | } | |
167 | ||
06f08719 LB |
168 | case ARG_FIDO2_WITH_UP: { |
169 | bool lock_with_up; | |
170 | ||
171 | r = parse_boolean_argument("--fido2-with-user-presence=", optarg, &lock_with_up); | |
172 | if (r < 0) | |
173 | return r; | |
174 | ||
175 | SET_FLAG(arg_fido2_lock_with, FIDO2ENROLL_UP, lock_with_up); | |
176 | ||
177 | break; | |
178 | } | |
179 | ||
8710a681 LP |
180 | case ARG_PASSWORD: |
181 | if (arg_enroll_type >= 0) | |
182 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
183 | "Multiple operations specified at once, refusing."); | |
184 | ||
185 | arg_enroll_type = ENROLL_PASSWORD; | |
186 | break; | |
187 | ||
188 | case ARG_RECOVERY_KEY: | |
189 | if (arg_enroll_type >= 0) | |
190 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
191 | "Multiple operations specified at once, refusing."); | |
192 | ||
193 | arg_enroll_type = ENROLL_RECOVERY; | |
194 | break; | |
195 | ||
196 | case ARG_PKCS11_TOKEN_URI: { | |
197 | _cleanup_free_ char *uri = NULL; | |
198 | ||
199 | if (streq(optarg, "list")) | |
200 | return pkcs11_list_tokens(); | |
201 | ||
202 | if (arg_enroll_type >= 0 || arg_pkcs11_token_uri) | |
203 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
204 | "Multiple operations specified at once, refusing."); | |
205 | ||
206 | if (streq(optarg, "auto")) { | |
207 | r = pkcs11_find_token_auto(&uri); | |
208 | if (r < 0) | |
209 | return r; | |
210 | } else { | |
211 | if (!pkcs11_uri_valid(optarg)) | |
212 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid PKCS#11 URI: %s", optarg); | |
213 | ||
214 | uri = strdup(optarg); | |
215 | if (!uri) | |
216 | return log_oom(); | |
217 | } | |
218 | ||
219 | arg_enroll_type = ENROLL_PKCS11; | |
220 | arg_pkcs11_token_uri = TAKE_PTR(uri); | |
221 | break; | |
222 | } | |
223 | ||
224 | case ARG_FIDO2_DEVICE: { | |
225 | _cleanup_free_ char *device = NULL; | |
226 | ||
227 | if (streq(optarg, "list")) | |
228 | return fido2_list_devices(); | |
229 | ||
230 | if (arg_enroll_type >= 0 || arg_fido2_device) | |
231 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
232 | "Multiple operations specified at once, refusing."); | |
233 | ||
234 | if (streq(optarg, "auto")) { | |
235 | r = fido2_find_device_auto(&device); | |
236 | if (r < 0) | |
237 | return r; | |
238 | } else { | |
239 | device = strdup(optarg); | |
240 | if (!device) | |
241 | return log_oom(); | |
242 | } | |
243 | ||
244 | arg_enroll_type = ENROLL_FIDO2; | |
245 | arg_fido2_device = TAKE_PTR(device); | |
246 | break; | |
247 | } | |
248 | ||
5e521624 LP |
249 | case ARG_TPM2_DEVICE: { |
250 | _cleanup_free_ char *device = NULL; | |
251 | ||
252 | if (streq(optarg, "list")) | |
253 | return tpm2_list_devices(); | |
254 | ||
255 | if (arg_enroll_type >= 0 || arg_tpm2_device) | |
256 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
257 | "Multiple operations specified at once, refusing."); | |
258 | ||
259 | if (!streq(optarg, "auto")) { | |
260 | device = strdup(optarg); | |
261 | if (!device) | |
262 | return log_oom(); | |
263 | } | |
264 | ||
265 | arg_enroll_type = ENROLL_TPM2; | |
266 | arg_tpm2_device = TAKE_PTR(device); | |
267 | break; | |
268 | } | |
269 | ||
270 | case ARG_TPM2_PCRS: { | |
271 | uint32_t mask; | |
272 | ||
273 | if (isempty(optarg)) { | |
274 | arg_tpm2_pcr_mask = 0; | |
275 | break; | |
276 | } | |
277 | ||
278 | r = tpm2_parse_pcrs(optarg, &mask); | |
279 | if (r < 0) | |
280 | return r; | |
281 | ||
282 | if (arg_tpm2_pcr_mask == UINT32_MAX) | |
283 | arg_tpm2_pcr_mask = mask; | |
284 | else | |
285 | arg_tpm2_pcr_mask |= mask; | |
286 | ||
287 | break; | |
288 | } | |
289 | ||
d2fafc42 LP |
290 | case ARG_WIPE_SLOT: { |
291 | const char *p = optarg; | |
292 | ||
293 | if (isempty(optarg)) { | |
294 | arg_wipe_slots_mask = 0; | |
295 | arg_wipe_slots_scope = WIPE_EXPLICIT; | |
296 | break; | |
297 | } | |
298 | ||
299 | for (;;) { | |
300 | _cleanup_free_ char *slot = NULL; | |
301 | unsigned n; | |
302 | ||
303 | r = extract_first_word(&p, &slot, ",", EXTRACT_DONT_COALESCE_SEPARATORS); | |
304 | if (r == 0) | |
305 | break; | |
306 | if (r < 0) | |
307 | return log_error_errno(r, "Failed to parse slot list: %s", optarg); | |
308 | ||
309 | if (streq(slot, "all")) | |
310 | arg_wipe_slots_scope = WIPE_ALL; | |
311 | else if (streq(slot, "empty")) { | |
312 | if (arg_wipe_slots_scope != WIPE_ALL) /* if "all" was specified before, that wins */ | |
313 | arg_wipe_slots_scope = WIPE_EMPTY_PASSPHRASE; | |
314 | } else if (streq(slot, "password")) | |
315 | arg_wipe_slots_mask = 1U << ENROLL_PASSWORD; | |
316 | else if (streq(slot, "recovery")) | |
317 | arg_wipe_slots_mask = 1U << ENROLL_RECOVERY; | |
318 | else if (streq(slot, "pkcs11")) | |
319 | arg_wipe_slots_mask = 1U << ENROLL_PKCS11; | |
320 | else if (streq(slot, "fido2")) | |
321 | arg_wipe_slots_mask = 1U << ENROLL_FIDO2; | |
322 | else if (streq(slot, "tpm2")) | |
323 | arg_wipe_slots_mask = 1U << ENROLL_TPM2; | |
324 | else { | |
325 | int *a; | |
326 | ||
327 | r = safe_atou(slot, &n); | |
328 | if (r < 0) | |
329 | return log_error_errno(r, "Failed to parse slot index: %s", slot); | |
330 | if (n > INT_MAX) | |
331 | return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Slot index out of range: %u", n); | |
332 | ||
333 | a = reallocarray(arg_wipe_slots, sizeof(int), arg_n_wipe_slots + 1); | |
334 | if (!a) | |
335 | return log_oom(); | |
336 | ||
337 | arg_wipe_slots = a; | |
338 | arg_wipe_slots[arg_n_wipe_slots++] = (int) n; | |
339 | } | |
340 | } | |
341 | break; | |
342 | } | |
343 | ||
8710a681 LP |
344 | case '?': |
345 | return -EINVAL; | |
346 | ||
347 | default: | |
348 | assert_not_reached("Unhandled option"); | |
349 | } | |
350 | } | |
351 | ||
8710a681 LP |
352 | if (optind >= argc) |
353 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
354 | "No block device node specified, refusing."); | |
355 | ||
356 | if (argc > optind+1) | |
357 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
358 | "Too many arguments, refusing."); | |
359 | ||
614b022c | 360 | r = parse_path_argument(argv[optind], false, &arg_node); |
8710a681 LP |
361 | if (r < 0) |
362 | return r; | |
363 | ||
5e521624 LP |
364 | if (arg_tpm2_pcr_mask == UINT32_MAX) |
365 | arg_tpm2_pcr_mask = TPM2_PCR_MASK_DEFAULT; | |
366 | ||
8710a681 LP |
367 | return 1; |
368 | } | |
369 | ||
370 | static int prepare_luks( | |
371 | struct crypt_device **ret_cd, | |
372 | void **ret_volume_key, | |
373 | size_t *ret_volume_key_size) { | |
374 | ||
375 | _cleanup_(crypt_freep) struct crypt_device *cd = NULL; | |
376 | _cleanup_(erase_and_freep) void *vk = NULL; | |
377 | char *e = NULL; | |
378 | size_t vks; | |
379 | int r; | |
380 | ||
381 | assert(ret_cd); | |
382 | assert(!ret_volume_key == !ret_volume_key_size); | |
383 | ||
384 | r = crypt_init(&cd, arg_node); | |
385 | if (r < 0) | |
386 | return log_error_errno(r, "Failed to allocate libcryptsetup context: %m"); | |
387 | ||
388 | cryptsetup_enable_logging(cd); | |
389 | ||
390 | r = crypt_load(cd, CRYPT_LUKS2, NULL); | |
391 | if (r < 0) | |
392 | return log_error_errno(r, "Failed to load LUKS2 superblock: %m"); | |
393 | ||
394 | if (!ret_volume_key) { | |
395 | *ret_cd = TAKE_PTR(cd); | |
396 | return 0; | |
397 | } | |
398 | ||
399 | r = crypt_get_volume_key_size(cd); | |
400 | if (r <= 0) | |
401 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size"); | |
402 | vks = (size_t) r; | |
403 | ||
404 | vk = malloc(vks); | |
405 | if (!vk) | |
406 | return log_oom(); | |
407 | ||
408 | e = getenv("PASSWORD"); | |
409 | if (e) { | |
410 | _cleanup_(erase_and_freep) char *password = NULL; | |
411 | ||
412 | password = strdup(e); | |
413 | if (!password) | |
414 | return log_oom(); | |
415 | ||
416 | string_erase(e); | |
417 | assert_se(unsetenv("PASSWORD") >= 0); | |
418 | ||
419 | r = crypt_volume_key_get( | |
420 | cd, | |
421 | CRYPT_ANY_SLOT, | |
422 | vk, | |
423 | &vks, | |
424 | password, | |
425 | strlen(password)); | |
426 | if (r < 0) | |
45861042 | 427 | return log_error_errno(r, "Password from environment variable $PASSWORD did not work."); |
8710a681 LP |
428 | } else { |
429 | AskPasswordFlags ask_password_flags = ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED; | |
430 | _cleanup_free_ char *question = NULL, *disk_path = NULL; | |
431 | unsigned i = 5; | |
432 | const char *id; | |
433 | ||
434 | question = strjoin("Please enter current passphrase for disk ", arg_node, ":"); | |
435 | if (!question) | |
436 | return log_oom(); | |
437 | ||
438 | disk_path = cescape(arg_node); | |
439 | if (!disk_path) | |
440 | return log_oom(); | |
441 | ||
442 | id = strjoina("cryptsetup:", disk_path); | |
443 | ||
444 | for (;;) { | |
445 | _cleanup_strv_free_erase_ char **passwords = NULL; | |
446 | char **p; | |
447 | ||
448 | if (--i == 0) | |
449 | return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), | |
450 | "Too many attempts, giving up:"); | |
451 | ||
452 | r = ask_password_auto( | |
8806bb4b | 453 | question, "drive-harddisk", id, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY, |
8710a681 LP |
454 | ask_password_flags, |
455 | &passwords); | |
456 | if (r < 0) | |
457 | return log_error_errno(r, "Failed to query password: %m"); | |
458 | ||
459 | r = -EPERM; | |
460 | STRV_FOREACH(p, passwords) { | |
461 | r = crypt_volume_key_get( | |
462 | cd, | |
463 | CRYPT_ANY_SLOT, | |
464 | vk, | |
465 | &vks, | |
466 | *p, | |
467 | strlen(*p)); | |
468 | if (r >= 0) | |
469 | break; | |
470 | } | |
471 | if (r >= 0) | |
472 | break; | |
473 | ||
474 | log_error_errno(r, "Password not correct, please try again."); | |
475 | ask_password_flags &= ~ASK_PASSWORD_ACCEPT_CACHED; | |
476 | } | |
477 | } | |
478 | ||
479 | *ret_cd = TAKE_PTR(cd); | |
480 | *ret_volume_key = TAKE_PTR(vk); | |
481 | *ret_volume_key_size = vks; | |
482 | ||
483 | return 0; | |
484 | } | |
485 | ||
486 | static int run(int argc, char *argv[]) { | |
487 | _cleanup_(crypt_freep) struct crypt_device *cd = NULL; | |
488 | _cleanup_(erase_and_freep) void *vk = NULL; | |
489 | size_t vks; | |
d2fafc42 | 490 | int slot, r; |
8710a681 LP |
491 | |
492 | log_show_color(true); | |
493 | log_parse_environment(); | |
494 | log_open(); | |
495 | ||
496 | r = parse_argv(argc, argv); | |
497 | if (r <= 0) | |
498 | return r; | |
499 | ||
d2fafc42 LP |
500 | if (arg_enroll_type < 0) |
501 | r = prepare_luks(&cd, NULL, NULL); /* No need to unlock device if we don't need the volume key because we don't need to enroll anything */ | |
502 | else | |
503 | r = prepare_luks(&cd, &vk, &vks); | |
8710a681 LP |
504 | if (r < 0) |
505 | return r; | |
506 | ||
507 | switch (arg_enroll_type) { | |
508 | ||
509 | case ENROLL_PASSWORD: | |
d2fafc42 | 510 | slot = enroll_password(cd, vk, vks); |
8710a681 LP |
511 | break; |
512 | ||
513 | case ENROLL_RECOVERY: | |
d2fafc42 | 514 | slot = enroll_recovery(cd, vk, vks); |
8710a681 LP |
515 | break; |
516 | ||
517 | case ENROLL_PKCS11: | |
d2fafc42 | 518 | slot = enroll_pkcs11(cd, vk, vks, arg_pkcs11_token_uri); |
8710a681 LP |
519 | break; |
520 | ||
521 | case ENROLL_FIDO2: | |
cde2f860 | 522 | slot = enroll_fido2(cd, vk, vks, arg_fido2_device, arg_fido2_lock_with); |
8710a681 LP |
523 | break; |
524 | ||
5e521624 | 525 | case ENROLL_TPM2: |
d2fafc42 | 526 | slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask); |
5e521624 LP |
527 | break; |
528 | ||
d2fafc42 LP |
529 | case _ENROLL_TYPE_INVALID: |
530 | /* List enrolled slots if we are called without anything to enroll or wipe */ | |
531 | if (!wipe_requested()) | |
532 | return list_enrolled(cd); | |
533 | ||
534 | /* Only slot wiping selected */ | |
535 | return wipe_slots(cd, arg_wipe_slots, arg_n_wipe_slots, arg_wipe_slots_scope, arg_wipe_slots_mask, -1); | |
536 | ||
8710a681 LP |
537 | default: |
538 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Operation not implemented yet."); | |
539 | } | |
d2fafc42 LP |
540 | if (slot < 0) |
541 | return slot; | |
8710a681 | 542 | |
d2fafc42 LP |
543 | /* After we completed enrolling, remove user selected slots */ |
544 | r = wipe_slots(cd, arg_wipe_slots, arg_n_wipe_slots, arg_wipe_slots_scope, arg_wipe_slots_mask, slot); | |
545 | if (r < 0) | |
546 | return r; | |
547 | ||
548 | return 0; | |
8710a681 LP |
549 | } |
550 | ||
551 | DEFINE_MAIN_FUNCTION(run); |