Blame contrib/sshaide.sh

Packit 762fc5
#!/bin/sh
Packit 762fc5
#
Packit 762fc5
# $Id$
Packit 762fc5
#
Packit 762fc5
# NAME
Packit 762fc5
#       sshaide.sh - SSH/AIDE remote integrity monitoring script
Packit 762fc5
#
Packit 762fc5
# SYNOPSIS
Packit 762fc5
#       sshaide.sh  -check|-init  ALL|<machine-list>
Packit 762fc5
#
Packit 762fc5
# DESCRIPTION
Packit 762fc5
#       sshaide.sh uses AIDE and SSH to remotely run integrity checks
Packit 762fc5
#       on ALL configured client systems or those specifically listed on
Packit 762fc5
#       the command line from a centralized manager station.  sshaide.sh
Packit 762fc5
#       stores all binaries, databases and reports on a secure, centralized
Packit 762fc5
#       manager station.  Database initialization or periodic checks are
Packit 762fc5
#       run on demand or via cron jobs from the manager stations based on
Packit 762fc5
#       local policy requirements.
Packit 762fc5
#
Packit 762fc5
#       sshaide.sh requires a valid account on the remote system and uses
Packit 762fc5
#       SSH RSA authentication with public/private password-less key pairs
Packit 762fc5
#       to obtain automated, scripted access to a remote system.  Naturally
Packit 762fc5
#       the account(s), sshaide.sh keys and manager system must be heavily
Packit 762fc5
#       protected from compromise.  To minimize potential problems, it is
Packit 762fc5
#       recommended that sshaide.sh use non-privileged accounts.  While
Packit 762fc5
#       this limits access to verify some files and diretories on remote
Packit 762fc5
#       systems, we believe it is an acceptable trade-off.  Most critical
Packit 762fc5
#       files and directories can be effectively monitored without having
Packit 762fc5
#       privileged access.  It is recommended that an unprivileged, but
Packit 762fc5
#       dedicated account on the manager station also be setup to manage
Packit 762fc5
#       AIDE databases, AIDE reports, remote logins and other sshaide.sh
Packit 762fc5
#       requirements.
Packit 762fc5
#
Packit 762fc5
#       Remote clients must have the public SSH RSA key that will be used
Packit 762fc5
#       by the sshaide.sh manager.  The sshaide.sh manager must have the
Packit 762fc5
#       managed client's SSH server RSA public key in known_hosts or
Packit 762fc5
#       hostkeys file.  Refer to your SSH documentation for instructions
Packit 762fc5
#       on setting up public SSH RSA keys.
Packit 762fc5
#
Packit 762fc5
# OPTIONS
Packit 762fc5
#       The option must be given in the proper order and with proper
Packit 762fc5
#       syntax.
Packit 762fc5
#
Packit 762fc5
#       -init   Initialize or re-initialize the AIDE database for the
Packit 762fc5
#               listed host or hosts.
Packit 762fc5
#
Packit 762fc5
#       -check  Run an integrity check on the specified system or systems.
Packit 762fc5
#               The database for any host being checked must have already
Packit 762fc5
#               been intialized.
Packit 762fc5
#
Packit 762fc5
# DIRECTORIES and FILES
Packit 762fc5
#       ~/
Packit 762fc5
#               This is the home directory of the user running sshaide.sh.
Packit 762fc5
#               By default, this is retrieved from the $HOME environment
Packit 762fc5
#               variable.
Packit 762fc5
#
Packit 762fc5
#       ~/bin
Packit 762fc5
#               The directory where the sshaide.sh script and AIDE
Packit 762fc5
#               binaries are stored.  Required.
Packit 762fc5
#
Packit 762fc5
#       ~/bin/sshaide.sh
Packit 762fc5
#               The sshaide.sh program.  This file.  Required.
Packit 762fc5
#
Packit 762fc5
#       ~/bin/aide.[platform]
Packit 762fc5
#               The AIDE binary for a [platform].  For example, a Linux
Packit 762fc5
#               2.4 binary may be named aide.linux-2.4.  These binaries
Packit 762fc5
#               will be linked to from the independent client directories
Packit 762fc5
#               based on their platform requirements.  Required.
Packit 762fc5
#
Packit 762fc5
#       ~/configs
Packit 762fc5
#               The directory where the AIDE configuration files are
Packit 762fc5
#               stored.  Common AIDE configurations are stored here and
Packit 762fc5
#               can be linked to from the independent client directories
Packit 762fc5
#               based on policy requirements.  Required.
Packit 762fc5
#
Packit 762fc5
#       ~/reports
Packit 762fc5
#               This directory will store the initialization logs and
Packit 762fc5
#               integrity check reports.  Integrity reports will be
Packit 762fc5
#               tar.gz'd by year-month-day-hour.  Required, but created
Packit 762fc5
#               automatically by sshaide.sh.
Packit 762fc5
#
Packit 762fc5
#       ~/clients
Packit 762fc5
#               This is the parent directory for all client hosts being
Packit 762fc5
#               managed.  Required.
Packit 762fc5
#
Packit 762fc5
#       ~/clients/[client-host]
Packit 762fc5
#               This directory is a specific client host to be managed by
Packit 762fc5
#               sshaide.sh. [client-host] is a host name.  Short host name
Packit 762fc5
#               is usually sufficient, but a fully qualified domain name
Packit 762fc5
#               may be used if there may be host name overlap from different
Packit 762fc5
#               subdomains.  Required for each client to be managed by
Packit 762fc5
#               sshaide.sh.
Packit 762fc5
#
Packit 762fc5
#       ~/clients/[client-host]/aide.db_[client_host]
Packit 762fc5
#               This file is the AIDE database for the [client-host] being
Packit 762fc5
#               managed by sshaide.sh.  Required, but created automatically
Packit 762fc5
#               by the -init process.
Packit 762fc5
#
Packit 762fc5
#       ~/clients/[client-host]/aide.db_[client-host].old
Packit 762fc5
#               This file is the previous AIDE database before the last
Packit 762fc5
#               -init process.  Not required.  Created automatically after
Packit 762fc5
#               the second or additional database initialization.
Packit 762fc5
#
Packit 762fc5
#       ~/clients/[client-host]/sshaide.conf
Packit 762fc5
#               This file contains client specific configuration information.
Packit 762fc5
#               Optional.  The following three options are available:
Packit 762fc5
#
Packit 762fc5
#                 emaillist         comma-separated-list-of-addresses
Packit 762fc5
#                       This option specifies the email addresses that
Packit 762fc5
#                       sshaide.sh output should be delivered to.
Packit 762fc5
#                 homedir           full-home-diretory-path-on-client
Packit 762fc5
#                       This option specifies the fully qualified path
Packit 762fc5
#                       used on the client host.  This would be equivalanet
Packit 762fc5
#                       to the $HOME environment variable on the client
Packit 762fc5
#                       system.
Packit 762fc5
#                 userid             remote-user-id
Packit 762fc5
#                       This option specifies the remote login id with
Packit 762fc5
#                       which to login to the remote system with.
Packit 762fc5
#
Packit 762fc5
#               All configuration options are optional, but if present,
Packit 762fc5
#               they must be begin in column 1 with whitespace separting
Packit 762fc5
#               the desired value(s).
Packit 762fc5
#
Packit 762fc5
#       ~/clients/[client-host]/reinit
Packit 762fc5
#               The existence of this file indicates that the AIDE database
Packit 762fc5
#               for this client host should be reinitialized through the
Packit 762fc5
#               -init process on the next run.  Simply `touch` this file
Packit 762fc5
#               whenever you want to reinitialize the client host database.
Packit 762fc5
#               This file will be automaticaly removed after the next -init
Packit 762fc5
#               process.  Optional.
Packit 762fc5
#
Packit 762fc5
#       ~/clients/[client-host]/aide.conf
Packit 762fc5
#               This is a soft link to the appropriate AIDE configuration
Packit 762fc5
#               file in ~/configs.   The following two lines are required
Packit 762fc5
#               for each configuration file:
Packit 762fc5
#
Packit 762fc5
#                 database=file:./aide.db
Packit 762fc5
#                 database_out=file:./aide.newdb
Packit 762fc5
#
Packit 762fc5
#       ~/clients/[client-host]/aide
Packit 762fc5
#               This is a soft link to the appropriate AIDE binary for
Packit 762fc5
#               the client host platform in ~/bin.  Required.
Packit 762fc5
#
Packit 762fc5
#       ~/tmp
Packit 762fc5
#               This is a temporary work directory for sshaide.sh.
Packit 762fc5
#               Required.
Packit 762fc5
#
Packit 762fc5
# Original concept and coding from:
Packit 762fc5
#   Judith A Freeman <jaf@uchicago.edu>
Packit 762fc5
#   University of Chicago
Packit 762fc5
#   Network Security Center <network-security@uchicago.edu>
Packit 762fc5
#   <http://security.uchicago.edu>
Packit 762fc5
#   28 June 1998 to 16 May 2000
Packit 762fc5
#
Packit 762fc5
# Updates by:
Packit 762fc5
#   John Kristoff <jtk@northwestern.edu>
Packit 762fc5
#   <http://aharp.ittns.northwestern.edu>
Packit 762fc5
#   Northwestern University
Packit 762fc5
#   Telecommunications and Network Services
Packit 762fc5
#
Packit 762fc5
# 2003-12-03,jtk: updated for AIDE v0.10 and Linux
Packit 762fc5
#   newly packaged as sshaide.sh
Packit 762fc5
#   adjusted default path to something more reasonable for linux
Packit 762fc5
#   replaced tripwire references with aide naming conventions
Packit 762fc5
#   replaced hard coded root user id with $userid variable from whoami
Packit 762fc5
#   added LC_ALL=C for grep to work with traditional [] interpretations
Packit 762fc5
#   added a cd to remote_aidedir on remote machine
Packit 762fc5
#   forced remote_aidedir directory creation (with 'mkdir -p')
Packit 762fc5
#   added quotes to ssh commands
Packit 762fc5
#   changed the email subject and header format
Packit 762fc5
#   changed mail delivery and email creation handling
Packit 762fc5
#   minor commenting edits
Packit 762fc5
#   adjusted wordlist for Linux and Solaris, exiting if file not found
Packit 762fc5
#   removed $1 for wordlist
Packit 762fc5
#   implemented config file for remote_aidedir and emaillist per machine
Packit 762fc5
#   changed reinit check from read (-r) to write (-w) check
Packit 762fc5
#   fixed tar/gzip'ing of reports only on -check mode
Packit 762fc5
#   removed unncessary root directory variable, use just aidedir
Packit 762fc5
# 2003-12-06,jtk:minor configuration updates
Packit 762fc5
#   added userid option to config and created $useriddefault
Packit 762fc5
#   set default remote home directory with $homedefault
Packit 762fc5
# 2003-12-16,jtk: fixed sshaide.conf usage
Packit 762fc5
#   added doc about userid config in sshaide.conf
Packit 762fc5
#   changed order of sshaide.conf config options so remote_aidedir works
Packit 762fc5
# 2004-02-12,jtk: minor doc editing
Packit 762fc5
 
