Commit 97d9ad15 authored by David Johnson's avatar David Johnson

Improve logging of m2crypto exceptions.

m2crypto's default SSLServer.handle_error function was just printing to
stdout; that is an easy fix.  However, what is hard is associating the
Exception with a client_address due to the
socket/M2Crypto.SSL.Connection abstraction abuse.  Lots of stuff
happens in Connection.accept(), and if an Exception is raised in there,
no client_address is returned to the caller (i.e. handle_request()).
m2crypto does a real disservice by overlaying the socket API and thus
masking so many customization points that any real user would want to use.
parent fd4dedfe
...@@ -48,6 +48,7 @@ try: ...@@ -48,6 +48,7 @@ try:
from M2Crypto import SSL from M2Crypto import SSL
from M2Crypto.SSL import SSLError from M2Crypto.SSL import SSLError
from M2Crypto.SSL import Checker from M2Crypto.SSL import Checker
from M2Crypto.SSL import SSLTimeoutError
except ImportError, e: except ImportError, e:
sys.stderr.write("error: The py-m2crypto port is not installed\n") sys.stderr.write("error: The py-m2crypto port is not installed\n")
sys.exit(1) sys.exit(1)
...@@ -186,30 +187,34 @@ class MyConnection(SSL.Connection): ...@@ -186,30 +187,34 @@ class MyConnection(SSL.Connection):
address bound to the other end of the SSL connection. address bound to the other end of the SSL connection.
""" """
sock, addr = self.socket.accept() sock, addr = self.socket.accept()
# Use our subclass, not the default SSL.connection try:
ssl = MyConnection(self.ctx, sock) # Use our subclass, not the default SSL.connection
# Set non-blocking so that the M2Crypto openssl wrapper glue ssl = MyConnection(self.ctx, sock)
# will honor the _timeout we're about to set; but only if the # Set non-blocking so that the M2Crypto openssl wrapper glue
# timeout is not None. # will honor the _timeout we're about to set; but only if the
if SSL_CLIENT_ACCEPT_TIMEOUT is not None: # timeout is not None.
sock.setblocking(False) if SSL_CLIENT_ACCEPT_TIMEOUT is not None:
# Set a timeout that gets used in the below call of ssl.accept_ssl() sock.setblocking(False)
ssl._timeout = SSL_CLIENT_ACCEPT_TIMEOUT # Set a timeout that gets used in the below call of ssl.accept_ssl()
ssl.addr = addr ssl._timeout = SSL_CLIENT_ACCEPT_TIMEOUT
ssl.setup_ssl() ssl.addr = addr
ssl.set_accept_state() ssl.setup_ssl()
ssl.accept_ssl() ssl.set_accept_state()
check = getattr(self, 'postConnectionCheck', ssl.accept_ssl()
self.serverPostConnectionCheck) check = getattr(self, 'postConnectionCheck',
if check is not None: self.serverPostConnectionCheck)
if not check(ssl.get_peer_cert(), ssl.addr[0]): if check is not None:
raise Checker.SSLVerificationError( if not check(ssl.get_peer_cert(), ssl.addr[0]):
'post connection check failed') raise Checker.SSLVerificationError(
# Make the socket blocking again. 'post connection check failed')
sock.setblocking(True) # Make the socket blocking again.
# ... and undo our timeout. sock.setblocking(True)
ssl._timeout = SSL_CLIENT_REQUEST_TIMEOUT # ... and undo our timeout.
return ssl, addr ssl._timeout = SSL_CLIENT_REQUEST_TIMEOUT
return ssl, addr
except Exception, exc:
exc.__setattr__('client_address',addr)
raise
# #
# A simple server based on the forking version SSLServer. We fork cause # A simple server based on the forking version SSLServer. We fork cause
...@@ -256,12 +261,12 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -256,12 +261,12 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
# #
# @param msg The message to log. # @param msg The message to log.
# #
def logit(self, msg): def logit(self, msg, facility=syslog.LOG_INFO):
if debug: if debug:
print msg print msg
pass pass
else: else:
syslog.syslog(syslog.LOG_INFO, msg); syslog.syslog(facility, msg);
pass pass
return return
...@@ -276,11 +281,11 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -276,11 +281,11 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
def set_path(self, path, client_address): def set_path(self, path, client_address):
if not self.emulabserver: if not self.emulabserver:
if path not in ALLOWED_PATHS: if path not in ALLOWED_PATHS:
self.logit("Disallowed path: %s" % path) self.logit("Disallowed path: %s" % path,facility=syslog.LOG_ERR)
raise Exception("Path not allowed: %s" % path) raise Exception("Path not allowed: %s" % path)
path = os.path.join(path, "lib") path = os.path.join(path, "lib")
if not os.access(path, os.X_OK): if not os.access(path, os.X_OK):
self.logit("Path not accessible by user: %s" % path) self.logit("Path not accessible by user: %s" % path,facility=syslog.LOG_ERR)
raise Exception("Permission denied: %s" % path) raise Exception("Permission denied: %s" % path)
if path not in sys.path: if path not in sys.path:
...@@ -396,11 +401,11 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -396,11 +401,11 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
(self.uid,self.uid_idx,self.unix_uid) = self.getuserid(self.uuid) (self.uid,self.uid_idx,self.unix_uid) = self.getuserid(self.uuid)
if self.unix_uid == 0: if self.unix_uid == 0:
self.logit('No such user: "%s"' % self.uuid) self.logit('No such user: "%s"' % self.uuid,facility=syslog.LOG_ERR)
raise Exception('No such user: "%s"' % self.uuid) raise Exception('No such user: "%s"' % self.uuid)
if self.unix_uid == -1: if self.unix_uid == -1:
self.logit('User "%s,%d" is not active' % (self.uid,self.uid_idx)) self.logit('User "%s,%d" is not active' % (self.uid,self.uid_idx),facility=syslog.LOG_ERR)
raise Exception('User "%s,%d" is not active' % raise Exception('User "%s,%d" is not active' %
(self.uid,self.uid_idx)) (self.uid,self.uid_idx))
...@@ -417,7 +422,7 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -417,7 +422,7 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
self.getusergroups(self.uid_idx); self.getusergroups(self.uid_idx);
if len(self.glist) == 0: if len(self.glist) == 0:
self.logit('No groups for user: "%s,%d"' % (self.uid,self.uid_idx)) self.logit('No groups for user: "%s,%d"' % (self.uid,self.uid_idx),facility=syslog.LOG_ERR)
raise Exception('No groups for user: "%s,%d"' % raise Exception('No groups for user: "%s,%d"' %
(self.uid,self.uid_idx)) (self.uid,self.uid_idx))
...@@ -432,7 +437,7 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -432,7 +437,7 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
serial = request.get_peer_cert().get_serial_number() serial = request.get_peer_cert().get_serial_number()
if self.checkcert(self.uid_idx, serial) == 0: if self.checkcert(self.uid_idx, serial) == 0:
self.logit('No such cert with serial "%s"' % serial) self.logit('No such cert with serial "%s"' % serial,facility=syslog.LOG_ERR)
raise Exception('No such cert with serial "%s"' % serial) raise Exception('No such cert with serial "%s"' % serial)
# #
...@@ -490,16 +495,16 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -490,16 +495,16 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
elif argdict.has_key("proj"): elif argdict.has_key("proj"):
project = argdict["proj"] project = argdict["proj"]
else: else:
self.logit('Too many groups and no project given as an arg') self.logit('Too many groups and no project given as an arg',facility=syslog.LOG_ERR)
pass pass
if project: if project:
if self.plist.has_key(project): if self.plist.has_key(project):
self.glist = self.plist[project] self.glist = self.plist[project]
self.logit("Setting groups from project %s" % project) self.logit("Setting groups from project %s" % project,facility=syslog.LOG_ERR)
else: else:
self.logit('Too many groups but not a member of "%s"' % self.logit('Too many groups but not a member of "%s"' %
project) project,facility=syslog.LOG_ERR)
pass pass
pass pass
pass pass
...@@ -515,7 +520,7 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -515,7 +520,7 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
os.environ["LOGNAME"] = self.uid; os.environ["LOGNAME"] = self.uid;
pass pass
except: except:
self.logit(traceback.format_exc()) self.logit(traceback.format_exc(),facility=syslog.LOG_ERR)
os._exit(1) os._exit(1)
pass pass
pass pass
...@@ -574,7 +579,7 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -574,7 +579,7 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
sys.path.remove(TBPATH) sys.path.remove(TBPATH)
self.finish_request(request, client_address) self.finish_request(request, client_address)
self.close_request(request) self.close_request(request)
self.logit("request finished"); self.logit("request from %s finished" % (client_address[0]));
os._exit(0) os._exit(0)
except: except:
try: try:
...@@ -585,6 +590,22 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ...@@ -585,6 +590,22 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
def verify_request(self, request, client_address): def verify_request(self, request, client_address):
return True return True
def handle_error(self, request, client_address):
caddr = "UNKNOWN"
if client_address is None:
(ext,exv,extb) = sys.exc_info()
if exv is not None and hasattr(exv,'client_address'):
caddr = exv.client_address[0]
if client_address is not None:
caddr = client_address[0]
if exv is not None and isinstance(exv,SSLTimeoutError):
self.logit("SSLTimeoutError from %s" % (str(caddr)))
else:
self.logit(
"error from %s: %s" % (str(caddr),traceback.format_exc()),
facility=syslog.LOG_ERR)
pass pass
# #
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment