aboutsummaryrefslogtreecommitdiffstats
path: root/protocols
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2006-09-22 20:39:31 +0200
committerWilmer van der Gaast <wilmer@gaast.net>2006-09-22 20:39:31 +0200
commitfe7a55434385fd858453dffdbb425a21f41e3859 (patch)
tree31f7d29dd436d59d80d06674c12b98b934ddb467 /protocols
parent8d7429102adf8dce6844f2f3da2723d1f87c6442 (diff)
Better detection of successful IQ authentication (using packet caching),
properly working SASL authentication (although only PLAIN so far).
Diffstat (limited to 'protocols')
-rw-r--r--protocols/jabber/io.c33
-rw-r--r--protocols/jabber/iq.c34
-rw-r--r--protocols/jabber/jabber.c6
-rw-r--r--protocols/jabber/jabber.h6
-rw-r--r--protocols/jabber/jabber_util.c29
-rw-r--r--protocols/jabber/sasl.c10
6 files changed, 105 insertions, 13 deletions
diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c
index 8f2ce0f1..333e3123 100644
--- a/protocols/jabber/io.c
+++ b/protocols/jabber/io.c
@@ -218,7 +218,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )
{
struct gaim_connection *gc = data;
struct jabber_data *jd = gc->proto_data;
- struct xt_node *c;
+ struct xt_node *c, *reply;
c = xt_find_node( node->children, "starttls" );
if( c )
@@ -230,9 +230,36 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )
*/
}
+ if( ( c = xt_find_node( node->children, "bind" ) ) )
+ {
+ reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) );
+ xt_add_attr( reply, "xmlns", "urn:ietf:params:xml:ns:xmpp-bind" );
+ reply = jabber_make_packet( "iq", "set", NULL, reply );
+ jabber_cache_packet( gc, reply );
+
+ if( !jabber_write_packet( gc, reply ) )
+ return XT_ABORT;
+
+ jd->flags |= JFLAG_WAIT_BIND;
+ }
+
+ if( ( c = xt_find_node( node->children, "session" ) ) )
+ {
+ reply = xt_new_node( "session", NULL, NULL );
+ xt_add_attr( reply, "xmlns", "urn:ietf:params:xml:ns:xmpp-session" );
+ reply = jabber_make_packet( "iq", "set", NULL, reply );
+ jabber_cache_packet( gc, reply );
+
+ if( !jabber_write_packet( gc, reply ) )
+ return XT_ABORT;
+
+ jd->flags |= JFLAG_WAIT_SESSION;
+ }
+
/* This flag is already set if we authenticated via SASL, so now
- we can resume the session in the new stream. */
- if( jd->flags & JFLAG_AUTHENTICATED )
+ we can resume the session in the new stream, if we don't have
+ to bind/initialize the session. */
+ if( jd->flags & JFLAG_AUTHENTICATED && ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
{
if( !jabber_get_roster( gc ) )
return XT_ABORT;
diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c
index bcce5289..fbb4a38b 100644
--- a/protocols/jabber/iq.c
+++ b/protocols/jabber/iq.c
@@ -27,7 +27,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
{
struct gaim_connection *gc = data;
struct jabber_data *jd = gc->proto_data;
- struct xt_node *query, *reply = NULL;
+ struct xt_node *query, *reply = NULL, *orig = NULL;
char *s, *type, *xmlns;
int st;
@@ -39,6 +39,9 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
xmlns = xt_find_attr( query, "xmlns" );
+ if( ( s = xt_find_attr( node, "id" ) ) )
+ orig = jabber_packet_from_cache( gc, s );
+
if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 )
{
/* Time to authenticate ourselves! */
@@ -81,8 +84,8 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
}
reply = jabber_make_packet( "iq", "set", NULL, reply );
+ jabber_cache_packet( gc, reply );
st = jabber_write_packet( gc, reply );
- xt_free_node( reply );
return st ? XT_HANDLED : XT_ABORT;
}
@@ -105,16 +108,35 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
presence_announce( gc );
}
- else if( strcmp( type, "result" ) == 0 )
+ else if( strcmp( type, "result" ) == 0 && orig )
{
- /* If we weren't authenticated yet, let's assume we are now.
- There are cleaner ways to do this, probably, but well.. */
- if( !( jd->flags & JFLAG_AUTHENTICATED ) )
+ struct xt_node *node;
+
+ if( !( jd->flags & JFLAG_AUTHENTICATED ) &&
+ ( node = xt_find_node( orig->children, "query" ) ) &&
+ ( node = xt_find_node( node->children, "username" ) ) &&
+ node->text_len )
{
+ /* This happens when we just successfully authenticated
+ the old (non-SASL) way. */
jd->flags |= JFLAG_AUTHENTICATED;
if( !jabber_get_roster( gc ) )
return XT_ABORT;
}
+ else if( ( node = xt_find_node( orig->children, "bind" ) ) ||
+ ( node = xt_find_node( orig->children, "session" ) ) )
+ {
+ if( strcmp( node->name, "bind" ) == 0 )
+ jd->flags &= ~JFLAG_WAIT_BIND;
+ else if( strcmp( node->name, "session" ) == 0 )
+ jd->flags &= ~JFLAG_WAIT_SESSION;
+
+ if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
+ {
+ if( !jabber_get_roster( gc ) )
+ return XT_ABORT;
+ }
+ }
}
else if( strcmp( type, "error" ) == 0 )
{
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 13eac23e..c8525db5 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -75,6 +75,8 @@ static void jabber_login( account_t *acc )
*jd->server = 0;
jd->server ++;
+ jd->node_cache = xt_new_node( "cache", NULL, NULL );
+
if( set_getbool( &acc->set, "ssl" ) )
{
signoff( gc );
@@ -102,6 +104,10 @@ static void jabber_close( struct gaim_connection *gc )
if( jd->fd >= 0 )
closesocket( jd->fd );
+ if( jd->tx_len )
+ g_free( jd->txq );
+
+ xt_free_node( jd->node_cache );
xt_free( jd->xt );
g_free( jd->username );
diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h
index f8b604b0..c2d3867e 100644
--- a/protocols/jabber/jabber.h
+++ b/protocols/jabber/jabber.h
@@ -34,6 +34,8 @@ typedef enum
JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream and want to do auth. */
JFLAG_AUTHENTICATED = 2, /* Set when we're successfully authenticatd. */
JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after SASL or TLS). */
+ JFLAG_WAIT_SESSION = 8, /* Set if we sent a <session> tag and need a reply before we continue. */
+ JFLAG_WAIT_BIND = 16, /* ... for <bind> tag. */
} jabber_flags_t;
/* iq.c */
@@ -52,6 +54,8 @@ int presence_send( struct gaim_connection *gc, char *to, char *show, char *statu
char *set_eval_resprio( set_t *set, char *value );
char *set_eval_tls( set_t *set, char *value );
struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children );
+void jabber_cache_packet( struct gaim_connection *gc, struct xt_node *node );
+struct xt_node *jabber_packet_from_cache( struct gaim_connection *gc, char *id );
/* io.c */
int jabber_write_packet( struct gaim_connection *gc, struct xt_node *node );
@@ -81,6 +85,8 @@ struct jabber_data
char *username; /* USERNAME@server */
char *server; /* username@SERVER -=> server/domain, not hostname */
+
+ struct xt_node *node_cache;
};
#endif
diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c
index 46811d05..88b9e55d 100644
--- a/protocols/jabber/jabber_util.c
+++ b/protocols/jabber/jabber_util.c
@@ -51,18 +51,43 @@ char *set_eval_tls( set_t *set, char *value )
struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children )
{
- char *id = g_strdup_printf( "BeeX%04x", next_id++ );
struct xt_node *node;
node = xt_new_node( name, NULL, children );
- xt_add_attr( node, "id", id );
if( type )
xt_add_attr( node, "type", type );
if( to )
xt_add_attr( node, "to", to );
+ return node;
+}
+
+/* Cache a node/packet for later use. Mainly useful for IQ packets if you need
+ them when you receive the response. Use this BEFORE sending the packet so
+ it'll get an id= tag, and do NOT free() the packet after writing it! */
+void jabber_cache_packet( struct gaim_connection *gc, struct xt_node *node )
+{
+ struct jabber_data *jd = gc->proto_data;
+ char *id = g_strdup_printf( "BeeX%04x", next_id++ );
+
+ /* FIXME: Maybe start using g_error() here if nodes still have a parent, for example? */
+
+ xt_add_attr( node, "id", id );
+ xt_add_child( jd->node_cache, node );
g_free( id );
+}
+
+/* Emptying this cache is a BIG TODO! */
+struct xt_node *jabber_packet_from_cache( struct gaim_connection *gc, char *id )
+{
+ struct jabber_data *jd = gc->proto_data;
+ struct xt_node *node;
+ char *s;
+
+ for( node = jd->node_cache->children; node; node = node->next )
+ if( ( s = xt_find_attr( node, "id" ) ) && strcmp( id, s ) == 0 )
+ break;
return node;
}
diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c
index 2f75e733..13ff9d26 100644
--- a/protocols/jabber/sasl.c
+++ b/protocols/jabber/sasl.c
@@ -70,7 +70,13 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data )
reply = xt_new_node( "auth", NULL, NULL );
xt_add_attr( reply, "xmlns", SASL_NS );
- if( sup_plain )
+ if( sup_digest && 0 )
+ {
+ xt_add_attr( reply, "mechanism", "DIGEST-MD5" );
+
+ /* The rest will be done later, when we receive a <challenge/>. */
+ }
+ else if( sup_plain )
{
int len;
@@ -140,5 +146,5 @@ gboolean sasl_supported( struct gaim_connection *gc )
{
struct jabber_data *jd = gc->proto_data;
- return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != NULL;
+ return ( (void*) ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) ) != NULL;
}