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