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