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