]> git.sur5r.net Git - openldap/blob - clients/tools/common.c
21a818106107f17705d236ec1007764f2d2bd68c
[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,
677                                 "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
678                 }
679                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug )
680                         != LDAP_OPT_SUCCESS )
681                 {
682                         fprintf( stderr,
683                                 "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
684                 }
685         }
686
687 #ifdef SIGPIPE
688         (void) SIGNAL( SIGPIPE, SIG_IGN );
689 #endif
690
691         if ( !not ) {
692                 int rc;
693
694                 if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
695                         /* construct URL */
696                         LDAPURLDesc url;
697                         memset( &url, 0, sizeof(url));
698
699                         url.lud_scheme = "ldap";
700                         url.lud_host = ldaphost;
701                         url.lud_port = ldapport;
702                         url.lud_scope = LDAP_SCOPE_DEFAULT;
703
704                         ldapuri = ldap_url_desc2str( &url );
705                 }
706
707                 if ( verbose ) {
708                         fprintf( stderr, "ldap_initialize( %s )\n",
709                                 ldapuri != NULL ? ldapuri : "<DEFAULT>" );
710                 }
711                 rc = ldap_initialize( &ld, ldapuri );
712                 if( rc != LDAP_SUCCESS ) {
713                         fprintf( stderr,
714                                 "Could not create LDAP session handle for URI=%s (%d): %s\n",
715                                 ldapuri, rc, ldap_err2string(rc) );
716                         exit( EXIT_FAILURE );
717                 }
718
719                 if( private_setup ) private_setup( ld );
720
721                 /* referrals */
722                 if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
723                         referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
724                 {
725                         fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
726                                 referrals ? "on" : "off" );
727                         exit( EXIT_FAILURE );
728                 }
729
730                 if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &protocol )
731                         != LDAP_OPT_SUCCESS )
732                 {
733                         fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
734                                 protocol );
735                         exit( EXIT_FAILURE );
736                 }
737
738                 if ( use_tls &&
739                         ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ))
740                 {
741                         ldap_perror( ld, "ldap_start_tls" );
742                         if ( use_tls > 1 ) {
743                                 exit( EXIT_FAILURE );
744                         }
745                 }
746         }
747
748         return ld;
749 }
750
751
752 void
753 tool_bind( LDAP *ld )
754 {
755 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
756         if ( ppolicy ) {
757                 LDAPControl *ctrls[2], c;
758                 c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
759                 c.ldctl_value.bv_val = NULL;
760                 c.ldctl_value.bv_len = 0;
761                 c.ldctl_iscritical = 0;
762                 ctrls[0] = &c;
763                 ctrls[1] = NULL;
764                 ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
765         }
766 #endif
767
768         if ( authmethod == LDAP_AUTH_SASL ) {
769 #ifdef HAVE_CYRUS_SASL
770                 void *defaults;
771                 int rc;
772
773                 if( sasl_secprops != NULL ) {
774                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
775                                 (void *) sasl_secprops );
776
777                         if( rc != LDAP_OPT_SUCCESS ) {
778                                 fprintf( stderr,
779                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
780                                         sasl_secprops );
781                                 exit( EXIT_FAILURE );
782                         }
783                 }
784
785                 defaults = lutil_sasl_defaults( ld,
786                         sasl_mech,
787                         sasl_realm,
788                         sasl_authc_id,
789                         passwd.bv_val,
790                         sasl_authz_id );
791
792                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
793                         sasl_mech, NULL, NULL,
794                         sasl_flags, lutil_sasl_interact, defaults );
795
796                 lutil_sasl_freedefs( defaults );
797                 if( rc != LDAP_SUCCESS ) {
798                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
799                         exit( EXIT_FAILURE );
800                 }
801 #else
802                 fprintf( stderr, "%s: not compiled with SASL support\n",
803                         prog );
804                 exit( EXIT_FAILURE );
805 #endif
806         } else {
807                 int msgid, err;
808                 LDAPMessage *result;
809                 LDAPControl **ctrls;
810                 char msgbuf[256];
811
812                 msgbuf[0] = 0;
813
814                 if (( msgid = ldap_bind( ld, binddn, passwd.bv_val, authmethod )) == -1 )
815                 {
816                         ldap_perror( ld, "ldap_bind" );
817                         exit( EXIT_FAILURE );
818                 }
819
820                 if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) {
821                         ldap_perror( ld, "ldap_result" );
822                         exit( EXIT_FAILURE );
823                 }
824
825                 if ( ldap_parse_result( ld, result, &err, NULL, NULL, NULL,
826                         &ctrls, 1 ) != LDAP_SUCCESS ) {
827                         ldap_perror( ld, "ldap_bind parse result" );
828                         exit( EXIT_FAILURE );
829                 }
830
831 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
832                 if ( ctrls && ppolicy ) {
833                         LDAPControl *ctrl;
834                         int expire, grace, len = 0;
835                         LDAPPasswordPolicyError pErr = -1;
836                         
837                         ctrl = ldap_find_control( LDAP_CONTROL_PASSWORDPOLICYRESPONSE, ctrls );
838                         if ( ctrl && ldap_parse_passwordpolicy_control( ld, ctrl,
839                                 &expire, &grace, &pErr ) == LDAP_SUCCESS ) {
840                                 if ( pErr != PP_noError ){
841                                         msgbuf[0] = ';';
842                                         msgbuf[1] = ' ';
843                                         strcpy( msgbuf+2, ldap_passwordpolicy_err2txt( pErr ));
844                                         len = strlen( msgbuf );
845                                 }
846                                 if ( expire >= 0 ) {
847                                         sprintf( msgbuf+len, " (Password expires in %d seconds)", expire );
848                                 } else if ( grace >= 0 ) {
849                                         sprintf( msgbuf+len, " (Password expired, %d grace logins remain)", grace );
850                                 }
851                         }
852                 }
853 #endif
854                 if ( err != LDAP_SUCCESS || msgbuf[0] ) {
855                         fprintf( stderr, "ldap_bind: %s%s\n", ldap_err2string( err ),
856                                 msgbuf );
857                         if ( err != LDAP_SUCCESS ) {
858                                 exit( EXIT_FAILURE );
859                         }
860                 }
861         }
862 }
863
864
865 /* Set server controls.  Add controls extra_c[0..count-1], if set. */
866 void
867 tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count )
868 {
869         int i = 0, j, crit = 0, err;
870         LDAPControl c[8], **ctrls;
871
872         ctrls = (LDAPControl**) malloc(sizeof(c) + (count+1)*sizeof(LDAPControl*));
873         if ( ctrls == NULL ) {
874                 fprintf( stderr, "No memory\n" );
875                 exit( EXIT_FAILURE );
876         }
877
878         if ( assertctl ) {
879                 BerElementBuffer berbuf;
880                 BerElement *ber = (BerElement *)&berbuf;
881                 
882                 if( assertion == NULL || *assertion == '\0' ) {
883                         fprintf( stderr, "Assertion=<empty>\n" );
884                         exit( EXIT_FAILURE );
885                 }
886
887                 ber_init2( ber, NULL, LBER_USE_DER );
888
889                 err = ldap_pvt_put_filter( ber, assertion );
890                 if( err < 0 ) {
891                         fprintf( stderr, "assertion encode failed (%d)\n", err );
892                         exit( EXIT_FAILURE );
893                 }
894
895                 err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
896                 if( err < 0 ) {
897                         fprintf( stderr, "assertion flatten failed (%d)\n", err );
898                         exit( EXIT_FAILURE );
899                 }
900
901                 c[i].ldctl_oid = LDAP_CONTROL_ASSERT;
902                 c[i].ldctl_iscritical = assertctl > 1;
903                 ctrls[i] = &c[i];
904                 i++;
905         }
906
907         if ( authzid ) {
908                 c[i].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
909                 c[i].ldctl_value.bv_val = authzid;
910                 c[i].ldctl_value.bv_len = strlen( authzid );
911                 c[i].ldctl_iscritical = 1;
912                 ctrls[i] = &c[i];
913                 i++;
914         }
915
916         if ( manageDSAit ) {
917                 c[i].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
918                 c[i].ldctl_value.bv_val = NULL;
919                 c[i].ldctl_value.bv_len = 0;
920                 c[i].ldctl_iscritical = manageDSAit > 1;
921                 ctrls[i] = &c[i];
922                 i++;
923         }
924
925         if ( noop ) {
926                 c[i].ldctl_oid = LDAP_CONTROL_NOOP;
927                 c[i].ldctl_value.bv_val = NULL;
928                 c[i].ldctl_value.bv_len = 0;
929                 c[i].ldctl_iscritical = noop > 1;
930                 ctrls[i] = &c[i];
931                 i++;
932         }
933
934         if ( preread ) {
935                 char berbuf[LBER_ELEMENT_SIZEOF];
936                 BerElement *ber = (BerElement *)berbuf;
937                 char **attrs = NULL;
938
939                 if( preread_attrs ) {
940                         attrs = ldap_str2charray( preread_attrs, "," );
941                 }
942
943                 ber_init2( ber, NULL, LBER_USE_DER );
944
945                 if( ber_printf( ber, "{v}", attrs ) == -1 ) {
946                         fprintf( stderr, "preread attrs encode failed.\n" );
947                         exit( EXIT_FAILURE );
948                 }
949
950                 err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
951                 if( err < 0 ) {
952                         fprintf( stderr, "preread flatten failed (%d)\n", err );
953                         exit( EXIT_FAILURE );
954                 }
955
956                 c[i].ldctl_oid = LDAP_CONTROL_PRE_READ;
957                 c[i].ldctl_iscritical = preread > 1;
958                 ctrls[i] = &c[i];
959                 i++;
960
961                 if( attrs ) ldap_charray_free( attrs );
962         }
963
964         if ( postread ) {
965                 char berbuf[LBER_ELEMENT_SIZEOF];
966                 BerElement *ber = (BerElement *)berbuf;
967                 char **attrs = NULL;
968
969                 if( postread_attrs ) {
970                         attrs = ldap_str2charray( postread_attrs, "," );
971                 }
972
973                 ber_init2( ber, NULL, LBER_USE_DER );
974
975                 if( ber_printf( ber, "{v}", attrs ) == -1 ) {
976                         fprintf( stderr, "postread attrs encode failed.\n" );
977                         exit( EXIT_FAILURE );
978                 }
979
980                 err = ber_flatten2( ber, &c[i].ldctl_value, 0 );
981                 if( err < 0 ) {
982                         fprintf( stderr, "postread flatten failed (%d)\n", err );
983                         exit( EXIT_FAILURE );
984                 }
985
986                 c[i].ldctl_oid = LDAP_CONTROL_POST_READ;
987                 c[i].ldctl_iscritical = postread > 1;
988                 ctrls[i] = &c[i];
989                 i++;
990
991                 if( attrs ) ldap_charray_free( attrs );
992         }
993
994         while ( count-- ) {
995                 ctrls[i++] = extra_c++;
996         }
997         ctrls[i] = NULL;
998
999         err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
1000
1001         if ( err != LDAP_OPT_SUCCESS ) {
1002                 for ( j = 0; j < i; j++ ) {
1003                         if ( ctrls[j]->ldctl_iscritical ) crit = 1;
1004                 }
1005                 fprintf( stderr, "Could not set %scontrols\n",
1006                         crit ? "critical " : "" );
1007         }
1008
1009         free( ctrls );
1010         if ( crit ) {
1011                 exit( EXIT_FAILURE );
1012         }
1013 }