#!/usr/bin/sh #---------------------------------------------------------------------------------- # /var/install/bin/certs-send-invalid-certs-warning - send warning email, # if certificates will become invalid within the next x days # # Copyright (c) 2001-2025 The Eisfair Team, team(at)eisfair(dot)org # # Creation: 2015-02-04 jed # Last Update: $Id$ # # Usage: certs-send-invalid-certs-warning commands # # Available commands: # # [-emailaddr email-address] - address to send email to # default: postmaster@your-domain # [-subject email-subject] - subject of email to be generated # default: TLS certificates warning # [-days number-of-days] - number of days in advance to show # warning, default: 20 days # [-xmailer "program-name"] - name of the programm/script which # has been used to send this message. # [--nosend] - show results on screen only # [--nosymlinks] - skip symbolic links to certificate # files # [--help] - show this help # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. #---------------------------------------------------------------------------------- # include eislib . /var/install/include/eislib . /var/install/include/jedlib # activate debug output #debug=true if ${debug:-false} then exec 2> /tmp/$(basename ${0})-trace$$.log set -x ask_debug=true export ask_debug fi #---------------------------------------------------------------------------------- # check if OpenSSL file isn't empty and contains valid data # # input: $1 - crt|crl|csr|dh|key # $2 - file name # # output: 0 - valid file # 1 - file is empty # 2 - file doesn't contain required block #---------------------------------------------------------------------------------- is_valid_openssl_file () { local _ivof_ret=0 local _ivof_type=$1 local _ivof_file="$2" local _ivof_pattern local _ivof_org_file local _ivof_rc1 local _ivof_rc2 if [ -n "${_ivof_type}" -a -n "${_ivof_file}" -a \( -f "${_ivof_file}" -o -L "${_ivof_file}" \) ] then case ${_ivof_type} in crt|cert ) _ivof_pattern="CERTIFICATE" ;; crl ) _ivof_pattern="X509 CRL" ;; csr ) _ivof_pattern="CERTIFICATE REQUEST" ;; dh ) _ivof_pattern="DH PARAMETERS" ;; key ) _ivof_pattern="RSA PRIVATE KEY" ;; esac if [ -L "${_ivof_file}" ] then # file is a symbolic link _ivof_org_file="`readlink -e "${_ivof_file}"`" if [ -z "${_ivof_org_file}" ] then # symbolic link is dead _ivof_ret=1 fi fi if [ ${_ivof_ret} -eq 0 -a -s ${_ivof_file} ] then # file not empty grep -q "^-----BEGIN ${_ivof_pattern}-----" "${_ivof_file}" _ivof_rc1=$? grep -q "^-----END ${_ivof_pattern}-----" "${_ivof_file}" _ivof_rc2=$? if [ ${_ivof_rc1} -ne 0 -o ${_ivof_rc2} -ne 0 ] then # certificate NOT found _ivof_ret=3 fi else # file is empty _ivof_ret=2 fi fi return ${_ivof_ret} } #---------------------------------------------------------------------------------- # send certification warning # # input: $1 - sender email domain # $2 - target email address # $3 - subject of warning message # $4 - number of days in advance to send warning # (time difference in seconds: x days * 24h * 60min * 60sec) # $5 - x-mailer string #---------------------------------------------------------------------------------- send_certs_warning () { local _scw_domain="$1" local _scw_address="$2" local _scw_subject="$3" local _scw_timediff=`expr $4 \* 86400` local _scw_xmailer="$5" local _scw_currdate=`(TZ=GMT; date +%s)` local _scw_futuredate=`expr ${_scw_currdate} + ${_scw_timediff}` local _scw_msg_file=${tmpfile} local _scw_filelist local _scw_certsubject local _scw_startdate local _scw_enddate local _scw_tmpdate local _scw_warning local _scw_exit local _scw_lable local _scw_length # insert hostname and date stamp _scw_subject=`insert_hostname "${_scw_subject}"` _scw_subject="`insert_date \"${_scw_subject}\"`" if [ ${nosend} -eq 1 ] then > ${_scw_msg_file} else { echo "From: Mailer-Daemon " echo "To: ${_scw_address}" if [ -n "${_scw_xmailer}" ] then echo "X-Mailer: ${_scw_xmailer}" fi echo "Subject: ${_scw_subject}" echo } > ${_scw_msg_file} fi { echo echo "Please check these certificates it will become invalid:" echo echo "Current date : `date +\"%b %d %T %Y %Z\"`" echo } >> ${_scw_msg_file} _scw_warning=0 ls ${certdir}/*.pem > /dev/null 2> /dev/null if [ $? -eq 0 ] then # files found, go on ... if [ ${nosymlinks} -eq 1 ] then _scw_filelist=$(find ${certdir} -maxdepth 1 -type f -name "*.pem" -printf '%p\n' | sort) else _scw_filelist=$(find ${certdir} -maxdepth 1 \( -type f -or -type l \) -name "*.pem" -printf '%p\n' | sort) fi for CNAME in ${_scw_filelist} do if is_valid_openssl_file 'cert' "${CNAME}" then # valid certificate block found # get certificate dates _scw_certsubject=`${openssl_bin} x509 -in ${CNAME} -noout -subject | cut -d= -f2- | sed 's/^ *//;s/ *$//'` _scw_startdate=`${openssl_bin} x509 -in ${CNAME} -noout -startdate | cut -d= -f2` _scw_enddate=`${openssl_bin} x509 -in ${CNAME} -noout -enddate | cut -d= -f2` # convert end date into seconds _scw_tmpdate=`date -d "${_scw_enddate}" +%s 2>/dev/null` # check for 2038 date error in date command if [ $? -eq 1 -a -z "${_scw_tmpdate}" ] then # set last possible fixed date to "Jan 19 3:14:06 2038 GMT" _scw_tmpdate="2147483646" fi if [ ${_scw_futuredate} -ge ${_scw_tmpdate} ] then _scw_warning=1 { # echo "Debug: $_scw_futuredate >= $tmpdate" # debug echo "Certificate : ${CNAME}" # print certificate subject _scw_exit=0 _scw_lable='Subject' while [ ${_scw_exit} -eq 0 ] do _scw_length=`expr length "${_scw_certsubject}"` if [ ${_scw_length} -gt 0 ] then # if certificate subject is greater than 72, print an aditional line if [ ${_scw_length} -gt 62 ] then echo " ${_scw_lable} : `echo "${_scw_certsubject}" | cut -c1-59` ..." _scw_certsubject="`echo "${_scw_certsubject}" | cut -c60- | sed 's/^ *//;s/ *$//'`" else echo " ${_scw_lable} : ${_scw_certsubject}" _scw_exit=1 fi _scw_lable=' ' else _scw_exit=2 fi done echo " Valid from : ${_scw_startdate}" echo " Valid until: ${_scw_enddate}" echo } >> ${_scw_msg_file} fi else # print error message _scw_warning=1 { echo "Certificate : ${CNAME}" echo " Error : File doesn't exist or is not a valid certificate in .pem format!" echo } >> ${_scw_msg_file} fi done fi if [ ${_scw_warning} -ne 0 ] then if [ ${nosend} -eq 0 ] then # send warning cat ${_scw_msg_file} | ${sendmail_bin} ${_scw_address} if [ ${quiet} -eq 0 ] then echo "email successfully send to '${_scw_address}'." fi else # show warning cat ${_scw_msg_file} fi else if [ ${quiet} -eq 0 -a ${nosend} -eq 0 ] then echo "nothing to do." fi fi # delete old tmp file rm -f ${_scw_msg_file} } #---------------------------------------------------------------------------------- # show help #---------------------------------------------------------------------------------- show_help () { echo "Usage: ${pgmname}" echo echo ' [-emailaddr email-address] - address to send email to' echo ' default: postmaster@your-domain' echo ' [-subject email-subject] - subject of email to be generated' echo ' default: TLS certificates warning' echo ' [-days number-of-days] - number of days in advance to send email' echo ' default: 20 days' echo ' [--nosend] - show results on screen only' echo ' [--nosymlinks] - skip symbolic links to certificate files' echo ' [--help] - show this help' echo } #================================================================================== # main #================================================================================== pgmname=`basename $0` module_name="`echo "${pgmname}" | cut -d- -f1 | cut -d. -f1`" tmpdir=/tmp ssldir=/usr/local/ssl certdir=${ssldir}/certs basefile=/etc/config.d/base openssl_bin=/usr/bin/openssl sendmail_bin=/usr/lib/sendmail if [ "`/usr/bin/eisman check ${module_name}`" = 'installed' ] then certs_version="`/usr/bin/eisman query --installed --fields=version --no-tty ${module_name} | sed -e '/^version/!d' -e 's/^version *//' | tail -n1`" else certs_version='unknown' fi tmpfile=${tmpdir}/certs-send-invalid-certs-warning.$$ senderdomain='' emailsubject='TLS certificates warning' emailaddress='' xmailer="EISFAIR ${pgmname} v${certs_version}" daysinadvance=20 nosend=0 nosymlinks=0 quiet=0 # command line parameter while [ $# -gt 0 ] do case $1 in *-days ) if is_numeric $2 then daysinadvance=$2 fi shift; shift ;; *-emailaddr ) # target email address echo "$2" | grep -q '@' if [ $? -eq 0 ] then emailaddress="$2" fi shift; shift ;; *-help|*-?|/? ) show_help exit 1 ;; *-nosend ) nosend=1 shift ;; *-nosymlinks ) nosymlinks=1 shift ;; *-subject ) emailsubject="$2" shift; shift ;; *-quiet ) quiet=1 shift ;; *-xmailer ) xmailer="$2" shift; shift ;; * ) # skip unknown switches shift ;; esac done if [ ${nosend} -eq 0 ] then if [ -z "${senderdomain}" ] then # get email sender domain for PNAME in mail ssmtp vmail do if [ "`/usr/bin/eisman check ${PNAME}`" = 'installed' ] then senderdomain=`/var/install/config.d/${PNAME}.sh getdomain` break fi done fi if [ -z "${emailaddress}" ] then emailaddress="Postmaster " fi fi send_certs_warning "${senderdomain}" "${emailaddress}" "${emailsubject}" "${daysinadvance}" "${xmailer}" #================================================================================== # end #================================================================================== exit 0