summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/rpc.py11
-rw-r--r--ipapython/ipasslfile.py179
-rw-r--r--ipapython/nsslib.py11
3 files changed, 197 insertions, 4 deletions
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index 48ac16b5a..6ac0cfa83 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -45,6 +45,13 @@ from ipapython import ipautil
from OpenSSL import SSL
import httplib
+try:
+ from httplib import SSLFile
+ from httplib import FakeSocket
+except ImportError:
+ from ipapython.ipasslfile import SSLFile
+ from ipapython.ipasslfile import FakeSocket
+
# Some Kerberos error definitions from krb5.h
KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN = (-1765328377L)
KRB5KRB_AP_ERR_TKT_EXPIRED = (-1765328352L)
@@ -195,7 +202,7 @@ class SSLTransport(Transport):
return SSLSocket(host, None, **(x509 or {}))
-class SSLFile(httplib.SSLFile):
+class SSLFile(SSLFile):
"""
Override the _read method so we can handle PyOpenSSL errors
gracefully.
@@ -227,7 +234,7 @@ class SSLFile(httplib.SSLFile):
return buf
-class FakeSocket(httplib.FakeSocket):
+class FakeSocket(FakeSocket):
"""
Override this class so we can end up using our own SSLFile
implementation.
diff --git a/ipapython/ipasslfile.py b/ipapython/ipasslfile.py
new file mode 100644
index 000000000..5525ab9b5
--- /dev/null
+++ b/ipapython/ipasslfile.py
@@ -0,0 +1,179 @@
+# This is a forward backport of the Python2.5 uuid module. It isn't available
+# in Python 2.6
+
+# The next several classes are used to define FakeSocket, a socket-like
+# interface to an SSL connection.
+
+# The primary complexity comes from faking a makefile() method. The
+# standard socket makefile() implementation calls dup() on the socket
+# file descriptor. As a consequence, clients can call close() on the
+# parent socket and its makefile children in any order. The underlying
+# socket isn't closed until they are all closed.
+
+# The implementation uses reference counting to keep the socket open
+# until the last client calls close(). SharedSocket keeps track of
+# the reference counting and SharedSocketClient provides an constructor
+# and close() method that call incref() and decref() correctly.
+
+class SharedSocket:
+ def __init__(self, sock):
+ self.sock = sock
+ self._refcnt = 0
+
+ def incref(self):
+ self._refcnt += 1
+
+ def decref(self):
+ self._refcnt -= 1
+ assert self._refcnt >= 0
+ if self._refcnt == 0:
+ self.sock.close()
+
+ def __del__(self):
+ self.sock.close()
+
+class SharedSocketClient:
+
+ def __init__(self, shared):
+ self._closed = 0
+ self._shared = shared
+ self._shared.incref()
+ self._sock = shared.sock
+
+ def close(self):
+ if not self._closed:
+ self._shared.decref()
+ self._closed = 1
+ self._shared = None
+
+class SSLFile(SharedSocketClient):
+ """File-like object wrapping an SSL socket."""
+
+ BUFSIZE = 8192
+
+ def __init__(self, sock, ssl, bufsize=None):
+ SharedSocketClient.__init__(self, sock)
+ self._ssl = ssl
+ self._buf = ''
+ self._bufsize = bufsize or self.__class__.BUFSIZE
+
+ def _read(self):
+ buf = ''
+ # put in a loop so that we retry on transient errors
+ while True:
+ try:
+ buf = self._ssl.read(self._bufsize)
+ except socket.sslerror, err:
+ if (err[0] == socket.SSL_ERROR_WANT_READ
+ or err[0] == socket.SSL_ERROR_WANT_WRITE):
+ continue
+ if (err[0] == socket.SSL_ERROR_ZERO_RETURN
+ or err[0] == socket.SSL_ERROR_EOF):
+ break
+ raise
+ except socket.error, err:
+ if err[0] == errno.EINTR:
+ continue
+ if err[0] == errno.EBADF:
+ # XXX socket was closed?
+ break
+ raise
+ else:
+ break
+ return buf
+
+ def read(self, size=None):
+ L = [self._buf]
+ avail = len(self._buf)
+ while size is None or avail < size:
+ s = self._read()
+ if s == '':
+ break
+ L.append(s)
+ avail += len(s)
+ all = "".join(L)
+ if size is None:
+ self._buf = ''
+ return all
+ else:
+ self._buf = all[size:]
+ return all[:size]
+
+ def readline(self):
+ L = [self._buf]
+ self._buf = ''
+ while 1:
+ i = L[-1].find("\n")
+ if i >= 0:
+ break
+ s = self._read()
+ if s == '':
+ break
+ L.append(s)
+ if i == -1:
+ # loop exited because there is no more data
+ return "".join(L)
+ else:
+ all = "".join(L)
+ # XXX could do enough bookkeeping not to do a 2nd search
+ i = all.find("\n") + 1
+ line = all[:i]
+ self._buf = all[i:]
+ return line
+
+ def readlines(self, sizehint=0):
+ total = 0
+ list = []
+ while True:
+ line = self.readline()
+ if not line:
+ break
+ list.append(line)
+ total += len(line)
+ if sizehint and total >= sizehint:
+ break
+ return list
+
+ def fileno(self):
+ return self._sock.fileno()
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ line = self.readline()
+ if not line:
+ raise StopIteration
+ return line
+
+class FakeSocket(SharedSocketClient):
+
+ class _closedsocket:
+ def __getattr__(self, name):
+ raise error(9, 'Bad file descriptor')
+
+ def __init__(self, sock, ssl):
+ sock = SharedSocket(sock)
+ SharedSocketClient.__init__(self, sock)
+ self._ssl = ssl
+
+ def close(self):
+ SharedSocketClient.close(self)
+ self._sock = self.__class__._closedsocket()
+
+ def makefile(self, mode, bufsize=None):
+ if mode != 'r' and mode != 'rb':
+ raise UnimplementedFileMode()
+ return SSLFile(self._shared, self._ssl, bufsize)
+
+ def send(self, stuff, flags = 0):
+ return self._ssl.write(stuff)
+
+ sendall = send
+
+ def recv(self, len = 1024, flags = 0):
+ return self._ssl.read(len)
+
+ def __getattr__(self, attr):
+ return getattr(self._sock, attr)
+
diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py
index fd27028e7..1b678305b 100644
--- a/ipapython/nsslib.py
+++ b/ipapython/nsslib.py
@@ -27,6 +27,13 @@ import nss.io as io
import nss.nss as nss
import nss.ssl as ssl
+try:
+ from httplib import SSLFile
+ from httplib import FakeSocket
+except ImportError:
+ from ipapython.ipasslfile import SSLFile
+ from ipapython.ipasslfile import FakeSocket
+
def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
cert = None
if chosen_nickname:
@@ -49,7 +56,7 @@ def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
return False
return False
-class SSLFile(httplib.SSLFile):
+class SSLFile(SSLFile):
"""
Override the _read method so we can use the NSS recv method.
"""
@@ -64,7 +71,7 @@ class SSLFile(httplib.SSLFile):
break
return buf
-class NSSFakeSocket(httplib.FakeSocket):
+class NSSFakeSocket(FakeSocket):
def makefile(self, mode, bufsize=None):
if mode != 'r' and mode != 'rb':
raise httplib.UnimplementedFileMode()