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 (at] 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 # 28 function 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 # 41 get_all_labeled_mounts() { 42 FS="`cat /proc/self/mounts | sort | uniq | awk '{print $2}'`" 43 for 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 50 done 51 } 52 53 get_rw_labeled_mounts() { 54 FS=`get_all_labeled_mounts | sort | uniq` 55 for i in $FS; do 56 grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)rw(,|$)' && echo $i 57 done 58 } 59 60 get_ro_labeled_mounts() { 61 FS=`get_all_labeled_mounts | sort | uniq` 62 for i in $FS; do 63 grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)ro(,|$)' && echo $i 64 done 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 # 71 get_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 # 79 get_unlabeled_type() { 80 SELINUXMNT=`grep selinuxfs /proc/self/mountinfo | head -1 | awk '{ print $5 }'` 81 cat $SELINUXMNT/initial_contexts/file | secon -t 82 } 83 84 exclude_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 104 exclude_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 # 116 fullFlag=0 117 BOOTTIME="" 118 VERBOSE="-p" 119 FORCEFLAG="" 120 DIRS="" 121 RPMILES="" 122 LOGFILE=`tty` 123 if [ $? != 0 ]; then 124 LOGFILE="/dev/null" 125 fi 126 LOGGER=/usr/sbin/logger 127 SETFILES=/sbin/setfiles 128 RESTORECON=/sbin/restorecon 129 FILESYSTEMSRW=`get_rw_labeled_mounts` 130 FILESYSTEMSRO=`get_ro_labeled_mounts` 131 FILESYSTEMS="$FILESYSTEMSRW $FILESYSTEMSRO" 132 SELINUXTYPE="targeted" 133 if [ -e /etc/selinux/config ]; then 134 . /etc/selinux/config 135 FC=/etc/selinux/${SELINUXTYPE}/contexts/files/file_contexts 136 else 137 FC=/etc/security/selinux/file_contexts 138 fi 139 140 # 141 # Log to either syslog or a LOGFILE 142 # 143 logit () { 144 if [ -n $LOGFILE ]; then 145 echo $1 >> $LOGFILE 146 fi 147 } 148 # 149 # Find files newer then the passed in date and fix the label 150 # 151 newer() { 152 DATE=$1 153 for m in `echo $FILESYSTEMSRW`; do 154 find $m -mount -newermt $DATE -print0 2>/dev/null | ${RESTORECON} ${FORCEFLAG} ${VERBOSE} -i -0 -f - 155 done; 156 157 } 158 159 # 160 # Compare PREVious File Context to currently installed File Context and 161 # run restorecon on all files affected by the differences. 162 # 163 diff_filecontext() { 164 if [ -f ${PREFC} -a -x /usr/bin/diff ]; then 165 TEMPFILE=`mktemp ${FC}.XXXXXXXXXX` 166 test -z "$TEMPFILE" && exit 167 PREFCTEMPFILE=`mktemp ${PREFC}.XXXXXXXXXX` 168 sed -r -e 's,:s0, ,g' $PREFC | sort -u > ${PREFCTEMPFILE} 169 sed -r -e 's,:s0, ,g' $FC | sort -u | \ 170 /usr/bin/diff -b ${PREFCTEMPFILE} - | \ 171 grep '^[<>]'|cut -c3-| grep ^/ | \ 172 egrep -v '(^/home|^/root|^/tmp|^/dev)' |\ 173 sed -r -e 's,[[:blank:]].*,,g' \ 174 -e 's|\(([/[:alnum:]]+)\)\?|{\1,}|g' \ 175 -e 's|([/[:alnum:]])\?|{\1,}|g' \ 176 -e 's|\?.*|*|g' \ 177 -e 's|\{.*|*|g' \ 178 -e 's|\(.*|*|g' \ 179 -e 's|\[.*|*|g' \ 180 -e 's|\.\*.*|*|g' \ 181 -e 's|\.\+.*|*|g' | \ 182 # These two sorts need to be separate commands \ 183 sort -u | \ 184 sort -d | \ 185 while read pattern ; \ 186 do if ! echo "$pattern" | grep -q -f ${TEMPFILE} 2>/dev/null; then \ 187 echo "$pattern"; \ 188 case "$pattern" in *"*") \ 189 echo "$pattern" | sed -e 's,^,^,' -e 's,\*$,,g' >> ${TEMPFILE};; 190 esac; \ 191 fi; \ 192 done | \ 193 ${RESTORECON} ${VERBOSE} -i -f - -R `exclude_dirs`; \ 194 rm -f ${TEMPFILE} ${PREFCTEMPFILE} 195 fi 196 } 197 # 198 # Log all Read Only file systems 199 # 200 LogReadOnly() { 201 if [ ! -z "$FILESYSTEMSRO" ]; then 202 logit "Warning: Skipping the following R/O filesystems:" 203 logit "$FILESYSTEMSRO" 204 fi 205 } 206 207 rpmlist() { 208 rpm -q --qf '[%{FILESTATES} %{FILENAMES}\n]' "$1" | grep '^0 ' | cut -f2- -d ' ' 209 [ ${PIPESTATUS[0]} != 0 ] && echo "$1 not found" >/dev/stderr 210 } 211 212 # 213 # restore 214 # if called with -n will only check file context 215 # 216 restore () { 217 OPTION=$1 218 shift 219 220 if [ ! -z "$PREFC" ]; then 221 diff_filecontext $* 222 exit $? 223 fi 224 if [ ! -z "$BOOTTIME" ]; then 225 newer $BOOTTIME 226 exit $? 227 fi 228 [ -x /usr/sbin/genhomedircon ] && /usr/sbin/genhomedircon 229 LogReadOnly 230 # 231 exclude_dirs="`exclude_dirs_from_relabelling $OPTION`" 232 if [ -n "${exclude_dirs}" ] 233 then 234 TEMPFCFILE=`mktemp ${FC}.XXXXXXXXXX` 235 test -z "$TEMPFCFILE" && exit 236 /bin/cp -p ${FC} ${TEMPFCFILE} &>/dev/null || exit 237 tmpdirs=${tempdirs//-e/} 238 for p in ${tmpdirs} 239 do 240 p="${p%/}" 241 p1="${p}(/.*)? -- <<none>>" 242 echo "${p1}" >> $TEMPFCFILE 243 logit "skipping the directory ${p}" 244 done 245 FC=$TEMPFCFILE 246 fi 247 if [ ! -z "$RPMFILES" ]; then 248 for i in `echo "$RPMFILES" | sed 's/,/ /g'`; do 249 rpmlist $i | ${RESTORECON} $exclude_dirs ${FORCEFLAG} ${VERBOSE} $* -R -i -f - 2>&1 | cat >> $LOGFILE 250 done 251 exit $? 252 fi 253 if [ ! -z "$FILEPATH" ]; then 254 ${RESTORECON} $exclude_dirs ${FORCEFLAG} ${VERBOSE} -R $* $FILEPATH 2>&1 | cat >> $LOGFILE 255 return 256 fi 257 if [ -n "${FILESYSTEMSRW}" ]; then 258 echo "${OPTION}ing `echo ${FILESYSTEMSRW}`" 259 ${SETFILES} ${VERBOSE} $exclude_dirs -q ${FORCEFLAG} $* ${FC} ${FILESYSTEMSRW} 2>&1 | cat >> $LOGFILE 260 else 261 echo >&2 "fixfiles: No suitable file systems found" 262 fi 263 if [ ${OPTION} != "Relabel" ]; then 264 return 265 fi 266 echo "Cleaning up labels on /tmp" 267 rm -rf /tmp/gconfd-* /tmp/pulse-* /tmp/orbit-* $TEMPFCFILE 268 269 UNDEFINED=`get_undefined_type` || exit $? 270 UNLABELED=`get_unlabeled_type` || exit $? 271 find /tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) \( -type s -o -type p \) -delete 272 find /tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --reference /tmp {} \; 273 find /var/tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --reference /var/tmp {} \; 274 find /var/run \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --reference /var/run {} \; 275 [ ! -e /var/lib/debug ] || find /var/lib/debug \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --reference /lib {} \; 276 exit 0 277 } 278 279 fullrelabel() { 280 logit "Cleaning out /tmp" 281 find /tmp/ -mindepth 1 -delete 282 LogReadOnly 283 restore Relabel 284 } 285 286 relabel() { 287 if [ ! -z "$RPMFILES" ]; then 288 restore Relabel 289 fi 290 291 if [ $fullFlag == 1 ]; then 292 fullrelabel 293 fi 294 295 echo -n " 296 Files in the /tmp directory may be labeled incorrectly, this command 297 can remove all files in /tmp. If you choose to remove files from /tmp, 298 a reboot will be required after completion. 299 300 Do you wish to clean out the /tmp directory [N]? " 301 read answer 302 if [ "$answer" = y -o "$answer" = Y ]; then 303 fullrelabel 304 else 305 restore Relabel 306 fi 307 } 308 309 process() { 310 # 311 # Make sure they specified one of the three valid commands 312 # 313 case "$1" in 314 restore) restore Relabel;; 315 check) VERBOSE="-v"; restore Check -n;; 316 verify) restore Verify -n -o -;; 317 relabel) relabel;; 318 onboot) 319 > /.autorelabel 320 [ -z "$FORCEFLAG" ] || echo -n "$FORCEFLAG " >> /.autorelabel 321 [ -z "$BOOTTIME" ] || echo -N $BOOTTIME >> /.autorelabel 322 # Force full relabel if / does not have a label on it 323 getfilecon / > /dev/null 2>&1 || echo -F >/.autorelabel 324 echo "System will relabel on next boot" 325 ;; 326 *) 327 usage 328 exit 1 329 esac 330 } 331 usage() { 332 echo $""" 333 Usage: $0 [-v] [-F] [-N time ] [-l logfile ] { check | restore| [-f] relabel | verify } [[dir/file] ... ] 334 or 335 Usage: $0 [-v] [-F] -R rpmpackage[,rpmpackage...] [-l logfile ] { check | restore | verify } 336 or 337 Usage: $0 [-v] [-F] -C PREVIOUS_FILECONTEXT { check | restore | verify } 338 or 339 Usage: $0 [-F] [-B] onboot 340 """ 341 } 342 343 if [ $# = 0 ]; then 344 usage 345 exit 1 346 fi 347 348 # See how we were called. 349 while getopts "N:BC:FfR:l:v" i; do 350 case "$i" in 351 B) 352 BOOTTIME=`/bin/who -b | awk '{print $3}'` 353 ;; 354 f) 355 fullFlag=1 356 ;; 357 v) 358 VERBOSE="-v" 359 ;; 360 R) 361 RPMFILES=$OPTARG 362 ;; 363 l) 364 LOGFILE=$OPTARG 365 ;; 366 C) 367 PREFC=$OPTARG 368 ;; 369 F) 370 FORCEFLAG="-F" 371 ;; 372 N) 373 BOOTTIME=$OPTARG 374 ;; 375 *) 376 usage 377 exit 1 378 esac 379 done 380 # Move out processed options from arguments 381 shift $(( OPTIND - 1 )) 382 383 # Check for the command 384 command=$1 385 if [ -z $command ]; then 386 usage 387 fi 388 389 # Move out command from arguments 390 shift 391 392 # 393 # check if they specified both DIRS and RPMFILES 394 # 395 396 if [ ! -z "$RPMFILES" ]; then 397 process $command 398 if [ $# -gt 0 ]; then 399 usage 400 fi 401 else 402 if [ -z "$1" ]; then 403 process $command 404 else 405 while [ -n "$1" ]; do 406 FILEPATH=$1 407 process $command 408 shift 409 done 410 fi 411 fi 412 exit $? 413