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