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