PBE will be restarted and will not be able to come up if user requests
creating IMM object class with same name of reserved ones.

This patch adds code to reject such request with SA_AIS_ERR_INVALID_PARAM.
---
 src/imm/agent/imma_om_api.cc                       |   1 -
 .../apitest/management/test_saImmOmClassCreate_2.c |  48 ++++++++++
 src/imm/immnd/immnd.conf                           |   9 ++
 src/imm/immnd/immnd_cb.h                           |   1 +
 src/imm/immnd/immnd_evt.c                          |  17 ++++
 src/imm/immnd/immnd_main.c                         | 106 +++++++++++++++++++++
 6 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/src/imm/agent/imma_om_api.cc b/src/imm/agent/imma_om_api.cc
index 7155799..a06f0ea 100644
--- a/src/imm/agent/imma_om_api.cc
+++ b/src/imm/agent/imma_om_api.cc
@@ -55,7 +55,6 @@ static bool immOmIsLoader = false;
 static const char *sysaClName = SA_IMM_ATTR_CLASS_NAME;
 static const char *sysaAdmName = SA_IMM_ATTR_ADMIN_OWNER_NAME;
 static const char *sysaImplName = SA_IMM_ATTR_IMPLEMENTER_NAME;
-
 static int imma_om_resurrect(IMMA_CB *cb, IMMA_CLIENT_NODE *cl_node,
                              bool *locked);
 static SaAisErrorT imma_finalizeCcb(SaImmCcbHandleT ccbHandle,
diff --git a/src/imm/apitest/management/test_saImmOmClassCreate_2.c 
b/src/imm/apitest/management/test_saImmOmClassCreate_2.c
index 3ae4b0f..967b819 100644
--- a/src/imm/apitest/management/test_saImmOmClassCreate_2.c
+++ b/src/imm/apitest/management/test_saImmOmClassCreate_2.c
@@ -426,6 +426,46 @@ void saImmOmClassCreate_2_19(void)
        safassert(saImmOmFinalize(immOmHandle), SA_AIS_OK);
 }
 
+/*
+  Verify it is not allowed to create IMM object class with reserved name.
+  NOTE: As the list of reserved class names is read from the environment
+  variable IMMSV_RESERVED_CLASS_NAMES which is defined in immnd.conf file,
+  these 02 below test cases could fail if "objects" or "classes" name do
+  not exist in the list.
+ */
+void saImmOmClassCreate_with_reserved_name_01(void)
+{
+       const SaImmClassNameT className = (SaImmClassNameT) "objects";
+       SaImmAttrDefinitionT_2 attr1 = {"rdn", SA_IMM_ATTR_SANAMET,
+                                       SA_IMM_ATTR_CONFIG | SA_IMM_ATTR_RDN,
+                                       NULL};
+       const SaImmAttrDefinitionT_2 *attrDefinitions[] = {&attr1, NULL};
+
+       safassert(saImmOmInitialize(&immOmHandle, &immOmCallbacks, &immVersion),
+                 SA_AIS_OK);
+       rc = saImmOmClassCreate_2(immOmHandle, className, SA_IMM_CLASS_CONFIG,
+                                 attrDefinitions);
+       test_validate(rc, SA_AIS_ERR_INVALID_PARAM);
+       safassert(saImmOmFinalize(immOmHandle), SA_AIS_OK);
+}
+
+void saImmOmClassCreate_with_reserved_name_02(void)
+{
+       const SaImmClassNameT className = (SaImmClassNameT) "classes";
+       SaImmAttrDefinitionT_2 attr1 = {
+               "rdn", SA_IMM_ATTR_SANAMET,
+               SA_IMM_ATTR_RUNTIME | SA_IMM_ATTR_RDN | SA_IMM_ATTR_CACHED,
+               NULL};
+       const SaImmAttrDefinitionT_2 *attrDefinitions[] = {&attr1, NULL};
+
+       safassert(saImmOmInitialize(&immOmHandle, &immOmCallbacks, &immVersion),
+                 SA_AIS_OK);
+       rc = saImmOmClassCreate_2(immOmHandle, className, SA_IMM_CLASS_RUNTIME,
+                                 attrDefinitions);
+       test_validate(rc, SA_AIS_ERR_INVALID_PARAM);
+       safassert(saImmOmFinalize(immOmHandle), SA_AIS_OK);
+}
+
 #define OPENSAF_IMM_NOSTD_FLAG_PARAM "opensafImmNostdFlags"
 #define OPENSAF_IMM_NOSTD_FLAG_ON 1
 #define OPENSAF_IMM_NOSTD_FLAG_OFF 2
