mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
31.31.2006 57a1a2d18386d01af5a3f6d72e63afe2b2954c71
Update a number of the client-side tools provided with OpenDS to ensure that
they use consistently incrementing message IDs for requests sent to the server.
In at least one case, it was possible for the same message ID to be used by the
client for two consecutive requests, which could trigger a race condition that
caused the server to refuse the second request.

Note that the underlying race condition still exists in the Directory Server
and will need to be addressed through a separate set of changes.

Reviwed By: David Page
OpenDS Issue Number: 614
7 files modified
173 ■■■■■ changed files
opends/src/server/org/opends/server/tools/LDAPCompare.java 29 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPConnection.java 33 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPDelete.java 31 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPModify.java 23 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPPasswordModify.java 26 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPSearch.java 23 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/StopDS.java 8 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPCompare.java
@@ -34,6 +34,7 @@
import java.text.ParseException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import org.opends.server.protocols.asn1.ASN1Element;
import org.opends.server.protocols.asn1.ASN1Exception;
@@ -76,12 +77,19 @@
      "org.opends.server.tools.LDAPCompare";
  // The message ID counter to use for requests.
  private AtomicInteger nextMessageID;
  /**
   * Constructor for the LDAPCompare object.
   *
   * @param  nextMessageID  The message ID counter to use for requests.
   */
  public LDAPCompare()
  public LDAPCompare(AtomicInteger nextMessageID)
  {
    this.nextMessageID = nextMessageID;
  }
  /**
@@ -103,12 +111,10 @@
                             LDAPCompareOptions compareOptions)
         throws IOException, LDAPException
  {
    int messageID = 1;
    for(String line : lines)
    {
      executeCompare(connection, attributeType, attributeVal, line,
                     messageID, compareOptions);
      messageID++;
                     compareOptions);
    }
  }
@@ -133,15 +139,13 @@
                             LDAPCompareOptions compareOptions)
         throws IOException, LDAPException
  {
    int messageID = 1;
    BufferedReader in = new BufferedReader(reader);
    String line = null;
    while ((line = in.readLine()) != null)
    {
      executeCompare(connection, attributeType, attributeVal, line,
                     messageID, compareOptions);
      messageID++;
                     compareOptions);
    }
    in.close();
  }
@@ -154,7 +158,6 @@
   * @param attributeType   The attribute type to compare.
   * @param attributeVal    The attribute value to compare.
   * @param line            The DN to compare attribute in.
   * @param messageID       The messageID for the request.
   * @param compareOptions  The constraints for the compare request.
   *
   * @throws  IOException  If a problem occurs while communicating with the
@@ -163,7 +166,7 @@
   * @throws  LDAPException  If the server returns an error response.
   */
  private void executeCompare(LDAPConnection connection, String attributeType,
                              byte[] attributeVal, String line, int messageID,
                              byte[] attributeVal, String line,
                              LDAPCompareOptions compareOptions)
          throws IOException, LDAPException
  {
@@ -183,7 +186,8 @@
      LDAPMessage responseMessage = null;
      try
      {
        LDAPMessage message = new LDAPMessage(messageID, protocolOp, controls);
        LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(),
                                              protocolOp, controls);
        int numBytes =
              connection.getASN1Writer().writeElement(message.encode());
        ASN1Element element = connection.getASN1Reader().readElement();
@@ -651,12 +655,13 @@
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
      AtomicInteger nextMessageID = new AtomicInteger(1);
      connection = new LDAPConnection(hostNameValue, portNumber,
                                      connectionOptions);
      connection.connectToHost(bindDNValue, bindPasswordValue);
      connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
      LDAPCompare ldapCompare = new LDAPCompare();
      LDAPCompare ldapCompare = new LDAPCompare(nextMessageID);
      if(fileNameValue == null && dnStrings.isEmpty())
      {
        // Read from stdin.
opends/src/server/org/opends/server/tools/LDAPConnection.java
@@ -99,19 +99,37 @@
   * Connects to the directory server instance running on specified hostname
   * and port number.
   *
   * @param bindDN               The DN to bind with.
   *
   * @param bindPassword         The password to bind with.
   * @param  bindDN        The DN to bind with.
   * @param  bindPassword  The password to bind with.
   *
   * @throws  LDAPConnectionException  If a problem occurs while attempting to
   *                                   establish the connection to the server.
   */
  public void connectToHost(String bindDN, String bindPassword)
         throws LDAPConnectionException
  {
    connectToHost(bindDN, bindPassword, new AtomicInteger(1));
  }
  /**
   * Connects to the directory server instance running on specified hostname
   * and port number.
   *
   * @param  bindDN         The DN to bind with.
   * @param  bindPassword   The password to bind with.
   * @param  nextMessageID  The message ID counter that should be used for
   *                        operations performed while establishing the
   *                        connection.
   *
   * @throws  LDAPConnectionException  If a problem occurs while attempting to
   *                                   establish the connection to the server.
   */
  public void connectToHost(String bindDN, String bindPassword,
                            AtomicInteger nextMessageID)
                            throws LDAPConnectionException
  {
    Socket socket = null;
    Socket startTLSSocket = null;
    int messageID = 1;
    int resultCode = -1;
    ArrayList<LDAPControl> requestControls = new ArrayList<LDAPControl> ();
    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl> ();
@@ -143,11 +161,11 @@
      ExtendedRequestProtocolOp extendedRequest =
           new ExtendedRequestProtocolOp(OID_START_TLS_REQUEST);
      LDAPMessage msg = new LDAPMessage(messageID, extendedRequest);
      LDAPMessage msg = new LDAPMessage(nextMessageID.getAndIncrement(),
                                        extendedRequest);
      try
      {
        asn1Writer.writeElement(msg.encode());
        messageID++;
        // Read the response from the server.
        msg = LDAPMessage.decode(asn1Reader.readElement().decodeAsSequence());
@@ -216,8 +234,7 @@
    }
    LDAPAuthenticationHandler handler = new LDAPAuthenticationHandler(
            asn1Reader, asn1Writer, hostName,
            new AtomicInteger(messageID));
            asn1Reader, asn1Writer, hostName, nextMessageID);
    try
    {
      ASN1OctetString bindPW;
opends/src/server/org/opends/server/tools/LDAPDelete.java
@@ -33,6 +33,7 @@
import java.io.Reader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1Element;
@@ -71,12 +72,21 @@
   */
  private static final String CLASS_NAME = "org.opends.server.tools.LDAPDelete";
  // The message ID counter to use for requests.
  private AtomicInteger nextMessageID;
  /**
   * Constructor for the LDAPDelete object.
   *
   * @param  nextMessageID  The next message ID to use for requests.
   */
  public LDAPDelete()
  public LDAPDelete(AtomicInteger nextMessageID)
  {
    this.nextMessageID = nextMessageID;
  }
  /**
@@ -96,11 +106,9 @@
                             LDAPDeleteOptions deleteOptions)
    throws IOException, LDAPException
  {
    int messageID = 1;
    for(String line : lines)
    {
      executeDelete(connection, line, messageID, deleteOptions);
      messageID++;
      executeDelete(connection, line, deleteOptions);
    }
  }
@@ -121,14 +129,12 @@
                             LDAPDeleteOptions deleteOptions)
         throws IOException, LDAPException
  {
    int messageID = 1;
    BufferedReader in = new BufferedReader(reader);
    String line = null;
    while ((line = in.readLine()) != null)
    {
      executeDelete(connection, line, messageID, deleteOptions);
      messageID++;
      executeDelete(connection, line, deleteOptions);
    }
    in.close();
  }
@@ -139,7 +145,6 @@
   *
   * @param connection        The connection to use to execute the request.
   * @param line           The DN to delete.
   * @param messageID      The messageID for the request.
   * @param deleteOptions  The list of constraints for this request.
   *
   * @throws  IOException  If a problem occurs while attempting to communicate
@@ -148,7 +153,7 @@
   * @throws  LDAPException  If the Directory Server returns an error response.
   */
  private void executeDelete(LDAPConnection connection, String line,
                             int messageID, LDAPDeleteOptions deleteOptions)
                             LDAPDeleteOptions deleteOptions)
          throws IOException, LDAPException
  {
    ArrayList<LDAPControl> controls = deleteOptions.getControls();
@@ -160,7 +165,8 @@
    System.out.println(getMessage(msgID, "DELETE", asn1OctetStr));
    if(!deleteOptions.showOperations())
    {
      LDAPMessage message = new LDAPMessage(messageID, protocolOp, controls);
      LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(),
                                            protocolOp, controls);
      LDAPMessage responseMessage = null;
      try
      {
@@ -547,11 +553,12 @@
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
      AtomicInteger nextMessageID = new AtomicInteger(1);
      connection = new LDAPConnection(hostNameValue, portNumber,
                                      connectionOptions);
      connection.connectToHost(bindDNValue, bindPasswordValue);
      connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
      LDAPDelete ldapDelete = new LDAPDelete();
      LDAPDelete ldapDelete = new LDAPDelete(nextMessageID);
      if(fileNameValue == null && dnStrings.isEmpty())
      {
        // Read from stdin.
opends/src/server/org/opends/server/tools/LDAPModify.java
@@ -33,6 +33,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicInteger;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1Element;
@@ -89,16 +90,20 @@
   */
  private static final String CLASS_NAME = "org.opends.server.tools.LDAPModify";
  // The message ID counter to use for requests.
  private AtomicInteger nextMessageID;
  // The LDIF file name.
  private String fileName = null;
  /**
   * Constructor for the LDAPModify object.
   *
   * @param  fileName  The name of the file containing the LDIF data to use for
   *                   the modifications.
   * @param  fileName       The name of the file containing the LDIF data to use
   *                        for the modifications.
   * @param  nextMessageID  The message ID counter to use for requests.
   */
  public LDAPModify(String fileName)
  public LDAPModify(String fileName, AtomicInteger nextMessageID)
  {
    if(fileName == null)
    {
@@ -107,6 +112,8 @@
    {
      this.fileName = fileName;
    }
    this.nextMessageID = nextMessageID;
  }
@@ -144,10 +151,8 @@
      throw new IOException(message);
    }
    int messageID = 1;
    while (true)
    {
      messageID++;
      ChangeRecordEntry entry = null;
      try
@@ -286,7 +291,8 @@
        try
        {
          LDAPMessage message =
               new LDAPMessage(messageID, protocolOp, controls);
               new LDAPMessage(nextMessageID.getAndIncrement(), protocolOp,
                               controls);
          // int numBytes =
          connection.getASN1Writer().writeElement(message.encode());
          ASN1Element element = connection.getASN1Reader().readElement();
@@ -882,11 +888,12 @@
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
      AtomicInteger nextMessageID = new AtomicInteger(1);
      connection = new LDAPConnection(hostNameValue, portNumber,
                                      connectionOptions);
      connection.connectToHost(bindDNValue, bindPasswordValue);
      connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
      LDAPModify ldapModify = new LDAPModify(fileNameValue);
      LDAPModify ldapModify = new LDAPModify(fileNameValue, nextMessageID);
      InputStream is = System.in;
      if(fileNameValue != null)
      {
opends/src/server/org/opends/server/tools/LDAPPasswordModify.java
@@ -30,6 +30,7 @@
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1Element;
@@ -204,13 +205,15 @@
    // Send the LDAP bind request if appropriate.
    AtomicInteger nextMessageID = new AtomicInteger(1);
    if ((bindDN != null) && (bindDN.length() > 0) && (bindPW != null) &&
        (bindPW.length() > 0))
    {
      BindRequestProtocolOp bindRequest =
           new BindRequestProtocolOp(new ASN1OctetString(bindDN), 3,
                                     new ASN1OctetString(bindPW));
      LDAPMessage requestMessage = new LDAPMessage(1, bindRequest);
      LDAPMessage requestMessage =
           new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest);
      try
      {
@@ -274,7 +277,8 @@
        try
        {
          requestMessage = new LDAPMessage(2, new UnbindRequestProtocolOp());
          requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
                                           new UnbindRequestProtocolOp());
          writer.writeElement(requestMessage.encode());
        }
        catch (Exception e) {}
@@ -316,7 +320,8 @@
    ExtendedRequestProtocolOp extendedRequest =
         new ExtendedRequestProtocolOp(OID_PASSWORD_MODIFY_REQUEST,
                                       requestValue);
    LDAPMessage requestMessage = new LDAPMessage(2, extendedRequest);
    LDAPMessage requestMessage =
         new LDAPMessage(nextMessageID.getAndIncrement(), extendedRequest);
    // Send the request to the server and read the response.
@@ -331,7 +336,8 @@
      try
      {
        requestMessage = new LDAPMessage(2, new UnbindRequestProtocolOp());
        requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
                                         new UnbindRequestProtocolOp());
        writer.writeElement(requestMessage.encode());
      }
      catch (Exception e2) {}
@@ -360,7 +366,8 @@
      try
      {
        requestMessage = new LDAPMessage(2, new UnbindRequestProtocolOp());
        requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
                                         new UnbindRequestProtocolOp());
        writer.writeElement(requestMessage.encode());
      }
      catch (Exception e2) {}
@@ -398,7 +405,8 @@
      try
      {
        requestMessage = new LDAPMessage(3, new UnbindRequestProtocolOp());
        requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
                                         new UnbindRequestProtocolOp());
        writer.writeElement(requestMessage.encode());
      }
      catch (Exception e) {}
@@ -447,7 +455,8 @@
        try
        {
          requestMessage = new LDAPMessage(2, new UnbindRequestProtocolOp());
          requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
                                           new UnbindRequestProtocolOp());
          writer.writeElement(requestMessage.encode());
        }
        catch (Exception e2) {}
@@ -466,7 +475,8 @@
    // Unbind from the server and close the connection.
    try
    {
      requestMessage = new LDAPMessage(3, new UnbindRequestProtocolOp());
      requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
                                       new UnbindRequestProtocolOp());
      writer.writeElement(requestMessage.encode());
    }
    catch (Exception e) {}
opends/src/server/org/opends/server/tools/LDAPSearch.java
@@ -34,6 +34,7 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicInteger;
import org.opends.server.controls.AccountUsableResponseControl;
import org.opends.server.controls.EntryChangeNotificationControl;
@@ -87,12 +88,21 @@
   */
  private static final String CLASS_NAME = "org.opends.server.tools.LDAPSearch";
  // The message ID counter to use for requests.
  private AtomicInteger nextMessageID;
  /**
   * Constructor for the LDAPSearch object.
   *
   * @param  nextMessageID  The message ID counter to use for requests.
   */
  public LDAPSearch()
  public LDAPSearch(AtomicInteger nextMessageID)
  {
    this.nextMessageID = nextMessageID;
  }
@@ -118,11 +128,8 @@
                            int wrapColumn )
         throws IOException, LDAPException
  {
    int messageID = 1;
    for (LDAPFilter filter: filters)
    {
      messageID++;
      ASN1OctetString asn1OctetStr = new ASN1OctetString(baseDN);
      SearchRequestProtocolOp protocolOp =
@@ -135,7 +142,8 @@
      try
      {
        boolean typesOnly = searchOptions.getTypesOnly();
        LDAPMessage message = new LDAPMessage(messageID, protocolOp,
        LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(),
                                              protocolOp,
                                              searchOptions.getControls());
        int numBytes =
            connection.getASN1Writer().writeElement(message.encode());
@@ -1091,11 +1099,12 @@
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
      AtomicInteger nextMessageID = new AtomicInteger(1);
      connection = new LDAPConnection(hostNameValue, portNumber,
                                      connectionOptions);
      connection.connectToHost(bindDNValue, bindPasswordValue);
      connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
      LDAPSearch ldapSearch = new LDAPSearch();
      LDAPSearch ldapSearch = new LDAPSearch(nextMessageID);
      ldapSearch.executeSearch(connection, baseDNValue, filters, attributes,
                               searchOptions, wrapColumn);
opends/src/server/org/opends/server/tools/StopDS.java
@@ -35,6 +35,7 @@
import java.util.LinkedList;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.opends.server.controls.ProxiedAuthV2Control;
import org.opends.server.protocols.asn1.ASN1Element;
@@ -461,12 +462,14 @@
    // Attempt to connect and authenticate to the Directory Server.
    AtomicInteger nextMessageID = new AtomicInteger(1);
    LDAPConnection connection;
    try
    {
      connection = new LDAPConnection(host.getValue(), port.getIntValue(),
                                      connectionOptions);
      connection.connectToHost(bindDN.getValue(), bindPW.getValue());
      connection.connectToHost(bindDN.getValue(), bindPW.getValue(),
                               nextMessageID);
    }
    catch (ArgumentException ae)
    {
@@ -549,7 +552,8 @@
    AddRequestProtocolOp addRequest = new AddRequestProtocolOp(entryDN,
                                                               attributes);
    LDAPMessage requestMessage = new LDAPMessage(1, addRequest, controls);
    LDAPMessage requestMessage =
         new LDAPMessage(nextMessageID.getAndIncrement(), addRequest, controls);
    // Send the request to the server and read the response.