mirror of
				https://github.com/python/cpython.git
				synced 2025-10-28 20:25:04 +00:00 
			
		
		
		
	Break SSL support out of _socket module and place it into a new
helper module _ssl. The support for the RAND_* APIs in _ssl is now only enabled for OpenSSL 0.9.5 and up since they were added in that release. Note that socketmodule.* should really be renamed to _socket.* -- unfortunately, this seems to lose the CVS history of the file. Please review and test... I was only able to test the header file chaos in socketmodule.c/h on Linux. The test run through fine and compiles don't give errors or warnings. WARNING: This patch does *not* include changes to the various non-Unix build process files.
This commit is contained in:
		
							parent
							
								
									e4418609f7
								
							
						
					
					
						commit
						a5d2b4cb18
					
				
					 7 changed files with 747 additions and 577 deletions
				
			
		|  | @ -39,6 +39,10 @@ | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| from _socket import * | from _socket import * | ||||||
|  | try: | ||||||
|  |     from _ssl import * | ||||||
|  | except ImportError: | ||||||
|  |     pass | ||||||
| 
 | 
 | ||||||
| import os, sys | import os, sys | ||||||
| 
 | 
 | ||||||
|  | @ -56,7 +60,7 @@ def socket(family, type, proto=0): | ||||||
|         return _socketobject(_realsocketcall(family, type, proto)) |         return _socketobject(_realsocketcall(family, type, proto)) | ||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
|         _realsslcall = _socket.ssl |         _realsslcall = _ssl.ssl | ||||||
|     except AttributeError: |     except AttributeError: | ||||||
|         pass # No ssl |         pass # No ssl | ||||||
|     else: |     else: | ||||||
|  |  | ||||||
|  | @ -21,6 +21,10 @@ Extension modules | ||||||
| 
 | 
 | ||||||
| Library | Library | ||||||
| 
 | 
 | ||||||
|  | - socket module: the SSL support was broken out of the main | ||||||
|  |   _socket module C helper and placed into a new _ssl helper | ||||||
|  |   which now gets imported by socket.py if available and working. | ||||||
|  | 
 | ||||||
| - encodings package: added aliases for all supported IANA character | - encodings package: added aliases for all supported IANA character | ||||||
|   sets |   sets | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -175,13 +175,13 @@ GLHACK=-Dclear=__GLclear | ||||||
| # Dynamic readlines | # Dynamic readlines | ||||||
| #xreadlines xreadlinesmodule.c | #xreadlines xreadlinesmodule.c | ||||||
| 
 | 
 | ||||||
| # for socket(2), without SSL support. | # Socket module helper for socket(2) | ||||||
| #_socket socketmodule.c | #_socket socketmodule.c | ||||||
| 
 | 
 | ||||||
| # Socket module compiled with SSL support; you must comment out the other | # Socket module helper for SSL support; you must comment out the other | ||||||
| # socket line above, and possibly edit the SSL variable: | # socket line above, and possibly edit the SSL variable: | ||||||
| #SSL=/usr/local/ssl | #SSL=/usr/local/ssl | ||||||
| #_socket socketmodule.c \ | #_ssl _ssl.c \ | ||||||
| #	-DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ | #	-DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ | ||||||
| #	-L$(SSL)/lib -lssl -lcrypto | #	-L$(SSL)/lib -lssl -lcrypto | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										461
									
								
								Modules/_ssl.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										461
									
								
								Modules/_ssl.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,461 @@ | ||||||
|  | /* 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" | ||||||
|  | 
 | ||||||
|  | /* Include symbols from _socket module */ | ||||||
|  | #include "socketmodule.h" | ||||||
|  | 
 | ||||||
