X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Futils_password.c;h=3374e18f53969f6b1dbab105496a7d5dc64d8027;hb=HEAD;hp=541806c71a7d6a8cd97f7dd6d733b13c1058f04a;hpb=064b2722c00e5d32b35d3f47b24e7be3ad1c132b;p=platform%2Fupstream%2Fcryptsetup.git diff --git a/src/utils_password.c b/src/utils_password.c index 541806c..3374e18 100644 --- a/src/utils_password.c +++ b/src/utils_password.c @@ -1,8 +1,8 @@ /* * Password quality check wrapper * - * Copyright (C) 2012, Red Hat, Inc. All rights reserved. - * Copyright (C) 2012-2014, Milan Broz + * Copyright (C) 2012-2023 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2023 Milan Broz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,17 +20,16 @@ */ #include "cryptsetup.h" +#include -int opt_force_password = 0; - -#if ENABLE_PWQUALITY +#if defined ENABLE_PWQUALITY #include static int tools_check_pwquality(const char *password) { int r; void *auxerror; - pwquality_settings_t *pwq; + pwquality_settings_t *pwq; log_dbg("Checking new password using default pwquality settings."); pwq = pwquality_default_settings(); @@ -39,7 +38,7 @@ static int tools_check_pwquality(const char *password) r = pwquality_read_config(pwq, NULL, &auxerror); if (r) { - log_err(_("Cannot check password quality: %s\n"), + log_err(_("Cannot check password quality: %s"), pwquality_strerror(NULL, 0, r, auxerror)); pwquality_free_settings(pwq); return -EINVAL; @@ -47,45 +46,286 @@ static int tools_check_pwquality(const char *password) r = pwquality_check(pwq, password, NULL, NULL, &auxerror); if (r < 0) { - log_err(_("Password quality check failed:\n %s\n"), + log_err(_("Password quality check failed:\n %s"), pwquality_strerror(NULL, 0, r, auxerror)); r = -EPERM; - } else { - log_dbg("New password libpwquality score is %d.", r); + } else r = 0; - } pwquality_free_settings(pwq); return r; } -#else /* ENABLE_PWQUALITY */ -static int tools_check_pwquality(const char *password) +#elif defined ENABLE_PASSWDQC +#include + +static int tools_check_passwdqc(const char *password) { + passwdqc_params_t params; + char *parse_reason = NULL; + const char *check_reason; + const char *config = PASSWDQC_CONFIG_FILE; + int r = -EINVAL; + + passwdqc_params_reset(¶ms); + + if (*config && passwdqc_params_load(¶ms, &parse_reason, config)) { + log_err(_("Cannot check password quality: %s"), + (parse_reason ? parse_reason : "Out of memory")); + goto out; + } + + check_reason = passwdqc_check(¶ms.qc, password, NULL, NULL); + if (check_reason) { + log_err(_("Password quality check failed: Bad passphrase (%s)"), + check_reason); + r = -EPERM; + } else + r = 0; +out: +#if HAVE_PASSWDQC_PARAMS_FREE + passwdqc_params_free(¶ms); +#endif + free(parse_reason); + return r; +} +#endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */ + +/* coverity[ +tainted_string_sanitize_content : arg-0 ] */ +static int tools_check_password(const char *password) +{ +#if defined ENABLE_PWQUALITY + return tools_check_pwquality(password); +#elif defined ENABLE_PASSWDQC + return tools_check_passwdqc(password); +#else return 0; +#endif +} + +/* Password reading helpers */ + +/* coverity[ -taint_source : arg-1 ] */ +static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen) +{ + bool eol = false; + size_t read_size = 0; + ssize_t r; + + do { + r = read(fd, pass, maxlen - read_size); + if ((r == -1 && errno != EINTR) || quit) + return -1; + if (r >= 0) { + if (!r || pass[r-1] == '\n') + eol = true; + read_size += (size_t)r; + pass = pass + r; + } + } while (!eol && read_size != maxlen); + + return (ssize_t)read_size; +} + +/* The pass buffer is zeroed and has trailing \0 already " */ +static int untimed_read(int fd, char *pass, size_t maxlen, size_t *realsize) +{ + ssize_t i; + + i = read_tty_eol(fd, pass, maxlen); + if (i > 0) { + if (pass[i-1] == '\n') { + pass[i-1] = '\0'; + *realsize = i - 1; + } else + *realsize = i; + i = 0; + } else if (i == 0) /* empty input */ + i = -1; + + return i; +} + +static int timed_read(int fd, char *pass, size_t maxlen, size_t *realsize, long timeout) +{ + struct timeval t; + fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */ + int failed = -1; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + t.tv_sec = timeout; + t.tv_usec = 0; + + if (select(fd+1, &fds, NULL, NULL, &t) > 0) + failed = untimed_read(fd, pass, maxlen, realsize); + + return failed; +} + +static int interactive_pass(const char *prompt, char *pass, size_t maxlen, + long timeout) +{ + struct termios orig, tmp; + int failed = -1; + int infd, outfd; + size_t realsize = 0; + + if (maxlen < 1) + return failed; + + /* Read and write to /dev/tty if available */ + infd = open("/dev/tty", O_RDWR); + if (infd == -1) { + infd = STDIN_FILENO; + outfd = STDERR_FILENO; + } else + outfd = infd; + + if (tcgetattr(infd, &orig)) + goto out; + + memcpy(&tmp, &orig, sizeof(tmp)); + tmp.c_lflag &= ~ECHO; + + if (prompt && write(outfd, prompt, strlen(prompt)) < 0) + goto out; + + tcsetattr(infd, TCSAFLUSH, &tmp); + if (timeout) + failed = timed_read(infd, pass, maxlen, &realsize, timeout); + else + failed = untimed_read(infd, pass, maxlen, &realsize); + tcsetattr(infd, TCSAFLUSH, &orig); +out: + if (!failed && write(outfd, "\n", 1)) {}; + + if (realsize == maxlen) + log_dbg("Read stopped at maximal interactive input length, passphrase can be trimmed."); + + if (infd != STDIN_FILENO) + close(infd); + return failed; } -#endif /* ENABLE_PWQUALITY */ +static int crypt_get_key_tty(const char *prompt, + char **key, size_t *key_size, + int timeout, int verify) +{ + int key_size_max = DEFAULT_PASSPHRASE_SIZE_MAX; + int r = -EINVAL; + char *pass = NULL, *pass_verify = NULL; + + *key = NULL; + *key_size = 0; + + log_dbg("Interactive passphrase entry requested."); + + pass = crypt_safe_alloc(key_size_max + 1); + if (!pass) { + log_err( _("Out of memory while reading passphrase.")); + return -ENOMEM; + } + + if (interactive_pass(prompt, pass, key_size_max, timeout)) { + log_err(_("Error reading passphrase from terminal.")); + goto out; + } + + if (verify) { + pass_verify = crypt_safe_alloc(key_size_max + 1); + if (!pass_verify) { + log_err(_("Out of memory while reading passphrase.")); + r = -ENOMEM; + goto out; + } + + if (interactive_pass(_("Verify passphrase: "), + pass_verify, key_size_max, timeout)) { + log_err(_("Error reading passphrase from terminal.")); + goto out; + } + + if (strncmp(pass, pass_verify, key_size_max)) { + log_err(_("Passphrases do not match.")); + r = -EPERM; + goto out; + } + } + + *key = pass; + /* coverity[string_null] (crypt_safe_alloc wipes string with additional \0) */ + *key_size = strlen(pass); + r = 0; +out: + crypt_safe_free(pass_verify); + if (r) + crypt_safe_free(pass); + return r; +} + +/* + * Note: --key-file=- is interpreted as a read from a binary file (stdin) + * key_size_max == 0 means detect maximum according to input type (tty/file) + */ int tools_get_key(const char *prompt, char **key, size_t *key_size, - size_t keyfile_offset, size_t keyfile_size_max, + uint64_t keyfile_offset, size_t keyfile_size_max, const char *key_file, int timeout, int verify, int pwquality, struct crypt_device *cd) { - int r, block; + char tmp[PATH_MAX], *backing_file; + int r = -EINVAL, block; block = tools_signals_blocked(); if (block) set_int_block(0); - r = crypt_get_key(prompt, key, key_size, keyfile_offset, - keyfile_size_max, key_file, timeout, verify, cd); + if (tools_is_stdin(key_file)) { + if (isatty(STDIN_FILENO)) { + if (keyfile_offset) { + log_err(_("Cannot use offset with terminal input.")); + } else { + r = 0; + if (!prompt && !crypt_get_device_name(cd)) + r = snprintf(tmp, sizeof(tmp), _("Enter passphrase: ")); + else if (!prompt) { + backing_file = crypt_loop_backing_file(crypt_get_device_name(cd)); + r = snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), backing_file ?: crypt_get_device_name(cd)); + free(backing_file); + } + if (r >= 0) + r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify); + else + r = -EINVAL; + } + } else { + log_dbg("STDIN descriptor passphrase entry requested."); + /* No keyfile means STDIN with EOL handling (\n will end input)). */ + r = crypt_keyfile_device_read(cd, NULL, key, key_size, + keyfile_offset, keyfile_size_max, + key_file ? 0 : CRYPT_KEYFILE_STOP_EOL); + } + } else { + log_dbg("File descriptor passphrase entry requested."); + r = crypt_keyfile_device_read(cd, key_file, key, key_size, + keyfile_offset, keyfile_size_max, 0); + } + if (block && !quit) set_int_block(1); /* Check pwquality for password (not keyfile) */ - if (pwquality && !opt_force_password && !key_file && !r) - r = tools_check_pwquality(*key); + if (pwquality && !key_file && !r) + r = tools_check_password(*key); return r; } + +void tools_passphrase_msg(int r) +{ + if (r == -EPERM) + log_err(_("No key available with this passphrase.")); + else if (r == -ENOENT) + log_err(_("No usable keyslot is available.")); +}