55c1343fe7713c0b701cd11466d4c06de21a2af3
[platform/upstream/cryptsetup.git] / src / utils_password.c
1 /*
2  * Password quality check wrapper
3  *
4  * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2012-2020 Milan Broz
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "cryptsetup.h"
23 #include <termios.h>
24
25 int opt_force_password = 0;
26
27 #if defined ENABLE_PWQUALITY
28 #include <pwquality.h>
29
30 static int tools_check_pwquality(const char *password)
31 {
32         int r;
33         void *auxerror;
34         pwquality_settings_t *pwq; 
35
36         log_dbg("Checking new password using default pwquality settings.");
37         pwq = pwquality_default_settings();
38         if (!pwq)
39                 return -EINVAL;
40
41         r = pwquality_read_config(pwq, NULL, &auxerror);
42         if (r) {
43                 log_err(_("Cannot check password quality: %s"),
44                         pwquality_strerror(NULL, 0, r, auxerror));
45                 pwquality_free_settings(pwq);
46                 return -EINVAL;
47         }
48
49         r = pwquality_check(pwq, password, NULL, NULL, &auxerror);
50         if (r < 0) {
51                 log_err(_("Password quality check failed:\n %s"),
52                         pwquality_strerror(NULL, 0, r, auxerror));
53                 r = -EPERM;
54         } else {
55                 log_dbg("New password libpwquality score is %d.", r);
56                 r = 0;
57         }
58
59         pwquality_free_settings(pwq);
60         return r;
61 }
62 #elif defined ENABLE_PASSWDQC
63 #include <passwdqc.h>
64
65 static int tools_check_pwquality(const char *password)
66 {
67         passwdqc_params_t params;
68         char *parse_reason;
69         const char *check_reason;
70         const char *config = PASSWDQC_CONFIG_FILE;
71
72         passwdqc_params_reset(&params);
73
74         if (*config && passwdqc_params_load(&params, &parse_reason, config)) {
75                 log_err(_("Cannot check password quality: %s"),
76                         (parse_reason ? parse_reason : "Out of memory"));
77                 free(parse_reason);
78                 return -EINVAL;
79         }
80
81         check_reason = passwdqc_check(&params.qc, password, NULL, NULL);
82         if (check_reason) {
83                 log_err(_("Password quality check failed: Bad passphrase (%s)"),
84                         check_reason);
85                 return -EPERM;
86         }
87
88         return 0;
89 }
90 #else /* !(ENABLE_PWQUALITY || ENABLE_PASSWDQC) */
91 static int tools_check_pwquality(const char *password)
92 {
93         return 0;
94 }
95 #endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
96
97 /* Password reading helpers */
98 static int untimed_read(int fd, char *pass, size_t maxlen)
99 {
100         ssize_t i;
101
102         i = read(fd, pass, maxlen);
103         if (i > 0) {
104                 pass[i-1] = '\0';
105                 i = 0;
106         } else if (i == 0) { /* EOF */
107                 *pass = 0;
108                 i = -1;
109         }
110         return i;
111 }
112
113 static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
114 {
115         struct timeval t;
116         fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */
117         int failed = -1;
118
119         FD_ZERO(&fds);
120         FD_SET(fd, &fds);
121         t.tv_sec = timeout;
122         t.tv_usec = 0;
123
124         if (select(fd+1, &fds, NULL, NULL, &t) > 0)
125                 failed = untimed_read(fd, pass, maxlen);
126
127         return failed;
128 }
129
130 static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
131                 long timeout)
132 {
133         struct termios orig, tmp;
134         int failed = -1;
135         int infd, outfd;
136
137         if (maxlen < 1)
138                 return failed;
139
140         /* Read and write to /dev/tty if available */
141         infd = open("/dev/tty", O_RDWR);
142         if (infd == -1) {
143                 infd = STDIN_FILENO;
144                 outfd = STDERR_FILENO;
145         } else
146                 outfd = infd;
147
148         if (tcgetattr(infd, &orig))
149                 goto out_err;
150
151         memcpy(&tmp, &orig, sizeof(tmp));
152         tmp.c_lflag &= ~ECHO;
153
154         if (prompt && write(outfd, prompt, strlen(prompt)) < 0)
155                 goto out_err;
156
157         tcsetattr(infd, TCSAFLUSH, &tmp);
158         if (timeout)
159                 failed = timed_read(infd, pass, maxlen, timeout);
160         else
161                 failed = untimed_read(infd, pass, maxlen);
162         tcsetattr(infd, TCSAFLUSH, &orig);
163
164 out_err:
165         if (!failed && write(outfd, "\n", 1)) {};
166
167         if (infd != STDIN_FILENO)
168                 close(infd);
169         return failed;
170 }
171
172 static int crypt_get_key_tty(const char *prompt,
173                              char **key, size_t *key_size,
174                              int timeout, int verify,
175                              struct crypt_device *cd)
176 {
177         int key_size_max = DEFAULT_PASSPHRASE_SIZE_MAX;
178         int r = -EINVAL;
179         char *pass = NULL, *pass_verify = NULL;
180
181         *key = NULL;
182         *key_size = 0;
183
184         log_dbg("Interactive passphrase entry requested.");
185
186         pass = crypt_safe_alloc(key_size_max + 1);
187         if (!pass) {
188                 log_err( _("Out of memory while reading passphrase."));
189                 return -ENOMEM;
190         }
191
192         if (interactive_pass(prompt, pass, key_size_max, timeout)) {
193                 log_err(_("Error reading passphrase from terminal."));
194                 goto out_err;
195         }
196         pass[key_size_max] = '\0';
197
198         if (verify) {
199                 pass_verify = crypt_safe_alloc(key_size_max);
200                 if (!pass_verify) {
201                         log_err(_("Out of memory while reading passphrase."));
202                         r = -ENOMEM;
203                         goto out_err;
204                 }
205
206                 if (interactive_pass(_("Verify passphrase: "),
207                     pass_verify, key_size_max, timeout)) {
208                         log_err(_("Error reading passphrase from terminal."));
209                         goto out_err;
210                 }
211
212                 if (strncmp(pass, pass_verify, key_size_max)) {
213                         log_err(_("Passphrases do not match."));
214                         r = -EPERM;
215                         goto out_err;
216                 }
217         }
218
219         *key = pass;
220         *key_size = strlen(pass);
221         r = 0;
222 out_err:
223         crypt_safe_free(pass_verify);
224         if (r)
225                 crypt_safe_free(pass);
226         return r;
227 }
228
229 /*
230  * Note: --key-file=- is interpreted as a read from a binary file (stdin)
231  * key_size_max == 0 means detect maximum according to input type (tty/file)
232  */
233 int tools_get_key(const char *prompt,
234                   char **key, size_t *key_size,
235                   uint64_t keyfile_offset, size_t keyfile_size_max,
236                   const char *key_file,
237                   int timeout, int verify, int pwquality,
238                   struct crypt_device *cd)
239 {
240         char tmp[PATH_MAX], *backing_file;
241         int r = -EINVAL, block;
242
243         block = tools_signals_blocked();
244         if (block)
245                 set_int_block(0);
246
247         if (tools_is_stdin(key_file)) {
248                 if (isatty(STDIN_FILENO)) {
249                         if (keyfile_offset) {
250                                 log_err(_("Cannot use offset with terminal input."));
251                         } else {
252                                 if (!prompt && !crypt_get_device_name(cd))
253                                         snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
254                                 else if (!prompt) {
255                                         backing_file = crypt_loop_backing_file(crypt_get_device_name(cd));
256                                         snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), backing_file ?: crypt_get_device_name(cd));
257                                         free(backing_file);
258                                 }
259                                 r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify, cd);
260                         }
261                 } else {
262                         log_dbg("STDIN descriptor passphrase entry requested.");
263                         /* No keyfile means STDIN with EOL handling (\n will end input)). */
264                         r = crypt_keyfile_device_read(cd, NULL, key, key_size,
265                                         keyfile_offset, keyfile_size_max,
266                                         key_file ? 0 : CRYPT_KEYFILE_STOP_EOL);
267                 }
268         } else {
269                 log_dbg("File descriptor passphrase entry requested.");
270                 r = crypt_keyfile_device_read(cd, key_file, key, key_size,
271                                               keyfile_offset, keyfile_size_max, 0);
272         }
273
274         if (block && !quit)
275                 set_int_block(1);
276
277         /* Check pwquality for password (not keyfile) */
278         if (pwquality && !opt_force_password && !key_file && !r)
279                 r = tools_check_pwquality(*key);
280
281         return r;
282 }
283
284 void tools_passphrase_msg(int r)
285 {
286         if (r == -EPERM)
287                 log_err(_("No key available with this passphrase."));
288         else if (r == -ENOENT)
289                 log_err(_("No usable keyslot is available."));
290 }
291
292 int tools_read_mk(const char *file, char **key, int keysize)
293 {
294         int fd;
295
296         if (!keysize || !key)
297                 return -EINVAL;
298
299         *key = crypt_safe_alloc(keysize);
300         if (!*key)
301                 return -ENOMEM;
302
303         fd = open(file, O_RDONLY);
304         if (fd == -1) {
305                 log_err(_("Cannot read keyfile %s."), file);
306                 goto fail;
307         }
308
309         if (read_buffer(fd, *key, keysize) != keysize) {
310                 log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
311                 close(fd);
312                 goto fail;
313         }
314         close(fd);
315         return 0;
316 fail:
317         crypt_safe_free(*key);
318         *key = NULL;
319         return -EINVAL;
320 }
321
322 int tools_write_mk(const char *file, const char *key, int keysize)
323 {
324         int fd, r = -EINVAL;
325
326         fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
327         if (fd < 0) {
328                 log_err(_("Cannot open keyfile %s for write."), file);
329                 return r;
330         }
331
332         if (write_buffer(fd, key, keysize) == keysize)
333                 r = 0;
334         else
335                 log_err(_("Cannot write to keyfile %s."), file);
336
337         close(fd);
338         return r;
339 }