|  | /* 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; | ||||||
|  | 	BIO*		sbio; | ||||||
|  | 	char    	server[X509_NAME_MAXLEN]; | ||||||
|  | 	char		issuer[X509_NAME_MAXLEN]; | ||||||
|  | 
 | ||||||
|  | } PySSLObject; | ||||||
|  | 
 | ||||||
|  | staticforward PyTypeObject PySSL_Type; | ||||||
|  | staticforward PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); | ||||||
|  | staticforward PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); | ||||||
|  | 
 | ||||||
|  | #define PySSLObject_Check(v)	((v)->ob_type == &PySSL_Type) | ||||||
|  | 
 | ||||||
|  | /* 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; | ||||||
|  | 
 | ||||||
|  | 	assert(ret <= 0); | ||||||
|  |      | ||||||
|  | 	err = SSL_get_error(obj->ssl, ret); | ||||||
|  | 	n = PyInt_FromLong(err); | ||||||
|  | 	if (n == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	v = PyTuple_New(2); | ||||||
|  | 	if (v == NULL) { | ||||||
|  | 		Py_DECREF(n); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	switch (SSL_get_error(obj->ssl, ret)) { | ||||||
|  | 	case SSL_ERROR_ZERO_RETURN: | ||||||
|  | 		errstr = "TLS/SSL connection has been closed"; | ||||||
|  | 		break; | ||||||
|  | 	case SSL_ERROR_WANT_READ: | ||||||
|  | 		errstr = "The operation did not complete (read)"; | ||||||
|  | 		break; | ||||||
|  | 	case SSL_ERROR_WANT_WRITE: | ||||||
|  | 		errstr = "The operation did not complete (write)"; | ||||||
|  | 		break; | ||||||
|  | 	case SSL_ERROR_WANT_X509_LOOKUP: | ||||||
|  | 		errstr = "The operation did not complete (X509 lookup)"; | ||||||
|  | 		break; | ||||||
|  | 	case SSL_ERROR_SYSCALL: | ||||||
|  | 	case SSL_ERROR_SSL: | ||||||
|  | 	{ | ||||||
|  | 		unsigned long e = ERR_get_error(); | ||||||
|  | 		if (e == 0) { | ||||||
|  | 			/* an EOF was observed that violates the protocol */ | ||||||
|  | 			errstr = "EOF occurred in violation of protocol"; | ||||||
|  | 		} else if (e == -1) { | ||||||
|  | 			/* the underlying BIO reported an I/O error */ | ||||||
|  | 			Py_DECREF(v); | ||||||
|  | 			Py_DECREF(n); | ||||||
|  | 			return obj->Socket->errorhandler(); | ||||||
|  | 		} else { | ||||||
|  | 			/* XXX Protected by global interpreter lock */ | ||||||
|  | 			errstr = ERR_error_string(e, NULL); | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 	default: | ||||||
|  | 		errstr = "Invalid error code"; | ||||||
|  | 	} | ||||||
|  | 	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); | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* This is a C function to be called for new object initialization */ | ||||||
|  | static PySSLObject * | ||||||
|  | newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file) | ||||||
|  | { | ||||||
|  | 	PySSLObject *self; | ||||||
|  | 	char *errstr = NULL; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ | ||||||
|  | 	if (self == NULL){ | ||||||
|  | 		errstr = "newPySSLObject error"; | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
|  | 	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; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ | ||||||
|  | 	if (self->ctx == NULL) { | ||||||
|  | 		errstr = "SSL_CTX_new error"; | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (key_file) { | ||||||
|  | 		if (SSL_CTX_use_PrivateKey_file(self->ctx, key_file, | ||||||
|  | 						SSL_FILETYPE_PEM) < 1) { | ||||||
|  | 			errstr = "SSL_CTX_use_PrivateKey_file error"; | ||||||
|  | 			goto fail; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SSL_CTX_use_certificate_chain_file(self->ctx, | ||||||
|  | 						       cert_file) < 1) { | ||||||
|  | 			errstr = "SSL_CTX_use_certificate_chain_file error"; | ||||||
|  | 			goto fail; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	SSL_CTX_set_verify(self->ctx, | ||||||
|  | 			   SSL_VERIFY_NONE, NULL); /* set verify lvl */ | ||||||
|  | 	self->ssl = SSL_new(self->ctx); /* New ssl struct */ | ||||||
|  | 	SSL_set_fd(self->ssl, Sock->sock_fd);	/* Set the socket for SSL */ | ||||||
|  | 	SSL_set_connect_state(self->ssl); | ||||||
|  | 
 | ||||||
|  | 	/* Actually negotiate SSL connection */ | ||||||
|  | 	/* XXX If SSL_connect() returns 0, it's also a failure. */ | ||||||
|  | 	ret = SSL_connect(self->ssl); | ||||||
|  | 	if (ret <= 0) { | ||||||
|  | 		PySSL_SetError(self, ret); | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
|  | 	self->ssl->debug = 1; | ||||||
|  | 
 | ||||||
|  | 	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); | ||||||
|  | 	} | ||||||
|  | 	self->Socket = Sock; | ||||||
|  | 	Py_INCREF(self->Socket); | ||||||
|  | 	return self; | ||||||
|  |  fail: | ||||||
|  | 	if (errstr) | ||||||
|  | 		PyErr_SetString(PySSLErrorObject, errstr); | ||||||
|  | 	Py_DECREF(self); | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* This is the Python function called for new object initialization */ | ||||||
|  | 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, | ||||||
|  | 			      (PyObject*)&Sock, | ||||||
|  | 			      &key_file, &cert_file)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	rv = newPySSLObject(Sock, key_file, cert_file); | ||||||
|  | 	if (rv == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	return (PyObject *)rv; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static char 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); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) | ||||||
|  | { | ||||||
|  | 	char *data; | ||||||
|  | 	int len; | ||||||
|  | 
 | ||||||
|  | 	if (!PyArg_ParseTuple(args, "s#:write", &data, &len)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	Py_BEGIN_ALLOW_THREADS | ||||||
|  | 	len = SSL_write(self->ssl, data, len); | ||||||
|  | 	Py_END_ALLOW_THREADS | ||||||
|  | 	if (len > 0) | ||||||
|  | 		return PyInt_FromLong(len); | ||||||
|  | 	else | ||||||
|  | 		return PySSL_SetError(self, len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static char 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; | ||||||
|  | 
 | ||||||
|  | 	if (!PyArg_ParseTuple(args, "|i:read", &len)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	if (!(buf = PyString_FromStringAndSize((char *) 0, len))) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	Py_BEGIN_ALLOW_THREADS | ||||||
|  | 	count = SSL_read(self->ssl, PyString_AsString(buf), len); | ||||||
|  | 	Py_END_ALLOW_THREADS | ||||||
|  |  	if (count <= 0) { | ||||||
|  | 		Py_DECREF(buf); | ||||||
|  | 		return PySSL_SetError(self, count); | ||||||
|  | 	} | ||||||
|  | 	if (count != len && _PyString_Resize(&buf, count) < 0) | ||||||
|  | 		return NULL; | ||||||
|  | 	return buf; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static char 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); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | staticforward 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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static char 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()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static char 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); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static char 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 */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static char module_doc[] = | ||||||
|  | "Implementation module for SSL socket operations.  See the socket module\n\
 | ||||||
|  | for documentation."; | ||||||
|  | 
 | ||||||
|  | DL_EXPORT(void) | ||||||
|  | init_ssl(void) | ||||||
|  | { | ||||||
|  | 	PyObject *m, *d; | ||||||
|  | 
 | ||||||
|  | 	PySSL_Type.ob_type = &PyType_Type; | ||||||
|  | 
 | ||||||
|  | 	m = Py_InitModule3("_ssl", PySSL_methods, module_doc); | ||||||
|  | 	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", NULL, 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", | ||||||
|  | 				SSL_ERROR_ZERO_RETURN); | ||||||
|  | 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ", | ||||||
|  | 				SSL_ERROR_WANT_READ); | ||||||
|  | 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE", | ||||||
|  | 				SSL_ERROR_WANT_WRITE); | ||||||
|  | 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP", | ||||||
|  | 				SSL_ERROR_WANT_X509_LOOKUP); | ||||||
|  | 	PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL", | ||||||
|  | 				SSL_ERROR_SYSCALL); | ||||||
|  | 	PyModule_AddIntConstant(m, "SSL_ERROR_SSL", | ||||||
|  | 				SSL_ERROR_SSL); | ||||||
|  | } | ||||||
|  | @ -1,7 +1,5 @@ | ||||||
| /* Socket module */ | /* Socket module */ | ||||||
| 
 | 
 | ||||||
| /* SSL support based on patches by Brian E Gallew and Laszlo Kovacs */ |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
| This module provides an interface to Berkeley socket IPC. | This module provides an interface to Berkeley socket IPC. | ||||||
| 
 | 
 | ||||||
|  | @ -35,7 +33,6 @@ Module interface: | ||||||
| - socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h> | - socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h> | ||||||
| - socket.inet_aton(IP address) -> 32-bit packed IP representation | - socket.inet_aton(IP address) -> 32-bit packed IP representation | ||||||
| - socket.inet_ntoa(packed IP) -> IP address string | - socket.inet_ntoa(packed IP) -> IP address string | ||||||
| - socket.ssl(socket, keyfile, certfile) -> new ssl object |  | ||||||
| - an Internet socket address is a pair (hostname, port) | - an Internet socket address is a pair (hostname, port) | ||||||
|   where hostname can be anything recognized by gethostbyname() |   where hostname can be anything recognized by gethostbyname() | ||||||
|   (including the dd.dd.dd.dd notation) and port is in host byte order |   (including the dd.dd.dd.dd notation) and port is in host byte order | ||||||
|  | @ -86,128 +83,111 @@ Socket methods: | ||||||
|    computed by the configure script are needed! */ |    computed by the configure script are needed! */ | ||||||
| 
 | 
 | ||||||
| #ifndef linux | #ifndef linux | ||||||
| #undef HAVE_GETHOSTBYNAME_R_3_ARG | # undef HAVE_GETHOSTBYNAME_R_3_ARG | ||||||
| #undef HAVE_GETHOSTBYNAME_R_5_ARG | # undef HAVE_GETHOSTBYNAME_R_5_ARG | ||||||
| #undef HAVE_GETHOSTBYNAME_R_6_ARG | # undef HAVE_GETHOSTBYNAME_R_6_ARG | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifndef WITH_THREAD | #ifndef WITH_THREAD | ||||||
| #undef HAVE_GETHOSTBYNAME_R | # undef HAVE_GETHOSTBYNAME_R | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_GETHOSTBYNAME_R | #ifdef HAVE_GETHOSTBYNAME_R | ||||||
| #if defined(_AIX) || defined(__osf__) | # if defined(_AIX) || defined(__osf__) | ||||||
| #define HAVE_GETHOSTBYNAME_R_3_ARG | #  define HAVE_GETHOSTBYNAME_R_3_ARG | ||||||
| #elif defined(__sun) || defined(__sgi) | # elif defined(__sun) || defined(__sgi) | ||||||
| #define HAVE_GETHOSTBYNAME_R_5_ARG | #  define HAVE_GETHOSTBYNAME_R_5_ARG | ||||||
| #elif defined(linux) | # elif defined(linux) | ||||||
| /* Rely on the configure script */ | /* Rely on the configure script */ | ||||||
| #else | # else | ||||||
| #undef HAVE_GETHOSTBYNAME_R | #  undef HAVE_GETHOSTBYNAME_R | ||||||
| #endif | # endif | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if !defined(HAVE_GETHOSTBYNAME_R) && defined(WITH_THREAD) && !defined(MS_WINDOWS) | #if !defined(HAVE_GETHOSTBYNAME_R) && defined(WITH_THREAD) && !defined(MS_WINDOWS) | ||||||
| #define USE_GETHOSTBYNAME_LOCK | # define USE_GETHOSTBYNAME_LOCK | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef USE_GETHOSTBYNAME_LOCK | #ifdef USE_GETHOSTBYNAME_LOCK | ||||||
| #include "pythread.h" | # include "pythread.h" | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if defined(PYCC_VACPP) | #if defined(PYCC_VACPP) | ||||||
| #include <types.h> | # include <types.h> | ||||||
| #include <io.h> | # include <io.h> | ||||||
| #include <sys/ioctl.h> | # include <sys/ioctl.h> | ||||||
| #include <utils.h> | # include <utils.h> | ||||||
| #include <ctype.h> | # include <ctype.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if defined(PYOS_OS2) | #if defined(PYOS_OS2) | ||||||
| #define  INCL_DOS | # define  INCL_DOS | ||||||
| #define  INCL_DOSERRORS | # define  INCL_DOSERRORS | ||||||
| #define  INCL_NOPMAPI | # define  INCL_NOPMAPI | ||||||
| #include <os2.h> | # include <os2.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 
 | /* Generic includes */ | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| 
 |  | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
