Blob Blame History Raw
From 3935dd9f2ac3aab9027783e45f499401476f52cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 19 Nov 2018 15:04:42 +0100
Subject: [PATCH 09/15] lib: add authselect_profile_features to list supported
 features

The feature list is automatically obtained from profile's template files.

Related to:
https://github.com/pbrezina/authselect/issues/107
---
 include/authselect.h         | 12 +++++
 src/lib/authselect_profile.c | 51 ++++++++++++++++++++++
 src/lib/util/string_array.c  | 36 +++++++++++++++
 src/lib/util/string_array.h  | 20 +++++++++
 src/lib/util/template.c      | 85 ++++++++++++++++++++++++++++++++++--
 src/lib/util/template.h      | 11 +++++
 6 files changed, 211 insertions(+), 4 deletions(-)

diff --git a/include/authselect.h b/include/authselect.h
index d52d460e38132cf81e8a03b88a530c634a2c8937..462f54291e8283d5778005ac1747dd03258584be 100644
--- a/include/authselect.h
+++ b/include/authselect.h
@@ -273,6 +273,18 @@ char **
 authselect_profile_nsswitch_maps(const struct authselect_profile *profile,
                                  const char **features);
 
+/**
+ * List features supported by the profile.
+ *
+ * It is necessary to free the returned pointer with @authselect_array_free.
+ *
+ * @param profile    Pointer to structure obtained by @authselect_profile.
+ *
+ * @return NULL-terminated array of supported features, NULL on error.
+ */
+char **
+authselect_profile_features(const struct authselect_profile *profile);
+
 /**
  * Free authconfig_profile structure obtained by @authselect_profile.
  *
diff --git a/src/lib/authselect_profile.c b/src/lib/authselect_profile.c
index 8a12a082802fbc4f3c8cb3af7379ad26372dcc0c..d0cf17b8b7a414a41427c88039687725dcf1a560 100644
--- a/src/lib/authselect_profile.c
+++ b/src/lib/authselect_profile.c
@@ -115,6 +115,57 @@ authselect_profile_nsswitch_maps(const struct authselect_profile *profile,
     return maps;
 }
 
+_PUBLIC_ char **
+authselect_profile_features(const struct authselect_profile *profile)
+{
+    char **features;
+    char **array;
+    errno_t ret;
+    int i;
+
+    if (profile == NULL) {
+        return NULL;
+    }
+
+    features = string_array_create(10);
+    if (features == NULL) {
+        ERROR("Unable to create array (out of memory)");
+        return NULL;
+    }
+
+    struct authselect_generated files[] = PROFILE_FILES(profile->files);
+
+    for (i = 0; files[i].path != NULL; i++) {
+        array = template_list_features(files[i].content);
+        if (array == NULL) {
+            ERROR("Unable to obtain feature list (out of memory)");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        features = string_array_concat(features, array, true);
+        string_array_free(array);
+
+        if (features == NULL) {
+            ERROR("Unable to obtain feature list (out of memory)");
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    string_array_sort(features);
+
+    ret = EOK;
+
+done:
+    if (ret != EOK) {
+        string_array_free(features);
+        return NULL;
+    }
+
+    return features;
+}
+
 _PUBLIC_ void
 authselect_profile_free(struct authselect_profile *profile)
 {
diff --git a/src/lib/util/string_array.c b/src/lib/util/string_array.c
index a074e23ee504792da7f1a9262e15c549de5747d3..43e30d0008b5709f97da9c43f8f2c28ef2475df5 100644
--- a/src/lib/util/string_array.c
+++ b/src/lib/util/string_array.c
@@ -159,3 +159,39 @@ string_array_del_value(char **array, const char *value)
 
     return array;
 }
+
+char **
+string_array_concat(char **to, char **items, bool unique)
+{
+    int i;
+
+    if (items == NULL) {
+        return to;
+    }
+
+    for (i = 0; items[i] != NULL; i++) {
+        to = string_array_add_value(to, items[i], unique);
+        if (to == NULL) {
+            return NULL;
+        }
+    }
+
+    return to;
+}
+
+static int
+string_array_sort_callback(const void *a, const void *b)
+{
+    return strcmp(*(char* const*)a, *(char* const*)b);
+}
+
+void
+string_array_sort(char **array)
+{
+    if (array == NULL) {
+        return;
+    }
+
+    qsort(array, string_array_count(array), sizeof(char *),
+          string_array_sort_callback);
+}
diff --git a/src/lib/util/string_array.h b/src/lib/util/string_array.h
index 9545685b2553228a109ab51e7c6a0fd16698fa3e..06aa46c008058163e5557d51e18258fa4e9a1523 100644
--- a/src/lib/util/string_array.h
+++ b/src/lib/util/string_array.h
@@ -118,4 +118,24 @@ string_array_add_value(char **array, const char *value, bool unique);
 char **
 string_array_del_value(char **array, const char *value);
 
+/**
+ * Concatenate two array. Array @items values will be appended to arra @to.
+ *
+ * @param to    NULL-terminated destination array.
+ * @param items NULL-terminated array to be appended into @to.
+ * @param unique If true, value will not be added if it is already present.
+ *
+ * @return Array or NULL if reallocation fails.
+ */
+char **
+string_array_concat(char **to, char **items, bool unique);
+
+/**
+ * Alphabetically sort a NULL-terminated string array.
+ *
+ * @param array NULL-terminated string array.
+ */
+void
+string_array_sort(char **array);
+
 #endif /* _STRING_ARRAY_H_ */
