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

240 lines
7.1 KiB
Diff
Raw Normal View History

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