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