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