# HG changeset patch # User Christian Hammond # Date 1062656365 0 # Node ID 6c95f01aaf49d8b3f908e60a17c003c45e781eb1 # Parent 05098da416bbb33e2ea5d148411709938bd255f8 [gaim-migrate @ 7270] Added optional GNUTLS support, which will also be used as a fallback if Mozilla NSS is not installed. committer: Tailor Script diff -r 05098da416bb -r 6c95f01aaf49 configure.ac --- a/configure.ac Thu Sep 04 05:36:09 2003 +0000 +++ b/configure.ac Thu Sep 04 06:19:25 2003 +0000 @@ -388,6 +388,8 @@ nss_manual_check="no" fi + enable_nss="no" + if test "x$nss_manual_check" = "xno"; then PKG_CHECK_MODULES(NSS, mozilla-nss, have_nss="yes", []) @@ -399,6 +401,7 @@ AC_DEFINE(HAVE_SSL, 1, [Define if you have SSL]) msg_ssl="yes (Mozilla NSS)" + enable_nss="yes" else nss_manual_check="yes" fi @@ -572,6 +575,8 @@ else msg_ssl="yes (Mozilla NSS)" fi + + enable_nss="yes" else NSS_CFLAGS="" NSPR_CFLAGS="" @@ -590,11 +595,16 @@ AC_SUBST(NSS_LIBS) fi +AM_CONDITIONAL(USE_NSS, test "x$enable_nss" = "xyes") + dnl # dnl # Check for GNUTLS if it's specified or if NSS failed. dnl # if test "x$msg_ssl" = "xno" -o "x$enable_gnutls" != "xno"; then + + enable_gnutls="no" prefix=`eval echo $prefix` + AC_ARG_WITH(gnutls-includes, [ --with-gnutls-includes=PREFIX Location of GNUTLS includes.], [ with_gnutls_includes="$withval" ], @@ -651,6 +661,8 @@ AC_DEFINE(HAVE_SSL) msg_ssl="yes (GNUTLS)" GNUTLS_LIBS="$with_gnutls_libs -lgnutls -lgcrypt" + + enable_gnutls="yes" else GNUTLS_CFLAGS="" GNUTLS_LIBS="" @@ -667,6 +679,8 @@ AC_SUBST(GNUTLS_CFLAGS) AC_SUBST(GNUTLS_LIBS) +AM_CONDITIONAL(USE_GNUTLS, test "x$enable_gnutls" = "xyes") + dnl Check for Tcl if test "$enable_tcl" = yes; then AC_MSG_CHECKING([for tclConfig.sh]) diff -r 05098da416bb -r 6c95f01aaf49 src/Makefile.am --- a/src/Makefile.am Thu Sep 04 05:36:09 2003 +0000 +++ b/src/Makefile.am Thu Sep 04 06:19:25 2003 +0000 @@ -4,6 +4,8 @@ getopt1.c \ Makefile.mingw \ win_gaim.c \ + ssl-nss.c \ + ssl-gnutls.c \ win32/IdleTracker/Makefile.mingw \ win32/IdleTracker/idletrack.c \ win32/IdleTracker/idletrack.h \ @@ -43,6 +45,14 @@ SUBDIRS = protocols +if USE_NSS +SSLSOURCES = ssl-nss.c +endif + +if USE_GNUTLS +SSLSOURCES = ssl-gnutls.c +endif + CORESOURCES = \ account.c \ account.h \ @@ -94,7 +104,8 @@ util.c \ util.h \ value.c \ - value.h + value.h \ + $(SSLSOURCES) bin_PROGRAMS = gaim gaim-remote gaim_SOURCES = \ @@ -165,7 +176,8 @@ $(SM_LIBS) \ $(INTLLIBS) \ $(GTKSPELL_LIBS) \ - $(NSS_LIBS) + $(NSS_LIBS) \ + $(GNUTLS_LIBS) gaim_remote_SOURCES = \ gaim-remote.c @@ -185,4 +197,5 @@ $(DEBUG_CFLAGS) \ $(GTK_CFLAGS) \ $(GTKSPELL_CFLAGS) \ - $(NSS_CFLAGS) + $(NSS_CFLAGS) \ + $(GNUTLS_CFLAGS) diff -r 05098da416bb -r 6c95f01aaf49 src/protocols/msn/session.c --- a/src/protocols/msn/session.c Thu Sep 04 05:36:09 2003 +0000 +++ b/src/protocols/msn/session.c Thu Sep 04 06:19:25 2003 +0000 @@ -39,7 +39,7 @@ session->users = msn_users_new(); session->groups = msn_groups_new(); -#ifdef HAVE_NSS +#ifdef HAVE_SSL session->protocol_ver = 9; #else session->protocol_ver = 7; diff -r 05098da416bb -r 6c95f01aaf49 src/ssl-gnutls.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ssl-gnutls.c Thu Sep 04 06:19:25 2003 +0000 @@ -0,0 +1,149 @@ +/** + * @file ssl-gnutls.c SSL Operations for GNUTLS + * @ingroup core + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * 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 "debug.h" +#include "sslconn.h" + +#include + +typedef struct +{ + gnutls_session session; + gnutls_certificate_client_credentials xcred; + +} GaimSslGnutlsData; + +#define GAIM_SSL_GNUTLS_DATA(gsc) ((GaimSslGnutlsData *)gsc->private_data) + +static gnutls_certificate_client_credentials xcred; + +static gboolean +ssl_gnutls_init(void) +{ + gnutls_global_init(); + + gnutls_certificate_allocate_credentials(&xcred); + gnutls_certificate_set_x509_trust_file(xcred, "ca.pem", GNUTLS_X509_FMT_PEM); + + return TRUE; +} + +static void +ssl_gnutls_uninit(void) +{ + gnutls_global_deinit(); + + gnutls_certificate_free_credentials(xcred); +} + +static void +ssl_gnutls_connect_cb(gpointer data, gint source, GaimInputCondition cond) +{ + GaimSslConnection *gsc = (GaimSslConnection *)data; + GaimSslGnutlsData *gnutls_data; + int ret; + const int cert_type_priority[2] = { GNUTLS_CRT_X509, 0 }; + + gsc->fd = source; + + gnutls_data = g_new0(GaimSslGnutlsData, 1); + gsc->private_data = gnutls_data; + + gnutls_init(&gnutls_data->session, GNUTLS_CLIENT); + gnutls_set_default_priority(gnutls_data->session); + + gnutls_certificate_type_set_priority(gnutls_data->session, + cert_type_priority); + + gnutls_credentials_set(gnutls_data->session, GNUTLS_CRD_CERTIFICATE, + xcred); + + gnutls_transport_set_ptr(gnutls_data->session, GINT_TO_POINTER(source)); + + gaim_debug_info("gnutls", "Handshaking\n"); + ret = gnutls_handshake(gnutls_data->session); + + if (ret < 0) + { + } + else + { + gaim_debug_info("gnutls", "Calling input function\n"); + gsc->input_func(gsc->user_data, (GaimSslConnection *)gsc, cond); + } +} + +static void +ssl_gnutls_close(GaimSslConnection *gsc) +{ + GaimSslGnutlsData *gnutls_data = GAIM_SSL_GNUTLS_DATA(gsc); + + gnutls_bye(gnutls_data->session, GNUTLS_SHUT_RDWR); + + gnutls_deinit(gnutls_data->session); +// gnutls_certificate_free_credentials(gnutls_data->xcred); + + g_free(gnutls_data); +} + +static size_t +ssl_gnutls_read(GaimSslConnection *gsc, void *data, size_t len) +{ + GaimSslGnutlsData *gnutls_data = GAIM_SSL_GNUTLS_DATA(gsc); + int s; + + s = gnutls_record_recv(gnutls_data->session, data, len); + + if (s < 0) + s = 0; + + gaim_debug_misc("gnutls", "s = %d\n", s); + + return s; +} + +static size_t +ssl_gnutls_write(GaimSslConnection *gsc, const void *data, size_t len) +{ + GaimSslGnutlsData *gnutls_data = GAIM_SSL_GNUTLS_DATA(gsc); + size_t s; + + gaim_debug_misc("gnutls", "Writing: {%s}\n", data); + + s = gnutls_record_send(gnutls_data->session, data, len); +} + +static GaimSslOps ssl_ops = +{ + ssl_gnutls_init, + ssl_gnutls_uninit, + ssl_gnutls_connect_cb, + ssl_gnutls_close, + ssl_gnutls_read, + ssl_gnutls_write +}; + +GaimSslOps * +gaim_ssl_gnutls_get_ops() +{ + return &ssl_ops; +} diff -r 05098da416bb -r 6c95f01aaf49 src/ssl-nss.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ssl-nss.c Thu Sep 04 06:19:25 2003 +0000 @@ -0,0 +1,273 @@ +/** + * @file ssl-nss.c SSL Operations for Mozilla NSS + * @ingroup core + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * 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 "debug.h" +#include "sslconn.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + PRFileDesc *fd; + PRFileDesc *in; + +} GaimSslNssData; + +#define GAIM_SSL_NSS_DATA(gsc) ((GaimSslNssData *)gsc->private_data) + +static const PRIOMethods *_nss_methods = NULL; +static PRDescIdentity _identity; + +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 +} + +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"); + + return status; +} + +static void +input_func(gpointer data, gint source, GaimInputCondition cond) +{ + GaimSslConnection *gsc = (GaimSslConnection *)data; + GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); + char *cp, *ip, *sp; + int op, kp0, kp1; + int result; + + result = SSL_SecurityStatus(nss_data->in, &op, &cp, &kp0, + &kp1, &ip, &sp); + + gaim_debug_misc("nss", + "bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + "subject DN: %s\n" + "issuer DN: %s\n", + cp, kp1, kp0, op, sp, ip); + + PR_Free(cp); + PR_Free(ip); + PR_Free(sp); + + gsc->input_func(gsc->user_data, gsc, cond); +} + +static gboolean +ssl_nss_init(void) +{ + 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. */ + SECMOD_AddNewModule("Builtins", LIBDIR "/libnssckbi.so", 0, 0); + NSS_SetDomesticPolicy(); + + _identity = PR_GetUniqueIdentity("Gaim"); + _nss_methods = PR_GetDefaultIOMethods(); + + return TRUE; +} + +static void +ssl_nss_uninit(void) +{ + PR_Cleanup(); + + _nss_methods = NULL; +} + +static void +ssl_nss_connect_cb(gpointer data, gint source, GaimInputCondition cond) +{ + GaimSslConnection *gsc = (GaimSslConnection *)data; + GaimSslNssData *nss_data = g_new0(GaimSslNssData, 1); + PRSocketOptionData socket_opt; + + gsc->private_data = nss_data; + + gsc->fd = source; + + nss_data->fd = PR_ImportTCPSocket(gsc->fd); + + if (nss_data->fd == NULL) + { + gaim_debug_error("nss", "nss_data->fd == NULL!\n"); + + gaim_ssl_close((GaimSslConnection *)gsc); + + return; + } + + socket_opt.option = PR_SockOpt_Nonblocking; + socket_opt.value.non_blocking = PR_FALSE; + + PR_SetSocketOption(nss_data->fd, &socket_opt); + + nss_data->in = SSL_ImportFD(NULL, nss_data->fd); + + if (nss_data->in == NULL) + { + gaim_debug_error("nss", "nss_data->in == NUL!\n"); + + 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); + + SSL_SetURL(nss_data->in, gsc->host); + + SSL_ResetHandshake(nss_data->in, PR_FALSE); + + if (SSL_ForceHandshake(nss_data->in)) + { + gaim_debug_error("nss", "Handshake failed\n"); + + gaim_ssl_close((GaimSslConnection *)gsc); + + return; + } + +#if 0 + gsc->input_func(gsc->user_data, (GaimSslConnection *)gsc, + cond); +#endif + + input_func(gsc, source, cond); +} + +static void +ssl_nss_close(GaimSslConnection *gsc) +{ + GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); + + if (nss_data->in) PR_Close(nss_data->in); + if (nss_data->fd) PR_Close(nss_data->fd); + + g_free(nss_data); +} + +static size_t +ssl_nss_read(GaimSslConnection *gsc, void *data, size_t len) +{ + GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); + + return PR_Read(nss_data->in, data, len); +} + +static size_t +ssl_nss_write(GaimSslConnection *gsc, const void *data, size_t len) +{ + GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); + + return PR_Write(nss_data->in, data, len); +} + +static GaimSslOps ssl_ops = +{ + ssl_nss_init, + ssl_nss_uninit, + ssl_nss_connect_cb, + ssl_nss_close, + ssl_nss_read, + ssl_nss_write +}; + +GaimSslOps * +gaim_ssl_nss_get_ops() +{ + return &ssl_ops; +} diff -r 05098da416bb -r 6c95f01aaf49 src/sslconn.c --- a/src/sslconn.c Thu Sep 04 05:36:09 2003 +0000 +++ b/src/sslconn.c Thu Sep 04 06:19:25 2003 +0000 @@ -25,235 +25,41 @@ #include "debug.h" #include "sslconn.h" +/* Pre-installed SSL op functions. */ #ifdef HAVE_NSS -# include -# include -# include -# include -# include -# include -# include -# include -# include - -typedef struct -{ - char *host; - int port; - void *user_data; - GaimSslInputFunction input_func; - - int fd; - int inpa; - - PRFileDesc *nss_fd; - PRFileDesc *nss_in; - -} GaimSslData; - -static gboolean _nss_initialized = FALSE; -static const PRIOMethods *_nss_methods = NULL; -static PRDescIdentity _identity; - -static void -destroy_ssl_data(GaimSslData *data) -{ - if (data->inpa) gaim_input_remove(data->inpa); - if (data->nss_in) PR_Close(data->nss_in); - if (data->nss_fd) PR_Close(data->nss_fd); - if (data->fd) close(data->fd); - - if (data->host != NULL) - g_free(data->host); - - g_free(data); -} - -static void -init_nss(void) -{ - if (_nss_initialized) - return; - - 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. */ - SECMOD_AddNewModule("Builtins", LIBDIR "/libnssckbi.so", 0, 0); - NSS_SetDomesticPolicy(); - - _identity = PR_GetUniqueIdentity("Gaim"); - _nss_methods = PR_GetDefaultIOMethods(); - - _nss_initialized = TRUE; -} - -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(GAIM_DEBUG_ERROR, "msn", "CERT_VerifyCertNow failed\n"); - CERT_DestroyCertificate(cert); - return status; - } - - CERT_DestroyCertificate(cert); - return SECSuccess; +GaimSslOps *gaim_ssl_nss_get_ops(); #endif -} - -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(GAIM_DEBUG_ERROR, "msn", - "Bad certificate: %d\n"); - - return status; -} - -static void -input_func(gpointer data, gint source, GaimInputCondition cond) -{ - GaimSslData *ssl_data = (GaimSslData *)data; - char *cp, *ip, *sp; - int op, kp0, kp1; - int result; - - result = SSL_SecurityStatus(ssl_data->nss_in, &op, &cp, &kp0, - &kp1, &ip, &sp); - - gaim_debug(GAIM_DEBUG_MISC, "msn", - "bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" - "subject DN: %s\n" - "issuer DN: %s\n", - cp, kp1, kp0, op, sp, ip); - - PR_Free(cp); - PR_Free(ip); - PR_Free(sp); - - ssl_data->input_func(ssl_data->user_data, (GaimSslConnection *)ssl_data, - cond); -} - -static void -ssl_connect_cb(gpointer data, gint source, GaimInputCondition cond) -{ - PRSocketOptionData socket_opt; - GaimSslData *ssl_data = (GaimSslData *)data; - - if (!_nss_initialized) - init_nss(); - - ssl_data->fd = source; - - ssl_data->nss_fd = PR_ImportTCPSocket(ssl_data->fd); - - if (ssl_data->nss_fd == NULL) - { - gaim_debug(GAIM_DEBUG_ERROR, "ssl", "nss_fd == NULL!\n"); - - destroy_ssl_data(ssl_data); - - return; - } - - socket_opt.option = PR_SockOpt_Nonblocking; - socket_opt.value.non_blocking = PR_FALSE; - - PR_SetSocketOption(ssl_data->nss_fd, &socket_opt); - - ssl_data->nss_in = SSL_ImportFD(NULL, ssl_data->nss_fd); - - if (ssl_data->nss_in == NULL) - { - gaim_debug(GAIM_DEBUG_ERROR, "ssl", "nss_in == NUL!\n"); - - destroy_ssl_data(ssl_data); - - return; - } - - SSL_OptionSet(ssl_data->nss_in, SSL_SECURITY, PR_TRUE); - SSL_OptionSet(ssl_data->nss_in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); - - SSL_AuthCertificateHook(ssl_data->nss_in, - (SSLAuthCertificate)ssl_auth_cert, - (void *)CERT_GetDefaultCertDB()); - SSL_BadCertHook(ssl_data->nss_in, (SSLBadCertHandler)ssl_bad_cert, NULL); - - SSL_SetURL(ssl_data->nss_in, ssl_data->host); - - SSL_ResetHandshake(ssl_data->nss_in, PR_FALSE); - - if (SSL_ForceHandshake(ssl_data->nss_in)) - { - gaim_debug(GAIM_DEBUG_ERROR, "ssl", "Handshake failed\n"); - - destroy_ssl_data(ssl_data); - - return; - } - -#if 0 - ssl_data->input_func(ssl_data->user_data, (GaimSslConnection *)ssl_data, - cond); +#ifdef HAVE_GNUTLS +GaimSslOps *gaim_ssl_gnutls_get_ops(); #endif - input_func(ssl_data, source, cond); + +static gboolean _ssl_initialized = FALSE; +static GaimSslOps *_ssl_ops = NULL; + +static gboolean +ssl_init(void) +{ + GaimSslOps *ops = gaim_ssl_get_ops(); + gboolean success = FALSE; + + if (_ssl_initialized) + return FALSE; + + if (ops != NULL && ops->init != NULL) + success = ops->init(); + + _ssl_initialized = success; + + return success; } -#endif /* HAVE_NSS */ gboolean gaim_ssl_is_supported(void) { -#ifdef HAVE_NSS - return TRUE; +#ifdef HAVE_SSL + return (gaim_ssl_get_ops() != NULL); #else return FALSE; #endif @@ -263,95 +69,138 @@ gaim_ssl_connect(GaimAccount *account, const char *host, int port, GaimSslInputFunction func, void *data) { -#ifdef HAVE_NSS + GaimSslConnection *gsc; + GaimSslOps *ops; int i; - GaimSslData *ssl_data; g_return_val_if_fail(host != NULL, NULL); g_return_val_if_fail(port != 0 && port != -1, NULL); g_return_val_if_fail(func != NULL, NULL); g_return_val_if_fail(gaim_ssl_is_supported(), NULL); - ssl_data = g_new0(GaimSslData, 1); + ops = gaim_ssl_get_ops(); + + g_return_val_if_fail(ops != NULL, NULL); + g_return_val_if_fail(ops->connect_cb != NULL, NULL); - ssl_data->host = g_strdup(host); - ssl_data->port = port; - ssl_data->user_data = data; - ssl_data->input_func = func; + if (!_ssl_initialized) + { + if (!ssl_init()) + return NULL; + } - i = gaim_proxy_connect(account, host, port, ssl_connect_cb, ssl_data); + gsc = g_new0(GaimSslConnection, 1); + + gsc->host = g_strdup(host); + gsc->port = port; + gsc->user_data = data; + gsc->input_func = func; + + i = gaim_proxy_connect(account, host, port, ops->connect_cb, gsc); if (i < 0) { - g_free(ssl_data->host); - g_free(ssl_data); + g_free(gsc->host); + g_free(gsc); return NULL; } - return (GaimSslConnection)ssl_data; -#else - return GINT_TO_POINTER(-1); -#endif + return (GaimSslConnection *)gsc; } void gaim_ssl_close(GaimSslConnection *gsc) { + GaimSslOps *ops; + g_return_if_fail(gsc != NULL); -#ifdef HAVE_NSS - destroy_ssl_data((GaimSslData *)gsc); -#endif + ops = gaim_ssl_get_ops(); + + if (gsc->inpa) + gaim_input_remove(gsc->inpa); + + if (ops != NULL && ops->close != NULL) + ops->close(gsc); + + if (gsc->fd) + close(gsc->fd); + + if (gsc->host != NULL) + g_free(gsc->host); + + g_free(gsc); } size_t gaim_ssl_read(GaimSslConnection *gsc, void *data, size_t len) { -#ifdef HAVE_NSS - GaimSslData *ssl_data = (GaimSslData *)gsc; + GaimSslOps *ops; g_return_val_if_fail(gsc != NULL, 0); g_return_val_if_fail(data != NULL, 0); g_return_val_if_fail(len > 0, 0); - return PR_Read(ssl_data->nss_in, data, len); -#else + ops = gaim_ssl_get_ops(); + + if (ops != NULL && ops->read != NULL) + return ops->read(gsc, data, len); + return 0; -#endif } size_t gaim_ssl_write(GaimSslConnection *gsc, const void *data, size_t len) { -#ifdef HAVE_NSS - GaimSslData *ssl_data = (GaimSslData *)gsc; + GaimSslOps *ops; g_return_val_if_fail(gsc != NULL, 0); g_return_val_if_fail(data != NULL, 0); g_return_val_if_fail(len > 0, 0); - return PR_Write(ssl_data->nss_in, data, len); -#else + ops = gaim_ssl_get_ops(); + + if (ops != NULL && ops->write != NULL) + return ops->write(gsc, data, len); + return 0; -#endif +} + +void +gaim_ssl_set_ops(GaimSslOps *ops) +{ + _ssl_ops = ops; +} + +GaimSslOps * +gaim_ssl_get_ops(void) +{ + return _ssl_ops; } void gaim_ssl_init(void) { +#if defined(HAVE_NSS) + gaim_ssl_set_ops(gaim_ssl_nss_get_ops()); +#elif defined(HAVE_GNUTLS) + gaim_ssl_set_ops(gaim_ssl_gnutls_get_ops()); +#endif } void gaim_ssl_uninit(void) { -#ifdef HAVE_NSS - if (!_nss_initialized) + GaimSslOps *ops; + + if (!_ssl_initialized) return; - PR_Cleanup(); + ops = gaim_ssl_get_ops(); - _nss_initialized = FALSE; - _nss_methods = NULL; -#endif + if (ops != NULL && ops->uninit != NULL) + ops->uninit(); + + _ssl_initialized = FALSE; } diff -r 05098da416bb -r 6c95f01aaf49 src/sslconn.h --- a/src/sslconn.h Thu Sep 04 05:36:09 2003 +0000 +++ b/src/sslconn.h Thu Sep 04 06:19:25 2003 +0000 @@ -25,16 +25,46 @@ #include "proxy.h" +#define GAIM_SSL_DEFAULT_PORT 443 + +typedef struct _GaimSslConnection GaimSslConnection; + +typedef void (*GaimSslInputFunction)(gpointer, GaimSslConnection *, + GaimInputCondition); + +struct _GaimSslConnection +{ + char *host; + int port; + void *user_data; + GaimSslInputFunction input_func; + + int fd; + int inpa; + + void *private_data; +}; + +/** + * SSL implementation operations structure. + * + * Every SSL implementation must provide one of these and register it. + */ +typedef struct +{ + gboolean (*init)(void); + void (*uninit)(void); + GaimInputFunction connect_cb; + void (*close)(GaimSslConnection *gsc); + size_t (*read)(GaimSslConnection *gsc, void *data, size_t len); + size_t (*write)(GaimSslConnection *gsc, const void *data, size_t len); + +} GaimSslOps; + #ifdef __cplusplus extern "C" { #endif -#define GAIM_SSL_DEFAULT_PORT 443 - -typedef void *GaimSslConnection; -typedef void (*GaimSslInputFunction)(gpointer, GaimSslConnection *, - GaimInputCondition); - /**************************************************************************/ /** @name SSL API */ /**************************************************************************/ @@ -99,6 +129,20 @@ /*@{*/ /** + * Sets the current SSL operations structure. + * + * @param ops The SSL operations structure to assign. + */ +void gaim_ssl_set_ops(GaimSslOps *ops); + +/** + * Returns the current SSL operations structure. + * + * @return The SSL operations structure. + */ +GaimSslOps *gaim_ssl_get_ops(void); + +/** * Initializes the SSL subsystem. */ void gaim_ssl_init(void);