xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/slappasswd.c (revision a8c74629f602faa0ccf8a463757d7baf858bbf3a)
1 /*	$NetBSD: slappasswd.c,v 1.2 2020/08/11 13:15:39 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2020 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 <sys/cdefs.h>
24 __RCSID("$NetBSD: slappasswd.c,v 1.2 2020/08/11 13:15:39 christos Exp $");
25 
26 #include "portable.h"
27 
28 #include <stdio.h>
29 
30 #include <ac/stdlib.h>
31 
32 #include <ac/ctype.h>
33 #include <ac/signal.h>
34 #include <ac/socket.h>
35 #include <ac/string.h>
36 #include <ac/time.h>
37 #include <ac/unistd.h>
38 
39 #include <ldap.h>
40 #include <lber_pvt.h>
41 #include <lutil.h>
42 #include <lutil_sha1.h>
43 
44 #include "ldap_defaults.h"
45 #include "slap.h"
46 
47 static int	verbose = 0;
48 static char	*modulepath = NULL;
49 static char	*moduleload = NULL;
50 
51 static void
52 usage(const char *s)
53 {
54 	fprintf(stderr,
55 		"Usage: %s [options]\n"
56 		"  -c format\tcrypt(3) salt format\n"
57 		"  -g\t\tgenerate random password\n"
58 		"  -h hash\tpassword scheme\n"
59 		"  -n\t\tomit trailing newline\n"
60 		"  -o <opt>[=val] specify an option with a(n optional) value\n"
61 		"  \tmodule-path=<pathspec>\n"
62 		"  \tmodule-load=<filename>\n"
63 		"  -s secret\tnew password\n"
64 		"  -u\t\tgenerate RFC2307 values (default)\n"
65 		"  -v\t\tincrease verbosity\n"
66 		"  -T file\tread file for new password\n"
67 		, s );
68 
69 	exit( EXIT_FAILURE );
70 }
71 
72 static int
73 parse_slappasswdopt( void )
74 {
75 	size_t	len = 0;
76 	char	*p;
77 
78 	p = strchr( optarg, '=' );
79 	if ( p != NULL ) {
80 		len = p - optarg;
81 		p++;
82 	}
83 
84 	if ( strncasecmp( optarg, "module-path", len ) == 0 ) {
85 		if ( modulepath )
86 			ch_free( modulepath );
87 		modulepath = ch_strdup( p );
88 
89 	} else if ( strncasecmp( optarg, "module-load", len ) == 0 ) {
90 		if ( moduleload )
91 			ch_free( moduleload );
92 		moduleload = ch_strdup( p );
93 
94 	} else {
95 		return -1;
96 	}
97 
98 	return 0;
99 }
100 
101 int
102 slappasswd( int argc, char *argv[] )
103 {
104 	int rc = EXIT_SUCCESS;
105 #ifdef LUTIL_SHA1_BYTES
106 	char	*default_scheme = "{SSHA}";
107 #else
108 	char	*default_scheme = "{SMD5}";
109 #endif
110 	char	*scheme = default_scheme;
111 
112 	char	*newpw = NULL;
113 	char	*pwfile = NULL;
114 	const char *text;
115 	const char *progname = "slappasswd";
116 
117 	int		i;
118 	char		*newline = "\n";
119 	struct berval passwd = BER_BVNULL;
120 	struct berval hash;
121 
122 #ifdef LDAP_DEBUG
123 	/* tools default to "none", so that at least LDAP_DEBUG_ANY
124 	 * messages show up; use -d 0 to reset */
125 	slap_debug = LDAP_DEBUG_NONE;
126 #endif
127 	ldap_syslog = 0;
128 
129 	while( (i = getopt( argc, argv,
130 		"c:d:gh:no:s:T:vu" )) != EOF )
131 	{
132 		switch (i) {
133 		case 'c':	/* crypt salt format */
134 			scheme = "{CRYPT}";
135 			lutil_salt_format( optarg );
136 			break;
137 
138 		case 'g':	/* new password (generate) */
139 			if ( pwfile != NULL ) {
140 				fprintf( stderr, "Option -g incompatible with -T\n" );
141 				return EXIT_FAILURE;
142 
143 			} else if ( newpw != NULL ) {
144 				fprintf( stderr, "New password already provided\n" );
145 				return EXIT_FAILURE;
146 
147 			} else if ( lutil_passwd_generate( &passwd, 8 )) {
148 				fprintf( stderr, "Password generation failed\n" );
149 				return EXIT_FAILURE;
150 			}
151 			break;
152 
153 		case 'h':	/* scheme */
154 			if ( scheme != default_scheme ) {
155 				fprintf( stderr, "Scheme already provided\n" );
156 				return EXIT_FAILURE;
157 
158 			} else {
159 				scheme = ch_strdup( optarg );
160 			}
161 			break;
162 
163 		case 'n':
164 			newline = "";
165 			break;
166 
167 		case 'o':
168 			if ( parse_slappasswdopt() ) {
169 				usage ( progname );
170 			}
171 			break;
172 
173 		case 's':	/* new password (secret) */
174 			if ( pwfile != NULL ) {
175 				fprintf( stderr, "Option -s incompatible with -T\n" );
176 				return EXIT_FAILURE;
177 
178 			} else if ( newpw != NULL ) {
179 				fprintf( stderr, "New password already provided\n" );
180 				return EXIT_FAILURE;
181 
182 			} else {
183 				char* p;
184 				newpw = ch_strdup( optarg );
185 
186 				for( p = optarg; *p != '\0'; p++ ) {
187 					*p = '\0';
188 				}
189 			}
190 			break;
191 
192 		case 'T':	/* password file */
193 			if ( pwfile != NULL ) {
194 				fprintf( stderr, "Password file already provided\n" );
195 				return EXIT_FAILURE;
196 
197 			} else if ( newpw != NULL ) {
198 				fprintf( stderr, "Option -T incompatible with -s/-g\n" );
199 				return EXIT_FAILURE;
200 
201 			}
202 			pwfile = optarg;
203 			break;
204 
205 		case 'u':	/* RFC2307 userPassword */
206 			break;
207 
208 		case 'v':	/* verbose */
209 			verbose++;
210 			break;
211 
212 		default:
213 			usage ( progname );
214 		}
215 	}
216 
217 	if( argc - optind != 0 ) {
218 		usage( progname );
219 	}
220 
221 #ifdef SLAPD_MODULES
222 	if ( module_init() != 0 ) {
223 		fprintf( stderr, "%s: module_init failed\n", progname );
224 		return EXIT_FAILURE;
225 	}
226 
227 	if ( modulepath && module_path(modulepath) ) {
228 		rc = EXIT_FAILURE;
229 		goto destroy;
230 	}
231 
232 	if ( moduleload && module_load(moduleload, 0, NULL) ) {
233 		rc = EXIT_FAILURE;
234 		goto destroy;
235 	}
236 #endif
237 
238 	if( pwfile != NULL ) {
239 		if( lutil_get_filed_password( pwfile, &passwd )) {
240 			rc = EXIT_FAILURE;
241 			goto destroy;
242 		}
243 	} else if ( BER_BVISEMPTY( &passwd )) {
244 		if( newpw == NULL ) {
245 			/* prompt for new password */
246 			char *cknewpw;
247 			newpw = ch_strdup(getpassphrase("New password: "));
248 			cknewpw = getpassphrase("Re-enter new password: ");
249 
250 			if( strcmp( newpw, cknewpw )) {
251 				fprintf( stderr, "Password values do not match\n" );
252 				rc = EXIT_FAILURE;
253 				goto destroy;
254 			}
255 		}
256 
257 		passwd.bv_val = newpw;
258 		passwd.bv_len = strlen(passwd.bv_val);
259 	} else {
260 		hash = passwd;
261 		goto print_pw;
262 	}
263 
264 	lutil_passwd_hash( &passwd, scheme, &hash, &text );
265 	if( hash.bv_val == NULL ) {
266 		fprintf( stderr,
267 			"Password generation failed for scheme %s: %s\n",
268 			scheme, text ? text : "" );
269 		rc = EXIT_FAILURE;
270 		goto destroy;
271 	}
272 
273 	if( lutil_passwd( &hash, &passwd, NULL, &text ) ) {
274 		fprintf( stderr, "Password verification failed. %s\n",
275 			text ? text : "" );
276 		rc = EXIT_FAILURE;
277 		goto destroy;
278 	}
279 
280 print_pw:;
281 	printf( "%s%s" , hash.bv_val, newline );
282 
283 destroy:;
284 #ifdef SLAPD_MODULES
285 	module_kill();
286 #endif
287 
288 	return rc;
289 }
290