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