diff options
Diffstat (limited to 'protocols/jabber/iq.c')
-rw-r--r-- | protocols/jabber/iq.c | 274 |
1 files changed, 149 insertions, 125 deletions
diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index ae4ed099..1b968739 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -27,161 +27,161 @@ 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, *orig = NULL, *c; - char *s, *type, *xmlns; - int st; + char *type, *s; - query = xt_find_node( node->children, "query" ); type = xt_find_attr( node, "type" ); if( !type ) - return XT_HANDLED; /* Ignore it for now, don't know what's best... */ + { + hide_login_progress_error( gc, "Received IQ packet without type!" ); + signoff( gc ); + return XT_ABORT; + } + + if( ( s = xt_find_attr( node, "id" ) ) && + ( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) ) + { + struct jabber_cache_entry *entry; + + entry = g_hash_table_lookup( jd->node_cache, s ); + + if( entry == NULL ) + serv_got_crap( gc, "WARNING: Received IQ %s packet with unknown/expired ID %s!", type, s ); + else if( entry->func ) + return entry->func( gc, node, entry->node ); + } + + return XT_HANDLED; +} + +static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); + +int jabber_init_iq_auth( struct gaim_connection *gc ) +{ + struct jabber_data *jd = gc->proto_data; + struct xt_node *node; + int st; + + node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) ); + xt_add_attr( node, "xmlns", "jabber:iq:auth" ); + node = jabber_make_packet( "iq", "get", NULL, node ); - xmlns = xt_find_attr( query, "xmlns" ); + jabber_cache_add( gc, node, jabber_do_iq_auth ); + st = jabber_write_packet( gc, node ); - if( ( s = xt_find_attr( node, "id" ) ) ) - orig = jabber_cache_get( gc, s ); + return st; +} + +static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ + struct jabber_data *jd = gc->proto_data; + struct xt_node *reply, *query; + xt_status st; + char *s; - if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 ) + query = xt_find_node( node->children, "query" ); + + /* Time to authenticate ourselves! */ + reply = xt_new_node( "query", NULL, NULL ); + xt_add_attr( reply, "xmlns", "jabber:iq:auth" ); + xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); + xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) ); + + if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) ) { - /* Time to authenticate ourselves! */ - reply = xt_new_node( "query", NULL, NULL ); - xt_add_attr( reply, "xmlns", "jabber:iq:auth" ); - xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); - xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) ); + /* We can do digest authentication, it seems, and of + course we prefer that. */ + SHA_CTX sha; + char hash_hex[40]; + unsigned char hash[20]; + int i; - if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) ) - { - /* We can do digest authentication, it seems, and of - course we prefer that. */ - SHA_CTX sha; - char hash_hex[40]; - unsigned char hash[20]; - int i; - - shaInit( &sha ); - shaUpdate( &sha, (unsigned char*) s, strlen( s ) ); - shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) ); - shaFinal( &sha, hash ); - - for( i = 0; i < 20; i ++ ) - sprintf( hash_hex + i * 2, "%02x", hash[i] ); - - xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) ); - } - else if( xt_find_node( query->children, "password" ) ) - { - /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ - xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) ); - } - else - { - xt_free_node( reply ); - - hide_login_progress( gc, "Can't find suitable authentication method" ); - signoff( gc ); - return XT_ABORT; - } + shaInit( &sha ); + shaUpdate( &sha, (unsigned char*) s, strlen( s ) ); + shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) ); + shaFinal( &sha, hash ); - reply = jabber_make_packet( "iq", "set", NULL, reply ); - jabber_cache_add( gc, reply ); - st = jabber_write_packet( gc, reply ); + for( i = 0; i < 20; i ++ ) + sprintf( hash_hex + i * 2, "%02x", hash[i] ); - return st ? XT_HANDLED : XT_ABORT; + xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) ); } - if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:roster" ) == 0 ) + else if( xt_find_node( query->children, "password" ) ) { - struct xt_node *node; - - node = query->children; - while( ( node = xt_find_node( node, "item" ) ) ) - { - char *jid = xt_find_attr( node, "jid" ); - char *name = xt_find_attr( node, "name" ); - char *sub = xt_find_attr( node, "subscription" ); - - if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) - add_buddy( gc, NULL, jid, name ); - - node = node->next; - } - - account_online( gc ); + /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ + xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) ); } - else if( strcmp( type, "result" ) == 0 && orig ) + else { - struct xt_node *c; + xt_free_node( reply ); - if( !( jd->flags & JFLAG_AUTHENTICATED ) && - ( c = xt_find_node( orig->children, "query" ) ) && - ( c = xt_find_node( c->children, "username" ) ) && - c->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; - } - /* Tricky: Look for <bind> in the reply, because the server - should confirm the chosen resource string there. For - <session>, however, look in the cache, because the server - will probably not include it in its reply. */ - else if( ( c = xt_find_node( node->children, "bind" ) ) || - ( c = xt_find_node( orig->children, "session" ) ) ) - { - if( strcmp( c->name, "bind" ) == 0 ) - { - c = xt_find_node( c->children, "jid" ); - if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && - strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 ) - serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 ); - - jd->flags &= ~JFLAG_WAIT_BIND; - } - else if( strcmp( c->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; - } - } + hide_login_progress( gc, "Can't find suitable authentication method" ); + signoff( gc ); + return XT_ABORT; } - else if( strcmp( type, "error" ) == 0 ) + + reply = jabber_make_packet( "iq", "set", NULL, reply ); + jabber_cache_add( gc, reply, jabber_finish_iq_auth ); + st = jabber_write_packet( gc, reply ); + + return st ? XT_HANDLED : XT_ABORT; +} + +static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ + char *type = xt_find_attr( node, "type" ); + struct jabber_data *jd = gc->proto_data; + + if( strcmp( type, "error" ) == 0 ) + { + hide_login_progress( gc, "Authentication failure" ); + signoff( gc ); + return XT_ABORT; + } + else if( strcmp( type, "result" ) == 0 ) { - if( !( jd->flags & JFLAG_AUTHENTICATED ) && - orig && - ( c = xt_find_node( orig->children, "query" ) ) && - ( c = xt_find_node( c->children, "username" ) ) && - c->text_len ) - { - hide_login_progress( gc, "Authentication failure" ); - signoff( gc ); + /* This happens when we just successfully authenticated the + old (non-SASL) way. */ + jd->flags |= JFLAG_AUTHENTICATED; + if( !jabber_get_roster( gc ) ) return XT_ABORT; - } } return XT_HANDLED; } -int jabber_start_iq_auth( struct gaim_connection *gc ) +xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) { struct jabber_data *jd = gc->proto_data; - struct xt_node *node; - int st; + struct xt_node *c; + char *s; - node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) ); - xt_add_attr( node, "xmlns", "jabber:iq:auth" ); - node = jabber_make_packet( "iq", "get", NULL, node ); + if( ( c = xt_find_node( node->children, "bind" ) ) ) + { + c = xt_find_node( c->children, "jid" ); + if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && + strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 ) + serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 ); + + jd->flags &= ~JFLAG_WAIT_BIND; + } + else + { + jd->flags &= ~JFLAG_WAIT_SESSION; + } - st = jabber_write_packet( gc, node ); + if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) + { + if( !jabber_get_roster( gc ) ) + return XT_ABORT; + } - xt_free_node( node ); - return st; + return XT_HANDLED; } +static xt_status jabber_parse_roster( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); + int jabber_get_roster( struct gaim_connection *gc ) { struct xt_node *node; @@ -193,12 +193,36 @@ int jabber_get_roster( struct gaim_connection *gc ) xt_add_attr( node, "xmlns", "jabber:iq:roster" ); node = jabber_make_packet( "iq", "get", NULL, node ); + jabber_cache_add( gc, node, jabber_parse_roster ); st = jabber_write_packet( gc, node ); - xt_free_node( node ); return st; } +static xt_status jabber_parse_roster( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ + struct xt_node *query, *c; + + query = xt_find_node( node->children, "query" ); + + c = query->children; + while( ( c = xt_find_node( c, "item" ) ) ) + { + char *jid = xt_find_attr( c, "jid" ); + char *name = xt_find_attr( c, "name" ); + char *sub = xt_find_attr( c, "subscription" ); + + if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) + add_buddy( gc, NULL, jid, name ); + + c = c->next; + } + + account_online( gc ); + + return XT_HANDLED; +} + int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name ) { struct xt_node *node; |