|  | 
 | ||||||
|  | /* Generic _socket.h definitions and includes */ | ||||||
|  | #define PySocket_BUILDING_SOCKET | ||||||
|  | #include "_socket.h" | ||||||
|  | 
 | ||||||
|  | /* Addressing includes */ | ||||||
|  | 
 | ||||||
| #ifndef MS_WINDOWS | #ifndef MS_WINDOWS | ||||||
| #include <netdb.h> | 
 | ||||||
| #include <sys/socket.h> | /* Non-MS WINDOWS includes */ | ||||||
| #include <netinet/in.h> | # include <netdb.h> | ||||||
| #if !(defined(__BEOS__) || defined(__CYGWIN__) || (defined(PYOS_OS2) && defined(PYCC_VACPP))) |  | ||||||
| #include <netinet/tcp.h> |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| /* Headers needed for inet_ntoa() and inet_addr() */ | /* Headers needed for inet_ntoa() and inet_addr() */ | ||||||
| #ifdef __BEOS__ | # ifdef __BEOS__ | ||||||
| #include <net/netdb.h> | #  include <net/netdb.h> | ||||||
| #elif defined(PYOS_OS2) && defined(PYCC_VACPP) | # elif defined(PYOS_OS2) && defined(PYCC_VACPP) | ||||||
| #include <netdb.h> | #  include <netdb.h> | ||||||
| typedef size_t socklen_t; | typedef size_t socklen_t; | ||||||
| #else | # else | ||||||
| #ifndef USE_GUSI1 | #  ifndef USE_GUSI1 | ||||||
| #include <arpa/inet.h> | #   include <arpa/inet.h> | ||||||
| #endif | #  endif | ||||||
| #endif | # endif | ||||||
| 
 | 
 | ||||||
| #ifndef RISCOS | # ifndef RISCOS | ||||||
| #include <fcntl.h> | #  include <fcntl.h> | ||||||
| #else | # else | ||||||
| #include <sys/fcntl.h> | #  include <sys/fcntl.h> | ||||||
| #define NO_DUP | #  define NO_DUP | ||||||
| int h_errno; /* not used */ | int h_errno; /* not used */ | ||||||
| #endif | # endif | ||||||
|  | 
 | ||||||
| #else | #else | ||||||
| #include <winsock.h> |  | ||||||
| #include <fcntl.h> |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|  | /* MS_WINDOWS includes */ | ||||||
|  | # include <fcntl.h> | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_SYS_UN_H |  | ||||||
| #include <sys/un.h> |  | ||||||
| #else |  | ||||||
| #undef AF_UNIX |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef HAVE_NETPACKET_PACKET_H |  | ||||||
| #include <sys/ioctl.h> |  | ||||||
| #include <net/if.h> |  | ||||||
| #include <netpacket/packet.h> |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_STDDEF_H | #ifdef HAVE_STDDEF_H | ||||||
| #include <stddef.h> | # include <stddef.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifndef offsetof | #ifndef offsetof | ||||||
| #define offsetof(type, member)	((size_t)(&((type *)0)->member)) | # define offsetof(type, member)	((size_t)(&((type *)0)->member)) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifndef O_NDELAY | #ifndef O_NDELAY | ||||||
| #define O_NDELAY O_NONBLOCK	/* For QNX only? */ | # define O_NDELAY O_NONBLOCK	/* For QNX only? */ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef USE_GUSI1 | #ifdef USE_GUSI1 | ||||||
| /* fdopen() isn't declared in stdio.h (sigh) */ | /* fdopen() isn't declared in stdio.h (sigh) */ | ||||||
| #include <GUSI.h> | # include <GUSI.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include "addrinfo.h" | #include "addrinfo.h" | ||||||
| 
 | 
 | ||||||
| #ifdef USE_SSL |  | ||||||
| #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" |  | ||||||
| #endif /* USE_SSL */ |  | ||||||
| 
 |  | ||||||
| #ifndef HAVE_INET_PTON | #ifndef HAVE_INET_PTON | ||||||
| int inet_pton (int af, const char *src, void *dst); | int inet_pton (int af, const char *src, void *dst); | ||||||
| const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); | const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); | ||||||
|  | @ -242,19 +222,6 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); | ||||||
| #define NO_DUP /* Actually it exists on NT 3.5, but what the heck... */ | #define NO_DUP /* Actually it exists on NT 3.5, but what the heck... */ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* abstract the socket file descriptor type */ |  | ||||||
| #ifdef MS_WINDOWS |  | ||||||
| typedef SOCKET SOCKET_T; |  | ||||||
| #	ifdef MS_WIN64 |  | ||||||
| #		define SIZEOF_SOCKET_T 8 |  | ||||||
| #	else |  | ||||||
| #		define SIZEOF_SOCKET_T 4 |  | ||||||
| #	endif |  | ||||||
| #else |  | ||||||
| typedef int SOCKET_T; |  | ||||||
| #	define SIZEOF_SOCKET_T SIZEOF_INT |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef MS_WIN32 | #ifdef MS_WIN32 | ||||||
| #	define EAFNOSUPPORT            WSAEAFNOSUPPORT | #	define EAFNOSUPPORT            WSAEAFNOSUPPORT | ||||||
| #	define snprintf _snprintf | #	define snprintf _snprintf | ||||||
|  | @ -269,7 +236,6 @@ typedef int SOCKET_T; | ||||||
| #define SOCKETCLOSE close | #define SOCKETCLOSE close | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /* XXX There's a problem here: *static* functions are not supposed to have
 | /* XXX There's a problem here: *static* functions are not supposed to have
 | ||||||
|    a Py prefix (or use CapitalizedWords).  Later... */ |    a Py prefix (or use CapitalizedWords).  Later... */ | ||||||
| 
 | 
 | ||||||
|  | @ -280,11 +246,6 @@ static PyObject *PySocket_Error; | ||||||
| static PyObject *PyH_Error; | static PyObject *PyH_Error; | ||||||
| static PyObject *PyGAI_Error; | static PyObject *PyGAI_Error; | ||||||
| 
 | 
 | ||||||
