4848#include "xccdf_policy_model_priv.h"
4949#include "public/xccdf_policy.h"
5050#include "oscap_helpers.h"
51+ #include "xccdf_benchmark.h"
5152
5253struct kickstart_commands {
5354 struct oscap_list * package_install ;
@@ -764,12 +765,12 @@ static inline int _parse_blueprint_fix(const char *fix_text, struct blueprint_cu
764765 return ret ;
765766}
766767
767- static inline int _parse_ansible_fix (const char * fix_text , struct oscap_list * variables , struct oscap_list * tasks )
768+ static inline int _parse_ansible_fix (struct xccdf_policy * policy , const char * fix_text , struct oscap_list * variables , struct oscap_list * tasks )
768769{
769770 // TODO: Tolerate different indentation styles in this regex
770771 const char * pattern =
771772 "- name: XCCDF Value [^ ]+ # promote to variable\n set_fact:\n"
772- " ([^:]+): (.+)\n tags:\n - always\n" ;
773+ " ([^:]+): (!!str )?( .+)\n tags:\n - always\n" ;
773774 char * err ;
774775 int errofs ;
775776
@@ -783,11 +784,11 @@ static inline int _parse_ansible_fix(const char *fix_text, struct oscap_list *va
783784
784785 // ovector sizing:
785786 // 2 elements are used for the whole needle,
786- // 4 elements are used for the 2 capture groups
787+ // 6 elements are used for the 3 capture groups
787788 // pcre documentation says we should allocate a third extra for additional
788789 // workspace.
789- // (2 + 4 ) * (3 / 2) = 9
790- int ovector [9 ];
790+ // (2 + 6 ) * (3 / 2) = 12
791+ int ovector [12 ];
791792
792793 const size_t fix_text_len = strlen (fix_text );
793794 int start_offset = 0 ;
@@ -796,8 +797,8 @@ static inline int _parse_ansible_fix(const char *fix_text, struct oscap_list *va
796797 0 , ovector , sizeof (ovector ) / sizeof (ovector [0 ]));
797798 if (match == -1 )
798799 break ;
799- if (match != 3 ) {
800- dE ("Expected 2 capture group matches per XCCDF variable. Found %i!" ,
800+ if (match != 4 ) {
801+ dE ("Expected 3 capture group matches per XCCDF variable. Found %i!" ,
801802 match - 1 );
802803 oscap_pcre_free (re );
803804 return 1 ;
@@ -806,18 +807,44 @@ static inline int _parse_ansible_fix(const char *fix_text, struct oscap_list *va
806807 // ovector[0] and [1] hold the start and end of the whole needle match
807808 // ovector[2] and [3] hold the start and end of the first capture group
808809 // ovector[4] and [5] hold the start and end of the second capture group
810+ // ovector[6] and [7] hold the start and end of the third capture group
809811 char * variable_name = malloc ((ovector [3 ] - ovector [2 ] + 1 ) * sizeof (char ));
810812 memcpy (variable_name , & fix_text [ovector [2 ]], ovector [3 ] - ovector [2 ]);
811813 variable_name [ovector [3 ] - ovector [2 ]] = '\0' ;
812814
813- char * variable_value = malloc ((ovector [5 ] - ovector [4 ] + 1 ) * sizeof (char ));
814- memcpy (variable_value , & fix_text [ovector [4 ]], ovector [5 ] - ovector [4 ]);
815- variable_value [ovector [5 ] - ovector [4 ]] = '\0' ;
815+ char * cast = malloc ((ovector [5 ] - ovector [4 ] + 1 ) * sizeof (char ));
816+ memcpy (cast , & fix_text [ovector [4 ]], ovector [5 ] - ovector [4 ]);
817+ cast [ovector [5 ] - ovector [4 ]] = '\0' ;
816818
817- char * var_line = oscap_sprintf (" %s: %s\n" , variable_name , variable_value );
819+ char * variable_id = malloc ((ovector [7 ] - ovector [6 ] + 1 ) * sizeof (char ));
820+ memcpy (variable_id , & fix_text [ovector [6 ]], ovector [7 ] - ovector [6 ]);
821+ variable_id [ovector [7 ] - ovector [6 ]] = '\0' ;
822+
823+ char * variable_value = NULL ;
824+ struct xccdf_item * item = xccdf_benchmark_get_item (xccdf_policy_get_benchmark (policy ), variable_id );
825+ if (item == NULL ) {
826+ dI ("Variable not found: %s" , variable_id );
827+ variable_value = strdup (variable_id );
828+ } else {
829+ variable_value = strdup (xccdf_policy_get_value_of_item (policy , item ));
830+ }
831+ free (variable_id );
832+
833+ char * var_line ;
834+ if (strchr (variable_value , '\n' ) != NULL ) {
835+ /* The value contains a multiline string. To ensure a valid YAML output
836+ we need to put is as scalar block and indent it.*/
837+ char * indented_variable_value = oscap_indent (variable_value , 6 );
838+ const char * terminator = oscap_str_endswith (indented_variable_value , "\n" ) ? "" : "\n" ;
839+ var_line = oscap_sprintf (" %s: %s|\n%s%s" , variable_name , cast , indented_variable_value , terminator );
840+ free (indented_variable_value );
841+ } else {
842+ var_line = oscap_sprintf (" %s: %s%s\n" , variable_name , cast , variable_value );
843+ }
818844
819845 free (variable_name );
820846 free (variable_value );
847+ free (cast );
821848
822849 if (!oscap_list_contains (variables , var_line , (oscap_cmp_func ) oscap_streq )) {
823850 oscap_list_add (variables , var_line );
@@ -829,7 +856,10 @@ static inline int _parse_ansible_fix(const char *fix_text, struct oscap_list *va
829856 char * remediation_part = malloc ((length_between_matches + 1 ) * sizeof (char ));
830857 memcpy (remediation_part , & fix_text [start_offset ], length_between_matches );
831858 remediation_part [length_between_matches ] = '\0' ;
832- oscap_list_add (tasks , remediation_part );
859+ oscap_trim (remediation_part );
860+ if (strlen (remediation_part ) > 0 ) {
861+ oscap_list_add (tasks , remediation_part );
862+ }
833863
834864 start_offset = ovector [1 ]; // next time start after the entire pattern
835865 }
@@ -838,7 +868,10 @@ static inline int _parse_ansible_fix(const char *fix_text, struct oscap_list *va
838868 char * remediation_part = malloc ((fix_text_len - start_offset + 1 ) * sizeof (char ));
839869 memcpy (remediation_part , & fix_text [start_offset ], fix_text_len - start_offset );
840870 remediation_part [fix_text_len - start_offset ] = '\0' ;
841- oscap_list_add (tasks , remediation_part );
871+ oscap_trim (remediation_part );
872+ if (strlen (remediation_part ) > 0 ) {
873+ oscap_list_add (tasks , remediation_part );
874+ }
842875 }
843876
844877 oscap_pcre_free (re );
@@ -863,7 +896,12 @@ static int _xccdf_policy_rule_get_fix_text(struct xccdf_policy *policy, struct x
863896
864897 // Process Text Substitute within the fix
865898 struct xccdf_fix * cfix = xccdf_fix_clone (fix );
866- int res = xccdf_policy_resolve_fix_substitution (policy , cfix , NULL , NULL );
899+ int res = 0 ;
900+ if (strcmp (template , "urn:xccdf:fix:script:ansible" ) == 0 ) {
901+ res = xccdf_policy_resolve_fix_substitution_ansible (policy , cfix , NULL , NULL );
902+ } else {
903+ res = xccdf_policy_resolve_fix_substitution (policy , cfix , NULL , NULL );
904+ }
867905 if (res != 0 ) {
868906 oscap_seterr (OSCAP_EFAMILY_OSCAP , "A fix for Rule/@id=\"%s\" was skipped: Text substitution failed." ,
869907 xccdf_rule_get_id (rule ));
@@ -1128,7 +1166,7 @@ static int _xccdf_policy_rule_generate_ansible_fix(struct xccdf_policy *policy,
11281166 if (fix_text == NULL ) {
11291167 return ret ;
11301168 }
1131- ret = _parse_ansible_fix (fix_text , variables , tasks );
1169+ ret = _parse_ansible_fix (policy , fix_text , variables , tasks );
11321170 free (fix_text );
11331171 return ret ;
11341172}
0 commit comments