Branch data Line data Source code
1 : : /* apps/passwd.c */
2 : :
3 : : #if defined OPENSSL_NO_MD5 || defined CHARSET_EBCDIC
4 : : # define NO_MD5CRYPT_1
5 : : #endif
6 : :
7 : : #if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1)
8 : :
9 : : #include <assert.h>
10 : : #include <string.h>
11 : :
12 : : #include "apps.h"
13 : :
14 : : #include <openssl/bio.h>
15 : : #include <openssl/err.h>
16 : : #include <openssl/evp.h>
17 : : #include <openssl/rand.h>
18 : : #ifndef OPENSSL_NO_DES
19 : : # include <openssl/des.h>
20 : : #endif
21 : : #ifndef NO_MD5CRYPT_1
22 : : # include <openssl/md5.h>
23 : : #endif
24 : :
25 : :
26 : : #undef PROG
27 : : #define PROG passwd_main
28 : :
29 : :
30 : : static unsigned const char cov_2char[64]={
31 : : /* from crypto/des/fcrypt.c */
32 : : 0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
33 : : 0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
34 : : 0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
35 : : 0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
36 : : 0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
37 : : 0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
38 : : 0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
39 : : 0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
40 : : };
41 : :
42 : : static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p,
43 : : char *passwd, BIO *out, int quiet, int table, int reverse,
44 : : size_t pw_maxlen, int usecrypt, int use1, int useapr1);
45 : :
46 : : /* -crypt - standard Unix password algorithm (default)
47 : : * -1 - MD5-based password algorithm
48 : : * -apr1 - MD5-based password algorithm, Apache variant
49 : : * -salt string - salt
50 : : * -in file - read passwords from file
51 : : * -stdin - read passwords from stdin
52 : : * -noverify - never verify when reading password from terminal
53 : : * -quiet - no warnings
54 : : * -table - format output as table
55 : : * -reverse - switch table columns
56 : : */
57 : :
58 : : int MAIN(int, char **);
59 : :
60 : 0 : int MAIN(int argc, char **argv)
61 : : {
62 : 0 : int ret = 1;
63 : 0 : char *infile = NULL;
64 : 0 : int in_stdin = 0;
65 : 0 : int in_noverify = 0;
66 : 0 : char *salt = NULL, *passwd = NULL, **passwds = NULL;
67 : 0 : char *salt_malloc = NULL, *passwd_malloc = NULL;
68 : 0 : size_t passwd_malloc_size = 0;
69 : 0 : int pw_source_defined = 0;
70 : 0 : BIO *in = NULL, *out = NULL;
71 : : int i, badopt, opt_done;
72 : 0 : int passed_salt = 0, quiet = 0, table = 0, reverse = 0;
73 : 0 : int usecrypt = 0, use1 = 0, useapr1 = 0;
74 : 0 : size_t pw_maxlen = 0;
75 : :
76 : 0 : apps_startup();
77 : :
78 [ # # ]: 0 : if (bio_err == NULL)
79 [ # # ]: 0 : if ((bio_err=BIO_new(BIO_s_file())) != NULL)
80 : 0 : BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
81 : :
82 [ # # ]: 0 : if (!load_config(bio_err, NULL))
83 : : goto err;
84 : 0 : out = BIO_new(BIO_s_file());
85 [ # # ]: 0 : if (out == NULL)
86 : : goto err;
87 : 0 : BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
88 : : #ifdef OPENSSL_SYS_VMS
89 : : {
90 : : BIO *tmpbio = BIO_new(BIO_f_linebuffer());
91 : : out = BIO_push(tmpbio, out);
92 : : }
93 : : #endif
94 : :
95 : 0 : badopt = 0, opt_done = 0;
96 : 0 : i = 0;
97 [ # # ][ # # ]: 0 : while (!badopt && !opt_done && argv[++i] != NULL)
98 : : {
99 [ # # ]: 0 : if (strcmp(argv[i], "-crypt") == 0)
100 : : usecrypt = 1;
101 [ # # ]: 0 : else if (strcmp(argv[i], "-1") == 0)
102 : : use1 = 1;
103 [ # # ]: 0 : else if (strcmp(argv[i], "-apr1") == 0)
104 : : useapr1 = 1;
105 [ # # ]: 0 : else if (strcmp(argv[i], "-salt") == 0)
106 : : {
107 [ # # ][ # # ]: 0 : if ((argv[i+1] != NULL) && (salt == NULL))
108 : : {
109 : 0 : passed_salt = 1;
110 : 0 : salt = argv[++i];
111 : : }
112 : : else
113 : : badopt = 1;
114 : : }
115 [ # # ]: 0 : else if (strcmp(argv[i], "-in") == 0)
116 : : {
117 [ # # ][ # # ]: 0 : if ((argv[i+1] != NULL) && !pw_source_defined)
118 : : {
119 : 0 : pw_source_defined = 1;
120 : 0 : infile = argv[++i];
121 : : }
122 : : else
123 : : badopt = 1;
124 : : }
125 [ # # ]: 0 : else if (strcmp(argv[i], "-stdin") == 0)
126 : : {
127 [ # # ]: 0 : if (!pw_source_defined)
128 : : {
129 : : pw_source_defined = 1;
130 : : in_stdin = 1;
131 : : }
132 : : else
133 : 0 : badopt = 1;
134 : : }
135 [ # # ]: 0 : else if (strcmp(argv[i], "-noverify") == 0)
136 : : in_noverify = 1;
137 [ # # ]: 0 : else if (strcmp(argv[i], "-quiet") == 0)
138 : : quiet = 1;
139 [ # # ]: 0 : else if (strcmp(argv[i], "-table") == 0)
140 : : table = 1;
141 [ # # ]: 0 : else if (strcmp(argv[i], "-reverse") == 0)
142 : : reverse = 1;
143 [ # # ]: 0 : else if (argv[i][0] == '-')
144 : : badopt = 1;
145 [ # # ]: 0 : else if (!pw_source_defined)
146 : : /* non-option arguments, use as passwords */
147 : : {
148 : 0 : pw_source_defined = 1;
149 : 0 : passwds = &argv[i];
150 : 0 : opt_done = 1;
151 : : }
152 : : else
153 : : badopt = 1;
154 : : }
155 : :
156 [ # # ]: 0 : if (!usecrypt && !use1 && !useapr1) /* use default */
157 : 0 : usecrypt = 1;
158 [ # # ]: 0 : if (usecrypt + use1 + useapr1 > 1) /* conflict */
159 : 0 : badopt = 1;
160 : :
161 : : /* reject unsupported algorithms */
162 : : #ifdef OPENSSL_NO_DES
163 : : if (usecrypt) badopt = 1;
164 : : #endif
165 : : #ifdef NO_MD5CRYPT_1
166 : : if (use1 || useapr1) badopt = 1;
167 : : #endif
168 : :
169 [ # # ]: 0 : if (badopt)
170 : : {
171 : 0 : BIO_printf(bio_err, "Usage: passwd [options] [passwords]\n");
172 : 0 : BIO_printf(bio_err, "where options are\n");
173 : : #ifndef OPENSSL_NO_DES
174 : 0 : BIO_printf(bio_err, "-crypt standard Unix password algorithm (default)\n");
175 : : #endif
176 : : #ifndef NO_MD5CRYPT_1
177 : 0 : BIO_printf(bio_err, "-1 MD5-based password algorithm\n");
178 : 0 : BIO_printf(bio_err, "-apr1 MD5-based password algorithm, Apache variant\n");
179 : : #endif
180 : 0 : BIO_printf(bio_err, "-salt string use provided salt\n");
181 : 0 : BIO_printf(bio_err, "-in file read passwords from file\n");
182 : 0 : BIO_printf(bio_err, "-stdin read passwords from stdin\n");
183 : 0 : BIO_printf(bio_err, "-noverify never verify when reading password from terminal\n");
184 : 0 : BIO_printf(bio_err, "-quiet no warnings\n");
185 : 0 : BIO_printf(bio_err, "-table format output as table\n");
186 : 0 : BIO_printf(bio_err, "-reverse switch table columns\n");
187 : :
188 : 0 : goto err;
189 : : }
190 : :
191 [ # # ]: 0 : if ((infile != NULL) || in_stdin)
192 : : {
193 : 0 : in = BIO_new(BIO_s_file());
194 [ # # ]: 0 : if (in == NULL)
195 : : goto err;
196 [ # # ]: 0 : if (infile != NULL)
197 : : {
198 [ # # ]: 0 : assert(in_stdin == 0);
199 [ # # ]: 0 : if (BIO_read_filename(in, infile) <= 0)
200 : : goto err;
201 : : }
202 : : else
203 : : {
204 [ # # ]: 0 : assert(in_stdin);
205 : 0 : BIO_set_fp(in, stdin, BIO_NOCLOSE);
206 : : }
207 : : }
208 : :
209 [ # # ]: 0 : if (usecrypt)
210 : : pw_maxlen = 8;
211 [ # # ]: 0 : else if (use1 || useapr1)
212 : 0 : pw_maxlen = 256; /* arbitrary limit, should be enough for most passwords */
213 : :
214 [ # # ]: 0 : if (passwds == NULL)
215 : : {
216 : : /* no passwords on the command line */
217 : :
218 : 0 : passwd_malloc_size = pw_maxlen + 2;
219 : : /* longer than necessary so that we can warn about truncation */
220 : 0 : passwd = passwd_malloc = OPENSSL_malloc(passwd_malloc_size);
221 [ # # ]: 0 : if (passwd_malloc == NULL)
222 : : goto err;
223 : : }
224 : :
225 [ # # ]: 0 : if ((in == NULL) && (passwds == NULL))
226 : : {
227 : : /* build a null-terminated list */
228 : : static char *passwds_static[2] = {NULL, NULL};
229 : :
230 : 0 : passwds = passwds_static;
231 [ # # ]: 0 : if (in == NULL)
232 [ # # ]: 0 : if (EVP_read_pw_string(passwd_malloc, passwd_malloc_size, "Password: ", !(passed_salt || in_noverify)) != 0)
233 : : goto err;
234 : 0 : passwds[0] = passwd_malloc;
235 : : }
236 : :
237 [ # # ]: 0 : if (in == NULL)
238 : : {
239 [ # # ]: 0 : assert(passwds != NULL);
240 [ # # ]: 0 : assert(*passwds != NULL);
241 : :
242 : : do /* loop over list of passwords */
243 : : {
244 : 0 : passwd = *passwds++;
245 [ # # ]: 0 : if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, out,
246 : : quiet, table, reverse, pw_maxlen, usecrypt, use1, useapr1))
247 : : goto err;
248 : : }
249 [ # # ]: 0 : while (*passwds != NULL);
250 : : }
251 : : else
252 : : /* in != NULL */
253 : : {
254 : : int done;
255 : :
256 [ # # ]: 0 : assert (passwd != NULL);
257 : : do
258 : : {
259 : 0 : int r = BIO_gets(in, passwd, pw_maxlen + 1);
260 [ # # ]: 0 : if (r > 0)
261 : : {
262 : 0 : char *c = (strchr(passwd, '\n')) ;
263 [ # # ]: 0 : if (c != NULL)
264 : 0 : *c = 0; /* truncate at newline */
265 : : else
266 : : {
267 : : /* ignore rest of line */
268 : : char trash[BUFSIZ];
269 : : do
270 : 0 : r = BIO_gets(in, trash, sizeof trash);
271 [ # # ][ # # ]: 0 : while ((r > 0) && (!strchr(trash, '\n')));
272 : : }
273 : :
274 [ # # ]: 0 : if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, out,
275 : : quiet, table, reverse, pw_maxlen, usecrypt, use1, useapr1))
276 : : goto err;
277 : : }
278 : 0 : done = (r <= 0);
279 : : }
280 [ # # ]: 0 : while (!done);
281 : : }
282 : : ret = 0;
283 : :
284 : : err:
285 : 0 : ERR_print_errors(bio_err);
286 [ # # ]: 0 : if (salt_malloc)
287 : 0 : OPENSSL_free(salt_malloc);
288 [ # # ]: 0 : if (passwd_malloc)
289 : 0 : OPENSSL_free(passwd_malloc);
290 [ # # ]: 0 : if (in)
291 : 0 : BIO_free(in);
292 [ # # ]: 0 : if (out)
293 : 0 : BIO_free_all(out);
294 : : apps_shutdown();
295 : 0 : OPENSSL_EXIT(ret);
296 : : }
297 : :
298 : :
299 : : #ifndef NO_MD5CRYPT_1
300 : : /* MD5-based password algorithm (should probably be available as a library
301 : : * function; then the static buffer would not be acceptable).
302 : : * For magic string "1", this should be compatible to the MD5-based BSD
303 : : * password algorithm.
304 : : * For 'magic' string "apr1", this is compatible to the MD5-based Apache
305 : : * password algorithm.
306 : : * (Apparently, the Apache password algorithm is identical except that the
307 : : * 'magic' string was changed -- the laziest application of the NIH principle
308 : : * I've ever encountered.)
309 : : */
310 : 0 : static char *md5crypt(const char *passwd, const char *magic, const char *salt)
311 : : {
312 : : static char out_buf[6 + 9 + 24 + 2]; /* "$apr1$..salt..$.......md5hash..........\0" */
313 : : unsigned char buf[MD5_DIGEST_LENGTH];
314 : : char *salt_out;
315 : : int n;
316 : : unsigned int i;
317 : : EVP_MD_CTX md,md2;
318 : : size_t passwd_len, salt_len;
319 : :
320 : 0 : passwd_len = strlen(passwd);
321 : 0 : out_buf[0] = '$';
322 : 0 : out_buf[1] = 0;
323 [ # # ]: 0 : assert(strlen(magic) <= 4); /* "1" or "apr1" */
324 : : strncat(out_buf, magic, 4);
325 : : strncat(out_buf, "$", 1);
326 : : strncat(out_buf, salt, 8);
327 [ # # ]: 0 : assert(strlen(out_buf) <= 6 + 8); /* "$apr1$..salt.." */
328 : 0 : salt_out = out_buf + 2 + strlen(magic);
329 : 0 : salt_len = strlen(salt_out);
330 [ # # ]: 0 : assert(salt_len <= 8);
331 : :
332 : 0 : EVP_MD_CTX_init(&md);
333 : 0 : EVP_DigestInit_ex(&md,EVP_md5(), NULL);
334 : 0 : EVP_DigestUpdate(&md, passwd, passwd_len);
335 : 0 : EVP_DigestUpdate(&md, "$", 1);
336 : 0 : EVP_DigestUpdate(&md, magic, strlen(magic));
337 : 0 : EVP_DigestUpdate(&md, "$", 1);
338 : 0 : EVP_DigestUpdate(&md, salt_out, salt_len);
339 : :
340 : 0 : EVP_MD_CTX_init(&md2);
341 : 0 : EVP_DigestInit_ex(&md2,EVP_md5(), NULL);
342 : 0 : EVP_DigestUpdate(&md2, passwd, passwd_len);
343 : 0 : EVP_DigestUpdate(&md2, salt_out, salt_len);
344 : 0 : EVP_DigestUpdate(&md2, passwd, passwd_len);
345 : 0 : EVP_DigestFinal_ex(&md2, buf, NULL);
346 : :
347 [ # # ]: 0 : for (i = passwd_len; i > sizeof buf; i -= sizeof buf)
348 : 0 : EVP_DigestUpdate(&md, buf, sizeof buf);
349 : 0 : EVP_DigestUpdate(&md, buf, i);
350 : :
351 : 0 : n = passwd_len;
352 [ # # ]: 0 : while (n)
353 : : {
354 [ # # ]: 0 : EVP_DigestUpdate(&md, (n & 1) ? "\0" : passwd, 1);
355 : 0 : n >>= 1;
356 : : }
357 : 0 : EVP_DigestFinal_ex(&md, buf, NULL);
358 : :
359 [ # # ]: 0 : for (i = 0; i < 1000; i++)
360 : : {
361 : 0 : EVP_DigestInit_ex(&md2,EVP_md5(), NULL);
362 [ # # ][ # # ]: 0 : EVP_DigestUpdate(&md2, (i & 1) ? (unsigned const char *) passwd : buf,
363 : 0 : (i & 1) ? passwd_len : sizeof buf);
364 [ # # ]: 0 : if (i % 3)
365 : 0 : EVP_DigestUpdate(&md2, salt_out, salt_len);
366 [ # # ]: 0 : if (i % 7)
367 : 0 : EVP_DigestUpdate(&md2, passwd, passwd_len);
368 [ # # ][ # # ]: 0 : EVP_DigestUpdate(&md2, (i & 1) ? buf : (unsigned const char *) passwd,
369 : : (i & 1) ? sizeof buf : passwd_len);
370 : 0 : EVP_DigestFinal_ex(&md2, buf, NULL);
371 : : }
372 : 0 : EVP_MD_CTX_cleanup(&md2);
373 : :
374 : : {
375 : : /* transform buf into output string */
376 : :
377 : : unsigned char buf_perm[sizeof buf];
378 : : int dest, source;
379 : : char *output;
380 : :
381 : : /* silly output permutation */
382 [ # # ]: 0 : for (dest = 0, source = 0; dest < 14; dest++, source = (source + 6) % 17)
383 : 0 : buf_perm[dest] = buf[source];
384 : 0 : buf_perm[14] = buf[5];
385 : 0 : buf_perm[15] = buf[11];
386 : : #ifndef PEDANTIC /* Unfortunately, this generates a "no effect" warning */
387 : : assert(16 == sizeof buf_perm);
388 : : #endif
389 : :
390 : 0 : output = salt_out + salt_len;
391 [ # # ]: 0 : assert(output == out_buf + strlen(out_buf));
392 : :
393 : 0 : *output++ = '$';
394 : :
395 [ # # ]: 0 : for (i = 0; i < 15; i += 3)
396 : : {
397 : 0 : *output++ = cov_2char[buf_perm[i+2] & 0x3f];
398 : 0 : *output++ = cov_2char[((buf_perm[i+1] & 0xf) << 2) |
399 : 0 : (buf_perm[i+2] >> 6)];
400 : 0 : *output++ = cov_2char[((buf_perm[i] & 3) << 4) |
401 : 0 : (buf_perm[i+1] >> 4)];
402 : 0 : *output++ = cov_2char[buf_perm[i] >> 2];
403 : : }
404 [ # # ]: 0 : assert(i == 15);
405 : 0 : *output++ = cov_2char[buf_perm[i] & 0x3f];
406 : 0 : *output++ = cov_2char[buf_perm[i] >> 6];
407 : 0 : *output = 0;
408 [ # # ]: 0 : assert(strlen(out_buf) < sizeof(out_buf));
409 : : }
410 : 0 : EVP_MD_CTX_cleanup(&md);
411 : :
412 : 0 : return out_buf;
413 : : }
414 : : #endif
415 : :
416 : :
417 : 0 : static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p,
418 : : char *passwd, BIO *out, int quiet, int table, int reverse,
419 : : size_t pw_maxlen, int usecrypt, int use1, int useapr1)
420 : : {
421 : 0 : char *hash = NULL;
422 : :
423 [ # # ]: 0 : assert(salt_p != NULL);
424 [ # # ]: 0 : assert(salt_malloc_p != NULL);
425 : :
426 : : /* first make sure we have a salt */
427 [ # # ]: 0 : if (!passed_salt)
428 : : {
429 : : #ifndef OPENSSL_NO_DES
430 [ # # ]: 0 : if (usecrypt)
431 : : {
432 [ # # ]: 0 : if (*salt_malloc_p == NULL)
433 : : {
434 : 0 : *salt_p = *salt_malloc_p = OPENSSL_malloc(3);
435 [ # # ]: 0 : if (*salt_malloc_p == NULL)
436 : : goto err;
437 : : }
438 [ # # ]: 0 : if (RAND_pseudo_bytes((unsigned char *)*salt_p, 2) < 0)
439 : : goto err;
440 : 0 : (*salt_p)[0] = cov_2char[(*salt_p)[0] & 0x3f]; /* 6 bits */
441 : 0 : (*salt_p)[1] = cov_2char[(*salt_p)[1] & 0x3f]; /* 6 bits */
442 : 0 : (*salt_p)[2] = 0;
443 : : #ifdef CHARSET_EBCDIC
444 : : ascii2ebcdic(*salt_p, *salt_p, 2); /* des_crypt will convert
445 : : * back to ASCII */
446 : : #endif
447 : : }
448 : : #endif /* !OPENSSL_NO_DES */
449 : :
450 : : #ifndef NO_MD5CRYPT_1
451 [ # # ]: 0 : if (use1 || useapr1)
452 : : {
453 : : int i;
454 : :
455 [ # # ]: 0 : if (*salt_malloc_p == NULL)
456 : : {
457 : 0 : *salt_p = *salt_malloc_p = OPENSSL_malloc(9);
458 [ # # ]: 0 : if (*salt_malloc_p == NULL)
459 : : goto err;
460 : : }
461 [ # # ]: 0 : if (RAND_pseudo_bytes((unsigned char *)*salt_p, 8) < 0)
462 : : goto err;
463 : :
464 [ # # ]: 0 : for (i = 0; i < 8; i++)
465 : 0 : (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */
466 : 0 : (*salt_p)[8] = 0;
467 : : }
468 : : #endif /* !NO_MD5CRYPT_1 */
469 : : }
470 : :
471 [ # # ]: 0 : assert(*salt_p != NULL);
472 : :
473 : : /* truncate password if necessary */
474 [ # # ]: 0 : if ((strlen(passwd) > pw_maxlen))
475 : : {
476 [ # # ]: 0 : if (!quiet)
477 : : /* XXX: really we should know how to print a size_t, not cast it */
478 : 0 : BIO_printf(bio_err, "Warning: truncating password to %u characters\n", (unsigned)pw_maxlen);
479 : 0 : passwd[pw_maxlen] = 0;
480 : : }
481 [ # # ]: 0 : assert(strlen(passwd) <= pw_maxlen);
482 : :
483 : : /* now compute password hash */
484 : : #ifndef OPENSSL_NO_DES
485 [ # # ]: 0 : if (usecrypt)
486 : 0 : hash = DES_crypt(passwd, *salt_p);
487 : : #endif
488 : : #ifndef NO_MD5CRYPT_1
489 [ # # ]: 0 : if (use1 || useapr1)
490 [ # # ]: 0 : hash = md5crypt(passwd, (use1 ? "1" : "apr1"), *salt_p);
491 : : #endif
492 [ # # ]: 0 : assert(hash != NULL);
493 : :
494 [ # # ]: 0 : if (table && !reverse)
495 : 0 : BIO_printf(out, "%s\t%s\n", passwd, hash);
496 [ # # ]: 0 : else if (table && reverse)
497 : 0 : BIO_printf(out, "%s\t%s\n", hash, passwd);
498 : : else
499 : 0 : BIO_printf(out, "%s\n", hash);
500 : : return 1;
501 : :
502 : : err:
503 : : return 0;
504 : : }
505 : : #else
506 : :
507 : : int MAIN(int argc, char **argv)
508 : : {
509 : : fputs("Program not available.\n", stderr)
510 : : OPENSSL_EXIT(1);
511 : : }
512 : : #endif
|