1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "ask-password-api.h"
4 #include "cryptenroll-password.h"
5 #include "env-util.h"
6 #include "escape.h"
7 #include "memory-util.h"
8 #include "pwquality-util.h"
9 #include "strv.h"
10
enroll_password(struct crypt_device * cd,const void * volume_key,size_t volume_key_size)11 int enroll_password(
12 struct crypt_device *cd,
13 const void *volume_key,
14 size_t volume_key_size) {
15
16 _cleanup_(erase_and_freep) char *new_password = NULL;
17 _cleanup_free_ char *error = NULL;
18 const char *node;
19 int r, keyslot;
20
21 assert_se(node = crypt_get_device_name(cd));
22
23 r = getenv_steal_erase("NEWPASSWORD", &new_password);
24 if (r < 0)
25 return log_error_errno(r, "Failed to acquire password from environment: %m");
26 if (r == 0) {
27 _cleanup_free_ char *disk_path = NULL;
28 unsigned i = 5;
29 const char *id;
30
31 assert_se(node = crypt_get_device_name(cd));
32
33 (void) suggest_passwords();
34
35 disk_path = cescape(node);
36 if (!disk_path)
37 return log_oom();
38
39 id = strjoina("cryptsetup:", disk_path);
40
41 for (;;) {
42 _cleanup_strv_free_erase_ char **passwords = NULL, **passwords2 = NULL;
43 _cleanup_free_ char *question = NULL;
44
45 if (--i == 0)
46 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
47 "Too many attempts, giving up:");
48
49 question = strjoin("Please enter new passphrase for disk ", node, ":");
50 if (!question)
51 return log_oom();
52
53 r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords);
54 if (r < 0)
55 return log_error_errno(r, "Failed to query password: %m");
56
57 assert(strv_length(passwords) == 1);
58
59 free(question);
60 question = strjoin("Please enter new passphrase for disk ", node, " (repeat):");
61 if (!question)
62 return log_oom();
63
64 r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords2);
65 if (r < 0)
66 return log_error_errno(r, "Failed to query password: %m");
67
68 assert(strv_length(passwords2) == 1);
69
70 if (strv_equal(passwords, passwords2)) {
71 new_password = passwords2[0];
72 passwords2 = mfree(passwords2);
73 break;
74 }
75
76 log_error("Password didn't match, try again.");
77 }
78 }
79
80 r = quality_check_password(new_password, NULL, &error);
81 if (r < 0)
82 return log_error_errno(r, "Failed to check password for quality: %m");
83 if (r == 0)
84 log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", error);
85
86 keyslot = crypt_keyslot_add_by_volume_key(
87 cd,
88 CRYPT_ANY_SLOT,
89 volume_key,
90 volume_key_size,
91 new_password,
92 strlen(new_password));
93 if (keyslot < 0)
94 return log_error_errno(keyslot, "Failed to add new password to %s: %m", node);
95
96 log_info("New password enrolled as key slot %i.", keyslot);
97 return keyslot;
98 }
99