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