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
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.tools;
028 import org.opends.messages.Message;
029
030 import java.io.BufferedReader;
031 import java.io.FileReader;
032 import java.io.InputStreamReader;
033 import java.io.IOException;
034 import java.io.OutputStream;
035 import java.io.PrintStream;
036 import java.io.Reader;
037 import java.util.ArrayList;
038 import java.util.LinkedList;
039 import java.util.concurrent.atomic.AtomicInteger;
040
041 import org.opends.server.protocols.asn1.ASN1Exception;
042 import org.opends.server.protocols.asn1.ASN1OctetString;
043 import org.opends.server.protocols.ldap.DeleteRequestProtocolOp;
044 import org.opends.server.protocols.ldap.DeleteResponseProtocolOp;
045 import org.opends.server.protocols.ldap.LDAPControl;
046 import org.opends.server.protocols.ldap.LDAPMessage;
047 import org.opends.server.protocols.ldap.ProtocolOp;
048 import org.opends.server.types.NullOutputStream;
049 import org.opends.server.types.DebugLogLevel;
050 import org.opends.server.types.LDAPException;
051 import org.opends.server.util.EmbeddedUtils;
052 import org.opends.server.util.PasswordReader;
053 import org.opends.server.util.args.ArgumentException;
054 import org.opends.server.util.args.ArgumentParser;
055 import org.opends.server.util.args.BooleanArgument;
056 import org.opends.server.util.args.FileBasedArgument;
057 import org.opends.server.util.args.IntegerArgument;
058 import org.opends.server.util.args.StringArgument;
059
060 import static org.opends.server.loggers.debug.DebugLogger.*;
061 import org.opends.server.loggers.debug.DebugTracer;
062 import static org.opends.messages.ToolMessages.*;
063 import static org.opends.server.protocols.ldap.LDAPResultCode.*;
064 import static org.opends.server.util.ServerConstants.*;
065 import static org.opends.server.util.StaticUtils.*;
066 import static org.opends.server.tools.ToolConstants.*;
067
068
069 /**
070 * This class provides a tool that can be used to issue delete requests to the
071 * Directory Server.
072 */
073 public class LDAPDelete
074 {
075 /**
076 * The tracer object for the debug logger.
077 */
078 private static final DebugTracer TRACER = getTracer();
079
080 /**
081 * The fully-qualified name of this class.
082 */
083 private static final String CLASS_NAME = "org.opends.server.tools.LDAPDelete";
084
085
086
087 // The message ID counter to use for requests.
088 private AtomicInteger nextMessageID;
089
090 // The print stream to use for standard error.
091 private PrintStream err;
092
093 // The print stream to use for standard output.
094 private PrintStream out;
095
096
097
098 /**
099 * Constructor for the LDAPDelete object.
100 *
101 * @param nextMessageID The next message ID to use for requests.
102 * @param out The print stream to use for standard output.
103 * @param err The print stream to use for standard error.
104 */
105 public LDAPDelete(AtomicInteger nextMessageID, PrintStream out,
106 PrintStream err)
107 {
108 this.nextMessageID = nextMessageID;
109 this.out = out;
110 this.err = err;
111 }
112
113 /**
114 * Execute the delete request on the specified list of DNs.
115 *
116 * @param connection The connection to use to execute the request.
117 * @param lines The list of DNs to delete.
118 * @param deleteOptions The constraints to use for this request.
119 *
120 * @throws IOException If a problem occurs while attempting to communicate
121 * with the Directory Server.
122 *
123 * @throws LDAPException If the Directory Server returns an error response.
124 */
125 public void readAndExecute(LDAPConnection connection,
126 ArrayList<String> lines,
127 LDAPDeleteOptions deleteOptions)
128 throws IOException, LDAPException
129 {
130 for(String line : lines)
131 {
132 executeDelete(connection, line, deleteOptions);
133 }
134 }
135
136 /**
137 * Read the specified DNs from the given reader
138 * (file or stdin) and execute the given delete request.
139 *
140 * @param connection The connection to use to execute the request.
141 * @param reader The reader to read the list of DNs from.
142 * @param deleteOptions The constraints to use for this request.
143 *
144 * @throws IOException If a problem occurs while attempting to communicate
145 * with the Directory Server.
146 *
147 * @throws LDAPException If the Directory Server returns an error response.
148 */
149 public void readAndExecute(LDAPConnection connection, Reader reader,
150 LDAPDeleteOptions deleteOptions)
151 throws IOException, LDAPException
152 {
153 BufferedReader in = new BufferedReader(reader);
154 String line = null;
155
156 while ((line = in.readLine()) != null)
157 {
158 executeDelete(connection, line, deleteOptions);
159 }
160 in.close();
161 }
162
163
164 /**
165 * Execute the delete request for the specified DN.
166 *
167 * @param connection The connection to use to execute the request.
168 * @param line The DN to delete.
169 * @param deleteOptions The list of constraints for this request.
170 *
171 * @throws IOException If a problem occurs while attempting to communicate
172 * with the Directory Server.
173 *
174 * @throws LDAPException If the Directory Server returns an error response.
175 */
176 private void executeDelete(LDAPConnection connection, String line,
177 LDAPDeleteOptions deleteOptions)
178 throws IOException, LDAPException
179 {
180 ArrayList<LDAPControl> controls = deleteOptions.getControls();
181 ProtocolOp protocolOp = null;
182 ASN1OctetString asn1OctetStr = new ASN1OctetString(line);
183
184 protocolOp = new DeleteRequestProtocolOp(asn1OctetStr);
185
186 out.println(INFO_PROCESSING_OPERATION.get(
187 "DELETE", String.valueOf(asn1OctetStr)));
188 if(!deleteOptions.showOperations())
189 {
190 LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(),
191 protocolOp, controls);
192 LDAPMessage responseMessage = null;
193 try
194 {
195 connection.getLDAPWriter().writeMessage(message);
196 responseMessage = connection.getLDAPReader().readMessage();
197 } catch(ASN1Exception ae)
198 {
199 if (debugEnabled())
200 {
201 TRACER.debugCaught(DebugLogLevel.ERROR, ae);
202 }
203 if (!deleteOptions.continueOnError())
204 {
205 throw new IOException(ae.getMessage());
206 }
207 else
208 {
209
210 Message msg = INFO_OPERATION_FAILED.get("DELETE");
211 err.println(wrapText(msg, MAX_LINE_WIDTH));
212 err.println(wrapText(ae.getMessage(), MAX_LINE_WIDTH));
213 return;
214 }
215 }
216
217 DeleteResponseProtocolOp op =
218 responseMessage.getDeleteResponseProtocolOp();
219 int resultCode = op.getResultCode();
220 Message errorMessage = op.getErrorMessage();
221 if(resultCode != SUCCESS && resultCode != REFERRAL &&
222 !deleteOptions.continueOnError())
223 {
224 Message msg = INFO_OPERATION_FAILED.get("DELETE");
225 throw new LDAPException(resultCode, errorMessage, msg,
226 op.getMatchedDN(), null);
227 } else
228 {
229 if(resultCode != SUCCESS && resultCode != REFERRAL)
230 {
231
232 Message msg = INFO_OPERATION_FAILED.get("DELETE");
233 LDAPToolUtils.printErrorMessage(err, msg, resultCode, errorMessage,
234 op.getMatchedDN());
235 } else
236 {
237
238 Message msg = INFO_OPERATION_SUCCESSFUL.get("DELETE", line);
239 out.println(msg);
240 }
241 }
242 }
243 }
244
245 /**
246 * The main method for LDAPDelete tool.
247 *
248 * @param args The command-line arguments provided to this program.
249 */
250
251 public static void main(String[] args)
252 {
253 int retCode = mainDelete(args, true, System.out, System.err);
254
255 if(retCode != 0)
256 {
257 System.exit(filterExitCode(retCode));
258 }
259 }
260
261 /**
262 * Parses the provided command-line arguments and uses that information to
263 * run the ldapdelete tool.
264 *
265 * @param args The command-line arguments provided to this program.
266 *
267 * @return The error code.
268 */
269
270 public static int mainDelete(String[] args)
271 {
272 return mainDelete(args, true, System.out, System.err);
273 }
274
275 /**
276 * Parses the provided command-line arguments and uses that information to
277 * run the ldapdelete tool.
278 *
279 * @param args The command-line arguments provided to this
280 * program.
281 * @param initializeServer Indicates whether to initialize the server.
282 * @param outStream The output stream to use for standard output, or
283 * <CODE>null</CODE> if standard output is not
284 * needed.
285 * @param errStream The output stream to use for standard error, or
286 * <CODE>null</CODE> if standard error is not
287 * needed.
288 *
289 * @return The error code.
290 */
291
292 public static int mainDelete(String[] args, boolean initializeServer,
293 OutputStream outStream, OutputStream errStream)
294 {
295 PrintStream out;
296 if (outStream == null)
297 {
298 out = NullOutputStream.printStream();
299 }
300 else
301 {
302 out = new PrintStream(outStream);
303 }
304
305 PrintStream err;
306 if (errStream == null)
307 {
308 err = NullOutputStream.printStream();
309 }
310 else
311 {
312 err = new PrintStream(errStream);
313 }
314
315
316 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
317 LDAPDeleteOptions deleteOptions = new LDAPDeleteOptions();
318 LDAPConnection connection = null;
319
320 BooleanArgument continueOnError = null;
321 BooleanArgument deleteSubtree = null;
322 BooleanArgument noop = null;
323 BooleanArgument saslExternal = null;
324 BooleanArgument showUsage = null;
325 BooleanArgument startTLS = null;
326 BooleanArgument trustAll = null;
327 BooleanArgument useSSL = null;
328 BooleanArgument verbose = null;
329 FileBasedArgument bindPasswordFile = null;
330 FileBasedArgument keyStorePasswordFile = null;
331 FileBasedArgument trustStorePasswordFile = null;
332 IntegerArgument port = null;
333 IntegerArgument version = null;
334 StringArgument bindDN = null;
335 StringArgument bindPassword = null;
336 StringArgument certNickname = null;
337 StringArgument controlStr = null;
338 StringArgument encodingStr = null;
339 StringArgument filename = null;
340 StringArgument hostName = null;
341 StringArgument keyStorePath = null;
342 StringArgument keyStorePassword = null;
343 StringArgument saslOptions = null;
344 StringArgument trustStorePath = null;
345 StringArgument trustStorePassword = null;
346 StringArgument propertiesFileArgument = null;
347 BooleanArgument noPropertiesFileArgument = null;
348
349 Reader rdr = null;
350 ArrayList<String> dnStrings = new ArrayList<String> ();
351
352 // Create the command-line argument parser for use with this program.
353 Message toolDescription = INFO_LDAPDELETE_TOOL_DESCRIPTION.get();
354 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription,
355 false, true, 0, 1, "\"DN\"");
356 try
357 {
358 propertiesFileArgument = new StringArgument("propertiesFilePath",
359 null, OPTION_LONG_PROP_FILE_PATH,
360 false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
361 INFO_DESCRIPTION_PROP_FILE_PATH.get());
362 argParser.addArgument(propertiesFileArgument);
363 argParser.setFilePropertiesArgument(propertiesFileArgument);
364
365 noPropertiesFileArgument = new BooleanArgument(
366 "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
367 INFO_DESCRIPTION_NO_PROP_FILE.get());
368 argParser.addArgument(noPropertiesFileArgument);
369 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
370
371 hostName = new StringArgument("host", OPTION_SHORT_HOST,
372 OPTION_LONG_HOST, false, false, true,
373 INFO_HOST_PLACEHOLDER.get(), "localhost",
374 null,
375 INFO_DESCRIPTION_HOST.get());
376 hostName.setPropertyName(OPTION_LONG_HOST);
377 argParser.addArgument(hostName);
378
379 port = new IntegerArgument("port", OPTION_SHORT_PORT,
380 OPTION_LONG_PORT, false, false, true,
381 INFO_PORT_PLACEHOLDER.get(), 389, null,
382 INFO_DESCRIPTION_PORT.get());
383 port.setPropertyName(OPTION_LONG_PORT);
384 argParser.addArgument(port);
385
386 useSSL = new BooleanArgument("useSSL", OPTION_SHORT_USE_SSL,
387 OPTION_LONG_USE_SSL,
388 INFO_DESCRIPTION_USE_SSL.get());
389 useSSL.setPropertyName(OPTION_LONG_USE_SSL);
390 argParser.addArgument(useSSL);
391
392 startTLS = new BooleanArgument("startTLS", OPTION_SHORT_START_TLS,
393 OPTION_LONG_START_TLS,
394 INFO_DESCRIPTION_START_TLS.get());
395 startTLS.setPropertyName(OPTION_LONG_START_TLS);
396 argParser.addArgument(startTLS);
397
398 bindDN = new StringArgument("bindDN", OPTION_SHORT_BINDDN,
399 OPTION_LONG_BINDDN, false, false, true,
400 INFO_BINDDN_PLACEHOLDER.get(), null, null,
401 INFO_DESCRIPTION_BINDDN.get());
402 bindDN.setPropertyName(OPTION_LONG_BINDPWD);
403 argParser.addArgument(bindDN);
404
405 bindPassword = new StringArgument("bindPassword", OPTION_SHORT_BINDPWD,
406 OPTION_LONG_BINDPWD,
407 false, false, true,
408 INFO_BINDPWD_PLACEHOLDER.get(),
409 null, null,
410 INFO_DESCRIPTION_BINDPASSWORD.get());
411 bindPassword.setPropertyName(OPTION_LONG_BINDPWD);
412 argParser.addArgument(bindPassword);
413
414 bindPasswordFile =
415 new FileBasedArgument("bindPasswordFile", OPTION_SHORT_BINDPWD_FILE,
416 OPTION_LONG_BINDPWD_FILE,
417 false, false,
418 INFO_BINDPWD_FILE_PLACEHOLDER.get(), null,
419 null, INFO_DESCRIPTION_BINDPASSWORDFILE.get());
420 bindPasswordFile.setPropertyName(OPTION_LONG_BINDPWD_FILE);
421 argParser.addArgument(bindPasswordFile);
422
423 filename = new StringArgument("filename", OPTION_SHORT_FILENAME,
424 OPTION_LONG_FILENAME, false, false,
425 true, INFO_FILE_PLACEHOLDER.get(), null,
426 null,
427 INFO_DELETE_DESCRIPTION_FILENAME.get());
428 filename.setPropertyName(OPTION_LONG_FILENAME);
429 argParser.addArgument(filename);
430
431 saslExternal =
432 new BooleanArgument("useSASLExternal", 'r',
433 "useSASLExternal",
434 INFO_DESCRIPTION_USE_SASL_EXTERNAL.get());
435 saslExternal.setPropertyName("useSASLExternal");
436 argParser.addArgument(saslExternal);
437
438 saslOptions = new StringArgument(
439 "saslOption", OPTION_SHORT_SASLOPTION,
440 OPTION_LONG_SASLOPTION,
441 false, true, true,
442 INFO_SASL_OPTION_PLACEHOLDER.get(), null,
443 null, INFO_DESCRIPTION_SASL_PROPERTIES.get());
444 saslOptions.setPropertyName(OPTION_LONG_SASLOPTION);
445 argParser.addArgument(saslOptions);
446
447 trustAll = new BooleanArgument("trustAll", 'X', "trustAll",
448 INFO_DESCRIPTION_TRUSTALL.get());
449 trustAll.setPropertyName("trustAll");
450 argParser.addArgument(trustAll);
451
452 keyStorePath = new StringArgument("keyStorePath",
453 OPTION_SHORT_KEYSTOREPATH,
454 OPTION_LONG_KEYSTOREPATH,
455 false, false, true,
456 INFO_KEYSTOREPATH_PLACEHOLDER.get(),
457 null, null,
458 INFO_DESCRIPTION_KEYSTOREPATH.get());
459 keyStorePath.setPropertyName(OPTION_LONG_KEYSTOREPATH);
460 argParser.addArgument(keyStorePath);
461
462 keyStorePassword =
463 new StringArgument("keyStorePassword",
464 OPTION_SHORT_KEYSTORE_PWD,
465 OPTION_LONG_KEYSTORE_PWD,
466 false, false,
467 true, INFO_KEYSTORE_PWD_PLACEHOLDER.get(),
468 null, null,
469 INFO_DESCRIPTION_KEYSTOREPASSWORD.get());
470 keyStorePassword.setPropertyName(OPTION_LONG_KEYSTORE_PWD);
471 argParser.addArgument(keyStorePassword);
472
473 keyStorePasswordFile =
474 new FileBasedArgument("keyStorePasswordFile",
475 OPTION_SHORT_KEYSTORE_PWD_FILE,
476 OPTION_LONG_KEYSTORE_PWD_FILE,
477 false, false,
478 INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get(),
479 null, null,
480 INFO_DESCRIPTION_KEYSTOREPASSWORD_FILE.get());
481 keyStorePasswordFile.setPropertyName(OPTION_LONG_KEYSTORE_PWD_FILE);
482 argParser.addArgument(keyStorePasswordFile);
483
484 certNickname = new StringArgument(
485 "certnickname", 'N', "certNickname",
486 false, false, true, INFO_NICKNAME_PLACEHOLDER.get(), null,
487 null, INFO_DESCRIPTION_CERT_NICKNAME.get());
488 certNickname.setPropertyName("certNickname");
489 argParser.addArgument(certNickname);
490
491 trustStorePath = new StringArgument(
492 "trustStorePath",
493 OPTION_SHORT_TRUSTSTOREPATH,
494 OPTION_LONG_TRUSTSTOREPATH,
495 false, false, true,
496 INFO_TRUSTSTOREPATH_PLACEHOLDER.get(),
497 null, null,
498 INFO_DESCRIPTION_TRUSTSTOREPATH.get());
499 trustStorePath.setPropertyName(OPTION_LONG_TRUSTSTOREPATH);
500 argParser.addArgument(trustStorePath);
501
502 trustStorePassword =
503 new StringArgument("trustStorePassword", null,
504 OPTION_LONG_TRUSTSTORE_PWD,
505 false, false, true,
506 INFO_TRUSTSTORE_PWD_PLACEHOLDER.get(), null,
507 null, INFO_DESCRIPTION_TRUSTSTOREPASSWORD.get());
508 trustStorePassword.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD);
509 argParser.addArgument(trustStorePassword);
510
511 trustStorePasswordFile =
512 new FileBasedArgument(
513 "trustStorePasswordFile",
514 OPTION_SHORT_TRUSTSTORE_PWD_FILE,
515 OPTION_LONG_TRUSTSTORE_PWD_FILE, false, false,
516 INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get(), null, null,
517 INFO_DESCRIPTION_TRUSTSTOREPASSWORD_FILE.get());
518 trustStorePasswordFile.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD_FILE);
519 argParser.addArgument(trustStorePasswordFile);
520
521 deleteSubtree =
522 new BooleanArgument("deleteSubtree", 'x', "deleteSubtree",
523 INFO_DELETE_DESCRIPTION_DELETE_SUBTREE.get());
524 deleteSubtree.setPropertyName("deleteSubtree");
525 argParser.addArgument(deleteSubtree);
526
527 controlStr =
528 new StringArgument("control", 'J', "control", false, true, true,
529 INFO_LDAP_CONTROL_PLACEHOLDER.get(),
530 null, null, INFO_DESCRIPTION_CONTROLS.get());
531 controlStr.setPropertyName("control");
532 argParser.addArgument(controlStr);
533
534 version = new IntegerArgument("version", OPTION_SHORT_PROTOCOL_VERSION,
535 OPTION_LONG_PROTOCOL_VERSION, false, false,
536 true,
537 INFO_PROTOCOL_VERSION_PLACEHOLDER.get(), 3,
538 null, INFO_DESCRIPTION_VERSION.get());
539 version.setPropertyName(OPTION_LONG_PROTOCOL_VERSION);
540 argParser.addArgument(version);
541
542 encodingStr = new StringArgument("encoding", 'i',
543 OPTION_LONG_ENCODING, false,
544 false, true,
545 INFO_ENCODING_PLACEHOLDER.get(), null,
546 null,
547 INFO_DESCRIPTION_ENCODING.get());
548 encodingStr.setPropertyName(OPTION_LONG_ENCODING);
549 argParser.addArgument(encodingStr);
550
551 continueOnError =
552 new BooleanArgument("continueOnError", 'c', "continueOnError",
553 INFO_DESCRIPTION_CONTINUE_ON_ERROR.get());
554 continueOnError.setPropertyName("continueOnError");
555 argParser.addArgument(continueOnError);
556
557 noop = new BooleanArgument("no-op", OPTION_SHORT_DRYRUN,
558 OPTION_LONG_DRYRUN, INFO_DESCRIPTION_NOOP.get());
559 noop.setPropertyName(OPTION_LONG_DRYRUN);
560 argParser.addArgument(noop);
561
562 verbose = new BooleanArgument("verbose", 'v', "verbose",
563 INFO_DESCRIPTION_VERBOSE.get());
564 verbose.setPropertyName("verbose");
565 argParser.addArgument(verbose);
566
567 showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
568 OPTION_LONG_HELP,
569 INFO_DESCRIPTION_SHOWUSAGE.get());
570 argParser.addArgument(showUsage);
571 argParser.setUsageArgument(showUsage, out);
572 } catch (ArgumentException ae)
573 {
574 Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
575
576 err.println(wrapText(message, MAX_LINE_WIDTH));
577 return 1;
578 }
579
580 // Parse the command-line arguments provided to this program.
581 try
582 {
583 argParser.parseArguments(args);
584 }
585 catch (ArgumentException ae)
586 {
587 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
588
589 err.println(wrapText(message, MAX_LINE_WIDTH));
590 err.println(argParser.getUsage());
591 return 1;
592 }
593
594 // If we should just display usage or version information,
595 // then it has already been done so just exit.
596 if (argParser.usageOrVersionDisplayed())
597 {
598 return 0;
599 }
600
601 if(bindPassword.isPresent() && bindPasswordFile.isPresent())
602 {
603 Message message = ERR_TOOL_CONFLICTING_ARGS.get(
604 bindPassword.getLongIdentifier(),
605 bindPasswordFile.getLongIdentifier());
606 err.println(wrapText(message, MAX_LINE_WIDTH));
607 return 1;
608 }
609
610 String hostNameValue = hostName.getValue();
611 int portNumber = 389;
612 try
613 {
614 portNumber = port.getIntValue();
615 } catch(ArgumentException ae)
616 {
617 if (debugEnabled())
618 {
619 TRACER.debugCaught(DebugLogLevel.ERROR, ae);
620 }
621 err.println(wrapText(ae.getMessage(), MAX_LINE_WIDTH));
622 return 1;
623 }
624
625 try
626 {
627 int versionNumber = version.getIntValue();
628 if(versionNumber != 2 && versionNumber != 3)
629 {
630
631 err.println(wrapText(ERR_DESCRIPTION_INVALID_VERSION.get(
632 String.valueOf(versionNumber)), MAX_LINE_WIDTH));
633 return 1;
634 }
635 connectionOptions.setVersionNumber(versionNumber);
636 } catch(ArgumentException ae)
637 {
638 if (debugEnabled())
639 {
640 TRACER.debugCaught(DebugLogLevel.ERROR, ae);
641 }
642 err.println(wrapText(ae.getMessage(), MAX_LINE_WIDTH));
643 return 1;
644 }
645
646 String bindDNValue = bindDN.getValue();
647 String fileNameValue = filename.getValue();
648 String bindPasswordValue = bindPassword.getValue();
649 if(bindPasswordValue != null && bindPasswordValue.equals("-"))
650 {
651 // read the password from the stdin.
652 try
653 {
654 out.print(INFO_LDAPAUTH_PASSWORD_PROMPT.get(bindDNValue));
655 char[] pwChars = PasswordReader.readPassword();
656 bindPasswordValue = new String(pwChars);
657 } catch(Exception ex)
658 {
659 if (debugEnabled())
660 {
661 TRACER.debugCaught(DebugLogLevel.ERROR, ex);
662 }
663 err.println(wrapText(ex.getMessage(), MAX_LINE_WIDTH));
664 return 1;
665 }
666 } else if(bindPasswordValue == null)
667 {
668 // Read from file if it exists.
669 bindPasswordValue = bindPasswordFile.getValue();
670 }
671
672 String keyStorePathValue = keyStorePath.getValue();
673 String trustStorePathValue = trustStorePath.getValue();
674
675 String keyStorePasswordValue = null;
676 if (keyStorePassword.isPresent())
677 {
678 keyStorePasswordValue = keyStorePassword.getValue();
679 }
680 else if (keyStorePasswordFile.isPresent())
681 {
682 keyStorePasswordValue = keyStorePasswordFile.getValue();
683 }
684
685 String trustStorePasswordValue = null;
686 if (trustStorePassword.isPresent())
687 {
688 trustStorePasswordValue = trustStorePassword.getValue();
689 }
690 else if (trustStorePasswordFile.isPresent())
691 {
692 trustStorePasswordValue = trustStorePasswordFile.getValue();
693 }
694
695 deleteOptions.setShowOperations(noop.isPresent());
696 deleteOptions.setVerbose(verbose.isPresent());
697 deleteOptions.setContinueOnError(continueOnError.isPresent());
698 deleteOptions.setEncoding(encodingStr.getValue());
699 deleteOptions.setDeleteSubtree(deleteSubtree.isPresent());
700
701 if(controlStr.isPresent())
702 {
703 for (String ctrlString : controlStr.getValues())
704 {
705 LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString, err);
706 if(ctrl == null)
707 {
708 Message message = ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString);
709 err.println(wrapText(message, MAX_LINE_WIDTH));
710 err.println(argParser.getUsage());
711 return 1;
712 }
713 deleteOptions.getControls().add(ctrl);
714 }
715 }
716
717 if(deleteOptions.getDeleteSubtree())
718 {
719 LDAPControl control = new LDAPControl(OID_SUBTREE_DELETE_CONTROL);
720 deleteOptions.getControls().add(control);
721 }
722
723 ArrayList<String> trailingArgs = argParser.getTrailingArguments();
724 for(String s : trailingArgs)
725 {
726 dnStrings.add(s);
727 }
728
729 // Set the connection options.
730 // Parse the SASL properties.
731 connectionOptions.setSASLExternal(saslExternal.isPresent());
732 if(saslOptions.isPresent())
733 {
734 LinkedList<String> values = saslOptions.getValues();
735 for(String saslOption : values)
736 {
737 if(saslOption.startsWith("mech="))
738 {
739 boolean val = connectionOptions.setSASLMechanism(saslOption);
740 if(val == false)
741 {
742 return 1;
743 }
744 } else
745 {
746 boolean val = connectionOptions.addSASLProperty(saslOption);
747 if(val == false)
748 {
749 return 1;
750 }
751 }
752 }
753 }
754 connectionOptions.setUseSSL(useSSL.isPresent());
755 connectionOptions.setStartTLS(startTLS.isPresent());
756
757 if(connectionOptions.useSASLExternal())
758 {
759 if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS())
760 {
761 Message message = ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get();
762 err.println(wrapText(message, MAX_LINE_WIDTH));
763 return 1;
764 }
765 if(keyStorePathValue == null)
766 {
767 Message message = ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get();
768 err.println(wrapText(message, MAX_LINE_WIDTH));
769 return 1;
770 }
771 }
772
773 LDAPDelete ldapDelete = null;
774 try
775 {
776 if (initializeServer)
777 {
778 // Bootstrap and initialize directory data structures.
779 EmbeddedUtils.initializeForClientUse();
780 }
781
782 // Connect to the specified host with the supplied userDN and password.
783 SSLConnectionFactory sslConnectionFactory = null;
784 if(connectionOptions.useSSL() || connectionOptions.useStartTLS())
785 {
786 String clientAlias;
787 if (certNickname.isPresent())
788 {
789 clientAlias = certNickname.getValue();
790 }
791 else
792 {
793 clientAlias = null;
794 }
795
796 sslConnectionFactory = new SSLConnectionFactory();
797 sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue,
798 keyStorePasswordValue, clientAlias,
799 trustStorePathValue, trustStorePasswordValue);
800 connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
801 }
802
803 AtomicInteger nextMessageID = new AtomicInteger(1);
804 connection = new LDAPConnection(hostNameValue, portNumber,
805 connectionOptions, out, err);
806 connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
807
808 ldapDelete = new LDAPDelete(nextMessageID, out, err);
809 if(fileNameValue == null && dnStrings.isEmpty())
810 {
811 // Read from stdin.
812 rdr = new InputStreamReader(System.in);
813 } else if(fileNameValue != null)
814 {
815 rdr = new FileReader(fileNameValue);
816 }
817
818 if(rdr != null)
819 {
820 ldapDelete.readAndExecute(connection, rdr, deleteOptions);
821 } else
822 {
823 ldapDelete.readAndExecute(connection, dnStrings, deleteOptions);
824 }
825 } catch(LDAPException le)
826 {
827 if (debugEnabled())
828 {
829 TRACER.debugCaught(DebugLogLevel.ERROR, le);
830 }
831 LDAPToolUtils.printErrorMessage(err, le.getMessageObject(),
832 le.getResultCode(),
833 le.getErrorMessage(),
834 le.getMatchedDN());
835 int code = le.getResultCode();
836 return code;
837 } catch(LDAPConnectionException lce)
838 {
839 if (debugEnabled())
840 {
841 TRACER.debugCaught(DebugLogLevel.ERROR, lce);
842 }
843 LDAPToolUtils.printErrorMessage(err, lce.getMessageObject(),
844 lce.getResultCode(),
845 lce.getErrorMessage(),
846 lce.getMatchedDN());
847 int code = lce.getResultCode();
848 return code;
849 } catch(Exception e)
850 {
851 if (debugEnabled())
852 {
853 TRACER.debugCaught(DebugLogLevel.ERROR, e);
854 }
855 err.println(wrapText(e.getMessage(), MAX_LINE_WIDTH));
856 return 1;
857 } finally
858 {
859 if(connection != null)
860 {
861 if (ldapDelete == null)
862 {
863 connection.close(null);
864 }
865 else
866 {
867 connection.close(ldapDelete.nextMessageID);
868 }
869 }
870 }
871 return 0;
872 }
873
874 }
875