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