]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptenroll/cryptenroll-password.c
9deb98f202f214c1a8d56d2c9c68e907fe8bad9f
[thirdparty/systemd.git] / src / cryptenroll / cryptenroll-password.c
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 "errno-util.h"
7 #include "escape.h"
8 #include "memory-util.h"
9 #include "password-quality-util.h"
10 #include "strv.h"
11
12 int load_volume_key_password(
13 struct crypt_device *cd,
14 const char *cd_node,
15 void *ret_vk,
16 size_t *ret_vks) {
17
18 _cleanup_(erase_and_freep) char *envpw = NULL;
19 int r;
20
21 assert_se(cd);
22 assert_se(cd_node);
23 assert_se(ret_vk);
24 assert_se(ret_vks);
25
26 r = getenv_steal_erase("PASSWORD", &envpw);
27 if (r < 0)
28 return log_error_errno(r, "Failed to acquire password from environment: %m");
29 if (r > 0) {
30 r = crypt_volume_key_get(
31 cd,
32 CRYPT_ANY_SLOT,
33 ret_vk,
34 ret_vks,
35 envpw,
36 strlen(envpw));
37 if (r < 0)
38 return log_error_errno(r, "Password from environment variable $PASSWORD did not work: %m");
39 } else {
40 AskPasswordFlags ask_password_flags = ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED;
41 _cleanup_free_ char *question = NULL, *disk_path = NULL;
42 unsigned i = 5;
43 const char *id;
44
45 question = strjoin("Please enter current passphrase for disk ", cd_node, ":");
46 if (!question)
47 return log_oom();
48
49 disk_path = cescape(cd_node);
50 if (!disk_path)
51 return log_oom();
52
53 id = strjoina("cryptsetup:", disk_path);
54
55 for (;;) {
56 _cleanup_strv_free_erase_ char **passwords = NULL;
57
58 if (--i == 0)
59 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
60 "Too many attempts, giving up.");
61
62 r = ask_password_auto(
63 question, "drive-harddisk", id, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY,
64 ask_password_flags,
65 &passwords);
66 if (r < 0)
67 return log_error_errno(r, "Failed to query password: %m");
68
69 r = -EPERM;
70 STRV_FOREACH(p, passwords) {
71 r = crypt_volume_key_get(
72 cd,
73 CRYPT_ANY_SLOT,
74 ret_vk,
75 ret_vks,
76 *p,
77 strlen(*p));
78 if (r >= 0)
79 break;
80 }
81 if (r >= 0)
82 break;
83
84 log_error_errno(r, "Password not correct, please try again: %m");
85 ask_password_flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
86 }
87 }
88
89 return r;
90 }
91
92 int enroll_password(
93 struct crypt_device *cd,
94 const void *volume_key,
95 size_t volume_key_size) {
96
97 _cleanup_(erase_and_freep) char *new_password = NULL;
98 _cleanup_free_ char *error = NULL;
99 const char *node;
100 int r, keyslot;
101
102 assert_se(node = crypt_get_device_name(cd));
103
104 r = getenv_steal_erase("NEWPASSWORD", &new_password);
105 if (r < 0)
106 return log_error_errno(r, "Failed to acquire password from environment: %m");
107 if (r == 0) {
108 _cleanup_free_ char *disk_path = NULL;
109 unsigned i = 5;
110 const char *id;
111
112 assert_se(node = crypt_get_device_name(cd));
113
114 (void) suggest_passwords();
115
116 disk_path = cescape(node);
117 if (!disk_path)
118 return log_oom();
119
120 id = strjoina("cryptsetup:", disk_path);
121
122 for (;;) {
123 _cleanup_strv_free_erase_ char **passwords = NULL, **passwords2 = NULL;
124 _cleanup_free_ char *question = NULL;
125
126 if (--i == 0)
127 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
128 "Too many attempts, giving up.");
129
130 question = strjoin("Please enter new passphrase for disk ", node, ":");
131 if (!question)
132 return log_oom();
133
134 r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords);
135 if (r < 0)
136 return log_error_errno(r, "Failed to query password: %m");
137
138 assert(strv_length(passwords) == 1);
139
140 free(question);
141 question = strjoin("Please enter new passphrase for disk ", node, " (repeat):");
142 if (!question)
143 return log_oom();
144
145 r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords2);
146 if (r < 0)
147 return log_error_errno(r, "Failed to query password: %m");
148
149 assert(strv_length(passwords2) == 1);
150
151 if (strv_equal(passwords, passwords2)) {
152 new_password = passwords2[0];
153 passwords2 = mfree(passwords2);
154 break;
155 }
156
157 log_error("Password didn't match, try again.");
158 }
159 }
160
161 r = check_password_quality(new_password, /* old */ NULL, /* user */ NULL, &error);
162 if (r < 0) {
163 if (ERRNO_IS_NOT_SUPPORTED(r))
164 log_warning("Password quality check is not supported, proceeding anyway.");
165 else
166 return log_error_errno(r, "Failed to check password quality: %m");
167 }
168 if (r == 0)
169 log_warning("Specified password does not pass quality checks (%s), proceeding anyway.", error);
170
171 keyslot = crypt_keyslot_add_by_volume_key(
172 cd,
173 CRYPT_ANY_SLOT,
174 volume_key,
175 volume_key_size,
176 new_password,
177 strlen(new_password));
178 if (keyslot < 0)
179 return log_error_errno(keyslot, "Failed to add new password to %s: %m", node);
180
181 log_info("New password enrolled as key slot %i.", keyslot);
182 return keyslot;
183 }