443 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			443 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
| #!/bin/bash
 | |
| # fixfiles
 | |
| #
 | |
| # Script to restore labels on a SELinux box
 | |
| #
 | |
| # Copyright (C) 2004-2013 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 -o nounset
 | |
| 
 | |
| #
 | |
| # seclabel support was added in 2.6.30.  This function will return a positive
 | |
| # number if the current kernel version is greater than 2.6.30, a negative
 | |
| # number if the current is less than 2.6.30 and 0 if they are the same.
 | |
| #
 | |
| function useseclabel {
 | |
| 	VER=`uname -r`
 | |
| 	SUP=2.6.30
 | |
| 	expr '(' "$VER" : '\([^.]*\)' ')' '-' '(' "$SUP" : '\([^.]*\)' ')' '|' \
 | |
| 	     '(' "$VER.0" : '[^.]*[.]\([^.]*\)' ')' '-' '(' "$SUP.0" : '[^.]*[.]\([^.]*\)' ')' '|' \
 | |
| 	     '(' "$VER.0.0" : '[^.]*[.][^.]*[.]\([^.]*\)' ')' '-' '(' "$SUP.0.0" : '[^.]*[.][^.]*[.]\([^.]*\)' ')'
 | |
| }
 | |
| 
 | |
| #
 | |
| # Get all mount points that support labeling.  Use the 'seclabel' field if it
 | |
| # is available.  Else fall back to known fs types which likely support xattrs
 | |
| # and we know were not context mounted.
 | |
| #
 | |
| get_all_labeled_mounts() {
 | |
| FS="`cat /proc/self/mounts | sort | uniq | awk '{print $2}'`"
 | |
| for i in $FS; do
 | |
| 	if [ `useseclabel` -ge 0 ]
 | |
| 	then
 | |
| 		grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)seclabel(,|$)' && echo $i
 | |
| 	else
 | |
| 		grep " $i " /proc/self/mounts | grep -v "context=" | egrep --silent '(ext[234]| ext4dev | gfs2 | xfs | jfs | btrfs )' && echo $i
 | |
| 	fi
 | |
| done
 | |
| }
 | |
| 
 | |
| get_rw_labeled_mounts() {
 | |
| FS=`get_all_labeled_mounts | sort | uniq`
 | |
| for i in $FS; do
 | |
| 	grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)rw(,|$)' && echo $i
 | |
| done
 | |
| }
 | |
| 
 | |
| get_ro_labeled_mounts() {
 | |
| FS=`get_all_labeled_mounts | sort | uniq`
 | |
| for i in $FS; do
 | |
| 	grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)ro(,|$)' && echo $i
 | |
| done
 | |
| }
 | |
| 
 | |
| #
 | |
| # Get the default label returned from the kernel for a file with a label the
 | |
| # kernel does not understand
 | |
| #
 | |
| get_undefined_type() {
 | |
| 	SELINUXMNT=`grep selinuxfs /proc/self/mountinfo | head -1 | awk '{ print $5 }'`
 | |
| 	cat ${SELINUXMNT}/initial_contexts/unlabeled | secon -t
 | |
| }
 | |
| 
 | |
| #
 | |
| # Get the default label for a file without a label
 | |
| #
 | |
| get_unlabeled_type() {
 | |
| 	SELINUXMNT=`grep selinuxfs /proc/self/mountinfo | head -1 | awk '{ print $5 }'`
 | |
| 	cat $SELINUXMNT/initial_contexts/file | secon -t
 | |
| }
 | |
| 
 | |
