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