#!/usr/bin/python3

import sys
import os
from subprocess import Popen, PIPE
from datetime import datetime, timedelta

default_pki_dirs = [
    "/etc/pki/shared",
    "/etc/pki/httpd",
    "/etc/pki/dovecot",
    "/etc/pki/postfix",
    "/etc/pki/mysql",
    "/etc/pki/pgsql",
    "/etc/pki/mongo",
    "/etc/pki/zabbix"
]

def ssl_end_date(crt):
    cert = open(crt, "rb").read()
    end_date = Popen(
        "openssl x509 -enddate -noout".split(),
        stdin=PIPE, stdout=PIPE
    ).communicate(cert)[0]
    # notAfter=May 12 05:19:41 2032 GMT
    return datetime.strptime(
        end_date.strip().decode("utf8").split("=", 1)[-1],
        "%b %d %H:%M:%S %Y GMT"
    )

def shortpath(p):
    if p.startswith("/etc/pki/"):
        return p[9:]
    return p

def kv_str(d):
    return ", ".join(["%s:%s" % (shortpath(k), v) for k, v in d.items()])

def find_crt_files(pki_paths):
    for pki_path in pki_paths:
        if os.path.isdir(pki_path):
            try:
                subdirs = os.listdir(pki_path)
            except IOError as err:
                print("CRT CRITICAL - %s (%s)" % (err.strerror, pki_path))
                sys.exit(2)
            except OSError as err:
                print("CRT CRITICAL - %s (%s)" % (err.strerror, pki_path))
                sys.exit(2)
            for crtfn in subdirs:
                if crtfn.endswith(".crt") or crtfn=="pubcert.pem":
                    crt = os.path.join(pki_path, crtfn)
                    yield crt
        elif os.path.isfile(pki_path):
            yield pki_path

if __name__ == "__main__":
    rets = dict(
        ok = {},
        warning = {},
        critical = {}
    )

    if sys.argv[1:]:
        default_pki_dirs = sys.argv[1:]
    #else:
    #    # add mod_md domains
    #    mod_md_dir = "/var/lib/httpd/md/domains"
    #    if os.path.isdir(mod_md_dir):
    #        default_pki_dirs.extend([
    #            os.path.join(mod_md_dir, x)
    #            for x in os.listdir(mod_md_dir)
    #        ])

    for crt in find_crt_files(default_pki_dirs):
        try:
            dt_end = ssl_end_date(crt)
            dt_now = datetime.now()
            diff = (dt_end-dt_now).days
        except IOError as err:
            rets["critical"][crt] = err.strerror
            continue
        except OSError as err:
            rets["critical"][crt] = err.strerror
            continue
        if diff<=14:
            rets["critical"][crt] = diff
        elif diff<=31:
            rets["warning"][crt] = diff
        else:
            rets["ok"][crt] = diff
    #print(default_pki_dirs)
    #print(rets)

    if not rets["ok"] and not rets["warning"] and not rets["critical"]:
        # need at least one valid certificate
        print("CRT CRITICAL - need at least one valid certificate")
        sys.exit(2)

    if rets["critical"]:
        print("CRT CRITICAL - %s" % kv_str(rets["critical"]))
        sys.exit(2)
    elif rets["warning"]:
        print("CRT WARNING - %s" % kv_str(rets["warning"]))
        sys.exit(1)
    else:
        print("CRT OK - %s" % kv_str(rets["ok"]))
        sys.exit(0)

