Blame SOURCES/openscap-1.2.18-prevent_duplicate_vars_in_playbooks-PR_1274.patch

8b65ee
From 84e2041d3b6d9a240ddab3f39c7baed8e718bfab Mon Sep 17 00:00:00 2001
8b65ee
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
8b65ee
Date: Tue, 20 Nov 2018 12:00:48 +0100
8b65ee
Subject: [PATCH 1/4] Prevent duplicate variables in Ansible Playbooks
8b65ee
8b65ee
The same XCCDF value can appear in multiple rules, which means
8b65ee
there can be same variable in multiple Ansible task. But when
8b65ee
we generate a Playbook we should put the variable only once.
8b65ee
Ansible produces a warning if there are multiple definitions
8b65ee
of the same variable.
8b65ee
---
8b65ee
 src/XCCDF_POLICY/xccdf_policy_remediate.c | 180 ++++++++++++----------
8b65ee
 1 file changed, 95 insertions(+), 85 deletions(-)
8b65ee
8b65ee
diff --git a/src/XCCDF_POLICY/xccdf_policy_remediate.c b/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
index 65544c7f74..6ac566225c 100644
8b65ee
--- a/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
+++ b/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
@@ -134,11 +134,11 @@ static int _write_remediation_to_fd_and_free(int output_fd, const char* template
8b65ee
 					free(text);
8b65ee
 					return 1;
8b65ee
 				}
8b65ee
-			}
8b65ee
 
8b65ee
-			if (_write_text_to_fd(output_fd, "\n") != 0) {
8b65ee
-				free(text);
8b65ee
-				return 1;
8b65ee
+				if (_write_text_to_fd(output_fd, "\n") != 0) {
8b65ee
+					free(text);
8b65ee
+					return 1;
8b65ee
+				}
8b65ee
 			}
8b65ee
 
8b65ee
 			if (next_delim != NULL) {
8b65ee
@@ -610,7 +610,7 @@ static int _write_fix_missing_warning_to_fd(const char *sys, int output_fd, stru
8b65ee
 	}
8b65ee
 }
8b65ee
 