| #ifdef USE_SSL |  | ||||||
| static PyObject *PySSLErrorObject; |  | ||||||
| #endif /* USE_SSL */ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #ifdef RISCOS | #ifdef RISCOS | ||||||
| /* Global variable which is !=0 if Python is running in a RISC OS taskwindow */ | /* Global variable which is !=0 if Python is running in a RISC OS taskwindow */ | ||||||
| static int taskwindow; | static int taskwindow; | ||||||
|  | @ -459,64 +420,6 @@ PyGAI_Err(int error) | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /* The object holding a socket.  It holds some extra information,
 |  | ||||||
|    like the address family, which is used to decode socket address |  | ||||||
|    arguments properly. */ |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
| 	PyObject_HEAD |  | ||||||
| 	SOCKET_T sock_fd;	/* Socket file descriptor */ |  | ||||||
| 	int sock_family;	/* Address family, e.g., AF_INET */ |  | ||||||
| 	int sock_type;		/* Socket type, e.g., SOCK_STREAM */ |  | ||||||
| 	int sock_proto;		/* Protocol type, usually 0 */ |  | ||||||
| 	union sock_addr { |  | ||||||
| 		struct sockaddr_in in; |  | ||||||
| #ifdef AF_UNIX |  | ||||||
| 		struct sockaddr_un un; |  | ||||||
| #endif |  | ||||||
| #ifdef ENABLE_IPV6 |  | ||||||
| 		struct sockaddr_in6 in6; |  | ||||||
| 		struct sockaddr_storage storage; |  | ||||||
| #endif |  | ||||||
| #ifdef HAVE_NETPACKET_PACKET_H |  | ||||||
| 		struct sockaddr_ll ll; |  | ||||||
| #endif |  | ||||||
| 	} sock_addr; |  | ||||||
| } PySocketSockObject; |  | ||||||
| 
 |  | ||||||
| #ifdef USE_SSL |  | ||||||
| 
 |  | ||||||
| #define X509_NAME_MAXLEN 256 |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
| 	PyObject_HEAD |  | ||||||
| 	PySocketSockObject *Socket;	/* Socket on which we're layered */ |  | ||||||
| 	SSL_CTX* 	ctx; |  | ||||||
| 	SSL*     	ssl; |  | ||||||
| 	X509*    	server_cert; |  | ||||||
| 	BIO*		sbio; |  | ||||||
| 	char    	server[X509_NAME_MAXLEN]; |  | ||||||
| 	char		issuer[X509_NAME_MAXLEN]; |  | ||||||
| 
 |  | ||||||
| } PySSLObject; |  | ||||||
| 
 |  | ||||||
| staticforward PyTypeObject PySSL_Type; |  | ||||||
| staticforward PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); |  | ||||||
| staticforward PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); |  | ||||||
| 
 |  | ||||||
| #define PySSLObject_Check(v)	((v)->ob_type == &PySSL_Type) |  | ||||||
| 
 |  | ||||||
| #endif /* USE_SSL */ |  | ||||||
| 
 |  | ||||||
| /* A forward reference to the Socktype type object.
 |  | ||||||
|    The Socktype variable contains pointers to various functions, |  | ||||||
|    some of which call newsockobject(), which uses Socktype, so |  | ||||||
|    there has to be a circular reference. */ |  | ||||||
| 
 |  | ||||||
| staticforward PyTypeObject PySocketSock_Type; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* Initialize a new socket object. */ | /* Initialize a new socket object. */ | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
|  | @ -530,6 +433,7 @@ init_sockobject(PySocketSockObject *s, | ||||||
| 	s->sock_family = family; | 	s->sock_family = family; | ||||||
| 	s->sock_type = type; | 	s->sock_type = type; | ||||||
| 	s->sock_proto = proto; | 	s->sock_proto = proto; | ||||||
|  | 	s->errorhandler = &PySocket_Err; | ||||||
| #ifdef RISCOS | #ifdef RISCOS | ||||||
| 	if(taskwindow) { | 	if(taskwindow) { | ||||||
| 		socketioctl(s->sock_fd, 0x80046679, (u_long*)&block); | 		socketioctl(s->sock_fd, 0x80046679, (u_long*)&block); | ||||||
|  | @ -867,7 +771,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, | ||||||
| 		strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name)); | 		strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name)); | ||||||
| 		ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; | 		ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; | ||||||
| 		if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { | 		if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { | ||||||
| 			PySocket_Err(); | 		        s->errorhandler(); | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
| 		addr = &(s->sock_addr.ll); | 		addr = &(s->sock_addr.ll); | ||||||
|  | @ -964,7 +868,7 @@ PySocketSock_accept(PySocketSockObject *s) | ||||||
| #else | #else | ||||||
| 	if (newfd < 0) | 	if (newfd < 0) | ||||||
| #endif | #endif | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 
 | 
 | ||||||
| 	/* Create the new object with unspecified family,
 | 	/* Create the new object with unspecified family,
 | ||||||
| 	   to avoid calls to bind() etc. on it. */ | 	   to avoid calls to bind() etc. on it. */ | ||||||
|  | @ -1101,7 +1005,7 @@ PySocketSock_setsockopt(PySocketSockObject *s, PyObject *args) | ||||||
| 	} | 	} | ||||||
| 	res = setsockopt(s->sock_fd, level, optname, (void *)buf, buflen); | 	res = setsockopt(s->sock_fd, level, optname, (void *)buf, buflen); | ||||||
| 	if (res < 0) | 	if (res < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	Py_INCREF(Py_None); | 	Py_INCREF(Py_None); | ||||||
| 	return Py_None; | 	return Py_None; | ||||||
| } | } | ||||||
|  | @ -1143,7 +1047,7 @@ PySocketSock_getsockopt(PySocketSockObject *s, PyObject *args) | ||||||
| 		res = getsockopt(s->sock_fd, level, optname, | 		res = getsockopt(s->sock_fd, level, optname, | ||||||
| 				 (void *)&flag, &flagsize); | 				 (void *)&flag, &flagsize); | ||||||
| 		if (res < 0) | 		if (res < 0) | ||||||
| 			return PySocket_Err(); | 			return s->errorhandler(); | ||||||
| 		return PyInt_FromLong(flag); | 		return PyInt_FromLong(flag); | ||||||
| 	} | 	} | ||||||
| 	if (buflen <= 0 || buflen > 1024) { | 	if (buflen <= 0 || buflen > 1024) { | ||||||
|  | @ -1158,7 +1062,7 @@ PySocketSock_getsockopt(PySocketSockObject *s, PyObject *args) | ||||||
| 			 (void *)PyString_AS_STRING(buf), &buflen); | 			 (void *)PyString_AS_STRING(buf), &buflen); | ||||||
| 	if (res < 0) { | 	if (res < 0) { | ||||||
| 		Py_DECREF(buf); | 		Py_DECREF(buf); | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	} | 	} | ||||||
| 	_PyString_Resize(&buf, buflen); | 	_PyString_Resize(&buf, buflen); | ||||||
| 	return buf; | 	return buf; | ||||||
|  | @ -1188,7 +1092,7 @@ PySocketSock_bind(PySocketSockObject *s, PyObject *addro) | ||||||
| 	res = bind(s->sock_fd, addr, addrlen); | 	res = bind(s->sock_fd, addr, addrlen); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (res < 0) | 	if (res < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	Py_INCREF(Py_None); | 	Py_INCREF(Py_None); | ||||||
| 	return Py_None; | 	return Py_None; | ||||||
| } | } | ||||||
|  | @ -1241,7 +1145,7 @@ PySocketSock_connect(PySocketSockObject *s, PyObject *addro) | ||||||
| 	res = connect(s->sock_fd, addr, addrlen); | 	res = connect(s->sock_fd, addr, addrlen); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (res < 0) | 	if (res < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	Py_INCREF(Py_None); | 	Py_INCREF(Py_None); | ||||||
| 	return Py_None; | 	return Py_None; | ||||||
| } | } | ||||||
|  | @ -1313,7 +1217,7 @@ PySocketSock_dup(PySocketSockObject *s) | ||||||
| 
 | 
 | ||||||
