001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS. 026 */ 027package org.opends.server.tools; 028 029import static org.opends.messages.ToolMessages.*; 030import static org.opends.server.extensions.ExtensionsConstants.*; 031import static org.opends.server.protocols.ldap.LDAPResultCode.*; 032import static org.opends.server.util.ServerConstants.*; 033import static org.opends.server.util.StaticUtils.*; 034 035import static com.forgerock.opendj.cli.ArgumentConstants.*; 036import static com.forgerock.opendj.cli.Utils.*; 037 038import java.io.OutputStream; 039import java.io.PrintStream; 040import java.util.ArrayList; 041import java.util.List; 042import java.util.concurrent.atomic.AtomicInteger; 043 044import org.forgerock.i18n.LocalizableMessage; 045import org.forgerock.opendj.io.ASN1; 046import org.forgerock.opendj.io.ASN1Reader; 047import org.forgerock.opendj.io.ASN1Writer; 048import org.forgerock.opendj.ldap.ByteString; 049import org.forgerock.opendj.ldap.ByteStringBuilder; 050import org.opends.server.controls.PasswordPolicyErrorType; 051import org.opends.server.controls.PasswordPolicyResponseControl; 052import org.opends.server.controls.PasswordPolicyWarningType; 053import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 054import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp; 055import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp; 056import org.opends.server.protocols.ldap.LDAPControl; 057import org.opends.server.protocols.ldap.LDAPMessage; 058import org.opends.server.protocols.ldap.LDAPResultCode; 059import org.opends.server.protocols.ldap.UnbindRequestProtocolOp; 060import org.opends.server.types.Control; 061import org.opends.server.types.DN; 062import org.opends.server.types.NullOutputStream; 063import org.opends.server.util.EmbeddedUtils; 064 065import com.forgerock.opendj.cli.ArgumentException; 066import com.forgerock.opendj.cli.ArgumentParser; 067import com.forgerock.opendj.cli.BooleanArgument; 068import com.forgerock.opendj.cli.CliConstants; 069import com.forgerock.opendj.cli.CommonArguments; 070import com.forgerock.opendj.cli.ConsoleApplication; 071import com.forgerock.opendj.cli.FileBasedArgument; 072import com.forgerock.opendj.cli.IntegerArgument; 073import com.forgerock.opendj.cli.StringArgument; 074 075/** 076 * This program provides a utility that uses the LDAP password modify extended 077 * operation to change the password for a user. It exposes the three primary 078 * options available for this operation, which are: 079 * 080 * <UL> 081 * <LI>The user identity whose password should be changed.</LI> 082 * <LI>The current password for the user.</LI> 083 * <LI>The new password for the user.</LI> 084 * </UL> 085 * 086 * All of these are optional components that may be included or omitted from the 087 * request. 088 */ 089public class LDAPPasswordModify 090{ 091 /** 092 * The fully-qualified name of this class. 093 */ 094 private static final String CLASS_NAME = 095 "org.opends.server.tools.LDAPPasswordModify"; 096 097 098 099 100 /** 101 * Parses the command-line arguments, establishes a connection to the 102 * Directory Server, sends the password modify request, and reads the 103 * response. 104 * 105 * @param args The command-line arguments provided to this program. 106 */ 107 public static void main(String[] args) 108 { 109 int returnCode = mainPasswordModify(args, true, System.out, System.err); 110 if (returnCode != 0) 111 { 112 System.exit(filterExitCode(returnCode)); 113 } 114 } 115 116 117 118 /** 119 * Parses the command-line arguments, establishes a connection to the 120 * Directory Server, sends the password modify request, and reads the 121 * response. 122 * 123 * @param args The command-line arguments provided to this program. 124 * 125 * @return An integer value of zero if everything completed successfully, or 126 * a nonzero value if an error occurred. 127 */ 128 public static int mainPasswordModify(String[] args) 129 { 130 return mainPasswordModify(args, true, System.out, System.err); 131 } 132 133 134 135 /** 136 * Parses the command-line arguments, establishes a connection to the 137 * Directory Server, sends the password modify request, and reads the 138 * response. 139 * 140 * @param args The command-line arguments provided to this 141 * program. 142 * @param initializeServer Indicates whether to initialize the server. 143 * @param outStream The output stream to use for standard output. 144 * @param errStream The output stream to use for standard error. 145 * 146 * @return An integer value of zero if everything completed successfully, or 147 * a nonzero value if an error occurred. 148 */ 149 public static int mainPasswordModify(String[] args, boolean initializeServer, 150 OutputStream outStream, 151 OutputStream errStream) 152 { 153 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 154 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 155 156 157 // Create the arguments that will be used by this program. 158 BooleanArgument provideDNForAuthzID; 159 BooleanArgument showUsage; 160 BooleanArgument trustAll; 161 BooleanArgument useSSL; 162 BooleanArgument useStartTLS; 163 FileBasedArgument bindPWFile; 164 StringArgument certNickname; 165 FileBasedArgument currentPWFile; 166 FileBasedArgument newPWFile; 167 FileBasedArgument sslKeyStorePINFile; 168 FileBasedArgument sslTrustStorePINFile; 169 IntegerArgument ldapPort; 170 StringArgument authzID; 171 StringArgument bindDN; 172 StringArgument bindPW; 173 StringArgument controlStr; 174 StringArgument currentPW; 175 StringArgument ldapHost; 176 StringArgument newPW; 177 StringArgument sslKeyStore; 178 StringArgument sslKeyStorePIN; 179 StringArgument sslTrustStore; 180 StringArgument sslTrustStorePIN; 181 IntegerArgument connectTimeout; 182 StringArgument propertiesFileArgument; 183 BooleanArgument noPropertiesFileArgument; 184 185 186 // Initialize the argument parser. 187 LocalizableMessage toolDescription = INFO_LDAPPWMOD_TOOL_DESCRIPTION.get(); 188 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, 189 false); 190 argParser.setShortToolDescription(REF_SHORT_DESC_LDAPPASSWORDMODIFY.get()); 191 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 192 193 try 194 { 195 propertiesFileArgument = new StringArgument("propertiesFilePath", 196 null, OPTION_LONG_PROP_FILE_PATH, 197 false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null, 198 INFO_DESCRIPTION_PROP_FILE_PATH.get()); 199 argParser.addArgument(propertiesFileArgument); 200 argParser.setFilePropertiesArgument(propertiesFileArgument); 201 202 noPropertiesFileArgument = new BooleanArgument( 203 "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE, 204 INFO_DESCRIPTION_NO_PROP_FILE.get()); 205 argParser.addArgument(noPropertiesFileArgument); 206 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); 207 208 ldapHost = new StringArgument("ldaphost", OPTION_SHORT_HOST, 209 OPTION_LONG_HOST, false, false, 210 true, INFO_HOST_PLACEHOLDER.get(), 211 "127.0.0.1", null, 212 INFO_LDAPPWMOD_DESCRIPTION_HOST.get()); 213 ldapHost.setPropertyName(OPTION_LONG_HOST); 214 argParser.addArgument(ldapHost); 215 216 217 ldapPort = new IntegerArgument( 218 "ldapport", OPTION_SHORT_PORT, 219 OPTION_LONG_PORT, false, false, 220 true, INFO_PORT_PLACEHOLDER.get(), 389, 221 null, true, 1, true, 222 65535, INFO_LDAPPWMOD_DESCRIPTION_PORT.get()); 223 ldapPort.setPropertyName(OPTION_LONG_PORT); 224 argParser.addArgument(ldapPort); 225 226 227 useSSL = new BooleanArgument("usessl", OPTION_SHORT_USE_SSL, 228 OPTION_LONG_USE_SSL, 229 INFO_LDAPPWMOD_DESCRIPTION_USE_SSL.get()); 230 useSSL.setPropertyName(OPTION_LONG_USE_SSL); 231 argParser.addArgument(useSSL); 232 233 234 useStartTLS = new BooleanArgument("usestarttls", OPTION_SHORT_START_TLS, 235 OPTION_LONG_START_TLS, 236 INFO_LDAPPWMOD_DESCRIPTION_USE_STARTTLS.get()); 237 useStartTLS.setPropertyName(OPTION_LONG_START_TLS); 238 argParser.addArgument(useStartTLS); 239 240 241 bindDN = new StringArgument("binddn", OPTION_SHORT_BINDDN, 242 OPTION_LONG_BINDDN, false, false, true, 243 INFO_BINDDN_PLACEHOLDER.get(), null, null, 244 INFO_LDAPPWMOD_DESCRIPTION_BIND_DN.get()); 245 bindDN.setPropertyName(OPTION_LONG_BINDDN); 246 argParser.addArgument(bindDN); 247 248 249 bindPW = new StringArgument("bindpw", OPTION_SHORT_BINDPWD, 250 OPTION_LONG_BINDPWD, false, false, 251 true, INFO_BINDPWD_PLACEHOLDER.get(), null, 252 null, 253 INFO_LDAPPWMOD_DESCRIPTION_BIND_PW.get()); 254 bindPW.setPropertyName(OPTION_LONG_BINDPWD); 255 argParser.addArgument(bindPW); 256 257 258 bindPWFile = 259 new FileBasedArgument("bindpwfile", OPTION_SHORT_BINDPWD_FILE, 260 OPTION_LONG_BINDPWD_FILE, false, 261 false, INFO_BINDPWD_FILE_PLACEHOLDER.get(), 262 null, null, 263 INFO_LDAPPWMOD_DESCRIPTION_BIND_PW_FILE.get()); 264 bindPWFile.setPropertyName(OPTION_LONG_BINDPWD_FILE); 265 argParser.addArgument(bindPWFile); 266 267 268 authzID = new StringArgument("authzid", 'a', "authzID", false, false, 269 true, INFO_PROXYAUTHID_PLACEHOLDER.get(), 270 null, null, 271 INFO_LDAPPWMOD_DESCRIPTION_AUTHZID.get()); 272 authzID.setPropertyName("authzID"); 273 argParser.addArgument(authzID); 274 275 276 provideDNForAuthzID = 277 new BooleanArgument("providednforauthzid", 'A',"provideDNForAuthzID", 278 INFO_LDAPPWMOD_DESCRIPTION_PROVIDE_DN_FOR_AUTHZID.get()); 279 provideDNForAuthzID.setPropertyName("provideDNForAuthzID"); 280 argParser.addArgument(provideDNForAuthzID); 281 282 283 newPW = new StringArgument("newpw", 'n', "newPassword", false, false, 284 true, INFO_NEW_PASSWORD_PLACEHOLDER.get(), 285 null, null, 286 INFO_LDAPPWMOD_DESCRIPTION_NEWPW.get()); 287 newPW.setPropertyName("newPassword"); 288 argParser.addArgument(newPW); 289 290 291 newPWFile = new FileBasedArgument( 292 "newpwfile", 'N', "newPasswordFile", 293 false, false, INFO_FILE_PLACEHOLDER.get(), null, null, 294 INFO_LDAPPWMOD_DESCRIPTION_NEWPWFILE.get()); 295 newPWFile.setPropertyName("newPasswordFile"); 296 argParser.addArgument(newPWFile); 297 298 299 currentPW = 300 new StringArgument("currentpw", 'c', "currentPassword", false, false, 301 true, INFO_CURRENT_PASSWORD_PLACEHOLDER.get(), 302 null, null, 303 INFO_LDAPPWMOD_DESCRIPTION_CURRENTPW.get()); 304 currentPW.setPropertyName("currentPassword"); 305 argParser.addArgument(currentPW); 306 307 308 currentPWFile = 309 new FileBasedArgument( 310 "currentpwfile", 'C', "currentPasswordFile", 311 false, false, INFO_FILE_PLACEHOLDER.get(), null, null, 312 INFO_LDAPPWMOD_DESCRIPTION_CURRENTPWFILE.get()); 313 currentPWFile.setPropertyName("currentPasswordFile"); 314 argParser.addArgument(currentPWFile); 315 316 317 trustAll = CommonArguments.getTrustAll(); 318 argParser.addArgument(trustAll); 319 320 321 sslKeyStore = 322 new StringArgument("keystorepath", OPTION_SHORT_KEYSTOREPATH, 323 OPTION_LONG_KEYSTOREPATH, false, false, 324 true, INFO_KEYSTOREPATH_PLACEHOLDER.get(), null, 325 null, 326 INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE.get()); 327 sslKeyStore.setPropertyName(OPTION_LONG_KEYSTOREPATH); 328 argParser.addArgument(sslKeyStore); 329 330 331 sslKeyStorePIN = 332 new StringArgument("keystorepassword", 333 OPTION_SHORT_KEYSTORE_PWD, 334 OPTION_LONG_KEYSTORE_PWD , 335 false, false, true, 336 INFO_KEYSTORE_PWD_PLACEHOLDER.get(), 337 null, null, 338 INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE_PIN.get()); 339 sslKeyStorePIN.setPropertyName(OPTION_LONG_KEYSTORE_PWD); 340 argParser.addArgument(sslKeyStorePIN); 341 342 343 sslKeyStorePINFile = 344 new FileBasedArgument( 345 "keystorepasswordfile", 346 OPTION_SHORT_KEYSTORE_PWD_FILE, 347 OPTION_LONG_KEYSTORE_PWD_FILE, 348 false, false, INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get(), 349 null, null, 350 INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE_PINFILE.get()); 351 sslKeyStorePINFile.setPropertyName(OPTION_LONG_KEYSTORE_PWD_FILE); 352 argParser.addArgument(sslKeyStorePINFile); 353 354 certNickname = new StringArgument("certnickname", null, "certNickname", 355 false, false, true, INFO_NICKNAME_PLACEHOLDER.get(), null, null, 356 INFO_DESCRIPTION_CERT_NICKNAME.get()); 357 certNickname.setPropertyName("certNickname"); 358 argParser.addArgument(certNickname); 359 360 361 362 sslTrustStore = 363 new StringArgument("truststorepath", 364 OPTION_SHORT_TRUSTSTOREPATH, 365 OPTION_LONG_TRUSTSTOREPATH, false, 366 false, true, 367 INFO_TRUSTSTOREPATH_PLACEHOLDER.get(), null, null, 368 INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE.get()); 369 sslTrustStore.setPropertyName(OPTION_LONG_TRUSTSTOREPATH); 370 argParser.addArgument(sslTrustStore); 371 372 373 sslTrustStorePIN = 374 new StringArgument("truststorepassword", null, 375 OPTION_LONG_TRUSTSTORE_PWD, 376 false, false, true, 377 INFO_TRUSTSTORE_PWD_PLACEHOLDER.get(), null, null, 378 INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE_PIN.get()); 379 sslTrustStorePIN.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD); 380 argParser.addArgument(sslTrustStorePIN); 381 382 383 sslTrustStorePINFile = 384 new FileBasedArgument("truststorepasswordfile", 385 OPTION_SHORT_TRUSTSTORE_PWD_FILE, 386 OPTION_LONG_TRUSTSTORE_PWD_FILE, false, false, 387 INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get(), null, 388 null, INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE_PINFILE.get()); 389 sslTrustStorePINFile.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD_FILE); 390 argParser.addArgument(sslTrustStorePINFile); 391 392 393 controlStr = 394 new StringArgument("control", 'J', "control", false, true, true, 395 INFO_LDAP_CONTROL_PLACEHOLDER.get(), 396 null, null, INFO_DESCRIPTION_CONTROLS.get()); 397 controlStr.setPropertyName("control"); 398 argParser.addArgument(controlStr); 399 400 int defaultTimeout = CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT; 401 connectTimeout = new IntegerArgument(OPTION_LONG_CONNECT_TIMEOUT, 402 null, OPTION_LONG_CONNECT_TIMEOUT, 403 false, false, true, INFO_TIMEOUT_PLACEHOLDER.get(), 404 defaultTimeout, null, 405 true, 0, false, Integer.MAX_VALUE, 406 INFO_DESCRIPTION_CONNECTION_TIMEOUT.get()); 407 connectTimeout.setPropertyName(OPTION_LONG_CONNECT_TIMEOUT); 408 argParser.addArgument(connectTimeout); 409 410 411 showUsage = CommonArguments.getShowUsage(); 412 argParser.addArgument(showUsage); 413 argParser.setUsageArgument(showUsage, out); 414 } 415 catch (ArgumentException ae) 416 { 417 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 418 return CLIENT_SIDE_PARAM_ERROR; 419 } 420 421 422 // Parse the command-line arguments provided to this program. 423 try 424 { 425 argParser.parseArguments(args); 426 } 427 catch (ArgumentException ae) 428 { 429 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 430 return CLIENT_SIDE_PARAM_ERROR; 431 } 432 433 434 // If the usage or version argument was provided, 435 // then we don't need to do anything else. 436 if (argParser.usageOrVersionDisplayed()) 437 { 438 return 0; 439 } 440 441 442 // Make sure that the user didn't specify any conflicting arguments. 443 if (bindPW.isPresent() && bindPWFile.isPresent()) 444 { 445 printWrappedText( 446 err, ERR_LDAPPWMOD_CONFLICTING_ARGS.get(bindPW.getLongIdentifier(), bindPWFile.getLongIdentifier())); 447 return CLIENT_SIDE_PARAM_ERROR; 448 } 449 450 if (newPW.isPresent() && newPWFile.isPresent()) 451 { 452 printWrappedText( 453 err, ERR_LDAPPWMOD_CONFLICTING_ARGS.get(newPW.getLongIdentifier(), newPWFile.getLongIdentifier())); 454 return CLIENT_SIDE_PARAM_ERROR; 455 } 456 457 if (currentPW.isPresent() && currentPWFile.isPresent()) 458 { 459 printWrappedText(err, 460 ERR_LDAPPWMOD_CONFLICTING_ARGS.get(currentPW.getLongIdentifier(), currentPWFile.getLongIdentifier())); 461 return CLIENT_SIDE_PARAM_ERROR; 462 } 463 464 if (useSSL.isPresent() && useStartTLS.isPresent()) 465 { 466 printWrappedText( 467 err, ERR_LDAPPWMOD_CONFLICTING_ARGS.get(useSSL.getLongIdentifier(), useStartTLS.getLongIdentifier())); 468 return CLIENT_SIDE_PARAM_ERROR; 469 } 470 471 if (sslKeyStorePIN.isPresent() && sslKeyStorePINFile.isPresent()) 472 { 473 printWrappedText(err, 474 ERR_TOOL_CONFLICTING_ARGS.get(sslKeyStorePIN.getLongIdentifier(), sslKeyStorePINFile.getLongIdentifier())); 475 return CLIENT_SIDE_PARAM_ERROR; 476 } 477 478 if (sslTrustStorePIN.isPresent() && sslTrustStorePINFile.isPresent()) 479 { 480 printWrappedText(err, ERR_TOOL_CONFLICTING_ARGS.get(sslTrustStorePIN.getLongIdentifier(), 481 sslTrustStorePINFile.getLongIdentifier())); 482 return CLIENT_SIDE_PARAM_ERROR; 483 } 484 485 486 // If a bind DN was provided, make sure that a password was given. If a 487 // password was given, make sure a bind DN was provided. If neither were 488 // given, then make sure that an authorization ID and the current password 489 // were provided. 490 if (bindDN.isPresent()) 491 { 492 if (!bindPW.isPresent() && !bindPWFile.isPresent()) 493 { 494 argParser.displayMessageAndUsageReference(err, ERR_LDAPPWMOD_BIND_DN_AND_PW_MUST_BE_TOGETHER.get()); 495 return CLIENT_SIDE_PARAM_ERROR; 496 } 497 } 498 else if (bindPW.isPresent() || bindPWFile.isPresent()) 499 { 500 argParser.displayMessageAndUsageReference(err, ERR_LDAPPWMOD_BIND_DN_AND_PW_MUST_BE_TOGETHER.get()); 501 return CLIENT_SIDE_PARAM_ERROR; 502 } 503 else 504 { 505 if (provideDNForAuthzID.isPresent()) 506 { 507 argParser.displayMessageAndUsageReference(err, 508 ERR_LDAPPWMOD_DEPENDENT_ARGS.get(provideDNForAuthzID.getLongIdentifier(), bindDN.getLongIdentifier())); 509 return CLIENT_SIDE_PARAM_ERROR; 510 } 511 512 if (!authzID.isPresent() || (!currentPW.isPresent() && !currentPWFile.isPresent())) 513 { 514 argParser.displayMessageAndUsageReference(err, ERR_LDAPPWMOD_ANON_REQUIRES_AUTHZID_AND_CURRENTPW.get()); 515 return CLIENT_SIDE_PARAM_ERROR; 516 } 517 } 518 519 520 // Get the host and port. 521 String host = ldapHost.getValue(); 522 int port; 523 try 524 { 525 port = ldapPort.getIntValue(); 526 } 527 catch (Exception e) 528 { 529 // This should never happen. 530 printWrappedText(err, e.toString()); 531 return CLIENT_SIDE_PARAM_ERROR; 532 } 533 534 535 // If a control string was provided, then decode the requested controls. 536 ArrayList<Control> controls = new ArrayList<>(); 537 if(controlStr.isPresent()) 538 { 539 for (String ctrlString : controlStr.getValues()) 540 { 541 LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString, err); 542 if(ctrl == null) 543 { 544 printWrappedText(err, ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString)); 545 return CLIENT_SIDE_PARAM_ERROR; 546 } 547 controls.add(ctrl); 548 } 549 } 550 551 552 // Perform a basic Directory Server bootstrap if appropriate. 553 if (initializeServer) 554 { 555 EmbeddedUtils.initializeForClientUse(); 556 } 557 558 559 // Establish a connection to the Directory Server. 560 AtomicInteger nextMessageID = new AtomicInteger(1); 561 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions(); 562 connectionOptions.setUseSSL(useSSL.isPresent()); 563 connectionOptions.setStartTLS(useStartTLS.isPresent()); 564 connectionOptions.setVersionNumber(3); 565 if(connectionOptions.useSSL() || connectionOptions.useStartTLS()) 566 { 567 String keyPIN = null; 568 if (sslKeyStorePIN.isPresent()) 569 { 570 keyPIN = sslKeyStorePIN.getValue(); 571 } 572 else if (sslKeyStorePINFile.isPresent()) 573 { 574 keyPIN = sslKeyStorePINFile.getValue(); 575 } 576 577 String trustPIN = null; 578 if (sslTrustStorePIN.isPresent()) 579 { 580 trustPIN = sslTrustStorePIN.getValue(); 581 } 582 else if (sslTrustStorePINFile.isPresent()) 583 { 584 trustPIN = sslTrustStorePINFile.getValue(); 585 } 586 587 try 588 { 589 String clientAlias; 590 if (certNickname.isPresent()) 591 { 592 clientAlias = certNickname.getValue(); 593 } 594 else 595 { 596 clientAlias = null; 597 } 598 SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory(); 599 sslConnectionFactory.init(trustAll.isPresent(), 600 sslKeyStore.getValue(), keyPIN, clientAlias, 601 sslTrustStore.getValue(), trustPIN); 602 connectionOptions.setSSLConnectionFactory(sslConnectionFactory); 603 } 604 catch (Exception e) 605 { 606 printWrappedText(err, ERR_LDAPPWMOD_ERROR_INITIALIZING_SSL.get(e)); 607 return CLIENT_SIDE_PARAM_ERROR; 608 } 609 } 610 611 LDAPConnection connection = new LDAPConnection(host, port, 612 connectionOptions, out, err); 613 String dn; 614 String pw; 615 if (bindPW.isPresent()) 616 { 617 dn = bindDN.getValue(); 618 pw = bindPW.getValue(); 619 if(pw != null && pw.equals("-")) 620 { 621 // read the password from the stdin. 622 try 623 { 624 out.print(INFO_LDAPAUTH_PASSWORD_PROMPT.get(dn)); 625 char[] pwChars = ConsoleApplication.readPassword(); 626 //As per rfc 4513(section-5.1.2) a client should avoid sending 627 //an empty password to the server. 628 while(pwChars.length==0) 629 { 630 printWrappedText(err, INFO_LDAPAUTH_NON_EMPTY_PASSWORD.get()); 631 out.print(INFO_LDAPAUTH_PASSWORD_PROMPT.get(dn)); 632 pwChars = ConsoleApplication.readPassword(); 633 } 634 pw = new String(pwChars); 635 } catch(Exception ex) 636 { 637 printWrappedText(err, ex.getMessage()); 638 return CLIENT_SIDE_PARAM_ERROR; 639 } 640 } 641 } 642 else if (bindPWFile.isPresent()) 643 { 644 dn = bindDN.getValue(); 645 pw = bindPWFile.getValue(); 646 } 647 else 648 { 649 dn = null; 650 pw = null; 651 } 652 653 try 654 { 655 int timeout = connectTimeout.getIntValue(); 656 connection.connectToHost(dn, pw, nextMessageID, timeout); 657 } 658 catch (LDAPConnectionException lce) 659 { 660 printWrappedText(err, ERR_LDAPPWMOD_CANNOT_CONNECT.get(lce.getMessage())); 661 return lce.getResultCode(); 662 } 663 catch (ArgumentException e) 664 { 665 // This should not occur because the arguments are already parsed. 666 // It is a bug 667 e.printStackTrace(); 668 throw new IllegalStateException("Unexpected error: "+e, e); 669 } 670 671 LDAPReader reader = connection.getLDAPReader(); 672 LDAPWriter writer = connection.getLDAPWriter(); 673 674 675 // Construct the password modify request. 676 ByteStringBuilder builder = new ByteStringBuilder(); 677 ASN1Writer asn1Writer = ASN1.getWriter(builder); 678 679 try 680 { 681 asn1Writer.writeStartSequence(); 682 if (authzID.isPresent()) 683 { 684 asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_USER_ID, 685 authzID.getValue()); 686 } 687 else if (provideDNForAuthzID.isPresent()) 688 { 689 asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_USER_ID, "dn:" + dn); 690 } 691 692 if (currentPW.isPresent()) 693 { 694 asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD, 695 currentPW.getValue()); 696 } 697 else if (currentPWFile.isPresent()) 698 { 699 asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD, 700 currentPWFile.getValue()); 701 } 702 else if (provideDNForAuthzID.isPresent()) 703 { 704 asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD, 705 pw); 706 } 707 708 if (newPW.isPresent()) 709 { 710 asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD, 711 newPW.getValue()); 712 } 713 else if (newPWFile.isPresent()) 714 { 715 asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD, 716 newPWFile.getValue()); 717 } 718 asn1Writer.writeEndSequence(); 719 } 720 catch(Exception e) 721 { 722 err.println(e); 723 } 724 725 ExtendedRequestProtocolOp extendedRequest = 726 new ExtendedRequestProtocolOp(OID_PASSWORD_MODIFY_REQUEST, 727 builder.toByteString()); 728 LDAPMessage requestMessage = 729 new LDAPMessage(nextMessageID.getAndIncrement(), extendedRequest, 730 controls); 731 732 733 // Send the request to the server and read the response. 734 try 735 { 736 writer.writeMessage(requestMessage); 737 } 738 catch (Exception e) 739 { 740 printWrappedText(err, ERR_LDAPPWMOD_CANNOT_SEND_PWMOD_REQUEST.get(e)); 741 unbind(nextMessageID, writer); 742 close(reader, writer); 743 return 1; 744 } 745 746 747 // Read the response from the server. 748 LDAPMessage responseMessage = null; 749 try 750 { 751 responseMessage = reader.readMessage(); 752 } 753 catch (Exception e) 754 { 755 printWrappedText(err, ERR_LDAPPWMOD_CANNOT_READ_PWMOD_RESPONSE.get(e)); 756 unbind(nextMessageID, writer); 757 close(reader, writer); 758 return 1; 759 } 760 761 762 // Make sure that the response was acceptable. 763 ExtendedResponseProtocolOp extendedResponse = 764 responseMessage.getExtendedResponseProtocolOp(); 765 int resultCode = extendedResponse.getResultCode(); 766 if (resultCode != LDAPResultCode.SUCCESS) 767 { 768 printWrappedText(err, ERR_LDAPPWMOD_FAILED.get(resultCode)); 769 770 LocalizableMessage errorMessage = extendedResponse.getErrorMessage(); 771 if (errorMessage != null && errorMessage.length() > 0) 772 { 773 printWrappedText(err, ERR_LDAPPWMOD_FAILURE_ERROR_MESSAGE.get(errorMessage)); 774 } 775 776 DN matchedDN = extendedResponse.getMatchedDN(); 777 if (matchedDN != null) 778 { 779 printWrappedText(err, ERR_LDAPPWMOD_FAILURE_MATCHED_DN.get(matchedDN)); 780 } 781 782 unbind(nextMessageID, writer); 783 close(reader, writer); 784 return resultCode; 785 } 786 else 787 { 788 printWrappedText(out, INFO_LDAPPWMOD_SUCCESSFUL.get()); 789 LocalizableMessage additionalInfo = extendedResponse.getErrorMessage(); 790 if (additionalInfo != null && additionalInfo.length() > 0) 791 { 792 printWrappedText(out, INFO_LDAPPWMOD_ADDITIONAL_INFO.get(additionalInfo)); 793 } 794 } 795 796 797 // See if the response included any controls that we recognize, and if so 798 // then handle them. 799 List<Control> responseControls = responseMessage.getControls(); 800 if (responseControls != null) 801 { 802 for (Control c : responseControls) 803 { 804 if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL)) 805 { 806 try 807 { 808 PasswordPolicyResponseControl pwPolicyControl = 809 PasswordPolicyResponseControl.DECODER 810 .decode(c.isCritical(), ((LDAPControl) c).getValue()); 811 812 PasswordPolicyWarningType pwPolicyWarningType = 813 pwPolicyControl.getWarningType(); 814 if (pwPolicyWarningType != null) 815 { 816 printWrappedText( 817 out, INFO_LDAPPWMOD_PWPOLICY_WARNING.get(pwPolicyWarningType, pwPolicyControl.getWarningValue())); 818 } 819 820 PasswordPolicyErrorType pwPolicyErrorType = 821 pwPolicyControl.getErrorType(); 822 if (pwPolicyErrorType != null) 823 { 824 printWrappedText(out, INFO_LDAPPWMOD_PWPOLICY_ERROR.get(pwPolicyErrorType)); 825 } 826 } 827 catch (Exception e) 828 { 829 printWrappedText(err, ERR_LDAPPWMOD_CANNOT_DECODE_PWPOLICY_CONTROL.get(e)); 830 } 831 } 832 } 833 } 834 835 836 // See if the response included a generated password. 837 ByteString responseValue = extendedResponse.getValue(); 838 if (responseValue != null) 839 { 840 try 841 { 842 ASN1Reader asn1Reader = ASN1.getReader(responseValue); 843 asn1Reader.readStartSequence(); 844 while(asn1Reader.hasNextElement()) 845 { 846 if (asn1Reader.peekType() == TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD) 847 { 848 printWrappedText(out, INFO_LDAPPWMOD_GENERATED_PASSWORD.get(asn1Reader.readOctetStringAsString())); 849 } 850 else 851 { 852 printWrappedText(err, ERR_LDAPPWMOD_UNRECOGNIZED_VALUE_TYPE.get(asn1Reader.readOctetStringAsString())); 853 } 854 } 855 asn1Reader.readEndSequence(); 856 } 857 catch (Exception e) 858 { 859 printWrappedText(err, ERR_LDAPPWMOD_COULD_NOT_DECODE_RESPONSE_VALUE.get(e)); 860 unbind(nextMessageID, writer); 861 close(reader, writer); 862 return 1; 863 } 864 } 865 866 867 // Unbind from the server and close the connection. 868 unbind(nextMessageID, writer); 869 close(reader, writer); 870 return 0; 871 } 872 873 private static void unbind(AtomicInteger nextMessageID, LDAPWriter writer) 874 { 875 try 876 { 877 LDAPMessage requestMessage = new LDAPMessage( 878 nextMessageID.getAndIncrement(), new UnbindRequestProtocolOp()); 879 writer.writeMessage(requestMessage); 880 } 881 catch (Exception e) {} 882 } 883 884} 885