From e3fb6789b0004c7162efde679632bf094b7b0eec Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 18 Dec 2005 17:10:24 +0100 Subject: Initial work on a SSPI SSL backend --- protocols/ssl_sspi.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 protocols/ssl_sspi.c (limited to 'protocols') diff --git a/protocols/ssl_sspi.c b/protocols/ssl_sspi.c new file mode 100644 index 00000000..2129f07b --- /dev/null +++ b/protocols/ssl_sspi.c @@ -0,0 +1,210 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - SSPI backend */ + +/* Copyright (C) 2005 Jelmer Vernooij */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ssl_client.h" +#include +#define SECURITY_WIN32 +#include +#include +#include + +static gboolean initialized = FALSE; +int ssl_errno; + +struct scd +{ + int fd; + SslInputFunction func; + gpointer data; + gboolean established; + int inpa; + CredHandle cred; /* SSL credentials */ + CtxtHandle context; /* SSL context */ + SecPkgContext_StreamSizes sizes; +}; + +static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); + +void sspi_global_init( void ) +{ + /* FIXME */ +} + +void sspi_global_deinit( void ) +{ + /* FIXME */ +} + +void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) +{ + struct scd *conn = g_new0( struct scd, 1 ); + SCHANNEL_CRED ssl_cred; + TimeStamp timestamp; + + conn->fd = proxy_connect( host, port, ssl_connected, conn ); + conn->func = func; + conn->data = data; + conn->inpa = -1; + + if( conn->fd < 0 ) + { + g_free( conn ); + return( NULL ); + } + + if( !initialized ) + { + sspi_global_init(); + initialized = TRUE; + atexit( sspi_global_deinit ); + } + + conn->context = NULL; + + memset(&ssl_cred, 0, sizeof(SCHANNEL_CRED)); + ssl_cred.dwVersion = SCHANNEL_CRED_VERSION; + ssl_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; + + SECURITY_STATUS st = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &ssl_cred, NULL, NULL, &conn->cred, ×tamp); + + InitializeSecurityContext(&conn->cred, &conn->context, host, FIXME, 1, FIXME); + + QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->sizes); + + + return( conn ); +} + +int ssl_read( void *conn, char *retdata, int len ) +{ + struct scd *scd = conn; + SecBufferDesc msg; + SecBuffer buf[4]; + int ret = -1, i; + char *data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer); + + /* FIXME: Try to read some data */ + + msg.ulVersion = SECBUFFER_VERSION; + msg.cBuffers = 4; + msg.pBuffers = buf; + + buf[0].BufferType = SECBUFFER_DATA; + buf[0].cbBuffer = len; + buf[0].pvBuffer = data; + + buf[1].BufferType = SECBUFFER_EMPTY; + buf[2].BufferType = SECBUFFER_EMPTY; + buf[3].BufferType = SECBUFFER_EMPTY; + + SECURITY_STATUS st = DecryptMessage(&scd->context, &msg, 0, NULL); + + for (i = 0; i < 4; i++) { + if (buf[i].BufferType == SECBUFFER_DATA) { + memcpy(retdata, buf[i].pvBuffer, len); + ret = len; + } + } + + g_free(data); + return( -1 ); +} + +int ssl_write( void *conn, const char *userdata, int len ) +{ + struct scd *scd = conn; + SecBuffer buf[4]; + SecBufferDesc msg; + char *data; + int ret; + + msg.ulVersion = SECBUFFER_VERSION; + msg.cBuffers = 4; + msg.pBuffers = buf; + + data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer); + memcpy(data + scd->sizes.cbHeader, userdata, len); + + buf[0].BufferType = SECBUFFER_STREAM_HEADER; + buf[0].cbBuffer = scd->sizes.cbHeader; + buf[0].pvBuffer = data; + + buf[1].BufferType = SECBUFFER_DATA; + buf[1].cbBuffer = len; + buf[1].pvBuffer = data + scd->sizes.cbHeader; + + buf[2].BufferType = SECBUFFER_STREAM_TRAILER; + buf[2].cbBuffer = scd->sizes.cbTrailer; + buf[2].pvBuffer = data + scd->sizes.cbHeader + len; + buf[3].BufferType = SECBUFFER_EMPTY; + + SECURITY_STATUS st = EncryptMessage(&scd->context, 0, &msg, 0); + + ret = send(scd->fd, data, + buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer, 0); + + g_free(data); + + return ret; +} + +void ssl_disconnect( void *conn ) +{ + struct scd *scd = conn; + + SecBufferDesc msg; + SecBuffer buf; + DWORD dw; + + dw = SCHANNEL_SHUTDOWN; + buf.cbBuffer = sizeof(dw); + buf.BufferType = SECBUFFER_TOKEN; + buf.pvBuffer = &dw; + + msg.ulVersion = SECBUFFER_VERSION; + msg.cBuffers = 1; + msg.pBuffers = &buf; + + SECURITY_STATUS st = ApplyControlToken(&scd->context, &msg); + + if (st != SEC_E_OK) { + /* FIXME */ + } + + /* FIXME: call InitializeSecurityContext(Schannel), passing + * in empty buffers*/ + + DeleteSecurityContext(&scd->context); + + closesocket( scd->fd ); + g_free(scd); +} + +int ssl_getfd( void *conn ) +{ + return( ((struct scd*)conn)->fd ); +} -- cgit v1.2.3 From 80c1e4d9e8c82a83499d6b66cdf3a95d15bf0fa1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 25 May 2006 01:31:20 +0200 Subject: #ifdef out some Win32-incompatible code blocks --- protocols/ssl_sspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'protocols') diff --git a/protocols/ssl_sspi.c b/protocols/ssl_sspi.c index 2129f07b..0529b4ec 100644 --- a/protocols/ssl_sspi.c +++ b/protocols/ssl_sspi.c @@ -38,7 +38,7 @@ int ssl_errno; struct scd { int fd; - SslInputFunction func; + ssl_input_function func; gpointer data; gboolean established; int inpa; @@ -59,7 +59,7 @@ void sspi_global_deinit( void ) /* FIXME */ } -void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) { struct scd *conn = g_new0( struct scd, 1 ); SCHANNEL_CRED ssl_cred; -- cgit v1.2.3 From 51a4ffb83d6fbe23f1c2b8499cc78584e7213812 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 25 May 2006 11:55:00 +0200 Subject: Some more work on SSL on Windows --- protocols/ssl_sspi.c | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) (limited to 'protocols') diff --git a/protocols/ssl_sspi.c b/protocols/ssl_sspi.c index 0529b4ec..c6d7def9 100644 --- a/protocols/ssl_sspi.c +++ b/protocols/ssl_sspi.c @@ -64,6 +64,13 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data struct scd *conn = g_new0( struct scd, 1 ); SCHANNEL_CRED ssl_cred; TimeStamp timestamp; + SecBuffer ibuf[2],obuf[1]; + SecBufferDesc ibufs,obufs; + ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | + ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR | + ISC_REQ_MANUAL_CRED_VALIDATION; + ULONG a; conn->fd = proxy_connect( host, port, ssl_connected, conn ); conn->func = func; @@ -83,17 +90,42 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data atexit( sspi_global_deinit ); } - conn->context = NULL; - memset(&ssl_cred, 0, sizeof(SCHANNEL_CRED)); ssl_cred.dwVersion = SCHANNEL_CRED_VERSION; ssl_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; SECURITY_STATUS st = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &ssl_cred, NULL, NULL, &conn->cred, ×tamp); + + if (st != SEC_E_OK) + return NULL; + + do { + /* initialize buffers */ + ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; + ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; + obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; + ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; + ibuf[1].BufferType = SECBUFFER_EMPTY; + + /* initialize buffer descriptors */ + ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; + ibufs.cBuffers = 2; obufs.cBuffers = 1; + ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; + + st = InitializeSecurityContext(&conn->cred, size?&conn->context:NULL, host, req, 0, SECURITY_NETWORK_DREP, size?&ibufs:NULL, 0, &conn->context, &obufs, &a, ×tamp); + if (obuf[0].pvBuffer && obuf[0].cbBuffer) { + send(conn->fd, obuf[0].pvBuffer, obuf[0].cbBuffer, 0); + } + + switch (st) { + case SEC_I_INCOMPLETE_CREDENTIALS: + break; + case SEC_I_CONTINUE_NEEDED: + + } - InitializeSecurityContext(&conn->cred, &conn->context, host, FIXME, 1, FIXME); - QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->sizes); + QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->sizes); return( conn ); @@ -200,6 +232,8 @@ void ssl_disconnect( void *conn ) DeleteSecurityContext(&scd->context); + FreeCredentialHandle(&scd->cred); + closesocket( scd->fd ); g_free(scd); } -- cgit v1.2.3 From 1cda4f348372a755d99b291e6f4f9973a949f441 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 26 May 2006 17:02:09 +0200 Subject: Fix some unresolved symbols. --- protocols/oscar/AUTHORS | 2 -- protocols/ssl_sspi.c | 81 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 53 insertions(+), 30 deletions(-) (limited to 'protocols') diff --git a/protocols/oscar/AUTHORS b/protocols/oscar/AUTHORS index 5ca13988..51e8768d 100644 --- a/protocols/oscar/AUTHORS +++ b/protocols/oscar/AUTHORS @@ -27,5 +27,3 @@ N: Brock Wilcox H: awwaiid E: awwaiid@auk.cx D: Figured out original password roasting - - diff --git a/protocols/ssl_sspi.c b/protocols/ssl_sspi.c index 110f0af2..a16423b1 100644 --- a/protocols/ssl_sspi.c +++ b/protocols/ssl_sspi.c @@ -31,6 +31,7 @@ #include #include #include +#include "sock.h" static gboolean initialized = FALSE; int ssl_errno; @@ -41,52 +42,59 @@ struct scd ssl_input_function func; gpointer data; gboolean established; - int inpa; CredHandle cred; /* SSL credentials */ CtxtHandle context; /* SSL context */ SecPkgContext_StreamSizes sizes; + + char *host; + + char *pending_raw_data; + gsize pending_raw_data_len; + char *pending_data; + gsize pending_data_len; }; static void ssl_connected(gpointer, gint, GaimInputCondition); -void sspi_global_init( void ) +void sspi_global_init(void) { /* FIXME */ } -void sspi_global_deinit( void ) +void sspi_global_deinit(void) { /* FIXME */ } -void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) +void *ssl_connect(char *host, int port, ssl_input_function func, gpointer data) { - struct scd *conn = g_new0( struct scd, 1 ); + struct scd *conn = g_new0(struct scd, 1); - conn->fd = proxy_connect( host, port, ssl_connected, conn ); + conn->fd = proxy_connect(host, port, ssl_connected, conn); + sock_make_nonblocking(conn->fd); conn->func = func; conn->data = data; - conn->inpa = -1; + conn->host = g_strdup(host); - if( conn->fd < 0 ) + if (conn->fd < 0) { - g_free( conn ); - return( NULL ); + g_free(conn); + return NULL; } - if( !initialized ) + if (!initialized) { sspi_global_init(); initialized = TRUE; - atexit( sspi_global_deinit ); + atexit(sspi_global_deinit); } return conn; } -static void ssl_connected(gpointer data, gint fd, GaimInputCondition cond) +static void ssl_connected(gpointer _conn, gint fd, GaimInputCondition cond) { - struct scd *conn = data; + struct scd *conn = _conn; SCHANNEL_CRED ssl_cred; TimeStamp timestamp; SecBuffer ibuf[2],obuf[1]; @@ -96,6 +104,8 @@ static void ssl_connected(gpointer data, gint fd, GaimInputCondition cond) ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR | ISC_REQ_MANUAL_CRED_VALIDATION; ULONG a; + gsize size = 0; + gchar *data = NULL; memset(&ssl_cred, 0, sizeof(SCHANNEL_CRED)); ssl_cred.dwVersion = SCHANNEL_CRED_VERSION; @@ -104,13 +114,13 @@ static void ssl_connected(gpointer data, gint fd, GaimInputCondition cond) SECURITY_STATUS st = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &ssl_cred, NULL, NULL, &conn->cred, ×tamp); if (st != SEC_E_OK) { - conn->func( conn->data, NULL, cond ); + conn->func(conn->data, NULL, cond); return; - + } do { /* initialize buffers */ - ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; + ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = data; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NULL; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NULL; ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; @@ -121,8 +131,9 @@ static void ssl_connected(gpointer data, gint fd, GaimInputCondition cond) ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; - st = InitializeSecurityContext(&conn->cred, size?&conn->context:NULL, host, req, 0, SECURITY_NETWORK_DREP, size?&ibufs:NULL, 0, &conn->context, &obufs, &a, ×tamp); + st = InitializeSecurityContext(&conn->cred, size?&conn->context:NULL, conn->host, req, 0, SECURITY_NETWORK_DREP, size?&ibufs:NULL, 0, &conn->context, &obufs, &a, ×tamp); if (obuf[0].pvBuffer && obuf[0].cbBuffer) { + /* FIXME: Check return value */ send(conn->fd, obuf[0].pvBuffer, obuf[0].cbBuffer, 0); } @@ -130,17 +141,20 @@ static void ssl_connected(gpointer data, gint fd, GaimInputCondition cond) case SEC_I_INCOMPLETE_CREDENTIALS: break; case SEC_I_CONTINUE_NEEDED: - + break; + case SEC_E_INCOMPLETE_MESSAGE: + break; + case SEC_E_OK: + break; } - QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->sizes); } while (1); - conn->func( conn->data, conn, cond ); + conn->func(conn->data, conn, cond); } -int ssl_read( void *conn, char *retdata, int len ) +int ssl_read(void *conn, char *retdata, int len) { struct scd *scd = conn; SecBufferDesc msg; @@ -164,6 +178,11 @@ int ssl_read( void *conn, char *retdata, int len ) SECURITY_STATUS st = DecryptMessage(&scd->context, &msg, 0, NULL); + if (st != SEC_E_OK) { + /* FIXME */ + return -1; + } + for (i = 0; i < 4; i++) { if (buf[i].BufferType == SECBUFFER_DATA) { memcpy(retdata, buf[i].pvBuffer, len); @@ -172,10 +191,10 @@ int ssl_read( void *conn, char *retdata, int len ) } g_free(data); - return( -1 ); + return -1; } -int ssl_write( void *conn, const char *userdata, int len ) +int ssl_write(void *conn, const char *userdata, int len) { struct scd *scd = conn; SecBuffer buf[4]; @@ -213,7 +232,7 @@ int ssl_write( void *conn, const char *userdata, int len ) return ret; } -void ssl_disconnect( void *conn ) +void ssl_disconnect(void *conn) { struct scd *scd = conn; @@ -243,11 +262,17 @@ void ssl_disconnect( void *conn ) FreeCredentialsHandle(&scd->cred); - closesocket( scd->fd ); + closesocket(scd->fd); + g_free(scd->host); g_free(scd); } -int ssl_getfd( void *conn ) +int ssl_getfd(void *conn) +{ + return ((struct scd*)conn)->fd; +} + +GaimInputCondition ssl_getdirection( void *conn ) { - return( ((struct scd*)conn)->fd ); + return GAIM_INPUT_WRITE; /* FIXME: or GAIM_INPUT_READ */ } -- cgit v1.2.3 From fcc2da97bcfa5e0d704179fae9c4ed59cbaf79c5 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 26 May 2006 17:46:51 +0200 Subject: Remove unnecessary Windows-specific code. --- protocols/yahoo/libyahoo2.c | 2 -- protocols/yahoo/yahoo_httplib.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'protocols') diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index c691f18b..967ba681 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -68,8 +68,6 @@ char *strchr (), *strrchr (); #ifdef __MINGW32__ # include -# define write(a,b,c) send(a,b,c,0) -# define read(a,b,c) recv(a,b,c,0) #endif #include diff --git a/protocols/yahoo/yahoo_httplib.c b/protocols/yahoo/yahoo_httplib.c index dbbe2a84..1b084992 100644 --- a/protocols/yahoo/yahoo_httplib.c +++ b/protocols/yahoo/yahoo_httplib.c @@ -50,8 +50,6 @@ char *strchr (), *strrchr (); #include "yahoo_debug.h" #ifdef __MINGW32__ # include -# define write(a,b,c) send(a,b,c,0) -# define read(a,b,c) recv(a,b,c,0) # define snprintf _snprintf #endif -- cgit v1.2.3 From add23a26034a7368f4fdc0707488719048322e89 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 16 Feb 2008 22:07:14 +0000 Subject: Moved xmltree to lib/ because I want to use it from more than just the Jabber module. --- protocols/jabber/Makefile | 2 +- protocols/jabber/xmltree.c | 589 --------------------------------------------- protocols/jabber/xmltree.h | 97 -------- 3 files changed, 1 insertion(+), 687 deletions(-) delete mode 100644 protocols/jabber/xmltree.c delete mode 100644 protocols/jabber/xmltree.h (limited to 'protocols') diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index 3ce78127..e7a505ba 100644 --- a/protocols/jabber/Makefile +++ b/protocols/jabber/Makefile @@ -9,7 +9,7 @@ -include ../../Makefile.settings # [SH] Program variables -objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o +objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o CFLAGS += -Wall LFLAGS += -r diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c deleted file mode 100644 index 62549eb5..00000000 --- a/protocols/jabber/xmltree.c +++ /dev/null @@ -1,589 +0,0 @@ -/***************************************************************************\ -* * -* BitlBee - An IRC to IM gateway * -* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * -* * -* Copyright 2006 Wilmer van der Gaast * -* * -* This library is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public * -* License as published by the Free Software Foundation, version * -* 2.1. * -* * -* This library is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * -* Lesser General Public License for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this library; if not, write to the Free Software Foundation, * -* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * -* * -****************************************************************************/ - -#include -#include -#include -#include -#include - -#include "xmltree.h" - -static void xt_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - struct xt_node *node = g_new0( struct xt_node, 1 ), *nt; - int i; - - node->parent = xt->cur; - node->name = g_strdup( element_name ); - - /* First count the number of attributes */ - for( i = 0; attr_names[i]; i ++ ); - - /* Then allocate a NULL-terminated array. */ - node->attr = g_new0( struct xt_attr, i + 1 ); - - /* And fill it, saving one variable by starting at the end. */ - for( i --; i >= 0; i -- ) - { - node->attr[i].key = g_strdup( attr_names[i] ); - node->attr[i].value = g_strdup( attr_values[i] ); - } - - /* Add it to the linked list of children nodes, if we have a current - node yet. */ - if( xt->cur ) - { - if( xt->cur->children ) - { - for( nt = xt->cur->children; nt->next; nt = nt->next ); - nt->next = node; - } - else - { - xt->cur->children = node; - } - } - else if( xt->root ) - { - /* ERROR situation: A second root-element??? */ - } - - /* Now this node will be the new current node. */ - xt->cur = node; - /* And maybe this is the root? */ - if( xt->root == NULL ) - xt->root = node; -} - -static void xt_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - struct xt_node *node = xt->cur; - - if( node == NULL ) - return; - - /* FIXME: Does g_renew also OFFICIALLY accept NULL arguments? */ - node->text = g_renew( char, node->text, node->text_len + text_len + 1 ); - memcpy( node->text + node->text_len, text, text_len ); - node->text_len += text_len; - /* Zero termination is always nice to have. */ - node->text[node->text_len] = 0; -} - -static void xt_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - - xt->cur->flags |= XT_COMPLETE; - xt->cur = xt->cur->parent; -} - -GMarkupParser xt_parser_funcs = -{ - xt_start_element, - xt_end_element, - xt_text, - NULL, - NULL -}; - -struct xt_parser *xt_new( gpointer data ) -{ - struct xt_parser *xt = g_new0( struct xt_parser, 1 ); - - xt->data = data; - xt_reset( xt ); - - return xt; -} - -/* Reset the parser, flush everything we have so far. For example, we need - this for XMPP when doing TLS/SASL to restart the stream. */ -void xt_reset( struct xt_parser *xt ) -{ - if( xt->parser ) - g_markup_parse_context_free( xt->parser ); - - xt->parser = g_markup_parse_context_new( &xt_parser_funcs, 0, xt, NULL ); - - if( xt->root ) - { - xt_free_node( xt->root ); - xt->root = NULL; - xt->cur = NULL; - } -} - -/* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on - end-of-stream and 1 otherwise. */ -int xt_feed( struct xt_parser *xt, char *text, int text_len ) -{ - if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) ) - { - return -1; - } - - return !( xt->root && xt->root->flags & XT_COMPLETE ); -} - -/* Find completed nodes and see if a handler has to be called. Passing - a node isn't necessary if you want to start at the root, just pass - NULL. This second argument is needed for recursive calls. */ -int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) -{ - struct xt_node *c; - xt_status st; - int i; - - /* Just in case someone likes infinite loops... */ - if( xt->root == NULL ) - return 0; - - if( node == NULL ) - return xt_handle( xt, xt->root, depth ); - - if( depth != 0 ) - for( c = node->children; c; c = c->next ) - if( !xt_handle( xt, c, depth > 0 ? depth - 1 : depth ) ) - return 0; - - if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) ) - { - for( i = 0; xt->handlers[i].func; i ++ ) - { - /* This one is fun! \o/ */ - - /* If handler.name == NULL it means it should always match. */ - if( ( xt->handlers[i].name == NULL || - /* If it's not, compare. There should always be a name. */ - g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) && - /* If handler.parent == NULL, it's a match. */ - ( xt->handlers[i].parent == NULL || - /* If there's a parent node, see if the name matches. */ - ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 : - /* If there's no parent, the handler should mention as a parent. */ - g_strcasecmp( xt->handlers[i].parent, "" ) == 0 ) ) ) - { - st = xt->handlers[i].func( node, xt->data ); - - if( st == XT_ABORT ) - return 0; - else if( st != XT_NEXT ) - break; - } - } - - node->flags |= XT_SEEN; - } - - return 1; -} - -/* Garbage collection: Cleans up all nodes that are handled. Useful for - streams because there's no reason to keep a complete packet history - in memory. */ -void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ) -{ - struct xt_node *c, *prev; - - if( !xt || !xt->root ) - return; - - if( node == NULL ) - return xt_cleanup( xt, xt->root, depth ); - - if( node->flags & XT_SEEN && node == xt->root ) - { - xt_free_node( xt->root ); - xt->root = xt->cur = NULL; - /* xt->cur should be NULL already, BTW... */ - - return; - } - - /* c contains the current node, prev the previous node (or NULL). - I admit, this one's pretty horrible. */ - for( c = node->children, prev = NULL; c; prev = c, c = c ? c->next : node->children ) - { - if( c->flags & XT_SEEN ) - { - /* Remove the node from the linked list. */ - if( prev ) - prev->next = c->next; - else - node->children = c->next; - - xt_free_node( c ); - - /* Since the for loop wants to get c->next, make sure - c points at something that exists (and that c->next - will actually be the next item we should check). c - can be NULL now, if we just removed the first item. - That explains the ? thing in for(). */ - c = prev; - } - else - { - /* This node can't be cleaned up yet, but maybe a - subnode can. */ - if( depth != 0 ) - xt_cleanup( xt, c, depth > 0 ? depth - 1 : depth ); - } - } -} - -static void xt_to_string_real( struct xt_node *node, GString *str ) -{ - char *buf; - struct xt_node *c; - int i; - - g_string_append_printf( str, "<%s", node->name ); - - for( i = 0; node->attr[i].key; i ++ ) - { - buf = g_markup_printf_escaped( " %s=\"%s\"", node->attr[i].key, node->attr[i].value ); - g_string_append( str, buf ); - g_free( buf ); - } - - if( node->text == NULL && node->children == NULL ) - { - g_string_append( str, "/>" ); - return; - } - - g_string_append( str, ">" ); - if( node->text_len > 0 ) - { - buf = g_markup_escape_text( node->text, node->text_len ); - g_string_append( str, buf ); - g_free( buf ); - } - - for( c = node->children; c; c = c->next ) - xt_to_string_real( c, str ); - - g_string_append_printf( str, "", node->name ); -} - -char *xt_to_string( struct xt_node *node ) -{ - GString *ret; - char *real; - - ret = g_string_new( "" ); - xt_to_string_real( node, ret ); - - real = ret->str; - g_string_free( ret, FALSE ); - - return real; -} - -#ifdef DEBUG -void xt_print( struct xt_node *node ) -{ - int i; - struct xt_node *c; - - /* Indentation */ - for( c = node; c->parent; c = c->parent ) - printf( "\t" ); - - /* Start the tag */ - printf( "<%s", node->name ); - - /* Print the attributes */ - for( i = 0; node->attr[i].key; i ++ ) - printf( " %s=\"%s\"", node->attr[i].key, g_markup_escape_text( node->attr[i].value, -1 ) ); - - /* /> in case there's really *nothing* inside this tag, otherwise - just >. */ - /* If this tag doesn't have any content at all... */ - if( node->text == NULL && node->children == NULL ) - { - printf( "/>\n" ); - return; - /* Then we're finished! */ - } - - /* Otherwise... */ - printf( ">" ); - - /* Only print the text if it contains more than whitespace (TEST). */ - if( node->text_len > 0 ) - { - for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ ); - if( node->text[i] ) - printf( "%s", g_markup_escape_text( node->text, -1 ) ); - } - - if( node->children ) - printf( "\n" ); - - for( c = node->children; c; c = c->next ) - xt_print( c ); - - if( node->children ) - for( c = node; c->parent; c = c->parent ) - printf( "\t" ); - - /* Non-empty tag is now finished. */ - printf( "\n", node->name ); -} -#endif - -struct xt_node *xt_dup( struct xt_node *node ) -{ - struct xt_node *dup = g_new0( struct xt_node, 1 ); - struct xt_node *c, *dc = NULL; - int i; - - /* Let's NOT copy the parent element here BTW! Only do it for children. */ - - dup->name = g_strdup( node->name ); - dup->flags = node->flags; - if( node->text ) - { - dup->text = g_memdup( node->text, node->text_len + 1 ); - dup->text_len = node->text_len; - } - - /* Count the number of attributes and allocate the new array. */ - for( i = 0; node->attr[i].key; i ++ ); - dup->attr = g_new0( struct xt_attr, i + 1 ); - - /* Copy them all! */ - for( i --; i >= 0; i -- ) - { - dup->attr[i].key = g_strdup( node->attr[i].key ); - dup->attr[i].value = g_strdup( node->attr[i].value ); - } - - /* This nice mysterious loop takes care of the children. */ - for( c = node->children; c; c = c->next ) - { - if( dc == NULL ) - dc = dup->children = xt_dup( c ); - else - dc = ( dc->next = xt_dup( c ) ); - - dc->parent = dup; - } - - return dup; -} - -/* Frees a node. This doesn't clean up references to itself from parents! */ -void xt_free_node( struct xt_node *node ) -{ - int i; - - if( !node ) - return; - - g_free( node->name ); - g_free( node->text ); - - for( i = 0; node->attr[i].key; i ++ ) - { - g_free( node->attr[i].key ); - g_free( node->attr[i].value ); - } - g_free( node->attr ); - - while( node->children ) - { - struct xt_node *next = node->children->next; - - xt_free_node( node->children ); - node->children = next; - } - - g_free( node ); -} - -void xt_free( struct xt_parser *xt ) -{ - if( !xt ) - return; - - if( xt->root ) - xt_free_node( xt->root ); - - g_markup_parse_context_free( xt->parser ); - - g_free( xt ); -} - -/* To find a node's child with a specific name, pass the node's children - list, not the node itself! The reason you have to do this by hand: So - that you can also use this function as a find-next. */ -struct xt_node *xt_find_node( struct xt_node *node, const char *name ) -{ - while( node ) - { - if( g_strcasecmp( node->name, name ) == 0 ) - break; - - node = node->next; - } - - return node; -} - -char *xt_find_attr( struct xt_node *node, const char *key ) -{ - int i; - - if( !node ) - return NULL; - - for( i = 0; node->attr[i].key; i ++ ) - if( g_strcasecmp( node->attr[i].key, key ) == 0 ) - break; - - return node->attr[i].value; -} - -struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ) -{ - struct xt_node *node, *c; - - node = g_new0( struct xt_node, 1 ); - node->name = g_strdup( name ); - node->children = children; - node->attr = g_new0( struct xt_attr, 1 ); - - if( text ) - { - node->text_len = strlen( text ); - node->text = g_memdup( text, node->text_len + 1 ); - } - - for( c = children; c; c = c->next ) - { - if( c->parent != NULL ) - { - /* ERROR CONDITION: They seem to have a parent already??? */ - } - - c->parent = node; - } - - return node; -} - -void xt_add_child( struct xt_node *parent, struct xt_node *child ) -{ - struct xt_node *node; - - /* This function can actually be used to add more than one child, so - do handle this properly. */ - for( node = child; node; node = node->next ) - { - if( node->parent != NULL ) - { - /* ERROR CONDITION: They seem to have a parent already??? */ - } - - node->parent = parent; - } - - if( parent->children == NULL ) - { - parent->children = child; - } - else - { - for( node = parent->children; node->next; node = node->next ); - node->next = child; - } -} - -void xt_add_attr( struct xt_node *node, const char *key, const char *value ) -{ - int i; - - /* Now actually it'd be nice if we can also change existing attributes - (which actually means this function doesn't have the right name). - So let's find out if we have this attribute already... */ - for( i = 0; node->attr[i].key; i ++ ) - if( strcmp( node->attr[i].key, key ) == 0 ) - break; - - if( node->attr[i].key == NULL ) - { - /* If not, allocate space for a new attribute. */ - node->attr = g_renew( struct xt_attr, node->attr, i + 2 ); - node->attr[i].key = g_strdup( key ); - node->attr[i+1].key = NULL; - } - else - { - /* Otherwise, free the old value before setting the new one. */ - g_free( node->attr[i].value ); - } - - node->attr[i].value = g_strdup( value ); -} - -int xt_remove_attr( struct xt_node *node, const char *key ) -{ - int i, last; - - for( i = 0; node->attr[i].key; i ++ ) - if( strcmp( node->attr[i].key, key ) == 0 ) - break; - - /* If we didn't find the attribute... */ - if( node->attr[i].key == NULL ) - return 0; - - g_free( node->attr[i].key ); - g_free( node->attr[i].value ); - - /* If it's the last, this is easy: */ - if( node->attr[i+1].key == NULL ) - { - node->attr[i].key = node->attr[i].value = NULL; - } - else /* It's also pretty easy, actually. */ - { - /* Find the last item. */ - for( last = i + 1; node->attr[last+1].key; last ++ ); - - node->attr[i] = node->attr[last]; - node->attr[last].key = NULL; - node->attr[last].value = NULL; - } - - /* Let's not bother with reallocating memory here. It takes time and - most packets don't stay in memory for long anyway. */ - - return 1; -} diff --git a/protocols/jabber/xmltree.h b/protocols/jabber/xmltree.h deleted file mode 100644 index b8b61641..00000000 --- a/protocols/jabber/xmltree.h +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************\ -* * -* BitlBee - An IRC to IM gateway * -* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * -* * -* Copyright 2006 Wilmer van der Gaast * -* * -* This library is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public * -* License as published by the Free Software Foundation, version * -* 2.1. * -* * -* This library is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * -* Lesser General Public License for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this library; if not, write to the Free Software Foundation, * -* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * -* * -****************************************************************************/ - -#ifndef _XMLTREE_H -#define _XMLTREE_H - -typedef enum -{ - XT_COMPLETE = 1, /* reached */ - XT_SEEN = 2, /* Handler called (or not defined) */ -} xt_flags; - -typedef enum -{ - XT_ABORT, /* Abort, don't handle the rest anymore */ - XT_HANDLED, /* Handled this tag properly, go to the next one */ - XT_NEXT /* Try if there's another matching handler */ -} xt_status; - -struct xt_attr -{ - char *key, *value; -}; - -struct xt_node -{ - struct xt_node *parent; - struct xt_node *children; - - char *name; - struct xt_attr *attr; - char *text; - int text_len; - - struct xt_node *next; - xt_flags flags; -}; - -typedef xt_status (*xt_handler_func) ( struct xt_node *node, gpointer data ); - -struct xt_handler_entry -{ - char *name, *parent; - xt_handler_func func; -}; - -struct xt_parser -{ - GMarkupParseContext *parser; - struct xt_node *root; - struct xt_node *cur; - - struct xt_handler_entry *handlers; - gpointer data; - - GError *gerr; -}; - -struct xt_parser *xt_new( gpointer data ); -void xt_reset( struct xt_parser *xt ); -int xt_feed( struct xt_parser *xt, char *text, int text_len ); -int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); -void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ); -char *xt_to_string( struct xt_node *node ); -void xt_print( struct xt_node *node ); -struct xt_node *xt_dup( struct xt_node *node ); -void xt_free_node( struct xt_node *node ); -void xt_free( struct xt_parser *xt ); -struct xt_node *xt_find_node( struct xt_node *node, const char *name ); -char *xt_find_attr( struct xt_node *node, const char *key ); - -struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ); -void xt_add_child( struct xt_node *parent, struct xt_node *child ); -void xt_add_attr( struct xt_node *node, const char *key, const char *value ); -int xt_remove_attr( struct xt_node *node, const char *key ); - -#endif -- cgit v1.2.3 From 4bbcba32aca2948f66c484ab074264fdb67609ae Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 16 Feb 2008 22:40:38 +0000 Subject: Moved xmltree handlers initialization to xt_new(). --- protocols/jabber/io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 86c216ef..9980dc8e 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -520,8 +520,7 @@ gboolean jabber_start_stream( struct im_connection *ic ) /* We'll start our stream now, so prepare everything to receive one from the server too. */ xt_free( jd->xt ); /* In case we're RE-starting. */ - jd->xt = xt_new( ic ); - jd->xt->handlers = (struct xt_handler_entry*) jabber_handlers; + jd->xt = xt_new( jabber_handlers, ic ); if( jd->r_inpa <= 0 ) jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic ); -- cgit v1.2.3 From e6648bf3b821ae40c0640857aae069bc0f5d90c4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 17 Feb 2008 11:16:01 +0000 Subject: Replaced old MSN Passport (v1.4) authentication code with what's described on http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener . This was an attempt to fix bug #360, but it didn't. However, this change may make BitlBee a little bit more future-proof. Plus, the code is tidier and sometimes faster than the old mechanism. --- protocols/msn/ns.c | 30 +++--- protocols/msn/passport.c | 275 ++++++++++++++++++----------------------------- protocols/msn/passport.h | 91 +++++++++++++--- 3 files changed, 200 insertions(+), 196 deletions(-) (limited to 'protocols') diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 0bb84a74..ff7da6ed 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -33,7 +33,7 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -static void msn_auth_got_passport_id( struct passport_reply *rep ); +static void msn_auth_got_passport_token( struct msn_auth_data *mad ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { @@ -213,7 +213,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) { /* Time for some Passport black magic... */ - if( !passport_get_id( msn_auth_got_passport_id, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) + if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) { imcb_error( ic, "Error while contacting Passport server" ); imc_logout( ic, TRUE ); @@ -673,22 +673,26 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int return( 1 ); } -static void msn_auth_got_passport_id( struct passport_reply *rep ) +static void msn_auth_got_passport_token( struct msn_auth_data *mad ) { - struct im_connection *ic = rep->data; - struct msn_data *md = ic->proto_data; - char *key = rep->result; - char buf[1024]; + struct im_connection *ic = mad->data; + struct msn_data *md; - if( key == NULL ) + /* Dead connection? */ + if( g_slist_find( msn_connections, ic ) == NULL ) + return; + + md = ic->proto_data; + if( mad->token ) { - imcb_error( ic, "Error during Passport authentication (%s)", - rep->error_string ? rep->error_string : "Unknown error" ); - imc_logout( ic, TRUE ); + char buf[1024]; + + g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); + msn_write( ic, buf, strlen( buf ) ); } else { - g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key ); - msn_write( ic, buf, strlen( buf ) ); + imcb_error( ic, "Error during Passport authentication: %s", mad->error ); + imc_logout( ic, TRUE ); } } diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 9fe6a174..7a15c3fe 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -1,8 +1,7 @@ -/* passport.c +/** passport.c * - * Functions to login to microsoft passport service for Messenger - * Copyright (C) 2004 Wouter Paesen - * Copyright (C) 2004 Wilmer van der Gaast + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 Wilmer van der Gaast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -23,208 +22,144 @@ #include "passport.h" #include "msn.h" #include "bitlbee.h" +#include "url.h" +#include "misc.h" +#include "xmltree.h" #include #include -#define MSN_BUF_LEN 8192 +static int passport_get_token_real( struct msn_auth_data *mad ); +static void passport_get_token_ready( struct http_request *req ); -static char *prd_cached = NULL; - -static int passport_get_id_real( gpointer func, gpointer data, char *header ); -static void passport_get_id_ready( struct http_request *req ); - -static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header ); -static void passport_retrieve_dalogin_ready( struct http_request *req ); - -static char *passport_create_header( char *cookie, char *email, char *pwd ); -static void destroy_reply( struct passport_reply *rep ); - -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ) +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ) { - char *header = passport_create_header( cookie, username, password ); + struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 ); + int i; - if( prd_cached == NULL ) - return passport_retrieve_dalogin( func, data, header ); - else - return passport_get_id_real( func, data, header ); + mad->username = g_strdup( username ); + mad->password = g_strdup( password ); + mad->cookie = g_strdup( cookie ); + + mad->callback = func; + mad->data = data; + + mad->url = g_strdup( SOAP_AUTHENTICATION_URL ); + mad->ttl = 3; /* Max. # of redirects. */ + + /* HTTP-escape stuff and s/,/&/ */ + http_decode( mad->cookie ); + for( i = 0; mad->cookie[i]; i ++ ) + if( mad->cookie[i] == ',' ) + mad->cookie[i] = '&'; + + return passport_get_token_real( mad ); } -static int passport_get_id_real( gpointer func, gpointer data, char *header ) +static int passport_get_token_real( struct msn_auth_data *mad ) { - struct passport_reply *rep; - char *server, *dummy, *reqs; + char *post_payload, *post_request; struct http_request *req; + url_t url; - rep = g_new0( struct passport_reply, 1 ); - rep->data = data; - rep->func = func; - rep->header = header; - - server = g_strdup( prd_cached ); - dummy = strchr( server, '/' ); - - if( dummy == NULL ) - { - destroy_reply( rep ); - return( 0 ); - } - - reqs = g_strdup_printf( "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); + url_set( &url, mad->url ); - *dummy = 0; - req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); + post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD, + mad->username, + mad->password, + mad->cookie ); - g_free( server ); - g_free( reqs ); + post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST, + url.file, url.host, + (int) strlen( post_payload ), + post_payload ); + + req = http_dorequest( url.host, url.port, 1, post_request, + passport_get_token_ready, mad ); - if( req == NULL ) - destroy_reply( rep ); + g_free( post_request ); + g_free( post_payload ); - return( req != NULL ); + return req != NULL; } -static void passport_get_id_ready( struct http_request *req ) +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ); +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ); + +static const struct xt_handler_entry passport_xt_handlers[] = { + { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token }, + { "S:Fault", "S:Envelope", passport_xt_handle_fault }, + { NULL, NULL, NULL } +}; + +static void passport_get_token_ready( struct http_request *req ) { - struct passport_reply *rep = req->data; + struct msn_auth_data *mad = req->data; + struct xt_parser *parser; - if( !g_slist_find( msn_connections, rep->data ) ) - { - destroy_reply( rep ); - return; - } + g_free( mad->url ); + g_free( mad->error ); + mad->url = mad->error = NULL; - if( req->finished && req->reply_headers && req->status_code == 200 ) + if( req->status_code == 200 ) { - char *dummy; - - if( ( dummy = strstr( req->reply_headers, "from-PP='" ) ) ) - { - char *responseend; - - dummy += strlen( "from-PP='" ); - responseend = strchr( dummy, '\'' ); - if( responseend ) - *responseend = 0; - - rep->result = g_strdup( dummy ); - } - else - { - rep->error_string = g_strdup( "Could not parse Passport server response" ); - } + parser = xt_new( passport_xt_handlers, mad ); + xt_feed( parser, req->reply_body, req->body_size ); + xt_handle( parser, NULL, -1 ); + xt_free( parser ); } else { - rep->error_string = g_strdup_printf( "HTTP error: %s", - req->status_string ? req->status_string : "Unknown error" ); + mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code, + req->status_string ? req->status_string : "unknown" ); } - rep->func( rep ); - destroy_reply( rep ); -} - -static char *passport_create_header( char *cookie, char *email, char *pwd ) -{ - char *buffer; - char *currenttoken; - char *email_enc, *pwd_enc; - - currenttoken = strstr( cookie, "lc=" ); - if( currenttoken == NULL ) - return NULL; - - email_enc = g_new0( char, strlen( email ) * 3 + 1 ); - strcpy( email_enc, email ); - http_encode( email_enc ); - - pwd_enc = g_new0( char, strlen( pwd ) * 3 + 1 ); - strcpy( pwd_enc, pwd ); - http_encode( pwd_enc ); - - buffer = g_strdup_printf( "Authorization: Passport1.4 OrgVerb=GET," - "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom," - "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc, - currenttoken ); - - g_free( email_enc ); - g_free( pwd_enc ); + if( mad->error == NULL && mad->token == NULL ) + mad->error = g_strdup( "Could not parse Passport server response" ); - return buffer; + if( mad->url && mad->token == NULL ) + { + passport_get_token_real( mad ); + } + else + { + mad->callback( mad ); + + g_free( mad->url ); + g_free( mad->username ); + g_free( mad->password ); + g_free( mad->cookie ); + g_free( mad->token ); + g_free( mad->error ); + g_free( mad ); + } } -static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ) { - struct passport_reply *rep = g_new0( struct passport_reply, 1 ); - struct http_request *req; + struct msn_auth_data *mad = data; + char *s; - rep->data = data; - rep->func = func; - rep->header = header; + if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 ) + mad->token = g_memdup( node->text, node->text_len + 1 ); - req = http_dorequest_url( "https://nexus.passport.com/rdr/pprdr.asp", passport_retrieve_dalogin_ready, rep ); - - if( !req ) - destroy_reply( rep ); - - return( req != NULL ); + return XT_HANDLED; } -static void passport_retrieve_dalogin_ready( struct http_request *req ) +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ) { - struct passport_reply *rep = req->data; - char *dalogin; - char *urlend; + struct msn_auth_data *mad = data; + struct xt_node *code = xt_find_node( node->children, "faultcode" ); + struct xt_node *string = xt_find_node( node->children, "faultstring" ); + struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" ); - if( !g_slist_find( msn_connections, rep->data ) ) - { - destroy_reply( rep ); - return; - } - - if( !req->finished || !req->reply_headers || req->status_code != 200 ) - { - rep->error_string = g_strdup_printf( "HTTP error while fetching DALogin: %s", - req->status_string ? req->status_string : "Unknown error" ); - goto failure; - } + if( redirect && redirect->text_len && mad->ttl-- > 0 ) + mad->url = g_memdup( redirect->text, redirect->text_len + 1 ); - dalogin = strstr( req->reply_headers, "DALogin=" ); - - if( !dalogin ) - { - rep->error_string = g_strdup( "Parse error while fetching DALogin" ); - goto failure; - } - - dalogin += strlen( "DALogin=" ); - urlend = strchr( dalogin, ',' ); - if( urlend ) - *urlend = 0; - - /* strip the http(s):// part from the url */ - urlend = strstr( urlend, "://" ); - if( urlend ) - dalogin = urlend + strlen( "://" ); - - if( prd_cached == NULL ) - prd_cached = g_strdup( dalogin ); - - if( passport_get_id_real( rep->func, rep->data, rep->header ) ) - { - rep->header = NULL; - destroy_reply( rep ); - return; - } + if( code == NULL || code->text_len == 0 ) + mad->error = g_strdup( "Unknown error" ); + else + mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? + string->text : "no description available" ); -failure: - rep->func( rep ); - destroy_reply( rep ); -} - -static void destroy_reply( struct passport_reply *rep ) -{ - g_free( rep->result ); - g_free( rep->header ); - g_free( rep->error_string ); - g_free( rep ); + return XT_HANDLED; } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index 9fd81a82..1d0c6edc 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -1,10 +1,7 @@ -#ifndef __PASSPORT_H__ -#define __PASSPORT_H__ /* passport.h * - * Functions to login to Microsoft Passport Service for Messenger - * Copyright (C) 2004 Wouter Paesen , - * Wilmer van der Gaast + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 Wilmer van der Gaast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -17,9 +14,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Thanks to http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener + for the specs! */ + +#ifndef __PASSPORT_H__ +#define __PASSPORT_H__ + #include #include #include @@ -32,15 +35,77 @@ #endif #include "nogaim.h" -struct passport_reply +struct msn_auth_data { - void (*func)( struct passport_reply * ); - void *data; - char *result; - char *header; - char *error_string; + char *url; + int ttl; + + char *username; + char *password; + char *cookie; + + /* The end result, the only thing we'll really be interested in + once finished. */ + char *token; + char *error; /* Yeah, or that... */ + + void (*callback)( struct msn_auth_data *mad ); + gpointer data; }; -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ); +#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf" + +#define SOAP_AUTHENTICATION_REQUEST \ +"POST %s HTTP/1.0\r\n" \ +"Accept: text/*\r\n" \ +"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ +"Host: %s\r\n" \ +"Content-Length: %d\r\n" \ +"Cache-Control: no-cache\r\n" \ +"\r\n" \ +"%s" + +#define SOAP_AUTHENTICATION_PAYLOAD \ +"" \ +"" \ + "
" \ + "" \ + "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}" \ + "4" \ + "1" \ + "" \ + "AQAAAAIAAABsYwQAAAAzMDg0" \ + "" \ + "" \ + "" \ + "%s" \ + "%s" \ + "" \ + "" \ + "
" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "http://Passport.NET/tb" \ + "" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "messenger.msn.com" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ +"
" + +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ); #endif /* __PASSPORT_H__ */ -- cgit v1.2.3 From 9186d15356a46576fb5b306f49a6acdb64fb7622 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 17 Feb 2008 11:26:44 +0000 Subject: Automatically truncate MSN passports to 16 characters because that's the maximum supported by MSN and giving a longer password will make the authentication fail. --- protocols/msn/passport.c | 5 +++++ protocols/msn/passport.h | 2 ++ 2 files changed, 7 insertions(+) (limited to 'protocols') diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 7a15c3fe..565d15f3 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -52,6 +52,11 @@ int passport_get_token( gpointer func, gpointer data, char *username, char *pass if( mad->cookie[i] == ',' ) mad->cookie[i] = '&'; + /* Microsoft doesn't allow password longer than 16 chars and silently + fails authentication if you give the "full version" of your passwd. */ + if( strlen( mad->password ) > MAX_PASSPORT_PWLEN ) + mad->password[MAX_PASSPORT_PWLEN] = 0; + return passport_get_token_real( mad ); } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index 1d0c6edc..517d2e91 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -35,6 +35,8 @@ #endif #include "nogaim.h" +#define MAX_PASSPORT_PWLEN 16 + struct msn_auth_data { char *url; -- cgit v1.2.3 From a869d9147584de96a0ac341416e551953167800f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Mar 2008 17:44:21 +0000 Subject: Indicate that we support YMSG protocol version 12, this should hopefully keep BitlBee working after 2008-04-02 . --- protocols/yahoo/libyahoo2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index ce38bc73..4e93449e 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -736,7 +736,7 @@ static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet data = y_new0(unsigned char, len + 1); memcpy(data + pos, "YMSG", 4); pos += 4; - pos += yahoo_put16(data + pos, 0x0a00); + pos += yahoo_put16(data + pos, 0x000c); pos += yahoo_put16(data + pos, 0x0000); pos += yahoo_put16(data + pos, pktlen + extra_pad); pos += yahoo_put16(data + pos, pkt->service); -- cgit v1.2.3 From 79eae4a9edb343eaad30425289f7737467a535bb Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Mar 2008 21:05:39 +0000 Subject: Inviting someone to a Yahoo! chatroom with msg=NULL is bad. I wonder if /invite ever worked in the Yahoo! module... --- protocols/yahoo/yahoo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 9f9ffcf7..36579d66 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -314,7 +314,7 @@ static void byahoo_chat_invite( struct groupchat *c, char *who, char *msg ) { struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data; - yahoo_conference_invite( yd->y2_id, NULL, c->data, c->title, msg ); + yahoo_conference_invite( yd->y2_id, NULL, c->data, c->title, msg ? msg : "" ); } static void byahoo_chat_leave( struct groupchat *c ) -- cgit v1.2.3 From 4bb50efd1015a04d44c301961710fa08e0eda162 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Mar 2008 23:53:54 +0000 Subject: Although I have no idea what the author meant with code like `if(cp != "\005")', I'm sure he feels homesick to QuickBasic. Since BitlBee doesn't use this function anyway, it doesn't really matter if my fix works. As long as it keeps the compiler quiet. --- protocols/yahoo/libyahoo2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index 4e93449e..80d88a85 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -3350,7 +3350,7 @@ static void yahoo_process_search_connection(struct yahoo_input_data *yid, int ov yct->age = atoi(cp); break; case 5: - if(cp != "\005") + if(strcmp(cp, "5") != 0) yct->location = cp; k = 0; break; -- cgit v1.2.3 From e960a523f587a83bd22d000b4451c5a21b2951e8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 14:39:34 +0000 Subject: Fixed cached_id_prefix memory leak. --- protocols/jabber/jabber.c | 1 + 1 file changed, 1 insertion(+) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 243ed7fd..0e23b4d4 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -266,6 +266,7 @@ static void jabber_logout( struct im_connection *ic ) xt_free( jd->xt ); + g_free( jd->cached_id_prefix ); g_free( jd->away_message ); g_free( jd->username ); g_free( jd ); -- cgit v1.2.3 From 8a2221a79b177a5c6d0b55dafebd39414d7fe10a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 23 Mar 2008 14:29:19 +0000 Subject: Fixed stalling issue with OpenSSL and Jabber (#368). --- protocols/jabber/io.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 9980dc8e..10efad37 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -240,8 +240,13 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition return FALSE; } - /* EAGAIN/etc or a successful read. */ - return TRUE; + if( ssl_pending( jd->ssl ) ) + /* OpenSSL empties the TCP buffers completely but may keep some + data in its internap buffers. select() won't see that, but + ssl_pending() does. */ + return jabber_read_callback( data, fd, cond ); + else + return TRUE; } gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ) -- cgit v1.2.3 From 9143aeb969697e05953b0f60a2fff2581fa0f18c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 5 Apr 2008 13:26:04 +0100 Subject: query.h now defines a callback function type, not using void* for it anymore. Got rid of the bogus window handler pointer as the first argument to the callback. --- protocols/jabber/jabber_util.c | 8 ++++++-- protocols/msn/msn_util.c | 8 ++++++-- protocols/nogaim.c | 17 ++++++++++------- protocols/nogaim.h | 3 ++- protocols/oscar/oscar.c | 18 ++++++++++++------ protocols/yahoo/yahoo.c | 8 ++++++-- 6 files changed, 42 insertions(+), 20 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 6e872040..518624f6 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -245,8 +245,10 @@ struct jabber_buddy_ask_data char *realname; }; -static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla ) +static void jabber_buddy_ask_yes( void *data ) { + struct jabber_buddy_ask_data *bla = data; + presence_send_request( bla->ic, bla->handle, "subscribed" ); if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) @@ -256,8 +258,10 @@ static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla g_free( bla ); } -static void jabber_buddy_ask_no( gpointer w, struct jabber_buddy_ask_data *bla ) +static void jabber_buddy_ask_no( void *data ) { + struct jabber_buddy_ask_data *bla = data; + presence_send_request( bla->ic, bla->handle, "subscribed" ); g_free( bla->handle ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index fae2877d..58ad22f8 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -89,8 +89,10 @@ struct msn_buddy_ask_data char *realname; }; -static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla ) +static void msn_buddy_ask_yes( void *data ) { + struct msn_buddy_ask_data *bla = data; + msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname ); if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) @@ -101,8 +103,10 @@ static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla ) g_free( bla ); } -static void msn_buddy_ask_no( gpointer w, struct msn_buddy_ask_data *bla ) +static void msn_buddy_ask_no( void *data ) { + struct msn_buddy_ask_data *bla = data; + msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname ); g_free( bla->handle ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 3ce15166..7466e93a 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -342,7 +342,8 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) /* dialogs.c */ -void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont ) +void imcb_ask( struct im_connection *ic, char *msg, void *data, + query_callback doit, query_callback dont ) { query_add( ic->irc, ic, msg, doit, dont, data ); } @@ -494,18 +495,20 @@ struct show_got_added_data char *handle; }; -void show_got_added_no( gpointer w, struct show_got_added_data *data ) +void show_got_added_no( void *data ) { - g_free( data->handle ); + g_free( ((struct show_got_added_data*)data)->handle ); g_free( data ); } -void show_got_added_yes( gpointer w, struct show_got_added_data *data ) +void show_got_added_yes( void *data ) { - data->ic->acc->prpl->add_buddy( data->ic, data->handle, NULL ); - /* imcb_add_buddy( data->ic, NULL, data->handle, data->handle ); */ + struct show_got_added_data *sga = data; - return show_got_added_no( w, data ); + sga->ic->acc->prpl->add_buddy( sga->ic, sga->handle, NULL ); + /* imcb_add_buddy( sga->ic, NULL, sga->handle, sga->handle ); */ + + return show_got_added_no( data ); } void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname ) diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 7d391edd..bdd8bae2 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -41,6 +41,7 @@ #include "bitlbee.h" #include "account.h" #include "proxy.h" +#include "query.h" #include "md5.h" #define BUF_LEN MSG_LEN @@ -260,7 +261,7 @@ G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G * - 'data' can be your custom struct - it will be passed to the callbacks. * - 'doit' or 'dont' will be called depending of the answer of the user. */ -G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont ); +G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, query_callback doit, query_callback dont ); G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname ); /* Buddy management */ diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 9e5de70a..7738c31f 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -1083,8 +1083,8 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ return 1; } -void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv); -void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv); +void oscar_accept_chat(void *data); +void oscar_reject_chat(void *data); static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) { struct im_connection *ic = sess->aux_data; @@ -1118,7 +1118,8 @@ static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ return 1; } -static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) { +static void gaim_icq_authgrant(void *data_) { + struct icq_auth *data = data_; char *uin, message; struct oscar_data *od = (struct oscar_data *)data->ic->proto_data; @@ -1133,7 +1134,8 @@ static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) { g_free(data); } -static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) { +static void gaim_icq_authdeny(void *data_) { + struct icq_auth *data = data_; char *uin, *message; struct oscar_data *od = (struct oscar_data *)data->ic->proto_data; @@ -2587,15 +2589,19 @@ struct groupchat *oscar_chat_with(struct im_connection * ic, char *who) return NULL; } -void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv) +void oscar_accept_chat(void *data) { + struct aim_chat_invitation * inv = data; + oscar_chat_join(inv->ic, inv->name, NULL, NULL); g_free(inv->name); g_free(inv); } -void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv) +void oscar_reject_chat(void *data) { + struct aim_chat_invitation * inv = data; + g_free(inv->name); g_free(inv); } diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 36579d66..ab30df4d 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -796,16 +796,20 @@ int ext_yahoo_connect(const char *host, int port) return -1; } -static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv ) +static void byahoo_accept_conf( void *data ) { + struct byahoo_conf_invitation *inv = data; + yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name ); imcb_chat_add_buddy( inv->c, inv->ic->acc->user ); g_free( inv->name ); g_free( inv ); } -static void byahoo_reject_conf( gpointer w, struct byahoo_conf_invitation *inv ) +static void byahoo_reject_conf( void *data ) { + struct byahoo_conf_invitation *inv = data; + yahoo_conference_decline( inv->yid, NULL, inv->members, inv->name, "User rejected groupchat" ); imcb_chat_free( inv->c ); g_free( inv->name ); -- cgit v1.2.3 From aa311173a85020bcbbbf61135a5451e171d422f5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 8 Apr 2008 21:44:34 +0100 Subject: Don't automatically enable MSN debugging messages for debugging builds. --- protocols/msn/msn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index c8f4f4c6..63759303 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -28,7 +28,7 @@ #define TYPING_NOTIFICATION_MESSAGE "\r\r\rBEWARE, ME R TYPINK MESSAGE!!!!\r\r\r" #define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r" -#ifdef DEBUG +#ifdef DEBUG_MSN #define debug( text... ) imcb_log( ic, text ); #else #define debug( text... ) -- cgit v1.2.3 From 99f929cb5faca663969361e4a142d0c309af1725 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 21 Apr 2008 22:53:15 +0100 Subject: Now checking if msn_sb_create() returns NULL. This is very unlikely, but can happen if we run out of file descriptors, for example. --- protocols/msn/ns.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'protocols') diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index ff7da6ed..ffaa90a7 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -177,7 +177,15 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } debug( "Connecting to a new switchboard with key %s", cmd[5] ); - sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW ); + + if( ( sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW ) ) == NULL ) + { + /* Although this isn't strictly fatal for the NS connection, it's + definitely something serious (we ran out of file descriptors?). */ + imcb_error( ic, "Could not create new switchboard" ); + imc_logout( ic, TRUE ); + return( 0 ); + } if( md->msgq ) { @@ -467,8 +475,18 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) debug( "Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4] ); - sb = msn_sb_create( ic, server, port, cmd[4], session ); - sb->who = g_strdup( cmd[5] ); + if( ( sb = msn_sb_create( ic, server, port, cmd[4], session ) ) == NULL ) + { + /* Although this isn't strictly fatal for the NS connection, it's + definitely something serious (we ran out of file descriptors?). */ + imcb_error( ic, "Could not create new switchboard" ); + imc_logout( ic, TRUE ); + return( 0 ); + } + else + { + sb->who = g_strdup( cmd[5] ); + } } else if( strcmp( cmd[0], "ADD" ) == 0 ) { -- cgit v1.2.3 From 21e5d4981de057bae5261720021757d893061652 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 10 Jun 2008 05:16:15 +0200 Subject: Move SSPI SSL implementation to same directory as other SSL backends. --- protocols/ssl_sspi.c | 278 --------------------------------------------------- 1 file changed, 278 deletions(-) delete mode 100644 protocols/ssl_sspi.c (limited to 'protocols') diff --git a/protocols/ssl_sspi.c b/protocols/ssl_sspi.c deleted file mode 100644 index a16423b1..00000000 --- a/protocols/ssl_sspi.c +++ /dev/null @@ -1,278 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* SSL module - SSPI backend */ - -/* Copyright (C) 2005 Jelmer Vernooij */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "ssl_client.h" -#include -#define SECURITY_WIN32 -#include -#include -#include -#include "sock.h" - -static gboolean initialized = FALSE; -int ssl_errno; - -struct scd -{ - int fd; - ssl_input_function func; - gpointer data; - gboolean established; - CredHandle cred; /* SSL credentials */ - CtxtHandle context; /* SSL context */ - SecPkgContext_StreamSizes sizes; - - char *host; - - char *pending_raw_data; - gsize pending_raw_data_len; - char *pending_data; - gsize pending_data_len; -}; - -static void ssl_connected(gpointer, gint, GaimInputCondition); - -void sspi_global_init(void) -{ - /* FIXME */ -} - -void sspi_global_deinit(void) -{ - /* FIXME */ -} - -void *ssl_connect(char *host, int port, ssl_input_function func, gpointer data) -{ - struct scd *conn = g_new0(struct scd, 1); - - conn->fd = proxy_connect(host, port, ssl_connected, conn); - sock_make_nonblocking(conn->fd); - conn->func = func; - conn->data = data; - conn->host = g_strdup(host); - - if (conn->fd < 0) - { - g_free(conn); - return NULL; - } - - if (!initialized) - { - sspi_global_init(); - initialized = TRUE; - atexit(sspi_global_deinit); - } - - return conn; -} - -static void ssl_connected(gpointer _conn, gint fd, GaimInputCondition cond) -{ - struct scd *conn = _conn; - SCHANNEL_CRED ssl_cred; - TimeStamp timestamp; - SecBuffer ibuf[2],obuf[1]; - SecBufferDesc ibufs,obufs; - ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | - ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | - ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR | - ISC_REQ_MANUAL_CRED_VALIDATION; - ULONG a; - gsize size = 0; - gchar *data = NULL; - - memset(&ssl_cred, 0, sizeof(SCHANNEL_CRED)); - ssl_cred.dwVersion = SCHANNEL_CRED_VERSION; - ssl_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; - - SECURITY_STATUS st = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &ssl_cred, NULL, NULL, &conn->cred, ×tamp); - - if (st != SEC_E_OK) { - conn->func(conn->data, NULL, cond); - return; - } - - do { - /* initialize buffers */ - ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = data; - ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NULL; - obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NULL; - ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; - ibuf[1].BufferType = SECBUFFER_EMPTY; - - /* initialize buffer descriptors */ - ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; - ibufs.cBuffers = 2; obufs.cBuffers = 1; - ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; - - st = InitializeSecurityContext(&conn->cred, size?&conn->context:NULL, conn->host, req, 0, SECURITY_NETWORK_DREP, size?&ibufs:NULL, 0, &conn->context, &obufs, &a, ×tamp); - if (obuf[0].pvBuffer && obuf[0].cbBuffer) { - /* FIXME: Check return value */ - send(conn->fd, obuf[0].pvBuffer, obuf[0].cbBuffer, 0); - } - - switch (st) { - case SEC_I_INCOMPLETE_CREDENTIALS: - break; - case SEC_I_CONTINUE_NEEDED: - break; - case SEC_E_INCOMPLETE_MESSAGE: - break; - case SEC_E_OK: - break; - } - - QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->sizes); - } while (1); - - conn->func(conn->data, conn, cond); -} - -int ssl_read(void *conn, char *retdata, int len) -{ - struct scd *scd = conn; - SecBufferDesc msg; - SecBuffer buf[4]; - int ret = -1, i; - char *data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer); - - /* FIXME: Try to read some data */ - - msg.ulVersion = SECBUFFER_VERSION; - msg.cBuffers = 4; - msg.pBuffers = buf; - - buf[0].BufferType = SECBUFFER_DATA; - buf[0].cbBuffer = len; - buf[0].pvBuffer = data; - - buf[1].BufferType = SECBUFFER_EMPTY; - buf[2].BufferType = SECBUFFER_EMPTY; - buf[3].BufferType = SECBUFFER_EMPTY; - - SECURITY_STATUS st = DecryptMessage(&scd->context, &msg, 0, NULL); - - if (st != SEC_E_OK) { - /* FIXME */ - return -1; - } - - for (i = 0; i < 4; i++) { - if (buf[i].BufferType == SECBUFFER_DATA) { - memcpy(retdata, buf[i].pvBuffer, len); - ret = len; - } - } - - g_free(data); - return -1; -} - -int ssl_write(void *conn, const char *userdata, int len) -{ - struct scd *scd = conn; - SecBuffer buf[4]; - SecBufferDesc msg; - char *data; - int ret; - - msg.ulVersion = SECBUFFER_VERSION; - msg.cBuffers = 4; - msg.pBuffers = buf; - - data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer); - memcpy(data + scd->sizes.cbHeader, userdata, len); - - buf[0].BufferType = SECBUFFER_STREAM_HEADER; - buf[0].cbBuffer = scd->sizes.cbHeader; - buf[0].pvBuffer = data; - - buf[1].BufferType = SECBUFFER_DATA; - buf[1].cbBuffer = len; - buf[1].pvBuffer = data + scd->sizes.cbHeader; - - buf[2].BufferType = SECBUFFER_STREAM_TRAILER; - buf[2].cbBuffer = scd->sizes.cbTrailer; - buf[2].pvBuffer = data + scd->sizes.cbHeader + len; - buf[3].BufferType = SECBUFFER_EMPTY; - - SECURITY_STATUS st = EncryptMessage(&scd->context, 0, &msg, 0); - - ret = send(scd->fd, data, - buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer, 0); - - g_free(data); - - return ret; -} - -void ssl_disconnect(void *conn) -{ - struct scd *scd = conn; - - SecBufferDesc msg; - SecBuffer buf; - DWORD dw; - - dw = SCHANNEL_SHUTDOWN; - buf.cbBuffer = sizeof(dw); - buf.BufferType = SECBUFFER_TOKEN; - buf.pvBuffer = &dw; - - msg.ulVersion = SECBUFFER_VERSION; - msg.cBuffers = 1; - msg.pBuffers = &buf; - - SECURITY_STATUS st = ApplyControlToken(&scd->context, &msg); - - if (st != SEC_E_OK) { - /* FIXME */ - } - - /* FIXME: call InitializeSecurityContext(Schannel), passing - * in empty buffers*/ - - DeleteSecurityContext(&scd->context); - - FreeCredentialsHandle(&scd->cred); - - closesocket(scd->fd); - g_free(scd->host); - g_free(scd); -} - -int ssl_getfd(void *conn) -{ - return ((struct scd*)conn)->fd; -} - -GaimInputCondition ssl_getdirection( void *conn ) -{ - return GAIM_INPUT_WRITE; /* FIXME: or GAIM_INPUT_READ */ -} -- cgit v1.2.3 From 52df5dfbe4761c26326083bef9daa80af9716858 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Jun 2008 02:19:12 +0100 Subject: This seems to fix the Yahoo! logoff code. I have no idea why this was broken (on purpose) in libyahoo2, but this fix seems to work and at least Valgrind is still happy. And I actually see myself log off now, and the fd is actually cleaned up properly. --- protocols/yahoo/libyahoo2.c | 11 ++++------- protocols/yahoo/yahoo.c | 4 ---- 2 files changed, 4 insertions(+), 11 deletions(-) (limited to 'protocols') diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index 80d88a85..897ba27b 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -380,7 +380,6 @@ static void del_from_list(struct yahoo_data *yd) } /* call repeatedly to get the next one */ -/* static struct yahoo_input_data * find_input_by_id(int id) { YList *l; @@ -391,7 +390,6 @@ static struct yahoo_input_data * find_input_by_id(int id) } return NULL; } -*/ static struct yahoo_input_data * find_input_by_id_and_webcam_user(int id, const char * who) { @@ -796,6 +794,7 @@ static int yahoo_send_data(int fd, void *data, int len) void yahoo_close(int id) { struct yahoo_data *yd = find_conn_by_id(id); + if(!yd) return; @@ -3165,7 +3164,7 @@ int yahoo_write_ready(int id, int fd, void *data) struct data_queue *tx; LOG(("write callback: id=%d fd=%d data=%p", id, fd, data)); - if(!yid || !yid->txqueues) + if(!yid || !yid->txqueues || !find_conn_by_id(id)) return -2; tx = yid->txqueues->data; @@ -3841,11 +3840,9 @@ void yahoo_logoff(int id) } } - -/* do { + do { yahoo_input_close(yid); - } while((yid = find_input_by_id(id)));*/ - + } while((yid = find_input_by_id(id))); } void yahoo_get_list(int id) diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index ab30df4d..c84685e9 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -453,10 +453,6 @@ gboolean byahoo_write_ready_callback( gpointer data, gint source, b_input_condit { struct byahoo_write_ready_data *d = data; - if( !byahoo_get_ic_by_id( d->id ) ) - /* WTF doesn't libyahoo clean this up? */ - return FALSE; - yahoo_write_ready( d->id, d->fd, d->data ); return FALSE; -- cgit v1.2.3 From 5ec4129afd5d47d7cea5d9cb455a364c17c8a8fa Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jun 2008 01:04:27 +0100 Subject: Added parsing of Jabber chatroom invitations. --- protocols/jabber/message.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'protocols') diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index fab62a91..6cb67d42 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -48,6 +48,23 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */ { GString *fullmsg = g_string_new( "" ); + + for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) + { + char *ns = xt_find_attr( c, "xmlns" ), *room; + struct xt_node *inv, *reason; + + if( strcmp( ns, XMLNS_MUC_USER ) == 0 && + ( inv = xt_find_node( c->children, "invite" ) ) ) + { + room = from; + from = xt_find_attr( inv, "from" ) ? : from; + + g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Invitation to chatroom %s >>\n", room ); + if( ( reason = xt_find_node( inv->children, "reason" ) ) && reason->text_len > 0 ) + g_string_append( fullmsg, reason->text ); + } + } if( ( s = strchr( from, '/' ) ) ) { -- cgit v1.2.3 From 7f697401c8261459ce60c985ae1423db7b22c79b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jun 2008 19:11:47 +0100 Subject: Using a port list instead of a single range for the allowed Jabber port numbers, adding 80 and 443. Partially closes #265. --- protocols/jabber/jabber.c | 32 +++++++++++++++++++++++++++----- protocols/jabber/jabber.h | 4 ---- 2 files changed, 27 insertions(+), 9 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 0e23b4d4..52a87d5d 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -36,11 +36,30 @@ GSList *jabber_connections; +/* First enty is the default */ +static const int jabber_port_list[] = { + 5222, + 5223, + 5220, + 5221, + 5224, + 5225, + 5226, + 5227, + 5228, + 5229, + 80, + 443, + 0 +}; + static void jabber_init( account_t *acc ) { set_t *s; + char str[16]; - s = set_add( &acc->set, "port", JABBER_PORT_DEFAULT, set_eval_int, acc ); + g_snprintf( str, sizeof( str ), "%d", jabber_port_list[0] ); + s = set_add( &acc->set, "port", str, set_eval_int, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); @@ -71,6 +90,7 @@ static void jabber_login( account_t *acc ) struct jabber_data *jd = g_new0( struct jabber_data, 1 ); struct ns_srv_reply *srv = NULL; char *connect_to, *s; + int i; /* For now this is needed in the _connected() handlers if using GLib event handling, to make sure we're not handling events @@ -176,11 +196,13 @@ static void jabber_login( account_t *acc ) imcb_log( ic, "Connecting" ); - if( set_getint( &acc->set, "port" ) < JABBER_PORT_MIN || - set_getint( &acc->set, "port" ) > JABBER_PORT_MAX ) + for( i = 0; jabber_port_list[i] > 0; i ++ ) + if( set_getint( &acc->set, "port" ) == jabber_port_list[i] ) + break; + + if( jabber_port_list[i] == 0 ) { - imcb_log( ic, "Incorrect port number, must be in the %d-%d range", - JABBER_PORT_MIN, JABBER_PORT_MAX ); + imcb_log( ic, "Illegal port number" ); imc_logout( ic, FALSE ); return; } diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 1ff0e8dd..023cf0f9 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -134,10 +134,6 @@ struct jabber_chat #define JABBER_XMLCONSOLE_HANDLE "xmlconsole" -#define JABBER_PORT_DEFAULT "5222" -#define JABBER_PORT_MIN 5220 -#define JABBER_PORT_MAX 5229 - /* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the first one should be used, but when storing a packet in the cache, a "special" kind of ID is assigned to make it easier later to figure out -- cgit v1.2.3 From 3e6764ab9c8ebd99683fd3c153161d96b32e05de Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jun 2008 00:34:11 +0100 Subject: Added jabber_util unittests (buddy_add/_by_jid only ATM). --- protocols/jabber/jabber_util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 518624f6..78d1009c 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -524,7 +524,9 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) /* If there's only one item in the list (and if the resource matches), removing it is simple. (And the hash reference should be removed too!) */ - if( bud->next == NULL && ( ( s == NULL || bud->resource == NULL ) || g_strcasecmp( bud->resource, s + 1 ) == 0 ) ) + if( bud->next == NULL && + ( ( s == NULL && bud->resource == NULL ) || + ( bud->resource && s && g_strcasecmp( bud->resource, s + 1 ) == 0 ) ) ) { g_hash_table_remove( jd->buddies, bud->bare_jid ); g_free( bud->bare_jid ); -- cgit v1.2.3 From 98de2cca016d458ad2980c59f334fae10164b3bb Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jun 2008 00:51:18 +0100 Subject: Now preserving case in JID resources, and handling them with case sensitivity since apparently that's how the RFC wants it. (While the rest of the JID should be case IN-sensitive. Consistency is hard to find these days...) Also extended the unittests a little bit. Closes #422. --- protocols/jabber/jabber_util.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 78d1009c..44dc5984 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -289,8 +289,13 @@ char *jabber_normalize( const char *orig ) len = strlen( orig ); new = g_new( char, len + 1 ); - for( i = 0; i < len; i ++ ) + + /* So it turns out the /resource part is case sensitive. Yeah, and + it's Unicode but feck Unicode. :-P So stop once we see a slash. */ + for( i = 0; i < len && orig[i] != '/' ; i ++ ) new[i] = tolower( orig[i] ); + for( ; orig[i]; i ++ ) + new[i] = orig[i]; new[i] = 0; return new; @@ -333,7 +338,7 @@ struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid_ for( bi = bud; bi; bi = bi->next ) { /* Check for dupes. */ - if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) + if( strcmp( bi->resource, s + 1 ) == 0 ) { *s = '/'; g_free( new ); @@ -386,7 +391,7 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, if( ( s = strchr( jid, '/' ) ) ) { - int none_found = 0; + int bare_exists = 0; *s = 0; if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) @@ -409,21 +414,19 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, /* See if there's an exact match. */ for( ; bud; bud = bud->next ) - if( g_strcasecmp( bud->resource, s + 1 ) == 0 ) + if( strcmp( bud->resource, s + 1 ) == 0 ) break; } else { - /* This hack is there to make sure that O_CREAT will - work if there's already another resouce present - for this JID, even if it's an unknown buddy. This - is done to handle conferences properly. */ - none_found = 1; - /* TODO(wilmer): Find out what I was thinking when I - wrote this??? And then fix it. This makes me sad... */ + /* This variable tells the if down here that the bare + JID already exists and we should feel free to add + more resources, if the caller asked for that. */ + bare_exists = 1; } - if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) ) + if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && + ( !bare_exists || imcb_find_buddy( ic, jid ) ) ) { *s = '/'; bud = jabber_buddy_add( ic, jid ); @@ -448,7 +451,7 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, else if( bud->resource && ( flags & GET_BUDDY_EXACT ) ) /* We want an exact match, so in thise case there shouldn't be a /resource. */ return NULL; - else if( ( bud->resource == NULL || bud->next == NULL ) ) + else if( bud->resource == NULL || bud->next == NULL ) /* No need for selection if there's only one option. */ return bud; else if( flags & GET_BUDDY_FIRST ) @@ -526,7 +529,7 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) should be removed too!) */ if( bud->next == NULL && ( ( s == NULL && bud->resource == NULL ) || - ( bud->resource && s && g_strcasecmp( bud->resource, s + 1 ) == 0 ) ) ) + ( bud->resource && s && strcmp( bud->resource, s + 1 ) == 0 ) ) ) { g_hash_table_remove( jd->buddies, bud->bare_jid ); g_free( bud->bare_jid ); @@ -549,7 +552,7 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) else { for( bi = bud, prev = NULL; bi; bi = (prev=bi)->next ) - if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) + if( strcmp( bi->resource, s + 1 ) == 0 ) break; g_free( full_jid ); -- cgit v1.2.3 From 424e66361e985d05e47a7af42e81cd32b09dd6e2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jun 2008 10:32:46 +0100 Subject: Partial fix for #419: Moved normalize() and some other stuff to OSCAR becuase it's the only place where it's used, and using this to strip spaces from all screennames before sending them to BitlBee. --- protocols/nogaim.h | 5 ---- protocols/oscar/oscar.c | 80 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 56 insertions(+), 29 deletions(-) (limited to 'protocols') diff --git a/protocols/nogaim.h b/protocols/nogaim.h index bdd8bae2..9fe843b5 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -44,11 +44,6 @@ #include "query.h" #include "md5.h" -#define BUF_LEN MSG_LEN -#define BUF_LONG ( BUF_LEN * 2 ) -#define MSG_LEN 2048 -#define BUF_LEN MSG_LEN - #define BUDDY_ALIAS_MAXLEN 388 /* because MSN names can be 387 characters */ #define WEBSITE "http://www.bitlbee.org/" diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 7738c31f..819ec27d 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -60,6 +60,9 @@ #define OSCAR_GROUP "Friends" +#define BUF_LEN 2048 +#define BUF_LONG ( BUF_LEN * 2 ) + /* Don't know if support for UTF8 is really working. For now it's UTF16 here. static int gaim_caps = AIM_CAPS_UTF8; */ @@ -240,6 +243,32 @@ static char *msgerrreason[] = { }; static int msgerrreasonlen = 25; +/* Hurray, this function is NOT thread-safe \o/ */ +static char *normalize(const char *s) +{ + static char buf[BUF_LEN]; + char *t, *u; + int x = 0; + + g_return_val_if_fail((s != NULL), NULL); + + u = t = g_strdup(s); + + strcpy(t, s); + g_strdown(t); + + while (*t && (x < BUF_LEN - 1)) { + if (*t != ' ' && *t != '!') { + buf[x] = *t; + x++; + } + t++; + } + buf[x] = '\0'; + g_free(u); + return buf; +} + static gboolean oscar_callback(gpointer data, gint source, b_input_condition condition) { aim_conn_t *conn = (aim_conn_t *)data; @@ -1001,13 +1030,13 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { g_hash_table_insert(od->ips, uin, (gpointer) (long) info->icqinfo.ipaddr); } - tmp = g_strdup(normalize(ic->acc->user)); - if (!strcmp(tmp, normalize(info->sn))) + if (!aim_sncmp(tmp, normalize(info->sn))) g_snprintf(ic->displayname, sizeof(ic->displayname), "%s", info->sn); - g_free(tmp); - imcb_buddy_status(ic, info->sn, flags, state_string, NULL); - /* imcb_buddy_times(ic, info->sn, signon, time_idle); */ + tmp = normalize(info->sn); + imcb_buddy_status(ic, tmp, flags, state_string, NULL); + /* imcb_buddy_times(ic, tmp, signon, time_idle); */ + return 1; } @@ -1021,7 +1050,7 @@ static int gaim_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...) { info = va_arg(ap, aim_userinfo_t *); va_end(ap); - imcb_buddy_status(ic, info->sn, 0, NULL, NULL ); + imcb_buddy_status(ic, normalize(info->sn), 0, NULL, NULL ); return 1; } @@ -1077,7 +1106,7 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ } strip_linefeed(tmp); - imcb_buddy_msg(ic, userinfo->sn, tmp, flags, 0); + imcb_buddy_msg(ic, normalize(userinfo->sn), tmp, flags, 0); g_free(tmp); return 1; @@ -1176,7 +1205,7 @@ static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ uin = g_strdup_printf("%u", args->uin); message = g_strdup(args->msg); strip_linefeed(message); - imcb_buddy_msg(ic, uin, message, 0, 0); + imcb_buddy_msg(ic, normalize(uin), message, 0, 0); g_free(uin); g_free(message); } break; @@ -1195,7 +1224,7 @@ static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ } strip_linefeed(message); - imcb_buddy_msg(ic, uin, message, 0, 0); + imcb_buddy_msg(ic, normalize(uin), message, 0, 0); g_free(uin); g_free(m); g_free(message); @@ -1470,7 +1499,7 @@ static int gaim_chat_join(aim_session_t *sess, aim_frame_t *fr, ...) { return 1; for (i = 0; i < count; i++) - imcb_chat_add_buddy(c->cnv, info[i].sn); + imcb_chat_add_buddy(c->cnv, normalize(info[i].sn)); return 1; } @@ -1493,7 +1522,7 @@ static int gaim_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...) { return 1; for (i = 0; i < count; i++) - imcb_chat_remove_buddy(c->cnv, info[i].sn, NULL); + imcb_chat_remove_buddy(c->cnv, normalize(info[i].sn), NULL); return 1; } @@ -1544,7 +1573,7 @@ static int gaim_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...) { tmp = g_malloc(BUF_LONG); g_snprintf(tmp, BUF_LONG, "%s", msg); - imcb_chat_msg(ccon->cnv, info->sn, tmp, 0, 0); + imcb_chat_msg(ccon->cnv, normalize(info->sn), tmp, 0, 0); g_free(tmp); return 1; @@ -1757,7 +1786,7 @@ static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) { time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0); g_snprintf(sender, sizeof(sender), "%u", msg->sender); strip_linefeed(dialog_msg); - imcb_buddy_msg(ic, sender, dialog_msg, 0, t); + imcb_buddy_msg(ic, normalize(sender), dialog_msg, 0, t); g_free(dialog_msg); } break; @@ -1778,7 +1807,7 @@ static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) { } strip_linefeed(dialog_msg); - imcb_buddy_msg(ic, sender, dialog_msg, 0, t); + imcb_buddy_msg(ic, normalize(sender), dialog_msg, 0, t); g_free(dialog_msg); g_free(m); } break; @@ -2016,23 +2045,26 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { struct im_connection *ic = sess->aux_data; struct aim_ssi_item *curitem; int tmp; + char *nrm; /* Add from server list to local list */ tmp = 0; for (curitem=sess->ssi.items; curitem; curitem=curitem->next) { switch (curitem->type) { case 0x0000: /* Buddy */ - if ((curitem->name) && (!imcb_find_buddy(ic, curitem->name))) { + nrm = normalize(curitem->name); + + if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) { char *realname = NULL; if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1)) realname = aim_gettlv_str(curitem->data, 0x0131, 1); - imcb_add_buddy(ic, curitem->name, NULL); + imcb_add_buddy(ic, nrm, NULL); if (realname) { - imcb_buddy_nick_hint(ic, curitem->name, realname); - imcb_rename_buddy(ic, curitem->name, realname); + imcb_buddy_nick_hint(ic, nrm, realname); + imcb_rename_buddy(ic, nrm, realname); g_free(realname); } } @@ -2044,7 +2076,7 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { for (list=ic->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next); if (!list) { char *name; - name = g_strdup(normalize(curitem->name)); + name = g_strdup(nrm); ic->permit = g_slist_append(ic->permit, name); tmp++; } @@ -2057,7 +2089,7 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { for (list=ic->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next); if (!list) { char *name; - name = g_strdup(normalize(curitem->name)); + name = g_strdup(nrm); ic->deny = g_slist_append(ic->deny, name); tmp++; } @@ -2119,7 +2151,7 @@ static int gaim_ssi_parseack( aim_session_t *sess, aim_frame_t *fr, ... ) st = aimbs_get16( &fr->data ); if( st == 0x00 ) { - imcb_add_buddy( sess->aux_data, list, NULL ); + imcb_add_buddy( sess->aux_data, normalize(list), NULL ); } else if( st == 0x0E ) { @@ -2449,15 +2481,15 @@ int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...) if(type2 == 0x0002) { /* User is typing */ - imcb_buddy_typing(ic, sn, OPT_TYPING); + imcb_buddy_typing(ic, normalize(sn), OPT_TYPING); } else if (type2 == 0x0001) { /* User has typed something, but is not actively typing (stale) */ - imcb_buddy_typing(ic, sn, OPT_THINKING); + imcb_buddy_typing(ic, normalize(sn), OPT_THINKING); } else { /* User has stopped typing */ - imcb_buddy_typing(ic, sn, 0); + imcb_buddy_typing(ic, normalize(sn), 0); } return 1; -- cgit v1.2.3 From c801d25cc574279566b35c3a9fce96962521670a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jun 2008 11:05:33 +0100 Subject: Fixed bug in [devel,394]. --- protocols/oscar/oscar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 819ec27d..1bd221b4 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -1030,7 +1030,7 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { g_hash_table_insert(od->ips, uin, (gpointer) (long) info->icqinfo.ipaddr); } - if (!aim_sncmp(tmp, normalize(info->sn))) + if (!aim_sncmp(ic->acc->user, info->sn)) g_snprintf(ic->displayname, sizeof(ic->displayname), "%s", info->sn); tmp = normalize(info->sn); -- cgit v1.2.3 From de823359bee02853be86b75ddc8272812502ff5d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jun 2008 13:26:19 +0100 Subject: Another fixup after [devel,394]. Clearly I'm not a morning person. --- protocols/oscar/oscar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'protocols') diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 1bd221b4..a3b4a071 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -2050,10 +2050,10 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { /* Add from server list to local list */ tmp = 0; for (curitem=sess->ssi.items; curitem; curitem=curitem->next) { + nrm = normalize(curitem->name); + switch (curitem->type) { case 0x0000: /* Buddy */ - nrm = normalize(curitem->name); - if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) { char *realname = NULL; -- cgit v1.2.3 From fab3d2d497e2819c142859a3698e85372e58df14 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jun 2008 14:02:15 +0100 Subject: Shut up a "mostly harmless" warning (this NULL would never actually be dereferenced as far as I can see). --- protocols/oscar/oscar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index a3b4a071..36e03166 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -2050,7 +2050,7 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { /* Add from server list to local list */ tmp = 0; for (curitem=sess->ssi.items; curitem; curitem=curitem->next) { - nrm = normalize(curitem->name); + nrm = curitem->name ? normalize(curitem->name) : NULL; switch (curitem->type) { case 0x0000: /* Buddy */ -- cgit v1.2.3 From 89d736a169cbff4520dcbb475aa7269b2cf4b837 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jun 2008 20:21:06 +0100 Subject: From the department of over-engineering, now cached packet IDs are full MD5 hashes instead of a known MD5 hash with a number. Just to make it harder to confuse BitlBee by sending it faked responses to packets. --- protocols/jabber/jabber.c | 24 +++++++++--------------- protocols/jabber/jabber.h | 2 +- protocols/jabber/jabber_util.c | 24 +++++++++++++++++++++--- 3 files changed, 31 insertions(+), 19 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 52a87d5d..c9c1d0a0 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -32,7 +32,6 @@ #include "bitlbee.h" #include "jabber.h" #include "md5.h" -#include "base64.h" GSList *jabber_connections; @@ -240,24 +239,20 @@ static void jabber_login( account_t *acc ) jabber_generate_id_hash( jd ); } +/* This generates an unfinished md5_state_t variable. Every time we generate + an ID, we finish the state by adding a sequence number and take the hash. */ static void jabber_generate_id_hash( struct jabber_data *jd ) { - md5_state_t id_hash; - md5_byte_t binbuf[16]; + md5_byte_t binbuf[4]; char *s; - md5_init( &id_hash ); - md5_append( &id_hash, (unsigned char *) jd->username, strlen( jd->username ) ); - md5_append( &id_hash, (unsigned char *) jd->server, strlen( jd->server ) ); + md5_init( &jd->cached_id_prefix ); + md5_append( &jd->cached_id_prefix, (unsigned char *) jd->username, strlen( jd->username ) ); + md5_append( &jd->cached_id_prefix, (unsigned char *) jd->server, strlen( jd->server ) ); s = set_getstr( &jd->ic->acc->set, "resource" ); - md5_append( &id_hash, (unsigned char *) s, strlen( s ) ); - random_bytes( binbuf, 16 ); - md5_append( &id_hash, binbuf, 16 ); - md5_finish( &id_hash, binbuf ); - - s = base64_encode( binbuf, 9 ); - jd->cached_id_prefix = g_strdup_printf( "%s%s", JABBER_CACHED_ID, s ); - g_free( s ); + md5_append( &jd->cached_id_prefix, (unsigned char *) s, strlen( s ) ); + random_bytes( binbuf, 4 ); + md5_append( &jd->cached_id_prefix, binbuf, 4 ); } static void jabber_logout( struct im_connection *ic ) @@ -288,7 +283,6 @@ static void jabber_logout( struct im_connection *ic ) xt_free( jd->xt ); - g_free( jd->cached_id_prefix ); g_free( jd->away_message ); g_free( jd->username ); g_free( jd ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 023cf0f9..904bf0c4 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -85,7 +85,7 @@ struct jabber_data struct jabber_away_state *away_state; char *away_message; - char *cached_id_prefix; + md5_state_t cached_id_prefix; GHashTable *node_cache; GHashTable *buddies; }; diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 44dc5984..1bee5009 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -22,6 +22,8 @@ \***************************************************************************/ #include "jabber.h" +#include "md5.h" +#include "base64.h" static unsigned int next_id = 1; @@ -133,11 +135,21 @@ void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_ca { struct jabber_data *jd = ic->proto_data; struct jabber_cache_entry *entry = g_new0( struct jabber_cache_entry, 1 ); - char *id; + md5_state_t id_hash; + md5_byte_t id_sum[16]; + char *id, *asc_hash; - id = g_strdup_printf( "%s%05x", jd->cached_id_prefix, ( next_id++ ) & 0xfffff ); + next_id ++; + + id_hash = jd->cached_id_prefix; + md5_append( &id_hash, (md5_byte_t*) &next_id, sizeof( next_id ) ); + md5_finish( &id_hash, id_sum ); + asc_hash = base64_encode( id_sum, 12 ); + + id = g_strdup_printf( "%s%s", JABBER_CACHED_ID, asc_hash ); xt_add_attr( node, "id", id ); g_free( id ); + g_free( asc_hash ); entry->node = node; entry->func = func; @@ -183,7 +195,7 @@ xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node * char *s; if( ( s = xt_find_attr( node, "id" ) ) == NULL || - strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 ) + strncmp( s, JABBER_CACHED_ID, strlen( JABBER_CACHED_ID ) ) != 0 ) { /* Silently ignore it, without an ID (or a non-cache ID) we don't know how to handle the packet and we @@ -195,8 +207,14 @@ xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node * if( entry == NULL ) { + /* + There's no longer an easy way to see if we generated this + one or someone else, and there's a ten-minute timeout anyway, + so meh. + imcb_log( ic, "Warning: Received %s-%s packet with unknown/expired ID %s!", node->name, xt_find_attr( node, "type" ) ? : "(no type)", s ); + */ } else if( entry->func ) { -- cgit v1.2.3 From dfbb0563ac250c65f74b7bb3f49ca8d2ccc9e9c8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 24 Jun 2008 10:01:29 +0100 Subject: Never use yahoo_close() directly, always use yahoo_logoff(). --- protocols/yahoo/yahoo.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'protocols') diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index c84685e9..197d76a1 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -162,10 +162,7 @@ static void byahoo_logout( struct im_connection *ic ) } g_slist_free( yd->buddygroups ); - if( yd->logged_in ) - yahoo_logoff( yd->y2_id ); - else - yahoo_close( yd->y2_id ); + yahoo_logoff( yd->y2_id ); g_free( yd ); } -- cgit v1.2.3 From 1145964911d0d7dd5145de6f7b9d4ed8aeeacd79 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 29 Jun 2008 12:11:50 +0100 Subject: Fixed two memory leaks in the MSN module. --- protocols/msn/ns.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'protocols') diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index ffaa90a7..fe48f96d 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -277,11 +277,25 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { if( num_parts == 5 ) { - md->buddycount = atoi( cmd[3] ); - md->groupcount = atoi( cmd[4] ); - if( md->groupcount > 0 ) + int i, groupcount; + + groupcount = atoi( cmd[4] ); + if( groupcount > 0 ) + { + /* valgrind says this is leaking memory, I'm guessing + that this happens during server redirects. */ + if( md->grouplist ) + { + for( i = 0; i < md->groupcount; i ++ ) + g_free( md->grouplist[i] ); + g_free( md->grouplist ); + } + + md->groupcount = groupcount; md->grouplist = g_new0( char *, md->groupcount ); + } + md->buddycount = atoi( cmd[3] ); if( !*cmd[3] || md->buddycount == 0 ) msn_logged_in( ic ); } @@ -664,6 +678,9 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int { imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); } + + g_free( inbox ); + g_free( folders ); } else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 ) { -- cgit v1.2.3