|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# SPDX-License-Identifier: GPL-2.0-or-later |
| 4 | +# Copyright (C) 2021 Red Hat Inc., Durham, North Carolina. |
| 5 | +# |
| 6 | +# Evgenii Kolesnikov <[email protected]> |
| 7 | +# |
| 8 | +# This is OpenSCAP's offline system remediation service wrapper script and |
| 9 | +# it is supposed to be executed by systemd. Not sutable for manual invocation. |
| 10 | + |
| 11 | + |
| 12 | +UCHAR_MAX=255 |
| 13 | +SYSTEMD_SYSTEM_UPDATE_LINK="/system-update" |
| 14 | +OSCAP_REMEDIATE_CONF_BASENAME="oscap-remediate-offline.conf.sh" |
| 15 | + |
| 16 | + |
| 17 | +display() { |
| 18 | + # Plymouth does not like messages longer than UCHAR_MAX |
| 19 | + plymouth display-message --text="${1:0:${UCHAR_MAX}}" |
| 20 | +} |
| 21 | + |
| 22 | +log() { |
| 23 | + echo "${@}" |
| 24 | +} |
| 25 | + |
| 26 | +err() { |
| 27 | + echo "${@}" >&2 |
| 28 | +} |
| 29 | + |
| 30 | +die() { |
| 31 | + err "${@}" |
| 32 | + display "OpenSCAP has failed to evaluate or remediate the system, please check the journal for the details."$'\n'"The system will now restart..." |
| 33 | + sleep 5 |
| 34 | + systemctl reboot |
| 35 | + exit 1 |
| 36 | +} |
| 37 | + |
| 38 | + |
| 39 | +config=$(readlink -f "${SYSTEMD_SYSTEM_UPDATE_LINK}") |
| 40 | + |
| 41 | +if [[ "$(basename ${config})" != "${OSCAP_REMEDIATE_CONF_BASENAME}" ]]; then |
| 42 | + log "The ${SYSTEMD_SYSTEM_UPDATE_LINK} symlink does not point to an oscap offline remediation configuration file, ignoring" |
| 43 | + exit 0 |
| 44 | +fi |
| 45 | + |
| 46 | +rm -f "${SYSTEMD_SYSTEM_UPDATE_LINK}" |
| 47 | +log "Removed ${SYSTEMD_SYSTEM_UPDATE_LINK}" |
| 48 | +log "Found the config file: ${config}" |
| 49 | + |
| 50 | +source "$config" |
| 51 | + |
| 52 | + |
| 53 | +log "OSCAP_REMEDIATE_DS: ${OSCAP_REMEDIATE_DS}" |
| 54 | + |
| 55 | +log "OSCAP_REMEDIATE_PROFILE_ID: ${OSCAP_REMEDIATE_PROFILE_ID}" |
| 56 | +log "OSCAP_REMEDIATE_DATASTREAM_ID: ${OSCAP_REMEDIATE_DATASTREAM_ID}" |
| 57 | +log "OSCAP_REMEDIATE_XCCDF_ID: ${OSCAP_REMEDIATE_XCCDF_ID}" |
| 58 | +log "OSCAP_REMEDIATE_BENCHMARK_ID: ${OSCAP_REMEDIATE_BENCHMARK_ID}" |
| 59 | + |
| 60 | +log "OSCAP_REMEDIATE_TAILORING: ${OSCAP_REMEDIATE_TAILORING}" |
| 61 | +log "OSCAP_REMEDIATE_TAILORING_ID: ${OSCAP_REMEDIATE_TAILORING_ID}" |
| 62 | + |
| 63 | +log "OSCAP_REMEDIATE_ARF_RESULT: ${OSCAP_REMEDIATE_ARF_RESULT}" |
| 64 | +log "OSCAP_REMEDIATE_HTML_REPORT: ${OSCAP_REMEDIATE_HTML_REPORT}" |
| 65 | + |
| 66 | +log "OSCAP_REMEDIATE_VERBOSE_LOG: ${OSCAP_REMEDIATE_VERBOSE_LOG}" |
| 67 | +log "OSCAP_REMEDIATE_VERBOSE_LEVEL: ${OSCAP_REMEDIATE_VERBOSE_LEVEL}" |
| 68 | + |
| 69 | + |
| 70 | +[[ -r "${OSCAP_REMEDIATE_DS}" ]] || { |
| 71 | + die "The data stream file does not exists: ${OSCAP_REMEDIATE_DS}" |
| 72 | +} |
| 73 | + |
| 74 | +[[ -n "${OSCAP_REMEDIATE_PROFILE_ID}" ]] || { |
| 75 | + die "The profile identifier is not defined" |
| 76 | +} |
| 77 | + |
| 78 | +[[ -z "${OSCAP_REMEDIATE_TAILORING}" || -r "${OSCAP_REMEDIATE_TAILORING}" ]] || { |
| 79 | + die "The tailoring file does not exists: ${OSCAP_REMEDIATE_TAILORING}" |
| 80 | +} |
| 81 | + |
| 82 | +oscap xccdf validate --skip-schematron "${OSCAP_REMEDIATE_DS}" || { |
| 83 | + die "Invalid data stream file: ${OSCAP_REMEDIATE_DS}" |
| 84 | +} |
| 85 | + |
| 86 | +profile=${OSCAP_REMEDIATE_PROFILE_ID} |
| 87 | +profile_id_arg="--profile=${OSCAP_REMEDIATE_PROFILE_ID}" |
| 88 | +profile_title_line=$(oscap info "${profile_id_arg}" "${OSCAP_REMEDIATE_DS}" | grep Title) || { |
| 89 | + die "Can not find the profile: ${profile}" |
| 90 | +} |
| 91 | +profile_title=${profile_title_line#*Title: } |
| 92 | +log "Profile: ${profile} (${profile_title})" |
| 93 | + |
| 94 | +args+=( ${OSCAP_REMEDIATE_VERBOSE_LOG:+"--verbose-log-file=${OSCAP_REMEDIATE_VERBOSE_LOG}"} ) |
| 95 | +# We don't want to create havok in the output, so no verbose messages unless they are redirected |
| 96 | +args+=( ${OSCAP_REMEDIATE_VERBOSE_LOG:+"--verbose=${OSCAP_REMEDIATE_VERBOSE_LEVEL:-INFO}"} ) |
| 97 | +args+=( "xccdf" ) |
| 98 | +args+=( "eval" ) |
| 99 | +args+=( "${profile_id_arg}" ) |
| 100 | +args+=( ${OSCAP_REMEDIATE_DATASTREAM_ID:+"--datastream-id=${OSCAP_REMEDIATE_DATASTREAM_ID}"} ) |
| 101 | +args+=( ${OSCAP_REMEDIATE_BENCHMARK_ID:+"--datastream-id=${OSCAP_REMEDIATE_BENCHMARK_ID}"} ) |
| 102 | +args+=( ${OSCAP_REMEDIATE_XCCDF_ID:+"--xccdf-id=${OSCAP_REMEDIATE_XCCDF_ID}"} ) |
| 103 | +args+=( ${OSCAP_REMEDIATE_TAILORING:+"--tailoring-file=${OSCAP_REMEDIATE_TAILORING}"} ) |
| 104 | +args+=( ${OSCAP_REMEDIATE_TAILORING_ID:+"--tailoring-id=${OSCAP_REMEDIATE_TAILORING_ID}"} ) |
| 105 | +args+=( ${OSCAP_REMEDIATE_ARF_RESULT:+"--results-arf=${OSCAP_REMEDIATE_ARF_RESULT}"} ) |
| 106 | +args+=( ${OSCAP_REMEDIATE_HTML_REPORT:+"--report=${OSCAP_REMEDIATE_HTML_REPORT}"} ) |
| 107 | +args+=( "--progress-full" ) |
| 108 | +args+=( "--remediate" ) |
| 109 | +args+=( "${OSCAP_REMEDIATE_DS}" ) |
| 110 | +log "Args: ${args[@]}" |
| 111 | + |
| 112 | +# Now we are good to go |
| 113 | +header="OpenSCAP is checking the system for compliance using"$'\n'"${profile_title}"$'\n\n'"Evaluating..." |
| 114 | +display "$header" |
| 115 | + |
| 116 | +while read -r line; do |
| 117 | + if [[ "${line}" =~ "---evaluation" ]]; then |
| 118 | + header="OpenSCAP is checking the system for compliance using"$'\n'"${profile_title}"$'\n\n' |
| 119 | + log "Evaluating..." |
| 120 | + elif [[ "${line}" =~ "---remediation" ]]; then |
| 121 | + header="OpenSCAP is remediating the system using"$'\n'"${profile_title}"$'\n\n' |
| 122 | + log "Remediating..." |
| 123 | + else |
| 124 | + # The line is: "rule_id|Rule Title|result" |
| 125 | + IFS="|" read -ra fields <<< "${line}" |
| 126 | + mark=$([[ "${fields[2]}" == "pass" ]] && echo "✔ " || echo "✘ ") |
| 127 | + |
| 128 | + display "${header}${mark}${fields[1]}" |
| 129 | + log "Rule: ${fields[0]} ${fields[2]}" |
| 130 | + fi |
| 131 | +done < <(oscap "${args[@]}" || { |
| 132 | + # Resturn value of 2 and more could mean partial remediation and whatnot, |
| 133 | + # no reason to frighten the user in those cases. |
| 134 | + if [[ $? == 1 ]]; then |
| 135 | + die "Result: 1, processing error" |
| 136 | + fi |
| 137 | + err "Result: $?" |
| 138 | +}) |
| 139 | + |
| 140 | +display "The system will now restart..." |
| 141 | +log "Done. Rebooting..." |
| 142 | +systemctl reboot |
0 commit comments