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