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