Blame SOURCES/0028-lib-refuse-to-activate-profile-if-unsupported-featur.patch

1756dc
From 85bbc387c3f7bcfd094b78e2fc2779e27aca348f Mon Sep 17 00:00:00 2001
1756dc
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
1756dc
Date: Tue, 20 Nov 2018 11:56:09 +0100
1756dc
Subject: [PATCH 10/15] lib: refuse to activate profile if unsupported feature
1756dc
 was selected
1756dc
1756dc
Resolves:
1756dc
https://github.com/pbrezina/authselect/issues/107
1756dc
---
1756dc
 include/authselect.h        |  1 +
1756dc
 src/lib/authselect.c        | 44 +++++++++++++++++++++++++++++++++++++
1756dc
 src/lib/util/string.c       | 40 +++++++++++++++++++++++++++++++++
1756dc
 src/lib/util/string.h       |  6 +++++
1756dc
 src/lib/util/string_array.c | 30 +++++++++++++++++++++++++
1756dc
 src/lib/util/string_array.h | 15 +++++++++++++
1756dc
 src/tests/Makefile.am       |  1 +
1756dc
 7 files changed, 137 insertions(+)
1756dc
1756dc
diff --git a/include/authselect.h b/include/authselect.h
1756dc
index 462f54291e8283d5778005ac1747dd03258584be..110f22a864157f898541be573e800ed7d6c38e0a 100644
1756dc
--- a/include/authselect.h
1756dc
+++ b/include/authselect.h
1756dc
@@ -70,6 +70,7 @@ enum authselect_profile_type {
1756dc
  *   authselect and @force_overwrite must be set to true to force
1756dc
  *   overwrite the existing files.
1756dc
  * - ENOENT if the profile was not found.
1756dc
+ * - EINVAL if unsupported feature was provided.
1756dc
  * - Other errno code on generic error.
1756dc
  */
1756dc
 int
1756dc
diff --git a/src/lib/authselect.c b/src/lib/authselect.c
1756dc
index 3148f63b60534480b05b1ddb5587e4ed09aaa84a..1b4337e2e0eae4f298e59f90cc9c8659891e23f3 100644
1756dc
--- a/src/lib/authselect.c
1756dc
+++ b/src/lib/authselect.c
1756dc
@@ -29,6 +29,45 @@
1756dc
 #include "lib/files/files.h"
1756dc
 #include "lib/profiles/profiles.h"
1756dc
 
1756dc
+static bool
1756dc
+authselect_check_features(const struct authselect_profile *profile,
1756dc
+                          const char **features)
1756dc
+{
1756dc
+    const char *similar;
1756dc
+    bool result = true;
1756dc
+    char **supported;
1756dc
+    int i;
1756dc
+
1756dc
+    if (features == NULL) {
1756dc
+        return true;
1756dc
+    }
1756dc
+
1756dc
+    supported = authselect_profile_features(profile);
1756dc
+    if (supported == NULL) {
1756dc
+        ERROR("Unable to obtain supported features");
1756dc
+        return false;
1756dc
+    }
1756dc
+
1756dc
+    for (i = 0; features[i] != NULL; i++) {
1756dc
+        if (string_array_has_value(supported, features[i])) {
1756dc
+            continue;
1756dc
+        }
1756dc
+
1756dc
+        result = false;
1756dc
+        similar = string_array_find_similar(features[i], supported, 5);
1756dc
+        if (similar != NULL) {
1756dc
+            ERROR("Unknown profile feature [%s], did you mean [%s]?",
1756dc
+                  features[i], similar);
1756dc
+        } else {
1756dc
+            ERROR("Unknown profile feature [%s]", features[i]);
1756dc
+        }
1756dc
+    }
1756dc
+
1756dc
+    string_array_free(supported);
1756dc
+
1756dc
+    return result;
1756dc
+}
1756dc
+
1756dc
 _PUBLIC_ void
1756dc
 authselect_set_debug_fn(authselect_debug_fn fn, void *pvt)
1756dc
 {
1756dc
@@ -53,6 +92,11 @@ authselect_activate(const char *profile_id,
1756dc
         return ret;
1756dc
     }
1756dc
 
1756dc
+    if (!authselect_check_features(profile, features)) {
1756dc
+        ret = EINVAL;
1756dc
+        goto done;
1756dc
+    }
1756dc
+
1756dc
     if (force_overwrite) {
1756dc
         INFO("Enforcing activation!");
1756dc
         ret = authselect_profile_activate(profile, features);
1756dc
diff --git a/src/lib/util/string.c b/src/lib/util/string.c
1756dc
index 73ae778663bd8db024620a58987833ede60307d1..e6803bcd4e41adc05eaa623089009b17ccd4f49b 100644
1756dc
--- a/src/lib/util/string.c
1756dc
+++ b/src/lib/util/string.c
1756dc
@@ -329,3 +329,43 @@ string_replace_shake(char *str, size_t original_length)
1756dc
         str[pos] = '\0';
1756dc
     }
1756dc
 }
1756dc
+
1756dc
+static int
1756dc
+min3(unsigned int a, unsigned int b, unsigned int c)
1756dc
+{
1756dc
+    if (a < b && a < c) {
1756dc
+        return a;
1756dc
+    } else if (b < a && b < c) {
1756dc
+        return b;
1756dc
+    }
1756dc
+
1756dc
+    return c;
1756dc
+}
1756dc
+
1756dc
+int
1756dc
+string_levenshtein(const char *a, const char *b)
1756dc
+{
1756dc
+    unsigned int len_a = strlen(a);
1756dc
+    unsigned int len_b = strlen(b);
1756dc
+    unsigned int x;
1756dc
+    unsigned int y;
1756dc
+    unsigned int last_diag;
1756dc
+    unsigned int old_diag;
1756dc
+    unsigned int column[len_a + 1];
1756dc
+
1756dc
+    for (y = 1; y <= len_a; y++) {
1756dc
+        column[y] = y;
1756dc
+    }
1756dc
+
1756dc
+    for (x = 1; x <= len_b; x++) {
1756dc
+        column[0] = x;
1756dc
+        for (y = 1, last_diag = x - 1; y <= len_a; y++) {
1756dc
+            old_diag = column[y];
1756dc
+            column[y] = min3(column[y] + 1, column[y - 1] + 1,
1756dc
+                             last_diag + (a[y - 1] == b[x - 1] ? 0 : 1));
1756dc
+            last_diag = old_diag;
1756dc
+        }
1756dc
+    }
1756dc
+
1756dc
+    return column[len_a];
1756dc
+}
1756dc
diff --git a/src/lib/util/string.h b/src/lib/util/string.h
1756dc
index d7ca04491e5ceff20bd1d6e136ea151166156546..e550d853d3fa0699909b84cc9febdae9d5884b9f 100644
1756dc
--- a/src/lib/util/string.h
1756dc
+++ b/src/lib/util/string.h
1756dc
@@ -179,4 +179,10 @@ string_remove_remainder(char *str, size_t from);
1756dc
 void
1756dc
 string_replace_shake(char *str, size_t original_length);
1756dc
 
1756dc
+/**
1756dc
+ * Compute Levenshtein distance of two strings.
1756dc
+ */
1756dc
+int
1756dc
+string_levenshtein(const char *a, const char *b);
1756dc
+
1756dc
 #endif /* _STRING_H_ */
1756dc
diff --git a/src/lib/util/string_array.c b/src/lib/util/string_array.c
1756dc
index 43e30d0008b5709f97da9c43f8f2c28ef2475df5..e56d66bdcce7c8a1cf99f9b91068614c4b8d3d81 100644
1756dc
--- a/src/lib/util/string_array.c
1756dc
+++ b/src/lib/util/string_array.c
1756dc
@@ -25,6 +25,7 @@
1756dc
 
1756dc
 #include "common/common.h"
1756dc
 #include "lib/util/string_array.h"
1756dc
+#include "lib/util/string.h"
1756dc
 
1756dc
 char **
1756dc
 string_array_create(size_t num_items)
1756dc
@@ -195,3 +196,32 @@ string_array_sort(char **array)
1756dc
     qsort(array, string_array_count(array), sizeof(char *),
1756dc
           string_array_sort_callback);
1756dc
 }
