]> git.sur5r.net Git - openldap/blob - clients/tools/ldappasswd.c
Fix misplaced "search" references
[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
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 update\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 authcid SASL authentication identity\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 authzid 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 (prog);
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( prog );
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                         strcmp( oldpw, ckoldpw ))
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                         strcmp( newpw, cknewpw ))
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                 passwd.bv_val = strdup( getpassphrase("Enter bind password: "));
537                 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
538         }
539
540         if ( debug ) {
541                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
542                         fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
543                 }
544                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
545                         fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
546                 }
547         }
548
549 #ifdef SIGPIPE
550         (void) SIGNAL( SIGPIPE, SIG_IGN );
551 #endif
552
553         /* connect to server */
554         if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
555                 if ( verbose ) {
556                         fprintf( stderr, "ldap_init( %s, %d )\n",
557                                 ldaphost != NULL ? ldaphost : "<DEFAULT>",
558                                 ldapport );
559                 }
560
561                 ld = ldap_init( ldaphost, ldapport );
562                 if( ld == NULL ) {
563                         perror("ldapsearch: ldap_init");
564                         return EXIT_FAILURE;
565                 }
566
567         } else {
568                 if ( verbose ) {
569                         fprintf( stderr, "ldap_initialize( %s )\n",
570                                 ldapuri != NULL ? ldapuri : "<DEFAULT>" );
571                 }
572
573                 rc = ldap_initialize( &ld, ldapuri );
574                 if( rc != LDAP_SUCCESS ) {
575                         fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
576                                 rc, ldap_err2string(rc) );
577                         return EXIT_FAILURE;
578                 }
579         }
580
581         /* referrals */
582         if (ldap_set_option( ld, LDAP_OPT_REFERRALS,
583                 referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
584         {
585                 fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
586                         referrals ? "on" : "off" );
587                 return EXIT_FAILURE;
588         }
589
590         /* LDAPv3 only */
591         version = LDAP_VERSION3;
592         rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
593
594         if(rc != LDAP_OPT_SUCCESS ) {
595                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version );
596                 return EXIT_FAILURE;
597         }
598
599         if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
600                 ldap_perror( ld, "ldap_start_tls" );
601                 if ( use_tls > 1 ) {
602                         return( EXIT_FAILURE );
603                 }
604         }
605
606         if ( authmethod == LDAP_AUTH_SASL ) {
607 #ifdef HAVE_CYRUS_SASL
608                 void *defaults;
609
610                 if( sasl_secprops != NULL ) {
611                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
612                                 (void *) sasl_secprops );
613                         
614                         if( rc != LDAP_OPT_SUCCESS ) {
615                                 fprintf( stderr,
616                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
617                                         sasl_secprops );
618                                 return( EXIT_FAILURE );
619                         }
620                 }
621                 
622                 defaults = lutil_sasl_defaults( ld,
623                         sasl_mech,
624                         sasl_realm,
625                         sasl_authc_id,
626                         passwd.bv_val,
627                         sasl_authz_id );
628
629                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
630                         sasl_mech, NULL, NULL,
631                         sasl_flags, lutil_sasl_interact, defaults );
632
633                 if( rc != LDAP_SUCCESS ) {
634                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
635                         return( EXIT_FAILURE );
636                 }
637 #else
638                 fprintf( stderr, "%s: not compiled with SASL support\n",
639                         prog );
640                 return( EXIT_FAILURE );
641 #endif
642         }
643         else {
644                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
645                                 != LDAP_SUCCESS ) {
646                         ldap_perror( ld, "ldap_bind" );
647                         return( EXIT_FAILURE );
648                 }
649         }
650
651         if( user != NULL || oldpw != NULL || newpw != NULL ) {
652                 /* build change password control */
653                 BerElement *ber = ber_alloc_t( LBER_USE_DER );
654
655                 if( ber == NULL ) {
656                         perror( "ber_alloc_t" );
657                         ldap_unbind( ld );
658                         return EXIT_FAILURE;
659                 }
660
661                 ber_printf( ber, "{" /*}*/ );
662
663                 if( user != NULL ) {
664                         ber_printf( ber, "ts",
665                                 LDAP_TAG_EXOP_MODIFY_PASSWD_ID, user );
666                         free(user);
667                 }
668
669                 if( oldpw != NULL ) {
670                         ber_printf( ber, "ts",
671                                 LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, oldpw );
672                         free(oldpw);
673                 }
674
675                 if( newpw != NULL ) {
676                         ber_printf( ber, "ts",
677                                 LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, newpw );
678                         free(newpw);
679                 }
680
681                 ber_printf( ber, /*{*/ "N}" );
682
683                 rc = ber_flatten( ber, &bv );
684
685                 if( rc < 0 ) {
686                         perror( "ber_flatten" );
687                         ldap_unbind( ld );
688                         return EXIT_FAILURE;
689                 }
690
691                 ber_free( ber, 1 );
692         }
693
694         if ( not ) {
695                 rc = LDAP_SUCCESS;
696                 goto skip;
697         }
698
699         rc = ldap_extended_operation( ld,
700                 LDAP_EXOP_MODIFY_PASSWD, bv, 
701                 NULL, NULL, &id );
702
703         ber_bvfree( bv );
704
705         if( rc != LDAP_SUCCESS ) {
706                 ldap_perror( ld, "ldap_extended_operation" );
707                 ldap_unbind( ld );
708                 return EXIT_FAILURE;
709         }
710
711         rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
712         if ( rc < 0 ) {
713                 ldap_perror( ld, "ldappasswd: ldap_result" );
714                 return rc;
715         }
716
717         rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 0 );
718
719         if( rc != LDAP_SUCCESS ) {
720                 ldap_perror( ld, "ldap_parse_result" );
721                 return rc;
722         }
723
724         rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 );
725
726         if( rc != LDAP_SUCCESS ) {
727                 ldap_perror( ld, "ldap_parse_result" );
728                 return rc;
729         }
730
731         if( retdata != NULL ) {
732                 ber_tag_t tag;
733                 char *s;
734                 BerElement *ber = ber_init( retdata );
735
736                 if( ber == NULL ) {
737                         perror( "ber_init" );
738                         ldap_unbind( ld );
739                         return EXIT_FAILURE;
740                 }
741
742                 /* we should check the tag */
743                 tag = ber_scanf( ber, "{a}", &s);
744
745                 if( tag == LBER_ERROR ) {
746                         perror( "ber_scanf" );
747                 } else {
748                         printf("New password: %s\n", s);
749                         free( s );
750                 }
751
752                 ber_free( ber, 1 );
753         }
754
755         if( verbose || code != LDAP_SUCCESS || matcheddn || text || refs ) {
756                 printf( "Result: %s (%d)\n", ldap_err2string( code ), code );
757
758                 if( text && *text ) {
759                         printf( "Additional info: %s\n", text );
760                 }
761
762                 if( matcheddn && *matcheddn ) {
763                         printf( "Matched DN: %s\n", matcheddn );
764                 }
765
766                 if( refs ) {
767                         int i;
768                         for( i=0; refs[i]; i++ ) {
769                                 printf("Referral: %s\n", refs[i] );
770                         }
771                 }
772         }
773
774         ber_memfree( text );
775         ber_memfree( matcheddn );
776         ber_memvfree( (void **) refs );
777         ber_memfree( retoid );
778         ber_bvfree( retdata );
779
780 skip:
781         /* disconnect from server */
782         ldap_unbind (ld);
783
784         return EXIT_SUCCESS;
785 }