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