xref: /netbsd-src/external/bsd/openldap/dist/clients/tools/common.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: common.c,v 1.10 2021/08/14 16:14:49 christos Exp $	*/
2 
3 /* common.c - common routines for the ldap client tools */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2021 The OpenLDAP Foundation.
8  * Portions Copyright 2003 Kurt D. Zeilenga.
9  * Portions Copyright 2003 IBM Corporation.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This file was initially created by Hallvard B. Furuseth based (in
22  * part) upon argument parsing code for individual tools located in
23  * this directory.   Additional contributors include:
24  *   Kurt D. Zeilenga (additional common argument and control support)
25  */
26 
27 #include <sys/cdefs.h>
28 __RCSID("$NetBSD: common.c,v 1.10 2021/08/14 16:14:49 christos Exp $");
29 
30 #include "portable.h"
31 
32 #include <stdio.h>
33 
34 #include <ac/stdlib.h>
35 #include <ac/signal.h>
36 #include <ac/string.h>
37 #include <ac/ctype.h>
38 #include <ac/unistd.h>
39 #include <ac/errno.h>
40 #include <ac/time.h>
41 #include <ac/socket.h>
42 
43 #ifdef HAVE_CYRUS_SASL
44 #ifdef HAVE_SASL_SASL_H
45 #include <sasl/sasl.h>
46 #else
47 #include <sasl.h>
48 #endif
49 #endif
50 
51 #include <ldap.h>
52 
53 #include "ldif.h"
54 #include "lutil.h"
55 #include "lutil_ldap.h"
56 #include "ldap_defaults.h"
57 #include "ldap_pvt.h"
58 #include "lber_pvt.h"
59 
60 #include "common.h"
61 
62 /* input-related vars */
63 
64 /* misc. parameters */
65 tool_type_t	tool_type;
66 int		contoper = 0;
67 int		debug = 0;
68 char		*infile = NULL;
69 int		dont = 0;
70 int		nocanon = 0;
71 int		referrals = 0;
72 int		verbose = 0;
73 int		ldif = 0;
74 ber_len_t	ldif_wrap = 0;
75 char		*prog = NULL;
76 
77 /* connection */
78 char		*ldapuri = NULL;
79 int		use_tls = 0;
80 int		protocol = -1;
81 int		version = 0;
82 
83 /* authc/authz */
84 int		authmethod = -1;
85 char		*binddn = NULL;
86 int		want_bindpw = 0;
87 struct berval	passwd = { 0, NULL };
88 char		*pw_file = NULL;
89 #ifdef HAVE_CYRUS_SASL
90 unsigned	sasl_flags = LDAP_SASL_AUTOMATIC;
91 char		*sasl_realm = NULL;
92 char		*sasl_authc_id = NULL;
93 char		*sasl_authz_id = NULL;
94 char		*sasl_mech = NULL;
95 char		*sasl_secprops = NULL;
96 #endif
97 
98 /* controls */
99 int		assertctl;
100 char		*assertion = NULL;
101 struct berval	assertionvalue = BER_BVNULL;
102 char		*authzid = NULL;
103 int		authzcrit = 1;
104 /* support deprecated early version of proxyAuthz */
105 #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ	"2.16.840.1.113730.3.4.12"
106 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
107 char		*proxydn = NULL;
108 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
109 int		manageDIT = 0;
110 int		manageDSAit = 0;
111 int		noop = 0;
112 int		ppolicy = 0;
113 int		preread = 0;
114 static char	*preread_attrs = NULL;
115 int		postread = 0;
116 static char	*postread_attrs = NULL;
117 ber_int_t	pr_morePagedResults = 1;
118 struct berval	pr_cookie = { 0, NULL };
119 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
120 int		chaining = 0;
121 static int	chainingResolve = -1;
122 static int	chainingContinuation = -1;
123 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
124 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
125 static int	sessionTracking = 0;
126 static char	*sessionTrackingName;
127 struct berval	stValue;
128 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
129 ber_int_t vlvPos;
130 ber_int_t vlvCount;
131 struct berval *vlvContext;
132 static int	bauthzid;
133 
134 LDAPControl	*unknown_ctrls = NULL;
135 int		unknown_ctrls_num = 0;
136 
137 /* options */
138 struct timeval	nettimeout = { -1 , 0 };
139 
140 typedef int (*print_ctrl_fn)( LDAP *ld, LDAPControl *ctrl );
141 
142 static int print_preread( LDAP *ld, LDAPControl *ctrl );
143 static int print_postread( LDAP *ld, LDAPControl *ctrl );
144 static int print_paged_results( LDAP *ld, LDAPControl *ctrl );
145 static int print_psearch( LDAP *ld, LDAPControl *ctrl );
146 #ifdef LDAP_CONTROL_AUTHZID_RESPONSE
147 static int print_authzid( LDAP *ld, LDAPControl *ctrl );
148 #endif
149 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
150 static int print_ppolicy( LDAP *ld, LDAPControl *ctrl );
151 #endif
152 static int print_sss( LDAP *ld, LDAPControl *ctrl );
153 static int print_vlv( LDAP *ld, LDAPControl *ctrl );
154 #ifdef LDAP_CONTROL_X_DEREF
155 static int print_deref( LDAP *ld, LDAPControl *ctrl );
156 #endif
157 #ifdef LDAP_CONTROL_X_WHATFAILED
158 static int print_whatfailed( LDAP *ld, LDAPControl *ctrl );
159 #endif
160 static int print_syncstate( LDAP *ld, LDAPControl *ctrl );
161 static int print_syncdone( LDAP *ld, LDAPControl *ctrl );
162 #ifdef LDAP_CONTROL_X_DIRSYNC
163 static int print_dirsync( LDAP *ld, LDAPControl *ctrl );
164 #endif
165 #ifdef LDAP_CONTROL_X_ACCOUNT_USABILITY
166 static int print_account_usability( LDAP *ld, LDAPControl *ctrl );
167 #endif
168 #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRED
169 static int print_netscape_pwexpired( LDAP *ld, LDAPControl *ctrl );
170 static int print_netscape_pwexpiring( LDAP *ld, LDAPControl *ctrl );
171 #endif
172 
173 static struct tool_ctrls_t {
174 	const char	*oid;
175 	unsigned	mask;
176 	print_ctrl_fn	func;
177 } tool_ctrl_response[] = {
178 	{ LDAP_CONTROL_PRE_READ,			TOOL_ALL,	print_preread },
179 	{ LDAP_CONTROL_POST_READ,			TOOL_ALL,	print_postread },
180 	{ LDAP_CONTROL_PAGEDRESULTS,			TOOL_SEARCH,	print_paged_results },
181 	{ LDAP_CONTROL_PERSIST_ENTRY_CHANGE_NOTICE,			TOOL_SEARCH,	print_psearch },
182 #ifdef LDAP_CONTROL_AUTHZID_RESPONSE
183 	/* this is generally deprecated in favor of LDAP WhoAmI? operation, hence only supported as a VC inner control */
184 	{ LDAP_CONTROL_AUTHZID_RESPONSE,		TOOL_VC,	print_authzid },
185 #endif
186 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
187 	{ LDAP_CONTROL_PASSWORDPOLICYRESPONSE,		TOOL_ALL,	print_ppolicy },
188 #endif
189 	{ LDAP_CONTROL_SORTRESPONSE,	TOOL_SEARCH,	print_sss },
190 	{ LDAP_CONTROL_VLVRESPONSE,		TOOL_SEARCH,	print_vlv },
191 #ifdef LDAP_CONTROL_X_DEREF
192 	{ LDAP_CONTROL_X_DEREF,				TOOL_SEARCH,	print_deref },
193 #endif
194 #ifdef LDAP_CONTROL_X_WHATFAILED
195 	{ LDAP_CONTROL_X_WHATFAILED,			TOOL_ALL,	print_whatfailed },
196 #endif
197 	{ LDAP_CONTROL_SYNC_STATE,			TOOL_SEARCH,	print_syncstate },
198 	{ LDAP_CONTROL_SYNC_DONE,			TOOL_SEARCH,	print_syncdone },
199 #ifdef LDAP_CONTROL_X_DIRSYNC
200 	{ LDAP_CONTROL_X_DIRSYNC,			TOOL_SEARCH,	print_dirsync },
201 #endif
202 #ifdef LDAP_CONTROL_X_ACCOUNT_USABILITY
203 	{ LDAP_CONTROL_X_ACCOUNT_USABILITY,		TOOL_SEARCH,	print_account_usability },
204 #endif
205 #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRED
206 	{ LDAP_CONTROL_X_PASSWORD_EXPIRED,		TOOL_ALL,	print_netscape_pwexpired },
207 	{ LDAP_CONTROL_X_PASSWORD_EXPIRING,		TOOL_ALL,	print_netscape_pwexpiring },
208 #endif
209 	{ NULL,						0,		NULL }
210 };
211 
212 /* "features" */
213 enum { Intr_None = 0, Intr_Abandon, Intr_Cancel, Intr_Ignore };
214 static volatile sig_atomic_t	gotintr, abcan;
215 
216 int backlog;
217 
218 
219 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
220 static int
st_value(LDAP * ld,struct berval * value)221 st_value( LDAP *ld, struct berval *value )
222 {
223 	char		*ip = NULL, *name = NULL;
224 	struct berval	id = { 0 };
225 	char		namebuf[ MAXHOSTNAMELEN ];
226 
227 	if ( gethostname( namebuf, sizeof( namebuf ) ) == 0 ) {
228 		struct hostent	*h;
229 		struct in_addr	addr;
230 
231 		name = namebuf;
232 
233 		h = gethostbyname( name );
234 		if ( h != NULL ) {
235 			AC_MEMCPY( &addr, h->h_addr, sizeof( addr ) );
236 			ip = inet_ntoa( addr );
237 		}
238 	}
239 
240 	if ( sessionTrackingName != NULL ) {
241 		ber_str2bv( sessionTrackingName , 0, 0, &id );
242 	} else
243 #ifdef HAVE_CYRUS_SASL
244 	if ( sasl_authz_id != NULL ) {
245 		ber_str2bv( sasl_authz_id, 0, 0, &id );
246 
247 	} else if ( sasl_authc_id != NULL ) {
248 		ber_str2bv( sasl_authc_id, 0, 0, &id );
249 
250 	} else
251 #endif /* HAVE_CYRUS_SASL */
252 	if ( binddn != NULL ) {
253 		ber_str2bv( binddn, 0, 0, &id );
254 	}
255 
256 	if ( ldap_create_session_tracking_value( ld,
257 		ip, name, LDAP_CONTROL_X_SESSION_TRACKING_USERNAME,
258 		&id, &stValue ) )
259 	{
260 		fprintf( stderr, _("Session tracking control encoding error!\n") );
261 		return -1;
262 	}
263 
264 	return 0;
265 }
266 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
267 
268 RETSIGTYPE
do_sig(int sig)269 do_sig( int sig )
270 {
271 	gotintr = abcan;
272 }
273 
274 void
tool_init(tool_type_t type)275 tool_init( tool_type_t type )
276 {
277 	tool_type = type;
278 	ldap_pvt_setlocale(LC_MESSAGES, "");
279 	ldap_pvt_bindtextdomain(OPENLDAP_PACKAGE, LDAP_LOCALEDIR);
280 	ldap_pvt_textdomain(OPENLDAP_PACKAGE);
281 }
282 
283 void
tool_destroy(void)284 tool_destroy( void )
285 {
286 	static int destroyed;
287 	if ( destroyed++ )
288 		return;
289 
290 #ifdef HAVE_CYRUS_SASL
291 	sasl_done();
292 #endif
293 #ifdef HAVE_TLS
294 	ldap_pvt_tls_destroy();
295 #endif
296 
297 	if ( ldapuri != NULL ) {
298 		ber_memfree( ldapuri );
299 		ldapuri = NULL;
300 	}
301 
302 	if ( pr_cookie.bv_val != NULL ) {
303 		ber_memfree( pr_cookie.bv_val );
304 		BER_BVZERO( &pr_cookie );
305 	}
306 
307 	if ( passwd.bv_val != NULL ) {
308 		ber_memfree( passwd.bv_val );
309 		BER_BVZERO( &passwd );
310 	}
311 
312 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
313 	if ( !BER_BVISNULL( &stValue ) ) {
314 		ber_memfree( stValue.bv_val );
315 		BER_BVZERO( &stValue );
316 	}
317 
318 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
319 }
320 
321 void
tool_common_usage(void)322 tool_common_usage( void )
323 {
324 	static const char *const descriptions[] = {
325 N_("  -d level   set LDAP debugging level to `level'\n"),
326 N_("  -D binddn  bind DN\n"),
327 N_("  -e [!]<ext>[=<extparam>] general extensions (! indicates criticality)\n")
328 N_("             [!]assert=<filter>     (RFC 4528; a RFC 4515 Filter string)\n")
329 N_("             [!]authzid=<authzid>   (RFC 4370; \"dn:<dn>\" or \"u:<user>\")\n")
330 N_("             [!]bauthzid            (RFC 3829)\n")
331 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
332 #if 0
333                  /* non-advertized support for proxyDN */
334 N_("             [!]proxydn=<dn>        (a RFC 4514 DN string)\n")
335 #endif
336 #endif
337 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
338 N_("             [!]chaining[=<resolveBehavior>[/<continuationBehavior>]]\n")
339 N_("                     one of \"chainingPreferred\", \"chainingRequired\",\n")
340 N_("                     \"referralsPreferred\", \"referralsRequired\"\n")
341 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
342 N_("             [!]manageDSAit         (RFC 3296)\n")
343 N_("             [!]noop\n")
344 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
345 N_("             ppolicy\n")
346 #endif
347 N_("             [!]postread[=<attrs>]  (RFC 4527; comma-separated attr list)\n")
348 N_("             [!]preread[=<attrs>]   (RFC 4527; comma-separated attr list)\n")
349 N_("             [!]relax\n")
350 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
351 N_("             [!]sessiontracking[=<username>]\n")
352 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
353 N_("             abandon, cancel, ignore (SIGINT sends abandon/cancel,\n"
354    "             or ignores response; if critical, doesn't wait for SIGINT.\n"
355    "             not really controls)\n")
356 N_("  -H URI     LDAP Uniform Resource Identifier(s)\n"),
357 N_("  -I         use SASL Interactive mode\n"),
358 N_("  -n         show what would be done but don't actually do it\n"),
359 N_("  -N         do not use reverse DNS to canonicalize SASL host name\n"),
360 N_("  -O props   SASL security properties\n"),
361 N_("  -o <opt>[=<optparam>] any libldap ldap.conf options, plus\n"),
362 N_("             ldif_wrap=<width> (in columns, or \"no\" for no wrapping)\n"),
363 N_("             nettimeout=<timeout> (in seconds, or \"none\" or \"max\")\n"),
364 N_("  -Q         use SASL Quiet mode\n"),
365 N_("  -R realm   SASL realm\n"),
366 N_("  -U authcid SASL authentication identity\n"),
367 N_("  -v         run in verbose mode (diagnostics to standard output)\n"),
368 N_("  -V         print version info (-VV only)\n"),
369 N_("  -w passwd  bind password (for simple authentication)\n"),
370 N_("  -W         prompt for bind password\n"),
371 N_("  -x         Simple authentication\n"),
372 N_("  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"),
373 N_("  -y file    Read password from file\n"),
374 N_("  -Y mech    SASL mechanism\n"),
375 N_("  -Z         Start TLS request (-ZZ to require successful response)\n"),
376 NULL
377 	};
378 	const char *const *cpp;
379 
380 	fputs( _("Common options:\n"), stderr );
381 	for( cpp = descriptions; *cpp != NULL; cpp++ ) {
382 		if( strchr( options, (*cpp)[3] ) || (*cpp)[3] == ' ' ) {
383 			fputs( _(*cpp), stderr );
384 		}
385 	}
386 
387 	tool_destroy();
388 }
389 
tool_perror(const char * func,int err,const char * extra,const char * matched,const char * info,char ** refs)390 void tool_perror(
391 	const char *func,
392 	int err,
393 	const char *extra,
394 	const char *matched,
395 	const char *info,
396 	char **refs )
397 {
398 	fprintf( stderr, "%s: %s (%d)%s\n",
399 		func, ldap_err2string( err ), err, extra ? extra : "" );
400 
401 	if ( matched && *matched ) {
402 		fprintf( stderr, _("\tmatched DN: %s\n"), matched );
403 	}
404 
405 	if ( info && *info ) {
406 		fprintf( stderr, _("\tadditional info: %s\n"), info );
407 	}
408 
409 	if ( refs && *refs ) {
410 		int i;
411 		fprintf( stderr, _("\treferrals:\n") );
412 		for( i=0; refs[i]; i++ ) {
413 			fprintf( stderr, "\t\t%s\n", refs[i] );
414 		}
415 	}
416 }
417 
418 
419 void
tool_args(int argc,char ** argv)420 tool_args( int argc, char **argv )
421 {
422 	int i;
423 
424 	while (( i = getopt( argc, argv, options )) != EOF ) {
425 		int crit, ival;
426 		char *control, *cvalue, *next;
427 		switch( i ) {
428 		case 'c':	/* continuous operation mode */
429 			contoper++;
430 			break;
431 		case 'C':	/* referrals: obsolete */
432 			referrals++;
433 			break;
434 		case 'd':
435 			ival = strtol( optarg, &next, 10 );
436 			if (next == NULL || next[0] != '\0') {
437 				fprintf( stderr, "%s: unable to parse debug value \"%s\"\n", prog, optarg);
438 				exit(EXIT_FAILURE);
439 			}
440 			debug |= ival;
441 			break;
442 		case 'D':	/* bind DN */
443 			if( binddn != NULL ) {
444 				fprintf( stderr, "%s: -D previously specified\n", prog );
445 				exit( EXIT_FAILURE );
446 			}
447 			binddn = optarg;
448 			break;
449 		case 'e':	/* general extensions (controls and such) */
450 			/* should be extended to support comma separated list of
451 			 *	[!]key[=value] parameters, e.g.  -e !foo,bar=567
452 			 */
453 
454 			crit = 0;
455 			cvalue = NULL;
456 			while ( optarg[0] == '!' ) {
457 				crit++;
458 				optarg++;
459 			}
460 
461 			control = optarg;
462 			if ( (cvalue = strchr( control, '=' )) != NULL ) {
463 				*cvalue++ = '\0';
464 			}
465 
466 			if ( strcasecmp( control, "assert" ) == 0 ) {
467 				if( assertctl ) {
468 					fprintf( stderr, "assert control previously specified\n");
469 					exit( EXIT_FAILURE );
470 				}
471 				if( cvalue == NULL ) {
472 					fprintf( stderr, "assert: control value expected\n" );
473 					usage();
474 				}
475 
476 				assertctl = 1 + crit;
477 
478 				assert( assertion == NULL );
479 				assertion = cvalue;
480 
481 			} else if ( strcasecmp( control, "authzid" ) == 0 ) {
482 				if( authzid != NULL ) {
483 					fprintf( stderr, "authzid control previously specified\n");
484 					exit( EXIT_FAILURE );
485 				}
486 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
487 				if( proxydn != NULL ) {
488 					fprintf( stderr, "authzid control incompatible with proxydn\n");
489 					exit( EXIT_FAILURE );
490 				}
491 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
492 				if( cvalue == NULL ) {
493 					fprintf( stderr, "authzid: control value expected\n" );
494 					usage();
495 				}
496 				if( !crit ) {
497 					fprintf( stderr, "authzid: must be marked critical\n" );
498 					usage();
499 				} else if ( crit > 1 ) {
500 					/* purposely flag proxied authorization
501 					 * as non-critical, to test DSA */
502 					authzcrit = 0;
503 				}
504 
505 				assert( authzid == NULL );
506 				authzid = cvalue;
507 
508 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
509 			} else if ( strcasecmp( control, "proxydn" ) == 0 ) {
510 				if( proxydn != NULL ) {
511 					fprintf( stderr, "proxydn control previously specified\n");
512 					exit( EXIT_FAILURE );
513 				}
514 				if( authzid != NULL ) {
515 					fprintf( stderr, "proxydn control incompatible with authzid\n");
516 					exit( EXIT_FAILURE );
517 				}
518 				if( cvalue == NULL ) {
519 					fprintf( stderr, "proxydn: control value expected\n" );
520 					usage();
521 				}
522 				if( !crit ) {
523 					fprintf( stderr, "proxydn: must be marked critical\n" );
524 					usage();
525 				} else if ( crit > 1 ) {
526 					/* purposely flag proxied authorization
527 					 * as non-critical, to test DSA */
528 					authzcrit = 0;
529 				}
530 
531 				assert( proxydn == NULL );
532 				proxydn = cvalue;
533 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
534 
535 			} else if ( strcasecmp( control, "bauthzid" ) == 0 ) {
536 				if( bauthzid ) {
537 					fprintf( stderr, "bauthzid control previously specified\n");
538 					exit( EXIT_FAILURE );
539 				}
540 				if( cvalue != NULL ) {
541 					fprintf( stderr, "bauthzid: no control value expected\n" );
542 					usage();
543 				}
544 				bauthzid = 1 + crit;
545 
546 			} else if ( ( strcasecmp( control, "relax" ) == 0 ) ||
547 				( strcasecmp( control, "manageDIT" ) == 0 ) )
548 			{
549 				if( manageDIT ) {
550 					fprintf( stderr,
551 						"relax control previously specified\n");
552 					exit( EXIT_FAILURE );
553 				}
554 				if( cvalue != NULL ) {
555 					fprintf( stderr,
556 						"relax: no control value expected\n" );
557 					usage();
558 				}
559 
560 				manageDIT = 1 + crit;
561 
562 			} else if ( strcasecmp( control, "manageDSAit" ) == 0 ) {
563 				if( manageDSAit ) {
564 					fprintf( stderr,
565 						"manageDSAit control previously specified\n");
566 					exit( EXIT_FAILURE );
567 				}
568 				if( cvalue != NULL ) {
569 					fprintf( stderr,
570 						"manageDSAit: no control value expected\n" );
571 					usage();
572 				}
573 
574 				manageDSAit = 1 + crit;
575 
576 			} else if ( strcasecmp( control, "noop" ) == 0 ) {
577 				if( noop ) {
578 					fprintf( stderr, "noop control previously specified\n");
579 					exit( EXIT_FAILURE );
580 				}
581 				if( cvalue != NULL ) {
582 					fprintf( stderr, "noop: no control value expected\n" );
583 					usage();
584 				}
585 
586 				noop = 1 + crit;
587 
588 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
589 			} else if ( strcasecmp( control, "ppolicy" ) == 0 ) {
590 				if( ppolicy ) {
591 					fprintf( stderr, "ppolicy control previously specified\n");
592 					exit( EXIT_FAILURE );
593 				}
594 				if( cvalue != NULL ) {
595 					fprintf( stderr, "ppolicy: no control value expected\n" );
596 					usage();
597 				}
598 				if( crit ) {
599 					fprintf( stderr, "ppolicy: critical flag not allowed\n" );
600 					usage();
601 				}
602 
603 				ppolicy = 1;
604 #endif
605 
606 			} else if ( strcasecmp( control, "preread" ) == 0 ) {
607 				if( preread ) {
608 					fprintf( stderr, "preread control previously specified\n");
609 					exit( EXIT_FAILURE );
610 				}
611 
612 				preread = 1 + crit;
613 				preread_attrs = cvalue;
614 
615 			} else if ( strcasecmp( control, "postread" ) == 0 ) {
616 				if( postread ) {
617 					fprintf( stderr, "postread control previously specified\n");
618 					exit( EXIT_FAILURE );
619 				}
620 
621 				postread = 1 + crit;
622 				postread_attrs = cvalue;
623 
624 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
625 			} else if ( strcasecmp( control, "chaining" ) == 0 ) {
626 				if ( chaining ) {
627 					fprintf( stderr, "chaining control previously specified\n");
628 					exit( EXIT_FAILURE );
629 				}
630 
631 				chaining = 1 + crit;
632 
633 				if ( cvalue != NULL ) {
634 					char	*continuation;
635 
636 					continuation = strchr( cvalue, '/' );
637 					if ( continuation ) {
638 						/* FIXME: this makes sense only in searches */
639 						*continuation++ = '\0';
640 						if ( strcasecmp( continuation, "chainingPreferred" ) == 0 ) {
641 							chainingContinuation = LDAP_CHAINING_PREFERRED;
642 						} else if ( strcasecmp( continuation, "chainingRequired" ) == 0 ) {
643 							chainingContinuation = LDAP_CHAINING_REQUIRED;
644 						} else if ( strcasecmp( continuation, "referralsPreferred" ) == 0 ) {
645 							chainingContinuation = LDAP_REFERRALS_PREFERRED;
646 						} else if ( strcasecmp( continuation, "referralsRequired" ) == 0 ) {
647 							chainingContinuation = LDAP_REFERRALS_REQUIRED;
648 						} else {
649 							fprintf( stderr,
650 								"chaining behavior control "
651 								"continuation value \"%s\" invalid\n",
652 								continuation );
653 							exit( EXIT_FAILURE );
654 						}
655 					}
656 
657 					if ( strcasecmp( cvalue, "chainingPreferred" ) == 0 ) {
658 						chainingResolve = LDAP_CHAINING_PREFERRED;
659 					} else if ( strcasecmp( cvalue, "chainingRequired" ) == 0 ) {
660 						chainingResolve = LDAP_CHAINING_REQUIRED;
661 					} else if ( strcasecmp( cvalue, "referralsPreferred" ) == 0 ) {
662 						chainingResolve = LDAP_REFERRALS_PREFERRED;
663 					} else if ( strcasecmp( cvalue, "referralsRequired" ) == 0 ) {
664 						chainingResolve = LDAP_REFERRALS_REQUIRED;
665 					} else {
666 						fprintf( stderr,
667 							"chaining behavior control "
668 							"resolve value \"%s\" invalid\n",
669 							cvalue);
670 						exit( EXIT_FAILURE );
671 					}
672 				}
673 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
674 
675 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
676 			} else if ( strcasecmp( control, "sessiontracking" ) == 0 ) {
677 				if ( sessionTracking ) {
678 					fprintf( stderr, "%s: session tracking can be only specified once\n", prog );
679 					exit( EXIT_FAILURE );
680 				}
681 				sessionTracking = 1;
682 				if ( crit ) {
683 					fprintf( stderr, "sessiontracking: critical flag not allowed\n" );
684 					usage();
685 				}
686 				if ( cvalue ) {
687 					sessionTrackingName = cvalue;
688 				}
689 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
690 
691 			/* this shouldn't go here, really; but it's a feature... */
692 			} else if ( strcasecmp( control, "abandon" ) == 0 ) {
693 				abcan = Intr_Abandon;
694 				if ( crit ) {
695 					gotintr = abcan;
696 				}
697 
698 			} else if ( strcasecmp( control, "cancel" ) == 0 ) {
699 				abcan = Intr_Cancel;
700 				if ( crit ) {
701 					gotintr = abcan;
702 				}
703 
704 			} else if ( strcasecmp( control, "ignore" ) == 0 ) {
705 				abcan = Intr_Ignore;
706 				if ( crit ) {
707 					gotintr = abcan;
708 				}
709 
710 			} else if ( strcasecmp( control, "backlog" ) == 0 ) {
711 				/* special search: accumulate lots of responses
712 				 * but don't read any, force slapd writer to wait.
713 				 * Then abandon the search and issue a new one.
714 				 */
715 				backlog = 1;
716 
717 			} else if ( tool_is_oid( control ) ) {
718 				LDAPControl	*tmpctrls, ctrl;
719 
720 				if ( unknown_ctrls != NULL ) {
721 					int i;
722 					for ( i = 0; unknown_ctrls[ i ].ldctl_oid != NULL; i++ ) {
723 						if ( strcmp( control, unknown_ctrls[ i ].ldctl_oid ) == 0 ) {
724 							fprintf( stderr, "%s control previously specified\n", control );
725 							exit( EXIT_FAILURE );
726 						}
727 					}
728 				}
729 
730 				tmpctrls = (LDAPControl *)ber_memrealloc( unknown_ctrls,
731 					(unknown_ctrls_num + 1)*sizeof( LDAPControl ) );
732 				if ( tmpctrls == NULL ) {
733 					fprintf( stderr, "%s: no memory?\n", prog );
734 					exit( EXIT_FAILURE );
735 				}
736 				unknown_ctrls = tmpctrls;
737 				ctrl.ldctl_oid = control;
738 				ctrl.ldctl_value.bv_val = NULL;
739 				ctrl.ldctl_value.bv_len = 0;
740 				ctrl.ldctl_iscritical = crit;
741 
742 				if ( cvalue != NULL ) {
743 					struct berval	bv;
744 					size_t		len = strlen( cvalue );
745 					int		retcode;
746 
747 					bv.bv_len = LUTIL_BASE64_DECODE_LEN( len );
748 					bv.bv_val = ber_memalloc( bv.bv_len + 1 );
749 
750 					retcode = lutil_b64_pton( cvalue,
751 						(unsigned char *)bv.bv_val,
752 						bv.bv_len );
753 
754 					if ( retcode == -1 || (unsigned) retcode > bv.bv_len ) {
755 						fprintf( stderr, "Unable to parse value of general control %s\n",
756 							control );
757 						usage();
758 					}
759 
760 					bv.bv_len = retcode;
761 					ctrl.ldctl_value = bv;
762 				}
763 
764 				/* don't free it */
765 				control = NULL;
766 				unknown_ctrls[ unknown_ctrls_num ] = ctrl;
767 				unknown_ctrls_num++;
768 
769 			} else {
770 				fprintf( stderr, "Invalid general control name: %s\n",
771 					control );
772 				usage();
773 			}
774 			break;
775 		case 'f':	/* read from file */
776 			if( infile != NULL ) {
777 				fprintf( stderr, "%s: -f previously specified\n", prog );
778 				exit( EXIT_FAILURE );
779 			}
780 			infile = optarg;
781 			break;
782 		case 'H':	/* ldap URI */
783 			if( ldapuri != NULL ) {
784 				fprintf( stderr, "%s: -H previously specified\n", prog );
785 				exit( EXIT_FAILURE );
786 			}
787 			ldapuri = ber_strdup( optarg );
788 			break;
789 		case 'I':
790 #ifdef HAVE_CYRUS_SASL
791 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
792 				fprintf( stderr, "%s: incompatible previous "
793 					"authentication choice\n",
794 					prog );
795 				exit( EXIT_FAILURE );
796 			}
797 			authmethod = LDAP_AUTH_SASL;
798 			sasl_flags = LDAP_SASL_INTERACTIVE;
799 			break;
800 #else
801 			fprintf( stderr, "%s: was not compiled with SASL support\n",
802 				prog );
803 			exit( EXIT_FAILURE );
804 #endif
805 		case 'M':
806 			/* enable Manage DSA IT */
807 			manageDSAit++;
808 			break;
809 		case 'n':	/* print operations, don't actually do them */
810 			dont++;
811 			break;
812 		case 'N':
813 			nocanon++;
814 			break;
815 		case 'o':
816 			control = optarg;
817 			if ( (cvalue = strchr( control, '=' )) != NULL ) {
818 				*cvalue++ = '\0';
819 			}
820 			for ( next=control; *next; next++ ) {
821 				if ( *next == '-' ) {
822 					*next = '_';
823 				}
824 			}
825 
826 			if ( strcasecmp( control, "nettimeout" ) == 0 ) {
827 				if( nettimeout.tv_sec != -1 ) {
828 					fprintf( stderr, "nettimeout option previously specified\n");
829 					exit( EXIT_FAILURE );
830 				}
831 				if( cvalue == NULL || cvalue[0] == '\0' ) {
832 					fprintf( stderr, "nettimeout: option value expected\n" );
833 					usage();
834 				}
835 		 		if ( strcasecmp( cvalue, "none" ) == 0 ) {
836 		 			nettimeout.tv_sec = 0;
837 		 		} else if ( strcasecmp( cvalue, "max" ) == 0 ) {
838 		 			nettimeout.tv_sec = LDAP_MAXINT;
839 		 		} else {
840 		 			ival = strtol( cvalue, &next, 10 );
841 		 			if ( next == NULL || next[0] != '\0' ) {
842 		 				fprintf( stderr,
843 		 					_("Unable to parse network timeout \"%s\"\n"), cvalue );
844 		 				exit( EXIT_FAILURE );
845 		 			}
846 		 			nettimeout.tv_sec = ival;
847 		 		}
848 		 		if( nettimeout.tv_sec < 0 || nettimeout.tv_sec > LDAP_MAXINT ) {
849 		 			fprintf( stderr, _("%s: invalid network timeout (%ld) specified\n"),
850 		 				prog, (long)nettimeout.tv_sec );
851 	 				exit( EXIT_FAILURE );
852  				}
853 
854 			} else if ( strcasecmp( control, "ldif_wrap" ) == 0 ) {
855 				if ( cvalue == 0 ) {
856 					ldif_wrap = LDIF_LINE_WIDTH;
857 
858 				} else if ( strcasecmp( cvalue, "no" ) == 0 ) {
859 					ldif_wrap = LDIF_LINE_WIDTH_MAX;
860 
861 				} else {
862 					unsigned int u;
863 					if ( lutil_atou( &u, cvalue ) ) {
864 						fprintf( stderr,
865 							_("Unable to parse ldif_wrap=\"%s\"\n"), cvalue );
866 		 				exit( EXIT_FAILURE );
867 					}
868 					ldif_wrap = (ber_len_t)u;
869 				}
870 
871 			} else if ( ldap_pvt_conf_option( control, cvalue, 1 ) ) {
872 				fprintf( stderr, "Invalid general option name: %s\n",
873 					control );
874 				usage();
875 			}
876 			break;
877 		case 'O':
878 #ifdef HAVE_CYRUS_SASL
879 			if( sasl_secprops != NULL ) {
880 				fprintf( stderr, "%s: -O previously specified\n", prog );
881 				exit( EXIT_FAILURE );
882 			}
883 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
884 				fprintf( stderr, "%s: incompatible previous "
885 					"authentication choice\n", prog );
886 				exit( EXIT_FAILURE );
887 			}
888 			authmethod = LDAP_AUTH_SASL;
889 			sasl_secprops = optarg;
890 #else
891 			fprintf( stderr, "%s: not compiled with SASL support\n", prog );
892 			exit( EXIT_FAILURE );
893 #endif
894 			break;
895 		case 'P':
896 			ival = strtol( optarg, &next, 10 );
897 			if ( next == NULL || next[0] != '\0' ) {
898 				fprintf( stderr, "%s: unable to parse protocol version \"%s\"\n", prog, optarg );
899 				exit( EXIT_FAILURE );
900 			}
901 			switch( ival ) {
902 			case 2:
903 				if( protocol == LDAP_VERSION3 ) {
904 					fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
905 						prog, protocol );
906 					exit( EXIT_FAILURE );
907 				}
908 				protocol = LDAP_VERSION2;
909 				break;
910 			case 3:
911 				if( protocol == LDAP_VERSION2 ) {
912 					fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
913 						prog, protocol );
914 					exit( EXIT_FAILURE );
915 				}
916 				protocol = LDAP_VERSION3;
917 				break;
918 			default:
919 				fprintf( stderr, "%s: protocol version should be 2 or 3\n",
920 					prog );
921 				usage();
922 			}
923 			break;
924 		case 'Q':
925 #ifdef HAVE_CYRUS_SASL
926 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
927 				fprintf( stderr, "%s: incompatible previous "
928 					"authentication choice\n",
929 					prog );
930 				exit( EXIT_FAILURE );
931 			}
932 			authmethod = LDAP_AUTH_SASL;
933 			sasl_flags = LDAP_SASL_QUIET;
934 			break;
935 #else
936 			fprintf( stderr, "%s: not compiled with SASL support\n",
937 				prog );
938 			exit( EXIT_FAILURE );
939 #endif
940 		case 'R':
941 #ifdef HAVE_CYRUS_SASL
942 			if( sasl_realm != NULL ) {
943 				fprintf( stderr, "%s: -R previously specified\n", prog );
944 				exit( EXIT_FAILURE );
945 			}
946 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
947 				fprintf( stderr, "%s: incompatible previous "
948 					"authentication choice\n",
949 					prog );
950 				exit( EXIT_FAILURE );
951 			}
952 			authmethod = LDAP_AUTH_SASL;
953 			sasl_realm = optarg;
954 #else
955 			fprintf( stderr, "%s: not compiled with SASL support\n",
956 				prog );
957 			exit( EXIT_FAILURE );
958 #endif
959 			break;
960 		case 'U':
961 #ifdef HAVE_CYRUS_SASL
962 			if( sasl_authc_id != NULL ) {
963 				fprintf( stderr, "%s: -U previously specified\n", prog );
964 				exit( EXIT_FAILURE );
965 			}
966 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
967 				fprintf( stderr, "%s: incompatible previous "
968 					"authentication choice\n",
969 					prog );
970 				exit( EXIT_FAILURE );
971 			}
972 			authmethod = LDAP_AUTH_SASL;
973 			sasl_authc_id = optarg;
974 #else
975 			fprintf( stderr, "%s: not compiled with SASL support\n",
976 				prog );
977 			exit( EXIT_FAILURE );
978 #endif
979 			break;
980 		case 'v':	/* verbose mode */
981 			verbose++;
982 			break;
983 		case 'V':	/* version */
984 			version++;
985 			break;
986 		case 'w':	/* password */
987 			passwd.bv_val = ber_strdup( optarg );
988 			{
989 				char* p;
990 
991 				for( p = optarg; *p != '\0'; p++ ) {
992 					*p = '\0';
993 				}
994 			}
995 			passwd.bv_len = strlen( passwd.bv_val );
996 			break;
997 		case 'W':
998 			want_bindpw++;
999 			break;
1000 		case 'y':
1001 			pw_file = optarg;
1002 			break;
1003 		case 'Y':
1004 #ifdef HAVE_CYRUS_SASL
1005 			if( sasl_mech != NULL ) {
1006 				fprintf( stderr, "%s: -Y previously specified\n", prog );
1007 				exit( EXIT_FAILURE );
1008 			}
1009 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
1010 				fprintf( stderr,
1011 					"%s: incompatible with authentication choice\n", prog );
1012 				exit( EXIT_FAILURE );
1013 			}
1014 			authmethod = LDAP_AUTH_SASL;
1015 			sasl_mech = optarg;
1016 #else
1017 			fprintf( stderr, "%s: not compiled with SASL support\n", prog );
1018 			exit( EXIT_FAILURE );
1019 #endif
1020 			break;
1021 		case 'x':
1022 			if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
1023 				fprintf( stderr, "%s: incompatible with previous "
1024 					"authentication choice\n", prog );
1025 				exit( EXIT_FAILURE );
1026 			}
1027 			authmethod = LDAP_AUTH_SIMPLE;
1028 			break;
1029 		case 'X':
1030 #ifdef HAVE_CYRUS_SASL
1031 			if( sasl_authz_id != NULL ) {
1032 				fprintf( stderr, "%s: -X previously specified\n", prog );
1033 				exit( EXIT_FAILURE );
1034 			}
1035 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
1036 				fprintf( stderr, "%s: -X incompatible with "
1037 					"authentication choice\n", prog );
1038 				exit( EXIT_FAILURE );
1039 			}
1040 			authmethod = LDAP_AUTH_SASL;
1041 			sasl_authz_id = optarg;
1042 #else
1043 			fprintf( stderr, "%s: not compiled with SASL support\n", prog );
1044 			exit( EXIT_FAILURE );
1045 #endif
1046 			break;
1047 		case 'Z':
1048 #ifdef HAVE_TLS
1049 			use_tls++;
1050 #else
1051 			fprintf( stderr, "%s: not compiled with TLS support\n", prog );
1052 			exit( EXIT_FAILURE );
1053 #endif
1054 			break;
1055 		default:
1056 			if( handle_private_option( i ) ) break;
1057 			fprintf( stderr, "%s: unrecognized option -%c\n",
1058 				prog, optopt );
1059 			usage();
1060 		}
1061 	}
1062 
1063 	{
1064 		/* prevent bad linking */
1065 		LDAPAPIInfo api;
1066 		api.ldapai_info_version = LDAP_API_INFO_VERSION;
1067 
1068 		if ( ldap_get_option(NULL, LDAP_OPT_API_INFO, &api)
1069 			!= LDAP_OPT_SUCCESS )
1070 		{
1071 			fprintf( stderr, "%s: ldap_get_option(API_INFO) failed\n", prog );
1072 			exit( EXIT_FAILURE );
1073 		}
1074 
1075 		if (api.ldapai_info_version != LDAP_API_INFO_VERSION) {
1076 			fprintf( stderr, "LDAP APIInfo version mismatch: "
1077 				"library %d, header %d\n",
1078 				api.ldapai_info_version, LDAP_API_INFO_VERSION );
1079 			exit( EXIT_FAILURE );
1080 		}
1081 
1082 		if( api.ldapai_api_version != LDAP_API_VERSION ) {
1083 			fprintf( stderr, "LDAP API version mismatch: "
1084 				"library %d, header %d\n",
1085 				api.ldapai_api_version, LDAP_API_VERSION );
1086 			exit( EXIT_FAILURE );
1087 		}
1088 
1089 		if( strcmp(api.ldapai_vendor_name, LDAP_VENDOR_NAME ) != 0 ) {
1090 			fprintf( stderr, "LDAP vendor name mismatch: "
1091 				"library %s, header %s\n",
1092 				api.ldapai_vendor_name, LDAP_VENDOR_NAME );
1093 			exit( EXIT_FAILURE );
1094 		}
1095 
1096 		if( api.ldapai_vendor_version != LDAP_VENDOR_VERSION ) {
1097 			fprintf( stderr, "LDAP vendor version mismatch: "
1098 				"library %d, header %d\n",
1099 				api.ldapai_vendor_version, LDAP_VENDOR_VERSION );
1100 			exit( EXIT_FAILURE );
1101 		}
1102 
1103 		if (version) {
1104 			fprintf( stderr, "%s: %s\t(LDAP library: %s %d)\n",
1105 				prog, __Version,
1106 				LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION );
1107 			if (version > 1) exit( EXIT_SUCCESS );
1108 		}
1109 
1110 		ldap_memfree( api.ldapai_vendor_name );
1111 		ber_memvfree( (void **)api.ldapai_extensions );
1112 	}
1113 
1114 	if (protocol == -1)
1115 		protocol = LDAP_VERSION3;
1116 
1117 	if (authmethod == -1 && protocol > LDAP_VERSION2) {
1118 #ifdef HAVE_CYRUS_SASL
1119 		if ( binddn != NULL ) {
1120 			authmethod = LDAP_AUTH_SIMPLE;
1121 		} else {
1122 			authmethod = LDAP_AUTH_SASL;
1123 		}
1124 #else
1125 		authmethod = LDAP_AUTH_SIMPLE;
1126 #endif
1127 	}
1128 
1129 	if( protocol == LDAP_VERSION2 ) {
1130 		if( assertctl || authzid || manageDIT || manageDSAit ||
1131 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
1132 			proxydn ||
1133 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
1134 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1135 			chaining ||
1136 #endif
1137 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1138 			sessionTracking ||
1139 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
1140 			noop || ppolicy || preread || postread )
1141 		{
1142 			fprintf( stderr, "%s: -e/-M incompatible with LDAPv2\n", prog );
1143 			exit( EXIT_FAILURE );
1144 		}
1145 #ifdef HAVE_TLS
1146 		if( use_tls ) {
1147 			fprintf( stderr, "%s: -Z incompatible with LDAPv2\n", prog );
1148 			exit( EXIT_FAILURE );
1149 		}
1150 #endif
1151 #ifdef HAVE_CYRUS_SASL
1152 		if( authmethod == LDAP_AUTH_SASL ) {
1153 			fprintf( stderr, "%s: -[IOQRUXY] incompatible with LDAPv2\n",
1154 				prog );
1155 			exit( EXIT_FAILURE );
1156 		}
1157 #endif
1158 	}
1159 
1160 	if ( ( pw_file || want_bindpw ) && !BER_BVISNULL( &passwd ) ) {
1161 		fprintf( stderr, "%s: -%c incompatible with -w\n",
1162 			prog, ( pw_file ? 'y' : 'W' ) );
1163 		exit( EXIT_FAILURE );
1164 	}
1165 }
1166 
1167 
1168 LDAP *
tool_conn_setup(int dont,void (* private_setup)(LDAP *))1169 tool_conn_setup( int dont, void (*private_setup)( LDAP * ) )
1170 {
1171 	LDAP *ld = NULL;
1172 
1173 	if ( debug ) {
1174 		if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug )
1175 			!= LBER_OPT_SUCCESS )
1176 		{
1177 			fprintf( stderr,
1178 				"Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
1179 		}
1180 		if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug )
1181 			!= LDAP_OPT_SUCCESS )
1182 		{
1183 			fprintf( stderr,
1184 				"Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
1185 		}
1186 	}
1187 
1188 #ifdef SIGPIPE
1189 	(void) SIGNAL( SIGPIPE, SIG_IGN );
1190 #endif
1191 
1192 	if ( abcan ) {
1193 		SIGNAL( SIGINT, do_sig );
1194 	}
1195 
1196 	if ( !dont ) {
1197 		int rc;
1198 
1199 		if ( ldapuri != NULL ) {
1200 			LDAPURLDesc	*ludlist, **ludp;
1201 			char		**urls = NULL;
1202 			int		nurls = 0;
1203 
1204 			rc = ldap_url_parselist( &ludlist, ldapuri );
1205 			if ( rc != LDAP_URL_SUCCESS ) {
1206 				fprintf( stderr,
1207 					"Could not parse LDAP URI(s)=%s (%d)\n",
1208 					ldapuri, rc );
1209 				exit( EXIT_FAILURE );
1210 			}
1211 
1212 			for ( ludp = &ludlist; *ludp != NULL; ) {
1213 				LDAPURLDesc	*lud = *ludp;
1214 				char		**tmp;
1215 
1216 				if ( lud->lud_dn != NULL && lud->lud_dn[ 0 ] != '\0' &&
1217 					( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) )
1218 				{
1219 					/* if no host but a DN is provided,
1220 					 * use DNS SRV to gather the host list
1221 					 * and turn it into a list of URIs
1222 					 * using the scheme provided */
1223 					char	*domain = NULL,
1224 						*hostlist = NULL,
1225 						**hosts = NULL;
1226 					int	i,
1227 						len_proto = strlen( lud->lud_scheme );
1228 
1229 					if ( ldap_dn2domain( lud->lud_dn, &domain )
1230 						|| domain == NULL )
1231 					{
1232 						fprintf( stderr,
1233 							"DNS SRV: Could not turn "
1234 							"DN=\"%s\" into a domain\n",
1235 							lud->lud_dn );
1236 						goto dnssrv_free;
1237 					}
1238 
1239 					rc = ldap_domain2hostlist( domain, &hostlist );
1240 					if ( rc ) {
1241 						fprintf( stderr,
1242 							"DNS SRV: Could not turn "
1243 							"domain=%s into a hostlist\n",
1244 							domain );
1245 						goto dnssrv_free;
1246 					}
1247 
1248 					hosts = ldap_str2charray( hostlist, " " );
1249 					if ( hosts == NULL ) {
1250 						fprintf( stderr,
1251 							"DNS SRV: Could not parse "
1252 							"hostlist=\"%s\"\n",
1253 							hostlist );
1254 						goto dnssrv_free;
1255 					}
1256 
1257 					for ( i = 0; hosts[ i ] != NULL; i++ )
1258 						/* count'em */ ;
1259 
1260 					tmp = (char **)ber_memrealloc( urls, sizeof( char * ) * ( nurls + i + 1 ) );
1261 					if ( tmp == NULL ) {
1262 						fprintf( stderr,
1263 							"DNS SRV: out of memory?\n" );
1264 						goto dnssrv_free;
1265 					}
1266 					urls = tmp;
1267 					urls[ nurls ] = NULL;
1268 
1269 					for ( i = 0; hosts[ i ] != NULL; i++ ) {
1270 						size_t	len = len_proto
1271 							+ STRLENOF( "://" )
1272 							+ strlen( hosts[ i ] )
1273 							+ 1;
1274 
1275 						urls[ nurls + i + 1 ] = NULL;
1276 						urls[ nurls + i ] = (char *)malloc( sizeof( char ) * len );
1277 						if ( urls[ nurls + i ] == NULL ) {
1278 							fprintf( stderr,
1279 								"DNS SRV: out of memory?\n" );
1280 							goto dnssrv_free;
1281 						}
1282 
1283 						snprintf( urls[ nurls + i ], len, "%s://%s",
1284 							lud->lud_scheme, hosts[ i ] );
1285 					}
1286 					nurls += i;
1287 
1288 dnssrv_free:;
1289 					ber_memvfree( (void **)hosts );
1290 					ber_memfree( hostlist );
1291 					ber_memfree( domain );
1292 
1293 				} else {
1294 					tmp = (char **)ber_memrealloc( urls, sizeof( char * ) * ( nurls + 2 ) );
1295 					if ( tmp == NULL ) {
1296 						fprintf( stderr,
1297 							"DNS SRV: out of memory?\n" );
1298 						break;
1299 					}
1300 					urls = tmp;
1301 					urls[ nurls + 1 ] = NULL;
1302 
1303 					urls[ nurls ] = ldap_url_desc2str( lud );
1304 					if ( urls[ nurls ] == NULL ) {
1305 						fprintf( stderr,
1306 							"DNS SRV: out of memory?\n" );
1307 						break;
1308 					}
1309 					nurls++;
1310 				}
1311 
1312 				*ludp = lud->lud_next;
1313 
1314 				lud->lud_next = NULL;
1315 				ldap_free_urldesc( lud );
1316 			}
1317 
1318 			if ( ludlist != NULL ) {
1319 				ldap_free_urllist( ludlist );
1320 				exit( EXIT_FAILURE );
1321 
1322 			} else if ( urls == NULL ) {
1323 				exit( EXIT_FAILURE );
1324 			}
1325 
1326 			ldap_memfree( ldapuri );
1327 			ldapuri = ldap_charray2str( urls, " " );
1328 			ber_memvfree( (void **)urls );
1329 		}
1330 
1331 		if ( verbose ) {
1332 			fprintf( stderr, "ldap_initialize( %s )\n",
1333 				ldapuri != NULL ? ldapuri : "<DEFAULT>" );
1334 		}
1335 		rc = ldap_initialize( &ld, ldapuri );
1336 		if( rc != LDAP_SUCCESS ) {
1337 			fprintf( stderr,
1338 				"Could not create LDAP session handle for URI=%s (%d): %s\n",
1339 				ldapuri, rc, ldap_err2string(rc) );
1340 			exit( EXIT_FAILURE );
1341 		}
1342 
1343 		if( private_setup ) private_setup( ld );
1344 
1345 		/* referrals: obsolete */
1346 		if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
1347 			referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
1348 		{
1349 			fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
1350 				referrals ? "on" : "off" );
1351 			tool_exit( ld, EXIT_FAILURE );
1352 		}
1353 
1354 #ifdef HAVE_CYRUS_SASL
1355 		/* canon */
1356 		if( nocanon ) {
1357 			if( ldap_set_option( ld, LDAP_OPT_X_SASL_NOCANON,
1358 				LDAP_OPT_ON ) != LDAP_OPT_SUCCESS )
1359 			{
1360 				fprintf( stderr, "Could not set LDAP_OPT_X_SASL_NOCANON on\n" );
1361 				tool_exit( ld, EXIT_FAILURE );
1362 			}
1363 		}
1364 #endif
1365 		if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &protocol )
1366 			!= LDAP_OPT_SUCCESS )
1367 		{
1368 			fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
1369 				protocol );
1370 			tool_exit( ld, EXIT_FAILURE );
1371 		}
1372 
1373 #ifdef HAVE_TLS
1374 		if ( use_tls ) {
1375 			rc = ldap_start_tls_s( ld, NULL, NULL );
1376 			if ( rc != LDAP_SUCCESS ) {
1377 				char *msg=NULL;
1378 				ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&msg);
1379 				tool_perror( "ldap_start_tls", rc, NULL, NULL, msg, NULL );
1380 				ldap_memfree(msg);
1381 				if ( use_tls > 1 || rc < 0 ) {
1382 					tool_exit( ld, EXIT_FAILURE );
1383 				}
1384 			}
1385 		}
1386 #endif
1387 
1388 		if ( nettimeout.tv_sec > 0 ) {
1389 	 		if ( ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (void *) &nettimeout )
1390 				!= LDAP_OPT_SUCCESS )
1391 			{
1392 		 		fprintf( stderr, "Could not set LDAP_OPT_NETWORK_TIMEOUT %ld\n",
1393 					(long)nettimeout.tv_sec );
1394 	 			tool_exit( ld, EXIT_FAILURE );
1395 			}
1396 		}
1397 	}
1398 
1399 	return ld;
1400 }
1401 
1402 
1403 void
tool_bind(LDAP * ld)1404 tool_bind( LDAP *ld )
1405 {
1406 	LDAPControl	**sctrlsp = NULL;
1407 	LDAPControl	*sctrls[4];
1408 	LDAPControl	sctrl[3];
1409 	int		nsctrls = 0;
1410 
1411 	int rc, msgid;
1412 	LDAPMessage *result = NULL;
1413 
1414 	int err;
1415 	char *matched = NULL;
1416 	char *info = NULL;
1417 	char **refs = NULL;
1418 	LDAPControl **ctrls = NULL;
1419 	char msgbuf[256];
1420 
1421 	msgbuf[0] = 0;
1422 
1423 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1424 	if ( ppolicy ) {
1425 		LDAPControl c;
1426 		c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
1427 		c.ldctl_value.bv_val = NULL;
1428 		c.ldctl_value.bv_len = 0;
1429 		c.ldctl_iscritical = 0;
1430 		sctrl[nsctrls] = c;
1431 		sctrls[nsctrls] = &sctrl[nsctrls];
1432 		sctrls[++nsctrls] = NULL;
1433 	}
1434 #endif
1435 
1436 	if ( bauthzid ) {
1437 		LDAPControl c;
1438 
1439 		c.ldctl_oid = LDAP_CONTROL_AUTHZID_REQUEST;
1440 		c.ldctl_iscritical = bauthzid > 1;
1441 		BER_BVZERO( &c.ldctl_value );
1442 
1443 		sctrl[nsctrls] = c;
1444 		sctrls[nsctrls] = &sctrl[nsctrls];
1445 		sctrls[++nsctrls] = NULL;
1446 	}
1447 
1448 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1449 	if ( sessionTracking ) {
1450 		LDAPControl c;
1451 
1452 		if ( BER_BVISNULL( &stValue) && st_value( ld, &stValue ) ) {
1453 			tool_exit( ld, EXIT_FAILURE );
1454 		}
1455 
1456 		c.ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
1457 		c.ldctl_iscritical = 0;
1458 		c.ldctl_value = stValue;
1459 
1460 		sctrl[nsctrls] = c;
1461 		sctrls[nsctrls] = &sctrl[nsctrls];
1462 		sctrls[++nsctrls] = NULL;
1463 	}
1464 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
1465 
1466 	if ( nsctrls ) {
1467 		sctrlsp = sctrls;
1468 	}
1469 
1470 	assert( nsctrls < (int) (sizeof(sctrls)/sizeof(sctrls[0])) );
1471 
1472 	if ( pw_file || want_bindpw ) {
1473 		assert( passwd.bv_val == NULL && passwd.bv_len == 0 );
1474 
1475 		if ( pw_file ) {
1476 			if ( lutil_get_filed_password( pw_file, &passwd ) ) {
1477 				tool_exit( ld, EXIT_FAILURE );
1478 			}
1479 
1480 		} else {
1481 			char *pw = getpassphrase( _("Enter LDAP Password: ") );
1482 			if ( pw ) {
1483 				passwd.bv_val = ber_strdup( pw );
1484 				passwd.bv_len = strlen( passwd.bv_val );
1485 			}
1486 		}
1487 	}
1488 
1489 	if ( authmethod == LDAP_AUTH_SASL ) {
1490 #ifdef HAVE_CYRUS_SASL
1491 		void *defaults;
1492 		const char *rmech = NULL;
1493 
1494 		if( sasl_secprops != NULL ) {
1495 			rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
1496 				(void *) sasl_secprops );
1497 
1498 			if( rc != LDAP_OPT_SUCCESS ) {
1499 				fprintf( stderr,
1500 					"Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
1501 					sasl_secprops );
1502 				tool_exit( ld, LDAP_LOCAL_ERROR );
1503 			}
1504 		}
1505 
1506 		defaults = lutil_sasl_defaults( ld,
1507 			sasl_mech,
1508 			sasl_realm,
1509 			sasl_authc_id,
1510 			passwd.bv_val,
1511 			sasl_authz_id );
1512 
1513 		do {
1514 			rc = ldap_sasl_interactive_bind( ld, binddn, sasl_mech,
1515 				sctrlsp, NULL, sasl_flags, lutil_sasl_interact, defaults,
1516 				result, &rmech, &msgid );
1517 
1518 			if ( rc != LDAP_SASL_BIND_IN_PROGRESS )
1519 				break;
1520 
1521 			ldap_msgfree( result );
1522 
1523 			if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
1524 				ldap_get_option( ld, LDAP_OPT_RESULT_CODE, (void*)&err );
1525 				ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&info );
1526 				tool_perror( "ldap_sasl_interactive_bind",
1527 					err, NULL, NULL, info, NULL );
1528 				ldap_memfree( info );
1529 				tool_exit( ld, err );
1530 			}
1531 		} while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
1532 
1533 		lutil_sasl_freedefs( defaults );
1534 
1535 		if ( rc != LDAP_SUCCESS ) {
1536 			ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&info );
1537 			tool_perror( "ldap_sasl_interactive_bind",
1538 				rc, NULL, NULL, info, NULL );
1539 			ldap_memfree( info );
1540 			tool_exit( ld, rc );
1541 		}
1542 #else
1543 		fprintf( stderr, "%s: not compiled with SASL support\n", prog );
1544 		tool_exit( ld, LDAP_NOT_SUPPORTED );
1545 #endif
1546 	} else {
1547 		/* simple bind */
1548 		rc = ldap_sasl_bind( ld, binddn, LDAP_SASL_SIMPLE, &passwd,
1549 			sctrlsp, NULL, &msgid );
1550 		if ( msgid == -1 ) {
1551 			tool_perror( "ldap_sasl_bind(SIMPLE)", rc,
1552 				NULL, NULL, NULL, NULL );
1553 			tool_exit( ld, rc );
1554 		}
1555 
1556 		rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result );
1557 		if ( rc == -1 ) {
1558 			tool_perror( "ldap_result", -1, NULL, NULL, NULL, NULL );
1559 			tool_exit( ld, LDAP_LOCAL_ERROR );
1560 		}
1561 
1562 		if ( rc == 0 ) {
1563 			tool_perror( "ldap_result", LDAP_TIMEOUT, NULL, NULL, NULL, NULL );
1564 			tool_exit( ld, LDAP_LOCAL_ERROR );
1565 		}
1566 	}
1567 
1568 	if ( result ) {
1569 		rc = ldap_parse_result( ld, result, &err, &matched, &info, &refs,
1570 		                        &ctrls, 1 );
1571 		if ( rc != LDAP_SUCCESS ) {
1572 			tool_perror( "ldap_bind parse result", rc, NULL, matched, info, refs );
1573 			tool_exit( ld, LDAP_LOCAL_ERROR );
1574 		}
1575 	}
1576 
1577 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1578 	if ( ctrls && ppolicy ) {
1579 		LDAPControl *ctrl;
1580 		int expire, grace, len = 0;
1581 		LDAPPasswordPolicyError pErr = -1;
1582 
1583 		ctrl = ldap_control_find( LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
1584 			ctrls, NULL );
1585 
1586 		if ( ctrl && ldap_parse_passwordpolicy_control( ld, ctrl,
1587 			&expire, &grace, &pErr ) == LDAP_SUCCESS )
1588 		{
1589 			if ( pErr != PP_noError ){
1590 				msgbuf[0] = ';';
1591 				msgbuf[1] = ' ';
1592 				strcpy( msgbuf+2, ldap_passwordpolicy_err2txt( pErr ));
1593 				len = strlen( msgbuf );
1594 			}
1595 			if ( expire >= 0 ) {
1596 				sprintf( msgbuf+len,
1597 					" (Password expires in %d seconds)",
1598 					expire );
1599 			} else if ( grace >= 0 ) {
1600 				sprintf( msgbuf+len,
1601 					" (Password expired, %d grace logins remain)",
1602 					grace );
1603 			}
1604 		}
1605 	}
1606 #endif
1607 
1608 	if ( ctrls && bauthzid ) {
1609 		LDAPControl *ctrl;
1610 
1611 		ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE,
1612 			ctrls, NULL );
1613 		if ( ctrl ) {
1614 			LDAPControl *ctmp[2];
1615 			ctmp[0] = ctrl;
1616 			ctmp[1] = NULL;
1617 			tool_print_ctrls( ld, ctmp );
1618 		}
1619 	}
1620 
1621 #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRED
1622 	if ( ctrls ) {
1623 		LDAPControl *ctrl;
1624 		ctrl = ldap_control_find( LDAP_CONTROL_X_PASSWORD_EXPIRED,
1625 			ctrls, NULL );
1626 		if ( !ctrl )
1627 			ctrl = ldap_control_find( LDAP_CONTROL_X_PASSWORD_EXPIRING,
1628 				ctrls, NULL );
1629 		if ( ctrl ) {
1630 			LDAPControl *ctmp[2];
1631 			ctmp[0] = ctrl;
1632 			ctmp[1] = NULL;
1633 			tool_print_ctrls( ld, ctmp );
1634 		}
1635 	}
1636 #endif
1637 
1638 	if ( ctrls ) {
1639 		ldap_controls_free( ctrls );
1640 	}
1641 
1642 	if ( err != LDAP_SUCCESS
1643 		|| msgbuf[0]
1644 		|| ( matched && matched[ 0 ] )
1645 		|| ( info && info[ 0 ] )
1646 		|| refs )
1647 	{
1648 		tool_perror( "ldap_bind", err, msgbuf, matched, info, refs );
1649 
1650 		if( matched ) ber_memfree( matched );
1651 		if( info ) ber_memfree( info );
1652 		if( refs ) ber_memvfree( (void **)refs );
1653 
1654 		if ( err != LDAP_SUCCESS ) tool_exit( ld, err );
1655 	}
1656 }
1657 
1658 void
tool_unbind(LDAP * ld)1659 tool_unbind( LDAP *ld )
1660 {
1661 	int err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, NULL );
1662 
1663 	if ( err != LDAP_OPT_SUCCESS ) {
1664 		fprintf( stderr, "Could not unset controls\n");
1665 	}
1666 
1667 	(void) ldap_unbind_ext( ld, NULL, NULL );
1668 }
1669 
1670 void
tool_exit(LDAP * ld,int status)1671 tool_exit( LDAP *ld, int status )
1672 {
1673 	if ( ld != NULL ) {
1674 		tool_unbind( ld );
1675 	}
1676 	tool_destroy();
1677 	exit( status );
1678 }
1679 
1680 
1681 /* Set server controls.  Add controls extra_c[0..count-1], if set. */
1682 void
tool_server_controls(LDAP * ld,LDAPControl * extra_c,int count)1683 tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count )
1684 {
1685 	int i = 0, j, crit = 0, err;
1686 	LDAPControl c[16], **ctrls;
1687 
1688 	if ( ! ( assertctl
1689 		|| authzid
1690 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
1691 		|| proxydn
1692 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
1693 		|| manageDIT
1694 		|| manageDSAit
1695 		|| noop
1696 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1697 		|| ppolicy
1698 #endif
1699 		|| preread
1700 		|| postread
1701 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1702 		|| chaining
1703 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1704 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1705 		|| sessionTracking
1706 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
1707 		|| count
1708 		|| unknown_ctrls_num ) )
1709 	{
1710 		return;
1711 	}
1712 
1713 	ctrls = (LDAPControl**) malloc(sizeof(c) + (count + unknown_ctrls_num + 1)*sizeof(LDAPControl*));
1714 	if ( ctrls == NULL ) {
1715 		fprintf( stderr, "No memory\n" );
1716 		tool_exit( ld, EXIT_FAILURE );
1717 	}
1718 
1719 	if ( assertctl ) {
1720 		if ( BER_BVISNULL( &assertionvalue ) ) {
1721 			err = ldap_create_assertion_control_value( ld,
1722 				assertion, &assertionvalue );
1723 			if ( err ) {
1724 				fprintf( stderr,
1725 					"Unable to create assertion value "
1726 					"\"%s\" (%d)\n", assertion, err );
1727 			}
1728 		}
1729 
1730 		c[i].ldctl_oid = LDAP_CONTROL_ASSERT;
1731 		c[i].ldctl_value = assertionvalue;
1732 		c[i].ldctl_iscritical = assertctl > 1;
1733 		ctrls[i] = &c[i];
1734 		i++;
1735 	}
1736 
1737 	if ( authzid ) {
1738 		c[i].ldctl_value.bv_val = authzid;
1739 		c[i].ldctl_value.bv_len = strlen( authzid );
1740 		c[i].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
1741 		c[i].ldctl_iscritical = authzcrit;
1742 		ctrls[i] = &c[i];
1743 		i++;
1744 	}
1745 
1746 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
1747 	/* NOTE: doesn't need an extra count because it's incompatible
1748 	 * with authzid */
1749 	if ( proxydn ) {
1750 		BerElementBuffer berbuf;
1751 		BerElement *ber = (BerElement *)&berbuf;
1752 
1753 		ber_init2( ber, NULL, LBER_USE_DER );
1754 
1755 		if ( ber_printf( ber, "s", proxydn ) == -1 ) {
1756 			tool_exit( ld, EXIT_FAILURE );
1757 		}
1758 
1759 		if ( ber_flatten2( ber, &c[i].ldctl_value, 0 ) == -1 ) {
1760 			tool_exit( ld, EXIT_FAILURE );
1761 		}
1762 
1763 		c[i].ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
1764 		c[i].ldctl_iscritical = authzcrit;
1765 		ctrls[i] = &c[i];
1766 		i++;
1767 	}
1768 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
1769 
1770 	if ( manageDIT ) {
1771 		c[i].ldctl_oid = LDAP_CONTROL_MANAGEDIT;
1772 		BER_BVZERO( &c[i].ldctl_value );
1773 		c[i].ldctl_iscritical = manageDIT > 1;
1774 		ctrls[i] = &c[i];
1775 		i++;
1776 	}
1777 
1778 	if ( manageDSAit ) {
1779 		c[i].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
1780 		BER_BVZERO( &c[i].ldctl_value );
1781 		c[i].ldctl_iscritical = manageDSAit > 1;
1782 		ctrls[i] = &c[i];
1783 		i++;
1784 	}
1785 
1786 	if ( noop ) {
1787 		c[i].ldctl_oid = LDAP_CONTROL_NOOP;
1788 		BER_BVZERO( &c[i].ldctl_value );
1789 		c[i].ldctl_iscritical = noop > 1;
1790 		ctrls[i] = &c[i];
1791 		i++;
1792 	}
1793 
1794 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1795 	if ( ppolicy ) {
1796 		c[i].ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
1797 		BER_BVZERO( &c[i].ldctl_value );
1798 		c[i].ldctl_iscritical = 0;
1799 		ctrls[i] = &c[i];
1800 		i++;
1801 	}
1802 #endif
1803 
1804 	if ( preread ) {
1805 		BerElementBuffer berbuf;
1806 		BerElement *ber = (BerElement *)&berbuf;
1807 		char **attrs = NULL;
1808 
1809 		if( preread_attrs ) {
1810 			attrs = ldap_str2charray( preread_attrs, "," );
1811 		}
1812 
1813 		ber_init2( ber, NULL, LBER_USE_DER );
1814 
1815 		if( ber_printf( ber, "{v}", attrs ) == -1 ) {
1816 			fprintf( stderr, "preread attrs encode failed.\n" );
1817 			tool_exit( ld, EXIT_FAILURE );
1818 		}
1819 
1820 		err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
1821 		if( err < 0 ) {
1822 			fprintf( stderr, "preread flatten failed (%d)\n", err );
1823 			tool_exit( ld, EXIT_FAILURE );
1824 		}
1825 
1826 		c[i].ldctl_oid = LDAP_CONTROL_PRE_READ;
1827 		c[i].ldctl_iscritical = preread > 1;
1828 		ctrls[i] = &c[i];
1829 		i++;
1830 
1831 		if( attrs ) ldap_charray_free( attrs );
1832 	}
1833 
1834 	if ( postread ) {
1835 		BerElementBuffer berbuf;
1836 		BerElement *ber = (BerElement *)&berbuf;
1837 		char **attrs = NULL;
1838 
1839 		if( postread_attrs ) {
1840 			attrs = ldap_str2charray( postread_attrs, "," );
1841 		}
1842 
1843 		ber_init2( ber, NULL, LBER_USE_DER );
1844 
1845 		if( ber_printf( ber, "{v}", attrs ) == -1 ) {
1846 			fprintf( stderr, "postread attrs encode failed.\n" );
1847 			tool_exit( ld, EXIT_FAILURE );
1848 		}
1849 
1850 		err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
1851 		if( err < 0 ) {
1852 			fprintf( stderr, "postread flatten failed (%d)\n", err );
1853 			tool_exit( ld, EXIT_FAILURE );
1854 		}
1855 
1856 		c[i].ldctl_oid = LDAP_CONTROL_POST_READ;
1857 		c[i].ldctl_iscritical = postread > 1;
1858 		ctrls[i] = &c[i];
1859 		i++;
1860 
1861 		if( attrs ) ldap_charray_free( attrs );
1862 	}
1863 
1864 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1865 	if ( chaining ) {
1866 		if ( chainingResolve > -1 ) {
1867 			BerElementBuffer berbuf;
1868 			BerElement *ber = (BerElement *)&berbuf;
1869 
1870 			ber_init2( ber, NULL, LBER_USE_DER );
1871 
1872 			err = ber_printf( ber, "{e" /* } */, chainingResolve );
1873 		    	if ( err == -1 ) {
1874 				ber_free( ber, 1 );
1875 				fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1876 				tool_exit( ld, EXIT_FAILURE );
1877 			}
1878 
1879 			if ( chainingContinuation > -1 ) {
1880 				err = ber_printf( ber, "e", chainingContinuation );
1881 		    		if ( err == -1 ) {
1882 					ber_free( ber, 1 );
1883 					fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1884 					tool_exit( ld, EXIT_FAILURE );
1885 				}
1886 			}
1887 
1888 			err = ber_printf( ber, /* { */ "N}" );
1889 		    	if ( err == -1 ) {
1890 				ber_free( ber, 1 );
1891 				fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1892 				tool_exit( ld, EXIT_FAILURE );
1893 			}
1894 
1895 			if ( ber_flatten2( ber, &c[i].ldctl_value, 0 ) == -1 ) {
1896 				tool_exit( ld, EXIT_FAILURE );
1897 			}
1898 
1899 		} else {
1900 			BER_BVZERO( &c[i].ldctl_value );
1901 		}
1902 
1903 		c[i].ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1904 		c[i].ldctl_iscritical = chaining > 1;
1905 		ctrls[i] = &c[i];
1906 		i++;
1907 	}
1908 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1909 
1910 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1911 	if ( sessionTracking ) {
1912 		if ( BER_BVISNULL( &stValue ) && st_value( ld, &stValue ) ) {
1913 			tool_exit( ld, EXIT_FAILURE );
1914 		}
1915 
1916 		c[i].ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
1917 		c[i].ldctl_iscritical = 0;
1918 		c[i].ldctl_value = stValue;
1919 
1920 		ctrls[i] = &c[i];
1921 		i++;
1922 	}
1923 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
1924 
1925 	while ( count-- ) {
1926 		ctrls[i++] = extra_c++;
1927 	}
1928 	for ( count = 0; count < unknown_ctrls_num; count++ ) {
1929 		ctrls[i++] = &unknown_ctrls[count];
1930 	}
1931 	ctrls[i] = NULL;
1932 
1933 	err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
1934 
1935 	if ( err != LDAP_OPT_SUCCESS ) {
1936 		for ( j = 0; j < i; j++ ) {
1937 			if ( ctrls[j]->ldctl_iscritical ) crit = 1;
1938 		}
1939 		fprintf( stderr, "Could not set %scontrols\n",
1940 			crit ? "critical " : "" );
1941 	}
1942 
1943  	free( ctrls );
1944 	if ( crit ) {
1945 		tool_exit( ld, EXIT_FAILURE );
1946 	}
1947 }
1948 
1949 int
tool_check_abandon(LDAP * ld,int msgid)1950 tool_check_abandon( LDAP *ld, int msgid )
1951 {
1952 	int	rc;
1953 	LDAPControl *sctrls[1] = { NULL };
1954 
1955 	switch ( gotintr ) {
1956 	case Intr_Cancel:
1957 		rc = ldap_cancel_s( ld, msgid, sctrls, NULL );
1958 		fprintf( stderr, "got interrupt, cancel got %d: %s\n",
1959 				rc, ldap_err2string( rc ) );
1960 		return -1;
1961 
1962 	case Intr_Abandon:
1963 		rc = ldap_abandon_ext( ld, msgid, sctrls, NULL );
1964 		fprintf( stderr, "got interrupt, abandon got %d: %s\n",
1965 				rc, ldap_err2string( rc ) );
1966 		return -1;
1967 
1968 	case Intr_Ignore:
1969 		/* just unbind, ignoring the request */
1970 		return -1;
1971 	}
1972 
1973 	return 0;
1974 }
1975 
1976 static int
print_prepostread(LDAP * ld,LDAPControl * ctrl,struct berval * what)1977 print_prepostread( LDAP *ld, LDAPControl *ctrl, struct berval *what)
1978 {
1979 	BerElement	*ber;
1980 	struct berval	bv;
1981 
1982 	tool_write_ldif( LDIF_PUT_COMMENT, "==> ",
1983 		what->bv_val, what->bv_len );
1984 	ber = ber_init( &ctrl->ldctl_value );
1985 	if ( ber == NULL ) {
1986 		/* error? */
1987 		return 1;
1988 
1989 	} else if ( ber_scanf( ber, "{m{" /*}}*/, &bv ) == LBER_ERROR ) {
1990 		/* error? */
1991 		return 1;
1992 
1993 	} else {
1994 		tool_write_ldif( LDIF_PUT_VALUE, "dn", bv.bv_val, bv.bv_len );
1995 
1996 		while ( ber_scanf( ber, "{m" /*}*/, &bv ) != LBER_ERROR ) {
1997 			int		i;
1998 			BerVarray	vals = NULL;
1999 			char		*str = NULL;
2000 
2001 			if ( ber_scanf( ber, "[W]", &vals ) == LBER_ERROR ||
2002 				vals == NULL )
2003 			{
2004 				/* error? */
2005 				return 1;
2006 			}
2007 
2008 			if ( ldif ) {
2009 				char *ptr;
2010 
2011 				str = malloc( bv.bv_len + STRLENOF(": ") + 1 );
2012 
2013 				ptr = str;
2014 				ptr = lutil_strncopy( ptr, bv.bv_val, bv.bv_len );
2015 				ptr = lutil_strcopy( ptr, ": " );
2016 			}
2017 
2018 			for ( i = 0; vals[ i ].bv_val != NULL; i++ ) {
2019 				tool_write_ldif(
2020 					ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2021 					ldif ? str : bv.bv_val, vals[ i ].bv_val, vals[ i ].bv_len );
2022 			}
2023 
2024 			ber_bvarray_free( vals );
2025 			if ( str ) free( str );
2026 		}
2027 	}
2028 
2029 	if ( ber != NULL ) {
2030 		ber_free( ber, 1 );
2031 	}
2032 
2033 	tool_write_ldif( LDIF_PUT_COMMENT, "<== ",
2034 		what->bv_val, what->bv_len );
2035 
2036 	return 0;
2037 }
2038 
2039 static int
print_preread(LDAP * ld,LDAPControl * ctrl)2040 print_preread( LDAP *ld, LDAPControl *ctrl )
2041 {
2042 	static struct berval what = BER_BVC( "preread" );
2043 
2044 	return print_prepostread( ld, ctrl, &what );
2045 }
2046 
2047 static int
print_postread(LDAP * ld,LDAPControl * ctrl)2048 print_postread( LDAP *ld, LDAPControl *ctrl )
2049 {
2050 	static struct berval what = BER_BVC( "postread" );
2051 
2052 	return print_prepostread( ld, ctrl, &what );
2053 }
2054 
2055 static int
print_paged_results(LDAP * ld,LDAPControl * ctrl)2056 print_paged_results( LDAP *ld, LDAPControl *ctrl )
2057 {
2058 	ber_int_t estimate;
2059 
2060 	/* note: pr_cookie is being malloced; it's freed
2061 	 * the next time the control is sent, but the last
2062 	 * time it's not; we don't care too much, because
2063 	 * the last time an empty value is returned... */
2064 	if ( ldap_parse_pageresponse_control( ld, ctrl, &estimate, &pr_cookie )
2065 		!= LDAP_SUCCESS )
2066 	{
2067 		/* error? */
2068 		return 1;
2069 
2070 	} else {
2071 		char	buf[ BUFSIZ ], *ptr = buf;
2072 		int plen;
2073 
2074 		if ( estimate > 0 ) {
2075 			plen = sprintf( buf, "estimate=%d cookie=", estimate );
2076 		} else {
2077 			plen = sprintf( buf, "cookie=" );
2078 		}
2079 
2080 		if ( pr_cookie.bv_len > 0 ) {
2081 			struct berval	bv;
2082 
2083 			bv.bv_len = LUTIL_BASE64_ENCODE_LEN(
2084 				pr_cookie.bv_len ) + 1;
2085 			ptr = ber_memalloc( bv.bv_len + 1 + plen );
2086 			bv.bv_val = ptr + plen;
2087 
2088 			strcpy( ptr, buf );
2089 
2090 			bv.bv_len = lutil_b64_ntop(
2091 				(unsigned char *) pr_cookie.bv_val,
2092 				pr_cookie.bv_len,
2093 				bv.bv_val, bv.bv_len );
2094 
2095 			pr_morePagedResults = 1;
2096 			plen += bv.bv_len;
2097 		}
2098 
2099 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2100 			ldif ? "pagedresults: " : "pagedresults",
2101 			ptr, plen );
2102 
2103 		if ( ptr != buf )
2104 			ber_memfree( ptr );
2105 	}
2106 
2107 	return 0;
2108 }
2109 
2110 static int
print_psearch(LDAP * ld,LDAPControl * ctrl)2111 print_psearch( LDAP *ld, LDAPControl *ctrl )
2112 {
2113 	int rc;
2114 	int chgtype;
2115 	int chgpres;
2116 	long chgnum;
2117 	struct berval prevdn;
2118 
2119 	rc = ldap_parse_entrychange_control( ld, ctrl, &chgtype, &prevdn,
2120 		&chgpres, &chgnum );
2121 	if ( rc == LDAP_SUCCESS ) {
2122 		char buf[ BUFSIZ ];
2123 		char *ptr = buf;
2124 		int blen = sizeof(buf), len;
2125 
2126 		switch( chgtype ) {
2127 		case LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD:
2128 			len = snprintf( ptr, blen, "add" );
2129 			ptr += len;
2130 			blen -= len;
2131 			break;
2132 		case LDAP_CONTROL_PERSIST_ENTRY_CHANGE_DELETE:
2133 			len = snprintf( ptr, blen, "delete" );
2134 			ptr += len;
2135 			blen -= len;
2136 			break;
2137 		case LDAP_CONTROL_PERSIST_ENTRY_CHANGE_MODIFY:
2138 			len = snprintf( ptr, blen, "modify" );
2139 			ptr += len;
2140 			blen -= len;
2141 			break;
2142 		case LDAP_CONTROL_PERSIST_ENTRY_CHANGE_RENAME:
2143 			len = snprintf( ptr, blen, "moddn" );
2144 			ptr += len;
2145 			blen -= len;
2146 			if ( prevdn.bv_val != NULL ) {
2147 				len = snprintf( ptr, blen, " prevdn %s", prevdn.bv_val );
2148 				ptr += len;
2149 				blen -= len;
2150 			}
2151 			break;
2152 		}
2153 		if ( chgpres ) {
2154 			len = snprintf( ptr, blen, " changeNumber %ld", chgnum) ;
2155 			ptr += len;
2156 			blen -= len;
2157 		}
2158 
2159 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2160 			ldif ? "persistentSearch: " : "persistentSearch", buf, len );
2161 	}
2162 
2163 	return rc;
2164 }
2165 
2166 static int
print_sss(LDAP * ld,LDAPControl * ctrl)2167 print_sss( LDAP *ld, LDAPControl *ctrl )
2168 {
2169 	int rc;
2170 	ber_int_t err;
2171 	char *attr;
2172 
2173 	rc = ldap_parse_sortresponse_control( ld, ctrl, &err, &attr );
2174 	if ( rc == LDAP_SUCCESS ) {
2175 		char buf[ BUFSIZ ];
2176 		rc = snprintf( buf, sizeof(buf), "(%d) %s%s%s",
2177 			err, ldap_err2string(err), attr ? " " : "", attr ? attr : "" );
2178 
2179 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2180 			ldif ? "sortResult: " : "sortResult", buf, rc );
2181 	}
2182 
2183 	return rc;
2184 }
2185 
2186 static int
print_vlv(LDAP * ld,LDAPControl * ctrl)2187 print_vlv( LDAP *ld, LDAPControl *ctrl )
2188 {
2189 	int rc;
2190 	ber_int_t err;
2191 	struct berval bv;
2192 
2193 	rc = ldap_parse_vlvresponse_control( ld, ctrl, &vlvPos, &vlvCount,
2194 		&vlvContext, &err );
2195 	if ( rc == LDAP_SUCCESS ) {
2196 		char buf[ BUFSIZ ];
2197 
2198 		if ( vlvContext && vlvContext->bv_len > 0 ) {
2199 			bv.bv_len = LUTIL_BASE64_ENCODE_LEN(
2200 				vlvContext->bv_len ) + 1;
2201 			bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2202 
2203 			bv.bv_len = lutil_b64_ntop(
2204 				(unsigned char *) vlvContext->bv_val,
2205 				vlvContext->bv_len,
2206 				bv.bv_val, bv.bv_len );
2207 		} else {
2208 			bv.bv_val = "";
2209 			bv.bv_len = 0;
2210 		}
2211 
2212 		rc = snprintf( buf, sizeof(buf), "pos=%d count=%d context=%s (%d) %s",
2213 			vlvPos, vlvCount, bv.bv_val,
2214 			err, ldap_err2string(err));
2215 
2216 		if ( bv.bv_len )
2217 			ber_memfree( bv.bv_val );
2218 
2219 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2220 			ldif ? "vlvResult" : "vlvResult", buf, rc );
2221 	}
2222 
2223 	return rc;
2224 }
2225 
2226 #ifdef LDAP_CONTROL_X_DEREF
2227 static int
print_deref(LDAP * ld,LDAPControl * ctrl)2228 print_deref( LDAP *ld, LDAPControl *ctrl )
2229 {
2230 	LDAPDerefRes    *drhead = NULL, *dr;
2231 	int		rc;
2232 
2233 	rc = ldap_parse_derefresponse_control( ld, ctrl, &drhead );
2234 	if ( rc != LDAP_SUCCESS ) {
2235 		return rc;
2236 	}
2237 
2238 	for ( dr = drhead; dr != NULL; dr = dr->next ) {
2239 		LDAPDerefVal	*dv;
2240 		ber_len_t	len;
2241 		char		*buf, *ptr;
2242 
2243 		len = strlen( dr->derefAttr ) + STRLENOF(": ");
2244 
2245 		for ( dv = dr->attrVals; dv != NULL; dv = dv->next ) {
2246 			if ( dv->vals != NULL ) {
2247 				int j;
2248 				ber_len_t tlen = strlen(dv->type);
2249 
2250 				for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
2251 					len += STRLENOF("<:=>;") + tlen + 4*((dv->vals[ j ].bv_len - 1)/3 + 1);
2252 				}
2253 			}
2254 		}
2255 		len += dr->derefVal.bv_len + STRLENOF("\n");
2256 		buf = ldap_memalloc( len + 1 );
2257 		if ( buf == NULL ) {
2258 			rc = LDAP_NO_MEMORY;
2259 			goto done;
2260 		}
2261 
2262 		ptr = buf;
2263 		ptr = lutil_strcopy( ptr, dr->derefAttr );
2264 		*ptr++ = ':';
2265 		*ptr++ = ' ';
2266 		for ( dv = dr->attrVals; dv != NULL; dv = dv->next ) {
2267 			if ( dv->vals != NULL ) {
2268 				int j;
2269 				for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
2270 					int k = ldif_is_not_printable( dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
2271 
2272 					*ptr++ = '<';
2273 					ptr = lutil_strcopy( ptr, dv->type );
2274 					if ( k ) {
2275 						*ptr++ = ':';
2276 					}
2277 					*ptr++ = '=';
2278 					if ( k ) {
2279 						k = lutil_b64_ntop(
2280 							(unsigned char *) dv->vals[ j ].bv_val,
2281 							dv->vals[ j ].bv_len,
2282 							ptr, buf + len - ptr );
2283 						assert( k >= 0 );
2284 						ptr += k;
2285 
2286 					} else {
2287 						ptr = lutil_memcopy( ptr, dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
2288 					}
2289 					*ptr++ = '>';
2290 					*ptr++ = ';';
2291 				}
2292 			}
2293 		}
2294 		ptr = lutil_strncopy( ptr, dr->derefVal.bv_val, dr->derefVal.bv_len );
2295 		*ptr = '\0';
2296 		assert( ptr <= buf + len );
2297 
2298 		tool_write_ldif( LDIF_PUT_COMMENT, NULL, buf, ptr - buf);
2299 
2300 		ldap_memfree( buf );
2301 	}
2302 
2303 	rc = LDAP_SUCCESS;
2304 
2305 done:;
2306 	ldap_derefresponse_free( drhead );
2307 
2308 	return rc;
2309 }
2310 #endif
2311 
2312 #ifdef LDAP_CONTROL_X_WHATFAILED
2313 static int
print_whatfailed(LDAP * ld,LDAPControl * ctrl)2314 print_whatfailed( LDAP *ld, LDAPControl *ctrl )
2315 {
2316 	BerElement *ber;
2317 	ber_tag_t tag;
2318 	ber_len_t siz;
2319 	BerVarray bva = NULL;
2320 
2321 	/* Create a BerElement from the berval returned in the control. */
2322 	ber = ber_init( &ctrl->ldctl_value );
2323 
2324 	if ( ber == NULL ) {
2325 		return LDAP_NO_MEMORY;
2326 	}
2327 
2328 	siz = sizeof(struct berval);
2329 	tag = ber_scanf( ber, "[M]", &bva, &siz, 0 );
2330 	if ( tag != LBER_ERROR ) {
2331 		int i;
2332 
2333 		tool_write_ldif( LDIF_PUT_COMMENT, " what failed:", NULL, 0 );
2334 
2335 		for ( i = 0; bva[i].bv_val != NULL; i++ ) {
2336 			tool_write_ldif( LDIF_PUT_COMMENT, NULL, bva[i].bv_val, bva[i].bv_len );
2337 		}
2338 
2339 		ldap_memfree( bva );
2340 	}
2341 
2342         ber_free( ber, 1 );
2343 
2344 
2345 	return 0;
2346 }
2347 #endif
2348 
2349 static int
print_syncstate(LDAP * ld,LDAPControl * ctrl)2350 print_syncstate( LDAP *ld, LDAPControl *ctrl )
2351 {
2352 	struct berval syncUUID, syncCookie = BER_BVNULL;
2353 	char buf[LDAP_LUTIL_UUIDSTR_BUFSIZE], *uuidstr = "(UUID malformed)";
2354 	BerElement *ber;
2355 	ber_tag_t tag;
2356 	ber_int_t state;
2357 	int rc;
2358 
2359 	if ( ldif ) {
2360 		return 0;
2361 	}
2362 
2363 	/* Create a BerElement from the berval returned in the control. */
2364 	ber = ber_init( &ctrl->ldctl_value );
2365 
2366 	if ( ber == NULL ) {
2367 		return LDAP_NO_MEMORY;
2368 	}
2369 
2370 	if ( ber_scanf( ber, "{em", &state, &syncUUID ) == LBER_ERROR ) {
2371 		ber_free( ber, 1 );
2372 		return 1;
2373 	}
2374 
2375 	tag = ber_get_stringbv( ber, &syncCookie, 0 );
2376 
2377 	rc = lutil_uuidstr_from_normalized(
2378 			syncUUID.bv_val, syncUUID.bv_len,
2379 			buf, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2380 
2381 	if ( rc > 0 && rc < LDAP_LUTIL_UUIDSTR_BUFSIZE ) {
2382 		uuidstr = buf;
2383 	}
2384 
2385 	switch ( state ) {
2386 		case LDAP_SYNC_PRESENT:
2387 			printf(_("# SyncState control, UUID %s present\n"), uuidstr);
2388 			break;
2389 		case LDAP_SYNC_ADD:
2390 			printf(_("# SyncState control, UUID %s added\n"), uuidstr);
2391 			break;
2392 		case LDAP_SYNC_MODIFY:
2393 			printf(_("# SyncState control, UUID %s modified\n"), uuidstr);
2394 			break;
2395 		case LDAP_SYNC_DELETE:
2396 			printf(_("# SyncState control, UUID %s deleted\n"), uuidstr);
2397 			break;
2398 		default:
2399 			ber_free( ber, 1 );
2400 			return 1;
2401 	}
2402 
2403 	if ( tag != LBER_ERROR ) {
2404 		if ( ldif_is_not_printable( syncCookie.bv_val, syncCookie.bv_len ) ) {
2405 			struct berval bv;
2406 
2407 			bv.bv_len = LUTIL_BASE64_ENCODE_LEN( syncCookie.bv_len ) + 1;
2408 			bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2409 
2410 			bv.bv_len = lutil_b64_ntop(
2411 					(unsigned char *) syncCookie.bv_val, syncCookie.bv_len,
2412 					bv.bv_val, bv.bv_len );
2413 
2414 			printf(_("# cookie:: %s\n"), bv.bv_val );
2415 			ber_memfree( bv.bv_val );
2416 		} else {
2417 			printf(_("# cookie: %s\n"), syncCookie.bv_val );
2418 		}
2419 	}
2420 
2421 	ber_free( ber, 1 );
2422 	return 0;
2423 }
2424 
2425 static int
print_syncdone(LDAP * ld,LDAPControl * ctrl)2426 print_syncdone( LDAP *ld, LDAPControl *ctrl )
2427 {
2428 	BerElement *ber;
2429 	struct berval cookie = BER_BVNULL;
2430 	ber_len_t len;
2431 	ber_int_t refreshDeletes = 0;
2432 
2433 	if ( ldif ) {
2434 		return 0;
2435 	}
2436 
2437 	/* Create a BerElement from the berval returned in the control. */
2438 	ber = ber_init( &ctrl->ldctl_value );
2439 
2440 	if ( ber == NULL ) {
2441 		return LDAP_NO_MEMORY;
2442 	}
2443 
2444 	ber_skip_tag( ber, &len );
2445 	if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
2446 		ber_scanf( ber, "m", &cookie );
2447 	}
2448 	if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
2449 		ber_scanf( ber, "b", &refreshDeletes );
2450 	}
2451 
2452 	printf(_("# SyncDone control refreshDeletes=%d\n"), refreshDeletes ? 1 : 0 );
2453 
2454 	if ( !BER_BVISNULL( &cookie ) ) {
2455 		if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) {
2456 			struct berval bv;
2457 
2458 			bv.bv_len = LUTIL_BASE64_ENCODE_LEN( cookie.bv_len ) + 1;
2459 			bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2460 
2461 			bv.bv_len = lutil_b64_ntop(
2462 					(unsigned char *) cookie.bv_val, cookie.bv_len,
2463 					bv.bv_val, bv.bv_len );
2464 
2465 			printf(_("# cookie:: %s\n"), bv.bv_val );
2466 			ber_memfree( bv.bv_val );
2467 		} else {
2468 			printf(_("# cookie: %s\n"), cookie.bv_val );
2469 		}
2470 	}
2471 
2472 	ber_free( ber, 1 );
2473 	return 0;
2474 }
2475 
2476 #ifdef LDAP_CONTROL_X_DIRSYNC
2477 static int
print_dirsync(LDAP * ld,LDAPControl * ctrl)2478 print_dirsync( LDAP *ld, LDAPControl *ctrl )
2479 {
2480 	int rc, continueFlag;
2481 	struct berval cookie;
2482 
2483 	rc = ldap_parse_dirsync_control( ld, ctrl,
2484 		&continueFlag, &cookie );
2485 	if ( rc == LDAP_SUCCESS ) {
2486 		printf(_("# DirSync control continueFlag=%d\n"), continueFlag );
2487 		if ( !BER_BVISNULL( &cookie )) {
2488 			if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) {
2489 				struct berval bv;
2490 
2491 				bv.bv_len = LUTIL_BASE64_ENCODE_LEN( cookie.bv_len ) + 1;
2492 				bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2493 
2494 				bv.bv_len = lutil_b64_ntop(
2495 						(unsigned char *) cookie.bv_val, cookie.bv_len,
2496 						bv.bv_val, bv.bv_len );
2497 
2498 				printf(_("# cookie:: %s\n"), bv.bv_val );
2499 				ber_memfree( bv.bv_val );
2500 			} else {
2501 				printf(_("# cookie: %s\n"), cookie.bv_val );
2502 			}
2503 		}
2504 	}
2505 	return rc;
2506 }
2507 #endif
2508 
2509 #ifdef LDAP_CONTROL_AUTHZID_RESPONSE
2510 static int
print_authzid(LDAP * ld,LDAPControl * ctrl)2511 print_authzid( LDAP *ld, LDAPControl *ctrl )
2512 {
2513 	if ( ctrl->ldctl_value.bv_len ) {
2514 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2515 			ldif ? "authzid: " : "authzid",
2516 		ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len );
2517 	} else {
2518 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2519 			ldif ? "authzid: " : "authzid",
2520 			"anonymous",  STRLENOF("anonymous") );
2521 	}
2522 
2523 	return 0;
2524 }
2525 #endif
2526 
2527 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
2528 static int
print_ppolicy(LDAP * ld,LDAPControl * ctrl)2529 print_ppolicy( LDAP *ld, LDAPControl *ctrl )
2530 {
2531 	int expire = 0, grace = 0, rc;
2532 	LDAPPasswordPolicyError	pperr;
2533 
2534 	rc = ldap_parse_passwordpolicy_control( ld, ctrl,
2535 		&expire, &grace, &pperr );
2536 	if ( rc == LDAP_SUCCESS ) {
2537 		char	buf[ BUFSIZ ], *ptr = buf;
2538 
2539 		if ( expire != -1 ) {
2540 			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2541 				"expire=%d", expire );
2542 		}
2543 
2544 		if ( grace != -1 ) {
2545 			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2546 				"%sgrace=%d", ptr == buf ? "" : " ", grace );
2547 		}
2548 
2549 		if ( pperr != PP_noError ) {
2550 			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2551 				"%serror=%d (%s)", ptr == buf ? "" : " ",
2552 				pperr,
2553 				ldap_passwordpolicy_err2txt( pperr ) );
2554 		}
2555 
2556 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2557 			ldif ? "ppolicy: " : "ppolicy", buf, ptr - buf );
2558 	}
2559 
2560 	return rc;
2561 }
2562 #endif
2563 
2564 #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRED
2565 static int
print_netscape_pwexpired(LDAP * ld,LDAPControl * ctrl)2566 print_netscape_pwexpired( LDAP *ld, LDAPControl *ctrl )
2567 {
2568 	printf(_("# PasswordExpired control\n") );
2569 	return 0;
2570 }
2571 
2572 static int
print_netscape_pwexpiring(LDAP * ld,LDAPControl * ctrl)2573 print_netscape_pwexpiring( LDAP *ld, LDAPControl *ctrl )
2574 {
2575 	long expiring = 0;
2576 	int rc;
2577 
2578 	rc = ldap_parse_password_expiring_control( ld, ctrl, &expiring );
2579 	if ( rc == LDAP_SUCCESS ) {
2580 		printf(_("# PasswordExpiring control seconds=%ld\n"), expiring );
2581 	}
2582 	return rc;
2583 }
2584 #endif
2585 
2586 #ifdef LDAP_CONTROL_X_ACCOUNT_USABILITY
2587 static int
print_account_usability(LDAP * ld,LDAPControl * ctrl)2588 print_account_usability( LDAP *ld, LDAPControl *ctrl )
2589 {
2590 	LDAPAccountUsability usability;
2591 	ber_int_t available = 0;
2592 	int rc;
2593 
2594 	rc = ldap_parse_accountusability_control( ld, ctrl, &available, &usability );
2595 	if ( rc == LDAP_SUCCESS ) {
2596 		char	buf[ BUFSIZ ], *ptr = buf;
2597 
2598 		ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2599 			   "%savailable", available ? "" : "not " );
2600 		if ( available ) {
2601 			if ( usability.seconds_remaining == -1 ) {
2602 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2603 					" and does not expire" );
2604 			} else {
2605 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2606 					" expire=%d", usability.seconds_remaining );
2607 			}
2608 		} else {
2609 			int added = 0;
2610 			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2611 				" (" /* ')' */ );
2612 
2613 			if ( usability.more_info.inactive ) {
2614 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2615 					"inactive " );
2616 				added++;
2617 			}
2618 			if ( usability.more_info.reset ) {
2619 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2620 					"reset " );
2621 				added++;
2622 			}
2623 			if ( usability.more_info.expired ) {
2624 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2625 					"expired " );
2626 				added++;
2627 			}
2628 
2629 			if ( added ) {
2630 				ptr[-1] = ')';
2631 				*ptr++ = ' ';
2632 			} else {
2633 				*(--ptr) = '\0';
2634 			}
2635 
2636 			if ( usability.more_info.remaining_grace != -1 ) {
2637 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2638 					"grace=%d ", usability.more_info.remaining_grace );
2639 			}
2640 
2641 			if ( usability.more_info.seconds_before_unlock != -1 ) {
2642 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2643 					"seconds_before_unlock=%d ", usability.more_info.seconds_before_unlock );
2644 			}
2645 
2646 			*(--ptr) = '\0';
2647 		}
2648 
2649 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2650 			ldif ? "accountUsability: " : "accountUsability", buf, ptr - buf );
2651 	}
2652 
2653 	return rc;
2654 }
2655 #endif
2656 
tool_print_ctrls(LDAP * ld,LDAPControl ** ctrls)2657 void tool_print_ctrls(
2658 	LDAP		*ld,
2659 	LDAPControl	**ctrls )
2660 {
2661 	int	i;
2662 	char	*ptr;
2663 
2664 	for ( i = 0; ctrls[i] != NULL; i++ ) {
2665 		/* control: OID criticality base64value */
2666 		struct berval b64 = BER_BVNULL;
2667 		ber_len_t len;
2668 		char *str;
2669 		int j;
2670 
2671 		/* FIXME: there might be cases where a control has NULL OID;
2672 		 * this makes little sense, especially when returned by the
2673 		 * server, but libldap happily allows it */
2674 		if ( ctrls[i]->ldctl_oid == NULL ) {
2675 			continue;
2676 		}
2677 
2678 		len = ldif ? 2 : 0;
2679 		len += strlen( ctrls[i]->ldctl_oid );
2680 
2681 		/* add enough for space after OID and the critical value itself */
2682 		len += ctrls[i]->ldctl_iscritical
2683 			? sizeof("true") : sizeof("false");
2684 
2685 		/* convert to base64 */
2686 		if ( !BER_BVISNULL( &ctrls[i]->ldctl_value ) ) {
2687 			b64.bv_len = LUTIL_BASE64_ENCODE_LEN(
2688 				ctrls[i]->ldctl_value.bv_len ) + 1;
2689 			b64.bv_val = ber_memalloc( b64.bv_len + 1 );
2690 
2691 			b64.bv_len = lutil_b64_ntop(
2692 				(unsigned char *) ctrls[i]->ldctl_value.bv_val,
2693 				ctrls[i]->ldctl_value.bv_len,
2694 				b64.bv_val, b64.bv_len );
2695 		}
2696 
2697 		if ( b64.bv_len ) {
2698 			len += 1 + b64.bv_len;
2699 		}
2700 
2701 		ptr = str = malloc( len + 1 );
2702 		if ( ldif ) {
2703 			ptr = lutil_strcopy( ptr, ": " );
2704 		}
2705 		ptr = lutil_strcopy( ptr, ctrls[i]->ldctl_oid );
2706 		ptr = lutil_strcopy( ptr, ctrls[i]->ldctl_iscritical
2707 			? " true" : " false" );
2708 
2709 		if ( b64.bv_len ) {
2710 			ptr = lutil_strcopy( ptr, " " );
2711 			ptr = lutil_strcopy( ptr, b64.bv_val );
2712 		}
2713 
2714 		if ( ldif < 2 ) {
2715 			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2716 				"control", str, len );
2717 		}
2718 
2719 		free( str );
2720 		if ( b64.bv_len ) {
2721 			ber_memfree( b64.bv_val );
2722 		}
2723 
2724 		/* known controls */
2725 		for ( j = 0; tool_ctrl_response[j].oid != NULL; j++ ) {
2726 			if ( strcmp( tool_ctrl_response[j].oid, ctrls[i]->ldctl_oid ) == 0 ) {
2727 				if ( !(tool_ctrl_response[j].mask & tool_type )) {
2728 					/* this control should not appear
2729 					 * with this tool; warning? */
2730 				}
2731 				break;
2732 			}
2733 		}
2734 
2735 		if ( tool_ctrl_response[j].oid != NULL && tool_ctrl_response[j].func ) {
2736 			(void)tool_ctrl_response[j].func( ld, ctrls[i] );
2737 		}
2738 	}
2739 }
2740 
2741 int
tool_write_ldif(int type,char * name,char * value,ber_len_t vallen)2742 tool_write_ldif( int type, char *name, char *value, ber_len_t vallen )
2743 {
2744 	char	*ldif;
2745 
2746 	if (( ldif = ldif_put_wrap( type, name, value, vallen, ldif_wrap )) == NULL ) {
2747 		return( -1 );
2748 	}
2749 
2750 	fputs( ldif, stdout );
2751 	ber_memfree( ldif );
2752 
2753 	return( 0 );
2754 }
2755 
2756 int
tool_is_oid(const char * s)2757 tool_is_oid( const char *s )
2758 {
2759 	int		first = 1;
2760 
2761 	if ( !isdigit( (unsigned char) s[ 0 ] ) ) {
2762 		return 0;
2763 	}
2764 
2765 	for ( ; s[ 0 ]; s++ ) {
2766 		if ( s[ 0 ] == '.' ) {
2767 			if ( s[ 1 ] == '\0' ) {
2768 				return 0;
2769 			}
2770 			first = 1;
2771 			continue;
2772 		}
2773 
2774 		if ( !isdigit( (unsigned char) s[ 0 ] ) ) {
2775 			return 0;
2776 		}
2777 
2778 		if ( first == 1 && s[ 0 ] == '0' && s[ 1 ] != '.' ) {
2779 			return 0;
2780 		}
2781 		first = 0;
2782 	}
2783 
2784 	return 1;
2785 }
2786