Fixed potential problem if auth was not called from the open callback.
authorMikael Hallendal <micke@imendio.com>
Sun, 25 Feb 2007 22:48:39 +0100
changeset 255 704881ac7788
parent 254 2fd96148acfa
child 256 2266e56746ed
Fixed potential problem if auth was not called from the open callback. The current SASL code required that you called authenticate from the open callback or the intial features message would be lost. Now the LmSASL object is iniated as soon as it's clear that we are going to talk XMPP. Added a SASL debug level. Some minor style fixes.
loudmouth/lm-connection.c
loudmouth/lm-debug.c
loudmouth/lm-debug.h
loudmouth/lm-sasl.c
loudmouth/lm-sasl.h
--- a/loudmouth/lm-connection.c	Sun Feb 25 01:15:25 2007 +0100
+++ b/loudmouth/lm-connection.c	Sun Feb 25 22:48:39 2007 +0100
@@ -696,6 +696,8 @@
 			    connection->stream_id);
 
 		connection->use_xmpp = TRUE;
+		
+		connection->sasl = lm_sasl_new (connection);
 	} else {
 		lm_verbose ("Old Jabber stream received: %s\n", 
 			    connection->stream_id);
@@ -872,9 +874,9 @@
 
 static LmHandlerResult
 connection_bind_reply (LmMessageHandler *handler,
-			LmConnection *connection,
-			LmMessage *message,
-			gpointer user_data)
+			LmConnection    *connection,
+			LmMessage       *message,
+			gpointer         user_data)
 {
 	LmMessage        *m;
 	LmMessageNode    *session_node;
@@ -913,11 +915,11 @@
 
 static LmHandlerResult
 _lm_connection_features_cb (LmMessageHandler *handler,
-			    LmConnection *connection,
-			    LmMessage *message,
-			    gpointer user_data)
+			    LmConnection     *connection,
+			    LmMessage        *message,
+			    gpointer          user_data)
 {
-	LmMessageNode    *bind_node;
+	LmMessageNode *bind_node;
 	
 	bind_node = lm_message_node_find_child (message->node, "bind");
 	if (bind_node) {
@@ -1249,11 +1251,11 @@
 						      notify);
 
 	if (connection->use_xmpp) {
-		connection->sasl = lm_sasl_new (connection,
-						username,
-						password,
-						connection->server,
-						connection_sasl_auth_finished);
+		lm_sasl_authenticate (connection->sasl,
+				      username, password,
+				      connection->server,
+				      connection_sasl_auth_finished);
+
 		connection->resource = g_strdup (resource);
 
 		connection->features_cb  =
--- a/loudmouth/lm-debug.c	Sun Feb 25 01:15:25 2007 +0100
+++ b/loudmouth/lm-debug.c	Sun Feb 25 22:48:39 2007 +0100
@@ -30,6 +30,7 @@
 	{"NET",          LM_LOG_LEVEL_NET},
 	{"PARSER",       LM_LOG_LEVEL_PARSER},
 	{"SSL",          LM_LOG_LEVEL_SSL},
+	{"SASL",         LM_LOG_LEVEL_SASL},
 	{"ALL",          LM_LOG_LEVEL_ALL}
 };
 
@@ -47,6 +48,12 @@
 		}
 		else if (log_level & LM_LOG_LEVEL_PARSER) {
 			g_print ("LM-PARSER: ");
+		} 
+		else if (log_level & LM_LOG_LEVEL_SASL) {
+			g_print ("LM-SASL: ");
+		}
+		else if (log_level & LM_LOG_LEVEL_SSL) {
+			g_print ("LM-SSL: ");
 		}
 	
 		g_print ("%s", message);
--- a/loudmouth/lm-debug.h	Sun Feb 25 01:15:25 2007 +0100
+++ b/loudmouth/lm-debug.h	Sun Feb 25 22:48:39 2007 +0100
@@ -28,10 +28,12 @@
 	LM_LOG_LEVEL_NET     = 1 << (G_LOG_LEVEL_USER_SHIFT + 1),
 	LM_LOG_LEVEL_PARSER  = 1 << (G_LOG_LEVEL_USER_SHIFT + 2),
 	LM_LOG_LEVEL_SSL     = 1 << (G_LOG_LEVEL_USER_SHIFT + 3),