@@ -1457,6 +1497,14 @@ __attribute__((constructor)) static void 
saImmOmInitialize_constructor(void)
        test_case_add(
            2, saImmOmClassCreate_2_19,
            "saImmOmClassCreate_2 - SA_AIS_OK, Create a class that has 
STRONG_DEFAULT flag without having default value");
+       test_case_add(
+               2, saImmOmClassCreate_with_reserved_name_01,
+               "saImmOmClassCreate_2 - SA_AIS_ERR_INVALID_PARAM,"
+               "Create a config class with reserved name");
+       test_case_add(
+               2, saImmOmClassCreate_with_reserved_name_02,
+               "saImmOmClassCreate_2 - SA_AIS_ERR_INVALID_PARAM,"
+               " Create a rt class with reserved name");
 
        test_case_add(2, saImmOmClassDescriptionGet_2_01,
                      "saImmOmClassDescriptionGet_2 - SA_AIS_OK");
diff --git a/src/imm/immnd/immnd.conf b/src/imm/immnd/immnd.conf
index 97af792..a2c6d85 100644
--- a/src/imm/immnd/immnd.conf
+++ b/src/imm/immnd/immnd.conf
@@ -71,3 +71,12 @@ export IMMSV_ENV_HEALTHCHECK_KEY="Default"
 
 # Uncomment the next line to enable info level logging
 #args="--loglevel=info"
+
+# The list of reserved table names. Each table is separated by a comma.
+# Any attempt to create IMM object class with one of these names will
+# get SA_AIS_ERR_INVALID_PARAM error code.
+# The default list is used if this enviroment variable is not defined.
+# export IMMSV_RESERVED_CLASS_NAMES="attr_def, attr_dflt, ccb_commits, classes,
+#                                    objects, objects_blob_multi,
+#                                    objects_int_multi, objects_real_multi,
+#                                    objects_text_multi, pbe_rep_version";
diff --git a/src/imm/immnd/immnd_cb.h b/src/imm/immnd/immnd_cb.h
index 7614d27..802b365 100644
--- a/src/imm/immnd/immnd_cb.h
+++ b/src/imm/immnd/immnd_cb.h
@@ -170,6 +170,7 @@ typedef struct immnd_cb_tag {
   struct timespec
       mJobStart;    // Start time for major server tasks like start, load, 
sync.
   char *mProgName;  // The full path name of the immnd executable.
+  char **reserved_class_names; // List of class names are reserved for PBE
   const char *mDir;      // The directory where imm.xml & pbe files reside
   const char *mFile;     // The imm.xml file to start from
   const char *mPbeFile;  // Pbe feature is configured (IMMSV_PBE_FILE).
diff --git a/src/imm/immnd/immnd_evt.c b/src/imm/immnd/immnd_evt.c
index b95dcdc..228b7dd 100644
--- a/src/imm/immnd/immnd_evt.c
+++ b/src/imm/immnd/immnd_evt.c
@@ -3592,6 +3592,17 @@ agent_rsp:
        return rc;
 }
 
+static bool is_class_name_reserved(const IMMND_CB* cb, const char* name)
+{
+       int i = 0;
+       const char* r_name;
+       char** list = cb->reserved_class_names;
+       while ((r_name = list[i++])) {
+               if (!strcmp(name, r_name)) return true;
+       }
+       return false;
+}
+
 /*
   Function for performing immnd local checks on fevs packed messages.
   Normally they pass the checks and are forwarded to the IMMD.
@@ -3864,6 +3875,12 @@ static SaAisErrorT immnd_fevs_local_checks(IMMND_CB *cb, 
IMMSV_FEVS *fevsReq,
                        }
                }
 
+               char *class_name =
+                       frwrd_evt.info.immnd.info.classDescr.className.buf;
+               if (is_class_name_reserved(cb, class_name)) {
+                       error = SA_AIS_ERR_INVALID_PARAM;
+               }
+
                break;
 
        case IMMND_EVT_A2ND_CLASS_DELETE:
diff --git a/src/imm/immnd/immnd_main.c b/src/imm/immnd/immnd_main.c
index b68b374..dd04875 100644
--- a/src/imm/immnd/immnd_main.c
+++ b/src/imm/immnd/immnd_main.c
@@ -48,8 +48,112 @@
 static IMMND_CB _immnd_cb;
 IMMND_CB *immnd_cb = &_immnd_cb;
 
+static const char* default_reserved_names[] = {
+       "attr_def",
+       "attr_dflt",
+       "ccb_commits",
+       "classes",
+       "objects",
+       "objects_blob_multi",
+       "objects_int_multi",
+       "objects_real_multi",
+       "objects_text_multi",
+       "pbe_rep_version"
+};
+
 /* Static Function Declerations */
 
+static char* trim_string(char* s)
+{
+       while (isspace((unsigned char) *s)) s++;
+       if (*s) {
+               char *p = s;
+               while (*p) p++;
+               while (isspace((unsigned char) *(--p)));
+               p[1] = '\0';
+       }
+       return s;
+}
+
+static bool is_valid_class_name(const char* input) {
+       size_t len = strlen(input);
+       size_t i = 0;
+       if (len == 0) return false;
+       for (; i < len; i++) {
+               if (input[i] == ' ') return false;
+       }
+       return true;
+}
+
+/*
+  Return the list of reserved class name if the input is valid, NULL otherwise.
+ */
+static char** parse_reserved_class_names(const char* input) {
+       char** result = NULL;
+       char* dup, *tofree;
+       char* token;
+       int i = 0, n_elements = 0;
+
+       dup = tofree = strdup(input);
+       token = strsep(&dup, ",");
+       while (token) {
+               token = trim_string(token);
+               if (is_valid_class_name(token) == false) {
+                       LOG_ER("The reserved name `%s` is invalid!", token);
+                       goto freedata;
+               }
+               result = (char**)realloc(result, sizeof(char*) * ++n_elements);
+               result[n_elements - 1] = strdup(token);
+               token = strsep(&dup, ",");
+       }
+
+       result = (char**)realloc(result, sizeof(char*) * (n_elements+1));
+       result[n_elements] = 0;
+
+       free(tofree);
+       return result;
+
+freedata:
+       for (i = 0; i < n_elements; i++) {
+               if (result[i]) free(result[i]);
+       }
+       free(tofree);
+       free(result);
+       return NULL;
+}
+
+/*
+  Save list of reserved class names into global control block.
+  Use the default list if the environment variable `IMMSV_RESERVED_CLASS_NAMES`
+  is not defined. If any invalid name exists, terminate IMMND and notify
+  the error to syslog.
+ */
+static void populate_reserved_class_names(IMMND_CB* cb)
+{
+       const char *envVar = NULL;
+       if ((envVar = getenv("IMMSV_RESERVED_CLASS_NAMES"))) {
+               cb->reserved_class_names = parse_reserved_class_names(envVar);
+               /* IMMND is terminated if any wrong with the input value */
+               if (!cb->reserved_class_names) {
+                       LOG_ER("The reserved class names are invalid! Exit...");
+                       assert(0);
+               }
+               LOG_NO("The list of reserved class names: %s", envVar);
+       } else {
+               size_t i = 0;
+               size_t len = sizeof(default_reserved_names)/
+                       sizeof(default_reserved_names[0]);
+               cb->reserved_class_names =
+                       (char**)calloc(1, len * sizeof(char*) + 1);
+               for (; i < len; i++) {
+                       cb->reserved_class_names[i] =
+                               strdup(default_reserved_names[i]);
+               }
+               cb->reserved_class_names[i] = NULL;
+               LOG_NO("Use default reserved class names.");
+       }
+}
+
 /**
  * USR1 signal is used when AMF wants instantiate us as a
  * component. Wake up the main thread so it can register with
@@ -150,6 +254,8 @@ static uint32_t immnd_initialize(char *progname)
        immnd_cb->clm_hdl = 0;
        immnd_cb->clmSelectionObject = -1;
 
+       populate_reserved_class_names(immnd_cb);
+
        /* isClmNodeJoined will be intially set to true, untill CLMS service is
           up. from there isClmNodeJoined will be controlled by CLM membership
           join/left.
-- 
1.9.1


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to