| 	newfd = dup(s->sock_fd); | 	newfd = dup(s->sock_fd); | ||||||
| 	if (newfd < 0) | 	if (newfd < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	sock = (PyObject *) PySocketSock_New(newfd, | 	sock = (PyObject *) PySocketSock_New(newfd, | ||||||
| 					     s->sock_family, | 					     s->sock_family, | ||||||
| 					     s->sock_type, | 					     s->sock_type, | ||||||
|  | @ -1347,7 +1251,7 @@ PySocketSock_getsockname(PySocketSockObject *s) | ||||||
| 	res = getsockname(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen); | 	res = getsockname(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (res < 0) | 	if (res < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	return makesockaddr(s->sock_fd, (struct sockaddr *) addrbuf, addrlen); | 	return makesockaddr(s->sock_fd, (struct sockaddr *) addrbuf, addrlen); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1375,7 +1279,7 @@ PySocketSock_getpeername(PySocketSockObject *s) | ||||||
| 	res = getpeername(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen); | 	res = getpeername(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (res < 0) | 	if (res < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	return makesockaddr(s->sock_fd, (struct sockaddr *) addrbuf, addrlen); | 	return makesockaddr(s->sock_fd, (struct sockaddr *) addrbuf, addrlen); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1405,7 +1309,7 @@ PySocketSock_listen(PySocketSockObject *s, PyObject *arg) | ||||||
| 	res = listen(s->sock_fd, backlog); | 	res = listen(s->sock_fd, backlog); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (res < 0) | 	if (res < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	Py_INCREF(Py_None); | 	Py_INCREF(Py_None); | ||||||
| 	return Py_None; | 	return Py_None; | ||||||
| } | } | ||||||
|  | @ -1451,7 +1355,7 @@ PySocketSock_makefile(PySocketSockObject *s, PyObject *args) | ||||||
| 	{ | 	{ | ||||||
| 		if (fd >= 0) | 		if (fd >= 0) | ||||||
| 			SOCKETCLOSE(fd); | 			SOCKETCLOSE(fd); | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	} | 	} | ||||||
| 	f = PyFile_FromFile(fp, "<socket>", mode, fclose); | 	f = PyFile_FromFile(fp, "<socket>", mode, fclose); | ||||||
| 	if (f != NULL) | 	if (f != NULL) | ||||||
|  | @ -1490,7 +1394,7 @@ PySocketSock_recv(PySocketSockObject *s, PyObject *args) | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (n < 0) { | 	if (n < 0) { | ||||||
| 		Py_DECREF(buf); | 		Py_DECREF(buf); | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	} | 	} | ||||||
| 	if (n != len && _PyString_Resize(&buf, n) < 0) | 	if (n != len && _PyString_Resize(&buf, n) < 0) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -1541,7 +1445,7 @@ PySocketSock_recvfrom(PySocketSockObject *s, PyObject *args) | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (n < 0) { | 	if (n < 0) { | ||||||
| 		Py_DECREF(buf); | 		Py_DECREF(buf); | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	} | 	} | ||||||
| 	if (n != len && _PyString_Resize(&buf, n) < 0) | 	if (n != len && _PyString_Resize(&buf, n) < 0) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -1575,7 +1479,7 @@ PySocketSock_send(PySocketSockObject *s, PyObject *args) | ||||||
| 	n = send(s->sock_fd, buf, len, flags); | 	n = send(s->sock_fd, buf, len, flags); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (n < 0) | 	if (n < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	return PyInt_FromLong((long)n); | 	return PyInt_FromLong((long)n); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1607,7 +1511,7 @@ PySocketSock_sendall(PySocketSockObject *s, PyObject *args) | ||||||
| 	} while (len > 0); | 	} while (len > 0); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (n < 0) | 	if (n < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	Py_INCREF(Py_None); | 	Py_INCREF(Py_None); | ||||||
| 	return Py_None; | 	return Py_None; | ||||||
| } | } | ||||||
|  | @ -1643,7 +1547,7 @@ PySocketSock_sendto(PySocketSockObject *s, PyObject *args) | ||||||
| 	n = sendto(s->sock_fd, buf, len, flags, addr, addrlen); | 	n = sendto(s->sock_fd, buf, len, flags, addr, addrlen); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (n < 0) | 	if (n < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	return PyInt_FromLong((long)n); | 	return PyInt_FromLong((long)n); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1669,7 +1573,7 @@ PySocketSock_shutdown(PySocketSockObject *s, PyObject *arg) | ||||||
| 	res = shutdown(s->sock_fd, how); | 	res = shutdown(s->sock_fd, how); | ||||||
| 	Py_END_ALLOW_THREADS | 	Py_END_ALLOW_THREADS | ||||||
| 	if (res < 0) | 	if (res < 0) | ||||||
| 		return PySocket_Err(); | 		return s->errorhandler(); | ||||||
| 	Py_INCREF(Py_None); | 	Py_INCREF(Py_None); | ||||||
| 	return Py_None; | 	return Py_None; | ||||||
| } | } | ||||||
|  | @ -2614,351 +2518,6 @@ static char getnameinfo_doc[] = | ||||||
| \n\ | \n\ | ||||||
| Get host and port for a sockaddr."; | Get host and port for a sockaddr."; | ||||||
| 
 | 
 | ||||||
| /* 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. |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #ifdef USE_SSL |  | ||||||
| static PyObject * |  | ||||||
| PySSL_SetError(SSL *ssl, int ret) |  | ||||||
| { |  | ||||||
| 	PyObject *v, *n, *s; |  | ||||||
| 	char *errstr; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	assert(ret <= 0); |  | ||||||
|      |  | ||||||
| 	err = SSL_get_error(ssl, ret); |  | ||||||
| 	n = PyInt_FromLong(err); |  | ||||||
| 	if (n == NULL) |  | ||||||
| 		return NULL; |  | ||||||
| 	v = PyTuple_New(2); |  | ||||||
| 	if (v == NULL) { |  | ||||||
| 		Py_DECREF(n); |  | ||||||
| 		return NULL; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	switch (SSL_get_error(ssl, ret)) { |  | ||||||
| 	case SSL_ERROR_ZERO_RETURN: |  | ||||||
| 		errstr = "TLS/SSL connection has been closed"; |  | ||||||
| 		break; |  | ||||||
| 	case SSL_ERROR_WANT_READ: |  | ||||||
| 		errstr = "The operation did not complete (read)"; |  | ||||||
| 		break; |  | ||||||
| 	case SSL_ERROR_WANT_WRITE: |  | ||||||
| 		errstr = "The operation did not complete (write)"; |  | ||||||
| 		break; |  | ||||||
| 	case SSL_ERROR_WANT_X509_LOOKUP: |  | ||||||
| 		errstr = "The operation did not complete (X509 lookup)"; |  | ||||||
| 		break; |  | ||||||
| 	case SSL_ERROR_SYSCALL: |  | ||||||
| 	case SSL_ERROR_SSL: |  | ||||||
| 	{ |  | ||||||
| 		unsigned long e = ERR_get_error(); |  | ||||||
| 		if (e == 0) { |  | ||||||
| 			/* an EOF was observed that violates the protocol */ |  | ||||||
| 			errstr = "EOF occurred in violation of protocol"; |  | ||||||
| 		} else if (e == -1) { |  | ||||||
| 			/* the underlying BIO reported an I/O error */ |  | ||||||
| 			Py_DECREF(v); |  | ||||||
| 			Py_DECREF(n); |  | ||||||
| 			return PySocket_Err(); |  | ||||||
| 		} else { |  | ||||||
| 			/* XXX Protected by global interpreter lock */ |  | ||||||
| 			errstr = ERR_error_string(e, NULL); |  | ||||||
| 		} |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 	default: |  | ||||||
| 		errstr = "Invalid error code"; |  | ||||||
| 	} |  | ||||||
| 	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); |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* This is a C function to be called for new object initialization */ |  | ||||||
| static PySSLObject * |  | ||||||
| newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file) |  | ||||||
| { |  | ||||||
| 	PySSLObject *self; |  | ||||||
| 	char *errstr = NULL; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ |  | ||||||
| 	if (self == NULL){ |  | ||||||
| 		errstr = "newPySSLObject error"; |  | ||||||
| 		goto fail; |  | ||||||
| 	} |  | ||||||
| 	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; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ |  | ||||||
| 	if (self->ctx == NULL) { |  | ||||||
| 		errstr = "SSL_CTX_new error"; |  | ||||||
| 		goto fail; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (key_file) { |  | ||||||
| 		if (SSL_CTX_use_PrivateKey_file(self->ctx, key_file, |  | ||||||
| 						SSL_FILETYPE_PEM) < 1) { |  | ||||||
| 			errstr = "SSL_CTX_use_PrivateKey_file error"; |  | ||||||
| 			goto fail; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SSL_CTX_use_certificate_chain_file(self->ctx, |  | ||||||
| 						       cert_file) < 1) { |  | ||||||
| 			errstr = "SSL_CTX_use_certificate_chain_file error"; |  | ||||||
| 			goto fail; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	SSL_CTX_set_verify(self->ctx, |  | ||||||
| 			   SSL_VERIFY_NONE, NULL); /* set verify lvl */ |  | ||||||
| 	self->ssl = SSL_new(self->ctx); /* New ssl struct */ |  | ||||||
| 	SSL_set_fd(self->ssl, Sock->sock_fd);	/* Set the socket for SSL */ |  | ||||||
| 	SSL_set_connect_state(self->ssl); |  | ||||||
| 
 |  | ||||||
| 	/* Actually negotiate SSL connection */ |  | ||||||
| 	/* XXX If SSL_connect() returns 0, it's also a failure. */ |  | ||||||
| 	ret = SSL_connect(self->ssl); |  | ||||||
| 	if (ret <= 0) { |  | ||||||
| 		PySSL_SetError(self->ssl, ret); |  | ||||||
| 		goto fail; |  | ||||||
| 	} |  | ||||||
| 	self->ssl->debug = 1; |  | ||||||
| 
 |  | ||||||
| 	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); |  | ||||||
| 	} |  | ||||||
| 	self->Socket = Sock; |  | ||||||
| 	Py_INCREF(self->Socket); |  | ||||||
| 	return self; |  | ||||||
|  fail: |  | ||||||
| 	if (errstr) |  | ||||||
| 		PyErr_SetString(PySSLErrorObject, errstr); |  | ||||||
| 	Py_DECREF(self); |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* This is the Python function called for new object initialization */ |  | ||||||
| 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", |  | ||||||
| 			      &PySocketSock_Type, (PyObject*)&Sock, |  | ||||||
| 			      &key_file, &cert_file)) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	rv = newPySSLObject(Sock, key_file, cert_file); |  | ||||||
| 	if (rv == NULL) |  | ||||||
| 		return NULL; |  | ||||||
| 	return (PyObject *)rv; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static char 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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) |  | ||||||
| { |  | ||||||
| 	char *data; |  | ||||||
| 	int len; |  | ||||||
| 
 |  | ||||||
| 	if (!PyArg_ParseTuple(args, "s#:write", &data, &len)) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	Py_BEGIN_ALLOW_THREADS |  | ||||||
| 	len = SSL_write(self->ssl, data, len); |  | ||||||
| 	Py_END_ALLOW_THREADS |  | ||||||
| 	if (len > 0) |  | ||||||
| 		return PyInt_FromLong(len); |  | ||||||
| 	else |  | ||||||
| 		return PySSL_SetError(self->ssl, len); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static char 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; |  | ||||||
| 
 |  | ||||||
| 	if (!PyArg_ParseTuple(args, "|i:read", &len)) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	if (!(buf = PyString_FromStringAndSize((char *) 0, len))) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	Py_BEGIN_ALLOW_THREADS |  | ||||||
| 	count = SSL_read(self->ssl, PyString_AsString(buf), len); |  | ||||||
| 	Py_END_ALLOW_THREADS |  | ||||||
|  	if (count <= 0) { |  | ||||||
| 		Py_DECREF(buf); |  | ||||||
| 		return PySSL_SetError(self->ssl, count); |  | ||||||
| 	} |  | ||||||
| 	if (count != len && _PyString_Resize(&buf, count) < 0) |  | ||||||
| 		return NULL; |  | ||||||
| 	return buf; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static char 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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| staticforward 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*/ |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /* 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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static char 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()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static char 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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static char 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 /* USE_SSL */ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* List of functions exported by this module. */ | /* List of functions exported by this module. */ | ||||||
| 
 | 
 | ||||||
| static PyMethodDef PySocket_methods[] = { | static PyMethodDef PySocket_methods[] = { | ||||||
|  | @ -2994,16 +2553,6 @@ static PyMethodDef PySocket_methods[] = { | ||||||
| 	 METH_VARARGS, getaddrinfo_doc}, | 	 METH_VARARGS, getaddrinfo_doc}, | ||||||
| 	{"getnameinfo",		PySocket_getnameinfo, | 	{"getnameinfo",		PySocket_getnameinfo, | ||||||
| 	 METH_VARARGS, getnameinfo_doc}, | 	 METH_VARARGS, getnameinfo_doc}, | ||||||
| #ifdef USE_SSL |  | ||||||
| 	{"ssl",			PySocket_ssl, |  | ||||||
| 	 METH_VARARGS, ssl_doc}, |  | ||||||
| 	{"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 /* USE_SSL */ |  | ||||||
| 	{NULL,			NULL}		 /* Sentinel */ | 	{NULL,			NULL}		 /* Sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -3094,6 +2643,14 @@ OS2init(void) | ||||||
| 
 | 
 | ||||||
| #endif /* PYOS_OS2 */ | #endif /* PYOS_OS2 */ | ||||||
| 
 | 
 | ||||||
|  | /* C API table - always add new things to the end for binary
 | ||||||
|  |    compatibility. */ | ||||||
|  | static | ||||||
|  | PySocketModule_APIObject PySocketModuleAPI = | ||||||
|  | { | ||||||
|  |     &PySocketSock_Type, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /* Initialize this module.
 | /* Initialize this module.
 | ||||||
|  *   This is called when the first 'import socket' is done, |  *   This is called when the first 'import socket' is done, | ||||||
|  *   via a table in config.c, if config.c is compiled with USE_SOCKET |  *   via a table in config.c, if config.c is compiled with USE_SOCKET | ||||||
|  | @ -3141,10 +2698,9 @@ init_socket(void) | ||||||
| 	PySocketSock_Type.tp_getattro = PyObject_GenericGetAttr; | 	PySocketSock_Type.tp_getattro = PyObject_GenericGetAttr; | ||||||
| 	PySocketSock_Type.tp_alloc = PyType_GenericAlloc; | 	PySocketSock_Type.tp_alloc = PyType_GenericAlloc; | ||||||
| 	PySocketSock_Type.tp_free = _PyObject_Del; | 	PySocketSock_Type.tp_free = _PyObject_Del; | ||||||
| #ifdef USE_SSL | 	m = Py_InitModule3(PySocket_MODULE_NAME,  | ||||||
| 	PySSL_Type.ob_type = &PyType_Type; | 			   PySocket_methods,  | ||||||
| #endif | 			   module_doc); | ||||||
| 	m = Py_InitModule3("_socket", PySocket_methods, module_doc); |  | ||||||
| 	d = PyModule_GetDict(m); | 	d = PyModule_GetDict(m); | ||||||
| 	PySocket_Error = PyErr_NewException("socket.error", NULL, NULL); | 	PySocket_Error = PyErr_NewException("socket.error", NULL, NULL); | ||||||
| 	if (PySocket_Error == NULL) | 	if (PySocket_Error == NULL) | ||||||
|  | @ -3159,29 +2715,6 @@ init_socket(void) | ||||||
| 	if (PyGAI_Error == NULL) | 	if (PyGAI_Error == NULL) | ||||||
| 		return; | 		return; | ||||||
| 	PyDict_SetItemString(d, "gaierror", PyGAI_Error); | 	PyDict_SetItemString(d, "gaierror", PyGAI_Error); | ||||||
| #ifdef USE_SSL |  | ||||||
| 	SSL_load_error_strings(); |  | ||||||
| 	SSLeay_add_ssl_algorithms(); |  | ||||||
| 	PySSLErrorObject = PyErr_NewException("socket.sslerror", NULL, 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", |  | ||||||
| 				SSL_ERROR_ZERO_RETURN); |  | ||||||
| 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ", |  | ||||||
| 				SSL_ERROR_WANT_READ); |  | ||||||
| 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE", |  | ||||||
| 				SSL_ERROR_WANT_WRITE); |  | ||||||
| 	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP", |  | ||||||
| 				SSL_ERROR_WANT_X509_LOOKUP); |  | ||||||
| 	PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL", |  | ||||||
| 				SSL_ERROR_SYSCALL); |  | ||||||
| 	PyModule_AddIntConstant(m, "SSL_ERROR_SSL", |  | ||||||
| 				SSL_ERROR_SSL); |  | ||||||
| #endif /* USE_SSL */ |  | ||||||
| 	if (PyDict_SetItemString(d, "SocketType", | 	if (PyDict_SetItemString(d, "SocketType", | ||||||
| 				 (PyObject *)&PySocketSock_Type) != 0) | 				 (PyObject *)&PySocketSock_Type) != 0) | ||||||
| 		return; | 		return; | ||||||
|  | @ -3189,6 +2722,12 @@ init_socket(void) | ||||||
| 				 (PyObject *)&PySocketSock_Type) != 0) | 				 (PyObject *)&PySocketSock_Type) != 0) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	/* Export C API */ | ||||||
|  | 	if (PyDict_SetItemString(d, PySocket_CAPI_NAME, | ||||||
|  | 	       PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL) | ||||||
|  | 				 ) != 0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	/* Address families (we only support AF_INET and AF_UNIX) */ | 	/* Address families (we only support AF_INET and AF_UNIX) */ | ||||||
| #ifdef AF_UNSPEC | #ifdef AF_UNSPEC | ||||||
| 	insint(d, "AF_UNSPEC", AF_UNSPEC); | 	insint(d, "AF_UNSPEC", AF_UNSPEC); | ||||||
|  |  | ||||||
							
								
								
									
										159
									
								
								Modules/socketmodule.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								Modules/socketmodule.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,159 @@ | ||||||
