X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fpasswd.c;h=e2c90960e5409d0e6280fa0b6a2bf06afce7eaf6;hp=2814b32c75e5a0a07c532163357cf757cb25dcdd;hb=fb2141c773ab0c5dfc78cc97d2445362b8048389;hpb=ca3a82c3b364e1e584546f0f3bbb938b0b472580 diff --git a/apps/passwd.c b/apps/passwd.c index 2814b32c75..e2c90960e5 100644 --- a/apps/passwd.c +++ b/apps/passwd.c @@ -1,4 +1,11 @@ -/* apps/passwd.c */ +/* + * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ #if defined OPENSSL_NO_MD5 || defined CHARSET_EBCDIC # define NO_MD5CRYPT_1 @@ -6,7 +13,6 @@ #if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1) -# include # include # include "apps.h" @@ -22,9 +28,6 @@ # include # endif -# undef PROG -# define PROG passwd_main - static unsigned const char cov_2char[64] = { /* from crypto/des/fcrypt.c */ 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, @@ -42,155 +45,141 @@ static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, int reverse, size_t pw_maxlen, int usecrypt, int use1, int useapr1); -/*- - * -crypt - standard Unix password algorithm (default) - * -1 - MD5-based password algorithm - * -apr1 - MD5-based password algorithm, Apache variant - * -salt string - salt - * -in file - read passwords from file - * -stdin - read passwords from stdin - * -noverify - never verify when reading password from terminal - * -quiet - no warnings - * -table - format output as table - * -reverse - switch table columns - */ - -int MAIN(int, char **); +typedef enum OPTION_choice { + OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_IN, + OPT_NOVERIFY, OPT_QUIET, OPT_TABLE, OPT_REVERSE, OPT_APR1, + OPT_1, OPT_CRYPT, OPT_SALT, OPT_STDIN +} OPTION_CHOICE; + +OPTIONS passwd_options[] = { + {"help", OPT_HELP, '-', "Display this summary"}, + {"in", OPT_IN, '<', "Pead passwords from file"}, + {"noverify", OPT_NOVERIFY, '-', + "Never verify when reading password from terminal"}, + {"quiet", OPT_QUIET, '-', "No warnings"}, + {"table", OPT_TABLE, '-', "Format output as table"}, + {"reverse", OPT_REVERSE, '-', "Switch table columns"}, + {"salt", OPT_SALT, 's', "Use provided salt"}, + {"stdin", OPT_STDIN, '-', "Read passwords from stdin"}, +# ifndef NO_MD5CRYPT_1 + {"apr1", OPT_APR1, '-', "MD5-based password algorithm, Apache variant"}, + {"1", OPT_1, '-', "MD5-based password algorithm"}, +# endif +# ifndef OPENSSL_NO_DES + {"crypt", OPT_CRYPT, '-', "Standard Unix password algorithm (default)"}, +# endif + {NULL} +}; -int MAIN(int argc, char **argv) +int passwd_main(int argc, char **argv) { - int ret = 1; - char *infile = NULL; - int in_stdin = 0; + BIO *in = NULL; + char *infile = NULL, *salt = NULL, *passwd = NULL, **passwds = NULL; + char *salt_malloc = NULL, *passwd_malloc = NULL, *prog; + OPTION_CHOICE o; + int in_stdin = 0, pw_source_defined = 0; +#ifndef OPENSSL_NO_UI int in_noverify = 0; - char *salt = NULL, *passwd = NULL, **passwds = NULL; - char *salt_malloc = NULL, *passwd_malloc = NULL; - size_t passwd_malloc_size = 0; - int pw_source_defined = 0; - BIO *in = NULL, *out = NULL; - int i, badopt, opt_done; +#endif int passed_salt = 0, quiet = 0, table = 0, reverse = 0; - int usecrypt = 0, use1 = 0, useapr1 = 0; - size_t pw_maxlen = 0; - - apps_startup(); - - if (bio_err == NULL) - if ((bio_err = BIO_new(BIO_s_file())) != NULL) - BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); - - if (!load_config(bio_err, NULL)) - goto err; - out = BIO_new(BIO_s_file()); - if (out == NULL) - goto err; - BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); -# ifdef OPENSSL_SYS_VMS - { - BIO *tmpbio = BIO_new(BIO_f_linebuffer()); - out = BIO_push(tmpbio, out); - } -# endif - - badopt = 0, opt_done = 0; - i = 0; - while (!badopt && !opt_done && argv[++i] != NULL) { - if (strcmp(argv[i], "-crypt") == 0) - usecrypt = 1; - else if (strcmp(argv[i], "-1") == 0) - use1 = 1; - else if (strcmp(argv[i], "-apr1") == 0) - useapr1 = 1; - else if (strcmp(argv[i], "-salt") == 0) { - if ((argv[i + 1] != NULL) && (salt == NULL)) { - passed_salt = 1; - salt = argv[++i]; - } else - badopt = 1; - } else if (strcmp(argv[i], "-in") == 0) { - if ((argv[i + 1] != NULL) && !pw_source_defined) { - pw_source_defined = 1; - infile = argv[++i]; - } else - badopt = 1; - } else if (strcmp(argv[i], "-stdin") == 0) { - if (!pw_source_defined) { - pw_source_defined = 1; - in_stdin = 1; - } else - badopt = 1; - } else if (strcmp(argv[i], "-noverify") == 0) + int ret = 1, usecrypt = 0, use1 = 0, useapr1 = 0; + size_t passwd_malloc_size = 0, pw_maxlen = 256; + + prog = opt_init(argc, argv, passwd_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_EOF: + case OPT_ERR: + opthelp: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + goto end; + case OPT_HELP: + opt_help(passwd_options); + ret = 0; + goto end; + case OPT_IN: + if (pw_source_defined) + goto opthelp; + infile = opt_arg(); + pw_source_defined = 1; + break; + case OPT_NOVERIFY: +#ifndef OPENSSL_NO_UI in_noverify = 1; - else if (strcmp(argv[i], "-quiet") == 0) +#endif + break; + case OPT_QUIET: quiet = 1; - else if (strcmp(argv[i], "-table") == 0) + break; + case OPT_TABLE: table = 1; - else if (strcmp(argv[i], "-reverse") == 0) + break; + case OPT_REVERSE: reverse = 1; - else if (argv[i][0] == '-') - badopt = 1; - else if (!pw_source_defined) - /* non-option arguments, use as passwords */ - { + break; + case OPT_1: + use1 = 1; + break; + case OPT_APR1: + useapr1 = 1; + break; + case OPT_CRYPT: + usecrypt = 1; + break; + case OPT_SALT: + passed_salt = 1; + salt = opt_arg(); + break; + case OPT_STDIN: + if (pw_source_defined) + goto opthelp; + in_stdin = 1; pw_source_defined = 1; - passwds = &argv[i]; - opt_done = 1; - } else - badopt = 1; + break; + } + } + argc = opt_num_rest(); + argv = opt_rest(); + + if (*argv) { + if (pw_source_defined) + goto opthelp; + pw_source_defined = 1; + passwds = argv; } - if (!usecrypt && !use1 && !useapr1) /* use default */ + if (!usecrypt && !use1 && !useapr1) { + /* use default */ usecrypt = 1; - if (usecrypt + use1 + useapr1 > 1) /* conflict */ - badopt = 1; + } + if (usecrypt + use1 + useapr1 > 1) { + /* conflict */ + goto opthelp; + } - /* reject unsupported algorithms */ # ifdef OPENSSL_NO_DES if (usecrypt) - badopt = 1; + goto opthelp; # endif # ifdef NO_MD5CRYPT_1 if (use1 || useapr1) - badopt = 1; -# endif - - if (badopt) { - BIO_printf(bio_err, "Usage: passwd [options] [passwords]\n"); - BIO_printf(bio_err, "where options are\n"); -# ifndef OPENSSL_NO_DES - BIO_printf(bio_err, - "-crypt standard Unix password algorithm (default)\n"); -# endif -# ifndef NO_MD5CRYPT_1 - BIO_printf(bio_err, - "-1 MD5-based password algorithm\n"); - BIO_printf(bio_err, - "-apr1 MD5-based password algorithm, Apache variant\n"); + goto opthelp; # endif - BIO_printf(bio_err, "-salt string use provided salt\n"); - BIO_printf(bio_err, "-in file read passwords from file\n"); - BIO_printf(bio_err, "-stdin read passwords from stdin\n"); - BIO_printf(bio_err, - "-noverify never verify when reading password from terminal\n"); - BIO_printf(bio_err, "-quiet no warnings\n"); - BIO_printf(bio_err, "-table format output as table\n"); - BIO_printf(bio_err, "-reverse switch table columns\n"); - goto err; + if (infile != NULL && in_stdin) { + BIO_printf(bio_err, "%s: Can't combine -in and -stdin\n", prog); + goto end; } - if ((infile != NULL) || in_stdin) { - in = BIO_new(BIO_s_file()); + if (infile != NULL || in_stdin) { + /* + * If in_stdin is true, we know that infile is NULL, and that + * bio_open_default() will give us back an alias for stdin. + */ + in = bio_open_default(infile, 'r', FORMAT_TEXT); if (in == NULL) - goto err; - if (infile != NULL) { - assert(in_stdin == 0); - if (BIO_read_filename(in, infile) <= 0) - goto err; - } else { - assert(in_stdin); - BIO_set_fp(in, stdin, BIO_NOCLOSE); - } + goto end; } if (usecrypt) @@ -203,37 +192,42 @@ int MAIN(int argc, char **argv) /* no passwords on the command line */ passwd_malloc_size = pw_maxlen + 2; - /* - * longer than necessary so that we can warn about truncation - */ - passwd = passwd_malloc = OPENSSL_malloc(passwd_malloc_size); - if (passwd_malloc == NULL) - goto err; + /* longer than necessary so that we can warn about truncation */ + passwd = passwd_malloc = + app_malloc(passwd_malloc_size, "password buffer"); } if ((in == NULL) && (passwds == NULL)) { - /* build a null-terminated list */ - static char *passwds_static[2] = { NULL, NULL }; - - passwds = passwds_static; - if (in == NULL) - if (EVP_read_pw_string - (passwd_malloc, passwd_malloc_size, "Password: ", - !(passed_salt || in_noverify)) != 0) - goto err; - passwds[0] = passwd_malloc; + if (1) { +#ifndef OPENSSL_NO_UI + /* build a null-terminated list */ + static char *passwds_static[2] = { NULL, NULL }; + + passwds = passwds_static; + if (in == NULL) + if (EVP_read_pw_string + (passwd_malloc, passwd_malloc_size, "Password: ", + !(passed_salt || in_noverify)) != 0) + goto end; + passwds[0] = passwd_malloc; + } else { +#endif + BIO_printf(bio_err, "password required\n"); + goto end; + } } + if (in == NULL) { assert(passwds != NULL); assert(*passwds != NULL); do { /* loop over list of passwords */ passwd = *passwds++; - if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, out, + if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, bio_out, quiet, table, reverse, pw_maxlen, usecrypt, use1, useapr1)) - goto err; + goto end; } while (*passwds != NULL); } else @@ -256,10 +250,10 @@ int MAIN(int argc, char **argv) while ((r > 0) && (!strchr(trash, '\n'))); } - if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, out, - quiet, table, reverse, pw_maxlen, usecrypt, - use1, useapr1)) - goto err; + if (!do_passwd + (passed_salt, &salt, &salt_malloc, passwd, bio_out, quiet, + table, reverse, pw_maxlen, usecrypt, use1, useapr1)) + goto end; } done = (r <= 0); } @@ -267,16 +261,12 @@ int MAIN(int argc, char **argv) } ret = 0; - err: + end: ERR_print_errors(bio_err); - if (salt_malloc) - OPENSSL_free(salt_malloc); - if (passwd_malloc) - OPENSSL_free(passwd_malloc); + OPENSSL_free(salt_malloc); + OPENSSL_free(passwd_malloc); BIO_free(in); - BIO_free_all(out); - apps_shutdown(); - OPENSSL_EXIT(ret); + return (ret); } # ifndef NO_MD5CRYPT_1 @@ -297,64 +287,93 @@ static char *md5crypt(const char *passwd, const char *magic, const char *salt) char *salt_out; int n; unsigned int i; - EVP_MD_CTX md, md2; - size_t passwd_len, salt_len; + EVP_MD_CTX *md = NULL, *md2 = NULL; + size_t passwd_len, salt_len, magic_len; passwd_len = strlen(passwd); out_buf[0] = '$'; out_buf[1] = 0; - assert(strlen(magic) <= 4); /* "1" or "apr1" */ - strncat(out_buf, magic, 4); - strncat(out_buf, "$", 1); - strncat(out_buf, salt, 8); - assert(strlen(out_buf) <= 6 + 8); /* "$apr1$..salt.." */ - salt_out = out_buf + 2 + strlen(magic); + magic_len = strlen(magic); + + if (magic_len > 4) /* assert it's "1" or "apr1" */ + return NULL; + + OPENSSL_strlcat(out_buf, magic, sizeof out_buf); + OPENSSL_strlcat(out_buf, "$", sizeof out_buf); + OPENSSL_strlcat(out_buf, salt, sizeof out_buf); + + if (strlen(out_buf) > 6 + 8) /* assert "$apr1$..salt.." */ + return NULL; + + salt_out = out_buf + 2 + magic_len; salt_len = strlen(salt_out); - assert(salt_len <= 8); - - EVP_MD_CTX_init(&md); - EVP_DigestInit_ex(&md, EVP_md5(), NULL); - EVP_DigestUpdate(&md, passwd, passwd_len); - EVP_DigestUpdate(&md, "$", 1); - EVP_DigestUpdate(&md, magic, strlen(magic)); - EVP_DigestUpdate(&md, "$", 1); - EVP_DigestUpdate(&md, salt_out, salt_len); - - EVP_MD_CTX_init(&md2); - EVP_DigestInit_ex(&md2, EVP_md5(), NULL); - EVP_DigestUpdate(&md2, passwd, passwd_len); - EVP_DigestUpdate(&md2, salt_out, salt_len); - EVP_DigestUpdate(&md2, passwd, passwd_len); - EVP_DigestFinal_ex(&md2, buf, NULL); - - for (i = passwd_len; i > sizeof buf; i -= sizeof buf) - EVP_DigestUpdate(&md, buf, sizeof buf); - EVP_DigestUpdate(&md, buf, i); + + if (salt_len > 8) + return NULL; + + md = EVP_MD_CTX_new(); + if (md == NULL + || !EVP_DigestInit_ex(md, EVP_md5(), NULL) + || !EVP_DigestUpdate(md, passwd, passwd_len) + || !EVP_DigestUpdate(md, "$", 1) + || !EVP_DigestUpdate(md, magic, magic_len) + || !EVP_DigestUpdate(md, "$", 1) + || !EVP_DigestUpdate(md, salt_out, salt_len)) + + md2 = EVP_MD_CTX_new(); + if (md2 == NULL + || !EVP_DigestInit_ex(md2, EVP_md5(), NULL) + || !EVP_DigestUpdate(md2, passwd, passwd_len) + || !EVP_DigestUpdate(md2, salt_out, salt_len) + || !EVP_DigestUpdate(md2, passwd, passwd_len) + || !EVP_DigestFinal_ex(md2, buf, NULL)) + goto err; + + for (i = passwd_len; i > sizeof buf; i -= sizeof buf) { + if (!EVP_DigestUpdate(md, buf, sizeof buf)) + goto err; + } + if (!EVP_DigestUpdate(md, buf, i)) + goto err; n = passwd_len; while (n) { - EVP_DigestUpdate(&md, (n & 1) ? "\0" : passwd, 1); + if (!EVP_DigestUpdate(md, (n & 1) ? "\0" : passwd, 1)) + goto err; n >>= 1; } - EVP_DigestFinal_ex(&md, buf, NULL); + if (!EVP_DigestFinal_ex(md, buf, NULL)) + return NULL; for (i = 0; i < 1000; i++) { - EVP_DigestInit_ex(&md2, EVP_md5(), NULL); - EVP_DigestUpdate(&md2, (i & 1) ? (unsigned const char *)passwd : buf, - (i & 1) ? passwd_len : sizeof buf); - if (i % 3) - EVP_DigestUpdate(&md2, salt_out, salt_len); - if (i % 7) - EVP_DigestUpdate(&md2, passwd, passwd_len); - EVP_DigestUpdate(&md2, (i & 1) ? buf : (unsigned const char *)passwd, - (i & 1) ? sizeof buf : passwd_len); - EVP_DigestFinal_ex(&md2, buf, NULL); + if (!EVP_DigestInit_ex(md2, EVP_md5(), NULL)) + goto err; + if (!EVP_DigestUpdate(md2, + (i & 1) ? (unsigned const char *)passwd : buf, + (i & 1) ? passwd_len : sizeof buf)) + goto err; + if (i % 3) { + if (!EVP_DigestUpdate(md2, salt_out, salt_len)) + goto err; + } + if (i % 7) { + if (!EVP_DigestUpdate(md2, passwd, passwd_len)) + goto err; + } + if (!EVP_DigestUpdate(md2, + (i & 1) ? buf : (unsigned const char *)passwd, + (i & 1) ? sizeof buf : passwd_len)) + goto err; + if (!EVP_DigestFinal_ex(md2, buf, NULL)) + goto err; } - EVP_MD_CTX_cleanup(&md2); + EVP_MD_CTX_free(md2); + EVP_MD_CTX_free(md); + md2 = NULL; + md = NULL; { /* transform buf into output string */ - unsigned char buf_perm[sizeof buf]; int dest, source; char *output; @@ -389,9 +408,13 @@ static char *md5crypt(const char *passwd, const char *magic, const char *salt) *output = 0; assert(strlen(out_buf) < sizeof(out_buf)); } - EVP_MD_CTX_cleanup(&md); return out_buf; + + err: + EVP_MD_CTX_free(md2); + EVP_MD_CTX_free(md); + return NULL; } # endif @@ -410,12 +433,10 @@ static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, # ifndef OPENSSL_NO_DES if (usecrypt) { if (*salt_malloc_p == NULL) { - *salt_p = *salt_malloc_p = OPENSSL_malloc(3); - if (*salt_malloc_p == NULL) - goto err; + *salt_p = *salt_malloc_p = app_malloc(3, "salt buffer"); } if (RAND_bytes((unsigned char *)*salt_p, 2) <= 0) - goto err; + goto end; (*salt_p)[0] = cov_2char[(*salt_p)[0] & 0x3f]; /* 6 bits */ (*salt_p)[1] = cov_2char[(*salt_p)[1] & 0x3f]; /* 6 bits */ (*salt_p)[2] = 0; @@ -431,12 +452,10 @@ static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, int i; if (*salt_malloc_p == NULL) { - *salt_p = *salt_malloc_p = OPENSSL_malloc(9); - if (*salt_malloc_p == NULL) - goto err; + *salt_p = *salt_malloc_p = app_malloc(9, "salt buffer"); } if (RAND_bytes((unsigned char *)*salt_p, 8) <= 0) - goto err; + goto end; for (i = 0; i < 8; i++) (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */ @@ -479,14 +498,14 @@ static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, BIO_printf(out, "%s\n", hash); return 1; - err: + end: return 0; } #else -int MAIN(int argc, char **argv) +int passwd_main(int argc, char **argv) { - fputs("Program not available.\n", stderr) - OPENSSL_EXIT(1); + BIO_printf(bio_err, "Program not available.\n"); + return (1); } #endif