1/* ldappasswd -- a tool for change LDAP passwords */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 The OpenLDAP Foundation. 6 * Portions Copyright 1998-2003 Kurt D. Zeilenga. 7 * Portions Copyright 1998-2001 Net Boolean Incorporated. 8 * Portions Copyright 2001-2003 IBM Corporation. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19/* Portions Copyright (c) 1992-1996 Regents of the University of Michigan. 20 * All rights reserved. 21 * 22 * Redistribution and use in source and binary forms are permitted 23 * provided that this notice is preserved and that due credit is given 24 * to the University of Michigan at Ann Arbor. The name of the 25 * University may not be used to endorse or promote products derived 26 * from this software without specific prior written permission. This 27 * software is provided ``as is'' without express or implied warranty. 28 */ 29/* ACKNOWLEDGEMENTS: 30 * The original ldappasswd(1) tool was developed by Dave Storey (F5 31 * Network), based on other OpenLDAP client tools (which are, of 32 * course, based on U-MICH LDAP). This version was rewritten 33 * by Kurt D. Zeilenga (based on other OpenLDAP client tools). 34 */ 35 36#include "portable.h" 37 38#include <stdio.h> 39 40#include <ac/stdlib.h> 41 42#include <ac/ctype.h> 43#include <ac/socket.h> 44#include <ac/string.h> 45#include <ac/time.h> 46#include <ac/unistd.h> 47 48#include <ldap.h> 49#include "lutil.h" 50#include "lutil_ldap.h" 51#include "ldap_defaults.h" 52 53#include "common.h" 54 55 56static struct berval newpw = { 0, NULL }; 57static struct berval oldpw = { 0, NULL }; 58 59static int want_newpw = 0; 60static int want_oldpw = 0; 61 62static char *oldpwfile = NULL; 63static char *newpwfile = NULL; 64 65void 66usage( void ) 67{ 68 fprintf( stderr, _("Change password of an LDAP user\n\n")); 69 fprintf( stderr,_("usage: %s [options] [user]\n"), prog); 70 fprintf( stderr, _(" user: the authentication identity, commonly a DN\n")); 71 fprintf( stderr, _("Password change options:\n")); 72 fprintf( stderr, _(" -a secret old password\n")); 73 fprintf( stderr, _(" -A prompt for old password\n")); 74 fprintf( stderr, _(" -t file read file for old password\n")); 75 fprintf( stderr, _(" -s secret new password\n")); 76 fprintf( stderr, _(" -S prompt for new password\n")); 77 fprintf( stderr, _(" -T file read file for new password\n")); 78 tool_common_usage(); 79 exit( EXIT_FAILURE ); 80} 81 82 83const char options[] = "a:As:St:T:" 84 "d:D:e:h:H:InNO:o:p:QR:U:vVw:WxX:y:Y:Z"; 85 86int 87handle_private_option( int i ) 88{ 89 switch ( i ) { 90#if 0 91 case 'E': /* passwd extensions */ { 92 int crit; 93 char *control, *cvalue; 94 if( protocol == LDAP_VERSION2 ) { 95 fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"), 96 prog, protocol ); 97 exit( EXIT_FAILURE ); 98 } 99 100 /* should be extended to support comma separated list of 101 * [!]key[=value] parameters, e.g. -E !foo,bar=567 102 */ 103 104 crit = 0; 105 cvalue = NULL; 106 if( optarg[0] == '!' ) { 107 crit = 1; 108 optarg++; 109 } 110 111 control = strdup( optarg ); 112 if ( (cvalue = strchr( control, '=' )) != NULL ) { 113 *cvalue++ = '\0'; 114 } 115 fprintf( stderr, _("Invalid passwd extension name: %s\n"), control ); 116 usage(); 117 } 118#endif 119 120 case 'a': /* old password (secret) */ 121 oldpw.bv_val = strdup( optarg ); 122 { 123 char* p; 124 for( p = optarg; *p != '\0'; p++ ) { 125 *p = '\0'; 126 } 127 } 128 oldpw.bv_len = strlen( oldpw.bv_val ); 129 break; 130 131 case 'A': /* prompt for old password */ 132 want_oldpw++; 133 break; 134 135 case 's': /* new password (secret) */ 136 newpw.bv_val = strdup (optarg); 137 { 138 char* p; 139 for( p = optarg; *p != '\0'; p++ ) { 140 *p = '\0'; 141 } 142 } 143 newpw.bv_len = strlen( newpw.bv_val ); 144 break; 145 146 case 'S': /* prompt for user password */ 147 want_newpw++; 148 break; 149 150 case 't': 151 oldpwfile = optarg; 152 break; 153 154 case 'T': 155 newpwfile = optarg; 156 break; 157 158 default: 159 return 0; 160 } 161 return 1; 162} 163 164 165int 166main( int argc, char *argv[] ) 167{ 168 int rc; 169 char *user = NULL; 170 171 LDAP *ld = NULL; 172 struct berval bv = {0, NULL}; 173 BerElement *ber = NULL; 174 175 int id, code = LDAP_OTHER; 176 LDAPMessage *res; 177 char *matcheddn = NULL, *text = NULL, **refs = NULL; 178 char *retoid = NULL; 179 struct berval *retdata = NULL; 180 LDAPControl **ctrls = NULL; 181 182 tool_init( TOOL_PASSWD ); 183 prog = lutil_progname( "ldappasswd", argc, argv ); 184 185 /* LDAPv3 only */ 186 protocol = LDAP_VERSION3; 187 188 tool_args( argc, argv ); 189 190 if( argc - optind > 1 ) { 191 usage(); 192 } else if ( argc - optind == 1 ) { 193 user = strdup( argv[optind] ); 194 } else { 195 user = NULL; 196 } 197 198 if( oldpwfile ) { 199 rc = lutil_get_filed_password( oldpwfile, &oldpw ); 200 if( rc ) { 201 rc = EXIT_FAILURE; 202 goto done; 203 } 204 } 205 206 if( want_oldpw && oldpw.bv_val == NULL ) { 207 /* prompt for old password */ 208 char *ckoldpw; 209 oldpw.bv_val = strdup(getpassphrase(_("Old password: "))); 210 ckoldpw = getpassphrase(_("Re-enter old password: ")); 211 212 if( oldpw.bv_val == NULL || ckoldpw == NULL || 213 strcmp( oldpw.bv_val, ckoldpw )) 214 { 215 fprintf( stderr, _("passwords do not match\n") ); 216 rc = EXIT_FAILURE; 217 goto done; 218 } 219 220 oldpw.bv_len = strlen( oldpw.bv_val ); 221 } 222 223 if( newpwfile ) { 224 rc = lutil_get_filed_password( newpwfile, &newpw ); 225 if( rc ) { 226 rc = EXIT_FAILURE; 227 goto done; 228 } 229 } 230 231 if( want_newpw && newpw.bv_val == NULL ) { 232 /* prompt for new password */ 233 char *cknewpw; 234 newpw.bv_val = strdup(getpassphrase(_("New password: "))); 235 cknewpw = getpassphrase(_("Re-enter new password: ")); 236 237 if( newpw.bv_val == NULL || cknewpw == NULL || 238 strcmp( newpw.bv_val, cknewpw )) 239 { 240 fprintf( stderr, _("passwords do not match\n") ); 241 rc = EXIT_FAILURE; 242 goto done; 243 } 244 245 newpw.bv_len = strlen( newpw.bv_val ); 246 } 247 248 ld = tool_conn_setup( 0, 0 ); 249 250 tool_bind( ld ); 251 252 if( user != NULL || oldpw.bv_val != NULL || newpw.bv_val != NULL ) { 253 /* build the password modify request data */ 254 ber = ber_alloc_t( LBER_USE_DER ); 255 256 if( ber == NULL ) { 257 perror( "ber_alloc_t" ); 258 rc = EXIT_FAILURE; 259 goto done; 260 } 261 262 ber_printf( ber, "{" /*}*/ ); 263 264 if( user != NULL ) { 265 ber_printf( ber, "ts", 266 LDAP_TAG_EXOP_MODIFY_PASSWD_ID, user ); 267 free(user); 268 } 269 270 if( oldpw.bv_val != NULL ) { 271 ber_printf( ber, "tO", 272 LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &oldpw ); 273 free(oldpw.bv_val); 274 } 275 276 if( newpw.bv_val != NULL ) { 277 ber_printf( ber, "tO", 278 LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &newpw ); 279 free(newpw.bv_val); 280 } 281 282 ber_printf( ber, /*{*/ "N}" ); 283 284 rc = ber_flatten2( ber, &bv, 0 ); 285 286 if( rc < 0 ) { 287 perror( "ber_flatten2" ); 288 rc = EXIT_FAILURE; 289 goto done; 290 } 291 } 292 293 if ( dont ) { 294 rc = LDAP_SUCCESS; 295 goto done; 296 } 297 298 tool_server_controls( ld, NULL, 0); 299 300 rc = ldap_extended_operation( ld, 301 LDAP_EXOP_MODIFY_PASSWD, bv.bv_val ? &bv : NULL, 302 NULL, NULL, &id ); 303 304 ber_free( ber, 1 ); 305 306 if( rc != LDAP_SUCCESS ) { 307 tool_perror( "ldap_extended_operation", rc, NULL, NULL, NULL, NULL ); 308 rc = EXIT_FAILURE; 309 goto done; 310 } 311 312 for ( ; ; ) { 313 struct timeval tv; 314 315 if ( tool_check_abandon( ld, id ) ) { 316 tool_exit( ld, LDAP_CANCELLED ); 317 } 318 319 tv.tv_sec = 0; 320 tv.tv_usec = 100000; 321 322 rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res ); 323 if ( rc < 0 ) { 324 tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL ); 325 tool_exit( ld, rc ); 326 } 327 328 if ( rc != 0 ) { 329 break; 330 } 331 } 332 333 rc = ldap_parse_result( ld, res, 334 &code, &matcheddn, &text, &refs, &ctrls, 0 ); 335 if( rc != LDAP_SUCCESS ) { 336 tool_perror( "ldap_parse_result", rc, NULL, NULL, NULL, NULL ); 337 rc = EXIT_FAILURE; 338 goto done; 339 } 340 341 rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 ); 342 if( rc != LDAP_SUCCESS ) { 343 tool_perror( "ldap_parse_extended_result", rc, NULL, NULL, NULL, NULL ); 344 rc = EXIT_FAILURE; 345 goto done; 346 } 347 348 if( retdata != NULL ) { 349 ber_tag_t tag; 350 char *s; 351 ber = ber_init( retdata ); 352 353 if( ber == NULL ) { 354 perror( "ber_init" ); 355 rc = EXIT_FAILURE; 356 goto done; 357 } 358 359 /* we should check the tag */ 360 tag = ber_scanf( ber, "{a}", &s); 361 362 if( tag == LBER_ERROR ) { 363 perror( "ber_scanf" ); 364 } else { 365 printf(_("New password: %s\n"), s); 366 ber_memfree( s ); 367 } 368 369 ber_free( ber, 1 ); 370 371 } else if ( code == LDAP_SUCCESS && newpw.bv_val == NULL ) { 372 tool_perror( "ldap_parse_extended_result", LDAP_DECODING_ERROR, 373 " new password expected", NULL, NULL, NULL ); 374 } 375 376 if( verbose || code != LDAP_SUCCESS || 377 ( matcheddn && *matcheddn ) || ( text && *text ) || refs || ctrls ) 378 { 379 printf( _("Result: %s (%d)\n"), ldap_err2string( code ), code ); 380 381 if( text && *text ) { 382 printf( _("Additional info: %s\n"), text ); 383 } 384 385 if( matcheddn && *matcheddn ) { 386 printf( _("Matched DN: %s\n"), matcheddn ); 387 } 388 389 if( refs ) { 390 int i; 391 for( i=0; refs[i]; i++ ) { 392 printf(_("Referral: %s\n"), refs[i] ); 393 } 394 } 395 396 if( ctrls ) { 397 tool_print_ctrls( ld, ctrls ); 398 ldap_controls_free( ctrls ); 399 } 400 } 401 402 ber_memfree( text ); 403 ber_memfree( matcheddn ); 404 ber_memvfree( (void **) refs ); 405 ber_memfree( retoid ); 406 ber_bvfree( retdata ); 407 408 rc = ( code == LDAP_SUCCESS ) ? EXIT_SUCCESS : EXIT_FAILURE; 409 410done: 411 /* disconnect from server */ 412 tool_exit( ld, rc ); 413} 414