From e91946ba08111b12778dee27517047e8dc899f84 Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 14 Aug 2020 23:17:09 +0200 Subject: [PATCH] Add script 'check_cert_for_dovecot.sh'. --- check_cert_for_dovecot.sh | 479 ++++++++++++++++++++++++ conf/check_cert_for_dovecot.conf.sample | 132 +++++++ 2 files changed, 611 insertions(+) create mode 100755 check_cert_for_dovecot.sh create mode 100644 conf/check_cert_for_dovecot.conf.sample diff --git a/check_cert_for_dovecot.sh b/check_cert_for_dovecot.sh new file mode 100755 index 0000000..c234578 --- /dev/null +++ b/check_cert_for_dovecot.sh @@ -0,0 +1,479 @@ +#!/usr/bin/env bash + +# =============================================================== +# - Don't make definitions here! Do this at the configuration file +# ================================================================ + +script_name="$(basename $(realpath $0))" +working_dir="$(dirname $(realpath $0))" + +conf_file="${working_dir}/conf/${script_name%%.*}.conf" + +# ---------- +# - +# - Script checks, whether the certificate for mumble services are up to date. If +# - newer versions than the installed one found, script changes the installed +# - key/cert to the latest version. +# - +# - Note !! +# - This script is very special to the server environment of machine 'o13-il.oopen.de' +# - +# ---------- + +LOCK_DIR="/tmp/${script_name%%.*}.LOCK" +log_file="${LOCK_DIR}/${script_name%%.*}.log" + +restart_service=false + + +# ------------- +# --- Some functions +# ------------- + +clean_up() { + + # Perform program exit housekeeping + rm -rf "$LOCK_DIR" + exit $1 +} + +echononl(){ + if $terminal ; then + echo X\\c > /tmp/shprompt$$ + if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then + echo -e -n "$*\\c" 1>&2 + else + echo -e -n "$*" 1>&2 + fi + rm /tmp/shprompt$$ + fi +} + +fatal(){ + echo "" + if $terminal ; then + echo -e " [ \033[31m\033[1mFatal\033[m ]: $*" + echo "" + echo -e " \033[31m\033[1mScript was interupted\033[m!" + else + echo " [ Fatal ]: $*" + echo "" + echo " Script was terminated...." + fi + echo "" + clean_up 1 +} + +error() { + echo "" + if $terminal ; then + echo -e " [ \033[31m\033[1mError\033[m ]: $*" + else + echo " [ Error ]: $*" + fi + echo "" +} + +warn() { + echo "" + if $terminal ; then + echo -e " [ \033[33m\033[1mWarning\033[m ]: $*" + else + echo " [ Warning ]: $*" + fi + echo "" +} + +info() { + if $terminal ; then + echo "" + echo -e " [ \033[32m\033[1mInfo\033[m ]: $*" + echo "" + fi +} + +echo_failed(){ + if $terminal ; then + echo -e "\033[75G[ \033[1;31mfailed\033[m ]" + fi +} + +echo_skipped() { + if $terminal ; then + echo -e "\033[75G[ \033[90mskipped\033[m ]" + fi +} + +echo_done() { + if $terminal ; then + echo -e "\033[75G[ \033[32mdone\033[m ]" + fi +} + +echo_ok() { + if $terminal ; then + echo -e "\033[75G[ \033[32mok\033[m ]" + fi +} + +blank_line() { + if $terminal ; then + echo "" + fi +} + + +# ------------- +# - Job is already running? +# ------------- + +# - If job already runs, stop execution.. +# - +if mkdir "$LOCK_DIR" 2> /dev/null ; then + + # - Remove lockdir when the script finishes, or when it receives a signal + # - + trap clean_up SIGHUP SIGINT SIGTERM + +else + + msg="A previos instance of script \"`basename $0`\" seems already be running." + + echo "" + if $terminal ; then + echo -e "[ \033[31m\033[1mFatal\033[m ]: $msg" + echo "" + echo -e " \033[31m\033[1mScript was interupted\033[m!" + else + echo " [ Fatal ]: $msg" + echo "" + echo " Script was interupted!" + fi + echo + + exit 1 + +fi + + +# ------------- +# --- Some checks +# ------------- + +# - Running in a terminal? +# - +if [[ -t 1 ]] ; then + terminal=true +else + terminal=false +fi + + +# - Read Configurations from $conf_file +# - +if [[ ! -f "$conf_file" ]]; then + fatal " Configuration file '$(basename ${conf_file})' not found!" +else + source $conf_file +fi + +[[ -z "$service_domain" ]] && fatal " Parameter 'service_domain' not set but is reqired!" + +[[ -z "$cert_installed" ]] && cert_installed="/etc/dovecot/ssl/mailserver.crt" +[[ -z "$cert_newest" ]] && cert_newest="/var/lib/dehydrated/certs/${service_domain}/fullchain.pem" +[[ -z "$key_installed" ]] && key_installed="/etc/dovecot/ssl/mailserver.key" +[[ -z "$key_newest" ]] && key_newest="/var/lib/dehydrated/certs/${service_domain}/privkey.pem" + +[[ -z "$service_name" ]] && service_name="Dovecot" +[[ -z "$check_string_ps" ]] && check_string_ps="[[:digit:]]\ /usr/local/dovecot-[[:digit:]]{1,2}\.[[:digit:]]{1,2}\.[[:digit:]]{1,2}(\.[[:digit:]]{1,2})?/sbin/dovecot" + +# - Systemd supported ? +# - +systemd_supported=false +systemd=$(which systemd) +systemctl=$(which systemctl) + +if [[ -n "$systemd" ]] && [[ -n "$systemctl" ]] ; then + systemd_supported=true +fi + +SYSTEMD_SERVICE= +SYSV_INIT_SCRIPT= + +if $systemd_supported ; then + if systemctl -t service list-unit-files \ + | grep -e "^${service_name,,}d" \ + | grep -q -E "(enabled|disabled|generated)" 2> /devnull ; then + + SYSTEMD_SERVICE="$(systemctl -t service list-unit-files | grep -e "^${service_name,,}d" | awk '{print$1}' | head -1)" + elif systemctl -t service list-unit-files \ + | grep -e "^${service_name,,}-server" \ + | grep -q -E "(enabled|disabled|generated)" 2> /devnull ; then + + SYSTEMD_SERVICE="$(systemctl -t service list-unit-files | grep -e "^${service_name,,}-server" | awk '{print$1}' | head -1)" + elif systemctl -t service list-unit-files \ + | grep -e "^${service_name,,}" \ + | grep -q -E "(enabled|disabled|generated)" 2> /devnull ; then + + SYSTEMD_SERVICE="$(systemctl -t service list-unit-files | grep -e "^${service_name,,}" | awk '{print$1}' | head -1)" + fi +fi + +if [[ -z "$SYSTEMD_SERVICE" ]]; then + if [[ -x "/etc/init.d/${service_name,,}" ]]; then + SYSV_INIT_SCRIPT="/etc/init.d/${service_name,,}" + elif [[ -x "/etc/init.d/${service_name,,}d" ]]; then + SYSV_INIT_SCRIPT="/etc/init.d/${service_name,,}d" + elif [[ -x "/etc/init.d/${service_name,,}-server" ]]; then + SYSV_INIT_SCRIPT="/etc/init.d/${service_name,,}-server" + fi +fi + +if [[ -z "$SYSTEMD_SERVICE" ]] && [[ -z "$SYSV_INIT_SCRIPT" ]] ; then + fatal "Neither an init-script nor a service file for $service_name found!" +fi + + +#echo "SYSTEMD_SERVICE: $SYSTEMD_SERVICE" +#echo "SYSV_INIT_SCRIPT: $SYSV_INIT_SCRIPT" +#clean_up 0 + + +# ------------- +# - Don't run script, if any give path for cert/key does not exists +# ------------- + +if [[ ! -f "$cert_newest" ]] ; then + fatal "Newest Certificate '$cert_newest' for service '${service_name}' not found!" +elif [[ ! -f "$key_newest" ]] ; then + fatal "Newest Key '$key_newest' for service '${service_name}' not found!" +fi + +blank_line +echononl " Create Cert/Key Directory '$(dirname "$cert_installed")'.." +if [[ ! -d "$(dirname "$cert_installed")" ]] ; then + mkdir -p "$(dirname "$cert_installed")" > $log_file 2>&1 + if [[ $? -eq 0 ]] ; then + echo_done + + echononl " Change Permissions for Cert/Key Directory '$(dirname "$cert_installed")'.." + chmod 755 "$(dirname "$cert_installed")" > $log_file 2>&1 + if [[ $? -eq 0 ]] ; then + echo_done + else + echo_failed + error "$(cat "$log_file")" + fi + + else + echo_failed + error "$(cat "$log_file")" + fi +else + echo_skipped +fi + +dh_pem_file="$(dirname "$cert_installed")/dh_4096.pem" +echononl " Create SSL DH parameters '$dh_pem_file'.." +if [[ -s "$dh_pem_file" ]]; then + echo_skipped +else + openssl dhparam -dsaparam -out "$dh_pem_file" 4096 > $log_file 2>&1 + if [[ $? -eq 0 ]] ; then + echo_done + else + echo_failed + error "$(cat "$log_file")" + fi +fi + + +# ------------- +# - Check if key/cert are up to date, change them if needed. +# ------------- + +if ! diff "$(realpath "$cert_installed")" "$(realpath "$cert_newest")" > /dev/null 2>&1 ; then + + _failed=false + + warn "Certificate for service '${service_name}' is outdated! + + Try to update certificate and key.." + + echononl " Update certificat for for service '${service_name}' .." + > $log_file + if [[ -h "$cert_installed" ]] ; then + rm "$(realpath "$cert_installed")" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + fi + + if [[ -f "$cert_installed" ]] ; then + rm "$cert_installed" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + fi + + cp -a "$(realpath "$cert_newest")" "$(dirname "$cert_installed")" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + + chmod 644 "$(dirname "$cert_installed")/$(basename "$(realpath "$cert_newest")")" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + + ln -s "$(basename "$(realpath "$cert_newest")")" "$cert_installed" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + + if $_failed ; then + echo_failed + error "$(cat "$log_file")" + else + echo_done + fi + + if ! $_failed ; then + + _failed=false + + echononl " Update key for service '${service_name}' .." + if [[ -h "$key_installed" ]] ; then + rm "$(realpath "$key_installed")" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + fi + + if [[ -f "key_installed" ]] ; then + rm "$key_installed" > $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + fi + + cp -a "$(realpath "$key_newest")" "$(dirname "$key_installed")" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + + chmod 644 "$(dirname "$key_installed")/$(basename "$(realpath "$key_newest")")" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + + ln -s "$(basename "$(realpath "$key_newest")")" "$key_installed" >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + + if $_failed ; then + echo_failed + error "$(cat "$log_file")" + else + echo_done + restart_service=true + fi + + fi + + if ! $_failed ; then + if $terminal ; then + info "Certificate/Key for service '${service_name}' is now up to date" + else + echo "" + echo " [ Info ]: Certificate/Key for service '${service_name}' is now up to date" + echo "" + fi + else + error "Updating Certificate/Key for service '${service_name}' failed!" + fi + +else + up_to_date=true + info "Certificate for service '${service_name}' is up to date!" +fi + +if $restart_service ; then + + _failed=false + echononl "Going to restart Service '${service_name}' .." + if [[ -n "$SYSTEMD_SERVICE" ]] ; then + $systemctl daemon-reload > $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + sleep 2 + + $systemctl stop $SYSTEMD_SERVICE >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + sleep 10 + + $systemctl start $SYSTEMD_SERVICE >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + if $_failed ; then + echo_failed + error "$(cat "$log_file")" + else + echo_done + fi + else + $SYSV_INIT_SCRIPT stop > $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + sleep 10 + $SYSV_INIT_SCRIPT start >> $log_file 2>&1 + if [[ $? -ne 0 ]]; then + _failed=true + fi + if $_failed ; then + echo_failed + error "$(cat "$log_file")" + else + echo_done + fi + fi + + if ! $_failed ; then + + declare -i counter=0 + PID=$(ps -e f | grep -E "${check_string_ps}"| grep -v grep | awk '{print$1}') + while [[ "X${PID}" = "X" ]]; do + if [[ $counter -gt 10 ]]; then + _failed=true + break + else + ((counter++)) + fi + sleep 1 + PID=$(ps -e f | grep -E "${check_string_ps}"| grep -v grep | awk '{print$1}') + done + + fi + + if $_failed ; then + error "Restarting service '${service_name}' failed!" + else + if $terminal ; then + info "'${service_name}' Service was restarted. the new pid is '$PID'." + else + echo "" + echo " '${service_name}' Service was restarted. the new pid is '$PID'." + echo "" + fi + fi + +fi + +clean_up 0 + diff --git a/conf/check_cert_for_dovecot.conf.sample b/conf/check_cert_for_dovecot.conf.sample new file mode 100644 index 0000000..1edbbaa --- /dev/null +++ b/conf/check_cert_for_dovecot.conf.sample @@ -0,0 +1,132 @@ +#--------------------------------------- +#----------------------------- +# Settings for script check_cert_for_dovecot.sh +#----------------------------- +#--------------------------------------- + +# - service_domain +# - +# - The main domain for which the certificate was issued +# - +# - Example: +# - service_domain="a.mx.oopen.de" +# - service_domain="mail.cadus.org" +# - service_domain="mx.warenform.de" +# - +#service_domain="" + + +# - service_name +# - +# - Name of service. +# - +# - Note: this var will also be used to determin systemd service file +# - or sysVinit script. +# - +# - Example: +# - service_name="Mumble" +# - service_name="Prosody" +# - +# - Defaults to: +# - service_name="Dovecot" +# - +#service_name="" + + +# - check_string_ps +# - +# - String wich (clearly) identifies the service at the process list (ps) +# - +# - Example: +# - check_string_ps="[[:digit:]]\ /usr/sbin/murmurd" +# - check_string_ps="" +# - +# - Defaults to: +# - check_string_ps="[[:digit:]]\ /usr/local/dovecot-[[:digit:]]{1,2}\.[[:digit:]]{1,2}\.[[:digit:]]{1,2}(\.[[:digit:]]{1,2})?/sbin/dovecot" +# - +#check_string_ps="" + + +# - service_user +# - +# - User under which the service is running. +# - +# - Example: +# - service_user="mumble-server" +# - service_user="prosody" +# - +# - Defaults to: +# - service_user="prosody" +# - +#service_user="" + + +# - service_group +# - +# - Group under which the service is running. +# - +# - Example: +# - service_group="mumble-server" +# - service_group="prosody" +# - +# - Defaults to: +# - service_group="prosody" +# - +#service_group="" + + +# - cert_installed +# - +# - Locataion of certificate read by service +# - +# - Example: +# - cert_installed="/var/lib/mumble-server/fullchain.pem" +# - cert_installed="/var/lib/dehydrated/certs/jabber.so36.net/fullchain.pem" +# - +# - Defaults to: +# - /etc/dovecot/ssl/mailserver.crt +# - +#cert_installed="" + + +# - key_installed +# - +# - Location of the key read by service +# - +# - Example: +# - key_installed="/var/lib/mumble-server/privkey.pem" +# - key_installed="/etc/prosody/certs/privkey_jabber.so36.pem" +# - +# - Defaults to: +# - /etc/dovecot/ssl/mailserver.key +# - +#key_installed="" + + +# - cert_newest +# - +# - Location of the newest certificate. +# - +# - Example: +# - cert_newest="/var/lib/dehydrated/certs/il-mumble.oopen.de/fullchain.pem" +# - cert_newest="/var/lib/dehydrated/certs/jabber.so36.net/fullchain.pem" +# - +# - Defaults to: +# - /var/lib/dehydrated/certs/${service_domain}/fullchain.pem +# - +#cert_newest="" + + +# - key_newest +# - +# - Location of the newest Key +# - +# - Example: +# - key_newest="/var/lib/dehydrated/certs/il-mumble.oopen.de/privkey.pem" +# - key_newest="/var/lib/dehydrated/certs/jabber.so36.net/privkey.pem" +# - +# - Defaults to: +# - /var/lib/dehydrated/certs/${service_domain}/privkey.pem +# - +#key_newest="" +