From f3f18fe2bcdaba7e3f3e7e30d6e3450088715139 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Fri, 29 Jul 2011 15:03:14 -0400
Subject: [PATCH] Add rule validator to libipa_hbac

https://fedorahosted.org/sssd/ticket/943
---
 Makefile.am                        |    2 +-
 src/providers/ipa/hbac_evaluator.c |   51 ++++++++++++++++
 src/providers/ipa/ipa_hbac.h       |   23 +++++++
 src/tests/ipa_hbac-tests.c         |  115 ++++++++++++++++++++++++++++++++++++
 4 files changed, 190 insertions(+), 1 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 6647528c82a1653c792940298060753bf65fa5d4..544068f0826549f9bdc4335cbbaf2c32f738afb7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -378,7 +378,7 @@ dist_pkgconfig_DATA += src/providers/ipa/ipa_hbac.pc
 libipa_hbac_la_SOURCES = \
     src/providers/ipa/hbac_evaluator.c
 libipa_hbac_la_LDFLAGS = \
-    -version 0:1:0 \
+    -version 0:0:1 \
     -lunistring
 
 include_HEADERS = \
diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c
index ee39a09ae35cb392b024f009483a22e2b5320a38..476ad6482a697a070102a60c1109a46f2f350af8 100644
--- a/src/providers/ipa/hbac_evaluator.c
+++ b/src/providers/ipa/hbac_evaluator.c
@@ -52,6 +52,57 @@ enum hbac_eval_result_int {
     HBAC_EVAL_UNMATCHED
 };
 
+static bool hbac_rule_element_is_complete(struct hbac_rule_element *el)
+{
+    if (el == NULL) return false;
+    if (el->category == HBAC_CATEGORY_ALL) return true;
+
+    if (el->names == NULL && el->groups == NULL) return false;
+
+    if ((el->names && el->names[0] != NULL)
+            || (el->groups && el->groups[0] != NULL))
+        return true;
+
+    /* If other categories are added, handle them here */
+
+    return false;
+}
+
+bool hbac_rule_is_complete(struct hbac_rule *rule, uint32_t *missing_attrs)
+{
+    bool complete = true;
+
+    *missing_attrs = 0;
+
+    if (rule == NULL) {
+        /* No rule passed in? */
+        return false;
+    }
+
+    /* Make sure we have all elements */
+    if (!hbac_rule_element_is_complete(rule->users)) {
+        complete = false;
+        *missing_attrs |= HBAC_RULE_ELEMENT_USERS;
+    }
+
+    if (!hbac_rule_element_is_complete(rule->services)) {
+        complete = false;
+        *missing_attrs |= HBAC_RULE_ELEMENT_SERVICES;
+    }
+
+    if (!hbac_rule_element_is_complete(rule->targethosts)) {
+        complete = false;
+        *missing_attrs |= HBAC_RULE_ELEMENT_TARGETHOSTS;
+    }
+
+    if (!hbac_rule_element_is_complete(rule->srchosts)) {
+        complete = false;
+        *missing_attrs |= HBAC_RULE_ELEMENT_SOURCEHOSTS;
+    }
+
+    return complete;
+}
+
 enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule,
                                              struct hbac_eval_req *hbac_req,
                                              enum hbac_error_code *error);
diff --git a/src/providers/ipa/ipa_hbac.h b/src/providers/ipa/ipa_hbac.h
index a1d5137852c1abfb9ae46110daa5491170bfe459..7de49d1ff9338a80e2ac45358777a1fc7a8eb5e7 100644
--- a/src/providers/ipa/ipa_hbac.h
+++ b/src/providers/ipa/ipa_hbac.h
@@ -151,4 +151,27 @@ const char *hbac_error_string(enum hbac_error_code code);
 
 void hbac_free_info(struct hbac_info *info);
 
