From 2e0b63ffd0df36ce05ec9a9801696b99676bbb19 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/2] IPA: Added caching of time policies for 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/sssd/ticket/2836
---
 src/lib/ipa_hbac/hbac_evaluator.c    | 21 ++++++++-----
 src/lib/ipa_hbac/ipa_hbac.h          | 12 ++++++--
 src/providers/ipa/ipa_access.c       |  1 +
 src/providers/ipa/ipa_hbac_common.c  | 59 ++++++++++++++++++++++++++++++++++++
 src/providers/ipa/ipa_hbac_private.h |  8 +++++
 src/providers/ipa/ipa_hbac_rules.c   |  5 +--
 src/tests/ipa_hbac-tests.c           |  4 +++
 7 files changed, 97 insertions(+), 13 deletions(-)

diff --git a/src/lib/ipa_hbac/hbac_evaluator.c b/src/lib/ipa_hbac/hbac_evaluator.c
index ce13bd535d323e69248fac49f64efda164d37bb3..12cee43f29c0a3d6707a2d9db940ef2ca9560f30 100644
--- a/src/lib/ipa_hbac/hbac_evaluator.c
+++ b/src/lib/ipa_hbac/hbac_evaluator.c
@@ -73,14 +73,6 @@ static void hbac_rule_element_debug_print(struct hbac_rule_element *el,
 /* auxiliary function for hbac_rule logging */
 static void hbac_rule_debug_print(struct hbac_rule *rule);
 
-
-/* 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,
@@ -103,6 +95,14 @@ 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;
@@ -135,6 +135,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/lib/ipa_hbac/ipa_hbac.h b/src/lib/ipa_hbac/ipa_hbac.h
index 8801c20c492caf53a089c2724c2ed4a96805904c..7c411ad8e3ba8d5ff5ebf5fca1e9da45168ea664 100644
--- a/src/lib/ipa_hbac/ipa_hbac.h
+++ b/src/lib/ipa_hbac/ipa_hbac.h
@@ -102,7 +102,9 @@ enum hbac_eval_result {
 /**
  * Opaque type contained in hbac_evaluator.c
  */
-struct hbac_time_rules;
+ struct hbac_time_rules {
+     const char **accesstimes;
+ };
 
 /**
  * Component of an HBAC rule
@@ -321,6 +323,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
  *
@@ -329,8 +334,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_access.c b/src/providers/ipa/ipa_access.c
index cc780217d5e3512f354dc0225f93ac818a60cd25..e6143919658761e1919f9a8d7c9e4f0bf91ee139 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -725,6 +725,7 @@ errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx,
                             IPA_EXTERNAL_HOST,
                             IPA_MEMBER_HOST,
                             IPA_HOST_CATEGORY,
+                            IPA_ACCESSTIME,
                             NULL };
 
     tmp_ctx = talloc_new(NULL);
diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c
index 82c531f15338a2ff609bd58ad449783d7a3a6af1..e4177e527f9200d8e98070cdc5fc9a02fbef2918 100644
--- a/src/providers/ipa/ipa_hbac_common.c
+++ b/src/providers/ipa/ipa_hbac_common.c
@@ -353,6 +353,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;
 
@@ -362,6 +372,55 @@ 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;
+    struct hbac_time_rules *new_times = NULL;
+
+    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_el(rule_attrs, IPA_ACCESSTIME, &el);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el failed");
+        goto done;
+    }
+    else if (ret == ENOENT || el->num_values == 0) {
+        el->num_values = 0;
+        DEBUG(SSSDBG_CONF_SETTINGS,
+              "No access time specified.\n");
+    }
+
+    new_times->accesstimes = sss_ldb_el_to_string_list(new_times, el);
+    if (new_times->accesstimes == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = EOK;
+    *_times = talloc_steal(mem_ctx, new_times);
+
+done:
+    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 8fc5dc6d03cc2373e32641a399157c900ec18107..dcaae17fa993f0aff7175d884b4fadeaff80e3fd 100644
--- a/src/providers/ipa/ipa_hbac_private.h
+++ b/src/providers/ipa/ipa_hbac_private.h
@@ -53,6 +53,7 @@
 #define IPA_CN "cn"
 #define IPA_MEMBER_SERVICE "memberService"
 #define IPA_SERVICE_CATEGORY "serviceCategory"
+#define IPA_ACCESSTIME "accessTime"
 #define IPA_TRUE_VALUE "TRUE"
 
 #define IPA_HBAC_BASE_TMPL "cn=hbac,%s"
@@ -129,6 +130,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 7912dbec98f9f4bb5e4c9a64d709196c53e7512b..f13fd45bc463388d144964f867983afd2ee467a2 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 *, 16);
     if (state->attrs == NULL) {
         ret = ENOMEM;
         goto immediate;
@@ -113,7 +113,8 @@ 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_ACCESSTIME;
+    state->attrs[15] = 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 c8ef7fe44d41770cfeca706e6d3396a8d0e7d6cf..c4c9d64c2000182774161f65bbe4d91abe8cc616 100644
--- a/src/tests/ipa_hbac-tests.c
+++ b/src/tests/ipa_hbac-tests.c
@@ -103,6 +103,10 @@ 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->accesstimes = NULL;
+
     *allow_rule = rule;
 }
 
-- 
2.5.5

