xref: /netbsd-src/external/bsd/openldap/dist/clients/tools/common.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: common.c,v 1.10 2021/08/14 16:14:49 christos Exp $	*/
24e6df137Slukem 
32de962bdSlukem /* common.c - common routines for the ldap client tools */
4cb54be06Stron /* $OpenLDAP$ */
52de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
62de962bdSlukem  *
7*549b59edSchristos  * Copyright 1998-2021 The OpenLDAP Foundation.
82de962bdSlukem  * Portions Copyright 2003 Kurt D. Zeilenga.
92de962bdSlukem  * Portions Copyright 2003 IBM Corporation.
102de962bdSlukem  * All rights reserved.
112de962bdSlukem  *
122de962bdSlukem  * Redistribution and use in source and binary forms, with or without
132de962bdSlukem  * modification, are permitted only as authorized by the OpenLDAP
142de962bdSlukem  * Public License.
152de962bdSlukem  *
162de962bdSlukem  * A copy of this license is available in the file LICENSE in the
172de962bdSlukem  * top-level directory of the distribution or, alternatively, at
182de962bdSlukem  * <http://www.OpenLDAP.org/license.html>.
192de962bdSlukem  */
202de962bdSlukem /* ACKNOWLEDGEMENTS:
212de962bdSlukem  * This file was initially created by Hallvard B. Furuseth based (in
222de962bdSlukem  * part) upon argument parsing code for individual tools located in
232de962bdSlukem  * this directory.   Additional contributors include:
242de962bdSlukem  *   Kurt D. Zeilenga (additional common argument and control support)
252de962bdSlukem  */
262de962bdSlukem 
27915bea73Schristos #include <sys/cdefs.h>
28*549b59edSchristos __RCSID("$NetBSD: common.c,v 1.10 2021/08/14 16:14:49 christos Exp $");
29915bea73Schristos 
302de962bdSlukem #include "portable.h"
312de962bdSlukem 
322de962bdSlukem #include <stdio.h>
332de962bdSlukem 
342de962bdSlukem #include <ac/stdlib.h>
352de962bdSlukem #include <ac/signal.h>
362de962bdSlukem #include <ac/string.h>
372de962bdSlukem #include <ac/ctype.h>
382de962bdSlukem #include <ac/unistd.h>
392de962bdSlukem #include <ac/errno.h>
402de962bdSlukem #include <ac/time.h>
412de962bdSlukem #include <ac/socket.h>
422de962bdSlukem 
432de962bdSlukem #ifdef HAVE_CYRUS_SASL
442de962bdSlukem #ifdef HAVE_SASL_SASL_H
452de962bdSlukem #include <sasl/sasl.h>
462de962bdSlukem #else
472de962bdSlukem #include <sasl.h>
482de962bdSlukem #endif
492de962bdSlukem #endif
502de962bdSlukem 
512de962bdSlukem #include <ldap.h>
522de962bdSlukem 
532de962bdSlukem #include "ldif.h"
542de962bdSlukem #include "lutil.h"
552de962bdSlukem #include "lutil_ldap.h"
562de962bdSlukem #include "ldap_defaults.h"
572de962bdSlukem #include "ldap_pvt.h"
582de962bdSlukem #include "lber_pvt.h"
592de962bdSlukem 
602de962bdSlukem #include "common.h"
612de962bdSlukem 
622de962bdSlukem /* input-related vars */
632de962bdSlukem 
642de962bdSlukem /* misc. parameters */
652de962bdSlukem tool_type_t	tool_type;
662de962bdSlukem int		contoper = 0;
672de962bdSlukem int		debug = 0;
682de962bdSlukem char		*infile = NULL;
692de962bdSlukem int		dont = 0;
704e6df137Slukem int		nocanon = 0;
712de962bdSlukem int		referrals = 0;
722de962bdSlukem int		verbose = 0;
732de962bdSlukem int		ldif = 0;
74915bea73Schristos ber_len_t	ldif_wrap = 0;
752de962bdSlukem char		*prog = NULL;
762de962bdSlukem 
772de962bdSlukem /* connection */
782de962bdSlukem char		*ldapuri = NULL;
792de962bdSlukem int		use_tls = 0;
802de962bdSlukem int		protocol = -1;
812de962bdSlukem int		version = 0;
822de962bdSlukem 
832de962bdSlukem /* authc/authz */
842de962bdSlukem int		authmethod = -1;
852de962bdSlukem char		*binddn = NULL;
862de962bdSlukem int		want_bindpw = 0;
872de962bdSlukem struct berval	passwd = { 0, NULL };
882de962bdSlukem char		*pw_file = NULL;
892de962bdSlukem #ifdef HAVE_CYRUS_SASL
902de962bdSlukem unsigned	sasl_flags = LDAP_SASL_AUTOMATIC;
912de962bdSlukem char		*sasl_realm = NULL;
922de962bdSlukem char		*sasl_authc_id = NULL;
932de962bdSlukem char		*sasl_authz_id = NULL;
942de962bdSlukem char		*sasl_mech = NULL;
952de962bdSlukem char		*sasl_secprops = NULL;
962de962bdSlukem #endif
972de962bdSlukem 
982de962bdSlukem /* controls */
992de962bdSlukem int		assertctl;
1002de962bdSlukem char		*assertion = NULL;
101bb30016cSlukem struct berval	assertionvalue = BER_BVNULL;
1022de962bdSlukem char		*authzid = NULL;
103*549b59edSchristos int		authzcrit = 1;
1042de962bdSlukem /* support deprecated early version of proxyAuthz */
1052de962bdSlukem #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ	"2.16.840.1.113730.3.4.12"
1062de962bdSlukem #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
1072de962bdSlukem char		*proxydn = NULL;
1082de962bdSlukem #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
1092de962bdSlukem int		manageDIT = 0;
1102de962bdSlukem int		manageDSAit = 0;
1112de962bdSlukem int		noop = 0;
1122de962bdSlukem int		ppolicy = 0;
1132de962bdSlukem int		preread = 0;
1142de962bdSlukem static char	*preread_attrs = NULL;
1152de962bdSlukem int		postread = 0;
1162de962bdSlukem static char	*postread_attrs = NULL;
1172de962bdSlukem ber_int_t	pr_morePagedResults = 1;
1182de962bdSlukem struct berval	pr_cookie = { 0, NULL };
1192de962bdSlukem #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1202de962bdSlukem int		chaining = 0;
1212de962bdSlukem static int	chainingResolve = -1;
1222de962bdSlukem static int	chainingContinuation = -1;
1232de962bdSlukem #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1242de962bdSlukem #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1252de962bdSlukem static int	sessionTracking = 0;
126*549b59edSchristos static char	*sessionTrackingName;
1272de962bdSlukem struct berval	stValue;
1282de962bdSlukem #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
1294e6df137Slukem ber_int_t vlvPos;
1304e6df137Slukem ber_int_t vlvCount;
1314e6df137Slukem struct berval *vlvContext;
132*549b59edSchristos static int	bauthzid;
1332de962bdSlukem 
1342de962bdSlukem LDAPControl	*unknown_ctrls = NULL;
1352de962bdSlukem int		unknown_ctrls_num = 0;
1362de962bdSlukem 
1372de962bdSlukem /* options */
1382de962bdSlukem struct timeval	nettimeout = { -1 , 0 };
1392de962bdSlukem 
1402de962bdSlukem typedef int (*print_ctrl_fn)( LDAP *ld, LDAPControl *ctrl );
1412de962bdSlukem 
1422de962bdSlukem static int print_preread( LDAP *ld, LDAPControl *ctrl );
1432de962bdSlukem static int print_postread( LDAP *ld, LDAPControl *ctrl );
1442de962bdSlukem static int print_paged_results( LDAP *ld, LDAPControl *ctrl );
145*549b59edSchristos static int print_psearch( LDAP *ld, LDAPControl *ctrl );
146*549b59edSchristos #ifdef LDAP_CONTROL_AUTHZID_RESPONSE
147*549b59edSchristos static int print_authzid( LDAP *ld, LDAPControl *ctrl );
148*549b59edSchristos #endif
1492de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1502de962bdSlukem static int print_ppolicy( LDAP *ld, LDAPControl *ctrl );
1512de962bdSlukem #endif
1524e6df137Slukem static int print_sss( LDAP *ld, LDAPControl *ctrl );
1534e6df137Slukem static int print_vlv( LDAP *ld, LDAPControl *ctrl );
1544e6df137Slukem #ifdef LDAP_CONTROL_X_DEREF
1554e6df137Slukem static int print_deref( LDAP *ld, LDAPControl *ctrl );
1564e6df137Slukem #endif
1574e6df137Slukem #ifdef LDAP_CONTROL_X_WHATFAILED
1584e6df137Slukem static int print_whatfailed( LDAP *ld, LDAPControl *ctrl );
1594e6df137Slukem #endif
160*549b59edSchristos static int print_syncstate( LDAP *ld, LDAPControl *ctrl );
161*549b59edSchristos static int print_syncdone( LDAP *ld, LDAPControl *ctrl );
162*549b59edSchristos #ifdef LDAP_CONTROL_X_DIRSYNC
163*549b59edSchristos static int print_dirsync( LDAP *ld, LDAPControl *ctrl );
164*549b59edSchristos #endif
165*549b59edSchristos #ifdef LDAP_CONTROL_X_ACCOUNT_USABILITY
166*549b59edSchristos static int print_account_usability( LDAP *ld, LDAPControl *ctrl );
167*549b59edSchristos #endif
168*549b59edSchristos #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRED
169*549b59edSchristos static int print_netscape_pwexpired( LDAP *ld, LDAPControl *ctrl );
170*549b59edSchristos static int print_netscape_pwexpiring( LDAP *ld, LDAPControl *ctrl );
171*549b59edSchristos #endif
1722de962bdSlukem 
1732de962bdSlukem static struct tool_ctrls_t {
1742de962bdSlukem 	const char	*oid;
1752de962bdSlukem 	unsigned	mask;
1762de962bdSlukem 	print_ctrl_fn	func;
1772de962bdSlukem } tool_ctrl_response[] = {
1782de962bdSlukem 	{ LDAP_CONTROL_PRE_READ,			TOOL_ALL,	print_preread },
1792de962bdSlukem 	{ LDAP_CONTROL_POST_READ,			TOOL_ALL,	print_postread },
1802de962bdSlukem 	{ LDAP_CONTROL_PAGEDRESULTS,			TOOL_SEARCH,	print_paged_results },
181*549b59edSchristos 	{ LDAP_CONTROL_PERSIST_ENTRY_CHANGE_NOTICE,			TOOL_SEARCH,	print_psearch },
182*549b59edSchristos #ifdef LDAP_CONTROL_AUTHZID_RESPONSE
183*549b59edSchristos 	/* this is generally deprecated in favor of LDAP WhoAmI? operation, hence only supported as a VC inner control */
184*549b59edSchristos 	{ LDAP_CONTROL_AUTHZID_RESPONSE,		TOOL_VC,	print_authzid },
185*549b59edSchristos #endif
1862de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1872de962bdSlukem 	{ LDAP_CONTROL_PASSWORDPOLICYRESPONSE,		TOOL_ALL,	print_ppolicy },
1882de962bdSlukem #endif
1894e6df137Slukem 	{ LDAP_CONTROL_SORTRESPONSE,	TOOL_SEARCH,	print_sss },
1904e6df137Slukem 	{ LDAP_CONTROL_VLVRESPONSE,		TOOL_SEARCH,	print_vlv },
1914e6df137Slukem #ifdef LDAP_CONTROL_X_DEREF
1924e6df137Slukem 	{ LDAP_CONTROL_X_DEREF,				TOOL_SEARCH,	print_deref },
1934e6df137Slukem #endif
1944e6df137Slukem #ifdef LDAP_CONTROL_X_WHATFAILED
1954e6df137Slukem 	{ LDAP_CONTROL_X_WHATFAILED,			TOOL_ALL,	print_whatfailed },
1964e6df137Slukem #endif
197*549b59edSchristos 	{ LDAP_CONTROL_SYNC_STATE,			TOOL_SEARCH,	print_syncstate },
198*549b59edSchristos 	{ LDAP_CONTROL_SYNC_DONE,			TOOL_SEARCH,	print_syncdone },
199*549b59edSchristos #ifdef LDAP_CONTROL_X_DIRSYNC
200*549b59edSchristos 	{ LDAP_CONTROL_X_DIRSYNC,			TOOL_SEARCH,	print_dirsync },
201*549b59edSchristos #endif
202*549b59edSchristos #ifdef LDAP_CONTROL_X_ACCOUNT_USABILITY
203*549b59edSchristos 	{ LDAP_CONTROL_X_ACCOUNT_USABILITY,		TOOL_SEARCH,	print_account_usability },
204*549b59edSchristos #endif
205*549b59edSchristos #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRED
206*549b59edSchristos 	{ LDAP_CONTROL_X_PASSWORD_EXPIRED,		TOOL_ALL,	print_netscape_pwexpired },
207*549b59edSchristos 	{ LDAP_CONTROL_X_PASSWORD_EXPIRING,		TOOL_ALL,	print_netscape_pwexpiring },
208*549b59edSchristos #endif
2092de962bdSlukem 	{ NULL,						0,		NULL }
2102de962bdSlukem };
2112de962bdSlukem 
2122de962bdSlukem /* "features" */
2132de962bdSlukem enum { Intr_None = 0, Intr_Abandon, Intr_Cancel, Intr_Ignore };
2142de962bdSlukem static volatile sig_atomic_t	gotintr, abcan;
2152de962bdSlukem 
216*549b59edSchristos int backlog;
217*549b59edSchristos 
2182de962bdSlukem 
2192de962bdSlukem #ifdef LDAP_CONTROL_X_SESSION_TRACKING
2202de962bdSlukem static int
st_value(LDAP * ld,struct berval * value)2212de962bdSlukem st_value( LDAP *ld, struct berval *value )
2222de962bdSlukem {
2232de962bdSlukem 	char		*ip = NULL, *name = NULL;
2242de962bdSlukem 	struct berval	id = { 0 };
2252de962bdSlukem 	char		namebuf[ MAXHOSTNAMELEN ];
2262de962bdSlukem 
2272de962bdSlukem 	if ( gethostname( namebuf, sizeof( namebuf ) ) == 0 ) {
2282de962bdSlukem 		struct hostent	*h;
2292de962bdSlukem 		struct in_addr	addr;
2302de962bdSlukem 
2312de962bdSlukem 		name = namebuf;
2322de962bdSlukem 
2332de962bdSlukem 		h = gethostbyname( name );
2342de962bdSlukem 		if ( h != NULL ) {
2352de962bdSlukem 			AC_MEMCPY( &addr, h->h_addr, sizeof( addr ) );
2362de962bdSlukem 			ip = inet_ntoa( addr );
2372de962bdSlukem 		}
2382de962bdSlukem 	}
2392de962bdSlukem 
240*549b59edSchristos 	if ( sessionTrackingName != NULL ) {
241*549b59edSchristos 		ber_str2bv( sessionTrackingName , 0, 0, &id );
242*549b59edSchristos 	} else
2432de962bdSlukem #ifdef HAVE_CYRUS_SASL
2442de962bdSlukem 	if ( sasl_authz_id != NULL ) {
2452de962bdSlukem 		ber_str2bv( sasl_authz_id, 0, 0, &id );
2462de962bdSlukem 
2472de962bdSlukem 	} else if ( sasl_authc_id != NULL ) {
2482de962bdSlukem 		ber_str2bv( sasl_authc_id, 0, 0, &id );
2492de962bdSlukem 
2502de962bdSlukem 	} else
2512de962bdSlukem #endif /* HAVE_CYRUS_SASL */
2522de962bdSlukem 	if ( binddn != NULL ) {
2532de962bdSlukem 		ber_str2bv( binddn, 0, 0, &id );
2542de962bdSlukem 	}
2552de962bdSlukem 
2562de962bdSlukem 	if ( ldap_create_session_tracking_value( ld,
2572de962bdSlukem 		ip, name, LDAP_CONTROL_X_SESSION_TRACKING_USERNAME,
2582de962bdSlukem 		&id, &stValue ) )
2592de962bdSlukem 	{
2602de962bdSlukem 		fprintf( stderr, _("Session tracking control encoding error!\n") );
2612de962bdSlukem 		return -1;
2622de962bdSlukem 	}
2632de962bdSlukem 
2642de962bdSlukem 	return 0;
2652de962bdSlukem }
2662de962bdSlukem #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
2672de962bdSlukem 
2682de962bdSlukem RETSIGTYPE
do_sig(int sig)2692de962bdSlukem do_sig( int sig )
2702de962bdSlukem {
2712de962bdSlukem 	gotintr = abcan;
2722de962bdSlukem }
2732de962bdSlukem 
2742de962bdSlukem void
tool_init(tool_type_t type)2752de962bdSlukem tool_init( tool_type_t type )
2762de962bdSlukem {
2772de962bdSlukem 	tool_type = type;
2782de962bdSlukem 	ldap_pvt_setlocale(LC_MESSAGES, "");
2792de962bdSlukem 	ldap_pvt_bindtextdomain(OPENLDAP_PACKAGE, LDAP_LOCALEDIR);
2802de962bdSlukem 	ldap_pvt_textdomain(OPENLDAP_PACKAGE);
2812de962bdSlukem }
2822de962bdSlukem 
2832de962bdSlukem void
tool_destroy(void)2842de962bdSlukem tool_destroy( void )
2852de962bdSlukem {
286cb54be06Stron 	static int destroyed;
287cb54be06Stron 	if ( destroyed++ )
288cb54be06Stron 		return;
289cb54be06Stron 
2902de962bdSlukem #ifdef HAVE_CYRUS_SASL
2912de962bdSlukem 	sasl_done();
2922de962bdSlukem #endif
2932de962bdSlukem #ifdef HAVE_TLS
2942de962bdSlukem 	ldap_pvt_tls_destroy();
2952de962bdSlukem #endif
2962de962bdSlukem 
2972de962bdSlukem 	if ( ldapuri != NULL ) {
2982de962bdSlukem 		ber_memfree( ldapuri );
2992de962bdSlukem 		ldapuri = NULL;
3002de962bdSlukem 	}
3012de962bdSlukem 
3022de962bdSlukem 	if ( pr_cookie.bv_val != NULL ) {
3032de962bdSlukem 		ber_memfree( pr_cookie.bv_val );
304cb54be06Stron 		BER_BVZERO( &pr_cookie );
3052de962bdSlukem 	}
3064e6df137Slukem 
3074e6df137Slukem 	if ( passwd.bv_val != NULL ) {
3084e6df137Slukem 		ber_memfree( passwd.bv_val );
309cb54be06Stron 		BER_BVZERO( &passwd );
3104e6df137Slukem 	}
311a8c4d9a8Sadam 
312*549b59edSchristos #ifdef LDAP_CONTROL_X_SESSION_TRACKING
313*549b59edSchristos 	if ( !BER_BVISNULL( &stValue ) ) {
314*549b59edSchristos 		ber_memfree( stValue.bv_val );
315*549b59edSchristos 		BER_BVZERO( &stValue );
316cb54be06Stron 	}
317cb54be06Stron 
318*549b59edSchristos #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
3192de962bdSlukem }
3202de962bdSlukem 
3212de962bdSlukem void
tool_common_usage(void)3222de962bdSlukem tool_common_usage( void )
3232de962bdSlukem {
3242de962bdSlukem 	static const char *const descriptions[] = {
3252de962bdSlukem N_("  -d level   set LDAP debugging level to `level'\n"),
3262de962bdSlukem N_("  -D binddn  bind DN\n"),
3272de962bdSlukem N_("  -e [!]<ext>[=<extparam>] general extensions (! indicates criticality)\n")
3284e6df137Slukem N_("             [!]assert=<filter>     (RFC 4528; a RFC 4515 Filter string)\n")
3294e6df137Slukem N_("             [!]authzid=<authzid>   (RFC 4370; \"dn:<dn>\" or \"u:<user>\")\n")
330*549b59edSchristos N_("             [!]bauthzid            (RFC 3829)\n")
3312de962bdSlukem #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
3322de962bdSlukem #if 0
3332de962bdSlukem                  /* non-advertized support for proxyDN */
3342de962bdSlukem N_("             [!]proxydn=<dn>        (a RFC 4514 DN string)\n")
3352de962bdSlukem #endif
3362de962bdSlukem #endif
3372de962bdSlukem #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
3382de962bdSlukem N_("             [!]chaining[=<resolveBehavior>[/<continuationBehavior>]]\n")
3392de962bdSlukem N_("                     one of \"chainingPreferred\", \"chainingRequired\",\n")
3402de962bdSlukem N_("                     \"referralsPreferred\", \"referralsRequired\"\n")
3412de962bdSlukem #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
3424e6df137Slukem N_("             [!]manageDSAit         (RFC 3296)\n")
3432de962bdSlukem N_("             [!]noop\n")
3442de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
3452de962bdSlukem N_("             ppolicy\n")
3462de962bdSlukem #endif
3474e6df137Slukem N_("             [!]postread[=<attrs>]  (RFC 4527; comma-separated attr list)\n")
3484e6df137Slukem N_("             [!]preread[=<attrs>]   (RFC 4527; comma-separated attr list)\n")
3492de962bdSlukem N_("             [!]relax\n")
3502de962bdSlukem #ifdef LDAP_CONTROL_X_SESSION_TRACKING
351*549b59edSchristos N_("             [!]sessiontracking[=<username>]\n")
3522de962bdSlukem #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
3532de962bdSlukem N_("             abandon, cancel, ignore (SIGINT sends abandon/cancel,\n"
3542de962bdSlukem    "             or ignores response; if critical, doesn't wait for SIGINT.\n"
3552de962bdSlukem    "             not really controls)\n")
3562de962bdSlukem N_("  -H URI     LDAP Uniform Resource Identifier(s)\n"),
3572de962bdSlukem N_("  -I         use SASL Interactive mode\n"),
3582de962bdSlukem N_("  -n         show what would be done but don't actually do it\n"),
3594e6df137Slukem N_("  -N         do not use reverse DNS to canonicalize SASL host name\n"),
3602de962bdSlukem N_("  -O props   SASL security properties\n"),
361*549b59edSchristos N_("  -o <opt>[=<optparam>] any libldap ldap.conf options, plus\n"),
362*549b59edSchristos N_("             ldif_wrap=<width> (in columns, or \"no\" for no wrapping)\n"),
3632de962bdSlukem N_("             nettimeout=<timeout> (in seconds, or \"none\" or \"max\")\n"),
3642de962bdSlukem N_("  -Q         use SASL Quiet mode\n"),
3652de962bdSlukem N_("  -R realm   SASL realm\n"),
3662de962bdSlukem N_("  -U authcid SASL authentication identity\n"),
3672de962bdSlukem N_("  -v         run in verbose mode (diagnostics to standard output)\n"),
3682de962bdSlukem N_("  -V         print version info (-VV only)\n"),
3692de962bdSlukem N_("  -w passwd  bind password (for simple authentication)\n"),
3702de962bdSlukem N_("  -W         prompt for bind password\n"),
3712de962bdSlukem N_("  -x         Simple authentication\n"),
3722de962bdSlukem N_("  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"),
3732de962bdSlukem N_("  -y file    Read password from file\n"),
3742de962bdSlukem N_("  -Y mech    SASL mechanism\n"),
3752de962bdSlukem N_("  -Z         Start TLS request (-ZZ to require successful response)\n"),
3762de962bdSlukem NULL
3772de962bdSlukem 	};
3782de962bdSlukem 	const char *const *cpp;
3792de962bdSlukem 
3802de962bdSlukem 	fputs( _("Common options:\n"), stderr );
3812de962bdSlukem 	for( cpp = descriptions; *cpp != NULL; cpp++ ) {
3822de962bdSlukem 		if( strchr( options, (*cpp)[3] ) || (*cpp)[3] == ' ' ) {
3832de962bdSlukem 			fputs( _(*cpp), stderr );
3842de962bdSlukem 		}
3852de962bdSlukem 	}
386cb54be06Stron 
387cb54be06Stron 	tool_destroy();
3882de962bdSlukem }
3892de962bdSlukem 
tool_perror(const char * func,int err,const char * extra,const char * matched,const char * info,char ** refs)3902de962bdSlukem void tool_perror(
3912de962bdSlukem 	const char *func,
3922de962bdSlukem 	int err,
3932de962bdSlukem 	const char *extra,
3942de962bdSlukem 	const char *matched,
3952de962bdSlukem 	const char *info,
3962de962bdSlukem 	char **refs )
3972de962bdSlukem {
3982de962bdSlukem 	fprintf( stderr, "%s: %s (%d)%s\n",
3992de962bdSlukem 		func, ldap_err2string( err ), err, extra ? extra : "" );
4002de962bdSlukem 
4012de962bdSlukem 	if ( matched && *matched ) {
4022de962bdSlukem 		fprintf( stderr, _("\tmatched DN: %s\n"), matched );
4032de962bdSlukem 	}
4042de962bdSlukem 
4052de962bdSlukem 	if ( info && *info ) {
4062de962bdSlukem 		fprintf( stderr, _("\tadditional info: %s\n"), info );
4072de962bdSlukem 	}
4082de962bdSlukem 
4092de962bdSlukem 	if ( refs && *refs ) {
4102de962bdSlukem 		int i;
4112de962bdSlukem 		fprintf( stderr, _("\treferrals:\n") );
4122de962bdSlukem 		for( i=0; refs[i]; i++ ) {
4132de962bdSlukem 			fprintf( stderr, "\t\t%s\n", refs[i] );
4142de962bdSlukem 		}
4152de962bdSlukem 	}
4162de962bdSlukem }
4172de962bdSlukem 
4182de962bdSlukem 
4192de962bdSlukem void
tool_args(int argc,char ** argv)4202de962bdSlukem tool_args( int argc, char **argv )
4212de962bdSlukem {
4222de962bdSlukem 	int i;
4232de962bdSlukem 
4242de962bdSlukem 	while (( i = getopt( argc, argv, options )) != EOF ) {
4252de962bdSlukem 		int crit, ival;
4262de962bdSlukem 		char *control, *cvalue, *next;
4272de962bdSlukem 		switch( i ) {
4282de962bdSlukem 		case 'c':	/* continuous operation mode */
4292de962bdSlukem 			contoper++;
4302de962bdSlukem 			break;
431cb54be06Stron 		case 'C':	/* referrals: obsolete */
4322de962bdSlukem 			referrals++;
4332de962bdSlukem 			break;
4342de962bdSlukem 		case 'd':
4352de962bdSlukem 			ival = strtol( optarg, &next, 10 );
4362de962bdSlukem 			if (next == NULL || next[0] != '\0') {
4372de962bdSlukem 				fprintf( stderr, "%s: unable to parse debug value \"%s\"\n", prog, optarg);
4382de962bdSlukem 				exit(EXIT_FAILURE);
4392de962bdSlukem 			}
4402de962bdSlukem 			debug |= ival;
4412de962bdSlukem 			break;
4422de962bdSlukem 		case 'D':	/* bind DN */
4432de962bdSlukem 			if( binddn != NULL ) {
4442de962bdSlukem 				fprintf( stderr, "%s: -D previously specified\n", prog );
4452de962bdSlukem 				exit( EXIT_FAILURE );
4462de962bdSlukem 			}
447*549b59edSchristos 			binddn = optarg;
4482de962bdSlukem 			break;
4492de962bdSlukem 		case 'e':	/* general extensions (controls and such) */
4502de962bdSlukem 			/* should be extended to support comma separated list of
4512de962bdSlukem 			 *	[!]key[=value] parameters, e.g.  -e !foo,bar=567
4522de962bdSlukem 			 */
4532de962bdSlukem 
4542de962bdSlukem 			crit = 0;
4552de962bdSlukem 			cvalue = NULL;
456*549b59edSchristos 			while ( optarg[0] == '!' ) {
457*549b59edSchristos 				crit++;
4582de962bdSlukem 				optarg++;
4592de962bdSlukem 			}
4602de962bdSlukem 
461*549b59edSchristos 			control = optarg;
4622de962bdSlukem 			if ( (cvalue = strchr( control, '=' )) != NULL ) {
4632de962bdSlukem 				*cvalue++ = '\0';
4642de962bdSlukem 			}
4652de962bdSlukem 
4662de962bdSlukem 			if ( strcasecmp( control, "assert" ) == 0 ) {
4672de962bdSlukem 				if( assertctl ) {
4682de962bdSlukem 					fprintf( stderr, "assert control previously specified\n");
4692de962bdSlukem 					exit( EXIT_FAILURE );
4702de962bdSlukem 				}
4712de962bdSlukem 				if( cvalue == NULL ) {
4722de962bdSlukem 					fprintf( stderr, "assert: control value expected\n" );
4732de962bdSlukem 					usage();
4742de962bdSlukem 				}
4752de962bdSlukem 
4762de962bdSlukem 				assertctl = 1 + crit;
4772de962bdSlukem 
4782de962bdSlukem 				assert( assertion == NULL );
479*549b59edSchristos 				assertion = cvalue;
4802de962bdSlukem 
4812de962bdSlukem 			} else if ( strcasecmp( control, "authzid" ) == 0 ) {
4822de962bdSlukem 				if( authzid != NULL ) {
4832de962bdSlukem 					fprintf( stderr, "authzid control previously specified\n");
4842de962bdSlukem 					exit( EXIT_FAILURE );
4852de962bdSlukem 				}
4862de962bdSlukem #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
4872de962bdSlukem 				if( proxydn != NULL ) {
4882de962bdSlukem 					fprintf( stderr, "authzid control incompatible with proxydn\n");
4892de962bdSlukem 					exit( EXIT_FAILURE );
4902de962bdSlukem 				}
4912de962bdSlukem #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
4922de962bdSlukem 				if( cvalue == NULL ) {
4932de962bdSlukem 					fprintf( stderr, "authzid: control value expected\n" );
4942de962bdSlukem 					usage();
4952de962bdSlukem 				}
4962de962bdSlukem 				if( !crit ) {
4972de962bdSlukem 					fprintf( stderr, "authzid: must be marked critical\n" );
4982de962bdSlukem 					usage();
499*549b59edSchristos 				} else if ( crit > 1 ) {
500*549b59edSchristos 					/* purposely flag proxied authorization
501*549b59edSchristos 					 * as non-critical, to test DSA */
502*549b59edSchristos 					authzcrit = 0;
5032de962bdSlukem 				}
5042de962bdSlukem 
5052de962bdSlukem 				assert( authzid == NULL );
506*549b59edSchristos 				authzid = cvalue;
5072de962bdSlukem 
5082de962bdSlukem #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
5092de962bdSlukem 			} else if ( strcasecmp( control, "proxydn" ) == 0 ) {
5102de962bdSlukem 				if( proxydn != NULL ) {
5112de962bdSlukem 					fprintf( stderr, "proxydn control previously specified\n");
5122de962bdSlukem 					exit( EXIT_FAILURE );
5132de962bdSlukem 				}
5142de962bdSlukem 				if( authzid != NULL ) {
5152de962bdSlukem 					fprintf( stderr, "proxydn control incompatible with authzid\n");
5162de962bdSlukem 					exit( EXIT_FAILURE );
5172de962bdSlukem 				}
5182de962bdSlukem 				if( cvalue == NULL ) {
5192de962bdSlukem 					fprintf( stderr, "proxydn: control value expected\n" );
5202de962bdSlukem 					usage();
5212de962bdSlukem 				}
5222de962bdSlukem 				if( !crit ) {
5232de962bdSlukem 					fprintf( stderr, "proxydn: must be marked critical\n" );
5242de962bdSlukem 					usage();
525*549b59edSchristos 				} else if ( crit > 1 ) {
526*549b59edSchristos 					/* purposely flag proxied authorization
527*549b59edSchristos 					 * as non-critical, to test DSA */
528*549b59edSchristos 					authzcrit = 0;
5292de962bdSlukem 				}
5302de962bdSlukem 
5312de962bdSlukem 				assert( proxydn == NULL );
532*549b59edSchristos 				proxydn = cvalue;
5332de962bdSlukem #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
5342de962bdSlukem 
535*549b59edSchristos 			} else if ( strcasecmp( control, "bauthzid" ) == 0 ) {
536*549b59edSchristos 				if( bauthzid ) {
537*549b59edSchristos 					fprintf( stderr, "bauthzid control previously specified\n");
538*549b59edSchristos 					exit( EXIT_FAILURE );
539*549b59edSchristos 				}
540*549b59edSchristos 				if( cvalue != NULL ) {
541*549b59edSchristos 					fprintf( stderr, "bauthzid: no control value expected\n" );
542*549b59edSchristos 					usage();
543*549b59edSchristos 				}
544*549b59edSchristos 				bauthzid = 1 + crit;
545*549b59edSchristos 
5462de962bdSlukem 			} else if ( ( strcasecmp( control, "relax" ) == 0 ) ||
5472de962bdSlukem 				( strcasecmp( control, "manageDIT" ) == 0 ) )
5482de962bdSlukem 			{
5492de962bdSlukem 				if( manageDIT ) {
5502de962bdSlukem 					fprintf( stderr,
5512de962bdSlukem 						"relax control previously specified\n");
5522de962bdSlukem 					exit( EXIT_FAILURE );
5532de962bdSlukem 				}
5542de962bdSlukem 				if( cvalue != NULL ) {
5552de962bdSlukem 					fprintf( stderr,
5562de962bdSlukem 						"relax: no control value expected\n" );
5572de962bdSlukem 					usage();
5582de962bdSlukem 				}
5592de962bdSlukem 
5602de962bdSlukem 				manageDIT = 1 + crit;
5612de962bdSlukem 
5622de962bdSlukem 			} else if ( strcasecmp( control, "manageDSAit" ) == 0 ) {
5632de962bdSlukem 				if( manageDSAit ) {
5642de962bdSlukem 					fprintf( stderr,
5652de962bdSlukem 						"manageDSAit control previously specified\n");
5662de962bdSlukem 					exit( EXIT_FAILURE );
5672de962bdSlukem 				}
5682de962bdSlukem 				if( cvalue != NULL ) {
5692de962bdSlukem 					fprintf( stderr,
5702de962bdSlukem 						"manageDSAit: no control value expected\n" );
5712de962bdSlukem 					usage();
5722de962bdSlukem 				}
5732de962bdSlukem 
5742de962bdSlukem 				manageDSAit = 1 + crit;
5752de962bdSlukem 
5762de962bdSlukem 			} else if ( strcasecmp( control, "noop" ) == 0 ) {
5772de962bdSlukem 				if( noop ) {
5782de962bdSlukem 					fprintf( stderr, "noop control previously specified\n");
5792de962bdSlukem 					exit( EXIT_FAILURE );
5802de962bdSlukem 				}
5812de962bdSlukem 				if( cvalue != NULL ) {
5822de962bdSlukem 					fprintf( stderr, "noop: no control value expected\n" );
5832de962bdSlukem 					usage();
5842de962bdSlukem 				}
5852de962bdSlukem 
5862de962bdSlukem 				noop = 1 + crit;
5872de962bdSlukem 
5882de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
5892de962bdSlukem 			} else if ( strcasecmp( control, "ppolicy" ) == 0 ) {
5902de962bdSlukem 				if( ppolicy ) {
5912de962bdSlukem 					fprintf( stderr, "ppolicy control previously specified\n");
5922de962bdSlukem 					exit( EXIT_FAILURE );
5932de962bdSlukem 				}
5942de962bdSlukem 				if( cvalue != NULL ) {
5952de962bdSlukem 					fprintf( stderr, "ppolicy: no control value expected\n" );
5962de962bdSlukem 					usage();
5972de962bdSlukem 				}
5982de962bdSlukem 				if( crit ) {
5992de962bdSlukem 					fprintf( stderr, "ppolicy: critical flag not allowed\n" );
6002de962bdSlukem 					usage();
6012de962bdSlukem 				}
6022de962bdSlukem 
6032de962bdSlukem 				ppolicy = 1;
6042de962bdSlukem #endif
6052de962bdSlukem 
6062de962bdSlukem 			} else if ( strcasecmp( control, "preread" ) == 0 ) {
6072de962bdSlukem 				if( preread ) {
6082de962bdSlukem 					fprintf( stderr, "preread control previously specified\n");
6092de962bdSlukem 					exit( EXIT_FAILURE );
6102de962bdSlukem 				}
6112de962bdSlukem 
6122de962bdSlukem 				preread = 1 + crit;
613*549b59edSchristos 				preread_attrs = cvalue;
6142de962bdSlukem 
6152de962bdSlukem 			} else if ( strcasecmp( control, "postread" ) == 0 ) {
6162de962bdSlukem 				if( postread ) {
6172de962bdSlukem 					fprintf( stderr, "postread control previously specified\n");
6182de962bdSlukem 					exit( EXIT_FAILURE );
6192de962bdSlukem 				}
6202de962bdSlukem 
6212de962bdSlukem 				postread = 1 + crit;
622*549b59edSchristos 				postread_attrs = cvalue;
6232de962bdSlukem 
6242de962bdSlukem #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
6252de962bdSlukem 			} else if ( strcasecmp( control, "chaining" ) == 0 ) {
626*549b59edSchristos 				if ( chaining ) {
627*549b59edSchristos 					fprintf( stderr, "chaining control previously specified\n");
628*549b59edSchristos 					exit( EXIT_FAILURE );
629*549b59edSchristos 				}
630*549b59edSchristos 
6312de962bdSlukem 				chaining = 1 + crit;
6322de962bdSlukem 
6332de962bdSlukem 				if ( cvalue != NULL ) {
6342de962bdSlukem 					char	*continuation;
6352de962bdSlukem 
6362de962bdSlukem 					continuation = strchr( cvalue, '/' );
6372de962bdSlukem 					if ( continuation ) {
6382de962bdSlukem 						/* FIXME: this makes sense only in searches */
6392de962bdSlukem 						*continuation++ = '\0';
6402de962bdSlukem 						if ( strcasecmp( continuation, "chainingPreferred" ) == 0 ) {
6412de962bdSlukem 							chainingContinuation = LDAP_CHAINING_PREFERRED;
6422de962bdSlukem 						} else if ( strcasecmp( continuation, "chainingRequired" ) == 0 ) {
6432de962bdSlukem 							chainingContinuation = LDAP_CHAINING_REQUIRED;
6442de962bdSlukem 						} else if ( strcasecmp( continuation, "referralsPreferred" ) == 0 ) {
6452de962bdSlukem 							chainingContinuation = LDAP_REFERRALS_PREFERRED;
6462de962bdSlukem 						} else if ( strcasecmp( continuation, "referralsRequired" ) == 0 ) {
6472de962bdSlukem 							chainingContinuation = LDAP_REFERRALS_REQUIRED;
6482de962bdSlukem 						} else {
6492de962bdSlukem 							fprintf( stderr,
6502de962bdSlukem 								"chaining behavior control "
6512de962bdSlukem 								"continuation value \"%s\" invalid\n",
6522de962bdSlukem 								continuation );
6532de962bdSlukem 							exit( EXIT_FAILURE );
6542de962bdSlukem 						}
6552de962bdSlukem 					}
6562de962bdSlukem 
6572de962bdSlukem 					if ( strcasecmp( cvalue, "chainingPreferred" ) == 0 ) {
6582de962bdSlukem 						chainingResolve = LDAP_CHAINING_PREFERRED;
6592de962bdSlukem 					} else if ( strcasecmp( cvalue, "chainingRequired" ) == 0 ) {
6602de962bdSlukem 						chainingResolve = LDAP_CHAINING_REQUIRED;
6612de962bdSlukem 					} else if ( strcasecmp( cvalue, "referralsPreferred" ) == 0 ) {
6622de962bdSlukem 						chainingResolve = LDAP_REFERRALS_PREFERRED;
6632de962bdSlukem 					} else if ( strcasecmp( cvalue, "referralsRequired" ) == 0 ) {
6642de962bdSlukem 						chainingResolve = LDAP_REFERRALS_REQUIRED;
6652de962bdSlukem 					} else {
6662de962bdSlukem 						fprintf( stderr,
6672de962bdSlukem 							"chaining behavior control "
6682de962bdSlukem 							"resolve value \"%s\" invalid\n",
6692de962bdSlukem 							cvalue);
6702de962bdSlukem 						exit( EXIT_FAILURE );
6712de962bdSlukem 					}
6722de962bdSlukem 				}
6732de962bdSlukem #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
6742de962bdSlukem 
675cb54be06Stron #ifdef LDAP_CONTROL_X_SESSION_TRACKING
676cb54be06Stron 			} else if ( strcasecmp( control, "sessiontracking" ) == 0 ) {
677cb54be06Stron 				if ( sessionTracking ) {
678cb54be06Stron 					fprintf( stderr, "%s: session tracking can be only specified once\n", prog );
679cb54be06Stron 					exit( EXIT_FAILURE );
680cb54be06Stron 				}
681cb54be06Stron 				sessionTracking = 1;
682cb54be06Stron 				if ( crit ) {
683cb54be06Stron 					fprintf( stderr, "sessiontracking: critical flag not allowed\n" );
684cb54be06Stron 					usage();
685cb54be06Stron 				}
686*549b59edSchristos 				if ( cvalue ) {
687*549b59edSchristos 					sessionTrackingName = cvalue;
688*549b59edSchristos 				}
689cb54be06Stron #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
690cb54be06Stron 
6912de962bdSlukem 			/* this shouldn't go here, really; but it's a feature... */
6922de962bdSlukem 			} else if ( strcasecmp( control, "abandon" ) == 0 ) {
6932de962bdSlukem 				abcan = Intr_Abandon;
6942de962bdSlukem 				if ( crit ) {
6952de962bdSlukem 					gotintr = abcan;
6962de962bdSlukem 				}
6972de962bdSlukem 
6982de962bdSlukem 			} else if ( strcasecmp( control, "cancel" ) == 0 ) {
6992de962bdSlukem 				abcan = Intr_Cancel;
7002de962bdSlukem 				if ( crit ) {
7012de962bdSlukem 					gotintr = abcan;
7022de962bdSlukem 				}
7032de962bdSlukem 
7042de962bdSlukem 			} else if ( strcasecmp( control, "ignore" ) == 0 ) {
7052de962bdSlukem 				abcan = Intr_Ignore;
7062de962bdSlukem 				if ( crit ) {
7072de962bdSlukem 					gotintr = abcan;
7082de962bdSlukem 				}
7092de962bdSlukem 
710*549b59edSchristos 			} else if ( strcasecmp( control, "backlog" ) == 0 ) {
711*549b59edSchristos 				/* special search: accumulate lots of responses
712*549b59edSchristos 				 * but don't read any, force slapd writer to wait.
713*549b59edSchristos 				 * Then abandon the search and issue a new one.
714*549b59edSchristos 				 */
715*549b59edSchristos 				backlog = 1;
716*549b59edSchristos 
7172de962bdSlukem 			} else if ( tool_is_oid( control ) ) {
7182de962bdSlukem 				LDAPControl	*tmpctrls, ctrl;
7192de962bdSlukem 
720*549b59edSchristos 				if ( unknown_ctrls != NULL ) {
721*549b59edSchristos 					int i;
722*549b59edSchristos 					for ( i = 0; unknown_ctrls[ i ].ldctl_oid != NULL; i++ ) {
723*549b59edSchristos 						if ( strcmp( control, unknown_ctrls[ i ].ldctl_oid ) == 0 ) {
724*549b59edSchristos 							fprintf( stderr, "%s control previously specified\n", control );
725*549b59edSchristos 							exit( EXIT_FAILURE );
726*549b59edSchristos 						}
727*549b59edSchristos 					}
728*549b59edSchristos 				}
729*549b59edSchristos 
7304e6df137Slukem 				tmpctrls = (LDAPControl *)ber_memrealloc( unknown_ctrls,
7312de962bdSlukem 					(unknown_ctrls_num + 1)*sizeof( LDAPControl ) );
7322de962bdSlukem 				if ( tmpctrls == NULL ) {
7332de962bdSlukem 					fprintf( stderr, "%s: no memory?\n", prog );
7342de962bdSlukem 					exit( EXIT_FAILURE );
7352de962bdSlukem 				}
7362de962bdSlukem 				unknown_ctrls = tmpctrls;
7372de962bdSlukem 				ctrl.ldctl_oid = control;
7382de962bdSlukem 				ctrl.ldctl_value.bv_val = NULL;
7392de962bdSlukem 				ctrl.ldctl_value.bv_len = 0;
7402de962bdSlukem 				ctrl.ldctl_iscritical = crit;
7412de962bdSlukem 
7422de962bdSlukem 				if ( cvalue != NULL ) {
7432de962bdSlukem 					struct berval	bv;
7442de962bdSlukem 					size_t		len = strlen( cvalue );
7452de962bdSlukem 					int		retcode;
7462de962bdSlukem 
7472de962bdSlukem 					bv.bv_len = LUTIL_BASE64_DECODE_LEN( len );
7482de962bdSlukem 					bv.bv_val = ber_memalloc( bv.bv_len + 1 );
7492de962bdSlukem 
7502de962bdSlukem 					retcode = lutil_b64_pton( cvalue,
7512de962bdSlukem 						(unsigned char *)bv.bv_val,
7522de962bdSlukem 						bv.bv_len );
7532de962bdSlukem 
7544e6df137Slukem 					if ( retcode == -1 || (unsigned) retcode > bv.bv_len ) {
7552de962bdSlukem 						fprintf( stderr, "Unable to parse value of general control %s\n",
7562de962bdSlukem 							control );
7572de962bdSlukem 						usage();
7582de962bdSlukem 					}
7592de962bdSlukem 
7602de962bdSlukem 					bv.bv_len = retcode;
7612de962bdSlukem 					ctrl.ldctl_value = bv;
7622de962bdSlukem 				}
7632de962bdSlukem 
764*549b59edSchristos 				/* don't free it */
765*549b59edSchristos 				control = NULL;
7662de962bdSlukem 				unknown_ctrls[ unknown_ctrls_num ] = ctrl;
7672de962bdSlukem 				unknown_ctrls_num++;
7682de962bdSlukem 
7692de962bdSlukem 			} else {
7702de962bdSlukem 				fprintf( stderr, "Invalid general control name: %s\n",
7712de962bdSlukem 					control );
7722de962bdSlukem 				usage();
7732de962bdSlukem 			}
7742de962bdSlukem 			break;
7752de962bdSlukem 		case 'f':	/* read from file */
7762de962bdSlukem 			if( infile != NULL ) {
7772de962bdSlukem 				fprintf( stderr, "%s: -f previously specified\n", prog );
7782de962bdSlukem 				exit( EXIT_FAILURE );
7792de962bdSlukem 			}
780*549b59edSchristos 			infile = optarg;
7812de962bdSlukem 			break;
7822de962bdSlukem 		case 'H':	/* ldap URI */
7832de962bdSlukem 			if( ldapuri != NULL ) {
7842de962bdSlukem 				fprintf( stderr, "%s: -H previously specified\n", prog );
7852de962bdSlukem 				exit( EXIT_FAILURE );
7862de962bdSlukem 			}
7872de962bdSlukem 			ldapuri = ber_strdup( optarg );
7882de962bdSlukem 			break;
7892de962bdSlukem 		case 'I':
7902de962bdSlukem #ifdef HAVE_CYRUS_SASL
7912de962bdSlukem 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
7922de962bdSlukem 				fprintf( stderr, "%s: incompatible previous "
7932de962bdSlukem 					"authentication choice\n",
7942de962bdSlukem 					prog );
7952de962bdSlukem 				exit( EXIT_FAILURE );
7962de962bdSlukem 			}
7972de962bdSlukem 			authmethod = LDAP_AUTH_SASL;
7982de962bdSlukem 			sasl_flags = LDAP_SASL_INTERACTIVE;
7992de962bdSlukem 			break;
8002de962bdSlukem #else
8012de962bdSlukem 			fprintf( stderr, "%s: was not compiled with SASL support\n",
8022de962bdSlukem 				prog );
8032de962bdSlukem 			exit( EXIT_FAILURE );
8042de962bdSlukem #endif
8052de962bdSlukem 		case 'M':
8062de962bdSlukem 			/* enable Manage DSA IT */
8072de962bdSlukem 			manageDSAit++;
8082de962bdSlukem 			break;
8092de962bdSlukem 		case 'n':	/* print operations, don't actually do them */
8102de962bdSlukem 			dont++;
8112de962bdSlukem 			break;
8124e6df137Slukem 		case 'N':
8134e6df137Slukem 			nocanon++;
8144e6df137Slukem 			break;
8152de962bdSlukem 		case 'o':
816*549b59edSchristos 			control = optarg;
8172de962bdSlukem 			if ( (cvalue = strchr( control, '=' )) != NULL ) {
8182de962bdSlukem 				*cvalue++ = '\0';
8192de962bdSlukem 			}
820*549b59edSchristos 			for ( next=control; *next; next++ ) {
821*549b59edSchristos 				if ( *next == '-' ) {
822*549b59edSchristos 					*next = '_';
823*549b59edSchristos 				}
824*549b59edSchristos 			}
8252de962bdSlukem 
8262de962bdSlukem 			if ( strcasecmp( control, "nettimeout" ) == 0 ) {
8272de962bdSlukem 				if( nettimeout.tv_sec != -1 ) {
8282de962bdSlukem 					fprintf( stderr, "nettimeout option previously specified\n");
8292de962bdSlukem 					exit( EXIT_FAILURE );
8302de962bdSlukem 				}
8312de962bdSlukem 				if( cvalue == NULL || cvalue[0] == '\0' ) {
8322de962bdSlukem 					fprintf( stderr, "nettimeout: option value expected\n" );
8332de962bdSlukem 					usage();
8342de962bdSlukem 				}
8352de962bdSlukem 		 		if ( strcasecmp( cvalue, "none" ) == 0 ) {
8362de962bdSlukem 		 			nettimeout.tv_sec = 0;
8372de962bdSlukem 		 		} else if ( strcasecmp( cvalue, "max" ) == 0 ) {
8382de962bdSlukem 		 			nettimeout.tv_sec = LDAP_MAXINT;
8392de962bdSlukem 		 		} else {
8402de962bdSlukem 		 			ival = strtol( cvalue, &next, 10 );
8412de962bdSlukem 		 			if ( next == NULL || next[0] != '\0' ) {
8422de962bdSlukem 		 				fprintf( stderr,
8432de962bdSlukem 		 					_("Unable to parse network timeout \"%s\"\n"), cvalue );
8442de962bdSlukem 		 				exit( EXIT_FAILURE );
8452de962bdSlukem 		 			}
8462de962bdSlukem 		 			nettimeout.tv_sec = ival;
8472de962bdSlukem 		 		}
8482de962bdSlukem 		 		if( nettimeout.tv_sec < 0 || nettimeout.tv_sec > LDAP_MAXINT ) {
8492de962bdSlukem 		 			fprintf( stderr, _("%s: invalid network timeout (%ld) specified\n"),
8502de962bdSlukem 		 				prog, (long)nettimeout.tv_sec );
8512de962bdSlukem 	 				exit( EXIT_FAILURE );
8522de962bdSlukem  				}
853cb54be06Stron 
854*549b59edSchristos 			} else if ( strcasecmp( control, "ldif_wrap" ) == 0 ) {
855cb54be06Stron 				if ( cvalue == 0 ) {
856cb54be06Stron 					ldif_wrap = LDIF_LINE_WIDTH;
857cb54be06Stron 
858cb54be06Stron 				} else if ( strcasecmp( cvalue, "no" ) == 0 ) {
859cb54be06Stron 					ldif_wrap = LDIF_LINE_WIDTH_MAX;
860cb54be06Stron 
861cb54be06Stron 				} else {
862cb54be06Stron 					unsigned int u;
863cb54be06Stron 					if ( lutil_atou( &u, cvalue ) ) {
864cb54be06Stron 						fprintf( stderr,
865*549b59edSchristos 							_("Unable to parse ldif_wrap=\"%s\"\n"), cvalue );
866cb54be06Stron 		 				exit( EXIT_FAILURE );
867cb54be06Stron 					}
868cb54be06Stron 					ldif_wrap = (ber_len_t)u;
869cb54be06Stron 				}
870cb54be06Stron 
871*549b59edSchristos 			} else if ( ldap_pvt_conf_option( control, cvalue, 1 ) ) {
8722de962bdSlukem 				fprintf( stderr, "Invalid general option name: %s\n",
8732de962bdSlukem 					control );
8742de962bdSlukem 				usage();
8752de962bdSlukem 			}
8762de962bdSlukem 			break;
8772de962bdSlukem 		case 'O':
8782de962bdSlukem #ifdef HAVE_CYRUS_SASL
8792de962bdSlukem 			if( sasl_secprops != NULL ) {
8802de962bdSlukem 				fprintf( stderr, "%s: -O previously specified\n", prog );
8812de962bdSlukem 				exit( EXIT_FAILURE );
8822de962bdSlukem 			}
8832de962bdSlukem 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
8842de962bdSlukem 				fprintf( stderr, "%s: incompatible previous "
8852de962bdSlukem 					"authentication choice\n", prog );
8862de962bdSlukem 				exit( EXIT_FAILURE );
8872de962bdSlukem 			}
8882de962bdSlukem 			authmethod = LDAP_AUTH_SASL;
889*549b59edSchristos 			sasl_secprops = optarg;
8902de962bdSlukem #else
8912de962bdSlukem 			fprintf( stderr, "%s: not compiled with SASL support\n", prog );
8922de962bdSlukem 			exit( EXIT_FAILURE );
8932de962bdSlukem #endif
8942de962bdSlukem 			break;
8952de962bdSlukem 		case 'P':
8962de962bdSlukem 			ival = strtol( optarg, &next, 10 );
8972de962bdSlukem 			if ( next == NULL || next[0] != '\0' ) {
8982de962bdSlukem 				fprintf( stderr, "%s: unable to parse protocol version \"%s\"\n", prog, optarg );
8992de962bdSlukem 				exit( EXIT_FAILURE );
9002de962bdSlukem 			}
9012de962bdSlukem 			switch( ival ) {
9022de962bdSlukem 			case 2:
9032de962bdSlukem 				if( protocol == LDAP_VERSION3 ) {
9042de962bdSlukem 					fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
9052de962bdSlukem 						prog, protocol );
9062de962bdSlukem 					exit( EXIT_FAILURE );
9072de962bdSlukem 				}
9082de962bdSlukem 				protocol = LDAP_VERSION2;
9092de962bdSlukem 				break;
9102de962bdSlukem 			case 3:
9112de962bdSlukem 				if( protocol == LDAP_VERSION2 ) {
9122de962bdSlukem 					fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
9132de962bdSlukem 						prog, protocol );
9142de962bdSlukem 					exit( EXIT_FAILURE );
9152de962bdSlukem 				}
9162de962bdSlukem 				protocol = LDAP_VERSION3;
9172de962bdSlukem 				break;
9182de962bdSlukem 			default:
9192de962bdSlukem 				fprintf( stderr, "%s: protocol version should be 2 or 3\n",
9202de962bdSlukem 					prog );
9212de962bdSlukem 				usage();
9222de962bdSlukem 			}
9232de962bdSlukem 			break;
9242de962bdSlukem 		case 'Q':
9252de962bdSlukem #ifdef HAVE_CYRUS_SASL
9262de962bdSlukem 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
9272de962bdSlukem 				fprintf( stderr, "%s: incompatible previous "
9282de962bdSlukem 					"authentication choice\n",
9292de962bdSlukem 					prog );
9302de962bdSlukem 				exit( EXIT_FAILURE );
9312de962bdSlukem 			}
9322de962bdSlukem 			authmethod = LDAP_AUTH_SASL;
9332de962bdSlukem 			sasl_flags = LDAP_SASL_QUIET;
9342de962bdSlukem 			break;
9352de962bdSlukem #else
9362de962bdSlukem 			fprintf( stderr, "%s: not compiled with SASL support\n",
9372de962bdSlukem 				prog );
9382de962bdSlukem 			exit( EXIT_FAILURE );
9392de962bdSlukem #endif
9402de962bdSlukem 		case 'R':
9412de962bdSlukem #ifdef HAVE_CYRUS_SASL
9422de962bdSlukem 			if( sasl_realm != NULL ) {
9432de962bdSlukem 				fprintf( stderr, "%s: -R previously specified\n", prog );
9442de962bdSlukem 				exit( EXIT_FAILURE );
9452de962bdSlukem 			}
9462de962bdSlukem 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
9472de962bdSlukem 				fprintf( stderr, "%s: incompatible previous "
9482de962bdSlukem 					"authentication choice\n",
9492de962bdSlukem 					prog );
9502de962bdSlukem 				exit( EXIT_FAILURE );
9512de962bdSlukem 			}
9522de962bdSlukem 			authmethod = LDAP_AUTH_SASL;
953*549b59edSchristos 			sasl_realm = optarg;
9542de962bdSlukem #else
9552de962bdSlukem 			fprintf( stderr, "%s: not compiled with SASL support\n",
9562de962bdSlukem 				prog );
9572de962bdSlukem 			exit( EXIT_FAILURE );
9582de962bdSlukem #endif
9592de962bdSlukem 			break;
9602de962bdSlukem 		case 'U':
9612de962bdSlukem #ifdef HAVE_CYRUS_SASL
9622de962bdSlukem 			if( sasl_authc_id != NULL ) {
9632de962bdSlukem 				fprintf( stderr, "%s: -U previously specified\n", prog );
9642de962bdSlukem 				exit( EXIT_FAILURE );
9652de962bdSlukem 			}
9662de962bdSlukem 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
9672de962bdSlukem 				fprintf( stderr, "%s: incompatible previous "
9682de962bdSlukem 					"authentication choice\n",
9692de962bdSlukem 					prog );
9702de962bdSlukem 				exit( EXIT_FAILURE );
9712de962bdSlukem 			}
9722de962bdSlukem 			authmethod = LDAP_AUTH_SASL;
973*549b59edSchristos 			sasl_authc_id = optarg;
9742de962bdSlukem #else
9752de962bdSlukem 			fprintf( stderr, "%s: not compiled with SASL support\n",
9762de962bdSlukem 				prog );
9772de962bdSlukem 			exit( EXIT_FAILURE );
9782de962bdSlukem #endif
9792de962bdSlukem 			break;
9802de962bdSlukem 		case 'v':	/* verbose mode */
9812de962bdSlukem 			verbose++;
9822de962bdSlukem 			break;
9832de962bdSlukem 		case 'V':	/* version */
9842de962bdSlukem 			version++;
9852de962bdSlukem 			break;
9862de962bdSlukem 		case 'w':	/* password */
9872de962bdSlukem 			passwd.bv_val = ber_strdup( optarg );
9882de962bdSlukem 			{
9892de962bdSlukem 				char* p;
9902de962bdSlukem 
9912de962bdSlukem 				for( p = optarg; *p != '\0'; p++ ) {
9922de962bdSlukem 					*p = '\0';
9932de962bdSlukem 				}
9942de962bdSlukem 			}
9952de962bdSlukem 			passwd.bv_len = strlen( passwd.bv_val );
9962de962bdSlukem 			break;
9972de962bdSlukem 		case 'W':
9982de962bdSlukem 			want_bindpw++;
9992de962bdSlukem 			break;
10002de962bdSlukem 		case 'y':
10012de962bdSlukem 			pw_file = optarg;
10022de962bdSlukem 			break;
10032de962bdSlukem 		case 'Y':
10042de962bdSlukem #ifdef HAVE_CYRUS_SASL
10052de962bdSlukem 			if( sasl_mech != NULL ) {
10062de962bdSlukem 				fprintf( stderr, "%s: -Y previously specified\n", prog );
10072de962bdSlukem 				exit( EXIT_FAILURE );
10082de962bdSlukem 			}
10092de962bdSlukem 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
10102de962bdSlukem 				fprintf( stderr,
10112de962bdSlukem 					"%s: incompatible with authentication choice\n", prog );
10122de962bdSlukem 				exit( EXIT_FAILURE );
10132de962bdSlukem 			}
10142de962bdSlukem 			authmethod = LDAP_AUTH_SASL;
1015*549b59edSchristos 			sasl_mech = optarg;
10162de962bdSlukem #else
10172de962bdSlukem 			fprintf( stderr, "%s: not compiled with SASL support\n", prog );
10182de962bdSlukem 			exit( EXIT_FAILURE );
10192de962bdSlukem #endif
10202de962bdSlukem 			break;
10212de962bdSlukem 		case 'x':
10222de962bdSlukem 			if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
10232de962bdSlukem 				fprintf( stderr, "%s: incompatible with previous "
10242de962bdSlukem 					"authentication choice\n", prog );
10252de962bdSlukem 				exit( EXIT_FAILURE );
10262de962bdSlukem 			}
10272de962bdSlukem 			authmethod = LDAP_AUTH_SIMPLE;
10282de962bdSlukem 			break;
10292de962bdSlukem 		case 'X':
10302de962bdSlukem #ifdef HAVE_CYRUS_SASL
10312de962bdSlukem 			if( sasl_authz_id != NULL ) {
10322de962bdSlukem 				fprintf( stderr, "%s: -X previously specified\n", prog );
10332de962bdSlukem 				exit( EXIT_FAILURE );
10342de962bdSlukem 			}
10352de962bdSlukem 			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
10362de962bdSlukem 				fprintf( stderr, "%s: -X incompatible with "
10372de962bdSlukem 					"authentication choice\n", prog );
10382de962bdSlukem 				exit( EXIT_FAILURE );
10392de962bdSlukem 			}
10402de962bdSlukem 			authmethod = LDAP_AUTH_SASL;
1041*549b59edSchristos 			sasl_authz_id = optarg;
10422de962bdSlukem #else
10432de962bdSlukem 			fprintf( stderr, "%s: not compiled with SASL support\n", prog );
10442de962bdSlukem 			exit( EXIT_FAILURE );
10452de962bdSlukem #endif
10462de962bdSlukem 			break;
10472de962bdSlukem 		case 'Z':
10482de962bdSlukem #ifdef HAVE_TLS
10492de962bdSlukem 			use_tls++;
10502de962bdSlukem #else
10512de962bdSlukem 			fprintf( stderr, "%s: not compiled with TLS support\n", prog );
10522de962bdSlukem 			exit( EXIT_FAILURE );
10532de962bdSlukem #endif
10542de962bdSlukem 			break;
10552de962bdSlukem 		default:
10562de962bdSlukem 			if( handle_private_option( i ) ) break;
10572de962bdSlukem 			fprintf( stderr, "%s: unrecognized option -%c\n",
10582de962bdSlukem 				prog, optopt );
10592de962bdSlukem 			usage();
10602de962bdSlukem 		}
10612de962bdSlukem 	}
10622de962bdSlukem 
10632de962bdSlukem 	{
10642de962bdSlukem 		/* prevent bad linking */
10652de962bdSlukem 		LDAPAPIInfo api;
10662de962bdSlukem 		api.ldapai_info_version = LDAP_API_INFO_VERSION;
10672de962bdSlukem 
10682de962bdSlukem 		if ( ldap_get_option(NULL, LDAP_OPT_API_INFO, &api)
10692de962bdSlukem 			!= LDAP_OPT_SUCCESS )
10702de962bdSlukem 		{
10712de962bdSlukem 			fprintf( stderr, "%s: ldap_get_option(API_INFO) failed\n", prog );
10722de962bdSlukem 			exit( EXIT_FAILURE );
10732de962bdSlukem 		}
10742de962bdSlukem 
10752de962bdSlukem 		if (api.ldapai_info_version != LDAP_API_INFO_VERSION) {
10762de962bdSlukem 			fprintf( stderr, "LDAP APIInfo version mismatch: "
10772de962bdSlukem 				"library %d, header %d\n",
10782de962bdSlukem 				api.ldapai_info_version, LDAP_API_INFO_VERSION );
10792de962bdSlukem 			exit( EXIT_FAILURE );
10802de962bdSlukem 		}
10812de962bdSlukem 
10822de962bdSlukem 		if( api.ldapai_api_version != LDAP_API_VERSION ) {
10832de962bdSlukem 			fprintf( stderr, "LDAP API version mismatch: "
10842de962bdSlukem 				"library %d, header %d\n",
10852de962bdSlukem 				api.ldapai_api_version, LDAP_API_VERSION );
10862de962bdSlukem 			exit( EXIT_FAILURE );
10872de962bdSlukem 		}
10882de962bdSlukem 
10892de962bdSlukem 		if( strcmp(api.ldapai_vendor_name, LDAP_VENDOR_NAME ) != 0 ) {
10902de962bdSlukem 			fprintf( stderr, "LDAP vendor name mismatch: "
10912de962bdSlukem 				"library %s, header %s\n",
10922de962bdSlukem 				api.ldapai_vendor_name, LDAP_VENDOR_NAME );
10932de962bdSlukem 			exit( EXIT_FAILURE );
10942de962bdSlukem 		}
10952de962bdSlukem 
10962de962bdSlukem 		if( api.ldapai_vendor_version != LDAP_VENDOR_VERSION ) {
10972de962bdSlukem 			fprintf( stderr, "LDAP vendor version mismatch: "
10982de962bdSlukem 				"library %d, header %d\n",
10992de962bdSlukem 				api.ldapai_vendor_version, LDAP_VENDOR_VERSION );
11002de962bdSlukem 			exit( EXIT_FAILURE );
11012de962bdSlukem 		}
11022de962bdSlukem 
11032de962bdSlukem 		if (version) {
11042de962bdSlukem 			fprintf( stderr, "%s: %s\t(LDAP library: %s %d)\n",
11052de962bdSlukem 				prog, __Version,
11062de962bdSlukem 				LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION );
11072de962bdSlukem 			if (version > 1) exit( EXIT_SUCCESS );
11082de962bdSlukem 		}
11092de962bdSlukem 
11102de962bdSlukem 		ldap_memfree( api.ldapai_vendor_name );
11112de962bdSlukem 		ber_memvfree( (void **)api.ldapai_extensions );
11122de962bdSlukem 	}
11132de962bdSlukem 
11142de962bdSlukem 	if (protocol == -1)
11152de962bdSlukem 		protocol = LDAP_VERSION3;
11162de962bdSlukem 
11172de962bdSlukem 	if (authmethod == -1 && protocol > LDAP_VERSION2) {
11182de962bdSlukem #ifdef HAVE_CYRUS_SASL
11194e6df137Slukem 		if ( binddn != NULL ) {
11204e6df137Slukem 			authmethod = LDAP_AUTH_SIMPLE;
11214e6df137Slukem 		} else {
11222de962bdSlukem 			authmethod = LDAP_AUTH_SASL;
11234e6df137Slukem 		}
11242de962bdSlukem #else
11252de962bdSlukem 		authmethod = LDAP_AUTH_SIMPLE;
11262de962bdSlukem #endif
11272de962bdSlukem 	}
11282de962bdSlukem 
11292de962bdSlukem 	if( protocol == LDAP_VERSION2 ) {
11302de962bdSlukem 		if( assertctl || authzid || manageDIT || manageDSAit ||
11312de962bdSlukem #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
11322de962bdSlukem 			proxydn ||
11332de962bdSlukem #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
11342de962bdSlukem #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
11352de962bdSlukem 			chaining ||
11362de962bdSlukem #endif
11372de962bdSlukem #ifdef LDAP_CONTROL_X_SESSION_TRACKING
11382de962bdSlukem 			sessionTracking ||
11392de962bdSlukem #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
11402de962bdSlukem 			noop || ppolicy || preread || postread )
11412de962bdSlukem 		{
11422de962bdSlukem 			fprintf( stderr, "%s: -e/-M incompatible with LDAPv2\n", prog );
11432de962bdSlukem 			exit( EXIT_FAILURE );
11442de962bdSlukem 		}
11452de962bdSlukem #ifdef HAVE_TLS
11462de962bdSlukem 		if( use_tls ) {
11472de962bdSlukem 			fprintf( stderr, "%s: -Z incompatible with LDAPv2\n", prog );
11482de962bdSlukem 			exit( EXIT_FAILURE );
11492de962bdSlukem 		}
11502de962bdSlukem #endif
11512de962bdSlukem #ifdef HAVE_CYRUS_SASL
11522de962bdSlukem 		if( authmethod == LDAP_AUTH_SASL ) {
11532de962bdSlukem 			fprintf( stderr, "%s: -[IOQRUXY] incompatible with LDAPv2\n",
11542de962bdSlukem 				prog );
11552de962bdSlukem 			exit( EXIT_FAILURE );
11562de962bdSlukem 		}
11572de962bdSlukem #endif
11582de962bdSlukem 	}
1159cb54be06Stron 
1160cb54be06Stron 	if ( ( pw_file || want_bindpw ) && !BER_BVISNULL( &passwd ) ) {
1161cb54be06Stron 		fprintf( stderr, "%s: -%c incompatible with -w\n",
1162cb54be06Stron 			prog, ( pw_file ? 'y' : 'W' ) );
1163cb54be06Stron 		exit( EXIT_FAILURE );
1164cb54be06Stron 	}
11652de962bdSlukem }
11662de962bdSlukem 
11672de962bdSlukem 
11682de962bdSlukem LDAP *
tool_conn_setup(int dont,void (* private_setup)(LDAP *))11692de962bdSlukem tool_conn_setup( int dont, void (*private_setup)( LDAP * ) )
11702de962bdSlukem {
11712de962bdSlukem 	LDAP *ld = NULL;
11722de962bdSlukem 
11732de962bdSlukem 	if ( debug ) {
11742de962bdSlukem 		if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug )
11752de962bdSlukem 			!= LBER_OPT_SUCCESS )
11762de962bdSlukem 		{
11772de962bdSlukem 			fprintf( stderr,
11782de962bdSlukem 				"Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
11792de962bdSlukem 		}
11802de962bdSlukem 		if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug )
11812de962bdSlukem 			!= LDAP_OPT_SUCCESS )
11822de962bdSlukem 		{
11832de962bdSlukem 			fprintf( stderr,
11842de962bdSlukem 				"Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
11852de962bdSlukem 		}
11862de962bdSlukem 	}
11872de962bdSlukem 
11882de962bdSlukem #ifdef SIGPIPE
11892de962bdSlukem 	(void) SIGNAL( SIGPIPE, SIG_IGN );
11902de962bdSlukem #endif
11912de962bdSlukem 
11922de962bdSlukem 	if ( abcan ) {
11932de962bdSlukem 		SIGNAL( SIGINT, do_sig );
11942de962bdSlukem 	}
11952de962bdSlukem 
11962de962bdSlukem 	if ( !dont ) {
11972de962bdSlukem 		int rc;
11982de962bdSlukem 
1199*549b59edSchristos 		if ( ldapuri != NULL ) {
12002de962bdSlukem 			LDAPURLDesc	*ludlist, **ludp;
12012de962bdSlukem 			char		**urls = NULL;
12022de962bdSlukem 			int		nurls = 0;
12032de962bdSlukem 
12042de962bdSlukem 			rc = ldap_url_parselist( &ludlist, ldapuri );
12052de962bdSlukem 			if ( rc != LDAP_URL_SUCCESS ) {
12062de962bdSlukem 				fprintf( stderr,
12072de962bdSlukem 					"Could not parse LDAP URI(s)=%s (%d)\n",
12082de962bdSlukem 					ldapuri, rc );
12092de962bdSlukem 				exit( EXIT_FAILURE );
12102de962bdSlukem 			}
12112de962bdSlukem 
12122de962bdSlukem 			for ( ludp = &ludlist; *ludp != NULL; ) {
12132de962bdSlukem 				LDAPURLDesc	*lud = *ludp;
12142de962bdSlukem 				char		**tmp;
12152de962bdSlukem 
12162de962bdSlukem 				if ( lud->lud_dn != NULL && lud->lud_dn[ 0 ] != '\0' &&
12172de962bdSlukem 					( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) )
12182de962bdSlukem 				{
12192de962bdSlukem 					/* if no host but a DN is provided,
12202de962bdSlukem 					 * use DNS SRV to gather the host list
12212de962bdSlukem 					 * and turn it into a list of URIs
12222de962bdSlukem 					 * using the scheme provided */
12232de962bdSlukem 					char	*domain = NULL,
12242de962bdSlukem 						*hostlist = NULL,
12252de962bdSlukem 						**hosts = NULL;
12262de962bdSlukem 					int	i,
12272de962bdSlukem 						len_proto = strlen( lud->lud_scheme );
12282de962bdSlukem 
12292de962bdSlukem 					if ( ldap_dn2domain( lud->lud_dn, &domain )
12302de962bdSlukem 						|| domain == NULL )
12312de962bdSlukem 					{
12322de962bdSlukem 						fprintf( stderr,
12332de962bdSlukem 							"DNS SRV: Could not turn "
12342de962bdSlukem 							"DN=\"%s\" into a domain\n",
12352de962bdSlukem 							lud->lud_dn );
12362de962bdSlukem 						goto dnssrv_free;
12372de962bdSlukem 					}
12382de962bdSlukem 
12392de962bdSlukem 					rc = ldap_domain2hostlist( domain, &hostlist );
12402de962bdSlukem 					if ( rc ) {
12412de962bdSlukem 						fprintf( stderr,
12422de962bdSlukem 							"DNS SRV: Could not turn "
12432de962bdSlukem 							"domain=%s into a hostlist\n",
12442de962bdSlukem 							domain );
12452de962bdSlukem 						goto dnssrv_free;
12462de962bdSlukem 					}
12472de962bdSlukem 
12482de962bdSlukem 					hosts = ldap_str2charray( hostlist, " " );
12492de962bdSlukem 					if ( hosts == NULL ) {
12502de962bdSlukem 						fprintf( stderr,
12512de962bdSlukem 							"DNS SRV: Could not parse "
12522de962bdSlukem 							"hostlist=\"%s\"\n",
12532de962bdSlukem 							hostlist );
12542de962bdSlukem 						goto dnssrv_free;
12552de962bdSlukem 					}
12562de962bdSlukem 
12572de962bdSlukem 					for ( i = 0; hosts[ i ] != NULL; i++ )
12582de962bdSlukem 						/* count'em */ ;
12592de962bdSlukem 
12604e6df137Slukem 					tmp = (char **)ber_memrealloc( urls, sizeof( char * ) * ( nurls + i + 1 ) );
12612de962bdSlukem 					if ( tmp == NULL ) {
12622de962bdSlukem 						fprintf( stderr,
12632de962bdSlukem 							"DNS SRV: out of memory?\n" );
12642de962bdSlukem 						goto dnssrv_free;
12652de962bdSlukem 					}
12662de962bdSlukem 					urls = tmp;
12672de962bdSlukem 					urls[ nurls ] = NULL;
12682de962bdSlukem 
12692de962bdSlukem 					for ( i = 0; hosts[ i ] != NULL; i++ ) {
12702de962bdSlukem 						size_t	len = len_proto
12712de962bdSlukem 							+ STRLENOF( "://" )
12722de962bdSlukem 							+ strlen( hosts[ i ] )
12732de962bdSlukem 							+ 1;
12742de962bdSlukem 
12752de962bdSlukem 						urls[ nurls + i + 1 ] = NULL;
12762de962bdSlukem 						urls[ nurls + i ] = (char *)malloc( sizeof( char ) * len );
12772de962bdSlukem 						if ( urls[ nurls + i ] == NULL ) {
12782de962bdSlukem 							fprintf( stderr,
12792de962bdSlukem 								"DNS SRV: out of memory?\n" );
12802de962bdSlukem 							goto dnssrv_free;
12812de962bdSlukem 						}
12822de962bdSlukem 
12832de962bdSlukem 						snprintf( urls[ nurls + i ], len, "%s://%s",
12842de962bdSlukem 							lud->lud_scheme, hosts[ i ] );
12852de962bdSlukem 					}
12862de962bdSlukem 					nurls += i;
12872de962bdSlukem 
12882de962bdSlukem dnssrv_free:;
12892de962bdSlukem 					ber_memvfree( (void **)hosts );
12902de962bdSlukem 					ber_memfree( hostlist );
12912de962bdSlukem 					ber_memfree( domain );
12922de962bdSlukem 
12932de962bdSlukem 				} else {
12944e6df137Slukem 					tmp = (char **)ber_memrealloc( urls, sizeof( char * ) * ( nurls + 2 ) );
12952de962bdSlukem 					if ( tmp == NULL ) {
12962de962bdSlukem 						fprintf( stderr,
12972de962bdSlukem 							"DNS SRV: out of memory?\n" );
12982de962bdSlukem 						break;
12992de962bdSlukem 					}
13002de962bdSlukem 					urls = tmp;
13012de962bdSlukem 					urls[ nurls + 1 ] = NULL;
13022de962bdSlukem 
13032de962bdSlukem 					urls[ nurls ] = ldap_url_desc2str( lud );
13042de962bdSlukem 					if ( urls[ nurls ] == NULL ) {
13052de962bdSlukem 						fprintf( stderr,
13062de962bdSlukem 							"DNS SRV: out of memory?\n" );
13072de962bdSlukem 						break;
13082de962bdSlukem 					}
13092de962bdSlukem 					nurls++;
13102de962bdSlukem 				}
13112de962bdSlukem 
13122de962bdSlukem 				*ludp = lud->lud_next;
13132de962bdSlukem 
13142de962bdSlukem 				lud->lud_next = NULL;
13152de962bdSlukem 				ldap_free_urldesc( lud );
13162de962bdSlukem 			}
13172de962bdSlukem 
13182de962bdSlukem 			if ( ludlist != NULL ) {
13192de962bdSlukem 				ldap_free_urllist( ludlist );
13202de962bdSlukem 				exit( EXIT_FAILURE );
13212de962bdSlukem 
13222de962bdSlukem 			} else if ( urls == NULL ) {
13232de962bdSlukem 				exit( EXIT_FAILURE );
13242de962bdSlukem 			}
13252de962bdSlukem 
13262de962bdSlukem 			ldap_memfree( ldapuri );
13272de962bdSlukem 			ldapuri = ldap_charray2str( urls, " " );
13282de962bdSlukem 			ber_memvfree( (void **)urls );
13292de962bdSlukem 		}
13302de962bdSlukem 
13312de962bdSlukem 		if ( verbose ) {
13322de962bdSlukem 			fprintf( stderr, "ldap_initialize( %s )\n",
13332de962bdSlukem 				ldapuri != NULL ? ldapuri : "<DEFAULT>" );
13342de962bdSlukem 		}
13352de962bdSlukem 		rc = ldap_initialize( &ld, ldapuri );
13362de962bdSlukem 		if( rc != LDAP_SUCCESS ) {
13372de962bdSlukem 			fprintf( stderr,
13382de962bdSlukem 				"Could not create LDAP session handle for URI=%s (%d): %s\n",
13392de962bdSlukem 				ldapuri, rc, ldap_err2string(rc) );
13402de962bdSlukem 			exit( EXIT_FAILURE );
13412de962bdSlukem 		}
13422de962bdSlukem 
13432de962bdSlukem 		if( private_setup ) private_setup( ld );
13442de962bdSlukem 
1345cb54be06Stron 		/* referrals: obsolete */
13462de962bdSlukem 		if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
13472de962bdSlukem 			referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
13482de962bdSlukem 		{
13492de962bdSlukem 			fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
13502de962bdSlukem 				referrals ? "on" : "off" );
1351cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
13522de962bdSlukem 		}
13532de962bdSlukem 
13544e6df137Slukem #ifdef HAVE_CYRUS_SASL
13554e6df137Slukem 		/* canon */
1356cb54be06Stron 		if( nocanon ) {
13574e6df137Slukem 			if( ldap_set_option( ld, LDAP_OPT_X_SASL_NOCANON,
1358cb54be06Stron 				LDAP_OPT_ON ) != LDAP_OPT_SUCCESS )
13594e6df137Slukem 			{
1360cb54be06Stron 				fprintf( stderr, "Could not set LDAP_OPT_X_SASL_NOCANON on\n" );
1361cb54be06Stron 				tool_exit( ld, EXIT_FAILURE );
1362cb54be06Stron 			}
13634e6df137Slukem 		}
13644e6df137Slukem #endif
13652de962bdSlukem 		if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &protocol )
13662de962bdSlukem 			!= LDAP_OPT_SUCCESS )
13672de962bdSlukem 		{
13682de962bdSlukem 			fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
13692de962bdSlukem 				protocol );
1370cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
13712de962bdSlukem 		}
13722de962bdSlukem 
1373657f4503Smrg #ifdef HAVE_TLS
13742de962bdSlukem 		if ( use_tls ) {
13752de962bdSlukem 			rc = ldap_start_tls_s( ld, NULL, NULL );
13762de962bdSlukem 			if ( rc != LDAP_SUCCESS ) {
13774e6df137Slukem 				char *msg=NULL;
13784e6df137Slukem 				ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&msg);
13794e6df137Slukem 				tool_perror( "ldap_start_tls", rc, NULL, NULL, msg, NULL );
13804e6df137Slukem 				ldap_memfree(msg);
1381*549b59edSchristos 				if ( use_tls > 1 || rc < 0 ) {
1382cb54be06Stron 					tool_exit( ld, EXIT_FAILURE );
13832de962bdSlukem 				}
13842de962bdSlukem 			}
13852de962bdSlukem 		}
1386657f4503Smrg #endif
13872de962bdSlukem 
13882de962bdSlukem 		if ( nettimeout.tv_sec > 0 ) {
13892de962bdSlukem 	 		if ( ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (void *) &nettimeout )
13902de962bdSlukem 				!= LDAP_OPT_SUCCESS )
13912de962bdSlukem 			{
13922de962bdSlukem 		 		fprintf( stderr, "Could not set LDAP_OPT_NETWORK_TIMEOUT %ld\n",
13932de962bdSlukem 					(long)nettimeout.tv_sec );
1394cb54be06Stron 	 			tool_exit( ld, EXIT_FAILURE );
13952de962bdSlukem 			}
13962de962bdSlukem 		}
13972de962bdSlukem 	}
13982de962bdSlukem 
13992de962bdSlukem 	return ld;
14002de962bdSlukem }
14012de962bdSlukem 
14022de962bdSlukem 
14032de962bdSlukem void
tool_bind(LDAP * ld)14042de962bdSlukem tool_bind( LDAP *ld )
14052de962bdSlukem {
14062de962bdSlukem 	LDAPControl	**sctrlsp = NULL;
1407*549b59edSchristos 	LDAPControl	*sctrls[4];
14082de962bdSlukem 	LDAPControl	sctrl[3];
14092de962bdSlukem 	int		nsctrls = 0;
14102de962bdSlukem 
1411*549b59edSchristos 	int rc, msgid;
1412*549b59edSchristos 	LDAPMessage *result = NULL;
1413*549b59edSchristos 
1414*549b59edSchristos 	int err;
1415*549b59edSchristos 	char *matched = NULL;
1416*549b59edSchristos 	char *info = NULL;
1417*549b59edSchristos 	char **refs = NULL;
1418*549b59edSchristos 	LDAPControl **ctrls = NULL;
1419*549b59edSchristos 	char msgbuf[256];
1420*549b59edSchristos 
1421*549b59edSchristos 	msgbuf[0] = 0;
1422*549b59edSchristos 
14232de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
14242de962bdSlukem 	if ( ppolicy ) {
14252de962bdSlukem 		LDAPControl c;
14262de962bdSlukem 		c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
14272de962bdSlukem 		c.ldctl_value.bv_val = NULL;
14282de962bdSlukem 		c.ldctl_value.bv_len = 0;
14292de962bdSlukem 		c.ldctl_iscritical = 0;
14302de962bdSlukem 		sctrl[nsctrls] = c;
14312de962bdSlukem 		sctrls[nsctrls] = &sctrl[nsctrls];
14322de962bdSlukem 		sctrls[++nsctrls] = NULL;
14332de962bdSlukem 	}
14342de962bdSlukem #endif
14352de962bdSlukem 
1436*549b59edSchristos 	if ( bauthzid ) {
1437*549b59edSchristos 		LDAPControl c;
1438*549b59edSchristos 
1439*549b59edSchristos 		c.ldctl_oid = LDAP_CONTROL_AUTHZID_REQUEST;
1440*549b59edSchristos 		c.ldctl_iscritical = bauthzid > 1;
1441*549b59edSchristos 		BER_BVZERO( &c.ldctl_value );
1442*549b59edSchristos 
1443*549b59edSchristos 		sctrl[nsctrls] = c;
1444*549b59edSchristos 		sctrls[nsctrls] = &sctrl[nsctrls];
1445*549b59edSchristos 		sctrls[++nsctrls] = NULL;
1446*549b59edSchristos 	}
1447*549b59edSchristos 
14482de962bdSlukem #ifdef LDAP_CONTROL_X_SESSION_TRACKING
14492de962bdSlukem 	if ( sessionTracking ) {
14502de962bdSlukem 		LDAPControl c;
14512de962bdSlukem 
1452cb54be06Stron 		if ( BER_BVISNULL( &stValue) && st_value( ld, &stValue ) ) {
1453cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
14542de962bdSlukem 		}
14552de962bdSlukem 
14562de962bdSlukem 		c.ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
14572de962bdSlukem 		c.ldctl_iscritical = 0;
1458*549b59edSchristos 		c.ldctl_value = stValue;
14592de962bdSlukem 
14602de962bdSlukem 		sctrl[nsctrls] = c;
14612de962bdSlukem 		sctrls[nsctrls] = &sctrl[nsctrls];
14622de962bdSlukem 		sctrls[++nsctrls] = NULL;
14632de962bdSlukem 	}
14642de962bdSlukem #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
14652de962bdSlukem 
14662de962bdSlukem 	if ( nsctrls ) {
14672de962bdSlukem 		sctrlsp = sctrls;
14682de962bdSlukem 	}
14692de962bdSlukem 
14704e6df137Slukem 	assert( nsctrls < (int) (sizeof(sctrls)/sizeof(sctrls[0])) );
14712de962bdSlukem 
1472a8c4d9a8Sadam 	if ( pw_file || want_bindpw ) {
1473a8c4d9a8Sadam 		assert( passwd.bv_val == NULL && passwd.bv_len == 0 );
1474a8c4d9a8Sadam 
1475a8c4d9a8Sadam 		if ( pw_file ) {
1476a8c4d9a8Sadam 			if ( lutil_get_filed_password( pw_file, &passwd ) ) {
1477cb54be06Stron 				tool_exit( ld, EXIT_FAILURE );
1478a8c4d9a8Sadam 			}
1479a8c4d9a8Sadam 
1480a8c4d9a8Sadam 		} else {
1481a8c4d9a8Sadam 			char *pw = getpassphrase( _("Enter LDAP Password: ") );
1482a8c4d9a8Sadam 			if ( pw ) {
1483a8c4d9a8Sadam 				passwd.bv_val = ber_strdup( pw );
1484a8c4d9a8Sadam 				passwd.bv_len = strlen( passwd.bv_val );
1485a8c4d9a8Sadam 			}
1486a8c4d9a8Sadam 		}
1487a8c4d9a8Sadam 	}
1488a8c4d9a8Sadam 
14892de962bdSlukem 	if ( authmethod == LDAP_AUTH_SASL ) {
14902de962bdSlukem #ifdef HAVE_CYRUS_SASL
14912de962bdSlukem 		void *defaults;
1492*549b59edSchristos 		const char *rmech = NULL;
14932de962bdSlukem 
14942de962bdSlukem 		if( sasl_secprops != NULL ) {
14952de962bdSlukem 			rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
14962de962bdSlukem 				(void *) sasl_secprops );
14972de962bdSlukem 
14982de962bdSlukem 			if( rc != LDAP_OPT_SUCCESS ) {
14992de962bdSlukem 				fprintf( stderr,
15002de962bdSlukem 					"Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
15012de962bdSlukem 					sasl_secprops );
1502cb54be06Stron 				tool_exit( ld, LDAP_LOCAL_ERROR );
15032de962bdSlukem 			}
15042de962bdSlukem 		}
15052de962bdSlukem 
15062de962bdSlukem 		defaults = lutil_sasl_defaults( ld,
15072de962bdSlukem 			sasl_mech,
15082de962bdSlukem 			sasl_realm,
15092de962bdSlukem 			sasl_authc_id,
15102de962bdSlukem 			passwd.bv_val,
15112de962bdSlukem 			sasl_authz_id );
15122de962bdSlukem 
1513*549b59edSchristos 		do {
1514*549b59edSchristos 			rc = ldap_sasl_interactive_bind( ld, binddn, sasl_mech,
1515*549b59edSchristos 				sctrlsp, NULL, sasl_flags, lutil_sasl_interact, defaults,
1516*549b59edSchristos 				result, &rmech, &msgid );
1517*549b59edSchristos 
1518*549b59edSchristos 			if ( rc != LDAP_SASL_BIND_IN_PROGRESS )
1519*549b59edSchristos 				break;
1520*549b59edSchristos 
1521*549b59edSchristos 			ldap_msgfree( result );
1522*549b59edSchristos 
1523*549b59edSchristos 			if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
1524*549b59edSchristos 				ldap_get_option( ld, LDAP_OPT_RESULT_CODE, (void*)&err );
1525*549b59edSchristos 				ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&info );
1526*549b59edSchristos 				tool_perror( "ldap_sasl_interactive_bind",
1527*549b59edSchristos 					err, NULL, NULL, info, NULL );
1528*549b59edSchristos 				ldap_memfree( info );
1529*549b59edSchristos 				tool_exit( ld, err );
1530*549b59edSchristos 			}
1531*549b59edSchristos 		} while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
15322de962bdSlukem 
15332de962bdSlukem 		lutil_sasl_freedefs( defaults );
1534*549b59edSchristos 
15352de962bdSlukem 		if ( rc != LDAP_SUCCESS ) {
1536*549b59edSchristos 			ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&info );
1537*549b59edSchristos 			tool_perror( "ldap_sasl_interactive_bind",
1538*549b59edSchristos 				rc, NULL, NULL, info, NULL );
1539*549b59edSchristos 			ldap_memfree( info );
1540cb54be06Stron 			tool_exit( ld, rc );
15412de962bdSlukem 		}
15422de962bdSlukem #else
15432de962bdSlukem 		fprintf( stderr, "%s: not compiled with SASL support\n", prog );
1544cb54be06Stron 		tool_exit( ld, LDAP_NOT_SUPPORTED );
15452de962bdSlukem #endif
15462de962bdSlukem 	} else {
15472de962bdSlukem 		/* simple bind */
15482de962bdSlukem 		rc = ldap_sasl_bind( ld, binddn, LDAP_SASL_SIMPLE, &passwd,
15492de962bdSlukem 			sctrlsp, NULL, &msgid );
15502de962bdSlukem 		if ( msgid == -1 ) {
15512de962bdSlukem 			tool_perror( "ldap_sasl_bind(SIMPLE)", rc,
15522de962bdSlukem 				NULL, NULL, NULL, NULL );
1553cb54be06Stron 			tool_exit( ld, rc );
15542de962bdSlukem 		}
15552de962bdSlukem 
15564e6df137Slukem 		rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result );
15574e6df137Slukem 		if ( rc == -1 ) {
15582de962bdSlukem 			tool_perror( "ldap_result", -1, NULL, NULL, NULL, NULL );
1559cb54be06Stron 			tool_exit( ld, LDAP_LOCAL_ERROR );
15602de962bdSlukem 		}
15612de962bdSlukem 
15624e6df137Slukem 		if ( rc == 0 ) {
15634e6df137Slukem 			tool_perror( "ldap_result", LDAP_TIMEOUT, NULL, NULL, NULL, NULL );
1564cb54be06Stron 			tool_exit( ld, LDAP_LOCAL_ERROR );
15654e6df137Slukem 		}
1566*549b59edSchristos 	}
15674e6df137Slukem 
1568cb54be06Stron 	if ( result ) {
15692de962bdSlukem 		rc = ldap_parse_result( ld, result, &err, &matched, &info, &refs,
15702de962bdSlukem 		                        &ctrls, 1 );
15712de962bdSlukem 		if ( rc != LDAP_SUCCESS ) {
15722de962bdSlukem 			tool_perror( "ldap_bind parse result", rc, NULL, matched, info, refs );
1573cb54be06Stron 			tool_exit( ld, LDAP_LOCAL_ERROR );
1574cb54be06Stron 		}
15752de962bdSlukem 	}
15762de962bdSlukem 
15772de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
15782de962bdSlukem 	if ( ctrls && ppolicy ) {
15792de962bdSlukem 		LDAPControl *ctrl;
15802de962bdSlukem 		int expire, grace, len = 0;
15812de962bdSlukem 		LDAPPasswordPolicyError pErr = -1;
15822de962bdSlukem 
15832de962bdSlukem 		ctrl = ldap_control_find( LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
15842de962bdSlukem 			ctrls, NULL );
15852de962bdSlukem 
15862de962bdSlukem 		if ( ctrl && ldap_parse_passwordpolicy_control( ld, ctrl,
15872de962bdSlukem 			&expire, &grace, &pErr ) == LDAP_SUCCESS )
15882de962bdSlukem 		{
15892de962bdSlukem 			if ( pErr != PP_noError ){
15902de962bdSlukem 				msgbuf[0] = ';';
15912de962bdSlukem 				msgbuf[1] = ' ';
15922de962bdSlukem 				strcpy( msgbuf+2, ldap_passwordpolicy_err2txt( pErr ));
15932de962bdSlukem 				len = strlen( msgbuf );
15942de962bdSlukem 			}
15952de962bdSlukem 			if ( expire >= 0 ) {
15962de962bdSlukem 				sprintf( msgbuf+len,
15972de962bdSlukem 					" (Password expires in %d seconds)",
15982de962bdSlukem 					expire );
15992de962bdSlukem 			} else if ( grace >= 0 ) {
16002de962bdSlukem 				sprintf( msgbuf+len,
16012de962bdSlukem 					" (Password expired, %d grace logins remain)",
16022de962bdSlukem 					grace );
16032de962bdSlukem 			}
16042de962bdSlukem 		}
16052de962bdSlukem 	}
16062de962bdSlukem #endif
16072de962bdSlukem 
1608*549b59edSchristos 	if ( ctrls && bauthzid ) {
1609*549b59edSchristos 		LDAPControl *ctrl;
1610*549b59edSchristos 
1611*549b59edSchristos 		ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE,
1612*549b59edSchristos 			ctrls, NULL );
1613*549b59edSchristos 		if ( ctrl ) {
1614*549b59edSchristos 			LDAPControl *ctmp[2];
1615*549b59edSchristos 			ctmp[0] = ctrl;
1616*549b59edSchristos 			ctmp[1] = NULL;
1617*549b59edSchristos 			tool_print_ctrls( ld, ctmp );
1618*549b59edSchristos 		}
1619*549b59edSchristos 	}
1620*549b59edSchristos 
1621*549b59edSchristos #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRED
1622*549b59edSchristos 	if ( ctrls ) {
1623*549b59edSchristos 		LDAPControl *ctrl;
1624*549b59edSchristos 		ctrl = ldap_control_find( LDAP_CONTROL_X_PASSWORD_EXPIRED,
1625*549b59edSchristos 			ctrls, NULL );
1626*549b59edSchristos 		if ( !ctrl )
1627*549b59edSchristos 			ctrl = ldap_control_find( LDAP_CONTROL_X_PASSWORD_EXPIRING,
1628*549b59edSchristos 				ctrls, NULL );
1629*549b59edSchristos 		if ( ctrl ) {
1630*549b59edSchristos 			LDAPControl *ctmp[2];
1631*549b59edSchristos 			ctmp[0] = ctrl;
1632*549b59edSchristos 			ctmp[1] = NULL;
1633*549b59edSchristos 			tool_print_ctrls( ld, ctmp );
1634*549b59edSchristos 		}
1635*549b59edSchristos 	}
1636*549b59edSchristos #endif
1637*549b59edSchristos 
16382de962bdSlukem 	if ( ctrls ) {
16392de962bdSlukem 		ldap_controls_free( ctrls );
16402de962bdSlukem 	}
16412de962bdSlukem 
16422de962bdSlukem 	if ( err != LDAP_SUCCESS
16432de962bdSlukem 		|| msgbuf[0]
16442de962bdSlukem 		|| ( matched && matched[ 0 ] )
16452de962bdSlukem 		|| ( info && info[ 0 ] )
16462de962bdSlukem 		|| refs )
16472de962bdSlukem 	{
16482de962bdSlukem 		tool_perror( "ldap_bind", err, msgbuf, matched, info, refs );
16492de962bdSlukem 
16502de962bdSlukem 		if( matched ) ber_memfree( matched );
16512de962bdSlukem 		if( info ) ber_memfree( info );
16522de962bdSlukem 		if( refs ) ber_memvfree( (void **)refs );
16532de962bdSlukem 
1654cb54be06Stron 		if ( err != LDAP_SUCCESS ) tool_exit( ld, err );
16552de962bdSlukem 	}
16562de962bdSlukem }
16572de962bdSlukem 
16582de962bdSlukem void
tool_unbind(LDAP * ld)16592de962bdSlukem tool_unbind( LDAP *ld )
16602de962bdSlukem {
16612de962bdSlukem 	int err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, NULL );
16622de962bdSlukem 
16632de962bdSlukem 	if ( err != LDAP_OPT_SUCCESS ) {
16642de962bdSlukem 		fprintf( stderr, "Could not unset controls\n");
16652de962bdSlukem 	}
16662de962bdSlukem 
16672de962bdSlukem 	(void) ldap_unbind_ext( ld, NULL, NULL );
16682de962bdSlukem }
16692de962bdSlukem 
1670cb54be06Stron void
tool_exit(LDAP * ld,int status)1671cb54be06Stron tool_exit( LDAP *ld, int status )
1672cb54be06Stron {
1673cb54be06Stron 	if ( ld != NULL ) {
1674cb54be06Stron 		tool_unbind( ld );
1675cb54be06Stron 	}
1676cb54be06Stron 	tool_destroy();
1677cb54be06Stron 	exit( status );
1678cb54be06Stron }
1679cb54be06Stron 
16802de962bdSlukem 
16812de962bdSlukem /* Set server controls.  Add controls extra_c[0..count-1], if set. */
16822de962bdSlukem void
tool_server_controls(LDAP * ld,LDAPControl * extra_c,int count)16832de962bdSlukem tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count )
16842de962bdSlukem {
16852de962bdSlukem 	int i = 0, j, crit = 0, err;
16862de962bdSlukem 	LDAPControl c[16], **ctrls;
16872de962bdSlukem 
16882de962bdSlukem 	if ( ! ( assertctl
16892de962bdSlukem 		|| authzid
16902de962bdSlukem #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
16912de962bdSlukem 		|| proxydn
16922de962bdSlukem #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
16932de962bdSlukem 		|| manageDIT
16942de962bdSlukem 		|| manageDSAit
16952de962bdSlukem 		|| noop
16962de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
16972de962bdSlukem 		|| ppolicy
16982de962bdSlukem #endif
16992de962bdSlukem 		|| preread
17002de962bdSlukem 		|| postread
17012de962bdSlukem #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
17022de962bdSlukem 		|| chaining
17032de962bdSlukem #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
17042de962bdSlukem #ifdef LDAP_CONTROL_X_SESSION_TRACKING
17052de962bdSlukem 		|| sessionTracking
17062de962bdSlukem #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
17072de962bdSlukem 		|| count
17082de962bdSlukem 		|| unknown_ctrls_num ) )
17092de962bdSlukem 	{
17102de962bdSlukem 		return;
17112de962bdSlukem 	}
17122de962bdSlukem 
17132de962bdSlukem 	ctrls = (LDAPControl**) malloc(sizeof(c) + (count + unknown_ctrls_num + 1)*sizeof(LDAPControl*));
17142de962bdSlukem 	if ( ctrls == NULL ) {
17152de962bdSlukem 		fprintf( stderr, "No memory\n" );
1716cb54be06Stron 		tool_exit( ld, EXIT_FAILURE );
17172de962bdSlukem 	}
17182de962bdSlukem 
17192de962bdSlukem 	if ( assertctl ) {
1720bb30016cSlukem 		if ( BER_BVISNULL( &assertionvalue ) ) {
1721bb30016cSlukem 			err = ldap_create_assertion_control_value( ld,
1722bb30016cSlukem 				assertion, &assertionvalue );
1723bb30016cSlukem 			if ( err ) {
1724bb30016cSlukem 				fprintf( stderr,
1725bb30016cSlukem 					"Unable to create assertion value "
1726bb30016cSlukem 					"\"%s\" (%d)\n", assertion, err );
17272de962bdSlukem 			}
17282de962bdSlukem 		}
17292de962bdSlukem 
17302de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_ASSERT;
1731bb30016cSlukem 		c[i].ldctl_value = assertionvalue;
17322de962bdSlukem 		c[i].ldctl_iscritical = assertctl > 1;
17332de962bdSlukem 		ctrls[i] = &c[i];
17342de962bdSlukem 		i++;
17352de962bdSlukem 	}
17362de962bdSlukem 
17372de962bdSlukem 	if ( authzid ) {
17382de962bdSlukem 		c[i].ldctl_value.bv_val = authzid;
17392de962bdSlukem 		c[i].ldctl_value.bv_len = strlen( authzid );
17402de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
1741*549b59edSchristos 		c[i].ldctl_iscritical = authzcrit;
17422de962bdSlukem 		ctrls[i] = &c[i];
17432de962bdSlukem 		i++;
17442de962bdSlukem 	}
17452de962bdSlukem 
17462de962bdSlukem #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
17472de962bdSlukem 	/* NOTE: doesn't need an extra count because it's incompatible
17482de962bdSlukem 	 * with authzid */
17492de962bdSlukem 	if ( proxydn ) {
17502de962bdSlukem 		BerElementBuffer berbuf;
17512de962bdSlukem 		BerElement *ber = (BerElement *)&berbuf;
17522de962bdSlukem 
17532de962bdSlukem 		ber_init2( ber, NULL, LBER_USE_DER );
17542de962bdSlukem 
17554e6df137Slukem 		if ( ber_printf( ber, "s", proxydn ) == -1 ) {
1756cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
17572de962bdSlukem 		}
17582de962bdSlukem 
17592de962bdSlukem 		if ( ber_flatten2( ber, &c[i].ldctl_value, 0 ) == -1 ) {
1760cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
17612de962bdSlukem 		}
17622de962bdSlukem 
17632de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
1764*549b59edSchristos 		c[i].ldctl_iscritical = authzcrit;
17652de962bdSlukem 		ctrls[i] = &c[i];
17662de962bdSlukem 		i++;
17672de962bdSlukem 	}
17682de962bdSlukem #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
17692de962bdSlukem 
17702de962bdSlukem 	if ( manageDIT ) {
17712de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_MANAGEDIT;
17722de962bdSlukem 		BER_BVZERO( &c[i].ldctl_value );
17732de962bdSlukem 		c[i].ldctl_iscritical = manageDIT > 1;
17742de962bdSlukem 		ctrls[i] = &c[i];
17752de962bdSlukem 		i++;
17762de962bdSlukem 	}
17772de962bdSlukem 
17782de962bdSlukem 	if ( manageDSAit ) {
17792de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
17802de962bdSlukem 		BER_BVZERO( &c[i].ldctl_value );
17812de962bdSlukem 		c[i].ldctl_iscritical = manageDSAit > 1;
17822de962bdSlukem 		ctrls[i] = &c[i];
17832de962bdSlukem 		i++;
17842de962bdSlukem 	}
17852de962bdSlukem 
17862de962bdSlukem 	if ( noop ) {
17872de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_NOOP;
17882de962bdSlukem 		BER_BVZERO( &c[i].ldctl_value );
17892de962bdSlukem 		c[i].ldctl_iscritical = noop > 1;
17902de962bdSlukem 		ctrls[i] = &c[i];
17912de962bdSlukem 		i++;
17922de962bdSlukem 	}
17932de962bdSlukem 
17942de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
17952de962bdSlukem 	if ( ppolicy ) {
17962de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
17972de962bdSlukem 		BER_BVZERO( &c[i].ldctl_value );
17982de962bdSlukem 		c[i].ldctl_iscritical = 0;
17992de962bdSlukem 		ctrls[i] = &c[i];
18002de962bdSlukem 		i++;
18012de962bdSlukem 	}
18022de962bdSlukem #endif
18032de962bdSlukem 
18042de962bdSlukem 	if ( preread ) {
18054e6df137Slukem 		BerElementBuffer berbuf;
18064e6df137Slukem 		BerElement *ber = (BerElement *)&berbuf;
18072de962bdSlukem 		char **attrs = NULL;
18082de962bdSlukem 
18092de962bdSlukem 		if( preread_attrs ) {
18102de962bdSlukem 			attrs = ldap_str2charray( preread_attrs, "," );
18112de962bdSlukem 		}
18122de962bdSlukem 
18132de962bdSlukem 		ber_init2( ber, NULL, LBER_USE_DER );
18142de962bdSlukem 
18152de962bdSlukem 		if( ber_printf( ber, "{v}", attrs ) == -1 ) {
18162de962bdSlukem 			fprintf( stderr, "preread attrs encode failed.\n" );
1817cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
18182de962bdSlukem 		}
18192de962bdSlukem 
18202de962bdSlukem 		err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
18212de962bdSlukem 		if( err < 0 ) {
18222de962bdSlukem 			fprintf( stderr, "preread flatten failed (%d)\n", err );
1823cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
18242de962bdSlukem 		}
18252de962bdSlukem 
18262de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_PRE_READ;
18272de962bdSlukem 		c[i].ldctl_iscritical = preread > 1;
18282de962bdSlukem 		ctrls[i] = &c[i];
18292de962bdSlukem 		i++;
18302de962bdSlukem 
18312de962bdSlukem 		if( attrs ) ldap_charray_free( attrs );
18322de962bdSlukem 	}
18332de962bdSlukem 
18342de962bdSlukem 	if ( postread ) {
18354e6df137Slukem 		BerElementBuffer berbuf;
18364e6df137Slukem 		BerElement *ber = (BerElement *)&berbuf;
18372de962bdSlukem 		char **attrs = NULL;
18382de962bdSlukem 
18392de962bdSlukem 		if( postread_attrs ) {
18402de962bdSlukem 			attrs = ldap_str2charray( postread_attrs, "," );
18412de962bdSlukem 		}
18422de962bdSlukem 
18432de962bdSlukem 		ber_init2( ber, NULL, LBER_USE_DER );
18442de962bdSlukem 
18452de962bdSlukem 		if( ber_printf( ber, "{v}", attrs ) == -1 ) {
18462de962bdSlukem 			fprintf( stderr, "postread attrs encode failed.\n" );
1847cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
18482de962bdSlukem 		}
18492de962bdSlukem 
18502de962bdSlukem 		err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
18512de962bdSlukem 		if( err < 0 ) {
18522de962bdSlukem 			fprintf( stderr, "postread flatten failed (%d)\n", err );
1853cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
18542de962bdSlukem 		}
18552de962bdSlukem 
18562de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_POST_READ;
18572de962bdSlukem 		c[i].ldctl_iscritical = postread > 1;
18582de962bdSlukem 		ctrls[i] = &c[i];
18592de962bdSlukem 		i++;
18602de962bdSlukem 
18612de962bdSlukem 		if( attrs ) ldap_charray_free( attrs );
18622de962bdSlukem 	}
18632de962bdSlukem 
18642de962bdSlukem #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
18652de962bdSlukem 	if ( chaining ) {
18662de962bdSlukem 		if ( chainingResolve > -1 ) {
18672de962bdSlukem 			BerElementBuffer berbuf;
18682de962bdSlukem 			BerElement *ber = (BerElement *)&berbuf;
18692de962bdSlukem 
18702de962bdSlukem 			ber_init2( ber, NULL, LBER_USE_DER );
18712de962bdSlukem 
18722de962bdSlukem 			err = ber_printf( ber, "{e" /* } */, chainingResolve );
18732de962bdSlukem 		    	if ( err == -1 ) {
18742de962bdSlukem 				ber_free( ber, 1 );
18752de962bdSlukem 				fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1876cb54be06Stron 				tool_exit( ld, EXIT_FAILURE );
18772de962bdSlukem 			}
18782de962bdSlukem 
18792de962bdSlukem 			if ( chainingContinuation > -1 ) {
18802de962bdSlukem 				err = ber_printf( ber, "e", chainingContinuation );
18812de962bdSlukem 		    		if ( err == -1 ) {
18822de962bdSlukem 					ber_free( ber, 1 );
18832de962bdSlukem 					fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1884cb54be06Stron 					tool_exit( ld, EXIT_FAILURE );
18852de962bdSlukem 				}
18862de962bdSlukem 			}
18872de962bdSlukem 
18882de962bdSlukem 			err = ber_printf( ber, /* { */ "N}" );
18892de962bdSlukem 		    	if ( err == -1 ) {
18902de962bdSlukem 				ber_free( ber, 1 );
18912de962bdSlukem 				fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1892cb54be06Stron 				tool_exit( ld, EXIT_FAILURE );
18932de962bdSlukem 			}
18942de962bdSlukem 
18952de962bdSlukem 			if ( ber_flatten2( ber, &c[i].ldctl_value, 0 ) == -1 ) {
1896cb54be06Stron 				tool_exit( ld, EXIT_FAILURE );
18972de962bdSlukem 			}
18982de962bdSlukem 
18992de962bdSlukem 		} else {
19002de962bdSlukem 			BER_BVZERO( &c[i].ldctl_value );
19012de962bdSlukem 		}
19022de962bdSlukem 
19032de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
19042de962bdSlukem 		c[i].ldctl_iscritical = chaining > 1;
19052de962bdSlukem 		ctrls[i] = &c[i];
19062de962bdSlukem 		i++;
19072de962bdSlukem 	}
19082de962bdSlukem #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
19092de962bdSlukem 
19102de962bdSlukem #ifdef LDAP_CONTROL_X_SESSION_TRACKING
19112de962bdSlukem 	if ( sessionTracking ) {
1912cb54be06Stron 		if ( BER_BVISNULL( &stValue ) && st_value( ld, &stValue ) ) {
1913cb54be06Stron 			tool_exit( ld, EXIT_FAILURE );
19142de962bdSlukem 		}
19152de962bdSlukem 
19162de962bdSlukem 		c[i].ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
19172de962bdSlukem 		c[i].ldctl_iscritical = 0;
1918*549b59edSchristos 		c[i].ldctl_value = stValue;
19192de962bdSlukem 
19202de962bdSlukem 		ctrls[i] = &c[i];
19212de962bdSlukem 		i++;
19222de962bdSlukem 	}
19232de962bdSlukem #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
19242de962bdSlukem 
19252de962bdSlukem 	while ( count-- ) {
19262de962bdSlukem 		ctrls[i++] = extra_c++;
19272de962bdSlukem 	}
19282de962bdSlukem 	for ( count = 0; count < unknown_ctrls_num; count++ ) {
19292de962bdSlukem 		ctrls[i++] = &unknown_ctrls[count];
19302de962bdSlukem 	}
19312de962bdSlukem 	ctrls[i] = NULL;
19322de962bdSlukem 
19332de962bdSlukem 	err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
19342de962bdSlukem 
19352de962bdSlukem 	if ( err != LDAP_OPT_SUCCESS ) {
19362de962bdSlukem 		for ( j = 0; j < i; j++ ) {
19372de962bdSlukem 			if ( ctrls[j]->ldctl_iscritical ) crit = 1;
19382de962bdSlukem 		}
19392de962bdSlukem 		fprintf( stderr, "Could not set %scontrols\n",
19402de962bdSlukem 			crit ? "critical " : "" );
19412de962bdSlukem 	}
19422de962bdSlukem 
19432de962bdSlukem  	free( ctrls );
19442de962bdSlukem 	if ( crit ) {
1945cb54be06Stron 		tool_exit( ld, EXIT_FAILURE );
19462de962bdSlukem 	}
19472de962bdSlukem }
19482de962bdSlukem 
19492de962bdSlukem int
tool_check_abandon(LDAP * ld,int msgid)19502de962bdSlukem tool_check_abandon( LDAP *ld, int msgid )
19512de962bdSlukem {
19522de962bdSlukem 	int	rc;
1953956cbeb4Schristos 	LDAPControl *sctrls[1] = { NULL };
19542de962bdSlukem 
19552de962bdSlukem 	switch ( gotintr ) {
19562de962bdSlukem 	case Intr_Cancel:
1957956cbeb4Schristos 		rc = ldap_cancel_s( ld, msgid, sctrls, NULL );
19582de962bdSlukem 		fprintf( stderr, "got interrupt, cancel got %d: %s\n",
19592de962bdSlukem 				rc, ldap_err2string( rc ) );
19602de962bdSlukem 		return -1;
19612de962bdSlukem 
19622de962bdSlukem 	case Intr_Abandon:
1963956cbeb4Schristos 		rc = ldap_abandon_ext( ld, msgid, sctrls, NULL );
19642de962bdSlukem 		fprintf( stderr, "got interrupt, abandon got %d: %s\n",
19652de962bdSlukem 				rc, ldap_err2string( rc ) );
19662de962bdSlukem 		return -1;
19672de962bdSlukem 
19682de962bdSlukem 	case Intr_Ignore:
19692de962bdSlukem 		/* just unbind, ignoring the request */
19702de962bdSlukem 		return -1;
19712de962bdSlukem 	}
19722de962bdSlukem 
19732de962bdSlukem 	return 0;
19742de962bdSlukem }
19752de962bdSlukem 
19762de962bdSlukem static int
print_prepostread(LDAP * ld,LDAPControl * ctrl,struct berval * what)19772de962bdSlukem print_prepostread( LDAP *ld, LDAPControl *ctrl, struct berval *what)
19782de962bdSlukem {
19792de962bdSlukem 	BerElement	*ber;
19802de962bdSlukem 	struct berval	bv;
19812de962bdSlukem 
19822de962bdSlukem 	tool_write_ldif( LDIF_PUT_COMMENT, "==> ",
19832de962bdSlukem 		what->bv_val, what->bv_len );
19842de962bdSlukem 	ber = ber_init( &ctrl->ldctl_value );
19852de962bdSlukem 	if ( ber == NULL ) {
19862de962bdSlukem 		/* error? */
19872de962bdSlukem 		return 1;
19882de962bdSlukem 
19892de962bdSlukem 	} else if ( ber_scanf( ber, "{m{" /*}}*/, &bv ) == LBER_ERROR ) {
19902de962bdSlukem 		/* error? */
19912de962bdSlukem 		return 1;
19922de962bdSlukem 
19932de962bdSlukem 	} else {
19942de962bdSlukem 		tool_write_ldif( LDIF_PUT_VALUE, "dn", bv.bv_val, bv.bv_len );
19952de962bdSlukem 
19962de962bdSlukem 		while ( ber_scanf( ber, "{m" /*}*/, &bv ) != LBER_ERROR ) {
19972de962bdSlukem 			int		i;
19982de962bdSlukem 			BerVarray	vals = NULL;
1999cb54be06Stron 			char		*str = NULL;
20002de962bdSlukem 
20012de962bdSlukem 			if ( ber_scanf( ber, "[W]", &vals ) == LBER_ERROR ||
20022de962bdSlukem 				vals == NULL )
20032de962bdSlukem 			{
20042de962bdSlukem 				/* error? */
20052de962bdSlukem 				return 1;
20062de962bdSlukem 			}
20072de962bdSlukem 
2008cb54be06Stron 			if ( ldif ) {
2009cb54be06Stron 				char *ptr;
2010cb54be06Stron 
2011cb54be06Stron 				str = malloc( bv.bv_len + STRLENOF(": ") + 1 );
2012cb54be06Stron 
2013cb54be06Stron 				ptr = str;
2014cb54be06Stron 				ptr = lutil_strncopy( ptr, bv.bv_val, bv.bv_len );
2015cb54be06Stron 				ptr = lutil_strcopy( ptr, ": " );
2016cb54be06Stron 			}
2017cb54be06Stron 
20182de962bdSlukem 			for ( i = 0; vals[ i ].bv_val != NULL; i++ ) {
20192de962bdSlukem 				tool_write_ldif(
20202de962bdSlukem 					ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2021cb54be06Stron 					ldif ? str : bv.bv_val, vals[ i ].bv_val, vals[ i ].bv_len );
20222de962bdSlukem 			}
20232de962bdSlukem 
20242de962bdSlukem 			ber_bvarray_free( vals );
2025cb54be06Stron 			if ( str ) free( str );
20262de962bdSlukem 		}
20272de962bdSlukem 	}
20282de962bdSlukem 
20292de962bdSlukem 	if ( ber != NULL ) {
20302de962bdSlukem 		ber_free( ber, 1 );
20312de962bdSlukem 	}
20322de962bdSlukem 
20332de962bdSlukem 	tool_write_ldif( LDIF_PUT_COMMENT, "<== ",
20342de962bdSlukem 		what->bv_val, what->bv_len );
20352de962bdSlukem 
20362de962bdSlukem 	return 0;
20372de962bdSlukem }
20382de962bdSlukem 
20392de962bdSlukem static int
print_preread(LDAP * ld,LDAPControl * ctrl)20402de962bdSlukem print_preread( LDAP *ld, LDAPControl *ctrl )
20412de962bdSlukem {
20422de962bdSlukem 	static struct berval what = BER_BVC( "preread" );
20432de962bdSlukem 
20442de962bdSlukem 	return print_prepostread( ld, ctrl, &what );
20452de962bdSlukem }
20462de962bdSlukem 
20472de962bdSlukem static int
print_postread(LDAP * ld,LDAPControl * ctrl)20482de962bdSlukem print_postread( LDAP *ld, LDAPControl *ctrl )
20492de962bdSlukem {
20502de962bdSlukem 	static struct berval what = BER_BVC( "postread" );
20512de962bdSlukem 
20522de962bdSlukem 	return print_prepostread( ld, ctrl, &what );
20532de962bdSlukem }
20542de962bdSlukem 
20552de962bdSlukem static int
print_paged_results(LDAP * ld,LDAPControl * ctrl)20562de962bdSlukem print_paged_results( LDAP *ld, LDAPControl *ctrl )
20572de962bdSlukem {
20582de962bdSlukem 	ber_int_t estimate;
20592de962bdSlukem 
20602de962bdSlukem 	/* note: pr_cookie is being malloced; it's freed
20612de962bdSlukem 	 * the next time the control is sent, but the last
20622de962bdSlukem 	 * time it's not; we don't care too much, because
20632de962bdSlukem 	 * the last time an empty value is returned... */
20642de962bdSlukem 	if ( ldap_parse_pageresponse_control( ld, ctrl, &estimate, &pr_cookie )
20652de962bdSlukem 		!= LDAP_SUCCESS )
20662de962bdSlukem 	{
20672de962bdSlukem 		/* error? */
20682de962bdSlukem 		return 1;
20692de962bdSlukem 
20702de962bdSlukem 	} else {
20712de962bdSlukem 		char	buf[ BUFSIZ ], *ptr = buf;
2072*549b59edSchristos 		int plen;
20732de962bdSlukem 
20742de962bdSlukem 		if ( estimate > 0 ) {
2075*549b59edSchristos 			plen = sprintf( buf, "estimate=%d cookie=", estimate );
2076*549b59edSchristos 		} else {
2077*549b59edSchristos 			plen = sprintf( buf, "cookie=" );
20782de962bdSlukem 		}
20792de962bdSlukem 
20802de962bdSlukem 		if ( pr_cookie.bv_len > 0 ) {
20812de962bdSlukem 			struct berval	bv;
20822de962bdSlukem 
20832de962bdSlukem 			bv.bv_len = LUTIL_BASE64_ENCODE_LEN(
20842de962bdSlukem 				pr_cookie.bv_len ) + 1;
2085*549b59edSchristos 			ptr = ber_memalloc( bv.bv_len + 1 + plen );
2086*549b59edSchristos 			bv.bv_val = ptr + plen;
2087*549b59edSchristos 
2088*549b59edSchristos 			strcpy( ptr, buf );
20892de962bdSlukem 
20902de962bdSlukem 			bv.bv_len = lutil_b64_ntop(
20912de962bdSlukem 				(unsigned char *) pr_cookie.bv_val,
20922de962bdSlukem 				pr_cookie.bv_len,
20932de962bdSlukem 				bv.bv_val, bv.bv_len );
20942de962bdSlukem 
20952de962bdSlukem 			pr_morePagedResults = 1;
2096*549b59edSchristos 			plen += bv.bv_len;
20972de962bdSlukem 		}
20982de962bdSlukem 
20992de962bdSlukem 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2100cb54be06Stron 			ldif ? "pagedresults: " : "pagedresults",
2101*549b59edSchristos 			ptr, plen );
2102*549b59edSchristos 
2103*549b59edSchristos 		if ( ptr != buf )
2104*549b59edSchristos 			ber_memfree( ptr );
21052de962bdSlukem 	}
21062de962bdSlukem 
21072de962bdSlukem 	return 0;
21082de962bdSlukem }
21092de962bdSlukem 
21104e6df137Slukem static int
print_psearch(LDAP * ld,LDAPControl * ctrl)2111*549b59edSchristos print_psearch( LDAP *ld, LDAPControl *ctrl )
2112*549b59edSchristos {
2113*549b59edSchristos 	int rc;
2114*549b59edSchristos 	int chgtype;
2115*549b59edSchristos 	int chgpres;
2116*549b59edSchristos 	long chgnum;
2117*549b59edSchristos 	struct berval prevdn;
2118*549b59edSchristos 
2119*549b59edSchristos 	rc = ldap_parse_entrychange_control( ld, ctrl, &chgtype, &prevdn,
2120*549b59edSchristos 		&chgpres, &chgnum );
2121*549b59edSchristos 	if ( rc == LDAP_SUCCESS ) {
2122*549b59edSchristos 		char buf[ BUFSIZ ];
2123*549b59edSchristos 		char *ptr = buf;
2124*549b59edSchristos 		int blen = sizeof(buf), len;
2125*549b59edSchristos 
2126*549b59edSchristos 		switch( chgtype ) {
2127*549b59edSchristos 		case LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD:
2128*549b59edSchristos 			len = snprintf( ptr, blen, "add" );
2129*549b59edSchristos 			ptr += len;
2130*549b59edSchristos 			blen -= len;
2131*549b59edSchristos 			break;
2132*549b59edSchristos 		case LDAP_CONTROL_PERSIST_ENTRY_CHANGE_DELETE:
2133*549b59edSchristos 			len = snprintf( ptr, blen, "delete" );
2134*549b59edSchristos 			ptr += len;
2135*549b59edSchristos 			blen -= len;
2136*549b59edSchristos 			break;
2137*549b59edSchristos 		case LDAP_CONTROL_PERSIST_ENTRY_CHANGE_MODIFY:
2138*549b59edSchristos 			len = snprintf( ptr, blen, "modify" );
2139*549b59edSchristos 			ptr += len;
2140*549b59edSchristos 			blen -= len;
2141*549b59edSchristos 			break;
2142*549b59edSchristos 		case LDAP_CONTROL_PERSIST_ENTRY_CHANGE_RENAME:
2143*549b59edSchristos 			len = snprintf( ptr, blen, "moddn" );
2144*549b59edSchristos 			ptr += len;
2145*549b59edSchristos 			blen -= len;
2146*549b59edSchristos 			if ( prevdn.bv_val != NULL ) {
2147*549b59edSchristos 				len = snprintf( ptr, blen, " prevdn %s", prevdn.bv_val );
2148*549b59edSchristos 				ptr += len;
2149*549b59edSchristos 				blen -= len;
2150*549b59edSchristos 			}
2151*549b59edSchristos 			break;
2152*549b59edSchristos 		}
2153*549b59edSchristos 		if ( chgpres ) {
2154*549b59edSchristos 			len = snprintf( ptr, blen, " changeNumber %ld", chgnum) ;
2155*549b59edSchristos 			ptr += len;
2156*549b59edSchristos 			blen -= len;
2157*549b59edSchristos 		}
2158*549b59edSchristos 
2159*549b59edSchristos 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2160*549b59edSchristos 			ldif ? "persistentSearch: " : "persistentSearch", buf, len );
2161*549b59edSchristos 	}
2162*549b59edSchristos 
2163*549b59edSchristos 	return rc;
2164*549b59edSchristos }
2165*549b59edSchristos 
2166*549b59edSchristos static int
print_sss(LDAP * ld,LDAPControl * ctrl)21674e6df137Slukem print_sss( LDAP *ld, LDAPControl *ctrl )
21684e6df137Slukem {
21694e6df137Slukem 	int rc;
21704e6df137Slukem 	ber_int_t err;
21714e6df137Slukem 	char *attr;
21724e6df137Slukem 
21734e6df137Slukem 	rc = ldap_parse_sortresponse_control( ld, ctrl, &err, &attr );
21744e6df137Slukem 	if ( rc == LDAP_SUCCESS ) {
21754e6df137Slukem 		char buf[ BUFSIZ ];
21764e6df137Slukem 		rc = snprintf( buf, sizeof(buf), "(%d) %s%s%s",
21774e6df137Slukem 			err, ldap_err2string(err), attr ? " " : "", attr ? attr : "" );
21784e6df137Slukem 
21794e6df137Slukem 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2180cb54be06Stron 			ldif ? "sortResult: " : "sortResult", buf, rc );
21814e6df137Slukem 	}
21824e6df137Slukem 
21834e6df137Slukem 	return rc;
21844e6df137Slukem }
21854e6df137Slukem 
21864e6df137Slukem static int
print_vlv(LDAP * ld,LDAPControl * ctrl)21874e6df137Slukem print_vlv( LDAP *ld, LDAPControl *ctrl )
21884e6df137Slukem {
21894e6df137Slukem 	int rc;
21904e6df137Slukem 	ber_int_t err;
21914e6df137Slukem 	struct berval bv;
21924e6df137Slukem 
21934e6df137Slukem 	rc = ldap_parse_vlvresponse_control( ld, ctrl, &vlvPos, &vlvCount,
21944e6df137Slukem 		&vlvContext, &err );
21954e6df137Slukem 	if ( rc == LDAP_SUCCESS ) {
21964e6df137Slukem 		char buf[ BUFSIZ ];
21974e6df137Slukem 
21984e6df137Slukem 		if ( vlvContext && vlvContext->bv_len > 0 ) {
21994e6df137Slukem 			bv.bv_len = LUTIL_BASE64_ENCODE_LEN(
22004e6df137Slukem 				vlvContext->bv_len ) + 1;
22014e6df137Slukem 			bv.bv_val = ber_memalloc( bv.bv_len + 1 );
22024e6df137Slukem 
22034e6df137Slukem 			bv.bv_len = lutil_b64_ntop(
22044e6df137Slukem 				(unsigned char *) vlvContext->bv_val,
22054e6df137Slukem 				vlvContext->bv_len,
22064e6df137Slukem 				bv.bv_val, bv.bv_len );
22074e6df137Slukem 		} else {
22084e6df137Slukem 			bv.bv_val = "";
22094e6df137Slukem 			bv.bv_len = 0;
22104e6df137Slukem 		}
22114e6df137Slukem 
22124e6df137Slukem 		rc = snprintf( buf, sizeof(buf), "pos=%d count=%d context=%s (%d) %s",
22134e6df137Slukem 			vlvPos, vlvCount, bv.bv_val,
22144e6df137Slukem 			err, ldap_err2string(err));
22154e6df137Slukem 
22164e6df137Slukem 		if ( bv.bv_len )
22174e6df137Slukem 			ber_memfree( bv.bv_val );
22184e6df137Slukem 
22194e6df137Slukem 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2220cb54be06Stron 			ldif ? "vlvResult" : "vlvResult", buf, rc );
22214e6df137Slukem 	}
22224e6df137Slukem 
22234e6df137Slukem 	return rc;
22244e6df137Slukem }
22254e6df137Slukem 
22264e6df137Slukem #ifdef LDAP_CONTROL_X_DEREF
22274e6df137Slukem static int
print_deref(LDAP * ld,LDAPControl * ctrl)22284e6df137Slukem print_deref( LDAP *ld, LDAPControl *ctrl )
22294e6df137Slukem {
22304e6df137Slukem 	LDAPDerefRes    *drhead = NULL, *dr;
22314e6df137Slukem 	int		rc;
22324e6df137Slukem 
22334e6df137Slukem 	rc = ldap_parse_derefresponse_control( ld, ctrl, &drhead );
22344e6df137Slukem 	if ( rc != LDAP_SUCCESS ) {
22354e6df137Slukem 		return rc;
22364e6df137Slukem 	}
22374e6df137Slukem 
22384e6df137Slukem 	for ( dr = drhead; dr != NULL; dr = dr->next ) {
22394e6df137Slukem 		LDAPDerefVal	*dv;
22404e6df137Slukem 		ber_len_t	len;
22414e6df137Slukem 		char		*buf, *ptr;
22424e6df137Slukem 
22434e6df137Slukem 		len = strlen( dr->derefAttr ) + STRLENOF(": ");
22444e6df137Slukem 
22454e6df137Slukem 		for ( dv = dr->attrVals; dv != NULL; dv = dv->next ) {
22464e6df137Slukem 			if ( dv->vals != NULL ) {
22474e6df137Slukem 				int j;
22484e6df137Slukem 				ber_len_t tlen = strlen(dv->type);
22494e6df137Slukem 
22504e6df137Slukem 				for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
22514e6df137Slukem 					len += STRLENOF("<:=>;") + tlen + 4*((dv->vals[ j ].bv_len - 1)/3 + 1);
22524e6df137Slukem 				}
22534e6df137Slukem 			}
22544e6df137Slukem 		}
22554e6df137Slukem 		len += dr->derefVal.bv_len + STRLENOF("\n");
22564e6df137Slukem 		buf = ldap_memalloc( len + 1 );
22574e6df137Slukem 		if ( buf == NULL ) {
22584e6df137Slukem 			rc = LDAP_NO_MEMORY;
22594e6df137Slukem 			goto done;
22604e6df137Slukem 		}
22614e6df137Slukem 
22624e6df137Slukem 		ptr = buf;
22634e6df137Slukem 		ptr = lutil_strcopy( ptr, dr->derefAttr );
22644e6df137Slukem 		*ptr++ = ':';
22654e6df137Slukem 		*ptr++ = ' ';
22664e6df137Slukem 		for ( dv = dr->attrVals; dv != NULL; dv = dv->next ) {
22674e6df137Slukem 			if ( dv->vals != NULL ) {
22684e6df137Slukem 				int j;
22694e6df137Slukem 				for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
22704e6df137Slukem 					int k = ldif_is_not_printable( dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
22714e6df137Slukem 
22724e6df137Slukem 					*ptr++ = '<';
22734e6df137Slukem 					ptr = lutil_strcopy( ptr, dv->type );
22744e6df137Slukem 					if ( k ) {
22754e6df137Slukem 						*ptr++ = ':';
22764e6df137Slukem 					}
22774e6df137Slukem 					*ptr++ = '=';
22784e6df137Slukem 					if ( k ) {
22794e6df137Slukem 						k = lutil_b64_ntop(
22804e6df137Slukem 							(unsigned char *) dv->vals[ j ].bv_val,
22814e6df137Slukem 							dv->vals[ j ].bv_len,
22824e6df137Slukem 							ptr, buf + len - ptr );
22834e6df137Slukem 						assert( k >= 0 );
22844e6df137Slukem 						ptr += k;
22854e6df137Slukem 
22864e6df137Slukem 					} else {
22874e6df137Slukem 						ptr = lutil_memcopy( ptr, dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
22884e6df137Slukem 					}
22894e6df137Slukem 					*ptr++ = '>';
22904e6df137Slukem 					*ptr++ = ';';
22914e6df137Slukem 				}
22924e6df137Slukem 			}
22934e6df137Slukem 		}
22944e6df137Slukem 		ptr = lutil_strncopy( ptr, dr->derefVal.bv_val, dr->derefVal.bv_len );
22954e6df137Slukem 		*ptr = '\0';
22964e6df137Slukem 		assert( ptr <= buf + len );
22974e6df137Slukem 
22984e6df137Slukem 		tool_write_ldif( LDIF_PUT_COMMENT, NULL, buf, ptr - buf);
22994e6df137Slukem 
23004e6df137Slukem 		ldap_memfree( buf );
23014e6df137Slukem 	}
23024e6df137Slukem 
23034e6df137Slukem 	rc = LDAP_SUCCESS;
23044e6df137Slukem 
23054e6df137Slukem done:;
23064e6df137Slukem 	ldap_derefresponse_free( drhead );
23074e6df137Slukem 
23084e6df137Slukem 	return rc;
23094e6df137Slukem }
23104e6df137Slukem #endif
23114e6df137Slukem 
23124e6df137Slukem #ifdef LDAP_CONTROL_X_WHATFAILED
23134e6df137Slukem static int
print_whatfailed(LDAP * ld,LDAPControl * ctrl)23144e6df137Slukem print_whatfailed( LDAP *ld, LDAPControl *ctrl )
23154e6df137Slukem {
23164e6df137Slukem 	BerElement *ber;
23174e6df137Slukem 	ber_tag_t tag;
23184e6df137Slukem 	ber_len_t siz;
23194e6df137Slukem 	BerVarray bva = NULL;
23204e6df137Slukem 
23214e6df137Slukem 	/* Create a BerElement from the berval returned in the control. */
23224e6df137Slukem 	ber = ber_init( &ctrl->ldctl_value );
23234e6df137Slukem 
23244e6df137Slukem 	if ( ber == NULL ) {
23254e6df137Slukem 		return LDAP_NO_MEMORY;
23264e6df137Slukem 	}
23274e6df137Slukem 
23284e6df137Slukem 	siz = sizeof(struct berval);
23294e6df137Slukem 	tag = ber_scanf( ber, "[M]", &bva, &siz, 0 );
23304e6df137Slukem 	if ( tag != LBER_ERROR ) {
23314e6df137Slukem 		int i;
23324e6df137Slukem 
23334e6df137Slukem 		tool_write_ldif( LDIF_PUT_COMMENT, " what failed:", NULL, 0 );
23344e6df137Slukem 
23354e6df137Slukem 		for ( i = 0; bva[i].bv_val != NULL; i++ ) {
23364e6df137Slukem 			tool_write_ldif( LDIF_PUT_COMMENT, NULL, bva[i].bv_val, bva[i].bv_len );
23374e6df137Slukem 		}
23384e6df137Slukem 
23394e6df137Slukem 		ldap_memfree( bva );
23404e6df137Slukem 	}
23414e6df137Slukem 
23424e6df137Slukem         ber_free( ber, 1 );
23434e6df137Slukem 
23444e6df137Slukem 
23454e6df137Slukem 	return 0;
23464e6df137Slukem }
23474e6df137Slukem #endif
23484e6df137Slukem 
2349*549b59edSchristos static int
print_syncstate(LDAP * ld,LDAPControl * ctrl)2350*549b59edSchristos print_syncstate( LDAP *ld, LDAPControl *ctrl )
2351*549b59edSchristos {
2352*549b59edSchristos 	struct berval syncUUID, syncCookie = BER_BVNULL;
2353*549b59edSchristos 	char buf[LDAP_LUTIL_UUIDSTR_BUFSIZE], *uuidstr = "(UUID malformed)";
2354*549b59edSchristos 	BerElement *ber;
2355*549b59edSchristos 	ber_tag_t tag;
2356*549b59edSchristos 	ber_int_t state;
2357*549b59edSchristos 	int rc;
2358*549b59edSchristos 
2359*549b59edSchristos 	if ( ldif ) {
2360*549b59edSchristos 		return 0;
2361*549b59edSchristos 	}
2362*549b59edSchristos 
2363*549b59edSchristos 	/* Create a BerElement from the berval returned in the control. */
2364*549b59edSchristos 	ber = ber_init( &ctrl->ldctl_value );
2365*549b59edSchristos 
2366*549b59edSchristos 	if ( ber == NULL ) {
2367*549b59edSchristos 		return LDAP_NO_MEMORY;
2368*549b59edSchristos 	}
2369*549b59edSchristos 
2370*549b59edSchristos 	if ( ber_scanf( ber, "{em", &state, &syncUUID ) == LBER_ERROR ) {
2371*549b59edSchristos 		ber_free( ber, 1 );
2372*549b59edSchristos 		return 1;
2373*549b59edSchristos 	}
2374*549b59edSchristos 
2375*549b59edSchristos 	tag = ber_get_stringbv( ber, &syncCookie, 0 );
2376*549b59edSchristos 
2377*549b59edSchristos 	rc = lutil_uuidstr_from_normalized(
2378*549b59edSchristos 			syncUUID.bv_val, syncUUID.bv_len,
2379*549b59edSchristos 			buf, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2380*549b59edSchristos 
2381*549b59edSchristos 	if ( rc > 0 && rc < LDAP_LUTIL_UUIDSTR_BUFSIZE ) {
2382*549b59edSchristos 		uuidstr = buf;
2383*549b59edSchristos 	}
2384*549b59edSchristos 
2385*549b59edSchristos 	switch ( state ) {
2386*549b59edSchristos 		case LDAP_SYNC_PRESENT:
2387*549b59edSchristos 			printf(_("# SyncState control, UUID %s present\n"), uuidstr);
2388*549b59edSchristos 			break;
2389*549b59edSchristos 		case LDAP_SYNC_ADD:
2390*549b59edSchristos 			printf(_("# SyncState control, UUID %s added\n"), uuidstr);
2391*549b59edSchristos 			break;
2392*549b59edSchristos 		case LDAP_SYNC_MODIFY:
2393*549b59edSchristos 			printf(_("# SyncState control, UUID %s modified\n"), uuidstr);
2394*549b59edSchristos 			break;
2395*549b59edSchristos 		case LDAP_SYNC_DELETE:
2396*549b59edSchristos 			printf(_("# SyncState control, UUID %s deleted\n"), uuidstr);
2397*549b59edSchristos 			break;
2398*549b59edSchristos 		default:
2399*549b59edSchristos 			ber_free( ber, 1 );
2400*549b59edSchristos 			return 1;
2401*549b59edSchristos 	}
2402*549b59edSchristos 
2403*549b59edSchristos 	if ( tag != LBER_ERROR ) {
2404*549b59edSchristos 		if ( ldif_is_not_printable( syncCookie.bv_val, syncCookie.bv_len ) ) {
2405*549b59edSchristos 			struct berval bv;
2406*549b59edSchristos 
2407*549b59edSchristos 			bv.bv_len = LUTIL_BASE64_ENCODE_LEN( syncCookie.bv_len ) + 1;
2408*549b59edSchristos 			bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2409*549b59edSchristos 
2410*549b59edSchristos 			bv.bv_len = lutil_b64_ntop(
2411*549b59edSchristos 					(unsigned char *) syncCookie.bv_val, syncCookie.bv_len,
2412*549b59edSchristos 					bv.bv_val, bv.bv_len );
2413*549b59edSchristos 
2414*549b59edSchristos 			printf(_("# cookie:: %s\n"), bv.bv_val );
2415*549b59edSchristos 			ber_memfree( bv.bv_val );
2416*549b59edSchristos 		} else {
2417*549b59edSchristos 			printf(_("# cookie: %s\n"), syncCookie.bv_val );
2418*549b59edSchristos 		}
2419*549b59edSchristos 	}
2420*549b59edSchristos 
2421*549b59edSchristos 	ber_free( ber, 1 );
2422*549b59edSchristos 	return 0;
2423*549b59edSchristos }
2424*549b59edSchristos 
2425*549b59edSchristos static int
print_syncdone(LDAP * ld,LDAPControl * ctrl)2426*549b59edSchristos print_syncdone( LDAP *ld, LDAPControl *ctrl )
2427*549b59edSchristos {
2428*549b59edSchristos 	BerElement *ber;
2429*549b59edSchristos 	struct berval cookie = BER_BVNULL;
2430*549b59edSchristos 	ber_len_t len;
2431*549b59edSchristos 	ber_int_t refreshDeletes = 0;
2432*549b59edSchristos 
2433*549b59edSchristos 	if ( ldif ) {
2434*549b59edSchristos 		return 0;
2435*549b59edSchristos 	}
2436*549b59edSchristos 
2437*549b59edSchristos 	/* Create a BerElement from the berval returned in the control. */
2438*549b59edSchristos 	ber = ber_init( &ctrl->ldctl_value );
2439*549b59edSchristos 
2440*549b59edSchristos 	if ( ber == NULL ) {
2441*549b59edSchristos 		return LDAP_NO_MEMORY;
2442*549b59edSchristos 	}
2443*549b59edSchristos 
2444*549b59edSchristos 	ber_skip_tag( ber, &len );
2445*549b59edSchristos 	if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
2446*549b59edSchristos 		ber_scanf( ber, "m", &cookie );
2447*549b59edSchristos 	}
2448*549b59edSchristos 	if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
2449*549b59edSchristos 		ber_scanf( ber, "b", &refreshDeletes );
2450*549b59edSchristos 	}
2451*549b59edSchristos 
2452*549b59edSchristos 	printf(_("# SyncDone control refreshDeletes=%d\n"), refreshDeletes ? 1 : 0 );
2453*549b59edSchristos 
2454*549b59edSchristos 	if ( !BER_BVISNULL( &cookie ) ) {
2455*549b59edSchristos 		if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) {
2456*549b59edSchristos 			struct berval bv;
2457*549b59edSchristos 
2458*549b59edSchristos 			bv.bv_len = LUTIL_BASE64_ENCODE_LEN( cookie.bv_len ) + 1;
2459*549b59edSchristos 			bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2460*549b59edSchristos 
2461*549b59edSchristos 			bv.bv_len = lutil_b64_ntop(
2462*549b59edSchristos 					(unsigned char *) cookie.bv_val, cookie.bv_len,
2463*549b59edSchristos 					bv.bv_val, bv.bv_len );
2464*549b59edSchristos 
2465*549b59edSchristos 			printf(_("# cookie:: %s\n"), bv.bv_val );
2466*549b59edSchristos 			ber_memfree( bv.bv_val );
2467*549b59edSchristos 		} else {
2468*549b59edSchristos 			printf(_("# cookie: %s\n"), cookie.bv_val );
2469*549b59edSchristos 		}
2470*549b59edSchristos 	}
2471*549b59edSchristos 
2472*549b59edSchristos 	ber_free( ber, 1 );
2473*549b59edSchristos 	return 0;
2474*549b59edSchristos }
2475*549b59edSchristos 
2476*549b59edSchristos #ifdef LDAP_CONTROL_X_DIRSYNC
2477*549b59edSchristos static int
print_dirsync(LDAP * ld,LDAPControl * ctrl)2478*549b59edSchristos print_dirsync( LDAP *ld, LDAPControl *ctrl )
2479*549b59edSchristos {
2480*549b59edSchristos 	int rc, continueFlag;
2481*549b59edSchristos 	struct berval cookie;
2482*549b59edSchristos 
2483*549b59edSchristos 	rc = ldap_parse_dirsync_control( ld, ctrl,
2484*549b59edSchristos 		&continueFlag, &cookie );
2485*549b59edSchristos 	if ( rc == LDAP_SUCCESS ) {
2486*549b59edSchristos 		printf(_("# DirSync control continueFlag=%d\n"), continueFlag );
2487*549b59edSchristos 		if ( !BER_BVISNULL( &cookie )) {
2488*549b59edSchristos 			if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) {
2489*549b59edSchristos 				struct berval bv;
2490*549b59edSchristos 
2491*549b59edSchristos 				bv.bv_len = LUTIL_BASE64_ENCODE_LEN( cookie.bv_len ) + 1;
2492*549b59edSchristos 				bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2493*549b59edSchristos 
2494*549b59edSchristos 				bv.bv_len = lutil_b64_ntop(
2495*549b59edSchristos 						(unsigned char *) cookie.bv_val, cookie.bv_len,
2496*549b59edSchristos 						bv.bv_val, bv.bv_len );
2497*549b59edSchristos 
2498*549b59edSchristos 				printf(_("# cookie:: %s\n"), bv.bv_val );
2499*549b59edSchristos 				ber_memfree( bv.bv_val );
2500*549b59edSchristos 			} else {
2501*549b59edSchristos 				printf(_("# cookie: %s\n"), cookie.bv_val );
2502*549b59edSchristos 			}
2503*549b59edSchristos 		}
2504*549b59edSchristos 	}
2505*549b59edSchristos 	return rc;
2506*549b59edSchristos }
2507*549b59edSchristos #endif
2508*549b59edSchristos 
2509*549b59edSchristos #ifdef LDAP_CONTROL_AUTHZID_RESPONSE
2510*549b59edSchristos static int
print_authzid(LDAP * ld,LDAPControl * ctrl)2511*549b59edSchristos print_authzid( LDAP *ld, LDAPControl *ctrl )
2512*549b59edSchristos {
2513*549b59edSchristos 	if ( ctrl->ldctl_value.bv_len ) {
2514*549b59edSchristos 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2515*549b59edSchristos 			ldif ? "authzid: " : "authzid",
2516*549b59edSchristos 		ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len );
2517*549b59edSchristos 	} else {
2518*549b59edSchristos 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2519*549b59edSchristos 			ldif ? "authzid: " : "authzid",
2520*549b59edSchristos 			"anonymous",  STRLENOF("anonymous") );
2521*549b59edSchristos 	}
2522*549b59edSchristos 
2523*549b59edSchristos 	return 0;
2524*549b59edSchristos }
2525*549b59edSchristos #endif
2526*549b59edSchristos 
25272de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
25282de962bdSlukem static int
print_ppolicy(LDAP * ld,LDAPControl * ctrl)25292de962bdSlukem print_ppolicy( LDAP *ld, LDAPControl *ctrl )
25302de962bdSlukem {
25312de962bdSlukem 	int expire = 0, grace = 0, rc;
25322de962bdSlukem 	LDAPPasswordPolicyError	pperr;
25332de962bdSlukem 
25342de962bdSlukem 	rc = ldap_parse_passwordpolicy_control( ld, ctrl,
25352de962bdSlukem 		&expire, &grace, &pperr );
25362de962bdSlukem 	if ( rc == LDAP_SUCCESS ) {
25372de962bdSlukem 		char	buf[ BUFSIZ ], *ptr = buf;
25382de962bdSlukem 
25392de962bdSlukem 		if ( expire != -1 ) {
25402de962bdSlukem 			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
25412de962bdSlukem 				"expire=%d", expire );
25422de962bdSlukem 		}
25432de962bdSlukem 
25442de962bdSlukem 		if ( grace != -1 ) {
25452de962bdSlukem 			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
25462de962bdSlukem 				"%sgrace=%d", ptr == buf ? "" : " ", grace );
25472de962bdSlukem 		}
25482de962bdSlukem 
25492de962bdSlukem 		if ( pperr != PP_noError ) {
25502de962bdSlukem 			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
25512de962bdSlukem 				"%serror=%d (%s)", ptr == buf ? "" : " ",
25522de962bdSlukem 				pperr,
25532de962bdSlukem 				ldap_passwordpolicy_err2txt( pperr ) );
25542de962bdSlukem 		}
25552de962bdSlukem 
25562de962bdSlukem 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2557cb54be06Stron 			ldif ? "ppolicy: " : "ppolicy", buf, ptr - buf );
25582de962bdSlukem 	}
25592de962bdSlukem 
25602de962bdSlukem 	return rc;
25612de962bdSlukem }
25622de962bdSlukem #endif
25632de962bdSlukem 
2564*549b59edSchristos #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRED
2565*549b59edSchristos static int
print_netscape_pwexpired(LDAP * ld,LDAPControl * ctrl)2566*549b59edSchristos print_netscape_pwexpired( LDAP *ld, LDAPControl *ctrl )
2567*549b59edSchristos {
2568*549b59edSchristos 	printf(_("# PasswordExpired control\n") );
2569*549b59edSchristos 	return 0;
2570*549b59edSchristos }
2571*549b59edSchristos 
2572*549b59edSchristos static int
print_netscape_pwexpiring(LDAP * ld,LDAPControl * ctrl)2573*549b59edSchristos print_netscape_pwexpiring( LDAP *ld, LDAPControl *ctrl )
2574*549b59edSchristos {
2575*549b59edSchristos 	long expiring = 0;
2576*549b59edSchristos 	int rc;
2577*549b59edSchristos 
2578*549b59edSchristos 	rc = ldap_parse_password_expiring_control( ld, ctrl, &expiring );
2579*549b59edSchristos 	if ( rc == LDAP_SUCCESS ) {
2580*549b59edSchristos 		printf(_("# PasswordExpiring control seconds=%ld\n"), expiring );
2581*549b59edSchristos 	}
2582*549b59edSchristos 	return rc;
2583*549b59edSchristos }
2584*549b59edSchristos #endif
2585*549b59edSchristos 
2586*549b59edSchristos #ifdef LDAP_CONTROL_X_ACCOUNT_USABILITY
2587*549b59edSchristos static int
print_account_usability(LDAP * ld,LDAPControl * ctrl)2588*549b59edSchristos print_account_usability( LDAP *ld, LDAPControl *ctrl )
2589*549b59edSchristos {
2590*549b59edSchristos 	LDAPAccountUsability usability;
2591*549b59edSchristos 	ber_int_t available = 0;
2592*549b59edSchristos 	int rc;
2593*549b59edSchristos 
2594*549b59edSchristos 	rc = ldap_parse_accountusability_control( ld, ctrl, &available, &usability );
2595*549b59edSchristos 	if ( rc == LDAP_SUCCESS ) {
2596*549b59edSchristos 		char	buf[ BUFSIZ ], *ptr = buf;
2597*549b59edSchristos 
2598*549b59edSchristos 		ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2599*549b59edSchristos 			   "%savailable", available ? "" : "not " );
2600*549b59edSchristos 		if ( available ) {
2601*549b59edSchristos 			if ( usability.seconds_remaining == -1 ) {
2602*549b59edSchristos 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2603*549b59edSchristos 					" and does not expire" );
2604*549b59edSchristos 			} else {
2605*549b59edSchristos 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2606*549b59edSchristos 					" expire=%d", usability.seconds_remaining );
2607*549b59edSchristos 			}
2608*549b59edSchristos 		} else {
2609*549b59edSchristos 			int added = 0;
2610*549b59edSchristos 			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2611*549b59edSchristos 				" (" /* ')' */ );
2612*549b59edSchristos 
2613*549b59edSchristos 			if ( usability.more_info.inactive ) {
2614*549b59edSchristos 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2615*549b59edSchristos 					"inactive " );
2616*549b59edSchristos 				added++;
2617*549b59edSchristos 			}
2618*549b59edSchristos 			if ( usability.more_info.reset ) {
2619*549b59edSchristos 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2620*549b59edSchristos 					"reset " );
2621*549b59edSchristos 				added++;
2622*549b59edSchristos 			}
2623*549b59edSchristos 			if ( usability.more_info.expired ) {
2624*549b59edSchristos 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2625*549b59edSchristos 					"expired " );
2626*549b59edSchristos 				added++;
2627*549b59edSchristos 			}
2628*549b59edSchristos 
2629*549b59edSchristos 			if ( added ) {
2630*549b59edSchristos 				ptr[-1] = ')';
2631*549b59edSchristos 				*ptr++ = ' ';
2632*549b59edSchristos 			} else {
2633*549b59edSchristos 				*(--ptr) = '\0';
2634*549b59edSchristos 			}
2635*549b59edSchristos 
2636*549b59edSchristos 			if ( usability.more_info.remaining_grace != -1 ) {
2637*549b59edSchristos 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2638*549b59edSchristos 					"grace=%d ", usability.more_info.remaining_grace );
2639*549b59edSchristos 			}
2640*549b59edSchristos 
2641*549b59edSchristos 			if ( usability.more_info.seconds_before_unlock != -1 ) {
2642*549b59edSchristos 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2643*549b59edSchristos 					"seconds_before_unlock=%d ", usability.more_info.seconds_before_unlock );
2644*549b59edSchristos 			}
2645*549b59edSchristos 
2646*549b59edSchristos 			*(--ptr) = '\0';
2647*549b59edSchristos 		}
2648*549b59edSchristos 
2649*549b59edSchristos 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2650*549b59edSchristos 			ldif ? "accountUsability: " : "accountUsability", buf, ptr - buf );
2651*549b59edSchristos 	}
2652*549b59edSchristos 
2653*549b59edSchristos 	return rc;
2654*549b59edSchristos }
2655*549b59edSchristos #endif
2656*549b59edSchristos 
tool_print_ctrls(LDAP * ld,LDAPControl ** ctrls)26572de962bdSlukem void tool_print_ctrls(
26582de962bdSlukem 	LDAP		*ld,
26592de962bdSlukem 	LDAPControl	**ctrls )
26602de962bdSlukem {
26612de962bdSlukem 	int	i;
26622de962bdSlukem 	char	*ptr;
26632de962bdSlukem 
26642de962bdSlukem 	for ( i = 0; ctrls[i] != NULL; i++ ) {
26652de962bdSlukem 		/* control: OID criticality base64value */
26662de962bdSlukem 		struct berval b64 = BER_BVNULL;
26672de962bdSlukem 		ber_len_t len;
26682de962bdSlukem 		char *str;
26692de962bdSlukem 		int j;
26702de962bdSlukem 
26712de962bdSlukem 		/* FIXME: there might be cases where a control has NULL OID;
26722de962bdSlukem 		 * this makes little sense, especially when returned by the
26732de962bdSlukem 		 * server, but libldap happily allows it */
26742de962bdSlukem 		if ( ctrls[i]->ldctl_oid == NULL ) {
26752de962bdSlukem 			continue;
26762de962bdSlukem 		}
26772de962bdSlukem 
26782de962bdSlukem 		len = ldif ? 2 : 0;
26792de962bdSlukem 		len += strlen( ctrls[i]->ldctl_oid );
26802de962bdSlukem 
26812de962bdSlukem 		/* add enough for space after OID and the critical value itself */
26822de962bdSlukem 		len += ctrls[i]->ldctl_iscritical
26832de962bdSlukem 			? sizeof("true") : sizeof("false");
26842de962bdSlukem 
26852de962bdSlukem 		/* convert to base64 */
26862de962bdSlukem 		if ( !BER_BVISNULL( &ctrls[i]->ldctl_value ) ) {
26872de962bdSlukem 			b64.bv_len = LUTIL_BASE64_ENCODE_LEN(
26882de962bdSlukem 				ctrls[i]->ldctl_value.bv_len ) + 1;
26892de962bdSlukem 			b64.bv_val = ber_memalloc( b64.bv_len + 1 );
26902de962bdSlukem 
26912de962bdSlukem 			b64.bv_len = lutil_b64_ntop(
26922de962bdSlukem 				(unsigned char *) ctrls[i]->ldctl_value.bv_val,
26932de962bdSlukem 				ctrls[i]->ldctl_value.bv_len,
26942de962bdSlukem 				b64.bv_val, b64.bv_len );
26952de962bdSlukem 		}
26962de962bdSlukem 
26972de962bdSlukem 		if ( b64.bv_len ) {
26982de962bdSlukem 			len += 1 + b64.bv_len;
26992de962bdSlukem 		}
27002de962bdSlukem 
27012de962bdSlukem 		ptr = str = malloc( len + 1 );
27022de962bdSlukem 		if ( ldif ) {
27032de962bdSlukem 			ptr = lutil_strcopy( ptr, ": " );
27042de962bdSlukem 		}
27052de962bdSlukem 		ptr = lutil_strcopy( ptr, ctrls[i]->ldctl_oid );
27062de962bdSlukem 		ptr = lutil_strcopy( ptr, ctrls[i]->ldctl_iscritical
27072de962bdSlukem 			? " true" : " false" );
27082de962bdSlukem 
27092de962bdSlukem 		if ( b64.bv_len ) {
27102de962bdSlukem 			ptr = lutil_strcopy( ptr, " " );
27112de962bdSlukem 			ptr = lutil_strcopy( ptr, b64.bv_val );
27122de962bdSlukem 		}
27132de962bdSlukem 
27142de962bdSlukem 		if ( ldif < 2 ) {
27152de962bdSlukem 			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
27162de962bdSlukem 				"control", str, len );
27172de962bdSlukem 		}
27182de962bdSlukem 
27192de962bdSlukem 		free( str );
27202de962bdSlukem 		if ( b64.bv_len ) {
27212de962bdSlukem 			ber_memfree( b64.bv_val );
27222de962bdSlukem 		}
27232de962bdSlukem 
27242de962bdSlukem 		/* known controls */
27252de962bdSlukem 		for ( j = 0; tool_ctrl_response[j].oid != NULL; j++ ) {
27262de962bdSlukem 			if ( strcmp( tool_ctrl_response[j].oid, ctrls[i]->ldctl_oid ) == 0 ) {
27271d7b1261Sjoerg 				if ( !(tool_ctrl_response[j].mask & tool_type )) {
27282de962bdSlukem 					/* this control should not appear
27292de962bdSlukem 					 * with this tool; warning? */
27302de962bdSlukem 				}
27312de962bdSlukem 				break;
27322de962bdSlukem 			}
27332de962bdSlukem 		}
27342de962bdSlukem 
27352de962bdSlukem 		if ( tool_ctrl_response[j].oid != NULL && tool_ctrl_response[j].func ) {
27362de962bdSlukem 			(void)tool_ctrl_response[j].func( ld, ctrls[i] );
27372de962bdSlukem 		}
27382de962bdSlukem 	}
27392de962bdSlukem }
27402de962bdSlukem 
27412de962bdSlukem int
tool_write_ldif(int type,char * name,char * value,ber_len_t vallen)27422de962bdSlukem tool_write_ldif( int type, char *name, char *value, ber_len_t vallen )
27432de962bdSlukem {
27442de962bdSlukem 	char	*ldif;
27452de962bdSlukem 
2746cb54be06Stron 	if (( ldif = ldif_put_wrap( type, name, value, vallen, ldif_wrap )) == NULL ) {
27472de962bdSlukem 		return( -1 );
27482de962bdSlukem 	}
27492de962bdSlukem 
27502de962bdSlukem 	fputs( ldif, stdout );
27512de962bdSlukem 	ber_memfree( ldif );
27522de962bdSlukem 
27532de962bdSlukem 	return( 0 );
27542de962bdSlukem }
27552de962bdSlukem 
27562de962bdSlukem int
tool_is_oid(const char * s)27572de962bdSlukem tool_is_oid( const char *s )
27582de962bdSlukem {
27592de962bdSlukem 	int		first = 1;
27602de962bdSlukem 
27612de962bdSlukem 	if ( !isdigit( (unsigned char) s[ 0 ] ) ) {
27622de962bdSlukem 		return 0;
27632de962bdSlukem 	}
27642de962bdSlukem 
27652de962bdSlukem 	for ( ; s[ 0 ]; s++ ) {
27662de962bdSlukem 		if ( s[ 0 ] == '.' ) {
27672de962bdSlukem 			if ( s[ 1 ] == '\0' ) {
27682de962bdSlukem 				return 0;
27692de962bdSlukem 			}
27702de962bdSlukem 			first = 1;
27712de962bdSlukem 			continue;
27722de962bdSlukem 		}
27732de962bdSlukem 
27742de962bdSlukem 		if ( !isdigit( (unsigned char) s[ 0 ] ) ) {
27752de962bdSlukem 			return 0;
27762de962bdSlukem 		}
27772de962bdSlukem 
27782de962bdSlukem 		if ( first == 1 && s[ 0 ] == '0' && s[ 1 ] != '.' ) {
27792de962bdSlukem 			return 0;
27802de962bdSlukem 		}
27812de962bdSlukem 		first = 0;
27822de962bdSlukem 	}
27832de962bdSlukem 
27842de962bdSlukem 	return 1;
27852de962bdSlukem }
2786