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