#!/bin/bash
#
# Lighttpd Tools.
#
# For suggestion, bug reports, please contact Pierre-Yves Landuré <pierre-yves@landure.fr>


SCRIPT_NAME="$(command basename ${0})"

# Print this script help.
function usage {
  command echo "
This tool ease LigHTTPd HTTP server administration from command line.

Usage :

  ${SCRIPT_NAME} setup-lighttpd
  ${SCRIPT_NAME} enable-php5
  ${SCRIPT_NAME} enable-x-send-file
  ${SCRIPT_NAME} disable-directory-listing
  ${SCRIPT_NAME} setup-fail2ban
  ${SCRIPT_NAME} add-virtual-host hostname path
  ${SCRIPT_NAME} add-redirect hostname target_url

  * setup-lighttpd : Install LigHTTPd and apply a default configuration.
  * enable-php5 : Enable PHP 5 FastCGI.
  * enable-x-send-file : Enable X-Send-File header support.
  * add-virtual-host, add-vhost : Add a virtual host serving the path content
      on the hostname. Optionnaly, you can set a default AllowOverride directive.
  * add-redirect : Add a virtual host redirecting a domain to the given target URL.
"
  exit 1
} # usage



# Common Apache 2 Vhost template
VHOST_TEMPLATE[0]='## SITE_HOSTNAME virtual hosting
##

server.modules += ( "mod_simple_vhost", "mod_accesslog" OTHER_SERVER_MODULES )

$HTTP ["host"] == "SITE_HOSTNAME" {
  server.indexfiles = ( "index.php", "index.html")
'

VHOST_TEMPLATE[1]='
}
'



LOGS_TEMPLATE='
  # The error log and access log. This can be used by awstats
  # Note : since we keed theses logs in /var/log/lighttpd, they are
  # automaticaly rotated by logrotate :D.

  # Access log format is compatible with Apache combined log.
  accesslog.format = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" 
  accesslog.filename = "/var/log/lighttpd/SITE_HOSTNAME-access.log"

  server.errorlog = "/var/log/lighttpd/SITE_HOSTNAME-error.log"
'



# Apache 2 standard Virtual Host template.
PATH_TEMPLATE='
  # The root folder of this virtual host.
  server.document-root = "SITE_PATH"
'


ERROR_404_HANDLER_TEMPLATE='
  server.error-handler-404 = "/index.php"
'


REDIRECT_TEMPLATE='
  url.redirect = ( "^/(.*)" => "REDIRECT_TARGET$1")
'