+
+#define HBAC_RULE_ELEMENT_USERS       0x01
+#define HBAC_RULE_ELEMENT_SERVICES    0x02
+#define HBAC_RULE_ELEMENT_TARGETHOSTS 0x04
+#define HBAC_RULE_ELEMENT_SOURCEHOSTS 0x08
+
+/**
+ * @brief Evaluate whether an HBAC rule contains all necessary elements
+ *
+ * @param[in] rule           An HBAC rule to evaluate
+ * @param[out] missing_attrs A list of attributes missing from the rule
+ *                           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
+ *
+ * @return True if the rule contains all mandatory attributes
+ *
+ * @note This function does not care if the rule is enabled or disabled
+ */
+bool hbac_rule_is_complete(struct hbac_rule *rule, uint32_t *missing_attrs);
+
 #endif /* IPA_HBAC_H_ */
diff --git a/src/tests/ipa_hbac-tests.c b/src/tests/ipa_hbac-tests.c
index d3d80387577f6791277178d811d60c1889fd8c87..330e49e7c5570e02937b558701ed96df5d4e32c4 100644
--- a/src/tests/ipa_hbac-tests.c
+++ b/src/tests/ipa_hbac-tests.c
@@ -188,6 +188,8 @@ START_TEST(ipa_hbac_test_allow_all)
     struct hbac_rule **rules;
     struct hbac_eval_req *eval_req;
     struct hbac_info *info;
+    bool is_valid;
+    uint32_t missing_attrs;
 
     test_ctx = talloc_new(global_talloc_context);
 
@@ -208,6 +210,11 @@ START_TEST(ipa_hbac_test_allow_all)
     fail_if(rules[0]->name == NULL);
     rules[1] = NULL;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_ALLOW,
@@ -228,6 +235,8 @@ START_TEST(ipa_hbac_test_allow_user)
     struct hbac_rule **rules;
     struct hbac_eval_req *eval_req;
     struct hbac_info *info;
+    bool is_valid;
+    uint32_t missing_attrs;
 
     test_ctx = talloc_new(global_talloc_context);
 
@@ -258,6 +267,11 @@ START_TEST(ipa_hbac_test_allow_user)
 
     rules[1] = NULL;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_ALLOW,
@@ -270,6 +284,11 @@ START_TEST(ipa_hbac_test_allow_user)
     /* Negative test */
     rules[0]->users->names[0] = HBAC_TEST_INVALID_USER;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_DENY,
@@ -290,6 +309,8 @@ START_TEST(ipa_hbac_test_allow_utf8)
     struct hbac_rule **rules;
     struct hbac_eval_req *eval_req;
     struct hbac_info *info;
+    bool is_valid;
+    uint32_t missing_attrs;
 
     test_ctx = talloc_new(global_talloc_context);
 
@@ -343,6 +364,11 @@ START_TEST(ipa_hbac_test_allow_utf8)
 
     rules[1] = NULL;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_ALLOW,
@@ -369,6 +395,11 @@ START_TEST(ipa_hbac_test_allow_utf8)
     eval_req->user->name = (const char *) &user_lowcase_tr;
     rules[0]->users->names[0] = (const char *) &user_upcase_tr;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_DENY,
@@ -389,6 +420,8 @@ START_TEST(ipa_hbac_test_allow_group)
     struct hbac_rule **rules;
     struct hbac_eval_req *eval_req;
     struct hbac_info *info;
+    bool is_valid;
+    uint32_t missing_attrs;
 
     test_ctx = talloc_new(global_talloc_context);
 
@@ -420,6 +453,11 @@ START_TEST(ipa_hbac_test_allow_group)
 
     rules[1] = NULL;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_ALLOW,
@@ -432,6 +470,11 @@ START_TEST(ipa_hbac_test_allow_group)
     /* Negative test */
     rules[0]->users->groups[0] = HBAC_TEST_INVALID_GROUP;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_DENY,
@@ -452,6 +495,8 @@ START_TEST(ipa_hbac_test_allow_svc)
     struct hbac_rule **rules;
     struct hbac_eval_req *eval_req;
     struct hbac_info *info;
+    bool is_valid;
+    uint32_t missing_attrs;
 
     test_ctx = talloc_new(global_talloc_context);
 
@@ -482,6 +527,11 @@ START_TEST(ipa_hbac_test_allow_svc)
 
     rules[1] = NULL;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_ALLOW,
@@ -494,6 +544,11 @@ START_TEST(ipa_hbac_test_allow_svc)
     /* Negative test */
     rules[0]->services->names[0] = HBAC_TEST_INVALID_SERVICE;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_DENY,