diff --git a/src/lib/util/template.c b/src/lib/util/template.c
index e38d1d7f1db2c90f1281e97f3ebbdd9d9d1a935d..fb373c0fd83e04c6c78d5f57d3d8e50e54c0377b 100644
--- a/src/lib/util/template.c
+++ b/src/lib/util/template.c
@@ -325,10 +325,27 @@ template_process_matches(const char *match_string,
         return ret;
     }
 
-    *_op = op;
-    *_feature = feature;
-    *_if_true = if_true;
-    *_if_false = if_false;
+    if (_op != NULL) {
+        *_op = op;
+    }
+
+    if (_feature != NULL) {
+        *_feature = feature;
+    } else {
+        free(feature);
+    }
+
+    if (_if_true != NULL) {
+        *_if_true = if_true;
+    } else {
+        free(if_true);
+    }
+
+    if (_if_false != NULL) {
+        *_if_false = if_false;
+    } else {
+        free(if_false);
+    }
 
     return EOK;
 }
@@ -478,6 +495,66 @@ template_generate_preamble()
     return preamble;
 }
 
+char **
+template_list_features(const char *template)
+{
+    regmatch_t m[RE_MATCHES];
+    const char *match_string;
+    char **features;
+    char *feature;
+    regex_t regex;
+    errno_t ret;
+    int reret;
+
+    features = string_array_create(10);
+    if (features == NULL) {
+        return NULL;
+    }
+
+    if (template == NULL) {
+        return features;
+    }
+
+    reret = regcomp(&regex, OP_RE, REG_EXTENDED | REG_NEWLINE);
+    if (reret != REG_NOERROR) {
+        ERROR("Unable to compile regular expression: regex error %d", reret);
+        ret = EFAULT;
+        goto done;
+    }
+
+    match_string = template;
+    while ((reret = regexec(&regex, match_string, RE_MATCHES, m, 0)) == REG_NOERROR) {
+        ret = template_process_matches(match_string, m, NULL, &feature,
+                                       NULL, NULL);
+        if (ret != EOK) {
+            ERROR("Unable to process match [%d]: %s", ret, strerror(ret));
+            goto done;
+        }
+
+        features = string_array_add_value(features, feature, true);
+        free(feature);
+
+        match_string += m[0].rm_eo;
+    }
+
+    if (reret != REG_NOMATCH) {
+        ERROR("Unable to search string: regex error %d", reret);
+        ret = EFAULT;
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    if (ret != EOK) {
+        string_array_free(features);
+        return NULL;
+    }
+
+    regfree(&regex);
+    return features;
+}
+
 errno_t
 template_write(const char *filepath,
                const char *content,
diff --git a/src/lib/util/template.h b/src/lib/util/template.h
index 57e076c257a8cdcbc9c2c8f4f5266b4c21f27941..1c412dcf15a7f0d5a5897b78b8b52ff67b7c3f95 100644
--- a/src/lib/util/template.h
+++ b/src/lib/util/template.h
@@ -37,6 +37,17 @@ char *
 template_generate(const char *template,
                   const char **features);
 
+/**
+ * Find all features available withint the @template and return them in
+ * NULL-terminated array.
+ *
+ * @param template    Template.
+ *
+ * @return List of features in NULL-terminated array or NULL on error.
+ */
+char **
+template_list_features(const char *template);
+
 /**
  * Write generated file preamble together with its content to a file.
  * If the file does not exist, it is created, otherwise its content
-- 
2.17.2