#!/bin/bash

# Title........: cmcs
# Description..: change management control system
# Author.......: Mitchell Johnston - uid 0
# Contact......: http://www.bdragon.net
# Last Modified: Mon Sep 07 2009
#----------------------------------

#  This is a complete rewrite of a tool I wrote a long time ago. It is designed to run
# via cron. I have not had time to test it on a Solaris system.

# variables
#----------------------------------
BOLD=$(tput smso)     # turn bold on
UBOLD=$(tput rmso)    # turn bold off
LINE=$(tput smul)     # turn underline on
ULINE=$(tput rmul)    # turn underline off
PROG=$(basename $0)    # name of script
LOG=/var/log/$PROG.log # set location
PATH=/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin:$PATH
BASEDIR=/var/cmcs      # where to keep everything
LOG=$BASEDIR/cmcs.log  # log of all actions
NOTICE="root"          # contact to send notices to

# functions
#----------------------------------
pause(){ # simple pause routine
echo -n "Please hit ENTER: "
read x
}

log (){ # simple log entry
echo "$(date '+%D %T') $$  $*">>$LOG
}

data(){ # parses self for data elements
sed -n '/^===DATA===/,$p' <$0|grep -v '===DATA==='
}

check(){ # perform crc
if [ "$OS" = "SunOS" ]
then
    /usr/bin/sum $1|cut -d' ' -f1
else
    /usr/bin/sum -s $1|cut -d' ' -f1
fi
}

help(){ # display help
cat <<END-HELP
${BOLD}$PROG${UBOLD}  - ${LINE}A tool to auto-version files on a system${ULINE}

${LINE}Options:${ULINE}
 -h         Display help
 -r {file}  Report on change history
 -R {file}  Restore file
 -d {file}  Display the difersance from current to the last change
 -f         Display listing of all the files it is configured to check for
 -l         Display the last run from the log: $LOG

${BOLD}NOTE:${UBOLD} {file} must be the full path to the origenal file.

Anything else and it will check all of the files it finds for changes against
the baseline. If it is a new file, it will add it.

Location of the file versions: ${LINE}$BASEDIR${ULINE}

The file list that it is configured to check is maintained in the bottom of
script.
END-HELP
}

# main
#---------------------------

## setup check
if [ ! -d $BASEDIR ]
then
        mkdir -p $BASEDIR
        log "Creating: $BASEDIR"
fi

case $1 in
    -h) # display help
        help
        exit;;
    -r) # report
        SOURCE=$2
        # check to make sure file is on system
        if [ ! -f $SOURCE ]
        then
            echo "${BOLD}$SOURCE${UBOLD} not found"
            echo " "
            echo "$PROG -r {full path to file}"
            echo "$PROG -r /etc/motd"
            exit 2
        else
            NAME=$(echo $SOURCE| tr '/' '_') # this converts / to - in the name
        fi
        echo "${BOLD}$SOURCE${UBOLD}"
        ls -l $BASEDIR/$NAME.*
        exit
        ;;
    -R) # restore file
        SOURCE=$2
        # check to make sure file is on system
        if [ ! -f $SOURCE ]
        then
            echo "${BOLD}$SOURCE${UBOLD} not found"
            echo " "
            echo "$PROG -R {full path to file}"
            echo "$PROG -R /etc/motd"
            exit 2
        else
            NAME=$(echo $SOURCE| tr '/' '_') # this converts / to - in the name
        fi
        # display available versions for selection
        ls -l $BASEDIR/$NAME.*
        echo " "
        echo -n "Which revision number do you want to restore (0-5): "
        read REV
        if [ ! -n $BASEDIR/$NAME.$REV ]
        then
            echo "$NAME.$REV does not exist"
            sleep 2
        else
            cp $BASEDIR/$NAME.$REV $SOURCE
            ES=$?
            if [ $ES -gt 0 ]
            then
                echo "Error performing restore"
                exit 1
            else
                log "cp $BASEDIR/$NAME.$REV $SOURCE"
                exit
            fi
        fi
        #
        ;;
    -d) # vimdiff a file threw revisions
        which vimdiff >/dev/null 2>&1
        ES=$?
        if [ $ES -gt 0 ]
        then
            echo "This feature requires ${LINE}vimdiff${ULINE} installed"
            exit 1
        fi
        SOURCE=$2
        NAME=$(echo $SOURCE| tr '/' '_') # this converts / to - in the name
        if [ ! -f $BASEDIR/$NAME ]
        then
            echo "${BOLD}No versions of $SOURCE in $BASEDIR${UBOLD}"
            exit 1
        else
            while :
            do
                clear
                ls -l $BASEDIR/$NAME.*
                echo "x - to exit"
                echo -n "Which version number do you want to compare: "
                read REV
                if [ -f $BASEDIR/$NAME.$REV ]
                then
                    vimdiff $SOURCE $BASEDIR/$NAME.$REV
                else
                    if [ "$REV" == "x" ]
                    then
                        exit
                    fi
                    echo "$REV is an invalid version number"
                    sleep 2
                fi
            done
        fi
        ;;
    -f) # display file listing
        data|more
        exit;;
    -l) # display log from last run
        RUN=$(tail -1 $LOG|cut -d' ' -f3)
        grep $RUN $LOG
        exit;;
