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