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.FileInputStream; 031 import java.io.InputStream; 032 import java.io.IOException; 033 import java.io.OutputStream; 034 import java.io.PrintStream; 035 import java.util.ArrayList; 036 import java.util.LinkedList; 037 import java.util.List; 038 import java.util.StringTokenizer; 039 import java.util.concurrent.atomic.AtomicInteger; 040 041 import org.opends.server.protocols.asn1.ASN1Element; 042 import org.opends.server.protocols.asn1.ASN1Exception; 043 import org.opends.server.protocols.asn1.ASN1OctetString; 044 import org.opends.server.protocols.asn1.ASN1Sequence; 045 import org.opends.server.protocols.ldap.AddRequestProtocolOp; 046 import org.opends.server.protocols.ldap.AddResponseProtocolOp; 047 import org.opends.server.protocols.ldap.DeleteRequestProtocolOp; 048 import org.opends.server.protocols.ldap.DeleteResponseProtocolOp; 049 import org.opends.server.protocols.ldap.LDAPAttribute; 050 import org.opends.server.protocols.ldap.LDAPControl; 051 import org.opends.server.protocols.ldap.LDAPFilter; 052 import org.opends.server.protocols.ldap.LDAPMessage; 053 import org.opends.server.protocols.ldap.ModifyRequestProtocolOp; 054 import org.opends.server.protocols.ldap.ModifyResponseProtocolOp; 055 import org.opends.server.protocols.ldap.ModifyDNRequestProtocolOp; 056 import org.opends.server.protocols.ldap.ModifyDNResponseProtocolOp; 057 import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp; 058 import org.opends.server.protocols.ldap.ProtocolOp; 059 import org.opends.server.types.Attribute; 060 import org.opends.server.types.DebugLogLevel; 061 import org.opends.server.types.DN; 062 import org.opends.server.types.LDAPException; 063 import org.opends.server.types.LDIFImportConfig; 064 import org.opends.server.types.NullOutputStream; 065 import org.opends.server.types.RawAttribute; 066 import org.opends.server.types.RawModification; 067 import org.opends.server.util.AddChangeRecordEntry; 068 import org.opends.server.util.ChangeRecordEntry; 069 import org.opends.server.util.EmbeddedUtils; 070 import org.opends.server.util.LDIFException; 071 import org.opends.server.util.LDIFReader; 072 import org.opends.server.util.ModifyChangeRecordEntry; 073 import org.opends.server.util.ModifyDNChangeRecordEntry; 074 import org.opends.server.util.PasswordReader; 075 import org.opends.server.util.args.ArgumentException; 076 import org.opends.server.util.args.ArgumentParser; 077 import org.opends.server.util.args.BooleanArgument; 078 import org.opends.server.util.args.FileBasedArgument; 079 import org.opends.server.util.args.IntegerArgument; 080 import org.opends.server.util.args.StringArgument; 081 082 import static org.opends.server.loggers.debug.DebugLogger.*; 083 import org.opends.server.loggers.debug.DebugTracer; 084 import static org.opends.messages.ToolMessages.*; 085 import static org.opends.server.protocols.ldap.LDAPResultCode.*; 086 import static org.opends.server.util.ServerConstants.*; 087 import static org.opends.server.util.StaticUtils.*; 088 import static org.opends.server.tools.ToolConstants.*; 089 090 091 092 /** 093 * This class provides a tool that can be used to issue modify requests to the 094 * Directory Server. 095 */ 096 public class LDAPModify 097 { 098 /** 099 * The tracer object for the debug logger. 100 */ 101 private static final DebugTracer TRACER = getTracer(); 102 103 /** 104 * The fully-qualified name of this class. 105 */ 106 private static final String CLASS_NAME = "org.opends.server.tools.LDAPModify"; 107 108 // The message ID counter to use for requests. 109 private AtomicInteger nextMessageID; 110 111 // The print stream to use for standard error. 112 private PrintStream err; 113 114 // The print stream to use for standard output. 115 private PrintStream out; 116 117 // The LDIF file name. 118 private String fileName = null; 119 120 /** 121 * Constructor for the LDAPModify object. 122 * 123 * @param fileName The name of the file containing the LDIF data to use 124 * for the modifications. 125 * @param nextMessageID The message ID counter to use for requests. 126 * @param out The print stream to use for standard output. 127 * @param err The print stream to use for standard error. 128 */ 129 public LDAPModify(String fileName, AtomicInteger nextMessageID, 130 PrintStream out, PrintStream err) 131 { 132 if(fileName == null) 133 { 134 this.fileName = "Console"; 135 } else 136 { 137 this.fileName = fileName; 138 } 139 140 this.nextMessageID = nextMessageID; 141 this.out = out; 142 this.err = err; 143 } 144 145 146 /** 147 * Read the specified change records from the given input stream 148 * (file or stdin) and execute the given modify request. 149 * 150 * @param connection The connection to use for this modify request. 151 * @param fileNameValue Name of the file from which to read. If null, 152 * input will be read from <code>System.in</code>. 153 * @param modifyOptions The constraints for the modify request. 154 * 155 * @throws IOException If a problem occurs while attempting to communicate 156 * with the Directory Server. 157 * 158 * @throws LDAPException If the Directory Server returns an error response. 159 */ 160 public void readAndExecute(LDAPConnection connection, String fileNameValue, 161 LDAPModifyOptions modifyOptions) 162 throws IOException, LDAPException 163 { 164 ArrayList<LDAPControl> controls = modifyOptions.getControls(); 165 LDIFReader reader; 166 167 // Create an LDIF import configuration to do this and then get the reader. 168 169 try 170 { 171 InputStream is = System.in; 172 if(fileNameValue != null) 173 { 174 is = new FileInputStream(fileNameValue); 175 } 176 177 LDIFImportConfig importConfig = new LDIFImportConfig(is); 178 reader = new LDIFReader(importConfig); 179 } catch (Exception e) 180 { 181 if (debugEnabled()) 182 { 183 TRACER.debugCaught(DebugLogLevel.ERROR, e); 184 } 185 Message message = 186 ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ.get(fileNameValue, 187 e.getLocalizedMessage()); 188 throw new IOException(message.toString()); 189 } 190 191 while (true) 192 { 193 ChangeRecordEntry entry = null; 194 195 try 196 { 197 entry = reader.readChangeRecord(modifyOptions.getDefaultAdd()); 198 } catch (LDIFException le) 199 { 200 if (debugEnabled()) 201 { 202 TRACER.debugCaught(DebugLogLevel.ERROR, le); 203 } 204 if (!modifyOptions.continueOnError()) 205 { 206 try 207 { 208 reader.close(); 209 } 210 catch (Exception e) 211 { 212 if (debugEnabled()) 213 { 214 TRACER.debugCaught(DebugLogLevel.ERROR, e); 215 } 216 } 217 218 Message message = ERR_LDIF_FILE_INVALID_LDIF_ENTRY.get( 219 le.getLineNumber(), fileName, String.valueOf(le)); 220 throw new IOException(message.toString()); 221 } 222 else 223 { 224 Message message = ERR_LDIF_FILE_INVALID_LDIF_ENTRY.get( 225 le.getLineNumber(), fileName, String.valueOf(le)); 226 err.println(wrapText(message, MAX_LINE_WIDTH)); 227 continue; 228 } 229 } catch (Exception e) 230 { 231 if (debugEnabled()) 232 { 233 TRACER.debugCaught(DebugLogLevel.ERROR, e); 234 } 235 236 if (!modifyOptions.continueOnError()) 237 { 238 try 239 { 240 reader.close(); 241 } 242 catch (Exception e2) 243 { 244 if (debugEnabled()) 245 { 246 TRACER.debugCaught(DebugLogLevel.ERROR, e2); 247 } 248 } 249 250 Message message = 251 ERR_LDIF_FILE_READ_ERROR.get(fileName, String.valueOf(e)); 252 throw new IOException(message.toString()); 253 } 254 else 255 { 256 Message message = ERR_LDIF_FILE_READ_ERROR.get( 257 fileName, String.valueOf(e)); 258 err.println(wrapText(message, MAX_LINE_WIDTH)); 259 continue; 260 } 261 } 262 263 // If the entry is null, then we have reached the end of the config file. 264 if(entry == null) 265 { 266 try 267 { 268 reader.close(); 269 } 270 catch (Exception e) 271 { 272 if (debugEnabled()) 273 { 274 TRACER.debugCaught(DebugLogLevel.ERROR, e); 275 } 276 } 277 278 break; 279 } 280 281 ProtocolOp protocolOp = null; 282 ASN1OctetString asn1OctetStr = 283 new ASN1OctetString(entry.getDN().toString()); 284 285 String operationType = ""; 286 int msgID = 0; 287 switch(entry.getChangeOperationType()) 288 { 289 case ADD: 290 operationType = "ADD"; 291 AddChangeRecordEntry addEntry = (AddChangeRecordEntry) entry; 292 List<Attribute> attrs = addEntry.getAttributes(); 293 ArrayList<RawAttribute> attributes = 294 new ArrayList<RawAttribute>(attrs.size()); 295 for(Attribute a : attrs) 296 { 297 attributes.add(new LDAPAttribute(a)); 298 } 299 protocolOp = new AddRequestProtocolOp(asn1OctetStr, attributes); 300 out.println(INFO_PROCESSING_OPERATION.get( 301 operationType, String.valueOf(asn1OctetStr))); 302 break; 303 case DELETE: 304 operationType = "DELETE"; 305 protocolOp = new DeleteRequestProtocolOp(asn1OctetStr); 306 out.println(INFO_PROCESSING_OPERATION.get( 307 operationType, String.valueOf(asn1OctetStr))); 308 break; 309 case MODIFY: 310 operationType = "MODIFY"; 311 ModifyChangeRecordEntry modEntry = (ModifyChangeRecordEntry) entry; 312 ArrayList<RawModification> mods = 313 new ArrayList<RawModification>(modEntry.getModifications()); 314 protocolOp = new ModifyRequestProtocolOp(asn1OctetStr, mods); 315 out.println(INFO_PROCESSING_OPERATION.get( 316 operationType, String.valueOf(asn1OctetStr))); 317 break; 318 case MODIFY_DN: 319 operationType = "MODIFY DN"; 320 ModifyDNChangeRecordEntry modDNEntry = 321 (ModifyDNChangeRecordEntry) entry; 322 if(modDNEntry.getNewSuperiorDN() != null) 323 { 324 protocolOp = new ModifyDNRequestProtocolOp(asn1OctetStr, 325 new ASN1OctetString(modDNEntry.getNewRDN().toString()), 326 modDNEntry.deleteOldRDN(), 327 new ASN1OctetString( 328 modDNEntry.getNewSuperiorDN().toString())); 329 } else 330 { 331 protocolOp = new ModifyDNRequestProtocolOp(asn1OctetStr, 332 new ASN1OctetString(modDNEntry.getNewRDN().toString()), 333 modDNEntry.deleteOldRDN()); 334 } 335 336 out.println(INFO_PROCESSING_OPERATION.get( 337 operationType, String.valueOf(asn1OctetStr))); 338 break; 339 default: 340 break; 341 } 342 343 if(!modifyOptions.showOperations()) 344 { 345 LDAPMessage responseMessage = null; 346 try 347 { 348 LDAPMessage message = 349 new LDAPMessage(nextMessageID.getAndIncrement(), protocolOp, 350 controls); 351 connection.getLDAPWriter().writeMessage(message); 352 responseMessage = connection.getLDAPReader().readMessage(); 353 } catch(ASN1Exception ae) 354 { 355 if (debugEnabled()) 356 { 357 TRACER.debugCaught(DebugLogLevel.ERROR, ae); 358 } 359 Message message = INFO_OPERATION_FAILED.get(operationType); 360 err.println(wrapText(message, MAX_LINE_WIDTH)); 361 err.println(wrapText(ae.getMessage(), MAX_LINE_WIDTH)); 362 if (!modifyOptions.continueOnError()) 363 { 364 throw new IOException(ae.getMessage()); 365 } 366 return; 367 } 368 369 int resultCode = 0; 370 Message errorMessage = null; 371 DN matchedDN = null; 372 List<String> referralURLs = null; 373 switch(entry.getChangeOperationType()) 374 { 375 case ADD: 376 AddResponseProtocolOp addOp = 377 responseMessage.getAddResponseProtocolOp(); 378 resultCode = addOp.getResultCode(); 379 errorMessage = addOp.getErrorMessage(); 380 matchedDN = addOp.getMatchedDN(); 381 referralURLs = addOp.getReferralURLs(); 382 break; 383 case DELETE: 384 DeleteResponseProtocolOp delOp = 385 responseMessage.getDeleteResponseProtocolOp(); 386 resultCode = delOp.getResultCode(); 387 errorMessage = delOp.getErrorMessage(); 388 matchedDN = delOp.getMatchedDN(); 389 referralURLs = delOp.getReferralURLs(); 390 break; 391 case MODIFY: 392 ModifyResponseProtocolOp modOp = 393 responseMessage.getModifyResponseProtocolOp(); 394 resultCode = modOp.getResultCode(); 395 errorMessage = modOp.getErrorMessage(); 396 matchedDN = modOp.getMatchedDN(); 397 referralURLs = modOp.getReferralURLs(); 398 break; 399 case MODIFY_DN: 400 ModifyDNResponseProtocolOp modDNOp = 401 responseMessage.getModifyDNResponseProtocolOp(); 402 resultCode = modDNOp.getResultCode(); 403 errorMessage = modDNOp.getErrorMessage(); 404 matchedDN = modDNOp.getMatchedDN(); 405 referralURLs = modDNOp.getReferralURLs(); 406 break; 407 default: 408 break; 409 } 410 411 if(resultCode != SUCCESS && resultCode != REFERRAL) 412 { 413 Message msg = INFO_OPERATION_FAILED.get(operationType); 414 415 if(!modifyOptions.continueOnError()) 416 { 417 throw new LDAPException(resultCode, errorMessage, msg, 418 matchedDN, null); 419 } else 420 { 421 LDAPToolUtils.printErrorMessage(err, msg, resultCode, errorMessage, 422 matchedDN); 423 } 424 } else 425 { 426 Message msg = INFO_OPERATION_SUCCESSFUL.get( 427 operationType, String.valueOf(asn1OctetStr)); 428 out.println(msg); 429 430 if (errorMessage != null) 431 { 432 out.println(wrapText(errorMessage, MAX_LINE_WIDTH)); 433 } 434 435 if (referralURLs != null) 436 { 437 out.println(referralURLs); 438 } 439 } 440 441 442 for (LDAPControl c : responseMessage.getControls()) 443 { 444 String oid = c.getOID(); 445 if (oid.equals(OID_LDAP_READENTRY_PREREAD)) 446 { 447 ASN1OctetString controlValue = c.getValue(); 448 if (controlValue == null) 449 { 450 451 err.println(wrapText( 452 ERR_LDAPMODIFY_PREREAD_NO_VALUE.get(), 453 MAX_LINE_WIDTH)); 454 continue; 455 } 456 457 SearchResultEntryProtocolOp searchEntry; 458 try 459 { 460 byte[] valueBytes = controlValue.value(); 461 ASN1Element valueElement = ASN1Element.decode(valueBytes); 462 searchEntry = 463 SearchResultEntryProtocolOp.decodeSearchEntry(valueElement); 464 } 465 catch (ASN1Exception ae) 466 { 467 468 err.println(wrapText( 469 ERR_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE.get( 470 ae.getMessage()), 471 MAX_LINE_WIDTH)); 472 continue; 473 } 474 catch (LDAPException le) 475 { 476 477 err.println(wrapText( 478 ERR_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE.get( 479 le.getMessage()), 480 MAX_LINE_WIDTH)); 481 continue; 482 } 483 484 StringBuilder buffer = new StringBuilder(); 485 searchEntry.toLDIF(buffer, 78); 486 out.println(INFO_LDAPMODIFY_PREREAD_ENTRY.get()); 487 out.println(buffer); 488 } 489 else if (oid.equals(OID_LDAP_READENTRY_POSTREAD)) 490 { 491 ASN1OctetString controlValue = c.getValue(); 492 if (controlValue == null) 493 { 494 495 err.println(wrapText( 496 ERR_LDAPMODIFY_POSTREAD_NO_VALUE.get(), 497 MAX_LINE_WIDTH)); 498 continue; 499 } 500 501 SearchResultEntryProtocolOp searchEntry; 502 try 503 { 504 byte[] valueBytes = controlValue.value(); 505 ASN1Element valueElement = ASN1Element.decode(valueBytes); 506 searchEntry = 507 SearchResultEntryProtocolOp.decodeSearchEntry(valueElement); 508 } 509 catch (ASN1Exception ae) 510 { 511 512 err.println(wrapText( 513 ERR_LDAPMODIFY_POSTREAD_CANNOT_DECODE_VALUE.get( 514 ae.getMessage()), 515 MAX_LINE_WIDTH)); 516 continue; 517 } 518 catch (LDAPException le) 519 { 520 521 err.println(wrapText( 522 ERR_LDAPMODIFY_POSTREAD_CANNOT_DECODE_VALUE.get( 523 le.getMessage()), 524 MAX_LINE_WIDTH)); 525 continue; 526 } 527 528 StringBuilder buffer = new StringBuilder(); 529 searchEntry.toLDIF(buffer, 78); 530 out.println(INFO_LDAPMODIFY_POSTREAD_ENTRY.get()); 531 out.println(buffer); 532 } 533 } 534 } 535 } 536 537 } 538 539 /** 540 * The main method for LDAPModify tool. 541 * 542 * @param args The command-line arguments provided to this program. 543 */ 544 545 public static void main(String[] args) 546 { 547 int retCode = mainModify(args, true, System.out, System.err); 548 549 if(retCode != 0) 550 { 551 System.exit(filterExitCode(retCode)); 552 } 553 } 554 555 556 /** 557 * Parses the provided command-line arguments and uses that information to 558 * run the ldapmodify tool. 559 * 560 * @param args The command-line arguments provided to this program. 561 * 562 * @return The error code. 563 */ 564 565 public static int mainModify(String[] args) 566 { 567 return mainModify(args, true, System.out, System.err); 568 } 569 570 571 /** 572 * Parses the provided command-line arguments and uses that information to 573 * run the ldapmodify tool. 574 * 575 * @param args The command-line arguments provided to this 576 * program. 577 * @param initializeServer Indicates whether to initialize the server. 578 * @param outStream The output stream to use for standard output, or 579 * <CODE>null</CODE> if standard output is not 580 * needed. 581 * @param errStream The output stream to use for standard error, or 582 * <CODE>null</CODE> if standard error is not 583 * needed. 584 * 585 * @return The error code. 586 */ 587 588 public static int mainModify(String[] args, boolean initializeServer, 589 OutputStream outStream, OutputStream errStream) 590 { 591 PrintStream out; 592 if (outStream == null) 593 { 594 out = NullOutputStream.printStream(); 595 } 596 else 597 { 598 out = new PrintStream(outStream); 599 } 600 601 PrintStream err; 602 if (errStream == null) 603 { 604 err = NullOutputStream.printStream(); 605 } 606 else 607 { 608 err = new PrintStream(errStream); 609 } 610 611 612 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions(); 613 LDAPModifyOptions modifyOptions = new LDAPModifyOptions(); 614 LDAPConnection connection = null; 615 616 BooleanArgument continueOnError = null; 617 BooleanArgument defaultAdd = null; 618 BooleanArgument noop = null; 619 BooleanArgument reportAuthzID = null; 620 BooleanArgument saslExternal = null; 621 BooleanArgument showUsage = null; 622 BooleanArgument startTLS = null; 623 BooleanArgument trustAll = null; 624 BooleanArgument useSSL = null; 625 BooleanArgument verbose = null; 626 FileBasedArgument bindPasswordFile = null; 627 FileBasedArgument keyStorePasswordFile = null; 628 FileBasedArgument trustStorePasswordFile = null; 629 IntegerArgument port = null; 630 IntegerArgument version = null; 631 StringArgument assertionFilter = null; 632 StringArgument bindDN = null; 633 StringArgument bindPassword = null; 634 StringArgument certNickname = null; 635 StringArgument controlStr = null; 636 StringArgument encodingStr = null; 637 StringArgument filename = null; 638 StringArgument hostName = null; 639 StringArgument keyStorePath = null; 640 StringArgument keyStorePassword = null; 641 StringArgument postReadAttributes = null; 642 StringArgument preReadAttributes = null; 643 StringArgument proxyAuthzID = null; 644 StringArgument saslOptions = null; 645 StringArgument trustStorePath = null; 646 StringArgument trustStorePassword = null; 647 StringArgument propertiesFileArgument = null; 648 BooleanArgument noPropertiesFileArgument = null; 649 650 // Create the command-line argument parser for use with this program. 651 Message toolDescription = INFO_LDAPMODIFY_TOOL_DESCRIPTION.get(); 652 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, 653 false); 654 try 655 { 656 propertiesFileArgument = new StringArgument("propertiesFilePath", 657 null, OPTION_LONG_PROP_FILE_PATH, 658 false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null, 659 INFO_DESCRIPTION_PROP_FILE_PATH.get()); 660 argParser.addArgument(propertiesFileArgument); 661 argParser.setFilePropertiesArgument(propertiesFileArgument); 662 663 noPropertiesFileArgument = new BooleanArgument( 664 "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE, 665 INFO_DESCRIPTION_NO_PROP_FILE.get()); 666 argParser.addArgument(noPropertiesFileArgument); 667 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); 668 669 hostName = new StringArgument("host", OPTION_SHORT_HOST, 670 OPTION_LONG_HOST, false, false, true, 671 INFO_HOST_PLACEHOLDER.get(), "localhost", 672 null, 673 INFO_DESCRIPTION_HOST.get()); 674 hostName.setPropertyName(OPTION_LONG_HOST); 675 argParser.addArgument(hostName); 676 677 port = new IntegerArgument("port", OPTION_SHORT_PORT, 678 OPTION_LONG_PORT, false, false, true, 679 INFO_PORT_PLACEHOLDER.get(), 389, null, 680 INFO_DESCRIPTION_PORT.get()); 681 port.setPropertyName(OPTION_LONG_PORT); 682 argParser.addArgument(port); 683 684 useSSL = new BooleanArgument("useSSL", OPTION_SHORT_USE_SSL, 685 OPTION_LONG_USE_SSL, 686 INFO_DESCRIPTION_USE_SSL.get()); 687 useSSL.setPropertyName(OPTION_LONG_USE_SSL); 688 argParser.addArgument(useSSL); 689 690 startTLS = new BooleanArgument("startTLS", OPTION_SHORT_START_TLS, 691 OPTION_LONG_START_TLS, 692 INFO_DESCRIPTION_START_TLS.get()); 693 startTLS.setPropertyName(OPTION_LONG_START_TLS); 694 argParser.addArgument(startTLS); 695 696 bindDN = new StringArgument("bindDN", OPTION_SHORT_BINDDN, 697 OPTION_LONG_BINDDN, false, false, true, 698 INFO_BINDDN_PLACEHOLDER.get(), null, null, 699 INFO_DESCRIPTION_BINDDN.get()); 700 bindDN.setPropertyName(OPTION_LONG_BINDDN); 701 argParser.addArgument(bindDN); 702 703 bindPassword = new StringArgument("bindPassword", OPTION_SHORT_BINDPWD, 704 OPTION_LONG_BINDPWD, 705 false, false, true, 706 INFO_BINDPWD_PLACEHOLDER.get(), 707 null, null, 708 INFO_DESCRIPTION_BINDPASSWORD.get()); 709 bindPassword.setPropertyName(OPTION_LONG_BINDPWD); 710 argParser.addArgument(bindPassword); 711 712 bindPasswordFile = 713 new FileBasedArgument("bindPasswordFile", 714 OPTION_SHORT_BINDPWD_FILE, 715 OPTION_LONG_BINDPWD_FILE, 716 false, false, 717 INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, 718 null, INFO_DESCRIPTION_BINDPASSWORDFILE.get()); 719 bindPasswordFile.setPropertyName(OPTION_LONG_BINDPWD_FILE); 720 argParser.addArgument(bindPasswordFile); 721 722 defaultAdd = new BooleanArgument( 723 "defaultAdd", 'a', "defaultAdd", 724 INFO_MODIFY_DESCRIPTION_DEFAULT_ADD.get()); 725 argParser.addArgument(defaultAdd); 726 727 filename = new StringArgument("filename", OPTION_SHORT_FILENAME, 728 OPTION_LONG_FILENAME, false, false, 729 true, INFO_FILE_PLACEHOLDER.get(), null, 730 null, 731 INFO_LDAPMODIFY_DESCRIPTION_FILENAME.get()); 732 filename.setPropertyName(OPTION_LONG_FILENAME); 733 argParser.addArgument(filename); 734 735 saslExternal = new BooleanArgument( 736 "useSASLExternal", 'r', 737 "useSASLExternal", 738 INFO_DESCRIPTION_USE_SASL_EXTERNAL.get()); 739 saslExternal.setPropertyName("useSASLExternal"); 740 argParser.addArgument(saslExternal); 741 742 saslOptions = new StringArgument("saslOption", OPTION_SHORT_SASLOPTION, 743 OPTION_LONG_SASLOPTION, false, 744 true, true, 745 INFO_SASL_OPTION_PLACEHOLDER.get(), null, 746 null, 747 INFO_DESCRIPTION_SASL_PROPERTIES.get()); 748 saslOptions.setPropertyName(OPTION_LONG_SASLOPTION); 749 argParser.addArgument(saslOptions); 750 751 trustAll = new BooleanArgument("trustAll", 'X', "trustAll", 752 INFO_DESCRIPTION_TRUSTALL.get()); 753 trustAll.setPropertyName("trustAll"); 754 argParser.addArgument(trustAll); 755 756 keyStorePath = new StringArgument("keyStorePath", 757 OPTION_SHORT_KEYSTOREPATH, 758 OPTION_LONG_KEYSTOREPATH, 759 false, false, true, 760 INFO_KEYSTOREPATH_PLACEHOLDER.get(), 761 null, null, 762 INFO_DESCRIPTION_KEYSTOREPATH.get()); 763 keyStorePath.setPropertyName(OPTION_LONG_KEYSTOREPATH); 764 argParser.addArgument(keyStorePath); 765 766 keyStorePassword = 767 new StringArgument("keyStorePassword", 768 OPTION_SHORT_KEYSTORE_PWD, 769 OPTION_LONG_KEYSTORE_PWD, 770 false, false, 771 true, 772 INFO_KEYSTORE_PWD_PLACEHOLDER.get(), 773 null, null, 774 INFO_DESCRIPTION_KEYSTOREPASSWORD.get()); 775 keyStorePassword.setPropertyName(OPTION_LONG_KEYSTORE_PWD); 776 argParser.addArgument(keyStorePassword); 777 778 keyStorePasswordFile = 779 new FileBasedArgument("keystorepasswordfile", 780 OPTION_SHORT_KEYSTORE_PWD_FILE, 781 OPTION_LONG_KEYSTORE_PWD_FILE, 782 false, false, 783 INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get(), 784 null, null, 785 INFO_DESCRIPTION_KEYSTOREPASSWORD_FILE.get()); 786 keyStorePasswordFile.setPropertyName(OPTION_LONG_KEYSTORE_PWD_FILE); 787 argParser.addArgument(keyStorePasswordFile); 788 789 certNickname = new StringArgument( 790 "certnickname", 'N', "certNickname", 791 false, false, true, INFO_NICKNAME_PLACEHOLDER.get(), null, 792 null, INFO_DESCRIPTION_CERT_NICKNAME.get()); 793 certNickname.setPropertyName("certNickname"); 794 argParser.addArgument(certNickname); 795 796 trustStorePath = new StringArgument( 797 "trustStorePath", 798 OPTION_SHORT_TRUSTSTOREPATH, 799 OPTION_LONG_TRUSTSTOREPATH, 800 false, false, true, 801 INFO_TRUSTSTOREPATH_PLACEHOLDER.get(), 802 null, null, 803 INFO_DESCRIPTION_TRUSTSTOREPATH.get()); 804 trustStorePath.setPropertyName(OPTION_LONG_TRUSTSTOREPATH); 805 argParser.addArgument(trustStorePath); 806 807 trustStorePassword = 808 new StringArgument("trustStorePassword", null, 809 OPTION_LONG_TRUSTSTORE_PWD , 810 false, false, true, 811 INFO_TRUSTSTORE_PWD_PLACEHOLDER.get(), null, 812 null, INFO_DESCRIPTION_TRUSTSTOREPASSWORD.get()); 813 trustStorePassword.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD); 814 argParser.addArgument(trustStorePassword); 815 816 trustStorePasswordFile = 817 new FileBasedArgument( 818 "truststorepasswordfile", 819 OPTION_SHORT_TRUSTSTORE_PWD_FILE, 820 OPTION_LONG_TRUSTSTORE_PWD_FILE, false, false, 821 INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get(), null, null, 822 INFO_DESCRIPTION_TRUSTSTOREPASSWORD_FILE.get()); 823 trustStorePasswordFile.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD_FILE); 824 argParser.addArgument(trustStorePasswordFile); 825 826 proxyAuthzID = new StringArgument("proxy_authzid", 827 OPTION_SHORT_PROXYAUTHID, 828 OPTION_LONG_PROXYAUTHID, false, 829 false, true, 830 INFO_PROXYAUTHID_PLACEHOLDER.get(), 831 null, null, 832 INFO_DESCRIPTION_PROXY_AUTHZID.get()); 833 proxyAuthzID.setPropertyName(OPTION_LONG_PROXYAUTHID); 834 argParser.addArgument(proxyAuthzID); 835 836 reportAuthzID = new BooleanArgument( 837 "reportauthzid", 'E', 838 "reportAuthzID", 839 INFO_DESCRIPTION_REPORT_AUTHZID.get()); 840 reportAuthzID.setPropertyName("reportAuthzID"); 841 argParser.addArgument(reportAuthzID); 842 843 assertionFilter = new StringArgument( 844 "assertionfilter", null, 845 OPTION_LONG_ASSERTION_FILE, 846 false, false, 847 true, 848 INFO_ASSERTION_FILTER_PLACEHOLDER.get(), 849 null, null, 850 INFO_DESCRIPTION_ASSERTION_FILTER.get()); 851 assertionFilter.setPropertyName(OPTION_LONG_ASSERTION_FILE); 852 argParser.addArgument(assertionFilter); 853 854 preReadAttributes = new StringArgument( 855 "prereadattrs", null, 856 "preReadAttributes", false, false, 857 true, INFO_ATTRIBUTE_LIST_PLACEHOLDER.get(), null, null, 858 INFO_DESCRIPTION_PREREAD_ATTRS.get()); 859 preReadAttributes.setPropertyName("preReadAttributes"); 860 argParser.addArgument(preReadAttributes); 861 862 postReadAttributes = new StringArgument( 863 "postreadattrs", null, 864 "postReadAttributes", false, 865 false, true, INFO_ATTRIBUTE_LIST_PLACEHOLDER.get(), null, 866 null, 867 INFO_DESCRIPTION_POSTREAD_ATTRS.get()); 868 postReadAttributes.setPropertyName("postReadAttributes"); 869 argParser.addArgument(postReadAttributes); 870 871 controlStr = 872 new StringArgument("control", 'J', "control", false, true, true, 873 INFO_LDAP_CONTROL_PLACEHOLDER.get(), 874 null, null, INFO_DESCRIPTION_CONTROLS.get()); 875 controlStr.setPropertyName("control"); 876 argParser.addArgument(controlStr); 877 878 version = new IntegerArgument("version", OPTION_SHORT_PROTOCOL_VERSION, 879 OPTION_LONG_PROTOCOL_VERSION, 880 false, false, true, 881 INFO_PROTOCOL_VERSION_PLACEHOLDER.get(), 3, null, 882 INFO_DESCRIPTION_VERSION.get()); 883 version.setPropertyName(OPTION_LONG_PROTOCOL_VERSION); 884 argParser.addArgument(version); 885 886 encodingStr = new StringArgument("encoding", 'i', "encoding", 887 false, false, 888 true, INFO_ENCODING_PLACEHOLDER.get(), 889 null, null, 890 INFO_DESCRIPTION_ENCODING.get()); 891 encodingStr.setPropertyName("encoding"); 892 argParser.addArgument(encodingStr); 893 894 continueOnError = new BooleanArgument("continueOnError", 'c', 895 "continueOnError", 896 INFO_DESCRIPTION_CONTINUE_ON_ERROR.get()); 897 continueOnError.setPropertyName("continueOnError"); 898 argParser.addArgument(continueOnError); 899 900 noop = new BooleanArgument("no-op", OPTION_SHORT_DRYRUN, 901 OPTION_LONG_DRYRUN, 902 INFO_DESCRIPTION_NOOP.get()); 903 noop.setPropertyName(OPTION_LONG_DRYRUN); 904 argParser.addArgument(noop); 905 906 verbose = new BooleanArgument("verbose", 'v', "verbose", 907 INFO_DESCRIPTION_VERBOSE.get()); 908 verbose.setPropertyName("verbose"); 909 argParser.addArgument(verbose); 910 911 showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP, 912 OPTION_LONG_HELP, 913 INFO_DESCRIPTION_SHOWUSAGE.get()); 914 argParser.addArgument(showUsage); 915 argParser.setUsageArgument(showUsage, out); 916 } catch (ArgumentException ae) 917 { 918 Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()); 919 920 err.println(wrapText(message, MAX_LINE_WIDTH)); 921 return 1; 922 } 923 924 // Parse the command-line arguments provided to this program. 925 try 926 { 927 argParser.parseArguments(args); 928 } 929 catch (ArgumentException ae) 930 { 931 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage()); 932 933 err.println(wrapText(message, MAX_LINE_WIDTH)); 934 err.println(argParser.getUsage()); 935 return 1; 936 } 937 938 // If we should just display usage or version information, 939 // then print it and exit. 940 if (argParser.usageOrVersionDisplayed()) 941 { 942 return 0; 943 } 944 945 if(bindPassword.isPresent() && bindPasswordFile.isPresent()) 946 { 947 Message message = ERR_TOOL_CONFLICTING_ARGS.get( 948 bindPassword.getLongIdentifier(), 949 bindPasswordFile.getLongIdentifier()); 950 err.println(wrapText(message, MAX_LINE_WIDTH)); 951 return 1; 952 } 953 954 String hostNameValue = hostName.getValue(); 955 int portNumber = 389; 956 try 957 { 958 portNumber = port.getIntValue(); 959 } catch(ArgumentException ae) 960 { 961 if (debugEnabled()) 962 { 963 TRACER.debugCaught(DebugLogLevel.ERROR, ae); 964 } 965 err.println(wrapText(ae.getMessage(), MAX_LINE_WIDTH)); 966 return 1; 967 } 968 969 try 970 { 971 int versionNumber = version.getIntValue(); 972 if(versionNumber != 2 && versionNumber != 3) 973 { 974 975 err.println(wrapText(ERR_DESCRIPTION_INVALID_VERSION.get( 976 String.valueOf(versionNumber)), MAX_LINE_WIDTH)); 977 return 1; 978 } 979 connectionOptions.setVersionNumber(versionNumber); 980 } catch(ArgumentException ae) 981 { 982 if (debugEnabled()) 983 { 984 TRACER.debugCaught(DebugLogLevel.ERROR, ae); 985 } 986 err.println(wrapText(ae.getMessage(), MAX_LINE_WIDTH)); 987 return 1; 988 } 989 990 String bindDNValue = bindDN.getValue(); 991 String fileNameValue = filename.getValue(); 992 String bindPasswordValue = bindPassword.getValue(); 993 if(bindPasswordValue != null && bindPasswordValue.equals("-")) 994 { 995 // read the password from the stdin. 996 try 997 { 998 out.print(INFO_LDAPAUTH_PASSWORD_PROMPT.get(bindDNValue)); 999 char[] pwChars = PasswordReader.readPassword(); 1000 bindPasswordValue = new String(pwChars); 1001 } catch(Exception ex) 1002 { 1003 if (debugEnabled()) 1004 { 1005 TRACER.debugCaught(DebugLogLevel.ERROR, ex); 1006 } 1007 err.println(wrapText(ex.getMessage(), MAX_LINE_WIDTH)); 1008 return 1; 1009 } 1010 } else if(bindPasswordValue == null) 1011 { 1012 // Read from file if it exists. 1013 bindPasswordValue = bindPasswordFile.getValue(); 1014 } 1015 1016 String keyStorePathValue = keyStorePath.getValue(); 1017 String trustStorePathValue = trustStorePath.getValue(); 1018 1019 String keyStorePasswordValue = null; 1020 if (keyStorePassword.isPresent()) 1021 { 1022 keyStorePasswordValue = keyStorePassword.getValue(); 1023 } 1024 else if (keyStorePasswordFile.isPresent()) 1025 { 1026 keyStorePasswordValue = keyStorePasswordFile.getValue(); 1027 } 1028 1029 String trustStorePasswordValue = null; 1030 if (trustStorePassword.isPresent()) 1031 { 1032 trustStorePasswordValue = trustStorePassword.getValue(); 1033 } 1034 else if (trustStorePasswordFile.isPresent()) 1035 { 1036 trustStorePasswordValue = trustStorePasswordFile.getValue(); 1037 } 1038 1039 modifyOptions.setShowOperations(noop.isPresent()); 1040 modifyOptions.setVerbose(verbose.isPresent()); 1041 modifyOptions.setContinueOnError(continueOnError.isPresent()); 1042 modifyOptions.setEncoding(encodingStr.getValue()); 1043 modifyOptions.setDefaultAdd(defaultAdd.isPresent()); 1044 1045 if (controlStr.isPresent()) 1046 { 1047 for (String ctrlString : controlStr.getValues()) 1048 { 1049 LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString, err); 1050 if(ctrl == null) 1051 { 1052 Message message = ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString); 1053 err.println(wrapText(message, MAX_LINE_WIDTH)); 1054 err.println(argParser.getUsage()); 1055 return 1; 1056 } 1057 modifyOptions.getControls().add(ctrl); 1058 } 1059 } 1060 1061 if (proxyAuthzID.isPresent()) 1062 { 1063 ASN1OctetString proxyValue = new ASN1OctetString(proxyAuthzID.getValue()); 1064 1065 LDAPControl proxyControl = 1066 new LDAPControl(OID_PROXIED_AUTH_V2, true, proxyValue); 1067 modifyOptions.getControls().add(proxyControl); 1068 } 1069 1070 if (assertionFilter.isPresent()) 1071 { 1072 String filterString = assertionFilter.getValue(); 1073 LDAPFilter filter; 1074 try 1075 { 1076 filter = LDAPFilter.decode(filterString); 1077 1078 LDAPControl assertionControl = 1079 new LDAPControl(OID_LDAP_ASSERTION, true, 1080 new ASN1OctetString(filter.encode().encode())); 1081 modifyOptions.getControls().add(assertionControl); 1082 } 1083 catch (LDAPException le) 1084 { 1085 Message message = ERR_LDAP_ASSERTION_INVALID_FILTER.get( 1086 le.getMessage()); 1087 err.println(wrapText(message, MAX_LINE_WIDTH)); 1088 return 1; 1089 } 1090 } 1091 1092 if (preReadAttributes.isPresent()) 1093 { 1094 String valueStr = preReadAttributes.getValue(); 1095 ArrayList<ASN1Element> attrElements = new ArrayList<ASN1Element>(); 1096 1097 StringTokenizer tokenizer = new StringTokenizer(valueStr, ", "); 1098 while (tokenizer.hasMoreTokens()) 1099 { 1100 attrElements.add(new ASN1OctetString(tokenizer.nextToken())); 1101 } 1102 1103 ASN1OctetString controlValue = 1104 new ASN1OctetString(new ASN1Sequence(attrElements).encode()); 1105 LDAPControl c = new LDAPControl(OID_LDAP_READENTRY_PREREAD, true, 1106 controlValue); 1107 modifyOptions.getControls().add(c); 1108 } 1109 1110 if (postReadAttributes.isPresent()) 1111 { 1112 String valueStr = postReadAttributes.getValue(); 1113 ArrayList<ASN1Element> attrElements = new ArrayList<ASN1Element>(); 1114 1115 StringTokenizer tokenizer = new StringTokenizer(valueStr, ", "); 1116 while (tokenizer.hasMoreTokens()) 1117 { 1118 attrElements.add(new ASN1OctetString(tokenizer.nextToken())); 1119 } 1120 1121 ASN1OctetString controlValue = 1122 new ASN1OctetString(new ASN1Sequence(attrElements).encode()); 1123 LDAPControl c = new LDAPControl(OID_LDAP_READENTRY_POSTREAD, true, 1124 controlValue); 1125 modifyOptions.getControls().add(c); 1126 } 1127 1128 // Set the connection options. 1129 connectionOptions.setSASLExternal(saslExternal.isPresent()); 1130 if(saslOptions.isPresent()) 1131 { 1132 LinkedList<String> values = saslOptions.getValues(); 1133 for(String saslOption : values) 1134 { 1135 if(saslOption.startsWith("mech=")) 1136 { 1137 boolean val = connectionOptions.setSASLMechanism(saslOption); 1138 if(val == false) 1139 { 1140 return 1; 1141 } 1142 } else 1143 { 1144 boolean val = connectionOptions.addSASLProperty(saslOption); 1145 if(val == false) 1146 { 1147 return 1; 1148 } 1149 } 1150 } 1151 } 1152 1153 connectionOptions.setUseSSL(useSSL.isPresent()); 1154 connectionOptions.setStartTLS(startTLS.isPresent()); 1155 connectionOptions.setReportAuthzID(reportAuthzID.isPresent()); 1156 1157 if(connectionOptions.useSASLExternal()) 1158 { 1159 if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS()) 1160 { 1161 Message message = ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get(); 1162 err.println(wrapText(message, MAX_LINE_WIDTH)); 1163 return 1; 1164 } 1165 if(keyStorePathValue == null) 1166 { 1167 Message message = ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get(); 1168 err.println(wrapText(message, MAX_LINE_WIDTH)); 1169 return 1; 1170 } 1171 } 1172 1173 connectionOptions.setVerbose(verbose.isPresent()); 1174 1175 LDAPModify ldapModify = null; 1176 try 1177 { 1178 if (initializeServer) 1179 { 1180 // Bootstrap and initialize directory data structures. 1181 EmbeddedUtils.initializeForClientUse(); 1182 } 1183 1184 // Connect to the specified host with the supplied userDN and password. 1185 SSLConnectionFactory sslConnectionFactory = null; 1186 if(connectionOptions.useSSL() || connectionOptions.useStartTLS()) 1187 { 1188 String clientAlias; 1189 if (certNickname.isPresent()) 1190 { 1191 clientAlias = certNickname.getValue(); 1192 } 1193 else 1194 { 1195 clientAlias = null; 1196 } 1197 1198 sslConnectionFactory = new SSLConnectionFactory(); 1199 sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue, 1200 keyStorePasswordValue, clientAlias, 1201 trustStorePathValue, trustStorePasswordValue); 1202 connectionOptions.setSSLConnectionFactory(sslConnectionFactory); 1203 } 1204 1205 AtomicInteger nextMessageID = new AtomicInteger(1); 1206 connection = new LDAPConnection(hostNameValue, portNumber, 1207 connectionOptions, out, err); 1208 connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID); 1209 1210 ldapModify = new LDAPModify(fileNameValue, nextMessageID, out, err); 1211 ldapModify.readAndExecute(connection, fileNameValue, modifyOptions); 1212 } catch(LDAPException le) 1213 { 1214 if (debugEnabled()) 1215 { 1216 TRACER.debugCaught(DebugLogLevel.ERROR, le); 1217 } 1218 LDAPToolUtils.printErrorMessage(err, le.getMessageObject(), 1219 le.getResultCode(), 1220 le.getErrorMessage(), le.getMatchedDN()); 1221 int code = le.getResultCode(); 1222 return code; 1223 } catch(LDAPConnectionException lce) 1224 { 1225 if (debugEnabled()) 1226 { 1227 TRACER.debugCaught(DebugLogLevel.ERROR, lce); 1228 } 1229 LDAPToolUtils.printErrorMessage(err, lce.getMessageObject(), 1230 lce.getResultCode(), 1231 lce.getErrorMessage(), 1232 lce.getMatchedDN()); 1233 int code = lce.getResultCode(); 1234 return code; 1235 } catch(Exception e) 1236 { 1237 if (debugEnabled()) 1238 { 1239 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1240 } 1241 err.println(wrapText(e.getMessage(), MAX_LINE_WIDTH)); 1242 return 1; 1243 } finally 1244 { 1245 if(connection != null) 1246 { 1247 if (ldapModify == null) 1248 { 1249 connection.close(null); 1250 } 1251 else 1252 { 1253 connection.close(ldapModify.nextMessageID); 1254 } 1255 } 1256 } 1257 return 0; 1258 } 1259 1260 } 1261