8b65ee
-static inline int _xccdf_policy_rule_generate_fix_ansible(const char *template, int output_fd, const char *fix_text, bool ansible_variable_mode)
8b65ee
+static inline int _parse_ansible_fix(const char *fix_text, struct oscap_list *variables, struct oscap_list *tasks)
8b65ee
 {
8b65ee
 #if defined USE_REGEX_PCRE
8b65ee
 	// TODO: Tolerate different indentation styles in this regex
8b65ee
@@ -649,69 +649,53 @@ static inline int _xccdf_policy_rule_generate_fix_ansible(const char *template,
8b65ee
 			return 1;
8b65ee
 		}
8b65ee
 
8b65ee
-		if (ansible_variable_mode) {
8b65ee
-			// ovector[0] and [1] hold the start and end of the whole needle match
8b65ee
-			// ovector[2] and [3] hold the start and end of the first capture group
8b65ee
-			// ovector[4] and [5] hold the start and end of the second capture group
8b65ee
-			char *variable_name = malloc((ovector[3] - ovector[2] + 1) * sizeof(char));
8b65ee
-			memcpy(variable_name, &fix_text[ovector[2]], ovector[3] - ovector[2]);
8b65ee
-			variable_name[ovector[3] - ovector[2]] = '\0';
8b65ee
+		// ovector[0] and [1] hold the start and end of the whole needle match
8b65ee
+		// ovector[2] and [3] hold the start and end of the first capture group
8b65ee
+		// ovector[4] and [5] hold the start and end of the second capture group
8b65ee
+		char *variable_name = malloc((ovector[3] - ovector[2] + 1) * sizeof(char));
8b65ee
+		memcpy(variable_name, &fix_text[ovector[2]], ovector[3] - ovector[2]);
8b65ee
+		variable_name[ovector[3] - ovector[2]] = '\0';
8b65ee
 
8b65ee
-			char *variable_value = malloc((ovector[5] - ovector[4] + 1) * sizeof(char));
8b65ee
-			memcpy(variable_value, &fix_text[ovector[4]], ovector[5] - ovector[4]);
8b65ee
-			variable_value[ovector[5] - ovector[4]] = '\0';
8b65ee
+		char *variable_value = malloc((ovector[5] - ovector[4] + 1) * sizeof(char));
8b65ee
+		memcpy(variable_value, &fix_text[ovector[4]], ovector[5] - ovector[4]);
8b65ee
+		variable_value[ovector[5] - ovector[4]] = '\0';
8b65ee
 
8b65ee
-			char *var_line = oscap_sprintf("  %s: %s", variable_name, variable_value);
8b65ee
+		char *var_line = oscap_sprintf("      %s: %s\n", variable_name, variable_value);
8b65ee
 
8b65ee
-			free(variable_name);
8b65ee
-			free(variable_value);
8b65ee
+		free(variable_name);
8b65ee
+		free(variable_value);
8b65ee
 
8b65ee
-			if (_write_remediation_to_fd_and_free(output_fd, template, var_line) != 0) {
8b65ee
-				pcre_free(re);
8b65ee
-				return 1;
8b65ee
-			}
8b65ee
-		}
8b65ee
-		else {
8b65ee
-			// Remarks: ovector doesn't contain values relative to start_offset, it contains
8b65ee
-			// absolute indices of fix_text.
8b65ee
-			const int length_between_matches = ovector[0] - start_offset;
8b65ee
-			char *remediation_part = malloc((length_between_matches + 1) * sizeof(char));
8b65ee
-			memcpy(remediation_part, &fix_text[start_offset], length_between_matches);
8b65ee
-			remediation_part[length_between_matches] = '\0';
8b65ee
-			if (_write_remediation_to_fd_and_free(output_fd, template, remediation_part) != 0) {
8b65ee
-				pcre_free(re);
8b65ee
-				return 1;
8b65ee
-			}
8b65ee
+		if (!oscap_list_contains(variables, var_line, (oscap_cmp_func) oscap_streq)) {
8b65ee
+			oscap_list_add(variables, var_line);
8b65ee
 		}
8b65ee
 
8b65ee
+		// Remarks: ovector doesn't contain values relative to start_offset, it contains
8b65ee
+		// absolute indices of fix_text.
8b65ee
+		const int length_between_matches = ovector[0] - start_offset;
8b65ee
+		char *remediation_part = malloc((length_between_matches + 1) * sizeof(char));
8b65ee
+		memcpy(remediation_part, &fix_text[start_offset], length_between_matches);
8b65ee
+		remediation_part[length_between_matches] = '\0';
8b65ee
+		oscap_list_add(tasks, remediation_part);
8b65ee
+
8b65ee
 		start_offset = ovector[1]; // next time start after the entire pattern
8b65ee
 	}
8b65ee
 
8b65ee
-	if (!ansible_variable_mode && fix_text_len - start_offset > 0) {
8b65ee
+	if (fix_text_len - start_offset > 0) {
8b65ee
 		char *remediation_part = malloc((fix_text_len - start_offset + 1) * sizeof(char));
8b65ee
 		memcpy(remediation_part, &fix_text[start_offset], fix_text_len - start_offset);
8b65ee
 		remediation_part[fix_text_len - start_offset] = '\0';
8b65ee
-
8b65ee
-		if (_write_remediation_to_fd_and_free(output_fd, template, remediation_part) != 0) {
8b65ee
-			pcre_free(re);
8b65ee
-			return 1;
8b65ee
-		}
8b65ee
+		oscap_list_add(tasks, remediation_part);
8b65ee
 	}
8b65ee
 
8b65ee
 	pcre_free(re);
8b65ee
 	return 0;
8b65ee
 #else
8b65ee
 	// TODO: Implement the post-process for posix regex as well
8b65ee
-	if (ansible_variable_mode) {
8b65ee
-		// this is not implemented so we don't write anything out for variables
8b65ee
-		return 0;
8b65ee
-	}
8b65ee
-	else
8b65ee
-		return _write_remediation_to_fd_and_free(output_fd, template, fix_text);
8b65ee
+	oscap_list_add(tasks, strdup(fix_text));
8b65ee
 #endif
8b65ee
 }
8b65ee
 
8b65ee
-static inline int _xccdf_policy_rule_generate_fix(struct xccdf_policy *policy, struct xccdf_rule *rule, const char *template, int output_fd, unsigned int current, unsigned int total, bool ansible_variable_mode)
8b65ee
+static int _xccdf_policy_rule_get_fix_text(struct xccdf_policy *policy, struct xccdf_rule *rule, const char *template, char **fix_text)
8b65ee
 {
8b65ee
 	// Ensure that given Rule is selected and applicable (CPE).
8b65ee
 	const bool is_selected = xccdf_policy_is_item_selected(policy, xccdf_rule_get_id(rule));
8b65ee
@@ -722,15 +706,8 @@ static inline int _xccdf_policy_rule_generate_fix(struct xccdf_policy *policy, s
8b65ee
 	// Find the most suitable fix.
8b65ee
 	const struct xccdf_fix *fix = _find_fix_for_template(policy, rule, template);
8b65ee
 	if (fix == NULL) {
8b65ee
-		int ret = _write_fix_header_to_fd(template, output_fd, rule, current, total);
8b65ee
-		if (ret != 0)
8b65ee
-			return ret;
8b65ee
-		ret = _write_fix_missing_warning_to_fd(template, output_fd, rule);
8b65ee
-		if (ret != 0)
8b65ee
-			return ret;
8b65ee
-		ret = _write_fix_footer_to_fd(template, output_fd, rule);
8b65ee
 		dI("No fix element was found for Rule/@id=\"%s\"", xccdf_rule_get_id(rule));
8b65ee
-		return ret;
8b65ee
+		return 0;
8b65ee
 	}
8b65ee
 	dI("Processing a fix for Rule/@id=\"%s\"", xccdf_rule_get_id(rule));
8b65ee
 
8b65ee
@@ -744,37 +721,55 @@ static inline int _xccdf_policy_rule_generate_fix(struct xccdf_policy *policy, s
8b65ee
 		return res == 1; // Value 2 indicates warning.
8b65ee
 	}
8b65ee
 	// Refine. Resolve XML comments, CDATA and remaining elements
8b65ee
-	char *fix_text = NULL;
8b65ee
-	if (_xccdf_fix_decode_xml(cfix, &fix_text) != 0) {
8b65ee
+	if (_xccdf_fix_decode_xml(cfix, fix_text) != 0) {
8b65ee
 		oscap_seterr(OSCAP_EFAMILY_OSCAP, "A fix element for Rule/@id=\"%s\" contains unresolved child elements.",
8b65ee
 				xccdf_rule_get_id(rule));
8b65ee
 		xccdf_fix_free(cfix);
8b65ee
 		return 1;
8b65ee
 	}
8b65ee
 	xccdf_fix_free(cfix);
8b65ee
+	return 0;
8b65ee
+}
8b65ee
 
8b65ee
-	int ret = _write_fix_header_to_fd(template, output_fd, rule, current, total);
8b65ee
+static int _xccdf_policy_rule_generate_fix(struct xccdf_policy *policy, struct xccdf_rule *rule, const char *template, int output_fd, unsigned int current, unsigned int total, bool ansible_variable_mode)
8b65ee
+{
8b65ee
+	char *fix_text = NULL;
8b65ee
+	int ret = _xccdf_policy_rule_get_fix_text(policy, rule, template, &fix_text);
8b65ee
+	if (fix_text == NULL || ret != 0) {
8b65ee
+		ret = _write_fix_header_to_fd(template, output_fd, rule, current, total);
8b65ee
+		if (ret != 0) {
8b65ee
+			return ret;
8b65ee
+		}
8b65ee
+		ret = _write_fix_missing_warning_to_fd(template, output_fd, rule);
8b65ee
+		if (ret != 0) {
8b65ee
+			return ret;
8b65ee
+		}
8b65ee
+		ret = _write_fix_footer_to_fd(template, output_fd, rule);
8b65ee
+		return ret;
8b65ee
+	}
8b65ee
+	ret = _write_fix_header_to_fd(template, output_fd, rule, current, total);
8b65ee
 	if (ret != 0) {
8b65ee
 		free(fix_text);
8b65ee
 		return ret;
8b65ee
 	}
8b65ee
+	ret = _write_remediation_to_fd_and_free(output_fd, template, fix_text);
8b65ee
+	if (ret != 0) {
8b65ee
+		return ret;
8b65ee
+	}
8b65ee
+	ret = _write_fix_footer_to_fd(template, output_fd, rule);
8b65ee
+	return ret;
8b65ee
+}
8b65ee
 
8b65ee
-	if (oscap_streq(template, "urn:xccdf:fix:script:ansible")) {
8b65ee
-		// Ansible is special because we have two output modes, variable and
8b65ee
-		// task mode. In both cases we have to do post processing. 
8b65ee
 
8b65ee
-		// We can't recover the return value (it is rewritten by a later call) to _write_fix_footer_to_fd
8b65ee
-		_xccdf_policy_rule_generate_fix_ansible(template, output_fd, fix_text, ansible_variable_mode);
8b65ee
-		free(fix_text);
8b65ee
-	}
8b65ee
-	else {
8b65ee
-		ret = _write_remediation_to_fd_and_free(output_fd, template, fix_text);
8b65ee
-		if (ret != 0) {
8b65ee
-			return ret;
8b65ee
-		}
8b65ee
+static int _xccdf_policy_rule_generate_ansible_fix(struct xccdf_policy *policy, struct xccdf_rule *rule, const char *template, struct oscap_list *variables, struct oscap_list *tasks)
8b65ee
+{
8b65ee
+	char *fix_text = NULL;
8b65ee
+	int ret = _xccdf_policy_rule_get_fix_text(policy, rule, template, &fix_text);
8b65ee
+	if (fix_text == NULL) {
8b65ee
+		return ret;
8b65ee
 	}
8b65ee
-
8b65ee
-	ret = _write_fix_footer_to_fd(template, output_fd, rule);
8b65ee
+	ret = _parse_ansible_fix(fix_text, variables, tasks);
8b65ee
+	free(fix_text);
8b65ee
 	return ret;
8b65ee
 }
8b65ee
 
8b65ee
@@ -988,30 +983,45 @@ int xccdf_policy_generate_fix(struct xccdf_policy *policy, struct xccdf_result *
8b65ee
 
8b65ee
 	// In Ansible we have to generate variables first and then tasks
8b65ee
 	if (strcmp(sys, "urn:xccdf:fix:script:ansible") == 0) {
8b65ee
+		struct oscap_list *variables = oscap_list_new();
8b65ee
+		struct oscap_list *tasks = oscap_list_new();
8b65ee
+		struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
8b65ee
+		while (oscap_iterator_has_more(rules_to_fix_it)) {
8b65ee
+			struct xccdf_rule *rule = (struct xccdf_rule*)oscap_iterator_next(rules_to_fix_it);
8b65ee
+			ret = _xccdf_policy_rule_generate_ansible_fix(policy, rule, sys, variables, tasks);
8b65ee
+			if (ret != 0)
8b65ee
+				break;
8b65ee
+		}
8b65ee
+		oscap_iterator_free(rules_to_fix_it);
8b65ee
+
8b65ee
 		_write_text_to_fd(output_fd, "   vars:\n");
8b65ee
+		struct oscap_iterator *variables_it = oscap_iterator_new(variables);
8b65ee
+		while(oscap_iterator_has_more(variables_it)) {
8b65ee
+			char *var_line = (char *) oscap_iterator_next(variables_it);
8b65ee
+			_write_text_to_fd(output_fd, var_line);
8b65ee
+		}
8b65ee
+		oscap_iterator_free(variables_it);
8b65ee
+		oscap_list_free(variables, free);
8b65ee
 
8b65ee
+		_write_text_to_fd(output_fd, "   tasks:\n");
8b65ee
+		struct oscap_iterator *tasks_it = oscap_iterator_new(tasks);
8b65ee
+		while(oscap_iterator_has_more(tasks_it)) {
8b65ee
+			char *var_line = strdup((char *) oscap_iterator_next(tasks_it));
8b65ee
+			_write_remediation_to_fd_and_free(output_fd, sys, var_line);
8b65ee
+		}
8b65ee
+		oscap_iterator_free(tasks_it);
8b65ee
+		oscap_list_free(tasks, free);
8b65ee
+	} else {
8b65ee
 		unsigned int current = 1;
8b65ee
 		struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
8b65ee
 		while (oscap_iterator_has_more(rules_to_fix_it)) {
8b65ee
 			struct xccdf_rule *rule = (struct xccdf_rule*)oscap_iterator_next(rules_to_fix_it);
8b65ee
-			ret = _xccdf_policy_rule_generate_fix(policy, rule, sys, output_fd, current++, total, true);
8b65ee
+			ret = _xccdf_policy_rule_generate_fix(policy, rule, sys, output_fd, current++, total, false);
8b65ee
 			if (ret != 0)
8b65ee
 				break;
8b65ee
 		}
8b65ee
 		oscap_iterator_free(rules_to_fix_it);
8b65ee
-
8b65ee
-		_write_text_to_fd(output_fd, "   tasks:\n");
8b65ee
-	}
8b65ee
-
8b65ee
-	unsigned int current = 1;
8b65ee
-	struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
8b65ee
-	while (oscap_iterator_has_more(rules_to_fix_it)) {
8b65ee
-		struct xccdf_rule *rule = (struct xccdf_rule*)oscap_iterator_next(rules_to_fix_it);
8b65ee
-		ret = _xccdf_policy_rule_generate_fix(policy, rule, sys, output_fd, current++, total, false);
8b65ee
-		if (ret != 0)
8b65ee
-			break;
8b65ee
 	}
8b65ee
-	oscap_iterator_free(rules_to_fix_it);
8b65ee
 
8b65ee
 	oscap_list_free(rules_to_fix, NULL);
8b65ee
 
8b65ee
8b65ee
From 8badfbf30f423ca2f9452ab3ac6daf8bb8d850e3 Mon Sep 17 00:00:00 2001
8b65ee
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
8b65ee
Date: Thu, 22 Nov 2018 13:43:40 +0100
8b65ee
Subject: [PATCH 2/4] Remove unused parameter
8b65ee
8b65ee
This parameter is not used in this function. The function is static
8b65ee
and it is used only at one place, so we can safely omit this parameter.
8b65ee
---
8b65ee
 src/XCCDF_POLICY/xccdf_policy_remediate.c | 4 ++--
8b65ee
 1 file changed, 2 insertions(+), 2 deletions(-)
8b65ee
8b65ee
diff --git a/src/XCCDF_POLICY/xccdf_policy_remediate.c b/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
index 6ac566225c..520e9ff4de 100644
8b65ee
--- a/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
+++ b/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
@@ -731,7 +731,7 @@ static int _xccdf_policy_rule_get_fix_text(struct xccdf_policy *policy, struct x
8b65ee
 	return 0;
8b65ee
 }
8b65ee
 
8b65ee
-static int _xccdf_policy_rule_generate_fix(struct xccdf_policy *policy, struct xccdf_rule *rule, const char *template, int output_fd, unsigned int current, unsigned int total, bool ansible_variable_mode)
8b65ee
+static int _xccdf_policy_rule_generate_fix(struct xccdf_policy *policy, struct xccdf_rule *rule, const char *template, int output_fd, unsigned int current, unsigned int total)
8b65ee
 {
8b65ee
 	char *fix_text = NULL;
8b65ee
 	int ret = _xccdf_policy_rule_get_fix_text(policy, rule, template, &fix_text);
8b65ee
@@ -1016,7 +1016,7 @@ int xccdf_policy_generate_fix(struct xccdf_policy *policy, struct xccdf_result *
8b65ee
 		struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
8b65ee
 		while (oscap_iterator_has_more(rules_to_fix_it)) {
8b65ee
 			struct xccdf_rule *rule = (struct xccdf_rule*)oscap_iterator_next(rules_to_fix_it);
8b65ee
-			ret = _xccdf_policy_rule_generate_fix(policy, rule, sys, output_fd, current++, total, false);
8b65ee
+			ret = _xccdf_policy_rule_generate_fix(policy, rule, sys, output_fd, current++, total);
8b65ee
 			if (ret != 0)
8b65ee
 				break;
8b65ee
 		}
8b65ee
8b65ee
From 90e0354c3eef165d8b467e6d843e9dfe1d264416 Mon Sep 17 00:00:00 2001
8b65ee
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
8b65ee
Date: Mon, 26 Nov 2018 18:18:47 +0100
8b65ee
Subject: [PATCH 3/4] Refactor: Extract functions
8b65ee
8b65ee
To improve the readability of the code we can refactor the code
8b65ee
that is specific to Ansible to a separate method. We can also make
8b65ee
a similar change in the `else` branch.
8b65ee
---
8b65ee
 src/XCCDF_POLICY/xccdf_policy_remediate.c | 94 +++++++++++++----------
8b65ee
 1 file changed, 54 insertions(+), 40 deletions(-)
8b65ee
8b65ee
diff --git a/src/XCCDF_POLICY/xccdf_policy_remediate.c b/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
index 520e9ff4de..bf36523dfd 100644
8b65ee
--- a/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
+++ b/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
@@ -929,6 +929,56 @@ static int _write_script_header_to_fd(struct xccdf_policy *policy, struct xccdf_
8b65ee
 	}
8b65ee
 }
8b65ee
 
8b65ee
+static int _xccdf_policy_generate_fix_ansible(struct oscap_list *rules_to_fix, struct xccdf_policy *policy, const char *sys, int output_fd)
8b65ee
+{
8b65ee
+	int ret = 0;
8b65ee
+	struct oscap_list *variables = oscap_list_new();
8b65ee
+	struct oscap_list *tasks = oscap_list_new();
8b65ee
+	struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
8b65ee
+	while (oscap_iterator_has_more(rules_to_fix_it)) {
8b65ee
+		struct xccdf_rule *rule = (struct xccdf_rule*)oscap_iterator_next(rules_to_fix_it);
8b65ee
+		ret = _xccdf_policy_rule_generate_ansible_fix(policy, rule, sys, variables, tasks);
8b65ee
+		if (ret != 0)
8b65ee
+			break;
8b65ee
+	}
8b65ee
+	oscap_iterator_free(rules_to_fix_it);
8b65ee
+
8b65ee
+	_write_text_to_fd(output_fd, "   vars:\n");
8b65ee
+	struct oscap_iterator *variables_it = oscap_iterator_new(variables);
8b65ee
+	while(oscap_iterator_has_more(variables_it)) {
8b65ee
+		char *var_line = (char *) oscap_iterator_next(variables_it);
8b65ee
+		_write_text_to_fd(output_fd, var_line);
8b65ee
+	}
8b65ee
+	oscap_iterator_free(variables_it);
8b65ee
+	oscap_list_free(variables, free);
8b65ee
+
8b65ee
+	_write_text_to_fd(output_fd, "   tasks:\n");
8b65ee
+	struct oscap_iterator *tasks_it = oscap_iterator_new(tasks);
8b65ee
+	while(oscap_iterator_has_more(tasks_it)) {
8b65ee
+		char *var_line = strdup((char *) oscap_iterator_next(tasks_it));
8b65ee
+		_write_remediation_to_fd_and_free(output_fd, sys, var_line);
8b65ee
+	}
8b65ee
+	oscap_iterator_free(tasks_it);
8b65ee
+	oscap_list_free(tasks, free);
8b65ee
+	return ret;
8b65ee
+}
8b65ee
+
8b65ee
+static int _xccdf_policy_generate_fix_other(struct oscap_list *rules_to_fix, struct xccdf_policy *policy, const char *sys, int output_fd)
8b65ee
+{
8b65ee
+	int ret = 0;
8b65ee
+	const unsigned int total = oscap_list_get_itemcount(rules_to_fix);
8b65ee
+	unsigned int current = 1;
8b65ee
+	struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
8b65ee
+	while (oscap_iterator_has_more(rules_to_fix_it)) {
8b65ee
+		struct xccdf_rule *rule = (struct xccdf_rule *) oscap_iterator_next(rules_to_fix_it);
8b65ee
+		ret = _xccdf_policy_rule_generate_fix(policy, rule, sys, output_fd, current++, total);
8b65ee
+		if (ret != 0)
8b65ee
+			break;
8b65ee
+	}
8b65ee
+	oscap_iterator_free(rules_to_fix_it);
8b65ee
+	return ret;
8b65ee
+}
8b65ee
+
8b65ee
 int xccdf_policy_generate_fix(struct xccdf_policy *policy, struct xccdf_result *result, const char *sys, int output_fd)
8b65ee
 {
8b65ee
 	__attribute__nonnull__(policy);
8b65ee
@@ -979,48 +1029,12 @@ int xccdf_policy_generate_fix(struct xccdf_policy *policy, struct xccdf_result *
8b65ee
 		xccdf_rule_result_iterator_free(rr_it);
8b65ee
 	}
8b65ee
 
8b65ee
-	const unsigned int total = oscap_list_get_itemcount(rules_to_fix);
8b65ee
-
8b65ee
-	// In Ansible we have to generate variables first and then tasks
8b65ee
+	// Ansible Playbooks are generated using a different function because
8b65ee
+	// in Ansible we have to generate variables first and then tasks
8b65ee
 	if (strcmp(sys, "urn:xccdf:fix:script:ansible") == 0) {
8b65ee
-		struct oscap_list *variables = oscap_list_new();
8b65ee
-		struct oscap_list *tasks = oscap_list_new();
8b65ee
-		struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
8b65ee
-		while (oscap_iterator_has_more(rules_to_fix_it)) {
8b65ee
-			struct xccdf_rule *rule = (struct xccdf_rule*)oscap_iterator_next(rules_to_fix_it);
8b65ee
-			ret = _xccdf_policy_rule_generate_ansible_fix(policy, rule, sys, variables, tasks);
8b65ee
-			if (ret != 0)
8b65ee
-				break;
8b65ee
-		}
8b65ee
-		oscap_iterator_free(rules_to_fix_it);
8b65ee
-
8b65ee
-		_write_text_to_fd(output_fd, "   vars:\n");
8b65ee
-		struct oscap_iterator *variables_it = oscap_iterator_new(variables);
8b65ee
-		while(oscap_iterator_has_more(variables_it)) {
8b65ee
-			char *var_line = (char *) oscap_iterator_next(variables_it);
8b65ee
-			_write_text_to_fd(output_fd, var_line);
8b65ee
-		}
8b65ee
-		oscap_iterator_free(variables_it);
8b65ee
-		oscap_list_free(variables, free);
8b65ee
-
8b65ee
-		_write_text_to_fd(output_fd, "   tasks:\n");
8b65ee
-		struct oscap_iterator *tasks_it = oscap_iterator_new(tasks);
8b65ee
-		while(oscap_iterator_has_more(tasks_it)) {
8b65ee
-			char *var_line = strdup((char *) oscap_iterator_next(tasks_it));
8b65ee
-			_write_remediation_to_fd_and_free(output_fd, sys, var_line);
8b65ee
-		}
8b65ee
-		oscap_iterator_free(tasks_it);
8b65ee
-		oscap_list_free(tasks, free);
8b65ee
+		ret = _xccdf_policy_generate_fix_ansible(rules_to_fix, policy, sys, output_fd);
8b65ee
 	} else {
8b65ee
-		unsigned int current = 1;
8b65ee
-		struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
8b65ee
-		while (oscap_iterator_has_more(rules_to_fix_it)) {
8b65ee
-			struct xccdf_rule *rule = (struct xccdf_rule*)oscap_iterator_next(rules_to_fix_it);
8b65ee
-			ret = _xccdf_policy_rule_generate_fix(policy, rule, sys, output_fd, current++, total);
8b65ee
-			if (ret != 0)
8b65ee
-				break;
8b65ee
-		}
8b65ee
-		oscap_iterator_free(rules_to_fix_it);
8b65ee
+		ret =  _xccdf_policy_generate_fix_other(rules_to_fix, policy, sys, output_fd);
8b65ee
 	}
8b65ee
 
8b65ee
 	oscap_list_free(rules_to_fix, NULL);
8b65ee
8b65ee
From 2a11da0a6a1643669caadb72f1a217fafcfea6d5 Mon Sep 17 00:00:00 2001
8b65ee
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
8b65ee
Date: Wed, 28 Nov 2018 14:19:12 +0100
8b65ee
Subject: [PATCH 4/4] Refactor: Remove duplicate code
8b65ee
8b65ee
---
8b65ee
 src/XCCDF_POLICY/xccdf_policy_remediate.c | 23 +++++++----------------
8b65ee
 1 file changed, 7 insertions(+), 16 deletions(-)
8b65ee
8b65ee
diff --git a/src/XCCDF_POLICY/xccdf_policy_remediate.c b/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
index bf36523dfd..15f9453938 100644
8b65ee
--- a/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
+++ b/src/XCCDF_POLICY/xccdf_policy_remediate.c
8b65ee
@@ -733,26 +733,17 @@ static int _xccdf_policy_rule_get_fix_text(struct xccdf_policy *policy, struct x
8b65ee
 
8b65ee
 static int _xccdf_policy_rule_generate_fix(struct xccdf_policy *policy, struct xccdf_rule *rule, const char *template, int output_fd, unsigned int current, unsigned int total)
8b65ee
 {
8b65ee
+	int ret = _write_fix_header_to_fd(template, output_fd, rule, current, total);
8b65ee
+	if (ret != 0) {
8b65ee
+		return ret;
8b65ee
+	}
8b65ee
 	char *fix_text = NULL;
8b65ee
-	int ret = _xccdf_policy_rule_get_fix_text(policy, rule, template, &fix_text);
8b65ee
+	ret = _xccdf_policy_rule_get_fix_text(policy, rule, template, &fix_text);
8b65ee
 	if (fix_text == NULL || ret != 0) {
8b65ee
-		ret = _write_fix_header_to_fd(template, output_fd, rule, current, total);
8b65ee
-		if (ret != 0) {
8b65ee
-			return ret;
8b65ee
-		}
8b65ee
 		ret = _write_fix_missing_warning_to_fd(template, output_fd, rule);
8b65ee
-		if (ret != 0) {
8b65ee
-			return ret;
8b65ee
-		}
8b65ee
-		ret = _write_fix_footer_to_fd(template, output_fd, rule);
8b65ee
-		return ret;
8b65ee
-	}
8b65ee
-	ret = _write_fix_header_to_fd(template, output_fd, rule, current, total);
8b65ee
-	if (ret != 0) {
8b65ee
-		free(fix_text);
8b65ee
-		return ret;
8b65ee
+	} else {
8b65ee
+		ret = _write_remediation_to_fd_and_free(output_fd, template, fix_text);
8b65ee
 	}
8b65ee
-	ret = _write_remediation_to_fd_and_free(output_fd, template, fix_text);
8b65ee
 	if (ret != 0) {
8b65ee
 		return ret;
8b65ee
 	}