annotate previous-work/more_control_helpers/bin/forall_direntries_from @ 20:c75924bd38e3

fix security hole relating to path for package user.
author Robert McIntyre <rlm@mit.edu>
date Thu, 10 Jan 2013 04:25:17 +0000
parents d6bef198ae71
children
rev   line source
rlm@1 1 #!/bin/bash
rlm@1 2 # Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
rlm@1 3 # You may do everything with this code except misrepresent its origin.
rlm@1 4 # PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND!
rlm@1 5
rlm@1 6 #The following list should contain the mount points of all filesystems
rlm@1 7 #that are to be scanned as a space-separated list within parentheses.
rlm@1 8 #/ will usually be in this list and if you have /usr
rlm@1 9 #on a separate partition, it will also be in this list. Other non-special
rlm@1 10 #filesystems where package users could own files should also be put in this
rlm@1 11 #list.
rlm@1 12 #Mount points whose filesystems are special, such as procfs or sysfs must
rlm@1 13 #not be in this list. While a simple find on those special filesystems should
rlm@1 14 #be harmless, operations such as "-exec grep something" are NOT SAFE and may
rlm@1 15 #have HARMFUL SIDE-EFFECTS, especially when performed as root.
rlm@1 16 fs_to_scan=(/)
rlm@1 17
rlm@1 18 #Files with a path prefix found in the following list are ignored.
rlm@1 19 #This list will usually contain the parent directory of your package users'
rlm@1 20 #home directories, because normally you don't want to scan those. You can
rlm@1 21 #also add other directories that will never contain package user files, such
rlm@1 22 #as /home. This reduces scan time.
rlm@1 23 #NOTE: The LFS-6.0 book uses a ramfs mounted on /dev and with that setup
rlm@1 24 #/dev does not need to be in the prune list. But since there is no requirement
rlm@1 25 #that /dev have its on filesystem it's better to prune it explicitly.
rlm@1 26 prune_prefixes=(/home /usr/src /dev /tools) #NO TRAILING SLASHES!!!!
rlm@1 27
rlm@1 28 if [ $# -lt 1 -o "$1" = "--help" ]; then
rlm@1 29 echo 1>&2
rlm@1 30 echo 1>&2 'USAGE: '"${0##*/}"' <user_or_group_name> [<find-commands>]'
rlm@1 31 echo 1>&2
rlm@1 32 echo 1>&2 ' If <find-commands> contains no action other than -prune, -print will be'
rlm@1 33 echo 1>&2 ' executed for all matching files.'
rlm@1 34 echo 1>&2 ' Entries will be matched if group and/or user equals <user_or_group_name>'
rlm@1 35 echo 1>&2 ' (numeric UID/GID allowed).'
rlm@1 36 echo 1>&2 ' All matching entries will be acted on, including device special files, so'
rlm@1 37 echo 1>&2 ' you should be extra careful with the <find-commands> you provide!'
rlm@1 38 echo 1>&2
rlm@1 39 exit 1
rlm@1 40 fi
rlm@1 41
rlm@1 42 #suppress ugly debug output from shell
rlm@1 43 trap ':' SIGPIPE
rlm@1 44
rlm@1 45 ugname="$1"
rlm@1 46 shift 1 #remove user_or_group_name from argument list
rlm@1 47
rlm@1 48 # Recent versions of find issue a warning if "-depth" is listed after a
rlm@1 49 # non-option argument. To prevent this warning if -depth is passed to
rlm@1 50 # this script, we pick up the "-depth" argument here to move it to the
rlm@1 51 # front later on.
rlm@1 52 depth=""
rlm@1 53 if [ "_$1" = "_-depth" ]; then
rlm@1 54 depth=-depth
rlm@1 55 shift 1
rlm@1 56 fi
rlm@1 57
rlm@1 58 ugmatcher=(-false)
rlm@1 59 #test if find accepts ugname as a user, and append to ugmatcher if it does
rlm@1 60 if find / -maxdepth 0 -user "$ugname" >/dev/null 2>&1 ; then
rlm@1 61 ugmatcher[${#ugmatcher[@]}]="-or"
rlm@1 62 ugmatcher[${#ugmatcher[@]}]="-user"
rlm@1 63 ugmatcher[${#ugmatcher[@]}]="$ugname"
rlm@1 64 fi
rlm@1 65 #test if find accepts ugname as a group, and append to ugmatcher if it does
rlm@1 66 if find / -maxdepth 0 -group "$ugname" >/dev/null 2>&1 ; then
rlm@1 67 ugmatcher[${#ugmatcher[@]}]="-or"
rlm@1 68 ugmatcher[${#ugmatcher[@]}]="-group"
rlm@1 69 ugmatcher[${#ugmatcher[@]}]="$ugname"
rlm@1 70 fi
rlm@1 71
rlm@1 72 #if find accepted ugname as neither user nor group, then exit
rlm@1 73 if [ "${#ugmatcher[@]}" = 1 ]; then
rlm@1 74 echo 1>&2 'find does not accept `'"$ugname'"' as group or user name'
rlm@1 75 exit 1
rlm@1 76 fi
rlm@1 77
rlm@1 78 #construct find commands that match the prune_prefixes. Each prefix will be
rlm@1 79 #matched as -path <prefix> -or -path <prefix>/*
rlm@1 80 #so that the directory itself and all subdirectories are matched.
rlm@1 81 y=(\( -false)
rlm@1 82 for ((i=0; $i<${#prune_prefixes[@]}; i=$i+1))
rlm@1 83 do
rlm@1 84 y[${#y[@]}]='-or'
rlm@1 85 y[${#y[@]}]=-path
rlm@1 86 y[${#y[@]}]="${prune_prefixes[$i]}"
rlm@1 87 y[${#y[@]}]='-or'
rlm@1 88 y[${#y[@]}]=-path
rlm@1 89 y[${#y[@]}]="${prune_prefixes[$i]}/*"
rlm@1 90 done
rlm@1 91 y[${#y[@]}]=')'
rlm@1 92
rlm@1 93 #In the following find command, the part
rlm@1 94 # -not ( ( "${y[@]}" -prune ) -or "${y[@]}" )
rlm@1 95 #is responsible for preventing the files that match prune_prefixes from
rlm@1 96 #being processed. The 2nd "${y[@]}" may seem redundant, but it isn't, because
rlm@1 97 #-prune has no effect and is always false when -depth is used.
rlm@1 98 #The -true before "$@" ensures that -depth can be passed as only parameter.
rlm@1 99 find "${fs_to_scan[@]}" $depth -xdev -noleaf \
rlm@1 100 -not \( \( "${y[@]}" -prune \) -or "${y[@]}" \) \
rlm@1 101 -and \( "${ugmatcher[@]}" \) -and \( -true "$@" \)