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