+	LM_LOG_LEVEL_SASL    = 1 << (G_LOG_LEVEL_USER_SHIFT + 4),
 	LM_LOG_LEVEL_ALL     = (LM_LOG_LEVEL_NET |
 				LM_LOG_LEVEL_VERBOSE |
 				LM_LOG_LEVEL_PARSER |
-				LM_LOG_LEVEL_SSL)
+				LM_LOG_LEVEL_SSL |
+				LM_LOG_LEVEL_SASL)
 } LmLogLevelFlags;
 
 #ifndef LM_LOG_DOMAIN
--- a/loudmouth/lm-sasl.c	Sun Feb 25 01:15:25 2007 +0100
+++ b/loudmouth/lm-sasl.c	Sun Feb 25 22:48:39 2007 +0100
@@ -65,6 +65,9 @@
 	LmMessageHandler    *success_cb;
 	LmMessageHandler    *failure_cb;
 
+	gboolean             features_received;
+	gboolean             start_auth;
+
 	LmSASLResultHandler  handler;
 };
 
@@ -152,7 +155,9 @@
 
 	return result;
 error:
-	g_debug ("Failed to parse challenge: %s", challenge);
+	g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL, 
+	       "Failed to parse challenge: %s", challenge);
+
 	g_hash_table_destroy (result);
 	return NULL;
 }
@@ -209,7 +214,8 @@
 	response = g_string_new ("");
 
 	if (sasl->username == NULL || sasl->password == NULL) {
-		g_debug ("%s: no username or password provided", G_STRFUNC);
+		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+		       "%s: no username or password provided", G_STRFUNC);
 		if (sasl->handler) {
 			sasl->handler (sasl, sasl->connection, 
 				       FALSE, "no username/password provided");
@@ -219,7 +225,9 @@
 
 	nonce = g_hash_table_lookup (challenge, "nonce");
 	if (nonce == NULL || nonce == '\0') {
-		g_debug ("%s: server didn't provide a nonce in the challenge", G_STRFUNC);
+		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+		       "%s: server didn't provide a nonce in the challenge", 
+		       G_STRFUNC);
 		if (sasl->handler) {
 			sasl->handler (sasl, sasl->connection,
 				       FALSE, "server error");
@@ -393,7 +401,8 @@
 
 	encoded = lm_message_node_get_value (node);
 	if (!encoded) {
-		g_debug ("%s: got empty challenge!", G_STRFUNC);
+		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+		       "%s: got empty challenge!", G_STRFUNC);
 		return FALSE;
 	}
 
@@ -402,7 +411,8 @@
 	g_free(challenge);
 
 	if (!h) {
-		g_debug ("%s: server sent an invalid challenge", G_STRFUNC);
+		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+		       "%s: server sent an invalid challenge", G_STRFUNC);
 		if (sasl->handler) {
 			sasl->handler (sasl, sasl->connection, 
 				       FALSE, "server error");
@@ -418,7 +428,9 @@
 		sasl_digest_md5_check_server_response (sasl, h); 
 		break;
 	default:
-		g_debug ("%s: server sent a challenge at the wrong time", G_STRFUNC);
+		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+		       "%s: server sent a challenge at the wrong time", 
+		       G_STRFUNC);
 		if (sasl->handler) {
 			sasl->handler (sasl, sasl->connection,
 				       FALSE, "server error");
@@ -489,7 +501,9 @@
 	switch (sasl->auth_type) {
 	case AUTH_TYPE_PLAIN:
 		if (sasl->state != SASL_AUTH_STATE_PLAIN_STARTED) {
-			g_debug ("%s: server sent success before finishing auth", G_STRFUNC);
+			g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+			       "%s: server sent success before finishing auth", 
+			       G_STRFUNC);
 			if (sasl->handler) {
 				sasl->handler (sasl, sasl->connection, 
 					       FALSE, "server error");
@@ -499,7 +513,9 @@
 	case AUTH_TYPE_DIGEST:
 		if (sasl->state != SASL_AUTH_STATE_DIGEST_MD5_SENT_AUTH_RESPONSE &&
 		    sasl->state != SASL_AUTH_STATE_DIGEST_MD5_SENT_FINAL_RESPONSE) {
-			g_debug ("%s: server sent success before finishing auth", G_STRFUNC);
+			g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+			       "%s: server sent success before finishing auth", 
+			       G_STRFUNC);
 			if (sasl->handler) {
 				sasl->handler (sasl, sasl->connection, 
 					       FALSE, "server error");
@@ -511,7 +527,8 @@
 		break;
 	}
 
-	g_debug ("%s: SASL authentication successful", G_STRFUNC);
+	g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+	       "%s: SASL authentication successful", G_STRFUNC);
 
 	if (sasl->handler) {
 		sasl->handler (sasl, sasl->connection, TRUE, NULL);
@@ -547,7 +564,8 @@
 		}
 	}
 	
-	g_debug ("%s: SASL authentication failed: %s", G_STRFUNC, reason);
+	g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+	       "%s: SASL authentication failed: %s", G_STRFUNC, reason);
 
 	if (sasl->handler) {
 		sasl->handler (sasl, sasl->connection, FALSE, reason);
@@ -576,7 +594,9 @@
 		sasl->state = SASL_AUTH_STATE_PLAIN_STARTED;
 
 		if (sasl->username == NULL || sasl->password == NULL) {
-			g_debug ("%s: no username or password provided", G_STRFUNC);
+			g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+			       "%s: no username or password provided", 
+			       G_STRFUNC);
 			if (sasl->handler) {
 				sasl->handler (sasl, sasl->connection, FALSE, "no username/password provided");
 			}
@@ -623,12 +643,13 @@
 }
 
 static gboolean
-lm_sasl_authenticate (LmSASL *sasl, LmMessageNode *mechanisms)
+sasl_set_auth_type (LmSASL *sasl, LmMessageNode *mechanisms)
 {
 	LmMessageNode *m;
-	AuthType       auth_type = 0;
 	const gchar   *ns;
 
+	sasl->auth_type = 0;
+
 	ns = lm_message_node_get_attribute (mechanisms, "xmlns");
 	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH) != 0) {
 		return FALSE;
@@ -643,25 +664,38 @@
 			continue;
 		}
 		if (strcmp (name, "PLAIN") == 0) {
-			auth_type |= AUTH_TYPE_PLAIN;
+			sasl->auth_type |= AUTH_TYPE_PLAIN;
 			continue;
 		}
 		if (strcmp (name, "DIGEST-MD5") == 0) {
-			auth_type |= AUTH_TYPE_DIGEST;
+			sasl->auth_type |= AUTH_TYPE_DIGEST;
 			continue;
 		}