Packit 762fc5
###
Packit 762fc5
### Basic setup
Packit 762fc5
###
Packit 762fc5
 
Packit 762fc5
# Get a limited path
Packit 762fc5
PATH=/bin:/usr/bin:/usr/local/bin:/usr/ucb
Packit 762fc5
 
Packit 762fc5
# For debugging only
Packit 762fc5
# set -x
Packit 762fc5
 
Packit 762fc5
###
Packit 762fc5
### Local variable declarations
Packit 762fc5
###
Packit 762fc5
 
Packit 762fc5
# set the remote username to login and run aide as
Packit 762fc5
useriddefault=`whoami`
Packit 762fc5
 
Packit 762fc5
# Who gets the mail if not set in client dir?
Packit 762fc5
maildefault=root@localhost
Packit 762fc5
 
Packit 762fc5
# remote home directory
Packit 762fc5
homedefault=/home/${useriddefault}
Packit 762fc5
 
Packit 762fc5
# $date in the form year-month-day-hour
Packit 762fc5
date=`date +%Y-%m-%d-%H`
Packit 762fc5
 
Packit 762fc5
# Where are we running out of
Packit 762fc5
aidedir=${HOME}
Packit 762fc5
 
Packit 762fc5
# Setup local directories and files for use
Packit 762fc5
clientdir=${aidedir}/clients
Packit 762fc5
tmpdir=${aidedir}/tmp
Packit 762fc5
 