| exclude_dirs_from_relabelling() {
 | |
|     exclude_from_relabelling=
 | |
|     if [ -e /etc/selinux/fixfiles_exclude_dirs ]
 | |
|     then
 | |
| 	while read i
 | |
| 	do
 | |
| 	  # skip blank line and comment
 | |
| 	  # skip not absolute path
 | |
| 	  # skip not directory
 | |
| 	  [ -z "${i}" ] && continue
 | |
| 	  [[ "${i}" =~ ^[[:blank:]]*# ]] && continue
 | |
| 	  [[ ! "${i}" =~ ^/.* ]] && continue
 | |
| 	  [[ ! -d "${i}" ]] && continue
 | |
| 	  exclude_from_relabelling="$exclude_from_relabelling -e $i"
 | |
| 	done < /etc/selinux/fixfiles_exclude_dirs
 | |
|     fi
 | |
|     echo "$exclude_from_relabelling"
 | |
| }
 | |
| 
 | |
| #
 | |
| # Set global Variables
 | |
| #
 | |
| fullFlag=0
 | |
| BOOTTIME=""
 | |
| VERBOSE="-p"
 | |
| FORCEFLAG=""
 | |
| THREADS=""
 | |
| RPMFILES=""
 | |
| PREFC=""
 | |
| RESTORE_MODE=""
 | |
| BIND_MOUNT_FILESYSTEMS=""
 | |
| SETFILES=/sbin/setfiles
 | |
| RESTORECON=/sbin/restorecon
 | |
| FILESYSTEMSRW=`get_rw_labeled_mounts`
 | |
| FILESYSTEMSRO=`get_ro_labeled_mounts`
 | |
| 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 all Read Only file systems
 | |
| #
 | |
| LogReadOnly() {
 | |
| if [ ! -z "$FILESYSTEMSRO" ]; then
 | |
|     echo "Warning: Skipping the following R/O filesystems:"
 | |
|     echo "$FILESYSTEMSRO"
 | |
| fi
 | |
| }
 | |
| 
 | |
| #
 | |
| # Log directories excluded from relabelling by configuration file
 | |
| #
 | |
| LogExcluded() {
 | |
| for i in ${EXCLUDEDIRS//-e / }; do
 | |
|     echo "skipping the directory $i"
 | |
| done
 | |
| }
 | |
| 
 | |
| #
 | |
| # Find files newer then the passed in date and fix the label
 | |
| #
 | |
| newer() {
 | |
|     DATE=$1
 | |
|     shift
 | |
|     LogReadOnly
 | |
|     for m in `echo $FILESYSTEMSRW`; do
 | |
| 	find $m -mount -newermt $DATE -print0 2>/dev/null | ${RESTORECON} ${FORCEFLAG} ${VERBOSE} ${THREADS} $* -i -0 -f -
 | |
|     done;
 | |
| }
 | |
| 
 | |
| #
 | |
| # Compare PREVious File Context to currently installed File Context and
 | |
| # run restorecon on all files affected by the differences.
 | |
| #
 | |
| diff_filecontext() {
 | |
| EXCLUDEDIRS="`exclude_dirs_from_relabelling`"
 | |
| for i in /sys /proc /mnt /var/tmp /var/lib/BackupPC /home /root /tmp; do
 | |
|     [ -e $i ]  && EXCLUDEDIRS="${EXCLUDEDIRS} -e $i";
 | |
| done
 | |
| LogExcluded
 | |
| 
 | |
| 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)' |\
 | |
| 	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' \
 | |
| 	       -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 -e 's,^,^,' -e 's,\*$,,g' >> ${TEMPFILE};;
 | |
| 		  esac; \
 | |
| 	       fi; \
 | |
| 	    done | \
 | |
| 	${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} ${THREADS} $* -i -R -f -; \
 | |
| 	rm -f ${TEMPFILE} ${PREFCTEMPFILE}
 | |
| fi
 | |
| }
 | |
| 
 | |
| rpmlist() {
 | |
| rpm -q --qf '[%{FILESTATES} %{FILENAMES}\n]' "$1" | grep '^0 ' | cut -f2- -d ' '
 | |
| [ ${PIPESTATUS[0]} != 0 ] && echo "$1 not found" >/dev/stderr
 | |
| }
 | |
| 
 | |
| #
 | |
| # restore
 | |
| # if called with -n will only check file context
 | |
| #
 | |
| restore () {
 | |
| OPTION=$1
 | |
| shift
 | |
| 
 | |
| # [-B | -N time ]
 | |
| if [ -n "$BOOTTIME" ]; then
 | |
| 	newer $BOOTTIME $*
 | |
| 	return
 | |
| fi
 | |
| 
 | |
| # -C PREVIOUS_FILECONTEXT
 | |
| if [ "$RESTORE_MODE" == PREFC ]; then
 | |
| 	diff_filecontext $*
 | |
| 	return
 | |
| fi
 | |
| 
 | |
| [ -x /usr/sbin/genhomedircon ] && /usr/sbin/genhomedircon
 | |
| 
 | |
| EXCLUDEDIRS="`exclude_dirs_from_relabelling`"
 | |
| LogExcluded
 | |
| 
 | |
| case "$RESTORE_MODE" in
 | |
|     RPMFILES)
 | |
| 	for i in `echo "$RPMFILES" | sed 's/,/ /g'`; do
 | |
| 	    rpmlist $i | ${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} ${THREADS} $* -i -R -f -
 | |
| 	done
 | |
|     ;;
 | |
|     FILEPATH)
 | |
| 	${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} ${THREADS} $* -R -- "$FILEPATH"
 | |
|     ;;
 | |
|     *)
 | |
