From 7abd5d082bdb603dbae7d7a801754b8d98cbdfc3 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slaznick@redhat.com>
Date: Mon, 13 Jul 2015 09:53:10 +0200
Subject: [PATCH 1/3] Added caching of time policies for IPA HBAC rules.

The time policies which are part of the FreeIPA HBAC Rule object
are now being cached along with other HBAC Rule objects' attributes.
Also, the cached time policies are transformed into hbac_time_rules
structure representation.

https://fedorahosted.org/freeipa/ticket/547
---
 src/providers/ipa/hbac_evaluator.c   |  19 +++---
 src/providers/ipa/ipa_access.c       |   3 +
 src/providers/ipa/ipa_hbac.h         |  14 ++++-
 src/providers/ipa/ipa_hbac_common.c  | 119 +++++++++++++++++++++++++++++++++++
 src/providers/ipa/ipa_hbac_private.h |  10 +++
 src/providers/ipa/ipa_hbac_rules.c   |   7 ++-
 src/tests/ipa_hbac-tests.c           |   6 ++
 7 files changed, 166 insertions(+), 12 deletions(-)

diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c
index f40f9e0a7f16f5e012079c637b89c8e49ec5d15b..d55041b627e74965c0ec254776aacbba56031ce0 100644
--- a/src/providers/ipa/hbac_evaluator.c
+++ b/src/providers/ipa/hbac_evaluator.c
@@ -38,13 +38,6 @@ typedef int errno_t;
 #define EOK 0
 #endif
 
-/* Placeholder structure for future HBAC time-based
- * evaluation rules
- */
-struct hbac_time_rules {
-    int not_yet_implemented;
-};
-
 enum hbac_eval_result_int {
     HBAC_EVAL_MATCH_ERROR = -1,
     HBAC_EVAL_MATCHED,
@@ -67,6 +60,13 @@ static bool hbac_rule_element_is_complete(struct hbac_rule_element *el)
     return false;
 }
 
+static bool hbac_rule_timerules_elem_is_complete(struct hbac_time_rules *el) {
+    if (el == NULL) return false;
+
+    /** Currently nothing has to be set */
+    return true;
+}
+
 bool hbac_rule_is_complete(struct hbac_rule *rule, uint32_t *missing_attrs)
 {
     bool complete = true;
@@ -99,6 +99,11 @@ bool hbac_rule_is_complete(struct hbac_rule *rule, uint32_t *missing_attrs)
         *missing_attrs |= HBAC_RULE_ELEMENT_SOURCEHOSTS;
     }
 
+    if (!hbac_rule_timerules_elem_is_complete(rule->timerules)) {
+        complete = false;
+        *missing_attrs |= HBAC_RULE_TIMERULES;
+    }
+
     return complete;
 }
 
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 3198e2bd2a4c8355eeccc129c85ae3d7d67f61b0..c60775fd01f816c19b3617caa04088a8052d35ed 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -686,6 +686,9 @@ errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx,
                             IPA_EXTERNAL_HOST,
                             IPA_MEMBER_HOST,
                             IPA_HOST_CATEGORY,
+                            IPA_TIMEZONE,
+                            IPA_ACCESSTIME,
+                            IPA_ACCESSTIME_EXCLUDE,
                             NULL };
 
     tmp_ctx = talloc_new(NULL);