esac


## main loop
log "Starting: file check"
for FILE in $(data)
do
    if [ -f $FILE ]
    then
        NAME=$(echo $FILE| tr '/' '_') # this converts / to - in the name

        #See if file is in BASEDIR If not, back the file up to BASEDIR
        if [ ! -f $BASEDIR/$NAME ]
        then
                cp $FILE $BASEDIR/$NAME
                CRC=$(check $FILE)
                log "Added: $CRC $FILE"
                continue
        fi

        #If so, compare to system version and verify that they match
        CURRENT=$(check $FILE)
        LAST=$(check $BASEDIR/$NAME)
        if [ $CURRENT -eq $LAST ]
        then
            continue
        else
            MTIME=$(ls -Ll $FILE | awk '{print $6, $7, $8}')
            [ -f $BASEDIR/$NAME.4 ] && mv $BASEDIR/$NAME.4  $BASEDIR/$NAME.5
            [ -f $BASEDIR/$NAME.3 ] && mv $BASEDIR/$NAME.3  $BASEDIR/$NAME.4
            [ -f $BASEDIR/$NAME.2 ] && mv $BASEDIR/$NAME.2  $BASEDIR/$NAME.3
            [ -f $BASEDIR/$NAME.1 ] && mv $BASEDIR/$NAME.1  $BASEDIR/$NAME.2
            [ -f $BASEDIR/$NAME.0 ] && mv $BASEDIR/$NAME.0  $BASEDIR/$NAME.1
            [ -f $BASEDIR/$NAME ] && mv $BASEDIR/$NAME  $BASEDIR/$NAME.0
            cp $FILE $BASEDIR/$NAME
            log "Change: on [$MTIME] $CURRENT $LAST $FILE"
        fi
    fi
done
log "Ending: file check"

exit
===DATA===
/boot/grub/default
/boot/grub/device.map
/boot/grub/menu.lst
/etc/*.conf
/etc/TIMEZONE
/etc/default/in.ftpd
/etc/default/in.telnetd
/etc/default/login
/etc/default/su
/etc/defaultroute
/etc/dfs/dfstab
/etc/fstab
/etc/fstab
/etc/ftpchroot
/etc/ftpusers
/etc/groups
/etc/hosts
/etc/hosts.*
/etc/hosts.equiv
/etc/httpd/conf.d/*
/etc/httpd/conf/*
/etc/inet/hosts
/etc/inetd.conf
/etc/inittab
/etc/mail/aliases
/etc/mail/sendmail.cf
/etc/motd
/etc/mrtg/mrtg.cfg
/etc/my.cnf
/etc/named.boot
/etc/named.conf
/etc/netmasks
/etc/nsswitch.conf
/etc/pam.conf
/etc/pam.d/*
/etc/passwd
/etc/php.d/*
/etc/printconf
/etc/printers.conf
/etc/profile
/etc/proftpd.conf
/etc/proftpd.include
/etc/rc2.d/*
/etc/rc3.d/*
/etc/rcS.d/*
/etc/resolv.conf
/etc/services
/etc/shadow
/etc/ssh/*
/etc/ssh2/*
/etc/sysconfig/*
/etc/syslog.conf
/etc/nagios/*.cfg
/etc/system
/etc/vsftpd/*
/etc/xinetd.d/*
/opt/apache/conf/access.conf
/opt/apache/conf/httpd.conf
/opt/apache/conf/srm.conf
/root/.bash_logout
/root/.bash_profile
/root/.bashrc
/root/.rhosts
/root/.ssh/authorized_keys
/root/.ssh/authorized_keys2
/root/.ssh/id_dsa
/root/.ssh/id_dsa.pub
/root/.ssh2/*
/usr/local/etc/aide.conf
/usr/local/mysql/var/my.cnf
/usr/local/apache/conf/access.conf
/usr/local/apache/conf/httpd.conf
/usr/local/apache/conf/srm.conf
/usr/local/apache/conf/copernicus_license.txt
/usr/openv/netbackup/bp.conf
/usr/openv/netbackup/exclude_list
/var/named/*
/var/qmail/control/*
/var/spool/at/crontabs/*
/var/spool/cron/crontabs/*