From fe4d6b1f8ee49c858ca2644851377ba2402d9509 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Thu, 25 Jul 2013 13:21:03 +0000
Subject: [PATCH] OPENDJ-948 (CR-1873) unauthorized disclosure of directory contents 

---
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java |  222 +++++++++++++++++++++++++++++++------------------------
 1 files changed, 125 insertions(+), 97 deletions(-)

diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index 0704a5c..910a7ed 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -70,8 +70,6 @@
    */
   private static final DebugTracer TRACER = getTracer();
 
-
-
   /**
    * The backend in which the target entry exists.
    */
@@ -295,40 +293,47 @@
     // Check for a request to cancel this operation.
     checkIfCanceled(false);
 
-    BooleanHolder executePostOpPlugins = new BooleanHolder(false);
-    processModify(executePostOpPlugins);
-
-    // If the password policy request control was included, then make sure we
-    // send the corresponding response control.
-    if (pwPolicyControlRequested)
+    try
     {
-      addResponseControl(new PasswordPolicyResponseControl(null, 0,
-                                                           pwpErrorType));
-    }
+      BooleanHolder executePostOpPlugins = new BooleanHolder(false);
+      processModify(executePostOpPlugins);
 
-    // Invoke the post-operation or post-synchronization modify plugins.
-    PluginConfigManager pluginConfigManager =
-        DirectoryServer.getPluginConfigManager();
-    if (isSynchronizationOperation())
-    {
-      if (getResultCode() == ResultCode.SUCCESS)
+      // If the password policy request control was included, then make sure we
+      // send the corresponding response control.
+      if (pwPolicyControlRequested)
       {
-        pluginConfigManager.invokePostSynchronizationModifyPlugins(this);
+        addResponseControl(new PasswordPolicyResponseControl(null, 0,
+            pwpErrorType));
+      }
+
+      // Invoke the post-operation or post-synchronization modify plugins.
+      PluginConfigManager pluginConfigManager =
+          DirectoryServer.getPluginConfigManager();
+      if (isSynchronizationOperation())
+      {
+        if (getResultCode() == ResultCode.SUCCESS)
+        {
+          pluginConfigManager.invokePostSynchronizationModifyPlugins(this);
+        }
+      }
+      else if (executePostOpPlugins.value)
+      {
+        // FIXME -- Should this also be done while holding the locks?
+        PluginResult.PostOperation postOpResult =
+            pluginConfigManager.invokePostOperationModifyPlugins(this);
+        if (!postOpResult.continueProcessing())
+        {
+          setResultCode(postOpResult.getResultCode());
+          appendErrorMessage(postOpResult.getErrorMessage());
+          setMatchedDN(postOpResult.getMatchedDN());
+          setReferralURLs(postOpResult.getReferralURLs());
+          return;
+        }
       }
     }
-    else if (executePostOpPlugins.value)
+    finally
     {
-      // FIXME -- Should this also be done while holding the locks?
-      PluginResult.PostOperation postOpResult =
-           pluginConfigManager.invokePostOperationModifyPlugins(this);
-      if (!postOpResult.continueProcessing())
-      {
-        setResultCode(postOpResult.getResultCode());
-        appendErrorMessage(postOpResult.getErrorMessage());
-        setMatchedDN(postOpResult.getMatchedDN());
-        setReferralURLs(postOpResult.getReferralURLs());
-        return;
-      }
+      LocalBackendWorkflowElement.filterNonDisclosableMatchedDN(this);
     }
 
 
@@ -407,16 +412,16 @@
 
     // Acquire a write lock on the target entry.
     final Lock entryLock = LockManager.lockWrite(entryDN);
-    if (entryLock == null)
-    {
-      setResultCode(ResultCode.BUSY);
-      appendErrorMessage(ERR_MODIFY_CANNOT_LOCK_ENTRY.get(String
-          .valueOf(entryDN)));
-      return;
-    }
 
     try
     {
+      if (entryLock == null)
+      {
+        setResultCodeAndMessageNoInfoDisclosure(currentEntry, ResultCode.BUSY,
+            ERR_MODIFY_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN)));
+        return;
+      }
+
       // Check for a request to cancel this operation.
       checkIfCanceled(false);
 
@@ -480,12 +485,9 @@
       // Create a duplicate of the entry and apply the changes to it.
       modifiedEntry = currentEntry.duplicate(false);
 
