1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/ssl/tsrc/topenssl/src/passwd.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,515 @@
1.4 +/* apps/passwd.c */
1.5 +
1.6 +#if defined OPENSSL_NO_MD5 || defined CHARSET_EBCDIC
1.7 +# define NO_MD5CRYPT_1
1.8 +#endif
1.9 +
1.10 +#if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1)
1.11 +
1.12 +#include <assert.h>
1.13 +#include <string.h>
1.14 +
1.15 +#include "apps.h"
1.16 +
1.17 +#include <openssl/bio.h>
1.18 +#include <openssl/err.h>
1.19 +#include <openssl/evp.h>
1.20 +#include <openssl/rand.h>
1.21 +#ifndef OPENSSL_NO_DES
1.22 +# include <openssl/des.h>
1.23 +#endif
1.24 +#ifndef NO_MD5CRYPT_1
1.25 +# include <openssl/md5.h>
1.26 +#endif
1.27 +
1.28 +
1.29 +#undef PROG
1.30 +#define PROG passwd_main
1.31 +
1.32 +
1.33 +static unsigned const char cov_2char[64]={
1.34 + /* from crypto/des/fcrypt.c */
1.35 + 0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
1.36 + 0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
1.37 + 0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
1.38 + 0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
1.39 + 0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
1.40 + 0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
1.41 + 0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
1.42 + 0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
1.43 +};
1.44 +
1.45 +static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p,
1.46 + char *passwd, BIO *out, int quiet, int table, int reverse,
1.47 + size_t pw_maxlen, int usecrypt, int use1, int useapr1);
1.48 +
1.49 +/* -crypt - standard Unix password algorithm (default)
1.50 + * -1 - MD5-based password algorithm
1.51 + * -apr1 - MD5-based password algorithm, Apache variant
1.52 + * -salt string - salt
1.53 + * -in file - read passwords from file
1.54 + * -stdin - read passwords from stdin
1.55 + * -noverify - never verify when reading password from terminal
1.56 + * -quiet - no warnings
1.57 + * -table - format output as table
1.58 + * -reverse - switch table columns
1.59 + */
1.60 +
1.61 +
1.62 +int MAIN(int, char **);
1.63 +
1.64 +int MAIN(int argc, char **argv)
1.65 + {
1.66 + int ret = 1;
1.67 + char *infile = NULL;
1.68 + int in_stdin = 0;
1.69 + int in_noverify = 0;
1.70 + char *salt = NULL, *passwd = NULL, **passwds = NULL;
1.71 + char *salt_malloc = NULL, *passwd_malloc = NULL;
1.72 + size_t passwd_malloc_size = 0;
1.73 + int pw_source_defined = 0;
1.74 + BIO *in = NULL, *out = NULL;
1.75 + int i, badopt, opt_done;
1.76 + int passed_salt = 0, quiet = 0, table = 0, reverse = 0;
1.77 + int usecrypt = 0, use1 = 0, useapr1 = 0;
1.78 + size_t pw_maxlen = 0;
1.79 +
1.80 + apps_startup();
1.81 +
1.82 + if (bio_err == NULL)
1.83 + if ((bio_err=BIO_new(BIO_s_file())) != NULL)
1.84 + BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
1.85 +
1.86 +
1.87 + if (!load_config(bio_err, NULL))
1.88 + goto err;
1.89 + out = BIO_new(BIO_s_file());
1.90 + if (out == NULL)
1.91 + goto err;
1.92 + BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
1.93 +#ifdef OPENSSL_SYS_VMS
1.94 + {
1.95 + BIO *tmpbio = BIO_new(BIO_f_linebuffer());
1.96 + out = BIO_push(tmpbio, out);
1.97 + }
1.98 +#endif
1.99 +
1.100 + badopt = 0, opt_done = 0;
1.101 + i = 0;
1.102 + while (!badopt && !opt_done && argv[++i] != NULL)
1.103 + {
1.104 + if (strcmp(argv[i], "-crypt") == 0)
1.105 + usecrypt = 1;
1.106 + else if (strcmp(argv[i], "-1") == 0)
1.107 + use1 = 1;
1.108 + else if (strcmp(argv[i], "-apr1") == 0)
1.109 + useapr1 = 1;
1.110 + else if (strcmp(argv[i], "-salt") == 0)
1.111 + {
1.112 + if ((argv[i+1] != NULL) && (salt == NULL))
1.113 + {
1.114 + passed_salt = 1;
1.115 + salt = argv[++i];
1.116 + }
1.117 + else
1.118 + badopt = 1;
1.119 + }
1.120 + else if (strcmp(argv[i], "-in") == 0)
1.121 + {
1.122 + if ((argv[i+1] != NULL) && !pw_source_defined)
1.123 + {
1.124 + pw_source_defined = 1;
1.125 + infile = argv[++i];
1.126 + }
1.127 + else
1.128 + badopt = 1;
1.129 + }
1.130 + else if (strcmp(argv[i], "-stdin") == 0)
1.131 + {
1.132 + if (!pw_source_defined)
1.133 + {
1.134 + pw_source_defined = 1;
1.135 + in_stdin = 1;
1.136 + }
1.137 + else
1.138 + badopt = 1;
1.139 + }
1.140 + else if (strcmp(argv[i], "-noverify") == 0)
1.141 + in_noverify = 1;
1.142 + else if (strcmp(argv[i], "-quiet") == 0)
1.143 + quiet = 1;
1.144 + else if (strcmp(argv[i], "-table") == 0)
1.145 + table = 1;
1.146 + else if (strcmp(argv[i], "-reverse") == 0)
1.147 + reverse = 1;
1.148 + else if (argv[i][0] == '-')
1.149 + badopt = 1;
1.150 + else if (!pw_source_defined)
1.151 + /* non-option arguments, use as passwords */
1.152 + {
1.153 + pw_source_defined = 1;
1.154 + passwds = &argv[i];
1.155 + opt_done = 1;
1.156 + }
1.157 + else
1.158 + badopt = 1;
1.159 + }
1.160 +
1.161 + if (!usecrypt && !use1 && !useapr1) /* use default */
1.162 + usecrypt = 1;
1.163 + if (usecrypt + use1 + useapr1 > 1) /* conflict */
1.164 + badopt = 1;
1.165 +
1.166 + /* reject unsupported algorithms */
1.167 +#ifdef OPENSSL_NO_DES
1.168 + if (usecrypt) badopt = 1;
1.169 +#endif
1.170 +#ifdef NO_MD5CRYPT_1
1.171 + if (use1 || useapr1) badopt = 1;
1.172 +#endif
1.173 +
1.174 + if (badopt)
1.175 + {
1.176 + BIO_printf(bio_err, "Usage: passwd [options] [passwords]\n");
1.177 + BIO_printf(bio_err, "where options are\n");
1.178 +#ifndef OPENSSL_NO_DES
1.179 + BIO_printf(bio_err, "-crypt standard Unix password algorithm (default)\n");
1.180 +#endif
1.181 +#ifndef NO_MD5CRYPT_1
1.182 + BIO_printf(bio_err, "-1 MD5-based password algorithm\n");
1.183 + BIO_printf(bio_err, "-apr1 MD5-based password algorithm, Apache variant\n");
1.184 +#endif
1.185 + BIO_printf(bio_err, "-salt string use provided salt\n");
1.186 + BIO_printf(bio_err, "-in file read passwords from file\n");
1.187 + BIO_printf(bio_err, "-stdin read passwords from stdin\n");
1.188 + BIO_printf(bio_err, "-noverify never verify when reading password from terminal\n");
1.189 + BIO_printf(bio_err, "-quiet no warnings\n");
1.190 + BIO_printf(bio_err, "-table format output as table\n");
1.191 + BIO_printf(bio_err, "-reverse switch table columns\n");
1.192 +
1.193 + goto err;
1.194 + }
1.195 +
1.196 + if ((infile != NULL) || in_stdin)
1.197 + {
1.198 + in = BIO_new(BIO_s_file());
1.199 + if (in == NULL)
1.200 + goto err;
1.201 + if (infile != NULL)
1.202 + {
1.203 + assert(in_stdin == 0);
1.204 + if (BIO_read_filename(in, infile) <= 0)
1.205 + goto err;
1.206 + }
1.207 + else
1.208 + {
1.209 + assert(in_stdin);
1.210 + BIO_set_fp(in, stdin, BIO_NOCLOSE);
1.211 +
1.212 + }
1.213 + }
1.214 +
1.215 + if (usecrypt)
1.216 + pw_maxlen = 8;
1.217 + else if (use1 || useapr1)
1.218 + pw_maxlen = 256; /* arbitrary limit, should be enough for most passwords */
1.219 +
1.220 + if (passwds == NULL)
1.221 + {
1.222 + /* no passwords on the command line */
1.223 +
1.224 + passwd_malloc_size = pw_maxlen + 2;
1.225 + /* longer than necessary so that we can warn about truncation */
1.226 + passwd = passwd_malloc = OPENSSL_malloc(passwd_malloc_size);
1.227 + if (passwd_malloc == NULL)
1.228 + goto err;
1.229 + }
1.230 +
1.231 + if ((in == NULL) && (passwds == NULL))
1.232 + {
1.233 + /* build a null-terminated list */
1.234 + static char *passwds_static[2] = {NULL, NULL};
1.235 +
1.236 + passwds = passwds_static;
1.237 + if (in == NULL)
1.238 + if (EVP_read_pw_string(passwd_malloc, passwd_malloc_size, "Password: ", !(passed_salt || in_noverify)) != 0)
1.239 + goto err;
1.240 + passwds[0] = passwd_malloc;
1.241 + }
1.242 +
1.243 + if (in == NULL)
1.244 + {
1.245 + assert(passwds != NULL);
1.246 + assert(*passwds != NULL);
1.247 +
1.248 + do /* loop over list of passwords */
1.249 + {
1.250 + passwd = *passwds++;
1.251 + if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, out,
1.252 + quiet, table, reverse, pw_maxlen, usecrypt, use1, useapr1))
1.253 + goto err;
1.254 + }
1.255 + while (*passwds != NULL);
1.256 + }
1.257 + else
1.258 + /* in != NULL */
1.259 + {
1.260 + int done;
1.261 +
1.262 + assert (passwd != NULL);
1.263 + do
1.264 + {
1.265 + int r = BIO_gets(in, passwd, pw_maxlen + 1);
1.266 + if (r > 0)
1.267 + {
1.268 + char *c = (strchr(passwd, '\n')) ;
1.269 + if (c != NULL)
1.270 + *c = 0; /* truncate at newline */
1.271 + else
1.272 + {
1.273 + /* ignore rest of line */
1.274 + char trash[BUFSIZ];
1.275 + do
1.276 + r = BIO_gets(in, trash, sizeof trash);
1.277 + while ((r > 0) && (!strchr(trash, '\n')));
1.278 + }
1.279 +
1.280 + if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, out,
1.281 + quiet, table, reverse, pw_maxlen, usecrypt, use1, useapr1))
1.282 + goto err;
1.283 + }
1.284 + done = (r <= 0);
1.285 + }
1.286 + while (!done);
1.287 + }
1.288 + ret = 0;
1.289 +
1.290 +err:
1.291 + ERR_print_errors(bio_err);
1.292 + if (salt_malloc)
1.293 + OPENSSL_free(salt_malloc);
1.294 + if (passwd_malloc)
1.295 + OPENSSL_free(passwd_malloc);
1.296 + if (in)
1.297 + BIO_free(in);
1.298 + if (out)
1.299 + BIO_free_all(out);
1.300 + apps_shutdown();
1.301 + OPENSSL_EXIT(ret);
1.302 + }
1.303 +
1.304 +
1.305 +#ifndef NO_MD5CRYPT_1
1.306 +/* MD5-based password algorithm (should probably be available as a library
1.307 + * function; then the static buffer would not be acceptable).
1.308 + * For magic string "1", this should be compatible to the MD5-based BSD
1.309 + * password algorithm.
1.310 + * For 'magic' string "apr1", this is compatible to the MD5-based Apache
1.311 + * password algorithm.
1.312 + * (Apparently, the Apache password algorithm is identical except that the
1.313 + * 'magic' string was changed -- the laziest application of the NIH principle
1.314 + * I've ever encountered.)
1.315 + */
1.316 +static char *md5crypt(const char *passwd, const char *magic, const char *salt)
1.317 + {
1.318 + static char out_buf[6 + 9 + 24 + 2]; /* "$apr1$..salt..$.......md5hash..........\0" */
1.319 + unsigned char buf[MD5_DIGEST_LENGTH];
1.320 + char *salt_out;
1.321 + int n;
1.322 + unsigned int i;
1.323 + EVP_MD_CTX md,md2;
1.324 + size_t passwd_len, salt_len;
1.325 +
1.326 + passwd_len = strlen(passwd);
1.327 + out_buf[0] = '$';
1.328 + out_buf[1] = 0;
1.329 + assert(strlen(magic) <= 4); /* "1" or "apr1" */
1.330 + strncat(out_buf, magic, 4);
1.331 + strncat(out_buf, "$", 1);
1.332 + strncat(out_buf, salt, 8);
1.333 + assert(strlen(out_buf) <= 6 + 8); /* "$apr1$..salt.." */
1.334 + salt_out = out_buf + 2 + strlen(magic);
1.335 + salt_len = strlen(salt_out);
1.336 + assert(salt_len <= 8);
1.337 +
1.338 + EVP_MD_CTX_init(&md);
1.339 + EVP_DigestInit_ex(&md,EVP_md5(), NULL);
1.340 + EVP_DigestUpdate(&md, passwd, passwd_len);
1.341 + EVP_DigestUpdate(&md, "$", 1);
1.342 + EVP_DigestUpdate(&md, magic, strlen(magic));
1.343 + EVP_DigestUpdate(&md, "$", 1);
1.344 + EVP_DigestUpdate(&md, salt_out, salt_len);
1.345 +
1.346 + EVP_MD_CTX_init(&md2);
1.347 + EVP_DigestInit_ex(&md2,EVP_md5(), NULL);
1.348 + EVP_DigestUpdate(&md2, passwd, passwd_len);
1.349 + EVP_DigestUpdate(&md2, salt_out, salt_len);
1.350 + EVP_DigestUpdate(&md2, passwd, passwd_len);
1.351 + EVP_DigestFinal_ex(&md2, buf, NULL);
1.352 +
1.353 + for (i = passwd_len; i > sizeof buf; i -= sizeof buf)
1.354 + EVP_DigestUpdate(&md, buf, sizeof buf);
1.355 + EVP_DigestUpdate(&md, buf, i);
1.356 +
1.357 + n = passwd_len;
1.358 + while (n)
1.359 + {
1.360 + EVP_DigestUpdate(&md, (n & 1) ? "\0" : passwd, 1);
1.361 + n >>= 1;
1.362 + }
1.363 + EVP_DigestFinal_ex(&md, buf, NULL);
1.364 +
1.365 + for (i = 0; i < 1000; i++)
1.366 + {
1.367 + EVP_DigestInit_ex(&md2,EVP_md5(), NULL);
1.368 + EVP_DigestUpdate(&md2, (i & 1) ? (unsigned const char *) passwd : buf,
1.369 + (i & 1) ? passwd_len : sizeof buf);
1.370 + if (i % 3)
1.371 + EVP_DigestUpdate(&md2, salt_out, salt_len);
1.372 + if (i % 7)
1.373 + EVP_DigestUpdate(&md2, passwd, passwd_len);
1.374 + EVP_DigestUpdate(&md2, (i & 1) ? buf : (unsigned const char *) passwd,
1.375 + (i & 1) ? sizeof buf : passwd_len);
1.376 + EVP_DigestFinal_ex(&md2, buf, NULL);
1.377 + }
1.378 + EVP_MD_CTX_cleanup(&md2);
1.379 +
1.380 + {
1.381 + /* transform buf into output string */
1.382 +
1.383 + unsigned char buf_perm[sizeof buf];
1.384 + int dest, source;
1.385 + char *output;
1.386 +
1.387 + /* silly output permutation */
1.388 + for (dest = 0, source = 0; dest < 14; dest++, source = (source + 6) % 17)
1.389 + buf_perm[dest] = buf[source];
1.390 + buf_perm[14] = buf[5];
1.391 + buf_perm[15] = buf[11];
1.392 +#ifndef PEDANTIC /* Unfortunately, this generates a "no effect" warning */
1.393 + assert(16 == sizeof buf_perm);
1.394 +#endif
1.395 +
1.396 + output = salt_out + salt_len;
1.397 + assert(output == out_buf + strlen(out_buf));
1.398 +
1.399 + *output++ = '$';
1.400 +
1.401 + for (i = 0; i < 15; i += 3)
1.402 + {
1.403 + *output++ = cov_2char[buf_perm[i+2] & 0x3f];
1.404 + *output++ = cov_2char[((buf_perm[i+1] & 0xf) << 2) |
1.405 + (buf_perm[i+2] >> 6)];
1.406 + *output++ = cov_2char[((buf_perm[i] & 3) << 4) |
1.407 + (buf_perm[i+1] >> 4)];
1.408 + *output++ = cov_2char[buf_perm[i] >> 2];
1.409 + }
1.410 + assert(i == 15);
1.411 + *output++ = cov_2char[buf_perm[i] & 0x3f];
1.412 + *output++ = cov_2char[buf_perm[i] >> 6];
1.413 + *output = 0;
1.414 + assert(strlen(out_buf) < sizeof(out_buf));
1.415 + }
1.416 + EVP_MD_CTX_cleanup(&md);
1.417 +
1.418 + return out_buf;
1.419 + }
1.420 +#endif
1.421 +
1.422 +
1.423 +static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p,
1.424 + char *passwd, BIO *out, int quiet, int table, int reverse,
1.425 + size_t pw_maxlen, int usecrypt, int use1, int useapr1)
1.426 + {
1.427 + char *hash = NULL;
1.428 +
1.429 + assert(salt_p != NULL);
1.430 + assert(salt_malloc_p != NULL);
1.431 +
1.432 + /* first make sure we have a salt */
1.433 + if (!passed_salt)
1.434 + {
1.435 +#ifndef OPENSSL_NO_DES
1.436 + if (usecrypt)
1.437 + {
1.438 + if (*salt_malloc_p == NULL)
1.439 + {
1.440 + *salt_p = *salt_malloc_p = OPENSSL_malloc(3);
1.441 + if (*salt_malloc_p == NULL)
1.442 + goto err;
1.443 + }
1.444 + if (RAND_pseudo_bytes((unsigned char *)*salt_p, 2) < 0)
1.445 + goto err;
1.446 + (*salt_p)[0] = cov_2char[(*salt_p)[0] & 0x3f]; /* 6 bits */
1.447 + (*salt_p)[1] = cov_2char[(*salt_p)[1] & 0x3f]; /* 6 bits */
1.448 + (*salt_p)[2] = 0;
1.449 +#ifdef CHARSET_EBCDIC
1.450 + ascii2ebcdic(*salt_p, *salt_p, 2); /* des_crypt will convert
1.451 + * back to ASCII */
1.452 +#endif
1.453 + }
1.454 +#endif /* !OPENSSL_NO_DES */
1.455 +
1.456 +#ifndef NO_MD5CRYPT_1
1.457 + if (use1 || useapr1)
1.458 + {
1.459 + int i;
1.460 +
1.461 + if (*salt_malloc_p == NULL)
1.462 + {
1.463 + *salt_p = *salt_malloc_p = OPENSSL_malloc(9);
1.464 + if (*salt_malloc_p == NULL)
1.465 + goto err;
1.466 + }
1.467 + if (RAND_pseudo_bytes((unsigned char *)*salt_p, 8) < 0)
1.468 + goto err;
1.469 +
1.470 + for (i = 0; i < 8; i++)
1.471 + (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */
1.472 + (*salt_p)[8] = 0;
1.473 + }
1.474 +#endif /* !NO_MD5CRYPT_1 */
1.475 + }
1.476 +
1.477 + assert(*salt_p != NULL);
1.478 +
1.479 + /* truncate password if necessary */
1.480 + if ((strlen(passwd) > pw_maxlen))
1.481 + {
1.482 + if (!quiet)
1.483 + /* XXX: really we should know how to print a size_t, not cast it */
1.484 + BIO_printf(bio_err, "Warning: truncating password to %u characters\n", (unsigned)pw_maxlen);
1.485 + passwd[pw_maxlen] = 0;
1.486 + }
1.487 + assert(strlen(passwd) <= pw_maxlen);
1.488 +
1.489 + /* now compute password hash */
1.490 +#ifndef OPENSSL_NO_DES
1.491 + if (usecrypt)
1.492 + hash = DES_crypt(passwd, *salt_p);
1.493 +#endif
1.494 +#ifndef NO_MD5CRYPT_1
1.495 + if (use1 || useapr1)
1.496 + hash = md5crypt(passwd, (use1 ? "1" : "apr1"), *salt_p);
1.497 +#endif
1.498 + assert(hash != NULL);
1.499 +
1.500 + if (table && !reverse)
1.501 + BIO_printf(out, "%s\t%s\n", passwd, hash);
1.502 + else if (table && reverse)
1.503 + BIO_printf(out, "%s\t%s\n", hash, passwd);
1.504 + else
1.505 + BIO_printf(out, "%s\n", hash);
1.506 + return 1;
1.507 +
1.508 +err:
1.509 + return 0;
1.510 + }
1.511 +#else
1.512 +
1.513 +int MAIN(int argc, char **argv)
1.514 + {
1.515 + fputs("Program not available.\n", stderr)
1.516 + OPENSSL_EXIT(1);
1.517 + }
1.518 +#endif