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.LDAPConstants.*; 034import static org.opends.server.protocols.ldap.LDAPResultCode.*; 035import static org.opends.server.util.ServerConstants.*; 036import static org.opends.server.util.StaticUtils.*; 037import static org.opends.server.util.args.LDAPConnectionArgumentParser.*; 038 039import java.io.BufferedReader; 040import java.io.FileReader; 041import java.io.IOException; 042import java.io.OutputStream; 043import java.io.PrintStream; 044import java.util.*; 045import java.util.concurrent.atomic.AtomicInteger; 046 047import org.forgerock.i18n.LocalizableMessage; 048import org.forgerock.i18n.slf4j.LocalizedLogger; 049import org.forgerock.opendj.ldap.ByteString; 050import org.forgerock.opendj.ldap.DecodeException; 051import org.opends.server.controls.*; 052import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 053import org.opends.server.protocols.ldap.*; 054import org.opends.server.types.*; 055import org.opends.server.util.Base64; 056import org.opends.server.util.EmbeddedUtils; 057 058import com.forgerock.opendj.cli.ArgumentException; 059import com.forgerock.opendj.cli.ArgumentParser; 060import com.forgerock.opendj.cli.BooleanArgument; 061import com.forgerock.opendj.cli.CliConstants; 062import com.forgerock.opendj.cli.CommonArguments; 063import com.forgerock.opendj.cli.FileBasedArgument; 064import com.forgerock.opendj.cli.IntegerArgument; 065import com.forgerock.opendj.cli.MultiChoiceArgument; 066import com.forgerock.opendj.cli.StringArgument; 067 068/** 069 * This class provides a tool that can be used to issue search requests to the 070 * Directory Server. 071 */ 072public class LDAPSearch 073{ 074 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 075 076 /** The fully-qualified name of this class. */ 077 private static final String CLASS_NAME = "org.opends.server.tools.LDAPSearch"; 078 079 080 081 /** The set of response controls for the search. */ 082 private List<Control> responseControls; 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 093 094 /** 095 * Constructor for the LDAPSearch object. 096 * 097 * @param nextMessageID The message ID counter to use for requests. 098 * @param out The print stream to use for standard output. 099 * @param err The print stream to use for standard error. 100 */ 101 public LDAPSearch(AtomicInteger nextMessageID, PrintStream out, 102 PrintStream err) 103 { 104 this.nextMessageID = nextMessageID; 105 this.out = out; 106 this.err = err; 107 responseControls = new ArrayList<>(); 108 } 109 110 111 /** 112 * Execute the search based on the specified input parameters. 113 * 114 * @param connection The connection to use for the search. 115 * @param baseDN The base DN for the search request. 116 * @param filters The filters to use for the results. 117 * @param attributes The attributes to return in the results. 118 * @param searchOptions The constraints for the search. 119 * @param wrapColumn The column at which to wrap long lines. 120 * 121 * @return The number of matching entries returned by the server. If there 122 * were multiple search filters provided, then this will be the 123 * total number of matching entries for all searches. 124 * 125 * @throws IOException If a problem occurs while attempting to communicate 126 * with the Directory Server. 127 * 128 * @throws LDAPException If the Directory Server returns an error response. 129 */ 130 public int executeSearch(LDAPConnection connection, String baseDN, 131 ArrayList<LDAPFilter> filters, 132 LinkedHashSet<String> attributes, 133 LDAPSearchOptions searchOptions, 134 int wrapColumn ) 135 throws IOException, LDAPException 136 { 137 int matchingEntries = 0; 138 139 for (LDAPFilter filter: filters) 140 { 141 ByteString asn1OctetStr = ByteString.valueOfUtf8(baseDN); 142 143 SearchRequestProtocolOp protocolOp = 144 new SearchRequestProtocolOp(asn1OctetStr, 145 searchOptions.getSearchScope(), 146 searchOptions.getDereferencePolicy(), 147 searchOptions.getSizeLimit(), 148 searchOptions.getTimeLimit(), 149 searchOptions.getTypesOnly(), 150 filter, attributes); 151 if(!searchOptions.showOperations()) 152 { 153 try 154 { 155 boolean typesOnly = searchOptions.getTypesOnly(); 156 LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(), 157 protocolOp, 158 searchOptions.getControls()); 159 connection.getLDAPWriter().writeMessage(message); 160 161 byte opType; 162 do 163 { 164 int resultCode = 0; 165 LocalizableMessage errorMessage = null; 166 DN matchedDN = null; 167 LDAPMessage responseMessage = 168 connection.getLDAPReader().readMessage(); 169 responseControls = responseMessage.getControls(); 170 171 172 opType = responseMessage.getProtocolOpType(); 173 switch(opType) 174 { 175 case OP_TYPE_SEARCH_RESULT_ENTRY: 176 for (Control c : responseControls) 177 { 178 if (c.getOID().equals(OID_ENTRY_CHANGE_NOTIFICATION)) 179 { 180 try 181 { 182 EntryChangeNotificationControl ecn = 183 EntryChangeNotificationControl.DECODER 184 .decode(c.isCritical(), ((LDAPControl) c).getValue()); 185 186 out.println(INFO_LDAPSEARCH_PSEARCH_CHANGE_TYPE.get(ecn.getChangeType())); 187 DN previousDN = ecn.getPreviousDN(); 188 if (previousDN != null) 189 { 190 out.println(INFO_LDAPSEARCH_PSEARCH_PREVIOUS_DN.get(previousDN)); 191 } 192 } catch (Exception e) {} 193 } 194 else if (c.getOID().equals(OID_ACCOUNT_USABLE_CONTROL)) 195 { 196 try 197 { 198 AccountUsableResponseControl acrc = 199 AccountUsableResponseControl.DECODER 200 .decode(c.isCritical(), ((LDAPControl) c).getValue()); 201 202 out.println(INFO_LDAPSEARCH_ACCTUSABLE_HEADER.get()); 203 if (acrc.isUsable()) 204 { 205 out.println(INFO_LDAPSEARCH_ACCTUSABLE_IS_USABLE.get()); 206 if (acrc.getSecondsBeforeExpiration() > 0) 207 { 208 int timeToExp = acrc.getSecondsBeforeExpiration(); 209 LocalizableMessage timeToExpStr = secondsToTimeString(timeToExp); 210 211 out.println( 212 INFO_LDAPSEARCH_ACCTUSABLE_TIME_UNTIL_EXPIRATION. 213 get(timeToExpStr)); 214 } 215 } 216 else 217 { 218 out.println( 219 INFO_LDAPSEARCH_ACCTUSABLE_NOT_USABLE.get()); 220 if (acrc.isInactive()) 221 { 222 out.println( 223 INFO_LDAPSEARCH_ACCTUSABLE_ACCT_INACTIVE.get()); 224 } 225 if (acrc.isReset()) 226 { 227 out.println( 228 INFO_LDAPSEARCH_ACCTUSABLE_PW_RESET.get()); 229 } 230 if (acrc.isExpired()) 231 { 232 out.println( 233 INFO_LDAPSEARCH_ACCTUSABLE_PW_EXPIRED.get()); 234 235 if (acrc.getRemainingGraceLogins() > 0) 236 { 237 out.println( 238 INFO_LDAPSEARCH_ACCTUSABLE_REMAINING_GRACE 239 .get(acrc.getRemainingGraceLogins())); 240 } 241 } 242 if (acrc.isLocked()) 243 { 244 out.println(INFO_LDAPSEARCH_ACCTUSABLE_LOCKED.get()); 245 if (acrc.getSecondsBeforeUnlock() > 0) 246 { 247 int timeToUnlock = acrc.getSecondsBeforeUnlock(); 248 LocalizableMessage timeToUnlockStr = 249 secondsToTimeString(timeToUnlock); 250 251 out.println( 252 INFO_LDAPSEARCH_ACCTUSABLE_TIME_UNTIL_UNLOCK 253 .get(timeToUnlockStr)); 254 } 255 } 256 } 257 } catch (Exception e) {} 258 } 259 else if (c.getOID().equals(OID_ECL_COOKIE_EXCHANGE_CONTROL)) 260 { 261 try 262 { 263 EntryChangelogNotificationControl ctrl = 264 EntryChangelogNotificationControl.DECODER.decode( 265 c.isCritical(), ((LDAPControl) c).getValue()); 266 out.println( 267 INFO_LDAPSEARCH_PUBLIC_CHANGELOG_COOKIE_EXC.get( 268 c.getOID(), ctrl.getCookie())); 269 } 270 catch (Exception e) 271 { 272 logger.traceException(e); 273 } 274 } 275 } 276 277 SearchResultEntryProtocolOp searchEntryOp = 278 responseMessage.getSearchResultEntryProtocolOp(); 279 StringBuilder sb = new StringBuilder(); 280 toLDIF(searchEntryOp, sb, wrapColumn, typesOnly); 281 out.print(sb.toString()); 282 matchingEntries++; 283 break; 284 285 case OP_TYPE_SEARCH_RESULT_REFERENCE: 286 SearchResultReferenceProtocolOp searchRefOp = 287 responseMessage.getSearchResultReferenceProtocolOp(); 288 out.println(searchRefOp.toString()); 289 break; 290 291 case OP_TYPE_SEARCH_RESULT_DONE: 292 SearchResultDoneProtocolOp searchOp = 293 responseMessage.getSearchResultDoneProtocolOp(); 294 resultCode = searchOp.getResultCode(); 295 errorMessage = searchOp.getErrorMessage(); 296 matchedDN = searchOp.getMatchedDN(); 297 298 for (Control c : responseMessage.getControls()) 299 { 300 if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) 301 { 302 try 303 { 304 ServerSideSortResponseControl sortResponse = 305 ServerSideSortResponseControl.DECODER 306 .decode(c.isCritical(), ((LDAPControl) c).getValue()); 307 int rc = sortResponse.getResultCode(); 308 if (rc != LDAPResultCode.SUCCESS) 309 { 310 LocalizableMessage msg = WARN_LDAPSEARCH_SORT_ERROR.get( 311 LDAPResultCode.toString(rc)); 312 err.println(msg); 313 } 314 } 315 catch (Exception e) 316 { 317 LocalizableMessage msg = 318 WARN_LDAPSEARCH_CANNOT_DECODE_SORT_RESPONSE.get( 319 getExceptionMessage(e)); 320 err.println(msg); 321 } 322 } 323 else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) 324 { 325 try 326 { 327 VLVResponseControl vlvResponse = 328 VLVResponseControl.DECODER.decode(c.isCritical(), 329 ((LDAPControl) c).getValue()); 330 int rc = vlvResponse.getVLVResultCode(); 331 if (rc == LDAPResultCode.SUCCESS) 332 { 333 LocalizableMessage msg = INFO_LDAPSEARCH_VLV_TARGET_OFFSET.get( 334 vlvResponse.getTargetPosition()); 335 out.println(msg); 336 337 338 msg = INFO_LDAPSEARCH_VLV_CONTENT_COUNT.get( 339 vlvResponse.getContentCount()); 340 out.println(msg); 341 } 342 else 343 { 344 LocalizableMessage msg = WARN_LDAPSEARCH_VLV_ERROR.get( 345 LDAPResultCode.toString(rc)); 346 err.println(msg); 347 } 348 } 349 catch (Exception e) 350 { 351 LocalizableMessage msg = 352 WARN_LDAPSEARCH_CANNOT_DECODE_VLV_RESPONSE.get( 353 getExceptionMessage(e)); 354 err.println(msg); 355 } 356 } 357 } 358 359 break; 360 default: 361 if(opType == OP_TYPE_EXTENDED_RESPONSE) 362 { 363 ExtendedResponseProtocolOp op = 364 responseMessage.getExtendedResponseProtocolOp(); 365 if(op.getOID().equals(OID_NOTICE_OF_DISCONNECTION)) 366 { 367 resultCode = op.getResultCode(); 368 errorMessage = op.getErrorMessage(); 369 matchedDN = op.getMatchedDN(); 370 break; 371 } 372 } 373 // FIXME - throw exception? 374 printWrappedText(err, INFO_SEARCH_OPERATION_INVALID_PROTOCOL.get(opType)); 375 } 376 377 if(resultCode != SUCCESS) 378 { 379 LocalizableMessage msg = INFO_OPERATION_FAILED.get("SEARCH"); 380 throw new LDAPException(resultCode, errorMessage, msg, 381 matchedDN, null); 382 } 383 else if (errorMessage != null) 384 { 385 out.println(); 386 printWrappedText(out, errorMessage); 387 } 388 389 } while(opType != OP_TYPE_SEARCH_RESULT_DONE); 390 391 } catch(DecodeException ae) 392 { 393 logger.traceException(ae); 394 throw new IOException(ae.getMessage()); 395 } 396 } 397 } 398 399 if (searchOptions.countMatchingEntries()) 400 { 401 LocalizableMessage message = 402 INFO_LDAPSEARCH_MATCHING_ENTRY_COUNT.get(matchingEntries); 403 out.println(message); 404 out.println(); 405 } 406 return matchingEntries; 407 } 408 409 /** 410 * Appends an LDIF representation of the entry to the provided buffer. 411 * 412 * @param entry The entry to be written as LDIF. 413 * @param buffer The buffer to which the entry should be appended. 414 * @param wrapColumn The column at which long lines should be wrapped. 415 * @param typesOnly Indicates whether to include only attribute types 416 * without values. 417 */ 418 public void toLDIF(SearchResultEntryProtocolOp entry, StringBuilder buffer, 419 int wrapColumn, boolean typesOnly) 420 { 421 // Add the DN to the buffer. 422 String dnString = entry.getDN().toString(); 423 int colsRemaining; 424 if (needsBase64Encoding(dnString)) 425 { 426 dnString = Base64.encode(getBytes(dnString)); 427 buffer.append("dn:: "); 428 429 colsRemaining = wrapColumn - 5; 430 } 431 else 432 { 433 buffer.append("dn: "); 434 435 colsRemaining = wrapColumn - 4; 436 } 437 438 int dnLength = dnString.length(); 439 if (dnLength <= colsRemaining || colsRemaining <= 0) 440 { 441 buffer.append(dnString); 442 buffer.append(EOL); 443 } 444 else 445 { 446 buffer.append(dnString, 0, colsRemaining); 447 buffer.append(EOL); 448 449 int startPos = colsRemaining; 450 while (dnLength - startPos > wrapColumn - 1) 451 { 452 buffer.append(" "); 453 buffer.append(dnString, startPos, startPos+wrapColumn-1); 454 buffer.append(EOL); 455 456 startPos += wrapColumn-1; 457 } 458 459 if (startPos < dnLength) 460 { 461 buffer.append(" "); 462 buffer.append(dnString.substring(startPos)); 463 buffer.append(EOL); 464 } 465 } 466 467 468 LinkedList<LDAPAttribute> attributes = entry.getAttributes(); 469 // Add the attributes to the buffer. 470 for (LDAPAttribute a : attributes) 471 { 472 String name = a.getAttributeType(); 473 int nameLength = name.length(); 474 475 476 if(typesOnly) 477 { 478 buffer.append(name); 479 buffer.append(EOL); 480 } else 481 { 482 for (ByteString v : a.getValues()) 483 { 484 String valueString; 485 if (needsBase64Encoding(v)) 486 { 487 valueString = Base64.encode(v); 488 buffer.append(name); 489 buffer.append(":: "); 490 491 colsRemaining = wrapColumn - nameLength - 3; 492 } else 493 { 494 valueString = v.toString(); 495 buffer.append(name); 496 buffer.append(": "); 497 498 colsRemaining = wrapColumn - nameLength - 2; 499 } 500 501 int valueLength = valueString.length(); 502 if (valueLength <= colsRemaining || colsRemaining <= 0) 503 { 504 buffer.append(valueString); 505 buffer.append(EOL); 506 } else 507 { 508 buffer.append(valueString, 0, colsRemaining); 509 buffer.append(EOL); 510 511 int startPos = colsRemaining; 512 while (valueLength - startPos > wrapColumn - 1) 513 { 514 buffer.append(" "); 515 buffer.append(valueString, startPos, startPos+wrapColumn-1); 516 buffer.append(EOL); 517 518 startPos += wrapColumn-1; 519 } 520 521 if (startPos < valueLength) 522 { 523 buffer.append(" "); 524 buffer.append(valueString.substring(startPos)); 525 buffer.append(EOL); 526 } 527 } 528 } 529 } 530 } 531 532 533 // Make sure to add an extra blank line to ensure that there will be one 534 // between this entry and the next. 535 buffer.append(EOL); 536 } 537 538 /** 539 * Retrieves the set of response controls included in the last search result 540 * done message. 541 * 542 * @return The set of response controls included in the last search result 543 * done message. 544 */ 545 public List<Control> getResponseControls() 546 { 547 return responseControls; 548 } 549 550 /** 551 * The main method for LDAPSearch tool. 552 * 553 * @param args The command-line arguments provided to this program. 554 */ 555 556 public static void main(String[] args) 557 { 558 int retCode = mainSearch(args, true, false, System.out, System.err); 559 560 if(retCode != 0) 561 { 562 System.exit(filterExitCode(retCode)); 563 } 564 } 565 566 /** 567 * Parses the provided command-line arguments and uses that information to 568 * run the ldapsearch tool. 569 * 570 * @param args The command-line arguments provided to this program. 571 * 572 * @return The error code. 573 */ 574 575 public static int mainSearch(String[] args) 576 { 577 return mainSearch(args, true, true, System.out, System.err); 578 } 579 580 /** 581 * Parses the provided command-line arguments and uses that information to 582 * run the ldapsearch tool. 583 * 584 * @param args The command-line arguments provided to this 585 * program. 586 * @param initializeServer Indicates whether to initialize the server. 587 * @param outStream The output stream to use for standard output, or 588 * <CODE>null</CODE> if standard output is not 589 * needed. 590 * @param errStream The output stream to use for standard error, or 591 * <CODE>null</CODE> if standard error is not 592 * needed. 593 * 594 * @return The error code. 595 */ 596 public static int mainSearch(String[] args, boolean initializeServer, 597 OutputStream outStream, OutputStream errStream) 598 { 599 return mainSearch(args, initializeServer, true, outStream, errStream); 600 } 601 602 /** 603 * Parses the provided command-line arguments and uses that information to 604 * run the ldapsearch tool. 605 * 606 * @param args The command-line arguments provided to this 607 * program. 608 * @param initializeServer Indicates whether to initialize the server. 609 * @param returnMatchingEntries whether when the option --countEntries is 610 * specified, the number of matching entries should 611 * be returned or not. 612 * @param outStream The output stream to use for standard output, or 613 * <CODE>null</CODE> if standard output is not 614 * needed. 615 * @param errStream The output stream to use for standard error, or 616 * <CODE>null</CODE> if standard error is not 617 * needed. 618 * 619 * @return The error code. 620 */ 621 622 public static int mainSearch(String[] args, boolean initializeServer, 623 boolean returnMatchingEntries, OutputStream outStream, 624 OutputStream errStream) 625 { 626 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 627 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 628 629 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions(); 630 LDAPSearchOptions searchOptions = new LDAPSearchOptions(); 631 LDAPConnection connection = null; 632 ArrayList<LDAPFilter> filters = new ArrayList<>(); 633 LinkedHashSet<String> attributes = new LinkedHashSet<>(); 634 635 BooleanArgument continueOnError = null; 636 BooleanArgument countEntries = null; 637 BooleanArgument dontWrap = null; 638 BooleanArgument noop = null; 639 BooleanArgument reportAuthzID = null; 640 BooleanArgument saslExternal = null; 641 BooleanArgument showUsage = null; 642 BooleanArgument trustAll = null; 643 BooleanArgument usePasswordPolicyControl = null; 644 BooleanArgument useSSL = null; 645 BooleanArgument startTLS = null; 646 BooleanArgument typesOnly = null; 647 BooleanArgument verbose = null; 648 FileBasedArgument bindPasswordFile = null; 649 FileBasedArgument keyStorePasswordFile = null; 650 FileBasedArgument trustStorePasswordFile = null; 651 IntegerArgument port = null; 652 IntegerArgument simplePageSize = null; 653 IntegerArgument sizeLimit = null; 654 IntegerArgument timeLimit = null; 655 IntegerArgument version = null; 656 StringArgument assertionFilter = null; 657 StringArgument baseDN = null; 658 StringArgument bindDN = null; 659 StringArgument bindPassword = null; 660 StringArgument certNickname = null; 661 StringArgument controlStr = null; 662 StringArgument dereferencePolicy = null; 663 StringArgument encodingStr = null; 664 StringArgument filename = null; 665 StringArgument hostName = null; 666 StringArgument keyStorePath = null; 667 StringArgument keyStorePassword = null; 668 StringArgument matchedValuesFilter = null; 669 StringArgument proxyAuthzID = null; 670 StringArgument pSearchInfo = null; 671 StringArgument saslOptions = null; 672 MultiChoiceArgument searchScope = null; 673 StringArgument sortOrder = null; 674 StringArgument trustStorePath = null; 675 StringArgument trustStorePassword = null; 676 IntegerArgument connectTimeout = null; 677 StringArgument vlvDescriptor = null; 678 StringArgument effectiveRightsUser = null; 679 StringArgument effectiveRightsAttrs = null; 680 StringArgument propertiesFileArgument = null; 681 BooleanArgument noPropertiesFileArgument = null; 682 BooleanArgument subEntriesArgument = null; 683 684 685 // Create the command-line argument parser for use with this program. 686 LocalizableMessage toolDescription = INFO_LDAPSEARCH_TOOL_DESCRIPTION.get(); 687 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, 688 false, true, 0, 0, 689 "[filter] [attributes ...]"); 690 argParser.setShortToolDescription(REF_SHORT_DESC_LDAPSEARCH.get()); 691 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 692 693 try 694 { 695 propertiesFileArgument = new StringArgument("propertiesFilePath", 696 null, OPTION_LONG_PROP_FILE_PATH, 697 false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null, 698 INFO_DESCRIPTION_PROP_FILE_PATH.get()); 699 argParser.addArgument(propertiesFileArgument); 700 argParser.setFilePropertiesArgument(propertiesFileArgument); 701 702 noPropertiesFileArgument = new BooleanArgument( 703 "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE, 704 INFO_DESCRIPTION_NO_PROP_FILE.get()); 705 argParser.addArgument(noPropertiesFileArgument); 706 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); 707 708 hostName = new StringArgument("host", OPTION_SHORT_HOST, 709 OPTION_LONG_HOST, false, false, true, 710 INFO_HOST_PLACEHOLDER.get(), "localhost", 711 null, 712 INFO_DESCRIPTION_HOST.get()); 713 hostName.setPropertyName(OPTION_LONG_HOST); 714 argParser.addArgument(hostName); 715 716 port = new IntegerArgument("port", OPTION_SHORT_PORT, 717 OPTION_LONG_PORT, false, false, true, 718 INFO_PORT_PLACEHOLDER.get(), 389, null, 719 true, 1, true, 65535, 720 INFO_DESCRIPTION_PORT.get()); 721 port.setPropertyName(OPTION_LONG_PORT); 722 argParser.addArgument(port); 723 724 useSSL = new BooleanArgument("useSSL", OPTION_SHORT_USE_SSL, 725 OPTION_LONG_USE_SSL, 726 INFO_DESCRIPTION_USE_SSL.get()); 727 useSSL.setPropertyName(OPTION_LONG_USE_SSL); 728 argParser.addArgument(useSSL); 729 730 startTLS = new BooleanArgument("startTLS", OPTION_SHORT_START_TLS, 731 OPTION_LONG_START_TLS, 732 INFO_DESCRIPTION_START_TLS.get()); 733 startTLS.setPropertyName(OPTION_LONG_START_TLS); 734 argParser.addArgument(startTLS); 735 736 bindDN = new StringArgument("bindDN", OPTION_SHORT_BINDDN, 737 OPTION_LONG_BINDDN, false, false, true, 738 INFO_BINDDN_PLACEHOLDER.get(), null, null, 739 INFO_DESCRIPTION_BINDDN.get()); 740 bindDN.setPropertyName(OPTION_LONG_BINDDN); 741 argParser.addArgument(bindDN); 742 743 bindPassword = new StringArgument("bindPassword", OPTION_SHORT_BINDPWD, 744 OPTION_LONG_BINDPWD, 745 false, false, true, 746 INFO_BINDPWD_PLACEHOLDER.get(), 747 null, null, 748 INFO_DESCRIPTION_BINDPASSWORD.get()); 749 bindPassword.setPropertyName(OPTION_LONG_BINDPWD); 750 argParser.addArgument(bindPassword); 751 752 bindPasswordFile = 753 new FileBasedArgument("bindPasswordFile", OPTION_SHORT_BINDPWD_FILE, 754 OPTION_LONG_BINDPWD_FILE, 755 false, false, 756 INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, 757 null, INFO_DESCRIPTION_BINDPASSWORDFILE.get()); 758 bindPasswordFile.setPropertyName(OPTION_LONG_BINDPWD_FILE); 759 argParser.addArgument(bindPasswordFile); 760 761 baseDN = new StringArgument("baseDN", OPTION_SHORT_BASEDN, 762 OPTION_LONG_BASEDN, true, false, true, 763 INFO_BASEDN_PLACEHOLDER.get(), null, null, 764 INFO_SEARCH_DESCRIPTION_BASEDN.get()); 765 baseDN.setPropertyName(OPTION_LONG_BASEDN); 766 argParser.addArgument(baseDN); 767 768 HashSet<String> allowedScopes = new HashSet<>(); 769 allowedScopes.add("base"); 770 allowedScopes.add("one"); 771 allowedScopes.add("sub"); 772 allowedScopes.add("subordinate"); 773 searchScope = new MultiChoiceArgument( 774 "searchScope", 's', "searchScope", false, 775 true, INFO_SEARCH_SCOPE_PLACEHOLDER.get(), allowedScopes, 776 false, 777 INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE.get()); 778 searchScope.setPropertyName("searchScope"); 779 searchScope.setDefaultValue("sub"); 780 argParser.addArgument(searchScope); 781 782 filename = new StringArgument("filename", OPTION_SHORT_FILENAME, 783 OPTION_LONG_FILENAME, false, false, 784 true, INFO_FILE_PLACEHOLDER.get(), null, 785 null, 786 INFO_SEARCH_DESCRIPTION_FILENAME.get()); 787 searchScope.setPropertyName(OPTION_LONG_FILENAME); 788 argParser.addArgument(filename); 789 790 saslExternal = new BooleanArgument( 791 "useSASLExternal", 'r', 792 "useSASLExternal", 793 INFO_DESCRIPTION_USE_SASL_EXTERNAL.get()); 794 saslExternal.setPropertyName("useSASLExternal"); 795 argParser.addArgument(saslExternal); 796 797 saslOptions = new StringArgument("saslOption", OPTION_SHORT_SASLOPTION, 798 OPTION_LONG_SASLOPTION, false, 799 true, true, 800 INFO_SASL_OPTION_PLACEHOLDER.get(), null, 801 null, 802 INFO_DESCRIPTION_SASL_PROPERTIES.get()); 803 saslOptions.setPropertyName(OPTION_LONG_SASLOPTION); 804 argParser.addArgument(saslOptions); 805 806 trustAll = CommonArguments.getTrustAll(); 807 argParser.addArgument(trustAll); 808 809 keyStorePath = new StringArgument("keyStorePath", 810 OPTION_SHORT_KEYSTOREPATH, 811 OPTION_LONG_KEYSTOREPATH, false, false, true, 812 INFO_KEYSTOREPATH_PLACEHOLDER.get(), null, 813 null, 814 INFO_DESCRIPTION_KEYSTOREPATH.get()); 815 keyStorePath.setPropertyName(OPTION_LONG_KEYSTOREPATH); 816 argParser.addArgument(keyStorePath); 817 818 keyStorePassword = new StringArgument("keyStorePassword", 819 OPTION_SHORT_KEYSTORE_PWD, 820 OPTION_LONG_KEYSTORE_PWD, false, false, 821 true, INFO_KEYSTORE_PWD_PLACEHOLDER.get(), 822 null, null, 823 INFO_DESCRIPTION_KEYSTOREPASSWORD.get()); 824 keyStorePassword.setPropertyName(OPTION_LONG_KEYSTORE_PWD); 825 argParser.addArgument(keyStorePassword); 826 827 keyStorePasswordFile = 828 new FileBasedArgument("keystorepasswordfile", 829 OPTION_SHORT_KEYSTORE_PWD_FILE, 830 OPTION_LONG_KEYSTORE_PWD_FILE, 831 false, false, 832 INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get(), 833 null, null, 834 INFO_DESCRIPTION_KEYSTOREPASSWORD_FILE.get()); 835 keyStorePasswordFile.setPropertyName(OPTION_LONG_KEYSTORE_PWD_FILE); 836 argParser.addArgument(keyStorePasswordFile); 837 838 certNickname = new StringArgument( 839 "certnickname", OPTION_SHORT_CERT_NICKNAME, 840 OPTION_LONG_CERT_NICKNAME, 841 false, false, true, INFO_NICKNAME_PLACEHOLDER.get(), null, 842 null, INFO_DESCRIPTION_CERT_NICKNAME.get()); 843 certNickname.setPropertyName(OPTION_LONG_CERT_NICKNAME); 844 argParser.addArgument(certNickname); 845 846 trustStorePath = new StringArgument("trustStorePath", 847 OPTION_SHORT_TRUSTSTOREPATH, 848 OPTION_LONG_TRUSTSTOREPATH, 849 false, false, true, 850 INFO_TRUSTSTOREPATH_PLACEHOLDER.get(), null, 851 null, 852 INFO_DESCRIPTION_TRUSTSTOREPATH.get()); 853 trustStorePath.setPropertyName(OPTION_LONG_TRUSTSTOREPATH); 854 argParser.addArgument(trustStorePath); 855 856 trustStorePassword = 857 new StringArgument("trustStorePassword", null, 858 OPTION_LONG_TRUSTSTORE_PWD, 859 false, false, true, 860 INFO_TRUSTSTORE_PWD_PLACEHOLDER.get(), 861 null, 862 null, INFO_DESCRIPTION_TRUSTSTOREPASSWORD.get()); 863 trustStorePassword.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD); 864 argParser.addArgument(trustStorePassword); 865 866 trustStorePasswordFile = 867 new FileBasedArgument( 868 "truststorepasswordfile", 869 OPTION_SHORT_TRUSTSTORE_PWD_FILE, 870 OPTION_LONG_TRUSTSTORE_PWD_FILE, false, false, 871 INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get(), null, null, 872 INFO_DESCRIPTION_TRUSTSTOREPASSWORD_FILE.get()); 873 trustStorePasswordFile.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD_FILE); 874 argParser.addArgument(trustStorePasswordFile); 875 876 proxyAuthzID = new StringArgument("proxy_authzid", 877 OPTION_SHORT_PROXYAUTHID, 878 OPTION_LONG_PROXYAUTHID, false, 879 false, true, 880 INFO_PROXYAUTHID_PLACEHOLDER.get(), 881 null, null, 882 INFO_DESCRIPTION_PROXY_AUTHZID.get()); 883 proxyAuthzID.setPropertyName(OPTION_LONG_PROXYAUTHID); 884 argParser.addArgument(proxyAuthzID); 885 886 reportAuthzID = new BooleanArgument( 887 "reportauthzid", 'E', OPTION_LONG_REPORT_AUTHZ_ID, 888 INFO_DESCRIPTION_REPORT_AUTHZID.get()); 889 reportAuthzID.setPropertyName(OPTION_LONG_REPORT_AUTHZ_ID); 890 argParser.addArgument(reportAuthzID); 891 892 usePasswordPolicyControl = new BooleanArgument( 893 "usepwpolicycontrol", null, 894 OPTION_LONG_USE_PW_POLICY_CTL, 895 INFO_DESCRIPTION_USE_PWP_CONTROL.get()); 896 usePasswordPolicyControl.setPropertyName(OPTION_LONG_USE_PW_POLICY_CTL); 897 argParser.addArgument(usePasswordPolicyControl); 898 899 pSearchInfo = new StringArgument("psearchinfo", 'C', "persistentSearch", 900 false, false, true, 901 INFO_PSEARCH_PLACEHOLDER.get(), 902 null, null, INFO_DESCRIPTION_PSEARCH_INFO.get()); 903 pSearchInfo.setPropertyName("persistentSearch"); 904 pSearchInfo.setDocDescriptionSupplement(SUPPLEMENT_DESCRIPTION_PSEARCH_INFO.get()); 905 argParser.addArgument(pSearchInfo); 906 907 simplePageSize = new IntegerArgument( 908 "simplepagesize", null, 909 "simplePageSize", false, false, true, 910 INFO_NUM_ENTRIES_PLACEHOLDER.get(), 1000, null, true, 1, 911 false, 0, 912 INFO_DESCRIPTION_SIMPLE_PAGE_SIZE.get()); 913 simplePageSize.setPropertyName("simplePageSize"); 914 argParser.addArgument(simplePageSize); 915 916 assertionFilter = new StringArgument( 917 "assertionfilter", null, 918 OPTION_LONG_ASSERTION_FILE, 919 false, false, 920 true, INFO_ASSERTION_FILTER_PLACEHOLDER.get(), 921 null, null, 922 INFO_DESCRIPTION_ASSERTION_FILTER.get()); 923 assertionFilter.setPropertyName(OPTION_LONG_ASSERTION_FILE); 924 argParser.addArgument(assertionFilter); 925 926 matchedValuesFilter = new StringArgument( 927 "matchedvalues", null, 928 "matchedValuesFilter", false, true, true, 929 INFO_FILTER_PLACEHOLDER.get(), null, null, 930 INFO_DESCRIPTION_MATCHED_VALUES_FILTER.get()); 931 matchedValuesFilter.setPropertyName("matchedValuesFilter"); 932 argParser.addArgument(matchedValuesFilter); 933 934 sortOrder = new StringArgument( 935 "sortorder", 'S', "sortOrder", false, 936 false, true, INFO_SORT_ORDER_PLACEHOLDER.get(), null, null, 937 INFO_DESCRIPTION_SORT_ORDER.get()); 938 sortOrder.setPropertyName("sortOrder"); 939 argParser.addArgument(sortOrder); 940 941 vlvDescriptor = 942 new StringArgument( 943 "vlvdescriptor", 'G', "virtualListView", false, 944 false, true, 945 INFO_VLV_PLACEHOLDER.get(), 946 null, null, INFO_DESCRIPTION_VLV.get()); 947 vlvDescriptor.setPropertyName("virtualListView"); 948 argParser.addArgument(vlvDescriptor); 949 950 controlStr = 951 new StringArgument("control", 'J', "control", false, true, true, 952 INFO_LDAP_CONTROL_PLACEHOLDER.get(), 953 null, null, INFO_DESCRIPTION_CONTROLS.get()); 954 controlStr.setPropertyName("control"); 955 controlStr.setDocDescriptionSupplement(SUPPLEMENT_DESCRIPTION_CONTROLS.get()); 956 argParser.addArgument(controlStr); 957 958 subEntriesArgument = new BooleanArgument("subEntries", 959 OPTION_SHORT_SUBENTRIES, OPTION_LONG_SUBENTRIES, 960 INFO_DESCRIPTION_SUBENTRIES.get()); 961 subEntriesArgument.setPropertyName(OPTION_LONG_SUBENTRIES); 962 argParser.addArgument(subEntriesArgument); 963 964 effectiveRightsUser = 965 new StringArgument("effectiveRightsUser", 966 OPTION_SHORT_EFFECTIVERIGHTSUSER, 967 OPTION_LONG_EFFECTIVERIGHTSUSER, false, false, true, 968 INFO_PROXYAUTHID_PLACEHOLDER.get(), null, null, 969 INFO_DESCRIPTION_EFFECTIVERIGHTS_USER.get( )); 970 effectiveRightsUser.setPropertyName(OPTION_LONG_EFFECTIVERIGHTSUSER); 971 argParser.addArgument(effectiveRightsUser); 972 973 effectiveRightsAttrs = 974 new StringArgument("effectiveRightsAttrs", 975 OPTION_SHORT_EFFECTIVERIGHTSATTR, 976 OPTION_LONG_EFFECTIVERIGHTSATTR, false, true, true, 977 INFO_ATTRIBUTE_PLACEHOLDER.get(), null, null, 978 INFO_DESCRIPTION_EFFECTIVERIGHTS_ATTR.get( )); 979 effectiveRightsAttrs.setPropertyName(OPTION_LONG_EFFECTIVERIGHTSATTR); 980 argParser.addArgument(effectiveRightsAttrs); 981 982 version = new IntegerArgument("version", OPTION_SHORT_PROTOCOL_VERSION, 983 OPTION_LONG_PROTOCOL_VERSION, false, false, 984 true, 985 INFO_PROTOCOL_VERSION_PLACEHOLDER.get(), 3, 986 null, INFO_DESCRIPTION_VERSION.get()); 987 version.setPropertyName(OPTION_LONG_PROTOCOL_VERSION); 988 argParser.addArgument(version); 989 990 int defaultTimeout = CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT; 991 connectTimeout = new IntegerArgument(OPTION_LONG_CONNECT_TIMEOUT, 992 null, OPTION_LONG_CONNECT_TIMEOUT, 993 false, false, true, INFO_TIMEOUT_PLACEHOLDER.get(), 994 defaultTimeout, null, 995 true, 0, false, Integer.MAX_VALUE, 996 INFO_DESCRIPTION_CONNECTION_TIMEOUT.get()); 997 connectTimeout.setPropertyName(OPTION_LONG_CONNECT_TIMEOUT); 998 argParser.addArgument(connectTimeout); 999 1000 encodingStr = new StringArgument("encoding", 'i', "encoding", false, 1001 false, true, 1002 INFO_ENCODING_PLACEHOLDER.get(), null, 1003 null, 1004 INFO_DESCRIPTION_ENCODING.get()); 1005 encodingStr.setPropertyName("encoding"); 1006 argParser.addArgument(encodingStr); 1007 1008 dereferencePolicy = 1009 new StringArgument("derefpolicy", 'a', "dereferencePolicy", false, 1010 false, true, 1011 INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(), "never", 1012 null, 1013 INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY.get()); 1014 dereferencePolicy.setPropertyName("dereferencePolicy"); 1015 argParser.addArgument(dereferencePolicy); 1016 1017 typesOnly = new BooleanArgument("typesOnly", 'A', "typesOnly", 1018 INFO_DESCRIPTION_TYPES_ONLY.get()); 1019 typesOnly.setPropertyName("typesOnly"); 1020 argParser.addArgument(typesOnly); 1021 1022 sizeLimit = new IntegerArgument("sizeLimit", 'z', "sizeLimit", false, 1023 false, true, 1024 INFO_SIZE_LIMIT_PLACEHOLDER.get(), 0, 1025 null, 1026 INFO_SEARCH_DESCRIPTION_SIZE_LIMIT.get()); 1027 sizeLimit.setPropertyName("sizeLimit"); 1028 argParser.addArgument(sizeLimit); 1029 1030 timeLimit = new IntegerArgument("timeLimit", 'l', "timeLimit", false, 1031 false, true, 1032 INFO_TIME_LIMIT_PLACEHOLDER.get(), 0, 1033 null, 1034 INFO_SEARCH_DESCRIPTION_TIME_LIMIT.get()); 1035 timeLimit.setPropertyName("timeLimit"); 1036 argParser.addArgument(timeLimit); 1037 1038 dontWrap = new BooleanArgument("dontwrap", 'T', 1039 "dontWrap", 1040 INFO_DESCRIPTION_DONT_WRAP.get()); 1041 dontWrap.setPropertyName("dontWrap"); 1042 argParser.addArgument(dontWrap); 1043 1044 countEntries = new BooleanArgument("countentries", null, "countEntries", 1045 INFO_DESCRIPTION_COUNT_ENTRIES.get()); 1046 countEntries.setPropertyName("countEntries"); 1047 argParser.addArgument(countEntries); 1048 1049 continueOnError = 1050 new BooleanArgument("continueOnError", 'c', "continueOnError", 1051 INFO_DESCRIPTION_CONTINUE_ON_ERROR.get()); 1052 continueOnError.setPropertyName("continueOnError"); 1053 argParser.addArgument(continueOnError); 1054 1055 noop = new BooleanArgument("noop", OPTION_SHORT_DRYRUN, 1056 OPTION_LONG_DRYRUN, INFO_DESCRIPTION_NOOP.get()); 1057 noop.setPropertyName(OPTION_LONG_DRYRUN); 1058 argParser.addArgument(noop); 1059 1060 verbose = CommonArguments.getVerbose(); 1061 argParser.addArgument(verbose); 1062 1063 showUsage = CommonArguments.getShowUsage(); 1064 argParser.addArgument(showUsage); 1065 argParser.setUsageArgument(showUsage, out); 1066 } catch (ArgumentException ae) 1067 { 1068 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 1069 return CLIENT_SIDE_PARAM_ERROR; 1070 } 1071 1072 // Parse the command-line arguments provided to this program. 1073 try 1074 { 1075 argParser.parseArguments(args); 1076 } 1077 catch (ArgumentException ae) 1078 { 1079 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 1080 return CLIENT_SIDE_PARAM_ERROR; 1081 } 1082 1083 // If we should just display usage or version information, 1084 // then print it and exit. 1085 if (argParser.usageOrVersionDisplayed()) 1086 { 1087 return 0; 1088 } 1089 1090 ArrayList<String> filterAndAttributeStrings = 1091 argParser.getTrailingArguments(); 1092 if(!filterAndAttributeStrings.isEmpty()) 1093 { 1094 // the list of trailing arguments should be structured as follow: 1095 // - If a filter file is present, trailing arguments are considered 1096 // as attributes 1097 // - If filter file is not present, the first trailing argument is 1098 // considered the filter, the other as attributes. 1099 if (! filename.isPresent()) 1100 { 1101 String filterString = filterAndAttributeStrings.remove(0); 1102 1103 try 1104 { 1105 filters.add(LDAPFilter.decode(filterString)); 1106 } catch (LDAPException le) 1107 { 1108 logger.traceException(le); 1109 printWrappedText(err, le.getMessage()); 1110 return CLIENT_SIDE_PARAM_ERROR; 1111 } 1112 } 1113 attributes.addAll(filterAndAttributeStrings); 1114 } 1115 1116 if(bindPassword.isPresent() && bindPasswordFile.isPresent()) 1117 { 1118 printWrappedText(err, 1119 ERR_TOOL_CONFLICTING_ARGS.get(bindPassword.getLongIdentifier(), bindPasswordFile.getLongIdentifier())); 1120 return CLIENT_SIDE_PARAM_ERROR; 1121 } 1122 1123 if (useSSL.isPresent() && startTLS.isPresent()) 1124 { 1125 printWrappedText(err, ERR_TOOL_CONFLICTING_ARGS.get(useSSL.getLongIdentifier(), startTLS.getLongIdentifier())); 1126 return CLIENT_SIDE_PARAM_ERROR; 1127 } 1128 1129 if (keyStorePassword.isPresent() && keyStorePasswordFile.isPresent()) 1130 { 1131 printWrappedText(err, ERR_TOOL_CONFLICTING_ARGS.get( 1132 keyStorePassword.getLongIdentifier(), keyStorePasswordFile.getLongIdentifier())); 1133 return CLIENT_SIDE_PARAM_ERROR; 1134 } 1135 1136 if (trustStorePassword.isPresent() && trustStorePasswordFile.isPresent()) 1137 { 1138 printWrappedText(err, ERR_TOOL_CONFLICTING_ARGS.get( 1139 trustStorePassword.getLongIdentifier(), trustStorePasswordFile.getLongIdentifier())); 1140 return CLIENT_SIDE_PARAM_ERROR; 1141 } 1142 1143 String hostNameValue = hostName.getValue(); 1144 int portNumber = 389; 1145 try 1146 { 1147 portNumber = port.getIntValue(); 1148 } catch(ArgumentException ae) 1149 { 1150 logger.traceException(ae); 1151 argParser.displayMessageAndUsageReference(err, ae.getMessageObject()); 1152 return CLIENT_SIDE_PARAM_ERROR; 1153 } 1154 1155 // Read the LDAP version number. 1156 try 1157 { 1158 int versionNumber = version.getIntValue(); 1159 if(versionNumber != 2 && versionNumber != 3) 1160 { 1161 printWrappedText(err, ERR_DESCRIPTION_INVALID_VERSION.get(versionNumber)); 1162 return CLIENT_SIDE_PARAM_ERROR; 1163 } 1164 connectionOptions.setVersionNumber(versionNumber); 1165 } catch(ArgumentException ae) 1166 { 1167 logger.traceException(ae); 1168 argParser.displayMessageAndUsageReference(err, ae.getMessageObject()); 1169 return CLIENT_SIDE_PARAM_ERROR; 1170 } 1171 1172 1173 // Indicate whether we should report the authorization ID and/or use the 1174 // password policy control. 1175 connectionOptions.setReportAuthzID(reportAuthzID.isPresent()); 1176 connectionOptions.setUsePasswordPolicyControl( 1177 usePasswordPolicyControl.isPresent()); 1178 1179 1180 String baseDNValue = baseDN.getValue(); 1181 String bindDNValue = bindDN.getValue(); 1182 String fileNameValue = filename.getValue(); 1183 String bindPasswordValue; 1184 try 1185 { 1186 bindPasswordValue = getPasswordValue( 1187 bindPassword, bindPasswordFile, bindDNValue, out, err); 1188 } 1189 catch (Exception ex) 1190 { 1191 logger.traceException(ex); 1192 printWrappedText(err, ex.getMessage()); 1193 return CLIENT_SIDE_PARAM_ERROR; 1194 } 1195 1196 String keyStorePathValue = keyStorePath.getValue(); 1197 String trustStorePathValue = trustStorePath.getValue(); 1198 1199 String keyStorePasswordValue = null; 1200 if (keyStorePassword.isPresent()) 1201 { 1202 keyStorePasswordValue = keyStorePassword.getValue(); 1203 } 1204 else if (keyStorePasswordFile.isPresent()) 1205 { 1206 keyStorePasswordValue = keyStorePasswordFile.getValue(); 1207 } 1208 1209 String trustStorePasswordValue = null; 1210 if (trustStorePassword.isPresent()) 1211 { 1212 trustStorePasswordValue = trustStorePassword.getValue(); 1213 } 1214 else if (trustStorePasswordFile.isPresent()) 1215 { 1216 trustStorePasswordValue = trustStorePasswordFile.getValue(); 1217 } 1218 1219 searchOptions.setTypesOnly(typesOnly.isPresent()); 1220 searchOptions.setShowOperations(noop.isPresent()); 1221 searchOptions.setVerbose(verbose.isPresent()); 1222 searchOptions.setContinueOnError(continueOnError.isPresent()); 1223 searchOptions.setEncoding(encodingStr.getValue()); 1224 searchOptions.setCountMatchingEntries(countEntries.isPresent()); 1225 try 1226 { 1227 searchOptions.setTimeLimit(timeLimit.getIntValue()); 1228 searchOptions.setSizeLimit(sizeLimit.getIntValue()); 1229 } catch(ArgumentException ex1) 1230 { 1231 argParser.displayMessageAndUsageReference(err, ex1.getMessageObject()); 1232 return CLIENT_SIDE_PARAM_ERROR; 1233 } 1234 if (!searchOptions.setSearchScope(searchScope.getValue(), err) 1235 || !searchOptions.setDereferencePolicy(dereferencePolicy.getValue(), err)) 1236 { 1237 return CLIENT_SIDE_PARAM_ERROR; 1238 } 1239 1240 if(controlStr.isPresent()) 1241 { 1242 for (String ctrlString : controlStr.getValues()) 1243 { 1244 Control ctrl = LDAPToolUtils.getControl(ctrlString, err); 1245 if(ctrl == null) 1246 { 1247 printWrappedText(err, ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString)); 1248 return CLIENT_SIDE_PARAM_ERROR; 1249 } 1250 searchOptions.getControls().add(ctrl); 1251 } 1252 } 1253 1254 if(effectiveRightsUser.isPresent()) { 1255 String authzID=effectiveRightsUser.getValue(); 1256 if (!authzID.startsWith("dn:")) { 1257 printWrappedText(err, ERR_EFFECTIVERIGHTS_INVALID_AUTHZID.get(authzID)); 1258 return CLIENT_SIDE_PARAM_ERROR; 1259 } 1260 Control effectiveRightsControl = 1261 new GetEffectiveRightsRequestControl(false, authzID.substring(3), 1262 effectiveRightsAttrs.getValues()); 1263 searchOptions.getControls().add(effectiveRightsControl); 1264 } 1265 1266 if (proxyAuthzID.isPresent()) 1267 { 1268 Control proxyControl = 1269 new ProxiedAuthV2Control(true, 1270 ByteString.valueOfUtf8(proxyAuthzID.getValue())); 1271 searchOptions.getControls().add(proxyControl); 1272 } 1273 1274 if (pSearchInfo.isPresent()) 1275 { 1276 String infoString = toLowerCase(pSearchInfo.getValue().trim()); 1277 HashSet<PersistentSearchChangeType> changeTypes = new HashSet<>(); 1278 boolean changesOnly = true; 1279 boolean returnECs = true; 1280 1281 StringTokenizer tokenizer = new StringTokenizer(infoString, ":"); 1282 1283 if (! tokenizer.hasMoreTokens()) 1284 { 1285 printWrappedText(err, ERR_PSEARCH_MISSING_DESCRIPTOR.get()); 1286 return CLIENT_SIDE_PARAM_ERROR; 1287 } 1288 else 1289 { 1290 String token = tokenizer.nextToken(); 1291 if (! token.equals("ps")) 1292 { 1293 printWrappedText(err, ERR_PSEARCH_DOESNT_START_WITH_PS.get(infoString)); 1294 return CLIENT_SIDE_PARAM_ERROR; 1295 } 1296 } 1297 1298 if (tokenizer.hasMoreTokens()) 1299 { 1300 StringTokenizer st = new StringTokenizer(tokenizer.nextToken(), ", "); 1301 while (st.hasMoreTokens()) 1302 { 1303 String token = st.nextToken(); 1304 if (token.equals("add")) 1305 { 1306 changeTypes.add(PersistentSearchChangeType.ADD); 1307 } 1308 else if (token.equals("delete") || token.equals("del")) 1309 { 1310 changeTypes.add(PersistentSearchChangeType.DELETE); 1311 } 1312 else if (token.equals("modify") || token.equals("mod")) 1313 { 1314 changeTypes.add(PersistentSearchChangeType.MODIFY); 1315 } 1316 else if (token.equals("modifydn") || token.equals("moddn") || 1317 token.equals("modrdn")) 1318 { 1319 changeTypes.add(PersistentSearchChangeType.MODIFY_DN); 1320 } 1321 else if (token.equals("any") || token.equals("all")) 1322 { 1323 changeTypes.add(PersistentSearchChangeType.ADD); 1324 changeTypes.add(PersistentSearchChangeType.DELETE); 1325 changeTypes.add(PersistentSearchChangeType.MODIFY); 1326 changeTypes.add(PersistentSearchChangeType.MODIFY_DN); 1327 } 1328 else 1329 { 1330 printWrappedText(err, ERR_PSEARCH_INVALID_CHANGE_TYPE.get(token)); 1331 return CLIENT_SIDE_PARAM_ERROR; 1332 } 1333 } 1334 } 1335 1336 if (changeTypes.isEmpty()) 1337 { 1338 changeTypes.add(PersistentSearchChangeType.ADD); 1339 changeTypes.add(PersistentSearchChangeType.DELETE); 1340 changeTypes.add(PersistentSearchChangeType.MODIFY); 1341 changeTypes.add(PersistentSearchChangeType.MODIFY_DN); 1342 } 1343 1344 if (tokenizer.hasMoreTokens()) 1345 { 1346 String token = tokenizer.nextToken(); 1347 if (token.equals("1") || token.equals("true") || token.equals("yes")) 1348 { 1349 changesOnly = true; 1350 } 1351 else if (token.equals("0") || token.equals("false") || 1352 token.equals("no")) 1353 { 1354 changesOnly = false; 1355 } 1356 else 1357 { 1358 printWrappedText(err, ERR_PSEARCH_INVALID_CHANGESONLY.get(token)); 1359 return CLIENT_SIDE_PARAM_ERROR; 1360 } 1361 } 1362 1363 if (tokenizer.hasMoreTokens()) 1364 { 1365 String token = tokenizer.nextToken(); 1366 if (token.equals("1") || token.equals("true") || token.equals("yes")) 1367 { 1368 returnECs = true; 1369 } 1370 else if (token.equals("0") || token.equals("false") || 1371 token.equals("no")) 1372 { 1373 returnECs = false; 1374 } 1375 else 1376 { 1377 printWrappedText(err, ERR_PSEARCH_INVALID_RETURN_ECS.get(token)); 1378 return CLIENT_SIDE_PARAM_ERROR; 1379 } 1380 } 1381 1382 PersistentSearchControl psearchControl = 1383 new PersistentSearchControl(changeTypes, changesOnly, returnECs); 1384 searchOptions.getControls().add(psearchControl); 1385 } 1386 1387 if (assertionFilter.isPresent()) 1388 { 1389 String filterString = assertionFilter.getValue(); 1390 LDAPFilter filter; 1391 try 1392 { 1393 filter = LDAPFilter.decode(filterString); 1394 1395 // FIXME -- Change this to the correct OID when the official one is 1396 // assigned. 1397 Control assertionControl = 1398 new LDAPAssertionRequestControl(true, filter); 1399 searchOptions.getControls().add(assertionControl); 1400 } 1401 catch (LDAPException le) 1402 { 1403 printWrappedText(err, ERR_LDAP_ASSERTION_INVALID_FILTER.get(le.getMessage())); 1404 return CLIENT_SIDE_PARAM_ERROR; 1405 } 1406 } 1407 1408 if (matchedValuesFilter.isPresent()) 1409 { 1410 LinkedList<String> mvFilterStrings = matchedValuesFilter.getValues(); 1411 ArrayList<MatchedValuesFilter> mvFilters = new ArrayList<>(); 1412 for (String s : mvFilterStrings) 1413 { 1414 try 1415 { 1416 LDAPFilter f = LDAPFilter.decode(s); 1417 mvFilters.add(MatchedValuesFilter.createFromLDAPFilter(f)); 1418 } 1419 catch (LDAPException le) 1420 { 1421 printWrappedText(err, ERR_LDAP_MATCHEDVALUES_INVALID_FILTER.get(le.getMessage())); 1422 return CLIENT_SIDE_PARAM_ERROR; 1423 } 1424 } 1425 1426 MatchedValuesControl mvc = new MatchedValuesControl(true, mvFilters); 1427 searchOptions.getControls().add(mvc); 1428 } 1429 1430 if (sortOrder.isPresent()) 1431 { 1432 try 1433 { 1434 searchOptions.getControls().add( 1435 new ServerSideSortRequestControl(sortOrder.getValue())); 1436 } 1437 catch (LDAPException le) 1438 { 1439 printWrappedText(err, ERR_LDAP_SORTCONTROL_INVALID_ORDER.get(le.getErrorMessage())); 1440 return CLIENT_SIDE_PARAM_ERROR; 1441 } 1442 } 1443 1444 if (vlvDescriptor.isPresent()) 1445 { 1446 if (! sortOrder.isPresent()) 1447 { 1448 printWrappedText(err, 1449 ERR_LDAPSEARCH_VLV_REQUIRES_SORT.get(vlvDescriptor.getLongIdentifier(), sortOrder.getLongIdentifier())); 1450 return CLIENT_SIDE_PARAM_ERROR; 1451 } 1452 1453 StringTokenizer tokenizer = 1454 new StringTokenizer(vlvDescriptor.getValue(), ":"); 1455 int numTokens = tokenizer.countTokens(); 1456 if (numTokens == 3) 1457 { 1458 try 1459 { 1460 int beforeCount = Integer.parseInt(tokenizer.nextToken()); 1461 int afterCount = Integer.parseInt(tokenizer.nextToken()); 1462 ByteString assertionValue = ByteString.valueOfUtf8(tokenizer.nextToken()); 1463 searchOptions.getControls().add( 1464 new VLVRequestControl(beforeCount, afterCount, assertionValue)); 1465 } 1466 catch (Exception e) 1467 { 1468 printWrappedText(err, ERR_LDAPSEARCH_VLV_INVALID_DESCRIPTOR.get()); 1469 return CLIENT_SIDE_PARAM_ERROR; 1470 } 1471 } 1472 else if (numTokens == 4) 1473 { 1474 try 1475 { 1476 int beforeCount = Integer.parseInt(tokenizer.nextToken()); 1477 int afterCount = Integer.parseInt(tokenizer.nextToken()); 1478 int offset = Integer.parseInt(tokenizer.nextToken()); 1479 int contentCount = Integer.parseInt(tokenizer.nextToken()); 1480 searchOptions.getControls().add( 1481 new VLVRequestControl(beforeCount, afterCount, offset, 1482 contentCount)); 1483 } 1484 catch (Exception e) 1485 { 1486 printWrappedText(err, ERR_LDAPSEARCH_VLV_INVALID_DESCRIPTOR.get()); 1487 return CLIENT_SIDE_PARAM_ERROR; 1488 } 1489 } 1490 else 1491 { 1492 printWrappedText(err, ERR_LDAPSEARCH_VLV_INVALID_DESCRIPTOR.get()); 1493 return CLIENT_SIDE_PARAM_ERROR; 1494 } 1495 } 1496 1497 if (subEntriesArgument.isPresent()) 1498 { 1499 Control subentriesControl = 1500 new SubentriesControl(true, true); 1501 searchOptions.getControls().add(subentriesControl); 1502 } 1503 1504 // Set the connection options. 1505 connectionOptions.setSASLExternal(saslExternal.isPresent()); 1506 if(saslOptions.isPresent()) 1507 { 1508 LinkedList<String> values = saslOptions.getValues(); 1509 for(String saslOption : values) 1510 { 1511 if(saslOption.startsWith("mech=")) 1512 { 1513 if (!connectionOptions.setSASLMechanism(saslOption)) 1514 { 1515 return CLIENT_SIDE_PARAM_ERROR; 1516 } 1517 } else 1518 { 1519 if (!connectionOptions.addSASLProperty(saslOption)) 1520 { 1521 return CLIENT_SIDE_PARAM_ERROR; 1522 } 1523 } 1524 } 1525 } 1526 connectionOptions.setUseSSL(useSSL.isPresent()); 1527 connectionOptions.setStartTLS(startTLS.isPresent()); 1528 1529 if(connectionOptions.useSASLExternal()) 1530 { 1531 if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS()) 1532 { 1533 printWrappedText(err, ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get()); 1534 return CLIENT_SIDE_PARAM_ERROR; 1535 } 1536 if(keyStorePathValue == null) 1537 { 1538 printWrappedText(err, ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get()); 1539 return CLIENT_SIDE_PARAM_ERROR; 1540 } 1541 } 1542 1543 connectionOptions.setVerbose(verbose.isPresent()); 1544 1545 // Read the filter strings. 1546 if(fileNameValue != null) 1547 { 1548 BufferedReader in = null; 1549 try 1550 { 1551 in = new BufferedReader(new FileReader(fileNameValue)); 1552 String line = null; 1553 1554 while ((line = in.readLine()) != null) 1555 { 1556 if(line.trim().equals("")) 1557 { 1558 // ignore empty lines. 1559 continue; 1560 } 1561 LDAPFilter ldapFilter = LDAPFilter.decode(line); 1562 filters.add(ldapFilter); 1563 } 1564 } catch(Exception e) 1565 { 1566 logger.traceException(e); 1567 printWrappedText(err, e.getMessage()); 1568 return CLIENT_SIDE_PARAM_ERROR; 1569 } 1570 finally 1571 { 1572 close(in); 1573 } 1574 } 1575 1576 if(filters.isEmpty()) 1577 { 1578 argParser.displayMessageAndUsageReference(err, ERR_SEARCH_NO_FILTERS.get()); 1579 return CLIENT_SIDE_PARAM_ERROR; 1580 } 1581 1582 int wrapColumn = 80; 1583 if (dontWrap.isPresent()) 1584 { 1585 wrapColumn = 0; 1586 } 1587 1588 LDAPSearch ldapSearch = null; 1589 try 1590 { 1591 if (initializeServer) 1592 { 1593 // Bootstrap and initialize directory data structures. 1594 EmbeddedUtils.initializeForClientUse(); 1595 } 1596 1597 // Connect to the specified host with the supplied userDN and password. 1598 SSLConnectionFactory sslConnectionFactory = null; 1599 if(connectionOptions.useSSL() || connectionOptions.useStartTLS()) 1600 { 1601 String clientAlias; 1602 if (certNickname.isPresent()) 1603 { 1604 clientAlias = certNickname.getValue(); 1605 } 1606 else 1607 { 1608 clientAlias = null; 1609 } 1610 1611 sslConnectionFactory = new SSLConnectionFactory(); 1612 sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue, 1613 keyStorePasswordValue, clientAlias, 1614 trustStorePathValue, trustStorePasswordValue); 1615 connectionOptions.setSSLConnectionFactory(sslConnectionFactory); 1616 } 1617 1618 if (noop.isPresent()) 1619 { 1620 // We don't actually need to open a connection or perform the search, 1621 // so we're done. We should return 0 to either mean that the processing 1622 // was successful or that there were no matching entries, based on 1623 // countEntries.isPresent() (but in either case the return value should 1624 // be zero). 1625 return 0; 1626 } 1627 1628 AtomicInteger nextMessageID = new AtomicInteger(1); 1629 connection = new LDAPConnection(hostNameValue, portNumber, 1630 connectionOptions, out, err); 1631 int timeout = pSearchInfo.isPresent()?0:connectTimeout.getIntValue(); 1632 connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID, 1633 timeout); 1634 1635 1636 int matchingEntries = 0; 1637 if (simplePageSize.isPresent()) 1638 { 1639 if (filters.size() > 1) 1640 { 1641 LocalizableMessage message = ERR_PAGED_RESULTS_REQUIRES_SINGLE_FILTER.get(); 1642 throw new LDAPException(CLIENT_SIDE_PARAM_ERROR, message); 1643 } 1644 1645 int pageSize = simplePageSize.getIntValue(); 1646 ByteString cookieValue = null; 1647 ArrayList<Control> origControls = searchOptions.getControls(); 1648 1649 while (true) 1650 { 1651 ArrayList<Control> newControls = new ArrayList<>(origControls.size() + 1); 1652 newControls.addAll(origControls); 1653 newControls.add(new PagedResultsControl(true, pageSize, cookieValue)); 1654 searchOptions.setControls(newControls); 1655 1656 ldapSearch = new LDAPSearch(nextMessageID, out, err); 1657 matchingEntries += ldapSearch.executeSearch(connection, baseDNValue, 1658 filters, attributes, 1659 searchOptions, 1660 wrapColumn); 1661 1662 List<Control> responseControls = 1663 ldapSearch.getResponseControls(); 1664 boolean responseFound = false; 1665 for (Control c : responseControls) 1666 { 1667 if (c.getOID().equals(OID_PAGED_RESULTS_CONTROL)) 1668 { 1669 try 1670 { 1671 PagedResultsControl control = PagedResultsControl.DECODER 1672 .decode(c.isCritical(), ((LDAPControl) c).getValue()); 1673 responseFound = true; 1674 cookieValue = control.getCookie(); 1675 break; 1676 } 1677 catch (DirectoryException de) 1678 { 1679 LocalizableMessage message = 1680 ERR_PAGED_RESULTS_CANNOT_DECODE.get(de.getMessage()); 1681 throw new LDAPException( 1682 CLIENT_SIDE_DECODING_ERROR, message, de); 1683 } 1684 } 1685 } 1686 1687 if (! responseFound) 1688 { 1689 LocalizableMessage message = ERR_PAGED_RESULTS_RESPONSE_NOT_FOUND.get(); 1690 throw new LDAPException(CLIENT_SIDE_CONTROL_NOT_FOUND, message); 1691 } 1692 else if (cookieValue.length() == 0) 1693 { 1694 break; 1695 } 1696 } 1697 } 1698 else 1699 { 1700 ldapSearch = new LDAPSearch(nextMessageID, out, err); 1701 matchingEntries = ldapSearch.executeSearch(connection, baseDNValue, 1702 filters, attributes, 1703 searchOptions, wrapColumn); 1704 } 1705 1706 if (countEntries.isPresent() && returnMatchingEntries) 1707 { 1708 return matchingEntries; 1709 } 1710 else 1711 { 1712 return 0; 1713 } 1714 1715 } catch(LDAPException le) 1716 { 1717 int code = le.getResultCode(); 1718 if (code == REFERRAL) 1719 { 1720 out.println(); 1721 printWrappedText(out, le.getErrorMessage()); 1722 } 1723 else 1724 { 1725 logger.traceException(le); 1726 1727 LDAPToolUtils.printErrorMessage(err, le.getMessageObject(), code, 1728 le.getErrorMessage(), le.getMatchedDN()); 1729 } 1730 return code; 1731 } catch(LDAPConnectionException lce) 1732 { 1733 logger.traceException(lce); 1734 LDAPToolUtils.printErrorMessage(err, 1735 lce.getMessageObject(), 1736 lce.getResultCode(), 1737 lce.getErrorMessage(), 1738 lce.getMatchedDN()); 1739 return lce.getResultCode(); 1740 } catch(Exception e) 1741 { 1742 logger.traceException(e); 1743 printWrappedText(err, e.getMessage()); 1744 return 1; 1745 } finally 1746 { 1747 if(connection != null) 1748 { 1749 if (ldapSearch == null) 1750 { 1751 connection.close(null); 1752 } 1753 else 1754 { 1755 connection.close(ldapSearch.nextMessageID); 1756 } 1757 } 1758 } 1759 } 1760 1761} 1762