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 2012 profiq, s.r.o. 016 * Portions Copyright 2012-2016 ForgeRock AS. 017 */ 018package org.opends.server.tools; 019 020import static com.forgerock.opendj.cli.ArgumentConstants.*; 021import static com.forgerock.opendj.cli.CliMessages.INFO_DESCRIPTION_BINDPASSWORDFILE; 022import static com.forgerock.opendj.cli.Utils.*; 023import static com.forgerock.opendj.cli.CommonArguments.*; 024 025import static org.opends.messages.ToolMessages.*; 026import static org.opends.server.protocols.ldap.LDAPResultCode.*; 027import static org.opends.server.util.ServerConstants.*; 028import static org.opends.server.util.cli.LDAPConnectionArgumentParser.*; 029 030import java.io.FileInputStream; 031import java.io.FileNotFoundException; 032import java.io.IOException; 033import java.io.InputStream; 034import java.io.OutputStream; 035import java.io.PrintStream; 036import java.util.*; 037import java.util.concurrent.atomic.AtomicInteger; 038 039import org.forgerock.i18n.LocalizableMessage; 040import org.forgerock.i18n.slf4j.LocalizedLogger; 041import org.forgerock.opendj.ldap.ByteString; 042import org.forgerock.opendj.ldap.DN; 043import org.forgerock.opendj.ldap.DecodeException; 044import org.forgerock.opendj.ldap.ResultCode; 045import org.opends.server.controls.*; 046import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 047import org.opends.server.plugins.ChangeNumberControlPlugin; 048import org.opends.server.protocols.ldap.AddRequestProtocolOp; 049import org.opends.server.protocols.ldap.AddResponseProtocolOp; 050import org.opends.server.protocols.ldap.DeleteRequestProtocolOp; 051import org.opends.server.protocols.ldap.DeleteResponseProtocolOp; 052import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp; 053import org.opends.server.protocols.ldap.LDAPAttribute; 054import org.opends.server.protocols.ldap.LDAPConstants; 055import org.opends.server.protocols.ldap.LDAPControl; 056import org.opends.server.protocols.ldap.LDAPFilter; 057import org.opends.server.protocols.ldap.LDAPMessage; 058import org.opends.server.protocols.ldap.ModifyDNRequestProtocolOp; 059import org.opends.server.protocols.ldap.ModifyDNResponseProtocolOp; 060import org.opends.server.protocols.ldap.ModifyRequestProtocolOp; 061import org.opends.server.protocols.ldap.ModifyResponseProtocolOp; 062import org.opends.server.protocols.ldap.ProtocolOp; 063import org.opends.server.types.*; 064import org.opends.server.util.AddChangeRecordEntry; 065import org.opends.server.util.ChangeRecordEntry; 066import org.opends.server.util.EmbeddedUtils; 067import org.opends.server.util.LDIFException; 068import org.opends.server.util.LDIFReader; 069import org.opends.server.util.ModifyChangeRecordEntry; 070import org.opends.server.util.ModifyDNChangeRecordEntry; 071 072import com.forgerock.opendj.cli.ArgumentException; 073import com.forgerock.opendj.cli.ArgumentParser; 074import com.forgerock.opendj.cli.BooleanArgument; 075import com.forgerock.opendj.cli.CliConstants; 076import com.forgerock.opendj.cli.FileBasedArgument; 077import com.forgerock.opendj.cli.IntegerArgument; 078import com.forgerock.opendj.cli.StringArgument; 079 080/** 081 * This class provides a tool that can be used to issue modify requests to the 082 * Directory Server. 083 */ 084public class LDAPModify 085{ 086 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 087 088 /** 089 * The fully-qualified name of this class. 090 */ 091 private static final String CLASS_NAME = "org.opends.server.tools.LDAPModify"; 092 093 /** The message ID counter to use for requests. */ 094 private final AtomicInteger nextMessageID; 095 096 /** The print stream to use for standard error. */ 097 private final PrintStream err; 098 099 /** The print stream to use for standard output. */ 100 private final PrintStream out; 101 102 /** 103 * Constructor for the LDAPModify object. 104 * 105 * @param nextMessageID The message ID counter to use for requests. 106 * @param out The print stream to use for standard output. 107 * @param err The print stream to use for standard error. 108 */ 109 public LDAPModify(AtomicInteger nextMessageID, PrintStream out, 110 PrintStream err) 111 { 112 this.nextMessageID = nextMessageID; 113 this.out = out; 114 this.err = err; 115 } 116 117 118 /** 119 * Read the specified change records from the given input stream 120 * (file or stdin) and execute the given modify request. 121 * 122 * @param connection The connection to use for this modify request. 123 * @param fileNameValue Name of the file from which to read. If null, 124 * input will be read from <code>System.in</code>. 125 * @param modifyOptions The constraints for the modify request. 126 * 127 * @throws IOException If a problem occurs while attempting to communicate 128 * with the Directory Server. 129 * 130 * @throws LDAPException If the Directory Server returns an error response. 131 */ 132 public void readAndExecute(LDAPConnection connection, String fileNameValue, 133 LDAPModifyOptions modifyOptions) 134 throws IOException, LDAPException 135 { 136 ArrayList<Control> controls = modifyOptions.getControls(); 137 LDIFReader reader; 138 139 // Create an LDIF import configuration to do this and then get the reader. 140 141 try 142 { 143 InputStream is = System.in; 144 if(fileNameValue != null) 145 { 146 is = new FileInputStream(fileNameValue); 147 } 148 149 LDIFImportConfig importConfig = new LDIFImportConfig(is); 150 importConfig.setValidateSchema(false); 151 reader = new LDIFReader(importConfig); 152 } catch (Exception e) 153 { 154 logger.traceException(e); 155 LocalizableMessage message = 156 ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ.get(fileNameValue, 157 e.getLocalizedMessage()); 158 throw new FileNotFoundException(message.toString()); 159 } 160 161 // Set this for error messages 162 if (fileNameValue == null) 163 { 164 fileNameValue = "Console"; 165 } 166 167 while (true) 168 { 169 ChangeRecordEntry entry = null; 170 171 try 172 { 173 entry = reader.readChangeRecord(modifyOptions.getDefaultAdd()); 174 } catch (LDIFException le) 175 { 176 logger.traceException(le); 177 if (!modifyOptions.continueOnError()) 178 { 179 try 180 { 181 reader.close(); 182 } 183 catch (Exception e) 184 { 185 logger.traceException(e); 186 } 187 188 LocalizableMessage message = ERR_LDIF_FILE_INVALID_LDIF_ENTRY.get( 189 le.getLineNumber(), fileNameValue, le); 190 throw new IOException(message.toString()); 191 } 192 else 193 { 194 printWrappedText(err, ERR_LDIF_FILE_INVALID_LDIF_ENTRY.get(le.getLineNumber(), fileNameValue, le)); 195 continue; 196 } 197 } catch (Exception e) 198 { 199 logger.traceException(e); 200 201 if (!modifyOptions.continueOnError()) 202 { 203 try 204 { 205 reader.close(); 206 } 207 catch (Exception e2) 208 { 209 logger.traceException(e2); 210 } 211 212 LocalizableMessage message = ERR_LDIF_FILE_READ_ERROR.get(fileNameValue, e); 213 throw new IOException(message.toString()); 214 } 215 else 216 { 217 printWrappedText(err, ERR_LDIF_FILE_READ_ERROR.get(fileNameValue, e)); 218 continue; 219 } 220 } 221 222 // If the entry is null, then we have reached the end of the config file. 223 if(entry == null) 224 { 225 try 226 { 227 reader.close(); 228 } 229 catch (Exception e) 230 { 231 logger.traceException(e); 232 } 233 234 break; 235 } 236 237 ProtocolOp protocolOp = null; 238 ByteString asn1OctetStr = 239 ByteString.valueOfUtf8(entry.getDN().toString()); 240 241 String operationType = ""; 242 switch(entry.getChangeOperationType()) 243 { 244 case ADD: 245 operationType = "ADD"; 246 AddChangeRecordEntry addEntry = (AddChangeRecordEntry) entry; 247 List<Attribute> attrs = addEntry.getAttributes(); 248 ArrayList<RawAttribute> attributes = new ArrayList<>(attrs.size()); 249 for(Attribute a : attrs) 250 { 251 attributes.add(new LDAPAttribute(a)); 252 } 253 protocolOp = new AddRequestProtocolOp(asn1OctetStr, attributes); 254 out.println(INFO_PROCESSING_OPERATION.get(operationType, asn1OctetStr)); 255 break; 256 case DELETE: 257 operationType = "DELETE"; 258 protocolOp = new DeleteRequestProtocolOp(asn1OctetStr); 259 out.println(INFO_PROCESSING_OPERATION.get(operationType, asn1OctetStr)); 260 break; 261 case MODIFY: 262 operationType = "MODIFY"; 263 ModifyChangeRecordEntry modEntry = (ModifyChangeRecordEntry) entry; 264 ArrayList<RawModification> mods = new ArrayList<>(modEntry.getModifications()); 265 protocolOp = new ModifyRequestProtocolOp(asn1OctetStr, mods); 266 out.println(INFO_PROCESSING_OPERATION.get(operationType, asn1OctetStr)); 267 break; 268 case MODIFY_DN: 269 operationType = "MODIFY DN"; 270 ModifyDNChangeRecordEntry modDNEntry = 271 (ModifyDNChangeRecordEntry) entry; 272 if(modDNEntry.getNewSuperiorDN() != null) 273 { 274 protocolOp = new ModifyDNRequestProtocolOp(asn1OctetStr, 275 ByteString.valueOfUtf8(modDNEntry.getNewRDN().toString()), 276 modDNEntry.deleteOldRDN(), 277 ByteString.valueOfUtf8( 278 modDNEntry.getNewSuperiorDN().toString())); 279 } else 280 { 281 protocolOp = new ModifyDNRequestProtocolOp(asn1OctetStr, 282 ByteString.valueOfUtf8(modDNEntry.getNewRDN().toString()), 283 modDNEntry.deleteOldRDN()); 284 } 285 286 out.println(INFO_PROCESSING_OPERATION.get(operationType, asn1OctetStr)); 287 break; 288 default: 289 break; 290 } 291 292 if(!modifyOptions.showOperations()) 293 { 294 LDAPMessage responseMessage = null; 295 try 296 { 297 LDAPMessage message = 298 new LDAPMessage(nextMessageID.getAndIncrement(), protocolOp, 299 controls); 300 connection.getLDAPWriter().writeMessage(message); 301 responseMessage = connection.getLDAPReader().readMessage(); 302 } catch(DecodeException ae) 303 { 304 logger.traceException(ae); 305 printWrappedText(err, INFO_OPERATION_FAILED.get(operationType)); 306 printWrappedText(err, ae.getMessage()); 307 if (!modifyOptions.continueOnError()) 308 { 309 String msg = LDAPToolUtils.getMessageForConnectionException(ae); 310 throw new IOException(msg, ae); 311 } 312 return; 313 } 314 315 int resultCode = 0; 316 LocalizableMessage errorMessage = null; 317 DN matchedDN = null; 318 List<String> referralURLs = null; 319 try 320 { 321 switch(entry.getChangeOperationType()) 322 { 323 case ADD: 324 AddResponseProtocolOp addOp = 325 responseMessage.getAddResponseProtocolOp(); 326 resultCode = addOp.getResultCode(); 327 errorMessage = addOp.getErrorMessage(); 328 matchedDN = addOp.getMatchedDN(); 329 referralURLs = addOp.getReferralURLs(); 330 break; 331 case DELETE: 332 DeleteResponseProtocolOp delOp = 333 responseMessage.getDeleteResponseProtocolOp(); 334 resultCode = delOp.getResultCode(); 335 errorMessage = delOp.getErrorMessage(); 336 matchedDN = delOp.getMatchedDN(); 337 referralURLs = delOp.getReferralURLs(); 338 break; 339 case MODIFY: 340 ModifyResponseProtocolOp modOp = 341 responseMessage.getModifyResponseProtocolOp(); 342 resultCode = modOp.getResultCode(); 343 errorMessage = modOp.getErrorMessage(); 344 matchedDN = modOp.getMatchedDN(); 345 referralURLs = modOp.getReferralURLs(); 346 break; 347 case MODIFY_DN: 348 ModifyDNResponseProtocolOp modDNOp = 349 responseMessage.getModifyDNResponseProtocolOp(); 350 resultCode = modDNOp.getResultCode(); 351 errorMessage = modDNOp.getErrorMessage(); 352 matchedDN = modDNOp.getMatchedDN(); 353 referralURLs = modDNOp.getReferralURLs(); 354 break; 355 default: 356 break; 357 } 358 } 359 catch (ClassCastException ce) 360 { 361 // It is possible that this is extended response. 362 if (responseMessage.getProtocolOpType() == 363 LDAPConstants.OP_TYPE_EXTENDED_RESPONSE) 364 { 365 ExtendedResponseProtocolOp extRes = 366 responseMessage.getExtendedResponseProtocolOp(); 367 resultCode = extRes.getResultCode(); 368 errorMessage = extRes.getErrorMessage(); 369 matchedDN = extRes.getMatchedDN(); 370 referralURLs = extRes.getReferralURLs(); 371 } 372 else 373 { 374 // This should not happen but if it does, then debug log it, 375 // set the error code to OTHER and fall through. 376 logger.traceException(ce); 377 resultCode = ResultCode.OTHER.intValue(); 378 errorMessage = null; 379 matchedDN = null; 380 referralURLs = null; 381 } 382 } 383 384 if(resultCode != SUCCESS && resultCode != REFERRAL) 385 { 386 LocalizableMessage msg = INFO_OPERATION_FAILED.get(operationType); 387 388 if(!modifyOptions.continueOnError()) 389 { 390 throw new LDAPException(resultCode, errorMessage, msg, 391 matchedDN, null); 392 } else 393 { 394 LDAPToolUtils.printErrorMessage(err, msg, resultCode, errorMessage, 395 matchedDN); 396 } 397 } else 398 { 399 out.println(INFO_OPERATION_SUCCESSFUL.get(operationType, asn1OctetStr)); 400 401 if (errorMessage != null) 402 { 403 printWrappedText(out, errorMessage); 404 } 405 406 if (referralURLs != null) 407 { 408 out.println(referralURLs); 409 } 410 } 411 412 413 for (Control c : responseMessage.getControls()) 414 { 415 String oid = c.getOID(); 416 if (oid.equals(OID_LDAP_READENTRY_PREREAD)) 417 { 418 SearchResultEntry searchEntry; 419 try 420 { 421 LDAPPreReadResponseControl prrc; 422 if(c instanceof LDAPControl) 423 { 424 // Control needs to be decoded 425 prrc = LDAPPreReadResponseControl.DECODER.decode( 426 c.isCritical(), ((LDAPControl) c).getValue()); 427 } 428 else 429 { 430 prrc = (LDAPPreReadResponseControl)c; 431 } 432 searchEntry = prrc.getSearchEntry(); 433 } 434 catch (DirectoryException de) 435 { 436 printWrappedText(err, ERR_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE.get(de.getMessage())); 437 continue; 438 } 439 440 StringBuilder buffer = new StringBuilder(); 441 searchEntry.toString(buffer, 0); 442 out.println(INFO_LDAPMODIFY_PREREAD_ENTRY.get()); 443 out.println(buffer); 444 } 445 else if (oid.equals(OID_LDAP_READENTRY_POSTREAD)) 446 { 447 SearchResultEntry searchEntry; 448 try 449 { 450 LDAPPostReadResponseControl pprc; 451 if (c instanceof LDAPControl) 452 { 453 // Control needs to be decoded 454 pprc = LDAPPostReadResponseControl.DECODER.decode(c 455 .isCritical(), ((LDAPControl) c).getValue()); 456 } 457 else 458 { 459 pprc = (LDAPPostReadResponseControl)c; 460 } 461 searchEntry = pprc.getSearchEntry(); 462 } 463 catch (DirectoryException de) 464 { 465 printWrappedText(err, ERR_LDAPMODIFY_POSTREAD_CANNOT_DECODE_VALUE.get(de.getMessage())); 466 continue; 467 } 468 469 StringBuilder buffer = new StringBuilder(); 470 searchEntry.toString(buffer, 0); 471 out.println(INFO_LDAPMODIFY_POSTREAD_ENTRY.get()); 472 out.println(buffer); 473 } 474 else if (oid.equals(OID_CSN_CONTROL)) 475 { 476 if(c instanceof LDAPControl) 477 { 478 // Don't really need to decode since its just an octet string. 479 out.println(INFO_CHANGE_NUMBER_CONTROL_RESULT.get( 480 operationType, ((LDAPControl)c).getValue())); 481 } 482 else 483 { 484 out.println(INFO_CHANGE_NUMBER_CONTROL_RESULT.get(operationType, 485 ((ChangeNumberControlPlugin.ChangeNumberControl)c).getCSN())); 486 } 487 } 488 } 489 } 490 } 491 492 } 493 494 /** 495 * The main method for LDAPModify tool. 496 * 497 * @param args The command-line arguments provided to this program. 498 */ 499 500 public static void main(String[] args) 501 { 502 int retCode = mainModify(args, true, System.out, System.err); 503 504 if(retCode != 0) 505 { 506 System.exit(filterExitCode(retCode)); 507 } 508 } 509 510 511 /** 512 * Parses the provided command-line arguments and uses that information to 513 * run the ldapmodify tool. 514 * 515 * @param args The command-line arguments provided to this program. 516 * 517 * @return The error code. 518 */ 519 520 public static int mainModify(String[] args) 521 { 522 return mainModify(args, true, System.out, System.err); 523 } 524 525 526 /** 527 * Parses the provided command-line arguments and uses that information to 528 * run the ldapmodify tool. 529 * 530 * @param args The command-line arguments provided to this 531 * program. 532 * @param initializeServer Indicates whether to initialize the server. 533 * @param outStream The output stream to use for standard output, or 534 * <CODE>null</CODE> if standard output is not 535 * needed. 536 * @param errStream The output stream to use for standard error, or 537 * <CODE>null</CODE> if standard error is not 538 * needed. 539 * 540 * @return The error code. 541 */ 542 543 public static int mainModify(String[] args, boolean initializeServer, 544 OutputStream outStream, OutputStream errStream) 545 { 546 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 547 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 548 549 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions(); 550 LDAPModifyOptions modifyOptions = new LDAPModifyOptions(); 551 LDAPConnection connection = null; 552 553 final BooleanArgument continueOnError; 554 final BooleanArgument defaultAdd; 555 final BooleanArgument noop; 556 final BooleanArgument reportAuthzID; 557 final BooleanArgument saslExternal; 558 final BooleanArgument showUsage; 559 final BooleanArgument startTLS; 560 final BooleanArgument trustAll; 561 final BooleanArgument useSSL; 562 final BooleanArgument verbose; 563 final FileBasedArgument bindPasswordFile; 564 final FileBasedArgument keyStorePasswordFile; 565 final FileBasedArgument trustStorePasswordFile; 566 final IntegerArgument connectTimeout; 567 final IntegerArgument port; 568 final IntegerArgument version; 569 final StringArgument assertionFilter; 570 final StringArgument bindDN; 571 final StringArgument bindPassword; 572 final StringArgument certNickname; 573 final StringArgument controlStr; 574 final StringArgument encodingStr; 575 final StringArgument filename; 576 final StringArgument hostName; 577 final StringArgument keyStorePath; 578 final StringArgument keyStorePassword; 579 final StringArgument postReadAttributes; 580 final StringArgument preReadAttributes; 581 final StringArgument proxyAuthzID; 582 final StringArgument saslOptions; 583 final StringArgument trustStorePath; 584 final StringArgument trustStorePassword; 585 final StringArgument propertiesFileArgument; 586 final BooleanArgument noPropertiesFileArgument; 587 588 // Create the command-line argument parser for use with this program. 589 LocalizableMessage toolDescription = INFO_LDAPMODIFY_TOOL_DESCRIPTION.get(); 590 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, 591 false); 592 argParser.setShortToolDescription(REF_SHORT_DESC_LDAPMODIFY.get()); 593 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 594 try 595 { 596 propertiesFileArgument = 597 StringArgument.builder(OPTION_LONG_PROP_FILE_PATH) 598 .description(INFO_DESCRIPTION_PROP_FILE_PATH.get()) 599 .valuePlaceholder(INFO_PROP_FILE_PATH_PLACEHOLDER.get()) 600 .buildAndAddToParser(argParser); 601 argParser.setFilePropertiesArgument(propertiesFileArgument); 602 603 noPropertiesFileArgument = 604 BooleanArgument.builder(OPTION_LONG_NO_PROP_FILE) 605 .description(INFO_DESCRIPTION_NO_PROP_FILE.get()) 606 .buildAndAddToParser(argParser); 607 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); 608 609 hostName = 610 StringArgument.builder(OPTION_LONG_HOST) 611 .shortIdentifier(OPTION_SHORT_HOST) 612 .description(INFO_DESCRIPTION_HOST.get()) 613 .defaultValue("localhost") 614 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 615 .buildAndAddToParser(argParser); 616 port = 617 IntegerArgument.builder(OPTION_LONG_PORT) 618 .shortIdentifier(OPTION_SHORT_PORT) 619 .description(INFO_DESCRIPTION_PORT.get()) 620 .range(1, 65535) 621 .defaultValue(389) 622 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 623 .buildAndAddToParser(argParser); 624 useSSL = 625 BooleanArgument.builder(OPTION_LONG_USE_SSL) 626 .shortIdentifier(OPTION_SHORT_USE_SSL) 627 .description(INFO_DESCRIPTION_USE_SSL.get()) 628 .buildAndAddToParser(argParser); 629 startTLS = 630 BooleanArgument.builder(OPTION_LONG_START_TLS) 631 .shortIdentifier(OPTION_SHORT_START_TLS) 632 .description(INFO_DESCRIPTION_START_TLS.get()) 633 .buildAndAddToParser(argParser); 634 bindDN = 635 StringArgument.builder(OPTION_LONG_BINDDN) 636 .shortIdentifier(OPTION_SHORT_BINDDN) 637 .description(INFO_DESCRIPTION_BINDDN.get()) 638 .valuePlaceholder(INFO_BINDDN_PLACEHOLDER.get()) 639 .buildAndAddToParser(argParser); 640 bindPassword = 641 StringArgument.builder(OPTION_LONG_BINDPWD) 642 .shortIdentifier(OPTION_SHORT_BINDPWD) 643 .description(INFO_DESCRIPTION_BINDPASSWORD.get()) 644 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 645 .buildAndAddToParser(argParser); 646 bindPasswordFile = 647 FileBasedArgument.builder(OPTION_LONG_BINDPWD_FILE) 648 .shortIdentifier(OPTION_SHORT_BINDPWD_FILE) 649 .description(INFO_DESCRIPTION_BINDPASSWORDFILE.get()) 650 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 651 .buildAndAddToParser(argParser); 652 defaultAdd = 653 BooleanArgument.builder("defaultAdd") 654 .shortIdentifier('a') 655 .description(INFO_MODIFY_DESCRIPTION_DEFAULT_ADD.get()) 656 .buildAndAddToParser(argParser); 657 filename = 658 StringArgument.builder(OPTION_LONG_FILENAME) 659 .shortIdentifier(OPTION_SHORT_FILENAME) 660 .description(INFO_LDAPMODIFY_DESCRIPTION_FILENAME.get()) 661 .valuePlaceholder(INFO_FILE_PLACEHOLDER.get()) 662 .buildAndAddToParser(argParser); 663 saslExternal = 664 BooleanArgument.builder("useSASLExternal") 665 .shortIdentifier('r') 666 .description(INFO_DESCRIPTION_USE_SASL_EXTERNAL.get()) 667 .buildAndAddToParser(argParser); 668 saslOptions = 669 StringArgument.builder(OPTION_LONG_SASLOPTION) 670 .shortIdentifier(OPTION_SHORT_SASLOPTION) 671 .description(INFO_DESCRIPTION_SASL_PROPERTIES.get()) 672 .multiValued() 673 .valuePlaceholder(INFO_SASL_OPTION_PLACEHOLDER.get()) 674 .buildAndAddToParser(argParser); 675 676 trustAll = trustAllArgument(); 677 argParser.addArgument(trustAll); 678 679 keyStorePath = 680 StringArgument.builder(OPTION_LONG_KEYSTOREPATH) 681 .shortIdentifier(OPTION_SHORT_KEYSTOREPATH) 682 .description(INFO_DESCRIPTION_KEYSTOREPATH.get()) 683 .valuePlaceholder(INFO_KEYSTOREPATH_PLACEHOLDER.get()) 684 .buildAndAddToParser(argParser); 685 keyStorePassword = 686 StringArgument.builder(OPTION_LONG_KEYSTORE_PWD) 687 .shortIdentifier(OPTION_SHORT_KEYSTORE_PWD) 688 .description(INFO_DESCRIPTION_KEYSTOREPASSWORD.get()) 689 .valuePlaceholder(INFO_KEYSTORE_PWD_PLACEHOLDER.get()) 690 .buildAndAddToParser(argParser); 691 keyStorePasswordFile = 692 FileBasedArgument.builder(OPTION_LONG_KEYSTORE_PWD_FILE) 693 .shortIdentifier(OPTION_SHORT_KEYSTORE_PWD_FILE) 694 .description(INFO_DESCRIPTION_KEYSTOREPASSWORD_FILE.get()) 695 .valuePlaceholder(INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get()) 696 .buildAndAddToParser(argParser); 697 certNickname = 698 StringArgument.builder("certNickname") 699 .shortIdentifier('N') 700 .description(INFO_DESCRIPTION_CERT_NICKNAME.get()) 701 .valuePlaceholder(INFO_NICKNAME_PLACEHOLDER.get()) 702 .buildAndAddToParser(argParser); 703 trustStorePath = 704 StringArgument.builder(OPTION_LONG_TRUSTSTOREPATH) 705 .shortIdentifier(OPTION_SHORT_TRUSTSTOREPATH) 706 .description(INFO_DESCRIPTION_TRUSTSTOREPATH.get()) 707 .valuePlaceholder(INFO_TRUSTSTOREPATH_PLACEHOLDER.get()) 708 .buildAndAddToParser(argParser); 709 trustStorePassword = 710 StringArgument.builder(OPTION_LONG_TRUSTSTORE_PWD) 711 .description(INFO_DESCRIPTION_TRUSTSTOREPASSWORD.get()) 712 .valuePlaceholder(INFO_TRUSTSTORE_PWD_PLACEHOLDER.get()) 713 .buildAndAddToParser(argParser); 714 trustStorePasswordFile = 715 FileBasedArgument.builder(OPTION_LONG_TRUSTSTORE_PWD_FILE) 716 .shortIdentifier(OPTION_SHORT_TRUSTSTORE_PWD_FILE) 717 .description(INFO_DESCRIPTION_TRUSTSTOREPASSWORD_FILE.get()) 718 .valuePlaceholder(INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get()) 719 .buildAndAddToParser(argParser); 720 proxyAuthzID = 721 StringArgument.builder(OPTION_LONG_PROXYAUTHID) 722 .shortIdentifier(OPTION_SHORT_PROXYAUTHID) 723 .description(INFO_DESCRIPTION_PROXY_AUTHZID.get()) 724 .valuePlaceholder(INFO_PROXYAUTHID_PLACEHOLDER.get()) 725 .buildAndAddToParser(argParser); 726 reportAuthzID = 727 BooleanArgument.builder("reportAuthzID") 728 .shortIdentifier('E') 729 .description(INFO_DESCRIPTION_REPORT_AUTHZID.get()) 730 .buildAndAddToParser(argParser); 731 assertionFilter = 732 StringArgument.builder(OPTION_LONG_ASSERTION_FILE) 733 .description(INFO_DESCRIPTION_ASSERTION_FILTER.get()) 734 .valuePlaceholder(INFO_ASSERTION_FILTER_PLACEHOLDER.get()) 735 .buildAndAddToParser(argParser); 736 preReadAttributes = 737 StringArgument.builder("preReadAttributes") 738 .description(INFO_DESCRIPTION_PREREAD_ATTRS.get()) 739 .valuePlaceholder(INFO_ATTRIBUTE_LIST_PLACEHOLDER.get()) 740 .buildAndAddToParser(argParser); 741 postReadAttributes = 742 StringArgument.builder("postReadAttributes") 743 .description(INFO_DESCRIPTION_POSTREAD_ATTRS.get()) 744 .valuePlaceholder(INFO_ATTRIBUTE_LIST_PLACEHOLDER.get()) 745 .buildAndAddToParser(argParser); 746 controlStr = 747 StringArgument.builder("control") 748 .shortIdentifier('J') 749 .description(INFO_DESCRIPTION_CONTROLS.get()) 750 .multiValued() 751 .valuePlaceholder(INFO_LDAP_CONTROL_PLACEHOLDER.get()) 752 .buildAndAddToParser(argParser); 753 version = 754 IntegerArgument.builder(OPTION_LONG_PROTOCOL_VERSION) 755 .shortIdentifier(OPTION_SHORT_PROTOCOL_VERSION) 756 .description(INFO_DESCRIPTION_VERSION.get()) 757 .defaultValue(3) 758 .valuePlaceholder(INFO_PROTOCOL_VERSION_PLACEHOLDER.get()) 759 .buildAndAddToParser(argParser); 760 connectTimeout = 761 IntegerArgument.builder(OPTION_LONG_CONNECT_TIMEOUT) 762 .description(INFO_DESCRIPTION_CONNECTION_TIMEOUT.get()) 763 .lowerBound(0) 764 .defaultValue(CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT) 765 .valuePlaceholder(INFO_TIMEOUT_PLACEHOLDER.get()) 766 .buildAndAddToParser(argParser); 767 encodingStr = 768 StringArgument.builder("encoding") 769 .shortIdentifier('i') 770 .description(INFO_DESCRIPTION_ENCODING.get()) 771 .valuePlaceholder(INFO_ENCODING_PLACEHOLDER.get()) 772 .buildAndAddToParser(argParser); 773 continueOnError = 774 BooleanArgument.builder("continueOnError") 775 .shortIdentifier('c') 776 .description(INFO_DESCRIPTION_CONTINUE_ON_ERROR.get()) 777 .buildAndAddToParser(argParser); 778 noop = 779 BooleanArgument.builder(OPTION_LONG_DRYRUN) 780 .shortIdentifier(OPTION_SHORT_DRYRUN) 781 .description(INFO_DESCRIPTION_NOOP.get()) 782 .buildAndAddToParser(argParser); 783 784 verbose = verboseArgument(); 785 argParser.addArgument(verbose); 786 787 showUsage = showUsageArgument(); 788 argParser.addArgument(showUsage); 789 argParser.setUsageArgument(showUsage, out); 790 } catch (ArgumentException ae) 791 { 792 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 793 return CLIENT_SIDE_PARAM_ERROR; 794 } 795 796 // Parse the command-line arguments provided to this program. 797 try 798 { 799 argParser.parseArguments(args); 800 } 801 catch (ArgumentException ae) 802 { 803 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 804 return CLIENT_SIDE_PARAM_ERROR; 805 } 806 807 // If we should just display usage or version information, 808 // then print it and exit. 809 if (argParser.usageOrVersionDisplayed()) 810 { 811 return SUCCESS; 812 } 813 814 if (bindPassword.isPresent() && bindPasswordFile.isPresent()) 815 { 816 printWrappedText(err, conflictingArgsErrorMessage(bindPassword, bindPasswordFile)); 817 return CLIENT_SIDE_PARAM_ERROR; 818 } 819 820 String hostNameValue = hostName.getValue(); 821 int portNumber = 389; 822 try 823 { 824 portNumber = port.getIntValue(); 825 } catch(ArgumentException ae) 826 { 827 logger.traceException(ae); 828 argParser.displayMessageAndUsageReference(err, ae.getMessageObject()); 829 return CLIENT_SIDE_PARAM_ERROR; 830 } 831 832 try 833 { 834 int versionNumber = version.getIntValue(); 835 if(versionNumber != 2 && versionNumber != 3) 836 { 837 printWrappedText(err, ERR_DESCRIPTION_INVALID_VERSION.get(versionNumber)); 838 return CLIENT_SIDE_PARAM_ERROR; 839 } 840 connectionOptions.setVersionNumber(versionNumber); 841 } catch(ArgumentException ae) 842 { 843 logger.traceException(ae); 844 argParser.displayMessageAndUsageReference(err, ae.getMessageObject()); 845 return CLIENT_SIDE_PARAM_ERROR; 846 } 847 848 String bindDNValue = bindDN.getValue(); 849 String fileNameValue = filename.getValue(); 850 String bindPasswordValue; 851 try 852 { 853 bindPasswordValue = getPasswordValue( 854 bindPassword, bindPasswordFile, bindDNValue, out, err); 855 } 856 catch (Exception ex) 857 { 858 logger.traceException(ex); 859 printWrappedText(err, ex.getMessage()); 860 return CLIENT_SIDE_PARAM_ERROR; 861 } 862 863 String keyStorePathValue = keyStorePath.getValue(); 864 String trustStorePathValue = trustStorePath.getValue(); 865 866 String keyStorePasswordValue = null; 867 if (keyStorePassword.isPresent()) 868 { 869 keyStorePasswordValue = keyStorePassword.getValue(); 870 } 871 else if (keyStorePasswordFile.isPresent()) 872 { 873 keyStorePasswordValue = keyStorePasswordFile.getValue(); 874 } 875 876 String trustStorePasswordValue = null; 877 if (trustStorePassword.isPresent()) 878 { 879 trustStorePasswordValue = trustStorePassword.getValue(); 880 } 881 else if (trustStorePasswordFile.isPresent()) 882 { 883 trustStorePasswordValue = trustStorePasswordFile.getValue(); 884 } 885 886 modifyOptions.setShowOperations(noop.isPresent()); 887 modifyOptions.setVerbose(verbose.isPresent()); 888 modifyOptions.setContinueOnError(continueOnError.isPresent()); 889 modifyOptions.setEncoding(encodingStr.getValue()); 890 modifyOptions.setDefaultAdd(defaultAdd.isPresent()); 891 892 if (controlStr.isPresent()) 893 { 894 for (String ctrlString : controlStr.getValues()) 895 { 896 Control ctrl = LDAPToolUtils.getControl(ctrlString, err); 897 if(ctrl == null) 898 { 899 printWrappedText(err, ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString)); 900 return CLIENT_SIDE_PARAM_ERROR; 901 } 902 modifyOptions.getControls().add(ctrl); 903 } 904 } 905 906 if (proxyAuthzID.isPresent()) 907 { 908 Control proxyControl = 909 new ProxiedAuthV2Control(true, 910 ByteString.valueOfUtf8(proxyAuthzID.getValue())); 911 modifyOptions.getControls().add(proxyControl); 912 } 913 914 if (assertionFilter.isPresent()) 915 { 916 String filterString = assertionFilter.getValue(); 917 LDAPFilter filter; 918 try 919 { 920 filter = LDAPFilter.decode(filterString); 921 922 Control assertionControl = 923 new LDAPAssertionRequestControl(true, filter); 924 modifyOptions.getControls().add(assertionControl); 925 } 926 catch (LDAPException le) 927 { 928 printWrappedText(err, ERR_LDAP_ASSERTION_INVALID_FILTER.get(le.getMessage())); 929 return CLIENT_SIDE_PARAM_ERROR; 930 } 931 } 932 933 if (preReadAttributes.isPresent()) 934 { 935 String valueStr = preReadAttributes.getValue(); 936 Set<String> attrElements = new LinkedHashSet<>(); 937 938 StringTokenizer tokenizer = new StringTokenizer(valueStr, ", "); 939 while (tokenizer.hasMoreTokens()) 940 { 941 attrElements.add(tokenizer.nextToken()); 942 } 943 944 Control c = new LDAPPreReadRequestControl(true, attrElements); 945 modifyOptions.getControls().add(c); 946 } 947 948 if (postReadAttributes.isPresent()) 949 { 950 String valueStr = postReadAttributes.getValue(); 951 Set<String> attrElements = new LinkedHashSet<>(); 952 953 StringTokenizer tokenizer = new StringTokenizer(valueStr, ", "); 954 while (tokenizer.hasMoreTokens()) 955 { 956 attrElements.add(tokenizer.nextToken()); 957 } 958 959 Control c = new LDAPPostReadRequestControl(true, attrElements); 960 modifyOptions.getControls().add(c); 961 } 962 963 // Set the connection options. 964 connectionOptions.setSASLExternal(saslExternal.isPresent()); 965 if(saslOptions.isPresent()) 966 { 967 for (String saslOption : saslOptions.getValues()) 968 { 969 boolean val = saslOption.startsWith("mech=") 970 ? connectionOptions.setSASLMechanism(saslOption) 971 : connectionOptions.addSASLProperty(saslOption); 972 if (!val) 973 { 974 return CLIENT_SIDE_PARAM_ERROR; 975 } 976 } 977 } 978 979 connectionOptions.setUseSSL(useSSL.isPresent()); 980 connectionOptions.setStartTLS(startTLS.isPresent()); 981 connectionOptions.setReportAuthzID(reportAuthzID.isPresent()); 982 983 if(connectionOptions.useSASLExternal()) 984 { 985 if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS()) 986 { 987 printWrappedText(err, ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get()); 988 return CLIENT_SIDE_PARAM_ERROR; 989 } 990 if(keyStorePathValue == null) 991 { 992 printWrappedText(err, ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get()); 993 return CLIENT_SIDE_PARAM_ERROR; 994 } 995 } 996 997 connectionOptions.setVerbose(verbose.isPresent()); 998 999 LDAPModify ldapModify = null; 1000 try 1001 { 1002 if (initializeServer) 1003 { 1004 // Bootstrap and initialize directory data structures. 1005 EmbeddedUtils.initializeForClientUse(); 1006 } 1007 1008 // Connect to the specified host with the supplied userDN and password. 1009 SSLConnectionFactory sslConnectionFactory = null; 1010 if(connectionOptions.useSSL() || connectionOptions.useStartTLS()) 1011 { 1012 String clientAlias; 1013 if (certNickname.isPresent()) 1014 { 1015 clientAlias = certNickname.getValue(); 1016 } 1017 else 1018 { 1019 clientAlias = null; 1020 } 1021 1022 sslConnectionFactory = new SSLConnectionFactory(); 1023 sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue, 1024 keyStorePasswordValue, clientAlias, 1025 trustStorePathValue, trustStorePasswordValue); 1026 connectionOptions.setSSLConnectionFactory(sslConnectionFactory); 1027 } 1028 1029 AtomicInteger nextMessageID = new AtomicInteger(1); 1030 connection = new LDAPConnection(hostNameValue, portNumber, 1031 connectionOptions, out, err); 1032 int timeout = connectTimeout.getIntValue(); 1033 connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID, 1034 timeout); 1035 1036 ldapModify = new LDAPModify(nextMessageID, out, err); 1037 ldapModify.readAndExecute(connection, fileNameValue, modifyOptions); 1038 } catch(LDAPException le) 1039 { 1040 logger.traceException(le); 1041 LDAPToolUtils.printErrorMessage(err, le.getMessageObject(), 1042 le.getResultCode(), 1043 le.getErrorMessage(), le.getMatchedDN()); 1044 return le.getResultCode(); 1045 } catch(LDAPConnectionException lce) 1046 { 1047 logger.traceException(lce); 1048 LDAPToolUtils.printErrorMessage(err, lce.getMessageObject(), 1049 lce.getResultCode(), 1050 lce.getErrorMessage(), 1051 lce.getMatchedDN()); 1052 return lce.getResultCode(); 1053 } catch (FileNotFoundException fe) 1054 { 1055 logger.traceException(fe); 1056 printWrappedText(err, fe.getMessage()); 1057 return CLIENT_SIDE_PARAM_ERROR; 1058 } 1059 catch(ArgumentException e) 1060 { 1061 argParser.displayMessageAndUsageReference(err, e.getMessageObject()); 1062 return 1; 1063 } 1064 catch(Exception e) 1065 { 1066 logger.traceException(e); 1067 printWrappedText(err, e.getMessage()); 1068 return OPERATIONS_ERROR; 1069 } finally 1070 { 1071 if(connection != null) 1072 { 1073 if (ldapModify == null) 1074 { 1075 connection.close(null); 1076 } 1077 else 1078 { 1079 connection.close(ldapModify.nextMessageID); 1080 } 1081 } 1082 } 1083 return SUCCESS; 1084 } 1085 1086} 1087