@@ -674,7 +674,7 @@ static inline int _parse_ansible_fix(const char *fix_text, struct oscap_list *va
674
674
memcpy (variable_value , & fix_text [ovector [4 ]], ovector [5 ] - ovector [4 ]);
675
675
variable_value [ovector [5 ] - ovector [4 ]] = '\0' ;
676
676
677
- char * var_line = oscap_sprintf (" %s: %s\n" , variable_name , variable_value );
677
+ char * var_line = oscap_sprintf (" %s: %s\n" , variable_name , variable_value );
678
678
679
679
free (variable_name );
680
680
free (variable_value );
@@ -802,6 +802,72 @@ static int _xccdf_item_recursive_gather_selected_rules(struct xccdf_policy *poli
802
802
return ret ;
803
803
}
804
804
805
+ static void _trim_trailing_whitespace (char * str , size_t str_len )
806
+ {
807
+ char * last_char = str + str_len - 1 ;
808
+ while (isspace (* last_char )) {
809
+ * last_char = '\0' ;
810
+ last_char -- ;
811
+ }
812
+ }
813
+
814
+ /* Handles multiline strings in profile title and description.
815
+ * Puts a '#' at the beginning of each line.
816
+ * Also removes trailing and leading whitespaces on each line.
817
+ */
818
+ static char * _comment_multiline_text (char * text )
819
+ {
820
+ if (text == NULL ) {
821
+ return oscap_strdup ("Not available" );
822
+ }
823
+ const char * filler = "\n# " ;
824
+ size_t buffer_size = strlen (text ) + 1 ; // +1 for terminating '\0'
825
+ char * buffer = malloc (buffer_size );
826
+ char * saveptr ;
827
+ size_t filler_len = strlen (filler );
828
+ size_t result_len = 0 ;
829
+ bool first = true;
830
+ char * str = text ;
831
+ while (true) {
832
+ char * token = oscap_strtok_r (str , "\n" , & saveptr );
833
+ if (token == NULL ) {
834
+ break ;
835
+ }
836
+ /* Strip leading whitespace */
837
+ while (isspace (* token )) {
838
+ token ++ ;
839
+ }
840
+ size_t token_len = strlen (token );
841
+ if (token_len > 0 ) {
842
+ /* Strip trailing whitespace */
843
+ _trim_trailing_whitespace (token , token_len );
844
+ token_len = strlen (token );
845
+ }
846
+ if (token_len > 0 ) {
847
+ /* Copy filler to output buffer */
848
+ if (!first ) {
849
+ if (buffer_size < result_len + filler_len + 1 ) {
850
+ buffer_size += filler_len ;
851
+ buffer = realloc (buffer , buffer_size );
852
+ }
853
+ strncpy (buffer + result_len , filler , filler_len + 1 );
854
+ result_len += filler_len ;
855
+ }
856
+ if (buffer_size < result_len + token_len + 1 ) {
857
+ buffer_size += token_len ;
858
+ buffer = realloc (buffer , buffer_size );
859
+ }
860
+ /* Copy token to output buffer */
861
+ strncpy (buffer + result_len , token , token_len + 1 );
862
+ result_len += token_len ;
863
+ first = false;
864
+ }
865
+ str = NULL ;
866
+ }
867
+ * (buffer + result_len ) = '\0' ;
868
+ return buffer ;
869
+ }
870
+
805
871
static int _write_script_header_to_fd (struct xccdf_policy * policy , struct xccdf_result * result , const char * sys , int output_fd )
806
872
{
807
873
if (!(oscap_streq (sys , "" ) || oscap_streq (sys , "urn:xccdf:fix:script:sh" ) || oscap_streq (sys , "urn:xccdf:fix:commands" ) ||
@@ -815,18 +881,21 @@ static int _write_script_header_to_fd(struct xccdf_policy *policy, struct xccdf_
815
881
"# $ ansible-playbook -i inventory.ini playbook.yml" :
816
882
"# $ sudo ./remediation-script.sh" ;
817
883
const char * oscap_version = oscap_get_version ();
818
- const char * format = sys != NULL ? sys : "" ;
819
- const char * template = sys != NULL ? " --template " : "" ;
884
+ const char * format = ansible_script ? "ansible" : "bash" ;
820
885
const char * remediation_type = ansible_script ? "Ansible Playbook" : "Bash Remediation Script" ;
821
886
822
887
char * fix_header ;
823
888
824
889
struct xccdf_profile * profile = xccdf_policy_get_profile (policy );
825
890
const char * profile_id = xccdf_profile_get_id (profile );
891
+
826
892
// Title
827
893
struct oscap_text_iterator * title_iterator = xccdf_profile_get_title (profile );
828
- char * profile_title = oscap_textlist_get_preferred_plaintext (title_iterator , NULL );
894
+ char * raw_profile_title = oscap_textlist_get_preferred_plaintext (title_iterator , NULL );
829
895
oscap_text_iterator_free (title_iterator );
896
+ char * profile_title = _comment_multiline_text (raw_profile_title );
897
+ free (raw_profile_title );
898
+
830
899
if (result == NULL ) {
831
900
// Profile-based remediation fix
832
901
struct xccdf_benchmark * benchmark = xccdf_policy_get_benchmark (policy );
@@ -838,34 +907,14 @@ static int _write_script_header_to_fd(struct xccdf_policy *policy, struct xccdf_
838
907
char * profile_description = description_iterator != NULL ?
839
908
oscap_textlist_get_preferred_plaintext (description_iterator , NULL ) : NULL ;
840
909
oscap_text_iterator_free (description_iterator );
910
+ char * commented_profile_description = _comment_multiline_text (profile_description );
911
+ free (profile_description );
841
912
842
913
const char * benchmark_version_info = xccdf_benchmark_get_version (benchmark );
843
914
const char * benchmark_id = xccdf_benchmark_get_id (benchmark );
844
915
const struct xccdf_version_info * xccdf_version = xccdf_benchmark_get_schema_version (benchmark );
845
916
const char * xccdf_version_name = xccdf_version_info_get_version (xccdf_version );
846
917
847
- if (NULL != profile_description ) {
848
- size_t new_lines = 0 ;
849
- size_t description_length = 1 ;
850
- for (const char * c = profile_description ; * c != '\0' ; ++ c , ++ description_length )
851
- if (* c == '\n' )
852
- ++ new_lines ;
853
-
854
- if (new_lines > 0 ) {
855
- const char filler [] = "# " ;
856
- char * commented_description = malloc (description_length + new_lines * (sizeof filler - 1 ));
857
- for (size_t i = 0 , j = 0 ; j < description_length ; ++ i , ++ j ) {
858
- commented_description [i ] = profile_description [j ];
859
- if (profile_description [j ] == '\n' ) {
860
- for (size_t k = 0 ; k < (sizeof filler - 1 ); ++ k )
861
- commented_description [++ i ] = filler [k ];
862
- }
863
- }
864
- free (profile_description );
865
- profile_description = commented_description ;
866
- }
867
- }
868
-
869
918
fix_header = oscap_sprintf (
870
919
"###############################################################################\n"
871
920
"#\n"
@@ -880,7 +929,7 @@ static int _write_script_header_to_fd(struct xccdf_policy *policy, struct xccdf_
880
929
"# XCCDF Version: %s\n"
881
930
"#\n"
882
931
"# This file was generated by OpenSCAP %s using:\n"
883
- "# $ oscap xccdf generate fix --profile %s%s %s xccdf-file.xml\n"
932
+ "# $ oscap xccdf generate fix --profile %s --fix-type %s xccdf-file.xml\n"
884
933
"#\n"
885
934
"# This %s is generated from an OpenSCAP profile without preliminary evaluation.\n"
886
935
"# It attempts to fix every selected rule, even if the system is already compliant.\n"
@@ -890,13 +939,13 @@ static int _write_script_header_to_fd(struct xccdf_policy *policy, struct xccdf_
890
939
"#\n"
891
940
"###############################################################################\n\n" ,
892
941
remediation_type , profile_title ,
893
- profile_description != NULL ? profile_description : "Not available" ,
942
+ commented_profile_description ,
894
943
profile_id , benchmark_id , benchmark_version_info , xccdf_version_name ,
895
- oscap_version , profile_id , template , format , remediation_type ,
944
+ oscap_version , profile_id , format , remediation_type ,
896
945
remediation_type , how_to_apply
897
946
);
898
947
899
- free (profile_description );
948
+ free (commented_profile_description );
900
949
901
950
} else {
902
951
// Results-based remediation fix
@@ -916,7 +965,7 @@ static int _write_script_header_to_fd(struct xccdf_policy *policy, struct xccdf_
916
965
"# Evaluation Start Time: %s\n"
917
966
"# Evaluation End Time: %s\n#\n"
918
967
"# This file was generated by OpenSCAP %s using:\n"
919
- "# $ oscap xccdf generate fix --result-id %s%s %s xccdf-results.xml\n"
968
+ "# $ oscap xccdf generate fix --result-id %s --fix-type %s xccdf-results.xml\n"
920
969
"#\n"
921
970
"# This %s is generated from the results of a profile evaluation.\n"
922
971
"# It attempts to remediate all issues from the selected rules that failed the test.\n"
@@ -927,7 +976,7 @@ static int _write_script_header_to_fd(struct xccdf_policy *policy, struct xccdf_
927
976
"###############################################################################\n\n" ,
928
977
remediation_type , profile_title , profile_id , xccdf_version_name ,
929
978
start_time != NULL ? start_time : "Unknown" , end_time , oscap_version ,
930
- result_id , template , format , remediation_type , remediation_type , how_to_apply
979
+ result_id , format , remediation_type , remediation_type , how_to_apply
931
980
);
932
981
}
933
982
free (profile_title );
0 commit comments