| 	if [ -n "${FILESYSTEMSRW}" ]; then
 | |
| 	    LogReadOnly
 | |
| 	    echo "${OPTION}ing `echo ${FILESYSTEMSRW}`"
 | |
| 
 | |
| 	    if [ -z "$BIND_MOUNT_FILESYSTEMS" ]; then
 | |
| 	        ${SETFILES} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -q ${THREADS} ${FC} ${FILESYSTEMSRW}
 | |
| 	    else
 | |
| 	        # we bind mount so we can fix the labels of files that have already been
 | |
| 	        # mounted over
 | |
| 	        for m in `echo $FILESYSTEMSRW`; do
 | |
| 	            TMP_MOUNT="$(mktemp -d)"
 | |
| 	            test -z ${TMP_MOUNT+x} && echo "Unable to find temporary directory!" && exit 1
 | |
| 
 | |
| 	            mkdir -p "${TMP_MOUNT}${m}" || exit 1
 | |
| 	            mount --bind "${m}" "${TMP_MOUNT}${m}" || exit 1
 | |
| 	            ${SETFILES} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} ${THREADS} $* -q ${FC} -r "${TMP_MOUNT}" "${TMP_MOUNT}${m}"
 | |
| 	            umount "${TMP_MOUNT}${m}" || exit 1
 | |
| 	            rm -rf "${TMP_MOUNT}" || echo "Error cleaning up."
 | |
| 	        done;
 | |
| 	    fi
 | |
| 	else
 | |
| 	    echo >&2 "fixfiles: No suitable file systems found"
 | |
| 	fi
 | |
| 	if [ ${OPTION} != "Relabel" ]; then
 | |
| 	    return
 | |
| 	fi
 | |
| 	echo "Cleaning up labels on /tmp"
 | |
| 	rm -rf /tmp/gconfd-* /tmp/pulse-* /tmp/orbit-*
 | |
| 
 | |
| 	UNDEFINED=`get_undefined_type` || exit $?
 | |
| 	UNLABELED=`get_unlabeled_type` || exit $?
 | |
| 	find /tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) \( -type s -o -type p \) -delete
 | |
| 	find /tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --no-dereference --reference /tmp {} \;
 | |
| 	find /var/tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --no-dereference --reference /var/tmp {} \;
 | |
| 	find /var/run \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --no-dereference --reference /var/run {} \;
 | |
| 	[ ! -e /var/lib/debug ] || find /var/lib/debug \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --no-dereference --reference /lib {} \;
 | |
|     ;;
 | |
| esac
 | |
| }
 | |
| 
 | |
| fullrelabel() {
 | |
|     echo "Cleaning out /tmp"
 | |
|     find /tmp/ -mindepth 1 -delete
 | |
|     restore Relabel
 | |
| }
 | |
| 
 | |
| 
 | |
| relabel() {
 | |
|     if [ -n "$RESTORE_MODE" -a "$RESTORE_MODE" != DEFAULT ]; then
 | |
| 	usage
 | |
| 	exit 1
 | |
|     fi
 | |
| 
 | |
|     if [ $fullFlag == 1  ]; then
 | |
| 	fullrelabel
 | |
| 	return
 | |
|     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 Relabel
 | |
|     fi
 | |
| }
 | |
| 
 | |
| process() {
 | |
| #
 | |
| # Make sure they specified one of the three valid commands
 | |
| #
 | |
| case "$1" in
 | |
|     restore) restore Relabel;;
 | |
|     check) VERBOSE="-v"; restore Check -n;;
 | |
|     verify) VERBOSE="-v"; restore Verify -n;;
 | |
|     relabel) relabel;;
 | |
|     onboot)
 | |
| 	if [ -n "$RESTORE_MODE" -a "$RESTORE_MODE" != DEFAULT ]; then
 | |
| 	    usage
 | |
| 	    exit 1
 | |
| 	fi
 | |
| 	> /.autorelabel || exit $?
 | |
| 	[ -z "$FORCEFLAG" ] || echo -n "$FORCEFLAG " >> /.autorelabel
 | |
