1#!/bin/bash 2# fixfiles 3# 4# Script to restore labels on a SELinux box 5# 6# Copyright (C) 2004-2013 Red Hat, Inc. 7# Authors: Dan Walsh <dwalsh@redhat.com> 8# 9# This program is free software; you can redistribute it and/or modify 10# it under the terms of the GNU General Public License as published by 11# the Free Software Foundation; either version 2 of the License, or 12# (at your option) any later version. 13# 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with this program; if not, write to the Free Software 21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 23# 24# seclabel support was added in 2.6.30. This function will return a positive 25# number if the current kernel version is greater than 2.6.30, a negative 26# number if the current is less than 2.6.30 and 0 if they are the same. 27# 28function useseclabel { 29 VER=`uname -r` 30 SUP=2.6.30 31 expr '(' "$VER" : '\([^.]*\)' ')' '-' '(' "$SUP" : '\([^.]*\)' ')' '|' \ 32 '(' "$VER.0" : '[^.]*[.]\([^.]*\)' ')' '-' '(' "$SUP.0" : '[^.]*[.]\([^.]*\)' ')' '|' \ 33 '(' "$VER.0.0" : '[^.]*[.][^.]*[.]\([^.]*\)' ')' '-' '(' "$SUP.0.0" : '[^.]*[.][^.]*[.]\([^.]*\)' ')' 34} 35 36# 37# Get all mount points that support labeling. Use the 'seclabel' field if it 38# is available. Else fall back to known fs types which likely support xattrs 39# and we know were not context mounted. 40# 41get_all_labeled_mounts() { 42FS="`cat /proc/self/mounts | sort | uniq | awk '{print $2}'`" 43for i in $FS; do 44 if [ `useseclabel` -ge 0 ] 45 then 46 grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)seclabel(,|$)' && echo $i 47 else 48 grep " $i " /proc/self/mounts | grep -v "context=" | egrep --silent '(ext[234]| ext4dev | gfs2 | xfs | jfs | btrfs )' && echo $i 49 fi 50done 51} 52 53get_rw_labeled_mounts() { 54FS=`get_all_labeled_mounts | sort | uniq` 55for i in $FS; do 56 grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)rw(,|$)' && echo $i 57done 58} 59 60get_ro_labeled_mounts() { 61FS=`get_all_labeled_mounts | sort | uniq` 62for i in $FS; do 63 grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)ro(,|$)' && echo $i 64done 65} 66 67# 68# Get the default label returned from the kernel for a file with a lable the 69# kernel does not understand 70# 71get_undefined_type() { 72 SELINUXMNT=`grep selinuxfs /proc/self/mountinfo | head -1 | awk '{ print $5 }'` 73 cat ${SELINUXMNT}/initial_contexts/unlabeled | secon -t 74} 75 76# 77# Get the default label for a file without a label 78# 79get_unlabeled_type() { 80 SELINUXMNT=`grep selinuxfs /proc/self/mountinfo | head -1 | awk '{ print $5 }'` 81 cat $SELINUXMNT/initial_contexts/file | secon -t 82} 83 84exclude_dirs_from_relabelling() { 85 exclude_from_relabelling= 86 if [ -e /etc/selinux/fixfiles_exclude_dirs ] 87 then 88 while read i 89 do 90 # skip blank line and comment 91 # skip not absolute path 92 # skip not directory 93 [ -z "${i}" ] && continue 94 [[ "${i}" =~ "^[[:blank:]]*#" ]] && continue 95 [[ ! "${i}" =~ ^/.* ]] && continue 96 [[ ! -d "${i}" ]] && continue 97 exclude_from_relabelling="$exclude_from_relabelling -e $i" 98 logit "skipping the directory $i" 99 done < /etc/selinux/fixfiles_exclude_dirs 100 fi 101 echo "$exclude_from_relabelling" 102} 103 104exclude_dirs() { 105 exclude= 106 for i in /sys /proc /dev /run /mnt /var/tmp /var/lib/BackupPC /home /tmp /dev; do 107 [ -e $i ] && exclude="$exclude -e $i"; 108 done 109 exclude="$exclude `exclude_dirs_from_relabelling`" 110 echo "$exclude" 111} 112 113# 114# Set global Variables 115# 116fullFlag=0 117BOOTTIME="" 118VERBOSE="-p" 119FORCEFLAG="" 120DIRS="" 121RPMILES="" 122LOGFILE=/proc/self/fd/1 123SETFILES=/sbin/setfiles 124RESTORECON=/sbin/restorecon 125FILESYSTEMSRW=`get_rw_labeled_mounts` 126FILESYSTEMSRO=`get_ro_labeled_mounts` 127FILESYSTEMS="$FILESYSTEMSRW $FILESYSTEMSRO" 128SELINUXTYPE="targeted" 129if [ -e /etc/selinux/config ]; then 130 . /etc/selinux/config 131 FC=/etc/selinux/${SELINUXTYPE}/contexts/files/file_contexts 132else 133 FC=/etc/security/selinux/file_contexts 134fi 135 136# 137# Write to LOGFILE 138# 139logit () { 140if [ -n $LOGFILE ]; then 141 echo $1 >> "$LOGFILE" 142fi 143} 144# 145# Find files newer then the passed in date and fix the label 146# 147newer() { 148 DATE=$1 149 shift 150 for m in `echo $FILESYSTEMSRW`; do 151 find $m -mount -newermt $DATE -print0 2>/dev/null | ${RESTORECON} ${FORCEFLAG} ${VERBOSE} $* -i -0 -f - 152 done; 153 154} 155 156# 157# Compare PREVious File Context to currently installed File Context and 158# run restorecon on all files affected by the differences. 159# 160diff_filecontext() { 161if [ -f ${PREFC} -a -x /usr/bin/diff ]; then 162 TEMPFILE=`mktemp ${FC}.XXXXXXXXXX` 163 test -z "$TEMPFILE" && exit 164 PREFCTEMPFILE=`mktemp ${PREFC}.XXXXXXXXXX` 165 sed -r -e 's,:s0, ,g' $PREFC | sort -u > ${PREFCTEMPFILE} 166 sed -r -e 's,:s0, ,g' $FC | sort -u | \ 167 /usr/bin/diff -b ${PREFCTEMPFILE} - | \ 168 grep '^[<>]'|cut -c3-| grep ^/ | \ 169 egrep -v '(^/home|^/root|^/tmp|^/dev)' |\ 170 sed -r -e 's,[[:blank:]].*,,g' \ 171 -e 's|\(([/[:alnum:]]+)\)\?|{\1,}|g' \ 172 -e 's|([/[:alnum:]])\?|{\1,}|g' \ 173 -e 's|\?.*|*|g' \ 174 -e 's|\{.*|*|g' \ 175 -e 's|\(.*|*|g' \ 176 -e 's|\[.*|*|g' \ 177 -e 's|\.\*.*|*|g' \ 178 -e 's|\.\+.*|*|g' | \ 179 # These two sorts need to be separate commands \ 180 sort -u | \ 181 sort -d | \ 182 while read pattern ; \ 183 do if ! echo "$pattern" | grep -q -f ${TEMPFILE} 2>/dev/null; then \ 184 echo "$pattern"; \ 185 case "$pattern" in *"*") \ 186 echo "$pattern" | sed -e 's,^,^,' -e 's,\*$,,g' >> ${TEMPFILE};; 187 esac; \ 188 fi; \ 189 done | \ 190 ${RESTORECON} ${VERBOSE} -i -f - -R $* `exclude_dirs`; \ 191 rm -f ${TEMPFILE} ${PREFCTEMPFILE} 192fi 193} 194# 195# Log all Read Only file systems 196# 197LogReadOnly() { 198if [ ! -z "$FILESYSTEMSRO" ]; then 199 logit "Warning: Skipping the following R/O filesystems:" 200 logit "$FILESYSTEMSRO" 201fi 202} 203 204rpmlist() { 205rpm -q --qf '[%{FILESTATES} %{FILENAMES}\n]' "$1" | grep '^0 ' | cut -f2- -d ' ' 206[ ${PIPESTATUS[0]} != 0 ] && echo "$1 not found" >/dev/stderr 207} 208 209# 210# restore 211# if called with -n will only check file context 212# 213restore () { 214OPTION=$1 215shift 216 217if [ ! -z "$PREFC" ]; then 218 diff_filecontext $* 219 exit $? 220fi 221if [ ! -z "$BOOTTIME" ]; then 222 newer $BOOTTIME $* 223 exit $? 224fi 225[ -x /usr/sbin/genhomedircon ] && /usr/sbin/genhomedircon 226LogReadOnly 227# 228exclude_dirs="`exclude_dirs_from_relabelling $OPTION`" 229if [ -n "${exclude_dirs}" ] 230then 231 TEMPFCFILE=`mktemp ${FC}.XXXXXXXXXX` 232 test -z "$TEMPFCFILE" && exit 233 /bin/cp -p ${FC} ${TEMPFCFILE} &>/dev/null || exit 234 tmpdirs=${tempdirs//-e/} 235 for p in ${tmpdirs} 236 do 237 p="${p%/}" 238 p1="${p}(/.*)? -- <<none>>" 239 echo "${p1}" >> $TEMPFCFILE 240 logit "skipping the directory ${p}" 241 done 242FC=$TEMPFCFILE 243fi 244if [ ! -z "$RPMFILES" ]; then 245 for i in `echo "$RPMFILES" | sed 's/,/ /g'`; do 246 rpmlist $i | ${RESTORECON} $exclude_dirs ${FORCEFLAG} ${VERBOSE} $* -R -i -f - 2>&1 | cat >> $LOGFILE 247 done 248 exit $? 249fi 250if [ ! -z "$FILEPATH" ]; then 251 ${RESTORECON} $exclude_dirs ${FORCEFLAG} ${VERBOSE} -R $* $FILEPATH 2>&1 | cat >> $LOGFILE 252 return 253fi 254if [ -n "${FILESYSTEMSRW}" ]; then 255 echo "${OPTION}ing `echo ${FILESYSTEMSRW}`" 256 ${SETFILES} ${VERBOSE} $exclude_dirs -q ${FORCEFLAG} $* ${FC} ${FILESYSTEMSRW} 2>&1 | cat >> $LOGFILE 257else 258 echo >&2 "fixfiles: No suitable file systems found" 259fi 260if [ ${OPTION} != "Relabel" ]; then 261 return 262fi 263echo "Cleaning up labels on /tmp" 264rm -rf /tmp/gconfd-* /tmp/pulse-* /tmp/orbit-* $TEMPFCFILE 265 266UNDEFINED=`get_undefined_type` || exit $? 267UNLABELED=`get_unlabeled_type` || exit $? 268find /tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) \( -type s -o -type p \) -delete 269find /tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --reference /tmp {} \; 270find /var/tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --reference /var/tmp {} \; 271find /var/run \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --reference /var/run {} \; 272[ ! -e /var/lib/debug ] || find /var/lib/debug \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --reference /lib {} \; 273exit 0 274} 275 276fullrelabel() { 277 logit "Cleaning out /tmp" 278 find /tmp/ -mindepth 1 -delete 279 LogReadOnly 280 restore Relabel 281} 282 283relabel() { 284 if [ ! -z "$RPMFILES" ]; then 285 restore Relabel 286 fi 287 288 if [ $fullFlag == 1 ]; then 289 fullrelabel 290 fi 291 292 echo -n " 293 Files in the /tmp directory may be labeled incorrectly, this command 294 can remove all files in /tmp. If you choose to remove files from /tmp, 295 a reboot will be required after completion. 296 297 Do you wish to clean out the /tmp directory [N]? " 298 read answer 299 if [ "$answer" = y -o "$answer" = Y ]; then 300 fullrelabel 301 else 302 restore Relabel 303 fi 304} 305 306process() { 307# 308# Make sure they specified one of the three valid commands 309# 310case "$1" in 311 restore) restore Relabel;; 312 check) VERBOSE="-v"; restore Check -n;; 313 verify) restore Verify -n;; 314 relabel) relabel;; 315 onboot) 316 > /.autorelabel 317 [ -z "$FORCEFLAG" ] || echo -n "$FORCEFLAG " >> /.autorelabel 318 [ -z "$BOOTTIME" ] || echo -N $BOOTTIME >> /.autorelabel 319 # Force full relabel if / does not have a label on it 320 getfilecon / > /dev/null 2>&1 || echo -F >/.autorelabel 321 echo "System will relabel on next boot" 322 ;; 323 *) 324 usage 325 exit 1 326esac 327} 328usage() { 329 echo $""" 330Usage: $0 [-v] [-F] [-N time ] [-l logfile ] { check | restore| [-f] relabel | verify } [[dir/file] ... ] 331or 332Usage: $0 [-v] [-F] -R rpmpackage[,rpmpackage...] [-l logfile ] { check | restore | verify } 333or 334Usage: $0 [-v] [-F] -C PREVIOUS_FILECONTEXT { check | restore | verify } 335or 336Usage: $0 [-F] [-B] onboot 337""" 338} 339 340if [ $# = 0 ]; then 341 usage 342 exit 1 343fi 344 345# See how we were called. 346while getopts "N:BC:FfR:l:v" i; do 347 case "$i" in 348 B) 349 BOOTTIME=`/bin/who -b | awk '{print $3}'` 350 ;; 351 f) 352 fullFlag=1 353 ;; 354 v) 355 VERBOSE="-v" 356 ;; 357 R) 358 RPMFILES=$OPTARG 359 ;; 360 l) 361 LOGFILE=$OPTARG 362 ;; 363 C) 364 PREFC=$OPTARG 365 ;; 366 F) 367 FORCEFLAG="-F" 368 ;; 369 N) 370 BOOTTIME=$OPTARG 371 ;; 372 *) 373 usage 374 exit 1 375esac 376done 377# Move out processed options from arguments 378shift $(( OPTIND - 1 )) 379 380# Check for the command 381command=$1 382if [ -z $command ]; then 383 usage 384fi 385 386# Move out command from arguments 387shift 388 389# 390# check if they specified both DIRS and RPMFILES 391# 392 393if [ ! -z "$RPMFILES" ]; then 394 process $command 395 if [ $# -gt 0 ]; then 396 usage 397 fi 398else 399 if [ -z "$1" ]; then 400 process $command 401 else 402 while [ -n "$1" ]; do 403 FILEPATH=$1 404 process $command 405 shift 406 done 407 fi 408fi 409exit $? 410