plugins/ssl/ssl-nss.c

changeset 14253
b63ebf84c42b
parent 14252
d10dda2777a9
child 14254
77edc7a6191a
--- a/plugins/ssl/ssl-nss.c	Sat Aug 19 00:24:14 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,433 +0,0 @@
-/**
- * @file ssl-nss.c Mozilla NSS SSL plugin.
- *
- * gaim
- *
- * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include "internal.h"
-#include "debug.h"
-#include "plugin.h"
-#include "sslconn.h"
-#include "version.h"
-
-#define SSL_NSS_PLUGIN_ID "ssl-nss"
-
-#ifdef HAVE_NSS
-
-#undef HAVE_LONG_LONG /* Make Mozilla less angry. If angry, Mozilla SMASH! */
-
-#include <nspr.h>
-#include <private/pprio.h>
-#include <nss.h>
-#include <pk11func.h>
-#include <prio.h>
-#include <secerr.h>
-#include <secmod.h>
-#include <ssl.h>
-#include <sslerr.h>
-#include <sslproto.h>
-
-typedef struct
-{
-	PRFileDesc *fd;
-	PRFileDesc *in;
-	guint handshake_handler;
-
-} GaimSslNssData;
-
-#define GAIM_SSL_NSS_DATA(gsc) ((GaimSslNssData *)gsc->private_data)
-
-static const PRIOMethods *_nss_methods = NULL;
-static PRDescIdentity _identity;
-
-/* Thank you, Evolution */
-static void
-set_errno(int code)
-{
-	/* FIXME: this should handle more. */
-	switch (code) {
-	case PR_INVALID_ARGUMENT_ERROR:
-		errno = EINVAL;
-		break;
-	case PR_PENDING_INTERRUPT_ERROR:
-		errno = EINTR;
-		break;
-	case PR_IO_PENDING_ERROR:
-		errno = EAGAIN;
-		break;
-	case PR_WOULD_BLOCK_ERROR:
-		errno = EAGAIN;
-		/*errno = EWOULDBLOCK; */
-		break;
-	case PR_IN_PROGRESS_ERROR:
-		errno = EINPROGRESS;
-		break;
-	case PR_ALREADY_INITIATED_ERROR:
-		errno = EALREADY;
-		break;
-	case PR_NETWORK_UNREACHABLE_ERROR:
-		errno = EHOSTUNREACH;
-		break;
-	case PR_CONNECT_REFUSED_ERROR:
-		errno = ECONNREFUSED;
-		break;
-	case PR_CONNECT_TIMEOUT_ERROR:
-	case PR_IO_TIMEOUT_ERROR:
-		errno = ETIMEDOUT;
-		break;
-	case PR_NOT_CONNECTED_ERROR:
-		errno = ENOTCONN;
-		break;
-	case PR_CONNECT_RESET_ERROR:
-		errno = ECONNRESET;
-		break;
-	case PR_IO_ERROR:
-	default:
-		errno = EIO;
-		break;
-	}
-}
-
-static void
-ssl_nss_init_nss(void)
-{
-	char *lib;
-	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
-	NSS_NoDB_Init(NULL);
-
-	/* TODO: Fix this so autoconf does the work trying to find this lib. */
-#ifndef _WIN32
-	lib = g_strdup(BR_LIBDIR("/libnssckbi.so"));
-#else
-	lib = g_strdup("nssckbi.dll");
-#endif
-	SECMOD_AddNewModule("Builtins", lib, 0, 0);
-	g_free(lib);
-	NSS_SetDomesticPolicy();
-
-	_identity = PR_GetUniqueIdentity("Gaim");
-	_nss_methods = PR_GetDefaultIOMethods();
-}
-
-static SECStatus
-ssl_auth_cert(void *arg, PRFileDesc *socket, PRBool checksig,
-			  PRBool is_server)
-{
-	return SECSuccess;
-
-#if 0
-	CERTCertificate *cert;
-	void *pinArg;
-	SECStatus status;
-
-	cert = SSL_PeerCertificate(socket);
-	pinArg = SSL_RevealPinArg(socket);
-
-	status = CERT_VerifyCertNow((CERTCertDBHandle *)arg, cert, checksig,
-								certUsageSSLClient, pinArg);
-
-	if (status != SECSuccess) {
-		gaim_debug_error("nss", "CERT_VerifyCertNow failed\n");
-		CERT_DestroyCertificate(cert);
-		return status;
-	}
-
-	CERT_DestroyCertificate(cert);
-	return SECSuccess;
-#endif
-}
-
-static SECStatus
-ssl_bad_cert(void *arg, PRFileDesc *socket)
-{
-	SECStatus status = SECFailure;
-	PRErrorCode err;
-
-	if (arg == NULL)
-		return status;
-
-	*(PRErrorCode *)arg = err = PORT_GetError();
-
-	switch (err)
-	{
-		case SEC_ERROR_INVALID_AVA:
-		case SEC_ERROR_INVALID_TIME:
-		case SEC_ERROR_BAD_SIGNATURE:
-		case SEC_ERROR_EXPIRED_CERTIFICATE:
-		case SEC_ERROR_UNKNOWN_ISSUER:
-		case SEC_ERROR_UNTRUSTED_CERT:
-		case SEC_ERROR_CERT_VALID:
-		case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
-		case SEC_ERROR_CRL_EXPIRED:
-		case SEC_ERROR_CRL_BAD_SIGNATURE:
-		case SEC_ERROR_EXTENSION_VALUE_INVALID:
-		case SEC_ERROR_CA_CERT_INVALID:
-		case SEC_ERROR_CERT_USAGES_INVALID:
-		case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
-			status = SECSuccess;
-			break;
-
-		default:
-			status = SECFailure;
-			break;
-	}
-
-	gaim_debug_error("nss", "Bad certificate: %d\n", err);
-
-	return status;
-}
-
-static gboolean
-ssl_nss_init(void)
-{
-   return TRUE;
-}
-
-static void
-ssl_nss_uninit(void)
-{
-	PR_Cleanup();
-
-	_nss_methods = NULL;
-}
-
-static void
-ssl_nss_handshake_cb(gpointer data, int fd, GaimInputCondition cond)
-{
-	GaimSslConnection *gsc = (GaimSslConnection *)data;
-	GaimSslNssData *nss_data = gsc->private_data;
-
-	/* I don't think this the best way to do this...
-	 * It seems to work because it'll eventually use the cached value
-	 */
-	if(SSL_ForceHandshake(nss_data->in) != SECSuccess) {
-		set_errno(PR_GetError());
-		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			return;
-
-		gaim_debug_error("nss", "Handshake failed %d\n", PR_GetError());
-
-		if (gsc->error_cb != NULL)
-			gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data);
-
-		gaim_ssl_close(gsc);
-
-		return;
-	}
-
-	gaim_input_remove(nss_data->handshake_handler);
-	nss_data->handshake_handler = 0;
-
-	gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
-}
-
-static void
-ssl_nss_connect(GaimSslConnection *gsc)
-{
-	GaimSslNssData *nss_data = g_new0(GaimSslNssData, 1);
-	PRSocketOptionData socket_opt;
-
-	gsc->private_data = nss_data;
-
-	nss_data->fd = PR_ImportTCPSocket(gsc->fd);
-
-	if (nss_data->fd == NULL)
-	{
-		gaim_debug_error("nss", "nss_data->fd == NULL!\n");
-
-		if (gsc->error_cb != NULL)
-			gsc->error_cb(gsc, GAIM_SSL_CONNECT_FAILED, gsc->connect_cb_data);
-
-		gaim_ssl_close((GaimSslConnection *)gsc);
-
-		return;
-	}
-
-	socket_opt.option = PR_SockOpt_Nonblocking;
-	socket_opt.value.non_blocking = PR_TRUE;
-
-	if (PR_SetSocketOption(nss_data->fd, &socket_opt) != PR_SUCCESS)
-		gaim_debug_warning("nss", "unable to set socket into non-blocking mode: %d\n", PR_GetError());
-
-	nss_data->in = SSL_ImportFD(NULL, nss_data->fd);
-
-	if (nss_data->in == NULL)
-	{
-		gaim_debug_error("nss", "nss_data->in == NUL!\n");
-
-		if (gsc->error_cb != NULL)
-			gsc->error_cb(gsc, GAIM_SSL_CONNECT_FAILED, gsc->connect_cb_data);
-
-		gaim_ssl_close((GaimSslConnection *)gsc);
-
-		return;
-	}
-
-	SSL_OptionSet(nss_data->in, SSL_SECURITY,            PR_TRUE);
-	SSL_OptionSet(nss_data->in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
-
-	SSL_AuthCertificateHook(nss_data->in,
-							(SSLAuthCertificate)ssl_auth_cert,
-							(void *)CERT_GetDefaultCertDB());
-	SSL_BadCertHook(nss_data->in, (SSLBadCertHandler)ssl_bad_cert, NULL);
-
-	if(gsc->host)
-		SSL_SetURL(nss_data->in, gsc->host);
-
-#if 0
-	/* This seems like it'd the be the correct way to implement the
-	nonblocking stuff, but it doesn't seem to work */
-	SSL_HandshakeCallback(nss_data->in,
-		(SSLHandshakeCallback) ssl_nss_handshake_cb, gsc);
-#endif
-	SSL_ResetHandshake(nss_data->in, PR_FALSE);
-
-	nss_data->handshake_handler = gaim_input_add(gsc->fd,
-		GAIM_INPUT_READ, ssl_nss_handshake_cb, gsc);
-
-	ssl_nss_handshake_cb(gsc, gsc->fd, GAIM_INPUT_READ);
-}
-
-static void
-ssl_nss_close(GaimSslConnection *gsc)
-{
-	GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc);
-
-	if(!nss_data)
-		return;
-
-	if (nss_data->in) PR_Close(nss_data->in);
-	/* if (nss_data->fd) PR_Close(nss_data->fd); */
-
-	if (nss_data->handshake_handler)
-		gaim_input_remove(nss_data->handshake_handler);
-
-	g_free(nss_data);
-	gsc->private_data = NULL;
-}
-
-static size_t
-ssl_nss_read(GaimSslConnection *gsc, void *data, size_t len)
-{
-	ssize_t ret;
-	GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc);
-
-	ret = PR_Read(nss_data->in, data, len);
-
-	if (ret == -1)
-		set_errno(PR_GetError());
-
-	return ret;
-}
-
-static size_t
-ssl_nss_write(GaimSslConnection *gsc, const void *data, size_t len)
-{
-	ssize_t ret;
-	GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc);
-
-	if(!nss_data)
-		return 0;
-
-	ret = PR_Write(nss_data->in, data, len);
-
-	if (ret == -1)
-		set_errno(PR_GetError());
-
-	return ret;
-}
-
-static GaimSslOps ssl_ops =
-{
-	ssl_nss_init,
-	ssl_nss_uninit,
-	ssl_nss_connect,
-	ssl_nss_close,
-	ssl_nss_read,
-	ssl_nss_write
-};
-
-#endif /* HAVE_NSS */
-
-
-static gboolean
-plugin_load(GaimPlugin *plugin)
-{
-#ifdef HAVE_NSS
-	if (!gaim_ssl_get_ops()) {
-		gaim_ssl_set_ops(&ssl_ops);
-	}
-
-	/* Init NSS now, so others can use it even if sslconn never does */
-	ssl_nss_init_nss();
-
-	return TRUE;
-#else
-	return FALSE;
-#endif
-}
-
-static gboolean
-plugin_unload(GaimPlugin *plugin)
-{
-#ifdef HAVE_NSS
-	if (gaim_ssl_get_ops() == &ssl_ops) {
-		gaim_ssl_set_ops(NULL);
-	}
-#endif
-
-	return TRUE;
-}
-
-static GaimPluginInfo info =
-{
-	GAIM_PLUGIN_MAGIC,
-	GAIM_MAJOR_VERSION,
-	GAIM_MINOR_VERSION,
-	GAIM_PLUGIN_STANDARD,                             /**< type           */
-	NULL,                                             /**< ui_requirement */
-	GAIM_PLUGIN_FLAG_INVISIBLE,                       /**< flags          */
-	NULL,                                             /**< dependencies   */
-	GAIM_PRIORITY_DEFAULT,                            /**< priority       */
-
-	SSL_NSS_PLUGIN_ID,                             /**< id             */
-	N_("NSS"),                                        /**< name           */
-	VERSION,                                          /**< version        */
-	                                                  /**  summary        */
-	N_("Provides SSL support through Mozilla NSS."),
-	                                                  /**  description    */
-	N_("Provides SSL support through Mozilla NSS."),
-	"Christian Hammond <chipx86@gnupdate.org>",
-	GAIM_WEBSITE,                                     /**< homepage       */
-
-	plugin_load,                                      /**< load           */
-	plugin_unload,                                    /**< unload         */
-	NULL,                                             /**< destroy        */
-
-	NULL,                                             /**< ui_info        */
-	NULL,                                             /**< extra_info     */
-	NULL,                                             /**< prefs_info     */
-	NULL                                              /**< actions        */
-};
-
-static void
-init_plugin(GaimPlugin *plugin)
-{
-}
-
-GAIM_INIT_PLUGIN(ssl_nss, init_plugin, info)

mercurial