1) This proposal includes the necessary directory structure / transform scripts, so remediation scripts could work for Fedora content too,
2) Since there (in RHEL6 content) are currently multiple remediation fixes of the form "search for text file pattern. Replace old value based on provided variable if found or append new value if not found": - accounts_maximum_age_login_defs.sh - accounts_minimum_age_login_defs.sh .. - accounts_umask_login_defs.sh .. - sshd_set_idle_timeout.sh (16 of this type in total right now), wrote 'replace or append pattern value in text file' remediation script generator (create_replace_or_append_pattern_value_in_text_file.sh), which can be used, when new remediation scripts of this type are needed. 3) Based on that script created remediation script for "Set password minimum length in login.defs" rule. Please review. Thank you && Regards, Jan. -- Jan iankko Lieskovsky / Red Hat Security Technologies Team
From 7add09df599faaf044218d637e36f819c8050fe6 Mon Sep 17 00:00:00 2001 From: Jan Lieskovsky <[email protected]> Date: Mon, 18 Nov 2013 18:00:27 +0100 Subject: [PATCH] [Fedora] Include directory structure to support remediations. [Fedora] Add text file pattern remediation script generator. [Fedora] Add remediation for "Set password minimum length in login.defs" rule Signed-off-by: Jan Lieskovsky <[email protected]> --- Fedora/Makefile | 5 + .../bash/accounts_password_minlen_login_defs.sh | 9 ++ Fedora/input/fixes/bash/templates/Makefile | 8 ++ ...replace_or_append_pattern_value_in_text_file.sh | 103 +++++++++++++++++++++ .../input/fixes/bash/templates/output/.gitignore | 2 + Fedora/input/fixes/bash/templates/support.sh | 9 ++ Fedora/input/profiles/common.xml | 1 + Fedora/scap-security-guide.spec | 8 +- Fedora/transforms/combinefixes.py | 49 ++++++++++ Fedora/transforms/xccdf-addfixes.xslt | 66 +++++++++++++ 10 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 Fedora/input/fixes/bash/accounts_password_minlen_login_defs.sh create mode 100644 Fedora/input/fixes/bash/templates/Makefile create mode 100755 Fedora/input/fixes/bash/templates/generators/create_replace_or_append_pattern_value_in_text_file.sh create mode 100644 Fedora/input/fixes/bash/templates/output/.gitignore create mode 100644 Fedora/input/fixes/bash/templates/support.sh create mode 100755 Fedora/transforms/combinefixes.py create mode 100644 Fedora/transforms/xccdf-addfixes.xslt diff --git a/Fedora/Makefile b/Fedora/Makefile index 1bdb6fe..0072a67 100644 --- a/Fedora/Makefile +++ b/Fedora/Makefile @@ -25,6 +25,10 @@ shorthand-guide: set-fedora-release shorthand2xccdf: shorthand-guide xsltproc -o $(OUT)/unlinked-unresolved-$(PROD)-xccdf.xml $(TRANS)/shorthand2xccdf.xslt $(OUT)/$(ID)-$(PROD)-shorthand.xml oscap xccdf resolve -o $(OUT)/unlinked-$(PROD)-xccdf.xml $(OUT)/unlinked-unresolved-$(PROD)-xccdf.xml + # Include fixes + ./$(TRANS)/combinefixes.py $(IN)/fixes/bash/ $(OUT)/bash-remediations.xml + xsltproc -stringparam fixes "../$(OUT)/bash-remediations.xml" -o $(OUT)/unlinked-$(PROD)-xccdf.xml $(TRANS)/xccdf-addfixes.xslt $(OUT)/unlinked-$(PROD)-xccdf.xml + xmllint --format --output $(OUT)/unlinked-$(PROD)-xccdf.xml $(OUT)/unlinked-$(PROD)-xccdf.xml checks: xmlwf $(IN)/checks/*.xml @@ -65,4 +69,5 @@ eval-common: content clean: rm -f $(OUT)/*.xml $(OUT)/*.html $(OUT)/*.xhtml $(OUT)/*.pdf $(OUT)/*.spec $(OUT)/*.tar $(OUT)/*.gz $(OUT)/*.ini $(OUT)/*.csv rm -f $(OUT)/$(FEDORA_GUIDE_XSLT) + rm -f $(IN)/fixes/bash/templates/output/*.sh rm -rf $(DIST)/content diff --git a/Fedora/input/fixes/bash/accounts_password_minlen_login_defs.sh b/Fedora/input/fixes/bash/accounts_password_minlen_login_defs.sh new file mode 100644 index 0000000..c950c3a --- /dev/null +++ b/Fedora/input/fixes/bash/accounts_password_minlen_login_defs.sh @@ -0,0 +1,9 @@ +source ./templates/support.sh +populate var_accounts_password_minlen_login_defs + +grep -q ^PASS_MIN_LEN /etc/login.defs && \ +sed -i "s/PASS_MIN_LEN.*/PASS_MIN_LEN\t$var_accounts_password_minlen_login_defs/g" /etc/login.defs +if ! [ $? -eq 0 ] +then + echo -e "PASS_MIN_LEN\t$var_accounts_password_minlen_login_defs" >> /etc/login.defs +fi diff --git a/Fedora/input/fixes/bash/templates/Makefile b/Fedora/input/fixes/bash/templates/Makefile new file mode 100644 index 0000000..d63e5c4 --- /dev/null +++ b/Fedora/input/fixes/bash/templates/Makefile @@ -0,0 +1,8 @@ +compare: + diff output/ ../ | grep -v "Only in ../" + +copy: + cp output/*.sh ../ + +clean: + rm -f output/*.sh diff --git a/Fedora/input/fixes/bash/templates/generators/create_replace_or_append_pattern_value_in_text_file.sh b/Fedora/input/fixes/bash/templates/generators/create_replace_or_append_pattern_value_in_text_file.sh new file mode 100755 index 0000000..d4f6603 --- /dev/null +++ b/Fedora/input/fixes/bash/templates/generators/create_replace_or_append_pattern_value_in_text_file.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +# SCAP "replace or append pattern value in text file based on variable" +# remediation script generator +# +# Required arguments: +# -p pattern to search content of text file for +# -f text file to be searched +# -v use variable as new value for the pattern +# -o name of resulting remediation script output file +# +# Optional arguments: +# -s request pattern match from the start of the line +# +# Example use: +# +# ./create_replace_or_append_pattern_value_in_text_file.sh \ +# -p PASS_MIN_LEN \ +# -f /etc/login.defs \ +# -v var_accounts_password_minlen_login_defs +# -o ../output/accounts_password_minlen_login_defs.sh + +# meaning: +# a remediation script to replace 'PASS_MIN_LEN' string +# in '/etc/login.defs' file with value of +# '$var_accounts_password_minlen_login_defs' variable +# would be created based on template and stored into +# 'accounts_password_minlen_login_defs.sh' output file +# Since no -s argument was provided the text file would +# be searched for any occurrence of 'PASS_MIN_LEN' row +# ----------------------------------------------------- + +# Define script routines below +# ---------------------------- + +#1 Usage function definition + +function usage { + echo -e "Usage:\n\t$0 [-s] -p pattern -f file -v variable -o output_script\n" + echo -e "-p pattern to search file for\t\t\t-f text file to be searched" + echo -e "-v name of the variable to be considered\t[-s] match the start of the line or not" + echo -e " to hold new value for pattern\t\t-o name of the resulting remediation script" +} + +#2 Remediation script generator function definition +# Expects pattern as first argument, file as second argument, +# and variable name as third argument + +function generate_replace_or_append_remediation_script { + + # Save the provided args to local variables + local pattern=$1 file=$2 variable=$3 remediation=$4 + + pattern_prefix='' + + if [ $MATCH_START_OF_LINE ] + then + pattern_prefix='^' + fi + + # Generate the remediation script + cat > $REMEDIATION << EOF +source ./templates/support.sh +populate $variable + +grep -q $pattern_prefix$pattern $file && \\ +sed -i "s/$pattern.*/$pattern\t\$$variable/g" $file +if ! [ \$? -eq 0 ] +then + echo -e "$pattern\t\$$variable" >> $file +fi +EOF + +} + + +##### Main body of the generator script ##### + +# Initialize variables +PATTERN=false FILE= false VARIABLE=false +MATCH_START_OF_LINE=false REMEDIATION=false + +# Specify valid options and action for each of them +while getopts "p:f:v:so:" opt +do + case $opt in + p ) PATTERN=$OPTARG ;; + f ) FILE=$OPTARG ;; + v ) VARIABLE=$OPTARG ;; + s ) MATCH_START_OF_LINE=true ;; + o ) REMEDIATION=$OPTARG ;; + * ) usage; exit + esac +done + +# Provided input wasn't correct. Just display usage message +if [ -z $PATTERN ] || [ -z $FILE ] || [ -z $VARIABLE ] || [ -z $REMEDIATION ] +then + usage +# Command line was correct, generate the remediation script +else + generate_replace_or_append_remediation_script $PATTERN $FILE $VARIABLE $REMEDIATION +fi diff --git a/Fedora/input/fixes/bash/templates/output/.gitignore b/Fedora/input/fixes/bash/templates/output/.gitignore new file mode 100644 index 0000000..041cc36 --- /dev/null +++ b/Fedora/input/fixes/bash/templates/output/.gitignore @@ -0,0 +1,2 @@ +# files to ignore +*.sh diff --git a/Fedora/input/fixes/bash/templates/support.sh b/Fedora/input/fixes/bash/templates/support.sh new file mode 100644 index 0000000..e25ce4d --- /dev/null +++ b/Fedora/input/fixes/bash/templates/support.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +function populate { +# code to populate environment variables needed (for unit testing) +if [ -z "${!1}" ]; then + echo "$1 is not defined. Exiting." + exit +fi +} diff --git a/Fedora/input/profiles/common.xml b/Fedora/input/profiles/common.xml index 8997e79..e7d7d25 100644 --- a/Fedora/input/profiles/common.xml +++ b/Fedora/input/profiles/common.xml @@ -24,6 +24,7 @@ <select idref="no_netrc_files" selected="true"/> <!-- Set Password Expiration Parameters section rules --> <select idref="accounts_password_minlen_login_defs" selected="true"/> + <refine-value idref="var_accounts_password_minlen_login_defs" selector="12" /> <select idref="accounts_minimum_age_login_defs" selected="true"/> <select idref="accounts_maximum_age_login_defs" selected="true"/> <select idref="accounts_password_warn_age_login_defs" selected="true"/> diff --git a/Fedora/scap-security-guide.spec b/Fedora/scap-security-guide.spec index 85f9e2d..c418b93 100644 --- a/Fedora/scap-security-guide.spec +++ b/Fedora/scap-security-guide.spec @@ -5,7 +5,7 @@ # file one level up - in the main scap-security-guide directory (instead of # this one). -%global fedorassgversion 3 +%global fedorassgversion 4.rc1 Name: scap-security-guide Version: 0.1.%{fedorassgversion} @@ -53,6 +53,12 @@ cp -a Fedora/input/auxiliary/scap-security-guide.8 %{buildroot}%{_mandir}/en/man %doc Fedora/LICENSE Fedora/output/ssg-fedora-guide.html %changelog +* Mon Nov 18 2013 Jan iankko Lieskovsky <[email protected]> 0.1.4.rc1-1 +- Include directory structure to support remediations +- Add SCAP "replace or append pattern value in text file based on variable" + remediation script generator +- Add remediation for "Set Password Minimum Length in login.defs" rule + * Mon Nov 18 2013 Jan iankko Lieskovsky <[email protected]> 0.1.3-1 - Update versioning scheme - move fedorassgrelease to be part of upstream version. Rename it to fedorassgversion to avoid name collision diff --git a/Fedora/transforms/combinefixes.py b/Fedora/transforms/combinefixes.py new file mode 100755 index 0000000..71fbe6f --- /dev/null +++ b/Fedora/transforms/combinefixes.py @@ -0,0 +1,49 @@ +#!/usr/bin/python + +import sys, os, re, lxml.etree as etree + +def substitute_vars(fix): + # brittle and troubling code to assign environment vars to XCCDF values + m = re.match("(\s*source\s+\S+)\n+(\s*populate\s+)(\S+)\n(.*)", fix.text, re.DOTALL) + if not m: + # no need to alter fix.text + return + # otherwise, create node to populate environment variable + varname = m.group(3) + mainscript = m.group(4) + fix.text = varname + "=" + '"' + # new <sub> element to reference XCCDF variable + xccdf_sub = etree.SubElement(fix, "sub", idref=varname) + xccdf_sub.tail = '"' + mainscript + fix.append(xccdf_sub) + + +def main(): + if len(sys.argv) < 2: + print "Provide a directory name, which contains the fixes." + sys.exit(1) + + fixdir = sys.argv[1] + output = sys.argv[2] + + fixcontent = etree.Element("fix-content", system="urn:xccdf:fix:script:sh", xmlns="http://checklists.nist.gov/xccdf/1.1") + fixgroup = etree.SubElement(fixcontent, "fix-group", id="bash", system="urn:xccdf:fix:script:sh", xmlns="http://checklists.nist.gov/xccdf/1.1") + + for filename in os.listdir(fixdir): + if filename.endswith(".sh"): + # create and populate new fix element based on shell file + fixname = os.path.splitext(filename)[0] + fix = etree.SubElement(fixgroup, "fix", rule=fixname) + with open( fixdir + "/" + filename, 'r') as f: + # assignment automatically escapes shell characters for XML + fix.text = f.read() + # replace instance of bash function "populate" with XCCDF variable substitution + substitute_vars(fix) + + tree = etree.ElementTree(fixcontent) + tree.write(output, pretty_print=True) + + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/Fedora/transforms/xccdf-addfixes.xslt b/Fedora/transforms/xccdf-addfixes.xslt new file mode 100644 index 0000000..0a7e1e2 --- /dev/null +++ b/Fedora/transforms/xccdf-addfixes.xslt @@ -0,0 +1,66 @@ +<?xml version="1.0"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xccdf="http://checklists.nist.gov/xccdf/1.1" xmlns:xhtml="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xccdf"> + +<!-- This transform expects a stringparam "fixes" specifying a filename + containing a list of fixes. It inserts these into the Rules + specified inside the fixes file. --> + +<xsl:variable name="fixgroup" select="document($fixes)/xccdf:fix-content/xccdf:fix-group" /> +<xsl:variable name="fixsystem" select="$fixgroup/@system"/> +<xsl:variable name="fixcommongroup" select="document($fixes)/xccdf:fix-content/xccdf:fix-common-group" /> + + <xsl:template match="xccdf:Rule"> + <xsl:copy> + <!-- deal with the fact that oscap demands fixes stand only before checks --> + <xsl:apply-templates select="@*|node()[not(self::xccdf:check)]"/> + + <xsl:variable name="rule_id" select="@id"/> + <xsl:for-each select="$fixgroup/xccdf:fix"> + <xsl:if test="@rule=$rule_id"> + <xsl:element name="fix" namespace="http://checklists.nist.gov/xccdf/1.1"> + <xsl:attribute name="system"><xsl:value-of select="$fixsystem"/></xsl:attribute> + <xsl:apply-templates select="node()"/> + </xsl:element> + </xsl:if> + </xsl:for-each> + <xsl:apply-templates select="node()[self::xccdf:check]"/> + + </xsl:copy> + </xsl:template> + + <xsl:template match="xccdf:Benchmark"> + <xsl:copy> + + <!-- plain-text elements must appear in sequence --> + <xsl:apply-templates select="@*"/> + <xsl:apply-templates select="xccdf:status"/> + <xsl:apply-templates select="xccdf:dc-status"/> + <xsl:apply-templates select="xccdf:title"/> + <xsl:apply-templates select="xccdf:description"/> + <xsl:apply-templates select="xccdf:notice"/> + <xsl:apply-templates select="xccdf:front-matter"/> + <xsl:apply-templates select="xccdf:rear-matter"/> + <xsl:apply-templates select="xccdf:reference"/> + + <xsl:for-each select="$fixcommongroup/xccdf:fix-common"> + <xsl:variable name="fix_common_id" select="@id"/> + <xsl:element name="plain-text" namespace="http://checklists.nist.gov/xccdf/1.1"> + <xsl:attribute name="id"><xsl:value-of select="$fix_common_id"/></xsl:attribute> + <xsl:value-of select="text()"/> + </xsl:element> + </xsl:for-each> + <xsl:apply-templates select="node()[not(self::xccdf:status|self::xccdf:dc-title|self::xccdf:title|self::xccdf:description|self::xccdf:notice|self::xccdf:front-matter|self::xccdf:rear-matter|self::xccdf:reference)]"/> +<!-- + <xsl:apply-templates select="node()[not(self::xccdf:status)]"/> +--> + </xsl:copy> + </xsl:template> + + <!-- copy everything else through to final output --> + <xsl:template match="@*|node()"> + <xsl:copy> + <xsl:apply-templates select="@*|node()" /> + </xsl:copy> + </xsl:template> + +</xsl:stylesheet> -- 1.8.3.1
_______________________________________________ scap-security-guide mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/scap-security-guide
