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