From 4e2366ebec6d1c05a9c22e7d01e010ee4dea45fc Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Wed, 06 Jun 2007 21:49:10 +0000
Subject: [PATCH] Put server into lockdown mode if ACI parsing fails during server startup or backend initialization. Issue #1750.

---
 opends/src/server/org/opends/server/authorization/dseecompat/AciList.java            |   73 ++++++----
 opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java |  161 ++++++++++++++++++++--
 opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java         |   70 +++++----
 opends/src/server/org/opends/server/messages/AciMessages.java                        |   38 ++++
 opends/src/server/org/opends/server/util/ServerConstants.java                        |   24 +++
 5 files changed, 287 insertions(+), 79 deletions(-)

diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index 274dd86..134262c 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -29,21 +29,22 @@
 
 import org.opends.server.admin.std.server.DseeCompatAccessControlHandlerCfg;
 import org.opends.server.api.AccessControlHandler;
-import static org.opends.server.messages.AciMessages.*;
 import static org.opends.server.authorization.dseecompat.Aci.*;
+import static org.opends.server.config.ConfigConstants.ATTR_AUTHZ_GLOBAL_ACI;
 import org.opends.server.core.*;
 import static org.opends.server.loggers.ErrorLogger.logError;
-import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
 import org.opends.server.loggers.debug.DebugTracer;
+import static org.opends.server.messages.AciMessages.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
-import org.opends.server.types.*;
-import static org.opends.server.util.StaticUtils.toLowerCase;
-import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
-import static org.opends.server.config.ConfigConstants.*;
-import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
-import static org.opends.server.schema.SchemaConstants.*;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import static org.opends.server.schema.SchemaConstants.SYNTAX_DN_OID;
+import org.opends.server.types.*;
 import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import static org.opends.server.util.StaticUtils.toLowerCase;
 
 import java.util.*;
 import java.util.concurrent.locks.Lock;
@@ -52,19 +53,26 @@
  * The AciHandler class performs the main processing for the
  * dseecompat package.
  */
