Home | History | Annotate | Line # | Download | only in libcrypt
bcrypt.c revision 1.3.2.2
      1  1.3.2.2  jmc /*	$NetBSD: bcrypt.c,v 1.3.2.2 2004/03/26 22:52:58 jmc Exp $	*/
      2  1.3.2.2  jmc /*	$OpenBSD: bcrypt.c,v 1.16 2002/02/19 19:39:36 millert Exp $	*/
      3  1.3.2.2  jmc 
      4  1.3.2.2  jmc /*
      5  1.3.2.2  jmc  * Copyright 1997 Niels Provos <provos (at) physnet.uni-hamburg.de>
      6  1.3.2.2  jmc  * All rights reserved.
      7  1.3.2.2  jmc  *
      8  1.3.2.2  jmc  * Redistribution and use in source and binary forms, with or without
      9  1.3.2.2  jmc  * modification, are permitted provided that the following conditions
     10  1.3.2.2  jmc  * are met:
     11  1.3.2.2  jmc  * 1. Redistributions of source code must retain the above copyright
     12  1.3.2.2  jmc  *    notice, this list of conditions and the following disclaimer.
     13  1.3.2.2  jmc  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.3.2.2  jmc  *    notice, this list of conditions and the following disclaimer in the
     15  1.3.2.2  jmc  *    documentation and/or other materials provided with the distribution.
     16  1.3.2.2  jmc  * 3. All advertising materials mentioning features or use of this software
     17  1.3.2.2  jmc  *    must display the following acknowledgement:
     18  1.3.2.2  jmc  *      This product includes software developed by Niels Provos.
     19  1.3.2.2  jmc  * 4. The name of the author may not be used to endorse or promote products
     20  1.3.2.2  jmc  *    derived from this software without specific prior written permission.
     21  1.3.2.2  jmc  *
     22  1.3.2.2  jmc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  1.3.2.2  jmc  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  1.3.2.2  jmc  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  1.3.2.2  jmc  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  1.3.2.2  jmc  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  1.3.2.2  jmc  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  1.3.2.2  jmc  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  1.3.2.2  jmc  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  1.3.2.2  jmc  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  1.3.2.2  jmc  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  1.3.2.2  jmc  */
     33  1.3.2.2  jmc 
     34  1.3.2.2  jmc /* This password hashing algorithm was designed by David Mazieres
     35  1.3.2.2  jmc  * <dm (at) lcs.mit.edu> and works as follows:
     36  1.3.2.2  jmc  *
     37  1.3.2.2  jmc  * 1. state := InitState ()
     38  1.3.2.2  jmc  * 2. state := ExpandKey (state, salt, password) 3.
     39  1.3.2.2  jmc  * REPEAT rounds:
     40  1.3.2.2  jmc  *	state := ExpandKey (state, 0, salt)
     41  1.3.2.2  jmc  *      state := ExpandKey(state, 0, password)
     42  1.3.2.2  jmc  * 4. ctext := "OrpheanBeholderScryDoubt"
     43  1.3.2.2  jmc  * 5. REPEAT 64:
     44  1.3.2.2  jmc  * 	ctext := Encrypt_ECB (state, ctext);
     45  1.3.2.2  jmc  * 6. RETURN Concatenate (salt, ctext);
     46  1.3.2.2  jmc  *
     47  1.3.2.2  jmc  */
     48  1.3.2.2  jmc 
     49  1.3.2.2  jmc #if 0
     50  1.3.2.2  jmc #include <stdio.h>
     51  1.3.2.2  jmc #endif
     52  1.3.2.2  jmc 
     53  1.3.2.2  jmc #include <sys/cdefs.h>
     54  1.3.2.2  jmc __RCSID("$NetBSD: bcrypt.c,v 1.3.2.2 2004/03/26 22:52:58 jmc Exp $");
     55  1.3.2.2  jmc 
     56  1.3.2.2  jmc #include <stdio.h>
     57  1.3.2.2  jmc #include <stdlib.h>
     58  1.3.2.2  jmc #include <sys/types.h>
     59  1.3.2.2  jmc #include <string.h>
     60  1.3.2.2  jmc #include <pwd.h>
     61  1.3.2.2  jmc 
     62  1.3.2.2  jmc #include "blowfish.c"
     63  1.3.2.2  jmc 
     64  1.3.2.2  jmc /* This implementation is adaptable to current computing power.
     65  1.3.2.2  jmc  * You can have up to 2^31 rounds which should be enough for some
     66  1.3.2.2  jmc  * time to come.
     67  1.3.2.2  jmc  */
     68  1.3.2.2  jmc 
     69  1.3.2.2  jmc #define BCRYPT_VERSION '2'
     70  1.3.2.2  jmc #define BCRYPT_MAXSALT 16	/* Precomputation is just so nice */
     71  1.3.2.2  jmc #define BCRYPT_BLOCKS 6		/* Ciphertext blocks */
     72  1.3.2.2  jmc #define BCRYPT_MINROUNDS 16	/* we have log2(rounds) in salt */
     73  1.3.2.2  jmc 
     74  1.3.2.2  jmc static void encode_salt(char *, u_int8_t *, u_int16_t, u_int8_t);
     75  1.3.2.2  jmc static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t);
     76  1.3.2.2  jmc static void decode_base64(u_int8_t *, u_int16_t, u_int8_t *);
     77  1.3.2.2  jmc 
     78  1.3.2.2  jmc char *__bcrypt(const char *, const char *);	/* XXX */
     79  1.3.2.2  jmc 
     80  1.3.2.2  jmc static char    encrypted[_PASSWORD_LEN];
     81  1.3.2.2  jmc static char    gsalt[BCRYPT_MAXSALT * 4 / 3 + 1];
     82  1.3.2.2  jmc static char    error[] = ":";
     83  1.3.2.2  jmc 
     84  1.3.2.2  jmc const static u_int8_t Base64Code[] =
     85  1.3.2.2  jmc "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
     86  1.3.2.2  jmc 
     87  1.3.2.2  jmc const static u_int8_t index_64[128] =
     88  1.3.2.2  jmc {
     89  1.3.2.2  jmc 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     90  1.3.2.2  jmc 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     91  1.3.2.2  jmc 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     92  1.3.2.2  jmc 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     93  1.3.2.2  jmc 	255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
     94  1.3.2.2  jmc 	56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
     95  1.3.2.2  jmc 	255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
     96  1.3.2.2  jmc 	7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
     97  1.3.2.2  jmc 	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
     98  1.3.2.2  jmc 	255, 255, 255, 255, 255, 255, 28, 29, 30,
     99  1.3.2.2  jmc 	31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    100  1.3.2.2  jmc 	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
    101  1.3.2.2  jmc 	51, 52, 53, 255, 255, 255, 255, 255
    102  1.3.2.2  jmc };
    103  1.3.2.2  jmc #define CHAR64(c)  ( (c) > 127 ? 255 : index_64[(c)])
    104  1.3.2.2  jmc 
    105  1.3.2.2  jmc static void
    106  1.3.2.2  jmc decode_base64(u_int8_t *buffer, u_int16_t len, u_int8_t *data)
    107  1.3.2.2  jmc {
    108  1.3.2.2  jmc 	u_int8_t *bp = buffer;
    109  1.3.2.2  jmc 	u_int8_t *p = data;
    110  1.3.2.2  jmc 	u_int8_t c1, c2, c3, c4;
    111  1.3.2.2  jmc 	while (bp < buffer + len) {
    112  1.3.2.2  jmc 		c1 = CHAR64(*p);
    113  1.3.2.2  jmc 		c2 = CHAR64(*(p + 1));
    114  1.3.2.2  jmc 
    115  1.3.2.2  jmc 		/* Invalid data */
    116  1.3.2.2  jmc 		if (c1 == 255 || c2 == 255)
    117  1.3.2.2  jmc 			break;
    118  1.3.2.2  jmc 
    119  1.3.2.2  jmc 		*bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
    120  1.3.2.2  jmc 		if (bp >= buffer + len)
    121  1.3.2.2  jmc 			break;
    122  1.3.2.2  jmc 
    123  1.3.2.2  jmc 		c3 = CHAR64(*(p + 2));
    124  1.3.2.2  jmc 		if (c3 == 255)
    125  1.3.2.2  jmc 			break;
    126  1.3.2.2  jmc 
    127  1.3.2.2  jmc 		*bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
    128  1.3.2.2  jmc 		if (bp >= buffer + len)
    129  1.3.2.2  jmc 			break;
    130  1.3.2.2  jmc 
    131  1.3.2.2  jmc 		c4 = CHAR64(*(p + 3));
    132  1.3.2.2  jmc 		if (c4 == 255)
    133  1.3.2.2  jmc 			break;
    134  1.3.2.2  jmc 		*bp++ = ((c3 & 0x03) << 6) | c4;
    135  1.3.2.2  jmc 
    136  1.3.2.2  jmc 		p += 4;
    137  1.3.2.2  jmc 	}
    138  1.3.2.2  jmc }
    139  1.3.2.2  jmc 
    140  1.3.2.2  jmc static void
    141  1.3.2.2  jmc encode_salt(char *salt, u_int8_t *csalt, u_int16_t clen, u_int8_t logr)
    142  1.3.2.2  jmc {
    143  1.3.2.2  jmc 	salt[0] = '$';
    144  1.3.2.2  jmc 	salt[1] = BCRYPT_VERSION;
    145  1.3.2.2  jmc 	salt[2] = 'a';
    146  1.3.2.2  jmc 	salt[3] = '$';
    147  1.3.2.2  jmc 
    148  1.3.2.2  jmc 	snprintf(salt + 4, 4, "%2.2u$", logr);
    149  1.3.2.2  jmc 
    150  1.3.2.2  jmc 	encode_base64((u_int8_t *) salt + 7, csalt, clen);
    151  1.3.2.2  jmc }
    152  1.3.2.2  jmc 
    153  1.3.2.2  jmc /* Generates a salt for this version of crypt.
    154  1.3.2.2  jmc    Since versions may change. Keeping this here
    155  1.3.2.2  jmc    seems sensible.
    156  1.3.2.2  jmc  */
    157  1.3.2.2  jmc char *
    158  1.3.2.2  jmc bcrypt_gensalt(u_int8_t log_rounds)
    159  1.3.2.2  jmc {
    160  1.3.2.2  jmc 	u_int8_t csalt[BCRYPT_MAXSALT];
    161  1.3.2.2  jmc 	u_int16_t i;
    162  1.3.2.2  jmc 	u_int32_t seed = 0;
    163  1.3.2.2  jmc 
    164  1.3.2.2  jmc 	for (i = 0; i < BCRYPT_MAXSALT; i++) {
    165  1.3.2.2  jmc 		if (i % 4 == 0)
    166  1.3.2.2  jmc 			seed = arc4random();
    167  1.3.2.2  jmc 		csalt[i] = seed & 0xff;
    168  1.3.2.2  jmc 		seed = seed >> 8;
    169  1.3.2.2  jmc 	}
    170  1.3.2.2  jmc 
    171  1.3.2.2  jmc 	if (log_rounds < 4)
    172  1.3.2.2  jmc 		log_rounds = 4;
    173  1.3.2.2  jmc 
    174  1.3.2.2  jmc 	encode_salt(gsalt, csalt, BCRYPT_MAXSALT, log_rounds);
    175  1.3.2.2  jmc 	return gsalt;
    176  1.3.2.2  jmc }
    177  1.3.2.2  jmc 
    178  1.3.2.2  jmc /* We handle $Vers$log2(NumRounds)$salt+passwd$
    179  1.3.2.2  jmc    i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
    180  1.3.2.2  jmc 
    181  1.3.2.2  jmc char   *
    182  1.3.2.2  jmc __bcrypt(key, salt)
    183  1.3.2.2  jmc 	const char   *key;
    184  1.3.2.2  jmc 	const char   *salt;
    185  1.3.2.2  jmc {
    186  1.3.2.2  jmc 	blf_ctx state;
    187  1.3.2.2  jmc 	u_int32_t rounds, i, k;
    188  1.3.2.2  jmc 	u_int16_t j;
    189  1.3.2.2  jmc 	u_int8_t key_len, salt_len, logr, minor;
    190  1.3.2.2  jmc 	u_int8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt";
    191  1.3.2.2  jmc 	u_int8_t csalt[BCRYPT_MAXSALT];
    192  1.3.2.2  jmc 	u_int32_t cdata[BCRYPT_BLOCKS];
    193  1.3.2.2  jmc 
    194  1.3.2.2  jmc 	/* Discard "$" identifier */
    195  1.3.2.2  jmc 	salt++;
    196  1.3.2.2  jmc 
    197  1.3.2.2  jmc 	if (*salt > BCRYPT_VERSION) {
    198  1.3.2.2  jmc 		/* How do I handle errors ? Return ':' */
    199  1.3.2.2  jmc 		return error;
    200  1.3.2.2  jmc 	}
    201  1.3.2.2  jmc 
    202  1.3.2.2  jmc 	/* Check for minor versions */
    203  1.3.2.2  jmc 	if (salt[1] != '$') {
    204  1.3.2.2  jmc 		 switch (salt[1]) {
    205  1.3.2.2  jmc 		 case 'a':
    206  1.3.2.2  jmc 			 /* 'ab' should not yield the same as 'abab' */
    207  1.3.2.2  jmc 			 minor = salt[1];
    208  1.3.2.2  jmc 			 salt++;
    209  1.3.2.2  jmc 			 break;
    210  1.3.2.2  jmc 		 default:
    211  1.3.2.2  jmc 			 return error;
    212  1.3.2.2  jmc 		 }
    213  1.3.2.2  jmc 	} else
    214  1.3.2.2  jmc 		 minor = 0;
    215  1.3.2.2  jmc 
    216  1.3.2.2  jmc 	/* Discard version + "$" identifier */
    217  1.3.2.2  jmc 	salt += 2;
    218  1.3.2.2  jmc 
    219  1.3.2.2  jmc 	if (salt[2] != '$')
    220  1.3.2.2  jmc 		/* Out of sync with passwd entry */
    221  1.3.2.2  jmc 		return error;
    222  1.3.2.2  jmc 
    223  1.3.2.2  jmc 	/* Computer power doesn't increase linear, 2^x should be fine */
    224  1.3.2.2  jmc 	if ((rounds = (u_int32_t) 1 << (logr = atoi(salt))) < BCRYPT_MINROUNDS)
    225  1.3.2.2  jmc 		return error;
    226  1.3.2.2  jmc 
    227  1.3.2.2  jmc 	/* Discard num rounds + "$" identifier */
    228  1.3.2.2  jmc 	salt += 3;
    229  1.3.2.2  jmc 
    230  1.3.2.2  jmc 	if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
    231  1.3.2.2  jmc 		return error;
    232  1.3.2.2  jmc 
    233  1.3.2.2  jmc 	/* We dont want the base64 salt but the raw data */
    234  1.3.2.2  jmc 	decode_base64(csalt, BCRYPT_MAXSALT, (u_int8_t *) salt);
    235  1.3.2.2  jmc 	salt_len = BCRYPT_MAXSALT;
    236  1.3.2.2  jmc 	key_len = strlen(key) + (minor >= 'a' ? 1 : 0);
    237  1.3.2.2  jmc 
    238  1.3.2.2  jmc 	/* Setting up S-Boxes and Subkeys */
    239  1.3.2.2  jmc 	Blowfish_initstate(&state);
    240  1.3.2.2  jmc 	Blowfish_expandstate(&state, csalt, salt_len,
    241  1.3.2.2  jmc 	    (u_int8_t *) key, key_len);
    242  1.3.2.2  jmc 	for (k = 0; k < rounds; k++) {
    243  1.3.2.2  jmc 		Blowfish_expand0state(&state, (u_int8_t *) key, key_len);
    244  1.3.2.2  jmc 		Blowfish_expand0state(&state, csalt, salt_len);
    245  1.3.2.2  jmc 	}
    246  1.3.2.2  jmc 
    247  1.3.2.2  jmc 	/* This can be precomputed later */
    248  1.3.2.2  jmc 	j = 0;
    249  1.3.2.2  jmc 	for (i = 0; i < BCRYPT_BLOCKS; i++)
    250  1.3.2.2  jmc 		cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);
    251  1.3.2.2  jmc 
    252  1.3.2.2  jmc 	/* Now do the encryption */
    253  1.3.2.2  jmc 	for (k = 0; k < 64; k++)
    254  1.3.2.2  jmc 		blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
    255  1.3.2.2  jmc 
    256  1.3.2.2  jmc 	for (i = 0; i < BCRYPT_BLOCKS; i++) {
    257  1.3.2.2  jmc 		ciphertext[4 * i + 3] = cdata[i] & 0xff;
    258  1.3.2.2  jmc 		cdata[i] = cdata[i] >> 8;
    259  1.3.2.2  jmc 		ciphertext[4 * i + 2] = cdata[i] & 0xff;
    260  1.3.2.2  jmc 		cdata[i] = cdata[i] >> 8;
    261  1.3.2.2  jmc 		ciphertext[4 * i + 1] = cdata[i] & 0xff;
    262  1.3.2.2  jmc 		cdata[i] = cdata[i] >> 8;
    263  1.3.2.2  jmc 		ciphertext[4 * i + 0] = cdata[i] & 0xff;
    264  1.3.2.2  jmc 	}
    265  1.3.2.2  jmc 
    266  1.3.2.2  jmc 
    267  1.3.2.2  jmc 	i = 0;
    268  1.3.2.2  jmc 	encrypted[i++] = '$';
    269  1.3.2.2  jmc 	encrypted[i++] = BCRYPT_VERSION;
    270  1.3.2.2  jmc 	if (minor)
    271  1.3.2.2  jmc 		encrypted[i++] = minor;
    272  1.3.2.2  jmc 	encrypted[i++] = '$';
    273  1.3.2.2  jmc 
    274  1.3.2.2  jmc 	snprintf(encrypted + i, 4, "%2.2u$", logr);
    275  1.3.2.2  jmc 
    276  1.3.2.2  jmc 	encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT);
    277  1.3.2.2  jmc 	encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext,
    278  1.3.2.2  jmc 	    4 * BCRYPT_BLOCKS - 1);
    279  1.3.2.2  jmc 	return encrypted;
    280  1.3.2.2  jmc }
    281  1.3.2.2  jmc 
    282  1.3.2.2  jmc static void
    283  1.3.2.2  jmc encode_base64(u_int8_t *buffer, u_int8_t *data, u_int16_t len)
    284  1.3.2.2  jmc {
    285  1.3.2.2  jmc 	u_int8_t *bp = buffer;
    286  1.3.2.2  jmc 	u_int8_t *p = data;
    287  1.3.2.2  jmc 	u_int8_t c1, c2;
    288  1.3.2.2  jmc 	while (p < data + len) {
    289  1.3.2.2  jmc 		c1 = *p++;
    290  1.3.2.2  jmc 		*bp++ = Base64Code[(c1 >> 2)];
    291  1.3.2.2  jmc 		c1 = (c1 & 0x03) << 4;
    292  1.3.2.2  jmc 		if (p >= data + len) {
    293  1.3.2.2  jmc 			*bp++ = Base64Code[c1];
    294  1.3.2.2  jmc 			break;
    295  1.3.2.2  jmc 		}
    296  1.3.2.2  jmc 		c2 = *p++;
    297  1.3.2.2  jmc 		c1 |= (c2 >> 4) & 0x0f;
    298  1.3.2.2  jmc 		*bp++ = Base64Code[c1];
    299  1.3.2.2  jmc 		c1 = (c2 & 0x0f) << 2;
    300  1.3.2.2  jmc 		if (p >= data + len) {
    301  1.3.2.2  jmc 			*bp++ = Base64Code[c1];
    302  1.3.2.2  jmc 			break;
    303  1.3.2.2  jmc 		}
    304  1.3.2.2  jmc 		c2 = *p++;
    305  1.3.2.2  jmc 		c1 |= (c2 >> 6) & 0x03;
    306  1.3.2.2  jmc 		*bp++ = Base64Code[c1];
    307  1.3.2.2  jmc 		*bp++ = Base64Code[c2 & 0x3f];
    308  1.3.2.2  jmc 	}
    309  1.3.2.2  jmc 	*bp = '\0';
    310  1.3.2.2  jmc }
    311  1.3.2.2  jmc #if 0
    312  1.3.2.2  jmc void
    313  1.3.2.2  jmc main()
    314  1.3.2.2  jmc {
    315  1.3.2.2  jmc 	char    blubber[73];
    316  1.3.2.2  jmc 	char    salt[100];
    317  1.3.2.2  jmc 	char   *p;
    318  1.3.2.2  jmc 	salt[0] = '$';
    319  1.3.2.2  jmc 	salt[1] = BCRYPT_VERSION;
    320  1.3.2.2  jmc 	salt[2] = '$';
    321  1.3.2.2  jmc 
    322  1.3.2.2  jmc 	snprintf(salt + 3, 4, "%2.2u$", 5);
    323  1.3.2.2  jmc 
    324  1.3.2.2  jmc 	printf("24 bytes of salt: ");
    325  1.3.2.2  jmc 	fgets(salt + 6, 94, stdin);
    326  1.3.2.2  jmc 	salt[99] = 0;
    327  1.3.2.2  jmc 	printf("72 bytes of password: ");
    328  1.3.2.2  jmc 	fpurge(stdin);
    329  1.3.2.2  jmc 	fgets(blubber, 73, stdin);
    330  1.3.2.2  jmc 	blubber[72] = 0;
    331  1.3.2.2  jmc 
    332  1.3.2.2  jmc 	p = crypt(blubber, salt);
    333  1.3.2.2  jmc 	printf("Passwd entry: %s\n\n", p);
    334  1.3.2.2  jmc 
    335  1.3.2.2  jmc 	p = bcrypt_gensalt(5);
    336  1.3.2.2  jmc 	printf("Generated salt: %s\n", p);
    337  1.3.2.2  jmc 	p = crypt(blubber, p);
    338  1.3.2.2  jmc 	printf("Passwd entry: %s\n", p);
    339  1.3.2.2  jmc }
    340  1.3.2.2  jmc #endif
    341