summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Aurich <darkrain42@pidgin.im>2009-12-01 07:32:53 +0000
committerPaul Aurich <darkrain42@pidgin.im>2009-12-01 07:32:53 +0000
commit914c238288f4fe2114d2c27082dddde74229408a (patch)
tree23731792c985a7247219893e70e0137521150421
parentc0f35ed74c23c0b1efe92e2aa5f792054e90b22e (diff)
downloadpidgin-914c238288f4fe2114d2c27082dddde74229408a.tar.gz
Let's try a more complex set of return states / values for auth mechs.
This won't build with Cyrus support yet.
-rw-r--r--libpurple/protocols/jabber/auth.c47
-rw-r--r--libpurple/protocols/jabber/auth.h14
-rw-r--r--libpurple/protocols/jabber/auth_digest_md5.c39
-rw-r--r--libpurple/protocols/jabber/auth_plain.c11
-rw-r--r--libpurple/protocols/jabber/auth_scram.c44
5 files changed, 104 insertions, 51 deletions
diff --git a/libpurple/protocols/jabber/auth.c b/libpurple/protocols/jabber/auth.c
index 64df7b5de9..c2a0125fe3 100644
--- a/libpurple/protocols/jabber/auth.c
+++ b/libpurple/protocols/jabber/auth.c
@@ -162,8 +162,10 @@ jabber_auth_start(JabberStream *js, xmlnode *packet)
{
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, xmlnode *packet)
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(JabberStream *js, xmlnode *packet)
}
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(JabberStream *js, xmlnode *packet)
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(JabberStream *js, xmlnode *packet)
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;
diff --git a/libpurple/protocols/jabber/auth.h b/libpurple/protocols/jabber/auth.h
index caf870da2c..88fa67cee5 100644
--- a/libpurple/protocols/jabber/auth.h
+++ b/libpurple/protocols/jabber/auth.h
@@ -29,13 +29,19 @@ typedef struct _JabberSaslMech JabberSaslMech;
#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);
};
diff --git a/libpurple/protocols/jabber/auth_digest_md5.c b/libpurple/protocols/jabber/auth_digest_md5.c
index 12ad950f1e..0f9cdba987 100644
--- a/libpurple/protocols/jabber/auth_digest_md5.c
+++ b/libpurple/protocols/jabber/auth_digest_md5.c
@@ -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, const char *passwd, const char *nonce,
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_challenge(JabberStream *js, xmlnode *packet)
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_challenge(JabberStream *js, xmlnode *packet)
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_challenge(JabberStream *js, xmlnode *packet)
g_free(dec_in);
g_hash_table_destroy(parts);
- return reply;
+ *response = reply;
+ return state;
}
static JabberSaslMech digest_md5_mech = {
diff --git a/libpurple/protocols/jabber/auth_plain.c b/libpurple/protocols/jabber/auth_plain.c
index 5f1b7b46d7..f810787649 100644
--- a/libpurple/protocols/jabber/auth_plain.c
+++ b/libpurple/protocols/jabber/auth_plain.c
@@ -80,13 +80,16 @@ static void disallow_plaintext_auth(PurpleAccount *account)
_("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(JabberStream *js, xmlnode *packet)
account, NULL, NULL,
account, allow_plaintext_auth, disallow_plaintext_auth);
g_free(msg);
- return NULL;
+ return JABBER_SASL_STATE_CONTINUE;
}
static JabberSaslMech plain_mech = {
diff --git a/libpurple/protocols/jabber/auth_scram.c b/libpurple/protocols/jabber/auth_scram.c
index d326ca383d..eb904975ee 100644
--- a/libpurple/protocols/jabber/auth_scram.c
+++ b/libpurple/protocols/jabber/auth_scram.c
@@ -341,7 +341,8 @@ static gchar *escape_username(const gchar *in)
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 *js, xmlnode *mechanisms)
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 *js, xmlnode *mechanisms)
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 *js, xmlnode *mechanisms)
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(JabberStream *js, xmlnode *challenge)
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(JabberStream *js, xmlnode *challenge)
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(JabberStream *js, xmlnode *challenge)
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(JabberStream *js, xmlnode *packet)
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)