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