e4f7cf060741d02a498e4862c6db07f7fb7424e7
[platform/upstream/cryptsetup.git] / src / utils_password.c
1 /*
2  * Password quality check wrapper
3  *
4  * Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2012-2021 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_passwdqc(const char *password)
66 {
67         passwdqc_params_t params;
68         char *parse_reason = NULL;
69         const char *check_reason;
70         const char *config = PASSWDQC_CONFIG_FILE;
71         int r = -EINVAL;
72
73         passwdqc_params_reset(&params);
74
75         if (*config && passwdqc_params_load(&params, &parse_reason, config)) {
76                 log_err(_("Cannot check password quality: %s"),
77                         (parse_reason ? parse_reason : "Out of memory"));
78                 goto out;
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                 r = -EPERM;
86         } else
87                 r = 0;
88 out:
89 #if HAVE_PASSWDQC_PARAMS_FREE
90         passwdqc_params_free(&params);
91 #endif
92         free(parse_reason);
93         return r;
94 }
95 #endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
96
97 /* coverity[ +tainted_string_sanitize_content : arg-0 ] */
98 static int tools_check_password(const char *password)
99 {
100 #if defined ENABLE_PWQUALITY
101         return tools_check_pwquality(password);
102 #elif defined ENABLE_PASSWDQC
103         return tools_check_passwdqc(password);
104 #else
105         return 0;
106 #endif
107 }
108
109 /* Password reading helpers */
110
111 static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen)
112 {
113         bool eol = false;
114         size_t read_size = 0;
115         ssize_t r;
116
117         do {
118                 r = read(fd, pass, maxlen - read_size);
119                 if ((r == -1 && errno != EINTR) || quit)
120                         return -1;
121                 if (r >= 0) {
122                         if (!r || pass[r-1] == '\n')
123                                 eol = true;
124                         read_size += (size_t)r;
125                         pass = pass + r;
126                 }
127         } while (!eol && read_size != maxlen);
128
129         return (ssize_t)read_size;
130 }
131
132 /* The pass buffer is zeroed and has trailing \0 already " */
133 static int untimed_read(int fd, char *pass, size_t maxlen)
134 {
135         ssize_t i;
136
137         i = read_tty_eol(fd, pass, maxlen);
138         if (i > 0) {
139                 if (pass[i-1] == '\n')
140                         pass[i-1] = '\0';
141                 i = 0;
142         } else if (i == 0) /* empty input */
143                 i = -1;
144
145         return i;
146 }
147
148 static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
149 {
150         struct timeval t;
151         fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */
152         int failed = -1;
153
154         FD_ZERO(&fds);
155         FD_SET(fd, &fds);
156         t.tv_sec = timeout;
157         t.tv_usec = 0;
158
159         if (select(fd+1, &fds, NULL, NULL, &t) > 0)
160                 failed = untimed_read(fd, pass, maxlen);
161
162         return failed;
163 }
164
165 static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
166                 long timeout)
167 {
168         struct termios orig, tmp;
169         int failed = -1;
170         int infd, outfd;
171
172         if (maxlen < 1)
173                 return failed;
174
175         /* Read and write to /dev/tty if available */
176         infd = open("/dev/tty", O_RDWR);
177         if (infd == -1) {
178                 infd = STDIN_FILENO;
179                 outfd = STDERR_FILENO;
180         } else
181                 outfd = infd;
182
183         if (tcgetattr(infd, &orig))
184                 goto out_err;
185
186         memcpy(&tmp, &orig, sizeof(tmp));
187         tmp.c_lflag &= ~ECHO;
188
189         if (prompt && write(outfd, prompt, strlen(prompt)) < 0)
190                 goto out_err;
191
192         tcsetattr(infd, TCSAFLUSH, &tmp);
193         if (timeout)
194                 failed = timed_read(infd, pass, maxlen, timeout);
195         else
196                 failed = untimed_read(infd, pass, maxlen);
197         tcsetattr(infd, TCSAFLUSH, &orig);
198
199 out_err:
200         if (!failed && write(outfd, "\n", 1)) {};
201
202         if (infd != STDIN_FILENO)
203                 close(infd);
204         return failed;
205 }
206
207 static int crypt_get_key_tty(const char *prompt,
208                              char **key, size_t *key_size,
209                              int timeout, int verify,
210                              struct crypt_device *cd)
211 {
212         int key_size_max = DEFAULT_PASSPHRASE_SIZE_MAX;
213         int r = -EINVAL;
214         char *pass = NULL, *pass_verify = NULL;
215
216         *key = NULL;
217         *key_size = 0;
218
219         log_dbg("Interactive passphrase entry requested.");
220
221         pass = crypt_safe_alloc(key_size_max + 1);
222         if (!pass) {
223                 log_err( _("Out of memory while reading passphrase."));
224                 return -ENOMEM;
225         }
226
227         if (interactive_pass(prompt, pass, key_size_max, timeout)) {
228                 log_err(_("Error reading passphrase from terminal."));
229                 goto out_err;
230         }
231
232         if (verify) {
233                 pass_verify = crypt_safe_alloc(key_size_max + 1);
234                 if (!pass_verify) {
235                         log_err(_("Out of memory while reading passphrase."));
236                         r = -ENOMEM;
237                         goto out_err;
238                 }
239
240                 if (interactive_pass(_("Verify passphrase: "),
241                     pass_verify, key_size_max, timeout)) {
242                         log_err(_("Error reading passphrase from terminal."));
243                         goto out_err;
244                 }
245
246                 if (strncmp(pass, pass_verify, key_size_max)) {
247                         log_err(_("Passphrases do not match."));
248                         r = -EPERM;
249                         goto out_err;
250                 }
251         }
252
253         *key = pass;
254         *key_size = strlen(pass);
255         r = 0;
256 out_err:
257         crypt_safe_free(pass_verify);
258         if (r)
259                 crypt_safe_free(pass);
260         return r;
261 }
262
263 /*
264  * Note: --key-file=- is interpreted as a read from a binary file (stdin)
265  * key_size_max == 0 means detect maximum according to input type (tty/file)
266  */
267 int tools_get_key(const char *prompt,
268                   char **key, size_t *key_size,
269                   uint64_t keyfile_offset, size_t keyfile_size_max,
270                   const char *key_file,
271                   int timeout, int verify, int pwquality,
272                   struct crypt_device *cd)
273 {
274         char tmp[PATH_MAX], *backing_file;
275         int r = -EINVAL, block;
276
277         block = tools_signals_blocked();
278         if (block)
279                 set_int_block(0);
280
281         if (tools_is_stdin(key_file)) {
282                 if (isatty(STDIN_FILENO)) {
283                         if (keyfile_offset) {
284                                 log_err(_("Cannot use offset with terminal input."));
285                         } else {
286                                 if (!prompt && !crypt_get_device_name(cd))
287                                         snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
288                                 else if (!prompt) {
289                                         backing_file = crypt_loop_backing_file(crypt_get_device_name(cd));
290                                         snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), backing_file ?: crypt_get_device_name(cd));
291                                         free(backing_file);
292                                 }
293                                 r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify, cd);
294                         }
295                 } else {
296                         log_dbg("STDIN descriptor passphrase entry requested.");
297                         /* No keyfile means STDIN with EOL handling (\n will end input)). */
298                         r = crypt_keyfile_device_read(cd, NULL, key, key_size,
299                                         keyfile_offset, keyfile_size_max,
300                                         key_file ? 0 : CRYPT_KEYFILE_STOP_EOL);
301                 }
302         } else {
303                 log_dbg("File descriptor passphrase entry requested.");
304                 r = crypt_keyfile_device_read(cd, key_file, key, key_size,
305                                               keyfile_offset, keyfile_size_max, 0);
306         }
307
308         if (block && !quit)
309                 set_int_block(1);
310
311         /* Check pwquality for password (not keyfile) */
312         if (pwquality && !opt_force_password && !key_file && !r)
313                 r = tools_check_password(*key);
314
315         return r;
316 }
317
318 void tools_passphrase_msg(int r)
319 {
320         if (r == -EPERM)
321                 log_err(_("No key available with this passphrase."));
322         else if (r == -ENOENT)
323                 log_err(_("No usable keyslot is available."));
324 }
325
326 int tools_read_mk(const char *file, char **key, int keysize)
327 {
328         int fd;
329
330         if (keysize <= 0 || !key)
331                 return -EINVAL;
332
333         *key = crypt_safe_alloc(keysize);
334         if (!*key)
335                 return -ENOMEM;
336
337         fd = open(file, O_RDONLY);
338         if (fd == -1) {
339                 log_err(_("Cannot read keyfile %s."), file);
340                 goto fail;
341         }
342
343         if (read_buffer(fd, *key, keysize) != keysize) {
344                 log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
345                 close(fd);
346                 goto fail;
347         }
348         close(fd);
349         return 0;
350 fail:
351         crypt_safe_free(*key);
352         *key = NULL;
353         return -EINVAL;
354 }
355
356 int tools_write_mk(const char *file, const char *key, int keysize)
357 {
358         int fd, r = -EINVAL;
359
360         if (keysize <= 0 || !key)
361                 return -EINVAL;
362
363         fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
364         if (fd < 0) {
365                 log_err(_("Cannot open keyfile %s for write."), file);
366                 return r;
367         }
368
369         if (write_buffer(fd, key, keysize) == keysize)
370                 r = 0;
371         else
372                 log_err(_("Cannot write to keyfile %s."), file);
373
374         close(fd);
375         return r;
376 }