@@ -514,6 +569,8 @@ START_TEST(ipa_hbac_test_allow_svcgroup)
     struct hbac_rule **rules;
     struct hbac_eval_req *eval_req;
     struct hbac_info *info;
+    bool is_valid;
+    uint32_t missing_attrs;
 
     test_ctx = talloc_new(global_talloc_context);
 
@@ -545,6 +602,11 @@ START_TEST(ipa_hbac_test_allow_svcgroup)
 
     rules[1] = NULL;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_ALLOW,
@@ -557,6 +619,11 @@ START_TEST(ipa_hbac_test_allow_svcgroup)
     /* Negative test */
     rules[0]->services->groups[0] = HBAC_TEST_INVALID_SERVICEGROUP;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_DENY,
@@ -577,6 +644,8 @@ START_TEST(ipa_hbac_test_allow_srchost)
     struct hbac_rule **rules;
     struct hbac_eval_req *eval_req;
     struct hbac_info *info;
+    bool is_valid;
+    uint32_t missing_attrs;
 
     test_ctx = talloc_new(global_talloc_context);
 
@@ -607,6 +676,11 @@ START_TEST(ipa_hbac_test_allow_srchost)
 
     rules[1] = NULL;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_ALLOW,
@@ -619,6 +693,11 @@ START_TEST(ipa_hbac_test_allow_srchost)
     /* Negative test */
     rules[0]->srchosts->names[0] = HBAC_TEST_INVALID_SRCHOST;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_DENY,
@@ -639,6 +718,8 @@ START_TEST(ipa_hbac_test_allow_srchostgroup)
     struct hbac_rule **rules;
     struct hbac_eval_req *eval_req;
     struct hbac_info *info;
+    bool is_valid;
+    uint32_t missing_attrs;
 
     test_ctx = talloc_new(global_talloc_context);
 
@@ -670,6 +751,11 @@ START_TEST(ipa_hbac_test_allow_srchostgroup)
 
     rules[1] = NULL;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_ALLOW,
@@ -682,6 +768,11 @@ START_TEST(ipa_hbac_test_allow_srchostgroup)
     /* Negative test */
     rules[0]->srchosts->groups[0] = HBAC_TEST_INVALID_SRCHOSTGROUP;
 
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rules[0], &missing_attrs);
+    fail_unless(is_valid);
+    fail_unless(missing_attrs == 0);
+
     /* Evaluate the rules */
     result = hbac_evaluate(rules, eval_req, &info);
     fail_unless(result == HBAC_EVAL_DENY,
@@ -695,6 +786,29 @@ START_TEST(ipa_hbac_test_allow_srchostgroup)
 }
 END_TEST
 
+START_TEST(ipa_hbac_test_incomplete)
+{
+    TALLOC_CTX *test_ctx;
+    struct hbac_rule *rule;
+    bool is_valid;
+    uint32_t missing_attrs;
+
+    test_ctx = talloc_new(global_talloc_context);
+
+    rule = talloc_zero(test_ctx, struct hbac_rule);
+
+    /* Validate this rule */
+    is_valid = hbac_rule_is_complete(rule, &missing_attrs);
+    fail_if(is_valid);
+    fail_unless(missing_attrs | HBAC_RULE_ELEMENT_USERS);
+    fail_unless(missing_attrs | HBAC_RULE_ELEMENT_SERVICES);
+    fail_unless(missing_attrs | HBAC_RULE_ELEMENT_TARGETHOSTS);
+    fail_unless(missing_attrs | HBAC_RULE_ELEMENT_SOURCEHOSTS);
+
+    talloc_free(test_ctx);
+}
+END_TEST
+
 Suite *hbac_test_suite (void)
 {
     Suite *s = suite_create ("HBAC");
@@ -712,6 +826,7 @@ Suite *hbac_test_suite (void)
     tcase_add_test(tc_hbac, ipa_hbac_test_allow_srchost);
     tcase_add_test(tc_hbac, ipa_hbac_test_allow_srchostgroup);
     tcase_add_test(tc_hbac, ipa_hbac_test_allow_utf8);
+    tcase_add_test(tc_hbac, ipa_hbac_test_incomplete);
 
     suite_add_tcase(s, tc_hbac);
     return s;
-- 
1.7.6

