Skip to content

Commit

Permalink
Refactored code to enable supply of ssh options via env var.
Browse files Browse the repository at this point in the history
  • Loading branch information
matejak committed Sep 10, 2018
1 parent 618b9e3 commit 3f813a2
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 47 deletions.
125 changes: 79 additions & 46 deletions utils/oscap-ssh
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,37 @@ function usage()
echo "specific option for oscap-ssh (must be first argument):"
echo " --sudo"
echo
echo "To supply additional options to ssh/scp, define the SSH_ADDITIONAL_OPTIONS variable"
echo "For instance, to ignore known hosts records, define SSH_ADDITIONAL_OPTIONS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'"
echo
echo "specific option for oscap-ssh (must be first argument):"
echo
echo "See \`man oscap\` to learn more about semantics of these options."
}

OSCAP_SUDO=""
SSH_ADDITIONAL_ARGS=""
# SSH_ADDITIONAL_OPTIONS may be defined in the calling shell
SSH_TTY_ALLOCATION_OPTION=""

# $1: The SSH command.
# $2: More of additional options (optional, space-separated string)
function ssh_execute_with_options {
ssh -o ControlPath="$MASTER_SOCKET" $SSH_ADDITIONAL_OPTIONS $2 -p "$SSH_PORT" "$SSH_HOST" "$1"
}

# $1: Local filename to copy
# $2: Remote destination
function scp_copy_to_temp_dir {
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" $SSH_ADDITIONAL_OPTIONS "$1" "$SSH_HOST:$REMOTE_TEMP_DIR/$2"
}

# $1: Remote filename to get
# $2: Local destination
function scp_retreive_from_temp_dir {
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" $SSH_ADDITIONAL_OPTIONS "$SSH_HOST:$REMOTE_TEMP_DIR/$1" "$2"
}