-		g_debug ("%s: unknown SASL auth mechanism: %s", G_STRFUNC, name);
+
+		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+		       "%s: unknown SASL auth mechanism: %s", G_STRFUNC, name);
 	}
-	if (auth_type == 0) {
-		g_debug ("%s: no supported SASL auth mechanisms found", G_STRFUNC);
+
+	return TRUE;
+}
+
+static gboolean
+sasl_authenticate (LmSASL *sasl)
+{
+	if (sasl->auth_type == 0) {
+		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL,
+		      "%s: no supported SASL auth mechanisms found",
+		      G_STRFUNC);
+
 		return FALSE;
 	}
+
 	/* Prefer DIGEST */
-	if (auth_type & AUTH_TYPE_DIGEST) {
+	if (sasl->auth_type & AUTH_TYPE_DIGEST) {
 		sasl->auth_type = AUTH_TYPE_DIGEST;
 		return sasl_start (sasl);
 	}
-	else if (auth_type & AUTH_TYPE_PLAIN) {
+	else if (sasl->auth_type & AUTH_TYPE_PLAIN) {
 		sasl->auth_type = AUTH_TYPE_PLAIN;
 		return sasl_start (sasl);
 	} 
@@ -678,45 +712,62 @@
     	LmMessageNode *mechanisms;
 	LmSASL        *sasl;
 
+	g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL, "Stream features received\n");
 	mechanisms = lm_message_node_find_child (message->node, "mechanisms");
 	if (!mechanisms) {
 		return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
 	}
 
 	sasl = (LmSASL *) user_data;
+	sasl->features_received = TRUE;
 
-	lm_sasl_authenticate (sasl, mechanisms);
+	sasl_set_auth_type (sasl, mechanisms);
+
+	if (sasl->start_auth) {
+		sasl_authenticate (sasl);
+	}
 
 	return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
 }
 
 LmSASL *