diff --git a/src/providers/ipa/ipa_hbac.h b/src/providers/ipa/ipa_hbac.h
index f43611351c8a5dfb20ca3d075f0bcd7bb71798c9..822321d5ab75b6a8db8cf85ffb65604a5bb1fef2 100644
--- a/src/providers/ipa/ipa_hbac.h
+++ b/src/providers/ipa/ipa_hbac.h
@@ -73,7 +73,11 @@ enum hbac_eval_result {
 /**
  * Opaque type contained in hbac_evaluator.c
  */
-struct hbac_time_rules;
+ struct hbac_time_rules {
+     const char *timezone;
+     const char **accesstimes;
+     const char **exceptions;
+ };
 
 /**
  * Component of an HBAC rule
@@ -292,6 +296,9 @@ void hbac_free_info(struct hbac_info *info);
 /** Source host element */
 #define HBAC_RULE_ELEMENT_SOURCEHOSTS 0x08
 
+/** Time rules */
+#define HBAC_RULE_TIMERULES 0x10
+
 /**
  * @brief Evaluate whether an HBAC rule contains all necessary elements
  *
@@ -300,8 +307,9 @@ void hbac_free_info(struct hbac_info *info);
  *                           This is a bitmask that may contain one or more
  *                           of #HBAC_RULE_ELEMENT_USERS,
  *                           #HBAC_RULE_ELEMENT_SERVICES,
- *                           #HBAC_RULE_ELEMENT_TARGETHOSTS and
- *                           #HBAC_RULE_ELEMENT_SOURCEHOSTS
+ *                           #HBAC_RULE_ELEMENT_TARGETHOSTS,
+ *                           #HBAC_RULE_ELEMENT_SOURCEHOSTS and
+ *                           #HBAC_RULE_TIMERULES
  *
  * @return True if the rule contains all mandatory attributes
  *
diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c
index 72a620ef0971a8bc657bd7bda3f61b4abdd614ee..f90bd393b14d34c26c3efbe8ca0b0707c1251b65 100644
--- a/src/providers/ipa/ipa_hbac_common.c
+++ b/src/providers/ipa/ipa_hbac_common.c
@@ -354,6 +354,16 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
+    ret = hbac_time_attrs_to_rule(new_rule, new_rule->name,
+                                  hbac_ctx->rules[idx],
+                                  &new_rule->timerules);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not parse time rules for rule [%s]\n",
+                new_rule->name);
+        goto done;
+    }
+
     *rule = new_rule;
     ret = EOK;
 
@@ -363,6 +373,115 @@ done:
 }
 
 errno_t
+hbac_time_attrs_to_rule(TALLOC_CTX *mem_ctx,
+                        const char *rule_name,
+                        struct sysdb_attrs *rule_attrs,
+                        struct hbac_time_rules **times)
+{
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct ldb_message_element *el;
+    const char *timezone;
+    struct hbac_time_rules *new_times = NULL;
+    int i;
+
+    tmp_ctx = talloc_new(mem_ctx);
+    if (tmp_ctx == NULL) return ENOMEM;
+
+    new_times = talloc_zero(tmp_ctx, struct hbac_time_rules);
+    if (new_times == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_LIBS, "Processing time policies for rule [%s]\n",
+            rule_name);
+
+    ret = sysdb_attrs_get_string(rule_attrs, IPA_TIMEZONE, &timezone);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed.\n");
+        goto done;
+    }
+    if (ret == ENOENT) {
+        /* No value = default behavior (utc) */
+        new_times->timezone = talloc_strdup(new_times, "utc");
+    }
+    else {
+        new_times->timezone = talloc_strdup(new_times,
+                                            timezone);
+    }
+
+    ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESSTIME, &el);
+    if(ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed");
+        goto done;
+    }
+    if(ret == ENOENT || el->num_values == 0) {
+        el->num_values = 0;
+        DEBUG(SSSDBG_CONF_SETTINGS,
+              "No access time specified.\n");
+    }
+
+    new_times->accesstimes = talloc_array(new_times,
+                                          const char *,
+                                          el->num_values + 1);
+    if (new_times->accesstimes == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for(i = 0; i < el->num_values; i++) {
+        new_times->accesstimes[i] = talloc_strdup(new_times->accesstimes,
+                                        (const char *)el->values[i].data);
+        if(new_times->accesstimes[i] == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+    new_times->accesstimes[i] = NULL;
+
+    ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESSTIME_EXCLUDE, &el);
+    if(ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed");
+        goto done;
+    }
+    if(ret == ENOENT || el->num_values == 0) {
+        el->num_values = 0;
+        DEBUG(SSSDBG_CONF_SETTINGS,
+              "No access time exceptions specified.\n");
+    }
+
+    new_times->exceptions = talloc_array(new_times,
+                                          const char *,
+                                          el->num_values + 1);
+    if (new_times->exceptions == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for(i = 0; i < el->num_values; i++) {
+        new_times->exceptions[i] = talloc_strdup(new_times->exceptions,
+                                        (const char *)el->values[i].data);
+        if(new_times->exceptions[i] == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+    new_times->exceptions[i] = NULL;
+
+    ret = EOK;
+
+done:
+    if (ret == EOK) {
+        *times = talloc_steal(mem_ctx, new_times);
+    }
+    talloc_free(tmp_ctx);
+
+    return ret;
+}
+
+
+errno_t
 hbac_get_category(struct sysdb_attrs *attrs,
                   const char *category_attr,
                   uint32_t *_categories)
diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h
index c831cd5c6dd2ed1ff2bc0d649a25ae1212548dda..f36d4ee1ef78c20a5c52b375d07cd5a426fe2275 100644
--- a/src/providers/ipa/ipa_hbac_private.h
+++ b/src/providers/ipa/ipa_hbac_private.h
@@ -53,6 +53,9 @@
 #define IPA_CN "cn"
 #define IPA_MEMBER_SERVICE "memberService"
 #define IPA_SERVICE_CATEGORY "serviceCategory"
+#define IPA_TIMEZONE "ipaTimeZone"
+#define IPA_ACCESSTIME "accessTime"
+#define IPA_ACCESSTIME_EXCLUDE "accessTimeExclude"
 #define IPA_TRUE_VALUE "TRUE"
 
 #define IPA_HBAC_BASE_TMPL "cn=hbac,%s"
@@ -129,6 +132,13 @@ hbac_service_attrs_to_rule(TALLOC_CTX *mem_ctx,
                            const char *rule_name,
                            struct sysdb_attrs *rule_attrs,
                            struct hbac_rule_element **services);
+
+errno_t
+hbac_time_attrs_to_rule(TALLOC_CTX *mem_ctx,
+                       const char *rule_name,
+                       struct sysdb_attrs *rule_attrs,
+                       struct hbac_time_rules **times);
+
 errno_t
 get_ipa_servicegroupname(TALLOC_CTX *mem_ctx,
                          struct sysdb_ctx *sysdb,
diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c
index ffef6dc4ce4229f2063d1b00308892bd3765f398..08dbaed5caa10b39ca7a8458335d57457ffc5255 100644
--- a/src/providers/ipa/ipa_hbac_rules.c
+++ b/src/providers/ipa/ipa_hbac_rules.c
@@ -94,7 +94,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx,
     state->opts = opts;
     state->search_bases = search_bases;
     state->search_base_iter = 0;
-    state->attrs = talloc_zero_array(state, const char *, 15);
+    state->attrs = talloc_zero_array(state, const char *, 18);
     if (state->attrs == NULL) {
         ret = ENOMEM;
         goto immediate;
@@ -113,7 +113,10 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx,
     state->attrs[11] = IPA_EXTERNAL_HOST;
     state->attrs[12] = IPA_MEMBER_HOST;
     state->attrs[13] = IPA_HOST_CATEGORY;
-    state->attrs[14] = NULL;
+    state->attrs[14] = IPA_TIMEZONE;
+    state->attrs[15] = IPA_ACCESSTIME;
+    state->attrs[16] = IPA_ACCESSTIME_EXCLUDE;
+    state->attrs[17] = NULL;
 
     rule_filter = talloc_asprintf(tmp_ctx,
                                   "(&(objectclass=%s)"
diff --git a/src/tests/ipa_hbac-tests.c b/src/tests/ipa_hbac-tests.c
index bd56c8f107b05f07b1ba8913fc14a03419d679f7..46f1e3e1e648a8a53f35857ba7752b81ef2425be 100644
--- a/src/tests/ipa_hbac-tests.c
+++ b/src/tests/ipa_hbac-tests.c
@@ -103,6 +103,12 @@ static void get_allow_all_rule(TALLOC_CTX *mem_ctx,
     rule->srchosts->names = NULL;
     rule->srchosts->groups = NULL;
 
+    rule->timerules = talloc_zero(rule, struct hbac_time_rules);
+    fail_if(rule->timerules == NULL);
+    rule->timerules->timezone = NULL;
+    rule->timerules->accesstimes = NULL;
+    rule->timerules->exceptions = NULL;
+
     *allow_rule = rule;
 }
 
-- 
2.4.3

