X-Git-Url: https://mop.ddnsfree.com/gitweb/?p=threegates.git;a=blobdiff_plain;f=raw%2Froot%2Fusr%2Fbin%2Fcrl-manager.py;fp=raw%2Froot%2Fusr%2Fbin%2Fcrl-manager.py;h=05ad5a87e722dad27b80e00e15e7eb8045cf47e5;hp=0000000000000000000000000000000000000000;hb=bffa64977018af66ca97dabf031388d319aa8b06;hpb=81a8da764f041fdd05f888a6104c626556e11a21 diff --git a/raw/root/usr/bin/crl-manager.py b/raw/root/usr/bin/crl-manager.py new file mode 100755 index 0000000..05ad5a8 --- /dev/null +++ b/raw/root/usr/bin/crl-manager.py @@ -0,0 +1,465 @@ +#! /usr/bin/env python +import os +import time +import popen2 +import sys +import filecmp +import shutil +import fcntl +import re +import time +import zlib +import httplib +import threading, select + +CRLURINEW = "/var/lib/3gates/crlurinew" +CRLURI = "/var/lib/3gates/crluri" +CRL = "/var/lib/3gates/crl" +CA_PATH = "/var/lib/3gates/ca" +CRLCHKTIME = 1800.0 + +start_time = 0 + +# hash of the CA: +# openssl crl -in CRL15 -inform der -hash -noout +# +# verify of the CRL: +# openssl crl -in CRL15 -inform der -CApath /etc/apache2/ssl/ca/ -noout + + +# +# Functions +# + +class command_output_processor(threading.Thread): + def __init__(self, subproc, sout, serr): + threading.Thread.__init__(self) + + self.lock = threading.Lock() + if sout: + self.sout = '' + else: + self.sout = False + if serr: + self.serr = '' + else: + self.serr = False + + ctrlrd, ctrlwr = os.pipe() + self.ctrlrd = os.fdopen(ctrlrd, "rb") + self.ctrlwr = os.fdopen(ctrlwr, "wb") + self.shutdown = True + self.output = subproc.fromchild + self.error = subproc.childerr + + def run(self): + self.lock.acquire() + self.shutdown = False + self.lock.release() + + while (not self.shutdown) and ((not self.output.closed) or (not self.error.closed)): + # print "main loop" + intrig = [ self.ctrlrd ] + if not self.output.closed: + intrig.append(self.output) + + if not self.error.closed: + intrig.append(self.error) + + # print "pre select" + retsel = select.select( intrig, [ ], [ ], 5) + # print "post select" + + if len(retsel[0]) == 0: + # print "no data" + continue + + # print "len range", len(retsel[0]) + for i in range(0,len(retsel[0])): + # print "LOOP %d: %d\n" % (i, len(retsel[0])) + if retsel[0][i] == self.ctrlrd: + self.ctrlrd.read() + + elif retsel[0][i] == self.output: + data = self.output.read() + + if (len(data) == 0): + self.output.close() + else: + pass # print "Stdout data len", len(data) + + if self.sout != False: + self.sout += data + + elif retsel[0][i] == self.error: + data = self.error.read() + if (len(data) == 0): + self.error.close() + else: + pass # print "Stderr data len", len(data) + + if self.serr != False: + self.serr += data + + self.lock.acquire() + try: + if not self.ctrlrd.closed: + self.ctrlrd.close() + if not self.ctrlwr.closed: + self.ctrlwr.close() + except: + print "exception at ctrl close" + pass + + self.shutdown = True + self.lock.release() + + + def stop(self): + self.lock.acquire() + if not self.shutdown: + self.ctrlwr.write("w") + self.shutdown = True + self.lock.release() + + +def execute_command(cmd, input, with_output, with_error, wait): + subret = -1 + subproc = popen2.Popen3(cmd, True) + + th = command_output_processor(subproc, with_output, with_error) + th.start() + + if input: + try: + poin = subproc.tochild + poin.write(input) + poin.close() + except Exception, e: + print "exception at poin close", e + pass + + for i in range(1, wait * 10): + # print "loop ", i + subret = subproc.poll() + if (subret != -1): + break + time.sleep(0.1) + else: + # FIXME: kill procedure here + print "NON ESCE" + print "prima della stop ", subret + th.stop() + ret = th.join() + + return (subret, th.sout, th.serr) + + + + +def crlurinew_mustupdate(crluri, crlurinew): + ldir = os.listdir(crlurinew) + for cf in ldir: + # find all new .cont files + if re.match("^[a-f0-9]{8}\.cont$", cf) == None: + continue + # TODO verify if the name it's really the hash of the content (anti-tampering) + + acc = os.access(crluri+"/"+cf, os.F_OK | os.R_OK | os.W_OK) + + if (acc == False): + return True + + return False + +def crluri_fromnew(crluri, crlurinew): + ldir = os.listdir(crlurinew) + for cf in ldir: + # find all new .cont files + if re.match("^[a-f0-9]{8}\.cont$", cf) == None: + continue + # TODO verify if the name it's really the hash of the content (anti-tampering) + + acc = os.access(crluri+"/"+cf, os.F_OK | os.R_OK | os.W_OK) + + if (acc == False): + print("copy file [%s]\n from dir:[%s]\n to dir: [%s]" % (cf, crlurinew, crluri)) + shutil.copyfile(crlurinew+"/"+cf, crluri+"/"+cf) + else: + print "WARNING: File %s just exists in %s." % (cf, crluri) + + os.remove(crlurinew+"/"+cf) + + return True + +def ssltime2int(s): + sout = re.sub('^.*= *', '', s).strip("\n") + t = time.strptime(sout, "%b %d %H:%M:%S %Y %Z") + ts = int(time.strftime("%s", t)) + return ts + +# +# Se non esiste l'expire o se esiste ed in scadenza rende True, altrimenti False +# +def crl_needverify(cu_name, crl, exptime, lcrldir): + c_name = cu_name.replace(".cont", ".crl") + + acc = os.access(crl+"/"+c_name, os.F_OK | os.R_OK | os.W_OK) + if acc == False: + return (True, None) + + for cfcrl in lcrldir: + if re.match( ("^[0-9]+\.%s$" % c_name), cfcrl) != None: + if ((float(re.sub("\.[a-f0-9]{8}\.crl$", "", cfcrl)) - time.time()) < exptime): + print " expire link expired" + return (True, cfcrl) + break + else: + print " expire link not found" + return (True, None) + + # print " expire link verified" + return (False, None) + +def crl_update(contfile, crluripath, crlpath, expiresym): + ret = False + + crl_file = re.sub("\.cont$", ".crl", contfile) + print "crl_update contfile: %s crl file %s" % (contfile, crl_file) + + f = file(crluripath+"/"+contfile, "r") + + + # FIMXME: modo migliore di looppare ? + while True: + s = f.readline(1024) + if s == '': + break + + uri = s.strip("\n") + + # verify proto + if (re.match("^[hH][tT][tT][pP]://", uri) != None): + # get http file + uri = re.sub("^[hH][tT][tT][pP]://", "", uri) + site = re.sub("/.*", "", uri) + page = re.sub("^[^/]*/", "/", uri) + + print "HTTP URI [%s] HOST [%s] PAGE [%s]" % (uri, site, page) + conn = httplib.HTTPConnection(site) + conn.request("GET", page) + r1 = conn.getresponse() + if r1.status != 200: + continue + + crl_data = r1.read() + conn.close() + break + + elif (re.match("^[lL][dD][aA][pP]://", uri) != None): + print "LDAP Path: [%s]" % uri + # get ldap file + continue + + f.close() + + # verify the crl + # openssl crl -inform der -CApath /etc/apache2/ssl/ca/ -noout + # print "execute 1" + subret, sout, serr = execute_command("/usr/bin/openssl crl -inform pem -CApath %s -noout" % CA_PATH , + crl_data, False, False, 20) + if (subret != 0): + # print "execute 2" + subret, sout, serr = execute_command("/usr/bin/openssl crl -inform der -CApath %s -noout" % CA_PATH , + crl_data, False, False, 20) + + if (subret != 0): + print "CRL verify FAILED!" + return False + else: + print "CRL verified!" + + + sout = "" + # print "execute 3" + subret, sout, serr = execute_command("/usr/bin/openssl crl -inform der -outform pem" , + crl_data, True, False, 20) + crl_data = sout + + + # verify that lastupdate was in the past + subret, sout, serr = execute_command("/usr/bin/openssl crl -inform pem -lastupdate -noout", + crl_data, True, False, 20) + + print "lastupdate: [%s]" % sout + ts_last = ssltime2int(sout) + print "lastupdate2: [%d]" % ts_last + print "start_time: [%d]" % start_time + if ts_last > start_time: + print "ERROR: lastupdate is in the future" + return False + + # verify that nextupdate was in the past + subret, sout, serr = execute_command("/usr/bin/openssl crl -inform pem -nextupdate -noout", + crl_data, True, False, 20) + + ts_next = ssltime2int(sout) + print "TS_NEXT: ", ts_next + if ts_next < start_time: + print "WARNING: nextupdate is in the past" + + # verify if exists an old copy of the crl and if is the same + acc = os.access(CRL+"/"+crl_file, os.F_OK | os.R_OK | os.W_OK) + if acc != False: + sout = "" + print "CRL verify:" + + print "execute 4: /usr/bin/openssl crl -inform pem -in %s -noout -fingerprint" % (CRL+"/"+crl_file) + subret, finger_old, serr = execute_command("/usr/bin/openssl crl -inform pem -in %s -noout -fingerprint" % (CRL+"/"+crl_file), + False, True, False, 20) + + if (subret != 0): + print "acquiring CRL fingerprint FAILED!", subret + return False + + subret, finger_new, serr = execute_command("/usr/bin/openssl crl -inform pem -noout -fingerprint", + crl_data, True, False, 20) + + if finger_old == finger_new: + return True + + + # update the crl file + print "UPDATE::save new file to: ", crl_file + newf = file(CRL+"/"+crl_file+"_new", "w") + newf.write(crl_data) + newf.close() + os.rename(CRL+"/"+crl_file+"_new", CRL+"/"+crl_file) + + print "UPDATE:expiretime file:", expiresym + # update the expiretime symlink + if expiresym != None: + os.unlink(CRL+"/"+expiresym) + + print "UPDATE:symlinking(%s, %s)" % (CRL+"/"+crl_file, CRL+"/"+str(ts_next)+"."+crl_file) + oldcwd = os.getcwd() + os.chdir(CRL) + os.symlink(crl_file, str(ts_next)+"."+crl_file) + os.chdir(oldcwd) + + subret, crl_hash, serr = execute_command("/usr/bin/openssl crl -inform pem -noout -hash", + crl_data, True, False, 20) + + crl_hash = crl_hash.strip("\n") + print "hash: [%s]" % crl_hash + + new_st = os.stat(CRL+"/"+crl_file) + print "NEW_ST: ", new_st.st_ino + + lcrldir = os.listdir(crlpath) + print "lcrldir: ", lcrldir + print "preemp: ", [ x for x in lcrldir if re.match(crl_hash+".r[0-9]+", x) ] + for crl_cur in [ x for x in lcrldir if re.match(crl_hash+".r[0-9]+", x) ]: + st = os.stat(crlpath+"/"+crl_cur) + print "CMP: ", st.st_ino + if new_st.st_ino == st.st_ino: + break + else: + for i in range(0, 1000): + acc = os.access(CRL+"/"+crl_hash+".r"+str(i), os.F_OK | os.R_OK | os.W_OK) + if acc == False: + oldcwd = os.getcwd() + os.chdir(CRL) + os.symlink(crl_file, crl_hash+".r"+str(i)) + os.chdir(oldcwd) + break + + + return ret + +# +# MAIN +# +if __name__=='__main__': + + start_time = time.time() + # + # VERIFY + # + # print "\n--- VERIFY ---\n" + update = False + old_umask = os.umask(0002) + fl = file(CRLURINEW + "/certgate.lck", "w+") + os.umask(old_umask) + # print "lock SH" + fcntl.flock(fl, fcntl.LOCK_SH) + + + while True: + # verify for new .cont files + update = crlurinew_mustupdate(CRLURI, CRLURINEW) + if update == True: + break + + ldir = os.listdir(CRLURI) + lcrldir = os.listdir(CRL) + for cf in ldir: + # for each .cont file verify existence of associated .crl file and it's expire time + if re.match("[a-f0-9]{8}\.cont$", cf) != None: + need, expiresym = crl_needverify(cf, CRL, CRLCHKTIME, lcrldir) + if need: + update = True + break + + # end of while True + break + + fcntl.flock(fl, fcntl.LOCK_UN) + # print "unlock SH" + + if update == False: + sys.exit(0) + + # + # UPDATE + # + # We lock in EX mode before continue. + # + print "\n--- UPDATE ---\n" + print "lock EX" + fcntl.flock(fl, fcntl.LOCK_EX) + + # try to copy new crluri from DMZ dir to working dir + crluri_fromnew(CRLURI, CRLURINEW) + + ldir = os.listdir(CRLURI) + lcrldir = os.listdir(CRL) + for cf in ldir: + # if .cont file verify existance of associated .crl file + if re.match("^[a-f0-9]{8}\.cont$", cf) != None: + need, expiresym = crl_needverify(cf, CRL, CRLCHKTIME, lcrldir) + if need: + # download and check update + crl_update(cf, CRLURI, CRL, expiresym) + + + fcntl.flock(fl, fcntl.LOCK_UN) + print "unlock EX" + + fl.close() + sys.exit(111) + +# while True: +# s = f.readline(1024) +# if s == '': +# break +# print s +# print len(s) + + +# f.close() + + exit + +# main() +