-      if (!noOp)
+      if (!noOp && !handleConflictResolution())
       {
-        if (!handleConflictResolution())
-        {
-          return;
-        }
+        return;
       }
 
       handleSchemaProcessing();
@@ -505,9 +507,10 @@
         if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
             .isAllowed(this))
         {
-          setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-          appendErrorMessage(ERR_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS
-              .get(String.valueOf(entryDN)));
+          setResultCodeAndMessageNoInfoDisclosure(modifiedEntry,
+              ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+              ERR_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String
+                  .valueOf(entryDN)));
           return;
         }
       }
@@ -620,15 +623,33 @@
       }
 
       setResponseData(de);
-      return;
     }
     finally
     {
-      LockManager.unlock(entryDN, entryLock);
+      if (entryLock != null)
+      {
+        LockManager.unlock(entryDN, entryLock);
+      }
       processSynchPostOperationPlugins();
     }
   }
 
+  private DirectoryException newDirectoryException(Entry entry,
+      ResultCode resultCode, Message message) throws DirectoryException
+  {
+    return LocalBackendWorkflowElement.newDirectoryException(this, entry, null,
+        resultCode, message, ResultCode.NO_SUCH_OBJECT,
+        ERR_MODIFY_NO_SUCH_ENTRY.get(String.valueOf(entryDN)));
+  }
+
+  private void setResultCodeAndMessageNoInfoDisclosure(Entry entry,
+      ResultCode realResultCode, Message realMessage) throws DirectoryException
+  {
+    LocalBackendWorkflowElement.setResultCodeAndMessageNoInfoDisclosure(this,
+        entry, null, realResultCode, realMessage, ResultCode.NO_SUCH_OBJECT,
+        ERR_MODIFY_NO_SUCH_ENTRY.get(String.valueOf(entryDN)));
+  }
+
   private DN findMatchedDN(DN entryDN)
   {
     try
@@ -694,7 +715,7 @@
               TRACER.debugCaught(DebugLogLevel.ERROR, de);
             }
 
-            throw new DirectoryException(de.getResultCode(),
+            throw newDirectoryException(currentEntry, de.getResultCode(),
                            ERR_MODIFY_CANNOT_PROCESS_ASSERTION_FILTER.get(
                                 String.valueOf(entryDN),
                                 de.getMessageObject()));
@@ -714,9 +735,9 @@
           {
             if (!filter.matchesEntry(currentEntry))
             {
-              throw new DirectoryException(ResultCode.ASSERTION_FAILED,
-                  ERR_MODIFY_ASSERTION_FAILED.get(String
-                      .valueOf(entryDN)));
+              throw newDirectoryException(currentEntry,
+                  ResultCode.ASSERTION_FAILED,
+                  ERR_MODIFY_ASSERTION_FAILED.get(String.valueOf(entryDN)));
             }
           }
           catch (DirectoryException de)
@@ -731,7 +752,7 @@
               TRACER.debugCaught(DebugLogLevel.ERROR, de);
             }
 
-            throw new DirectoryException(de.getResultCode(),
+            throw newDirectoryException(currentEntry, de.getResultCode(),
                            ERR_MODIFY_CANNOT_PROCESS_ASSERTION_FILTER.get(
                                 String.valueOf(entryDN),
                                 de.getMessageObject()));
@@ -825,7 +846,7 @@
         {
           if ((backend == null) || (! backend.supportsControl(oid)))
           {
-            throw new DirectoryException(
+            throw newDirectoryException(currentEntry,
                            ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
                            ERR_MODIFY_UNSUPPORTED_CRITICAL_CONTROL.get(
                                 String.valueOf(entryDN), oid));
@@ -858,8 +879,9 @@
         if (! (isInternalOperation() || isSynchronizationOperation() ||
                 m.isInternal()))
         {
-          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
-                  ERR_MODIFY_ATTR_IS_NO_USER_MOD.get(
+          throw newDirectoryException(currentEntry,
+              ResultCode.CONSTRAINT_VIOLATION,
+              ERR_MODIFY_ATTR_IS_NO_USER_MOD.get(
                           String.valueOf(entryDN), a.getName()));
         }
       }
@@ -875,8 +897,9 @@
           if (! (isInternalOperation() || isSynchronizationOperation() ||
                   m.isInternal()))
           {
-            throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
-                    ERR_MODIFY_ATTR_IS_OBSOLETE.get(
+            throw newDirectoryException(currentEntry,
+                ResultCode.CONSTRAINT_VIOLATION,
+                ERR_MODIFY_ATTR_IS_OBSOLETE.get(
                             String.valueOf(entryDN), a.getName()));
           }
         }
@@ -1379,7 +1402,7 @@
     // attribute.
     if (attr.isEmpty())
     {
-      throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+      throw newDirectoryException(currentEntry, ResultCode.PROTOCOL_ERROR,
           ERR_MODIFY_ADD_NO_VALUES.get(String.valueOf(entryDN),
               attr.getName()));
     }
@@ -1403,15 +1426,17 @@
             if (!syntax.isHumanReadable() || syntax.isBinary())
             {
               // Value is not human-readable
-              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
-                ERR_MODIFY_ADD_INVALID_SYNTAX_NO_VALUE.get(
-                    String.valueOf(entryDN), attr.getName(), invalidReason));
+              throw newDirectoryException(currentEntry,
+                  ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+                  ERR_MODIFY_ADD_INVALID_SYNTAX_NO_VALUE.get(
+                      String.valueOf(entryDN), attr.getName(), invalidReason));
             }
             else
             {
-              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
-                ERR_MODIFY_ADD_INVALID_SYNTAX.get(String.valueOf(entryDN), attr
-                    .getName(), v.getValue().toString(), invalidReason));
+              throw newDirectoryException(currentEntry,
+                  ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+                  ERR_MODIFY_ADD_INVALID_SYNTAX.get(String.valueOf(entryDN),
+                      attr.getName(), v.getValue().toString(), invalidReason));
             }
           }
         }
