ssl-gnutls.c

来自「Linux下的多协议即时通讯程序源代码」· C语言 代码 · 共 306 行

C
306
字号
/** * @file ssl-gnutls.c GNUTLS SSL plugin. * * purple * * 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_GNUTLS_PLUGIN_ID "ssl-gnutls"#ifdef HAVE_GNUTLS#include <gnutls/gnutls.h>typedef struct{	gnutls_session session;	guint handshake_handler;} PurpleSslGnutlsData;#define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data)static gnutls_certificate_client_credentials xcred;static voidssl_gnutls_init_gnutls(void){	gnutls_global_init();	gnutls_certificate_allocate_credentials(&xcred);	gnutls_certificate_set_x509_trust_file(xcred, "ca.pem",		GNUTLS_X509_FMT_PEM);}static gbooleanssl_gnutls_init(void){   return TRUE;}static voidssl_gnutls_uninit(void){	gnutls_global_deinit();	gnutls_certificate_free_credentials(xcred);}static void ssl_gnutls_handshake_cb(gpointer data, gint source,		PurpleInputCondition cond){	PurpleSslConnection *gsc = data;	PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc);	ssize_t ret;	purple_debug_info("gnutls", "Handshaking\n");	ret = gnutls_handshake(gnutls_data->session);	if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)		return;	purple_input_remove(gnutls_data->handshake_handler);	gnutls_data->handshake_handler = 0;	if(ret != 0) {		purple_debug_error("gnutls", "Handshake failed. Error %s\n",			gnutls_strerror(ret));		if(gsc->error_cb != NULL)			gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED,				gsc->connect_cb_data);		purple_ssl_close(gsc);	} else {		purple_debug_info("gnutls", "Handshake complete\n");		gsc->connect_cb(gsc->connect_cb_data, gsc, cond);	}}static voidssl_gnutls_connect(PurpleSslConnection *gsc){	PurpleSslGnutlsData *gnutls_data;	static const int cert_type_priority[2] = { GNUTLS_CRT_X509, 0 };	gnutls_data = g_new0(PurpleSslGnutlsData, 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(gsc->fd));	gnutls_data->handshake_handler = purple_input_add(gsc->fd,		PURPLE_INPUT_READ, ssl_gnutls_handshake_cb, gsc);	/* Orborde asks: Why are we configuring a callback, then	   immediately calling it?	   Answer: gnutls_handshake (up in handshake_cb) needs to be called	   once in order to get the ball rolling on the SSL connection.	   Once it has done so, only then will the server reply, triggering	   the callback.	   Since the logic driving gnutls_handshake is the same with the first	   and subsequent calls, we'll just fire the callback immediately to	   accomplish this.	*/	ssl_gnutls_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ);}static voidssl_gnutls_close(PurpleSslConnection *gsc){	PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc);	if(!gnutls_data)		return;	if(gnutls_data->handshake_handler)		purple_input_remove(gnutls_data->handshake_handler);	gnutls_bye(gnutls_data->session, GNUTLS_SHUT_RDWR);	gnutls_deinit(gnutls_data->session);	g_free(gnutls_data);	gsc->private_data = NULL;}static size_tssl_gnutls_read(PurpleSslConnection *gsc, void *data, size_t len){	PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc);	ssize_t s;	s = gnutls_record_recv(gnutls_data->session, data, len);	if(s == GNUTLS_E_AGAIN || s == GNUTLS_E_INTERRUPTED) {		s = -1;		errno = EAGAIN;	} else if(s < 0) {		purple_debug_error("gnutls", "receive failed: %s\n",				gnutls_strerror(s));		s = -1;		/*		 * TODO: Set errno to something more appropriate.  Or even		 *       better: allow ssl plugins to keep track of their		 *       own error message, then add a new ssl_ops function		 *       that returns the error message.		 */		errno = EIO;	}	return s;}static size_tssl_gnutls_write(PurpleSslConnection *gsc, const void *data, size_t len){	PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc);	ssize_t s = 0;	/* XXX: when will gnutls_data be NULL? */	if(gnutls_data)		s = gnutls_record_send(gnutls_data->session, data, len);	if(s == GNUTLS_E_AGAIN || s == GNUTLS_E_INTERRUPTED) {		s = -1;		errno = EAGAIN;	} else if(s < 0) {		purple_debug_error("gnutls", "send failed: %s\n",				gnutls_strerror(s));		s = -1;		/*		 * TODO: Set errno to something more appropriate.  Or even		 *       better: allow ssl plugins to keep track of their		 *       own error message, then add a new ssl_ops function		 *       that returns the error message.		 */		errno = EIO;	}	return s;}static PurpleSslOps ssl_ops ={	ssl_gnutls_init,	ssl_gnutls_uninit,	ssl_gnutls_connect,	ssl_gnutls_close,	ssl_gnutls_read,	ssl_gnutls_write,	/* padding */	NULL,	NULL,	NULL,	NULL};#endif /* HAVE_GNUTLS */static gbooleanplugin_load(PurplePlugin *plugin){#ifdef HAVE_GNUTLS	if(!purple_ssl_get_ops()) {		purple_ssl_set_ops(&ssl_ops);	}	/* Init GNUTLS now so others can use it even if sslconn never does */	ssl_gnutls_init_gnutls();	return TRUE;#else	return FALSE;#endif}static gbooleanplugin_unload(PurplePlugin *plugin){#ifdef HAVE_GNUTLS	if(purple_ssl_get_ops() == &ssl_ops) {		purple_ssl_set_ops(NULL);	}#endif	return TRUE;}static PurplePluginInfo info ={	PURPLE_PLUGIN_MAGIC,	PURPLE_MAJOR_VERSION,	PURPLE_MINOR_VERSION,	PURPLE_PLUGIN_STANDARD,                             /**< type           */	NULL,                                             /**< ui_requirement */	PURPLE_PLUGIN_FLAG_INVISIBLE,                       /**< flags          */	NULL,                                             /**< dependencies   */	PURPLE_PRIORITY_DEFAULT,                            /**< priority       */	SSL_GNUTLS_PLUGIN_ID,                             /**< id             */	N_("GNUTLS"),                                     /**< name           */	VERSION,                                          /**< version        */	                                                  /**  summary        */	N_("Provides SSL support through GNUTLS."),	                                                  /**  description    */	N_("Provides SSL support through GNUTLS."),	"Christian Hammond <chipx86@gnupdate.org>",	PURPLE_WEBSITE,                                     /**< homepage       */	plugin_load,                                      /**< load           */	plugin_unload,                                    /**< unload         */	NULL,                                             /**< destroy        */	NULL,                                             /**< ui_info        */	NULL,                                             /**< extra_info     */	NULL,                                             /**< prefs_info     */	NULL,                                             /**< actions        */	/* padding */	NULL,	NULL,	NULL,	NULL};static voidinit_plugin(PurplePlugin *plugin){}PURPLE_INIT_PLUGIN(ssl_gnutls, init_plugin, info)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?