|  | /* Socket module header file */ | ||||||
|  | 
 | ||||||
|  | /* Includes needed for the sockaddr_* symbols below */ | ||||||
|  | #ifndef MS_WINDOWS | ||||||
|  | # include <sys/socket.h> | ||||||
|  | # include <netinet/in.h> | ||||||
|  | # if !(defined(__BEOS__) || defined(__CYGWIN__) || (defined(PYOS_OS2) && defined(PYCC_VACPP))) | ||||||
|  | #  include <netinet/tcp.h> | ||||||
|  | # endif | ||||||
|  | 
 | ||||||
|  | #else /* MS_WINDOWS */ | ||||||
|  | # include <winsock.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef HAVE_SYS_UN_H | ||||||
|  | # include <sys/un.h> | ||||||
|  | #else | ||||||
|  | # undef AF_UNIX | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef HAVE_NETPACKET_PACKET_H | ||||||
|  | # include <sys/ioctl.h> | ||||||
|  | # include <net/if.h> | ||||||
|  | # include <netpacket/packet.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef Py__SOCKET_H | ||||||
|  | #define Py__SOCKET_H | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Python module and C API name */ | ||||||
|  | #define PySocket_MODULE_NAME	"_socket" | ||||||
|  | #define PySocket_CAPI_NAME	"CAPI" | ||||||
|  | 
 | ||||||
