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-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static com.forgerock.opendj.cli.ArgumentConstants.*; 020import static com.forgerock.opendj.cli.CliMessages.INFO_DESCRIPTION_BINDPASSWORDFILE; 021import static com.forgerock.opendj.cli.Utils.*; 022import static com.forgerock.opendj.cli.CommonArguments.*; 023 024import static org.opends.messages.ToolMessages.*; 025import static org.opends.server.protocols.ldap.LDAPResultCode.*; 026import static org.opends.server.util.cli.LDAPConnectionArgumentParser.*; 027 028import java.io.BufferedReader; 029import java.io.FileReader; 030import java.io.IOException; 031import java.io.InputStreamReader; 032import java.io.OutputStream; 033import java.io.PrintStream; 034import java.io.Reader; 035import java.util.ArrayList; 036import java.util.List; 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.DecodeException; 043import org.opends.server.controls.SubtreeDeleteControl; 044import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 045import org.opends.server.protocols.ldap.DeleteRequestProtocolOp; 046import org.opends.server.protocols.ldap.DeleteResponseProtocolOp; 047import org.opends.server.protocols.ldap.LDAPMessage; 048import org.opends.server.protocols.ldap.ProtocolOp; 049import org.opends.server.types.Control; 050import org.opends.server.types.LDAPException; 051import org.opends.server.types.NullOutputStream; 052import org.opends.server.util.EmbeddedUtils; 053 054import com.forgerock.opendj.cli.ArgumentException; 055import com.forgerock.opendj.cli.ArgumentParser; 056import com.forgerock.opendj.cli.BooleanArgument; 057import com.forgerock.opendj.cli.CliConstants; 058import com.forgerock.opendj.cli.FileBasedArgument; 059import com.forgerock.opendj.cli.IntegerArgument; 060import com.forgerock.opendj.cli.StringArgument; 061 062/** 063 * This class provides a tool that can be used to issue delete requests to the 064 * Directory Server. 065 */ 066public class LDAPDelete 067{ 068 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 069 070 /** The fully-qualified name of this class. */ 071 private static final String CLASS_NAME = "org.opends.server.tools.LDAPDelete"; 072 073 074 /** The message ID counter to use for requests. */ 075 private final AtomicInteger nextMessageID; 076 077 /** The print stream to use for standard error. */ 078 private final PrintStream err; 079 /** The print stream to use for standard output. */ 080 private final PrintStream out; 081 082 083 084 /** 085 * Constructor for the LDAPDelete object. 086 * 087 * @param nextMessageID The next message ID to use for requests. 088 * @param out The print stream to use for standard output. 089 * @param err The print stream to use for standard error. 090 */ 091 public LDAPDelete(AtomicInteger nextMessageID, PrintStream out, 092 PrintStream err) 093 { 094 this.nextMessageID = nextMessageID; 095 this.out = out; 096 this.err = err; 097 } 098 099 /** 100 * Execute the delete request on the specified list of DNs. 101 * 102 * @param connection The connection to use to execute the request. 103 * @param lines The list of DNs to delete. 104 * @param deleteOptions The constraints to use for this request. 105 * 106 * @throws IOException If a problem occurs while attempting to communicate 107 * with the Directory Server. 108 * 109 * @throws LDAPException If the Directory Server returns an error response. 110 */ 111 public void readAndExecute(LDAPConnection connection, 112 List<String> lines, 113 LDAPDeleteOptions deleteOptions) 114 throws IOException, LDAPException 115 { 116 for(String line : lines) 117 { 118 executeDelete(connection, line, deleteOptions); 119 } 120 } 121 122 /** 123 * Read the specified DNs from the given reader 124 * (file or stdin) and execute the given delete request. 125 * 126 * @param connection The connection to use to execute the request. 127 * @param reader The reader to read the list of DNs from. 128 * @param deleteOptions The constraints to use for this request. 129 * 130 * @throws IOException If a problem occurs while attempting to communicate 131 * with the Directory Server. 132 * 133 * @throws LDAPException If the Directory Server returns an error response. 134 */ 135 public void readAndExecute(LDAPConnection connection, Reader reader, 136 LDAPDeleteOptions deleteOptions) 137 throws IOException, LDAPException 138 { 139 BufferedReader in = new BufferedReader(reader); 140 String line = null; 141 142 while ((line = in.readLine()) != null) 143 { 144 executeDelete(connection, line, deleteOptions); 145 } 146 in.close(); 147 } 148 149 150 /** 151 * Execute the delete request for the specified DN. 152 * 153 * @param connection The connection to use to execute the request. 154 * @param line The DN to delete. 155 * @param deleteOptions The list of constraints for this request. 156 * 157 * @throws IOException If a problem occurs while attempting to communicate 158 * with the Directory Server. 159 * 160 * @throws LDAPException If the Directory Server returns an error response. 161 */ 162 private void executeDelete(LDAPConnection connection, String line, 163 LDAPDeleteOptions deleteOptions) 164 throws IOException, LDAPException 165 { 166 ArrayList<Control> controls = deleteOptions.getControls(); 167 ProtocolOp protocolOp = null; 168 ByteString asn1OctetStr = ByteString.valueOfUtf8(line); 169 170 protocolOp = new DeleteRequestProtocolOp(asn1OctetStr); 171 172 out.println(INFO_PROCESSING_OPERATION.get("DELETE", asn1OctetStr)); 173 if(!deleteOptions.showOperations()) 174 { 175 LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(), 176 protocolOp, controls); 177 LDAPMessage responseMessage = null; 178 try 179 { 180 connection.getLDAPWriter().writeMessage(message); 181 responseMessage = connection.getLDAPReader().readMessage(); 182 } catch(DecodeException ae) 183 { 184 logger.traceException(ae); 185 if (!deleteOptions.continueOnError()) 186 { 187 String msg = LDAPToolUtils.getMessageForConnectionException(ae); 188 throw new IOException(msg, ae); 189 } 190 else 191 { 192 printWrappedText(err, INFO_OPERATION_FAILED.get("DELETE")); 193 printWrappedText(err, ae.getMessage()); 194 return; 195 } 196 } 197 198 DeleteResponseProtocolOp op = 199 responseMessage.getDeleteResponseProtocolOp(); 200 int resultCode = op.getResultCode(); 201 LocalizableMessage errorMessage = op.getErrorMessage(); 202 if(resultCode != SUCCESS && resultCode != REFERRAL && 203 !deleteOptions.continueOnError()) 204 { 205 LocalizableMessage msg = INFO_OPERATION_FAILED.get("DELETE"); 206 throw new LDAPException(resultCode, errorMessage, msg, 207 op.getMatchedDN(), null); 208 } else 209 { 210 if(resultCode != SUCCESS && resultCode != REFERRAL) 211 { 212 LocalizableMessage msg = INFO_OPERATION_FAILED.get("DELETE"); 213 LDAPToolUtils.printErrorMessage(err, msg, resultCode, errorMessage, 214 op.getMatchedDN()); 215 } else 216 { 217 LocalizableMessage msg = INFO_OPERATION_SUCCESSFUL.get("DELETE", line); 218 out.println(msg); 219 } 220 } 221 } 222 } 223 224 /** 225 * The main method for LDAPDelete tool. 226 * 227 * @param args The command-line arguments provided to this program. 228 */ 229 230 public static void main(String[] args) 231 { 232 int retCode = mainDelete(args, true, System.out, System.err); 233 234 if(retCode != 0) 235 { 236 System.exit(filterExitCode(retCode)); 237 } 238 } 239 240 /** 241 * Parses the provided command-line arguments and uses that information to 242 * run the ldapdelete tool. 243 * 244 * @param args The command-line arguments provided to this program. 245 * 246 * @return The error code. 247 */ 248 249 public static int mainDelete(String[] args) 250 { 251 return mainDelete(args, true, System.out, System.err); 252 } 253 254 /** 255 * Parses the provided command-line arguments and uses that information to 256 * run the ldapdelete tool. 257 * 258 * @param args The command-line arguments provided to this 259 * program. 260 * @param initializeServer Indicates whether to initialize the server. 261 * @param outStream The output stream to use for standard output, or 262 * <CODE>null</CODE> if standard output is not 263 * needed. 264 * @param errStream The output stream to use for standard error, or 265 * <CODE>null</CODE> if standard error is not 266 * needed. 267 * 268 * @return The error code. 269 */ 270 271 public static int mainDelete(String[] args, boolean initializeServer, 272 OutputStream outStream, OutputStream errStream) 273 { 274 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 275 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 276 277 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions(); 278 LDAPDeleteOptions deleteOptions = new LDAPDeleteOptions(); 279 LDAPConnection connection = null; 280 281 final BooleanArgument continueOnError; 282 final BooleanArgument deleteSubtree; 283 final BooleanArgument noop; 284 final BooleanArgument saslExternal; 285 final BooleanArgument showUsage; 286 final BooleanArgument startTLS; 287 final BooleanArgument trustAll; 288 final BooleanArgument useSSL; 289 final BooleanArgument verbose; 290 final FileBasedArgument bindPasswordFile; 291 final FileBasedArgument keyStorePasswordFile; 292 final FileBasedArgument trustStorePasswordFile; 293 final IntegerArgument port; 294 final IntegerArgument version; 295 final StringArgument bindDN; 296 final StringArgument bindPassword; 297 final StringArgument certNickname; 298 final StringArgument controlStr; 299 final StringArgument encodingStr; 300 final StringArgument filename; 301 final StringArgument hostName; 302 final StringArgument keyStorePath; 303 final StringArgument keyStorePassword; 304 final StringArgument saslOptions; 305 final StringArgument trustStorePath; 306 final StringArgument trustStorePassword; 307 final IntegerArgument connectTimeout; 308 final StringArgument propertiesFileArgument; 309 final BooleanArgument noPropertiesFileArgument; 310 311 Reader rdr = null; 312 List<String> dnStrings = new ArrayList<>(); 313 314 // Create the command-line argument parser for use with this program. 315 LocalizableMessage toolDescription = INFO_LDAPDELETE_TOOL_DESCRIPTION.get(); 316 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, 317 false, true, 0, 1, "\"DN\""); 318 argParser.setShortToolDescription(REF_SHORT_DESC_LDAPDELETE.get()); 319 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 320 try 321 { 322 propertiesFileArgument = 323 StringArgument.builder(OPTION_LONG_PROP_FILE_PATH) 324 .description(INFO_DESCRIPTION_PROP_FILE_PATH.get()) 325 .valuePlaceholder(INFO_PROP_FILE_PATH_PLACEHOLDER.get()) 326 .buildAndAddToParser(argParser); 327 argParser.setFilePropertiesArgument(propertiesFileArgument); 328 329 noPropertiesFileArgument = 330 BooleanArgument.builder(OPTION_LONG_NO_PROP_FILE) 331 .description(INFO_DESCRIPTION_NO_PROP_FILE.get()) 332 .buildAndAddToParser(argParser); 333 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); 334 335 hostName = 336 StringArgument.builder(OPTION_LONG_HOST) 337 .shortIdentifier(OPTION_SHORT_HOST) 338 .description(INFO_DESCRIPTION_HOST.get()) 339 .defaultValue("localhost") 340 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 341 .buildAndAddToParser(argParser); 342 port = 343 IntegerArgument.builder(OPTION_LONG_PORT) 344 .shortIdentifier(OPTION_SHORT_PORT) 345 .description(INFO_DESCRIPTION_PORT.get()) 346 .range(1, 65535) 347 .defaultValue(389) 348 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 349 .buildAndAddToParser(argParser); 350 useSSL = 351 BooleanArgument.builder(OPTION_LONG_USE_SSL) 352 .shortIdentifier(OPTION_SHORT_USE_SSL) 353 .description(INFO_DESCRIPTION_USE_SSL.get()) 354 .buildAndAddToParser(argParser); 355 startTLS = 356 BooleanArgument.builder(OPTION_LONG_START_TLS) 357 .shortIdentifier(OPTION_SHORT_START_TLS) 358 .description(INFO_DESCRIPTION_START_TLS.get()) 359 .buildAndAddToParser(argParser); 360 bindDN = 361 StringArgument.builder(OPTION_LONG_BINDDN) 362 .shortIdentifier(OPTION_SHORT_BINDDN) 363 .description(INFO_DESCRIPTION_BINDDN.get()) 364 .valuePlaceholder(INFO_BINDDN_PLACEHOLDER.get()) 365 .buildAndAddToParser(argParser); 366 bindPassword = 367 StringArgument.builder(OPTION_LONG_BINDPWD) 368 .shortIdentifier(OPTION_SHORT_BINDPWD) 369 .description(INFO_DESCRIPTION_BINDPASSWORD.get()) 370 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 371 .buildAndAddToParser(argParser); 372 bindPasswordFile = 373 FileBasedArgument.builder(OPTION_LONG_BINDPWD_FILE) 374 .shortIdentifier(OPTION_SHORT_BINDPWD_FILE) 375 .description(INFO_DESCRIPTION_BINDPASSWORDFILE.get()) 376 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 377 .buildAndAddToParser(argParser); 378 filename = 379 StringArgument.builder(OPTION_LONG_FILENAME) 380 .shortIdentifier(OPTION_SHORT_FILENAME) 381 .description(INFO_DELETE_DESCRIPTION_FILENAME.get()) 382 .valuePlaceholder(INFO_FILE_PLACEHOLDER.get()) 383 .buildAndAddToParser(argParser); 384 saslExternal = 385 BooleanArgument.builder("useSASLExternal") 386 .shortIdentifier('r') 387 .description(INFO_DESCRIPTION_USE_SASL_EXTERNAL.get()) 388 .buildAndAddToParser(argParser); 389 saslOptions = 390 StringArgument.builder(OPTION_LONG_SASLOPTION) 391 .shortIdentifier(OPTION_SHORT_SASLOPTION) 392 .description(INFO_DESCRIPTION_SASL_PROPERTIES.get()) 393 .multiValued() 394 .valuePlaceholder(INFO_SASL_OPTION_PLACEHOLDER.get()) 395 .buildAndAddToParser(argParser); 396 397 trustAll = trustAllArgument(); 398 argParser.addArgument(trustAll); 399 400 keyStorePath = 401 StringArgument.builder(OPTION_LONG_KEYSTOREPATH) 402 .shortIdentifier(OPTION_SHORT_KEYSTOREPATH) 403 .description(INFO_DESCRIPTION_KEYSTOREPATH.get()) 404 .valuePlaceholder(INFO_KEYSTOREPATH_PLACEHOLDER.get()) 405 .buildAndAddToParser(argParser); 406 keyStorePassword = 407 StringArgument.builder(OPTION_LONG_KEYSTORE_PWD) 408 .shortIdentifier(OPTION_SHORT_KEYSTORE_PWD) 409 .description(INFO_DESCRIPTION_KEYSTOREPASSWORD.get()) 410 .valuePlaceholder(INFO_KEYSTORE_PWD_PLACEHOLDER.get()) 411 .buildAndAddToParser(argParser); 412 keyStorePasswordFile = 413 FileBasedArgument.builder(OPTION_LONG_KEYSTORE_PWD_FILE) 414 .shortIdentifier(OPTION_SHORT_KEYSTORE_PWD_FILE) 415 .description(INFO_DESCRIPTION_KEYSTOREPASSWORD_FILE.get()) 416 .valuePlaceholder(INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get()) 417 .buildAndAddToParser(argParser); 418 certNickname = 419 StringArgument.builder("certNickname") 420 .shortIdentifier('N') 421 .description(INFO_DESCRIPTION_CERT_NICKNAME.get()) 422 .valuePlaceholder(INFO_NICKNAME_PLACEHOLDER.get()) 423 .buildAndAddToParser(argParser); 424 trustStorePath = 425 StringArgument.builder(OPTION_LONG_TRUSTSTOREPATH) 426 .shortIdentifier(OPTION_SHORT_TRUSTSTOREPATH) 427 .description(INFO_DESCRIPTION_TRUSTSTOREPATH.get()) 428 .valuePlaceholder(INFO_TRUSTSTOREPATH_PLACEHOLDER.get()) 429 .buildAndAddToParser(argParser); 430 trustStorePassword = 431 StringArgument.builder(OPTION_LONG_TRUSTSTORE_PWD) 432 .description(INFO_DESCRIPTION_TRUSTSTOREPASSWORD.get()) 433 .valuePlaceholder(INFO_TRUSTSTORE_PWD_PLACEHOLDER.get()) 434 .buildAndAddToParser(argParser); 435 trustStorePasswordFile = 436 FileBasedArgument.builder(OPTION_LONG_TRUSTSTORE_PWD_FILE) 437 .shortIdentifier(OPTION_SHORT_TRUSTSTORE_PWD_FILE) 438 .description(INFO_DESCRIPTION_TRUSTSTOREPASSWORD_FILE.get()) 439 .valuePlaceholder(INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get()) 440 .buildAndAddToParser(argParser); 441 deleteSubtree = 442 BooleanArgument.builder("deleteSubtree") 443 .shortIdentifier('x') 444 .description(INFO_DELETE_DESCRIPTION_DELETE_SUBTREE.get()) 445 .buildAndAddToParser(argParser); 446 controlStr = 447 StringArgument.builder("control") 448 .shortIdentifier('J') 449 .description(INFO_DESCRIPTION_CONTROLS.get()) 450 .multiValued() 451 .valuePlaceholder(INFO_LDAP_CONTROL_PLACEHOLDER.get()) 452 .buildAndAddToParser(argParser); 453 version = 454 IntegerArgument.builder(OPTION_LONG_PROTOCOL_VERSION) 455 .shortIdentifier(OPTION_SHORT_PROTOCOL_VERSION) 456 .description(INFO_DESCRIPTION_VERSION.get()) 457 .defaultValue(3) 458 .valuePlaceholder(INFO_PROTOCOL_VERSION_PLACEHOLDER.get()) 459 .buildAndAddToParser(argParser); 460 connectTimeout = 461 IntegerArgument.builder(OPTION_LONG_CONNECT_TIMEOUT) 462 .description(INFO_DESCRIPTION_CONNECTION_TIMEOUT.get()) 463 .lowerBound(0) 464 .defaultValue(CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT) 465 .valuePlaceholder(INFO_TIMEOUT_PLACEHOLDER.get()) 466 .buildAndAddToParser(argParser); 467 encodingStr = 468 StringArgument.builder(OPTION_LONG_ENCODING) 469 .shortIdentifier('i') 470 .description(INFO_DESCRIPTION_ENCODING.get()) 471 .valuePlaceholder(INFO_ENCODING_PLACEHOLDER.get()) 472 .buildAndAddToParser(argParser); 473 continueOnError = 474 BooleanArgument.builder("continueOnError") 475 .shortIdentifier('c') 476 .description(INFO_DESCRIPTION_CONTINUE_ON_ERROR.get()) 477 .buildAndAddToParser(argParser); 478 noop = 479 BooleanArgument.builder(OPTION_LONG_DRYRUN) 480 .shortIdentifier(OPTION_SHORT_DRYRUN) 481 .description(INFO_DESCRIPTION_NOOP.get()) 482 .buildAndAddToParser(argParser); 483 484 verbose = verboseArgument(); 485 argParser.addArgument(verbose); 486 487 showUsage = showUsageArgument(); 488 argParser.addArgument(showUsage); 489 argParser.setUsageArgument(showUsage, out); 490 } catch (ArgumentException ae) 491 { 492 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 493 return CLIENT_SIDE_PARAM_ERROR; 494 } 495 496 // Parse the command-line arguments provided to this program. 497 try 498 { 499 argParser.parseArguments(args); 500 } 501 catch (ArgumentException ae) 502 { 503 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 504 return CLIENT_SIDE_PARAM_ERROR; 505 } 506 507 // If we should just display usage or version information, 508 // then it has already been done so just exit. 509 if (argParser.usageOrVersionDisplayed()) 510 { 511 return 0; 512 } 513 514 if (bindPassword.isPresent() && bindPasswordFile.isPresent()) 515 { 516 printWrappedText(err, conflictingArgsErrorMessage(bindPassword, bindPasswordFile)); 517 return CLIENT_SIDE_PARAM_ERROR; 518 } 519 520 521 String hostNameValue = hostName.getValue(); 522 int portNumber = 389; 523 try 524 { 525 portNumber = port.getIntValue(); 526 } catch(ArgumentException ae) 527 { 528 logger.traceException(ae); 529 argParser.displayMessageAndUsageReference(err, ae.getMessageObject()); 530 return CLIENT_SIDE_PARAM_ERROR; 531 } 532 533 try 534 { 535 int versionNumber = version.getIntValue(); 536 if(versionNumber != 2 && versionNumber != 3) 537 { 538 printWrappedText(err, ERR_DESCRIPTION_INVALID_VERSION.get(versionNumber)); 539 return CLIENT_SIDE_PARAM_ERROR; 540 } 541 connectionOptions.setVersionNumber(versionNumber); 542 } catch(ArgumentException ae) 543 { 544 logger.traceException(ae); 545 argParser.displayMessageAndUsageReference(err, ae.getMessageObject()); 546 return CLIENT_SIDE_PARAM_ERROR; 547 } 548 549 String bindDNValue = bindDN.getValue(); 550 String fileNameValue = filename.getValue(); 551 String bindPasswordValue; 552 try 553 { 554 bindPasswordValue = getPasswordValue( 555 bindPassword, bindPasswordFile, bindDNValue, out, err); 556 } 557 catch (Exception ex) 558 { 559 logger.traceException(ex); 560 printWrappedText(err, ex.getMessage()); 561 return CLIENT_SIDE_PARAM_ERROR; 562 } 563 564 String keyStorePathValue = keyStorePath.getValue(); 565 String trustStorePathValue = trustStorePath.getValue(); 566 567 String keyStorePasswordValue = null; 568 if (keyStorePassword.isPresent()) 569 { 570 keyStorePasswordValue = keyStorePassword.getValue(); 571 } 572 else if (keyStorePasswordFile.isPresent()) 573 { 574 keyStorePasswordValue = keyStorePasswordFile.getValue(); 575 } 576 577 String trustStorePasswordValue = null; 578 if (trustStorePassword.isPresent()) 579 { 580 trustStorePasswordValue = trustStorePassword.getValue(); 581 } 582 else if (trustStorePasswordFile.isPresent()) 583 { 584 trustStorePasswordValue = trustStorePasswordFile.getValue(); 585 } 586 587 deleteOptions.setShowOperations(noop.isPresent()); 588 deleteOptions.setVerbose(verbose.isPresent()); 589 deleteOptions.setContinueOnError(continueOnError.isPresent()); 590 deleteOptions.setEncoding(encodingStr.getValue()); 591 deleteOptions.setDeleteSubtree(deleteSubtree.isPresent()); 592 593 if(controlStr.isPresent()) 594 { 595 for (String ctrlString : controlStr.getValues()) 596 { 597 Control ctrl = LDAPToolUtils.getControl(ctrlString, err); 598 if(ctrl == null) 599 { 600 printWrappedText(err, ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString)); 601 return CLIENT_SIDE_PARAM_ERROR; 602 } 603 deleteOptions.getControls().add(ctrl); 604 } 605 } 606 607 if(deleteOptions.getDeleteSubtree()) 608 { 609 Control control = new SubtreeDeleteControl(false); 610 deleteOptions.getControls().add(control); 611 } 612 613 ArrayList<String> trailingArgs = argParser.getTrailingArguments(); 614 dnStrings.addAll(trailingArgs); 615 616 // Set the connection options. 617 // Parse the SASL properties. 618 connectionOptions.setSASLExternal(saslExternal.isPresent()); 619 if(saslOptions.isPresent()) 620 { 621 for (String saslOption : saslOptions.getValues()) 622 { 623 boolean val = saslOption.startsWith("mech=") 624 ? connectionOptions.setSASLMechanism(saslOption) 625 : connectionOptions.addSASLProperty(saslOption); 626 if (!val) 627 { 628 return CLIENT_SIDE_PARAM_ERROR; 629 } 630 } 631 } 632 connectionOptions.setUseSSL(useSSL.isPresent()); 633 connectionOptions.setStartTLS(startTLS.isPresent()); 634 635 if(connectionOptions.useSASLExternal()) 636 { 637 if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS()) 638 { 639 printWrappedText(err, ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get()); 640 return CLIENT_SIDE_PARAM_ERROR; 641 } 642 if(keyStorePathValue == null) 643 { 644 printWrappedText(err, ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get()); 645 return CLIENT_SIDE_PARAM_ERROR; 646 } 647 } 648 649 LDAPDelete ldapDelete = null; 650 try 651 { 652 if (initializeServer) 653 { 654 // Bootstrap and initialize directory data structures. 655 EmbeddedUtils.initializeForClientUse(); 656 } 657 658 // Connect to the specified host with the supplied userDN and password. 659 SSLConnectionFactory sslConnectionFactory = null; 660 if(connectionOptions.useSSL() || connectionOptions.useStartTLS()) 661 { 662 String clientAlias; 663 if (certNickname.isPresent()) 664 { 665 clientAlias = certNickname.getValue(); 666 } 667 else 668 { 669 clientAlias = null; 670 } 671 672 sslConnectionFactory = new SSLConnectionFactory(); 673 sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue, 674 keyStorePasswordValue, clientAlias, 675 trustStorePathValue, trustStorePasswordValue); 676 connectionOptions.setSSLConnectionFactory(sslConnectionFactory); 677 } 678 679 AtomicInteger nextMessageID = new AtomicInteger(1); 680 connection = new LDAPConnection(hostNameValue, portNumber, 681 connectionOptions, out, err); 682 int timeout = connectTimeout.getIntValue(); 683 connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID, 684 timeout); 685 686 ldapDelete = new LDAPDelete(nextMessageID, out, err); 687 if(fileNameValue == null && dnStrings.isEmpty()) 688 { 689 // Read from stdin. 690 rdr = new InputStreamReader(System.in); 691 } else if(fileNameValue != null) 692 { 693 rdr = new FileReader(fileNameValue); 694 } 695 696 if(rdr != null) 697 { 698 ldapDelete.readAndExecute(connection, rdr, deleteOptions); 699 } else 700 { 701 ldapDelete.readAndExecute(connection, dnStrings, deleteOptions); 702 } 703 } catch(LDAPException le) 704 { 705 logger.traceException(le); 706 LDAPToolUtils.printErrorMessage(err, le.getMessageObject(), 707 le.getResultCode(), 708 le.getErrorMessage(), 709 le.getMatchedDN()); 710 return le.getResultCode(); 711 } catch(LDAPConnectionException lce) 712 { 713 logger.traceException(lce); 714 LDAPToolUtils.printErrorMessage(err, lce.getMessageObject(), 715 lce.getResultCode(), 716 lce.getErrorMessage(), 717 lce.getMatchedDN()); 718 return lce.getResultCode(); 719 } 720 catch(ArgumentException e) 721 { 722 argParser.displayMessageAndUsageReference(err, e.getMessageObject()); 723 return 1; 724 } 725 catch (Exception e) 726 { 727 logger.traceException(e); 728 printWrappedText(err, e.getMessage()); 729 return 1; 730 } finally 731 { 732 if(connection != null) 733 { 734 if (ldapDelete == null) 735 { 736 connection.close(null); 737 } 738 else 739 { 740 connection.close(ldapDelete.nextMessageID); 741 } 742 } 743 } 744 return 0; 745 } 746 747} 748