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