Packit 762fc5
progname=`basename $0`
Packit 762fc5
 
Packit 762fc5
###
Packit 762fc5
### Functions
Packit 762fc5
###
Packit 762fc5
 
Packit 762fc5
# Give usage statement
Packit 762fc5
usage () {
Packit 762fc5
    echo ""
Packit 762fc5
    echo "Usage: `${progname}` <run-mode> ALL|<machine-list>"
Packit 762fc5
    echo "  run-mode: -init | -check"
Packit 762fc5
    echo "  machine-list: space separated list in quotes"
Packit 762fc5
    echo ""
Packit 762fc5
}
Packit 762fc5
 
Packit 762fc5
## gen_rand_word  - returns a semi-random word
Packit 762fc5
##    only returns words that are all lowercase letters
Packit 762fc5
 
Packit 762fc5
gen_rand_word () {
Packit 762fc5
    # Set the word list
Packit 762fc5
    if test -r "/usr/share/dict/words" ; then
Packit 762fc5
        # For Linux
Packit 762fc5
        _wordlist="/usr/share/dict/words"
Packit 762fc5
    elif test -r "/usr/dict/words" ; then
Packit 762fc5
        # For Solaris
Packit 762fc5
        _wordlist="/usr/dict/words"
Packit 762fc5
    else
Packit 762fc5
        echo ERROR: words file not found!  Exiting...
Packit 762fc5
        exit 0
Packit 762fc5
    fi
Packit 762fc5
 
Packit 762fc5
    _randnum=`date +%H%S%Y%m%H%d%S%S`
Packit 762fc5
    _listlines=`cat ${_wordlist} | wc -l`
Packit 762fc5
    _linenum=`expr ${_randnum} % ${_listlines}`
Packit 762fc5
 
Packit 762fc5
    # If we picked line 0, change it to 1 'cause line 0 doesn't exist
Packit 762fc5
    if test ${_linenum} -eq 0 ; then
Packit 762fc5
        _linenum=1
Packit 762fc5
    fi
Packit 762fc5
 
Packit 762fc5
    _randword=`grep -n . ${_wordlist} | grep "^${_linenum}:" | cut -d: -f2`
Packit 762fc5
 
Packit 762fc5
    # If $_randword has anything other than lower-case chars, try again
Packit 762fc5
    (echo ${_randword} | LC_ALL=C grep '[^a-z]' 2>&1 >> /dev/null \
Packit 762fc5
            && gen_rand_word ) || \
Packit 762fc5
 
Packit 762fc5
    # Return the word
Packit 762fc5
    echo ${_randword}
Packit 762fc5
}
Packit 762fc5
 
