"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/src/utils_password.c" (13 Jan 2022, 7924 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "utils_password.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.4.1_vs_2.4.2.

    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 #if defined ENABLE_PWQUALITY
   26 #include <pwquality.h>
   27 
   28 static int tools_check_pwquality(const char *password)
   29 {
   30     int r;
   31     void *auxerror;
   32     pwquality_settings_t *pwq;
   33 
   34     log_dbg("Checking new password using default pwquality settings.");
   35     pwq = pwquality_default_settings();
   36     if (!pwq)
   37         return -EINVAL;
   38 
   39     r = pwquality_read_config(pwq, NULL, &auxerror);
   40     if (r) {
   41         log_err(_("Cannot check password quality: %s"),
   42             pwquality_strerror(NULL, 0, r, auxerror));
   43         pwquality_free_settings(pwq);
   44         return -EINVAL;
   45     }
   46 
   47     r = pwquality_check(pwq, password, NULL, NULL, &auxerror);
   48     if (r < 0) {
   49         log_err(_("Password quality check failed:\n %s"),
   50             pwquality_strerror(NULL, 0, r, auxerror));
   51         r = -EPERM;
   52     } else {
   53         log_dbg("New password libpwquality score is %d.", r);
   54         r = 0;
   55     }
   56 
   57     pwquality_free_settings(pwq);
   58     return r;
   59 }
   60 #elif defined ENABLE_PASSWDQC
   61 #include <passwdqc.h>
   62 
   63 static int tools_check_passwdqc(const char *password)
   64 {
   65     passwdqc_params_t params;
   66     char *parse_reason = NULL;
   67     const char *check_reason;
   68     const char *config = PASSWDQC_CONFIG_FILE;
   69     int r = -EINVAL;
   70 
   71     passwdqc_params_reset(&params);
   72 
   73     if (*config && passwdqc_params_load(&params, &parse_reason, config)) {
   74         log_err(_("Cannot check password quality: %s"),
   75             (parse_reason ? parse_reason : "Out of memory"));
   76         goto out;
   77     }
   78 
   79     check_reason = passwdqc_check(&params.qc, password, NULL, NULL);
   80     if (check_reason) {
   81         log_err(_("Password quality check failed: Bad passphrase (%s)"),
   82             check_reason);
   83         r = -EPERM;
   84     } else
   85         r = 0;
   86 out:
   87 #if HAVE_PASSWDQC_PARAMS_FREE
   88     passwdqc_params_free(&params);
   89 #endif
   90     free(parse_reason);
   91     return r;
   92 }
   93 #endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
   94 
   95 /* coverity[ +tainted_string_sanitize_content : arg-0 ] */
   96 static int tools_check_password(const char *password)
   97 {
   98 #if defined ENABLE_PWQUALITY
   99     return tools_check_pwquality(password);
  100 #elif defined ENABLE_PASSWDQC
  101     return tools_check_passwdqc(password);
  102 #else
  103     return 0;
  104 #endif
  105 }
  106 
  107 /* Password reading helpers */
  108 
  109 static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen)
  110 {
  111     bool eol = false;
  112     size_t read_size = 0;
  113     ssize_t r;
  114 
  115     do {
  116         r = read(fd, pass, maxlen - read_size);
  117         if ((r == -1 && errno != EINTR) || quit)
  118             return -1;
  119         if (r >= 0) {
  120             if (!r || pass[r-1] == '\n')
  121                 eol = true;
  122             read_size += (size_t)r;
  123             pass = pass + r;
  124         }
  125     } while (!eol && read_size != maxlen);
  126 
  127     return (ssize_t)read_size;
  128 }
  129 
  130 /* The pass buffer is zeroed and has trailing \0 already " */
  131 static int untimed_read(int fd, char *pass, size_t maxlen)
  132 {
  133     ssize_t i;
  134 
  135     i = read_tty_eol(fd, pass, maxlen);
  136     if (i > 0) {
  137         if (pass[i-1] == '\n')
  138             pass[i-1] = '\0';
  139         i = 0;
  140     } else if (i == 0) /* empty input */
  141         i = -1;
  142 
  143     return i;
  144 }
  145 
  146 static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
  147 {
  148     struct timeval t;
  149     fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */
  150     int failed = -1;
  151 
  152     FD_ZERO(&fds);
  153     FD_SET(fd, &fds);
  154     t.tv_sec = timeout;
  155     t.tv_usec = 0;
  156 
  157     if (select(fd+1, &fds, NULL, NULL, &t) > 0)
  158         failed = untimed_read(fd, pass, maxlen);
  159 
  160     return failed;
  161 }
  162 
  163 static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
  164         long timeout)
  165 {
  166     struct termios orig, tmp;
  167     int failed = -1;
  168     int infd, outfd;
  169 
  170     if (maxlen < 1)
  171         return failed;
  172 
  173     /* Read and write to /dev/tty if available */
  174     infd = open("/dev/tty", O_RDWR);
  175     if (infd == -1) {
  176         infd = STDIN_FILENO;
  177         outfd = STDERR_FILENO;
  178     } else
  179         outfd = infd;
  180 
  181     if (tcgetattr(infd, &orig))
  182         goto out;
  183 
  184     memcpy(&tmp, &orig, sizeof(tmp));
  185     tmp.c_lflag &= ~ECHO;
  186 
  187     if (prompt && write(outfd, prompt, strlen(prompt)) < 0)
  188         goto out;
  189 
  190     tcsetattr(infd, TCSAFLUSH, &tmp);
  191     if (timeout)
  192         failed = timed_read(infd, pass, maxlen, timeout);
  193     else
  194         failed = untimed_read(infd, pass, maxlen);
  195     tcsetattr(infd, TCSAFLUSH, &orig);
  196 out:
  197     if (!failed && write(outfd, "\n", 1)) {};
  198 
  199     if (infd != STDIN_FILENO)
  200         close(infd);
  201     return failed;
  202 }
  203 
  204 static int crypt_get_key_tty(const char *prompt,
  205                  char **key, size_t *key_size,
  206                  int timeout, int verify)
  207 {
  208     int key_size_max = DEFAULT_PASSPHRASE_SIZE_MAX;
  209     int r = -EINVAL;
  210     char *pass = NULL, *pass_verify = NULL;
  211 
  212     *key = NULL;
  213     *key_size = 0;
  214 
  215     log_dbg("Interactive passphrase entry requested.");
  216 
  217     pass = crypt_safe_alloc(key_size_max + 1);
  218     if (!pass) {
  219         log_err( _("Out of memory while reading passphrase."));
  220         return -ENOMEM;
  221     }
  222 
  223     if (interactive_pass(prompt, pass, key_size_max, timeout)) {
  224         log_err(_("Error reading passphrase from terminal."));
  225         goto out;
  226     }
  227 
  228     if (verify) {
  229         pass_verify = crypt_safe_alloc(key_size_max + 1);
  230         if (!pass_verify) {
  231             log_err(_("Out of memory while reading passphrase."));
  232             r = -ENOMEM;
  233             goto out;
  234         }
  235 
  236         if (interactive_pass(_("Verify passphrase: "),
  237             pass_verify, key_size_max, timeout)) {
  238             log_err(_("Error reading passphrase from terminal."));
  239             goto out;
  240         }
  241 
  242         if (strncmp(pass, pass_verify, key_size_max)) {
  243             log_err(_("Passphrases do not match."));
  244             r = -EPERM;
  245             goto out;
  246         }
  247     }
  248 
  249     *key = pass;
  250     *key_size = strlen(pass);
  251     r = 0;
  252 out:
  253     crypt_safe_free(pass_verify);
  254     if (r)
  255         crypt_safe_free(pass);
  256     return r;
  257 }
  258 
  259 /*
  260  * Note: --key-file=- is interpreted as a read from a binary file (stdin)
  261  * key_size_max == 0 means detect maximum according to input type (tty/file)
  262  */
  263 int tools_get_key(const char *prompt,
  264           char **key, size_t *key_size,
  265           uint64_t keyfile_offset, size_t keyfile_size_max,
  266           const char *key_file,
  267           int timeout, int verify, int pwquality,
  268           struct crypt_device *cd)
  269 {
  270     char tmp[PATH_MAX], *backing_file;
  271     int r = -EINVAL, block;
  272 
  273     block = tools_signals_blocked();
  274     if (block)
  275         set_int_block(0);
  276 
  277     if (tools_is_stdin(key_file)) {
  278         if (isatty(STDIN_FILENO)) {
  279             if (keyfile_offset) {
  280                 log_err(_("Cannot use offset with terminal input."));
  281             } else {
  282                 if (!prompt && !crypt_get_device_name(cd))
  283                     snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
  284                 else if (!prompt) {
  285                     backing_file = crypt_loop_backing_file(crypt_get_device_name(cd));
  286                     snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), backing_file ?: crypt_get_device_name(cd));
  287                     free(backing_file);
  288                 }
  289                 r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify);
  290             }
  291         } else {
  292             log_dbg("STDIN descriptor passphrase entry requested.");
  293             /* No keyfile means STDIN with EOL handling (\n will end input)). */
  294             r = crypt_keyfile_device_read(cd, NULL, key, key_size,
  295                     keyfile_offset, keyfile_size_max,
  296                     key_file ? 0 : CRYPT_KEYFILE_STOP_EOL);
  297         }
  298     } else {
  299         log_dbg("File descriptor passphrase entry requested.");
  300         r = crypt_keyfile_device_read(cd, key_file, key, key_size,
  301                           keyfile_offset, keyfile_size_max, 0);
  302     }
  303 
  304     if (block && !quit)
  305         set_int_block(1);
  306 
  307     /* Check pwquality for password (not keyfile) */
  308     if (pwquality && !key_file && !r)
  309         r = tools_check_password(*key);
  310 
  311     return r;
  312 }
  313 
  314 void tools_passphrase_msg(int r)
  315 {
  316     if (r == -EPERM)
  317         log_err(_("No key available with this passphrase."));
  318     else if (r == -ENOENT)
  319         log_err(_("No usable keyslot is available."));
  320 }