@@ -1455,16 +1480,16 @@
     // Add the provided attribute or merge an existing attribute with
     // the values of the new attribute. If there are any duplicates,
     // then fail.
-    List<AttributeValue> duplicateValues =
-      new LinkedList<AttributeValue>();
+    List<AttributeValue> duplicateValues = new LinkedList<AttributeValue>();
     modifiedEntry.addAttribute(attr, duplicateValues);
     if (!duplicateValues.isEmpty() && !permissiveModify)
     {
       String duplicateValuesStr = collectionToString(duplicateValues, ", ");
 
-      throw new DirectoryException(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS,
-          ERR_MODIFY_ADD_DUPLICATE_VALUE.get(String.valueOf(entryDN), attr
-              .getName(), duplicateValuesStr));
+      throw newDirectoryException(currentEntry,
+          ResultCode.ATTRIBUTE_OR_VALUE_EXISTS,
+          ERR_MODIFY_ADD_DUPLICATE_VALUE.get(
+              String.valueOf(entryDN), attr.getName(), duplicateValuesStr));
     }
   }
 
@@ -1505,16 +1530,16 @@
       ObjectClass oc = DirectoryServer.getObjectClass(lowerName);
       if (oc == null)
       {
-        Message message = ERR_ENTRY_ADD_UNKNOWN_OC.get(name, String
-            .valueOf(entryDN));
-        throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
+        throw newDirectoryException(currentEntry,
+            ResultCode.OBJECTCLASS_VIOLATION,
+            ERR_ENTRY_ADD_UNKNOWN_OC.get(name, String.valueOf(entryDN)));
       }
 
       if (oc.isObsolete())
       {
-        Message message = ERR_ENTRY_ADD_OBSOLETE_OC.get(name, String
-            .valueOf(entryDN));
-        throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
+        throw newDirectoryException(currentEntry,
+            ResultCode.CONSTRAINT_VIOLATION,
+            ERR_ENTRY_ADD_OBSOLETE_OC.get(name, String.valueOf(entryDN)));
       }
     }
   }
@@ -1551,10 +1576,10 @@
             (! modifiedEntry.hasValue(t, attr.getOptions(),
                                       rdn.getAttributeValue(t))))
         {
-          throw new DirectoryException(ResultCode.NOT_ALLOWED_ON_RDN,
-                                       ERR_MODIFY_DELETE_RDN_ATTR.get(
-                                            String.valueOf(entryDN),
-                                            attr.getName()));
+          throw newDirectoryException(currentEntry,
+              ResultCode.NOT_ALLOWED_ON_RDN,
+              ERR_MODIFY_DELETE_RDN_ATTR.get(
+                  String.valueOf(entryDN), attr.getName()));
         }
       }
       else