1756dc
+
1756dc
+const char *
1756dc
+string_array_find_similar(const char *value, char **array, int max_distance)
1756dc
+{
1756dc
+    const char *word = NULL;
1756dc
+    int current;
1756dc
+    int best;
1756dc
+    int i;
1756dc
+
1756dc
+    for (i = 0; array[i] != NULL; i++) {
1756dc
+        current = string_levenshtein(value, array[i]);
1756dc
+        if (word == NULL) {
1756dc
+            best = current;
1756dc
+            word = array[i];
1756dc
+            continue;
1756dc
+        }
1756dc
+
1756dc
+        if (current < best) {
1756dc
+            best = current;
1756dc
+            word = array[i];
1756dc
+        }
1756dc
+    }
1756dc
+
1756dc
+    if (best > max_distance) {
1756dc
+        return NULL;
1756dc
+    }
1756dc
+
1756dc
+    return word;
1756dc
+}
1756dc
diff --git a/src/lib/util/string_array.h b/src/lib/util/string_array.h
1756dc
index 06aa46c008058163e5557d51e18258fa4e9a1523..ba9760b5d66a9619ca8edea5e3418c5cfbbec929 100644
1756dc
--- a/src/lib/util/string_array.h
1756dc
+++ b/src/lib/util/string_array.h
1756dc
@@ -138,4 +138,19 @@ string_array_concat(char **to, char **items, bool unique);
1756dc
 void
1756dc
 string_array_sort(char **array);
1756dc
 
1756dc
+/**
1756dc
+ * Find similar word inside a NULL-terminated array, based on Levenshtein
1756dc
+ * distance algorithm.
1756dc
+ *
1756dc
+ * @param value        Value to search in @array.
1756dc
+ * @param array        NULL-terminated string array.
1756dc
+ * @param max_distance Maximum distance between two strings. If the real
1756dc
+ *                     distance is greater then this value, those string
1756dc
+ *                     are not considered as similar.
1756dc
+ *
1756dc
+ * @return Most similar word that was found or NULL if non was found.
1756dc
+ */
1756dc
+const char *
1756dc
+string_array_find_similar(const char *value, char **array, int max_distance);
1756dc
+
1756dc
 #endif /* _STRING_ARRAY_H_ */
1756dc
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
1756dc
index 1cfebeab6bf3b36e760372b05482fd9f322feab1..e1505e6b5787a669065e5ea3c7acf55ea110c4da 100644
1756dc
--- a/src/tests/Makefile.am
1756dc
+++ b/src/tests/Makefile.am
1756dc
@@ -23,6 +23,7 @@ check_PROGRAMS = $(TESTS)
1756dc
 test_util_string_array_SOURCES = \
1756dc
     test_util_string_array.c \
1756dc
     ../lib/util/string_array.c \
1756dc
+    ../lib/util/string.c \
1756dc
     $(NULL)
1756dc
 test_util_string_array_CFLAGS = \
1756dc
     $(AM_CFLAGS)
1756dc
-- 
1756dc
2.17.2
1756dc