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