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