view previous-work/more_control_helpers/bin/list_package @ 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
line wrap: on
line source
1 #!/bin/bash
2 # Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
3 # You may do everything with this code except misrepresent its origin.
4 # PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND!
6 if [ $# -lt 1 -o \( $# -gt 1 -a "z$1" != "z:man" -a "z$1" != "z:mani" -a "z$1" != "z:lib" \) -o "$1" = "--help" ]; then
7 echo 1>&2
8 echo 1>&2 'USAGE: '"${0##*/}"' <user_or_group_name>'
9 echo 1>&2
10 echo 1>&2 ' Entries will be matched if group and/or user equals <user_or_group_name>'
11 echo 1>&2 ' (numeric UID/GID allowed).'
12 echo 1>&2 ' This script uses `forall_direntries_from'"'"' and `list_suspicious_files_from'"'."
13 echo 1>&2
14 echo 1>&2 ' NOTE: Several minutes may pass before you see the first output.'
15 echo 1>&2 ' You should probably redirect output to a file for later reference.'
16 echo 1>&2
17 echo 1>&2 ' WARNING! This program is for listing files from package users only!'
18 echo 1>&2 ' Do NOT use it to list files from untrusted users!'
19 echo 1>&2 ' An untrusted user could set up a manipulated manpage to exploit'
20 echo 1>&2 ' a bug in man when it is used to extract the summary!'
21 exit 1
22 fi
24 # KNOWN BUGS:
25 # - when extracting summaries from manpages, candidate manpages are considered
26 # in alphabetic order rather than the order used by the man command.
27 # The problem with this is that section 8, which contains manpages for
28 # admin commands, will be considered after lower-numbered sections.
29 # In the rare case that an admin command has the same name as a topic from
30 # a lower-numbered manpage installed by the same package, the summary will
31 # be taken from the wrong manpage.
32 # An example for such a clash are the faillog.5 and faillog.8 manpages from
33 # the shadow package.
34 # Because this problem is difficult to fix, rare and easily spotted (since
35 # the manpage that should have provided the summary will be listed under
36 # EXTRA MANPAGES) I won't fix it.
38 ugname="$1"
40 #suppress ugly debug output from shell
41 trap ':' SIGPIPE
43 if [ $# -gt 1 ]; then
44 name="${2##*/}"
45 case "$1" in
46 :man)
47 name=${name%.gz}
48 name=${name%.bz2}
49 name=${name%.*}
50 echo $'command\2'"$name"$'\2man\2'"$2" ;;
51 :mani)
52 name=${name%.gz}
53 name=${name%.bz2}
54 name=${name%.*}
55 echo $'command\2'"$name"$'\2mani\2'"$2" ;;
56 :lib)
57 name=${name%.a}
58 name=${name%%.so*}
59 echo "lib $name"
60 ;;
61 esac
62 exit 0
63 fi
65 sanitize() { tr -c '[:print:]' '?' ; }
67 # $1: <commandname>
68 # $2: command\2<commandname>\2cmd\2(-><linktarget>)
69 # $3: command\2<commandname>\2man[i]\2<manpage_path> or <empty>
70 expand_command()
71 {
72 sep=$'\2'
73 cmdname="$1"
74 cmdline="$2"
75 manline="$3"
76 linktarget="${cmdline##*${sep}}"
78 if [ -z "$manline" ]; then
79 description='No manpage'
80 #the "l" at the beginning is just to make it sort after "lib"
81 echo -n "lmanlessbin $cmdname" | sanitize
82 echo
84 else # if [ ! -z "$manline" ]; then
85 manpage=${manline##*${sep}}
86 manpagedir=${manpage%/*}
87 wsc='[[:space:],]\+'
88 # The cd $manpagedir is a workaround for a bug in man-db that causes it
89 # to attempt to resolve paths relative to cwd.
90 # The `t l;d;:l;n;b l' in the sed command is voodoo magic to make sed
91 # output only the first match but to keep eating up all input. I use this
92 # instead of `| head -n 1', because head breaks the pipe after doing
93 # its 1 line output, which (if it happens before sed has processed the
94 # complete input) freaks out man and causes it to emit a totally
95 # silly error message including "No such file or directory", which is
96 # annoying when you do testing without suppressing man's errors.
97 # The $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' removes the backspace-based
98 # as well as ESC-based formatting from man's output.
99 description="$( { cd "$manpagedir/.." 2>/dev/null ;
100 COLUMNS=300 man "$manpage" 2>/dev/null ||
101 echo " $name - Broken manpage" ; } |
102 sed $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' |
103 sed -n "/^NAME/,/^[A-Z]/s/^.*${wsc}${cmdname}${wsc}.*-\+${wsc}\(.*\)/\1/p;t l;d;:l;n;b l" )"
104 if [ -z "$description" ]; then
105 description="$( cd "$manpagedir/.." 2>/dev/null ;
106 COLUMNS=300 man "$manpage" 2>/dev/null |
107 sed $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' |
108 sed -n "s/^.*${wsc}..*${wsc}.*-\+${wsc}\(.*\)/\1/p;t l;d;:l;n;b l" )"
109 fi
110 test -z "$description" && description="Weird manpage"
111 fi
113 echo -n "binexe $cmdname" | sanitize
114 test "$linktarget" != '(->)' && echo -n "$linktarget" | sanitize
115 echo
116 #the "lx" in "lxdescription" is just to make sure it sorts after "lmanlessbin"
117 echo -n "lxdescription $cmdname: $description" | sanitize
118 echo
119 }
121 # NOTE: The -path and -lname stuff at the beginning of the following is
122 # there to make sure that none of the lines output by find contains
123 # a) \n or \r, because that would mess up post-processing the output
124 # line-by-line.
125 # b) \x7f, because this character triggers one of the nastier bash-bugs
126 # wrt string handling
127 # c) \2, because I use this as separator within the lines
128 # (Why \2 and not \0 or \1 ? Because bash can't cope with \0 at all and has
129 # bugs related to \1.)
130 #
131 # Because of this, having the final section called "ALL FILES" is technically
132 # a lie, because files with a path containing one of the abovementioned
133 # characters will not appear in output.
134 # However, a) no sane package contains such files
135 # b) they will be listed in the output from list_suspicious_files
136 cmd=(\( -path $'*\n*' -or -path $'*\r*' -or -path $'*\x7f*'
137 -or -path $'*\2*'
138 -or -lname $'*\n*' -or -lname $'*\r*' -or -lname $'*\x7f*'
139 -or -lname $'*\2*'
140 \)
141 -or
142 \(
143 \( -printf "zall %p\n" \) ,
144 \(
145 \( -type f -or -xtype f \) -and
146 \(
147 \( -perm -u+x \( -path "*/bin/*" -or -path "*/sbin/*" \) -printf 'command\2%f\2cmd\2(->%l)\n' \)
148 -or \( -path "*/man/man*/*" -exec "$0" ":man" {} \; \)
149 -or \( -path "*/man/*/man*/*" -exec "$0" ":mani" {} \; \)
150 -or \( \( -name "lib*.so" -or -name "lib*.a" -or -name "lib*.so.*" \) -path "*/lib/*" -exec "$0" ":lib" {} \; \)
151 -or \( -type f -perm -u+x -not \( \( -name "lib*.so" -or -name "lib*.a" -or -name "lib*.so.*" \) -path "*/lib/*" \) -printf "nobinexe %p\n" \)
152 \)
153 \)
154 \)
155 )
157 forall_direntries_from "$ugname" "${cmd[@]}" | sort -u |
158 {
159 sep=$'\2'
160 hold=''
161 for((;;))
162 do
163 if [ -z "$hold" ]; then
164 read -r line || break
165 else
166 line="$hold"
167 hold=''
168 fi
170 case "z$line" in
171 zcommand${sep}*${sep}cmd${sep}*)
172 cmdname=${line#command${sep}}
173 cmdname=${cmdname%%${sep}*}
174 read -r hold
175 case "z$hold" in
176 zcommand${sep}${cmdname}${sep}man${sep}*|zcommand${sep}${cmdname}${sep}mani${sep}*)
177 expand_command "$cmdname" "$line" "$hold"
178 hold=''
179 ;;
181 z*)
182 expand_command "$cmdname" "$line" ""
183 ;;
184 esac
185 ;;
187 zcommand${sep}*${sep}man${sep}*|command${sep}*${sep}mani${sep}*)
189 echo -n "manextra ${line##*${sep}}" | sanitize
190 echo
191 ;;
193 z*)
194 echo -n "$line" | sanitize
195 echo
196 ;;
197 esac
199 done
200 } | sort | #no -u here, bc. the above processing may equalize different files
201 {
202 # (1) binexe: Executables (in *bin/)
203 # (2) lib: Libraries (in *lib/*)
204 # (3) lmanlessbin: Executables (in *bin/) without manpages
205 # (4) lxdescription: Summaries for executables (in *bin/)
206 # (5) manextra: Extra manpages
207 # full paths, no perms
208 # (6) nobinexe: Executables not in *bin/ (excluding *lib/*.so and *lib/*.so.*)
209 # full paths, no perms
210 # (7) zall: All files
211 # full paths, no perms
213 curstate=''
214 while read -r line
215 do
216 newstate="${line%% *}"
217 if [ "$newstate" != "$curstate" ]; then
218 curstate="$newstate"
219 case "$curstate" in
220 binexe)
221 echo 'EXECUTABLES (in */bin or */sbin)'
222 echo -n " ${line#binexe }"
223 ;;
224 lib)
225 echo
226 echo
227 echo 'LIBRARIES (lib*.a or lib*.so)'
228 echo -n " ${line#lib }"
229 ;;
230 lmanlessbin)
231 echo
232 echo
233 echo 'EXECUTABLES WITH NO MANPAGE (in */bin or */sbin)'
234 echo -n " ${line#lmanlessbin }"
235 ;;
236 lxdescription)
237 echo
238 echo
239 echo 'MANPAGE SUMMARIES OF EXECUTABLES (in */bin or */sbin)'
240 echo " ${line#lxdescription }"
241 ;;
242 manextra)
243 echo
244 echo 'EXTRA MANPAGES'
245 echo " ${line#manextra }"
246 ;;
247 nobinexe)
248 echo
249 echo 'EXTRA EXECUTABLES (not in */bin or */sbin)'
250 echo " ${line#nobinexe }"
251 ;;
252 zall)
253 echo
254 echo 'ALL FILES'
255 echo " ${line#zall }"
256 ;;
257 *)
258 echo
259 echo
260 echo 'UNEXPECTED LINE'
261 echo " $line"
262 ;;
264 esac
265 else
266 case "$curstate" in
267 binexe) echo -n ", ${line#binexe }"
268 ;;
269 lib) echo -n ", ${line#lib }"
270 ;;
271 lmanlessbin) echo -n ", ${line#lmanlessbin }"
272 ;;
273 lxdescription) echo " ${line#lxdescription }"
274 ;;
275 manextra) echo " ${line#manextra }"
276 ;;
277 nobinexe) echo " ${line#nobinexe }"
278 ;;
279 zall) echo " ${line#zall }"
280 ;;
281 *)
282 echo
283 echo 'UNEXPECTED LINE'
284 echo " $line"
285 ;;
286 esac
287 fi
288 done
289 }
291 list_suspicious_files_from "$ugname"