#!/bin/bash # Custom ErrorLog script to write out the apache error log lines to # both syslog # (for CSIRT ) and to a "normal" error_log file. # Also parse the error and write out a user-specific log message # to /www/error//error_log- function guess_owner { # Guessing owner owner=`/usr/bin/stat --printf="%U" "$1" 2> /dev/null` if [ -z "${owner}" ] then owner=`echo "$1" | /bin/awk -F/ '{ if ( $2 == "user" || $2 == "home" ) print $3 }'` fi if [ "${owner}" = "UNKNOWN" ] then owner= fi if [ -z "${owner}" ] then owner=`/usr/bin/stat --printf="%U" "${1%/*}" 2> /dev/null` if [ -z "${owner}" ] then owner=`echo "${1%/*}" | /bin/awk -F/ '{ if ( $2 == "user" || $2 == "home" ) print $3 }'` fi if [ "${owner}" = "UNKNOWN" ] then owner= fi fi echo "${owner}" } function print_error_line { if [ $# -eq 2 ] then owner="$1" error="$2" if [ -n "${owner}" -a ! "x${owner}" = "xroot" -a ! "x${owner}" = "xapache" ] then timestamp=`date +"%Y%m%d"` owner_dir="${OUTPUTDIR}/${owner}" owner_log="${owner_dir}/error_log-${timestamp}.txt" if [ ! -d "${owner_dir}" ] then if [ `/usr/bin/id -u` -eq 0 ] then # /usr/bin/sudo -u janjust /bin/chmod 777 "${OUTPUTDIR}" /bin/su -s /bin/sh ${owner} -c "/bin/mkdir --mode=700 \"${owner_dir}\"" # /usr/bin/sudo -u janjust /bin/chmod 755 "${OUTPUTDIR}" fi # cd to it explicitly to trigger an automounter (cd "${owner_dir}" 2> /dev/null) fi if [ -d "${owner_dir}" ] then echo "${error}" 2> /dev/null >> "${owner_log}" if [ $? -ne 0 -a `/usr/bin/id -u` -eq 0 ] then # we use 'tee' here to avoid wildcard/quote/backtick expansion errors # AND we avoid the need for a subshell with output redirection echo "${error}" | /bin/su -s /bin/sh ${owner} -c "/usr/bin/tee --append \"${owner_log}\"" 2>&1 > /dev/null # Previously: # echo "${error}" | /usr/bin/sudo -n -u ${owner} /bin/dd of="${owner_log}" # oflag=append conv=notrunc status=noxfer 2> /dev/null fi fi fi fi } [ -f /etc/sysconfig/httpd_syslogger ] && . /etc/sysconfig/httpd_syslogger if [ x"$HTTPDLOGGER_ERRLOGFILE" = x"" ]; then LOG_FILE=/var/log/httpd/error_log else LOG_FILE="$HTTPDLOGGER_ERRLOGFILE" fi if [ x"$HTTPDLOGGER_ERRTAG" = x"" ]; then TAG="-t http-error" else TAG="-t $HTTPDLOGGER_ERRTAG" fi if [ x"$HTTPDLOGGER_USERDIR" = x"" ]; then OUTPUTDIR=/data/week/www-errors else OUTPUTDIR="$HTTPDLOGGER_USERDIR" fi if [ x"$HTTPDLOGGER_PERUSERERRORS" = x"yes" ]; then USERERRORS=1 else USERERRORS=0 fi # Now process the input while read line do # write out to the error_log file and to syslog if [ x"$HTTPDLOGGER_LOCALFILE" != x"no" ]; then echo "${line}" | /usr/bin/tee --append ${LOG_FILE} | /usr/bin/logger $TAG $HTTPDLOGGER_LOGARGS $@ else echo "${line}" | /usr/bin/logger $TAG $HTTPDLOGGER_LOGARGS $@ fi if [ $USERERRORS -eq 0 ]; then continue fi # now parse the line and try to deduce the owner of any offending/missing file or script msg=`echo "${line}" | /bin/sed -n 's/\[\(.*\)\] \[\(.*\)\] \[client \(.*\)\] \(.*\)/\4/p'` if [ -z "${msg}" ] then continue fi # reset some vars file= owner= # does the error message start with "PHP" if [ ! "x${msg}" = "x${msg#PHP}" ] then file=`echo "$msg" | /bin/sed -n 's/^PHP.* in \/\(.*\) on line.*/\/\1/p'` owner=`guess_owner "${file}"` elif [ ! "x${msg}" = "x${msg#File does not exist}" ] then file=`echo "$msg" | /bin/sed -n 's/^File does not exist: \(.*\)/\1/p'` file=${file%, referer*} elif [ ! "x${msg}" = "x${msg#script }" ] then # first check for "script '....' not found" file=`echo "$msg" | /bin/sed -n "s/^script '\(.*\)'.*/\1/p"` # now check for "not found or unable to stat: .... if [ -z "${file}" ] then file=`echo "${msg}" | /bin/sed -n "s/^script not found or unable to stat: \(.*\)/\1/p"` file=${file%, referer*} fi elif [ ! "x${msg}" = "x${msg#(2)No such file or directory: Could not open password file: }" ] then file=`echo "$msg" | /bin/sed -n 's/^(2)No such file or directory: Could not open password file: \(.*\)/\1/p'` file=${file%, referer*} elif [ ! "x${msg}" = "x${msg#(13)Permission denied}" ] then warn="${msg#(13)Permission denied: } " # check for "deny server access" file=`echo "${warn}" | /bin/sed -n "s/deny server access: \(.*\)/\1/p"` file=${file%, referer*} # now check for "cannot read directory" if [ -z "${file}" ] then file=`echo "${warn}" | /bin/sed -n "s/cannot read directory for multi: \(.*\)/\1/p"` file=${file%, referer*} fi # now check for "pcfg_openfile" if [ -z "${file}" ] then file=`echo "${warn}" | /bin/sed -n "s/\(.*\) pcfg_openfile: unable to check htaccess file/\1/p"` file=${file%, referer*} fi elif [ ! "x${msg}" = "x${msg#Symbolic link not allowed or link target not accessible:}" ] then file=`echo "$msg" | /bin/sed -n "s/^Symbolic link not allowed or link target not accessible: \(.*\)/\1/p"` file=${file%, referer*} elif [ ! "x${msg}" = "x${msg#mod_mime_magic:}" ] then file=`echo "$msg" | /bin/sed -n "s/^mod_mime_magic: can't read .\(.*\)'.*/\1/p"` # elif [ ! "x${msg}" = "x${msg#}" ] # then # debug "msg: Annoying Wordpress plugin error" # # ignore # elif [ ! "x${msg}" = "x${msg#(5)Input/output error: access to /~form/forum}" ] # then # debug "msg: Form input/output error" # # ignore # elif [ ! "x${msg}" = "x${msg#client denied by server configuration:}" ] # then # debug "msg: client denied by server configuration" # # ignore # else # debug "other type of error" # debug "$msg" fi # Now try to find the owner and write out the error line to the right file owner=`guess_owner "${file}"` print_error_line "${owner}" "${line}" done