def initSessions(): global sessionLock try: # Get database connection parameters _dhost = config_get("database", "host") ccsd_session.dhost = _dhost!="" and _dhost or None log_info("host = %s" % ccsd_session.dhost) _ddatabase = config_get("database", "database") ccsd_session.database = _ddatabase!="" and _ddatabase or None log_info("database = %s" % ccsd_session.database) _duser = config_get("database", "user") ccsd_session.duser = _duser!="" and _duser or None log_info("duser = %s" % ccsd_session.duser) _dpass = config_get("database", "password") ccsd_session.dpass = _dpass!="" and _dpass or None # Does the admin want us to log query times ccsd_session.log_times = config_getboolean(None, "log_db_times", False) # Create a program wide 'admin' session which is always present ccsd_session.sessions[ADMIN_SESSION_ID] = \ ccsd_session("admin", SESSION_RW, "", -1, -1, ADMIN_SESSION_ID) # Load any other saved sessions ccsd_session.sessions.update(loadSessions()) # Initialise the lock sessionLock = threading.RLock() log_info("Successfully loaded sessions") except: log_fatal("Failed to load initial program state!", sys.exc_info())
def send_mail(send_from, send_to, subject, text, files=[], cc=[], bcc=[]): """Send an email, optionally with some attachments""" from ccsd_config import config_get # Try and read the server and domain from the config file, but this # might fail, if it hasn't been started yet try: server = config_get("network", "smtp_server", "localhost") except: server = "localhost" try: domain = config_get("network", "domain") except: domain = "localhost" # Ensure the sender address is fully qualified if send_from.find("@") == -1: send_from = "%s@%s" % (send_from, domain) # Create the MIME message msg = MIMEMultipart() msg['From'] = send_from msg['To'] = COMMASPACE.join(send_to) msg['Date'] = formatdate(localtime=True) msg['Subject'] = subject # Handle Carbon-copy recipients if len(cc) > 0: msg['CC'] = COMMAPSACE.join(cc) send_to.extend(cc) # Handle Blind-carbon-copy recipients if len(bcc) > 0: send_to.extend(bcc) # Attach the message text msg.attach( MIMEText(text) ) # Attach files for f in files: part = MIMEBase('application', "octet-stream") part.set_payload( open(f,"rb").read() ) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f)) msg.attach(part) # Send the message smtp = smtplib.SMTP(server) smtp.sendmail(send_from, send_to, msg.as_string()) smtp.close() return True
def startCCSDServer(key, cert, cacert): """Initialises the CCSD Server. This function never returns as it enters a mainloop """ global server_running, recurring try: # Port and logfile port = int(config_get(None, "port", DEFAULT_CLIENT_PORT)) logfile = config_get(None, "request_log", DEFAULT_REQUEST_LOG) # Initialise an HTTP server httpd = AsyncHTTPServer(('', port), CCSDHandler) log_info("Server Started. Ready to serve requests...") server_running = True except: log_fatal("Could not initialise the server!", sys.exc_info()) # Start the mainloop while server_running: try: # Check recurring functions to see if they need to be called now = time.time() for sched_time, func in recurring.items(): if sched_time <= now: try: func() except: log_error("Unknown error in recurring function!", \ sys.exc_info()) del recurring[sched_time] newTime = sched_time + func._interval recurring[newTime] = func # put in a timeout so we don't monopolise the CPU asyncore.poll(30) except socket.error: # Socket operation died, ignore log_error("Socket operation failed! Continuing.", sys.exc_info()) continue except SystemExit: # Ignore, server_running will be set to false shortly continue except: # Unknown ERROR (etype, value, tb) = sys.exc_info() log_error("Unexpected error caught by mainloop! - %s" % value, (etype, value, tb))
def _doCertificateLogon(self, request): """Attempt to logon using the client certificate This can only succeed if: * the client certificate CN matches a username * cert_logins is not disabled in the configuration file """ from ccsd_session import startSession, startBasicSession from crcnetd.modules.ccs_contact import getUserCache # Check incoming peer certificate cert = request.channel.transport.socket.get_peer_certificate() subj = cert.get_subject() domain = config_get('network','domain', '') username = "******" % (subj.CN , domain) allow_login = config_getboolean(None, "cert_logins", True) if not allow_login: None # CN matches a MAC address #return startBasicSession(username, SESSION_RW) # Does the CN match a username? users = getUserCache(ADMIN_SESSION_ID) if username in users.keys(): if users[username]["enabled"]: # Make sure a session exists for the user return startSession(users[username]['login_id'], SESSION_RW) # CN matches a MAC address #return startBasicSession(username, SESSION_RW) return None
def handleDaemonise(): # Read command line options is_daemon = 0 optlist, args = getopt.gnu_getopt(sys.argv[1:], OPTION_LIST) for (arg, val) in optlist: if arg == "-d": is_daemon = daemonise() # Make sure logger knows our status setDaemonStatus(is_daemon) setTracebackLog(config_get(None, "traceback_log", None))
def daemonise(): """Detach a process from the controlling terminal and run it in the background as a daemon. http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731 """ # Get pidfile location pidfile = config_get(None, "pidfile", DEFAULT_PIDFILE) # Check pidfile is writable if os.access(os.path.dirname(pidfile), os.W_OK) != 1: log_fatal("Unable to write to pid file (%s)" % pidfile) try: pid = os.fork() except OSError, e: raise Exception, "%s [%d]" % (e.strerror, e.errno)
def startCCSDServer(key, cert, cacert): """Initialises the CCSD Server. This function never returns as it enters the twisted mainloop """ try: # Local networks localnets = config_get(None, "local_networks", "127.0.0.0/8") # Register standard HTTP XMLRPC handler for local requests registerHTTPResource("RPC2", ccsd_local_xmlrpc, localnets=localnets.split(",")) # Register HTTPS XMLRPC Handler use_ssl = config_getboolean(None, "use_ssl", True) if use_ssl: registerHTTPSResource("RPC2", ccsd_xmlrpc) # Setup XMLRPC Handler configuration ccsd_xmlrpc.log_times = config_get(None, "log_times", None) ccsd_xmlrpc.profile = config_getboolean(None, "profile", False) ccsd_xmlrpc.prof_dir = config_get(None, "profile_dir", \ DEFAULT_PROFILE_DIR) ccsd_xmlrpc.log_threads = config_get(None, "log_threads", None) ccsd_xmlrpc.max_threads = config_getint(None, "max_threads", DEFAULT_MAX_THREADS) # SSL Context class SCF: def __init__(self, key, cert, cacert): self.mKey = key self.mCert = cert self.mCACert = cacert def verify(self, conn, cert, errnum, depth, ok): """Checks the certificate of an incoming connection""" # If there is already an error bail now if not ok: return ok # Only perform further verification on client certs if depth>0: return ok # At this point we know the certificate is signed by a # trusted CA, check the issuer OU matches the incoming cert # OU and the incoming cert is not a server cert # XXX: Should look at using something like nsCertType rather # than the CN field for this. s = cert.get_subject() i = cert.get_issuer() if s.OU != i.OU: log_warn("Rejected incoming connection from invalid " "SSL cert (%s). OU did not match." % s) return 0 if s.CN == "server": log_warn("Rejected incoming connection from server SSL " "cert (%s)." % s) return 0 return 1 def getContext(self): """Create an SSL context.""" ctx = SSL.Context(SSL.SSLv2_METHOD) # Add the CA certificate(s) store = ctx.get_cert_store() for cert in self.mCACert: store.add_cert(cert) # Load the private key and certificate ctx.use_privatekey(self.mKey) ctx.use_certificate(self.mCert) ctx.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, self.verify) ctx.set_verify_depth(len(self.mCACert)) return ctx # Port and logfile http_port = int(config_get(None, "http_port", DEFAULT_HTTP_SERVER_PORT)) https_port = int(config_get(None, "https_port", DEFAULT_HTTPS_SERVER_PORT)) logfile = config_get(None, "request_log", DEFAULT_REQUEST_LOG) # Pass off control to Twisted's mainloop threadable.init() suggestThreadpoolSize(ccsd_xmlrpc.max_threads) reactor.listenTCP(http_port, server.Site(_http_root, logfile)) if use_ssl: reactor.listenSSL(https_port, server.Site(_https_root, logfile), \ SCF(key, cert, cacert)) reactor.addSystemEventTrigger("before", "shutdown", shutdownHandler) log_info("Server Started. Ready to serve requests...") except: log_fatal("Could not initialise the server!", sys.exc_info()) reactor.run()
def loadModules(opmode): """Loads modules appropriate for the current server""" # Initialise modules mDir = "%s/modules" % os.path.dirname(os.path.dirname(__file__)) dMods = config_get(None, "modules", None) if dMods is None: return [] modules = [] if opmode == CCSD_SERVER: prefix = "ccs" else: prefix = "ccs_monitor" # Scan through the list and load valid modules for module in dMods.split(","): module = module.strip() if module == "": continue mname = "%s_%s" % (prefix, module) mfile = "%s/%s.py" % (mDir, mname) # Check module exists if not os.path.exists(mfile): log_fatal("Cannot load requested module '%s'. File not found!" % \ module) # Load the modules code fd = open(mfile, "r") data = fd.read() fd.close() # Look for a line containing ccsd_mod_type idx = data.find("ccs_mod_type") if idx == -1: log_fatal("Module '%s' has no ccs_mod_type property!" % module) try: code = compile(data[idx:data.find("\n",idx)], "%s.py" % mname, \ 'single') eval(code) if ccs_mod_type is None: log_fatal("Could not determine type of module '%s'!" % module) if type(ccs_mod_type)==type([]): if opmode not in ccs_mod_type: log_fatal("Module '%s' cannot be used with this mode!" % \ module) continue else: if opmode != ccs_mod_type: log_fatal("Module '%s' cannot be used with this mode!" % \ module) continue except: log_fatal("Could not determine type of module '%s'!" % module, \ sys.exc_info()) # Load the module try: exec "import crcnetd.modules.%s" % mname m = eval("crcnetd.modules.%s" % mname) except: log_fatal("Module '%s' failed to load!" % module, sys.exc_info()) modules.append(m) log_info("Loaded Module: %s" % module) return modules