-public class AciHandler extends AccessControlHandler
-{
+public class AciHandler extends AccessControlHandler {
   /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
 
+
     /*
      * The list that holds that ACIs keyed by the DN of the entry
-      * holding the ACI.
+     * holding the ACI.
      */
     private AciList aciList;
 
+    /*
+     * The listener that handles ACI changes caused by LDAP operations, ACI
+     * decode failure alert logging and backend initialization ACI list
+     * adjustment.
+     */
+    private AciListenerManager aciListenerMgr;
+
     /**
      * Attribute type corresponding to "aci" attribute.
      */
@@ -95,21 +103,15 @@
      */
      public static String ALL_ATTRS_MATCHED = "allAttrsMatched";
 
-
     /**
      * This constructor instantiates the ACI handler class that performs the
      * main processing for the dseecompat ACI package. It does the following
      * initializations:
      *
+     *
      *  - Instantiates the ACI list cache.
      *
-     *  - Instantiates and registers the change notification listener that is
-     *    used to manage the ACI list cache after ACI modifications have been
-     *    performed.
-     *
-     *  - Instantiates and registers the backend initialization listener that is
-     *    used to manage the ACI list cache when backends are
-     *    initialized/finalized.
+     *  - Instantiates thr AciListenerManager.
      *
      *  - Processes all global attribute types found in the configuration entry
      *    and adds them to the ACI list cache.
@@ -124,11 +126,9 @@
     */
     public AciHandler(DseeCompatAccessControlHandlerCfg configuration)
     throws InitializationException  {
-        aciList = new AciList(configuration.dn());
-        AciListenerManager aciListenerMgr =
-            new AciListenerManager(aciList);
-        DirectoryServer.registerChangeNotificationListener(aciListenerMgr);
-        DirectoryServer.registerBackendInitializationListener(aciListenerMgr);
+        DN configurationDN=configuration.dn();
+        aciList = new AciList(configurationDN);
+        aciListenerMgr = new AciListenerManager(aciList, configurationDN);
         if((aciType = DirectoryServer.getAttributeType("aci")) == null)
             aciType = DirectoryServer.getDefaultAttributeType("aci");
         if((globalAciType =
@@ -143,7 +143,9 @@
      * Process all global ACI attribute types found in the configuration
      * entry and adds them to that ACI list cache. It also logs messages about
      * the number of ACI attribute types added to the cache. This method is
-     * called once at startup.
+     * called once at startup.  It also will put the server into  lockdown
+     * mode if needed.
+     *
      * @param configuration   The config handler containing the ACI
      *  configuration information.
      * @throws InitializationException If there is an error reading
@@ -153,6 +155,7 @@
         DseeCompatAccessControlHandlerCfg configuration)
     throws InitializationException {
         int msgID;
+        LinkedList<String>failedACIMsgs=new LinkedList<String>();
         SortedSet<String> globalAci = configuration.getGlobalACI();
         try {
             if (globalAci != null)   {
@@ -167,7 +170,9 @@
                         attVals);
                 Entry e = new Entry(configuration.dn(), null, null, null);
                 e.addAttribute(attr, new ArrayList<AttributeValue>());
-                int aciCount =  aciList.addAci(e, false, true);
+                int aciCount =  aciList.addAci(e, false, true, failedACIMsgs);
+                if(!failedACIMsgs.isEmpty())
+                    aciListenerMgr.logMsgsSetLockDownMode(failedACIMsgs);
                 msgID  = MSGID_ACI_ADD_LIST_GLOBAL_ACIS;
                 String message = getMessage(msgID, Integer.toString(aciCount));
                 logError(ErrorLogCategory.ACCESS_CONTROL,
@@ -194,7 +199,9 @@
     /**
      * Process all ACIs under the "cn=config" naming context and adds them to
      * the ACI list cache. It also logs messages about the number of ACIs added
-     * to the cache. This method is called once at startup.
+     * to the cache. This method is called once at startup.  It will put the
+     * server in lockdown mode if needed.
+     *
      * @throws InitializationException If there is an error searching for
      * the ACIs in the naming context.
      */
@@ -204,6 +211,7 @@
             DN configDN=DN.decode("cn=config");
             LinkedHashSet<String> attrs = new LinkedHashSet<String>(1);
             attrs.add("aci");
+            LinkedList<String>failedACIMsgs=new LinkedList<String>();
             InternalClientConnection conn =
                     InternalClientConnection.getRootConnection();
             InternalSearchOperation op = conn.processSearch(configDN,
@@ -216,7 +224,10 @@
                 logError(ErrorLogCategory.ACCESS_CONTROL,
                         ErrorLogSeverity.INFORMATIONAL, message, msgID);
             } else {
-                int validAcis = aciList.addAci(op.getSearchEntries());
+                int validAcis =
+                           aciList.addAci(op.getSearchEntries(), failedACIMsgs);
+                if(!failedACIMsgs.isEmpty())
+                    aciListenerMgr.logMsgsSetLockDownMode(failedACIMsgs);
                 int    msgID  = MSGID_ACI_ADD_LIST_ACIS;
                 String message = getMessage(msgID, Integer.toString(validAcis),
                         String.valueOf(configDN));
@@ -231,6 +242,7 @@
         }
     }
 
+
     /**
      * Checks to see if a LDAP modification is allowed access.
      *
@@ -372,7 +384,7 @@
      * @return  True if access is allowed.
      */
     private boolean testApplicableLists(AciEvalContext evalCtx) {
-        EnumEvalResult res=EnumEvalResult.FALSE;
+        EnumEvalResult res;
         evalCtx.setEvalReason(EnumEvalReason.NO_REASON);
         LinkedList<Aci>denys=evalCtx.getDenyList();
         LinkedList<Aci>allows=evalCtx.getAllowList();
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
index d472dc6..c8a720d 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
@@ -27,16 +27,16 @@
 
 package org.opends.server.authorization.dseecompat;
 
-import static org.opends.server.messages.AciMessages.*;
+import org.opends.server.api.Backend;
+import static org.opends.server.authorization.dseecompat.AciHandler.aciType;
+import static org.opends.server.authorization.dseecompat.AciHandler.globalAciType;
 import static org.opends.server.loggers.ErrorLogger.logError;
+import static org.opends.server.messages.AciMessages.MSGID_ACI_ADD_LIST_FAILED_DECODE;
 import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.types.*;
 
 import java.util.*;
 
-import static org.opends.server.authorization.dseecompat.AciHandler.*;
-import org.opends.server.types.*;
-import org.opends.server.api.Backend;
-
 /**
  * The AciList class performs caching of the ACI attribute values
  * using the entry DN as the key.
@@ -135,9 +135,12 @@
    * to check for global ACIs since they are processe by the AciHandler at
    * startup using the addACi single entry method.
    * @param entries The set of entries containing the "aci" attribute values.
+   * @param failedACIMsgs List that will hold error messages from ACI decode
+   *                      exceptions.
    * @return The number of valid ACI attribute values added to the ACI list.
    */
-  public synchronized int addAci(List<? extends Entry> entries)
+  public synchronized int addAci(List<? extends Entry> entries,
+                                 LinkedList<String> failedACIMsgs)
   {
     // Copy the ACI list.
     LinkedHashMap<DN,List<Aci>> aciCopy = copyList();
@@ -147,7 +150,8 @@
       DN dn=entry.getDN();
       List<Attribute> attributeList =
            entry.getOperationalAttribute(AciHandler.aciType);
-      validAcis += addAciAttributeList(aciCopy, dn, attributeList);
+      validAcis += addAciAttributeList(aciCopy, dn, configDN,
+                                       attributeList, failedACIMsgs);
     }
 
     // Replace the ACI list with the copy.
@@ -162,10 +166,13 @@
    * @param hasAci True if the "aci" attribute type was seen in the entry.
    * @param hasGlobalAci True if the "ds-cfg-global-aci" attribute type was
    * seen in the entry.
+   * @param failedACIMsgs List that will hold error messages from ACI decode
+   *                      exceptions.
    * @return The number of valid ACI attribute values added to the ACI list.
    */
   public synchronized int addAci(Entry entry,  boolean hasAci,
-                                               boolean hasGlobalAci) {
+                                 boolean hasGlobalAci,
+                                 LinkedList<String> failedACIMsgs) {
     int validAcis=0;
 
     // Copy the ACI list.
@@ -175,12 +182,14 @@
     //attributes are skipped.
     if(hasGlobalAci && entry.getDN().equals(configDN)) {
         List<Attribute> attributeList = entry.getAttribute(globalAciType);
-        validAcis = addAciAttributeList(aciCopy, DN.nullDN(), attributeList);
+        validAcis = addAciAttributeList(aciCopy, DN.nullDN(), configDN,
+                                        attributeList, failedACIMsgs);
     }
 
     if(hasAci) {
         List<Attribute> attributeList = entry.getAttribute(aciType);
-        validAcis += addAciAttributeList(aciCopy, entry.getDN(), attributeList);
+        validAcis += addAciAttributeList(aciCopy, entry.getDN(), configDN,
+                                         attributeList, failedACIMsgs);
     }
     // Replace the ACI list with the copy.
     aciList = aciCopy;
@@ -194,13 +203,18 @@
    * returned of the number of valid ACIs added.
    * @param aciList The ACI list to which the ACI is to be added.
    * @param dn The DN to use as the key in the ACI list.
+   * @param configDN The DN of the configuration entry used to configure the
+   *                 ACI handler. Used if a global ACI has an decode exception.
    * @param attributeList List of attributes containing the ACI attribute
    * values.
+   * @param failedACIMsgs List that will hold error messages from ACI decode
+   *                      exceptions.
    * @return The number of valid attribute values added to the ACI list.
    */
-  private static int addAciAttributeList(
-       LinkedHashMap<DN,List<Aci>> aciList, DN dn,
-       List<Attribute> attributeList) {
+  private static int addAciAttributeList(LinkedHashMap<DN,List<Aci>> aciList,
+                                         DN dn, DN configDN,
+                                         List<Attribute> attributeList,
+                                         LinkedList<String> failedACIMsgs) {
 
     if (attributeList == null) {
       return 0;
@@ -215,19 +229,16 @@
           acis.add(aci);
           validAcis++;
         } catch (AciException ex) {
-          /* An illegal ACI might have been loaded
-           * during import and is failing at ACI handler
-           * initialization time. Log a message and continue
-           * processing. ACIs added via LDAP add have their
-           * syntax checked before adding and should never
-           * hit this code.
-           */
           int    msgID  = MSGID_ACI_ADD_LIST_FAILED_DECODE;
-          String message = getMessage(msgID,
-                                      ex.getMessage());
-          logError(ErrorLogCategory.ACCESS_CONTROL,
-                   ErrorLogSeverity.INFORMATIONAL,
-                   message, msgID);
+          DN msgDN=dn;
+          if(dn == DN.nullDN()) {
+            msgDN=configDN;
+          }
+            String t=value.getValue().toString();
+          String message = getMessage(msgID, value.getValue().toString(),
+                                            String.valueOf(msgDN),
+                                            ex.getMessage());
+          failedACIMsgs.add(message);
         }
       }
     }
@@ -255,12 +266,14 @@
 
       // Copy the ACI list.
       LinkedHashMap<DN,List<Aci>> aciCopy = copyList();
+      LinkedList<String>failedACIMsgs=new LinkedList<String>();
       //Process "aci" attribute types.
       if(hasAci) {
           aciCopy.remove(oldEntry.getDN());
           List<Attribute> attributeList =
                   newEntry.getOperationalAttribute(aciType);
-          addAciAttributeList(aciCopy,newEntry.getDN(),attributeList);
+          addAciAttributeList(aciCopy,newEntry.getDN(), configDN,
+                              attributeList, failedACIMsgs);
       }
       //Process global "ds-cfg-global-aci" attribute type. The oldentry
       //DN is checked to verify it is equal to the config DN. If not those
@@ -269,7 +282,8 @@
           aciCopy.remove(DN.nullDN());
           List<Attribute> attributeList =
                   newEntry.getAttribute(globalAciType);
-          addAciAttributeList(aciCopy, DN.nullDN(), attributeList);
+          addAciAttributeList(aciCopy, DN.nullDN(), configDN,
+                              attributeList, failedACIMsgs);
       }
       // Replace the ACI list with the copy.
       aciList = aciCopy;
@@ -376,8 +390,9 @@
             //ACI with a new DN is being made. Log a message if it does and
             //keep going.
             int    msgID  = MSGID_ACI_ADD_LIST_FAILED_DECODE;
-            String message = getMessage(msgID,
-                    ex.getMessage());
+            String message = getMessage(msgID, aci.toString(),
+                                        String.valueOf(relocateDN),
+                                        ex.getMessage());
             logError(ErrorLogCategory.ACCESS_CONTROL,
                     ErrorLogSeverity.INFORMATIONAL,
                     message, msgID);
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
index dbf1143..4e1e10b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -30,6 +30,7 @@
 import org.opends.server.api.ChangeNotificationListener;
 import org.opends.server.api.BackendInitializationListener;
 import org.opends.server.api.Backend;
+import org.opends.server.api.AlertGenerator;
 import org.opends.server.types.operation.PostResponseAddOperation;
 import org.opends.server.types.operation.PostResponseDeleteOperation;
 import org.opends.server.types.operation.PostResponseModifyOperation;
@@ -42,8 +43,12 @@
 import org.opends.server.types.*;
 import static org.opends.server.messages.AciMessages.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.core.DirectoryServer;
+import static org.opends.server.util.ServerConstants.*;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.LinkedList;
+import java.util.LinkedHashMap;
 
 /**
  * The AciListenerManager updates an ACI list after each
@@ -51,13 +56,31 @@
  * and finalized.
  */
 public class AciListenerManager
-        implements ChangeNotificationListener, BackendInitializationListener {
+        implements ChangeNotificationListener, BackendInitializationListener,
+                   AlertGenerator {
   /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
 
 
+    /**
+     * The fully-qualified name of this class.
+     */
+    private static final String CLASS_NAME =
+         "org.opends.server.authorization.dseecompat.AciListenerManager";
+
+    /*
+     *  The configuration DN.
+     */
+    private DN configurationDN;
+
+
+    /*
+     *  True if the server is in lockdown mode.
+     */
+    private boolean inLockDownMode=false;
+
     /*
      * The AciList caches the ACIs.
      */
@@ -87,11 +110,23 @@
     }
 
     /**
-     * Save the list created by the AciHandler routine.
+     * Save the list created by the AciHandler routine. Registers as an
+     * Alert Generator that can send alerts when the server is being put
+     * in lockdown  mode. Registers as backend initialization listener that is
+     * used to manage the ACI list cache when backends are
+     * initialized/finalized. Registers as a change notification listener that
+     * is used to manage the ACI list cache after ACI modifications have been
+     * performed.
+     *
      * @param aciList The list object created and loaded by the handler.
+     * @param cfgDN The DN of the access control configuration entry.
      */
-    public AciListenerManager(AciList aciList) {
+    public AciListenerManager(AciList aciList, DN cfgDN) {
         this.aciList=aciList;
+        this.configurationDN=cfgDN;
+        DirectoryServer.registerChangeNotificationListener(this);
+        DirectoryServer.registerBackendInitializationListener(this);
+        DirectoryServer.registerAlertGenerator(this);
     }
 
     /**
@@ -118,10 +153,13 @@
     public void handleAddOperation(PostResponseAddOperation addOperation,
                                    Entry entry) {
         boolean hasAci, hasGlobalAci=false;
+        //Ignore this list, the ACI syntax has already passed and it should be
+        //empty.
+        LinkedList<String>failedACIMsgs=new LinkedList<String>();
         //This entry might have both global and aci attribute types.
         if((hasAci=entry.hasOperationalAttribute(AciHandler.aciType)) ||
                 (hasGlobalAci=entry.hasAttribute(AciHandler.globalAciType)))
-            aciList.addAci(entry, hasAci, hasGlobalAci);
+            aciList.addAci(entry, hasAci, hasGlobalAci, failedACIMsgs);
     }
 
     /**
@@ -176,18 +214,18 @@
     public void performBackendInitializationProcessing(Backend backend) {
       InternalClientConnection conn =
            InternalClientConnection.getRootConnection();
+      LinkedList<String>failedACIMsgs=new LinkedList<String>();
       for (DN baseDN : backend.getBaseDNs()) {
         try {
           if (! backend.entryExists(baseDN))  {
             continue;
           }
         } catch (Exception e) {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-          //TODO log message
-          continue;
+            if (debugEnabled())
+            {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+            }
+            continue;
         }
         InternalSearchOperation internalSearch =
              new InternalSearchOperation(
@@ -200,12 +238,11 @@
         try  {
           backend.search(internalSearch);
         } catch (Exception e) {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-          //TODO log message
-          continue;
+            if (debugEnabled())
+            {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+            }
+            continue;
         }
         if(internalSearch.getSearchEntries().isEmpty()) {
           int    msgID  = MSGID_ACI_ADD_LIST_NO_ACIS;
@@ -214,7 +251,9 @@
                    ErrorLogSeverity.INFORMATIONAL, message, msgID);
         } else {
           int validAcis = aciList.addAci(
-               internalSearch.getSearchEntries());
+               internalSearch.getSearchEntries(), failedACIMsgs);
+          if(!failedACIMsgs.isEmpty())
+                    logMsgsSetLockDownMode(failedACIMsgs);
           int    msgID  = MSGID_ACI_ADD_LIST_ACIS;
           String message = getMessage(msgID, Integer.toString(validAcis),
                                       String.valueOf(baseDN));
@@ -232,4 +271,92 @@
     public void performBackendFinalizationProcessing(Backend backend) {
         aciList.removeAci(backend);
     }
+
+
+
+    /**
+     * Retrieves the fully-qualified name of the Java class for this alert
+     * generator implementation.
+     *
+     * @return  The fully-qualified name of the Java class for this alert
+     *          generator implementation.
+     */
+    public String getClassName()
+    {
+        return CLASS_NAME;
+    }
+
+
+    /**
+     * Retrieves the DN of the configuration entry used to configure the
+     * handler.
+     *
+     * @return  The DN of the configuration entry containing the Access Control
+     *          configuration information.
+     */
+    public DN getComponentEntryDN()
+    {
+      return this.configurationDN;
+    }
+
+
+    /**
+     * Retrieves information about the set of alerts that this generator may
+     * produce.  The map returned should be between the notification type for a
+     * particular notification and the human-readable description for that
+     * notification.  This alert generator must not generate any alerts with
+     * types that are not contained in this list.
+     *
+     * @return  Information about the set of alerts that this generator may
+     *          produce.
+     */
+    public LinkedHashMap<String,String> getAlerts()
+    {
+        LinkedHashMap<String,String> alerts =
+                new LinkedHashMap<String,String>();
+        alerts.put(ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED,
+                ALERT_DESCRIPTION_ACCESS_CONTROL_PARSE_FAILED);
+        return alerts;
+
+    }
+
+    /**
+     * Log the exception messages from the failed ACI decode and then put the
+     * server in lockdown mode -- if needed.
+     *
+     * @param failedACIMsgs  List of exception messages from failed ACI decodes.
+     */
+    public  void logMsgsSetLockDownMode(LinkedList<String> failedACIMsgs) {
+        int msgID=MSGID_ACI_SERVER_DECODE_FAILED;
+        for(String msg : failedACIMsgs) {
+            String message=getMessage(msgID, msg);
+            logError(ErrorLogCategory.ACCESS_CONTROL,
+                    ErrorLogSeverity.SEVERE_ERROR,
+                    message, msgID);
+        }
+        if(!inLockDownMode)
+            setLockDownMode();
+    }
+
+
+    /**
+     * Send an MSGID_ACI_ENTER_LOCKDOWN_MODE alert notification and put the
+     * server in lockdown mode.
+     *
+     */
+    private void setLockDownMode() {
+        if(!inLockDownMode) {
+            inLockDownMode=true;
+            //Send ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED alert that
+            //lockdown is about to be entered.
+            int lockDownID=MSGID_ACI_ENTER_LOCKDOWN_MODE;
+            String lockDownMsg=getMessage(lockDownID);
+            DirectoryServer.sendAlertNotification(this,
+                    ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED,
+                    lockDownID, lockDownMsg );
+            //Enter lockdown mode.
+            DirectoryServer.setLockdownMode(true);
+
+        }
+    }
 }
diff --git a/opends/src/server/org/opends/server/messages/AciMessages.java b/opends/src/server/org/opends/server/messages/AciMessages.java
index 536d22f..722a2e0 100644
--- a/opends/src/server/org/opends/server/messages/AciMessages.java
+++ b/opends/src/server/org/opends/server/messages/AciMessages.java
@@ -496,8 +496,9 @@
      * The message ID for the ACI message that will be generated when
      * an ACI decode failed because of an syntax error. This message is usually
      * generated by an invalid ACI that was added during import which
-     * fails the decode at server startup. This takes one
-     * argument, which is the message string thrown by the AciException.
+     * fails the decode at server startup. This takes three
+     * argument, which are the ACI string, the DN of the entry containing the
+     * ACI, and the message string thrown by the AciException.
      */
     public static final int MSGID_ACI_ADD_LIST_FAILED_DECODE =
         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 48;
@@ -764,6 +765,25 @@
   public static final int MSGID_ACI_SYNTAX_ROLEDN_NOT_SUPPORTED =
        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 76;
 
+   /**
+   * The message ID for the message that will be used if there are ACI decode
+   * failures at server initialization time or during a backend initialization.
+   * This takes one argument, which is the error message from the ACI decode
+   * exception.
+   */
+  public static final int MSGID_ACI_SERVER_DECODE_FAILED =
+       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 77;
+
+
+   /**
+   * The message ID for the message that will be used if there are ACI decode
+   * failures at server initialization time or during a backend initialization
+   * causing the server is being put in lockdown mode. The takes no arguments.
+   */
+  public static final int MSGID_ACI_ENTER_LOCKDOWN_MODE =
+       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 78;
+
+
     /**
      * Associates a set of generic messages with the message IDs defined in
      * this class.
@@ -1066,8 +1086,8 @@
                "because of the following reason: %s");
 
         registerMessage(MSGID_ACI_ADD_LIST_FAILED_DECODE,
-                "An attempt to decode an Access Control Instruction (ACI)" +
-                " failed because of the following reason: %s");
+                " \"%s\", located in the entry \"%s\", " +
+                "because of the following reason: %s");
 
         registerMessage(MSGID_ACI_ADD_LIST_NO_ACIS,
                 "No Access Control Instruction (ACI) attribute types were" +
@@ -1203,5 +1223,15 @@
               "value \"%s\" is invalid because it contains" +
               " the roledn keyword, which is not supported,  replace it with " +
               "the groupdn keyword");
+
+        registerMessage(MSGID_ACI_SERVER_DECODE_FAILED,
+                "Failed to decode the Access Control " +
+                "Instruction (ACI)%s");
+
+        registerMessage(MSGID_ACI_ENTER_LOCKDOWN_MODE,
+                "The server is being put into lockdown mode because " +
+                "invalid ACIs rules were detected either when the server " +
+                "was started or during a backend initialization");
+
     }
 }
diff --git a/opends/src/server/org/opends/server/util/ServerConstants.java b/opends/src/server/org/opends/server/util/ServerConstants.java
index 74178c8..c61045d 100644
--- a/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -1557,6 +1557,30 @@
 
 
   /**
+   * The description for the alert type that will be used for the alert
+   * notification generated if the dseecompat access control subsystem failed
+   * to parse one or more ACI rules when the server is first started or a
+   * backend is being initialized.
+   */
+  public static final String ALERT_DESCRIPTION_ACCESS_CONTROL_PARSE_FAILED =
+          "This alert type will be used to notify administrators if the  " +
+             "dseecompat access control subsystem failed to correctly parse " +
+             "one or more ACI rules when the server is first started.";
+
+
+
+  /**
+   * The alert type string that will be used for the alert notification
+   * generated if the dseecompat access control subsystem failed to parse
+   * one or more ACI rules when the server is first started or a backend
+   * is being initialized.
+   */
+  public static final String ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED =
+          "org.opends.server.authentiation.dseecompat.ACIParseFailed";
+
+
+
+  /**
    * The name of the default password storage scheme that will be used for new
    * passwords.
    */

--
Gitblit v1.10.0