Packit 762fc5
init_cmds () {
Packit 762fc5
 
Packit 762fc5
    if test ! -d ${aidedir}/reports/initlogs/ ; then
Packit 762fc5
        mkdir -p ${aidedir}/reports/initlogs/
Packit 762fc5
    fi
Packit 762fc5
 
Packit 762fc5
    ssh -l $userid $machine "(umask 077 ; cd ${remote_aidedir}; ${remote_aidedir}/aide --init --config=${remote_aidedir}/aide.conf 2>&1 | tee ${remote_aidedir}/initoutput >> /dev/null)"
Packit 762fc5
 
Packit 762fc5
    # Copy output back to file
Packit 762fc5
    mkdir -p ${tmpdir}/initoutput/${date}
Packit 762fc5
    scp -q ${userid}@${machine}:${remote_aidedir}/initoutput ${inittmp}/${machine}
Packit 762fc5
    # backup old database if it exists
Packit 762fc5
    if test -r ${clientdir}/${machine}/aide.db_${machine} ; then
Packit 762fc5
        mv ${clientdir}/${machine}/aide.db_${machine} ${clientdir}/${machine}/aide.db_${machine}.old
Packit 762fc5
    fi
Packit 762fc5
 
Packit 762fc5
    scp -q ${userid}@${machine}:${remote_aidedir}/aide.newdb ${clientdir}/${machine}/aide.db_${machine}
Packit 762fc5
}
Packit 762fc5
 
