]> git.sur5r.net Git - openldap/blob - clients/tools/common.c
c39b9c1a2154c2fbebf1adf93bd5065317e5d6b9
[openldap] / clients / tools / common.c
1 /* common.c - common routines for the ldap client tools */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2009 The OpenLDAP Foundation.
6  * Portions Copyright 2003 Kurt D. Zeilenga.
7  * Portions Copyright 2003 IBM Corporation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This file was initially created by Hallvard B. Furuseth based (in
20  * part) upon argument parsing code for individual tools located in
21  * this directory.   Additional contributors include:
22  *   Kurt D. Zeilenga (additional common argument and control support)
23  */
24
25 #include "portable.h"
26
27 #include <stdio.h>
28
29 #include <ac/stdlib.h>
30 #include <ac/signal.h>
31 #include <ac/string.h>
32 #include <ac/ctype.h>
33 #include <ac/unistd.h>
34 #include <ac/errno.h>
35 #include <ac/time.h>
36 #include <ac/socket.h>
37
38 #ifdef HAVE_CYRUS_SASL
39 #ifdef HAVE_SASL_SASL_H
40 #include <sasl/sasl.h>
41 #else
42 #include <sasl.h>
43 #endif
44 #endif
45
46 #include <ldap.h>
47
48 #include "ldif.h"
49 #include "lutil.h"
50 #include "lutil_ldap.h"
51 #include "ldap_defaults.h"
52 #include "ldap_pvt.h"
53 #include "lber_pvt.h"
54
55 #include "common.h"
56
57 /* input-related vars */
58
59 /* misc. parameters */
60 tool_type_t     tool_type;
61 int             contoper = 0;
62 int             debug = 0;
63 char            *infile = NULL;
64 int             dont = 0;
65 int             nocanon = 0;
66 int             referrals = 0;
67 int             verbose = 0;
68 int             ldif = 0;
69 char            *prog = NULL;
70
71 /* connection */
72 char            *ldapuri = NULL;
73 char            *ldaphost = NULL;
74 int             ldapport = 0;
75 int             use_tls = 0;
76 int             protocol = -1;
77 int             version = 0;
78
79 /* authc/authz */
80 int             authmethod = -1;
81 char            *binddn = NULL;
82 int             want_bindpw = 0;
83 struct berval   passwd = { 0, NULL };
84 char            *pw_file = NULL;
85 #ifdef HAVE_CYRUS_SASL
86 unsigned        sasl_flags = LDAP_SASL_AUTOMATIC;
87 char            *sasl_realm = NULL;
88 char            *sasl_authc_id = NULL;
89 char            *sasl_authz_id = NULL;
90 char            *sasl_mech = NULL;
91 char            *sasl_secprops = NULL;
92 #endif
93
94 /* controls */
95 int             assertctl;
96 char            *assertion = NULL;
97 struct berval   assertionvalue = BER_BVNULL;
98 char            *authzid = NULL;
99 /* support deprecated early version of proxyAuthz */
100 #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ       "2.16.840.1.113730.3.4.12"
101 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
102 char            *proxydn = NULL;
103 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
104 int             manageDIT = 0;
105 int             manageDSAit = 0;
106 int             noop = 0;
107 int             ppolicy = 0;
108 int             preread = 0;
109 static char     *preread_attrs = NULL;
110 int             postread = 0;
111 static char     *postread_attrs = NULL;
112 ber_int_t       pr_morePagedResults = 1;
113 struct berval   pr_cookie = { 0, NULL };
114 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
115 int             chaining = 0;
116 static int      chainingResolve = -1;
117 static int      chainingContinuation = -1;
118 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
119 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
120 static int      sessionTracking = 0;
121 struct berval   stValue;
122 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
123 ber_int_t vlvPos;
124 ber_int_t vlvCount;
125 struct berval *vlvContext;
126
127 LDAPControl     *unknown_ctrls = NULL;
128 int             unknown_ctrls_num = 0;
129
130 /* options */
131 struct timeval  nettimeout = { -1 , 0 };
132
133 typedef int (*print_ctrl_fn)( LDAP *ld, LDAPControl *ctrl );
134
135 static int print_preread( LDAP *ld, LDAPControl *ctrl );
136 static int print_postread( LDAP *ld, LDAPControl *ctrl );
137 static int print_paged_results( LDAP *ld, LDAPControl *ctrl );
138 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
139 static int print_ppolicy( LDAP *ld, LDAPControl *ctrl );
140 #endif
141 static int print_sss( LDAP *ld, LDAPControl *ctrl );
142 static int print_vlv( LDAP *ld, LDAPControl *ctrl );
143 #ifdef LDAP_CONTROL_X_DEREF
144 static int print_deref( LDAP *ld, LDAPControl *ctrl );
145 #endif
146 #ifdef LDAP_CONTROL_X_WHATFAILED
147 static int print_whatfailed( LDAP *ld, LDAPControl *ctrl );
148 #endif
149
150 static struct tool_ctrls_t {
151         const char      *oid;
152         unsigned        mask;
153         print_ctrl_fn   func;
154 } tool_ctrl_response[] = {
155         { LDAP_CONTROL_PRE_READ,                        TOOL_ALL,       print_preread },
156         { LDAP_CONTROL_POST_READ,                       TOOL_ALL,       print_postread },
157         { LDAP_CONTROL_PAGEDRESULTS,                    TOOL_SEARCH,    print_paged_results },
158 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
159         { LDAP_CONTROL_PASSWORDPOLICYRESPONSE,          TOOL_ALL,       print_ppolicy },
160 #endif
161         { LDAP_CONTROL_SORTRESPONSE,    TOOL_SEARCH,    print_sss },
162         { LDAP_CONTROL_VLVRESPONSE,             TOOL_SEARCH,    print_vlv },
163 #ifdef LDAP_CONTROL_X_DEREF
164         { LDAP_CONTROL_X_DEREF,                         TOOL_SEARCH,    print_deref },
165 #endif
166 #ifdef LDAP_CONTROL_X_WHATFAILED
167         { LDAP_CONTROL_X_WHATFAILED,                    TOOL_ALL,       print_whatfailed },
168 #endif
169         { NULL,                                         0,              NULL }
170 };
171
172 /* "features" */
173 enum { Intr_None = 0, Intr_Abandon, Intr_Cancel, Intr_Ignore }; 
174 static volatile sig_atomic_t    gotintr, abcan;
175
176
177 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
178 static int
179 st_value( LDAP *ld, struct berval *value )
180 {
181         char            *ip = NULL, *name = NULL;
182         struct berval   id = { 0 };
183         char            namebuf[ MAXHOSTNAMELEN ];
184
185         if ( gethostname( namebuf, sizeof( namebuf ) ) == 0 ) {
186                 struct hostent  *h;
187                 struct in_addr  addr;
188
189                 name = namebuf;
190
191                 h = gethostbyname( name );
192                 if ( h != NULL ) {
193                         AC_MEMCPY( &addr, h->h_addr, sizeof( addr ) );
194                         ip = inet_ntoa( addr );
195                 }
196         }
197
198 #ifdef HAVE_CYRUS_SASL
199         if ( sasl_authz_id != NULL ) {
200                 ber_str2bv( sasl_authz_id, 0, 0, &id );
201
202         } else if ( sasl_authc_id != NULL ) {
203                 ber_str2bv( sasl_authc_id, 0, 0, &id );
204
205         } else 
206 #endif /* HAVE_CYRUS_SASL */
207         if ( binddn != NULL ) {
208                 ber_str2bv( binddn, 0, 0, &id );
209         }
210
211         if ( ldap_create_session_tracking_value( ld,
212                 ip, name, LDAP_CONTROL_X_SESSION_TRACKING_USERNAME,
213                 &id, &stValue ) )
214         {
215                 fprintf( stderr, _("Session tracking control encoding error!\n") );
216                 return -1;
217         }
218
219         return 0;
220 }
221 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
222
223 RETSIGTYPE
224 do_sig( int sig )
225 {
226         gotintr = abcan;
227 }
228
229 void
230 tool_init( tool_type_t type )
231 {
232         tool_type = type;
233         ldap_pvt_setlocale(LC_MESSAGES, "");
234         ldap_pvt_bindtextdomain(OPENLDAP_PACKAGE, LDAP_LOCALEDIR);
235         ldap_pvt_textdomain(OPENLDAP_PACKAGE);
236 }
237
238 void
239 tool_destroy( void )
240 {
241 #ifdef HAVE_CYRUS_SASL
242         sasl_done();
243 #endif
244 #ifdef HAVE_TLS
245         ldap_pvt_tls_destroy();
246 #endif
247
248         if ( ldapuri != NULL ) {
249                 ber_memfree( ldapuri );
250                 ldapuri = NULL;
251         }
252
253         if ( pr_cookie.bv_val != NULL ) {
254                 ber_memfree( pr_cookie.bv_val );
255                 pr_cookie.bv_val = NULL;
256                 pr_cookie.bv_len = 0;
257         }
258
259         if ( binddn != NULL ) {
260                 ber_memfree( binddn );
261         }
262
263 #if 0   /* not yet */
264         if ( passwd.bv_val != NULL ) {
265                 ber_memfree( passwd.bv_val );
266         }
267 #endif
268 }
269
270 void
271 tool_common_usage( void )
272 {
273         static const char *const descriptions[] = {
274 N_("  -c         continuous operation mode (do not stop on errors)\n"),
275 N_("  -d level   set LDAP debugging level to `level'\n"),
276 N_("  -D binddn  bind DN\n"),
277 N_("  -e [!]<ext>[=<extparam>] general extensions (! indicates criticality)\n")
278 N_("             [!]assert=<filter>     (RFC 4528; a RFC 4515 Filter string)\n")
279 N_("             [!]authzid=<authzid>   (RFC 4370; \"dn:<dn>\" or \"u:<user>\")\n")
280 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
281 #if 0
282                  /* non-advertized support for proxyDN */
283 N_("             [!]proxydn=<dn>        (a RFC 4514 DN string)\n")
284 #endif
285 #endif
286 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
287 N_("             [!]chaining[=<resolveBehavior>[/<continuationBehavior>]]\n")
288 N_("                     one of \"chainingPreferred\", \"chainingRequired\",\n")
289 N_("                     \"referralsPreferred\", \"referralsRequired\"\n")
290 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
291 N_("             [!]manageDSAit         (RFC 3296)\n")
292 N_("             [!]noop\n")
293 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
294 N_("             ppolicy\n")
295 #endif
296 N_("             [!]postread[=<attrs>]  (RFC 4527; comma-separated attr list)\n")
297 N_("             [!]preread[=<attrs>]   (RFC 4527; comma-separated attr list)\n")
298 N_("             [!]relax\n")
299 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
300 N_("             [!]sessiontracking\n")
301 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
302 N_("             abandon, cancel, ignore (SIGINT sends abandon/cancel,\n"
303    "             or ignores response; if critical, doesn't wait for SIGINT.\n"
304    "             not really controls)\n")
305 N_("  -f file    read operations from `file'\n"),
306 N_("  -h host    LDAP server\n"),
307 N_("  -H URI     LDAP Uniform Resource Identifier(s)\n"),
308 N_("  -I         use SASL Interactive mode\n"),
309 N_("  -M         enable Manage DSA IT control (-MM to make critical)\n"),
310 N_("  -n         show what would be done but don't actually do it\n"),
311 N_("  -N         do not use reverse DNS to canonicalize SASL host name\n"),
312 N_("  -O props   SASL security properties\n"),
313 N_("  -o <opt>[=<optparam] general options\n"),
314 N_("             nettimeout=<timeout> (in seconds, or \"none\" or \"max\")\n"),
315 N_("  -p port    port on LDAP server\n"),
316 N_("  -P version protocol version (default: 3)\n"),
317 N_("  -Q         use SASL Quiet mode\n"),
318 N_("  -R realm   SASL realm\n"),
319 N_("  -U authcid SASL authentication identity\n"),
320 N_("  -v         run in verbose mode (diagnostics to standard output)\n"),
321 N_("  -V         print version info (-VV only)\n"),
322 N_("  -w passwd  bind password (for simple authentication)\n"),
323 N_("  -W         prompt for bind password\n"),
324 N_("  -x         Simple authentication\n"),
325 N_("  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"),
326 N_("  -y file    Read password from file\n"),
327 N_("  -Y mech    SASL mechanism\n"),
328 N_("  -Z         Start TLS request (-ZZ to require successful response)\n"),
329 NULL
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
341 void 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
370 void
371 tool_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
1075 LDAP *
1076 tool_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
1207 dnssrv_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                 if ( use_tls ) {
1292                         rc = ldap_start_tls_s( ld, NULL, NULL );
1293                         if ( rc != LDAP_SUCCESS ) {
1294                                 tool_perror( "ldap_start_tls", rc, NULL, NULL, NULL, NULL );
1295                                 if ( use_tls > 1 ) {
1296                                         exit( EXIT_FAILURE );
1297                                 }
1298                         }
1299                 }
1300
1301                 if ( nettimeout.tv_sec > 0 ) {
1302                         if ( ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (void *) &nettimeout )
1303                                 != LDAP_OPT_SUCCESS )
1304                         {
1305                                 fprintf( stderr, "Could not set LDAP_OPT_NETWORK_TIMEOUT %ld\n",
1306                                         (long)nettimeout.tv_sec );
1307                                 exit( EXIT_FAILURE );
1308                         }
1309                 }
1310         }
1311
1312         return ld;
1313 }
1314
1315
1316 void
1317 tool_bind( LDAP *ld )
1318 {
1319         LDAPControl     **sctrlsp = NULL;
1320         LDAPControl     *sctrls[3];
1321         LDAPControl     sctrl[3];
1322         int             nsctrls = 0;
1323
1324 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1325         if ( ppolicy ) {
1326                 LDAPControl c;
1327                 c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
1328                 c.ldctl_value.bv_val = NULL;
1329                 c.ldctl_value.bv_len = 0;
1330                 c.ldctl_iscritical = 0;
1331                 sctrl[nsctrls] = c;
1332                 sctrls[nsctrls] = &sctrl[nsctrls];
1333                 sctrls[++nsctrls] = NULL;
1334         }
1335 #endif
1336
1337 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1338         if ( sessionTracking ) {
1339                 LDAPControl c;
1340
1341                 if (stValue.bv_val == NULL && st_value( ld, &stValue ) ) {
1342                         exit( EXIT_FAILURE );
1343                 }
1344
1345                 c.ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
1346                 c.ldctl_iscritical = 0;
1347                 ber_dupbv( &c.ldctl_value, &stValue );
1348
1349                 sctrl[nsctrls] = c;
1350                 sctrls[nsctrls] = &sctrl[nsctrls];
1351                 sctrls[++nsctrls] = NULL;
1352         }
1353 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
1354
1355         if ( nsctrls ) {
1356                 sctrlsp = sctrls;
1357         }
1358
1359         assert( nsctrls < (int) (sizeof(sctrls)/sizeof(sctrls[0])) );
1360
1361         if ( authmethod == LDAP_AUTH_SASL ) {
1362 #ifdef HAVE_CYRUS_SASL
1363                 void *defaults;
1364                 int rc;
1365
1366                 if( sasl_secprops != NULL ) {
1367                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
1368                                 (void *) sasl_secprops );
1369
1370                         if( rc != LDAP_OPT_SUCCESS ) {
1371                                 fprintf( stderr,
1372                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
1373                                         sasl_secprops );
1374                                 exit( LDAP_LOCAL_ERROR );
1375                         }
1376                 }
1377
1378                 defaults = lutil_sasl_defaults( ld,
1379                         sasl_mech,
1380                         sasl_realm,
1381                         sasl_authc_id,
1382                         passwd.bv_val,
1383                         sasl_authz_id );
1384
1385                 rc = ldap_sasl_interactive_bind_s( ld, binddn, sasl_mech,
1386                         sctrlsp,
1387                         NULL, sasl_flags, lutil_sasl_interact, defaults );
1388
1389                 lutil_sasl_freedefs( defaults );
1390                 if( rc != LDAP_SUCCESS ) {
1391                         tool_perror( "ldap_sasl_interactive_bind_s",
1392                                 rc, NULL, NULL, NULL, NULL );
1393                         exit( rc );
1394                 }
1395 #else
1396                 fprintf( stderr, "%s: not compiled with SASL support\n", prog );
1397                 exit( LDAP_NOT_SUPPORTED );
1398 #endif
1399         } else {
1400                 int msgid, err, rc;
1401                 LDAPMessage *result;
1402                 LDAPControl **ctrls;
1403                 char msgbuf[256];
1404                 char *matched = NULL;
1405                 char *info = NULL;
1406                 char **refs = NULL;
1407
1408                 msgbuf[0] = 0;
1409
1410                 {
1411                         /* simple bind */
1412                         rc = ldap_sasl_bind( ld, binddn, LDAP_SASL_SIMPLE, &passwd,
1413                                 sctrlsp, NULL, &msgid );
1414                         if ( msgid == -1 ) {
1415                                 tool_perror( "ldap_sasl_bind(SIMPLE)", rc,
1416                                         NULL, NULL, NULL, NULL );
1417                                 exit( rc );
1418                         }
1419                 }
1420
1421                 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 ) {
1422                         tool_perror( "ldap_result", -1, NULL, NULL, NULL, NULL );
1423                         exit( LDAP_LOCAL_ERROR );
1424                 }
1425
1426                 rc = ldap_parse_result( ld, result, &err, &matched, &info, &refs,
1427                         &ctrls, 1 );
1428                 if ( rc != LDAP_SUCCESS ) {
1429                         tool_perror( "ldap_bind parse result", rc, NULL, matched, info, refs );
1430                         exit( LDAP_LOCAL_ERROR );
1431                 }
1432
1433 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1434                 if ( ctrls && ppolicy ) {
1435                         LDAPControl *ctrl;
1436                         int expire, grace, len = 0;
1437                         LDAPPasswordPolicyError pErr = -1;
1438                         
1439                         ctrl = ldap_control_find( LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
1440                                 ctrls, NULL );
1441
1442                         if ( ctrl && ldap_parse_passwordpolicy_control( ld, ctrl,
1443                                 &expire, &grace, &pErr ) == LDAP_SUCCESS )
1444                         {
1445                                 if ( pErr != PP_noError ){
1446                                         msgbuf[0] = ';';
1447                                         msgbuf[1] = ' ';
1448                                         strcpy( msgbuf+2, ldap_passwordpolicy_err2txt( pErr ));
1449                                         len = strlen( msgbuf );
1450                                 }
1451                                 if ( expire >= 0 ) {
1452                                         sprintf( msgbuf+len,
1453                                                 " (Password expires in %d seconds)",
1454                                                 expire );
1455                                 } else if ( grace >= 0 ) {
1456                                         sprintf( msgbuf+len,
1457                                                 " (Password expired, %d grace logins remain)",
1458                                                 grace );
1459                                 }
1460                         }
1461                 }
1462 #endif
1463
1464                 if ( ctrls ) {
1465                         ldap_controls_free( ctrls );
1466                 }
1467
1468                 if ( err != LDAP_SUCCESS
1469                         || msgbuf[0]
1470                         || ( matched && matched[ 0 ] )
1471                         || ( info && info[ 0 ] )
1472                         || refs )
1473                 {
1474                         tool_perror( "ldap_bind", err, msgbuf, matched, info, refs );
1475
1476                         if( matched ) ber_memfree( matched );
1477                         if( info ) ber_memfree( info );
1478                         if( refs ) ber_memvfree( (void **)refs );
1479
1480                         if ( err != LDAP_SUCCESS ) exit( err );
1481                 }
1482         }
1483 }
1484
1485 void
1486 tool_unbind( LDAP *ld )
1487 {
1488         int err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, NULL );
1489
1490         if ( err != LDAP_OPT_SUCCESS ) {
1491                 fprintf( stderr, "Could not unset controls\n");
1492         }
1493
1494         (void) ldap_unbind_ext( ld, NULL, NULL );
1495 }
1496
1497
1498 /* Set server controls.  Add controls extra_c[0..count-1], if set. */
1499 void
1500 tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count )
1501 {
1502         int i = 0, j, crit = 0, err;
1503         LDAPControl c[16], **ctrls;
1504
1505         if ( ! ( assertctl
1506                 || authzid
1507 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
1508                 || proxydn
1509 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
1510                 || manageDIT
1511                 || manageDSAit
1512                 || noop
1513 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1514                 || ppolicy
1515 #endif
1516                 || preread
1517                 || postread
1518 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1519                 || chaining
1520 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1521 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1522                 || sessionTracking
1523 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
1524                 || count
1525                 || unknown_ctrls_num ) )
1526         {
1527                 return;
1528         }
1529
1530         ctrls = (LDAPControl**) malloc(sizeof(c) + (count + unknown_ctrls_num + 1)*sizeof(LDAPControl*));
1531         if ( ctrls == NULL ) {
1532                 fprintf( stderr, "No memory\n" );
1533                 exit( EXIT_FAILURE );
1534         }
1535
1536         if ( assertctl ) {
1537                 if ( BER_BVISNULL( &assertionvalue ) ) {
1538                         err = ldap_create_assertion_control_value( ld,
1539                                 assertion, &assertionvalue );
1540                         if ( err ) {
1541                                 fprintf( stderr,
1542                                         "Unable to create assertion value "
1543                                         "\"%s\" (%d)\n", assertion, err );
1544                         }
1545                 }
1546
1547                 c[i].ldctl_oid = LDAP_CONTROL_ASSERT;
1548                 c[i].ldctl_value = assertionvalue;
1549                 c[i].ldctl_iscritical = assertctl > 1;
1550                 ctrls[i] = &c[i];
1551                 i++;
1552         }
1553
1554         if ( authzid ) {
1555                 c[i].ldctl_value.bv_val = authzid;
1556                 c[i].ldctl_value.bv_len = strlen( authzid );
1557                 c[i].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
1558                 c[i].ldctl_iscritical = 1;
1559                 ctrls[i] = &c[i];
1560                 i++;
1561         }
1562
1563 #ifdef LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
1564         /* NOTE: doesn't need an extra count because it's incompatible
1565          * with authzid */
1566         if ( proxydn ) {
1567                 BerElementBuffer berbuf;
1568                 BerElement *ber = (BerElement *)&berbuf;
1569                 
1570                 ber_init2( ber, NULL, LBER_USE_DER );
1571
1572                 if ( ber_printf( ber, "s", proxydn ) == -1 ) {
1573                         exit( EXIT_FAILURE );
1574                 }
1575
1576                 if ( ber_flatten2( ber, &c[i].ldctl_value, 0 ) == -1 ) {
1577                         exit( EXIT_FAILURE );
1578                 }
1579
1580                 c[i].ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
1581                 c[i].ldctl_iscritical = 1;
1582                 ctrls[i] = &c[i];
1583                 i++;
1584         }
1585 #endif /* LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ */
1586
1587         if ( manageDIT ) {
1588                 c[i].ldctl_oid = LDAP_CONTROL_MANAGEDIT;
1589                 BER_BVZERO( &c[i].ldctl_value );
1590                 c[i].ldctl_iscritical = manageDIT > 1;
1591                 ctrls[i] = &c[i];
1592                 i++;
1593         }
1594
1595         if ( manageDSAit ) {
1596                 c[i].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
1597                 BER_BVZERO( &c[i].ldctl_value );
1598                 c[i].ldctl_iscritical = manageDSAit > 1;
1599                 ctrls[i] = &c[i];
1600                 i++;
1601         }
1602
1603         if ( noop ) {
1604                 c[i].ldctl_oid = LDAP_CONTROL_NOOP;
1605                 BER_BVZERO( &c[i].ldctl_value );
1606                 c[i].ldctl_iscritical = noop > 1;
1607                 ctrls[i] = &c[i];
1608                 i++;
1609         }
1610
1611 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
1612         if ( ppolicy ) {
1613                 c[i].ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
1614                 BER_BVZERO( &c[i].ldctl_value );
1615                 c[i].ldctl_iscritical = 0;
1616                 ctrls[i] = &c[i];
1617                 i++;
1618         }
1619 #endif
1620
1621         if ( preread ) {
1622                 BerElementBuffer berbuf;
1623                 BerElement *ber = (BerElement *)&berbuf;
1624                 char **attrs = NULL;
1625
1626                 if( preread_attrs ) {
1627                         attrs = ldap_str2charray( preread_attrs, "," );
1628                 }
1629
1630                 ber_init2( ber, NULL, LBER_USE_DER );
1631
1632                 if( ber_printf( ber, "{v}", attrs ) == -1 ) {
1633                         fprintf( stderr, "preread attrs encode failed.\n" );
1634                         exit( EXIT_FAILURE );
1635                 }
1636
1637                 err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
1638                 if( err < 0 ) {
1639                         fprintf( stderr, "preread flatten failed (%d)\n", err );
1640                         exit( EXIT_FAILURE );
1641                 }
1642
1643                 c[i].ldctl_oid = LDAP_CONTROL_PRE_READ;
1644                 c[i].ldctl_iscritical = preread > 1;
1645                 ctrls[i] = &c[i];
1646                 i++;
1647
1648                 if( attrs ) ldap_charray_free( attrs );
1649         }
1650
1651         if ( postread ) {
1652                 BerElementBuffer berbuf;
1653                 BerElement *ber = (BerElement *)&berbuf;
1654                 char **attrs = NULL;
1655
1656                 if( postread_attrs ) {
1657                         attrs = ldap_str2charray( postread_attrs, "," );
1658                 }
1659
1660                 ber_init2( ber, NULL, LBER_USE_DER );
1661
1662                 if( ber_printf( ber, "{v}", attrs ) == -1 ) {
1663                         fprintf( stderr, "postread attrs encode failed.\n" );
1664                         exit( EXIT_FAILURE );
1665                 }
1666
1667                 err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
1668                 if( err < 0 ) {
1669                         fprintf( stderr, "postread flatten failed (%d)\n", err );
1670                         exit( EXIT_FAILURE );
1671                 }
1672
1673                 c[i].ldctl_oid = LDAP_CONTROL_POST_READ;
1674                 c[i].ldctl_iscritical = postread > 1;
1675                 ctrls[i] = &c[i];
1676                 i++;
1677
1678                 if( attrs ) ldap_charray_free( attrs );
1679         }
1680
1681 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1682         if ( chaining ) {
1683                 if ( chainingResolve > -1 ) {
1684                         BerElementBuffer berbuf;
1685                         BerElement *ber = (BerElement *)&berbuf;
1686
1687                         ber_init2( ber, NULL, LBER_USE_DER );
1688
1689                         err = ber_printf( ber, "{e" /* } */, chainingResolve );
1690                         if ( err == -1 ) {
1691                                 ber_free( ber, 1 );
1692                                 fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1693                                 exit( EXIT_FAILURE );
1694                         }
1695
1696                         if ( chainingContinuation > -1 ) {
1697                                 err = ber_printf( ber, "e", chainingContinuation );
1698                                 if ( err == -1 ) {
1699                                         ber_free( ber, 1 );
1700                                         fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1701                                         exit( EXIT_FAILURE );
1702                                 }
1703                         }
1704
1705                         err = ber_printf( ber, /* { */ "N}" );
1706                         if ( err == -1 ) {
1707                                 ber_free( ber, 1 );
1708                                 fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1709                                 exit( EXIT_FAILURE );
1710                         }
1711
1712                         if ( ber_flatten2( ber, &c[i].ldctl_value, 0 ) == -1 ) {
1713                                 exit( EXIT_FAILURE );
1714                         }
1715
1716                 } else {
1717                         BER_BVZERO( &c[i].ldctl_value );
1718                 }
1719
1720                 c[i].ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1721                 c[i].ldctl_iscritical = chaining > 1;
1722                 ctrls[i] = &c[i];
1723                 i++;
1724         }
1725 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1726
1727 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1728         if ( sessionTracking ) {
1729                 if ( stValue.bv_val == NULL && st_value( ld, &stValue ) ) {
1730                         exit( EXIT_FAILURE );
1731                 }
1732
1733                 c[i].ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
1734                 c[i].ldctl_iscritical = 0;
1735                 ber_dupbv( &c[i].ldctl_value, &stValue );
1736
1737                 ctrls[i] = &c[i];
1738                 i++;
1739         }
1740 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
1741
1742         while ( count-- ) {
1743                 ctrls[i++] = extra_c++;
1744         }
1745         for ( count = 0; count < unknown_ctrls_num; count++ ) {
1746                 ctrls[i++] = &unknown_ctrls[count];
1747         }
1748         ctrls[i] = NULL;
1749
1750         err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
1751
1752         if ( err != LDAP_OPT_SUCCESS ) {
1753                 for ( j = 0; j < i; j++ ) {
1754                         if ( ctrls[j]->ldctl_iscritical ) crit = 1;
1755                 }
1756                 fprintf( stderr, "Could not set %scontrols\n",
1757                         crit ? "critical " : "" );
1758         }
1759
1760         free( ctrls );
1761         if ( crit ) {
1762                 exit( EXIT_FAILURE );
1763         }
1764 }
1765
1766 int
1767 tool_check_abandon( LDAP *ld, int msgid )
1768 {
1769         int     rc;
1770
1771         switch ( gotintr ) {
1772         case Intr_Cancel:
1773                 rc = ldap_cancel_s( ld, msgid, NULL, NULL );
1774                 fprintf( stderr, "got interrupt, cancel got %d: %s\n",
1775                                 rc, ldap_err2string( rc ) );
1776                 return -1;
1777
1778         case Intr_Abandon:
1779                 rc = ldap_abandon_ext( ld, msgid, NULL, NULL );
1780                 fprintf( stderr, "got interrupt, abandon got %d: %s\n",
1781                                 rc, ldap_err2string( rc ) );
1782                 return -1;
1783
1784         case Intr_Ignore:
1785                 /* just unbind, ignoring the request */
1786                 return -1;
1787         }
1788
1789         return 0;
1790 }
1791
1792 static int
1793 print_prepostread( LDAP *ld, LDAPControl *ctrl, struct berval *what)
1794 {
1795         BerElement      *ber;
1796         struct berval   bv;
1797
1798         tool_write_ldif( LDIF_PUT_COMMENT, "==> ",
1799                 what->bv_val, what->bv_len );
1800         ber = ber_init( &ctrl->ldctl_value );
1801         if ( ber == NULL ) {
1802                 /* error? */
1803                 return 1;
1804
1805         } else if ( ber_scanf( ber, "{m{" /*}}*/, &bv ) == LBER_ERROR ) {
1806                 /* error? */
1807                 return 1;
1808
1809         } else {
1810                 tool_write_ldif( LDIF_PUT_VALUE, "dn", bv.bv_val, bv.bv_len );
1811
1812                 while ( ber_scanf( ber, "{m" /*}*/, &bv ) != LBER_ERROR ) {
1813                         int             i;
1814                         BerVarray       vals = NULL;
1815
1816                         if ( ber_scanf( ber, "[W]", &vals ) == LBER_ERROR ||
1817                                 vals == NULL )
1818                         {
1819                                 /* error? */
1820                                 return 1;
1821                         }
1822                 
1823                         for ( i = 0; vals[ i ].bv_val != NULL; i++ ) {
1824                                 tool_write_ldif(
1825                                         ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1826                                         bv.bv_val, vals[ i ].bv_val, vals[ i ].bv_len );
1827                         }
1828
1829                         ber_bvarray_free( vals );
1830                 }
1831         }
1832
1833         if ( ber != NULL ) {
1834                 ber_free( ber, 1 );
1835         }
1836
1837         tool_write_ldif( LDIF_PUT_COMMENT, "<== ",
1838                 what->bv_val, what->bv_len );
1839
1840         return 0;
1841 }
1842
1843 static int
1844 print_preread( LDAP *ld, LDAPControl *ctrl )
1845 {
1846         static struct berval what = BER_BVC( "preread" );
1847
1848         return print_prepostread( ld, ctrl, &what );
1849 }
1850
1851 static int
1852 print_postread( LDAP *ld, LDAPControl *ctrl )
1853 {
1854         static struct berval what = BER_BVC( "postread" );
1855
1856         return print_prepostread( ld, ctrl, &what );
1857 }
1858
1859 static int
1860 print_paged_results( LDAP *ld, LDAPControl *ctrl )
1861 {
1862         ber_int_t estimate;
1863
1864         /* note: pr_cookie is being malloced; it's freed
1865          * the next time the control is sent, but the last
1866          * time it's not; we don't care too much, because
1867          * the last time an empty value is returned... */
1868         if ( ldap_parse_pageresponse_control( ld, ctrl, &estimate, &pr_cookie )
1869                 != LDAP_SUCCESS )
1870         {
1871                 /* error? */
1872                 return 1;
1873
1874         } else {
1875                 /* FIXME: check buffer overflow */
1876                 char    buf[ BUFSIZ ], *ptr = buf;
1877
1878                 if ( estimate > 0 ) {
1879                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
1880                                 "estimate=%d", estimate );
1881                 }
1882
1883                 if ( pr_cookie.bv_len > 0 ) {
1884                         struct berval   bv;
1885
1886                         bv.bv_len = LUTIL_BASE64_ENCODE_LEN(
1887                                 pr_cookie.bv_len ) + 1;
1888                         bv.bv_val = ber_memalloc( bv.bv_len + 1 );
1889
1890                         bv.bv_len = lutil_b64_ntop(
1891                                 (unsigned char *) pr_cookie.bv_val,
1892                                 pr_cookie.bv_len,
1893                                 bv.bv_val, bv.bv_len );
1894
1895                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
1896                                 "%scookie=%s", ptr == buf ? "" : " ",
1897                                 bv.bv_val );
1898
1899                         ber_memfree( bv.bv_val );
1900
1901                         pr_morePagedResults = 1;
1902
1903                 } else {
1904                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
1905                                 "%scookie=", ptr == buf ? "" : " " );
1906                 }
1907
1908                 tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1909                         "pagedresults", buf, ptr - buf );
1910         }
1911
1912         return 0;
1913 }
1914
1915 static int
1916 print_sss( LDAP *ld, LDAPControl *ctrl )
1917 {
1918         int rc;
1919         ber_int_t err;
1920         char *attr;
1921
1922         rc = ldap_parse_sortresponse_control( ld, ctrl, &err, &attr );
1923         if ( rc == LDAP_SUCCESS ) {
1924                 char buf[ BUFSIZ ];
1925                 rc = snprintf( buf, sizeof(buf), "(%d) %s%s%s",
1926                         err, ldap_err2string(err), attr ? " " : "", attr ? attr : "" );
1927
1928                 tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1929                         "sortResult", buf, rc );
1930         }
1931
1932         return rc;
1933 }
1934
1935 static int
1936 print_vlv( LDAP *ld, LDAPControl *ctrl )
1937 {
1938         int rc;
1939         ber_int_t err;
1940         struct berval bv;
1941
1942         rc = ldap_parse_vlvresponse_control( ld, ctrl, &vlvPos, &vlvCount,
1943                 &vlvContext, &err );
1944         if ( rc == LDAP_SUCCESS ) {
1945                 char buf[ BUFSIZ ];
1946
1947                 if ( vlvContext && vlvContext->bv_len > 0 ) {
1948                         bv.bv_len = LUTIL_BASE64_ENCODE_LEN(
1949                                 vlvContext->bv_len ) + 1;
1950                         bv.bv_val = ber_memalloc( bv.bv_len + 1 );
1951
1952                         bv.bv_len = lutil_b64_ntop(
1953                                 (unsigned char *) vlvContext->bv_val,
1954                                 vlvContext->bv_len,
1955                                 bv.bv_val, bv.bv_len );
1956                 } else {
1957                         bv.bv_val = "";
1958                         bv.bv_len = 0;
1959                 }
1960
1961                 rc = snprintf( buf, sizeof(buf), "pos=%d count=%d context=%s (%d) %s",
1962                         vlvPos, vlvCount, bv.bv_val,
1963                         err, ldap_err2string(err));
1964
1965                 if ( bv.bv_len )
1966                         ber_memfree( bv.bv_val );
1967
1968                 tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1969                         "vlvResult", buf, rc );
1970         }
1971
1972         return rc;
1973 }
1974
1975 #ifdef LDAP_CONTROL_X_DEREF
1976 static int
1977 print_deref( LDAP *ld, LDAPControl *ctrl )
1978 {
1979         LDAPDerefRes    *drhead = NULL, *dr;
1980         int             rc;
1981
1982         rc = ldap_parse_derefresponse_control( ld, ctrl, &drhead );
1983         if ( rc != LDAP_SUCCESS ) {
1984                 return rc;
1985         }
1986
1987         for ( dr = drhead; dr != NULL; dr = dr->next ) {
1988                 LDAPDerefVal    *dv;
1989                 ber_len_t       len;
1990                 char            *buf, *ptr;
1991
1992                 len = strlen( dr->derefAttr ) + STRLENOF(": ");
1993
1994                 for ( dv = dr->attrVals; dv != NULL; dv = dv->next ) {
1995                         if ( dv->vals != NULL ) {
1996                                 int j;
1997                                 ber_len_t tlen = strlen(dv->type);
1998
1999                                 for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
2000                                         len += STRLENOF("<:=>;") + tlen + 4*((dv->vals[ j ].bv_len - 1)/3 + 1);
2001                                 }
2002                         }
2003                 }
2004                 len += dr->derefVal.bv_len + STRLENOF("\n");
2005                 buf = ldap_memalloc( len + 1 );
2006                 if ( buf == NULL ) {
2007                         rc = LDAP_NO_MEMORY;
2008                         goto done;
2009                 }
2010
2011                 ptr = buf;
2012                 ptr = lutil_strcopy( ptr, dr->derefAttr );
2013                 *ptr++ = ':';
2014                 *ptr++ = ' ';
2015                 for ( dv = dr->attrVals; dv != NULL; dv = dv->next ) {
2016                         if ( dv->vals != NULL ) {
2017                                 int j;
2018                                 for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
2019                                         int k;
2020
2021                                         for ( k = 0; k < dv->vals[ j ].bv_len; k++ ) {
2022                                                 if ( !isprint( dv->vals[ j ].bv_val[k] ) ) {
2023                                                         k = -1;
2024                                                         break;
2025                                                 }
2026                                         }
2027
2028                                         *ptr++ = '<';
2029                                         ptr = lutil_strcopy( ptr, dv->type );
2030                                         if ( k == -1 ) {
2031                                                 *ptr++ = ':';
2032                                         }
2033                                         *ptr++ = '=';
2034                                         if ( k == -1 ) {
2035                                                 k = lutil_b64_ntop(
2036                                                         (unsigned char *) dv->vals[ j ].bv_val,
2037                                                         dv->vals[ j ].bv_len,
2038                                                         ptr, buf + len - ptr );
2039                                                 assert( k >= 0 );
2040                                                 ptr += k;
2041                                                 
2042                                         } else {
2043                                                 ptr = lutil_memcopy( ptr, dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
2044                                         }
2045                                         *ptr++ = '>';
2046                                         *ptr++ = ';';
2047                                 }
2048                         }
2049                 }
2050                 ptr = lutil_strncopy( ptr, dr->derefVal.bv_val, dr->derefVal.bv_len );
2051                 *ptr++ = '\n';
2052                 *ptr = '\0';
2053                 assert( ptr <= buf + len );
2054
2055                 tool_write_ldif( LDIF_PUT_COMMENT, NULL, buf, ptr - buf);
2056
2057                 ldap_memfree( buf );
2058         }
2059
2060         rc = LDAP_SUCCESS;
2061
2062 done:;
2063         ldap_derefresponse_free( drhead );
2064
2065         return rc;
2066 }
2067 #endif
2068
2069 #ifdef LDAP_CONTROL_X_WHATFAILED
2070 static int
2071 print_whatfailed( LDAP *ld, LDAPControl *ctrl )
2072 {
2073         BerElement *ber;
2074         ber_tag_t tag;
2075         ber_len_t siz;
2076         BerVarray bva = NULL;
2077
2078         /* Create a BerElement from the berval returned in the control. */
2079         ber = ber_init( &ctrl->ldctl_value );
2080
2081         if ( ber == NULL ) {
2082                 return LDAP_NO_MEMORY;
2083         }
2084
2085         siz = sizeof(struct berval);
2086         tag = ber_scanf( ber, "[M]", &bva, &siz, 0 );
2087         if ( tag != LBER_ERROR ) {
2088                 int i;
2089
2090                 tool_write_ldif( LDIF_PUT_COMMENT, " what failed:", NULL, 0 );
2091
2092                 for ( i = 0; bva[i].bv_val != NULL; i++ ) {
2093                         tool_write_ldif( LDIF_PUT_COMMENT, NULL, bva[i].bv_val, bva[i].bv_len );
2094                 }
2095
2096                 ldap_memfree( bva );
2097         }
2098
2099         ber_free( ber, 1 );
2100
2101
2102         return 0;
2103 }
2104 #endif
2105
2106 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
2107 static int
2108 print_ppolicy( LDAP *ld, LDAPControl *ctrl )
2109 {
2110         int expire = 0, grace = 0, rc;
2111         LDAPPasswordPolicyError pperr;
2112
2113         rc = ldap_parse_passwordpolicy_control( ld, ctrl,
2114                 &expire, &grace, &pperr );
2115         if ( rc == LDAP_SUCCESS ) {
2116                 char    buf[ BUFSIZ ], *ptr = buf;
2117
2118                 if ( expire != -1 ) {
2119                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2120                                 "expire=%d", expire );
2121                 }
2122
2123                 if ( grace != -1 ) {
2124                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2125                                 "%sgrace=%d", ptr == buf ? "" : " ", grace );
2126                 }
2127
2128                 if ( pperr != PP_noError ) {
2129                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
2130                                 "%serror=%d (%s)", ptr == buf ? "" : " ",
2131                                 pperr,
2132                                 ldap_passwordpolicy_err2txt( pperr ) );
2133                 }
2134
2135                 tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2136                         "ppolicy", buf, ptr - buf );
2137         }
2138
2139         return rc;
2140 }
2141 #endif
2142
2143 void tool_print_ctrls(
2144         LDAP            *ld,
2145         LDAPControl     **ctrls )
2146 {
2147         int     i;
2148         char    *ptr;
2149
2150         for ( i = 0; ctrls[i] != NULL; i++ ) {
2151                 /* control: OID criticality base64value */
2152                 struct berval b64 = BER_BVNULL;
2153                 ber_len_t len;
2154                 char *str;
2155                 int j;
2156
2157                 /* FIXME: there might be cases where a control has NULL OID;
2158                  * this makes little sense, especially when returned by the
2159                  * server, but libldap happily allows it */
2160                 if ( ctrls[i]->ldctl_oid == NULL ) {
2161                         continue;
2162                 }
2163
2164                 len = ldif ? 2 : 0;
2165                 len += strlen( ctrls[i]->ldctl_oid );
2166
2167                 /* add enough for space after OID and the critical value itself */
2168                 len += ctrls[i]->ldctl_iscritical
2169                         ? sizeof("true") : sizeof("false");
2170
2171                 /* convert to base64 */
2172                 if ( !BER_BVISNULL( &ctrls[i]->ldctl_value ) ) {
2173                         b64.bv_len = LUTIL_BASE64_ENCODE_LEN(
2174                                 ctrls[i]->ldctl_value.bv_len ) + 1;
2175                         b64.bv_val = ber_memalloc( b64.bv_len + 1 );
2176
2177                         b64.bv_len = lutil_b64_ntop(
2178                                 (unsigned char *) ctrls[i]->ldctl_value.bv_val,
2179                                 ctrls[i]->ldctl_value.bv_len,
2180                                 b64.bv_val, b64.bv_len );
2181                 }
2182
2183                 if ( b64.bv_len ) {
2184                         len += 1 + b64.bv_len;
2185                 }
2186
2187                 ptr = str = malloc( len + 1 );
2188                 if ( ldif ) {
2189                         ptr = lutil_strcopy( ptr, ": " );
2190                 }
2191                 ptr = lutil_strcopy( ptr, ctrls[i]->ldctl_oid );
2192                 ptr = lutil_strcopy( ptr, ctrls[i]->ldctl_iscritical
2193                         ? " true" : " false" );
2194
2195                 if ( b64.bv_len ) {
2196                         ptr = lutil_strcopy( ptr, " " );
2197                         ptr = lutil_strcopy( ptr, b64.bv_val );
2198                 }
2199
2200                 if ( ldif < 2 ) {
2201                         tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2202                                 "control", str, len );
2203                 }
2204
2205                 free( str );
2206                 if ( b64.bv_len ) {
2207                         ber_memfree( b64.bv_val );
2208                 }
2209
2210                 /* known controls */
2211                 for ( j = 0; tool_ctrl_response[j].oid != NULL; j++ ) {
2212                         if ( strcmp( tool_ctrl_response[j].oid, ctrls[i]->ldctl_oid ) == 0 ) {
2213                                 if ( !tool_ctrl_response[j].mask & tool_type ) {
2214                                         /* this control should not appear
2215                                          * with this tool; warning? */
2216                                 }
2217                                 break;
2218                         }
2219                 }
2220
2221                 if ( tool_ctrl_response[j].oid != NULL && tool_ctrl_response[j].func ) {
2222                         (void)tool_ctrl_response[j].func( ld, ctrls[i] );
2223                 }
2224         }
2225 }
2226
2227 int
2228 tool_write_ldif( int type, char *name, char *value, ber_len_t vallen )
2229 {
2230         char    *ldif;
2231
2232         if (( ldif = ldif_put( type, name, value, vallen )) == NULL ) {
2233                 return( -1 );
2234         }
2235
2236         fputs( ldif, stdout );
2237         ber_memfree( ldif );
2238
2239         return( 0 );
2240 }
2241
2242 int
2243 tool_is_oid( const char *s )
2244 {
2245         int             first = 1;
2246
2247         if ( !isdigit( (unsigned char) s[ 0 ] ) ) {
2248                 return 0;
2249         }
2250
2251         for ( ; s[ 0 ]; s++ ) {
2252                 if ( s[ 0 ] == '.' ) {
2253                         if ( s[ 1 ] == '\0' ) {
2254                                 return 0;
2255                         }
2256                         first = 1;
2257                         continue;
2258                 }
2259
2260                 if ( !isdigit( (unsigned char) s[ 0 ] ) ) {
2261                         return 0;
2262                 }
2263
2264                 if ( first == 1 && s[ 0 ] == '0' && s[ 1 ] != '.' ) {
2265                         return 0;
2266                 }
2267                 first = 0;
2268         }
2269
2270         return 1;
2271 }
2272