@@ -1563,10 +1588,10 @@
         {
           String missingValuesStr = collectionToString(missingValues, ", ");
 
-          throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
-                       ERR_MODIFY_DELETE_MISSING_VALUES.get(
-                            String.valueOf(entryDN), attr.getName(),
-                            missingValuesStr));
+          throw newDirectoryException(currentEntry,
+              ResultCode.NO_SUCH_ATTRIBUTE,
+              ERR_MODIFY_DELETE_MISSING_VALUES.get(
+                  String.valueOf(entryDN), attr.getName(), missingValuesStr));
         }
       }
     }
@@ -1574,7 +1599,7 @@
     {
       if (! permissiveModify)
       {
-        throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
+        throw newDirectoryException(currentEntry, ResultCode.NO_SUCH_ATTRIBUTE,
                      ERR_MODIFY_DELETE_NO_SUCH_ATTR.get(
                           String.valueOf(entryDN), attr.getName()));
       }
@@ -1615,15 +1640,17 @@
             if (!syntax.isHumanReadable() || syntax.isBinary())
             {
               // Value is not human-readable
-              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
-                ERR_MODIFY_REPLACE_INVALID_SYNTAX_NO_VALUE.get(
-                    String.valueOf(entryDN), attr.getName(), invalidReason));
+              throw newDirectoryException(currentEntry,
+                  ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+                  ERR_MODIFY_REPLACE_INVALID_SYNTAX_NO_VALUE.get(
+                      String.valueOf(entryDN), attr.getName(), invalidReason));
             }
             else
             {
-              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
-                ERR_MODIFY_REPLACE_INVALID_SYNTAX.get(String.valueOf(entryDN),
-                    attr.getName(), v.getValue().toString(), invalidReason));
+              throw newDirectoryException(currentEntry,
+                  ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+                  ERR_MODIFY_REPLACE_INVALID_SYNTAX.get(String.valueOf(entryDN),
+                      attr.getName(), v.getValue().toString(), invalidReason));
             }
           }
         }
@@ -1673,7 +1700,7 @@
         && (!modifiedEntry.hasValue(t, attr.getOptions(), rdn
             .getAttributeValue(t))))
     {
-      throw new DirectoryException(ResultCode.NOT_ALLOWED_ON_RDN,
+      throw newDirectoryException(modifiedEntry, ResultCode.NOT_ALLOWED_ON_RDN,
           ERR_MODIFY_DELETE_RDN_ATTR.get(String.valueOf(entryDN), attr
               .getName()));
     }
@@ -1699,7 +1726,7 @@
     RDN rdn = modifiedEntry.getDN().getRDN();
     if ((rdn != null) && rdn.hasAttributeType(t))
     {
-      throw new DirectoryException(ResultCode.NOT_ALLOWED_ON_RDN,
+      throw newDirectoryException(modifiedEntry, ResultCode.NOT_ALLOWED_ON_RDN,
           ERR_MODIFY_INCREMENT_RDN.get(String.valueOf(entryDN),
               attr.getName()));
     }
@@ -1708,14 +1735,14 @@
     // an integer.
     if (attr.isEmpty())
     {
-      throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+      throw newDirectoryException(modifiedEntry, ResultCode.PROTOCOL_ERROR,
           ERR_MODIFY_INCREMENT_REQUIRES_VALUE.get(String.valueOf(entryDN), attr
               .getName()));
     }
 
     if (attr.size() > 1)
     {
-      throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+      throw newDirectoryException(modifiedEntry, ResultCode.PROTOCOL_ERROR,
           ERR_MODIFY_INCREMENT_REQUIRES_SINGLE_VALUE.get(String
               .valueOf(entryDN), attr.getName()));
     }
@@ -1743,7 +1770,8 @@
     Attribute a = modifiedEntry.getExactAttribute(t, attr.getOptions());
     if (a == null)
     {
-      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+      throw newDirectoryException(modifiedEntry,
+          ResultCode.CONSTRAINT_VIOLATION,
           ERR_MODIFY_INCREMENT_REQUIRES_EXISTING_VALUE.get(String
               .valueOf(entryDN), attr.getName()));
     }
@@ -2110,8 +2138,8 @@
               SynchronizationProviderResult result =
                   provider.handleConflictResolution(this);
               if (! result.continueProcessing()) {
-                  setResultCode(result.getResultCode());
-                  appendErrorMessage(result.getErrorMessage());
+                  setResultCodeAndMessageNoInfoDisclosure(modifiedEntry,
+                      result.getResultCode(), result.getErrorMessage());
                   setMatchedDN(result.getMatchedDN());
                   setReferralURLs(result.getReferralURLs());
                   returnVal = false;

--
Gitblit v1.10.0