| /* SSL socket module  | 
 |  | 
 |    SSL support based on patches by Brian E Gallew and Laszlo Kovacs. | 
 |  | 
 |    This module is imported by socket.py. It should *not* be used | 
 |    directly. | 
 |  | 
 | */ | 
 |  | 
 | #include "Python.h" | 
 | enum py_ssl_error { | 
 | 	/* these mirror ssl.h */ | 
 | 	PY_SSL_ERROR_NONE,                  | 
 | 	PY_SSL_ERROR_SSL,                    | 
 | 	PY_SSL_ERROR_WANT_READ,              | 
 | 	PY_SSL_ERROR_WANT_WRITE,             | 
 | 	PY_SSL_ERROR_WANT_X509_LOOKUP,       | 
 | 	PY_SSL_ERROR_SYSCALL,     /* look at error stack/return value/errno */ | 
 | 	PY_SSL_ERROR_ZERO_RETURN,            | 
 | 	PY_SSL_ERROR_WANT_CONNECT, | 
 | 	/* start of non ssl.h errorcodes */  | 
 | 	PY_SSL_ERROR_EOF,         /* special case of SSL_ERROR_SYSCALL */ | 
 | 	PY_SSL_ERROR_INVALID_ERROR_CODE | 
 | }; | 
 |  | 
 | /* Include symbols from _socket module */ | 
 | #include "socketmodule.h" | 
 |  | 
 | #if defined(HAVE_POLL_H)  | 
 | #include <poll.h> | 
 | #elif defined(HAVE_SYS_POLL_H) | 
 | #include <sys/poll.h> | 
 | #endif | 
 |  | 
 | /* Include OpenSSL header files */ | 
 | #include "openssl/rsa.h" | 
 | #include "openssl/crypto.h" | 
 | #include "openssl/x509.h" | 
 | #include "openssl/pem.h" | 
 | #include "openssl/ssl.h" | 
 | #include "openssl/err.h" | 
 | #include "openssl/rand.h" | 
 |  | 
 | /* SSL error object */ | 
 | static PyObject *PySSLErrorObject; | 
 |  | 
 | /* SSL socket object */ | 
 |  | 
 | #define X509_NAME_MAXLEN 256 | 
 |  | 
 | /* RAND_* APIs got added to OpenSSL in 0.9.5 */ | 
 | #if OPENSSL_VERSION_NUMBER >= 0x0090500fL | 
 | # define HAVE_OPENSSL_RAND 1 | 
 | #else | 
 | # undef HAVE_OPENSSL_RAND | 
 | #endif | 
 |  | 
 | typedef struct { | 
 | 	PyObject_HEAD | 
 | 	PySocketSockObject *Socket;	/* Socket on which we're layered */ | 
 | 	SSL_CTX* 	ctx; | 
 | 	SSL*     	ssl; | 
 | 	X509*    	server_cert; | 
 | 	char    	server[X509_NAME_MAXLEN]; | 
 | 	char		issuer[X509_NAME_MAXLEN]; | 
 |  | 
 | } PySSLObject; | 
 |  | 
 | static PyTypeObject PySSL_Type; | 
 | static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); | 
 | static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); | 
 | static int check_socket_and_wait_for_timeout(PySocketSockObject *s,  | 
 | 					     int writing); | 
 |  | 
 | #define PySSLObject_Check(v)	((v)->ob_type == &PySSL_Type) | 
 |  | 
 | typedef enum { | 
 | 	SOCKET_IS_NONBLOCKING, | 
 | 	SOCKET_IS_BLOCKING, | 
 | 	SOCKET_HAS_TIMED_OUT, | 
 | 	SOCKET_HAS_BEEN_CLOSED, | 
 | 	SOCKET_TOO_LARGE_FOR_SELECT, | 
 | 	SOCKET_OPERATION_OK | 
 | } timeout_state; | 
 |  | 
 | /* XXX It might be helpful to augment the error message generated | 
 |    below with the name of the SSL function that generated the error. | 
 |    I expect it's obvious most of the time. | 
 | */ | 
 |  | 
 | static PyObject * | 
 | PySSL_SetError(PySSLObject *obj, int ret) | 
 | { | 
 | 	PyObject *v, *n, *s; | 
 | 	char *errstr; | 
 | 	int err; | 
 | 	enum py_ssl_error p; | 
 |  | 
 | 	assert(ret <= 0); | 
 |      | 
 | 	err = SSL_get_error(obj->ssl, ret); | 
 |  | 
 | 	switch (err) { | 
 | 	case SSL_ERROR_ZERO_RETURN: | 
 | 		errstr = "TLS/SSL connection has been closed"; | 
 | 		p = PY_SSL_ERROR_ZERO_RETURN; | 
 | 		break; | 
 | 	case SSL_ERROR_WANT_READ: | 
 | 		errstr = "The operation did not complete (read)"; | 
 | 		p = PY_SSL_ERROR_WANT_READ; | 
 | 		break; | 
 | 	case SSL_ERROR_WANT_WRITE: | 
 | 		p = PY_SSL_ERROR_WANT_WRITE; | 
 | 		errstr = "The operation did not complete (write)"; | 
 | 		break; | 
 | 	case SSL_ERROR_WANT_X509_LOOKUP: | 
 | 		p = PY_SSL_ERROR_WANT_X509_LOOKUP; | 
 | 		errstr = "The operation did not complete (X509 lookup)"; | 
 | 		break; | 
 | 	case SSL_ERROR_WANT_CONNECT: | 
 | 		p = PY_SSL_ERROR_WANT_CONNECT; | 
 | 		errstr = "The operation did not complete (connect)"; | 
 | 		break; | 
 | 	case SSL_ERROR_SYSCALL: | 
 | 	{ | 
 | 		unsigned long e = ERR_get_error(); | 
 | 		if (e == 0) { | 
 | 			if (ret == 0 || !obj->Socket) { | 
 | 				p = PY_SSL_ERROR_EOF; | 
 | 				errstr = "EOF occurred in violation of protocol"; | 
 | 			} else if (ret == -1) { | 
 | 				/* the underlying BIO reported an I/O error */ | 
 | 				return obj->Socket->errorhandler(); | 
 | 			} else {  /* possible? */ | 
 | 				p = PY_SSL_ERROR_SYSCALL; | 
 | 				errstr = "Some I/O error occurred"; | 
 | 			} | 
 | 		} else { | 
 | 			p = PY_SSL_ERROR_SYSCALL; | 
 | 			/* XXX Protected by global interpreter lock */ | 
 | 			errstr = ERR_error_string(e, NULL); | 
 | 		} | 
 | 		break; | 
 | 	}    | 
 | 	case SSL_ERROR_SSL: | 
 | 	{ | 
 | 		unsigned long e = ERR_get_error(); | 
 | 		p = PY_SSL_ERROR_SSL; | 
 | 		if (e != 0)  | 
 | 			/* XXX Protected by global interpreter lock */ | 
 | 			errstr = ERR_error_string(e, NULL); | 
 | 		else { /* possible? */ | 
 | 			errstr = "A failure in the SSL library occurred"; | 
 | 		} | 
 | 		break; | 
 | 	} | 
 | 	default: | 
 | 		p = PY_SSL_ERROR_INVALID_ERROR_CODE; | 
 | 		errstr = "Invalid error code"; | 
 | 	} | 
 | 	n = PyInt_FromLong((long) p); | 
 | 	if (n == NULL) | 
 | 		return NULL; | 
 | 	v = PyTuple_New(2); | 
 | 	if (v == NULL) { | 
 | 		Py_DECREF(n); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	s = PyString_FromString(errstr); | 
 | 	if (s == NULL) { | 
 | 		Py_DECREF(v); | 
 | 		Py_DECREF(n); | 
 | 	} | 
 | 	PyTuple_SET_ITEM(v, 0, n); | 
 | 	PyTuple_SET_ITEM(v, 1, s); | 
 | 	PyErr_SetObject(PySSLErrorObject, v); | 
 | 	Py_DECREF(v); | 
 | 	return NULL; | 
 | } | 
 |  | 
 | static PySSLObject * | 
 | newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file) | 
 | { | 
 | 	PySSLObject *self; | 
 | 	char *errstr = NULL; | 
 | 	int ret; | 
 | 	int err; | 
 | 	int sockstate; | 
 |  | 
 | 	self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ | 
 | 	if (self == NULL) | 
 | 		return NULL; | 
 | 	memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN); | 
 | 	memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN); | 
 | 	self->server_cert = NULL; | 
 | 	self->ssl = NULL; | 
 | 	self->ctx = NULL; | 
 | 	self->Socket = NULL; | 
 |  | 
 | 	if ((key_file && !cert_file) || (!key_file && cert_file)) { | 
 | 		errstr = "Both the key & certificate files must be specified"; | 
 | 		goto fail; | 
 | 	} | 
 |  | 
 | 	Py_BEGIN_ALLOW_THREADS | 
 | 	self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ | 
 | 	Py_END_ALLOW_THREADS | 
 | 	if (self->ctx == NULL) { | 
 | 		errstr = "SSL_CTX_new error"; | 
 | 		goto fail; | 
 | 	} | 
 |  | 
 | 	if (key_file) { | 
 | 		Py_BEGIN_ALLOW_THREADS | 
 | 		ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file, | 
 | 						SSL_FILETYPE_PEM); | 
 | 		Py_END_ALLOW_THREADS | 
 | 		if (ret < 1) { | 
 | 			errstr = "SSL_CTX_use_PrivateKey_file error"; | 
 | 			goto fail; | 
 | 		} | 
 |  | 
 | 		Py_BEGIN_ALLOW_THREADS | 
 | 		ret = SSL_CTX_use_certificate_chain_file(self->ctx, | 
 | 						       cert_file); | 
 | 		Py_END_ALLOW_THREADS | 
 | 		SSL_CTX_set_options(self->ctx, SSL_OP_ALL); /* ssl compatibility */ | 
 | 		if (ret < 1) { | 
 | 			errstr = "SSL_CTX_use_certificate_chain_file error"; | 
 | 			goto fail; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	Py_BEGIN_ALLOW_THREADS | 
 | 	SSL_CTX_set_verify(self->ctx, | 
 | 			   SSL_VERIFY_NONE, NULL); /* set verify lvl */ | 
 | 	self->ssl = SSL_new(self->ctx); /* New ssl struct */ | 
 | 	Py_END_ALLOW_THREADS | 
 | 	SSL_set_fd(self->ssl, Sock->sock_fd);	/* Set the socket for SSL */ | 
 |  | 
 | 	/* If the socket is in non-blocking mode or timeout mode, set the BIO | 
 | 	 * to non-blocking mode (blocking is the default) | 
 | 	 */ | 
 | 	if (Sock->sock_timeout >= 0.0) { | 
 | 		/* Set both the read and write BIO's to non-blocking mode */ | 
 | 		BIO_set_nbio(SSL_get_rbio(self->ssl), 1); | 
 | 		BIO_set_nbio(SSL_get_wbio(self->ssl), 1); | 
 | 	} | 
 |  | 
 | 	Py_BEGIN_ALLOW_THREADS | 
 | 	SSL_set_connect_state(self->ssl); | 
 | 	Py_END_ALLOW_THREADS | 
 |  | 
 | 	/* Actually negotiate SSL connection */ | 
 | 	/* XXX If SSL_connect() returns 0, it's also a failure. */ | 
 | 	sockstate = 0; | 
 | 	do { | 
 | 		Py_BEGIN_ALLOW_THREADS | 
 | 		ret = SSL_connect(self->ssl); | 
 | 		err = SSL_get_error(self->ssl, ret); | 
 | 		Py_END_ALLOW_THREADS | 
 | 		if(PyErr_CheckSignals()) { | 
 |                         goto fail; | 
 | 		} | 
 | 		if (err == SSL_ERROR_WANT_READ) { | 
 | 			sockstate = check_socket_and_wait_for_timeout(Sock, 0); | 
 | 		} else if (err == SSL_ERROR_WANT_WRITE) { | 
 | 			sockstate = check_socket_and_wait_for_timeout(Sock, 1); | 
 | 		} else { | 
 | 			sockstate = SOCKET_OPERATION_OK; | 
 | 		} | 
 | 	        if (sockstate == SOCKET_HAS_TIMED_OUT) { | 
 | 			PyErr_SetString(PySSLErrorObject, "The connect operation timed out"); | 
 | 			goto fail; | 
 | 		} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { | 
 | 			PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); | 
 | 			goto fail; | 
 | 		} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { | 
 | 			PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); | 
 | 			goto fail; | 
 | 		} else if (sockstate == SOCKET_IS_NONBLOCKING) { | 
 | 			break; | 
 | 		} | 
 | 	} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); | 
 | 	if (ret <= 0) { | 
 | 		PySSL_SetError(self, ret); | 
 | 		goto fail; | 
 | 	} | 
 | 	self->ssl->debug = 1; | 
 |  | 
 | 	Py_BEGIN_ALLOW_THREADS | 
 | 	if ((self->server_cert = SSL_get_peer_certificate(self->ssl))) { | 
 | 		X509_NAME_oneline(X509_get_subject_name(self->server_cert), | 
 | 				  self->server, X509_NAME_MAXLEN); | 
 | 		X509_NAME_oneline(X509_get_issuer_name(self->server_cert), | 
 | 				  self->issuer, X509_NAME_MAXLEN); | 
 | 	} | 
 | 	Py_END_ALLOW_THREADS | 
 | 	self->Socket = Sock; | 
 | 	Py_INCREF(self->Socket); | 
 | 	return self; | 
 |  fail: | 
 | 	if (errstr) | 
 | 		PyErr_SetString(PySSLErrorObject, errstr); | 
 | 	Py_DECREF(self); | 
 | 	return NULL; | 
 | } | 
 |  | 
 | static PyObject * | 
 | PySocket_ssl(PyObject *self, PyObject *args) | 
 | { | 
 | 	PySSLObject *rv; | 
 | 	PySocketSockObject *Sock; | 
 | 	char *key_file = NULL; | 
 | 	char *cert_file = NULL; | 
 |  | 
 | 	if (!PyArg_ParseTuple(args, "O!|zz:ssl", | 
 | 			      PySocketModule.Sock_Type, | 
 | 			      &Sock, | 
 | 			      &key_file, &cert_file)) | 
 | 		return NULL; | 
 |  | 
 | 	rv = newPySSLObject(Sock, key_file, cert_file); | 
 | 	if (rv == NULL) | 
 | 		return NULL; | 
 | 	return (PyObject *)rv; | 
 | } | 
 |  | 
 | PyDoc_STRVAR(ssl_doc, | 
 | "ssl(socket, [keyfile, certfile]) -> sslobject"); | 
 |  | 
 | /* SSL object methods */ | 
 |  | 
 | static PyObject * | 
 | PySSL_server(PySSLObject *self) | 
 | { | 
 | 	return PyString_FromString(self->server); | 
 | } | 
 |  | 
 | static PyObject * | 
 | PySSL_issuer(PySSLObject *self) | 
 | { | 
 | 	return PyString_FromString(self->issuer); | 
 | } | 
 |  | 
 |  | 
 | static void PySSL_dealloc(PySSLObject *self) | 
 | { | 
 | 	if (self->server_cert)	/* Possible not to have one? */ | 
 | 		X509_free (self->server_cert); | 
 | 	if (self->ssl) | 
 | 	    SSL_free(self->ssl); | 
 | 	if (self->ctx) | 
 | 	    SSL_CTX_free(self->ctx); | 
 | 	Py_XDECREF(self->Socket); | 
 | 	PyObject_Del(self); | 
 | } | 
 |  | 
 | /* If the socket has a timeout, do a select()/poll() on the socket. | 
 |    The argument writing indicates the direction. | 
 |    Returns one of the possibilities in the timeout_state enum (above). | 
 |  */ | 
 |  | 
 | static int | 
 | check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing) | 
 | { | 
 | 	fd_set fds; | 
 | 	struct timeval tv; | 
 | 	int rc; | 
 |  | 
 | 	/* Nothing to do unless we're in timeout mode (not non-blocking) */ | 
 | 	if (s->sock_timeout < 0.0) | 
 | 		return SOCKET_IS_BLOCKING; | 
 | 	else if (s->sock_timeout == 0.0) | 
 | 		return SOCKET_IS_NONBLOCKING; | 
 |  | 
 | 	/* Guard against closed socket */ | 
 | 	if (s->sock_fd < 0) | 
 | 		return SOCKET_HAS_BEEN_CLOSED; | 
 |  | 
 | 	/* Prefer poll, if available, since you can poll() any fd | 
 | 	 * which can't be done with select(). */ | 
 | #ifdef HAVE_POLL | 
 | 	{ | 
 | 		struct pollfd pollfd; | 
 | 		int timeout; | 
 |  | 
 | 		pollfd.fd = s->sock_fd; | 
 | 		pollfd.events = writing ? POLLOUT : POLLIN; | 
 |  | 
 | 		/* s->sock_timeout is in seconds, timeout in ms */ | 
 | 		timeout = (int)(s->sock_timeout * 1000 + 0.5); | 
 | 		Py_BEGIN_ALLOW_THREADS | 
 | 		rc = poll(&pollfd, 1, timeout); | 
 | 		Py_END_ALLOW_THREADS | 
 |  | 
 | 		goto normal_return; | 
 | 	} | 
 | #endif | 
 |  | 
 | 	/* Guard against socket too large for select*/ | 
 | #ifndef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE | 
 | 	if (s->sock_fd >= FD_SETSIZE) | 
 | 		return SOCKET_TOO_LARGE_FOR_SELECT; | 
 | #endif | 
 |  | 
 | 	/* Construct the arguments to select */ | 
 | 	tv.tv_sec = (int)s->sock_timeout; | 
 | 	tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); | 
 | 	FD_ZERO(&fds); | 
 | 	FD_SET(s->sock_fd, &fds); | 
 |  | 
 | 	/* See if the socket is ready */ | 
 | 	Py_BEGIN_ALLOW_THREADS | 
 | 	if (writing) | 
 | 		rc = select(s->sock_fd+1, NULL, &fds, NULL, &tv); | 
 | 	else | 
 | 		rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv); | 
 | 	Py_END_ALLOW_THREADS | 
 |  | 
 | normal_return: | 
 | 	/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise | 
 | 	   (when we are able to write or when there's something to read) */ | 
 | 	return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; | 
 | } | 
 |  | 
 | static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) | 
 | { | 
 | 	char *data; | 
 | 	int len; | 
 | 	int count; | 
 | 	int sockstate; | 
 | 	int err; | 
 |  | 
 | 	if (!PyArg_ParseTuple(args, "s#:write", &data, &count)) | 
 | 		return NULL; | 
 |  | 
 | 	sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); | 
 | 	if (sockstate == SOCKET_HAS_TIMED_OUT) { | 
 | 		PyErr_SetString(PySSLErrorObject, "The write operation timed out"); | 
 | 		return NULL; | 
 | 	} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { | 
 | 		PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); | 
 | 		return NULL; | 
 | 	} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { | 
 | 		PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); | 
 | 		return NULL; | 
 | 	} | 
 | 	do { | 
 | 		err = 0; | 
 | 		Py_BEGIN_ALLOW_THREADS | 
 | 		len = SSL_write(self->ssl, data, count); | 
 | 		err = SSL_get_error(self->ssl, len); | 
 | 		Py_END_ALLOW_THREADS | 
 | 		if(PyErr_CheckSignals()) { | 
 | 			return NULL; | 
 | 		} | 
 | 		if (err == SSL_ERROR_WANT_READ) { | 
 | 			sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); | 
 | 		} else if (err == SSL_ERROR_WANT_WRITE) { | 
 | 			sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); | 
 | 		} else { | 
 | 			sockstate = SOCKET_OPERATION_OK; | 
 | 		} | 
 | 	        if (sockstate == SOCKET_HAS_TIMED_OUT) { | 
 | 			PyErr_SetString(PySSLErrorObject, "The write operation timed out"); | 
 | 			return NULL; | 
 | 		} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { | 
 | 			PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); | 
 | 			return NULL; | 
 | 		} else if (sockstate == SOCKET_IS_NONBLOCKING) { | 
 | 			break; | 
 | 		} | 
 | 	} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); | 
 | 	if (len > 0) | 
 | 		return PyInt_FromLong(len); | 
 | 	else | 
 | 		return PySSL_SetError(self, len); | 
 | } | 
 |  | 
 | PyDoc_STRVAR(PySSL_SSLwrite_doc, | 
 | "write(s) -> len\n\ | 
 | \n\ | 
 | Writes the string s into the SSL object.  Returns the number\n\ | 
 | of bytes written."); | 
 |  | 
 | static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) | 
 | { | 
 | 	PyObject *buf; | 
 | 	int count = 0; | 
 | 	int len = 1024; | 
 | 	int sockstate; | 
 | 	int err; | 
 |  | 
 | 	if (!PyArg_ParseTuple(args, "|i:read", &len)) | 
 | 		return NULL; | 
 |  | 
 | 	if (!(buf = PyString_FromStringAndSize((char *) 0, len))) | 
 | 		return NULL; | 
 | 	 | 
 | 	/* first check if there are bytes ready to be read */ | 
 | 	Py_BEGIN_ALLOW_THREADS | 
 | 	count = SSL_pending(self->ssl); | 
 | 	Py_END_ALLOW_THREADS | 
 |  | 
 | 	if (!count) { | 
 | 		sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); | 
 | 		if (sockstate == SOCKET_HAS_TIMED_OUT) { | 
 | 			PyErr_SetString(PySSLErrorObject, "The read operation timed out"); | 
 | 			Py_DECREF(buf); | 
 | 			return NULL; | 
 | 		} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { | 
 | 			PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); | 
 | 			return NULL; | 
 | 		} | 
 | 	} | 
 | 	do { | 
 | 		err = 0; | 
 | 		Py_BEGIN_ALLOW_THREADS | 
 | 		count = SSL_read(self->ssl, PyString_AsString(buf), len); | 
 | 		err = SSL_get_error(self->ssl, count); | 
 | 		Py_END_ALLOW_THREADS | 
 | 		if(PyErr_CheckSignals()) { | 
 | 			Py_DECREF(buf); | 
 | 			return NULL; | 
 | 		} | 
 | 		if (err == SSL_ERROR_WANT_READ) { | 
 | 			sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); | 
 | 		} else if (err == SSL_ERROR_WANT_WRITE) { | 
 | 			sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); | 
 | 		} else { | 
 | 			sockstate = SOCKET_OPERATION_OK; | 
 | 		} | 
 | 	        if (sockstate == SOCKET_HAS_TIMED_OUT) { | 
 | 			PyErr_SetString(PySSLErrorObject, "The read operation timed out"); | 
 | 			Py_DECREF(buf); | 
 | 			return NULL; | 
 | 		} else if (sockstate == SOCKET_IS_NONBLOCKING) { | 
 | 			break; | 
 | 		} | 
 | 	} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); | 
 |  	if (count <= 0) { | 
 | 		Py_DECREF(buf); | 
 | 		return PySSL_SetError(self, count); | 
 | 	} | 
 | 	if (count != len) | 
 | 		_PyString_Resize(&buf, count); | 
 | 	return buf; | 
 | } | 
 |  | 
 | PyDoc_STRVAR(PySSL_SSLread_doc, | 
 | "read([len]) -> string\n\ | 
 | \n\ | 
 | Read up to len bytes from the SSL socket."); | 
 |  | 
 | static PyMethodDef PySSLMethods[] = { | 
 | 	{"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, | 
 | 	          PySSL_SSLwrite_doc}, | 
 | 	{"read", (PyCFunction)PySSL_SSLread, METH_VARARGS, | 
 | 	          PySSL_SSLread_doc}, | 
 | 	{"server", (PyCFunction)PySSL_server, METH_NOARGS}, | 
 | 	{"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS}, | 
 | 	{NULL, NULL} | 
 | }; | 
 |  | 
 | static PyObject *PySSL_getattr(PySSLObject *self, char *name) | 
 | { | 
 | 	return Py_FindMethod(PySSLMethods, (PyObject *)self, name); | 
 | } | 
 |  | 
 | static PyTypeObject PySSL_Type = { | 
 | 	PyObject_HEAD_INIT(NULL) | 
 | 	0,				/*ob_size*/ | 
 | 	"socket.SSL",			/*tp_name*/ | 
 | 	sizeof(PySSLObject),		/*tp_basicsize*/ | 
 | 	0,				/*tp_itemsize*/ | 
 | 	/* methods */ | 
 | 	(destructor)PySSL_dealloc,	/*tp_dealloc*/ | 
 | 	0,				/*tp_print*/ | 
 | 	(getattrfunc)PySSL_getattr,	/*tp_getattr*/ | 
 | 	0,				/*tp_setattr*/ | 
 | 	0,				/*tp_compare*/ | 
 | 	0,				/*tp_repr*/ | 
 | 	0,				/*tp_as_number*/ | 
 | 	0,				/*tp_as_sequence*/ | 
 | 	0,				/*tp_as_mapping*/ | 
 | 	0,				/*tp_hash*/ | 
 | }; | 
 |  | 
 | #ifdef HAVE_OPENSSL_RAND | 
 |  | 
 | /* helper routines for seeding the SSL PRNG */ | 
 | static PyObject * | 
 | PySSL_RAND_add(PyObject *self, PyObject *args) | 
 | { | 
 |     char *buf; | 
 |     int len; | 
 |     double entropy; | 
 |  | 
 |     if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) | 
 | 	return NULL; | 
 |     RAND_add(buf, len, entropy); | 
 |     Py_INCREF(Py_None); | 
 |     return Py_None; | 
 | } | 
 |  | 
 | PyDoc_STRVAR(PySSL_RAND_add_doc, | 
 | "RAND_add(string, entropy)\n\ | 
 | \n\ | 
 | Mix string into the OpenSSL PRNG state.  entropy (a float) is a lower\n\ | 
 | bound on the entropy contained in string."); | 
 |  | 
 | static PyObject * | 
 | PySSL_RAND_status(PyObject *self) | 
 | { | 
 |     return PyInt_FromLong(RAND_status()); | 
 | } | 
 |  | 
 | PyDoc_STRVAR(PySSL_RAND_status_doc, | 
 | "RAND_status() -> 0 or 1\n\ | 
 | \n\ | 
 | Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 if not.\n\ | 
 | It is necessary to seed the PRNG with RAND_add() on some platforms before\n\ | 
 | using the ssl() function."); | 
 |  | 
 | static PyObject * | 
 | PySSL_RAND_egd(PyObject *self, PyObject *arg) | 
 | { | 
 |     int bytes; | 
 |  | 
 |     if (!PyString_Check(arg)) | 
 | 	return PyErr_Format(PyExc_TypeError, | 
 | 			    "RAND_egd() expected string, found %s", | 
 | 			    arg->ob_type->tp_name); | 
 |     bytes = RAND_egd(PyString_AS_STRING(arg)); | 
 |     if (bytes == -1) { | 
 | 	PyErr_SetString(PySSLErrorObject, | 
 | 			"EGD connection failed or EGD did not return " | 
 | 			"enough data to seed the PRNG"); | 
 | 	return NULL; | 
 |     } | 
 |     return PyInt_FromLong(bytes); | 
 | } | 
 |  | 
 | PyDoc_STRVAR(PySSL_RAND_egd_doc, | 
 | "RAND_egd(path) -> bytes\n\ | 
 | \n\ | 
 | Queries the entropy gather daemon (EGD) on socket path.  Returns number\n\ | 
 | of bytes read.  Raises socket.sslerror if connection to EGD fails or\n\ | 
 | if it does provide enough data to seed PRNG."); | 
 |  | 
 | #endif | 
 |  | 
 | /* List of functions exported by this module. */ | 
 |  | 
 | static PyMethodDef PySSL_methods[] = { | 
 | 	{"ssl",			PySocket_ssl, | 
 | 	 METH_VARARGS, ssl_doc}, | 
 | #ifdef HAVE_OPENSSL_RAND | 
 | 	{"RAND_add",            PySSL_RAND_add, METH_VARARGS,  | 
 | 	 PySSL_RAND_add_doc}, | 
 | 	{"RAND_egd",            PySSL_RAND_egd, METH_O, | 
 | 	 PySSL_RAND_egd_doc}, | 
 | 	{"RAND_status",         (PyCFunction)PySSL_RAND_status, METH_NOARGS, | 
 | 	 PySSL_RAND_status_doc}, | 
 | #endif | 
 | 	{NULL,			NULL}		 /* Sentinel */ | 
 | }; | 
 |  | 
 |  | 
 | PyDoc_STRVAR(module_doc, | 
 | "Implementation module for SSL socket operations.  See the socket module\n\ | 
 | for documentation."); | 
 |  | 
 | PyMODINIT_FUNC | 
 | init_ssl(void) | 
 | { | 
 | 	PyObject *m, *d; | 
 |  | 
 | 	PySSL_Type.ob_type = &PyType_Type; | 
 |  | 
 | 	m = Py_InitModule3("_ssl", PySSL_methods, module_doc); | 
 | 	if (m == NULL) | 
 | 		return; | 
 | 	d = PyModule_GetDict(m); | 
 |  | 
 | 	/* Load _socket module and its C API */ | 
 | 	if (PySocketModule_ImportModuleAndAPI()) | 
 |  	    	return; | 
 |  | 
 | 	/* Init OpenSSL */ | 
 | 	SSL_load_error_strings(); | 
 | 	SSLeay_add_ssl_algorithms(); | 
 |  | 
 | 	/* Add symbols to module dict */ | 
 | 	PySSLErrorObject = PyErr_NewException("socket.sslerror", | 
 |                                                PySocketModule.error, | 
 |                                                NULL); | 
 | 	if (PySSLErrorObject == NULL) | 
 | 		return; | 
 | 	PyDict_SetItemString(d, "sslerror", PySSLErrorObject); | 
 | 	if (PyDict_SetItemString(d, "SSLType", | 
 | 				 (PyObject *)&PySSL_Type) != 0) | 
 | 		return; | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN", | 
 | 				PY_SSL_ERROR_ZERO_RETURN); | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ", | 
 | 				PY_SSL_ERROR_WANT_READ); | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE", | 
 | 				PY_SSL_ERROR_WANT_WRITE); | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP", | 
 | 				PY_SSL_ERROR_WANT_X509_LOOKUP); | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL", | 
 | 				PY_SSL_ERROR_SYSCALL); | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_SSL", | 
 | 				PY_SSL_ERROR_SSL); | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_CONNECT", | 
 | 				PY_SSL_ERROR_WANT_CONNECT); | 
 | 	/* non ssl.h errorcodes */ | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_EOF", | 
 | 				PY_SSL_ERROR_EOF); | 
 | 	PyModule_AddIntConstant(m, "SSL_ERROR_INVALID_ERROR_CODE", | 
 | 				PY_SSL_ERROR_INVALID_ERROR_CODE); | 
 |  | 
 | } |