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