1 |
#!/bin/bash |
2 |
|
3 |
# Custom ErrorLog script to write out the apache error log lines to |
4 |
# both syslog # (for CSIRT ) and to a "normal" error_log file. |
5 |
# Also parse the error and write out a user-specific log message |
6 |
# to /www/error/<user>/error_log-<TIMESTAMP> |
7 |
|
8 |
function guess_owner |
9 |
{ |
10 |
# Guessing owner |
11 |
owner=`/usr/bin/stat --printf="%U" "$1" 2> /dev/null` |
12 |
if [ -z "${owner}" ] |
13 |
then |
14 |
owner=`echo "$1" | /bin/awk -F/ '{ if ( $2 == "user" || $2 == "home" ) print $3 }'` |
15 |
fi |
16 |
if [ "${owner}" = "UNKNOWN" ] |
17 |
then |
18 |
owner= |
19 |
fi |
20 |
if [ -z "${owner}" ] |
21 |
then |
22 |
owner=`/usr/bin/stat --printf="%U" "${1%/*}" 2> /dev/null` |
23 |
if [ -z "${owner}" ] |
24 |
then |
25 |
owner=`echo "${1%/*}" | /bin/awk -F/ '{ if ( $2 == "user" || $2 == "home" ) print $3 }'` |
26 |
fi |
27 |
if [ "${owner}" = "UNKNOWN" ] |
28 |
then |
29 |
owner= |
30 |
fi |
31 |
fi |
32 |
|
33 |
echo "${owner}" |
34 |
} |
35 |
|
36 |
function print_error_line |
37 |
{ |
38 |
if [ $# -eq 2 ] |
39 |
then |
40 |
owner="$1" |
41 |
error="$2" |
42 |
|
43 |
if [ -n "${owner}" -a ! "x${owner}" = "xroot" -a ! "x${owner}" = "xapache" ] |
44 |
then |
45 |
timestamp=`date +"%Y%m%d"` |
46 |
owner_dir="${OUTPUTDIR}/${owner}" |
47 |
owner_log="${owner_dir}/error_log-${timestamp}.txt" |
48 |
if [ ! -d "${owner_dir}" ] |
49 |
then |
50 |
if [ `/usr/bin/id -u` -eq 0 ] |
51 |
then |
52 |
# /usr/bin/sudo -u janjust /bin/chmod 777 "${OUTPUTDIR}" |
53 |
/bin/su -s /bin/sh ${owner} -c "/bin/mkdir --mode=700 \"${owner_dir}\"" |
54 |
# /usr/bin/sudo -u janjust /bin/chmod 755 "${OUTPUTDIR}" |
55 |
fi |
56 |
# cd to it explicitly to trigger an automounter |
57 |
(cd "${owner_dir}" 2> /dev/null) |
58 |
fi |
59 |
if [ -d "${owner_dir}" ] |
60 |
then |
61 |
echo "${error}" 2> /dev/null >> "${owner_log}" |
62 |
if [ $? -ne 0 -a `/usr/bin/id -u` -eq 0 ] |
63 |
then |
64 |
# we use 'tee' here to avoid wildcard/quote/backtick expansion errors |
65 |
# AND we avoid the need for a subshell with output redirection |
66 |
echo "${error}" | /bin/su -s /bin/sh ${owner} -c "/usr/bin/tee --append \"${owner_log}\"" 2>&1 > /dev/null |
67 |
# Previously: |
68 |
# echo "${error}" | /usr/bin/sudo -n -u ${owner} /bin/dd of="${owner_log}" |
69 |
# oflag=append conv=notrunc status=noxfer 2> /dev/null |
70 |
fi |
71 |
fi |
72 |
fi |
73 |
fi |
74 |
} |
75 |
|
76 |
|
77 |
[ -f /etc/sysconfig/httpd_syslogger ] && . /etc/sysconfig/httpd_syslogger |
78 |
|
79 |
if [ x"$HTTPDLOGGER_ERRLOGFILE" = x"" ]; then |
80 |
LOG_FILE=/var/log/httpd/error_log |
81 |
else |
82 |
LOG_FILE="$HTTPDLOGGER_ERRLOGFILE" |
83 |
fi |
84 |
|
85 |
if [ x"$HTTPDLOGGER_ERRTAG" = x"" ]; then |
86 |
TAG="-t http-error" |
87 |
else |
88 |
TAG="-t $HTTPDLOGGER_ERRTAG" |
89 |
fi |
90 |
|
91 |
if [ x"$HTTPDLOGGER_USERDIR" = x"" ]; then |
92 |
OUTPUTDIR=/data/week/www-errors |
93 |
else |
94 |
OUTPUTDIR="$HTTPDLOGGER_USERDIR" |
95 |
fi |
96 |
|
97 |
if [ x"$HTTPDLOGGER_PERUSERERRORS" = x"yes" ]; then |
98 |
USERERRORS=1 |
99 |
else |
100 |
USERERRORS=0 |
101 |
fi |
102 |
|
103 |
|
104 |
# Now process the input |
105 |
while read line |
106 |
do |
107 |
# write out to the error_log file and to syslog |
108 |
if [ x"$HTTPDLOGGER_LOCALFILE" != x"no" ]; then |
109 |
echo "${line}" | /usr/bin/tee --append ${LOG_FILE} | /usr/bin/logger $TAG $HTTPDLOGGER_LOGARGS $@ |
110 |
else |
111 |
echo "${line}" | /usr/bin/logger $TAG $HTTPDLOGGER_LOGARGS $@ |
112 |
fi |
113 |
|
114 |
if [ $USERERRORS -eq 0 ]; then |
115 |
continue |
116 |
fi |
117 |
|
118 |
# now parse the line and try to deduce the owner of any offending/missing file or script |
119 |
msg=`echo "${line}" | /bin/sed -n 's/\[\(.*\)\] \[\(.*\)\] \[client \(.*\)\] \(.*\)/\4/p'` |
120 |
|
121 |
if [ -z "${msg}" ] |
122 |
then |
123 |
continue |
124 |
fi |
125 |
|
126 |
# reset some vars |
127 |
file= |
128 |
owner= |
129 |
|
130 |
# does the error message start with "PHP" |
131 |
if [ ! "x${msg}" = "x${msg#PHP}" ] |
132 |
then |
133 |
file=`echo "$msg" | /bin/sed -n 's/^PHP.* in \/\(.*\) on line.*/\/\1/p'` |
134 |
owner=`guess_owner "${file}"` |
135 |
elif [ ! "x${msg}" = "x${msg#File does not exist}" ] |
136 |
then |
137 |
file=`echo "$msg" | /bin/sed -n 's/^File does not exist: \(.*\)/\1/p'` |
138 |
file=${file%, referer*} |
139 |
elif [ ! "x${msg}" = "x${msg#script }" ] |
140 |
then |
141 |
# first check for "script '....' not found" |
142 |
file=`echo "$msg" | /bin/sed -n "s/^script '\(.*\)'.*/\1/p"` |
143 |
# now check for "not found or unable to stat: .... |
144 |
if [ -z "${file}" ] |
145 |
then |
146 |
file=`echo "${msg}" | /bin/sed -n "s/^script not found or unable to stat: \(.*\)/\1/p"` |
147 |
file=${file%, referer*} |
148 |
fi |
149 |
elif [ ! "x${msg}" = "x${msg#(2)No such file or directory: Could not open password file: }" ] |
150 |
then |
151 |
file=`echo "$msg" | /bin/sed -n 's/^(2)No such file or directory: Could not open password file: \(.*\)/\1/p'` |
152 |
file=${file%, referer*} |
153 |
elif [ ! "x${msg}" = "x${msg#(13)Permission denied}" ] |
154 |
then |
155 |
warn="${msg#(13)Permission denied: } " |
156 |
# check for "deny server access" |
157 |
file=`echo "${warn}" | /bin/sed -n "s/deny server access: \(.*\)/\1/p"` |
158 |
file=${file%, referer*} |
159 |
# now check for "cannot read directory" |
160 |
if [ -z "${file}" ] |
161 |
then |
162 |
file=`echo "${warn}" | /bin/sed -n "s/cannot read directory for multi: \(.*\)/\1/p"` |
163 |
file=${file%, referer*} |
164 |
fi |
165 |
# now check for "pcfg_openfile" |
166 |
if [ -z "${file}" ] |
167 |
then |
168 |
file=`echo "${warn}" | /bin/sed -n "s/\(.*\) pcfg_openfile: unable to check htaccess file/\1/p"` |
169 |
file=${file%, referer*} |
170 |
fi |
171 |
elif [ ! "x${msg}" = "x${msg#Symbolic link not allowed or link target not accessible:}" ] |
172 |
then |
173 |
file=`echo "$msg" | /bin/sed -n "s/^Symbolic link not allowed or link target not accessible: \(.*\)/\1/p"` |
174 |
file=${file%, referer*} |
175 |
elif [ ! "x${msg}" = "x${msg#mod_mime_magic:}" ] |
176 |
then |
177 |
file=`echo "$msg" | /bin/sed -n "s/^mod_mime_magic: can't read .\(.*\)'.*/\1/p"` |
178 |
|
179 |
# elif [ ! "x${msg}" = "x${msg#<ul></ul>}" ] |
180 |
# then |
181 |
# debug "msg: Annoying Wordpress plugin error" |
182 |
# # ignore |
183 |
# elif [ ! "x${msg}" = "x${msg#(5)Input/output error: access to /~form/forum}" ] |
184 |
# then |
185 |
# debug "msg: Form input/output error" |
186 |
# # ignore |
187 |
# elif [ ! "x${msg}" = "x${msg#client denied by server configuration:}" ] |
188 |
# then |
189 |
# debug "msg: client denied by server configuration" |
190 |
# # ignore |
191 |
# else |
192 |
# debug "other type of error" |
193 |
# debug "$msg" |
194 |
fi |
195 |
|
196 |
# Now try to find the owner and write out the error line to the right file |
197 |
owner=`guess_owner "${file}"` |
198 |
print_error_line "${owner}" "${line}" |
199 |
done |
200 |
|