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