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