# Get the absolute path for a file or directory.
#
# @param string $path A relative path.
#
# @return ${REALPATH} A absolute path.
REALPATH=""
function realpath {
  command test ${#} -ne 1 && exit 1
  REALPATH=$(/bin/readlink -f "${1}")
} # realpath



# Check if a binary is present
#
# @param string $binary The binary to check.
# @param string $package The package the binary come from.
#
# @return Exit with error if the binary is missing.
function check_binary {
  command test ${#} -ne 2 && exit 1

  # Test the binary presence.
  if [ -z "$(which "${1}")" ]; then
    echo "Error : '${1}' is missing. Please install package '${2}'."
    exit 1
  fi
} # check_binary



# Check if MySQL connection is working
#
# @param string $mysql_host The MySQL host.
# @param string $mysql_user The MySQL user.
# @param string $mysql_password The MySQL password.
# @param string $mysql_db The MySQL DB.
#
# @return Exit with error if connection to MySQL fail.
function check_mysql {
  command test ${#} -ne 4 && exit 1

  # Test the MySQL connection.
  if ! command mysql --execute="SELECT 1" \
            --host="${1}" --user="${2}" --password="${3}" \
            "${4}" 2>&1 > /dev/null; then
    echo "Error : Unable to connect to MySQL. Please provide valid MySQL connection parameters."
    exit 1
  fi
} # check_mysql



# Download a file from the given URL.
#
# @param string $url The URL of the file to download.
#
# @return ${DOWNLOAD_FILE} The path to the downloaded file.
DOWNLOAD_FILE=""
function download_file {
  command test ${#} -ne 1 && exit 1

  # Download a file.
  DOWNLOAD_FILE="$(command mktemp)"
  command wget --quiet "${1}" \
      --output-document="${DOWNLOAD_FILE}"

  if [ ! -s "${DOWNLOAD_FILE}" ]; then
    command rm "${DOWNLOAD_FILE}"
    echo "Error : Unable to download file from '${1}'."
    exit 1
  fi
} # download_file



# Download and uncompress a tgz file from the given URL.
#
# @param string $url The URL of the file to download.
#
# @return ${DOWNLOAD_TGZ} The path to the extracted content.
DOWNLOAD_TGZ=""
function download_tgz {
  command test ${#} -ne 1 && exit 1

  download_file "${1}"

  # Untar the downloaded file and place it at its final location.
  DOWNLOAD_TGZ="$(command mktemp -d)"
  command tar --directory "${DOWNLOAD_TGZ}" -xzf "${DOWNLOAD_FILE}"
  command rm "${DOWNLOAD_FILE}"

  if [ $(command ls -1 --all "${DOWNLOAD_TGZ}" | command wc --lines) -eq 0 ]; then
    echo "Error : unable to untar file downloaded from '${1}'."
    exit 1
  fi
} # download_tgz



# Convert a hostname to a valid site configuration filename.
#
# @param string $hostname A host name.
#
# @return ${SITE_CONF} A site configuration filename.
SITE_CONF=""
function site_conf {
  command test ${#} -ne 1 && exit 1

  SITE_CONF="$(command echo "${1}" | command sed -e 's/\./-/g')"
}



# Read the eth0 IP.
#
# @return A IP address.
function eth0_ip {
  command ifconfig eth0 \
            | command grep "inet adr" \
            | command sed -e 's/.*inet adr:\([^ ]*\).*/\1/'
} # eth0_ip



# Reload LigHTTPd configuration only if valid.
#
# @return void
function lighttpd_reload {
  if command lighttpd -t -f /etc/lighttpd/lighttpd.conf; then
    /etc/init.d/lighttpd reload
  else
    echo "Error in Lighttpd configuration : reload cancelled."
    exit 1
  fi
  exit 0
} # lighttpd_reload



# Force LigHTTPd configuration reload only if valid.
#
# @return void
function lighttpd_force_reload {
  if command lighttpd -t -f /etc/lighttpd/lighttpd.conf; then
    /etc/init.d/lighttpd force-reload
  else
    echo "Error in Lighttpd configuration : forced reload cancelled."
    exit 1
  fi

  exit 0
} # lighttpd_force_reload



# Check for binaries presence
check_binary "basename" "coreutils"
check_binary "dirname" "coreutils"
check_binary "tar" "tar"
check_binary "mktemp" "mktemp"
check_binary "sed" "sed"
#check_binary "wget" "wget"
#check_binary "unzip" "unzip"
#check_binary "apg" "apg"
#check_binary "mysql" "mysql-client"

# Check if at least one args given.
command test ${#} -eq 0 && usage

case "${1}" in

  setup-lighttpd )
    command apt-get -y install lighttpd libterm-readline-gnu-perl
    exit 0
    ;;



  enable-php5 )
    check_binary "lighty-enable-mod" "lighttpd"

    # Installating apache2 with php5.
    command apt-get -y install php5-cgi

    if [ -n "$(command grep '/usr/bin/php4-cgi' /etc/lighttpd/conf-available/10-fastcgi.conf)" ]; then
      command cp "/etc/lighttpd/conf-available/10-fastcgi.conf" "/etc/lighttpd/conf-available/10-fastcgi-php5.conf"
      command sed -i -e 's/php4/php/g' "/etc/lighttpd/conf-available/10-fastcgi-php5.conf"
    fi

    if [ -e "/etc/lighttpd/conf-available/10-fastcgi-php5.conf" ]; then
      command lighty-enable-mod fastcgi-php5
    elif [ -e "/etc/lighttpd/conf-available/10-fastcgi-php.conf" ]; then
      command lighty-enable-mod fastcgi-php
    elif [ -e "/etc/lighttpd/conf-available/15-fastcgi-php.conf" ]; then
      command lighty-enable-mod fastcgi
      command lighty-enable-mod fastcgi-php
    else
      command lighty-enable-mod fastcgi
    fi

    /etc/init.d/lighttpd force-reload

    exit 0
    ;;



  enable-x-send-file )
    check_binary "lighty-enable-mod" "lighttpd"

    PHP_FCGI_FILE="/etc/lighttpd/conf-available/15-fastcgi-php.conf"
    if [ ! -e "${PHP_FCGI_FILE}" ]; then
      PHP_FCGI_FILE="/etc/lighttpd/conf-available/10-fastcgi-php5.conf"
      if [ ! -e "${PHP_FCGI_FILE}" ]; then
        PHP_FCGI_FILE="/etc/lighttpd/conf-available/10-fastcgi-php.conf"
      fi
    fi

    if [ -z "$(command grep "x-send-file" "${PHP_FCGI_FILE}")" ]; then
      command sed -i -e '/bin-path/a\
\t\t"allow-x-send-file" => "enable",' \
        "${PHP_FCGI_FILE}"
    fi

    /etc/init.d/lighttpd force-reload

    exit 0
    ;;



  setup-fail2ban )
    check_binary "lighty-enable-mod" "lighttpd"

    # Installing fail2ban for Apache 2 attack prevention.
    command apt-get -y install fail2ban

    # Adding specific configuration for lighttpd :
    if [ -z "$(command grep "[lighttpd]" "/etc/fail2ban/jail.conf")" ]; then
      echo "
[lighttpd]

enabled = true
port  = http,https
filter  = apache-auth
logpath = /var/log/lihttpd/*error.log
maxretry = 6 

[lighttpd-noscript]

enabled = true
port    = http,https
filter  = apache-noscript
logpath = /var/log/lighttpd/*error.log
maxretry = 6 

[lighttpd-overflows]

enabled = true
port    = http,https
filter  = apache-overflows
logpath = /var/log/lighttpd/*error.log
maxretry = 2
" >> /etc/fail2ban/jail.conf
    fi

    /etc/init.d/fail2ban restart

    exit 0
    ;;



  add-virtual-host|add-vhost )
    # Check if valid number of arguments given (6).
    command test ${#} -ne 3 && usage

    check_binary "lighty-enable-mod" "lighttpd"

    SITE_HOSTNAME="${2}"
    realpath "${3}"
    SITE_PATH="${REALPATH}"

    if [ ! -e "${SITE_PATH}/index.php" ]; then # Test if index.php present.
      ERROR_404_HANDLER_TEMPLATE=""
    fi # Test if index.php present.

    site_conf "${SITE_HOSTNAME}"

    command echo "${VHOST_TEMPLATE[0]}
${LOGS_TEMPLATE}
${PATH_TEMPLATE}
${ERROR_404_HANDLER_TEMPLATE}
${VHOST_TEMPLATE[1]}" \
      | command sed -e "s|SITE_HOSTNAME|${SITE_HOSTNAME}|g" \
                    -e "s|SITE_PATH|${SITE_PATH}|g" \
                    -e "s|OTHER_SERVER_MODULES||g" \
         > "/etc/lighttpd/conf-available/20-${SITE_CONF}.conf"

    command lighty-enable-mod "${SITE_CONF}"

    lighttpd_reload
    exit 0
    ;;



  add-redirect)
    # Check if valid number of arguments given.
    command test ${#} -ne 3 && usage

    check_binary "lighty-enable-mod" "lighttpd"

    SITE_HOSTNAME="${2}"
    REDIRECT_TARGET=$(command echo "${3}/" \
             | command sed -e 's|//$|/|')


    REDIRECT_TARGET_URI=$(command echo "${REDIRECT_TARGET}" \
             | command sed -e 's|[^:]*://[^/]*\(/.*\)/$|\1|')

    site_conf "${SITE_HOSTNAME}"

    command echo "${VHOST_TEMPLATE[0]}
${REDIRECT_TEMPLATE}
${VHOST_TEMPLATE[1]}" \
      | command sed -e "s|SITE_HOSTNAME|${SITE_HOSTNAME}|g" \
                    -e "s|REDIRECT_TARGET|${REDIRECT_TARGET_URI}|g" \
                    -e 's|OTHER_SERVER_MODULES|, "mod_redirect"|g' \
         > "/etc/lighttpd/conf-available/20-${SITE_CONF}.conf"

    command lighty-enable-mod "${SITE_CONF}"

    lighttpd_reload
    exit 0
    ;;



  * )
    echo "Error : '${1}' is not a valid action."
    usage
    ;;
esac

exit 0
