2 * Password quality check wrapper
4 * Copyright (C) 2012-2023 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2012-2023 Milan Broz
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.
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.
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.
22 #include "cryptsetup.h"
25 #if defined ENABLE_PWQUALITY
26 #include <pwquality.h>
28 static int tools_check_pwquality(const char *password)
32 pwquality_settings_t *pwq;
34 log_dbg("Checking new password using default pwquality settings.");
35 pwq = pwquality_default_settings();
39 r = pwquality_read_config(pwq, NULL, &auxerror);
41 log_err(_("Cannot check password quality: %s"),
42 pwquality_strerror(NULL, 0, r, auxerror));
43 pwquality_free_settings(pwq);
47 r = pwquality_check(pwq, password, NULL, NULL, &auxerror);
49 log_err(_("Password quality check failed:\n %s"),
50 pwquality_strerror(NULL, 0, r, auxerror));
55 pwquality_free_settings(pwq);
58 #elif defined ENABLE_PASSWDQC
61 static int tools_check_passwdqc(const char *password)
63 passwdqc_params_t params;
64 char *parse_reason = NULL;
65 const char *check_reason;
66 const char *config = PASSWDQC_CONFIG_FILE;
69 passwdqc_params_reset(¶ms);
71 if (*config && passwdqc_params_load(¶ms, &parse_reason, config)) {
72 log_err(_("Cannot check password quality: %s"),
73 (parse_reason ? parse_reason : "Out of memory"));
77 check_reason = passwdqc_check(¶ms.qc, password, NULL, NULL);
79 log_err(_("Password quality check failed: Bad passphrase (%s)"),
85 #if HAVE_PASSWDQC_PARAMS_FREE
86 passwdqc_params_free(¶ms);
91 #endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
93 /* coverity[ +tainted_string_sanitize_content : arg-0 ] */
94 static int tools_check_password(const char *password)
96 #if defined ENABLE_PWQUALITY
97 return tools_check_pwquality(password);
98 #elif defined ENABLE_PASSWDQC
99 return tools_check_passwdqc(password);
105 /* Password reading helpers */
107 /* coverity[ -taint_source : arg-1 ] */
108 static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen)
111 size_t read_size = 0;
115 r = read(fd, pass, maxlen - read_size);
116 if ((r == -1 && errno != EINTR) || quit)
119 if (!r || pass[r-1] == '\n')
121 read_size += (size_t)r;
124 } while (!eol && read_size != maxlen);
126 return (ssize_t)read_size;
129 /* The pass buffer is zeroed and has trailing \0 already " */
130 static int untimed_read(int fd, char *pass, size_t maxlen, size_t *realsize)
134 i = read_tty_eol(fd, pass, maxlen);
136 if (pass[i-1] == '\n') {
142 } else if (i == 0) /* empty input */
148 static int timed_read(int fd, char *pass, size_t maxlen, size_t *realsize, long timeout)
151 fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */
159 if (select(fd+1, &fds, NULL, NULL, &t) > 0)
160 failed = untimed_read(fd, pass, maxlen, realsize);
165 static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
168 struct termios orig, tmp;
176 /* Read and write to /dev/tty if available */
177 infd = open("/dev/tty", O_RDWR);
180 outfd = STDERR_FILENO;
184 if (tcgetattr(infd, &orig))
187 memcpy(&tmp, &orig, sizeof(tmp));
188 tmp.c_lflag &= ~ECHO;
190 if (prompt && write(outfd, prompt, strlen(prompt)) < 0)
193 tcsetattr(infd, TCSAFLUSH, &tmp);
195 failed = timed_read(infd, pass, maxlen, &realsize, timeout);
197 failed = untimed_read(infd, pass, maxlen, &realsize);
198 tcsetattr(infd, TCSAFLUSH, &orig);
200 if (!failed && write(outfd, "\n", 1)) {};
202 if (realsize == maxlen)
203 log_dbg("Read stopped at maximal interactive input length, passphrase can be trimmed.");
205 if (infd != STDIN_FILENO)
210 static int crypt_get_key_tty(const char *prompt,
211 char **key, size_t *key_size,
212 int timeout, int verify)
214 int key_size_max = DEFAULT_PASSPHRASE_SIZE_MAX;
216 char *pass = NULL, *pass_verify = NULL;
221 log_dbg("Interactive passphrase entry requested.");
223 pass = crypt_safe_alloc(key_size_max + 1);
225 log_err( _("Out of memory while reading passphrase."));
229 if (interactive_pass(prompt, pass, key_size_max, timeout)) {
230 log_err(_("Error reading passphrase from terminal."));
235 pass_verify = crypt_safe_alloc(key_size_max + 1);
237 log_err(_("Out of memory while reading passphrase."));
242 if (interactive_pass(_("Verify passphrase: "),
243 pass_verify, key_size_max, timeout)) {
244 log_err(_("Error reading passphrase from terminal."));
248 if (strncmp(pass, pass_verify, key_size_max)) {
249 log_err(_("Passphrases do not match."));
256 /* coverity[string_null] (crypt_safe_alloc wipes string with additional \0) */
257 *key_size = strlen(pass);
260 crypt_safe_free(pass_verify);
262 crypt_safe_free(pass);
267 * Note: --key-file=- is interpreted as a read from a binary file (stdin)
268 * key_size_max == 0 means detect maximum according to input type (tty/file)
270 int tools_get_key(const char *prompt,
271 char **key, size_t *key_size,
272 uint64_t keyfile_offset, size_t keyfile_size_max,
273 const char *key_file,
274 int timeout, int verify, int pwquality,
275 struct crypt_device *cd)
277 char tmp[PATH_MAX], *backing_file;
278 int r = -EINVAL, block;
280 block = tools_signals_blocked();
284 if (tools_is_stdin(key_file)) {
285 if (isatty(STDIN_FILENO)) {
286 if (keyfile_offset) {
287 log_err(_("Cannot use offset with terminal input."));
290 if (!prompt && !crypt_get_device_name(cd))
291 r = snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
293 backing_file = crypt_loop_backing_file(crypt_get_device_name(cd));
294 r = snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), backing_file ?: crypt_get_device_name(cd));
298 r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify);
303 log_dbg("STDIN descriptor passphrase entry requested.");
304 /* No keyfile means STDIN with EOL handling (\n will end input)). */
305 r = crypt_keyfile_device_read(cd, NULL, key, key_size,
306 keyfile_offset, keyfile_size_max,
307 key_file ? 0 : CRYPT_KEYFILE_STOP_EOL);
310 log_dbg("File descriptor passphrase entry requested.");
311 r = crypt_keyfile_device_read(cd, key_file, key, key_size,
312 keyfile_offset, keyfile_size_max, 0);
318 /* Check pwquality for password (not keyfile) */
319 if (pwquality && !key_file && !r)
320 r = tools_check_password(*key);
325 void tools_passphrase_msg(int r)
328 log_err(_("No key available with this passphrase."));
329 else if (r == -ENOENT)
330 log_err(_("No usable keyslot is available."));