| 	[ -z "$BOOTTIME" ] || echo -n "-N $BOOTTIME " >> /.autorelabel
 | |
| 	[ -z "$BIND_MOUNT_FILESYSTEMS" ] || echo -n "-M " >> /.autorelabel
 | |
| 	[ -z "$THREADS" ] || echo -n "$THREADS " >> /.autorelabel
 | |
| 	# Force full relabel if SELinux is not enabled
 | |
| 	selinuxenabled || echo -F > /.autorelabel
 | |
| 	echo "System will relabel on next boot"
 | |
| 	;;
 | |
|     *)
 | |
|     usage
 | |
|     exit 1
 | |
| esac
 | |
| }
 | |
| usage() {
 | |
| 	echo $"""
 | |
| Usage: $0 [-v] [-F] [-M] [-f] [-T nthreads] relabel
 | |
| or
 | |
| Usage: $0 [-v] [-F] [-B | -N time ] [-T nthreads] { check | restore | verify }
 | |
| or
 | |
| Usage: $0 [-v] [-F] [-T nthreads] { check | restore | verify } dir/file ...
 | |
| or
 | |
| Usage: $0 [-v] [-F] [-T nthreads] -R rpmpackage[,rpmpackage...] { check | restore | verify }
 | |
| or
 | |
| Usage: $0 [-v] [-F] [-T nthreads] -C PREVIOUS_FILECONTEXT { check | restore | verify }
 | |
| or
 | |
| Usage: $0 [-F] [-M] [-B] [-T nthreads] onboot
 | |
| """
 | |
| }
 | |
| 
 | |
| if [ $# -eq 0 ]; then
 | |
| 	usage
 | |
| 	exit 1
 | |
| fi
 | |
| 
 | |
| set_restore_mode() {
 | |
| 	if [ -n "$RESTORE_MODE" ]; then
 | |
| 		# can't specify two different modes
 | |
| 		usage
 | |
| 		exit 1
 | |
| 	fi
 | |
| 	RESTORE_MODE="$1"
 | |
| }
 | |
| 
 | |
| # See how we were called.
 | |
| while getopts "N:BC:FfR:l:vMT:" i; do
 | |
|     case "$i" in
 | |
| 	B)
 | |
| 		BOOTTIME=`/bin/who -b | awk '{print $3}'`
 | |
| 		set_restore_mode DEFAULT
 | |
| 		;;
 | |
| 	N)
 | |
| 		BOOTTIME=$OPTARG
 | |
| 		set_restore_mode BOOTTIME
 | |
| 		;;
 | |
| 	R)
 | |
| 		RPMFILES=$OPTARG
 | |
| 		set_restore_mode RPMFILES
 | |
| 		;;
 | |
| 	C)
 | |
| 		PREFC=$OPTARG
 | |
| 		set_restore_mode PREFC
 | |
| 		;;
 | |
| 	v)
 | |
| 		VERBOSE="-v"
 | |
| 		;;
 | |
| 	l)
 | |
| 		# Old scripts use obsolete option `-l logfile`
 | |
| 		echo "Redirecting output to $OPTARG"
 | |
| 		exec >>"$OPTARG" 2>&1
 | |
| 		;;
 | |
| 	M)
 | |
| 		BIND_MOUNT_FILESYSTEMS="-M"
 | |
| 		;;
 | |
| 	F)
 | |
| 		FORCEFLAG="-F"
 | |
| 		;;
 | |
| 	f)
 | |
| 		fullFlag=1
 | |
| 		;;
 | |
| 	T)
 | |
| 		THREADS="-T $OPTARG"
 | |
| 		;;
 | |
| 	*)
 | |
| 	    usage
 | |
| 	    exit 1
 | |
| esac
 | |
| done
 | |
| # Move out processed options from arguments
 | |
| shift $(( OPTIND - 1 ))
 | |
| 
 | |
| # Check for the command
 | |
| if [ $# -eq 0 ]; then
 | |
|     usage
 | |
|     exit 1
 | |
| fi
 | |
| command="$1"
 | |
| 
 | |
| # Move out command from arguments
 | |
| shift
 | |
| 
 | |
| if [ $# -gt 0 ]; then
 | |
|     set_restore_mode FILEPATH
 | |
|     while [ $# -gt 0 ]; do
 | |
| 	FILEPATH="$1"
 | |
| 	process "$command" || exit $?
 | |
| 	shift
 | |
|     done
 | |
| else
 | |
|     process "$command"
 | |
| fi
 | |
| 
 |