"Fossies" - the Fresh Open Source Software Archive

Member "passwdqc-2.0.3/pwqcheck.c" (23 Jun 2023, 5618 Bytes) of package /linux/privat/passwdqc-2.0.3.tar.gz:


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 "pwqcheck.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.4.0_vs_2.0.0.

    1 /*
    2  * Copyright (c) 2008,2009 by Dmitry V. Levin
    3  * Copyright (c) 2010,2016,2021 by Solar Designer
    4  * See LICENSE
    5  */
    6 
    7 #include <stdio.h>
    8 #include <stdlib.h>
    9 #include <string.h>
   10 
   11 #include "passwdqc.h"
   12 
   13 static void clean(char *dst, size_t size)
   14 {
   15     if (!dst)
   16         return;
   17     _passwdqc_memzero(dst, size);
   18     free(dst);
   19 }
   20 
   21 static char *read_line(size_t size, int eof_ok)
   22 {
   23     char *p, *buf = malloc(size + 1);
   24 
   25     if (!buf) {
   26         fprintf(stderr, "pwqcheck: Memory allocation failed.\n");
   27         return NULL;
   28     }
   29 
   30     if (!fgets(buf, size + 1, stdin)) {
   31         clean(buf, size + 1);
   32         if (!eof_ok || !feof(stdin) || ferror(stdin))
   33             fprintf(stderr,
   34                 "pwqcheck: Error reading standard input.\n");
   35         return NULL;
   36     }
   37 
   38     if (strlen(buf) >= size) {
   39         clean(buf, size + 1);
   40         fprintf(stderr, "pwqcheck: Line too long.\n");
   41         return NULL;
   42     }
   43 
   44     if ((p = strpbrk(buf, "\r\n")))
   45         *p = '\0';
   46 
   47     return buf;
   48 }
   49 
   50 static char *extract_string(char **stringp)
   51 {
   52     char *token = *stringp, *colon;
   53 
   54     if (!token)
   55         return "";
   56 
   57     colon = strchr(token, ':');
   58     if (colon) {
   59         *colon = '\0';
   60         *stringp = colon + 1;
   61     } else
   62         *stringp = NULL;
   63 
   64     return token;
   65 }
   66 
   67 static struct passwd *parse_pwline(char *line, struct passwd *pw)
   68 {
   69     if (!strchr(line, ':')) {
   70 #ifdef _MSC_VER
   71         memset(pw, 0, sizeof(*pw));
   72         pw->pw_name = line;
   73 #else
   74         struct passwd *p = getpwnam(line);
   75         endpwent();
   76         if (!p) {
   77             fprintf(stderr, "pwqcheck: User not found.\n");
   78             return NULL;
   79         }
   80         if (p->pw_passwd)
   81             _passwdqc_memzero(p->pw_passwd, strlen(p->pw_passwd));
   82         memcpy(pw, p, sizeof(*pw));
   83 #endif
   84     } else {
   85         memset(pw, 0, sizeof(*pw));
   86         pw->pw_name = extract_string(&line);
   87         pw->pw_passwd = extract_string(&line);
   88         extract_string(&line); /* uid */
   89         extract_string(&line); /* gid */
   90         pw->pw_gecos = extract_string(&line);
   91         pw->pw_dir = extract_string(&line);
   92         pw->pw_shell = line ? line : "";
   93         if (!*pw->pw_name || !*pw->pw_dir) {
   94             fprintf(stderr, "pwqcheck: Invalid passwd entry.\n");
   95             return NULL;
   96         }
   97     }
   98     return pw;
   99 }
  100 
  101 static void
  102 print_help(void)
  103 {
  104     puts("Check passphrase quality.\n"
  105         "\nFor each passphrase to check, pwqcheck reads up to 3 lines from standard input:\n"
  106         "  first line is a new passphrase,\n"
  107         "  second line is an old passphrase, and\n"
  108         "  third line is either an existing account name or a passwd entry.\n"
  109         "\nUsage: pwqcheck [options]\n"
  110         "\nValid options are:\n"
  111         "  min=N0,N1,N2,N3,N4\n"
  112         "       set minimum allowed lengths for different kinds of passphrases;\n"
  113         "  max=N\n"
  114         "       set maximum allowed passphrase length;\n"
  115         "  passphrase=N\n"
  116         "       set number of words required for a passphrase;\n"
  117         "  match=N\n"
  118         "       set length of common substring in substring check;\n"
  119         "  similar=permit|deny\n"
  120         "       whether a new passphrase is allowed to be similar to the old one;\n"
  121         "  wordlist=FILE\n"
  122         "       deny passwords that are based on lines of a tiny external text file;\n"
  123         "  denylist=FILE\n"
  124         "       deny passphrases directly appearing in a tiny external text file;\n"
  125         "  filter=FILE\n"
  126         "       deny passphrases directly appearing in a maybe huge binary filter file;\n"
  127         "  config=FILE\n"
  128         "       load config FILE in passwdqc.conf format;\n"
  129         "  -1\n"
  130         "       read just 1 line (new passphrase);\n"
  131         "  -2\n"
  132         "       read just 2 lines (new and old passphrases);\n"
  133         "  --multi\n"
  134         "       check multiple passphrases (until EOF);\n"
  135         "  --version\n"
  136         "       print program version and exit;\n"
  137         "  -h or --help\n"
  138         "       print this help text and exit.");
  139 }
  140 
  141 int main(int argc, const char **argv)
  142 {
  143     passwdqc_params_t params;
  144     const char *check_reason;
  145     char *parse_reason, *newpass, *oldpass, *pwline;
  146     struct passwd pwbuf, *pw;
  147     int lines_to_read = 3, multi = 0;
  148     size_t size = 8192;
  149     int rc = 1;
  150 
  151     while (argc > 1 && argv[1][0] == '-') {
  152         const char *arg = argv[1];
  153 
  154         if (!strcmp("-h", arg) || !strcmp("--help", arg)) {
  155             print_help();
  156             return 0;
  157         }
  158 
  159         if (!strcmp("--version", arg)) {
  160             printf("pwqcheck version %s\n", PASSWDQC_VERSION);
  161             return 0;
  162         }
  163 
  164         if ((arg[1] == '1' || arg[1] == '2') && !arg[2]) {
  165             lines_to_read = arg[1] - '0';
  166             goto next_arg;
  167         }
  168 
  169         if (!strcmp("--multi", arg)) {
  170             multi = 1;
  171             goto next_arg;
  172         }
  173 
  174         break;
  175 
  176 next_arg:
  177         argc--; argv++;
  178     }
  179 
  180     passwdqc_params_reset(&params);
  181     if (argc > 1 &&
  182         passwdqc_params_parse(&params, &parse_reason, argc - 1,
  183         argv + 1)) {
  184         fprintf(stderr, "pwqcheck: %s\n",
  185             (parse_reason ? parse_reason : "Out of memory"));
  186         free(parse_reason);
  187         return rc;
  188     }
  189 
  190     if ((size_t)params.qc.max + 1 > size)
  191         size = (size_t)params.qc.max + 1;
  192 
  193 next_pass:
  194     oldpass = pwline = NULL; pw = NULL;
  195     if (!(newpass = read_line(size, multi))) {
  196         if (multi && feof(stdin) && !ferror(stdin) &&
  197             fflush(stdout) >= 0)
  198             rc = 0;
  199         goto done;
  200     }
  201     if (lines_to_read >= 2 && !(oldpass = read_line(size, 0)))
  202         goto done;
  203     if (lines_to_read >= 3 && (!(pwline = read_line(size, 0)) ||
  204         !parse_pwline(pwline, pw = &pwbuf)))
  205         goto done;
  206 
  207     check_reason = passwdqc_check(&params.qc, newpass, oldpass, pw);
  208     if (!check_reason) {
  209         if (multi)
  210             printf("OK: %s\n", newpass);
  211         else if (puts("OK") >= 0 && fflush(stdout) >= 0)
  212             rc = 0;
  213         goto cleanup;
  214     }
  215     if (multi)
  216         printf("Bad passphrase (%s): %s\n", check_reason, newpass);
  217     else
  218         printf("Bad passphrase (%s)\n", check_reason);
  219 
  220 cleanup:
  221     _passwdqc_memzero(&pwbuf, sizeof(pwbuf));
  222     clean(pwline, size);
  223     clean(oldpass, size);
  224     clean(newpass, size);
  225 
  226     if (multi)
  227         goto next_pass;
  228 
  229     passwdqc_params_free(&params);
  230 
  231     return rc;
  232 
  233 done:
  234     multi = 0;
  235     goto cleanup;
  236 }