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