function sanity_check_arguments {
if [ $# -lt 1 ]; then
echo "No arguments provided."
usage
Expand All @@ -95,46 +121,53 @@ elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
elif [ "$1" == "sudo" ] || [ "$1" == "--sudo" ]; then
OSCAP_SUDO="sudo"
# force pseudo-tty allocation so that users can type their password if necessary
SSH_ADDITIONAL_ARGS="-t"
SSH_TTY_ALLOCATION_OPTION="-t"
shift
fi
if [ $# -lt 2 ]; then
echo "Missing ssh host and ssh port."
usage
die
fi
}

SSH_HOST="$1"
SSH_PORT="$2"

if [ "$3" == "--v" ] || [ "$3" == "--version" ]; then
function check_oscap_arguments {
if [ "$1" == "--v" ] || [ "$1" == "--version" ]; then
true
elif [ "$3" == "-h" ] || [ "$3" == "--help" ]; then
elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
true
elif [ "$3" == "info" ]; then
elif [ "$1" == "info" ]; then
true
elif [ "$3 $4" == "xccdf eval" ]; then
elif [ "$1 $2" == "xccdf eval" ]; then
true
elif [ "$3 $4" == "oval eval" ]; then
elif [ "$1 $2" == "oval eval" ]; then
true
elif [ "$3 $4" == "oval collect" ]; then
elif [ "$1 $2" == "oval collect" ]; then
true
else
die "This script only supports '-h', '--help', '--v', '--version', 'info', 'xccdf eval', 'oval eval' and 'oval collect'."
fi
}

sanity_check_arguments "$@"

SSH_HOST="$1"
SSH_PORT="$2"

shift 2

check_oscap_arguments "$@"

MASTER_SOCKET_DIR=$(mktemp -d)
MASTER_SOCKET="$MASTER_SOCKET_DIR/ssh_socket"

echo "Connecting to '$SSH_HOST' on port '$SSH_PORT'..."
ssh -M -f -N -o ServerAliveInterval=60 -o ControlPath="$MASTER_SOCKET" -p "$SSH_PORT" "$SSH_HOST" || die "Failed to connect!"
ssh -M -f -N -o ServerAliveInterval=60 -o ControlPath="$MASTER_SOCKET" -p "$SSH_PORT" $SSH_ADDITIONAL_OPTIONS "$SSH_HOST" || die "Failed to connect!"
echo "Connected!"

REMOTE_TEMP_DIR=$(ssh -o ControlPath="$MASTER_SOCKET" -p "$SSH_PORT" "$SSH_HOST" mktemp -d) || die "Failed to create remote temporary directory!"
REMOTE_TEMP_DIR=$(ssh_execute_with_options "mktemp -d") || die "Failed to create remote temporary directory!"

args=("$@")
oscap_args=("$@")

LOCAL_CONTENT_PATH=""
LOCAL_TAILORING_PATH=""
Expand All @@ -151,38 +184,38 @@ OVAL_RESULTS=""
for i in $(seq 0 `expr $# - 1`); do
let j=i+1

case "${args[i]}" in
case "${oscap_args[i]}" in
("--tailoring-file")
LOCAL_TAILORING_PATH=${args[j]}
args[j]="$REMOTE_TEMP_DIR/tailoring.xml"
LOCAL_TAILORING_PATH=${oscap_args[j]}
oscap_args[j]="$REMOTE_TEMP_DIR/tailoring.xml"
;;
("--cpe")
LOCAL_CPE_PATH=${args[j]}
args[j]="$REMOTE_TEMP_DIR/cpe.xml"
LOCAL_CPE_PATH=${oscap_args[j]}
oscap_args[j]="$REMOTE_TEMP_DIR/cpe.xml"
;;
("--variables")
LOCAL_VARIABLES_PATH=${args[j]}
args[j]="$REMOTE_TEMP_DIR/variables.xml"
LOCAL_VARIABLES_PATH=${oscap_args[j]}
oscap_args[j]="$REMOTE_TEMP_DIR/variables.xml"
;;
("--directives")
LOCAL_DIRECTIVES_PATH=${args[j]}
args[j]="$REMOTE_TEMP_DIR/directives.xml"
LOCAL_DIRECTIVES_PATH=${oscap_args[j]}
oscap_args[j]="$REMOTE_TEMP_DIR/directives.xml"
;;
("--results")
TARGET_RESULTS=${args[j]}
args[j]="$REMOTE_TEMP_DIR/results.xml"
TARGET_RESULTS=${oscap_args[j]}
oscap_args[j]="$REMOTE_TEMP_DIR/results.xml"
;;
("--results-arf")
TARGET_RESULTS_ARF=${args[j]}
args[j]="$REMOTE_TEMP_DIR/results-arf.xml"
TARGET_RESULTS_ARF=${oscap_args[j]}
oscap_args[j]="$REMOTE_TEMP_DIR/results-arf.xml"
;;
("--report")
TARGET_REPORT=${args[j]}
args[j]="$REMOTE_TEMP_DIR/report.html"
TARGET_REPORT=${oscap_args[j]}
oscap_args[j]="$REMOTE_TEMP_DIR/report.html"
;;
("--syschar")
TARGET_SYSCHAR=${args[j]}
args[j]="$REMOTE_TEMP_DIR/syschar.xml"
TARGET_SYSCHAR=${oscap_args[j]}
oscap_args[j]="$REMOTE_TEMP_DIR/syschar.xml"
;;
("--oval-results")
OVAL_RESULTS="yes"
Expand All @@ -194,8 +227,8 @@ done

if [ "$1" != "--v" ] && [ "$1" != "--version" ] && [ "$1" != "-h" ] && [ "$1" != "--help" ]; then
# Last argument should be the content path
LOCAL_CONTENT_PATH="${args[`expr $# - 1`]}"
args[`expr $# - 1`]="$REMOTE_TEMP_DIR/input.xml"
LOCAL_CONTENT_PATH="${oscap_args[`expr $# - 1`]}"
oscap_args[`expr $# - 1`]="$REMOTE_TEMP_DIR/input.xml"
fi

[ "$LOCAL_CONTENT_PATH" == "" ] || [ -f "$LOCAL_CONTENT_PATH" ] || die "Expected the last argument to be an input file, '$LOCAL_CONTENT_PATH' isn't a valid file path or the file doesn't exist!"
Expand All @@ -206,54 +239,54 @@ fi

if [ "$LOCAL_CONTENT_PATH" != "" ]; then
echo "Copying input file '$LOCAL_CONTENT_PATH' to remote working directory '$REMOTE_TEMP_DIR'..."
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$LOCAL_CONTENT_PATH" "$SSH_HOST:$REMOTE_TEMP_DIR/input.xml" || die "Failed to copy input file to remote temporary directory!"
scp_copy_to_temp_dir "$LOCAL_CONTENT_PATH" input.xml || die "Failed to copy input file to remote temporary directory!"
fi
if [ "$LOCAL_TAILORING_PATH" != "" ]; then
echo "Copying tailoring file '$LOCAL_TAILORING_PATH' to remote working directory '$REMOTE_TEMP_DIR'..."
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$LOCAL_TAILORING_PATH" "$SSH_HOST:$REMOTE_TEMP_DIR/tailoring.xml" || die "Failed to copy tailoring file to remote temporary directory!"
scp_copy_to_temp_dir "$LOCAL_TAILORING_PATH" tailoring.xml || die "Failed to copy tailoring file to remote temporary directory!"
fi
if [ "$LOCAL_CPE_PATH" != "" ]; then
echo "Copying CPE file '$LOCAL_CPE_PATH' to remote working directory '$REMOTE_TEMP_DIR'..."
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$LOCAL_CPE_PATH" "$SSH_HOST:$REMOTE_TEMP_DIR/cpe.xml" || die "Failed to copy CPE file to remote temporary directory!"
scp_copy_to_temp_dir "$LOCAL_CPE_PATH" cpe.xml || die "Failed to copy CPE file to remote temporary directory!"
fi
if [ "$LOCAL_VARIABLES_PATH" != "" ]; then
echo "Copying OVAL variables file '$LOCAL_VARIABLES_PATH' to remote working directory '$REMOTE_TEMP_DIR'..."
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$LOCAL_VARIABLES_PATH" "$SSH_HOST:$REMOTE_TEMP_DIR/variables.xml" || die "Failed to copy OVAL variables file to remote temporary directory!"
scp_copy_to_temp_dir "$LOCAL_VARIABLES_PATH" variables.xml || die "Failed to copy OVAL variables file to remote temporary directory!"
fi
if [ "$LOCAL_DIRECTIVES_PATH" != "" ]; then
echo "Copying OVAL directives file '$LOCAL_DIRECTIVES_PATH' to remote working directory '$REMOTE_TEMP_DIR'..."
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$LOCAL_DIRECTIVES_PATH" "$SSH_HOST:$REMOTE_TEMP_DIR/directives.xml" || die "Failed to copy OVAL directives file to remote temporary directory!"
scp_copy_to_temp_dir "$LOCAL_DIRECTIVES_PATH" directives.xml || die "Failed to copy OVAL directives file to remote temporary directory!"
fi

echo "Starting the evaluation..."
# changing directory because of --oval-results support. oval results files are
# dumped into PWD, and we can't be sure by the file names - we need controlled
# environment
ssh -o ControlPath="$MASTER_SOCKET" $SSH_ADDITIONAL_ARGS -p "$SSH_PORT" "$SSH_HOST" "cd $REMOTE_TEMP_DIR; $OSCAP_SUDO oscap ${args[*]}"
ssh_execute_with_options "cd $REMOTE_TEMP_DIR; $OSCAP_SUDO oscap ${oscap_args[*]}" "$SSH_TTY_ALLOCATION_OPTION"
OSCAP_EXIT_CODE=$?
echo "oscap exit code: $OSCAP_EXIT_CODE"

echo "Copying back requested files..."
if [ "$TARGET_RESULTS" != "" ]; then
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$SSH_HOST:$REMOTE_TEMP_DIR/results.xml" "$TARGET_RESULTS" || die "Failed to copy the results file back to local machine!"
scp_retreive_from_temp_dir results.xml "$TARGET_RESULTS" || die "Failed to copy the results file back to local machine!"
fi
if [ "$TARGET_RESULTS_ARF" != "" ]; then
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$SSH_HOST:$REMOTE_TEMP_DIR/results-arf.xml" "$TARGET_RESULTS_ARF" || die "Failed to copy the ARF file back to local machine!"
scp_retreive_from_temp_dir results-arf.xml "$TARGET_RESULTS_ARF" || die "Failed to copy the ARF file back to local machine!"
fi
if [ "$TARGET_REPORT" != "" ]; then
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$SSH_HOST:$REMOTE_TEMP_DIR/report.html" "$TARGET_REPORT" || die "Failed to copy the HTML report back to local machine!"
scp_retreive_from_temp_dir report.html "$TARGET_REPORT" || die "Failed to copy the HTML report back to local machine!"
fi
if [ "$TARGET_SYSCHAR" != "" ]; then
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$SSH_HOST:$REMOTE_TEMP_DIR/syschar.xml" "$TARGET_SYSCHAR" || die "Failed to copy the OVAL syschar file back to local machine!"
scp_retreive_from_temp_dir syschar.xml "$TARGET_SYSCHAR" || die "Failed to copy the OVAL syschar file back to local machine!"
fi
if [ "$OVAL_RESULTS" == "yes" ]; then
scp -o ControlPath="$MASTER_SOCKET" -P "$SSH_PORT" "$SSH_HOST:$REMOTE_TEMP_DIR/*.result.xml" "./" || die "Failed to copy OVAL result files back to local machine!"
scp_retreive_from_temp_dir '*.result.xml' "./" || die "Failed to copy OVAL result files back to local machine!"
fi

echo "Removing remote temporary directory..."
ssh -o ControlPath="$MASTER_SOCKET" -p "$SSH_PORT" "$SSH_HOST" "rm -r $REMOTE_TEMP_DIR" || die "Failed to remove remote temporary directory!"
ssh_execute_with_options "rm -r $REMOTE_TEMP_DIR" || die "Failed to remove remote temporary directory!"
echo "Disconnecting ssh and removing master ssh socket directory..."
ssh -o ControlPath="$MASTER_SOCKET" -p "$SSH_PORT" "$SSH_HOST" -O exit || die "Failed to disconnect!"
ssh -o ControlPath="$MASTER_SOCKET" $SSH_ADDITIONAL_OPTIONS -p "$SSH_PORT" "$SSH_HOST" -O exit || die "Failed to disconnect!"
rm -r "$MASTER_SOCKET_DIR" || die "Failed to remove local master SSH socket directory!"

exit $OSCAP_EXIT_CODE
8 changes: 7 additions & 1 deletion utils/oscap-ssh.8
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,16 @@ Supported options are:
Specific option for oscap-ssh (must be first argument):
--sudo

.SH EXEMPLARY USAGE
.SS Environment variables
oscap-ssh checks out the SSH_ADDITIONAL_OPTIONS environment variable, and pastes its contents into the command-line of ssh to the location where options are expected.
Supply the variable in form of a string that corresponds to a section of the ssh command-line and that consists of options you want to pass.

.SH EXAMPLE USAGE
.SS Simple XCCDF evaluation
The following command evaluates a remote Fedora machine as root. HTML report is written out as report.html on the local machine. Can be executed from any machine that has ssh, scp and bash. The local machine does not need to have openscap installed.
It also uses the SSH_ADDITIONAL_OPTIONS variable to configure ssh in such way that contents of the known_hosts file are ignored.

$ export SSH_ADDITIONAL_OPTIONS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
$ oscap-ssh [email protected] 22 xccdf eval --profile xccdf_org.ssgproject.content_profile_common --report report.html /usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml

.SS XCCDF Evaluation with tailoring file
Expand Down

0 comments on commit 3f813a2

Please sign in to comment.