]> git.sur5r.net Git - openldap/blob - clients/tools/ldappasswd.c
124ed1d425658ed28099987dbc4d7a79f4f1943e
[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\told password\n"
36 "       -A\t\tprompt for old password\n"
37 "       -s secret\tnew password\n"
38 "       -S\t\tprompt for new password\n"
39
40 "Common options:\n"
41 "       -d level\tdebugging level\n"
42 "       -C\t\tchase referrals\n"
43 "       -D binddn\tbind DN\n"
44 "       -h host\t\tLDAP server (default: localhost)\n"
45 "       -n\t\tmake no modifications\n"
46 "       -O secprops\tSASL security properties\n"
47 "       -p port\t\tport on LDAP server\n"
48 "       -U user\t\tSASL authentication identity (username)\n"
49 "       -v\t\tverbose mode\n"
50 "       -w passwd\tbind password (for simple authentication)\n"
51 "       -W\t\tprompt for bind password\n"
52 "       -x\t\tSimple authentication\n"
53 "       -X id\t\tSASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
54 "       -Y mech\t\tSASL mechanism\n"
55 "       -Z\t\tissue Start TLS request (-ZZ to require successful response)\n"
56                 , s );
57
58         exit( EXIT_FAILURE );
59 }
60
61 int
62 main( int argc, char *argv[] )
63 {
64         int rc;
65         char    *prog = NULL;
66         char    *ldaphost = NULL;
67
68         char    *dn = NULL;
69         char    *binddn = NULL;
70
71         struct berval passwd = { 0, NULL };
72         char    *newpw = NULL;
73         char    *oldpw = NULL;
74
75         int             want_bindpw = 0;
76         int             want_newpw = 0;
77         int             want_oldpw = 0;
78
79         int             noupdates = 0;
80         int             i;
81         int             ldapport = 0;
82         int             debug = 0;
83         int             version = -1;
84         int             authmethod = -1;
85 #ifdef HAVE_CYRUS_SASL
86         char            *sasl_authc_id = NULL;
87         char            *sasl_authz_id = NULL;
88         char            *sasl_mech = NULL;
89         char            *sasl_secprops = NULL;
90 #endif
91         int             use_tls = 0;
92         int             referrals = 0;
93         LDAP           *ld;
94         struct berval *bv = NULL;
95
96         int id, code;
97         LDAPMessage *res;
98         char *matcheddn = NULL, *text = NULL, **refs = NULL;
99         char    *retoid = NULL;
100         struct berval *retdata = NULL;
101
102     prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : ++prog;
103
104         if (argc == 1)
105                 usage (argv[0]);
106
107         while( (i = getopt( argc, argv,
108                 "Aa:Ss:" "Cd:D:h:nO:p:U:vw:WxX:Y:Z" )) != EOF )
109         {
110                 switch (i) {
111                 /* Password Options */
112                 case 'A':       /* prompt for old password */
113                         want_oldpw++;
114                         break;
115
116                 case 'a':       /* old password (secret) */
117                         oldpw = strdup (optarg);
118
119                         {
120                                 char* p;
121
122                                 for( p = optarg; *p == '\0'; p++ ) {
123                                         *p = '*';
124                                 }
125                         }
126                         break;
127
128                 case 'S':       /* prompt for user password */
129                         want_newpw++;
130                         break;
131
132                 case 's':       /* new password (secret) */
133                         newpw = strdup (optarg);
134                         {
135                                 char* p;
136
137                                 for( p = optarg; *p == '\0'; p++ ) {
138                                         *p = '*';
139                                 }
140                         }
141                         break;
142
143                 /* Common Options */
144                 case 'C':
145                         referrals++;
146                         break;
147
148                 case 'D':       /* bind distinguished name */
149                         binddn = strdup (optarg);
150                         break;
151
152                 case 'd':       /* debugging option */
153                         debug |= atoi (optarg);
154                         break;
155
156                 case 'h':       /* ldap host */
157                         ldaphost = strdup (optarg);
158                         break;
159
160                 case 'n':       /* don't update entry(s) */
161                         noupdates++;
162                         break;
163
164                 case 'p':       /* ldap port */
165                         ldapport = strtol( optarg, NULL, 10 );
166                         break;
167
168                 case 'v':       /* verbose */
169                         verbose++;
170                         break;
171
172                 case 'W':       /* prompt for bind password */
173                         want_bindpw++;
174                         break;
175
176                 case 'w':       /* bind password */
177                         passwd.bv_val = strdup (optarg);
178                         {
179                                 char* p;
180
181                                 for( p = optarg; *p == '\0'; p++ ) {
182                                         *p = '*';
183                                 }
184                         }
185                         passwd.bv_len = strlen( passwd.bv_val );
186                         break;
187
188                 case 'O':
189 #ifdef HAVE_CYRUS_SASL
190                         sasl_secprops = strdup( optarg );
191                         authmethod = LDAP_AUTH_SASL;
192 #else
193                         fprintf( stderr, "%s was not compiled with SASL support\n",
194                                 argv[0] );
195                         return( EXIT_FAILURE );
196 #endif
197                         break;
198                 case 'Y':
199 #ifdef HAVE_CYRUS_SASL
200                         if ( strcasecmp( optarg, "any" ) &&
201                                         strcmp( optarg, "*" ) ) {
202                                 sasl_mech = strdup( optarg );
203                         }
204                         authmethod = LDAP_AUTH_SASL;
205 #else
206                         fprintf( stderr, "%s was not compiled with SASL "
207                                 "support\n", argv[0] );
208                         return( EXIT_FAILURE );
209 #endif
210                         break;
211                 case 'U':
212 #ifdef HAVE_CYRUS_SASL
213                         sasl_authc_id = strdup( optarg );
214                         authmethod = LDAP_AUTH_SASL;
215 #else
216                         fprintf( stderr, "%s was not compiled with SASL "
217                                 "support\n", argv[0] );
218                         return( EXIT_FAILURE );
219 #endif
220                         break;
221                 case 'x':
222                         if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
223                                 fprintf( stderr, "%s: incompatible with previous "
224                                         "authentication choice\n", prog );
225                                 return EXIT_FAILURE;
226                         }
227                         authmethod = LDAP_AUTH_SIMPLE;
228                         break;
229                 case 'X':
230 #ifdef HAVE_CYRUS_SASL
231                         sasl_authz_id = strdup( optarg );
232                         authmethod = LDAP_AUTH_SASL;
233 #else
234                         fprintf( stderr, "%s was not compiled with SASL "
235                                 "support\n", argv[0] );
236                         return( EXIT_FAILURE );
237 #endif
238                         break;
239                 case 'Z':
240 #ifdef HAVE_TLS
241                         use_tls++;
242 #else
243                         fprintf( stderr, "%s was not compiled with TLS "
244                                 "support\n", argv[0] );
245                         return( EXIT_FAILURE );
246 #endif
247                         break;
248
249                 default:
250                         fprintf( stderr, "%s: unrecongized option -%c\n",
251                                 prog, optopt );
252                         usage (argv[0]);
253                 }
254         }
255
256         if( argc - optind != 1 ) {
257                 usage( argv[0] );
258         } 
259
260         if (authmethod == -1) {
261 #ifdef HAVE_CYRUS_SASL
262                 authmethod = LDAP_AUTH_SASL;
263 #else
264                 authmethod = LDAP_AUTH_SIMPLE;
265 #endif
266         }
267
268         dn = strdup( argv[optind] );
269
270         if( want_oldpw && oldpw == NULL ) {
271                 /* prompt for old password */
272                 char *ckoldpw;
273                 newpw = strdup(getpassphrase("Old password: "));
274                 ckoldpw = getpassphrase("Re-enter old password: ");
275
276                 if( newpw== NULL || ckoldpw == NULL ||
277                         strncmp( oldpw, ckoldpw, strlen(oldpw) ))
278                 {
279                         fprintf( stderr, "passwords do not match\n" );
280                         return EXIT_FAILURE;
281                 }
282         }
283
284         if( want_newpw && newpw == NULL ) {
285                 /* prompt for new password */
286                 char *cknewpw;
287                 newpw = strdup(getpassphrase("New password: "));
288                 cknewpw = getpassphrase("Re-enter new password: ");
289
290                 if( newpw== NULL || cknewpw == NULL ||
291                         strncmp( newpw, cknewpw, strlen(newpw) ))
292                 {
293                         fprintf( stderr, "passwords do not match\n" );
294                         return EXIT_FAILURE;
295                 }
296         }
297
298         if( binddn == NULL && dn != NULL ) {
299                 binddn = dn;
300                 dn = NULL;
301
302                 if( passwd.bv_val == NULL ) {
303                         passwd.bv_val = oldpw;
304                         passwd.bv_len = oldpw == NULL ? 0 : strlen( oldpw );
305                 }
306         }
307
308         if (want_bindpw && passwd.bv_val == NULL ) {
309                 /* handle bind password */
310                 fprintf( stderr, "Bind DN: %s\n", binddn );
311                 passwd.bv_val = strdup( getpassphrase("Enter bind password: "));
312                 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
313         }
314
315         if ( debug ) {
316                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
317                         fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
318                 }
319                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
320                         fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
321                 }
322         }
323
324 #ifdef SIGPIPE
325         (void) SIGNAL( SIGPIPE, SIG_IGN );
326 #endif
327
328         /* connect to server */
329         if ((ld = ldap_init( ldaphost, ldapport )) == NULL) {
330                 perror("ldap_init");
331                 return EXIT_FAILURE;
332         }
333
334         /* referrals */
335         if (ldap_set_option( ld, LDAP_OPT_REFERRALS,
336                 referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
337         {
338                 fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
339                         referrals ? "on" : "off" );
340                 return EXIT_FAILURE;
341         }
342
343         /* LDAPv3 only */
344         version = 3;
345         rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
346
347         if(rc != LDAP_OPT_SUCCESS ) {
348                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version );
349                 return EXIT_FAILURE;
350         }
351
352         if ( use_tls && ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
353                 if ( use_tls > 1 ) {
354                         ldap_perror( ld, "ldap_start_tls" );
355                         return( EXIT_FAILURE );
356                 }
357                 fprintf( stderr, "WARNING: could not start TLS\n" );
358         }
359
360         if ( authmethod == LDAP_AUTH_SASL ) {
361 #ifdef HAVE_CYRUS_SASL
362                 if( sasl_secprops != NULL ) {
363                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
364                                 (void *) sasl_secprops );
365                         
366                         if( rc != LDAP_OPT_SUCCESS ) {
367                                 fprintf( stderr,
368                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
369                                         sasl_secprops );
370                                 return( EXIT_FAILURE );
371                         }
372                 }
373                 
374                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
375                         sasl_mech, NULL, NULL, lutil_sasl_interact );
376
377                 if( rc != LDAP_SUCCESS ) {
378                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
379                         return( EXIT_FAILURE );
380                 }
381 #else
382                 fprintf( stderr, "%s was not compiled with SASL support\n",
383                         argv[0] );
384                 return( EXIT_FAILURE );
385 #endif
386         }
387         else {
388                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
389                                 != LDAP_SUCCESS ) {
390                         ldap_perror( ld, "ldap_bind" );
391                         return( EXIT_FAILURE );
392                 }
393         }
394
395         if( dn != NULL || oldpw != NULL || newpw != NULL ) {
396                 /* build change password control */
397                 BerElement *ber = ber_alloc_t( LBER_USE_DER );
398
399                 if( ber == NULL ) {
400                         perror( "ber_alloc_t" );
401                         ldap_unbind( ld );
402                         return EXIT_FAILURE;
403                 }
404
405                 ber_printf( ber, "{" /*}*/ );
406
407                 if( dn != NULL ) {
408                         ber_printf( ber, "ts",
409                                 LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID, dn );
410                         free(dn);
411                 }
412
413                 if( oldpw != NULL ) {
414                         ber_printf( ber, "ts",
415                                 LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, oldpw );
416                         free(oldpw);
417                 }
418
419                 if( newpw != NULL ) {
420                         ber_printf( ber, "ts",
421                                 LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, newpw );
422                         free(newpw);
423                 }
424
425                 ber_printf( ber, /*{*/ "N}" );
426
427                 rc = ber_flatten( ber, &bv );
428
429                 if( rc < 0 ) {
430                         perror( "ber_flatten" );
431                         ldap_unbind( ld );
432                         return EXIT_FAILURE;
433                 }
434
435                 ber_free( ber, 1 );
436         }
437
438         if ( noupdates ) {
439                 rc = LDAP_SUCCESS;
440                 goto skip;
441         }
442
443         rc = ldap_extended_operation( ld,
444                 LDAP_EXOP_X_MODIFY_PASSWD, bv, 
445                 NULL, NULL, &id );
446
447         ber_bvfree( bv );
448
449         if( rc != LDAP_SUCCESS ) {
450                 ldap_perror( ld, "ldap_extended_operation" );
451                 ldap_unbind( ld );
452                 return EXIT_FAILURE;
453         }
454
455         rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
456         if ( rc < 0 ) {
457                 ldap_perror( ld, "ldappasswd: ldap_result" );
458                 return rc;
459         }
460
461         rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 0 );
462
463         if( rc != LDAP_SUCCESS ) {
464                 ldap_perror( ld, "ldap_parse_result" );
465                 return rc;
466         }
467
468         rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 );
469
470         if( rc != LDAP_SUCCESS ) {
471                 ldap_perror( ld, "ldap_parse_result" );
472                 return rc;
473         }
474
475         if( retdata != NULL ) {
476                 ber_tag_t tag;
477                 char *s;
478                 BerElement *ber = ber_init( retdata );
479
480                 if( ber == NULL ) {
481                         perror( "ber_init" );
482                         ldap_unbind( ld );
483                         return EXIT_FAILURE;
484                 }
485
486                 /* we should check the tag */
487                 tag = ber_scanf( ber, "{a}", &s);
488
489                 if( tag == LBER_ERROR ) {
490                         perror( "ber_scanf" );
491                 } else {
492                         printf("New password: %s\n", s);
493                         free( s );
494                 }
495
496                 ber_free( ber, 1 );
497         }
498
499         if( verbose || code != LDAP_SUCCESS || matcheddn || text || refs ) {
500                 printf( "Result: %s (%d)\n", ldap_err2string( code ), code );
501
502                 if( text && *text ) {
503                         printf( "Additional info: %s\n", text );
504                 }
505
506                 if( matcheddn && *matcheddn ) {
507                         printf( "Matched DN: %s\n", matcheddn );
508                 }
509
510                 if( refs ) {
511                         int i;
512                         for( i=0; refs[i]; i++ ) {
513                                 printf("Referral: %s\n", refs[i] );
514                         }
515                 }
516         }
517
518         ber_memfree( text );
519         ber_memfree( matcheddn );
520         ber_memvfree( (void **) refs );
521         ber_memfree( retoid );
522         ber_bvfree( retdata );
523
524 skip:
525         /* disconnect from server */
526         ldap_unbind (ld);
527
528         return EXIT_SUCCESS;
529 }