]> git.sur5r.net Git - openldap/blob - clients/tools/common.c
Sync with HEAD
[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-2005 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/unistd.h>
33 #include <ac/errno.h>
34
35 #include <ldap.h>
36
37 #include "lutil_ldap.h"
38 #include "ldap_defaults.h"
39 #include "ldap_pvt.h"
40 #include "lber_pvt.h"
41
42 #include "common.h"
43
44
45 int   authmethod = -1;
46 char *binddn = NULL;
47 int   contoper = 0;
48 int   debug = 0;
49 char *infile = NULL;
50 char *ldapuri = NULL;
51 char *ldaphost = NULL;
52 int   ldapport = 0;
53 #ifdef HAVE_CYRUS_SASL
54 unsigned sasl_flags = LDAP_SASL_AUTOMATIC;
55 char    *sasl_realm = NULL;
56 char    *sasl_authc_id = NULL;
57 char    *sasl_authz_id = NULL;
58 char    *sasl_mech = NULL;
59 char    *sasl_secprops = NULL;
60 #endif
61 int   use_tls = 0;
62
63 int       assertctl;
64 char *assertion = NULL;
65 char *authzid = NULL;
66 int   manageDSAit = 0;
67 int   noop = 0;
68 int   ppolicy = 0;
69 int   preread = 0;
70 char *preread_attrs = NULL;
71 int   postread = 0;
72 char *postread_attrs = NULL;
73
74 int   not = 0;
75 int   want_bindpw = 0;
76 struct berval passwd = { 0, NULL };
77 char *pw_file = NULL;
78 int   referrals = 0;
79 int   protocol = -1;
80 int   verbose = 0;
81 int   version = 0;
82
83 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
84 int chaining = 0;
85 static int chainingResolve = -1;
86 static int chainingContinuation = -1;
87 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
88
89 /* Set in main() */
90 char *prog = NULL;
91
92 void
93 tool_init( void )
94 {
95         ldap_pvt_setlocale(LC_MESSAGES, "");
96         ldap_pvt_bindtextdomain(OPENLDAP_PACKAGE, LDAP_LOCALEDIR);
97         ldap_pvt_textdomain(OPENLDAP_PACKAGE);
98 }
99
100 void
101 tool_common_usage( void )
102 {
103         static const char *const descriptions[] = {
104 N_("  -c         continuous operation mode (do not stop on errors)\n"),
105 N_("  -C         chase referrals (anonymously)\n"),
106 N_("  -d level   set LDAP debugging level to `level'\n"),
107 N_("  -D binddn  bind DN\n"),
108 N_("  -e [!]<ext>[=<extparam>] general extensions (! indicates criticality)\n")
109 N_("             [!]assert=<filter>     (an RFC 2254 Filter)\n")
110 N_("             [!]authzid=<authzid>   (\"dn:<dn>\" or \"u:<user>\")\n")
111 N_("             [!]manageDSAit\n")
112 N_("             [!]noop\n")
113 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
114 N_("             ppolicy\n")
115 #endif
116 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
117 N_("             [!]chaining[=<resolveBehavior>[/<continuationBehavior>]]\n")
118 N_("                     one of \"chainingPreferred\", \"chainingRequired\",\n")
119 N_("                     \"referralsPreferred\", \"referralsRequired\"\n")
120 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
121 N_("             [!]postread[=<attrs>]  (a comma-separated attribute list)\n")
122 N_("             [!]preread[=<attrs>]   (a comma-separated attribute list)\n"),
123 N_("  -f file    read operations from `file'\n"),
124 N_("  -h host    LDAP server\n"),
125 N_("  -H URI     LDAP Uniform Resource Indentifier(s)\n"),
126 N_("  -I         use SASL Interactive mode\n"),
127 N_("  -k         use Kerberos authentication\n"),
128 N_("  -K         like -k, but do only step 1 of the Kerberos bind\n"),
129 N_("  -M         enable Manage DSA IT control (-MM to make critical)\n"),
130 N_("  -n         show what would be done but don't actually do it\n"),
131 N_("  -O props   SASL security properties\n"),
132 N_("  -p port    port on LDAP server\n"),
133 N_("  -P version procotol version (default: 3)\n"),
134 N_("  -Q         use SASL Quiet mode\n"),
135 N_("  -R realm   SASL realm\n"),
136 N_("  -U authcid SASL authentication identity\n"),
137 N_("  -v         run in verbose mode (diagnostics to standard output)\n"),
138 N_("  -V         print version info (-VV only)\n"),
139 N_("  -w passwd  bind password (for simple authentication)\n"),
140 N_("  -W         prompt for bind password\n"),
141 N_("  -x         Simple authentication\n"),
142 N_("  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"),
143 N_("  -y file    Read password from file\n"),
144 N_("  -Y mech    SASL mechanism\n"),
145 N_("  -Z         Start TLS request (-ZZ to require successful response)\n"),
146 NULL
147         };
148         const char *const *cpp;
149
150         fputs( _("Common options:\n"), stderr );
151         for( cpp = descriptions; *cpp != NULL; cpp++ ) {
152                 if( strchr( options, (*cpp)[3] ) || (*cpp)[3] == ' ' ) {
153                         fputs( _(*cpp), stderr );
154                 }
155         }
156 }
157
158
159 void
160 tool_args( int argc, char **argv )
161 {
162         int i;
163
164         while (( i = getopt( argc, argv, options )) != EOF ) {
165                 int crit, ival;
166                 char *control, *cvalue, *next;
167                 switch( i ) {
168                 case 'c':       /* continuous operation mode */
169                         contoper++;
170                         break;
171                 case 'C':
172                         referrals++;
173                         break;
174                 case 'd':
175                         ival = strtol( optarg, &next, 10 );
176                         if (next == NULL || next[0] != '\0') {
177                                 fprintf( stderr, "%s: unable to parse debug value \"%s\"\n", prog, optarg);
178                                 exit(EXIT_FAILURE);
179                         }
180                         debug |= ival;
181                         break;
182                 case 'D':       /* bind DN */
183                         if( binddn != NULL ) {
184                                 fprintf( stderr, "%s: -D previously specified\n", prog );
185                                 exit( EXIT_FAILURE );
186                         }
187                         binddn = ber_strdup( optarg );
188                         break;
189                 case 'e': /* general extensions (controls and such) */
190                         /* should be extended to support comma separated list of
191                          *      [!]key[=value] parameters, e.g.  -e !foo,bar=567
192                          */
193
194                         crit = 0;
195                         cvalue = NULL;
196                         if( optarg[0] == '!' ) {
197                                 crit = 1;
198                                 optarg++;
199                         }
200
201                         control = ber_strdup( optarg );
202                         if ( (cvalue = strchr( control, '=' )) != NULL ) {
203                                 *cvalue++ = '\0';
204                         }
205
206                         if ( strcasecmp( control, "assert" ) == 0 ) {
207                                 if( assertctl ) {
208                                         fprintf( stderr, "assert control previously specified\n");
209                                         exit( EXIT_FAILURE );
210                                 }
211                                 if( cvalue == NULL ) {
212                                         fprintf( stderr, "assert: control value expected\n" );
213                                         usage();
214                                 }
215
216                                 assertctl = 1 + crit;
217
218                                 assert( assertion == NULL );
219                                 assertion = cvalue;
220
221                         } else if ( strcasecmp( control, "authzid" ) == 0 ) {
222                                 if( authzid != NULL ) {
223                                         fprintf( stderr, "authzid control previously specified\n");
224                                         exit( EXIT_FAILURE );
225                                 }
226                                 if( cvalue == NULL ) {
227                                         fprintf( stderr, "authzid: control value expected\n" );
228                                         usage();
229                                 }
230                                 if( !crit ) {
231                                         fprintf( stderr, "authzid: must be marked critical\n" );
232                                         usage();
233                                 }
234
235                                 assert( authzid == NULL );
236                                 authzid = cvalue;
237
238                         } else if ( strcasecmp( control, "manageDSAit" ) == 0 ) {
239                                 if( manageDSAit ) {
240                                         fprintf( stderr,
241                                                 "manageDSAit control previously specified\n");
242                                         exit( EXIT_FAILURE );
243                                 }
244                                 if( cvalue != NULL ) {
245                                         fprintf( stderr,
246                                                 "manageDSAit: no control value expected\n" );
247                                         usage();
248                                 }
249
250                                 manageDSAit = 1 + crit;
251
252                         } else if ( strcasecmp( control, "noop" ) == 0 ) {
253                                 if( noop ) {
254                                         fprintf( stderr, "noop control previously specified\n");
255                                         exit( EXIT_FAILURE );
256                                 }
257                                 if( cvalue != NULL ) {
258                                         fprintf( stderr, "noop: no control value expected\n" );
259                                         usage();
260                                 }
261
262                                 noop = 1 + crit;
263
264 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
265                         } else if ( strcasecmp( control, "ppolicy" ) == 0 ) {
266                                 if( ppolicy ) {
267                                         fprintf( stderr, "ppolicy control previously specified\n");
268                                         exit( EXIT_FAILURE );
269                                 }
270                                 if( cvalue != NULL ) {
271                                         fprintf( stderr, "ppolicy: no control value expected\n" );
272                                         usage();
273                                 }
274                                 if( crit ) {
275                                         fprintf( stderr, "ppolicy: critical flag not allowed\n" );
276                                         usage();
277                                 }
278
279                                 ppolicy = 1;
280 #endif
281
282                         } else if ( strcasecmp( control, "preread" ) == 0 ) {
283                                 if( preread ) {
284                                         fprintf( stderr, "preread control previously specified\n");
285                                         exit( EXIT_FAILURE );
286                                 }
287
288                                 preread = 1 + crit;
289                                 preread_attrs = cvalue;
290
291                         } else if ( strcasecmp( control, "postread" ) == 0 ) {
292                                 if( postread ) {
293                                         fprintf( stderr, "postread control previously specified\n");
294                                         exit( EXIT_FAILURE );
295                                 }
296
297                                 postread = 1 + crit;
298                                 postread_attrs = cvalue;
299
300 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
301                         } else if ( strcasecmp( control, "chaining" ) == 0 ) {
302                                 chaining = 1 + crit;
303
304                                 if ( cvalue != NULL ) {
305                                         char    *continuation;
306
307                                         continuation = strchr( cvalue, '/' );
308                                         if ( continuation ) {
309                                                 /* FIXME: this makes sense only in searches */
310                                                 *continuation++ = '\0';
311                                                 if ( strcasecmp( continuation, "chainingPreferred" ) == 0 ) {
312                                                         chainingContinuation = LDAP_CHAINING_PREFERRED;
313                                                 } else if ( strcasecmp( continuation, "chainingRequired" ) == 0 ) {
314                                                         chainingContinuation = LDAP_CHAINING_REQUIRED;
315                                                 } else if ( strcasecmp( continuation, "referralsPreferred" ) == 0 ) {
316                                                         chainingContinuation = LDAP_REFERRALS_PREFERRED;
317                                                 } else if ( strcasecmp( continuation, "referralsRequired" ) == 0 ) {
318                                                         chainingContinuation = LDAP_REFERRALS_REQUIRED;
319                                                 } else {
320                                                         fprintf( stderr,
321                                                                 "chaining behavior control "
322                                                                 "continuation value \"%s\" invalid\n",
323                                                                 continuation );
324                                                         exit( EXIT_FAILURE );
325                                                 }
326                                         }
327         
328                                         if ( strcasecmp( cvalue, "chainingPreferred" ) == 0 ) {
329                                                 chainingResolve = LDAP_CHAINING_PREFERRED;
330                                         } else if ( strcasecmp( cvalue, "chainingRequired" ) == 0 ) {
331                                                 chainingResolve = LDAP_CHAINING_REQUIRED;
332                                         } else if ( strcasecmp( cvalue, "referralsPreferred" ) == 0 ) {
333                                                 chainingResolve = LDAP_REFERRALS_PREFERRED;
334                                         } else if ( strcasecmp( cvalue, "referralsRequired" ) == 0 ) {
335                                                 chainingResolve = LDAP_REFERRALS_REQUIRED;
336                                         } else {
337                                                 fprintf( stderr,
338                                                         "chaining behavior control "
339                                                         "resolve value \"%s\" invalid\n",
340                                                         cvalue);
341                                                 exit( EXIT_FAILURE );
342                                         }
343                                 }
344 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
345
346                         } else {
347                                 fprintf( stderr, "Invalid general control name: %s\n",
348                                         control );
349                                 usage();
350                         }
351                         break;
352                 case 'f':       /* read from file */
353                         if( infile != NULL ) {
354                                 fprintf( stderr, "%s: -f previously specified\n", prog );
355                                 exit( EXIT_FAILURE );
356                         }
357                         infile = ber_strdup( optarg );
358                         break;
359                 case 'h':       /* ldap host */
360                         if( ldaphost != NULL ) {
361                                 fprintf( stderr, "%s: -h previously specified\n", prog );
362                                 exit( EXIT_FAILURE );
363                         }
364                         ldaphost = ber_strdup( optarg );
365                         break;
366                 case 'H':       /* ldap URI */
367                         if( ldapuri != NULL ) {
368                                 fprintf( stderr, "%s: -H previously specified\n", prog );
369                                 exit( EXIT_FAILURE );
370                         }
371                         ldapuri = ber_strdup( optarg );
372                         break;
373                 case 'I':
374 #ifdef HAVE_CYRUS_SASL
375                         if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
376                                 fprintf( stderr, "%s: incompatible previous "
377                                         "authentication choice\n",
378                                         prog );
379                                 exit( EXIT_FAILURE );
380                         }
381                         authmethod = LDAP_AUTH_SASL;
382                         sasl_flags = LDAP_SASL_INTERACTIVE;
383                         break;
384 #else
385                         fprintf( stderr, "%s: was not compiled with SASL support\n",
386                                 prog );
387                         exit( EXIT_FAILURE );
388 #endif
389                 case 'k':       /* kerberos bind */
390 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
391                         if( authmethod != -1 ) {
392                                 fprintf( stderr, "%s: -k incompatible with previous "
393                                         "authentication choice\n", prog );
394                                 exit( EXIT_FAILURE );
395                         }
396                         authmethod = LDAP_AUTH_KRBV4;
397 #else
398                         fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
399                         exit( EXIT_FAILURE );
400 #endif
401                         break;
402                 case 'K':       /* kerberos bind, part one only */
403 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
404                         if( authmethod != -1 ) {
405                                 fprintf( stderr, "%s: incompatible with previous "
406                                         "authentication choice\n", prog );
407                                 exit( EXIT_FAILURE );
408                         }
409                         authmethod = LDAP_AUTH_KRBV41;
410 #else
411                         fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
412                         exit( EXIT_FAILURE );
413 #endif
414                         break;
415                 case 'M':
416                         /* enable Manage DSA IT */
417                         manageDSAit++;
418                         break;
419                 case 'n':       /* print operations, don't actually do them */
420                         not++;
421                         break;
422                 case 'O':
423 #ifdef HAVE_CYRUS_SASL
424                         if( sasl_secprops != NULL ) {
425                                 fprintf( stderr, "%s: -O previously specified\n", prog );
426                                 exit( EXIT_FAILURE );
427                         }
428                         if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
429                                 fprintf( stderr, "%s: incompatible previous "
430                                         "authentication choice\n", prog );
431                                 exit( EXIT_FAILURE );
432                         }
433                         authmethod = LDAP_AUTH_SASL;
434                         sasl_secprops = ber_strdup( optarg );
435 #else
436                         fprintf( stderr, "%s: not compiled with SASL support\n", prog );
437                         exit( EXIT_FAILURE );
438 #endif
439                         break;
440                 case 'p':
441                         if( ldapport ) {
442                                 fprintf( stderr, "%s: -p previously specified\n", prog );
443                                 exit( EXIT_FAILURE );
444                         }
445                         ival = strtol( optarg, &next, 10 );
446                         if ( next == NULL || next[0] != '\0' ) {
447                                 fprintf( stderr, "%s: unable to parse port number \"%s\"\n", prog, optarg );
448                                 exit( EXIT_FAILURE );
449                         }
450                         ldapport = ival;
451                         break;
452                 case 'P':
453                         ival = strtol( optarg, &next, 10 );
454                         if ( next == NULL || next[0] != '\0' ) {
455                                 fprintf( stderr, "%s: unabel to parse protocol version \"%s\"\n", prog, optarg );
456                                 exit( EXIT_FAILURE );
457                         }
458                         switch( ival ) {
459                         case 2:
460                                 if( protocol == LDAP_VERSION3 ) {
461                                         fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
462                                                 prog, protocol );
463                                         exit( EXIT_FAILURE );
464                                 }
465                                 protocol = LDAP_VERSION2;
466                                 break;
467                         case 3:
468                                 if( protocol == LDAP_VERSION2 ) {
469                                         fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
470                                                 prog, protocol );
471                                         exit( EXIT_FAILURE );
472                                 }
473                                 protocol = LDAP_VERSION3;
474                                 break;
475                         default:
476                                 fprintf( stderr, "%s: protocol version should be 2 or 3\n",
477                                         prog );
478                                 usage();
479                         }
480                         break;
481                 case 'Q':
482 #ifdef HAVE_CYRUS_SASL
483                         if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
484                                 fprintf( stderr, "%s: incompatible previous "
485                                         "authentication choice\n",
486                                         prog );
487                                 exit( EXIT_FAILURE );
488                         }
489                         authmethod = LDAP_AUTH_SASL;
490                         sasl_flags = LDAP_SASL_QUIET;
491                         break;
492 #else
493                         fprintf( stderr, "%s: not compiled with SASL support\n",
494                                 prog );
495                         exit( EXIT_FAILURE );
496 #endif
497                 case 'R':
498 #ifdef HAVE_CYRUS_SASL
499                         if( sasl_realm != NULL ) {
500                                 fprintf( stderr, "%s: -R previously specified\n", prog );
501                                 exit( EXIT_FAILURE );
502                         }
503                         if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
504                                 fprintf( stderr, "%s: incompatible previous "
505                                         "authentication choice\n",
506                                         prog );
507                                 exit( EXIT_FAILURE );
508                         }
509                         authmethod = LDAP_AUTH_SASL;
510                         sasl_realm = ber_strdup( optarg );
511 #else
512                         fprintf( stderr, "%s: not compiled with SASL support\n",
513                                 prog );
514                         exit( EXIT_FAILURE );
515 #endif
516                         break;
517                 case 'U':
518 #ifdef HAVE_CYRUS_SASL
519                         if( sasl_authc_id != NULL ) {
520                                 fprintf( stderr, "%s: -U previously specified\n", prog );
521                                 exit( EXIT_FAILURE );
522                         }
523                         if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
524                                 fprintf( stderr, "%s: incompatible previous "
525                                         "authentication choice\n",
526                                         prog );
527                                 exit( EXIT_FAILURE );
528                         }
529                         authmethod = LDAP_AUTH_SASL;
530                         sasl_authc_id = ber_strdup( optarg );
531 #else
532                         fprintf( stderr, "%s: not compiled with SASL support\n",
533                                 prog );
534                         exit( EXIT_FAILURE );
535 #endif
536                         break;
537                 case 'v':       /* verbose mode */
538                         verbose++;
539                         break;
540                 case 'V':       /* version */
541                         version++;
542                         break;
543                 case 'w':       /* password */
544                         passwd.bv_val = ber_strdup( optarg );
545                         {
546                                 char* p;
547
548                                 for( p = optarg; *p != '\0'; p++ ) {
549                                         *p = '\0';
550                                 }
551                         }
552                         passwd.bv_len = strlen( passwd.bv_val );
553                         break;
554                 case 'W':
555                         want_bindpw++;
556                         break;
557                 case 'y':
558                         pw_file = optarg;
559                         break;
560                 case 'Y':
561 #ifdef HAVE_CYRUS_SASL
562                         if( sasl_mech != NULL ) {
563                                 fprintf( stderr, "%s: -Y previously specified\n", prog );
564                                 exit( EXIT_FAILURE );
565                         }
566                         if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
567                                 fprintf( stderr,
568                                         "%s: incompatible with authentication choice\n", prog );
569                                 exit( EXIT_FAILURE );
570                         }
571                         authmethod = LDAP_AUTH_SASL;
572                         sasl_mech = ber_strdup( optarg );
573 #else
574                         fprintf( stderr, "%s: not compiled with SASL support\n", prog );
575                         exit( EXIT_FAILURE );
576 #endif
577                         break;
578                 case 'x':
579                         if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
580                                 fprintf( stderr, "%s: incompatible with previous "
581                                         "authentication choice\n", prog );
582                                 exit( EXIT_FAILURE );
583                         }
584                         authmethod = LDAP_AUTH_SIMPLE;
585                         break;
586                 case 'X':
587 #ifdef HAVE_CYRUS_SASL
588                         if( sasl_authz_id != NULL ) {
589                                 fprintf( stderr, "%s: -X previously specified\n", prog );
590                                 exit( EXIT_FAILURE );
591                         }
592                         if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
593                                 fprintf( stderr, "%s: -X incompatible with "
594                                         "authentication choice\n", prog );
595                                 exit( EXIT_FAILURE );
596                         }
597                         authmethod = LDAP_AUTH_SASL;
598                         sasl_authz_id = ber_strdup( optarg );
599 #else
600                         fprintf( stderr, "%s: not compiled with SASL support\n", prog );
601                         exit( EXIT_FAILURE );
602 #endif
603                         break;
604                 case 'Z':
605 #ifdef HAVE_TLS
606                         use_tls++;
607 #else
608                         fprintf( stderr, "%s: not compiled with TLS support\n", prog );
609                         exit( EXIT_FAILURE );
610 #endif
611                         break;
612                 default:
613                         if( handle_private_option( i ) ) break;
614                         fprintf( stderr, "%s: unrecognized option -%c\n",
615                                 prog, optopt );
616                         usage();
617                 }
618         }
619
620         {
621                 /* prevent bad linking */
622                 LDAPAPIInfo api;
623                 api.ldapai_info_version = LDAP_API_INFO_VERSION;
624
625                 if ( ldap_get_option(NULL, LDAP_OPT_API_INFO, &api)
626                         != LDAP_OPT_SUCCESS )
627                 {
628                         fprintf( stderr, "%s: ldap_get_option(API_INFO) failed\n", prog );
629                         exit( EXIT_FAILURE );
630                 }
631
632                 if (api.ldapai_info_version != LDAP_API_INFO_VERSION) {
633                         fprintf( stderr, "LDAP APIInfo version mismatch: "
634                                 "got %d, expected %d\n",
635                                 api.ldapai_info_version, LDAP_API_INFO_VERSION );
636                         exit( EXIT_FAILURE );
637                 }
638
639                 if( api.ldapai_api_version != LDAP_API_VERSION ) {
640                         fprintf( stderr, "LDAP API version mismatch: "
641                                 "got %d, expected %d\n",
642                                 api.ldapai_api_version, LDAP_API_VERSION );
643                         exit( EXIT_FAILURE );
644                 }
645
646                 if( strcmp(api.ldapai_vendor_name, LDAP_VENDOR_NAME ) != 0 ) {
647                         fprintf( stderr, "LDAP vendor name mismatch: "
648                                 "got %s, expected %s\n",
649                                 api.ldapai_vendor_name, LDAP_VENDOR_NAME );
650                         exit( EXIT_FAILURE );
651                 }
652
653                 if( api.ldapai_vendor_version != LDAP_VENDOR_VERSION ) {
654                         fprintf( stderr, "LDAP vendor version mismatch: "
655                                 "got %d, expected %d\n",
656                                 api.ldapai_vendor_version, LDAP_VENDOR_VERSION );
657                         exit( EXIT_FAILURE );
658                 }
659
660                 if (version) {
661                         fprintf( stderr, "%s: %s\t(LDAP library: %s %d)\n",
662                                 prog, __Version,
663                                 LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION );
664                         if (version > 1) exit( EXIT_SUCCESS );
665                 }
666         }
667
668         if (protocol == -1)
669                 protocol = LDAP_VERSION3;
670
671         if (authmethod == -1 && protocol > LDAP_VERSION2) {
672 #ifdef HAVE_CYRUS_SASL
673                 authmethod = LDAP_AUTH_SASL;
674 #else
675                 authmethod = LDAP_AUTH_SIMPLE;
676 #endif
677         }
678
679         if( ldapuri == NULL ) {
680                 if( ldapport && ( ldaphost == NULL )) {
681                         fprintf( stderr, "%s: -p without -h is invalid.\n", prog );
682                         exit( EXIT_FAILURE );
683                 }
684         } else {
685                 if( ldaphost != NULL ) {
686                         fprintf( stderr, "%s: -H incompatible with -h\n", prog );
687                         exit( EXIT_FAILURE );
688                 }
689                 if( ldapport ) {
690                         fprintf( stderr, "%s: -H incompatible with -p\n", prog );
691                         exit( EXIT_FAILURE );
692                 }
693         }
694         if( protocol == LDAP_VERSION2 ) {
695                 if( authzid || manageDSAit || noop || ppolicy ) {
696                         fprintf( stderr, "%s: -e/-M incompatible with LDAPv2\n", prog );
697                         exit( EXIT_FAILURE );
698                 }
699 #ifdef HAVE_TLS
700                 if( use_tls ) {
701                         fprintf( stderr, "%s: -Z incompatible with LDAPv2\n", prog );
702                         exit( EXIT_FAILURE );
703                 }
704 #endif
705 #ifdef HAVE_CYRUS_SASL
706                 if( authmethod == LDAP_AUTH_SASL ) {
707                         fprintf( stderr, "%s: -[IOQRUXY] incompatible with LDAPv2\n",
708                                 prog );
709                         exit( EXIT_FAILURE );
710                 }
711 #endif
712         } else {
713 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
714                 if ( authmethod == LDAP_AUTH_KRBV4 || authmethod == LDAP_AUTH_KRBV41 ) {
715                         fprintf( stderr, "%s: -k/-K incompatible with LDAPv%d\n",
716                                 prog, protocol );
717                         exit( EXIT_FAILURE );
718                 }
719 #endif
720         }
721 }
722
723
724 LDAP *
725 tool_conn_setup( int not, void (*private_setup)( LDAP * ) )
726 {
727         LDAP *ld = NULL;
728
729         if ( debug ) {
730                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug )
731                         != LBER_OPT_SUCCESS )
732                 {
733                         fprintf( stderr,
734                                 "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
735                 }
736                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug )
737                         != LDAP_OPT_SUCCESS )
738                 {
739                         fprintf( stderr,
740                                 "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
741                 }
742         }
743
744 #ifdef SIGPIPE
745         (void) SIGNAL( SIGPIPE, SIG_IGN );
746 #endif
747
748         if ( !not ) {
749                 int rc;
750
751                 if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
752                         /* construct URL */
753                         LDAPURLDesc url;
754                         memset( &url, 0, sizeof(url));
755
756                         url.lud_scheme = "ldap";
757                         url.lud_host = ldaphost;
758                         url.lud_port = ldapport;
759                         url.lud_scope = LDAP_SCOPE_DEFAULT;
760
761                         ldapuri = ldap_url_desc2str( &url );
762                 }
763
764                 if ( verbose ) {
765                         fprintf( stderr, "ldap_initialize( %s )\n",
766                                 ldapuri != NULL ? ldapuri : "<DEFAULT>" );
767                 }
768                 rc = ldap_initialize( &ld, ldapuri );
769                 if( rc != LDAP_SUCCESS ) {
770                         fprintf( stderr,
771                                 "Could not create LDAP session handle for URI=%s (%d): %s\n",
772                                 ldapuri, rc, ldap_err2string(rc) );
773                         exit( EXIT_FAILURE );
774                 }
775
776                 if( private_setup ) private_setup( ld );
777
778                 /* referrals */
779                 if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
780                         referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
781                 {
782                         fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
783                                 referrals ? "on" : "off" );
784                         exit( EXIT_FAILURE );
785                 }
786
787                 if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &protocol )
788                         != LDAP_OPT_SUCCESS )
789                 {
790                         fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
791                                 protocol );
792                         exit( EXIT_FAILURE );
793                 }
794
795                 if ( use_tls &&
796                         ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ))
797                 {
798                         ldap_perror( ld, "ldap_start_tls" );
799                         if ( use_tls > 1 ) {
800                                 exit( EXIT_FAILURE );
801                         }
802                 }
803         }
804
805         return ld;
806 }
807
808
809 void
810 tool_bind( LDAP *ld )
811 {
812 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
813         if ( ppolicy ) {
814                 LDAPControl *ctrls[2], c;
815                 c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
816                 c.ldctl_value.bv_val = NULL;
817                 c.ldctl_value.bv_len = 0;
818                 c.ldctl_iscritical = 0;
819                 ctrls[0] = &c;
820                 ctrls[1] = NULL;
821                 ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
822         }
823 #endif
824
825         if ( authmethod == LDAP_AUTH_SASL ) {
826 #ifdef HAVE_CYRUS_SASL
827                 void *defaults;
828                 int rc;
829
830                 if( sasl_secprops != NULL ) {
831                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
832                                 (void *) sasl_secprops );
833
834                         if( rc != LDAP_OPT_SUCCESS ) {
835                                 fprintf( stderr,
836                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
837                                         sasl_secprops );
838                                 exit( EXIT_FAILURE );
839                         }
840                 }
841
842                 defaults = lutil_sasl_defaults( ld,
843                         sasl_mech,
844                         sasl_realm,
845                         sasl_authc_id,
846                         passwd.bv_val,
847                         sasl_authz_id );
848
849                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
850                         sasl_mech, NULL, NULL,
851                         sasl_flags, lutil_sasl_interact, defaults );
852
853                 lutil_sasl_freedefs( defaults );
854                 if( rc != LDAP_SUCCESS ) {
855                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
856                         exit( EXIT_FAILURE );
857                 }
858 #else
859                 fprintf( stderr, "%s: not compiled with SASL support\n",
860                         prog );
861                 exit( EXIT_FAILURE );
862 #endif
863         } else {
864                 int msgid, err;
865                 LDAPMessage *result;
866                 LDAPControl **ctrls;
867                 char msgbuf[256];
868
869                 msgbuf[0] = 0;
870
871                 if (( msgid = ldap_bind( ld, binddn, passwd.bv_val, authmethod )) == -1 )
872                 {
873                         ldap_perror( ld, "ldap_bind" );
874                         exit( EXIT_FAILURE );
875                 }
876
877                 if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) {
878                         ldap_perror( ld, "ldap_result" );
879                         exit( EXIT_FAILURE );
880                 }
881
882                 if ( ldap_parse_result( ld, result, &err, NULL, NULL, NULL,
883                         &ctrls, 1 ) != LDAP_SUCCESS ) {
884                         ldap_perror( ld, "ldap_bind parse result" );
885                         exit( EXIT_FAILURE );
886                 }
887
888 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
889                 if ( ctrls && ppolicy ) {
890                         LDAPControl *ctrl;
891                         int expire, grace, len = 0;
892                         LDAPPasswordPolicyError pErr = -1;
893                         
894                         ctrl = ldap_find_control( LDAP_CONTROL_PASSWORDPOLICYRESPONSE, ctrls );
895                         if ( ctrl && ldap_parse_passwordpolicy_control( ld, ctrl,
896                                 &expire, &grace, &pErr ) == LDAP_SUCCESS ) {
897                                 if ( pErr != PP_noError ){
898                                         msgbuf[0] = ';';
899                                         msgbuf[1] = ' ';
900                                         strcpy( msgbuf+2, ldap_passwordpolicy_err2txt( pErr ));
901                                         len = strlen( msgbuf );
902                                 }
903                                 if ( expire >= 0 ) {
904                                         sprintf( msgbuf+len, " (Password expires in %d seconds)", expire );
905                                 } else if ( grace >= 0 ) {
906                                         sprintf( msgbuf+len, " (Password expired, %d grace logins remain)", grace );
907                                 }
908                         }
909                 }
910 #endif
911                 if ( err != LDAP_SUCCESS || msgbuf[0] ) {
912                         fprintf( stderr, "ldap_bind: %s%s\n", ldap_err2string( err ),
913                                 msgbuf );
914                         if ( err != LDAP_SUCCESS ) {
915                                 exit( EXIT_FAILURE );
916                         }
917                 }
918         }
919 }
920
921
922 /* Set server controls.  Add controls extra_c[0..count-1], if set. */
923 void
924 tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count )
925 {
926         int i = 0, j, crit = 0, err;
927         LDAPControl c[9], **ctrls;
928
929         ctrls = (LDAPControl**) malloc(sizeof(c) + (count+1)*sizeof(LDAPControl*));
930         if ( ctrls == NULL ) {
931                 fprintf( stderr, "No memory\n" );
932                 exit( EXIT_FAILURE );
933         }
934
935         if ( assertctl ) {
936                 BerElementBuffer berbuf;
937                 BerElement *ber = (BerElement *)&berbuf;
938                 
939                 if( assertion == NULL || *assertion == '\0' ) {
940                         fprintf( stderr, "Assertion=<empty>\n" );
941                         exit( EXIT_FAILURE );
942                 }
943
944                 ber_init2( ber, NULL, LBER_USE_DER );
945
946                 err = ldap_pvt_put_filter( ber, assertion );
947                 if( err < 0 ) {
948                         fprintf( stderr, "assertion encode failed (%d)\n", err );
949                         exit( EXIT_FAILURE );
950                 }
951
952                 err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
953                 if( err < 0 ) {
954                         fprintf( stderr, "assertion flatten failed (%d)\n", err );
955                         exit( EXIT_FAILURE );
956                 }
957
958                 c[i].ldctl_oid = LDAP_CONTROL_ASSERT;
959                 c[i].ldctl_iscritical = assertctl > 1;
960                 ctrls[i] = &c[i];
961                 i++;
962         }
963
964         if ( authzid ) {
965                 c[i].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
966                 c[i].ldctl_value.bv_val = authzid;
967                 c[i].ldctl_value.bv_len = strlen( authzid );
968                 c[i].ldctl_iscritical = 1;
969                 ctrls[i] = &c[i];
970                 i++;
971         }
972
973         if ( manageDSAit ) {
974                 c[i].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
975                 BER_BVZERO( &c[i].ldctl_value );
976                 c[i].ldctl_iscritical = manageDSAit > 1;
977                 ctrls[i] = &c[i];
978                 i++;
979         }
980
981         if ( noop ) {
982                 c[i].ldctl_oid = LDAP_CONTROL_NOOP;
983                 BER_BVZERO( &c[i].ldctl_value );
984                 c[i].ldctl_iscritical = noop > 1;
985                 ctrls[i] = &c[i];
986                 i++;
987         }
988
989         if ( preread ) {
990                 char berbuf[LBER_ELEMENT_SIZEOF];
991                 BerElement *ber = (BerElement *)berbuf;
992                 char **attrs = NULL;
993
994                 if( preread_attrs ) {
995                         attrs = ldap_str2charray( preread_attrs, "," );
996                 }
997
998                 ber_init2( ber, NULL, LBER_USE_DER );
999
1000                 if( ber_printf( ber, "{v}", attrs ) == -1 ) {
1001                         fprintf( stderr, "preread attrs encode failed.\n" );
1002                         exit( EXIT_FAILURE );
1003                 }
1004
1005                 err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
1006                 if( err < 0 ) {
1007                         fprintf( stderr, "preread flatten failed (%d)\n", err );
1008                         exit( EXIT_FAILURE );
1009                 }
1010
1011                 c[i].ldctl_oid = LDAP_CONTROL_PRE_READ;
1012                 c[i].ldctl_iscritical = preread > 1;
1013                 ctrls[i] = &c[i];
1014                 i++;
1015
1016                 if( attrs ) ldap_charray_free( attrs );
1017         }
1018
1019         if ( postread ) {
1020                 char berbuf[LBER_ELEMENT_SIZEOF];
1021                 BerElement *ber = (BerElement *)berbuf;
1022                 char **attrs = NULL;
1023
1024                 if( postread_attrs ) {
1025                         attrs = ldap_str2charray( postread_attrs, "," );
1026                 }
1027
1028                 ber_init2( ber, NULL, LBER_USE_DER );
1029
1030                 if( ber_printf( ber, "{v}", attrs ) == -1 ) {
1031                         fprintf( stderr, "postread attrs encode failed.\n" );
1032                         exit( EXIT_FAILURE );
1033                 }
1034
1035                 err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
1036                 if( err < 0 ) {
1037                         fprintf( stderr, "postread flatten failed (%d)\n", err );
1038                         exit( EXIT_FAILURE );
1039                 }
1040
1041                 c[i].ldctl_oid = LDAP_CONTROL_POST_READ;
1042                 c[i].ldctl_iscritical = postread > 1;
1043                 ctrls[i] = &c[i];
1044                 i++;
1045
1046                 if( attrs ) ldap_charray_free( attrs );
1047         }
1048
1049 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1050         if ( chaining ) {
1051                 if ( chainingResolve > -1 ) {
1052                         BerElementBuffer berbuf;
1053                         BerElement *ber = (BerElement *)&berbuf;
1054
1055                         ber_init2( ber, NULL, LBER_USE_DER );
1056
1057                         err = ber_printf( ber, "{e" /* } */, chainingResolve );
1058                         if ( err == -1 ) {
1059                                 ber_free( ber, 1 );
1060                                 fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1061                                 exit( EXIT_FAILURE );
1062                         }
1063
1064                         if ( chainingContinuation > -1 ) {
1065                                 err = ber_printf( ber, "e", chainingContinuation );
1066                                 if ( err == -1 ) {
1067                                         ber_free( ber, 1 );
1068                                         fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1069                                         exit( EXIT_FAILURE );
1070                                 }
1071                         }
1072
1073                         err = ber_printf( ber, /* { */ "N}" );
1074                         if ( err == -1 ) {
1075                                 ber_free( ber, 1 );
1076                                 fprintf( stderr, _("Chaining behavior control encoding error!\n") );
1077                                 exit( EXIT_FAILURE );
1078                         }
1079
1080                         if ( ber_flatten2( ber, &c[i].ldctl_value, 0 ) == -1 ) {
1081                                 exit( EXIT_FAILURE );
1082                         }
1083
1084                 } else {
1085                         BER_BVZERO( &c[i].ldctl_value );
1086                 }
1087
1088                 c[i].ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1089                 c[i].ldctl_iscritical = chaining > 1;
1090                 ctrls[i] = &c[i];
1091                 i++;
1092         }
1093 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1094
1095         while ( count-- ) {
1096                 ctrls[i++] = extra_c++;
1097         }
1098         ctrls[i] = NULL;
1099
1100         err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
1101
1102         if ( err != LDAP_OPT_SUCCESS ) {
1103                 for ( j = 0; j < i; j++ ) {
1104                         if ( ctrls[j]->ldctl_iscritical ) crit = 1;
1105                 }
1106                 fprintf( stderr, "Could not set %scontrols\n",
1107                         crit ? "critical " : "" );
1108         }
1109
1110         free( ctrls );
1111         if ( crit ) {
1112                 exit( EXIT_FAILURE );
1113         }
1114 }