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