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