|  | /* Abstract the socket file descriptor type */ | ||||||
|  | #ifdef MS_WINDOWS | ||||||
|  | typedef SOCKET SOCKET_T; | ||||||
|  | #	ifdef MS_WIN64 | ||||||
|  | #		define SIZEOF_SOCKET_T 8 | ||||||
|  | #	else | ||||||
|  | #		define SIZEOF_SOCKET_T 4 | ||||||
|  | #	endif | ||||||
|  | #else | ||||||
|  | typedef int SOCKET_T; | ||||||
|  | #	define SIZEOF_SOCKET_T SIZEOF_INT | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* The object holding a socket.  It holds some extra information,
 | ||||||
|  |    like the address family, which is used to decode socket address | ||||||
|  |    arguments properly. */ | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  | 	PyObject_HEAD | ||||||
|  | 	SOCKET_T sock_fd;	/* Socket file descriptor */ | ||||||
|  | 	int sock_family;	/* Address family, e.g., AF_INET */ | ||||||
|  | 	int sock_type;		/* Socket type, e.g., SOCK_STREAM */ | ||||||
|  | 	int sock_proto;		/* Protocol type, usually 0 */ | ||||||
|  | 	union sock_addr { | ||||||
|  | 		struct sockaddr_in in; | ||||||
|  | #ifdef AF_UNIX | ||||||
|  | 		struct sockaddr_un un; | ||||||
|  | #endif | ||||||
|  | #ifdef ENABLE_IPV6 | ||||||
|  | 		struct sockaddr_in6 in6; | ||||||
|  | 		struct sockaddr_storage storage; | ||||||
|  | #endif | ||||||
|  | #ifdef HAVE_NETPACKET_PACKET_H | ||||||
|  | 		struct sockaddr_ll ll; | ||||||
|  | #endif | ||||||
|  | 	} sock_addr; | ||||||
|  |     	PyObject *(*errorhandler)(void); /* Error handler; checks
 | ||||||
|  | 					    errno, returns NULL and | ||||||
|  | 					    sets a Python exception */ | ||||||
|  | } PySocketSockObject; | ||||||
|  | 
 | ||||||
|  | /* A forward reference to the Socktype type object.
 | ||||||
|  |    The Socktype variable contains pointers to various functions, | ||||||
|  |    some of which call newsockobject(), which uses Socktype, so | ||||||
|  |    there has to be a circular reference. */ | ||||||
|  | 
 | ||||||
|  | extern DL_IMPORT(PyTypeObject) PySocketSock_Type; | ||||||
|  | 
 | ||||||
|  | /* --- C API ----------------------------------------------------*/ | ||||||
|  | 
 | ||||||
|  | /* C API for usage by other Python modules */ | ||||||
|  | typedef struct { | ||||||
|  | 	  | ||||||
|  |     PyTypeObject *Sock_Type; | ||||||
|  | 
 | ||||||
|  | } PySocketModule_APIObject; | ||||||
|  |      | ||||||
|  | #ifndef PySocket_BUILDING_SOCKET | ||||||
|  | 
 | ||||||
