]>
Commit | Line | Data |
---|---|---|
7e1b7485 RS |
1 | /* ==================================================================== |
2 | * Copyright (c) 2000-2015 The OpenSSL Project. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in | |
13 | * the documentation and/or other materials provided with the | |
14 | * distribution. | |
15 | * | |
16 | * 3. All advertising materials mentioning features or use of this | |
17 | * software must display the following acknowledgment: | |
18 | * "This product includes software developed by the OpenSSL Project | |
19 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
20 | * | |
21 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
22 | * endorse or promote products derived from this software without | |
23 | * prior written permission. For written permission, please contact | |
24 | * licensing@OpenSSL.org. | |
25 | * | |
26 | * 5. Products derived from this software may not be called "OpenSSL" | |
27 | * nor may "OpenSSL" appear in their names without prior written | |
28 | * permission of the OpenSSL Project. | |
29 | * | |
30 | * 6. Redistributions of any form whatsoever must retain the following | |
31 | * acknowledgment: | |
32 | * "This product includes software developed by the OpenSSL Project | |
33 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
34 | * | |
35 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
36 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
37 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
38 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
39 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
40 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
41 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
42 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
44 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
45 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
46 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
47 | * ==================================================================== | |
48 | */ | |
bb325c7d | 49 | |
cf1b7d96 | 50 | #if defined OPENSSL_NO_MD5 || defined CHARSET_EBCDIC |
1f4643a2 | 51 | # define NO_MD5CRYPT_1 |
3ebf0be1 BM |
52 | #endif |
53 | ||
cf1b7d96 | 54 | #if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1) |
bb325c7d | 55 | |
0f113f3e MC |
56 | # include <assert.h> |
57 | # include <string.h> | |
58 | ||
59 | # include "apps.h" | |
60 | ||
61 | # include <openssl/bio.h> | |
62 | # include <openssl/err.h> | |
63 | # include <openssl/evp.h> | |
64 | # include <openssl/rand.h> | |
65 | # ifndef OPENSSL_NO_DES | |
66 | # include <openssl/des.h> | |
67 | # endif | |
68 | # ifndef NO_MD5CRYPT_1 | |
69 | # include <openssl/md5.h> | |
70 | # endif | |
71 | ||
0f113f3e MC |
72 | static unsigned const char cov_2char[64] = { |
73 | /* from crypto/des/fcrypt.c */ | |
74 | 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, | |
75 | 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, | |
76 | 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, | |
77 | 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, | |
78 | 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, | |
79 | 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, | |
80 | 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, | |
81 | 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A | |
bb325c7d BM |
82 | }; |
83 | ||
e6e7b5f3 | 84 | static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, |
0f113f3e MC |
85 | char *passwd, BIO *out, int quiet, int table, |
86 | int reverse, size_t pw_maxlen, int usecrypt, int use1, | |
87 | int useapr1); | |
e6e7b5f3 | 88 | |
7e1b7485 RS |
89 | typedef enum OPTION_choice { |
90 | OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, | |
91 | OPT_IN, | |
92 | OPT_NOVERIFY, OPT_QUIET, OPT_TABLE, OPT_REVERSE, OPT_APR1, | |
93 | OPT_1, OPT_CRYPT, OPT_SALT, OPT_STDIN | |
94 | } OPTION_CHOICE; | |
95 | ||
96 | OPTIONS passwd_options[] = { | |
97 | {"help", OPT_HELP, '-', "Display this summary"}, | |
98 | {"in", OPT_IN, '<', "Pead passwords from file"}, | |
99 | {"noverify", OPT_NOVERIFY, '-', | |
100 | "Never verify when reading password from terminal"}, | |
101 | {"quiet", OPT_QUIET, '-', "No warnings"}, | |
102 | {"table", OPT_TABLE, '-', "Format output as table"}, | |
103 | {"reverse", OPT_REVERSE, '-', "Switch table columns"}, | |
104 | # ifndef NO_MD5CRYPT_1 | |
105 | {"apr1", OPT_APR1, '-', "MD5-based password algorithm, Apache variant"}, | |
106 | {"1", OPT_1, '-', "MD5-based password algorithm"}, | |
107 | # endif | |
108 | # ifndef OPENSSL_NO_DES | |
109 | {"crypt", OPT_CRYPT, '-', "Standard Unix password algorithm (default)"}, | |
110 | # endif | |
111 | {"salt", OPT_SALT, 's', "Use provided salt"}, | |
112 | {"stdin", OPT_STDIN, '-', "Read passwords from stdin"}, | |
113 | {NULL} | |
114 | }; | |
07fb39c3 | 115 | |
7e1b7485 | 116 | int passwd_main(int argc, char **argv) |
0f113f3e | 117 | { |
7e1b7485 RS |
118 | BIO *in = NULL; |
119 | char *infile = NULL, *salt = NULL, *passwd = NULL, **passwds = NULL; | |
120 | char *salt_malloc = NULL, *passwd_malloc = NULL, *prog; | |
121 | OPTION_CHOICE o; | |
122 | int in_stdin = 0, in_noverify = 0, pw_source_defined = 0; | |
0f113f3e | 123 | int passed_salt = 0, quiet = 0, table = 0, reverse = 0; |
7e1b7485 RS |
124 | int ret = 1, usecrypt = 0, use1 = 0, useapr1 = 0; |
125 | size_t passwd_malloc_size = 0, pw_maxlen = 256; | |
126 | ||
127 | prog = opt_init(argc, argv, passwd_options); | |
128 | while ((o = opt_next()) != OPT_EOF) { | |
129 | switch (o) { | |
130 | case OPT_EOF: | |
131 | case OPT_ERR: | |
132 | opthelp: | |
133 | BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); | |
134 | goto end; | |
135 | case OPT_HELP: | |
136 | opt_help(passwd_options); | |
137 | ret = 0; | |
138 | goto end; | |
139 | case OPT_IN: | |
140 | if (pw_source_defined) | |
141 | goto opthelp; | |
142 | infile = opt_arg(); | |
143 | pw_source_defined = 1; | |
144 | break; | |
145 | case OPT_NOVERIFY: | |
0f113f3e | 146 | in_noverify = 1; |
7e1b7485 RS |
147 | break; |
148 | case OPT_QUIET: | |
0f113f3e | 149 | quiet = 1; |
7e1b7485 RS |
150 | break; |
151 | case OPT_TABLE: | |
0f113f3e | 152 | table = 1; |
7e1b7485 RS |
153 | break; |
154 | case OPT_REVERSE: | |
0f113f3e | 155 | reverse = 1; |
7e1b7485 RS |
156 | break; |
157 | case OPT_1: | |
158 | use1 = 1; | |
159 | break; | |
160 | case OPT_APR1: | |
161 | useapr1 = 1; | |
162 | break; | |
163 | case OPT_CRYPT: | |
164 | usecrypt = 1; | |
165 | break; | |
166 | case OPT_SALT: | |
167 | passed_salt = 1; | |
168 | salt = opt_arg(); | |
169 | break; | |
170 | case OPT_STDIN: | |
171 | if (pw_source_defined) | |
172 | goto opthelp; | |
173 | in_stdin = 1; | |
174 | break; | |
175 | } | |
176 | } | |
177 | argc = opt_num_rest(); | |
178 | argv = opt_rest(); | |
179 | ||
180 | if (*argv) { | |
181 | if (pw_source_defined) | |
182 | goto opthelp; | |
183 | pw_source_defined = 1; | |
184 | passwds = argv; | |
0f113f3e MC |
185 | } |
186 | ||
7e1b7485 RS |
187 | if (!usecrypt && !use1 && !useapr1) { |
188 | /* use default */ | |
0f113f3e | 189 | usecrypt = 1; |
7e1b7485 RS |
190 | } |
191 | if (usecrypt + use1 + useapr1 > 1) { | |
192 | /* conflict */ | |
193 | goto opthelp; | |
194 | } | |
0f113f3e | 195 | |
0f113f3e MC |
196 | # ifdef OPENSSL_NO_DES |
197 | if (usecrypt) | |
7e1b7485 | 198 | goto opthelp; |
0f113f3e MC |
199 | # endif |
200 | # ifdef NO_MD5CRYPT_1 | |
201 | if (use1 || useapr1) | |
7e1b7485 | 202 | goto opthelp; |
0f113f3e MC |
203 | # endif |
204 | ||
7e1b7485 RS |
205 | if (infile && in_stdin) { |
206 | BIO_printf(bio_err, "%s: Can't combine -in and -stdin\n", prog); | |
207 | goto end; | |
0f113f3e MC |
208 | } |
209 | ||
7e1b7485 RS |
210 | in = bio_open_default(infile, "r"); |
211 | if (in == NULL) | |
212 | goto end; | |
0f113f3e MC |
213 | |
214 | if (usecrypt) | |
215 | pw_maxlen = 8; | |
216 | else if (use1 || useapr1) | |
217 | pw_maxlen = 256; /* arbitrary limit, should be enough for most | |
218 | * passwords */ | |
219 | ||
220 | if (passwds == NULL) { | |
221 | /* no passwords on the command line */ | |
222 | ||
223 | passwd_malloc_size = pw_maxlen + 2; | |
224 | /* | |
225 | * longer than necessary so that we can warn about truncation | |
226 | */ | |
227 | passwd = passwd_malloc = OPENSSL_malloc(passwd_malloc_size); | |
228 | if (passwd_malloc == NULL) | |
7e1b7485 | 229 | goto end; |
0f113f3e MC |
230 | } |
231 | ||
232 | if ((in == NULL) && (passwds == NULL)) { | |
233 | /* build a null-terminated list */ | |
234 | static char *passwds_static[2] = { NULL, NULL }; | |
235 | ||
236 | passwds = passwds_static; | |
237 | if (in == NULL) | |
238 | if (EVP_read_pw_string | |
239 | (passwd_malloc, passwd_malloc_size, "Password: ", | |
240 | !(passed_salt || in_noverify)) != 0) | |
7e1b7485 | 241 | goto end; |
0f113f3e MC |
242 | passwds[0] = passwd_malloc; |
243 | } | |
244 | ||
245 | if (in == NULL) { | |
246 | assert(passwds != NULL); | |
247 | assert(*passwds != NULL); | |
248 | ||
249 | do { /* loop over list of passwords */ | |
250 | passwd = *passwds++; | |
7e1b7485 | 251 | if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, bio_out, |
0f113f3e MC |
252 | quiet, table, reverse, pw_maxlen, usecrypt, use1, |
253 | useapr1)) | |
7e1b7485 | 254 | goto end; |
0f113f3e MC |
255 | } |
256 | while (*passwds != NULL); | |
257 | } else | |
258 | /* in != NULL */ | |
259 | { | |
260 | int done; | |
261 | ||
262 | assert(passwd != NULL); | |
263 | do { | |
264 | int r = BIO_gets(in, passwd, pw_maxlen + 1); | |
265 | if (r > 0) { | |
266 | char *c = (strchr(passwd, '\n')); | |
267 | if (c != NULL) | |
268 | *c = 0; /* truncate at newline */ | |
269 | else { | |
270 | /* ignore rest of line */ | |
271 | char trash[BUFSIZ]; | |
272 | do | |
273 | r = BIO_gets(in, trash, sizeof trash); | |
274 | while ((r > 0) && (!strchr(trash, '\n'))); | |
275 | } | |
276 | ||
7e1b7485 RS |
277 | if (!do_passwd |
278 | (passed_salt, &salt, &salt_malloc, passwd, bio_out, quiet, | |
279 | table, reverse, pw_maxlen, usecrypt, use1, useapr1)) | |
280 | goto end; | |
0f113f3e MC |
281 | } |
282 | done = (r <= 0); | |
283 | } | |
284 | while (!done); | |
285 | } | |
286 | ret = 0; | |
287 | ||
7e1b7485 | 288 | end: |
0f113f3e MC |
289 | ERR_print_errors(bio_err); |
290 | if (salt_malloc) | |
291 | OPENSSL_free(salt_malloc); | |
292 | if (passwd_malloc) | |
293 | OPENSSL_free(passwd_malloc); | |
ca3a82c3 | 294 | BIO_free(in); |
7e1b7485 | 295 | return (ret); |
0f113f3e MC |
296 | } |
297 | ||
298 | # ifndef NO_MD5CRYPT_1 | |
299 | /* | |
300 | * MD5-based password algorithm (should probably be available as a library | |
301 | * function; then the static buffer would not be acceptable). For magic | |
302 | * string "1", this should be compatible to the MD5-based BSD password | |
303 | * algorithm. For 'magic' string "apr1", this is compatible to the MD5-based | |
304 | * Apache password algorithm. (Apparently, the Apache password algorithm is | |
305 | * identical except that the 'magic' string was changed -- the laziest | |
306 | * application of the NIH principle I've ever encountered.) | |
1f4643a2 BM |
307 | */ |
308 | static char *md5crypt(const char *passwd, const char *magic, const char *salt) | |
0f113f3e MC |
309 | { |
310 | /* "$apr1$..salt..$.......md5hash..........\0" */ | |
311 | static char out_buf[6 + 9 + 24 + 2]; | |
312 | unsigned char buf[MD5_DIGEST_LENGTH]; | |
313 | char *salt_out; | |
314 | int n; | |
315 | unsigned int i; | |
316 | EVP_MD_CTX md, md2; | |
317 | size_t passwd_len, salt_len; | |
318 | ||
319 | passwd_len = strlen(passwd); | |
320 | out_buf[0] = '$'; | |
321 | out_buf[1] = 0; | |
322 | assert(strlen(magic) <= 4); /* "1" or "apr1" */ | |
323 | strncat(out_buf, magic, 4); | |
324 | strncat(out_buf, "$", 1); | |
325 | strncat(out_buf, salt, 8); | |
326 | assert(strlen(out_buf) <= 6 + 8); /* "$apr1$..salt.." */ | |
327 | salt_out = out_buf + 2 + strlen(magic); | |
328 | salt_len = strlen(salt_out); | |
329 | assert(salt_len <= 8); | |
330 | ||
331 | EVP_MD_CTX_init(&md); | |
332 | EVP_DigestInit_ex(&md, EVP_md5(), NULL); | |
333 | EVP_DigestUpdate(&md, passwd, passwd_len); | |
334 | EVP_DigestUpdate(&md, "$", 1); | |
335 | EVP_DigestUpdate(&md, magic, strlen(magic)); | |
336 | EVP_DigestUpdate(&md, "$", 1); | |
337 | EVP_DigestUpdate(&md, salt_out, salt_len); | |
338 | ||
339 | EVP_MD_CTX_init(&md2); | |
340 | EVP_DigestInit_ex(&md2, EVP_md5(), NULL); | |
341 | EVP_DigestUpdate(&md2, passwd, passwd_len); | |
342 | EVP_DigestUpdate(&md2, salt_out, salt_len); | |
343 | EVP_DigestUpdate(&md2, passwd, passwd_len); | |
344 | EVP_DigestFinal_ex(&md2, buf, NULL); | |
345 | ||
346 | for (i = passwd_len; i > sizeof buf; i -= sizeof buf) | |
347 | EVP_DigestUpdate(&md, buf, sizeof buf); | |
348 | EVP_DigestUpdate(&md, buf, i); | |
349 | ||
350 | n = passwd_len; | |
351 | while (n) { | |
352 | EVP_DigestUpdate(&md, (n & 1) ? "\0" : passwd, 1); | |
353 | n >>= 1; | |
354 | } | |
355 | EVP_DigestFinal_ex(&md, buf, NULL); | |
356 | ||
357 | for (i = 0; i < 1000; i++) { | |
358 | EVP_DigestInit_ex(&md2, EVP_md5(), NULL); | |
359 | EVP_DigestUpdate(&md2, (i & 1) ? (unsigned const char *)passwd : buf, | |
360 | (i & 1) ? passwd_len : sizeof buf); | |
361 | if (i % 3) | |
362 | EVP_DigestUpdate(&md2, salt_out, salt_len); | |
363 | if (i % 7) | |
364 | EVP_DigestUpdate(&md2, passwd, passwd_len); | |
365 | EVP_DigestUpdate(&md2, (i & 1) ? buf : (unsigned const char *)passwd, | |
366 | (i & 1) ? sizeof buf : passwd_len); | |
367 | EVP_DigestFinal_ex(&md2, buf, NULL); | |
368 | } | |
369 | EVP_MD_CTX_cleanup(&md2); | |
370 | ||
371 | { | |
372 | /* transform buf into output string */ | |
373 | ||
374 | unsigned char buf_perm[sizeof buf]; | |
375 | int dest, source; | |
376 | char *output; | |
377 | ||
378 | /* silly output permutation */ | |
379 | for (dest = 0, source = 0; dest < 14; | |
380 | dest++, source = (source + 6) % 17) | |
381 | buf_perm[dest] = buf[source]; | |
382 | buf_perm[14] = buf[5]; | |
383 | buf_perm[15] = buf[11]; | |
384 | # ifndef PEDANTIC /* Unfortunately, this generates a "no | |
385 | * effect" warning */ | |
386 | assert(16 == sizeof buf_perm); | |
387 | # endif | |
388 | ||
389 | output = salt_out + salt_len; | |
390 | assert(output == out_buf + strlen(out_buf)); | |
391 | ||
392 | *output++ = '$'; | |
393 | ||
394 | for (i = 0; i < 15; i += 3) { | |
395 | *output++ = cov_2char[buf_perm[i + 2] & 0x3f]; | |
396 | *output++ = cov_2char[((buf_perm[i + 1] & 0xf) << 2) | | |
397 | (buf_perm[i + 2] >> 6)]; | |
398 | *output++ = cov_2char[((buf_perm[i] & 3) << 4) | | |
399 | (buf_perm[i + 1] >> 4)]; | |
400 | *output++ = cov_2char[buf_perm[i] >> 2]; | |
401 | } | |
402 | assert(i == 15); | |
403 | *output++ = cov_2char[buf_perm[i] & 0x3f]; | |
404 | *output++ = cov_2char[buf_perm[i] >> 6]; | |
405 | *output = 0; | |
406 | assert(strlen(out_buf) < sizeof(out_buf)); | |
407 | } | |
408 | EVP_MD_CTX_cleanup(&md); | |
409 | ||
410 | return out_buf; | |
411 | } | |
412 | # endif | |
e6e7b5f3 BM |
413 | |
414 | static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, | |
0f113f3e MC |
415 | char *passwd, BIO *out, int quiet, int table, |
416 | int reverse, size_t pw_maxlen, int usecrypt, int use1, | |
417 | int useapr1) | |
418 | { | |
419 | char *hash = NULL; | |
420 | ||
421 | assert(salt_p != NULL); | |
422 | assert(salt_malloc_p != NULL); | |
423 | ||
424 | /* first make sure we have a salt */ | |
425 | if (!passed_salt) { | |
426 | # ifndef OPENSSL_NO_DES | |
427 | if (usecrypt) { | |
428 | if (*salt_malloc_p == NULL) { | |
429 | *salt_p = *salt_malloc_p = OPENSSL_malloc(3); | |
430 | if (*salt_malloc_p == NULL) | |
7e1b7485 | 431 | goto end; |
0f113f3e | 432 | } |
266483d2 | 433 | if (RAND_bytes((unsigned char *)*salt_p, 2) <= 0) |
7e1b7485 | 434 | goto end; |
0f113f3e MC |
435 | (*salt_p)[0] = cov_2char[(*salt_p)[0] & 0x3f]; /* 6 bits */ |
436 | (*salt_p)[1] = cov_2char[(*salt_p)[1] & 0x3f]; /* 6 bits */ | |
437 | (*salt_p)[2] = 0; | |
438 | # ifdef CHARSET_EBCDIC | |
439 | ascii2ebcdic(*salt_p, *salt_p, 2); /* des_crypt will convert back | |
440 | * to ASCII */ | |
441 | # endif | |
442 | } | |
443 | # endif /* !OPENSSL_NO_DES */ | |
444 | ||
445 | # ifndef NO_MD5CRYPT_1 | |
446 | if (use1 || useapr1) { | |
447 | int i; | |
448 | ||
449 | if (*salt_malloc_p == NULL) { | |
450 | *salt_p = *salt_malloc_p = OPENSSL_malloc(9); | |
451 | if (*salt_malloc_p == NULL) | |
7e1b7485 | 452 | goto end; |
0f113f3e | 453 | } |
266483d2 | 454 | if (RAND_bytes((unsigned char *)*salt_p, 8) <= 0) |
7e1b7485 | 455 | goto end; |
0f113f3e MC |
456 | |
457 | for (i = 0; i < 8; i++) | |
458 | (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */ | |
459 | (*salt_p)[8] = 0; | |
460 | } | |
461 | # endif /* !NO_MD5CRYPT_1 */ | |
462 | } | |
463 | ||
464 | assert(*salt_p != NULL); | |
465 | ||
466 | /* truncate password if necessary */ | |
467 | if ((strlen(passwd) > pw_maxlen)) { | |
468 | if (!quiet) | |
469 | /* | |
470 | * XXX: really we should know how to print a size_t, not cast it | |
471 | */ | |
472 | BIO_printf(bio_err, | |
473 | "Warning: truncating password to %u characters\n", | |
474 | (unsigned)pw_maxlen); | |
475 | passwd[pw_maxlen] = 0; | |
476 | } | |
477 | assert(strlen(passwd) <= pw_maxlen); | |
478 | ||
479 | /* now compute password hash */ | |
480 | # ifndef OPENSSL_NO_DES | |
481 | if (usecrypt) | |
482 | hash = DES_crypt(passwd, *salt_p); | |
483 | # endif | |
484 | # ifndef NO_MD5CRYPT_1 | |
485 | if (use1 || useapr1) | |
486 | hash = md5crypt(passwd, (use1 ? "1" : "apr1"), *salt_p); | |
487 | # endif | |
488 | assert(hash != NULL); | |
489 | ||
490 | if (table && !reverse) | |
491 | BIO_printf(out, "%s\t%s\n", passwd, hash); | |
492 | else if (table && reverse) | |
493 | BIO_printf(out, "%s\t%s\n", hash, passwd); | |
494 | else | |
495 | BIO_printf(out, "%s\n", hash); | |
0f113f3e | 496 | return 0; |
7e1b7485 RS |
497 | |
498 | end: | |
499 | return 1; | |
0f113f3e | 500 | } |
3ebf0be1 | 501 | #else |
e6e7b5f3 | 502 | |
7e1b7485 | 503 | int passwd_main(int argc, char **argv) |
0f113f3e MC |
504 | { |
505 | fputs("Program not available.\n", stderr) | |
7e1b7485 | 506 | return (1); |
0f113f3e | 507 | } |
3ebf0be1 | 508 | #endif |