/*
* Password quality check wrapper
*
- * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2012-2020 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
#include "cryptsetup.h"
#include <termios.h>
-int opt_force_password = 0;
-
#if defined ENABLE_PWQUALITY
#include <pwquality.h>
{
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();
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;
#elif defined ENABLE_PASSWDQC
#include <passwdqc.h>
-static int tools_check_pwquality(const char *password)
+static int tools_check_passwdqc(const char *password)
{
passwdqc_params_t params;
- char *parse_reason;
+ 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"));
- free(parse_reason);
- return -EINVAL;
+ 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);
- return -EPERM;
- }
-
- return 0;
+ r = -EPERM;
+ } else
+ r = 0;
+out:
+#if HAVE_PASSWDQC_PARAMS_FREE
+ passwdqc_params_free(¶ms);
+#endif
+ free(parse_reason);
+ return r;
}
-#else /* !(ENABLE_PWQUALITY || ENABLE_PASSWDQC) */
-static int tools_check_pwquality(const char *password)
+#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
}
-#endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
/* Password reading helpers */
-static int untimed_read(int fd, char *pass, size_t maxlen)
+
+/* 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(fd, pass, maxlen);
+ i = read_tty_eol(fd, pass, maxlen);
if (i > 0) {
- pass[i-1] = '\0';
+ if (pass[i-1] == '\n') {
+ pass[i-1] = '\0';
+ *realsize = i - 1;
+ } else
+ *realsize = i;
i = 0;
- } else if (i == 0) { /* EOF */
- *pass = 0;
+ } else if (i == 0) /* empty input */
i = -1;
- }
+
return i;
}
-static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
+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 */
t.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL, &t) > 0)
- failed = untimed_read(fd, pass, maxlen);
+ failed = untimed_read(fd, pass, maxlen, realsize);
return failed;
}
struct termios orig, tmp;
int failed = -1;
int infd, outfd;
+ size_t realsize = 0;
if (maxlen < 1)
return failed;
outfd = infd;
if (tcgetattr(infd, &orig))
- goto out_err;
+ goto out;
memcpy(&tmp, &orig, sizeof(tmp));
tmp.c_lflag &= ~ECHO;
if (prompt && write(outfd, prompt, strlen(prompt)) < 0)
- goto out_err;
+ goto out;
tcsetattr(infd, TCSAFLUSH, &tmp);
if (timeout)
- failed = timed_read(infd, pass, maxlen, timeout);
+ failed = timed_read(infd, pass, maxlen, &realsize, timeout);
else
- failed = untimed_read(infd, pass, maxlen);
+ failed = untimed_read(infd, pass, maxlen, &realsize);
tcsetattr(infd, TCSAFLUSH, &orig);
-
-out_err:
+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;
static int crypt_get_key_tty(const char *prompt,
char **key, size_t *key_size,
- int timeout, int verify,
- struct crypt_device *cd)
+ int timeout, int verify)
{
int key_size_max = DEFAULT_PASSPHRASE_SIZE_MAX;
int r = -EINVAL;
if (interactive_pass(prompt, pass, key_size_max, timeout)) {
log_err(_("Error reading passphrase from terminal."));
- goto out_err;
+ goto out;
}
- pass[key_size_max] = '\0';
if (verify) {
- pass_verify = crypt_safe_alloc(key_size_max);
+ pass_verify = crypt_safe_alloc(key_size_max + 1);
if (!pass_verify) {
log_err(_("Out of memory while reading passphrase."));
r = -ENOMEM;
- goto out_err;
+ goto out;
}
if (interactive_pass(_("Verify passphrase: "),
pass_verify, key_size_max, timeout)) {
log_err(_("Error reading passphrase from terminal."));
- goto out_err;
+ goto out;
}
if (strncmp(pass, pass_verify, key_size_max)) {
log_err(_("Passphrases do not match."));
r = -EPERM;
- goto out_err;
+ goto out;
}
}
*key = pass;
+ /* coverity[string_null] (crypt_safe_alloc wipes string with additional \0) */
*key_size = strlen(pass);
r = 0;
-out_err:
+out:
crypt_safe_free(pass_verify);
if (r)
crypt_safe_free(pass);
if (keyfile_offset) {
log_err(_("Cannot use offset with terminal input."));
} else {
+ r = 0;
if (!prompt && !crypt_get_device_name(cd))
- snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
+ r = snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
else if (!prompt) {
backing_file = crypt_loop_backing_file(crypt_get_device_name(cd));
- snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), 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);
}
- r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify, cd);
+ 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.");
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;
}
else if (r == -ENOENT)
log_err(_("No usable keyslot is available."));
}
-
-int tools_read_mk(const char *file, char **key, int keysize)
-{
- int fd;
-
- if (!keysize || !key)
- return -EINVAL;
-
- *key = crypt_safe_alloc(keysize);
- if (!*key)
- return -ENOMEM;
-
- fd = open(file, O_RDONLY);
- if (fd == -1) {
- log_err(_("Cannot read keyfile %s."), file);
- goto fail;
- }
-
- if (read_buffer(fd, *key, keysize) != keysize) {
- log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
- close(fd);
- goto fail;
- }
- close(fd);
- return 0;
-fail:
- crypt_safe_free(*key);
- *key = NULL;
- return -EINVAL;
-}
-
-int tools_write_mk(const char *file, const char *key, int keysize)
-{
- int fd, r = -EINVAL;
-
- fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
- if (fd < 0) {
- log_err(_("Cannot open keyfile %s for write."), file);
- return r;
- }
-
- if (write_buffer(fd, key, keysize) == keysize)
- r = 0;
- else
- log_err(_("Cannot write to keyfile %s."), file);
-
- close(fd);
- return r;
-}