Packit 762fc5
check_cmds () {
Packit 762fc5
    scp -q $db ${userid}@${machine}:${remote_aidedir}/aide.db
Packit 762fc5
    ssh -l $userid $machine "umask 077 && cd ${remote_aidedir} && ${remote_aidedir}/aide --config=${remote_aidedir}/aide.conf 2>&1 | tee ${remote_aidedir}/report >> /dev/null"
Packit 762fc5
 
Packit 762fc5
    # Copy output back to file
Packit 762fc5
    if test ! -d ${aidedir}/reports/${date} ; then
Packit 762fc5
        mkdir ${aidedir}/reports/${date}
Packit 762fc5
    fi
Packit 762fc5
    scp -q ${userid}@${machine}:${remote_aidedir}/report $reports/${machine}
Packit 762fc5
 
Packit 762fc5
}
Packit 762fc5
 
Packit 762fc5
###
Packit 762fc5
### The program
Packit 762fc5
###
Packit 762fc5
 
Packit 762fc5
# From the commandline
Packit 762fc5
case $# in
Packit 762fc5
    2) mode=$1; thehosts=$2 ;;
Packit 762fc5
    *) usage; exit 1 ;;
Packit 762fc5
esac
Packit 762fc5
 
Packit 762fc5
# Set mode specific variables
Packit 762fc5
case $mode in
Packit 762fc5
    -init)       initlogs=${aidedir}/reports/initlogs
Packit 762fc5
                 inittmp=${tmpdir}/initoutput/${date}
Packit 762fc5
                 mail_fordir=${inittmp} ;;
Packit 762fc5
    -check)      reports=${aidedir}/reports/${date}
Packit 762fc5
                 mail_fordir=${reports} ;;
Packit 762fc5
esac
Packit 762fc5
 
Packit 762fc5
#
Packit 762fc5
case $thehosts in
Packit 762fc5
     ALL) forcmd=`ls ${clientdir}` ;;
Packit 762fc5
       *) forcmd=$thehosts ;;
Packit 762fc5
esac
Packit 762fc5
 
Packit 762fc5
for machine in $forcmd ; do
Packit 762fc5
    sleep 2  # so we get a different random word
Packit 762fc5
 
Packit 762fc5
    (    ## background it (this is so it runs in parellel)
Packit 762fc5
 
Packit 762fc5
    # Set up local directories and files for use
Packit 762fc5
    config=${clientdir}/${machine}/aide.conf
Packit 762fc5
    db=${clientdir}/${machine}/aide.db_${machine}
Packit 762fc5
    binary=${clientdir}/${machine}/aide
Packit 762fc5
    log=${clientdir}/${machine}/log
Packit 762fc5
    sshaide_conf=${clientdir}/${machine}/sshaide.conf
Packit 762fc5
 
Packit 762fc5
    # Set up temporary directory name for remote machine
Packit 762fc5
    rand_word=`gen_rand_word`
Packit 762fc5
 
Packit 762fc5
    # Apply client host configuration options
Packit 762fc5
    if  test ! -r ${sshaide_conf}  ; then
Packit 762fc5
        remote_aidedir=${homedefault}/${rand_word}.$$
Packit 762fc5
        mailrcpts=${maildefault}
Packit 762fc5
        userid=${useriddefault}
Packit 762fc5
    else
Packit 762fc5
        # Get the email addresses to send reports to
Packit 762fc5
        grep '^emaillist' ${sshaide_conf}
Packit 762fc5
        if [ $? != 0 ] ; then
Packit 762fc5
            mailrcpts=${maildefault}
Packit 762fc5
        else
Packit 762fc5
            mailrcpts=`grep -m1 '^emaillist' ${sshaide_conf} | \
Packit 762fc5
            awk '{print $2}'`
Packit 762fc5
        fi
Packit 762fc5
        # Get the remote user id
Packit 762fc5
        grep '^userid' ${sshaide_conf}
Packit 762fc5
        if [ $? != 0 ] ; then
Packit 762fc5
            userid=${useriddefault}
Packit 762fc5
        else
Packit 762fc5
            userid=`grep -m1 '^userid' ${sshaide_conf} | \
Packit 762fc5
            awk '{print $2}'`
Packit 762fc5
        fi
Packit 762fc5
        # Get home directory to use on remote machine
Packit 762fc5
        grep '^homedir' ${sshaide_conf}
Packit 762fc5
        if [ $? != 0 ] ; then
Packit 762fc5
            remote_aidedir=/home/${userid}/${rand_word}.$$
Packit 762fc5
        else
Packit 762fc5
            remote_aidedir=`grep -m1 '^homedir' ${sshaide_conf} | \
Packit 762fc5
            awk '{print $2}'`/${rand_word}.$$
Packit 762fc5
        fi
Packit 762fc5
    fi
Packit 762fc5
 
Packit 762fc5
    # Do the dirty work
Packit 762fc5
    ssh -l $userid $machine "mkdir -p $remote_aidedir"
Packit 762fc5
    scp -q $config ${userid}@${machine}:${remote_aidedir}
Packit 762fc5
    scp -q $binary ${userid}@${machine}:${remote_aidedir}
Packit 762fc5
 
Packit 762fc5
    case $mode in
Packit 762fc5
        -init)        init_cmds ;;
