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