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