#!/bin/sh -fu

OSEC_CONF_DIR="${OSEC_CONF_DIR:-/etc/osec}"
TARGET_OSEC_CONF_DIR="${TARGET_OSEC_CONF_DIR:-OSEC_CONF_DIR}"

REPORT_LOG_BASE=/var/log/integalert
FACILITY=user
BASE_PROFILE='integalert'
LOG_TAG='integalert'

## Add other profiles here
KNOWN_SUB_PROFILES='main container vm'

. shell-source
source_if_exists /etc/sysconfig/integalert

### Main

show_usage() {
    echo "Usage: ${0##*/} [$(echo "$KNOWN_SUB_PROFILES" | tr ' ' '|')] [fix|check|configure]" >&2
}

action=
parse_action() {
    case "$1" in
	fix|check|configure)
	    action="$1"
	    ;;
	*)
	    return 1
    esac

    return 0
}

SUBPROFILE=
if [ $# -eq 0 ]; then
    SUBPROFILE='main'
else
    parse_action "$1" ||:
    if [ -n "$action" ]; then
	SUBPROFILE='main'
    else
	if echo "$KNOWN_SUB_PROFILES" | grep -qFw -- "$1"; then
	    SUBPROFILE="$1"
	else
	    echo "Error! Unknown profile: $1" >&2
	    show_usage
	    exit 1
	fi
    fi
fi

if [ $# -gt 1 ]; then
    if ! parse_action "$2"; then
	echo "Error! Unknown mode: $2" >&2
	show_usage
	exit 1
    fi
fi

[ -n "$action" ] || action='check'

case "$SUBPROFILE" in
    main)
	PROFILE="$BASE_PROFILE"
	;;
    *)
	PROFILE="${BASE_PROFILE}_$SUBPROFILE"
	;;
esac

if [ -z "$PROFILE" ]; then
    echo "BUG!: Empty profile!" >&2
    exit 2
fi

if ! parse_action "$action"; then
    echo "BUG!: Unexpected action '$action'!" >&2
    exit 2
fi

if [ ! -d $OSEC_CONF_DIR/$PROFILE ]; then
    echo "Create osec profile \"$PROFILE\"" >&2
    mkdir -p $OSEC_CONF_DIR/$PROFILE
fi

if [ ! -e $OSEC_CONF_DIR/$PROFILE/dirs.conf ]; then
    case "$SUBPROFILE" in
	main)
	    echo "Warning! Initializing $OSEC_CONF_DIR/$PROFILE/dirs.conf with $OSEC_CONF_DIR/dirs.conf" >&2
	    cat $OSEC_CONF_DIR/dirs.conf >$OSEC_CONF_DIR/$PROFILE/dirs.conf
	    ;;
	*)
	    touch "$OSEC_CONF_DIR/$PROFILE/dirs.conf"
	    ;;
    esac
fi

if [ ! -s $OSEC_CONF_DIR/$PROFILE/dirs.conf ]; then
    echo "Warning! $OSEC_CONF_DIR/$PROFILE/dirs.conf is empty! Please, fill it with a directory list corresponding to your setup." >&2
    exit 0
fi

if [ ! -e $OSEC_CONF_DIR/$PROFILE/exclude.conf ]; then
    case "$SUBPROFILE" in
	main)
	    if [ -e $OSEC_CONF_DIR/exclude.conf ]; then
		echo "Warning! Initializing $OSEC_CONF_DIR/$PROFILE/exclude.conf with $OSEC_CONF_DIR/exclude.conf" >&2
		cat $OSEC_CONF_DIR/exclude.conf >$OSEC_CONF_DIR/$PROFILE/exclude.conf
	    else
		touch $OSEC_CONF_DIR/$PROFILE/exclude.conf
	    fi
	    ;;
	*)
	    touch $OSEC_CONF_DIR/$PROFILE/exclude.conf
	    ;;
    esac
fi

case "$SUBPROFILE" in
    main)
	REPORT_LOG="$REPORT_LOG_BASE"
	mode_clause=
	;;
    *)
	REPORT_LOG="${REPORT_LOG_BASE}_$SUBPROFILE"
	mode_clause=", $SUBPROFILE mode"
	;;
esac

if [ ! -e $OSEC_CONF_DIR/$PROFILE/pipe.conf ]; then
    cat >$OSEC_CONF_DIR/$PROFILE/pipe.conf <<EOF
