]> git.sur5r.net Git - openldap/blob - clients/tools/ldappasswd.c
First-cut proxy authorization support.
[openldap] / clients / tools / ldappasswd.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include <ac/stdlib.h>
12
13 #include <ac/ctype.h>
14 #include <ac/signal.h>
15 #include <ac/socket.h>
16 #include <ac/string.h>
17 #include <ac/time.h>
18 #include <ac/unistd.h>
19
20 #include <ldap.h>
21 #include "lutil.h"
22 #include "lutil_ldap.h"
23 #include "ldap_defaults.h"
24
25 static int      verbose = 0;
26
27 static void
28 usage(const char *s)
29 {
30         fprintf(stderr,
31 "Change password of an LDAP user\n\n"
32 "usage: %s [options] [user]\n"
33 "  user: the autentication identity, commonly a DN\n"
34 "Password change options:\n"
35 "  -a secret  old password\n"
36 "  -A         prompt for old password\n"
37 "  -s secret  new password\n"
38 "  -S         prompt for new password\n"
39
40 "Common options:\n"
41 "  -d level   set LDAP debugging level to `level'\n"
42 "  -D binddn  bind DN\n"
43 "  -e [!]<ctrl>[=<ctrlparam>] general controls (! indicates criticality)\n"
44 "             [!]authzid=<authzid> (\"dn:<dn>\" or \"u:<user>\")\n"
45 "             [!]manageDSAit   (alternate form, see -M)\n"
46 "             [!]noop\n"
47 "  -f file    read operations from `file'\n"
48 "  -h host    LDAP server(s)\n"
49 "  -H URI     LDAP Uniform Resource Indentifier(s)\n"
50 "  -I         use SASL Interactive mode\n"
51 "  -n         show what would be done but don't actually update\n"
52 "  -O props   SASL security properties\n"
53 "  -p port    port on LDAP server\n"
54 "  -Q         use SASL Quiet mode\n"
55 "  -R realm   SASL realm\n"
56 "  -U authcid SASL authentication identity\n"
57 "  -v         run in verbose mode (diagnostics to standard output)\n"
58 "  -w passwd  bind passwd (for simple authentication)\n"
59 "  -W         prompt for bind passwd\n"
60 "  -x         Simple authentication\n"
61 "  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
62 "  -Y mech    SASL mechanism\n"
63 "  -Z         Start TLS request (-ZZ to require successful response)\n"
64                 , s );
65
66         exit( EXIT_FAILURE );
67 }
68
69 int
70 main( int argc, char *argv[] )
71 {
72         int rc;
73         char    *prog = NULL;
74         char    *ldaphost = NULL;
75         char    *ldapuri = NULL;
76
77         char    *user = NULL;
78         char    *binddn = NULL;
79
80         struct berval passwd = { 0, NULL };
81         char    *newpw = NULL;
82         char    *oldpw = NULL;
83
84         int             want_bindpw = 0;
85         int             want_newpw = 0;
86         int             want_oldpw = 0;
87
88         int             not = 0;
89         int             i;
90         int             ldapport = 0;
91         int             debug = 0;
92         int             version = -1;
93         int             authmethod = -1;
94         int             manageDSAit = 0;
95         int             noop = 0;
96         int             crit;
97         char    *control, *cvalue;
98         char    *authzid = NULL;
99
100 #ifdef HAVE_CYRUS_SASL
101         unsigned        sasl_flags = LDAP_SASL_AUTOMATIC;
102         char            *sasl_realm = NULL;
103         char            *sasl_authc_id = NULL;
104         char            *sasl_authz_id = NULL;
105         char            *sasl_mech = NULL;
106         char            *sasl_secprops = NULL;
107 #endif
108
109         int             use_tls = 0;
110         int             referrals = 0;
111         LDAP           *ld = NULL;
112         struct berval *bv = NULL;
113
114         int id, code = LDAP_OTHER;
115         LDAPMessage *res;
116         char *matcheddn = NULL, *text = NULL, **refs = NULL;
117         char    *retoid = NULL;
118         struct berval *retdata = NULL;
119
120     prog = lutil_progname( "ldappasswd", argc, argv );
121
122         while( (i = getopt( argc, argv, "Aa:Ss:"
123                 "Cd:D:e:h:H:InO:p:QR:U:vw:WxX:Y:Z" )) != EOF )
124         {
125                 switch (i) {
126                 /* Password Options */
127                 case 'A':       /* prompt for old password */
128                         want_oldpw++;
129                         break;
130
131                 case 'a':       /* old password (secret) */
132                         oldpw = strdup (optarg);
133
134                         {
135                                 char* p;
136
137                                 for( p = optarg; *p != '\0'; p++ ) {
138                                         *p = '\0';
139                                 }
140                         }
141                         break;
142
143         case 'E': /* passwd controls */
144                 if( version == LDAP_VERSION2 ) {
145                         fprintf( stderr, "%s: -E incompatible with LDAPv%d\n",
146                                 prog, version );
147                         return EXIT_FAILURE;
148                 }
149
150                 /* should be extended to support comma separated list of
151                  *      [!]key[=value] parameters, e.g.  -E !foo,bar=567
152                  */
153
154                 crit = 0;
155                 cvalue = NULL;
156                 if( optarg[0] == '!' ) {
157                         crit = 1;
158                         optarg++;
159                 }
160
161                 control = strdup( optarg );
162                 if ( (cvalue = strchr( control, '=' )) != NULL ) {
163                         *cvalue++ = '\0';
164                 }
165                 fprintf( stderr, "Invalid passwd control name: %s\n", control );
166                 usage(prog);
167                 return EXIT_FAILURE;
168                 case 'S':       /* prompt for user password */
169                         want_newpw++;
170                         break;
171
172                 case 's':       /* new password (secret) */
173                         newpw = strdup (optarg);
174                         {
175                                 char* p;
176
177                                 for( p = optarg; *p != '\0'; p++ ) {
178                                         *p = '\0';
179                                 }
180                         }
181                         break;
182
183         /* Common Options (including options we don't use) */
184         case 'C':
185                 referrals++;
186                 break;
187         case 'd':
188             debug |= atoi( optarg );
189             break;
190         case 'D':       /* bind DN */
191                 if( binddn != NULL ) {
192                         fprintf( stderr, "%s: -D previously specified\n", prog );
193                         return EXIT_FAILURE;
194                 }
195             binddn = strdup( optarg );
196             break;
197         case 'e': /* general controls */
198                 if( version == LDAP_VERSION2 ) {
199                         fprintf( stderr, "%s: -e incompatible with LDAPv%d\n",
200                                 prog, version );
201                         return EXIT_FAILURE;
202                 }
203
204                 /* should be extended to support comma separated list of
205                  *      [!]key[=value] parameters, e.g.  -e !foo,bar=567
206                  */
207
208                 crit = 0;
209                 cvalue = NULL;
210                 if( optarg[0] == '!' ) {
211                         crit = 1;
212                         optarg++;
213                 }
214
215                 control = strdup( optarg );
216                 if ( (cvalue = strchr( control, '=' )) != NULL ) {
217                         *cvalue++ = '\0';
218                 }
219
220                 if ( strcasecmp( control, "authzid" ) == 0 ) {
221                         if( authzid != NULL ) {
222                                 fprintf( stderr, "authzid control previously specified\n");
223                                 return EXIT_FAILURE;
224                         }
225                         if( cvalue == NULL ) {
226                                 fprintf( stderr, "authzid: control value expected\n" );
227                                 usage(prog);
228                                 return EXIT_FAILURE;
229                         }
230                         if( !crit ) {
231                                 fprintf( stderr, "authzid: must be marked critical\n" );
232                                 usage(prog);
233                                 return EXIT_FAILURE;
234                         }
235
236                         assert( authzid == NULL );
237                         authzid = cvalue;
238
239                 } else if ( strcasecmp( control, "manageDSAit" ) == 0 ) {
240                         if( manageDSAit ) {
241                                 fprintf( stderr, "manageDSAit control previously specified\n");
242                                 return EXIT_FAILURE;
243                         }
244                         if( cvalue != NULL ) {
245                                 fprintf( stderr, "manageDSAit: no control value expected\n" );
246                                 usage(prog);
247                                 return EXIT_FAILURE;
248                         }
249
250                         manageDSAit = 1 + crit;
251
252                 } else if ( strcasecmp( control, "noop" ) == 0 ) {
253                         if( cvalue != NULL ) {
254                                 fprintf( stderr, "noop: no control value expected\n" );
255                                 usage(prog);
256                                 return EXIT_FAILURE;
257                         }
258
259                         noop = 1 + crit;
260
261                 } else {
262                         fprintf( stderr, "Invalid general control name: %s\n", control );
263                         usage(prog);
264                         return EXIT_FAILURE;
265                 }
266                 break;
267         case 'h':       /* ldap host */
268                 if( ldapuri != NULL ) {
269                         fprintf( stderr, "%s: -h incompatible with -H\n", prog );
270                         return EXIT_FAILURE;
271                 }
272                 if( ldaphost != NULL ) {
273                         fprintf( stderr, "%s: -h previously specified\n", prog );
274                         return EXIT_FAILURE;
275                 }
276             ldaphost = strdup( optarg );
277             break;
278         case 'H':       /* ldap URI */
279                 if( ldaphost != NULL ) {
280                         fprintf( stderr, "%s: -H incompatible with -h\n", prog );
281                         return EXIT_FAILURE;
282                 }
283                 if( ldapport ) {
284                         fprintf( stderr, "%s: -H incompatible with -p\n", prog );
285                         return EXIT_FAILURE;
286                 }
287                 if( ldapuri != NULL ) {
288                         fprintf( stderr, "%s: -H previously specified\n", prog );
289                         return EXIT_FAILURE;
290                 }
291             ldapuri = strdup( optarg );
292             break;
293         case 'I':
294 #ifdef HAVE_CYRUS_SASL
295                 if( version == LDAP_VERSION2 ) {
296                         fprintf( stderr, "%s: -I incompatible with version %d\n",
297                                 prog, version );
298                         return EXIT_FAILURE;
299                 }
300                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
301                         fprintf( stderr, "%s: incompatible previous "
302                                 "authentication choice\n",
303                                 prog );
304                         return EXIT_FAILURE;
305                 }
306                 authmethod = LDAP_AUTH_SASL;
307                 version = LDAP_VERSION3;
308                 sasl_flags = LDAP_SASL_INTERACTIVE;
309                 break;
310 #else
311                 fprintf( stderr, "%s: was not compiled with SASL support\n",
312                         prog );
313                 return( EXIT_FAILURE );
314 #endif
315         case 'k':       /* kerberos bind */
316 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
317                 if( version > LDAP_VERSION2 ) {
318                         fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
319                                 prog, version );
320                         return EXIT_FAILURE;
321                 }
322
323                 if( authmethod != -1 ) {
324                         fprintf( stderr, "%s: -k incompatible with previous "
325                                 "authentication choice\n", prog );
326                         return EXIT_FAILURE;
327                 }
328                         
329                 authmethod = LDAP_AUTH_KRBV4;
330 #else
331                 fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
332                 return EXIT_FAILURE;
333 #endif
334             break;
335         case 'K':       /* kerberos bind, part one only */
336 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
337                 if( version > LDAP_VERSION2 ) {
338                         fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
339                                 prog, version );
340                         return EXIT_FAILURE;
341                 }
342                 if( authmethod != -1 ) {
343                         fprintf( stderr, "%s: incompatible with previous "
344                                 "authentication choice\n", prog );
345                         return EXIT_FAILURE;
346                 }
347
348                 authmethod = LDAP_AUTH_KRBV41;
349 #else
350                 fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
351                 return( EXIT_FAILURE );
352 #endif
353             break;
354         case 'M':
355                 /* enable Manage DSA IT */
356                 if( version == LDAP_VERSION2 ) {
357                         fprintf( stderr, "%s: -M incompatible with LDAPv%d\n",
358                                 prog, version );
359                         return EXIT_FAILURE;
360                 }
361                 manageDSAit++;
362                 version = LDAP_VERSION3;
363                 break;
364         case 'n':       /* print deletes, don't actually do them */
365             ++not;
366             break;
367         case 'O':
368 #ifdef HAVE_CYRUS_SASL
369                 if( sasl_secprops != NULL ) {
370                         fprintf( stderr, "%s: -O previously specified\n", prog );
371                         return EXIT_FAILURE;
372                 }
373                 if( version == LDAP_VERSION2 ) {
374                         fprintf( stderr, "%s: -O incompatible with LDAPv%d\n",
375                                 prog, version );
376                         return EXIT_FAILURE;
377                 }
378                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
379                         fprintf( stderr, "%s: incompatible previous "
380                                 "authentication choice\n", prog );
381                         return EXIT_FAILURE;
382                 }
383                 authmethod = LDAP_AUTH_SASL;
384                 version = LDAP_VERSION3;
385                 sasl_secprops = strdup( optarg );
386 #else
387                 fprintf( stderr, "%s: not compiled with SASL support\n",
388                         prog );
389                 return( EXIT_FAILURE );
390 #endif
391                 break;
392         case 'p':
393                 if( ldapport ) {
394                         fprintf( stderr, "%s: -p previously specified\n", prog );
395                         return EXIT_FAILURE;
396                 }
397             ldapport = atoi( optarg );
398             break;
399         case 'P':
400                 switch( atoi(optarg) ) {
401                 case 2:
402                         if( version == LDAP_VERSION3 ) {
403                                 fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
404                                         prog, version );
405                                 return EXIT_FAILURE;
406                         }
407                         version = LDAP_VERSION2;
408                         break;
409                 case 3:
410                         if( version == LDAP_VERSION2 ) {
411                                 fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
412                                         prog, version );
413                                 return EXIT_FAILURE;
414                         }
415                         version = LDAP_VERSION3;
416                         break;
417                 default:
418                         fprintf( stderr, "%s: protocol version should be 2 or 3\n",
419                                 prog );
420                         usage( prog );
421                         return( EXIT_FAILURE );
422                 }
423                 break;
424         case 'Q':
425 #ifdef HAVE_CYRUS_SASL
426                 if( version == LDAP_VERSION2 ) {
427                         fprintf( stderr, "%s: -Q incompatible with version %d\n",
428                                 prog, version );
429                         return EXIT_FAILURE;
430                 }
431                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
432                         fprintf( stderr, "%s: incompatible previous "
433                                 "authentication choice\n",
434                                 prog );
435                         return EXIT_FAILURE;
436                 }
437                 authmethod = LDAP_AUTH_SASL;
438                 version = LDAP_VERSION3;
439                 sasl_flags = LDAP_SASL_QUIET;
440                 break;
441 #else
442                 fprintf( stderr, "%s: not compiled with SASL support\n",
443                         prog );
444                 return( EXIT_FAILURE );
445 #endif
446         case 'R':
447 #ifdef HAVE_CYRUS_SASL
448                 if( sasl_realm != NULL ) {
449                         fprintf( stderr, "%s: -R previously specified\n", prog );
450                         return EXIT_FAILURE;
451                 }
452                 if( version == LDAP_VERSION2 ) {
453                         fprintf( stderr, "%s: -R incompatible with version %d\n",
454                                 prog, version );
455                         return EXIT_FAILURE;
456                 }
457                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
458                         fprintf( stderr, "%s: incompatible previous "
459                                 "authentication choice\n",
460                                 prog );
461                         return EXIT_FAILURE;
462                 }
463                 authmethod = LDAP_AUTH_SASL;
464                 version = LDAP_VERSION3;
465                 sasl_realm = strdup( optarg );
466 #else
467                 fprintf( stderr, "%s: not compiled with SASL support\n",
468                         prog );
469                 return( EXIT_FAILURE );
470 #endif
471                 break;
472         case 'U':
473 #ifdef HAVE_CYRUS_SASL
474                 if( sasl_authc_id != NULL ) {
475                         fprintf( stderr, "%s: -U previously specified\n", prog );
476                         return EXIT_FAILURE;
477                 }
478                 if( version == LDAP_VERSION2 ) {
479                         fprintf( stderr, "%s: -U incompatible with version %d\n",
480                                 prog, version );
481                         return EXIT_FAILURE;
482                 }
483                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
484                         fprintf( stderr, "%s: incompatible previous "
485                                 "authentication choice\n",
486                                 prog );
487                         return EXIT_FAILURE;
488                 }
489                 authmethod = LDAP_AUTH_SASL;
490                 version = LDAP_VERSION3;
491                 sasl_authc_id = strdup( optarg );
492 #else
493                 fprintf( stderr, "%s: not compiled with SASL support\n",
494                         prog );
495                 return( EXIT_FAILURE );
496 #endif
497                 break;
498         case 'v':       /* verbose mode */
499             verbose++;
500             break;
501         case 'w':       /* password */
502             passwd.bv_val = strdup( optarg );
503                 {
504                         char* p;
505
506                         for( p = optarg; *p != '\0'; p++ ) {
507                                 *p = '\0';
508                         }
509                 }
510                 passwd.bv_len = strlen( passwd.bv_val );
511             break;
512         case 'W':
513                 want_bindpw++;
514                 break;
515         case 'Y':
516 #ifdef HAVE_CYRUS_SASL
517                 if( sasl_mech != NULL ) {
518                         fprintf( stderr, "%s: -Y previously specified\n", prog );
519                         return EXIT_FAILURE;
520                 }
521                 if( version == LDAP_VERSION2 ) {
522                         fprintf( stderr, "%s: -Y incompatible with version %d\n",
523                                 prog, version );
524                         return EXIT_FAILURE;
525                 }
526                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
527                         fprintf( stderr, "%s: incompatible with authentication choice\n", prog );
528                         return EXIT_FAILURE;
529                 }
530                 authmethod = LDAP_AUTH_SASL;
531                 version = LDAP_VERSION3;
532                 sasl_mech = strdup( optarg );
533 #else
534                 fprintf( stderr, "%s: not compiled with SASL support\n",
535                         prog );
536                 return( EXIT_FAILURE );
537 #endif
538                 break;
539         case 'x':
540                 if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
541                         fprintf( stderr, "%s: incompatible with previous "
542                                 "authentication choice\n", prog );
543                         return EXIT_FAILURE;
544                 }
545                 authmethod = LDAP_AUTH_SIMPLE;
546                 break;
547         case 'X':
548 #ifdef HAVE_CYRUS_SASL
549                 if( sasl_authz_id != NULL ) {
550                         fprintf( stderr, "%s: -X previously specified\n", prog );
551                         return EXIT_FAILURE;
552                 }
553                 if( version == LDAP_VERSION2 ) {
554                         fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
555                                 prog, version );
556                         return EXIT_FAILURE;
557                 }
558                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
559                         fprintf( stderr, "%s: -X incompatible with "
560                                 "authentication choice\n", prog );
561                         return EXIT_FAILURE;
562                 }
563                 authmethod = LDAP_AUTH_SASL;
564                 version = LDAP_VERSION3;
565                 sasl_authz_id = strdup( optarg );
566 #else
567                 fprintf( stderr, "%s: not compiled with SASL support\n",
568                         prog );
569                 return( EXIT_FAILURE );
570 #endif
571                 break;
572         case 'Z':
573 #ifdef HAVE_TLS
574                 if( version == LDAP_VERSION2 ) {
575                         fprintf( stderr, "%s: -Z incompatible with version %d\n",
576                                 prog, version );
577                         return EXIT_FAILURE;
578                 }
579                 version = LDAP_VERSION3;
580                 use_tls++;
581 #else
582                 fprintf( stderr, "%s: not compiled with TLS support\n",
583                         prog );
584                 return( EXIT_FAILURE );
585 #endif
586                 break;
587
588
589                 default:
590                         fprintf( stderr, "%s: unrecognized option -%c\n",
591                                 prog, optopt );
592                         usage (prog);
593                 }
594         }
595
596         if (authmethod == -1) {
597 #ifdef HAVE_CYRUS_SASL
598                 authmethod = LDAP_AUTH_SASL;
599 #else
600                 authmethod = LDAP_AUTH_SIMPLE;
601 #endif
602         }
603
604         if( argc - optind > 1 ) {
605                 usage( prog );
606         } else if ( argc - optind == 1 ) {
607                 user = strdup( argv[optind] );
608         } else {
609                 user = NULL;
610         }
611
612         if( want_oldpw && oldpw == NULL ) {
613                 /* prompt for old password */
614                 char *ckoldpw;
615                 oldpw = strdup(getpassphrase("Old password: "));
616                 ckoldpw = getpassphrase("Re-enter old password: ");
617
618                 if( oldpw== NULL || ckoldpw == NULL ||
619                         strcmp( oldpw, ckoldpw ))
620                 {
621                         fprintf( stderr, "passwords do not match\n" );
622                         return EXIT_FAILURE;
623                 }
624         }
625
626         if( want_newpw && newpw == NULL ) {
627                 /* prompt for new password */
628                 char *cknewpw;
629                 newpw = strdup(getpassphrase("New password: "));
630                 cknewpw = getpassphrase("Re-enter new password: ");
631
632                 if( newpw== NULL || cknewpw == NULL ||
633                         strcmp( newpw, cknewpw ))
634                 {
635                         fprintf( stderr, "passwords do not match\n" );
636                         return EXIT_FAILURE;
637                 }
638         }
639
640         if (want_bindpw && passwd.bv_val == NULL ) {
641                 /* handle bind password */
642                 passwd.bv_val = strdup( getpassphrase("Enter bind password: "));
643                 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
644         }
645
646         if ( debug ) {
647                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
648                         fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
649                 }
650                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
651                         fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
652                 }
653         }
654
655 #ifdef SIGPIPE
656         (void) SIGNAL( SIGPIPE, SIG_IGN );
657 #endif
658
659         /* connect to server */
660         if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
661                 if ( verbose ) {
662                         fprintf( stderr, "ldap_init( %s, %d )\n",
663                                 ldaphost != NULL ? ldaphost : "<DEFAULT>",
664                                 ldapport );
665                 }
666
667                 ld = ldap_init( ldaphost, ldapport );
668                 if( ld == NULL ) {
669                         perror("ldapsearch: ldap_init");
670                         return EXIT_FAILURE;
671                 }
672
673         } else {
674                 if ( verbose ) {
675                         fprintf( stderr, "ldap_initialize( %s )\n",
676                                 ldapuri != NULL ? ldapuri : "<DEFAULT>" );
677                 }
678
679                 rc = ldap_initialize( &ld, ldapuri );
680                 if( rc != LDAP_SUCCESS ) {
681                         fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
682                                 rc, ldap_err2string(rc) );
683                         return EXIT_FAILURE;
684                 }
685         }
686
687         /* referrals */
688         if (ldap_set_option( ld, LDAP_OPT_REFERRALS,
689                 referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
690         {
691                 fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
692                         referrals ? "on" : "off" );
693                 return EXIT_FAILURE;
694         }
695
696         /* LDAPv3 only */
697         version = LDAP_VERSION3;
698         rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
699
700         if(rc != LDAP_OPT_SUCCESS ) {
701                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version );
702                 return EXIT_FAILURE;
703         }
704
705         if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
706                 ldap_perror( ld, "ldap_start_tls" );
707                 if ( use_tls > 1 ) {
708                         return( EXIT_FAILURE );
709                 }
710         }
711
712         if ( authmethod == LDAP_AUTH_SASL ) {
713 #ifdef HAVE_CYRUS_SASL
714                 void *defaults;
715
716                 if( sasl_secprops != NULL ) {
717                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
718                                 (void *) sasl_secprops );
719                         
720                         if( rc != LDAP_OPT_SUCCESS ) {
721                                 fprintf( stderr,
722                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
723                                         sasl_secprops );
724                                 return( EXIT_FAILURE );
725                         }
726                 }
727                 
728                 defaults = lutil_sasl_defaults( ld,
729                         sasl_mech,
730                         sasl_realm,
731                         sasl_authc_id,
732                         passwd.bv_val,
733                         sasl_authz_id );
734
735                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
736                         sasl_mech, NULL, NULL,
737                         sasl_flags, lutil_sasl_interact, defaults );
738
739                 if( rc != LDAP_SUCCESS ) {
740                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
741                         return( EXIT_FAILURE );
742                 }
743 #else
744                 fprintf( stderr, "%s: not compiled with SASL support\n",
745                         prog );
746                 return( EXIT_FAILURE );
747 #endif
748         }
749         else {
750                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
751                                 != LDAP_SUCCESS ) {
752                         ldap_perror( ld, "ldap_bind" );
753                         return( EXIT_FAILURE );
754                 }
755         }
756
757         if ( authzid || manageDSAit || noop ) {
758                 int err, crit=0, i=0;
759                 LDAPControl c[3];
760                 LDAPControl *ctrls[4];
761
762                 if ( authzid ) {
763                         c[i].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
764                         c[i].ldctl_value.bv_val = authzid;
765                         c[i].ldctl_value.bv_len = strlen( authzid );
766                         c[i].ldctl_iscritical = 1;
767
768                         if( c[i].ldctl_iscritical ) crit++;
769                         ctrls[i] = &c[i];
770                         ctrls[++i] = NULL;
771                 }
772
773                 if ( manageDSAit ) {
774                         c[i].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
775                         c[i].ldctl_value.bv_val = NULL;
776                         c[i].ldctl_value.bv_len = 0;
777                         c[i].ldctl_iscritical = manageDSAit > 1;
778
779                         if( c[i].ldctl_iscritical ) crit++;
780                         ctrls[i] = &c[i];
781                         ctrls[++i] = NULL;
782                 }
783
784                 if ( noop ) {
785                         c[i].ldctl_oid = LDAP_CONTROL_NOOP;
786                         c[i].ldctl_value.bv_val = NULL;
787                         c[i].ldctl_value.bv_len = 0;
788                         c[i].ldctl_iscritical = noop > 1;
789
790                         if( c[i].ldctl_iscritical ) crit++;
791                         ctrls[i] = &c[i];
792                         ctrls[++i] = NULL;
793                 }
794         
795                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
796
797                 if( err != LDAP_OPT_SUCCESS ) {
798                         fprintf( stderr, "Could not set %scontrols\n",
799                                 crit ? "critical " : "" );
800                         if ( crit ) {
801                                 return EXIT_FAILURE;
802                         }
803                 }
804         }
805
806         if( user != NULL || oldpw != NULL || newpw != NULL ) {
807                 /* build change password control */
808                 BerElement *ber = ber_alloc_t( LBER_USE_DER );
809
810                 if( ber == NULL ) {
811                         perror( "ber_alloc_t" );
812                         ldap_unbind( ld );
813                         return EXIT_FAILURE;
814                 }
815
816                 ber_printf( ber, "{" /*}*/ );
817
818                 if( user != NULL ) {
819                         ber_printf( ber, "ts",
820                                 LDAP_TAG_EXOP_MODIFY_PASSWD_ID, user );
821                         free(user);
822                 }
823
824                 if( oldpw != NULL ) {
825                         ber_printf( ber, "ts",
826                                 LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, oldpw );
827                         free(oldpw);
828                 }
829
830                 if( newpw != NULL ) {
831                         ber_printf( ber, "ts",
832                                 LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, newpw );
833                         free(newpw);
834                 }
835
836                 ber_printf( ber, /*{*/ "N}" );
837
838                 rc = ber_flatten( ber, &bv );
839
840                 if( rc < 0 ) {
841                         perror( "ber_flatten" );
842                         ldap_unbind( ld );
843                         return EXIT_FAILURE;
844                 }
845
846                 ber_free( ber, 1 );
847         }
848
849         if ( not ) {
850                 rc = LDAP_SUCCESS;
851                 goto skip;
852         }
853
854         rc = ldap_extended_operation( ld,
855                 LDAP_EXOP_MODIFY_PASSWD, bv, 
856                 NULL, NULL, &id );
857
858         ber_bvfree( bv );
859
860         if( rc != LDAP_SUCCESS ) {
861                 ldap_perror( ld, "ldap_extended_operation" );
862                 ldap_unbind( ld );
863                 return EXIT_FAILURE;
864         }
865
866         rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
867         if ( rc < 0 ) {
868                 ldap_perror( ld, "ldappasswd: ldap_result" );
869                 return rc;
870         }
871
872         rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 0 );
873
874         if( rc != LDAP_SUCCESS ) {
875                 ldap_perror( ld, "ldap_parse_result" );
876                 return rc;
877         }
878
879         rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 );
880
881         if( rc != LDAP_SUCCESS ) {
882                 ldap_perror( ld, "ldap_parse_result" );
883                 return rc;
884         }
885
886         if( retdata != NULL ) {
887                 ber_tag_t tag;
888                 char *s;
889                 BerElement *ber = ber_init( retdata );
890
891                 if( ber == NULL ) {
892                         perror( "ber_init" );
893                         ldap_unbind( ld );
894                         return EXIT_FAILURE;
895                 }
896
897                 /* we should check the tag */
898                 tag = ber_scanf( ber, "{a}", &s);
899
900                 if( tag == LBER_ERROR ) {
901                         perror( "ber_scanf" );
902                 } else {
903                         printf("New password: %s\n", s);
904                         free( s );
905                 }
906
907                 ber_free( ber, 1 );
908         }
909
910         if( verbose || code != LDAP_SUCCESS || matcheddn || text || refs ) {
911                 printf( "Result: %s (%d)\n", ldap_err2string( code ), code );
912
913                 if( text && *text ) {
914                         printf( "Additional info: %s\n", text );
915                 }
916
917                 if( matcheddn && *matcheddn ) {
918                         printf( "Matched DN: %s\n", matcheddn );
919                 }
920
921                 if( refs ) {
922                         int i;
923                         for( i=0; refs[i]; i++ ) {
924                                 printf("Referral: %s\n", refs[i] );
925                         }
926                 }
927         }
928
929         ber_memfree( text );
930         ber_memfree( matcheddn );
931         ber_memvfree( (void **) refs );
932         ber_memfree( retoid );
933         ber_bvfree( retdata );
934
935 skip:
936         /* disconnect from server */
937         ldap_unbind (ld);
938
939         return code == LDAP_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
940 }