1/*	$NetBSD$	*/
2
3/* OpenLDAP: pkg/ldap/servers/slapd/slappasswd.c,v 1.5.2.7 2010/04/13 20:23:21 kurt Exp */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1998-2010 The OpenLDAP Foundation.
7 * Portions Copyright 1998-2003 Kurt D. Zeilenga.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18/* ACKNOWLEDGEMENTS:
19 * This work was initially developed by Kurt Zeilenga for inclusion
20 * in OpenLDAP Software.
21 */
22
23#include "portable.h"
24
25#include <stdio.h>
26
27#include <ac/stdlib.h>
28
29#include <ac/ctype.h>
30#include <ac/signal.h>
31#include <ac/socket.h>
32#include <ac/string.h>
33#include <ac/time.h>
34#include <ac/unistd.h>
35
36#include <ldap.h>
37#include <lber_pvt.h>
38#include <lutil.h>
39#include <lutil_sha1.h>
40
41#include "ldap_defaults.h"
42#include "slap.h"
43
44static int	verbose = 0;
45
46static void
47usage(const char *s)
48{
49	fprintf(stderr,
50		"Usage: %s [options]\n"
51		"  -c format\tcrypt(3) salt format\n"
52		"  -g\t\tgenerate random password\n"
53		"  -h hash\tpassword scheme\n"
54		"  -n\t\tomit trailing newline\n"
55		"  -s secret\tnew password\n"
56		"  -u\t\tgenerate RFC2307 values (default)\n"
57		"  -v\t\tincrease verbosity\n"
58		"  -T file\tread file for new password\n"
59		, s );
60
61	exit( EXIT_FAILURE );
62}
63
64int
65slappasswd( int argc, char *argv[] )
66{
67#ifdef LUTIL_SHA1_BYTES
68	char	*default_scheme = "{SSHA}";
69#else
70	char	*default_scheme = "{SMD5}";
71#endif
72	char	*scheme = default_scheme;
73
74	char	*newpw = NULL;
75	char	*pwfile = NULL;
76	const char *text;
77	const char *progname = "slappasswd";
78
79	int		i;
80	char		*newline = "\n";
81	struct berval passwd = BER_BVNULL;
82	struct berval hash;
83
84	while( (i = getopt( argc, argv,
85		"c:d:gh:ns:T:vu" )) != EOF )
86	{
87		switch (i) {
88		case 'c':	/* crypt salt format */
89			scheme = "{CRYPT}";
90			lutil_salt_format( optarg );
91			break;
92
93		case 'g':	/* new password (generate) */
94			if ( pwfile != NULL ) {
95				fprintf( stderr, "Option -g incompatible with -T\n" );
96				return EXIT_FAILURE;
97
98			} else if ( newpw != NULL ) {
99				fprintf( stderr, "New password already provided\n" );
100				return EXIT_FAILURE;
101
102			} else if ( lutil_passwd_generate( &passwd, 8 )) {
103				fprintf( stderr, "Password generation failed\n" );
104				return EXIT_FAILURE;
105			}
106			break;
107
108		case 'h':	/* scheme */
109			if ( scheme != default_scheme ) {
110				fprintf( stderr, "Scheme already provided\n" );
111				return EXIT_FAILURE;
112
113			} else {
114				scheme = ch_strdup( optarg );
115			}
116			break;
117
118		case 'n':
119			newline = "";
120			break;
121
122		case 's':	/* new password (secret) */
123			if ( pwfile != NULL ) {
124				fprintf( stderr, "Option -s incompatible with -T\n" );
125				return EXIT_FAILURE;
126
127			} else if ( newpw != NULL ) {
128				fprintf( stderr, "New password already provided\n" );
129				return EXIT_FAILURE;
130
131			} else {
132				char* p;
133				newpw = ch_strdup( optarg );
134
135				for( p = optarg; *p != '\0'; p++ ) {
136					*p = '\0';
137				}
138			}
139			break;
140
141		case 'T':	/* password file */
142			if ( pwfile != NULL ) {
143				fprintf( stderr, "Password file already provided\n" );
144				return EXIT_FAILURE;
145
146			} else if ( newpw != NULL ) {
147				fprintf( stderr, "Option -T incompatible with -s/-g\n" );
148				return EXIT_FAILURE;
149
150			}
151			pwfile = optarg;
152			break;
153
154		case 'u':	/* RFC2307 userPassword */
155			break;
156
157		case 'v':	/* verbose */
158			verbose++;
159			break;
160
161		default:
162			usage ( progname );
163		}
164	}
165
166	if( argc - optind != 0 ) {
167		usage( progname );
168	}
169
170	if( pwfile != NULL ) {
171		if( lutil_get_filed_password( pwfile, &passwd )) {
172			return EXIT_FAILURE;
173		}
174	} else if ( BER_BVISEMPTY( &passwd )) {
175		if( newpw == NULL ) {
176			/* prompt for new password */
177			char *cknewpw;
178			newpw = ch_strdup(getpassphrase("New password: "));
179			cknewpw = getpassphrase("Re-enter new password: ");
180
181			if( strcmp( newpw, cknewpw )) {
182				fprintf( stderr, "Password values do not match\n" );
183				return EXIT_FAILURE;
184			}
185		}
186
187		passwd.bv_val = newpw;
188		passwd.bv_len = strlen(passwd.bv_val);
189	} else {
190		hash = passwd;
191		goto print_pw;
192	}
193
194	lutil_passwd_hash( &passwd, scheme, &hash, &text );
195	if( hash.bv_val == NULL ) {
196		fprintf( stderr,
197			"Password generation failed for scheme %s: %s\n",
198			scheme, text ? text : "" );
199		return EXIT_FAILURE;
200	}
201
202	if( lutil_passwd( &hash, &passwd, NULL, &text ) ) {
203		fprintf( stderr, "Password verification failed. %s\n",
204			text ? text : "" );
205		return EXIT_FAILURE;
206	}
207
208print_pw:;
209	printf( "%s%s" , hash.bv_val, newline );
210	return EXIT_SUCCESS;
211}
212