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