Blob Blame History Raw
diff --git a/src/OVAL/probes/unix/linux/systemdunitdependency.c b/src/OVAL/probes/unix/linux/systemdunitdependency.c
index 2f194ce07..e2cbdb7d2 100644
--- a/src/OVAL/probes/unix/linux/systemdunitdependency.c
+++ b/src/OVAL/probes/unix/linux/systemdunitdependency.c
@@ -37,6 +37,8 @@
 #include "common/list.h"
 #include <string.h>
 
+static void get_all_dependencies_by_unit(DBusConnection *conn, const char *unit, SEXP_t *item, struct oscap_htable *visited_units);
+
 static char *get_property_by_unit_path(DBusConnection *conn, const char *unit_path, const char *property)
 {
 	DBusMessage *msg = NULL;
@@ -135,7 +137,38 @@ static bool is_unit_name_a_target(const char *unit)
 	return strncmp(unit + len - suffix_len, suffix, suffix_len) == 0;
 }
 
-static void get_all_dependencies_by_unit(DBusConnection *conn, const char *unit, int(*callback)(const char *, void *), void *cbarg, bool include_requires, bool include_wants)
+static int add_unit_dependency(const char *dependency, SEXP_t *item, struct oscap_htable *visited_units)
+{
+	if (oscap_htable_get(visited_units, dependency) != NULL) {
+		return 1;
+	}
+	oscap_htable_add(visited_units, dependency, (void *) true);
+	SEXP_t *se_dependency = SEXP_string_new(dependency, strlen(dependency));
+	probe_item_ent_add(item, "dependency", NULL, se_dependency);
+	SEXP_free(se_dependency);
+	return 0;
+}
+
+static void process_unit_property(const char *property, DBusConnection *conn, const char *path, SEXP_t *item, struct oscap_htable *visited_units)
+{
+	char *values_s = get_property_by_unit_path(conn, path, property);
+	if (values_s) {
+		char **values = oscap_split(values_s, ", ");
+		for (int i = 0; values[i] != NULL; ++i) {
+			if (oscap_strcmp(values[i], "") == 0) {
+				continue;
+			}
+
+			if (add_unit_dependency(values[i], item, visited_units) == 0) {
+				get_all_dependencies_by_unit(conn, values[i], item, visited_units);
+			}
+		}
+		free(values);
+	}
+	free(values_s);
+}
+
+static void get_all_dependencies_by_unit(DBusConnection *conn, const char *unit, SEXP_t *item, struct oscap_htable *visited_units)
 {
 	if (!unit || strcmp(unit, "(null)") == 0)
 		return;
@@ -146,66 +179,12 @@ static void get_all_dependencies_by_unit(DBusConnection *conn, const char *unit,
 
 	char *path = get_path_by_unit(conn, unit);
 
-	if (include_requires) {
-		char *requires_s = get_property_by_unit_path(conn, path, "Requires");
-		if (requires_s) {
-			char **requires = oscap_split(requires_s, ", ");
-			for (int i = 0; requires[i] != NULL; ++i) {
-				if (oscap_strcmp(requires[i], "") == 0)
-					continue;
-
-				if (callback(requires[i], cbarg) == 0) {
-					get_all_dependencies_by_unit(conn, requires[i],
-									callback, cbarg,
-									include_requires, include_wants);
-				} else {
-					free(requires);
-					free(requires_s);
-					free(path);
-					return;
-				}
-			}
-			free(requires);
-		}
-		free(requires_s);
-	}
-
-	if (include_wants) {
-		char *wants_s = get_property_by_unit_path(conn, path, "Wants");
-		if (wants_s)
-		{
-			char **wants = oscap_split(wants_s, ", ");
-			for (int i = 0; wants[i] != NULL; ++i) {
-				if (oscap_strcmp(wants[i], "") == 0)
-					continue;
-
-				if (callback(wants[i], cbarg) == 0) {
-					get_all_dependencies_by_unit(conn, wants[i],
-									callback, cbarg,
-									include_requires, include_wants);
-				} else {
-					free(wants);
-					free(wants_s);
-					free(path);
-					return;
-				}
-			}
-			free(wants);
-		}
-		free(wants_s);
-	}
+	process_unit_property("Requires", conn, path, item, visited_units);
+	process_unit_property("Wants", conn, path, item, visited_units);
 
 	free(path);
 }
 
-static int dependency_callback(const char *dependency, void *cbarg)
-{
-	SEXP_t *item = (SEXP_t *)cbarg;
-	SEXP_t *se_dependency = SEXP_string_new(dependency, strlen(dependency));
-	probe_item_ent_add(item, "dependency", NULL, se_dependency);
-	return 0;
-}
-
 static int unit_callback(const char *unit, void *cbarg)
 {
 	struct unit_callback_vars *vars = (struct unit_callback_vars *)cbarg;
@@ -221,8 +200,9 @@ static int unit_callback(const char *unit, void *cbarg)
 					 "unit", OVAL_DATATYPE_SEXP, se_unit,
 					 NULL);
 
-	get_all_dependencies_by_unit(vars->dbus_conn, unit,
-				     dependency_callback, item, true, true);
+	struct oscap_htable *visited_units = oscap_htable_new();
+	get_all_dependencies_by_unit(vars->dbus_conn, unit, item, visited_units);
+	oscap_htable_free(visited_units, NULL);
 
 	probe_item_collect(vars->ctx, item);
 	SEXP_free(se_unit);