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