|  | /* --- C API ----------------------------------------------------*/ | ||||||
|  | 
 | ||||||
|  | /* Interfacestructure to C API for other modules.
 | ||||||
|  |    Call PySocket_ImportModuleAPI() to initialize this | ||||||
|  |    structure. After that usage is simple: | ||||||
|  | 
 | ||||||
|  |    if (!PyArg_ParseTuple(args, "O!|zz:ssl", | ||||||
|  |                          &PySocketModule.Sock_Type, (PyObject*)&Sock, | ||||||
|  | 	 		 &key_file, &cert_file)) | ||||||
|  |  	 return NULL; | ||||||
|  |    ... | ||||||
|  | 
 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | static  | ||||||
|  | PySocketModule_APIObject PySocketModule; | ||||||
|  | 
 | ||||||
|  | /* You *must* call this before using any of the functions in
 | ||||||
|  |    PySocketModule and check its outcome; otherwise all accesses will | ||||||
|  |    result in a segfault. Returns 0 on success. */ | ||||||
|  | 
 | ||||||
|  | #ifndef DPRINTF | ||||||
|  | # define DPRINTF if (0) printf | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static | ||||||
|  | int PySocketModule_ImportModuleAndAPI(void) | ||||||
|  | { | ||||||
|  |     PyObject *mod = 0, *v = 0; | ||||||
|  |     char *apimodule = PySocket_MODULE_NAME; | ||||||
|  |     char *apiname = PySocket_CAPI_NAME; | ||||||
|  |     void *api; | ||||||
|  |      | ||||||
|  |     DPRINTF("Importing the %s C API...\n",apimodule); | ||||||
|  |     mod = PyImport_ImportModule(apimodule); | ||||||
|  |     if (mod == NULL) | ||||||
|  | 	goto onError; | ||||||
|  |     DPRINTF(" %s package found\n",apimodule); | ||||||
|  |     v = PyObject_GetAttrString(mod,apiname); | ||||||
|  |     if (v == NULL) | ||||||
|  | 	goto onError; | ||||||
|  |     Py_DECREF(mod); | ||||||
|  |     DPRINTF(" API object %s found\n",apiname); | ||||||
|  |     api = PyCObject_AsVoidPtr(v); | ||||||
|  |     if (api == NULL) | ||||||
|  | 	goto onError; | ||||||
|  |     Py_DECREF(v); | ||||||
|  |     memcpy(&PySocketModule, api, sizeof(PySocketModule)); | ||||||
|  |     DPRINTF(" API object loaded and initialized.\n"); | ||||||
|  |     return 0; | ||||||
|  |      | ||||||
|  |  onError: | ||||||
|  |     DPRINTF(" not found.\n"); | ||||||
|  |     Py_XDECREF(mod); | ||||||
|  |     Py_XDECREF(v); | ||||||
|  |     return -1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #endif /* !Py__SOCKET_H */ | ||||||
							
								
								
									
										43
									
								
								setup.py
									
										
									
									
									
								
							
							
						
						
									
										43
									
								
								setup.py
									
										
									
									
									
								
							|  | @ -173,21 +173,26 @@ def build_extension(self, ext): | ||||||
|             self.get_ext_filename(self.get_ext_fullname(ext.name))) |             self.get_ext_filename(self.get_ext_fullname(ext.name))) | ||||||
|         try: |         try: | ||||||
|             imp.load_dynamic(ext.name, ext_filename) |             imp.load_dynamic(ext.name, ext_filename) | ||||||
|         except ImportError: |         except ImportError, why: | ||||||
|             self.announce('WARNING: removing "%s" since importing it failed' % |  | ||||||
|                           ext.name) |  | ||||||
|             assert not self.inplace |  | ||||||
|             fullname = self.get_ext_fullname(ext.name) |  | ||||||
|             ext_filename = os.path.join(self.build_lib, |  | ||||||
|                                         self.get_ext_filename(fullname)) |  | ||||||
|             os.remove(ext_filename) |  | ||||||
| 
 | 
 | ||||||
|             # XXX -- This relies on a Vile HACK in |             if 1: | ||||||
|             # distutils.command.build_ext.build_extension().  The |                 self.announce('*** WARNING: removing "%s" since importing it' | ||||||
|             # _built_objects attribute is stored there strictly for |                               ' failed: %s' % (ext.name, why)) | ||||||
|             # use here. |                 assert not self.inplace | ||||||
|             for filename in self._built_objects: |                 fullname = self.get_ext_fullname(ext.name) | ||||||
|                 os.remove(filename) |                 ext_filename = os.path.join(self.build_lib, | ||||||
|  |                                             self.get_ext_filename(fullname)) | ||||||
|  |                 os.remove(ext_filename) | ||||||
|  | 
 | ||||||
|  |                 # XXX -- This relies on a Vile HACK in | ||||||
|  |                 # distutils.command.build_ext.build_extension().  The | ||||||
|  |                 # _built_objects attribute is stored there strictly for | ||||||
|  |                 # use here. | ||||||
|  |                 for filename in self._built_objects: | ||||||
|  |                     os.remove(filename) | ||||||
|  |             else: | ||||||
|  |                 self.announce('*** WARNING: importing extension "%s" ' | ||||||
|  |                               'failed: %s' % (ext.name, why)) | ||||||
| 
 | 
 | ||||||
|     def get_platform (self): |     def get_platform (self): | ||||||
|         # Get value of sys.platform |         # Get value of sys.platform | ||||||
|  | @ -359,7 +364,8 @@ def detect_modules(self): | ||||||
|         exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) ) |         exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) ) | ||||||
| 
 | 
 | ||||||
|         # socket(2) |         # socket(2) | ||||||
|         # Detect SSL support for the socket module |         exts.append( Extension('_socket', ['socketmodule.c']) ) | ||||||
|  |         # Detect SSL support for the socket module (via _ssl) | ||||||
|         ssl_incs = find_file('openssl/ssl.h', inc_dirs, |         ssl_incs = find_file('openssl/ssl.h', inc_dirs, | ||||||
|                              ['/usr/local/ssl/include', |                              ['/usr/local/ssl/include', | ||||||
|                               '/usr/contrib/ssl/include/' |                               '/usr/contrib/ssl/include/' | ||||||
|  | @ -372,13 +378,10 @@ def detect_modules(self): | ||||||
| 
 | 
 | ||||||
|         if (ssl_incs is not None and |         if (ssl_incs is not None and | ||||||
|             ssl_libs is not None): |             ssl_libs is not None): | ||||||
|             exts.append( Extension('_socket', ['socketmodule.c'], |             exts.append( Extension('_ssl', ['_ssl.c'], | ||||||
|                                    include_dirs = ssl_incs, |                                    include_dirs = ssl_incs, | ||||||
|                                    library_dirs = ssl_libs, |                                    library_dirs = ssl_libs, | ||||||
|                                    libraries = ['ssl', 'crypto'], |                                    libraries = ['ssl', 'crypto']) ) | ||||||
|                                    define_macros = [('USE_SSL',1)] ) ) |  | ||||||
|         else: |  | ||||||
|             exts.append( Extension('_socket', ['socketmodule.c']) ) |  | ||||||
| 
 | 
 | ||||||
|         # Modules that provide persistent dictionary-like semantics.  You will |         # Modules that provide persistent dictionary-like semantics.  You will | ||||||
|         # probably want to arrange for at least one of them to be available on |         # probably want to arrange for at least one of them to be available on | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Marc-André Lemburg
						Marc-André Lemburg