#!/bin/sh
# fixfiles
#
# Script to restore labels on a SELinux box
#
# Copyright (C) 2004 Red Hat, Inc.
# Authors: Dan Walsh <dwalsh@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Set global Variables
#
checkFlag=0
restoreFlag=0
relabelFlag=0
fullFlag=0
rpmFlag=0
rpmFiles=""
outfileFlag=0
OUTFILES=""
logfileFlag=0
LOGFILE=/dev/null
SYSLOGFLAG="-l"
SETFILES=/usr/sbin/setfiles
FILESYSTEMSRW=`mount | grep -v "context=" | egrep -v '\((|.*,)bind(,.*|)\)' | awk '/(ext[23]| xfs | reiserfs ).*\(rw/{print $3}';`
FILESYSTEMSRO=`mount | grep -v "context=" | egrep -v '\((|.*,)bind(,.*|)\)' | awk '/(ext[23]| xfs | reiserfs ).*\(ro/{print $3}';`
FILESYSTEMS="$FILESYSTEMSRW $FILESYSTEMSRO"
SELINUXTYPE="targeted"

if [ -e /etc/selinux/config ]; then
    . /etc/selinux/config
    FC=/etc/selinux/${SELINUXTYPE}/contexts/files/file_contexts
else
    FC=/etc/security/selinux/file_contexts
fi

logit () {
if [ $logfileFlag = 0 ]; then
    logger -i $1
else
    echo $1 >> $LOGFILE
fi
}
checkLabels () {
if [ ! -z "$1" ]; then
    for i in `echo $1 | sed 's/,/ /g'`; do
	rpm -q -l $i | restorecon ${OUTFILES} -n -v -f - 2>&1 >> $LOGFILE
    done
else
    if [ ! -z "$FILESYSTEMSRO" ]; then
        logit "Warning: Skipping the following R/O filesystems:"
        logit "$FILESYSTEMSRO"
    fi
    ${SETFILES} ${OUTFILES} ${SYSLOGFLAG} -n -v ${FC} ${FILESYSTEMSRW} 2>&1 >> $LOGFILE
fi
}

restoreLabels () {
if [ ! -z "$1" ]; then
    for i in `echo $1 | sed 's/,/ /g'`; do
	rpm -q -l $i | restorecon ${OUTFILES} -v -f - 2>&1 >> $LOGFILE
    done
else
    if [ ! -z "$FILESYSTEMSRO" ]; then
        logit "Warning: Skipping the following R/O filesystems:"
        logit "$FILESYSTEMSRO"
    fi
    ${SETFILES} ${OUTFILES} ${SYSLOGFLAG} -v ${FC} ${FILESYSTEMS} 2>&1 >> $LOGFILE
fi
}

relabel() {
logit "Cleaning out /tmp"
rm -rf /tmp/.??* /tmp/*
if [ ! -z "$1" ]; then
    for i in `echo $1 | sed 's/,/ /g'`; do
	rpm -q -l $i | restorecon ${OUTFILES} -v -f - 2>&1 >> $LOGFILE
    done
else
    if [ ! -z "$FILESYSTEMSRO" ]; then
        logit "Warning: Skipping the following R/O filesystems:"
        logit "$FILESYSTEMSRO"
    fi
    ${SETFILES} ${OUTFILES} ${SYSLOGFLAG} -v ${FC} ${FILESYSTEMS} 2>&1 >> $LOGFILE
fi
}
relabelCheck() {
    echo -n "
    Files in the /tmp directory may be labeled incorrectly, this command 
    can remove all files in /tmp.  If you choose to remove files from /tmp, 
    a reboot will be required after completion.
    
    Do you wish to clean out the /tmp directory [N]? "
    read answer
    if [ "$answer" = y -o  "$answer" = Y ]; then 
	relabel $1
    else
	restoreLabels $1
    fi

}

usage() {
      	echo $"Usage: $0 {-R rpmpackage[,rpmpackage...] [-l logfile ] [-o outputfile ] |check|restore|[-F] relabel}"
}

if [ $# = 0 ]; then
	usage
	exit 1
fi

# See how we were called.
for i in $@; do
if [ $rpmFlag = 2 ]; then
    rpmFiles=$i
    rpmFlag=1
    continue
fi
if [ $outfileFlag = 2 ]; then
    OUTFILES="-o $i"
    outfileFlag=1
    continue
fi
if [ $logfileFlag = 2 ]; then
    LOGFILE="$i"
    echo > $LOGFILE
    SYSLOGFLAG=""
    logfileFlag=1
    continue
fi

case "$i" in
	check)
		checkFlag=1
		;;
	restore)
		restoreFlag=1
		;;
	relabel)
		relabelFlag=1
		;;
        -F)
		fullFlag=1
		;;
        -R)
		rpmFlag=2
		;;
        -o)
		outfileFlag=2
		;;
        -l)
		logfileFlag=2
		;;
	*)
	    usage
	    exit 1
esac
done
if [ `expr $checkFlag + $restoreFlag + $relabelFlag` -gt 1 ]; then 
    usage
    exit 1
fi

if [ $checkFlag = 1 ]; then
    checkLabels $rpmFiles
fi
if [ $restoreFlag = 1 ]; then
    restoreLabels $rpmFiles
fi
if [ $relabelFlag = 1 ]; then
    if [ $fullFlag = 1 ]; then
	relabel $rpmFiles
    else
	relabelCheck $rpmFiles
    fi
fi

exit $?