PROFILE="$PROFILE"
DIRS_FILE=$TARGET_OSEC_CONF_DIR/$PROFILE/dirs.conf
EXCLUDE_FILE=$TARGET_OSEC_CONF_DIR/$PROFILE/exclude.conf
REPORT_LOG='$REPORT_LOG.log'
IMMUTABLE_DATABASE=\${INTEGALERT_READONLY:-yes}
SEND_PIPE='$TARGET_OSEC_CONF_DIR/$PROFILE/sender'
EOF

    ## Add a profile-specific things for pipe.conf here
    case "$SUBPROFILE" in
	vm)
            cat <<EOF
IGNORE_FIELDS=inode
EOF
	    ;;
    esac >>$OSEC_CONF_DIR/$PROFILE/pipe.conf
fi

if [ ! -e $OSEC_CONF_DIR/$PROFILE/sender ]; then
    cat >$OSEC_CONF_DIR/$PROFILE/sender <<EOF
#!/bin/sh -fu

PROFILE="$PROFILE"
LOG_TAG="$LOG_TAG"
REPORT_LOG='$REPORT_LOG.log'
FACILITY=${FACILITY:-user}
INTEGALERT_ACTION="\${INTEGALERT_ACTION:-check}"

# Pipe out the report to log file:
cat >"\$REPORT_LOG"
echo "System integrity \${INTEGALERT_ACTION}$mode_clause (\$STAT)" >>"\$REPORT_LOG"

priority=info
[ "\$ADDED" = '0' ] || priority=alert
[ "\$REMOVED" = '0' ] || priority=alert
[ "\$CHANGED" = '0' ] || priority=alert

# Write a summary message to the system log:
logger -t "\$LOG_TAG" -p "\$FACILITY.\$priority" \\
    "System integrity \${INTEGALERT_ACTION}$mode_clause (\$STAT)"
EOF

    chmod 0755 $OSEC_CONF_DIR/$PROFILE/sender
fi

case "$action" in
    configure)
	exit 0
	;;
    fix)
	IMMUTABLE_DATABASE=no
	;;
    *)
	IMMUTABLE_DATABASE=yes
	;;
esac

mkdir -p "${REPORT_LOG%/*}"

if [ ! -e "$OSEC_CONF_DIR/$PROFILE/pipe.conf" ]; then
    echo "BUG!: OSEC profile $PROFILE doesn't exist!" >&2
    exit 2
fi

export IMMUTABLE_DATABASE
export INTEGALERT_READONLY=$IMMUTABLE_DATABASE
export INTEGALERT_ACTION="$action"
/usr/share/osec/osec.cron "$PROFILE"
ret=$?

case "$SUBPROFILE" in
    main)
	for_clause=
	;;
    *)
	for_clause=" for '$SUBPROFILE'"
	;;
esac

mkdir -p "${REPORT_LOG}_logs"
cat "$REPORT_LOG.log" >"${REPORT_LOG}_logs/$(date --iso-8601).log"

case "$action" in
    fix)
	if [ $ret -eq 0 ]; then
            echo "Integrity database$for_clause updated." >&2
        else
            echo "Error updating integrity database$for_clause!" >&2
        fi

        exit $ret
        ;;
esac

if [ $ret -eq 0 ] && grep -q "(chg=0,add=0,del=0)" "$REPORT_LOG.log"
then
    echo "Integrity check$for_clause OK." >&2
    logger -t "$LOG_TAG" -p "$FACILITY.info" \
	   "Integrity check$for_clause OK"
else
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" >&2
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" >&2
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" >&2
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" >&2
    echo "Integrity check failure$for_clause!" >&2
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" >&2
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" >&2
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" >&2
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" >&2

    logger -t "$LOG_TAG" -p "$FACILITY.alert" \
	   "Integrity check failure$for_clause!"

    if [ -d $OSEC_CONF_DIR/$PROFILE/trigger.d ]; then
	echo "Run triggers in $OSEC_CONF_DIR/$PROFILE/trigger.d..." >&2
	ls $OSEC_CONF_DIR/$PROFILE/trigger.d | while read f; do
	    case "$f" in
		*~)
		    continue
		    ;;
	    esac
	    [ -x "$OSEC_CONF_DIR/$PROFILE/trigger.d/$f" ] || \
		continue
	    cat "$REPORT_LOG.log" | \
		"$OSEC_CONF_DIR/$PROFILE/trigger.d/$f"
	done
    fi

    ret=1
fi

exit $ret
