aboutsummaryrefslogtreecommitdiffstats
path: root/protocols
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2006-09-22 18:56:58 +0200
committerWilmer van der Gaast <wilmer@gaast.net>2006-09-22 18:56:58 +0200
commit8d7429102adf8dce6844f2f3da2723d1f87c6442 (patch)
tree78a178e4798f8f11ac5590137efc0642aeea6378 /protocols
parent59974884ba72d6e8fa008d07ee93bd228d30a99c (diff)
Fixed return value on incomplete write()s in write handler, protection
against write()ing to sockets that are closed already, hopefully sane detection for SASL support, and only sending type=unavailable presence tag to logged in sessions.
Diffstat (limited to 'protocols')
-rw-r--r--protocols/jabber/io.c67
-rw-r--r--protocols/jabber/iq.c2
-rw-r--r--protocols/jabber/jabber.h4
-rw-r--r--protocols/jabber/sasl.c20
-rw-r--r--protocols/nogaim.c5
5 files changed, 86 insertions, 12 deletions
diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c
index c7c1d8d9..8f2ce0f1 100644
--- a/protocols/jabber/io.c
+++ b/protocols/jabber/io.c
@@ -72,6 +72,9 @@ static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition
struct jabber_data *jd = gc->proto_data;
int st;
+ if( jd->fd == -1 )
+ return FALSE;
+
st = write( jd->fd, jd->txq, jd->tx_len );
if( st == jd->tx_len )
@@ -85,6 +88,10 @@ static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition
}
else if( st == 0 || ( st < 0 && !sockerr_again() ) )
{
+ /* Set fd to -1 to make sure we won't write to it anymore. */
+ closesocket( jd->fd ); /* Shouldn't be necessary after errors? */
+ jd->fd = -1;
+
hide_login_progress_error( gc, "Short write() to server" );
signoff( gc );
return FALSE;
@@ -98,7 +105,7 @@ static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition
g_free( jd->txq );
jd->txq = s;
- return FALSE;
+ return TRUE;
}
else
{
@@ -115,6 +122,9 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
char buf[512];
int st;
+ if( jd->fd == -1 )
+ return FALSE;
+
st = read( fd, buf, sizeof( buf ) );
if( st > 0 )
@@ -138,7 +148,6 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
if( jd->flags & JFLAG_STREAM_RESTART )
{
jd->flags &= ~JFLAG_STREAM_RESTART;
- xt_reset( jd->xt );
jabber_start_stream( gc );
}
@@ -155,7 +164,12 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
if( g_strcasecmp( jd->xt->root->name, "stream:stream" ) == 0 )
{
jd->flags |= JFLAG_STREAM_STARTED;
- return jabber_start_auth( gc );
+
+ /* If there's no version attribute, assume
+ this is an old server that can't do SASL
+ authentication. */
+ if( !sasl_supported( gc ) )
+ return jabber_start_iq_auth( gc );
}
else
{
@@ -167,6 +181,9 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
}
else if( st == 0 || ( st < 0 && !sockerr_again() ) )
{
+ closesocket( jd->fd );
+ jd->fd = -1;
+
hide_login_progress_error( gc, "Error while reading from server" );
signoff( gc );
return FALSE;
@@ -197,6 +214,33 @@ static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data )
return XT_ABORT;
}
+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;
+
+ c = xt_find_node( node->children, "starttls" );
+ if( c )
+ {
+ /*
+ jd->flags |= JFLAG_SUPPORTS_TLS;
+ if( xt_find_node( c->children, "required" ) )
+ jd->flags |= JFLAG_REQUIRES_TLS;
+ */
+ }
+
+ /* 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 )
+ {
+ if( !jabber_get_roster( gc ) )
+ return XT_ABORT;
+ }
+
+ return XT_HANDLED;
+}
+
static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data )
{
printf( "Received unknown packet:\n" );
@@ -207,9 +251,10 @@ static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data )
static const struct xt_handler_entry jabber_handlers[] = {
{ "stream:stream", "<root>", jabber_end_of_stream },
- { "iq", "stream:stream", jabber_pkt_iq },
{ "message", "stream:stream", jabber_pkt_message },
{ "presence", "stream:stream", jabber_pkt_presence },
+ { "iq", "stream:stream", jabber_pkt_iq },
+ { "stream:features", "stream:stream", jabber_pkt_features },
{ "mechanisms", "stream:features", sasl_pkt_mechanisms },
{ "challenge", "stream:stream", sasl_pkt_challenge },
{ "success", "stream:stream", sasl_pkt_result },
@@ -230,7 +275,8 @@ gboolean jabber_start_stream( struct gaim_connection *gc )
jd->xt = xt_new( gc );
jd->xt->handlers = (struct xt_handler_entry*) jabber_handlers;
- jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, gc );
+ if( jd->r_inpa <= 0 )
+ jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, gc );
greet = g_strdup_printf( "<?xml version='1.0' ?>"
"<stream:stream to=\"%s\" xmlns=\"jabber:client\" "
@@ -253,11 +299,14 @@ void jabber_end_stream( struct gaim_connection *gc )
{
char eos[] = "</stream:stream>";
struct xt_node *node;
- int st;
+ int st = 1;
- node = jabber_make_packet( "presence", "unavailable", NULL, NULL );
- st = jabber_write_packet( gc, node );
- xt_free_node( node );
+ if( gc->flags & OPT_LOGGED_IN )
+ {
+ node = jabber_make_packet( "presence", "unavailable", NULL, NULL );
+ st = jabber_write_packet( gc, node );
+ xt_free_node( node );
+ }
if( st )
jabber_write( gc, eos, strlen( eos ) );
diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c
index 119176f9..bcce5289 100644
--- a/protocols/jabber/iq.c
+++ b/protocols/jabber/iq.c
@@ -129,7 +129,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
return XT_HANDLED;
}
-int jabber_start_auth( struct gaim_connection *gc )
+int jabber_start_iq_auth( struct gaim_connection *gc )
{
struct jabber_data *jd = gc->proto_data;
struct xt_node *node;
diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h
index 03fe57a7..f8b604b0 100644
--- a/protocols/jabber/jabber.h
+++ b/protocols/jabber/jabber.h
@@ -34,12 +34,11 @@ 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_SUPPORTS_TLS = 8, /* Set when there's <starttls/> in <stream:features>. */
} jabber_flags_t;
/* iq.c */
xt_status jabber_pkt_iq( struct xt_node *node, gpointer data );
-int jabber_start_auth( struct gaim_connection *gc );
+int jabber_start_iq_auth( struct gaim_connection *gc );
int jabber_get_roster( struct gaim_connection *gc );
xt_status jabber_pkt_message( struct xt_node *node, gpointer data );
@@ -65,6 +64,7 @@ void jabber_end_stream( struct gaim_connection *gc );
xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data );
xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data );
xt_status sasl_pkt_result( struct xt_node *node, gpointer data );
+gboolean sasl_supported( struct gaim_connection *gc );
struct jabber_data
{
diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c
index da577877..2f75e733 100644
--- a/protocols/jabber/sasl.c
+++ b/protocols/jabber/sasl.c
@@ -34,6 +34,15 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data )
char *s;
int sup_plain = 0, sup_digest = 0;
+ if( !sasl_supported( gc ) )
+ {
+ /* Should abort this now, since we should already be doing
+ IQ authentication. Strange things happen when you try
+ to do both... */
+ serv_got_crap( gc, "XMPP 1.0 non-compliant server seems to support SASL, please report this as a BitlBee bug!" );
+ return XT_HANDLED;
+ }
+
s = xt_find_attr( node, "xmlns" );
if( !s || strcmp( s, SASL_NS ) != 0 )
{
@@ -93,6 +102,7 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data )
xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data )
{
+ return XT_HANDLED;
}
xt_status sasl_pkt_result( struct xt_node *node, gpointer data )
@@ -122,3 +132,13 @@ xt_status sasl_pkt_result( struct xt_node *node, gpointer data )
return XT_HANDLED;
}
+
+/* This one is needed to judge if we'll do authentication using IQ or SASL.
+ It's done by checking if the <stream:stream> from the server has a
+ version attribute. I don't know if this is the right way though... */
+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;
+}
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index 47e2bda6..ec87ccd5 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -279,6 +279,11 @@ void signoff( struct gaim_connection *gc )
user_t *t, *u = irc->users;
account_t *a;
+ /* Nested calls might happen sometimes, this is probably the best
+ place to catch them. */
+ if( gc->flags & OPT_LOGGING_OUT )
+ return;
+
serv_got_crap( gc, "Signing off.." );
b_event_remove( gc->keepalive );