-lm_sasl_new (LmConnection        *connection,
-	     const gchar         *username,
-	     const gchar         *password,
-	     const gchar         *server,
-	     LmSASLResultHandler  handler)
+lm_sasl_new (LmConnection *connection)
 {
-	LmSASL *sasl = g_new0 (LmSASL, 1);
+	LmSASL *sasl;
+	
+	sasl = g_new0 (LmSASL, 1);
 
 	sasl->connection = connection;
+	sasl->features_received = FALSE;
+	sasl->start_auth = FALSE;
+
+	sasl->features_cb = lm_message_handler_new (sasl_features_cb,
+						    sasl,
+						    NULL);
+
+	lm_connection_register_message_handler (connection,
+						sasl->features_cb,
+						LM_MESSAGE_TYPE_STREAM_FEATURES,
+						LM_HANDLER_PRIORITY_FIRST);
+	return sasl;
+}
+
+void
+lm_sasl_authenticate (LmSASL              *sasl,
+		      const gchar         *username,
+		      const gchar         *password,
+		      const gchar         *server,
+		      LmSASLResultHandler  handler)
+{
 	sasl->username   = g_strdup (username);
 	sasl->password   = g_strdup (password);
 	sasl->server     = g_strdup (server);
 	sasl->handler    = handler;
 
-	sasl->features_cb = lm_message_handler_new (sasl_features_cb,
-						    sasl,
-						    NULL);
-	lm_connection_register_message_handler (connection,
-						sasl->features_cb,
-						LM_MESSAGE_TYPE_STREAM_FEATURES,
-						LM_HANDLER_PRIORITY_FIRST);
-
 	sasl->challenge_cb = lm_message_handler_new (sasl_challenge_cb,
 						     sasl,
 						     NULL);
-	lm_connection_register_message_handler (connection,
+	lm_connection_register_message_handler (sasl->connection,
 						sasl->challenge_cb,
 						LM_MESSAGE_TYPE_CHALLENGE,
 						LM_HANDLER_PRIORITY_FIRST);
@@ -724,7 +775,7 @@
 	sasl->success_cb = lm_message_handler_new (sasl_success_cb,
 						   sasl,
 						   NULL);
-	lm_connection_register_message_handler (connection,
+	lm_connection_register_message_handler (sasl->connection,
 						sasl->success_cb,
 						LM_MESSAGE_TYPE_SUCCESS,
 						LM_HANDLER_PRIORITY_FIRST);
@@ -732,11 +783,16 @@
 	sasl->failure_cb = lm_message_handler_new (sasl_failure_cb,
 						   sasl,
 						   NULL);
-	lm_connection_register_message_handler (connection,
+	lm_connection_register_message_handler (sasl->connection,
 						sasl->failure_cb,
 						LM_MESSAGE_TYPE_FAILURE,
 						LM_HANDLER_PRIORITY_FIRST);
-	return sasl;
+
+	if (sasl->features_received) {
+		sasl_authenticate (sasl);
+	} else {
+		sasl->start_auth = TRUE;
+	}
 }
 
 void
--- a/loudmouth/lm-sasl.h	Sun Feb 25 01:15:25 2007 +0100
+++ b/loudmouth/lm-sasl.h	Sun Feb 25 22:48:39 2007 +0100
@@ -36,11 +36,13 @@
 				     gboolean success,
 				     const gchar *reason);
 
-LmSASL *lm_sasl_new (LmConnection *connection,
-		     const gchar *username,
-		     const gchar *password,
-		     const gchar *server,
-		     LmSASLResultHandler handler);
+LmSASL *lm_sasl_new (LmConnection *connection);
+
+void lm_sasl_authenticate (LmSASL *sasl, 
+			   const gchar *username,
+			   const gchar *password,
+			   const gchar *server,
+			   LmSASLResultHandler handler);
 
 void lm_sasl_free (LmSASL *sasl);