5 kx #!/bin/sh
5 kx #
5 kx # Will check all certificates stored in $CERTDIR for their expiration date,
5 kx # and will display (if optional "stdout" argument is given), or mail a warning
5 kx # message to $MAILADDR (if script is executed without any parameter
5 kx # - unattended mode suitable for cron execution) for each particular certificate
5 kx # that is about to expire in time less to, or equal to $DAYS after this script
5 kx # has been executed, or if it has already expired.
5 kx # This stupid script (C) 2006,2007 Jan Rafaj
5 kx
5 kx ########################## CONFIGURATION SECTION BEGIN #########################
5 kx # Note: all settings are mandatory
5 kx # Warning will be sent if a certificate expires in time <= days given here
5 kx DAYS=7
5 kx # E-mail address where to send warnings
5 kx MAILADDR=root
5 kx # Directory with certificates to check
5 kx CERTDIR=/etc/ssl/certs
5 kx # Directory where to keep state files if this script isnt executed with "stdout"
5 kx STATEDIR=/var/run
5 kx ########################### CONFIGURATION SECTION END ##########################
5 kx
5 kx PATH=/bin:/usr/bin:/sbin:/usr/sbin
5 kx DAY_IN_SECS=$((60*60*24))
5 kx DATE_CURRENT=$(date '+%s')
5 kx
5 kx usage()
5 kx {
5 kx echo "Usage: $0 [stdout]"
5 kx echo
5 kx echo "Detailed description and configuration is embedded within the script."
5 kx exit 0
5 kx }
5 kx
5 kx message()
5 kx {
5 kx cat << EOF
5 kx WARNING: certificate $certfile
5 kx is about to expire in time equal to or less than $DAYS days from now on,
5 kx or has already expired - it might be a good idea to obtain/create new one.
5 kx
5 kx EOF
5 kx }
5 kx
5 kx message_mail()
5 kx {
5 kx message
5 kx cat << EOF
5 kx NOTE: This message is being sent only once.
5 kx
5 kx A lock-file
5 kx $STATEDIR/certwatch-mailwarning-sent-$certfilebase
5 kx has been created, which will prevent this script from mailing you again
5 kx upon its subsequent executions by crond. You dont need to care about it;
5 kx the file will be auto-deleted as soon as you'll prolong your certificate.
5 kx EOF
5 kx }
5 kx
5 kx unset stdout
5 kx case $# in
5 kx 0) ;;
5 kx 1) if [ "$1" = "-h" -o "$1" == "--help" ]; then
5 kx usage
5 kx elif [ "$1" = "stdout" ]; then
5 kx stdout=1
5 kx else
5 kx usage
5 kx fi
5 kx ;;
5 kx *) usage ;;
5 kx esac
5 kx
5 kx for dir in $STATEDIR $CERTDIR ; do
5 kx if [ ! -d $dir ]; then
5 kx echo "ERROR: directory $dir does not exist"
5 kx exit 1
5 kx fi
5 kx done
5 kx for binary in basename date find grep mail openssl touch ; do
5 kx if [ ! \( -x /usr/bin/$binary -o -x /bin/$binary \) ]; then
5 kx echo "ERROR: /usr/bin/$binary not found"
5 kx exit 1
5 kx fi
5 kx done
5 kx
5 kx find $CERTDIR -type f -maxdepth 1 | while read certfile ; do
5 kx if [ "$certfile" != "/etc/ssl/certs/ca-certificates.crt" ]; then
5 kx certfilebase="$(basename "$certfile")"
5 kx inform=PEM
5 kx echo "$certfile" | grep -q -i '\.net$'
5 kx if [ $? -eq 0 ]; then
5 kx # This is based purely on filename extension, so may give false results.
5 kx # But lets assume noone uses NET format certs today, ok?
5 kx continue
5 kx fi
5 kx echo "$certfile" | grep -q -i '\.der$'
5 kx if [ $? -eq 0 -o "$(file "$certfile" | egrep '(ASCII|PEM)')" == "" ]; then
5 kx inform=DER
5 kx fi
5 kx # We wont use '-checkend' since it is not properly documented (as of
5 kx # OpenSSL 0.9.8e).
5 kx DATE_CERT_EXPIRES=$(openssl x509 -in "$certfile" -inform $inform -noout -enddate | sed 's/^notAfter=//')
5 kx DATE_CERT_EXPIRES=$(date -d"$DATE_CERT_EXPIRES" +%s)
5 kx if [ $(($DATE_CERT_EXPIRES - $DATE_CURRENT)) -le $(($DAYS * $DAY_IN_SECS)) ]
5 kx then
5 kx if [ $stdout ]; then
5 kx message
5 kx else
5 kx if [ ! -f $STATEDIR/certwatch-mailwarning-sent-"$certfilebase" ]; then
5 kx subject="$0: certificate $certfile expiration warning"
5 kx message_mail | mail -r "certwatch@$HOSTNAME" \
5 kx -s "$subject" \
5 kx $MAILADDR 2>/dev/null
5 kx # echo "Mail about expiring certificate $certfile sent to $MAILADDR."
5 kx # echo "If you need to send it again, please remove lock-file"
5 kx # echo "$STATEDIR/certwatch-mailwarning-sent-$certfilebase ."
5 kx # echo
5 kx fi
5 kx touch $STATEDIR/certwatch-mailwarning-sent-"$certfilebase"
5 kx fi
5 kx else
5 kx if [ ! $stdout ]; then
5 kx if [ -f $STATEDIR/certwatch-mailwarning-sent-"$certfilebase" ]; then
5 kx rm $STATEDIR/certwatch-mailwarning-sent-"$certfilebase"
5 kx fi
5 kx fi
5 kx fi
5 kx fi
5 kx done