--- /dev/null
+#! /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()
+