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