]> git.sur5r.net Git - openldap/blob - clients/tools/ldappasswd.c
LCUP Response Control Code
[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( manageDSAit ) {
218                                 fprintf( stderr, "manageDSAit control previously specified");
219                                 return EXIT_FAILURE;
220                         }
221                         if( cvalue != NULL ) {
222                                 fprintf( stderr, "manageDSAit: no control value expected" );
223                                 usage(prog);
224                                 return EXIT_FAILURE;
225                         }
226
227                         manageDSAit = 1 + crit;
228                         free( control );
229                         break;
230                         
231                 } else if ( strcasecmp( control, "noop" ) == 0 ) {
232                         if( cvalue != NULL ) {
233                                 fprintf( stderr, "noop: no control value expected" );
234                                 usage(prog);
235                                 return EXIT_FAILURE;
236                         }
237
238                         noop = 1 + crit;
239                         free( control );
240                         break;
241
242                 } else {
243                         fprintf( stderr, "Invalid general control name: %s\n", control );
244                         usage(prog);
245                         return EXIT_FAILURE;
246                 }
247         case 'h':       /* ldap host */
248                 if( ldapuri != NULL ) {
249                         fprintf( stderr, "%s: -h incompatible with -H\n", prog );
250                         return EXIT_FAILURE;
251                 }
252                 if( ldaphost != NULL ) {
253                         fprintf( stderr, "%s: -h previously specified\n", prog );
254                         return EXIT_FAILURE;
255                 }
256             ldaphost = strdup( optarg );
257             break;
258         case 'H':       /* ldap URI */
259                 if( ldaphost != NULL ) {
260                         fprintf( stderr, "%s: -H incompatible with -h\n", prog );
261                         return EXIT_FAILURE;
262                 }
263                 if( ldapport ) {
264                         fprintf( stderr, "%s: -H incompatible with -p\n", prog );
265                         return EXIT_FAILURE;
266                 }
267                 if( ldapuri != NULL ) {
268                         fprintf( stderr, "%s: -H previously specified\n", prog );
269                         return EXIT_FAILURE;
270                 }
271             ldapuri = strdup( optarg );
272             break;
273         case 'I':
274 #ifdef HAVE_CYRUS_SASL
275                 if( version == LDAP_VERSION2 ) {
276                         fprintf( stderr, "%s: -I incompatible with version %d\n",
277                                 prog, version );
278                         return EXIT_FAILURE;
279                 }
280                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
281                         fprintf( stderr, "%s: incompatible previous "
282                                 "authentication choice\n",
283                                 prog );
284                         return EXIT_FAILURE;
285                 }
286                 authmethod = LDAP_AUTH_SASL;
287                 version = LDAP_VERSION3;
288                 sasl_flags = LDAP_SASL_INTERACTIVE;
289                 break;
290 #else
291                 fprintf( stderr, "%s: was not compiled with SASL support\n",
292                         prog );
293                 return( EXIT_FAILURE );
294 #endif
295         case 'k':       /* kerberos bind */
296 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
297                 if( version > LDAP_VERSION2 ) {
298                         fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
299                                 prog, version );
300                         return EXIT_FAILURE;
301                 }
302
303                 if( authmethod != -1 ) {
304                         fprintf( stderr, "%s: -k incompatible with previous "
305                                 "authentication choice\n", prog );
306                         return EXIT_FAILURE;
307                 }
308                         
309                 authmethod = LDAP_AUTH_KRBV4;
310 #else
311                 fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
312                 return EXIT_FAILURE;
313 #endif
314             break;
315         case 'K':       /* kerberos bind, part one only */
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                 if( authmethod != -1 ) {
323                         fprintf( stderr, "%s: incompatible with previous "
324                                 "authentication choice\n", prog );
325                         return EXIT_FAILURE;
326                 }
327
328                 authmethod = LDAP_AUTH_KRBV41;
329 #else
330                 fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
331                 return( EXIT_FAILURE );
332 #endif
333             break;
334         case 'M':
335                 /* enable Manage DSA IT */
336                 if( version == LDAP_VERSION2 ) {
337                         fprintf( stderr, "%s: -M incompatible with LDAPv%d\n",
338                                 prog, version );
339                         return EXIT_FAILURE;
340                 }
341                 manageDSAit++;
342                 version = LDAP_VERSION3;
343                 break;
344         case 'n':       /* print deletes, don't actually do them */
345             ++not;
346             break;
347         case 'O':
348 #ifdef HAVE_CYRUS_SASL
349                 if( sasl_secprops != NULL ) {
350                         fprintf( stderr, "%s: -O previously specified\n", prog );
351                         return EXIT_FAILURE;
352                 }
353                 if( version == LDAP_VERSION2 ) {
354                         fprintf( stderr, "%s: -O incompatible with LDAPv%d\n",
355                                 prog, version );
356                         return EXIT_FAILURE;
357                 }
358                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
359                         fprintf( stderr, "%s: incompatible previous "
360                                 "authentication choice\n", prog );
361                         return EXIT_FAILURE;
362                 }
363                 authmethod = LDAP_AUTH_SASL;
364                 version = LDAP_VERSION3;
365                 sasl_secprops = strdup( optarg );
366 #else
367                 fprintf( stderr, "%s: not compiled with SASL support\n",
368                         prog );
369                 return( EXIT_FAILURE );
370 #endif
371                 break;
372         case 'p':
373                 if( ldapport ) {
374                         fprintf( stderr, "%s: -p previously specified\n", prog );
375                         return EXIT_FAILURE;
376                 }
377             ldapport = atoi( optarg );
378             break;
379         case 'P':
380                 switch( atoi(optarg) ) {
381                 case 2:
382                         if( version == LDAP_VERSION3 ) {
383                                 fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
384                                         prog, version );
385                                 return EXIT_FAILURE;
386                         }
387                         version = LDAP_VERSION2;
388                         break;
389                 case 3:
390                         if( version == LDAP_VERSION2 ) {
391                                 fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
392                                         prog, version );
393                                 return EXIT_FAILURE;
394                         }
395                         version = LDAP_VERSION3;
396                         break;
397                 default:
398                         fprintf( stderr, "%s: protocol version should be 2 or 3\n",
399                                 prog );
400                         usage( prog );
401                         return( EXIT_FAILURE );
402                 } break;
403         case 'Q':
404 #ifdef HAVE_CYRUS_SASL
405                 if( version == LDAP_VERSION2 ) {
406                         fprintf( stderr, "%s: -Q incompatible with version %d\n",
407                                 prog, version );
408                         return EXIT_FAILURE;
409                 }
410                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
411                         fprintf( stderr, "%s: incompatible previous "
412                                 "authentication choice\n",
413                                 prog );
414                         return EXIT_FAILURE;
415                 }
416                 authmethod = LDAP_AUTH_SASL;
417                 version = LDAP_VERSION3;
418                 sasl_flags = LDAP_SASL_QUIET;
419                 break;
420 #else
421                 fprintf( stderr, "%s: not compiled with SASL support\n",
422                         prog );
423                 return( EXIT_FAILURE );
424 #endif
425         case 'R':
426 #ifdef HAVE_CYRUS_SASL
427                 if( sasl_realm != NULL ) {
428                         fprintf( stderr, "%s: -R previously specified\n", prog );
429                         return EXIT_FAILURE;
430                 }
431                 if( version == LDAP_VERSION2 ) {
432                         fprintf( stderr, "%s: -R incompatible with version %d\n",
433                                 prog, version );
434                         return EXIT_FAILURE;
435                 }
436                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
437                         fprintf( stderr, "%s: incompatible previous "
438                                 "authentication choice\n",
439                                 prog );
440                         return EXIT_FAILURE;
441                 }
442                 authmethod = LDAP_AUTH_SASL;
443                 version = LDAP_VERSION3;
444                 sasl_realm = strdup( optarg );
445 #else
446                 fprintf( stderr, "%s: not compiled with SASL support\n",
447                         prog );
448                 return( EXIT_FAILURE );
449 #endif
450                 break;
451         case 'U':
452 #ifdef HAVE_CYRUS_SASL
453                 if( sasl_authc_id != NULL ) {
454                         fprintf( stderr, "%s: -U previously specified\n", prog );
455                         return EXIT_FAILURE;
456                 }
457                 if( version == LDAP_VERSION2 ) {
458                         fprintf( stderr, "%s: -U incompatible with version %d\n",
459                                 prog, version );
460                         return EXIT_FAILURE;
461                 }
462                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
463                         fprintf( stderr, "%s: incompatible previous "
464                                 "authentication choice\n",
465                                 prog );
466                         return EXIT_FAILURE;
467                 }
468                 authmethod = LDAP_AUTH_SASL;
469                 version = LDAP_VERSION3;
470                 sasl_authc_id = strdup( optarg );
471 #else
472                 fprintf( stderr, "%s: not compiled with SASL support\n",
473                         prog );
474                 return( EXIT_FAILURE );
475 #endif
476                 break;
477         case 'v':       /* verbose mode */
478             verbose++;
479             break;
480         case 'w':       /* password */
481             passwd.bv_val = strdup( optarg );
482                 {
483                         char* p;
484
485                         for( p = optarg; *p != '\0'; p++ ) {
486                                 *p = '\0';
487                         }
488                 }
489                 passwd.bv_len = strlen( passwd.bv_val );
490             break;
491         case 'W':
492                 want_bindpw++;
493                 break;
494         case 'Y':
495 #ifdef HAVE_CYRUS_SASL
496                 if( sasl_mech != NULL ) {
497                         fprintf( stderr, "%s: -Y previously specified\n", prog );
498                         return EXIT_FAILURE;
499                 }
500                 if( version == LDAP_VERSION2 ) {
501                         fprintf( stderr, "%s: -Y incompatible with version %d\n",
502                                 prog, version );
503                         return EXIT_FAILURE;
504                 }
505                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
506                         fprintf( stderr, "%s: incompatible with authentication choice\n", prog );
507                         return EXIT_FAILURE;
508                 }
509                 authmethod = LDAP_AUTH_SASL;
510                 version = LDAP_VERSION3;
511                 sasl_mech = strdup( optarg );
512 #else
513                 fprintf( stderr, "%s: not compiled with SASL support\n",
514                         prog );
515                 return( EXIT_FAILURE );
516 #endif
517                 break;
518         case 'x':
519                 if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
520                         fprintf( stderr, "%s: incompatible with previous "
521                                 "authentication choice\n", prog );
522                         return EXIT_FAILURE;
523                 }
524                 authmethod = LDAP_AUTH_SIMPLE;
525                 break;
526         case 'X':
527 #ifdef HAVE_CYRUS_SASL
528                 if( sasl_authz_id != NULL ) {
529                         fprintf( stderr, "%s: -X previously specified\n", prog );
530                         return EXIT_FAILURE;
531                 }
532                 if( version == LDAP_VERSION2 ) {
533                         fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
534                                 prog, version );
535                         return EXIT_FAILURE;
536                 }
537                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
538                         fprintf( stderr, "%s: -X incompatible with "
539                                 "authentication choice\n", prog );
540                         return EXIT_FAILURE;
541                 }
542                 authmethod = LDAP_AUTH_SASL;
543                 version = LDAP_VERSION3;
544                 sasl_authz_id = strdup( optarg );
545 #else
546                 fprintf( stderr, "%s: not compiled with SASL support\n",
547                         prog );
548                 return( EXIT_FAILURE );
549 #endif
550                 break;
551         case 'Z':
552 #ifdef HAVE_TLS
553                 if( version == LDAP_VERSION2 ) {
554                         fprintf( stderr, "%s: -Z incompatible with version %d\n",
555                                 prog, version );
556                         return EXIT_FAILURE;
557                 }
558                 version = LDAP_VERSION3;
559                 use_tls++;
560 #else
561                 fprintf( stderr, "%s: not compiled with TLS support\n",
562                         prog );
563                 return( EXIT_FAILURE );
564 #endif
565                 break;
566
567
568                 default:
569                         fprintf( stderr, "%s: unrecognized option -%c\n",
570                                 prog, optopt );
571                         usage (prog);
572                 }
573         }
574
575         if (authmethod == -1) {
576 #ifdef HAVE_CYRUS_SASL
577                 authmethod = LDAP_AUTH_SASL;
578 #else
579                 authmethod = LDAP_AUTH_SIMPLE;
580 #endif
581         }
582
583         if( argc - optind > 1 ) {
584                 usage( prog );
585         } else if ( argc - optind == 1 ) {
586                 user = strdup( argv[optind] );
587         } else {
588                 user = NULL;
589         }
590
591         if( want_oldpw && oldpw == NULL ) {
592                 /* prompt for old password */
593                 char *ckoldpw;
594                 oldpw = strdup(getpassphrase("Old password: "));
595                 ckoldpw = getpassphrase("Re-enter old password: ");
596
597                 if( oldpw== NULL || ckoldpw == NULL ||
598                         strcmp( oldpw, ckoldpw ))
599                 {
600                         fprintf( stderr, "passwords do not match\n" );
601                         return EXIT_FAILURE;
602                 }
603         }
604
605         if( want_newpw && newpw == NULL ) {
606                 /* prompt for new password */
607                 char *cknewpw;
608                 newpw = strdup(getpassphrase("New password: "));
609                 cknewpw = getpassphrase("Re-enter new password: ");
610
611                 if( newpw== NULL || cknewpw == NULL ||
612                         strcmp( newpw, cknewpw ))
613                 {
614                         fprintf( stderr, "passwords do not match\n" );
615                         return EXIT_FAILURE;
616                 }
617         }
618
619         if (want_bindpw && passwd.bv_val == NULL ) {
620                 /* handle bind password */
621                 passwd.bv_val = strdup( getpassphrase("Enter bind password: "));
622                 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
623         }
624
625         if ( debug ) {
626                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
627                         fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
628                 }
629                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
630                         fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
631                 }
632         }
633
634 #ifdef SIGPIPE
635         (void) SIGNAL( SIGPIPE, SIG_IGN );
636 #endif
637
638         /* connect to server */
639         if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
640                 if ( verbose ) {
641                         fprintf( stderr, "ldap_init( %s, %d )\n",
642                                 ldaphost != NULL ? ldaphost : "<DEFAULT>",
643                                 ldapport );
644                 }
645
646                 ld = ldap_init( ldaphost, ldapport );
647                 if( ld == NULL ) {
648                         perror("ldapsearch: ldap_init");
649                         return EXIT_FAILURE;
650                 }
651
652         } else {
653                 if ( verbose ) {
654                         fprintf( stderr, "ldap_initialize( %s )\n",
655                                 ldapuri != NULL ? ldapuri : "<DEFAULT>" );
656                 }
657
658                 rc = ldap_initialize( &ld, ldapuri );
659                 if( rc != LDAP_SUCCESS ) {
660                         fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
661                                 rc, ldap_err2string(rc) );
662                         return EXIT_FAILURE;
663                 }
664         }
665
666         /* referrals */
667         if (ldap_set_option( ld, LDAP_OPT_REFERRALS,
668                 referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
669         {
670                 fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
671                         referrals ? "on" : "off" );
672                 return EXIT_FAILURE;
673         }
674
675         /* LDAPv3 only */
676         version = LDAP_VERSION3;
677         rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
678
679         if(rc != LDAP_OPT_SUCCESS ) {
680                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version );
681                 return EXIT_FAILURE;
682         }
683
684         if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
685                 ldap_perror( ld, "ldap_start_tls" );
686                 if ( use_tls > 1 ) {
687                         return( EXIT_FAILURE );
688                 }
689         }
690
691         if ( authmethod == LDAP_AUTH_SASL ) {
692 #ifdef HAVE_CYRUS_SASL
693                 void *defaults;
694
695                 if( sasl_secprops != NULL ) {
696                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
697                                 (void *) sasl_secprops );
698                         
699                         if( rc != LDAP_OPT_SUCCESS ) {
700                                 fprintf( stderr,
701                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
702                                         sasl_secprops );
703                                 return( EXIT_FAILURE );
704                         }
705                 }
706                 
707                 defaults = lutil_sasl_defaults( ld,
708                         sasl_mech,
709                         sasl_realm,
710                         sasl_authc_id,
711                         passwd.bv_val,
712                         sasl_authz_id );
713
714                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
715                         sasl_mech, NULL, NULL,
716                         sasl_flags, lutil_sasl_interact, defaults );
717
718                 if( rc != LDAP_SUCCESS ) {
719                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
720                         return( EXIT_FAILURE );
721                 }
722 #else
723                 fprintf( stderr, "%s: not compiled with SASL support\n",
724                         prog );
725                 return( EXIT_FAILURE );
726 #endif
727         }
728         else {
729                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
730                                 != LDAP_SUCCESS ) {
731                         ldap_perror( ld, "ldap_bind" );
732                         return( EXIT_FAILURE );
733                 }
734         }
735
736         if ( manageDSAit || noop ) {
737                 int err, i = 0;
738                 LDAPControl c1, c2;
739                 LDAPControl *ctrls[3];
740
741                 if ( manageDSAit ) {
742                         ctrls[i++] = &c1;
743                         ctrls[i] = NULL;
744                         c1.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
745                         c1.ldctl_value.bv_val = NULL;
746                         c1.ldctl_value.bv_len = 0;
747                         c1.ldctl_iscritical = manageDSAit > 1;
748                 }
749
750                 if ( noop ) {
751                         ctrls[i++] = &c2;
752                         ctrls[i] = NULL;
753
754                         c2.ldctl_oid = LDAP_CONTROL_NOOP;
755                         c2.ldctl_value.bv_val = NULL;
756                         c2.ldctl_value.bv_len = 0;
757                         c2.ldctl_iscritical = noop > 1;
758                 }
759         
760                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
761
762                 if( err != LDAP_OPT_SUCCESS ) {
763                         fprintf( stderr, "Could not set %scontrols\n",
764                                 (c1.ldctl_iscritical || c2.ldctl_iscritical)
765                                 ? "critical " : "" );
766                         if ( c1.ldctl_iscritical && c2.ldctl_iscritical ) {
767                                 return EXIT_FAILURE;
768                         }
769                 }
770         }
771
772         if( user != NULL || oldpw != NULL || newpw != NULL ) {
773                 /* build change password control */
774                 BerElement *ber = ber_alloc_t( LBER_USE_DER );
775
776                 if( ber == NULL ) {
777                         perror( "ber_alloc_t" );
778                         ldap_unbind( ld );
779                         return EXIT_FAILURE;
780                 }
781
782                 ber_printf( ber, "{" /*}*/ );
783
784                 if( user != NULL ) {
785                         ber_printf( ber, "ts",
786                                 LDAP_TAG_EXOP_MODIFY_PASSWD_ID, user );
787                         free(user);
788                 }
789
790                 if( oldpw != NULL ) {
791                         ber_printf( ber, "ts",
792                                 LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, oldpw );
793                         free(oldpw);
794                 }
795
796                 if( newpw != NULL ) {
797                         ber_printf( ber, "ts",
798                                 LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, newpw );
799                         free(newpw);
800                 }
801
802                 ber_printf( ber, /*{*/ "N}" );
803
804                 rc = ber_flatten( ber, &bv );
805
806                 if( rc < 0 ) {
807                         perror( "ber_flatten" );
808                         ldap_unbind( ld );
809                         return EXIT_FAILURE;
810                 }
811
812                 ber_free( ber, 1 );
813         }
814
815         if ( not ) {
816                 rc = LDAP_SUCCESS;
817                 goto skip;
818         }
819
820         rc = ldap_extended_operation( ld,
821                 LDAP_EXOP_MODIFY_PASSWD, bv, 
822                 NULL, NULL, &id );
823
824         ber_bvfree( bv );
825
826         if( rc != LDAP_SUCCESS ) {
827                 ldap_perror( ld, "ldap_extended_operation" );
828                 ldap_unbind( ld );
829                 return EXIT_FAILURE;
830         }
831
832         rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
833         if ( rc < 0 ) {
834                 ldap_perror( ld, "ldappasswd: ldap_result" );
835                 return rc;
836         }
837
838         rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 0 );
839
840         if( rc != LDAP_SUCCESS ) {
841                 ldap_perror( ld, "ldap_parse_result" );
842                 return rc;
843         }
844
845         rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 );
846
847         if( rc != LDAP_SUCCESS ) {
848                 ldap_perror( ld, "ldap_parse_result" );
849                 return rc;
850         }
851
852         if( retdata != NULL ) {
853                 ber_tag_t tag;
854                 char *s;
855                 BerElement *ber = ber_init( retdata );
856
857                 if( ber == NULL ) {
858                         perror( "ber_init" );
859                         ldap_unbind( ld );
860                         return EXIT_FAILURE;
861                 }
862
863                 /* we should check the tag */
864                 tag = ber_scanf( ber, "{a}", &s);
865
866                 if( tag == LBER_ERROR ) {
867                         perror( "ber_scanf" );
868                 } else {
869                         printf("New password: %s\n", s);
870                         free( s );
871                 }
872
873                 ber_free( ber, 1 );
874         }
875
876         if( verbose || code != LDAP_SUCCESS || matcheddn || text || refs ) {
877                 printf( "Result: %s (%d)\n", ldap_err2string( code ), code );
878
879                 if( text && *text ) {
880                         printf( "Additional info: %s\n", text );
881                 }
882
883                 if( matcheddn && *matcheddn ) {
884                         printf( "Matched DN: %s\n", matcheddn );
885                 }
886
887                 if( refs ) {
888                         int i;
889                         for( i=0; refs[i]; i++ ) {
890                                 printf("Referral: %s\n", refs[i] );
891                         }
892                 }
893         }
894
895         ber_memfree( text );
896         ber_memfree( matcheddn );
897         ber_memvfree( (void **) refs );
898         ber_memfree( retoid );
899         ber_bvfree( retdata );
900
901 skip:
902         /* disconnect from server */
903         ldap_unbind (ld);
904
905         return code == LDAP_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
906 }