Packit 762fc5
        -check)       check_cmds ;;
Packit 762fc5
    esac
Packit 762fc5
 
Packit 762fc5
    # Delete remote directory
Packit 762fc5
    ssh -l $userid $machine "rm -rf $remote_aidedir"
Packit 762fc5
 
Packit 762fc5
    # If $mail_fordir doesn't exist, don't continue
Packit 762fc5
    if test ! -d "${mail_fordir}" ; then
Packit 762fc5
        echo "${progname}:${mail_fordir} doesn't exist,"
Packit 762fc5
        echo "exiting now, not sending mail"
Packit 762fc5
        exit 1
Packit 762fc5
    fi
Packit 762fc5
     
Packit 762fc5
    ###
Packit 762fc5
    ### Mail reports out
Packit 762fc5
    ###
Packit 762fc5
     
Packit 762fc5
    cat ${mail_fordir}/${machine} \
Packit 762fc5
    | mail -s "### AIDE ${mode} ${machine} ${date}" ${mailrcpts}
Packit 762fc5
 
Packit 762fc5
    )
Packit 762fc5
done
Packit 762fc5
 
Packit 762fc5
# Wait for all bg processes to finish before continuing
Packit 762fc5
wait
Packit 762fc5
 
Packit 762fc5
# Tar and compress the reports
Packit 762fc5
if test $mode = -check ; then
Packit 762fc5
    tar cf ${reports}.tar ${reports}
Packit 762fc5
    rm -rf ${reports}
Packit 762fc5
    gzip -9 ${reports}.tar
Packit 762fc5
fi
Packit 762fc5
 
Packit 762fc5
# If mode is check, examine clientdir for reinit file, and
Packit 762fc5
# reinitialize if it exists
Packit 762fc5
 
Packit 762fc5
if test $mode = -check ; then
Packit 762fc5
    for host in $forcmd ; do
Packit 762fc5
        if test -w ${clientdir}/${host}/reinit ; then
Packit 762fc5
            ${aidedir}/bin/${progname} -init ${host} &
Packit 762fc5
            rm ${clientdir}/${host}/reinit
Packit 762fc5
        fi
Packit 762fc5
    done
Packit 762fc5
fi
Packit 762fc5
 
Packit 762fc5
###
Packit 762fc5
### Clean up init stuff
Packit 762fc5
###
Packit 762fc5
 
Packit 762fc5
if test $mode = -init ; then
Packit 762fc5
 
Packit 762fc5
    # Concatenate inittmp directories into initlogs
Packit 762fc5
    for host in `ls -A ${mail_fordir}` ; do
Packit 762fc5
    (
Packit 762fc5
    echo "********************************************"
Packit 762fc5
    echo ${host} $date ${mode}
Packit 762fc5
    echo "********************************************"
Packit 762fc5
    echo ""
Packit 762fc5
    cat ${mail_fordir}/${host}
Packit 762fc5
    echo ""
Packit 762fc5
    )| tee -a $initlogs/`date +%Y-%m` >> /dev/null
Packit 762fc5
    done
Packit 762fc5
 
Packit 762fc5
    # Delete inittmp directory
Packit 762fc5
    rm -rf ${tmpdir}/initoutput
Packit 762fc5
fi