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