xref: /netbsd-src/external/bsd/openldap/dist/clients/tools/ldappasswd.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: ldappasswd.c,v 1.1.1.3 2010/12/12 15:18:12 adam Exp $	*/
2 
3 /* ldappasswd -- a tool for change LDAP passwords */
4 /* OpenLDAP: pkg/ldap/clients/tools/ldappasswd.c,v 1.136.2.10 2010/04/15 22:16:50 quanah Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2010 The OpenLDAP Foundation.
8  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
9  * Portions Copyright 1998-2001 Net Boolean Incorporated.
10  * Portions Copyright 2001-2003 IBM Corporation.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted only as authorized by the OpenLDAP
15  * Public License.
16  *
17  * A copy of this license is available in the file LICENSE in the
18  * top-level directory of the distribution or, alternatively, at
19  * <http://www.OpenLDAP.org/license.html>.
20  */
21 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
22  * All rights reserved.
23  *
24  * Redistribution and use in source and binary forms are permitted
25  * provided that this notice is preserved and that due credit is given
26  * to the University of Michigan at Ann Arbor.  The name of the
27  * University may not be used to endorse or promote products derived
28  * from this software without specific prior written permission.  This
29  * software is provided ``as is'' without express or implied warranty.
30  */
31 /* ACKNOWLEDGEMENTS:
32  * The original ldappasswd(1) tool was developed by Dave Storey (F5
33  * Network), based on other OpenLDAP client tools (which are, of
34  * course, based on U-MICH LDAP).  This version was rewritten
35  * by Kurt D. Zeilenga (based on other OpenLDAP client tools).
36  */
37 
38 #include "portable.h"
39 
40 #include <stdio.h>
41 
42 #include <ac/stdlib.h>
43 
44 #include <ac/ctype.h>
45 #include <ac/socket.h>
46 #include <ac/string.h>
47 #include <ac/time.h>
48 #include <ac/unistd.h>
49 
50 #include <ldap.h>
51 #include "lutil.h"
52 #include "lutil_ldap.h"
53 #include "ldap_defaults.h"
54 
55 #include "common.h"
56 
57 
58 static struct berval newpw = { 0, NULL };
59 static struct berval oldpw = { 0, NULL };
60 
61 static int   want_newpw = 0;
62 static int   want_oldpw = 0;
63 
64 static char *oldpwfile = NULL;
65 static char *newpwfile = NULL;
66 
67 void
68 usage( void )
69 {
70 	fprintf( stderr, _("Change password of an LDAP user\n\n"));
71 	fprintf( stderr,_("usage: %s [options] [user]\n"), prog);
72 	fprintf( stderr, _("  user: the authentication identity, commonly a DN\n"));
73 	fprintf( stderr, _("Password change options:\n"));
74 	fprintf( stderr, _("  -a secret  old password\n"));
75 	fprintf( stderr, _("  -A         prompt for old password\n"));
76 	fprintf( stderr, _("  -t file    read file for old password\n"));
77 	fprintf( stderr, _("  -s secret  new password\n"));
78 	fprintf( stderr, _("  -S         prompt for new password\n"));
79 	fprintf( stderr, _("  -T file    read file for new password\n"));
80 	tool_common_usage();
81 	exit( EXIT_FAILURE );
82 }
83 
84 
85 const char options[] = "a:As:St:T:"
86 	"d:D:e:h:H:InNO:o:p:QR:U:vVw:WxX:y:Y:Z";
87 
88 int
89 handle_private_option( int i )
90 {
91 	switch ( i ) {
92 #if 0
93 	case 'E': /* passwd extensions */ {
94 		int		crit;
95 		char	*control, *cvalue;
96 		if( protocol == LDAP_VERSION2 ) {
97 			fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
98 			         prog, protocol );
99 			exit( EXIT_FAILURE );
100 		}
101 
102 		/* should be extended to support comma separated list of
103 		 *	[!]key[=value] parameters, e.g.  -E !foo,bar=567
104 		 */
105 
106 		crit = 0;
107 		cvalue = NULL;
108 		if( optarg[0] == '!' ) {
109 			crit = 1;
110 			optarg++;
111 		}
112 
113 		control = strdup( optarg );
114 		if ( (cvalue = strchr( control, '=' )) != NULL ) {
115 			*cvalue++ = '\0';
116 		}
117 		fprintf( stderr, _("Invalid passwd extension name: %s\n"), control );
118 		usage();
119 		}
120 #endif
121 
122 	case 'a':	/* old password (secret) */
123 		oldpw.bv_val = strdup( optarg );
124 		{
125 			char* p;
126 			for( p = optarg; *p != '\0'; p++ ) {
127 				*p = '\0';
128 			}
129 		}
130 		oldpw.bv_len = strlen( oldpw.bv_val );
131 		break;
132 
133 	case 'A':	/* prompt for old password */
134 		want_oldpw++;
135 		break;
136 
137 	case 's':	/* new password (secret) */
138 		newpw.bv_val = strdup (optarg);
139 		{
140 			char* p;
141 			for( p = optarg; *p != '\0'; p++ ) {
142 				*p = '\0';
143 			}
144 		}
145 		newpw.bv_len = strlen( newpw.bv_val );
146 		break;
147 
148 	case 'S':	/* prompt for user password */
149 		want_newpw++;
150 		break;
151 
152 	case 't':
153 		oldpwfile = optarg;
154 		break;
155 
156 	case 'T':
157 		newpwfile = optarg;
158 		break;
159 
160 	default:
161 		return 0;
162 	}
163 	return 1;
164 }
165 
166 
167 int
168 main( int argc, char *argv[] )
169 {
170 	int rc;
171 	char	*user = NULL;
172 
173 	LDAP	       *ld = NULL;
174 	struct berval bv = {0, NULL};
175 	BerElement  *ber = NULL;
176 
177 	int id, code = LDAP_OTHER;
178 	LDAPMessage *res;
179 	char *matcheddn = NULL, *text = NULL, **refs = NULL;
180 	char	*retoid = NULL;
181 	struct berval *retdata = NULL;
182 	LDAPControl **ctrls = NULL;
183 
184     tool_init( TOOL_PASSWD );
185 	prog = lutil_progname( "ldappasswd", argc, argv );
186 
187 	/* LDAPv3 only */
188 	protocol = LDAP_VERSION3;
189 
190 	tool_args( argc, argv );
191 
192 	if( argc - optind > 1 ) {
193 		usage();
194 	} else if ( argc - optind == 1 ) {
195 		user = strdup( argv[optind] );
196 	} else {
197 		user = NULL;
198 	}
199 
200 	if( oldpwfile ) {
201 		rc = lutil_get_filed_password( oldpwfile, &oldpw );
202 		if( rc ) {
203 			rc = EXIT_FAILURE;
204 			goto done;
205 		}
206 	}
207 
208 	if( want_oldpw && oldpw.bv_val == NULL ) {
209 		/* prompt for old password */
210 		char *ckoldpw;
211 		oldpw.bv_val = strdup(getpassphrase(_("Old password: ")));
212 		ckoldpw = getpassphrase(_("Re-enter old password: "));
213 
214 		if( oldpw.bv_val == NULL || ckoldpw == NULL ||
215 			strcmp( oldpw.bv_val, ckoldpw ))
216 		{
217 			fprintf( stderr, _("passwords do not match\n") );
218 			rc = EXIT_FAILURE;
219 			goto done;
220 		}
221 
222 		oldpw.bv_len = strlen( oldpw.bv_val );
223 	}
224 
225 	if( newpwfile ) {
226 		rc = lutil_get_filed_password( newpwfile, &newpw );
227 		if( rc ) {
228 			rc = EXIT_FAILURE;
229 			goto done;
230 		}
231 	}
232 
233 	if( want_newpw && newpw.bv_val == NULL ) {
234 		/* prompt for new password */
235 		char *cknewpw;
236 		newpw.bv_val = strdup(getpassphrase(_("New password: ")));
237 		cknewpw = getpassphrase(_("Re-enter new password: "));
238 
239 		if( newpw.bv_val == NULL || cknewpw == NULL ||
240 			strcmp( newpw.bv_val, cknewpw ))
241 		{
242 			fprintf( stderr, _("passwords do not match\n") );
243 			rc = EXIT_FAILURE;
244 			goto done;
245 		}
246 
247 		newpw.bv_len = strlen( newpw.bv_val );
248 	}
249 
250 	ld = tool_conn_setup( 0, 0 );
251 
252 	tool_bind( ld );
253 
254 	if ( assertion || authzid || manageDSAit || noop ) {
255 		tool_server_controls( ld, NULL, 0 );
256 	}
257 
258 	if( user != NULL || oldpw.bv_val != NULL || newpw.bv_val != NULL ) {
259 		/* build the password modify request data */
260 		ber = ber_alloc_t( LBER_USE_DER );
261 
262 		if( ber == NULL ) {
263 			perror( "ber_alloc_t" );
264 			rc = EXIT_FAILURE;
265 			goto done;
266 		}
267 
268 		ber_printf( ber, "{" /*}*/ );
269 
270 		if( user != NULL ) {
271 			ber_printf( ber, "ts",
272 				LDAP_TAG_EXOP_MODIFY_PASSWD_ID, user );
273 			free(user);
274 		}
275 
276 		if( oldpw.bv_val != NULL ) {
277 			ber_printf( ber, "tO",
278 				LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &oldpw );
279 			free(oldpw.bv_val);
280 		}
281 
282 		if( newpw.bv_val != NULL ) {
283 			ber_printf( ber, "tO",
284 				LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &newpw );
285 			free(newpw.bv_val);
286 		}
287 
288 		ber_printf( ber, /*{*/ "N}" );
289 
290 		rc = ber_flatten2( ber, &bv, 0 );
291 
292 		if( rc < 0 ) {
293 			perror( "ber_flatten2" );
294 			rc = EXIT_FAILURE;
295 			goto done;
296 		}
297 	}
298 
299 	if ( dont ) {
300 		rc = LDAP_SUCCESS;
301 		goto done;
302 	}
303 
304 	tool_server_controls( ld, NULL, 0);
305 
306 	rc = ldap_extended_operation( ld,
307 		LDAP_EXOP_MODIFY_PASSWD, bv.bv_val ? &bv : NULL,
308 		NULL, NULL, &id );
309 
310 	ber_free( ber, 1 );
311 
312 	if( rc != LDAP_SUCCESS ) {
313 		tool_perror( "ldap_extended_operation", rc, NULL, NULL, NULL, NULL );
314 		rc = EXIT_FAILURE;
315 		goto done;
316 	}
317 
318 	for ( ; ; ) {
319 		struct timeval	tv;
320 
321 		if ( tool_check_abandon( ld, id ) ) {
322 			return LDAP_CANCELLED;
323 		}
324 
325 		tv.tv_sec = 0;
326 		tv.tv_usec = 100000;
327 
328 		rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
329 		if ( rc < 0 ) {
330 			tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
331 			return rc;
332 		}
333 
334 		if ( rc != 0 ) {
335 			break;
336 		}
337 	}
338 
339 	rc = ldap_parse_result( ld, res,
340 		&code, &matcheddn, &text, &refs, &ctrls, 0 );
341 	if( rc != LDAP_SUCCESS ) {
342 		tool_perror( "ldap_parse_result", rc, NULL, NULL, NULL, NULL );
343 		rc = EXIT_FAILURE;
344 		goto done;
345 	}
346 
347 	rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 );
348 	if( rc != LDAP_SUCCESS ) {
349 		tool_perror( "ldap_parse_extended_result", rc, NULL, NULL, NULL, NULL );
350 		rc = EXIT_FAILURE;
351 		goto done;
352 	}
353 
354 	if( retdata != NULL ) {
355 		ber_tag_t tag;
356 		char *s;
357 		ber = ber_init( retdata );
358 
359 		if( ber == NULL ) {
360 			perror( "ber_init" );
361 			rc = EXIT_FAILURE;
362 			goto done;
363 		}
364 
365 		/* we should check the tag */
366 		tag = ber_scanf( ber, "{a}", &s);
367 
368 		if( tag == LBER_ERROR ) {
369 			perror( "ber_scanf" );
370 		} else {
371 			printf(_("New password: %s\n"), s);
372 			ber_memfree( s );
373 		}
374 
375 		ber_free( ber, 1 );
376 
377 	} else if ( code == LDAP_SUCCESS && newpw.bv_val == NULL ) {
378 		tool_perror( "ldap_parse_extended_result", LDAP_DECODING_ERROR,
379 			" new password expected", NULL, NULL, NULL );
380 	}
381 
382 	if( verbose || code != LDAP_SUCCESS ||
383 		matcheddn || text || refs || ctrls )
384 	{
385 		printf( _("Result: %s (%d)\n"), ldap_err2string( code ), code );
386 
387 		if( text && *text ) {
388 			printf( _("Additional info: %s\n"), text );
389 		}
390 
391 		if( matcheddn && *matcheddn ) {
392 			printf( _("Matched DN: %s\n"), matcheddn );
393 		}
394 
395 		if( refs ) {
396 			int i;
397 			for( i=0; refs[i]; i++ ) {
398 				printf(_("Referral: %s\n"), refs[i] );
399 			}
400 		}
401 
402 		if( ctrls ) {
403 			tool_print_ctrls( ld, ctrls );
404 			ldap_controls_free( ctrls );
405 		}
406 	}
407 
408 	ber_memfree( text );
409 	ber_memfree( matcheddn );
410 	ber_memvfree( (void **) refs );
411 	ber_memfree( retoid );
412 	ber_bvfree( retdata );
413 
414 	rc = ( code == LDAP_SUCCESS ) ? EXIT_SUCCESS : EXIT_FAILURE;
415 
416 done:
417 	/* disconnect from server */
418 	if ( ld )
419 		tool_unbind( ld );
420 	tool_destroy();
421 	return rc;
422 }
423