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.text.ParseException; 036import java.util.ArrayList; 037import java.util.List; 038import java.util.concurrent.atomic.AtomicInteger; 039 040import org.forgerock.i18n.LocalizableMessage; 041import org.forgerock.opendj.ldap.ByteString; 042import org.forgerock.opendj.ldap.DecodeException; 043import org.opends.server.controls.LDAPAssertionRequestControl; 044import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 045import org.opends.server.protocols.ldap.CompareRequestProtocolOp; 046import org.opends.server.protocols.ldap.CompareResponseProtocolOp; 047import org.opends.server.protocols.ldap.LDAPFilter; 048import org.opends.server.protocols.ldap.LDAPMessage; 049import org.opends.server.protocols.ldap.ProtocolOp; 050import org.opends.server.types.Control; 051import org.opends.server.types.LDAPException; 052import org.opends.server.types.NullOutputStream; 053import org.opends.server.util.Base64; 054import org.opends.server.util.EmbeddedUtils; 055 056import com.forgerock.opendj.cli.ArgumentException; 057import com.forgerock.opendj.cli.ArgumentParser; 058import com.forgerock.opendj.cli.BooleanArgument; 059import com.forgerock.opendj.cli.CliConstants; 060import com.forgerock.opendj.cli.ClientException; 061import com.forgerock.opendj.cli.FileBasedArgument; 062import com.forgerock.opendj.cli.IntegerArgument; 063import com.forgerock.opendj.cli.StringArgument; 064 065/** 066 * This class provides a tool that can be used to issue compare requests to the 067 * Directory Server. 068 */ 069public class LDAPCompare 070{ 071 /** The fully-qualified name of this class. */ 072 private static final String CLASS_NAME = 073 "org.opends.server.tools.LDAPCompare"; 074 075 076 /** The message ID counter to use for requests. */ 077 private final AtomicInteger nextMessageID; 078 079 /** The print stream to use for standard error. */ 080 private final PrintStream err; 081 /** The print stream to use for standard output. */ 082 private final PrintStream out; 083 084 /** Tells whether the command-line is being executed in script friendly mode or not. */ 085 private boolean isScriptFriendly; 086 087 088 /** 089 * Constructor for the LDAPCompare object. 090 * 091 * @param nextMessageID The message ID counter to use for requests. 092 * @param out The print stream to use for standard output. 093 * @param err The print stream to use for standard error. 094 */ 095 public LDAPCompare(AtomicInteger nextMessageID, PrintStream out, 096 PrintStream err) 097 { 098 this.nextMessageID = nextMessageID; 099 this.out = out; 100 this.err = err; 101 } 102 103 /** 104 * Execute the compare request in the specified list of DNs. 105 * 106 * @param connection The connection to execute the request on. 107 * @param attributeType The attribute type to compare. 108 * @param attributeVal The attribute value to compare. 109 * @param lines The list of DNs to compare the attribute in. 110 * @param compareOptions The constraints for the compare request. 111 * @return the LDAP result code for the operation 112 * 113 * @throws IOException If a problem occurs while communicating with the 114 * Directory Server. 115 * 116 * @throws LDAPException If the server returns an error response. 117 */ 118 public int readAndExecute(LDAPConnection connection, String attributeType, 119 byte[] attributeVal, List<String> lines, 120 LDAPCompareOptions compareOptions) 121 throws IOException, LDAPException 122 { 123 int aggResultCode = SUCCESS; 124 for(String line : lines) 125 { 126 int resultCode = 127 executeCompare(connection, attributeType, attributeVal, line, 128 compareOptions); 129 aggResultCode = aggregateResultCode(aggResultCode, resultCode); 130 } 131 return aggResultCode; 132 } 133 134 135 /** 136 * Read the specified DNs from the given reader 137 * (file or stdin) and execute the given compare request. 138 * 139 * @param connection The connection to execute the request on. 140 * @param attributeType The attribute type to compare. 141 * @param attributeVal The attribute value to compare. 142 * @param reader The reader to read the list of DNs from. 143 * @param compareOptions The constraints for the compare request. 144 * @return the LDAP result code for the operation 145 * 146 * @throws IOException If a problem occurs while communicating with the 147 * Directory Server. 148 * 149 * @throws LDAPException If the server returns an error response. 150 */ 151 public int readAndExecute(LDAPConnection connection, String attributeType, 152 byte[] attributeVal, Reader reader, 153 LDAPCompareOptions compareOptions) 154 throws IOException, LDAPException 155 { 156 int aggResultCode = 0; 157 BufferedReader in = new BufferedReader(reader); 158 String line = null; 159 160 while ((line = in.readLine()) != null) 161 { 162 int resultCode = 163 executeCompare(connection, attributeType, attributeVal, line, 164 compareOptions); 165 aggResultCode = aggregateResultCode(aggResultCode, resultCode); 166 } 167 in.close(); 168 return aggResultCode; 169 } 170 171 172 /** 173 * Aggregates a new result code to the existing aggregated result codes. This 174 * method always overwrites the {@link LDAPResultCode#SUCCESS} and 175 * {@link LDAPResultCode#COMPARE_TRUE} result codes with the new result code. 176 * Then 177 * 178 * @param aggResultCodes 179 * the aggregated result codes (a.k.a "accumulator") 180 * @param newResultCode 181 * the new result code to aggregate 182 * @return the new aggregated result code 183 */ 184 int aggregateResultCode(int aggResultCodes, int newResultCode) 185 { 186 if (aggResultCodes == SUCCESS || aggResultCodes == COMPARE_TRUE) 187 { 188 aggResultCodes = newResultCode; 189 } 190 else if (aggResultCodes == COMPARE_FALSE && newResultCode != COMPARE_TRUE) 191 { 192 aggResultCodes = newResultCode; 193 } 194 return aggResultCodes; 195 } 196 197 198 /** 199 * Execute the compare request for the specified DN entry. 200 * 201 * @param connection The connection to execute the request on. 202 * @param attributeType The attribute type to compare. 203 * @param attributeVal The attribute value to compare. 204 * @param line The DN to compare attribute in. 205 * @param compareOptions The constraints for the compare request. 206 * @return the LDAP result code for the operation 207 * 208 * @throws IOException If a problem occurs while communicating with the 209 * Directory Server. 210 * 211 * @throws LDAPException If the server returns an error response. 212 */ 213 private int executeCompare(LDAPConnection connection, String attributeType, 214 byte[] attributeVal, String line, 215 LDAPCompareOptions compareOptions) 216 throws IOException, LDAPException 217 { 218 ArrayList<Control> controls = compareOptions.getControls(); 219 ByteString dnOctetStr = ByteString.valueOfUtf8(line); 220 ByteString attrValOctetStr = ByteString.wrap(attributeVal); 221 222 ProtocolOp protocolOp = new CompareRequestProtocolOp(dnOctetStr, 223 attributeType, attrValOctetStr); 224 225 226 if (!isScriptFriendly()) 227 { 228 out.println(INFO_PROCESSING_COMPARE_OPERATION.get( 229 attributeType, attrValOctetStr, dnOctetStr)); 230 } 231 232 if(!compareOptions.showOperations()) 233 { 234 LDAPMessage responseMessage = null; 235 try 236 { 237 LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(), 238 protocolOp, controls); 239 connection.getLDAPWriter().writeMessage(message); 240 responseMessage = connection.getLDAPReader().readMessage(); 241 } catch(DecodeException ae) 242 { 243 if (!compareOptions.continueOnError()) 244 { 245 String message = LDAPToolUtils.getMessageForConnectionException(ae); 246 throw new IOException(message, ae); 247 } 248 else 249 { 250 printWrappedText(err, INFO_OPERATION_FAILED.get("COMPARE")); 251 printWrappedText(err, ae.getMessage()); 252 return OPERATIONS_ERROR; 253 } 254 } 255 256 CompareResponseProtocolOp op = 257 responseMessage.getCompareResponseProtocolOp(); 258 int resultCode = op.getResultCode(); 259 LocalizableMessage errorMessage = op.getErrorMessage(); 260 261 if(resultCode != COMPARE_TRUE && resultCode != COMPARE_FALSE 262 && !compareOptions.continueOnError()) 263 { 264 LocalizableMessage msg = INFO_OPERATION_FAILED.get("COMPARE"); 265 throw new LDAPException(resultCode, errorMessage, msg, 266 op.getMatchedDN(), null); 267 } else 268 { 269 if(resultCode == COMPARE_FALSE) 270 { 271 if (isScriptFriendly()) 272 { 273 out.println(line+": "+COMPARE_FALSE); 274 } 275 else 276 { 277 out.println(INFO_COMPARE_OPERATION_RESULT_FALSE.get(line)); 278 } 279 } else if(resultCode == COMPARE_TRUE) 280 { 281 if (isScriptFriendly()) 282 { 283 out.println(line+": "+COMPARE_TRUE); 284 } 285 else 286 { 287 out.println(INFO_COMPARE_OPERATION_RESULT_TRUE.get(line)); 288 } 289 } else 290 { 291 LocalizableMessage msg = INFO_OPERATION_FAILED.get("COMPARE"); 292 LDAPToolUtils.printErrorMessage(err, msg, resultCode, errorMessage, 293 op.getMatchedDN()); 294 } 295 } 296 return resultCode; 297 } 298 return SUCCESS; 299 } 300 301 /** 302 * The main method for LDAPCompare tool. 303 * 304 * @param args The command-line arguments provided to this program. 305 */ 306 public static void main(String[] args) 307 { 308 int retCode = mainCompare(args, true, System.out, System.err); 309 if(retCode != 0) 310 { 311 System.exit(filterExitCode(retCode)); 312 } 313 } 314 315 /** 316 * Parses the provided command-line arguments and uses that information to 317 * run the ldapcompare tool. 318 * 319 * @param args The command-line arguments provided to this program. 320 * 321 * @return The error code. 322 */ 323 public static int mainCompare(String[] args) 324 { 325 return mainCompare(args, true, System.out, System.err); 326 } 327 328 /** 329 * Parses the provided command-line arguments and uses that information to 330 * run the ldapcompare tool. 331 * 332 * @param args The command-line arguments provided to this 333 * program. 334 * @param initializeServer Indicates whether to initialize the server. 335 * @param outStream The output stream to use for standard output, or 336 * <CODE>null</CODE> if standard output is not 337 * needed. 338 * @param errStream The output stream to use for standard error, or 339 * <CODE>null</CODE> if standard error is not 340 * needed. 341 * 342 * @return The error code. 343 */ 344 public static int mainCompare(String[] args, boolean initializeServer, 345 OutputStream outStream, OutputStream errStream) 346 { 347 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 348 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 349 350 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions(); 351 LDAPCompareOptions compareOptions = new LDAPCompareOptions(); 352 LDAPConnection connection = null; 353 354 final BooleanArgument continueOnError; 355 final BooleanArgument noop; 356 final BooleanArgument saslExternal; 357 final BooleanArgument showUsage; 358 final BooleanArgument useCompareResultCode; 359 final BooleanArgument startTLS; 360 final BooleanArgument trustAll; 361 final BooleanArgument useSSL; 362 final BooleanArgument verbose; 363 final FileBasedArgument bindPasswordFile; 364 final FileBasedArgument keyStorePasswordFile; 365 final FileBasedArgument trustStorePasswordFile; 366 final IntegerArgument port; 367 final IntegerArgument version; 368 final StringArgument assertionFilter; 369 final StringArgument bindDN; 370 final StringArgument bindPassword; 371 final StringArgument certNickname; 372 final StringArgument controlStr; 373 final StringArgument encodingStr; 374 final StringArgument filename; 375 final StringArgument hostName; 376 final StringArgument keyStorePath; 377 final StringArgument keyStorePassword; 378 final StringArgument saslOptions; 379 final StringArgument trustStorePath; 380 final StringArgument trustStorePassword; 381 final IntegerArgument connectTimeout; 382 final StringArgument propertiesFileArgument; 383 final BooleanArgument noPropertiesFileArgument; 384 BooleanArgument scriptFriendlyArgument = null; 385 386 final List<String> dnStrings = new ArrayList<> (); 387 final String attributeType; 388 final byte[] attributeVal; 389 Reader rdr = null; 390 391 // Create the command-line argument parser for use with this program. 392 LocalizableMessage toolDescription = INFO_LDAPCOMPARE_TOOL_DESCRIPTION.get(); 393 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, 394 false, true, 1, 0, 395 " \'attribute:value\' \"DN\" ..."); 396 argParser.setShortToolDescription(REF_SHORT_DESC_LDAPCOMPARE.get()); 397 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 398 399 try 400 { 401 scriptFriendlyArgument = 402 BooleanArgument.builder("script-friendly") 403 .shortIdentifier('s') 404 .description(INFO_DESCRIPTION_SCRIPT_FRIENDLY.get()) 405 .buildAndAddToParser(argParser); 406 propertiesFileArgument = 407 StringArgument.builder(OPTION_LONG_PROP_FILE_PATH) 408 .description(INFO_DESCRIPTION_PROP_FILE_PATH.get()) 409 .valuePlaceholder(INFO_PROP_FILE_PATH_PLACEHOLDER.get()) 410 .buildAndAddToParser(argParser); 411 argParser.setFilePropertiesArgument(propertiesFileArgument); 412 413 noPropertiesFileArgument = 414 BooleanArgument.builder(OPTION_LONG_NO_PROP_FILE) 415 .description(INFO_DESCRIPTION_NO_PROP_FILE.get()) 416 .buildAndAddToParser(argParser); 417 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); 418 419 hostName = 420 StringArgument.builder(OPTION_LONG_HOST) 421 .shortIdentifier(OPTION_SHORT_HOST) 422 .description(INFO_DESCRIPTION_HOST.get()) 423 .defaultValue("localhost") 424 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 425 .buildAndAddToParser(argParser); 426 port = 427 IntegerArgument.builder(OPTION_LONG_PORT) 428 .shortIdentifier(OPTION_SHORT_PORT) 429 .description(INFO_DESCRIPTION_PORT.get()) 430 .range(1, 65535) 431 .defaultValue(389) 432 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 433 .buildAndAddToParser(argParser); 434 useSSL = 435 BooleanArgument.builder(OPTION_LONG_USE_SSL) 436 .shortIdentifier(OPTION_SHORT_USE_SSL) 437 .description(INFO_DESCRIPTION_USE_SSL.get()) 438 .buildAndAddToParser(argParser); 439 startTLS = 440 BooleanArgument.builder(OPTION_LONG_START_TLS) 441 .shortIdentifier(OPTION_SHORT_START_TLS) 442 .description(INFO_DESCRIPTION_START_TLS.get()) 443 .buildAndAddToParser(argParser); 444 bindDN = 445 StringArgument.builder(OPTION_LONG_BINDDN) 446 .shortIdentifier(OPTION_SHORT_BINDDN) 447 .description(INFO_DESCRIPTION_BINDDN.get()) 448 .valuePlaceholder(INFO_BINDDN_PLACEHOLDER.get()) 449 .buildAndAddToParser(argParser); 450 bindPassword = 451 StringArgument.builder(OPTION_LONG_BINDPWD) 452 .shortIdentifier(OPTION_SHORT_BINDPWD) 453 .description(INFO_DESCRIPTION_BINDPASSWORD.get()) 454 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 455 .buildAndAddToParser(argParser); 456 bindPasswordFile = 457 FileBasedArgument.builder(OPTION_LONG_BINDPWD_FILE) 458 .shortIdentifier(OPTION_SHORT_BINDPWD_FILE) 459 .description(INFO_DESCRIPTION_BINDPASSWORDFILE.get()) 460 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 461 .buildAndAddToParser(argParser); 462 filename = 463 StringArgument.builder(OPTION_LONG_FILENAME) 464 .shortIdentifier(OPTION_SHORT_FILENAME) 465 .description(INFO_COMPARE_DESCRIPTION_FILENAME.get()) 466 .valuePlaceholder(INFO_FILE_PLACEHOLDER.get()) 467 .buildAndAddToParser(argParser); 468 saslExternal = 469 BooleanArgument.builder("useSASLExternal") 470 .shortIdentifier('r') 471 .description(INFO_DESCRIPTION_USE_SASL_EXTERNAL.get()) 472 .buildAndAddToParser(argParser); 473 saslOptions = 474 StringArgument.builder(OPTION_LONG_SASLOPTION) 475 .shortIdentifier(OPTION_SHORT_SASLOPTION) 476 .description(INFO_DESCRIPTION_SASL_PROPERTIES.get()) 477 .multiValued() 478 .valuePlaceholder(INFO_SASL_OPTION_PLACEHOLDER.get()) 479 .buildAndAddToParser(argParser); 480 481 trustAll = trustAllArgument(); 482 argParser.addArgument(trustAll); 483 484 keyStorePath = 485 StringArgument.builder(OPTION_LONG_KEYSTOREPATH) 486 .shortIdentifier(OPTION_SHORT_KEYSTOREPATH) 487 .description(INFO_DESCRIPTION_KEYSTOREPATH.get()) 488 .valuePlaceholder(INFO_KEYSTOREPATH_PLACEHOLDER.get()) 489 .buildAndAddToParser(argParser); 490 keyStorePassword = 491 StringArgument.builder(OPTION_LONG_KEYSTORE_PWD) 492 .shortIdentifier(OPTION_SHORT_KEYSTORE_PWD) 493 .description(INFO_DESCRIPTION_KEYSTOREPASSWORD.get()) 494 .valuePlaceholder(INFO_KEYSTORE_PWD_PLACEHOLDER.get()) 495 .buildAndAddToParser(argParser); 496 keyStorePasswordFile = 497 FileBasedArgument.builder(OPTION_LONG_KEYSTORE_PWD_FILE) 498 .shortIdentifier(OPTION_SHORT_KEYSTORE_PWD_FILE) 499 .description(INFO_DESCRIPTION_KEYSTOREPASSWORD_FILE.get()) 500 .valuePlaceholder(INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get()) 501 .buildAndAddToParser(argParser); 502 certNickname = 503 StringArgument.builder("certNickname") 504 .shortIdentifier('N') 505 .description(INFO_DESCRIPTION_CERT_NICKNAME.get()) 506 .valuePlaceholder(INFO_NICKNAME_PLACEHOLDER.get()) 507 .buildAndAddToParser(argParser); 508 trustStorePath = 509 StringArgument.builder(OPTION_LONG_TRUSTSTOREPATH) 510 .shortIdentifier(OPTION_SHORT_TRUSTSTOREPATH) 511 .description(INFO_DESCRIPTION_TRUSTSTOREPATH.get()) 512 .valuePlaceholder(INFO_TRUSTSTOREPATH_PLACEHOLDER.get()) 513 .buildAndAddToParser(argParser); 514 trustStorePassword = 515 StringArgument.builder(OPTION_LONG_TRUSTSTORE_PWD) 516 .description(INFO_DESCRIPTION_TRUSTSTOREPASSWORD.get()) 517 .valuePlaceholder(INFO_TRUSTSTORE_PWD_PLACEHOLDER.get()) 518 .buildAndAddToParser(argParser); 519 trustStorePasswordFile = 520 FileBasedArgument.builder(OPTION_LONG_TRUSTSTORE_PWD_FILE) 521 .shortIdentifier(OPTION_SHORT_TRUSTSTORE_PWD_FILE) 522 .description(INFO_DESCRIPTION_TRUSTSTOREPASSWORD_FILE.get()) 523 .valuePlaceholder(INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get()) 524 .buildAndAddToParser(argParser); 525 assertionFilter = 526 StringArgument.builder(OPTION_LONG_ASSERTION_FILE) 527 .description(INFO_DESCRIPTION_ASSERTION_FILTER.get()) 528 .valuePlaceholder(INFO_ASSERTION_FILTER_PLACEHOLDER.get()) 529 .buildAndAddToParser(argParser); 530 controlStr = 531 StringArgument.builder("control") 532 .shortIdentifier('J') 533 .description(INFO_DESCRIPTION_CONTROLS.get()) 534 .multiValued() 535 .valuePlaceholder(INFO_LDAP_CONTROL_PLACEHOLDER.get()) 536 .buildAndAddToParser(argParser); 537 version = 538 IntegerArgument.builder(OPTION_LONG_PROTOCOL_VERSION) 539 .shortIdentifier(OPTION_SHORT_PROTOCOL_VERSION) 540 .description(INFO_DESCRIPTION_VERSION.get()) 541 .defaultValue(3) 542 .valuePlaceholder(INFO_PROTOCOL_VERSION_PLACEHOLDER.get()) 543 .buildAndAddToParser(argParser); 544 connectTimeout = 545 IntegerArgument.builder(OPTION_LONG_CONNECT_TIMEOUT) 546 .description(INFO_DESCRIPTION_CONNECTION_TIMEOUT.get()) 547 .lowerBound(0) 548 .defaultValue(CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT) 549 .valuePlaceholder(INFO_TIMEOUT_PLACEHOLDER.get()) 550 .buildAndAddToParser(argParser); 551 encodingStr = 552 StringArgument.builder("encoding") 553 .shortIdentifier('i') 554 .description(INFO_DESCRIPTION_ENCODING.get()) 555 .valuePlaceholder(INFO_ENCODING_PLACEHOLDER.get()) 556 .buildAndAddToParser(argParser); 557 continueOnError = 558 BooleanArgument.builder("continueOnError") 559 .shortIdentifier('c') 560 .description(INFO_DESCRIPTION_CONTINUE_ON_ERROR.get()) 561 .buildAndAddToParser(argParser); 562 noop = 563 BooleanArgument.builder(OPTION_LONG_DRYRUN) 564 .shortIdentifier(OPTION_SHORT_DRYRUN) 565 .description(INFO_DESCRIPTION_NOOP.get()) 566 .buildAndAddToParser(argParser); 567 568 verbose = verboseArgument(); 569 argParser.addArgument(verbose); 570 571 showUsage = showUsageArgument(); 572 argParser.addArgument(showUsage); 573 574 useCompareResultCode = 575 BooleanArgument.builder("useCompareResultCode") 576 .shortIdentifier('m') 577 .description(INFO_LDAPCOMPARE_DESCRIPTION_USE_COMPARE_RESULT.get()) 578 .buildAndAddToParser(argParser); 579 580 argParser.setUsageArgument(showUsage, out); 581 } catch (ArgumentException ae) 582 { 583 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 584 return CLIENT_SIDE_PARAM_ERROR; 585 } 586 587 // Parse the command-line arguments provided to this program. 588 try 589 { 590 argParser.parseArguments(args); 591 } 592 catch (ArgumentException ae) 593 { 594 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 595 return CLIENT_SIDE_PARAM_ERROR; 596 } 597 598 // If we should just display usage or version information, 599 // then print it and exit. 600 if (argParser.usageOrVersionDisplayed()) 601 { 602 return SUCCESS; 603 } 604 605 if (bindPassword.isPresent() && bindPasswordFile.isPresent()) 606 { 607 printWrappedText(err, conflictingArgsErrorMessage(bindPassword, bindPasswordFile)); 608 return CLIENT_SIDE_PARAM_ERROR; 609 } 610 611 ArrayList<String> attrAndDNStrings = argParser.getTrailingArguments(); 612 613 if(attrAndDNStrings.isEmpty()) 614 { 615 printWrappedText(err, ERR_LDAPCOMPARE_NO_ATTR.get()); 616 return CLIENT_SIDE_PARAM_ERROR; 617 } 618 619 // First element should be an attribute string. 620 String attributeString = attrAndDNStrings.remove(0); 621 // Rest are DN strings 622 dnStrings.addAll(attrAndDNStrings); 623 624 // If no DNs were provided, then exit with an error. 625 if (dnStrings.isEmpty() && !filename.isPresent()) 626 { 627 printWrappedText(err, ERR_LDAPCOMPARE_NO_DNS.get()); 628 return CLIENT_SIDE_PARAM_ERROR; 629 } 630 631 // If trailing DNs were provided and the filename argument was also 632 // provided, exit with an error. 633 if (!dnStrings.isEmpty() && filename.isPresent()) 634 { 635 printWrappedText(err, ERR_LDAPCOMPARE_FILENAME_AND_DNS.get()); 636 return CLIENT_SIDE_PARAM_ERROR; 637 } 638 639 // parse the attribute string 640 int idx = attributeString.indexOf(":"); 641 if(idx == -1) 642 { 643 printWrappedText(err, ERR_LDAPCOMPARE_INVALID_ATTR_STRING.get(attributeString)); 644 return CLIENT_SIDE_PARAM_ERROR; 645 } 646 attributeType = attributeString.substring(0, idx); 647 String remainder = attributeString.substring(idx+1, 648 attributeString.length()); 649 if (remainder.length() > 0) 650 { 651 char nextChar = remainder.charAt(0); 652 if(nextChar == ':') 653 { 654 String base64 = remainder.substring(1, remainder.length()); 655 try 656 { 657 attributeVal = Base64.decode(base64); 658 } 659 catch (ParseException e) 660 { 661 printWrappedText(err, INFO_COMPARE_CANNOT_BASE64_DECODE_ASSERTION_VALUE.get()); 662 printWrappedText(err, e.getLocalizedMessage()); 663 return CLIENT_SIDE_PARAM_ERROR; 664 } 665 } else if(nextChar == '<') 666 { 667 try 668 { 669 String filePath = remainder.substring(1, remainder.length()); 670 attributeVal = LDAPToolUtils.readBytesFromFile(filePath, err); 671 } 672 catch (Exception e) 673 { 674 printWrappedText(err, INFO_COMPARE_CANNOT_READ_ASSERTION_VALUE_FROM_FILE.get(e)); 675 return CLIENT_SIDE_PARAM_ERROR; 676 } 677 } else 678 { 679 attributeVal = remainder.getBytes(); 680 } 681 } 682 else 683 { 684 attributeVal = remainder.getBytes(); 685 } 686 687 String hostNameValue = hostName.getValue(); 688 int portNumber = 389; 689 try 690 { 691 portNumber = port.getIntValue(); 692 } catch (ArgumentException ae) 693 { 694 argParser.displayMessageAndUsageReference(err, ae.getMessageObject()); 695 return CLIENT_SIDE_PARAM_ERROR; 696 } 697 698 try 699 { 700 int versionNumber = version.getIntValue(); 701 if(versionNumber != 2 && versionNumber != 3) 702 { 703 printWrappedText(err, ERR_DESCRIPTION_INVALID_VERSION.get(versionNumber)); 704 return CLIENT_SIDE_PARAM_ERROR; 705 } 706 connectionOptions.setVersionNumber(versionNumber); 707 } catch(ArgumentException ae) 708 { 709 argParser.displayMessageAndUsageReference(err, ae.getMessageObject()); 710 return CLIENT_SIDE_PARAM_ERROR; 711 } 712 713 714 String bindDNValue = bindDN.getValue(); 715 String fileNameValue = filename.getValue(); 716 String bindPasswordValue; 717 try 718 { 719 bindPasswordValue = getPasswordValue( 720 bindPassword, bindPasswordFile, bindDNValue, out, err); 721 } 722 catch (ClientException ex) 723 { 724 printWrappedText(err, ex.getMessage()); 725 return CLIENT_SIDE_PARAM_ERROR; 726 } 727 728 String keyStorePathValue = keyStorePath.getValue(); 729 String trustStorePathValue = trustStorePath.getValue(); 730 731 String keyStorePasswordValue = null; 732 if (keyStorePassword.isPresent()) 733 { 734 keyStorePasswordValue = keyStorePassword.getValue(); 735 } 736 else if (keyStorePasswordFile.isPresent()) 737 { 738 keyStorePasswordValue = keyStorePasswordFile.getValue(); 739 } 740 741 String trustStorePasswordValue = null; 742 if (trustStorePassword.isPresent()) 743 { 744 trustStorePasswordValue = trustStorePassword.getValue(); 745 } 746 else if (trustStorePasswordFile.isPresent()) 747 { 748 trustStorePasswordValue = trustStorePasswordFile.getValue(); 749 } 750 751 compareOptions.setShowOperations(noop.isPresent()); 752 compareOptions.setVerbose(verbose.isPresent()); 753 compareOptions.setContinueOnError(continueOnError.isPresent()); 754 compareOptions.setEncoding(encodingStr.getValue()); 755 756 if(controlStr.isPresent()) 757 { 758 for (String ctrlString : controlStr.getValues()) 759 { 760 Control ctrl = LDAPToolUtils.getControl(ctrlString, err); 761 if(ctrl == null) 762 { 763 printWrappedText(err, ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString)); 764 return CLIENT_SIDE_PARAM_ERROR; 765 } 766 compareOptions.getControls().add(ctrl); 767 } 768 } 769 770 if (assertionFilter.isPresent()) 771 { 772 String filterString = assertionFilter.getValue(); 773 LDAPFilter filter; 774 try 775 { 776 filter = LDAPFilter.decode(filterString); 777 778 Control assertionControl = 779 new LDAPAssertionRequestControl(true, filter); 780 compareOptions.getControls().add(assertionControl); 781 } 782 catch (LDAPException le) 783 { 784 printWrappedText(err, ERR_LDAP_ASSERTION_INVALID_FILTER.get(le.getMessage())); 785 return CLIENT_SIDE_PARAM_ERROR; 786 } 787 } 788 789 // Set the connection options. 790 // Parse the SASL properties. 791 connectionOptions.setSASLExternal(saslExternal.isPresent()); 792 if(saslOptions.isPresent()) 793 { 794 for (String saslOption : saslOptions.getValues()) 795 { 796 boolean val; 797 if(saslOption.startsWith("mech=")) 798 { 799 val = connectionOptions.setSASLMechanism(saslOption); 800 } 801 else 802 { 803 val = connectionOptions.addSASLProperty(saslOption); 804 } 805 if(!val) 806 { 807 return CLIENT_SIDE_PARAM_ERROR; 808 } 809 } 810 } 811 connectionOptions.setUseSSL(useSSL.isPresent()); 812 connectionOptions.setStartTLS(startTLS.isPresent()); 813 814 if(connectionOptions.useSASLExternal()) 815 { 816 if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS()) 817 { 818 printWrappedText(err, ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get()); 819 return CLIENT_SIDE_PARAM_ERROR; 820 } 821 if(keyStorePathValue == null) 822 { 823 printWrappedText(err, ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get()); 824 return CLIENT_SIDE_PARAM_ERROR; 825 } 826 } 827 828 LDAPCompare ldapCompare = null; 829 try 830 { 831 if (initializeServer) 832 { 833 // Bootstrap and initialize directory data structures. 834 EmbeddedUtils.initializeForClientUse(); 835 } 836 837 // Connect to the specified host with the supplied userDN and password. 838 SSLConnectionFactory sslConnectionFactory = null; 839 if(connectionOptions.useSSL() || connectionOptions.useStartTLS()) 840 { 841 String clientAlias; 842 if (certNickname.isPresent()) 843 { 844 clientAlias = certNickname.getValue(); 845 } 846 else 847 { 848 clientAlias = null; 849 } 850 851 sslConnectionFactory = new SSLConnectionFactory(); 852 sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue, 853 keyStorePasswordValue, clientAlias, 854 trustStorePathValue, trustStorePasswordValue); 855 connectionOptions.setSSLConnectionFactory(sslConnectionFactory); 856 } 857 858 AtomicInteger nextMessageID = new AtomicInteger(1); 859 connection = new LDAPConnection(hostNameValue, portNumber, 860 connectionOptions, out, err); 861 862 int timeout = connectTimeout.getIntValue(); 863 connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID, 864 timeout); 865 866 ldapCompare = new LDAPCompare(nextMessageID, out, err); 867 ldapCompare.isScriptFriendly = scriptFriendlyArgument.isPresent(); 868 if(fileNameValue == null && dnStrings.isEmpty()) 869 { 870 // Read from stdin. 871 rdr = new InputStreamReader(System.in); 872 } else if(fileNameValue != null) 873 { 874 try 875 { 876 rdr = new FileReader(fileNameValue); 877 } 878 catch (Throwable t) 879 { 880 String details = t.getMessage(); 881 if (details == null) 882 { 883 details = t.toString(); 884 } 885 printWrappedText(err, ERR_LDAPCOMPARE_ERROR_READING_FILE.get(fileNameValue, details)); 886 return CLIENT_SIDE_PARAM_ERROR; 887 } 888 } 889 int resultCode; 890 if(rdr != null) 891 { 892 resultCode = 893 ldapCompare.readAndExecute(connection, attributeType, attributeVal, 894 rdr, compareOptions); 895 } else 896 { 897 resultCode = 898 ldapCompare.readAndExecute(connection, attributeType, attributeVal, 899 dnStrings, compareOptions); 900 } 901 902 if (useCompareResultCode.isPresent()) 903 { 904 return resultCode; 905 } 906 return SUCCESS; 907 } catch(LDAPException le) 908 { 909 LDAPToolUtils.printErrorMessage( 910 err, le.getMessageObject(), 911 le.getResultCode(), 912 le.getMessageObject(), 913 le.getMatchedDN()); 914 return le.getResultCode(); 915 } catch(LDAPConnectionException lce) 916 { 917 LDAPToolUtils.printErrorMessage(err, 918 lce.getMessageObject(), 919 lce.getResultCode(), 920 lce.getMessageObject(), 921 lce.getMatchedDN()); 922 return lce.getResultCode(); 923 } catch(Exception e) 924 { 925 printWrappedText(err, e.getMessage()); 926 return OPERATIONS_ERROR; 927 } finally 928 { 929 if(connection != null) 930 { 931 if (ldapCompare != null) 932 { 933 connection.close(ldapCompare.nextMessageID); 934 } 935 else 936 { 937 connection.close(null); 938 } 939 } 940 } 941 } 942 943 private boolean isScriptFriendly() 944 { 945 return isScriptFriendly; 946 } 947}