#!/bin/sh # fixfiles # # Script to restore labels on a SELinux box # # Copyright (C) 2004 Red Hat, Inc. # Authors: Dan Walsh # # 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 # fullFlag=0 FORCEFLAG="" DIRS="" RPMILES="" OUTFILES="" LOGFILE=`tty` if [ $? != 0 ]; then LOGFILE="/dev/null" fi SYSLOGFLAG="-l" LOGGER=/usr/sbin/logger SETFILES=/sbin/setfiles RESTORECON=/sbin/restorecon FILESYSTEMSRW=`mount | grep -v "context=" | egrep -v '\((|.*,)bind(,.*|)\)' | awk '/(ext[23]| xfs | jfs ).*\(rw/{print $3}';` FILESYSTEMSRO=`mount | grep -v "context=" | egrep -v '\((|.*,)bind(,.*|)\)' | awk '/(ext[23]| xfs | jfs ).*\(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 # # Log to either syslog or a LOGFILE # logit () { if [ -n $LOGFILE ]; then echo $1 >> $LOGFILE fi } # # Compare PREVious File Context to currently installed File Context and # run restorecon on all files affected by the differences. # diff_filecontext() { if [ -f ${PREFC} -a -x /usr/bin/diff ]; then TEMPFILE=`mktemp ${FC}.XXXXXXXXXX` test -z "$TEMPFILE" && exit PREFCTEMPFILE=`mktemp ${PREFC}.XXXXXXXXXX` sed -r -e 's,:s0, ,g' $PREFC | sort -u > ${PREFCTEMPFILE} sed -r -e 's,:s0, ,g' $FC | sort -u | \ /usr/bin/diff -b ${PREFCTEMPFILE} - | \ grep '^[<>]'|cut -c3-| grep ^/ | \ egrep -v '(^/home|^/root|^/tmp|^/dev)' |\ sed -r -e 's,[[:blank:]].*,,g' \ -e 's|\(([/[:alnum:]]+)\)\?|{\1,}|g' \ -e 's|([/[:alnum:]])\?|{\1,}|g' \ -e 's|\?.*|*|g' \ -e 's|\(.*|*|g' \ -e 's|\[.*|*|g' \ -e 's|\.\*.*|*|g' \ -e 's|\.\+.*|*|g' | \ # These two sorts need to be separate commands \ sort -u | \ sort -d | \ while read pattern ; \ do if ! echo "$pattern" | grep -q -f ${TEMPFILE} 2>/dev/null; then \ echo "$pattern"; \ case "$pattern" in *"*") \ echo "$pattern" | sed 's,\*$,,g' >> ${TEMPFILE};; esac; \ fi; \ done | \ while read pattern ; do find $pattern \ ! \( -fstype ext2 -o -fstype ext3 -o -fstype jfs -o -fstype xfs \) -prune -o \ \( -wholename /home -o -wholename /root -o -wholename /tmp -wholename /dev \) -prune -o -print; \ done 2> /dev/null | \ ${RESTORECON} $2 -v -f - rm -f ${TEMPFILE} ${PREFCTEMPFILE} fi } # # Log all Read Only file systems # LogReadOnly() { if [ ! -z "$FILESYSTEMSRO" ]; then logit "Warning: Skipping the following R/O filesystems:" logit "$FILESYSTEMSRO" fi } rpmlist() { rpm -q --qf '[%{FILESTATES} %{FILENAMES}\n]' "$1" | grep '^0 ' | cut -f2- -d ' ' } # # restore # if called with -n will only check file context # restore () { if [ ! -z "$PREFC" ]; then diff_filecontext $1 exit $? fi if [ ! -z "$RPMFILES" ]; then for i in `echo "$RPMFILES" | sed 's/,/ /g'`; do rpmlist $i | ${RESTORECON} ${OUTFILES} ${FORCEFLAG} $* -i -f - 2>&1 >> $LOGFILE done exit $? fi if [ ! -z "$DIRS" ]; then if [ -x /usr/bin/find ]; then for d in ${DIRS} ; do find $d \ ! \( -fstype ext2 -o -fstype ext3 -o -fstype jfs -o -fstype xfs \) -prune -o -print | \ ${RESTORECON} ${OUTFILES} ${FORCEFLAG} $* -f - 2>&1 >> $LOGFILE done else ${RESTORECON} ${OUTFILES} ${FORCEFLAG} -R $* $DIRS 2>&1 >> $LOGFILE fi exit $? fi LogReadOnly ${SETFILES} ${OUTFILES} ${SYSLOGFLAG} ${FORCEFLAG} $* ${FC} ${FILESYSTEMSRW} 2>&1 >> $LOGFILE exit $? } fullrelabel() { logit "Cleaning out /tmp" rm -rf /tmp/.??* /tmp/* LogReadOnly restore } relabel() { if [ ! -z "$RPMFILES" ]; then restore fi if [ $fullFlag == 1 ]; then fullrelabel fi 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 fullrelabel else restore fi } usage() { echo $"Usage: $0 [-l logfile ] [-o outputfile ] { check | restore|[-F] relabel } [[dir] ... ] " echo or echo $"Usage: $0 -R rpmpackage[,rpmpackage...] -C PREVIOUS_FILECONTEXT [-l logfile ] [-o outputfile ] { check | restore }" } if [ $# = 0 ]; then usage exit 1 fi # See how we were called. while getopts "C:Ffo:R:l:" i; do case "$i" in f) fullFlag=1 ;; R) RPMFILES=$OPTARG ;; o) OUTFILES=$OPTARG ;; l) LOGFILE=$OPTARG ;; C) PREFC=$OPTARG ;; F) FORCEFLAG="-F" ;; *) usage exit 1 esac done # Check for the command eval command=\$${OPTIND} let OPTIND=$OPTIND+1 if [ -z $command ]; then usage fi # # check if they specified both DIRS and RPMFILES # if [ ! -z "$RPMFILES" ]; then if [ $OPTIND -le $# ]; then usage fi else while [ $OPTIND -le $# ]; do eval DIR=\$${OPTIND} DIRS="$DIRS $DIR" let OPTIND=$OPTIND+1 done fi # # Make sure they specified one of the three valid commands # case "$command" in restore) restore -p ;; check) restore -n -v ;; verify) restore -n -o -;; relabel) relabel;; *) usage exit 1 esac