Merge with release-2.x.y

Wed, 05 Nov 2014 13:22:39 -0500

author
Daniel Atallah <datallah@pidgin.im>
date
Wed, 05 Nov 2014 13:22:39 -0500
changeset 36229
c6b248d98ba9
parent 36226
c84a673e6105 (current diff)
parent 36228
1cdc641d433e (diff)
child 36230
f784f0d12ffe

Merge with release-2.x.y

ChangeLog file | annotate | diff | comparison | revisions
libpurple/pluginpref.c file | annotate | diff | comparison | revisions
libpurple/plugins/ssl/Makefile.am file | annotate | diff | comparison | revisions
libpurple/plugins/ssl/Makefile.mingw file | annotate | diff | comparison | revisions
libpurple/plugins/ssl/ssl-nss.c file | annotate | diff | comparison | revisions
pidgin/win32/nsis/pidgin-installer.nsi file | annotate | diff | comparison | revisions
--- a/ChangeLog	Tue Nov 04 22:18:30 2014 -0800
+++ b/ChangeLog	Wed Nov 05 13:22:39 2014 -0500
@@ -76,14 +76,17 @@
 	  was an offline message. (Flavius Anton) (#2497)
 
 version 2.10.11 (?/?/?):
+	General:
+	* Fix handling of Self-Signed SSL/TLS Certificates when using the NSS
+	  plugin (#16412)
+	* Improve default cipher suites used with the NSS plugin (#16262)
+	* Add NSS Preferences plugin which allows the SSL/TLS Versions and
+	  cipher suites to be configured (#8061)
+
 	Gadu-Gadu:
 	* Fix a bug that prevented plugin to load when compiled without GnuTLS.
 	  (mancha) (#16431)
 
-	General:
-	* Fix handling of Self-Signed SSL/TLS Certificates when using the NSS
-	  plugin (#16412)
-
 version 2.10.10 (10/22/14):
 	General:
 	* Check the basic constraints extension when validating SSL/TLS
--- a/libpurple/pluginpref.c	Tue Nov 04 22:18:30 2014 -0800
+++ b/libpurple/pluginpref.c	Wed Nov 05 13:22:39 2014 -0500
@@ -154,8 +154,6 @@
 		tmp = g_list_delete_link(tmp, tmp);
 		tmp = g_list_delete_link(tmp, tmp);
 	}
-
-	g_list_free(pref->choices);
 	g_free(pref);
 }
 
--- a/libpurple/plugins/ssl/Makefile.am	Tue Nov 04 22:18:30 2014 -0800
+++ b/libpurple/plugins/ssl/Makefile.am	Wed Nov 05 13:22:39 2014 -0500
@@ -6,9 +6,11 @@
 ssl_la_LDFLAGS        = -module @PLUGIN_LDFLAGS@
 ssl_gnutls_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
 ssl_nss_la_LDFLAGS    = -module @PLUGIN_LDFLAGS@
+nss_prefs_la_LDFLAGS  = -module -avoid-version
 
 if PLUGINS
 
+
 plugin_LTLIBRARIES = \
 	ssl.la
 if USE_GNUTLS
@@ -17,16 +19,19 @@
 endif
 if USE_NSS
 plugin_LTLIBRARIES += \
-	ssl-nss.la
+	ssl-nss.la	\
+	nss-prefs.la
 endif
 
 ssl_la_SOURCES        = ssl.c
 ssl_gnutls_la_SOURCES = ssl-gnutls.c
 ssl_nss_la_SOURCES    = ssl-nss.c
+nss_prefs_la_SOURCES  = nss-prefs.c
 
 ssl_la_LIBADD        = @PURPLE_LIBS@
 ssl_gnutls_la_LIBADD = @PURPLE_LIBS@ $(GNUTLS_LIBS)
 ssl_nss_la_LIBADD    = @PURPLE_LIBS@ $(NSS_LIBS)
+nss_prefs_la_LIBADD  = $(GLIB_LIBS) $(NSS_LIBS)
 
 endif # PLUGINS
 
@@ -39,4 +44,5 @@
 
 ssl_gnutls_la_CFLAGS = $(AM_CPPFLAGS) $(GNUTLS_CFLAGS)
 ssl_nss_la_CFLAGS = $(AM_CPPFLAGS) $(NSS_CFLAGS)
+nss_prefs_la_CFLAGS = $(AM_CPPFLAGS) $(NSS_CFLAGS)
 
--- a/libpurple/plugins/ssl/Makefile.mingw	Tue Nov 04 22:18:30 2014 -0800
+++ b/libpurple/plugins/ssl/Makefile.mingw	Wed Nov 05 13:22:39 2014 -0500
@@ -13,6 +13,7 @@
 TARGET = ssl
 TARGET_NSS = ssl-nss
 TARGET_GNUTLS = ssl-gnutls
+TARGET_NSSPREEFS = nss-prefs
 
 ##
 ## INCLUDE PATHS
@@ -39,10 +40,12 @@
 ##
 C_SRC =			ssl.c
 C_SRC_NSS =		ssl-nss.c
-C_SRC_GNUTLS =	ssl-gnutls.c
+C_SRC_GNUTLS =		ssl-gnutls.c
+C_SRC_NSSPREFS =	nss-prefs.c
 OBJECTS = $(C_SRC:%.c=%.o)
 OBJECTS_NSS = $(C_SRC_NSS:%.c=%.o)
 OBJECTS_GNUTLS = $(C_SRC_GNUTLS:%.c=%.o)
+OBJECTS_NSSPREFS = $(C_SRC_NSSPREFS:%.c=%.o)
 
 ##
 ## LIBRARIES
@@ -66,12 +69,13 @@
 ##
 .PHONY: all install clean
 
-all: $(TARGET).dll $(TARGET_NSS).dll $(TARGET_GNUTLS).dll
+all: $(TARGET).dll $(TARGET_NSS).dll $(TARGET_GNUTLS).dll $(TARGET_NSSPREFS).dll
 
 install: all $(PURPLE_INSTALL_PLUGINS_DIR) $(PURPLE_INSTALL_DIR)
 	cp $(TARGET).dll $(PURPLE_INSTALL_PLUGINS_DIR)
 	cp $(TARGET_NSS).dll $(PURPLE_INSTALL_PLUGINS_DIR)
 	cp $(TARGET_GNUTLS).dll $(PURPLE_INSTALL_PLUGINS_DIR)
+	cp $(TARGET_NSSPREFS).dll $(PURPLE_INSTALL_PLUGINS_DIR)
 
 $(OBJECTS) $(OBJECTS_NSS) $(OBJECTS_GNUTLS): $(PURPLE_CONFIG_H)
 
@@ -87,10 +91,13 @@
 $(TARGET_GNUTLS).dll: $(PURPLE_DLL) $(OBJECTS_GNUTLS)
 	$(CC) -shared $(OBJECTS_GNUTLS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET_GNUTLS).dll
 
+$(TARGET_NSSPREFS).dll: $(PURPLE_DLL) $(OBJECTS_NSSPREFS)
+	$(CC) -shared $(OBJECTS_NSSPREFS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET_NSSPREFS).dll
+
 ##
 ## CLEAN RULES
 ##
 clean:
-	rm -f $(OBJECTS) $(OBJECTS_NSS) $(TARGET).dll $(TARGET_NSS).dll $(TARGET_GNUTLS).dll
+	rm -f $(OBJECTS) $(OBJECTS_NSS) $(OBJECTS_GNUTLS) $(OBJECTS_NSSPREFS) $(TARGET).dll $(TARGET_NSS).dll $(TARGET_GNUTLS).dll $(TARGET_NSSPREFS).dll
 
 include $(PIDGIN_COMMON_TARGETS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/ssl/nss-prefs.c	Wed Nov 05 13:22:39 2014 -0500
@@ -0,0 +1,529 @@
+/*
+ * Plugin to configure NSS
+ *
+ * Copyright (C) 2014, Daniel Atallah <datallah@pidgin.im>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02111-1301, USA.
+ */
+#include "internal.h"
+#include "debug.h"
+#include "plugin.h"
+#include "version.h"
+
+#ifdef _WIN32
+# ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+/* WINDDK_BUILD is defined because the checks around usage of
+ * intrisic functions are wrong in nspr */
+#define WINDDK_BUILD
+# endif
+#endif
+
+#include <nspr.h>
+#include <nss.h>
+#include <nssb64.h>
+#include <ocsp.h>
+#include <pk11func.h>
+#include <prio.h>
+#include <secerr.h>
+#include <secmod.h>
+#include <ssl.h>
+#include <sslerr.h>
+#include <sslproto.h>
+
+/* There's a bug in some versions of this header that requires that some of
+   the headers above be included first. This is true for at least libnss
+   3.15.4. */
+#include <certdb.h>
+
+#define PLUGIN_ID "core-nss_prefs"
+
+#define PREF_BASE		"/plugins/core/nss_prefs"
+#define CIPHERS_PREF	PREF_BASE "/cipher_list"
+#define CIPHER_TMP_ROOT PREF_BASE "/ciphers_dummy_ui"
+#define CIPHER_TMP		CIPHER_TMP_ROOT "/0x%04x"
+#define MIN_TLS			PREF_BASE "/min_tls"
+#define MAX_TLS			PREF_BASE "/max_tls"
+
+static PurplePlugin *handle = NULL;
+static GList *tmp_prefs = NULL;
+static GList *default_ciphers = NULL;
+#if NSS_VMAJOR > 3 || ( NSS_VMAJOR == 3 && NSS_VMINOR >= 14 )
+static SSLVersionRange *default_versions = NULL;
+#endif
+
+static gchar *get_error_text(void)
+{
+	PRInt32 len = PR_GetErrorTextLength();
+	gchar *ret = NULL;
+
+	if (len > 0) {
+		ret = g_malloc(len + 1);
+		len = PR_GetErrorText(ret);
+		ret[len] = '\0';
+	}
+
+	return ret;
+}
+
+static GList *get_current_cipher_list(gboolean force_default) {
+	GList *conf_ciphers = NULL;
+	if (!force_default) {
+		conf_ciphers = purple_prefs_get_string_list(CIPHERS_PREF);
+	}
+
+	/* If we don't have any specifically configured ciphers, use the
+	 * a copy of the defaults */
+	if (!conf_ciphers) {
+		GList *tmp;
+		for(tmp = default_ciphers; tmp; tmp = tmp->next) {
+			conf_ciphers = g_list_prepend(conf_ciphers, g_strdup(tmp->data));
+		}
+	}
+
+	return conf_ciphers;
+}
+
+static void
+enable_ciphers(gboolean force_default) {
+	const PRUint16 *cipher;
+	GList *conf_ciphers, *tmp;
+	SECStatus rv;
+
+	conf_ciphers = get_current_cipher_list(force_default);
+
+	/** First disable everything */
+	for (cipher = SSL_GetImplementedCiphers(); *cipher != 0; ++cipher) {
+		rv = SSL_CipherPrefSetDefault(*cipher, PR_FALSE);
+		if (rv != SECSuccess) {
+			gchar *error_msg = get_error_text();
+			purple_debug_warning("nss-prefs",
+					"Unable to disable 0x%04x: %s\n",
+					*cipher, error_msg);
+			g_free(error_msg);
+		}
+	}
+
+	for (tmp = conf_ciphers; tmp; tmp = g_list_delete_link(tmp, tmp)) {
+		guint64 parsed = g_ascii_strtoull(tmp->data, NULL, 16);
+
+		if (parsed == 0 || parsed > PR_UINT16_MAX) {
+			purple_debug_error("nss-prefs",
+					"Cipher '%s' is not valid.\n",
+					(const char *) tmp->data);
+			g_free(tmp->data);
+			continue;
+		}
+
+		rv = SSL_CipherPrefSetDefault((PRUint16) parsed, PR_TRUE);
+		if (rv != SECSuccess) {
+			gchar *error_msg = get_error_text();
+			purple_debug_warning("nss-prefs",
+					"Unable to enable 0x%04x: %s\n",
+					*cipher, error_msg);
+			g_free(error_msg);
+		}
+		purple_debug_info("nss-prefs",
+				"Enabled Cipher 0x%04x.\n", (PRUint16) parsed);
+
+		g_free(tmp->data);
+	}
+}
+
+static void set_cipher_pref(const char *pref, PurplePrefType type,
+		gconstpointer value, gpointer user_data) {
+	const PRUint16 *cipher = user_data;
+	GList *conf_ciphers, *tmp;
+	gboolean enabled = GPOINTER_TO_INT(value);
+	gboolean found = FALSE;
+
+	purple_debug_info("nss-prefs",
+			"%s pref for Cipher 0x%04x.\n",
+			enabled ? "Adding" : "Removing", *cipher);
+
+	conf_ciphers = get_current_cipher_list(FALSE);
+
+	for (tmp = conf_ciphers; tmp; tmp = tmp->next) {
+		guint64 parsed = g_ascii_strtoull(tmp->data, NULL, 16);
+		if (parsed == 0 || parsed > PR_UINT16_MAX) {
+			purple_debug_error("nss-prefs",
+					"Cipher '%s' is not valid to set_cipher_pref.\n",
+					(const char *) tmp->data);
+		}
+		if (parsed == *cipher) {
+			if (!enabled) {
+				g_free(tmp->data);
+				conf_ciphers = g_list_delete_link(conf_ciphers, tmp);
+			}
+			found = TRUE;
+			break;
+		}
+	}
+	if (!found) {
+		if (enabled) {
+			conf_ciphers = g_list_prepend(conf_ciphers,
+					g_strdup_printf("0x%04x", *cipher));
+		} else {
+			purple_debug_info("nss-prefs",
+					"Unable to find 0x%04x to disable.\n",
+					*cipher);
+		}
+	}
+
+	purple_prefs_set_string_list(CIPHERS_PREF, conf_ciphers);
+
+	for (tmp = conf_ciphers; tmp; tmp = g_list_delete_link(tmp, tmp)) {
+		g_free(tmp->data);
+	}
+
+	enable_ciphers(FALSE);
+}
+
+static void set_versions(gboolean force_default) {
+#if NSS_VMAJOR > 3 || ( NSS_VMAJOR == 3 && NSS_VMINOR >= 14 )
+	SSLVersionRange supported, enabled;
+
+	/* Get the ranges of supported and enabled SSL versions */
+	if ((SSL_VersionRangeGetSupported(ssl_variant_stream, &supported) == SECSuccess) &&
+			(SSL_VersionRangeGetDefault(ssl_variant_stream, &enabled) == SECSuccess)) {
+		PRUint16 tmp;
+
+		/* Store the defaults if this is the first time we've encountered them */
+		if (!default_versions) {
+			default_versions = g_new0(SSLVersionRange, 1);
+			default_versions->min = enabled.min;
+			default_versions->max = enabled.max;
+		}
+
+		if (force_default) {
+			tmp = default_versions->min;
+		} else {
+			tmp = purple_prefs_get_int(MIN_TLS);
+		}
+		if (tmp > 0) {
+			enabled.min = tmp;
+		}
+
+		if (force_default) {
+			tmp = default_versions->max;
+		} else {
+			tmp = purple_prefs_get_int(MAX_TLS);
+		}
+		if (tmp > 0) {
+			enabled.max = tmp;
+		}
+
+		if (SSL_VersionRangeSetDefault(ssl_variant_stream, &enabled) == SECSuccess) {
+			purple_debug_info("nss-prefs", "Changed allowed TLS versions to "
+					"0x%04hx through 0x%04hx\n", enabled.min, enabled.max);
+		} else {
+			purple_debug_error("nss-prefs", "Error setting allowed TLS versions to "
+					"0x%04hx through 0x%04hx\n", enabled.min, enabled.max);
+		}
+	}
+#else
+	purple_debug_error("nss-prefs", "Unable set SSL/TLS Versions\n");
+#endif /* NSS >= 3.14 */
+}
+
+static void set_version_pref(const char *pref, PurplePrefType type,
+		gconstpointer value, gpointer user_data) {
+	set_versions(FALSE);
+}
+
+/* This is horrible, but is the only way I can think of to tie into the
+ * prefs UI. Add a bunch of temporary prefs that will be used to set
+ * the prefs list. They'll get cleaned up when the plugin is unloaded*/
+static void init_tmp_prefs(void) {
+	GList *conf_ciphers, *tmp;
+	const PRUint16 *cipher;
+
+	if (tmp_prefs) {
+		return;
+	}
+
+	conf_ciphers = get_current_cipher_list(FALSE);
+
+	purple_prefs_add_none(CIPHER_TMP_ROOT);
+	for (cipher = SSL_GetImplementedCiphers(); *cipher != 0; ++cipher) {
+		gboolean found = FALSE;
+		gchar *pref_name = g_strdup_printf(CIPHER_TMP, *cipher);
+
+		tmp_prefs = g_list_prepend(tmp_prefs, pref_name);
+
+		tmp = conf_ciphers;
+		while (tmp) {
+			guint64 parsed = g_ascii_strtoull(tmp->data, NULL, 16);
+			if (parsed == 0 || parsed > PR_UINT16_MAX) {
+				purple_debug_error("nss-prefs",
+						"Cipher '%s' is not valid to init_tmp_pref.\n",
+						(const char *) tmp->data);
+			}
+			if (parsed == *cipher) {
+				found = TRUE;
+				/** Remove the entry since we're done with it */
+				g_free(tmp->data);
+				conf_ciphers = g_list_delete_link(conf_ciphers, tmp);
+				break;
+			}
+			tmp = tmp->next;
+		}
+		purple_prefs_add_bool(pref_name, found);
+		purple_prefs_set_bool(pref_name, found);
+		purple_prefs_connect_callback(handle, pref_name,
+				set_cipher_pref, (void *) cipher);
+	}
+	tmp_prefs = g_list_reverse(tmp_prefs);
+
+	for (tmp = conf_ciphers; tmp; tmp = g_list_delete_link(tmp, tmp)) {
+		g_free(tmp->data);
+	}
+
+}
+
+static PurplePluginPrefFrame *
+get_plugin_pref_frame(PurplePlugin *plugin) {
+	PurplePluginPrefFrame *frame;
+	PurplePluginPref *ppref;
+	int offset;
+	GList *tmp;
+#if NSS_VMAJOR > 3 || ( NSS_VMAJOR == 3 && NSS_VMINOR >= 14 )
+	SSLVersionRange supported, enabled;
+#endif /* NSS >= 3.14 */
+
+	frame = purple_plugin_pref_frame_new();
+
+	ppref = purple_plugin_pref_new_with_label(_("TLS/SSL Versions"));
+	purple_plugin_pref_frame_add(frame, ppref);
+#if NSS_VMAJOR > 3 || ( NSS_VMAJOR == 3 && NSS_VMINOR >= 14 )
+	/* Get the ranges of supported and enabled SSL versions */
+	if ((SSL_VersionRangeGetSupported(ssl_variant_stream, &supported) == SECSuccess) &&
+			(SSL_VersionRangeGetDefault(ssl_variant_stream, &enabled) == SECSuccess)) {
+		PRUint16 tmp_version;
+		PurplePluginPref *ppref_max;
+
+		ppref = purple_plugin_pref_new_with_name_and_label(MIN_TLS,
+				_("Minimum Version"));
+		purple_plugin_pref_set_type(ppref, PURPLE_PLUGIN_PREF_CHOICE);
+		ppref_max = purple_plugin_pref_new_with_name_and_label(MAX_TLS,
+				_("Maximum Version"));
+		purple_plugin_pref_set_type(ppref_max, PURPLE_PLUGIN_PREF_CHOICE);
+
+		for (tmp_version = supported.min; tmp_version <= supported.max; tmp_version++) {
+			gchar *ver;
+			switch (tmp_version) {
+				case SSL_LIBRARY_VERSION_2:
+					ver = g_strdup(_("SSL 2"));
+					break;
+				case SSL_LIBRARY_VERSION_3_0:
+					ver = g_strdup(_("SSL 3"));
+					break;
+				case SSL_LIBRARY_VERSION_TLS_1_0:
+					ver = g_strdup(_("TLS 1.0"));
+					break;
+				case SSL_LIBRARY_VERSION_TLS_1_1:
+					ver = g_strdup(_("TLS 1.1"));
+					break;
+				case SSL_LIBRARY_VERSION_TLS_1_2:
+					ver = g_strdup(_("TLS 1.2"));
+					break;
+				case SSL_LIBRARY_VERSION_TLS_1_3:
+					ver = g_strdup(_("TLS 1.3"));
+					break;
+				default:
+					ver = g_strdup_printf("0x%04hx", tmp_version);
+			}
+			purple_plugin_pref_add_choice(ppref, ver, GINT_TO_POINTER((gint) tmp_version));
+			purple_plugin_pref_add_choice(ppref_max, ver, GINT_TO_POINTER((gint) tmp_version));
+			g_free(ver);
+		}
+		purple_plugin_pref_frame_add(frame, ppref);
+		purple_plugin_pref_frame_add(frame, ppref_max);
+	}
+#else
+	/* TODO: look into how to do this for older versions? */
+
+	ppref = purple_plugin_pref_new_with_label(_("Not Supported for NSS < 3.14"));
+	purple_plugin_pref_frame_add(frame, ppref);
+
+#endif /* NSS >= 3.14 */
+
+	ppref = purple_plugin_pref_new_with_label(_("Ciphers"));
+	purple_plugin_pref_frame_add(frame, ppref);
+
+	init_tmp_prefs();
+
+	offset = strlen(CIPHER_TMP_ROOT) + 1;
+	for (tmp = tmp_prefs; tmp; tmp = tmp->next) {
+		guint64 parsed = g_ascii_strtoull( (char *) tmp->data + offset,
+				NULL, 16);
+		PRUint16 cipher;
+		SECStatus rv;
+		gchar **split;
+		gchar *escaped_name;
+		SSLCipherSuiteInfo info;
+
+		if (parsed == 0 || parsed > PR_UINT16_MAX) {
+			purple_debug_error("nss-prefs",
+					"Cipher '%s' is not valid to build pref frame.\n",
+					(const char *) tmp->data + offset);
+			continue;
+		}
+
+		cipher = (PRUint16) parsed;
+
+		rv = SSL_GetCipherSuiteInfo(cipher, &info, (int)(sizeof info));
+		if (rv != SECSuccess) {
+			gchar *error_msg = get_error_text();
+			purple_debug_warning("nss-prefs",
+					"SSL_GetCipherSuiteInfo didn't like value 0x%04x: %s\n",
+					cipher, error_msg);
+			g_free(error_msg);
+			continue;
+		}
+		escaped_name = g_strdup_printf("%s (0x%04x)",
+				info.cipherSuiteName, cipher);
+		/** Escape the _ for the label */
+		split = g_strsplit(escaped_name, "_", -1);
+		g_free(escaped_name);
+		escaped_name = g_strjoinv("__", split);
+		g_strfreev(split);
+		ppref = purple_plugin_pref_new_with_name_and_label(
+				(const char *) tmp->data, escaped_name);
+		g_free(escaped_name);
+		purple_plugin_pref_frame_add(frame, ppref);
+	}
+
+	return frame;
+}
+
+static gboolean
+plugin_load(PurplePlugin *plugin) {
+	const PRUint16 *cipher;
+
+	handle = plugin;
+
+	tmp_prefs = NULL;
+	default_ciphers = NULL;
+
+	for (cipher = SSL_GetImplementedCiphers(); *cipher != 0; ++cipher) {
+		PRBool enabled;
+		SECStatus rv = SSL_CipherPrefGetDefault(*cipher, &enabled);
+		if (rv == SECSuccess && enabled) {
+			default_ciphers = g_list_prepend(default_ciphers,
+					g_strdup_printf("0x%04x", *cipher));
+		}
+	}
+
+	enable_ciphers(FALSE);
+	set_versions(FALSE);
+	purple_prefs_connect_callback(handle, MIN_TLS,
+				set_version_pref, GINT_TO_POINTER(FALSE));
+	purple_prefs_connect_callback(handle, MAX_TLS,
+				set_version_pref, GINT_TO_POINTER(TRUE));
+
+	return TRUE;
+}
+
+static gboolean
+plugin_unload(PurplePlugin *plugin) {
+
+	/* Remove the temporary prefs */
+	if (tmp_prefs) {
+		purple_prefs_remove(CIPHER_TMP_ROOT);
+		while (tmp_prefs) {
+			g_free(tmp_prefs->data);
+			tmp_prefs = g_list_delete_link(tmp_prefs, tmp_prefs);
+		}
+	}
+
+	/* Restore the original ciphers */
+	enable_ciphers(TRUE);
+	while (default_ciphers) {
+		g_free(default_ciphers->data);
+		default_ciphers = g_list_delete_link(default_ciphers,
+				default_ciphers);
+	}
+
+	set_versions(TRUE);
+#if NSS_VMAJOR > 3 || ( NSS_VMAJOR == 3 && NSS_VMINOR >= 14 )
+	g_free(default_versions);
+	default_versions = NULL;
+#endif
+
+	return TRUE;
+}
+
+
+static PurplePluginUiInfo prefs_info = {
+	get_plugin_pref_frame,
+	0,   /* page_num (Reserved) */
+	NULL, /* frame (Reserved) */
+	/* Padding */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static PurplePluginInfo info = {
+	PURPLE_PLUGIN_MAGIC,
+	PURPLE_MAJOR_VERSION,
+	PURPLE_MINOR_VERSION,
+	PURPLE_PLUGIN_STANDARD,				/**< type           */
+	NULL,						/**< ui_requirement */
+	0,						/**< flags          */
+	NULL,						/**< dependencies   */
+	PURPLE_PRIORITY_DEFAULT,			/**< priority       */
+
+	PLUGIN_ID,					/**< id             */
+	N_("NSS Preferences"),				/**< name           */
+	DISPLAY_VERSION,				/**< version        */
+							/**  summary        */
+	N_("Configure Ciphers and other Settings for "
+	   "the NSS SSL/TLS Plugin"),
+							/**  description    */
+	N_("Configure Ciphers and other Settings for "
+	   "the NSS SSL/TLS Plugin"),
+	"Daniel Atallah <datallah@pidgin.im>",		/**< author         */
+	PURPLE_WEBSITE,					/**< homepage       */
+
+	plugin_load,					/**< load           */
+	plugin_unload,					/**< unload         */
+	NULL,						/**< destroy        */
+
+	NULL,						/**< ui_info        */
+	NULL,						/**< extra_info     */
+	&prefs_info,					/**< prefs_info     */
+	NULL,
+	/* Padding */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static void
+init_plugin(PurplePlugin *plugin) {
+	info.dependencies = g_list_prepend(info.dependencies, "ssl-nss");
+
+	purple_prefs_add_none(PREF_BASE);
+	purple_prefs_add_string_list(CIPHERS_PREF, NULL);
+	purple_prefs_add_int(MIN_TLS, 0);
+	purple_prefs_add_int(MAX_TLS, 0);
+}
+
+PURPLE_INIT_PLUGIN(nss_prefs, init_plugin, info)
--- a/libpurple/plugins/ssl/ssl-nss.c	Tue Nov 04 22:18:30 2014 -0800
+++ b/libpurple/plugins/ssl/ssl-nss.c	Wed Nov 05 13:22:39 2014 -0500
@@ -197,7 +197,6 @@
 		const PRUint16 suite = *cipher;
 		SECStatus rv;
 		PRBool enabled;
-		PRErrorCode err;
 		SSLCipherSuiteInfo info;
 
 		rv = SSL_CipherPrefGetDefault(suite, &enabled);
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Tue Nov 04 22:18:30 2014 -0800
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Wed Nov 05 13:22:39 2014 -0500
@@ -593,6 +593,7 @@
     Delete "$INSTDIR\plugins\markerline.dll"
     Delete "$INSTDIR\plugins\newline.dll"
     Delete "$INSTDIR\plugins\notify.dll"
+    Delete "$INSTDIR\plugins\nss-prefs.dll"
     Delete "$INSTDIR\plugins\offlinemsg.dll"
     Delete "$INSTDIR\plugins\perl.dll"
     Delete "$INSTDIR\plugins\pidginrc.dll"

mercurial