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