#!/usr/bin/env bash # DESCRIPTION: # print length of all zimbra queues # or # letsencrypt update certificate procedure # # DEPENDENCIES: # - privileged rights # - zimbra zmcontrol, zmqstat, zmcertmgr # - curl # - openssl # - cerbot # - Python 3 # - existing /usr/local/bin/sendmail.py # # PARAMETERS: # 1: "qn" - execution without pauses # 2: "que" - print length of all zimbra queues # 2: "svc" - print number of stopped services # 2: "ssl" - letsencrypt certificate update procedure # 3: custom configuration file path # # FUNCTIONS: # ####################################### # Print message and add to log. # Globals: # logs # Arguments: # 1: message to print and logging ####################################### addtologs() { echo "$(date +'%Y.%m.%d-%H:%M:%S') $1" | tee -a "${logs}" } ####################################### # Waiting for press [ENTER]. # Globals: # None # Arguments: # None ####################################### execpause() { read -r -p "Press [ENTER] to continue... " } ####################################### # Exit procedure. # Globals: # show # Arguments: # None ####################################### execquite() { addtologs "execution time is $(($(date +%s)-time)) seconds, exit" if [ "${show}" != "qn" ]; then execpause fi exit } ####################################### # Error exit procedure # Globals: # None # Arguments: # 1: message to print and logging ####################################### execerror() { addtologs "error: $1" execquite } ####################################### # Parsing config file and creating global vars. # Globals: # None # Arguments: # None ####################################### getconfig() { logs=$(grep "logs=" "${conf}" | cut -d= -f2) python3=$(grep "python3=" "${conf}" | cut -d= -f2) certemail=$(grep "certemail=" "${conf}" | cut -d= -f2) certfirst=$(grep "certfirst=" "${conf}" | cut -d= -f2) IFS=" " read -r -a certalias <<< "$(grep "certalias=" "${conf}" | cut -d= -f2)" } ####################################### # Checking user rights. # Globals: # None # Arguments: # None # return: # 0 - if privileged rights, 1 - if not privileged rights ####################################### checkroot() { if [ "${EUID}" -ne 0 ]; then return 1 # false else return 0 # true fi } ####################################### # Counting zimbra queues. # Globals: # None # Arguments: # None # return: # length of all queues ####################################### calcqueue(){ object=0 while read -r QUE; do object=$(( object + $(echo "${QUE}" | cut -d= -f2) )) done <<< "$(/opt/zimbra/libexec/zmqstat)" printf "%s\n" "${object}" return "${object}" } ####################################### # Counting zimbra stopped services. # Globals: # None # Arguments: # None # return: # number of stopped services ####################################### isrunning(){ counter=0 while read -r service; do if ! grep -q "$(cat /etc/hostname)" <<< "${service}"; then if grep -q "Stopped" <<< "${service}"; then (( counter++ )) fi fi done <<< "$(su - zimbra -c '/opt/zimbra/bin/zmcontrol status')" printf "%s\n" "${counter}" return "${counter}" } ####################################### # Print certificate expiration date in epoch # Globals: # None # Arguments: # 1: certificate path or site url ####################################### certcheck() { if [ -e "${1}" ]; then printf '%s\n' "$(date -d "$(openssl x509 -text -noout -in "${1}" | grep 'Not After' | cut -d':' -f2-)" +%s)" else export LANG=C printf '%s\n' "$(date -d "$(curl --insecure -vvI "${1}" 2>&1 | grep "expire date" | cut -d':' -f2-)" +%s)" fi } ####################################### # Renew and deploy certificate # Globals: # certfirst # certalias # certemail # Arguments: # None ####################################### certrenew() { # letsencrypt request su - zimbra -c "/opt/zimbra/bin/zmcontrol stop" certarray="-d ${certfirst}" if [ ${#certalias[@]} -ne 0 ]; then for domain in "${certalias[@]}"; do certarray+=" -d ${domain}" done fi certbot certonly --standalone --email "${certemail}" --preferred-chain "ISRG Root X1" "${certarray}" wget -O - https://letsencrypt.org/certs/isrgrootx1.pem.txt --no-check-certificate >> "/etc/letsencrypt/live/${certfirst}/chain.pem" su - zimbra -c "/opt/zimbra/bin/zmcontrol start" # zimbra cert deploy cp "/etc/letsencrypt/live/${certfirst}/privkey.pem" /opt/zimbra/ssl/zimbra/commercial/commercial.key cp "/etc/letsencrypt/live/${certfirst}/chain.pem" /opt/zimbra/ssl/zimbra/commercial/chain.pem cp "/etc/letsencrypt/live/${certfirst}/cert.pem" /opt/zimbra/ssl/zimbra/commercial/cert.pem chown -R zimbra:zimbra /opt/zimbra/ssl/zimbra/commercial/ su - zimbra -c "/opt/zimbra/bin/zmcertmgr verifycrt comm /opt/zimbra/ssl/zimbra/commercial/commercial.key /opt/zimbra/ssl/zimbra/commercial/cert.pem /opt/zimbra/ssl/zimbra/commercial/chain.pem" su - zimbra -c "/opt/zimbra/bin/zmcertmgr deploycrt comm /opt/zimbra/ssl/zimbra/commercial/cert.pem /opt/zimbra/ssl/zimbra/commercial/chain.pem" su - zimbra -c "/opt/zimbra/bin/zmcontrol restart" } ####################################### # Send email information about deployed certificate # Globals: # python3 # certfirst # Arguments: # None ####################################### startsendmail() { subj="[SSL Status] $(cat /etc/hostname): certificates renewed" ( "${python3}" /usr/local/bin/sendmail.py \ -u "$(grep "from=" /usr/local/bin/sendmail.config | cut -d= -f2)" \ -p "$(grep "pass=" /usr/local/bin/sendmail.config | cut -d= -f2)" \ -d "$(grep "dest=" /usr/local/bin/sendmail.config | cut -d= -f2)" \ --smtp "$(grep "smtp=" /usr/local/bin/sendmail.config | cut -d= -f2)" \ --port "$(grep "port=" /usr/local/bin/sendmail.config | cut -d= -f2)" \ --stls "True" \ --subj "${subj}" \ --text "$(curl --insecure -vvI "${certfirst}" 2>&1 | awk 'BEGIN { cert=0 } /^\* SSL connection/ { cert=1 } /^\*/ { if (cert) print }')" \ >> /dev/null 2>&1 & ) addtologs "sent mail with subject '${subj}'" } # # VARIABLES: # show=$1 does=$2 conf=$3 if [ -z "${conf}" ] || [ "${conf}" == "-" ]; then conf="$(dirname "$(realpath "$0")")/$(basename -s .sh "$0").conf" fi time=$(date +%s) cd "$(dirname "$(realpath "$0")")" || execerror if [ ! -e "${conf}" ]; then : else getconfig fi if [ -z "${logs}" ]; then logs=/dev/null elif [ ! -e "${logs}" ]; then touch "${logs}" fi if ! command -v curl &> /dev/null || \ ! command -v openssl &> /dev/null || \ ! command -v certbot &> /dev/null || \ ! command -v /opt/zimbra/bin/zmcontrol &> /dev/null || \ ! command -v /opt/zimbra/bin/zmcertmgr &> /dev/null || \ ! command -v /opt/zimbra/libexec/zmqstat &> /dev/null || \ ! command -v /usr/local/bin/sendmail.py &> /dev/null || \ ! command -v "${python3}" &> /dev/null; then execerror "Not found dependencies" fi # # MAIN: # if checkroot; then if [ "${does}" = "ssl" ]; then expired=$(certcheck "/etc/letsencrypt/live/${certfirst}/cert.pem") targets=$(( expired - 2592000 )) if [[ "${time}" -le "${targets}" ]]; then addtologs "${certfirst} expired $(date -d "1970-01-01 UTC $expired seconds" +"%Y.%m.%d %T")" addtologs "${certfirst} certificates renew delayed" else certrenew && addtologs "${certfirst} certificates renewed" startsendmail fi elif [ "${does}" = "que" ]; then result=$(calcqueue) addtologs "Zimbra queue has ${result} objects" > /dev/null printf "%s\n" "${result}" execquite > /dev/null elif [ "${does}" = "svc" ]; then result=$(isrunning) addtologs "Zimbra has ${result} stopped services" > /dev/null printf "%s\n" "${result}" execquite > /dev/null else printf "%s\n" "Usage example: $0 qn ssl" printf "%s\n" "Usage example: $0 - que" fi execquite else execerror "Restart this as root!" fi