Makefile: Add security compiling option (RELRO, SC, and FORTIFY)
[platform/upstream/cryptsetup.git] / src / utils_password.c
index e4f7cf0..3374e18 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Password quality check wrapper
  *
- * Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2012-2021 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
@@ -22,8 +22,6 @@
 #include "cryptsetup.h"
 #include <termios.h>
 
-int opt_force_password = 0;
-
 #if defined ENABLE_PWQUALITY
 #include <pwquality.h>
 
@@ -31,7 +29,7 @@ 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();
@@ -51,10 +49,8 @@ static int tools_check_pwquality(const char *password)
                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;
@@ -108,6 +104,7 @@ static int tools_check_password(const char *password)
 
 /* Password reading helpers */
 
+/* coverity[ -taint_source : arg-1 ] */
 static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen)
 {
        bool eol = false;
@@ -130,14 +127,17 @@ static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen)
 }
 
 /* The pass buffer is zeroed and has trailing \0 already " */
-static int untimed_read(int fd, char *pass, size_t maxlen)
+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')
+               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;
@@ -145,7 +145,7 @@ static int untimed_read(int fd, char *pass, size_t maxlen)
        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 */
@@ -157,7 +157,7 @@ static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
        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;
 }
@@ -168,6 +168,7 @@ static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
        struct termios orig, tmp;
        int failed = -1;
        int infd, outfd;
+       size_t realsize = 0;
 
        if (maxlen < 1)
                return failed;
@@ -181,24 +182,26 @@ static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
                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;
@@ -206,8 +209,7 @@ out_err:
 
 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;
@@ -226,7 +228,7 @@ static int crypt_get_key_tty(const char *prompt,
 
        if (interactive_pass(prompt, pass, key_size_max, timeout)) {
                log_err(_("Error reading passphrase from terminal."));
-               goto out_err;
+               goto out;
        }
 
        if (verify) {
@@ -234,26 +236,27 @@ static int crypt_get_key_tty(const char *prompt,
                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);
@@ -283,14 +286,18 @@ int tools_get_key(const char *prompt,
                        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.");
@@ -309,7 +316,7 @@ int tools_get_key(const char *prompt,
                set_int_block(1);
 
        /* Check pwquality for password (not keyfile) */
-       if (pwquality && !opt_force_password && !key_file && !r)
+       if (pwquality && !key_file && !r)
                r = tools_check_password(*key);
 
        return r;
@@ -322,55 +329,3 @@ void tools_passphrase_msg(int 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 <= 0 || !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;
-
-       if (keysize <= 0 || !key)
-               return -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;
-}