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