cpw.darkrain42.xmpp.scram: 90b6819f: Let's try a more complex set of return s...

darkrain42 at pidgin.im darkrain42 at pidgin.im
Tue Dec 1 02:36:47 EST 2009


-----------------------------------------------------------------
Revision: 90b6819fa75dbf90fc1c2132fe445eaf4661c383
Ancestor: f23be1307e15efad8ead51f499dd2eb638d0306f
Author: darkrain42 at pidgin.im
Date: 2009-12-01T07:32:53
Branch: im.pidgin.cpw.darkrain42.xmpp.scram
URL: http://d.pidgin.im/viewmtn/revision/info/90b6819fa75dbf90fc1c2132fe445eaf4661c383

Modified files:
        libpurple/protocols/jabber/auth.c
        libpurple/protocols/jabber/auth.h
        libpurple/protocols/jabber/auth_digest_md5.c
        libpurple/protocols/jabber/auth_plain.c
        libpurple/protocols/jabber/auth_scram.c

ChangeLog: 

Let's try a more complex set of return states / values for auth mechs.

This won't build with Cyrus support yet.

-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/auth.c	33525782a88e6371457b1b7bb399cf0bfcdee44a
+++ libpurple/protocols/jabber/auth.c	4e6fdfa14bb38a130dee2106af5c38772201ecdf
@@ -162,8 +162,10 @@ jabber_auth_start(JabberStream *js, xmln
 {
 	GSList *mechanisms = NULL;
 	GSList *l;
-	xmlnode *response;
+	xmlnode *response = NULL;
 	xmlnode *mechs, *mechnode;
+	JabberSaslState state;
+	const char *msg = NULL;
 
 	if(js->registration) {
 		jabber_register_start(js);
@@ -214,8 +216,12 @@ jabber_auth_start(JabberStream *js, xmln
 		return;
 	}
 
-	response = js->auth_mech->start(js, mechs);
-	if (response) {
+	state = js->auth_mech->start(js, mechs, &response, &msg);
+	if (state == JABBER_SASL_STATE_FAIL) {
+		purple_connection_error_reason(js->gc,
+				PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
+				msg ? msg : _("Unknown Error"));
+	} else if (response) {
 		jabber_send(js, response);
 		xmlnode_free(response);
 	}
@@ -413,8 +419,14 @@ jabber_auth_handle_challenge(JabberStrea
 	}
 
 	if (js->auth_mech && js->auth_mech->handle_challenge) {
-		xmlnode *response = js->auth_mech->handle_challenge(js, packet);
-		if (response != NULL) {
+		xmlnode *response = NULL;
+		const char *msg = NULL;
+		JabberSaslState state = js->auth_mech->handle_challenge(js, packet, &response, &msg);
+		if (state == JABBER_SASL_STATE_FAIL) {
+			purple_connection_error_reason(js->gc,
+					PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
+					msg ? msg : _("Invalid challenge from server"));
+		} else if (response) {
 			jabber_send(js, response);
 			xmlnode_free(response);
 		}
@@ -433,9 +445,21 @@ void jabber_auth_handle_success(JabberSt
 		return;
 	}
 
-	if (js->auth_mech && js->auth_mech->handle_success &&
-			!js->auth_mech->handle_success(js, packet)) {
-		return;
+	if (js->auth_mech && js->auth_mech->handle_success) {
+		const char *msg = NULL;
+		JabberSaslState state = js->auth_mech->handle_success(js, packet, &msg);
+
+		if (state == JABBER_SASL_STATE_FAIL) {
+			purple_connection_error_reason(js->gc,
+					PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
+					msg ? msg : _("Invalid response from server"));
+			return;
+		} else if (state == JABBER_SASL_STATE_CONTINUE) {
+			purple_connection_error_reason(js->gc,
+					PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
+					msg ? msg : _("Server thinks authentication is complete, but client does not"));
+			return;
+		}
 	}
 
 	/*
@@ -452,8 +476,11 @@ void jabber_auth_handle_failure(JabberSt
 	char *msg;
 
 	if (js->auth_mech && js->auth_mech->handle_failure) {
-		xmlnode *stanza = js->auth_mech->handle_failure(js, packet);
-		if (stanza) {
+		xmlnode *stanza = NULL;
+		const char *msg = NULL;
+		JabberSaslState state = js->auth_mech->handle_failure(js, packet, &stanza, &msg);
+
+		if (state != JABBER_SASL_STATE_FAIL && stanza) {
 			jabber_send(js, stanza);
 			xmlnode_free(stanza);
 			return;
============================================================
--- libpurple/protocols/jabber/auth.h	5c420ab419bd1cd5f25ad5e609b280c3a063f838
+++ libpurple/protocols/jabber/auth.h	5de434da6e406659e76310786a8840555fff589c
@@ -29,13 +29,19 @@ typedef struct _JabberSaslMech JabberSas
 #include "jabber.h"
 #include "xmlnode.h"
 
+typedef enum {
+	JABBER_SASL_STATE_FAIL = -1,    /* Abort, Retry, Fail? */
+	JABBER_SASL_STATE_OK = 0,       /* Hooray! */
+	JABBER_SASL_STATE_CONTINUE = 1  /* More authentication required */
+} JabberSaslState;
+
 struct _JabberSaslMech {
 	gint8 priority; /* Higher priority will be tried before lower priority */
 	const gchar *name;
-	xmlnode *(*start)(JabberStream *js, xmlnode *mechanisms);
-	xmlnode *(*handle_challenge)(JabberStream *js, xmlnode *packet);
-	gboolean (*handle_success)(JabberStream *js, xmlnode *packet);
-	xmlnode *(*handle_failure)(JabberStream *js, xmlnode *packet);
+	JabberSaslState (*start)(JabberStream *js, xmlnode *mechanisms, xmlnode **reply, const char **msg);
+	JabberSaslState (*handle_challenge)(JabberStream *js, xmlnode *packet, xmlnode **reply, const char **msg);
+	JabberSaslState (*handle_success)(JabberStream *js, xmlnode *packet, const char **msg);
+	JabberSaslState (*handle_failure)(JabberStream *js, xmlnode *packet, xmlnode **reply, const char **msg);
 	void (*dispose)(JabberStream *js);
 };
 
============================================================
--- libpurple/protocols/jabber/auth_digest_md5.c	d9ecb35ff0a36daefb463c56905396dfadc8938f
+++ libpurple/protocols/jabber/auth_digest_md5.c	54b9882edca5af04170c7b4402fd1e8b5d9f7833
@@ -30,15 +30,16 @@
 #include "auth.h"
 #include "jabber.h"
 
-static xmlnode *digest_md5_start(JabberStream *js, xmlnode *packet)
+static JabberSaslState
+digest_md5_start(JabberStream *js, xmlnode *packet, xmlnode **response,
+                 const char **msg)
 {
-	xmlnode *auth;
-
-	auth = xmlnode_new("auth");
+	xmlnode *auth = xmlnode_new("auth");
 	xmlnode_set_namespace(auth, NS_XMPP_SASL);
 	xmlnode_set_attrib(auth, "mechanism", "DIGEST-MD5");
 
-	return auth;
+	*response = auth;
+	return JABBER_SASL_STATE_CONTINUE;
 }
 
 /* Parts of this algorithm are inspired by stuff in libgsasl */
@@ -163,19 +164,20 @@ generate_response_value(JabberID *jid, c
 	return z;
 }
 
-static xmlnode *digest_md5_handle_challenge(JabberStream *js, xmlnode *packet)
+static JabberSaslState
+digest_md5_handle_challenge(JabberStream *js, xmlnode *packet,
+                            xmlnode **response, const char **msg)
 {
 	xmlnode *reply = NULL;
 	char *enc_in = xmlnode_get_data(packet);
 	char *dec_in;
 	char *enc_out;
 	GHashTable *parts;
+	JabberSaslState state = JABBER_SASL_STATE_CONTINUE;
 
 	if (!enc_in) {
-		purple_connection_error_reason(js->gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Invalid response from server"));
-		return NULL;
+		*msg = _("Invalid response from server");
+		return JABBER_SASL_STATE_FAIL;
 	}
 
 	dec_in = (char *)purple_base64_decode(enc_in, NULL);
@@ -191,9 +193,8 @@ static xmlnode *digest_md5_handle_challe
 			reply = xmlnode_new("response");
 			xmlnode_set_namespace(reply, NS_XMPP_SASL);
 		} else {
-			purple_connection_error_reason(js->gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Invalid challenge from server"));
+			*msg = _("Invalid challenge from server");
+			state = JABBER_SASL_STATE_FAIL;
 		}
 		g_free(js->expected_rspauth);
 		js->expected_rspauth = NULL;
@@ -216,11 +217,10 @@ static xmlnode *digest_md5_handle_challe
 		if(!realm)
 			realm = js->user->domain;
 
-		if (nonce == NULL || realm == NULL)
-			purple_connection_error_reason(js->gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Invalid challenge from server"));
-		else {
+		if (nonce == NULL || realm == NULL) {
+			*msg = _("Invalid challenge from server");
+			state = JABBER_SASL_STATE_FAIL;
+		} else {
 			GString *response = g_string_new("");
 			char *a2;
 			char *auth_resp;
@@ -272,7 +272,8 @@ static xmlnode *digest_md5_handle_challe
 	g_free(dec_in);
 	g_hash_table_destroy(parts);
 
-	return reply;
+	*response = reply;
+	return state;
 }
 
 static JabberSaslMech digest_md5_mech = {
============================================================
--- libpurple/protocols/jabber/auth_plain.c	c86a14b6b296440a33e7495d4435eaf0df0ec61f
+++ libpurple/protocols/jabber/auth_plain.c	2bd068ef26d51259ac7adaed2443539c16753890
@@ -80,13 +80,16 @@ static void disallow_plaintext_auth(Purp
 		_("Server requires plaintext authentication over an unencrypted stream"));
 }
 
-static xmlnode *jabber_plain_start(JabberStream *js, xmlnode *packet)
+static JabberSaslState
+jabber_plain_start(JabberStream *js, xmlnode *packet, xmlnode **response, const char **error)
 {
 	PurpleAccount *account = purple_connection_get_account(js->gc);
 	char *msg;
 
-	if (jabber_stream_is_ssl(js) || purple_account_get_bool(account, "auth_plain_in_clear", FALSE))
-		return finish_plaintext_authentication(js);
+	if (jabber_stream_is_ssl(js) || purple_account_get_bool(account, "auth_plain_in_clear", FALSE)) {
+		*response = finish_plaintext_authentication(js);
+		return JABBER_SASL_STATE_OK;
+	}
 
 	msg = g_strdup_printf(_("%s requires plaintext authentication over an unencrypted connection.  Allow this and continue authentication?"),
 			purple_account_get_username(account));
@@ -97,7 +100,7 @@ static xmlnode *jabber_plain_start(Jabbe
 			account, NULL, NULL,
 			account, allow_plaintext_auth, disallow_plaintext_auth);
 	g_free(msg);
-	return NULL;
+	return JABBER_SASL_STATE_CONTINUE;
 }
 
 static JabberSaslMech plain_mech = {
============================================================
--- libpurple/protocols/jabber/auth_scram.c	022ddbb448c0ab860c4ad5ea1551018715877f05
+++ libpurple/protocols/jabber/auth_scram.c	403db21f131a6114fab65b6d0cf9b96cfc883ae3
@@ -341,7 +341,8 @@ static gchar *escape_username(const gcha
 	return tmp2;
 }
 
-static xmlnode *scram_start(JabberStream *js, xmlnode *mechanisms)
+static JabberSaslState
+scram_start(JabberStream *js, xmlnode *mechanisms, xmlnode **out, const char **error)
 {
 	xmlnode *reply;
 	JabberScramData *data;
@@ -355,8 +356,8 @@ static xmlnode *scram_start(JabberStream
 
 	prepped_node = jabber_saslprep(js->user->node);
 	if (!prepped_node) {
-		/* TODO: Error handling in the response value from scram_start */
-		return NULL;
+		*error = _("Unable to canonicalize username");
+		return JABBER_SASL_STATE_FAIL;
 	}
 
 	tmp = escape_username(prepped_node);
@@ -366,7 +367,8 @@ static xmlnode *scram_start(JabberStream
 	prepped_pass = jabber_saslprep(purple_connection_get_password(js->gc));
 	if (!prepped_pass) {
 		g_free(prepped_node);
-		return NULL;
+		*error = _("Unable to canonicalize password");
+		return JABBER_SASL_STATE_FAIL;
 	}
 
 	data = js->auth_mech_data = g_new0(JabberScramData, 1);
@@ -401,22 +403,26 @@ static xmlnode *scram_start(JabberStream
 	g_free(enc_out);
 	g_free(dec_out);
 
-	return reply;
+	*out = reply;
+	return JABBER_SASL_STATE_CONTINUE;
 }
 
-static xmlnode *scram_handle_challenge(JabberStream *js, xmlnode *challenge)
+static JabberSaslState
+scram_handle_challenge(JabberStream *js, xmlnode *challenge, xmlnode **out, const char **error)
 {
 	JabberScramData *data = js->auth_mech_data;
 	xmlnode *reply;
 	gchar *enc_in, *dec_in;
 	gchar *enc_out = NULL, *dec_out = NULL;
 	gsize len;
+	JabberSaslState state = JABBER_SASL_STATE_FAIL;
 
 	enc_in = xmlnode_get_data(challenge);
 	if (!enc_in || *enc_in == '\0') {
 		reply = xmlnode_new("abort");
 		xmlnode_set_namespace(reply, NS_XMPP_SASL);
 		data->step = -1;
+		*error = _("Invalid challenge from server");
 		goto out;
 	}
 
@@ -427,6 +433,7 @@ static xmlnode *scram_handle_challenge(J
 		reply = xmlnode_new("abort");
 		xmlnode_set_namespace(reply, NS_XMPP_SASL);
 		data->step = -1;
+		*error = _("Malicious challenge from server");
 		goto out;
 	}
 
@@ -436,6 +443,7 @@ static xmlnode *scram_handle_challenge(J
 		reply = xmlnode_new("abort");
 		xmlnode_set_namespace(reply, NS_XMPP_SASL);
 		data->step = -1;
+		*error = _("Invalid challenge from server");
 		goto out;
 	}
 
@@ -450,14 +458,18 @@ static xmlnode *scram_handle_challenge(J
 		xmlnode_insert_data(reply, enc_out, -1);
 	}
 
+	state = JABBER_SASL_STATE_CONTINUE;
+
 out:
 	g_free(enc_out);
 	g_free(dec_out);
 
-	return reply;
+	*out = reply;
+	return state;
 }
 
-static gboolean scram_handle_success(JabberStream *js, xmlnode *packet)
+static JabberSaslState
+scram_handle_success(JabberStream *js, xmlnode *packet, const char **error)
 {
 	JabberScramData *data = js->auth_mech_data;
 	char *enc_in, *dec_in;
@@ -468,28 +480,32 @@ static gboolean scram_handle_success(Jab
 	g_return_val_if_fail(enc_in != NULL && *enc_in != '\0', FALSE);
 
 	if (data->step == 3)
-		return TRUE;
+		return JABBER_SASL_STATE_OK;
 
-	if (data->step != 2)
-		return FALSE;
+	if (data->step != 2) {
+		*error = _("Unexpected response from server");
+		return JABBER_SASL_STATE_FAIL;
+	}
 
 	dec_in = (gchar *)purple_base64_decode(enc_in, &len);
 	g_free(enc_in);
 	if (!dec_in || len != strlen(dec_in)) {
 		/* Danger afoot; SCRAM shouldn't contain NUL bytes */
 		g_free(dec_in);
-		return FALSE;
+		*error = _("Invalid challenge from server");
+		return JABBER_SASL_STATE_FAIL;
 	}
 
 	purple_debug_misc("jabber", "decoded success: %s\n", dec_in);
 
 	if (!jabber_scram_feed_parser(data, dec_in, &dec_out) || dec_out != NULL) {
 		g_free(dec_out);
-		return FALSE;
+		*error = _("Invalid challenge from server");
+		return JABBER_SASL_STATE_FAIL;
 	}
 
 	/* Hooray */
-	return TRUE;
+	return JABBER_SASL_STATE_OK;
 }
 
 void jabber_scram_data_destroy(JabberScramData *data)


More information about the Commits mailing list