From df1694b9559d4abec748b0506b5f44e684d022a8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 14:15:42 +0200 Subject: Moving all generic files to lib/ instead of having some in / and some in protocols/, and adding RC4 code. --- lib/Makefile | 37 ++++ lib/events.h | 66 ++++++ lib/events_glib.c | 137 +++++++++++++ lib/events_libevent.c | 247 ++++++++++++++++++++++ lib/http_client.c | 453 ++++++++++++++++++++++++++++++++++++++++ lib/http_client.h | 57 ++++++ lib/ini.c | 90 ++++++++ lib/ini.h | 43 ++++ lib/md5.c | 392 +++++++++++++++++++++++++++++++++++ lib/md5.h | 85 ++++++++ lib/misc.c | 481 +++++++++++++++++++++++++++++++++++++++++++ lib/misc.h | 51 +++++ lib/proxy.c | 556 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/proxy.h | 53 +++++ lib/rc4.c | 179 ++++++++++++++++ lib/rc4.h | 35 ++++ lib/sha.c | 173 ++++++++++++++++ lib/sha.h | 21 ++ lib/ssl_bogus.c | 57 ++++++ lib/ssl_client.h | 42 ++++ lib/ssl_gnutls.c | 206 +++++++++++++++++++ lib/ssl_nss.c | 190 +++++++++++++++++ lib/ssl_openssl.c | 221 ++++++++++++++++++++ lib/url.c | 107 ++++++++++ lib/url.h | 44 ++++ 25 files changed, 4023 insertions(+) create mode 100644 lib/Makefile create mode 100644 lib/events.h create mode 100644 lib/events_glib.c create mode 100644 lib/events_libevent.c create mode 100644 lib/http_client.c create mode 100644 lib/http_client.h create mode 100644 lib/ini.c create mode 100644 lib/ini.h create mode 100644 lib/md5.c create mode 100644 lib/md5.h create mode 100644 lib/misc.c create mode 100644 lib/misc.h create mode 100644 lib/proxy.c create mode 100644 lib/proxy.h create mode 100644 lib/rc4.c create mode 100644 lib/rc4.h create mode 100644 lib/sha.c create mode 100644 lib/sha.h create mode 100644 lib/ssl_bogus.c create mode 100644 lib/ssl_client.h create mode 100644 lib/ssl_gnutls.c create mode 100644 lib/ssl_nss.c create mode 100644 lib/ssl_openssl.c create mode 100644 lib/url.c create mode 100644 lib/url.h (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 00000000..80cdd9a5 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,37 @@ +########################### +## Makefile for BitlBee ## +## ## +## Copyright 2006 Lintux ## +########################### + +### DEFINITIONS + +-include ../Makefile.settings + +# [SH] Program variables +objects = $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o rc4.o sha.o $(SSL_CLIENT) url.o + +CFLAGS += -Wall +LFLAGS += -r + +# [SH] Phony targets +all: lib.o + +.PHONY: all clean distclean + +clean: $(subdirs) + rm -f *.o $(OUTFILE) core + +distclean: clean $(subdirs) + +### MAIN PROGRAM + +lib.o: $(objects) $(subdirs) + @echo '*' Linking lib.o + @$(LD) $(LFLAGS) $(objects) -o lib.o + +$(objects): ../Makefile.settings Makefile + +$(objects): %.o: %.c + @echo '*' Compiling $< + @$(CC) -c $(CFLAGS) $< -o $@ diff --git a/lib/events.h b/lib/events.h new file mode 100644 index 00000000..781fca6a --- /dev/null +++ b/lib/events.h @@ -0,0 +1,66 @@ +/* + * nogaim + * + * Copyright (C) 2006 Wilmer van der Gaast and others + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Split off the event handling things from proxy.[ch] (and adding timer + * stuff. This to allow BitlBee to use other libs than GLib for event + * handling. + */ + + +#ifndef _EVENTS_H_ +#define _EVENTS_H_ + +#include +#ifndef _WIN32 +#include +#include +#include +#endif +#include +#include + +typedef enum { + GAIM_INPUT_READ = 1 << 1, + GAIM_INPUT_WRITE = 1 << 2 +} b_input_condition; +typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond); + +#define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) +#define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) +#define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) + +// #define event_debug( x... ) printf( x ) +#define event_debug( x... ) + +G_MODULE_EXPORT void b_main_init(); +G_MODULE_EXPORT void b_main_run(); +G_MODULE_EXPORT void b_main_quit(); + +G_MODULE_EXPORT gint b_input_add(int fd, b_input_condition cond, b_event_handler func, gpointer data); +G_MODULE_EXPORT gint b_timeout_add(gint timeout, b_event_handler func, gpointer data); +G_MODULE_EXPORT void b_event_remove(gint id); + +#ifdef EVENTS_LIBEVENT +G_MODULE_EXPORT void closesocket(int fd); +#endif + +#endif /* _EVENTS_H_ */ diff --git a/lib/events_glib.c b/lib/events_glib.c new file mode 100644 index 00000000..620720cd --- /dev/null +++ b/lib/events_glib.c @@ -0,0 +1,137 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* + * Event handling (using GLib) + */ + +/* + 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 +*/ + +#define BITLBEE_CORE +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#else +#include "sock.h" +#define ETIMEDOUT WSAETIMEDOUT +#define EINPROGRESS WSAEINPROGRESS +#endif +#include +#include +#include "proxy.h" + +typedef struct _GaimIOClosure { + b_event_handler function; + guint result; + gpointer data; +} GaimIOClosure; + +static GMainLoop *loop; + +void b_main_init() +{ + loop = g_main_new( FALSE ); +} + +void b_main_run() +{ + g_main_run( loop ); +} + +void b_main_quit() +{ + g_main_quit( loop ); +} + +static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) +{ + GaimIOClosure *closure = data; + b_input_condition gaim_cond = 0; + gboolean st; + + if (condition & GAIM_READ_COND) + gaim_cond |= GAIM_INPUT_READ; + if (condition & GAIM_WRITE_COND) + gaim_cond |= GAIM_INPUT_WRITE; + + event_debug( "gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data ); + + st = closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond); + + if( !st ) + event_debug( "Returned FALSE, cancelling.\n" ); + + return st; +} + +static void gaim_io_destroy(gpointer data) +{ + event_debug( "gaim_io_destroy( 0x%x )\n", data ); + g_free(data); +} + +gint b_input_add(gint source, b_input_condition condition, b_event_handler function, gpointer data) +{ + GaimIOClosure *closure = g_new0(GaimIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = 0; + + closure->function = function; + closure->data = data; + + if (condition & GAIM_INPUT_READ) + cond |= GAIM_READ_COND; + if (condition & GAIM_INPUT_WRITE) + cond |= GAIM_WRITE_COND; + + channel = g_io_channel_unix_new(source); + closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, + gaim_io_invoke, closure, gaim_io_destroy); + + event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d (0x%x)\n", source, condition, function, data, closure->result, closure ); + + g_io_channel_unref(channel); + return closure->result; +} + +gint b_timeout_add(gint timeout, b_event_handler func, gpointer data) +{ + gint st = g_timeout_add(timeout, func, data); + + event_debug( "b_timeout_add( %d, %d, %d ) = %d\n", timeout, func, data, st ); + + return st; +} + +void b_event_remove(gint tag) +{ + event_debug( "b_event_remove( %d )\n", tag ); + + if (tag > 0) + g_source_remove(tag); +} diff --git a/lib/events_libevent.c b/lib/events_libevent.c new file mode 100644 index 00000000..1119c2ab --- /dev/null +++ b/lib/events_libevent.c @@ -0,0 +1,247 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* + * Event handling (using libevent) + */ + +/* + 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 +*/ + +#define BITLBEE_CORE +#include +#include +#include +#include +#include +#include "proxy.h" + +#include +#include + +static guint id_next; +static GHashTable *id_hash; +static int quitting = 0; + +/* Since libevent doesn't handle two event handlers for one fd-condition + very well (which happens sometimes when BitlBee changes event handlers + for a combination), let's buid some indexes so we can delete them here + already, just in time. */ +static GHashTable *read_hash; +static GHashTable *write_hash; + +struct b_event_data +{ + guint id; + struct event evinfo; + gint timeout; + b_event_handler function; + void *data; +}; + +void b_main_init() +{ + event_init(); + + id_next = 1; + id_hash = g_hash_table_new( g_int_hash, g_int_equal ); + read_hash = g_hash_table_new( g_int_hash, g_int_equal ); + write_hash = g_hash_table_new( g_int_hash, g_int_equal ); +} + +void b_main_run() +{ + event_dispatch(); +} + +void b_main_quit() +{ + struct timeval tv; + + /* libevent sometimes generates events before really quitting, + we want to stop them. */ + quitting = 1; + + memset( &tv, 0, sizeof( struct timeval ) ); + event_loopexit( &tv ); +} + +static void b_event_passthrough( int fd, short event, void *data ) +{ + struct b_event_data *b_ev = data; + b_input_condition cond = 0; + int id; + + if( fd >= 0 ) + { + if( event & EV_READ ) + cond |= GAIM_INPUT_READ; + if( event & EV_WRITE ) + cond |= GAIM_INPUT_WRITE; + } + + event_debug( "b_event_passthrough( %d, %d, 0x%x ) (%d)\n", fd, event, (int) data, b_ev->id ); + + /* Since the called function might cancel this handler already + (which free()s b_ev, we have to remember the ID here. */ + id = b_ev->id; + + if( quitting ) + { + b_event_remove( id ); + return; + } + + if( !b_ev->function( b_ev->data, fd, cond ) ) + { + event_debug( "Handler returned FALSE: " ); + b_event_remove( id ); + } + else if( fd == -1 ) + { + struct timeval tv; + + tv.tv_sec = b_ev->timeout / 1000; + tv.tv_usec = ( b_ev->timeout % 1000 ) * 1000; + + evtimer_add( &b_ev->evinfo, &tv ); + } +} + +gint b_input_add( gint fd, b_input_condition condition, b_event_handler function, gpointer data ) +{ + struct b_event_data *b_ev; + + event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) ", fd, condition, function, data ); + + if( ( condition & GAIM_INPUT_READ && ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) || + ( condition & GAIM_INPUT_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) ) + { + /* We'll stick with this libevent entry, but give it a new BitlBee id. */ + g_hash_table_remove( id_hash, &b_ev->id ); + + event_debug( "(replacing old handler (id = %d)) = %d\n", b_ev->id, id_next ); + + b_ev->id = id_next++; + b_ev->function = function; + b_ev->data = data; + } + else + { + GIOCondition out_cond; + + event_debug( "(new) = %d\n", id_next ); + + b_ev = g_new0( struct b_event_data, 1 ); + b_ev->id = id_next++; + b_ev->function = function; + b_ev->data = data; + + out_cond = EV_PERSIST; + if( condition & GAIM_INPUT_READ ) + out_cond |= EV_READ; + if( condition & GAIM_INPUT_WRITE ) + out_cond |= EV_WRITE; + + event_set( &b_ev->evinfo, fd, out_cond, b_event_passthrough, b_ev ); + event_add( &b_ev->evinfo, NULL ); + + if( out_cond & EV_READ ) + g_hash_table_insert( read_hash, &b_ev->evinfo.ev_fd, b_ev ); + if( out_cond & EV_WRITE ) + g_hash_table_insert( write_hash, &b_ev->evinfo.ev_fd, b_ev ); + } + + g_hash_table_insert( id_hash, &b_ev->id, b_ev ); + return b_ev->id; +} + +/* TODO: Persistence for timers! */ +gint b_timeout_add( gint timeout, b_event_handler function, gpointer data ) +{ + struct b_event_data *b_ev = g_new0( struct b_event_data, 1 ); + struct timeval tv; + + b_ev->id = id_next++; + b_ev->timeout = timeout; + b_ev->function = function; + b_ev->data = data; + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + evtimer_set( &b_ev->evinfo, b_event_passthrough, b_ev ); + evtimer_add( &b_ev->evinfo, &tv ); + + event_debug( "b_timeout_add( %d, 0x%x, 0x%x ) = %d\n", timeout, function, data, b_ev->id ); + + g_hash_table_insert( id_hash, &b_ev->id, b_ev ); + + return b_ev->id; +} + +void b_event_remove( gint id ) +{ + struct b_event_data *b_ev = g_hash_table_lookup( id_hash, &id ); + + event_debug( "b_event_remove( %d )\n", id ); + if( b_ev ) + { + g_hash_table_remove( id_hash, &b_ev->id ); + if( b_ev->evinfo.ev_fd >= 0 ) + { + if( b_ev->evinfo.ev_events & EV_READ ) + g_hash_table_remove( read_hash, &b_ev->evinfo.ev_fd ); + if( b_ev->evinfo.ev_events & EV_WRITE ) + g_hash_table_remove( write_hash, &b_ev->evinfo.ev_fd ); + } + + event_del( &b_ev->evinfo ); + g_free( b_ev ); + } + else + { + event_debug( "Already removed?\n" ); + } +} + +void closesocket( int fd ) +{ + struct b_event_data *b_ev; + + /* Since epoll() (the main reason we use libevent) automatically removes sockets from + the epoll() list when a socket gets closed and some modules have a habit of + closing sockets before removing event handlers, our and libevent's administration + get a little bit messed up. So this little function will remove the handlers + properly before closing a socket. */ + + if( ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) + { + event_debug( "Warning: fd %d still had a read event handler when shutting down.\n", fd ); + b_event_remove( b_ev->id ); + } + if( ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) + { + event_debug( "Warning: fd %d still had a write event handler when shutting down.\n", fd ); + b_event_remove( b_ev->id ); + } + + close( fd ); +} diff --git a/lib/http_client.c b/lib/http_client.c new file mode 100644 index 00000000..b00fcf98 --- /dev/null +++ b/lib/http_client.c @@ -0,0 +1,453 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* HTTP(S) module */ + +/* + 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 +#include + +#include "http_client.h" +#include "url.h" +#include "sock.h" + + +static gboolean http_connected( gpointer data, int source, b_input_condition cond ); +static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ); +static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ); + + +void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) +{ + struct http_request *req; + int error = 0; + + req = g_new0( struct http_request, 1 ); + + if( ssl ) + { + req->ssl = ssl_connect( host, port, http_ssl_connected, req ); + if( req->ssl == NULL ) + error = 1; + } + else + { + req->fd = proxy_connect( host, port, http_connected, req ); + if( req->fd < 0 ) + error = 1; + } + + if( error ) + { + g_free( req ); + return( NULL ); + } + + req->func = func; + req->data = data; + req->request = g_strdup( request ); + req->request_length = strlen( request ); + + return( req ); +} + +void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) +{ + url_t *url = g_new0( url_t, 1 ); + char *request; + void *ret; + + if( !url_set( url, url_string ) ) + { + g_free( url ); + return NULL; + } + + if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS ) + { + g_free( url ); + return NULL; + } + + request = g_strdup_printf( "GET %s HTTP/1.0\r\n" + "Host: %s\r\n" + "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n" + "\r\n", url->file, url->host ); + + ret = http_dorequest( url->host, url->port, + url->proto == PROTO_HTTPS, request, func, data ); + + g_free( url ); + g_free( request ); + return ret; +} + +/* This one is actually pretty simple... Might get more calls if we can't write + the whole request at once. */ +static gboolean http_connected( gpointer data, int source, b_input_condition cond ) +{ + struct http_request *req = data; + int st; + + if( source < 0 ) + goto error; + + if( req->inpa > 0 ) + b_event_remove( req->inpa ); + + sock_make_nonblocking( req->fd ); + + if( req->ssl ) + { + st = ssl_write( req->ssl, req->request + req->bytes_written, + req->request_length - req->bytes_written ); + if( st < 0 ) + { + if( ssl_errno != SSL_AGAIN ) + { + ssl_disconnect( req->ssl ); + goto error; + } + } + } + else + { + st = write( source, req->request + req->bytes_written, + req->request_length - req->bytes_written ); + if( st < 0 ) + { + if( !sockerr_again() ) + { + closesocket( req->fd ); + goto error; + } + } + } + + if( st > 0 ) + req->bytes_written += st; + + if( req->bytes_written < req->request_length ) + req->inpa = b_input_add( source, + req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE, + http_connected, req ); + else + req->inpa = b_input_add( source, GAIM_INPUT_READ, http_incoming_data, req ); + + return FALSE; + +error: + req->status_string = g_strdup( "Error while writing HTTP request" ); + + req->func( req ); + + g_free( req->request ); + g_free( req ); + + return FALSE; +} + +static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ) +{ + struct http_request *req = data; + + if( source == NULL ) + return http_connected( data, -1, cond ); + + req->fd = ssl_getfd( source ); + + return http_connected( data, req->fd, cond ); +} + +static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) +{ + struct http_request *req = data; + int evil_server = 0; + char buffer[2048]; + char *end1, *end2; + int st; + + if( req->inpa > 0 ) + b_event_remove( req->inpa ); + + if( req->ssl ) + { + st = ssl_read( req->ssl, buffer, sizeof( buffer ) ); + if( st < 0 ) + { + if( ssl_errno != SSL_AGAIN ) + { + /* goto cleanup; */ + + /* YAY! We have to deal with crappy Microsoft + servers that LOVE to send invalid TLS + packets that abort connections! \o/ */ + + goto got_reply; + } + } + else if( st == 0 ) + { + goto got_reply; + } + } + else + { + st = read( req->fd, buffer, sizeof( buffer ) ); + if( st < 0 ) + { + if( !sockerr_again() ) + { + req->status_string = g_strdup( strerror( errno ) ); + goto cleanup; + } + } + else if( st == 0 ) + { + goto got_reply; + } + } + + if( st > 0 ) + { + req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); + memcpy( req->reply_headers + req->bytes_read, buffer, st ); + req->bytes_read += st; + } + + /* There will be more! */ + req->inpa = b_input_add( req->fd, + req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ, + http_incoming_data, req ); + + return FALSE; + +got_reply: + /* Maybe if the webserver is overloaded, or when there's bad SSL + support... */ + if( req->bytes_read == 0 ) + { + req->status_string = g_strdup( "Empty HTTP reply" ); + goto cleanup; + } + + /* Zero termination is very convenient. */ + req->reply_headers[req->bytes_read] = 0; + + /* Find the separation between headers and body, and keep stupid + webservers in mind. */ + end1 = strstr( req->reply_headers, "\r\n\r\n" ); + end2 = strstr( req->reply_headers, "\n\n" ); + + if( end2 && end2 < end1 ) + { + end1 = end2 + 1; + evil_server = 1; + } + else if( end1 ) + { + end1 += 2; + } + else + { + req->status_string = g_strdup( "Malformed HTTP reply" ); + goto cleanup; + } + + *end1 = 0; + + if( evil_server ) + req->reply_body = end1 + 1; + else + req->reply_body = end1 + 2; + + req->body_size = req->reply_headers + req->bytes_read - req->reply_body; + + if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) + { + if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) + { + req->status_string = g_strdup( "Can't parse status code" ); + req->status_code = -1; + } + else + { + char *eol; + + if( evil_server ) + eol = strchr( end1, '\n' ); + else + eol = strchr( end1, '\r' ); + + req->status_string = g_strndup( end1 + 1, eol - end1 - 1 ); + + /* Just to be sure... */ + if( ( eol = strchr( req->status_string, '\r' ) ) ) + *eol = 0; + if( ( eol = strchr( req->status_string, '\n' ) ) ) + *eol = 0; + } + } + else + { + req->status_string = g_strdup( "Can't locate status code" ); + req->status_code = -1; + } + + if( req->status_code == 301 || req->status_code == 302 ) + { + char *loc, *new_request, *new_host; + int error = 0, new_port, new_proto; + + /* We might fill it again, so let's not leak any memory. */ + g_free( req->status_string ); + req->status_string = NULL; + + loc = strstr( req->reply_headers, "\nLocation: " ); + if( loc == NULL ) /* We can't handle this redirect... */ + { + req->status_string = g_strdup( "Can't locate Location: header" ); + goto cleanup; + } + + loc += 11; + while( *loc == ' ' ) + loc ++; + + /* TODO/FIXME: Possibly have to handle relative redirections, + and rewrite Host: headers. Not necessary for now, it's + enough for passport authentication like this. */ + + if( *loc == '/' ) + { + /* Just a different pathname... */ + + /* Since we don't cache the servername, and since we + don't need this yet anyway, I won't implement it. */ + + req->status_string = g_strdup( "Can't handle recursive redirects" ); + + goto cleanup; + } + else + { + /* A whole URL */ + url_t *url; + char *s; + + s = strstr( loc, "\r\n" ); + if( s == NULL ) + goto cleanup; + + url = g_new0( url_t, 1 ); + *s = 0; + + if( !url_set( url, loc ) ) + { + req->status_string = g_strdup( "Malformed redirect URL" ); + g_free( url ); + goto cleanup; + } + + /* Okay, this isn't fun! We have to rebuild the request... :-( */ + new_request = g_malloc( req->request_length + strlen( url->file ) ); + + /* So, now I just allocated enough memory, so I'm + going to use strcat(), whether you like it or not. :-) */ + + sprintf( new_request, "GET %s HTTP/1.0", url->file ); + + s = strstr( req->request, "\r\n" ); + if( s == NULL ) + { + req->status_string = g_strdup( "Error while rebuilding request string" ); + g_free( new_request ); + g_free( url ); + goto cleanup; + } + + strcat( new_request, s ); + new_host = g_strdup( url->host ); + new_port = url->port; + new_proto = url->proto; + + g_free( url ); + } + + if( req->ssl ) + ssl_disconnect( req->ssl ); + else + closesocket( req->fd ); + + req->fd = -1; + req->ssl = NULL; + + if( new_proto == PROTO_HTTPS ) + { + req->ssl = ssl_connect( new_host, new_port, http_ssl_connected, req ); + if( req->ssl == NULL ) + error = 1; + } + else + { + req->fd = proxy_connect( new_host, new_port, http_connected, req ); + if( req->fd < 0 ) + error = 1; + } + g_free( new_host ); + + if( error ) + { + req->status_string = g_strdup( "Connection problem during redirect" ); + g_free( new_request ); + goto cleanup; + } + + g_free( req->request ); + g_free( req->reply_headers ); + req->request = new_request; + req->request_length = strlen( new_request ); + req->bytes_read = req->bytes_written = req->inpa = 0; + req->reply_headers = req->reply_body = NULL; + + return FALSE; + } + + /* Assume that a closed connection means we're finished, this indeed + breaks with keep-alive connections and faulty connections. */ + req->finished = 1; + +cleanup: + if( req->ssl ) + ssl_disconnect( req->ssl ); + else + closesocket( req->fd ); + + req->func( req ); + + g_free( req->request ); + g_free( req->reply_headers ); + g_free( req->status_string ); + g_free( req ); + + return FALSE; +} diff --git a/lib/http_client.h b/lib/http_client.h new file mode 100644 index 00000000..50ee80cf --- /dev/null +++ b/lib/http_client.h @@ -0,0 +1,57 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* HTTP(S) module */ + +/* + 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 + +#include "ssl_client.h" + +struct http_request; + +typedef void (*http_input_function)( struct http_request * ); + +struct http_request +{ + char *request; + int request_length; + int status_code; + char *status_string; + char *reply_headers; + char *reply_body; + int body_size; + int finished; + + void *ssl; + int fd; + + int inpa; + int bytes_written; + int bytes_read; + + http_input_function func; + gpointer data; +}; + +void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); +void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); diff --git a/lib/ini.c b/lib/ini.c new file mode 100644 index 00000000..c63a132e --- /dev/null +++ b/lib/ini.c @@ -0,0 +1,90 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* INI file reading code */ + +/* + 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 +*/ +#define BITLBEE_CORE +#include "bitlbee.h" + +ini_t *ini_open( char *file ) +{ + ini_t *ini = g_new0( ini_t, 1 ); + + if( ( ini->fp = fopen( file, "r" ) ) == NULL ) + { + g_free( ini ); + return( NULL ); + } + + return( ini ); +} + +int ini_read( ini_t *file ) +{ + char key[MAX_STRING], s[MAX_STRING], *t; + int i; + + while( !feof( file->fp ) ) + { + *s = 0; + fscanf( file->fp, "%127[^\n#]s", s ); + fscanf( file->fp, "%*[^\n]s" ); + fgetc( file->fp ); /* Skip newline */ + file->line ++; + if( strchr( s, '=' ) ) + { + sscanf( s, "%[^ =]s", key ); + if( ( t = strchr( key, '.' ) ) ) + { + *t = 0; + strcpy( file->section, key ); + t ++; + } + else + { + strcpy( file->section, file->c_section ); + t = key; + } + sscanf( t, "%s", file->key ); + t = strchr( s, '=' ) + 1; + for( i = 0; t[i] == ' '; i ++ ); + strcpy( file->value, &t[i] ); + for( i = strlen( file->value ) - 1; file->value[i] == 32; i -- ) + file->value[i] = 0; + + return( 1 ); + } + else if( ( t = strchr( s, '[' ) ) ) + { + strcpy( file->c_section, t + 1 ); + t = strchr( file->c_section, ']' ); + *t = 0; + } + } + return( 0 ); +} + +void ini_close( ini_t *file ) +{ + fclose( file->fp ); + g_free( file ); +} diff --git a/lib/ini.h b/lib/ini.h new file mode 100644 index 00000000..5eab472b --- /dev/null +++ b/lib/ini.h @@ -0,0 +1,43 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* INI file reading code */ + +/* + 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 +*/ + +#ifndef _INI_H +#define _INI_H + +typedef struct +{ + FILE *fp; + int line; + char c_section[MAX_STRING]; + char section[MAX_STRING]; + char key[MAX_STRING]; + char value[MAX_STRING]; +} ini_t; + +ini_t *ini_open( char *file ); +int ini_read( ini_t *file ); +void ini_close( ini_t *file ); + +#endif diff --git a/lib/md5.c b/lib/md5.c new file mode 100644 index 00000000..e6273585 --- /dev/null +++ b/lib/md5.c @@ -0,0 +1,392 @@ +/* + Copyright (C) 1999 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include + +#ifdef TEST +/* + * Compile with -DTEST to create a self-contained executable test program. + * The test program should print out the same values as given in section + * A.5 of RFC 1321, reproduced below. + */ +#include +main() +{ + static const char *const test[7] = { + "", /*d41d8cd98f00b204e9800998ecf8427e*/ + "945399884.61923487334tuvga", /*0cc175b9c0f1b6a831c399e269772661*/ + "abc", /*900150983cd24fb0d6963f7d28e17f72*/ + "message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/ + "abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + /*d174ab98d277d9f5a5611c2c9f419d9f*/ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/ + }; + int i; + + for (i = 0; i < 7; ++i) { + md5_state_t state; + md5_byte_t digest[16]; + int di; + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i])); + md5_finish(&state, digest); + printf("MD5 (\"%s\") = ", test[i]); + for (di = 0; di < 16; ++di) + printf("%02x", digest[di]); + printf("\n"); + } + return 0; +} +#endif /* TEST */ + + +/* + * For reference, here is the program that computed the T values. + */ +#if 0 +#include +main() +{ + int i; + for (i = 1; i <= 64; ++i) { + unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); + printf("#define T%d 0x%08lx\n", i, v); + } + return 0; +} +#endif +/* + * End of T computation program. + */ +#define T1 0xd76aa478 +#define T2 0xe8c7b756 +#define T3 0x242070db +#define T4 0xc1bdceee +#define T5 0xf57c0faf +#define T6 0x4787c62a +#define T7 0xa8304613 +#define T8 0xfd469501 +#define T9 0x698098d8 +#define T10 0x8b44f7af +#define T11 0xffff5bb1 +#define T12 0x895cd7be +#define T13 0x6b901122 +#define T14 0xfd987193 +#define T15 0xa679438e +#define T16 0x49b40821 +#define T17 0xf61e2562 +#define T18 0xc040b340 +#define T19 0x265e5a51 +#define T20 0xe9b6c7aa +#define T21 0xd62f105d +#define T22 0x02441453 +#define T23 0xd8a1e681 +#define T24 0xe7d3fbc8 +#define T25 0x21e1cde6 +#define T26 0xc33707d6 +#define T27 0xf4d50d87 +#define T28 0x455a14ed +#define T29 0xa9e3e905 +#define T30 0xfcefa3f8 +#define T31 0x676f02d9 +#define T32 0x8d2a4c8a +#define T33 0xfffa3942 +#define T34 0x8771f681 +#define T35 0x6d9d6122 +#define T36 0xfde5380c +#define T37 0xa4beea44 +#define T38 0x4bdecfa9 +#define T39 0xf6bb4b60 +#define T40 0xbebfbc70 +#define T41 0x289b7ec6 +#define T42 0xeaa127fa +#define T43 0xd4ef3085 +#define T44 0x04881d05 +#define T45 0xd9d4d039 +#define T46 0xe6db99e5 +#define T47 0x1fa27cf8 +#define T48 0xc4ac5665 +#define T49 0xf4292244 +#define T50 0x432aff97 +#define T51 0xab9423a7 +#define T52 0xfc93a039 +#define T53 0x655b59c3 +#define T54 0x8f0ccc92 +#define T55 0xffeff47d +#define T56 0x85845dd1 +#define T57 0x6fa87e4f +#define T58 0xfe2ce6e0 +#define T59 0xa3014314 +#define T60 0x4e0811a1 +#define T61 0xf7537e82 +#define T62 0xbd3af235 +#define T63 0x2ad7d2bb +#define T64 0xeb86d391 + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; + +#ifndef ARCH_IS_BIG_ENDIAN +# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ +#endif +#if ARCH_IS_BIG_ENDIAN + + /* + * On big-endian machines, we must arrange the bytes in the right + * order. (This also works on machines of unknown byte order.) + */ + md5_word_t X[16]; + const md5_byte_t *xp = data; + int i; + + for (i = 0; i < 16; ++i, xp += 4) + X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + +#else /* !ARCH_IS_BIG_ENDIAN */ + + /* + * On little-endian machines, we can process properly aligned data + * without copying it. + */ + md5_word_t xbuf[16]; + const md5_word_t *X; + + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } +#endif + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = 0xefcdab89; + pms->abcd[2] = 0x98badcfe; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/lib/md5.h b/lib/md5.h new file mode 100644 index 00000000..f24f2ff1 --- /dev/null +++ b/lib/md5.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 1999 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2004-03-09 Jelmer Vernooij add G_MODULE_EXPORT for Bitlbee + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +#include +#include + +/* + * This code has some adaptations for the Ghostscript environment, but it + * will compile and run correctly in any environment with 8-bit chars and + * 32-bit ints. Specifically, it assumes that if the following are + * defined, they have the same meaning as in Ghostscript: P1, P2, P3, + * ARCH_IS_BIG_ENDIAN. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +G_MODULE_EXPORT void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +G_MODULE_EXPORT void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +G_MODULE_EXPORT void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/lib/misc.c b/lib/misc.c new file mode 100644 index 00000000..d8d6a4c7 --- /dev/null +++ b/lib/misc.c @@ -0,0 +1,481 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* + * Various utility functions. Some are copied from Gaim to support the + * IM-modules, most are from BitlBee. + * + * Copyright (C) 1998-1999, Mark Spencer + * (and possibly other members of the Gaim team) + * Copyright 2002-2005 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 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 +*/ + +#define BITLBEE_CORE +#include "nogaim.h" +#include +#include +#include +#include +#include +#include + +void strip_linefeed(gchar *text) +{ + int i, j; + gchar *text2 = g_malloc(strlen(text) + 1); + + for (i = 0, j = 0; text[i]; i++) + if (text[i] != '\r') + text2[j++] = text[i]; + text2[j] = '\0'; + + strcpy(text, text2); + g_free(text2); +} + +char *add_cr(char *text) +{ + char *ret = NULL; + int count = 0, j; + unsigned int i; + + if (text[0] == '\n') + count++; + for (i = 1; i < strlen(text); i++) + if (text[i] == '\n' && text[i - 1] != '\r') + count++; + + if (count == 0) + return g_strdup(text); + + ret = g_malloc0(strlen(text) + count + 1); + + i = 0; j = 0; + if (text[i] == '\n') + ret[j++] = '\r'; + ret[j++] = text[i++]; + for (; i < strlen(text); i++) { + if (text[i] == '\n' && text[i - 1] != '\r') + ret[j++] = '\r'; + ret[j++] = text[i]; + } + + return ret; +} + +char *tobase64(const char *text) +{ + char *out; + int len; + + len = strlen(text); + out = g_malloc((len + 2) /* the == padding */ + / 3 /* every 3-byte block */ + * 4 /* becomes a 4-byte one */ + + 1); /* and of course, ASCIIZ! */ + + base64_encode_real(text, len, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); + + return out; +} + +void base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, char *b64digits) +{ + for (; inlen >= 3; inlen -= 3) + { + *out++ = b64digits[in[0] >> 2]; + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; + *out++ = b64digits[in[2] & 0x3f]; + in += 3; + } + if (inlen > 0) + { + *out++ = b64digits[in[0] >> 2]; + if (inlen > 1) + { + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[((in[1]<<2) & 0x3c)]; + } + else + { + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[64]; + } + *out++ = b64digits[64]; + } + *out = '\0'; +} + +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 != ' ') { + buf[x] = *t; + x++; + } + t++; + } + buf[x] = '\0'; + g_free(u); + return buf; +} + +time_t get_time(int year, int month, int day, int hour, int min, int sec) +{ + struct tm tm; + + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; + return mktime(&tm); +} + +typedef struct htmlentity +{ + char code[8]; + char is[4]; +} htmlentity_t; + +/* FIXME: This is ISO8859-1(5) centric, so might cause problems with other charsets. */ + +static const htmlentity_t ent[] = +{ + { "lt", "<" }, + { "gt", ">" }, + { "amp", "&" }, + { "quot", "\"" }, + { "aacute", "á" }, + { "eacute", "é" }, + { "iacute", "é" }, + { "oacute", "ó" }, + { "uacute", "ú" }, + { "agrave", "à" }, + { "egrave", "è" }, + { "igrave", "ì" }, + { "ograve", "ò" }, + { "ugrave", "ù" }, + { "acirc", "â" }, + { "ecirc", "ê" }, + { "icirc", "î" }, + { "ocirc", "ô" }, + { "ucirc", "û" }, + { "auml", "ä" }, + { "euml", "ë" }, + { "iuml", "ï" }, + { "ouml", "ö" }, + { "uuml", "ü" }, + { "nbsp", " " }, + { "", "" } +}; + +void strip_html( char *in ) +{ + char *start = in; + char *out = g_malloc( strlen( in ) + 1 ); + char *s = out, *cs; + int i, matched; + + memset( out, 0, strlen( in ) + 1 ); + + while( *in ) + { + if( *in == '<' && ( isalpha( *(in+1) ) || *(in+1) == '/' ) ) + { + /* If in points at a < and in+1 points at a letter or a slash, this is probably + a HTML-tag. Try to find a closing > and continue there. If the > can't be + found, assume that it wasn't a HTML-tag after all. */ + + cs = in; + + while( *in && *in != '>' ) + in ++; + + if( *in ) + { + if( g_strncasecmp( cs+1, "br", 2) == 0 ) + *(s++) = '\n'; + in ++; + } + else + { + in = cs; + *(s++) = *(in++); + } + } + else if( *in == '&' ) + { + cs = ++in; + while( *in && isalpha( *in ) ) + in ++; + + if( *in == ';' ) in ++; + matched = 0; + + for( i = 0; *ent[i].code; i ++ ) + if( g_strncasecmp( ent[i].code, cs, strlen( ent[i].code ) ) == 0 ) + { + int j; + + for( j = 0; ent[i].is[j]; j ++ ) + *(s++) = ent[i].is[j]; + + matched = 1; + break; + } + + /* None of the entities were matched, so return the string */ + if( !matched ) + { + in = cs - 1; + *(s++) = *(in++); + } + } + else + { + *(s++) = *(in++); + } + } + + strcpy( start, out ); + g_free( out ); +} + +char *escape_html( const char *html ) +{ + const char *c = html; + GString *ret; + char *str; + + if( html == NULL ) + return( NULL ); + + ret = g_string_new( "" ); + + while( *c ) + { + switch( *c ) + { + case '&': + ret = g_string_append( ret, "&" ); + break; + case '<': + ret = g_string_append( ret, "<" ); + break; + case '>': + ret = g_string_append( ret, ">" ); + break; + case '"': + ret = g_string_append( ret, """ ); + break; + default: + ret = g_string_append_c( ret, *c ); + } + c ++; + } + + str = ret->str; + g_string_free( ret, FALSE ); + return( str ); +} + +void info_string_append(GString *str, char *newline, char *name, char *value) +{ + if( value && value[0] ) + g_string_sprintfa( str, "%s%s: %s", newline, name, value ); +} + +/* Decode%20a%20file%20name */ +void http_decode( char *s ) +{ + char *t; + int i, j, k; + + t = g_new( char, strlen( s ) + 1 ); + + for( i = j = 0; s[i]; i ++, j ++ ) + { + if( s[i] == '%' ) + { + if( sscanf( s + i + 1, "%2x", &k ) ) + { + t[j] = k; + i += 2; + } + else + { + *t = 0; + break; + } + } + else + { + t[j] = s[i]; + } + } + t[j] = 0; + + strcpy( s, t ); + g_free( t ); +} + +/* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */ +/* This fuction is safe, but make sure you call it safely as well! */ +void http_encode( char *s ) +{ + char *t; + int i, j; + + t = g_strdup( s ); + + for( i = j = 0; t[i]; i ++, j ++ ) + { + /* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */ + if( !isalnum( t[i] ) ) + { + sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] ); + j += 2; + } + else + { + s[j] = t[i]; + } + } + s[j] = 0; + + g_free( t ); +} + +/* Strip newlines from a string. Modifies the string passed to it. */ +char *strip_newlines( char *source ) +{ + int i; + + for( i = 0; source[i] != '\0'; i ++ ) + if( source[i] == '\n' || source[i] == '\r' ) + source[i] = ' '; + + return source; +} + +#ifdef IPV6 +/* Wrap an IPv4 address into IPv6 space. Not thread-safe... */ +char *ipv6_wrap( char *src ) +{ + static char dst[64]; + int i; + + for( i = 0; src[i]; i ++ ) + if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) + break; + + /* Hmm, it's not even an IP... */ + if( src[i] ) + return src; + + g_snprintf( dst, sizeof( dst ), "::ffff:%s", src ); + + return dst; +} + +/* Unwrap an IPv4 address into IPv6 space. Thread-safe, because it's very simple. :-) */ +char *ipv6_unwrap( char *src ) +{ + int i; + + if( g_strncasecmp( src, "::ffff:", 7 ) != 0 ) + return src; + + for( i = 7; src[i]; i ++ ) + if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) + break; + + /* Hmm, it's not even an IP... */ + if( src[i] ) + return src; + + return ( src + 7 ); +} +#endif + +/* Convert from one charset to another. + + from_cs, to_cs: Source and destination charsets + src, dst: Source and destination strings + size: Size if src. 0 == use strlen(). strlen() is not reliable for UNICODE/UTF16 strings though. + maxbuf: Maximum number of bytes to write to dst + + Returns the number of bytes written to maxbuf or -1 on an error. +*/ +signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ) +{ + GIConv cd; + size_t res; + size_t inbytesleft, outbytesleft; + char *inbuf = src; + char *outbuf = dst; + + cd = g_iconv_open( to_cs, from_cs ); + if( cd == (GIConv) -1 ) + return( -1 ); + + inbytesleft = size ? size : strlen( src ); + outbytesleft = maxbuf - 1; + res = g_iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + *outbuf = '\0'; + g_iconv_close( cd ); + + if( res == (size_t) -1 ) + return( -1 ); + else + return( outbuf - dst ); +} + +char *set_eval_charset( irc_t *irc, set_t *set, char *value ) +{ + GIConv cd; + + if ( g_strncasecmp( value, "none", 4 ) == 0 ) + return( value ); + + cd = g_iconv_open( "UTF-8", value ); + if( cd == (GIConv) -1 ) + return( NULL ); + + g_iconv_close( cd ); + return( value ); +} diff --git a/lib/misc.h b/lib/misc.h new file mode 100644 index 00000000..c7eec19b --- /dev/null +++ b/lib/misc.h @@ -0,0 +1,51 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Misc. functions */ + +/* + 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 +*/ + +#ifndef _UTIL_H +#define _UTIL_H + +G_MODULE_EXPORT void strip_linefeed( gchar *text ); +G_MODULE_EXPORT char *add_cr( char *text ); +G_MODULE_EXPORT char *strip_newlines(char *source); +G_MODULE_EXPORT char *tobase64( const char *text ); +G_MODULE_EXPORT void base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, char *b64digits ); +G_MODULE_EXPORT char *normalize( const char *s ); +G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); + +G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); +double gettime( void ); + +G_MODULE_EXPORT void strip_html( char *msg ); +G_MODULE_EXPORT char *escape_html( const char *html ); +G_MODULE_EXPORT void http_decode( char *s ); +G_MODULE_EXPORT void http_encode( char *s ); + +G_MODULE_EXPORT char *ipv6_wrap( char *src ); +G_MODULE_EXPORT char *ipv6_unwrap( char *src ); + +G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); +char *set_eval_charset( irc_t *irc, set_t *set, char *value ); + +#endif diff --git a/lib/proxy.c b/lib/proxy.c new file mode 100644 index 00000000..b8aa304d --- /dev/null +++ b/lib/proxy.c @@ -0,0 +1,556 @@ +/* + * gaim + * + * Copyright (C) 1998-1999, Mark Spencer + * Copyright (C) 2002-2004, Wilmer van der Gaast, 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define BITLBEE_CORE +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#else +#include "sock.h" +#define ETIMEDOUT WSAETIMEDOUT +#define EINPROGRESS WSAEINPROGRESS +#endif +#include +#include +#include "nogaim.h" +#include "proxy.h" + +char proxyhost[128] = ""; +int proxyport = 0; +int proxytype = PROXY_NONE; +char proxyuser[128] = ""; +char proxypass[128] = ""; + +struct PHB { + b_event_handler func, proxy_func; + gpointer data, proxy_data; + char *host; + int port; + int fd; + gint inpa; +}; + + + +static struct sockaddr_in *gaim_gethostbyname(const char *host, int port) +{ + static struct sockaddr_in sin; + + if (!inet_aton(host, &sin.sin_addr)) { + struct hostent *hp; + if (!(hp = gethostbyname(host))) { + return NULL; + } + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + } else + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + + return &sin; +} + +static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond) +{ + struct PHB *phb = data; + unsigned int len; + int error = ETIMEDOUT; + len = sizeof(error); + +#ifndef _WIN32 + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + closesocket(source); + b_event_remove(phb->inpa); + if( phb->proxy_func ) + phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ); + else { + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb); + } + return FALSE; + } +#endif + sock_make_blocking(source); + b_event_remove(phb->inpa); + if( phb->proxy_func ) + phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ); + else { + phb->func(phb->data, source, GAIM_INPUT_READ); + g_free(phb); + } + + return FALSE; +} + +static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb) +{ + struct sockaddr_in *sin; + int fd = -1; + + if (!(sin = gaim_gethostbyname(host, port))) { + g_free(phb); + return -1; + } + + if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { + g_free(phb); + return -1; + } + + sock_make_nonblocking(fd); + + event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); + + if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { + if (sockerr_again()) { + phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); + phb->fd = fd; + } else { + closesocket(fd); + g_free(phb); + return -1; + } + } + + return fd; +} + + +/* Connecting to HTTP proxies */ + +#define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" +#define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" + +static gboolean http_canread(gpointer data, gint source, b_input_condition cond) +{ + int nlc = 0; + int pos = 0; + struct PHB *phb = data; + char inputline[8192]; + + b_event_remove(phb->inpa); + + while ((pos < sizeof(inputline)-1) && (nlc != 2) && (read(source, &inputline[pos++], 1) == 1)) { + if (inputline[pos - 1] == '\n') + nlc++; + else if (inputline[pos - 1] != '\r') + nlc = 0; + } + inputline[pos] = '\0'; + + if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) || + (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { + phb->func(phb->data, source, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + + return FALSE; +} + +static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond) +{ + char cmd[384]; + struct PHB *phb = data; + unsigned int len; + int error = ETIMEDOUT; + if (phb->inpa > 0) + b_event_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + sock_make_blocking(source); + + g_snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, + phb->host, phb->port); + if (send(source, cmd, strlen(cmd), 0) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + if (proxyuser && *proxyuser) { + char *t1, *t2; + t1 = g_strdup_printf("%s:%s", proxyuser, proxypass); + t2 = tobase64(t1); + g_free(t1); + g_snprintf(cmd, sizeof(cmd), "Proxy-Authorization: Basic %s\r\n", t2); + g_free(t2); + if (send(source, cmd, strlen(cmd), 0) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + } + + g_snprintf(cmd, sizeof(cmd), "\r\n"); + if (send(source, cmd, strlen(cmd), 0) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb); + + return FALSE; +} + +static int proxy_connect_http(const char *host, unsigned short port, struct PHB *phb) +{ + phb->host = g_strdup(host); + phb->port = port; + phb->proxy_func = http_canwrite; + phb->proxy_data = phb; + + return( proxy_connect_none( proxyhost, proxyport, phb ) ); +} + + +/* Connecting to SOCKS4 proxies */ + +static gboolean s4_canread(gpointer data, gint source, b_input_condition cond) +{ + unsigned char packet[12]; + struct PHB *phb = data; + + b_event_remove(phb->inpa); + + memset(packet, 0, sizeof(packet)); + if (read(source, packet, 9) >= 4 && packet[1] == 90) { + phb->func(phb->data, source, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + + return FALSE; +} + +static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond) +{ + unsigned char packet[12]; + struct hostent *hp; + struct PHB *phb = data; + unsigned int len; + int error = ETIMEDOUT; + if (phb->inpa > 0) + b_event_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + sock_make_blocking(source); + + /* XXX does socks4 not support host name lookups by the proxy? */ + if (!(hp = gethostbyname(phb->host))) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + packet[0] = 4; + packet[1] = 1; + packet[2] = phb->port >> 8; + packet[3] = phb->port & 0xff; + packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; + packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; + packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; + packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; + packet[8] = 0; + if (write(source, packet, 9) != 9) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb); + + return FALSE; +} + +static int proxy_connect_socks4(const char *host, unsigned short port, struct PHB *phb) +{ + phb->host = g_strdup(host); + phb->port = port; + phb->proxy_func = s4_canwrite; + phb->proxy_data = phb; + + return( proxy_connect_none( proxyhost, proxyport, phb ) ); +} + + +/* Connecting to SOCKS5 proxies */ + +static gboolean s5_canread_again(gpointer data, gint source, b_input_condition cond) +{ + unsigned char buf[512]; + struct PHB *phb = data; + + b_event_remove(phb->inpa); + + if (read(source, buf, 10) < 10) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + if ((buf[0] != 0x05) || (buf[1] != 0x00)) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->func(phb->data, source, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + + return FALSE; +} + +static void s5_sendconnect(gpointer data, gint source) +{ + unsigned char buf[512]; + struct PHB *phb = data; + int hlen = strlen(phb->host); + + buf[0] = 0x05; + buf[1] = 0x01; /* CONNECT */ + buf[2] = 0x00; /* reserved */ + buf[3] = 0x03; /* address type -- host name */ + buf[4] = hlen; + memcpy(buf + 5, phb->host, hlen); + buf[5 + strlen(phb->host)] = phb->port >> 8; + buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; + + if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); +} + +static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond) +{ + unsigned char buf[512]; + struct PHB *phb = data; + + b_event_remove(phb->inpa); + + if (read(source, buf, 2) < 2) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + if ((buf[0] != 0x01) || (buf[1] != 0x00)) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + s5_sendconnect(phb, source); + + return FALSE; +} + +static gboolean s5_canread(gpointer data, gint source, b_input_condition cond) +{ + unsigned char buf[512]; + struct PHB *phb = data; + + b_event_remove(phb->inpa); + + if (read(source, buf, 2) < 2) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + if ((buf[0] != 0x05) || (buf[1] == 0xff)) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + if (buf[1] == 0x02) { + unsigned int i = strlen(proxyuser), j = strlen(proxypass); + buf[0] = 0x01; /* version 1 */ + buf[1] = i; + memcpy(buf + 2, proxyuser, i); + buf[2 + i] = j; + memcpy(buf + 2 + i + 1, proxypass, j); + if (write(source, buf, 3 + i + j) < 3 + i + j) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); + } else { + s5_sendconnect(phb, source); + } + + return FALSE; +} + +static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond) +{ + unsigned char buf[512]; + int i; + struct PHB *phb = data; + unsigned int len; + int error = ETIMEDOUT; + if (phb->inpa > 0) + b_event_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + sock_make_blocking(source); + + i = 0; + buf[0] = 0x05; /* SOCKS version 5 */ + if (proxyuser[0]) { + buf[1] = 0x02; /* two methods */ + buf[2] = 0x00; /* no authentication */ + buf[3] = 0x02; /* username/password authentication */ + i = 4; + } else { + buf[1] = 0x01; + buf[2] = 0x00; + i = 3; + } + + if (write(source, buf, i) < i) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb); + + return FALSE; +} + +static int proxy_connect_socks5(const char *host, unsigned short port, struct PHB *phb) +{ + phb->host = g_strdup(host); + phb->port = port; + phb->proxy_func = s5_canwrite; + phb->proxy_data = phb; + + return( proxy_connect_none( proxyhost, proxyport, phb ) ); +} + + +/* Export functions */ + +int proxy_connect(const char *host, int port, b_event_handler func, gpointer data) +{ + struct PHB *phb; + + if (!host || !port || (port == -1) || !func || strlen(host) > 128) { + return -1; + } + + phb = g_new0(struct PHB, 1); + phb->func = func; + phb->data = data; + +#ifndef _WIN32 + sethostent(1); +#endif + + if ((proxytype == PROXY_NONE) || !proxyhost || !proxyhost[0] || !proxyport || (proxyport == -1)) + return proxy_connect_none(host, port, phb); + else if (proxytype == PROXY_HTTP) + return proxy_connect_http(host, port, phb); + else if (proxytype == PROXY_SOCKS4) + return proxy_connect_socks4(host, port, phb); + else if (proxytype == PROXY_SOCKS5) + return proxy_connect_socks5(host, port, phb); + + if (phb->host) g_free(phb); + g_free(phb); + return -1; +} diff --git a/lib/proxy.h b/lib/proxy.h new file mode 100644 index 00000000..680790a5 --- /dev/null +++ b/lib/proxy.h @@ -0,0 +1,53 @@ +/* + * nogaim + * + * Copyright (C) 1998-1999, Mark Spencer + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* this is the export part of the proxy.c file. it does a little + prototype-ing stuff and redefine some net function to mask them + with some kind of transparent layer */ + +#ifndef _PROXY_H_ +#define _PROXY_H_ + +#include +#ifndef _WIN32 +#include +#include +#include +#endif +#include +#include + +#include "events.h" + +#define PROXY_NONE 0 +#define PROXY_HTTP 1 +#define PROXY_SOCKS4 2 +#define PROXY_SOCKS5 3 + +extern char proxyhost[128]; +extern int proxyport; +extern int proxytype; +extern char proxyuser[128]; +extern char proxypass[128]; + +G_MODULE_EXPORT int proxy_connect(const char *host, int port, b_event_handler func, gpointer data); + +#endif /* _PROXY_H_ */ diff --git a/lib/rc4.c b/lib/rc4.c new file mode 100644 index 00000000..3559f71e --- /dev/null +++ b/lib/rc4.c @@ -0,0 +1,179 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple (but secure) RC4 implementation for safer password storage. * +* * +* Copyright 2006 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 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +/* + This file implements RC4-encryption, which will mainly be used to save IM + passwords safely in the new XML-format. Possibly other uses will come up + later. It's supposed to be quite reliable (thanks to the use of a 6-byte + IV/seed), certainly compared to the old format. The only realistic way to + crack BitlBee passwords now is to use a sniffer to get your hands on the + user's password. + + If you see that something's wrong in this implementation (I asked a + couple of people to look at it already, but who knows), please tell me. + + The reason I chose for RC4 is because it's pretty simple but effective, + so it will work without adding several KBs or an extra library dependency. +*/ + + +#include +#include +#include +#include "rc4.h" + +/* Add some seed to the password, to make sure we *never* use the same key. + This defines how many byes we use as a seed. */ +#define RC4_IV_LEN 6 + +/* To defend against a "Fluhrer, Mantin and Shamir attack", it is recommended + to shuffle S[] just a bit more before you start to use it. This defines how + many bytes we'll request before we'll really use them for encryption. */ +#define RC4_CYCLES 1024 + +struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles ) +{ + struct rc4_state *st; + int i, j, tmp; + + st = g_malloc( sizeof( struct rc4_state ) ); + st->i = st->j = 0; + for( i = 0; i < 256; i ++ ) + st->S[i] = i; + + if( kl <= 0 ) + kl = strlen( (char*) key ); + + for( i = j = 0; i < 256; i ++ ) + { + j = ( j + st->S[i] + key[i%kl] ) & 0xff; + tmp = st->S[i]; + st->S[i] = st->S[j]; + st->S[j] = tmp; + } + + for( i = 0; i < cycles; i ++ ) + rc4_getbyte( st ); + + return st; +} + +/* + For those who don't know, RC4 is basically an algorithm that generates a + stream of bytes after you give it a key. Just get a byte from it and xor + it with your cleartext. To decrypt, just give it the same key again and + start xorring. + + The function above initializes the RC4 byte generator, the next function + can be used to get bytes from the generator (and shuffle things a bit). +*/ + +unsigned char rc4_getbyte( struct rc4_state *st ) +{ + unsigned char tmp; + + /* Unfortunately the st-> stuff doesn't really improve readability here... */ + st->i ++; + st->j += st->S[st->i]; + tmp = st->S[st->i]; + st->S[st->i] = st->S[st->j]; + st->S[st->j] = tmp; + + return st->S[(st->S[st->i] + st->S[st->j]) & 0xff]; +} + +/* + The following two functions can be used for reliable encryption and + decryption. Known plaintext attacks are prevented by adding some (6, + by default) random bytes to the password before setting up the RC4 + structures. These 6 bytes are also saved in the results, because of + course we'll need them in rc4_decode(). + + Because the length of the resulting string is unknown to the caller, + it should pass a char**. Since the encode/decode functions allocate + memory for the string, make sure the char** points at a NULL-pointer + (or at least to something you already free()d), or you'll leak + memory. And of course, don't forget to free() the result when you + don't need it anymore. + + Both functions return the number of bytes in the result string. +*/ + +int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *password ) +{ + struct rc4_state *st; + unsigned char *key; + int key_len, i; + + key_len = strlen( password ) + RC4_IV_LEN; + if( clear_len <= 0 ) + clear_len = strlen( (char*) clear ); + + /* Prepare buffers and the key + IV */ + *crypt = g_malloc( clear_len + RC4_IV_LEN ); + key = g_malloc( key_len ); + strcpy( (char*) key, password ); + for( i = 0; i < RC4_IV_LEN; i ++ ) + key[key_len-RC4_IV_LEN+i] = crypt[0][i] = rand() & 0xff; + + /* Generate the initial S[] from the IVed key. */ + st = rc4_keymaker( key, key_len, RC4_CYCLES ); + g_free( key ); + + for( i = 0; i < clear_len; i ++ ) + crypt[0][i+RC4_IV_LEN] = clear[i] ^ rc4_getbyte( st ); + + g_free( st ); + + return clear_len + RC4_IV_LEN; +} + +int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char *password ) +{ + struct rc4_state *st; + unsigned char *key; + int key_len, clear_len, i; + + key_len = strlen( password ) + RC4_IV_LEN; + clear_len = crypt_len - RC4_IV_LEN; + + /* Prepare buffers and the key + IV */ + *clear = g_malloc( clear_len + 1 ); + key = g_malloc( key_len ); + strcpy( (char*) key, password ); + for( i = 0; i < RC4_IV_LEN; i ++ ) + key[key_len-RC4_IV_LEN+i] = crypt[i]; + + /* Generate the initial S[] from the IVed key. */ + st = rc4_keymaker( key, key_len, RC4_CYCLES ); + g_free( key ); + + for( i = 0; i < clear_len; i ++ ) + clear[0][i] = crypt[i+RC4_IV_LEN] ^ rc4_getbyte( st ); + clear[0][i] = 0; /* Nice to have for plaintexts. */ + + g_free( st ); + + return clear_len; +} diff --git a/lib/rc4.h b/lib/rc4.h new file mode 100644 index 00000000..8d50b508 --- /dev/null +++ b/lib/rc4.h @@ -0,0 +1,35 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple (but secure) RC4 implementation for safer password storage. * +* * +* Copyright 2006 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 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + + +struct rc4_state +{ + unsigned char S[256]; + unsigned char i, j; +}; + +struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles ); +unsigned char rc4_getbyte( struct rc4_state *st ); +int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *password ); +int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char *password ); diff --git a/lib/sha.c b/lib/sha.c new file mode 100644 index 00000000..895505a1 --- /dev/null +++ b/lib/sha.c @@ -0,0 +1,173 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is SHA 180-1 Reference Implementation (Compact version) + * + * The Initial Developer of the Original Code is Paul Kocher of + * Cryptography Research. Portions created by Paul Kocher are + * Copyright (C) 1995-9 by Cryptography Research, Inc. All + * Rights Reserved. + * + * Contributor(s): + * + */ + +#define BITLBEE_CORE +#include "nogaim.h" + +static void shaHashBlock(SHA_CTX *ctx); + +void shaInit(SHA_CTX *ctx) { + int i; + + ctx->lenW = 0; + ctx->sizeHi = ctx->sizeLo = 0; + + /* Initialize H with the magic constants (see FIPS180 for constants) + */ + ctx->H[0] = 0x67452301L; + ctx->H[1] = 0xefcdab89L; + ctx->H[2] = 0x98badcfeL; + ctx->H[3] = 0x10325476L; + ctx->H[4] = 0xc3d2e1f0L; + + for (i = 0; i < 80; i++) + ctx->W[i] = 0; +} + + +void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len) { + int i; + + /* Read the data into W and process blocks as they get full + */ + for (i = 0; i < len; i++) { + ctx->W[ctx->lenW / 4] <<= 8; + ctx->W[ctx->lenW / 4] |= (guint32)dataIn[i]; + if ((++ctx->lenW) % 64 == 0) { + shaHashBlock(ctx); + ctx->lenW = 0; + } + ctx->sizeLo += 8; + ctx->sizeHi += (ctx->sizeLo < 8); + } +} + + +void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]) { + unsigned char pad0x80 = 0x80; + unsigned char pad0x00 = 0x00; + unsigned char padlen[8]; + int i; + + /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length + */ + padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); + padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); + padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); + padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); + padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); + padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); + padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); + padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); + shaUpdate(ctx, &pad0x80, 1); + while (ctx->lenW != 56) + shaUpdate(ctx, &pad0x00, 1); + shaUpdate(ctx, padlen, 8); + + /* Output hash + */ + for (i = 0; i < 20; i++) { + hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); + ctx->H[i / 4] <<= 8; + } + + /* + * Re-initialize the context (also zeroizes contents) + */ + shaInit(ctx); +} + + +void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]) { + SHA_CTX ctx; + + shaInit(&ctx); + shaUpdate(&ctx, dataIn, len); + shaFinal(&ctx, hashout); +} + + +#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL) + +static void shaHashBlock(SHA_CTX *ctx) { + int t; + guint32 A,B,C,D,E,TEMP; + + for (t = 16; t <= 79; t++) + ctx->W[t] = + SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); + + A = ctx->H[0]; + B = ctx->H[1]; + C = ctx->H[2]; + D = ctx->H[3]; + E = ctx->H[4]; + + for (t = 0; t <= 19; t++) { + TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 20; t <= 39; t++) { + TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 40; t <= 59; t++) { + TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 60; t <= 79; t++) { + TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + + ctx->H[0] += A; + ctx->H[1] += B; + ctx->H[2] += C; + ctx->H[3] += D; + ctx->H[4] += E; +} + +/*---------------------------------------------------------------------------- + * + * This code added by Thomas "temas" Muldowney for Jabber compatability + * + *---------------------------------------------------------------------------*/ +char *shahash(char *str) +{ + static char final[41]; + char *pos; + unsigned char hashval[20]; + int x; + + if(!str || strlen(str) == 0) + return NULL; + + shaBlock((unsigned char *)str, strlen(str), hashval); + + pos = final; + for(x=0;x<20;x++) + { + g_snprintf(pos, 3, "%02x", hashval[x]); + pos += 2; + } + return (char *)final; +} diff --git a/lib/sha.h b/lib/sha.h new file mode 100644 index 00000000..e8152b1b --- /dev/null +++ b/lib/sha.h @@ -0,0 +1,21 @@ +#ifndef __SHA_H__ +#define __SHA_H__ + +#include + +G_MODULE_EXPORT int strprintsha(char *dest, int *hashval); + +typedef struct { + guint32 H[5]; + guint32 W[80]; + int lenW; + guint32 sizeHi,sizeLo; +} SHA_CTX; + +G_MODULE_EXPORT void shaInit(SHA_CTX *ctx); +G_MODULE_EXPORT void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len); +G_MODULE_EXPORT void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]); +G_MODULE_EXPORT void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]); +G_MODULE_EXPORT char *shahash(char *str); + +#endif diff --git a/lib/ssl_bogus.c b/lib/ssl_bogus.c new file mode 100644 index 00000000..00aaa7c4 --- /dev/null +++ b/lib/ssl_bogus.c @@ -0,0 +1,57 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - dummy version */ + +/* + 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" + +int ssl_errno; + +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) +{ + return( NULL ); +} + +int ssl_read( void *conn, char *buf, int len ) +{ + return( -1 ); +} + +int ssl_write( void *conn, const char *buf, int len ) +{ + return( -1 ); +} + +void ssl_disconnect( void *conn_ ) +{ +} + +int ssl_getfd( void *conn ) +{ + return( -1 ); +} + +b_input_condition ssl_getdirection( void *conn ) +{ + return GAIM_INPUT_READ; +} diff --git a/lib/ssl_client.h b/lib/ssl_client.h new file mode 100644 index 00000000..1a9c79e9 --- /dev/null +++ b/lib/ssl_client.h @@ -0,0 +1,42 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module */ + +/* + 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 +#include "proxy.h" + +#define SSL_OK 0 +#define SSL_NOHANDSHAKE 1 +#define SSL_AGAIN 2 + +extern int ssl_errno; + +typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition); + +G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); +G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); +G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); +G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); +G_MODULE_EXPORT int ssl_getfd( void *conn ); +G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c new file mode 100644 index 00000000..3ebe1756 --- /dev/null +++ b/lib/ssl_gnutls.c @@ -0,0 +1,206 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - GnuTLS version */ + +/* + 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 +#include +#include +#include "proxy.h" +#include "ssl_client.h" +#include "sock.h" +#include "stdlib.h" + +int ssl_errno = 0; + +static gboolean initialized = FALSE; + +struct scd +{ + ssl_input_function func; + gpointer data; + int fd; + gboolean established; + int inpa; + + gnutls_session session; + gnutls_certificate_credentials xcred; +}; + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); + + +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 ); + conn->func = func; + conn->data = data; + conn->inpa = -1; + + if( conn->fd < 0 ) + { + g_free( conn ); + return( NULL ); + } + + if( !initialized ) + { + gnutls_global_init(); + initialized = TRUE; + atexit( gnutls_global_deinit ); + } + + gnutls_certificate_allocate_credentials( &conn->xcred ); + gnutls_init( &conn->session, GNUTLS_CLIENT ); + gnutls_set_default_priority( conn->session ); + gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); + + return( conn ); +} + +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + if( source == -1 ) + { + conn->func( conn->data, NULL, cond ); + + gnutls_deinit( conn->session ); + gnutls_certificate_free_credentials( conn->xcred ); + + g_free( conn ); + + return FALSE; + } + + sock_make_nonblocking( conn->fd ); + gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); + + return ssl_handshake( data, source, cond ); +} + +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + int st; + + if( ( st = gnutls_handshake( conn->session ) ) < 0 ) + { + if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) + { + conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), + ssl_handshake, data ); + } + else + { + conn->func( conn->data, NULL, cond ); + + gnutls_deinit( conn->session ); + gnutls_certificate_free_credentials( conn->xcred ); + closesocket( conn->fd ); + + g_free( conn ); + } + } + else + { + /* For now we can't handle non-blocking perfectly everywhere... */ + sock_make_blocking( conn->fd ); + + conn->established = TRUE; + conn->func( conn->data, conn, cond ); + } + + return FALSE; +} + +int ssl_read( void *conn, char *buf, int len ) +{ + int st; + + if( !((struct scd*)conn)->established ) + { + ssl_errno = SSL_NOHANDSHAKE; + return( -1 ); + } + + st = gnutls_record_recv( ((struct scd*)conn)->session, buf, len ); + + ssl_errno = SSL_OK; + if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) + ssl_errno = SSL_AGAIN; + + return st; +} + +int ssl_write( void *conn, const char *buf, int len ) +{ + int st; + + if( !((struct scd*)conn)->established ) + { + ssl_errno = SSL_NOHANDSHAKE; + return( -1 ); + } + + st = gnutls_record_send( ((struct scd*)conn)->session, buf, len ); + + ssl_errno = SSL_OK; + if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) + ssl_errno = SSL_AGAIN; + + return st; +} + +void ssl_disconnect( void *conn_ ) +{ + struct scd *conn = conn_; + + if( conn->inpa != -1 ) + b_event_remove( conn->inpa ); + + if( conn->established ) + gnutls_bye( conn->session, GNUTLS_SHUT_WR ); + + closesocket( conn->fd ); + + gnutls_deinit( conn->session ); + gnutls_certificate_free_credentials( conn->xcred ); + g_free( conn ); +} + +int ssl_getfd( void *conn ) +{ + return( ((struct scd*)conn)->fd ); +} + +b_input_condition ssl_getdirection( void *conn ) +{ + return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ? + GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +} diff --git a/lib/ssl_nss.c b/lib/ssl_nss.c new file mode 100644 index 00000000..218b3a80 --- /dev/null +++ b/lib/ssl_nss.c @@ -0,0 +1,190 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - NSS version */ + +/* Copyright 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 "bitlbee.h" +#include "proxy.h" +#include "ssl_client.h" +#include "sock.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int ssl_errno = 0; + +static gboolean initialized = FALSE; + +struct scd +{ + ssl_input_function func; + gpointer data; + int fd; + PRFileDesc *prfd; + gboolean established; +}; + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); + + +static SECStatus nss_auth_cert (void *arg, PRFileDesc *socket, PRBool checksig, PRBool isserver) +{ + return SECSuccess; +} + +static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket) +{ + PRErrorCode err; + + if(!arg) return SECFailure; + + *(PRErrorCode *)arg = err = PORT_GetError(); + + switch(err) { + case SEC_ERROR_INVALID_AVA: + case SEC_ERROR_INVALID_TIME: + case SEC_ERROR_BAD_SIGNATURE: + case SEC_ERROR_EXPIRED_CERTIFICATE: + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_CERT: + case SEC_ERROR_CERT_VALID: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + case SEC_ERROR_CRL_EXPIRED: + case SEC_ERROR_CRL_BAD_SIGNATURE: + case SEC_ERROR_EXTENSION_VALUE_INVALID: + case SEC_ERROR_CA_CERT_INVALID: + case SEC_ERROR_CERT_USAGES_INVALID: + case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: + return SECSuccess; + + default: + return SECFailure; + } +} + + +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 ); + conn->func = func; + conn->data = data; + + if( conn->fd < 0 ) + { + g_free( conn ); + return( NULL ); + } + + if( !initialized ) + { + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + NSS_NoDB_Init(NULL); + NSS_SetDomesticPolicy(); + } + + + return( conn ); +} + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + if( source == -1 ) + goto ssl_connected_failure; + + /* Until we find out how to handle non-blocking I/O with NSS... */ + sock_make_blocking( conn->fd ); + + conn->prfd = SSL_ImportFD(NULL, PR_ImportTCPSocket(source)); + SSL_OptionSet(conn->prfd, SSL_SECURITY, PR_TRUE); + SSL_OptionSet(conn->prfd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + SSL_BadCertHook(conn->prfd, (SSLBadCertHandler)nss_bad_cert, NULL); + SSL_AuthCertificateHook(conn->prfd, (SSLAuthCertificate)nss_auth_cert, (void *)CERT_GetDefaultCertDB()); + SSL_ResetHandshake(conn->prfd, PR_FALSE); + + if (SSL_ForceHandshake(conn->prfd)) { + goto ssl_connected_failure; + } + + + conn->established = TRUE; + conn->func( conn->data, conn, cond ); + return FALSE; + + ssl_connected_failure: + + conn->func( conn->data, NULL, cond ); + + PR_Close( conn -> prfd ); + if( source >= 0 ) closesocket( source ); + g_free( conn ); + + return FALSE; +} + +int ssl_read( void *conn, char *buf, int len ) +{ + if( !((struct scd*)conn)->established ) + return( 0 ); + + return( PR_Read( ((struct scd*)conn)->prfd, buf, len ) ); +} + +int ssl_write( void *conn, const char *buf, int len ) +{ + if( !((struct scd*)conn)->established ) + return( 0 ); + + return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) ); +} + +void ssl_disconnect( void *conn_ ) +{ + struct scd *conn = conn_; + + PR_Close( conn->prfd ); + closesocket( conn->fd ); + + g_free( conn ); +} + +int ssl_getfd( void *conn ) +{ + return( ((struct scd*)conn)->fd ); +} + +b_input_condition ssl_getdirection( void *conn ) +{ + /* Just in case someone calls us, let's return the most likely case: */ + return GAIM_INPUT_READ; +} diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c new file mode 100644 index 00000000..b6f6c520 --- /dev/null +++ b/lib/ssl_openssl.c @@ -0,0 +1,221 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - OpenSSL version */ + +/* + 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 +#include +#include +#include +#include +#include + +#include "proxy.h" +#include "ssl_client.h" +#include "sock.h" + +int ssl_errno = 0; + +static gboolean initialized = FALSE; + +struct scd +{ + ssl_input_function func; + gpointer data; + int fd; + gboolean established; + + int inpa; + int lasterr; /* Necessary for SSL_get_error */ + SSL *ssl; + SSL_CTX *ssl_ctx; +}; + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); + + +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) +{ + struct scd *conn = g_new0( struct scd, 1 ); + SSL_METHOD *meth; + + conn->fd = proxy_connect( host, port, ssl_connected, conn ); + conn->func = func; + conn->data = data; + + if( conn->fd < 0 ) + { + g_free( conn ); + return( NULL ); + } + + if( !initialized ) + { + initialized = TRUE; + SSLeay_add_ssl_algorithms(); + } + + meth = TLSv1_client_method(); + conn->ssl_ctx = SSL_CTX_new( meth ); + if( conn->ssl_ctx == NULL ) + { + conn->fd = -1; + return( NULL ); + } + + conn->ssl = SSL_new( conn->ssl_ctx ); + if( conn->ssl == NULL ) + { + conn->fd = -1; + return( NULL ); + } + + return( conn ); +} + +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + if( source == -1 ) + return ssl_handshake( data, -1, cond ); + + /* We can do at least the handshake with non-blocking I/O */ + sock_make_nonblocking( conn->fd ); + SSL_set_fd( conn->ssl, conn->fd ); + + return ssl_handshake( data, source, cond ); +} + +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + int st; + + if( ( st = SSL_connect( conn->ssl ) ) < 0 ) + { + conn->lasterr = SSL_get_error( conn->ssl, st ); + if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) + goto ssl_connected_failure; + + conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); + return FALSE; + } + + conn->established = TRUE; + sock_make_blocking( conn->fd ); /* For now... */ + conn->func( conn->data, conn, cond ); + return FALSE; + +ssl_connected_failure: + conn->func( conn->data, NULL, cond ); + + if( conn->ssl ) + { + SSL_shutdown( conn->ssl ); + SSL_free( conn->ssl ); + } + if( conn->ssl_ctx ) + { + SSL_CTX_free( conn->ssl_ctx ); + } + if( source >= 0 ) closesocket( source ); + g_free( conn ); + + return FALSE; +} + +int ssl_read( void *conn, char *buf, int len ) +{ + int st; + + if( !((struct scd*)conn)->established ) + { + ssl_errno = SSL_NOHANDSHAKE; + return -1; + } + + st = SSL_read( ((struct scd*)conn)->ssl, buf, len ); + + ssl_errno = SSL_OK; + if( st <= 0 ) + { + ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); + if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) + ssl_errno = SSL_AGAIN; + } + + return st; +} + +int ssl_write( void *conn, const char *buf, int len ) +{ + int st; + + if( !((struct scd*)conn)->established ) + { + ssl_errno = SSL_NOHANDSHAKE; + return -1; + } + + st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); + + ssl_errno = SSL_OK; + if( st <= 0 ) + { + ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); + if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) + ssl_errno = SSL_AGAIN; + } + + return st; +} + +void ssl_disconnect( void *conn_ ) +{ + struct scd *conn = conn_; + + if( conn->inpa != -1 ) + b_event_remove( conn->inpa ); + + if( conn->established ) + SSL_shutdown( conn->ssl ); + + closesocket( conn->fd ); + + SSL_free( conn->ssl ); + SSL_CTX_free( conn->ssl_ctx ); + g_free( conn ); +} + +int ssl_getfd( void *conn ) +{ + return( ((struct scd*)conn)->fd ); +} + +b_input_condition ssl_getdirection( void *conn ) +{ + return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +} diff --git a/lib/url.c b/lib/url.c new file mode 100644 index 00000000..e4deac78 --- /dev/null +++ b/lib/url.c @@ -0,0 +1,107 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2001-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* URL/mirror stuff - Stolen from Axel */ + +/* + 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 "url.h" + +/* Convert an URL to a url_t structure */ +int url_set( url_t *url, char *set_url ) +{ + char s[MAX_STRING]; + char *i; + + /* protocol:// */ + if( ( i = strstr( set_url, "://" ) ) == NULL ) + { + url->proto = PROTO_DEFAULT; + strncpy( s, set_url, MAX_STRING ); + } + else + { + if( g_strncasecmp( set_url, "http", i - set_url ) == 0 ) + url->proto = PROTO_HTTP; + else if( g_strncasecmp( set_url, "https", i - set_url ) == 0 ) + url->proto = PROTO_HTTPS; + else if( g_strncasecmp( set_url, "socks4", i - set_url ) == 0 ) + url->proto = PROTO_SOCKS4; + else if( g_strncasecmp( set_url, "socks5", i - set_url ) == 0 ) + url->proto = PROTO_SOCKS5; + else + { + return( 0 ); + } + strncpy( s, i + 3, MAX_STRING ); + } + + /* Split */ + if( ( i = strchr( s, '/' ) ) == NULL ) + { + strcpy( url->file, "/" ); + } + else + { + strncpy( url->file, i, MAX_STRING ); + *i = 0; + } + strncpy( url->host, s, MAX_STRING ); + + /* Check for username in host field */ + if( strrchr( url->host, '@' ) != NULL ) + { + strncpy( url->user, url->host, MAX_STRING ); + i = strrchr( url->user, '@' ); + *i = 0; + strcpy( url->host, i + 1 ); + *url->pass = 0; + } + /* If not: Fill in defaults */ + else + { + *url->user = *url->pass = 0; + } + + /* Password? */ + if( ( i = strchr( url->user, ':' ) ) != NULL ) + { + *i = 0; + strcpy( url->pass, i + 1 ); + } + /* Port number? */ + if( ( i = strchr( url->host, ':' ) ) != NULL ) + { + *i = 0; + sscanf( i + 1, "%d", &url->port ); + } + else + { + if( url->proto == PROTO_HTTP ) + url->port = 80; + else if( url->proto == PROTO_HTTPS ) + url->port = 443; + else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS4 ) + url->port = 1080; + } + + return( url->port > 0 ); +} diff --git a/lib/url.h b/lib/url.h new file mode 100644 index 00000000..e9e1ecfe --- /dev/null +++ b/lib/url.h @@ -0,0 +1,44 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2001-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* URL/mirror stuff - Stolen from Axel */ + +/* + 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 "bitlbee.h" + +#define PROTO_HTTP 2 +#define PROTO_HTTPS 5 +#define PROTO_SOCKS4 3 +#define PROTO_SOCKS5 4 +#define PROTO_DEFAULT PROTO_HTTP + +typedef struct url +{ + int proto; + int port; + char host[MAX_STRING]; + char file[MAX_STRING]; + char user[MAX_STRING]; + char pass[MAX_STRING]; +} url_t; + +int url_set( url_t *url, char *set_url ); -- cgit v1.2.3 From 7ed3199067034b4fda4055778e02274f83bcfcb8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 16:07:01 +0200 Subject: Moved Base64-related functions to a separate file and added decode funtions. --- lib/Makefile | 2 +- lib/base64.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/base64.h | 33 +++++++++++++ lib/misc.c | 44 ----------------- lib/misc.h | 2 - lib/proxy.c | 1 + lib/rc4.c | 1 - lib/rc4.h | 1 - 8 files changed, 188 insertions(+), 49 deletions(-) create mode 100644 lib/base64.c create mode 100644 lib/base64.h (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 80cdd9a5..6408c5ba 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ -include ../Makefile.settings # [SH] Program variables -objects = $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o rc4.o sha.o $(SSL_CLIENT) url.o +objects = base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o rc4.o sha.o $(SSL_CLIENT) url.o CFLAGS += -Wall LFLAGS += -r diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 00000000..69069dae --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,153 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Base64 handling functions. encode_real() is mostly based on the y64 en- * +* coder from libyahoo2. Moving it to a new file because it's getting big. * +* * +* Copyright 2006 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 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include +#include +#include "base64.h" + +static const char real_b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + +char *tobase64(const char *text) +{ + return base64_encode(text, strlen(text)); +} + +char *base64_encode(const char *in, int len) +{ + char *out; + + out = g_malloc((len + 2) /* the == padding */ + / 3 /* every 3-byte block */ + * 4 /* becomes a 4-byte one */ + + 1); /* and of course, ASCIIZ! */ + + base64_encode_real((unsigned char*) in, len, (unsigned char*) out, real_b64); + + return out; +} + +int base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, const char *b64digits) +{ + int outlen = 0; + + for (; inlen >= 3; inlen -= 3) + { + out[outlen++] = b64digits[in[0] >> 2]; + out[outlen++] = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + out[outlen++] = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; + out[outlen++] = b64digits[in[2] & 0x3f]; + in += 3; + } + if (inlen > 0) + { + out[outlen++] = b64digits[in[0] >> 2]; + if (inlen > 1) + { + out[outlen++] = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + out[outlen++] = b64digits[((in[1]<<2) & 0x3c)]; + } + else + { + out[outlen++] = b64digits[((in[0]<<4) & 0x30)]; + out[outlen++] = b64digits[64]; + } + out[outlen++] = b64digits[64]; + } + out[outlen] = 0; + + return outlen; +} + +/* Just a simple wrapper, but usually not very convenient because of zero + termination. */ +char *frombase64(const char *in) +{ + unsigned char *out; + + base64_decode(in, &out); + + return (char*) out; +} + +/* FIXME: Lookup table stuff is not threadsafe! (But for now BitlBee is not threaded.) */ +int base64_decode(const char *in, unsigned char **out) +{ + static char b64rev[256] = { 0 }; + int len, i; + + /* Create a reverse-lookup for the Base64 sequence. */ + if( b64rev[0] == 0 ) + { + memset( b64rev, 0xff, 256 ); + for( i = 0; i <= 64; i ++ ) + b64rev[(int)real_b64[i]] = i; + } + + len = strlen( in ); + *out = g_malloc( ( len + 6 ) / 4 * 3 ); + len = base64_decode_real( (unsigned char*) in, *out, b64rev ); + *out = g_realloc( *out, len + 1 ); + out[0][len] = 0; /* Zero termination can't hurt. */ + + return len; +} + +int base64_decode_real(const unsigned char *in, unsigned char *out, char *b64rev) +{ + int i, outlen = 0; + + for( i = 0; in[i]; i += 4 ) + { + int sx; + + sx = b64rev[(int)in[i+0]]; + if( sx >= 64 ) + break; + out[outlen] = ( sx << 2 ) & 0xfc; + + sx = b64rev[(int)in[i+1]]; + if( sx >= 64 ) + break; + out[outlen] |= ( sx >> 4 ) & 0x03; + outlen ++; + out[outlen] = ( sx << 4 ) & 0xf0; + + sx = b64rev[(int)in[i+2]]; + if( sx >= 64 ) + break; + out[outlen] |= ( sx >> 2 ) & 0x0f; + outlen ++; + out[outlen] = ( sx << 6 ) & 0xc0; + + sx = b64rev[(int)in[i+3]]; + if( sx >= 64 ) + break; + out[outlen] |= sx; + outlen ++; + } + + /* If sx > 64 the base64 string was damaged. Should we ignore this? */ + + return outlen; +} diff --git a/lib/base64.h b/lib/base64.h new file mode 100644 index 00000000..570f2b14 --- /dev/null +++ b/lib/base64.h @@ -0,0 +1,33 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Base64 handling functions. encode_real() is mostly based on the y64 en- * +* coder from libyahoo2. Moving it to a new file because it's getting big. * +* * +* Copyright 2006 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 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include +#include + +G_MODULE_EXPORT char *tobase64( const char *text ); +G_MODULE_EXPORT char *base64_encode( const char *in, int len ); +G_MODULE_EXPORT int base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, const char *b64digits ); +G_MODULE_EXPORT char *frombase64( const char *in ); +G_MODULE_EXPORT int base64_decode( const char *in, unsigned char **out ); +G_MODULE_EXPORT int base64_decode_real( const unsigned char *in, unsigned char *out, char *b64reverse ); diff --git a/lib/misc.c b/lib/misc.c index d8d6a4c7..9f592289 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -83,50 +83,6 @@ char *add_cr(char *text) return ret; } -char *tobase64(const char *text) -{ - char *out; - int len; - - len = strlen(text); - out = g_malloc((len + 2) /* the == padding */ - / 3 /* every 3-byte block */ - * 4 /* becomes a 4-byte one */ - + 1); /* and of course, ASCIIZ! */ - - base64_encode_real(text, len, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); - - return out; -} - -void base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, char *b64digits) -{ - for (; inlen >= 3; inlen -= 3) - { - *out++ = b64digits[in[0] >> 2]; - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; - *out++ = b64digits[in[2] & 0x3f]; - in += 3; - } - if (inlen > 0) - { - *out++ = b64digits[in[0] >> 2]; - if (inlen > 1) - { - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[((in[1]<<2) & 0x3c)]; - } - else - { - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[64]; - } - *out++ = b64digits[64]; - } - *out = '\0'; -} - char *normalize(const char *s) { static char buf[BUF_LEN]; diff --git a/lib/misc.h b/lib/misc.h index c7eec19b..ed019bd8 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -29,8 +29,6 @@ G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); G_MODULE_EXPORT char *strip_newlines(char *source); -G_MODULE_EXPORT char *tobase64( const char *text ); -G_MODULE_EXPORT void base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, char *b64digits ); G_MODULE_EXPORT char *normalize( const char *s ); G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); diff --git a/lib/proxy.c b/lib/proxy.c index b8aa304d..453cde91 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -40,6 +40,7 @@ #include #include "nogaim.h" #include "proxy.h" +#include "base64.h" char proxyhost[128] = ""; int proxyport = 0; diff --git a/lib/rc4.c b/lib/rc4.c index 3559f71e..2b732ba2 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -5,7 +5,6 @@ * * * Copyright 2006 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 as published by * * the Free Software Foundation; either version 2 of the License, or * diff --git a/lib/rc4.h b/lib/rc4.h index 8d50b508..6c9ea6b9 100644 --- a/lib/rc4.h +++ b/lib/rc4.h @@ -5,7 +5,6 @@ * * * Copyright 2006 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 as published by * * the Free Software Foundation; either version 2 of the License, or * -- cgit v1.2.3 From 88086dbd9002123be39d00c53460f1ec9f2b719a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 19:23:27 +0200 Subject: Added versioning information to the XML-file (convenient for later format changes), got rid of confusing "Password successfully changed" message when the user uses the identify-command and protected rc4_decode() against short inputs. --- lib/rc4.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/rc4.c b/lib/rc4.c index 2b732ba2..cbe0e2c0 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -157,6 +157,12 @@ int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char key_len = strlen( password ) + RC4_IV_LEN; clear_len = crypt_len - RC4_IV_LEN; + if( clear_len < 0 ) + { + *clear = g_strdup( "" ); + return 0; + } + /* Prepare buffers and the key + IV */ *clear = g_malloc( clear_len + 1 ); key = g_malloc( key_len ); -- cgit v1.2.3 From 171946457cccb7280f0918201093e79bbc9eac72 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 28 Jun 2006 16:47:05 +0200 Subject: Added random_bytes() function for better/more reliable randomization and moved set_eval_ops() to a slightly more suitable place. --- lib/misc.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- lib/misc.h | 10 +++++--- lib/rc4.c | 9 ++++++-- 3 files changed, 78 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index 9f592289..784d80d6 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2006 Wilmer van der Gaast and others * \********************************************************************/ /* @@ -10,7 +10,7 @@ * * Copyright (C) 1998-1999, Mark Spencer * (and possibly other members of the Gaim team) - * Copyright 2002-2005 Wilmer van der Gaast + * Copyright 2002-2006 Wilmer van der Gaast */ /* @@ -421,17 +421,67 @@ signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t si return( outbuf - dst ); } -char *set_eval_charset( irc_t *irc, set_t *set, char *value ) +/* A pretty reliable random number generator. Tries to use the /dev/random + devices first, and falls back to the random number generator from libc + when it fails. Opens randomizer devices with O_NONBLOCK to make sure a + lack of entropy won't halt BitlBee. */ +void random_bytes( unsigned char *buf, int count ) { - GIConv cd; - - if ( g_strncasecmp( value, "none", 4 ) == 0 ) - return( value ); - - cd = g_iconv_open( "UTF-8", value ); - if( cd == (GIConv) -1 ) - return( NULL ); - - g_iconv_close( cd ); - return( value ); + static int use_dev = -1; + + /* Actually this probing code isn't really necessary, is it? */ + if( use_dev == -1 ) + { + if( access( "/dev/random", R_OK ) == 0 || access( "/dev/urandom", R_OK ) == 0 ) + use_dev = 1; + else + { + use_dev = 0; + srand( ( getpid() << 16 ) ^ time( NULL ) ); + } + } + + if( use_dev ) + { + int fd; + + /* At least on Linux, /dev/random can block if there's not + enough entropy. We really don't want that, so if it can't + give anything, use /dev/urandom instead. */ + if( ( fd = open( "/dev/random", O_RDONLY | O_NONBLOCK ) ) >= 0 ) + if( read( fd, buf, count ) == count ) + { + close( fd ); + return; + } + close( fd ); + + /* urandom isn't supposed to block at all, but just to be + sure. If it blocks, we'll disable use_dev and use the libc + randomizer instead. */ + if( ( fd = open( "/dev/urandom", O_RDONLY | O_NONBLOCK ) ) >= 0 ) + if( read( fd, buf, count ) == count ) + { + close( fd ); + return; + } + close( fd ); + + /* If /dev/random blocks once, we'll still try to use it + again next time. If /dev/urandom also fails for some + reason, stick with libc during this session. */ + + use_dev = 0; + srand( ( getpid() << 16 ) ^ time( NULL ) ); + } + + if( !use_dev ) + { + int i; + + /* Possibly the LSB of rand() isn't very random on some + platforms. Seems okay on at least Linux and OSX though. */ + for( i = 0; i < count; i ++ ) + buf[i] = rand() & 0xff; + } } diff --git a/lib/misc.h b/lib/misc.h index ed019bd8..57ff3e37 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -23,8 +23,11 @@ Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _UTIL_H -#define _UTIL_H +#ifndef _MISC_H +#define _MISC_H + +#include +#include G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); @@ -44,6 +47,7 @@ G_MODULE_EXPORT char *ipv6_wrap( char *src ); G_MODULE_EXPORT char *ipv6_unwrap( char *src ); G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); -char *set_eval_charset( irc_t *irc, set_t *set, char *value ); + +G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count ); #endif diff --git a/lib/rc4.c b/lib/rc4.c index cbe0e2c0..86b74ef5 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -38,8 +38,10 @@ #include +#include #include #include +#include "misc.h" #include "rc4.h" /* Add some seed to the password, to make sure we *never* use the same key. @@ -133,8 +135,11 @@ int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *crypt = g_malloc( clear_len + RC4_IV_LEN ); key = g_malloc( key_len ); strcpy( (char*) key, password ); - for( i = 0; i < RC4_IV_LEN; i ++ ) - key[key_len-RC4_IV_LEN+i] = crypt[0][i] = rand() & 0xff; + + /* Add the salt. Save it for later (when decrypting) and, of course, + add it to the encryption key. */ + random_bytes( crypt[0], RC4_IV_LEN ); + memcpy( key + key_len - RC4_IV_LEN, crypt[0], RC4_IV_LEN ); /* Generate the initial S[] from the IVed key. */ st = rc4_keymaker( key, key_len, RC4_CYCLES ); -- cgit v1.2.3 From 5100caa16bb707d89f1873aca99b5f87abc1dd56 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 1 Jul 2006 17:52:05 +0200 Subject: Added "account set" command. --- lib/misc.c | 34 ++++++++++++++++++++++++++++++++++ lib/misc.h | 3 +++ lib/rc4.c | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index 784d80d6..17599946 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -485,3 +485,37 @@ void random_bytes( unsigned char *buf, int count ) buf[i] = rand() & 0xff; } } + +int is_bool( char *value ) +{ + if( *value == 0 ) + return 0; + + if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) + return 1; + if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) + return 1; + + while( *value ) + if( !isdigit( *value ) ) + return 0; + else + value ++; + + return 1; +} + +int bool2int( char *value ) +{ + int i; + + if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) + return 1; + if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) + return 0; + + if( sscanf( value, "%d", &i ) == 1 ) + return i; + + return 0; +} diff --git a/lib/misc.h b/lib/misc.h index 57ff3e37..b021e642 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -50,4 +50,7 @@ G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count ); +G_MODULE_EXPORT int is_bool( char *value ); +G_MODULE_EXPORT int bool2int( char *value ); + #endif diff --git a/lib/rc4.c b/lib/rc4.c index 86b74ef5..5e334507 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -164,7 +164,7 @@ int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char if( clear_len < 0 ) { - *clear = g_strdup( "" ); + *clear = (unsigned char*) g_strdup( "" ); return 0; } -- cgit v1.2.3 From 04026d44c29f2b7d64f81bb2d2d061a7d111662f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Jul 2006 19:26:13 +0200 Subject: Fixed a broken call to set_get() (CRASH), shut up a compiler warning in events_glib and now using the right evaluator for acc->"auto_reconnect". --- lib/events_glib.c | 5 ++++- lib/events_libevent.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/events_glib.c b/lib/events_glib.c index 620720cd..38938380 100644 --- a/lib/events_glib.c +++ b/lib/events_glib.c @@ -121,7 +121,10 @@ gint b_input_add(gint source, b_input_condition condition, b_event_handler funct gint b_timeout_add(gint timeout, b_event_handler func, gpointer data) { - gint st = g_timeout_add(timeout, func, data); + /* GSourceFunc and the BitlBee event handler function aren't + really the same, but they're "compatible". ;-) It will do + for now, BitlBee only looks at the "data" argument. */ + gint st = g_timeout_add(timeout, (GSourceFunc) func, data); event_debug( "b_timeout_add( %d, %d, %d ) = %d\n", timeout, func, data, st ); diff --git a/lib/events_libevent.c b/lib/events_libevent.c index 1119c2ab..f2b4d15c 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -100,7 +100,7 @@ static void b_event_passthrough( int fd, short event, void *data ) event_debug( "b_event_passthrough( %d, %d, 0x%x ) (%d)\n", fd, event, (int) data, b_ev->id ); /* Since the called function might cancel this handler already - (which free()s b_ev, we have to remember the ID here. */ + (which free()s b_ev), we have to remember the ID here. */ id = b_ev->id; if( quitting ) -- cgit v1.2.3 From 0aaca60fdc1a6793b438ecc926bd937073d22685 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 19 Jul 2006 18:52:38 +0200 Subject: Added some (more) comments to .h files in lib/ and some minor fixes/cleanups. --- lib/events.h | 31 ++++++++++++++++++++++++++----- lib/http_client.h | 45 +++++++++++++++++++++++++++++++++++---------- lib/rc4.h | 2 ++ lib/ssl_client.h | 30 ++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/events.h b/lib/events.h index 781fca6a..0588547f 100644 --- a/lib/events.h +++ b/lib/events.h @@ -19,11 +19,17 @@ * */ -/* - * Split off the event handling things from proxy.[ch] (and adding timer - * stuff. This to allow BitlBee to use other libs than GLib for event - * handling. - */ +/* This stuff used to be in proxy.c too, but I split it off so BitlBee can + use other libraries (like libevent) to handle events. proxy.c is one very + nice piece of work from Gaim. It connects to a TCP server in the back- + ground and calls a callback function once the connection is ready to use. + This function (proxy_connect()) can be found in proxy.c. (It also + transparently handles HTTP/SOCKS proxies, when necessary.) + + This file offers some extra event handling toys, which will be handled + by GLib or libevent. The advantage of using libevent is that it can use + more advanced I/O polling functions like epoll() in recent Linux + kernels. This should improve BitlBee's scalability. */ #ifndef _EVENTS_H_ @@ -38,12 +44,15 @@ #include #include +/* The conditions you can pass to gaim_input_add()/that will be passed to + the given callback function. */ typedef enum { GAIM_INPUT_READ = 1 << 1, GAIM_INPUT_WRITE = 1 << 2 } b_input_condition; typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond); +/* For internal use. */ #define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) #define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) #define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) @@ -51,14 +60,26 @@ typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition co // #define event_debug( x... ) printf( x ) #define event_debug( x... ) +/* Call this once when the program starts. It'll initialize the event handler + library (if necessary) and then return immediately. */ G_MODULE_EXPORT void b_main_init(); + +/* This one enters the event loop. It shouldn't return until one of the event + handlers calls b_main_quit(). */ G_MODULE_EXPORT void b_main_run(); G_MODULE_EXPORT void b_main_quit(); + +/* Add event handlers (for I/O or a timeout). The event handler will be called + every time the event "happens", until your event handler returns FALSE (or + until you remove it using b_event_remove(). As usual, the data argument + can be used to pass your own data to the event handler. */ G_MODULE_EXPORT gint b_input_add(int fd, b_input_condition cond, b_event_handler func, gpointer data); G_MODULE_EXPORT gint b_timeout_add(gint timeout, b_event_handler func, gpointer data); G_MODULE_EXPORT void b_event_remove(gint id); +/* For now, closesocket() is only a function when using libevent. With GLib + it's a preprocessor macro. */ #ifdef EVENTS_LIBEVENT G_MODULE_EXPORT void closesocket(int fd); #endif diff --git a/lib/http_client.h b/lib/http_client.h index 50ee80cf..78d6dbd1 100644 --- a/lib/http_client.h +++ b/lib/http_client.h @@ -23,24 +23,48 @@ Suite 330, Boston, MA 02111-1307 USA */ -#include +/* http_client allows you to talk (asynchronously, again) to HTTP servers. + In the "background" it will send the whole query and wait for a complete + response to come back. Right now it's only used by the MSN Passport + authentication code, but it might be useful for other things too (for + example the AIM usericon patch uses this so icons can be stored on + webservers instead of the local filesystem). + + Didn't test this too much, but it seems to work well. Just don't look + at the code that handles HTTP 30x redirects. ;-) The function is + probably not very useful for downloading lots of data since it keeps + everything in a memory buffer until the download is completed (and + can't pass any data or whatever before then). It's very useful for + doing quick requests without blocking the whole program, though. */ +#include #include "ssl_client.h" struct http_request; +/* Your callback function should look like this: */ typedef void (*http_input_function)( struct http_request * ); +/* This structure will be filled in by the http_dorequest* functions, and + it will be passed to the callback function. Use the data field to add + your own data. */ struct http_request { - char *request; - int request_length; - int status_code; - char *status_string; + char *request; /* The request to send to the server. */ + int request_length; /* Its size. */ + int status_code; /* The numeric HTTP status code. (Or -1 + if something really went wrong) */ + char *status_string; /* The error text. */ char *reply_headers; char *reply_body; - int body_size; - int finished; + int body_size; /* The number of bytes in reply_body. */ + int finished; /* Set to non-0 if the request was completed + successfully. */ + + http_input_function func; + gpointer data; + + /* Please don't touch the things down here, you shouldn't need them. */ void *ssl; int fd; @@ -48,10 +72,11 @@ struct http_request int inpa; int bytes_written; int bytes_read; - - http_input_function func; - gpointer data; }; +/* The _url variant is probably more useful than the raw version. The raw + version is probably only useful if you want to do POST requests or if + you want to add some extra headers. As you can see, HTTPS connections + are also supported (using ssl_client). */ void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); diff --git a/lib/rc4.h b/lib/rc4.h index 6c9ea6b9..2d4d3cc8 100644 --- a/lib/rc4.h +++ b/lib/rc4.h @@ -22,6 +22,8 @@ \***************************************************************************/ +/* See rc4.c for more information. */ + struct rc4_state { unsigned char S[256]; diff --git a/lib/ssl_client.h b/lib/ssl_client.h index 1a9c79e9..964caee4 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -23,20 +23,50 @@ Suite 330, Boston, MA 02111-1307 USA */ +/* ssl_client makes it easier to open SSL connections to servers. (It + doesn't offer SSL server functionality yet, but it could be useful + to add it later.) Different ssl_client modules are available, and + ssl_client tries to make them all behave the same. It's very simple + and basic, it just imitates the proxy_connect() function from the + Gaim libs and passes the socket to the program once the handshake + is completed. */ + #include #include "proxy.h" +/* Some generic error codes. Especially SSL_AGAIN is important if you + want to do asynchronous I/O. */ #define SSL_OK 0 #define SSL_NOHANDSHAKE 1 #define SSL_AGAIN 2 extern int ssl_errno; +/* This is what your callback function should look like. */ typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition); + +/* Connect to host:port, call the given function when the connection is + ready to be used for SSL traffic. This is all done asynchronously, no + blocking I/O! (Except for the DNS lookups, for now...) */ G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); + +/* Obviously you need special read/write functions to read data. */ G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); + +/* Abort the SSL connection and disconnect the socket. Do not use close() + directly, both the SSL library and the peer will be unhappy! */ G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); + +/* Get the fd for this connection, you will usually need it for event + handling. */ G_MODULE_EXPORT int ssl_getfd( void *conn ); + +/* This function returns GAIM_INPUT_READ/WRITE. With SSL connections it's + possible that something has to be read while actually were trying to + write something (think about key exchange/refresh/etc). So when an + SSL operation returned SSL_AGAIN, *always* use this function when + adding an event handler to the queue. (And it should perform exactly + the same action as the handler that just received the SSL_AGAIN.) */ G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); -- cgit v1.2.3 From d1f8759e5034dacb489123719ca86c5d802f154d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 14 Aug 2006 21:32:43 +0200 Subject: Just a little typo in rc4.c --- lib/rc4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/rc4.c b/lib/rc4.c index 5e334507..6223077a 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -45,7 +45,7 @@ #include "rc4.h" /* Add some seed to the password, to make sure we *never* use the same key. - This defines how many byes we use as a seed. */ + This defines how many bytes we use as a seed. */ #define RC4_IV_LEN 6 /* To defend against a "Fluhrer, Mantin and Shamir attack", it is recommended -- cgit v1.2.3 From 51fdc4512cc77fd6b59b582f27887657d7c3721e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 17 Sep 2006 17:56:16 +0200 Subject: add_cr() is not used anymore, and HTML entity handling got UTFized some time ago already, so no need for that FIXME comment. --- lib/misc.c | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index 17599946..64666492 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -53,36 +53,6 @@ void strip_linefeed(gchar *text) g_free(text2); } -char *add_cr(char *text) -{ - char *ret = NULL; - int count = 0, j; - unsigned int i; - - if (text[0] == '\n') - count++; - for (i = 1; i < strlen(text); i++) - if (text[i] == '\n' && text[i - 1] != '\r') - count++; - - if (count == 0) - return g_strdup(text); - - ret = g_malloc0(strlen(text) + count + 1); - - i = 0; j = 0; - if (text[i] == '\n') - ret[j++] = '\r'; - ret[j++] = text[i++]; - for (; i < strlen(text); i++) { - if (text[i] == '\n' && text[i - 1] != '\r') - ret[j++] = '\r'; - ret[j++] = text[i]; - } - - return ret; -} - char *normalize(const char *s) { static char buf[BUF_LEN]; @@ -123,12 +93,10 @@ time_t get_time(int year, int month, int day, int hour, int min, int sec) typedef struct htmlentity { - char code[8]; - char is[4]; + char code[7]; + char is[3]; } htmlentity_t; -/* FIXME: This is ISO8859-1(5) centric, so might cause problems with other charsets. */ - static const htmlentity_t ent[] = { { "lt", "<" }, -- cgit v1.2.3 From 9544acba1fecb11b0b6a0e6260e302890d4c2337 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 20 Sep 2006 11:34:02 +0200 Subject: Using LGPL for generic parts, where possible. --- lib/rc4.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/rc4.c b/lib/rc4.c index 6223077a..f2c76f54 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -5,19 +5,19 @@ * * * Copyright 2006 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 as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * +* 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 program is distributed in the hope that it will be useful, * +* 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 General Public License for more details. * +* 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 General Public License along * -* with this program; if not, write to the Free Software Foundation, Inc., * -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* 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 * * * \***************************************************************************/ -- cgit v1.2.3 From 42127dcd26be4f6746004237eac5333ffbb94f8e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 24 Sep 2006 13:57:45 +0200 Subject: Added support for SSL- and TLS-connections. Checking of the "tls" user setting has to be finished, plus an ssl_starttls() function for the other SSL libraries (this code will only compile with GnuTLS for now). --- lib/ssl_client.h | 4 ++++ lib/ssl_gnutls.c | 45 ++++++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/ssl_client.h b/lib/ssl_client.h index 964caee4..dcbf9a01 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -51,6 +51,10 @@ typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition); blocking I/O! (Except for the DNS lookups, for now...) */ G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); +/* Start an SSL session on an existing fd. Useful for STARTTLS functionality, + for example in Jabber. */ +G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer data ); + /* Obviously you need special read/write functions to read data. */ G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index 3ebe1756..fc848bb1 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -62,22 +62,28 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data if( conn->fd < 0 ) { g_free( conn ); - return( NULL ); + return NULL; } - if( !initialized ) - { - gnutls_global_init(); - initialized = TRUE; - atexit( gnutls_global_deinit ); - } + return conn; +} + +/* FIXME: It can happen that the handshake fails even before ssl_connected() + returns already. This function will then return an invalid pointer because + these failures can't be detected properly yet. Maybe ssl_connected() + shouldn't be called directly, but via a short timeout? */ +void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) +{ + struct scd *conn = g_new0( struct scd, 1 ); - gnutls_certificate_allocate_credentials( &conn->xcred ); - gnutls_init( &conn->session, GNUTLS_CLIENT ); - gnutls_set_default_priority( conn->session ); - gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); + conn->fd = fd; + conn->func = func; + conn->data = data; + conn->inpa = -1; + + ssl_connected( conn, fd, GAIM_INPUT_WRITE ); - return( conn ); + return conn; } static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); @@ -90,14 +96,23 @@ static gboolean ssl_connected( gpointer data, gint source, b_input_condition con { conn->func( conn->data, NULL, cond ); - gnutls_deinit( conn->session ); - gnutls_certificate_free_credentials( conn->xcred ); - g_free( conn ); return FALSE; } + if( !initialized ) + { + gnutls_global_init(); + initialized = TRUE; + atexit( gnutls_global_deinit ); + } + + gnutls_certificate_allocate_credentials( &conn->xcred ); + gnutls_init( &conn->session, GNUTLS_CLIENT ); + gnutls_set_default_priority( conn->session ); + gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); + sock_make_nonblocking( conn->fd ); gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); -- cgit v1.2.3 From c1ed6527576ac4c6ee1241f662e7db8e59327fd8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 2 Oct 2006 15:19:13 +0200 Subject: No more double free()/crashes when trying to set up an SSL connection to a non-SSL server, and better handling of TLS connection setup by initializing the TLS session from a callback function (which guarantees a valid return value from ssl_starttls() before any error callback could be called). --- lib/ssl_gnutls.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index fc848bb1..7481127a 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -48,6 +48,8 @@ struct scd }; static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) @@ -68,10 +70,6 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data return conn; } -/* FIXME: It can happen that the handshake fails even before ssl_connected() - returns already. This function will then return an invalid pointer because - these failures can't be detected properly yet. Maybe ssl_connected() - shouldn't be called directly, but via a short timeout? */ void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) { struct scd *conn = g_new0( struct scd, 1 ); @@ -81,12 +79,26 @@ void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) conn->data = data; conn->inpa = -1; - ssl_connected( conn, fd, GAIM_INPUT_WRITE ); + /* This function should be called via a (short) timeout instead of + directly from here, because these SSL calls are *supposed* to be + *completely* asynchronous and not ready yet when this function + (or *_connect, for examle) returns. Also, errors are reported via + the callback function, not via this function's return value. + + In short, doing things like this makes the rest of the code a lot + simpler. */ + + b_timeout_add( 1, ssl_starttls_real, conn ); return conn; } -static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE ); +} static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) { -- cgit v1.2.3 From 36e9f62a6e6fdb1217b3b819320ac5a94025c448 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 7 Oct 2006 19:46:28 +0200 Subject: Added SRV lookups to automatically find out the correct server for a domain. --- lib/misc.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/misc.h | 10 ++++++++++ 2 files changed, 67 insertions(+) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index 64666492..9061af39 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -39,6 +39,11 @@ #include #include +#ifdef HAVE_RESOLV_A +#include +#include +#endif + void strip_linefeed(gchar *text) { int i, j; @@ -487,3 +492,55 @@ int bool2int( char *value ) return 0; } + +struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain ) +{ + struct ns_srv_reply *reply = NULL; +#ifdef HAVE_RESOLV_A + char name[1024]; + unsigned char querybuf[1024]; + const unsigned char *buf; + ns_msg nsh; + ns_rr rr; + int i, len, size; + + g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain ); + + if( ( size = res_query( name, ns_c_in, ns_t_srv, querybuf, sizeof( querybuf ) ) ) <= 0 ) + return NULL; + + if( ns_initparse( querybuf, size, &nsh ) != 0 ) + return NULL; + + if( ns_parserr( &nsh, ns_s_an, 0, &rr ) != 0 ) + return NULL; + + size = ns_rr_rdlen( rr ); + buf = ns_rr_rdata( rr ); + + len = 0; + for( i = 6; i < size && buf[i]; i += buf[i] + 1 ) + len += buf[i] + 1; + + if( i > size ) + return NULL; + + reply = g_malloc( sizeof( struct ns_srv_reply ) + len ); + memcpy( reply->name, buf + 7, len ); + + for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 ) + reply->name[i] = '.'; + + if( i > len ) + { + g_free( reply ); + return NULL; + } + + reply->prio = ( buf[0] << 8 ) | buf[1]; + reply->weight = ( buf[2] << 8 ) | buf[3]; + reply->port = ( buf[4] << 8 ) | buf[5]; +#endif + + return reply; +} diff --git a/lib/misc.h b/lib/misc.h index b021e642..55dabfc4 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -29,6 +29,14 @@ #include #include +struct ns_srv_reply +{ + int prio; + int weight; + int port; + char name[]; +}; + G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); G_MODULE_EXPORT char *strip_newlines(char *source); @@ -53,4 +61,6 @@ G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count ); G_MODULE_EXPORT int is_bool( char *value ); G_MODULE_EXPORT int bool2int( char *value ); +G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain ); + #endif -- cgit v1.2.3 From f920d9eb003541245e0fc32a381447cbba8fbea5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 19 Oct 2006 09:51:35 +0200 Subject: Added starttls code to ssl_openssl.c so GnuTLS isn't the only supported SSL module in this branch anymore. --- lib/ssl_gnutls.c | 2 - lib/ssl_openssl.c | 117 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 77 insertions(+), 42 deletions(-) (limited to 'lib') diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index 7481127a..fbd1d0c0 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -107,9 +107,7 @@ static gboolean ssl_connected( gpointer data, gint source, b_input_condition con if( source == -1 ) { conn->func( conn->data, NULL, cond ); - g_free( conn ); - return FALSE; } diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index b6f6c520..b1ba1db9 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -52,23 +52,66 @@ struct scd }; static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) { struct scd *conn = g_new0( struct scd, 1 ); - SSL_METHOD *meth; 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 ); + return NULL; } + return conn; +} + +void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) +{ + struct scd *conn = g_new0( struct scd, 1 ); + + conn->fd = fd; + conn->func = func; + conn->data = data; + conn->inpa = -1; + + /* This function should be called via a (short) timeout instead of + directly from here, because these SSL calls are *supposed* to be + *completely* asynchronous and not ready yet when this function + (or *_connect, for examle) returns. Also, errors are reported via + the callback function, not via this function's return value. + + In short, doing things like this makes the rest of the code a lot + simpler. */ + + b_timeout_add( 1, ssl_starttls_real, conn ); + + return conn; +} + +static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE ); +} + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + SSL_METHOD *meth; + + if( source == -1 ) + goto ssl_connected_failure; + if( !initialized ) { initialized = TRUE; @@ -78,35 +121,35 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data meth = TLSv1_client_method(); conn->ssl_ctx = SSL_CTX_new( meth ); if( conn->ssl_ctx == NULL ) - { - conn->fd = -1; - return( NULL ); - } + goto ssl_connected_failure; conn->ssl = SSL_new( conn->ssl_ctx ); if( conn->ssl == NULL ) - { - conn->fd = -1; - return( NULL ); - } - - return( conn ); -} - -static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); - -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) -{ - struct scd *conn = data; - - if( source == -1 ) - return ssl_handshake( data, -1, cond ); + goto ssl_connected_failure; /* We can do at least the handshake with non-blocking I/O */ sock_make_nonblocking( conn->fd ); SSL_set_fd( conn->ssl, conn->fd ); return ssl_handshake( data, source, cond ); + +ssl_connected_failure: + conn->func( conn->data, NULL, cond ); + + if( conn->ssl ) + { + SSL_shutdown( conn->ssl ); + SSL_free( conn->ssl ); + } + if( conn->ssl_ctx ) + { + SSL_CTX_free( conn->ssl_ctx ); + } + if( source >= 0 ) closesocket( source ); + g_free( conn ); + + return FALSE; + } static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) @@ -118,7 +161,18 @@ static gboolean ssl_handshake( gpointer data, gint source, b_input_condition con { conn->lasterr = SSL_get_error( conn->ssl, st ); if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) - goto ssl_connected_failure; + { + conn->func( conn->data, NULL, cond ); + + SSL_shutdown( conn->ssl ); + SSL_free( conn->ssl ); + SSL_CTX_free( conn->ssl_ctx ); + + if( source >= 0 ) closesocket( source ); + g_free( conn ); + + return FALSE; + } conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); return FALSE; @@ -128,23 +182,6 @@ static gboolean ssl_handshake( gpointer data, gint source, b_input_condition con sock_make_blocking( conn->fd ); /* For now... */ conn->func( conn->data, conn, cond ); return FALSE; - -ssl_connected_failure: - conn->func( conn->data, NULL, cond ); - - if( conn->ssl ) - { - SSL_shutdown( conn->ssl ); - SSL_free( conn->ssl ); - } - if( conn->ssl_ctx ) - { - SSL_CTX_free( conn->ssl_ctx ); - } - if( source >= 0 ) closesocket( source ); - g_free( conn ); - - return FALSE; } int ssl_read( void *conn, char *buf, int len ) -- cgit v1.2.3 From 2c7df621d2337437a46b0ccee6a7801bc04db8f4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 6 Dec 2006 13:15:09 +0100 Subject: Fix testsuite. --- lib/Makefile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 6408c5ba..b1bddb3e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -17,6 +17,8 @@ LFLAGS += -r # [SH] Phony targets all: lib.o +check: + .PHONY: all clean distclean clean: $(subdirs) -- cgit v1.2.3 From a51be6448b7a6aa100f27873ce40b835068a66a7 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 6 Dec 2006 15:16:56 +0100 Subject: Fix gcov. --- lib/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index b1bddb3e..33073c27 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -16,8 +16,9 @@ LFLAGS += -r # [SH] Phony targets all: lib.o - -check: +check: all +gcov: + gcov *.c .PHONY: all clean distclean -- cgit v1.2.3 From 7bee5af91e56f1e58232b895fd40c367aec67e8a Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 24 Dec 2006 22:47:18 +0100 Subject: Add tests for set_url(). Fixed a bug where the default port wasn't set when socks5 was used. --- lib/url.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/url.c b/lib/url.c index e4deac78..c6fdc4c8 100644 --- a/lib/url.c +++ b/lib/url.c @@ -99,7 +99,7 @@ int url_set( url_t *url, char *set_url ) url->port = 80; else if( url->proto == PROTO_HTTPS ) url->port = 443; - else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS4 ) + else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS5 ) url->port = 1080; } -- cgit v1.2.3 From 348c11b16c156979ef2c7141ca7450af693b3713 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 22 Jan 2007 10:42:55 +0100 Subject: Add lcov target --- lib/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 33073c27..a9038987 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -17,6 +17,7 @@ LFLAGS += -r # [SH] Phony targets all: lib.o check: all +lcov: gcov: gcov *.c -- cgit v1.2.3 From b6423a0964c121edfb7a4318b1d909916d099d4d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 18 Feb 2007 23:57:12 +0000 Subject: Little fix copied from Jelmer's integration branch, want to import the rest after doing this devel release because there are quite a lot of changes in it. --- lib/url.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/url.c b/lib/url.c index e4deac78..c6fdc4c8 100644 --- a/lib/url.c +++ b/lib/url.c @@ -99,7 +99,7 @@ int url_set( url_t *url, char *set_url ) url->port = 80; else if( url->proto == PROTO_HTTPS ) url->port = 443; - else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS4 ) + else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS5 ) url->port = 1080; } -- cgit v1.2.3 From 3b6eadc990664f9929bceb4f7d14498cf672f0d1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 7 Jul 2007 19:19:28 +0200 Subject: Fix some warnings in storage.c. --- lib/base64.c | 4 ++-- lib/base64.h | 2 +- lib/rc4.c | 8 ++++---- lib/rc4.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/base64.c b/lib/base64.c index 69069dae..64e9692a 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -30,10 +30,10 @@ static const char real_b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv char *tobase64(const char *text) { - return base64_encode(text, strlen(text)); + return base64_encode((const unsigned char *)text, strlen(text)); } -char *base64_encode(const char *in, int len) +char *base64_encode(const unsigned char *in, int len) { char *out; diff --git a/lib/base64.h b/lib/base64.h index 570f2b14..ebd74bf1 100644 --- a/lib/base64.h +++ b/lib/base64.h @@ -26,7 +26,7 @@ #include G_MODULE_EXPORT char *tobase64( const char *text ); -G_MODULE_EXPORT char *base64_encode( const char *in, int len ); +G_MODULE_EXPORT char *base64_encode( const unsigned char *in, int len ); G_MODULE_EXPORT int base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, const char *b64digits ); G_MODULE_EXPORT char *frombase64( const char *in ); G_MODULE_EXPORT int base64_decode( const char *in, unsigned char **out ); diff --git a/lib/rc4.c b/lib/rc4.c index f2c76f54..635b802a 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -121,7 +121,7 @@ unsigned char rc4_getbyte( struct rc4_state *st ) Both functions return the number of bytes in the result string. */ -int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *password ) +int rc4_encode( char *clear, int clear_len, unsigned char **crypt, char *password ) { struct rc4_state *st; unsigned char *key; @@ -129,7 +129,7 @@ int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char key_len = strlen( password ) + RC4_IV_LEN; if( clear_len <= 0 ) - clear_len = strlen( (char*) clear ); + clear_len = strlen( clear ); /* Prepare buffers and the key + IV */ *crypt = g_malloc( clear_len + RC4_IV_LEN ); @@ -153,7 +153,7 @@ int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char return clear_len + RC4_IV_LEN; } -int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char *password ) +int rc4_decode( unsigned char *crypt, int crypt_len, char **clear, char *password ) { struct rc4_state *st; unsigned char *key; @@ -164,7 +164,7 @@ int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char if( clear_len < 0 ) { - *clear = (unsigned char*) g_strdup( "" ); + *clear = g_strdup( "" ); return 0; } diff --git a/lib/rc4.h b/lib/rc4.h index 2d4d3cc8..52de06b1 100644 --- a/lib/rc4.h +++ b/lib/rc4.h @@ -32,5 +32,5 @@ struct rc4_state struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles ); unsigned char rc4_getbyte( struct rc4_state *st ); -int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *password ); -int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char *password ); +int rc4_encode( char *clear, int clear_len, unsigned char **crypt, char *password ); +int rc4_decode( unsigned char *crypt, int crypt_len, char **clear, char *password ); -- cgit v1.2.3 From b9e4ab55dff62611e825de013b32fadab782362f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 7 Jul 2007 19:21:12 +0200 Subject: Fix ssl_bogus. --- lib/ssl_bogus.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/ssl_bogus.c b/lib/ssl_bogus.c index 00aaa7c4..5bae3496 100644 --- a/lib/ssl_bogus.c +++ b/lib/ssl_bogus.c @@ -51,6 +51,11 @@ int ssl_getfd( void *conn ) return( -1 ); } +void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) +{ + return NULL; +} + b_input_condition ssl_getdirection( void *conn ) { return GAIM_INPUT_READ; -- cgit v1.2.3 From a7b59252ddd85810c3b14357fd43602c800b9cb6 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 7 Oct 2007 21:42:37 +0100 Subject: Renaming RC4 to ArcFour (possible trademark issues). --- lib/Makefile | 2 +- lib/arc.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/arc.h | 36 +++++++++++ lib/rc4.c | 189 ---------------------------------------------------------- lib/rc4.h | 36 ----------- 5 files changed, 229 insertions(+), 226 deletions(-) create mode 100644 lib/arc.c create mode 100644 lib/arc.h delete mode 100644 lib/rc4.c delete mode 100644 lib/rc4.h (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index a9038987..bc1966d9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ -include ../Makefile.settings # [SH] Program variables -objects = base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o rc4.o sha.o $(SSL_CLIENT) url.o +objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha.o $(SSL_CLIENT) url.o CFLAGS += -Wall LFLAGS += -r diff --git a/lib/arc.c b/lib/arc.c new file mode 100644 index 00000000..a8e863f2 --- /dev/null +++ b/lib/arc.c @@ -0,0 +1,192 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple (but secure) ArcFour implementation for safer password storage. * +* * +* 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 * +* * +\***************************************************************************/ + +/* + This file implements ArcFour-encryption, which will mainly be used to + save IM passwords safely in the new XML-format. Possibly other uses will + come up later. It's supposed to be quite reliable (thanks to the use of a + 6-byte IV/seed), certainly compared to the old format. The only realistic + way to crack BitlBee passwords now is to use a sniffer to get your hands + on the user's password. + + If you see that something's wrong in this implementation (I asked a + couple of people to look at it already, but who knows), please tell me. + + The reason I picked ArcFour is because it's pretty simple but effective, + so it will work without adding several KBs or an extra library dependency. + + (ArcFour is an RC4-compatible cipher. See for details: + http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt) +*/ + + +#include +#include +#include +#include +#include "misc.h" +#include "arc.h" + +/* Add some seed to the password, to make sure we *never* use the same key. + This defines how many bytes we use as a seed. */ +#define ARC_IV_LEN 6 + +/* To defend against a "Fluhrer, Mantin and Shamir attack", it is recommended + to shuffle S[] just a bit more before you start to use it. This defines how + many bytes we'll request before we'll really use them for encryption. */ +#define ARC_CYCLES 1024 + +struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles ) +{ + struct arc_state *st; + int i, j, tmp; + + st = g_malloc( sizeof( struct arc_state ) ); + st->i = st->j = 0; + for( i = 0; i < 256; i ++ ) + st->S[i] = i; + + if( kl <= 0 ) + kl = strlen( (char*) key ); + + for( i = j = 0; i < 256; i ++ ) + { + j = ( j + st->S[i] + key[i%kl] ) & 0xff; + tmp = st->S[i]; + st->S[i] = st->S[j]; + st->S[j] = tmp; + } + + for( i = 0; i < cycles; i ++ ) + arc_getbyte( st ); + + return st; +} + +/* + For those who don't know, ArcFour is basically an algorithm that generates + a stream of bytes after you give it a key. Just get a byte from it and + xor it with your cleartext. To decrypt, just give it the same key again + and start xorring. + + The function above initializes the byte generator, the next function can + be used to get bytes from the generator (and shuffle things a bit). +*/ + +unsigned char arc_getbyte( struct arc_state *st ) +{ + unsigned char tmp; + + /* Unfortunately the st-> stuff doesn't really improve readability here... */ + st->i ++; + st->j += st->S[st->i]; + tmp = st->S[st->i]; + st->S[st->i] = st->S[st->j]; + st->S[st->j] = tmp; + + return st->S[(st->S[st->i] + st->S[st->j]) & 0xff]; +} + +/* + The following two functions can be used for reliable encryption and + decryption. Known plaintext attacks are prevented by adding some (6, + by default) random bytes to the password before setting up the state + structures. These 6 bytes are also saved in the results, because of + course we'll need them in arc_decode(). + + Because the length of the resulting string is unknown to the caller, + it should pass a char**. Since the encode/decode functions allocate + memory for the string, make sure the char** points at a NULL-pointer + (or at least to something you already free()d), or you'll leak + memory. And of course, don't forget to free() the result when you + don't need it anymore. + + Both functions return the number of bytes in the result string. +*/ + +int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password ) +{ + struct arc_state *st; + unsigned char *key; + int key_len, i; + + key_len = strlen( password ) + ARC_IV_LEN; + if( clear_len <= 0 ) + clear_len = strlen( clear ); + + /* Prepare buffers and the key + IV */ + *crypt = g_malloc( clear_len + ARC_IV_LEN ); + key = g_malloc( key_len ); + strcpy( (char*) key, password ); + + /* Add the salt. Save it for later (when decrypting) and, of course, + add it to the encryption key. */ + random_bytes( crypt[0], ARC_IV_LEN ); + memcpy( key + key_len - ARC_IV_LEN, crypt[0], ARC_IV_LEN ); + + /* Generate the initial S[] from the IVed key. */ + st = arc_keymaker( key, key_len, ARC_CYCLES ); + g_free( key ); + + for( i = 0; i < clear_len; i ++ ) + crypt[0][i+ARC_IV_LEN] = clear[i] ^ arc_getbyte( st ); + + g_free( st ); + + return clear_len + ARC_IV_LEN; +} + +int arc_decode( unsigned char *crypt, int crypt_len, char **clear, char *password ) +{ + struct arc_state *st; + unsigned char *key; + int key_len, clear_len, i; + + key_len = strlen( password ) + ARC_IV_LEN; + clear_len = crypt_len - ARC_IV_LEN; + + if( clear_len < 0 ) + { + *clear = g_strdup( "" ); + return 0; + } + + /* Prepare buffers and the key + IV */ + *clear = g_malloc( clear_len + 1 ); + key = g_malloc( key_len ); + strcpy( (char*) key, password ); + for( i = 0; i < ARC_IV_LEN; i ++ ) + key[key_len-ARC_IV_LEN+i] = crypt[i]; + + /* Generate the initial S[] from the IVed key. */ + st = arc_keymaker( key, key_len, ARC_CYCLES ); + g_free( key ); + + for( i = 0; i < clear_len; i ++ ) + clear[0][i] = crypt[i+ARC_IV_LEN] ^ arc_getbyte( st ); + clear[0][i] = 0; /* Nice to have for plaintexts. */ + + g_free( st ); + + return clear_len; +} diff --git a/lib/arc.h b/lib/arc.h new file mode 100644 index 00000000..882372ed --- /dev/null +++ b/lib/arc.h @@ -0,0 +1,36 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple (but secure) ArcFour implementation for safer password storage. * +* * +* Copyright 2007 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 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + + +/* See arc.c for more information. */ + +struct arc_state +{ + unsigned char S[256]; + unsigned char i, j; +}; + +struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles ); +unsigned char arc_getbyte( struct arc_state *st ); +int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password ); +int arc_decode( unsigned char *crypt, int crypt_len, char **clear, char *password ); diff --git a/lib/rc4.c b/lib/rc4.c deleted file mode 100644 index 635b802a..00000000 --- a/lib/rc4.c +++ /dev/null @@ -1,189 +0,0 @@ -/***************************************************************************\ -* * -* BitlBee - An IRC to IM gateway * -* Simple (but secure) RC4 implementation for safer password storage. * -* * -* 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 * -* * -\***************************************************************************/ - -/* - This file implements RC4-encryption, which will mainly be used to save IM - passwords safely in the new XML-format. Possibly other uses will come up - later. It's supposed to be quite reliable (thanks to the use of a 6-byte - IV/seed), certainly compared to the old format. The only realistic way to - crack BitlBee passwords now is to use a sniffer to get your hands on the - user's password. - - If you see that something's wrong in this implementation (I asked a - couple of people to look at it already, but who knows), please tell me. - - The reason I chose for RC4 is because it's pretty simple but effective, - so it will work without adding several KBs or an extra library dependency. -*/ - - -#include -#include -#include -#include -#include "misc.h" -#include "rc4.h" - -/* Add some seed to the password, to make sure we *never* use the same key. - This defines how many bytes we use as a seed. */ -#define RC4_IV_LEN 6 - -/* To defend against a "Fluhrer, Mantin and Shamir attack", it is recommended - to shuffle S[] just a bit more before you start to use it. This defines how - many bytes we'll request before we'll really use them for encryption. */ -#define RC4_CYCLES 1024 - -struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles ) -{ - struct rc4_state *st; - int i, j, tmp; - - st = g_malloc( sizeof( struct rc4_state ) ); - st->i = st->j = 0; - for( i = 0; i < 256; i ++ ) - st->S[i] = i; - - if( kl <= 0 ) - kl = strlen( (char*) key ); - - for( i = j = 0; i < 256; i ++ ) - { - j = ( j + st->S[i] + key[i%kl] ) & 0xff; - tmp = st->S[i]; - st->S[i] = st->S[j]; - st->S[j] = tmp; - } - - for( i = 0; i < cycles; i ++ ) - rc4_getbyte( st ); - - return st; -} - -/* - For those who don't know, RC4 is basically an algorithm that generates a - stream of bytes after you give it a key. Just get a byte from it and xor - it with your cleartext. To decrypt, just give it the same key again and - start xorring. - - The function above initializes the RC4 byte generator, the next function - can be used to get bytes from the generator (and shuffle things a bit). -*/ - -unsigned char rc4_getbyte( struct rc4_state *st ) -{ - unsigned char tmp; - - /* Unfortunately the st-> stuff doesn't really improve readability here... */ - st->i ++; - st->j += st->S[st->i]; - tmp = st->S[st->i]; - st->S[st->i] = st->S[st->j]; - st->S[st->j] = tmp; - - return st->S[(st->S[st->i] + st->S[st->j]) & 0xff]; -} - -/* - The following two functions can be used for reliable encryption and - decryption. Known plaintext attacks are prevented by adding some (6, - by default) random bytes to the password before setting up the RC4 - structures. These 6 bytes are also saved in the results, because of - course we'll need them in rc4_decode(). - - Because the length of the resulting string is unknown to the caller, - it should pass a char**. Since the encode/decode functions allocate - memory for the string, make sure the char** points at a NULL-pointer - (or at least to something you already free()d), or you'll leak - memory. And of course, don't forget to free() the result when you - don't need it anymore. - - Both functions return the number of bytes in the result string. -*/ - -int rc4_encode( char *clear, int clear_len, unsigned char **crypt, char *password ) -{ - struct rc4_state *st; - unsigned char *key; - int key_len, i; - - key_len = strlen( password ) + RC4_IV_LEN; - if( clear_len <= 0 ) - clear_len = strlen( clear ); - - /* Prepare buffers and the key + IV */ - *crypt = g_malloc( clear_len + RC4_IV_LEN ); - key = g_malloc( key_len ); - strcpy( (char*) key, password ); - - /* Add the salt. Save it for later (when decrypting) and, of course, - add it to the encryption key. */ - random_bytes( crypt[0], RC4_IV_LEN ); - memcpy( key + key_len - RC4_IV_LEN, crypt[0], RC4_IV_LEN ); - - /* Generate the initial S[] from the IVed key. */ - st = rc4_keymaker( key, key_len, RC4_CYCLES ); - g_free( key ); - - for( i = 0; i < clear_len; i ++ ) - crypt[0][i+RC4_IV_LEN] = clear[i] ^ rc4_getbyte( st ); - - g_free( st ); - - return clear_len + RC4_IV_LEN; -} - -int rc4_decode( unsigned char *crypt, int crypt_len, char **clear, char *password ) -{ - struct rc4_state *st; - unsigned char *key; - int key_len, clear_len, i; - - key_len = strlen( password ) + RC4_IV_LEN; - clear_len = crypt_len - RC4_IV_LEN; - - if( clear_len < 0 ) - { - *clear = g_strdup( "" ); - return 0; - } - - /* Prepare buffers and the key + IV */ - *clear = g_malloc( clear_len + 1 ); - key = g_malloc( key_len ); - strcpy( (char*) key, password ); - for( i = 0; i < RC4_IV_LEN; i ++ ) - key[key_len-RC4_IV_LEN+i] = crypt[i]; - - /* Generate the initial S[] from the IVed key. */ - st = rc4_keymaker( key, key_len, RC4_CYCLES ); - g_free( key ); - - for( i = 0; i < clear_len; i ++ ) - clear[0][i] = crypt[i+RC4_IV_LEN] ^ rc4_getbyte( st ); - clear[0][i] = 0; /* Nice to have for plaintexts. */ - - g_free( st ); - - return clear_len; -} diff --git a/lib/rc4.h b/lib/rc4.h deleted file mode 100644 index 52de06b1..00000000 --- a/lib/rc4.h +++ /dev/null @@ -1,36 +0,0 @@ -/***************************************************************************\ -* * -* BitlBee - An IRC to IM gateway * -* Simple (but secure) RC4 implementation for safer password storage. * -* * -* Copyright 2006 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 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 along * -* with this program; if not, write to the Free Software Foundation, Inc., * -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * -* * -\***************************************************************************/ - - -/* See rc4.c for more information. */ - -struct rc4_state -{ - unsigned char S[256]; - unsigned char i, j; -}; - -struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles ); -unsigned char rc4_getbyte( struct rc4_state *st ); -int rc4_encode( char *clear, int clear_len, unsigned char **crypt, char *password ); -int rc4_decode( unsigned char *crypt, int crypt_len, char **clear, char *password ); -- cgit v1.2.3 From e2869bf14ee7aca93d29edd142d60a7184b4d449 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 7 Oct 2007 23:07:25 +0100 Subject: "Changed" the ArcFour implementation. I'm afraid this was a waste of time, but at least I added a neat unittest... --- lib/arc.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/arc.c b/lib/arc.c index a8e863f2..617f6b96 100644 --- a/lib/arc.c +++ b/lib/arc.c @@ -60,23 +60,30 @@ struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles ) { struct arc_state *st; int i, j, tmp; + unsigned char S2[256]; st = g_malloc( sizeof( struct arc_state ) ); st->i = st->j = 0; - for( i = 0; i < 256; i ++ ) - st->S[i] = i; - if( kl <= 0 ) kl = strlen( (char*) key ); + for( i = 0; i < 256; i ++ ) + { + st->S[i] = i; + S2[i] = key[i%kl]; + } + for( i = j = 0; i < 256; i ++ ) { - j = ( j + st->S[i] + key[i%kl] ) & 0xff; + j = ( j + st->S[i] + S2[i] ) & 0xff; tmp = st->S[i]; st->S[i] = st->S[j]; st->S[j] = tmp; } + memset( S2, 0, 256 ); + i = j = 0; + for( i = 0; i < cycles; i ++ ) arc_getbyte( st ); @@ -103,8 +110,9 @@ unsigned char arc_getbyte( struct arc_state *st ) tmp = st->S[st->i]; st->S[st->i] = st->S[st->j]; st->S[st->j] = tmp; + tmp = (st->S[st->i] + st->S[st->j]) & 0xff; - return st->S[(st->S[st->i] + st->S[st->j]) & 0xff]; + return st->S[tmp]; } /* -- cgit v1.2.3 From d444c09e6c7ac6fc3c1686af0e63c09805d8cd00 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 12 Oct 2007 01:06:50 +0100 Subject: Added word_wrap() function to misc.c and using it at the right places so that long messages in groupchats also get wrapped properly (instead of truncated). --- lib/misc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/misc.h | 2 ++ 2 files changed, 50 insertions(+) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index 9061af39..5e385d4a 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -544,3 +544,51 @@ struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain ) return reply; } + +/* Word wrapping. Yes, I know this isn't UTF-8 clean. I'm willing to take the risk. */ +char *word_wrap( char *msg, int line_len ) +{ + GString *ret = g_string_sized_new( strlen( msg ) + 16 ); + + while( strlen( msg ) > line_len ) + { + int i; + + /* First try to find out if there's a newline already. Don't + want to add more splits than necessary. */ + for( i = line_len; i > 0 && msg[i] != '\n'; i -- ); + if( msg[i] == '\n' ) + { + g_string_append_len( ret, msg, i + 1 ); + msg += i + 1; + continue; + } + + for( i = line_len; i > 0; i -- ) + { + if( msg[i] == '-' ) + { + g_string_append_len( ret, msg, i + 1 ); + g_string_append_c( ret, '\n' ); + msg += i + 1; + break; + } + else if( msg[i] == ' ' ) + { + g_string_append_len( ret, msg, i ); + g_string_append_c( ret, '\n' ); + msg += i + 1; + break; + } + } + if( i == 0 ) + { + g_string_append_len( ret, msg, line_len ); + g_string_append_c( ret, '\n' ); + msg += line_len; + } + } + g_string_append( ret, msg ); + + return g_string_free( ret, FALSE ); +} diff --git a/lib/misc.h b/lib/misc.h index 55dabfc4..1d76f7f2 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -63,4 +63,6 @@ G_MODULE_EXPORT int bool2int( char *value ); G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain ); +G_MODULE_EXPORT char *word_wrap( char *msg, int line_len ); + #endif -- cgit v1.2.3 From f618a4a446d9de22298f45edba53eadf87129efc Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 12 Oct 2007 14:11:57 +0200 Subject: Fix GCC warning. --- lib/proxy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/proxy.c b/lib/proxy.c index 7911b06f..dff5d0a4 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -210,7 +210,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond return FALSE; } - if (proxyuser && *proxyuser) { + if (strlen(proxyuser) > 0) { char *t1, *t2; t1 = g_strdup_printf("%s:%s", proxyuser, proxypass); t2 = tobase64(t1); @@ -538,7 +538,7 @@ int proxy_connect(const char *host, int port, b_event_handler func, gpointer dat phb->func = func; phb->data = data; - if ((proxytype == PROXY_NONE) || !proxyhost || !proxyhost[0] || !proxyport || (proxyport == -1)) + if ((proxytype == PROXY_NONE) || strlen(proxyhost) > 0 || !proxyport || (proxyport == -1)) return proxy_connect_none(host, port, phb); else if (proxytype == PROXY_HTTP) return proxy_connect_http(host, port, phb); -- cgit v1.2.3 From e9b755e3726fa41ac2d4ed1c3a6192d1af68edbc Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 18 Oct 2007 18:44:25 +0200 Subject: Use standard functions for dealing with both IPv6 and IPv4. --- lib/misc.c | 40 ---------------------------------------- lib/misc.h | 3 --- 2 files changed, 43 deletions(-) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index 5e385d4a..ceba9d95 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -321,46 +321,6 @@ char *strip_newlines( char *source ) return source; } -#ifdef IPV6 -/* Wrap an IPv4 address into IPv6 space. Not thread-safe... */ -char *ipv6_wrap( char *src ) -{ - static char dst[64]; - int i; - - for( i = 0; src[i]; i ++ ) - if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) - break; - - /* Hmm, it's not even an IP... */ - if( src[i] ) - return src; - - g_snprintf( dst, sizeof( dst ), "::ffff:%s", src ); - - return dst; -} - -/* Unwrap an IPv4 address into IPv6 space. Thread-safe, because it's very simple. :-) */ -char *ipv6_unwrap( char *src ) -{ - int i; - - if( g_strncasecmp( src, "::ffff:", 7 ) != 0 ) - return src; - - for( i = 7; src[i]; i ++ ) - if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) - break; - - /* Hmm, it's not even an IP... */ - if( src[i] ) - return src; - - return ( src + 7 ); -} -#endif - /* Convert from one charset to another. from_cs, to_cs: Source and destination charsets diff --git a/lib/misc.h b/lib/misc.h index 1d76f7f2..e32b5f12 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -51,9 +51,6 @@ G_MODULE_EXPORT char *escape_html( const char *html ); G_MODULE_EXPORT void http_decode( char *s ); G_MODULE_EXPORT void http_encode( char *s ); -G_MODULE_EXPORT char *ipv6_wrap( char *src ); -G_MODULE_EXPORT char *ipv6_unwrap( char *src ); - G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count ); -- cgit v1.2.3 From 56f260affd91651cb0c44ee14713f7dfa0717ad4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 22 Nov 2007 22:56:52 +0000 Subject: Some changes to get rid of compiler warnings. (And disabling strict aliasing because there are too many warnings about it. :-P) --- lib/ssl_gnutls.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index fbd1d0c0..221a2862 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -35,6 +35,14 @@ int ssl_errno = 0; static gboolean initialized = FALSE; +#include + +#if defined(ULONG_MAX) && ULONG_MAX > 4294967295UL +#define GNUTLS_STUPID_CAST (long) +#else +#define GNUTLS_STUPID_CAST (int) +#endif + struct scd { ssl_input_function func; @@ -124,7 +132,7 @@ static gboolean ssl_connected( gpointer data, gint source, b_input_condition con gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); sock_make_nonblocking( conn->fd ); - gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); + gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) GNUTLS_STUPID_CAST conn->fd ); return ssl_handshake( data, source, cond ); } -- cgit v1.2.3 From df6d1da013f42caa5f11dbcbb0d54710682811f7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 23 Nov 2007 22:25:04 +0000 Subject: Replaced GPL-incompatible MD5 hashing code. --- lib/md5.c | 577 +++++++++++++++++++++++--------------------------------------- lib/md5.h | 102 ++++------- 2 files changed, 239 insertions(+), 440 deletions(-) (limited to 'lib') diff --git a/lib/md5.c b/lib/md5.c index e6273585..08c298a2 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -1,392 +1,235 @@ /* - Copyright (C) 1999 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - + * MD5 hashing code copied from Lepton's crack + * + * Adapted to be API-compatible with the previous (GPL-incompatible) code. */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321. - It is derived directly from the text of the RFC and not from the - reference implementation. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. */ +#include +#include /* for memcpy() */ #include "md5.h" -#include -#ifdef TEST +static void md5_transform(u_int32_t buf[4], u_int32_t const in[16]); + /* - * Compile with -DTEST to create a self-contained executable test program. - * The test program should print out the same values as given in section - * A.5 of RFC 1321, reproduced below. + * Wrapper function for all-in-one MD5 + * + * Bernardo Reino, aka Lepton. + * 20021120 */ -#include -main() + +void md5_init(struct MD5Context *ctx) { - static const char *const test[7] = { - "", /*d41d8cd98f00b204e9800998ecf8427e*/ - "945399884.61923487334tuvga", /*0cc175b9c0f1b6a831c399e269772661*/ - "abc", /*900150983cd24fb0d6963f7d28e17f72*/ - "message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/ - "abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/ - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - /*d174ab98d277d9f5a5611c2c9f419d9f*/ - "12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/ - }; - int i; - - for (i = 0; i < 7; ++i) { - md5_state_t state; - md5_byte_t digest[16]; - int di; - - md5_init(&state); - md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i])); - md5_finish(&state, digest); - printf("MD5 (\"%s\") = ", test[i]); - for (di = 0; di < 16; ++di) - printf("%02x", digest[di]); - printf("\n"); - } - return 0; -} -#endif /* TEST */ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} /* - * For reference, here is the program that computed the T values. + * Update context to reflect the concatenation of another buffer full + * of bytes. */ -#if 0 -#include -main() +void md5_append(struct MD5Context *ctx, const md5_byte_t *buf, + unsigned int len) { - int i; - for (i = 1; i <= 64; ++i) { - unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); - printf("#define T%d 0x%08lx\n", i, v); - } - return 0; + u_int32_t t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u_int32_t) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + md5_transform(ctx->buf, (u_int32_t *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + md5_transform(ctx->buf, (u_int32_t *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); } -#endif + /* - * End of T computation program. + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) */ -#define T1 0xd76aa478 -#define T2 0xe8c7b756 -#define T3 0x242070db -#define T4 0xc1bdceee -#define T5 0xf57c0faf -#define T6 0x4787c62a -#define T7 0xa8304613 -#define T8 0xfd469501 -#define T9 0x698098d8 -#define T10 0x8b44f7af -#define T11 0xffff5bb1 -#define T12 0x895cd7be -#define T13 0x6b901122 -#define T14 0xfd987193 -#define T15 0xa679438e -#define T16 0x49b40821 -#define T17 0xf61e2562 -#define T18 0xc040b340 -#define T19 0x265e5a51 -#define T20 0xe9b6c7aa -#define T21 0xd62f105d -#define T22 0x02441453 -#define T23 0xd8a1e681 -#define T24 0xe7d3fbc8 -#define T25 0x21e1cde6 -#define T26 0xc33707d6 -#define T27 0xf4d50d87 -#define T28 0x455a14ed -#define T29 0xa9e3e905 -#define T30 0xfcefa3f8 -#define T31 0x676f02d9 -#define T32 0x8d2a4c8a -#define T33 0xfffa3942 -#define T34 0x8771f681 -#define T35 0x6d9d6122 -#define T36 0xfde5380c -#define T37 0xa4beea44 -#define T38 0x4bdecfa9 -#define T39 0xf6bb4b60 -#define T40 0xbebfbc70 -#define T41 0x289b7ec6 -#define T42 0xeaa127fa -#define T43 0xd4ef3085 -#define T44 0x04881d05 -#define T45 0xd9d4d039 -#define T46 0xe6db99e5 -#define T47 0x1fa27cf8 -#define T48 0xc4ac5665 -#define T49 0xf4292244 -#define T50 0x432aff97 -#define T51 0xab9423a7 -#define T52 0xfc93a039 -#define T53 0x655b59c3 -#define T54 0x8f0ccc92 -#define T55 0xffeff47d -#define T56 0x85845dd1 -#define T57 0x6fa87e4f -#define T58 0xfe2ce6e0 -#define T59 0xa3014314 -#define T60 0x4e0811a1 -#define T61 0xf7537e82 -#define T62 0xbd3af235 -#define T63 0x2ad7d2bb -#define T64 0xeb86d391 - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +void md5_finish(struct MD5Context *ctx, md5_byte_t digest[16]) { - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; - -#ifndef ARCH_IS_BIG_ENDIAN -# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ -#endif -#if ARCH_IS_BIG_ENDIAN - - /* - * On big-endian machines, we must arrange the bytes in the right - * order. (This also works on machines of unknown byte order.) - */ - md5_word_t X[16]; - const md5_byte_t *xp = data; - int i; - - for (i = 0; i < 16; ++i, xp += 4) - X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - -#else /* !ARCH_IS_BIG_ENDIAN */ - - /* - * On little-endian machines, we can process properly aligned data - * without copying it. - */ - md5_word_t xbuf[16]; - const md5_word_t *X; - - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } -#endif - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + md5_transform(ctx->buf, (u_int32_t *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + + /* Append length in bits and transform */ + ((u_int32_t *) ctx->in)[14] = ctx->bits[0]; + ((u_int32_t *) ctx->in)[15] = ctx->bits[1]; + + md5_transform(ctx->buf, (u_int32_t *) ctx->in); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = 0xefcdab89; - pms->abcd[2] = 0x98badcfe; - pms->abcd[3] = 0x10325476; -} +/* The four core functions - F1 is optimized somewhat */ -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void md5_transform(u_int32_t buf[4], u_int32_t const in[16]) { - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); + register u_int32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; } diff --git a/lib/md5.h b/lib/md5.h index f24f2ff1..86568b7a 100644 --- a/lib/md5.h +++ b/lib/md5.h @@ -1,85 +1,41 @@ /* - Copyright (C) 1999 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - + * MD5 hashing code copied from Lepton's crack + * + * Adapted to be API-compatible with the previous (GPL-incompatible) code. */ -/* - Independent implementation of MD5 (RFC 1321). - This code implements the MD5 Algorithm defined in RFC 1321. - It is derived directly from the text of the RFC and not from the - reference implementation. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2004-03-09 Jelmer Vernooij add G_MODULE_EXPORT for Bitlbee - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. */ -#ifndef md5_INCLUDED -# define md5_INCLUDED +#ifndef _MD5_H +#define _MD5_H -#include +#include #include -/* - * This code has some adaptations for the Ghostscript environment, but it - * will compile and run correctly in any environment with 8-bit chars and - * 32-bit ints. Specifically, it assumes that if the following are - * defined, they have the same meaning as in Ghostscript: P1, P2, P3, - * ARCH_IS_BIG_ENDIAN. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ +typedef u_int8_t md5_byte_t; +typedef struct MD5Context { + u_int32_t buf[4]; + u_int32_t bits[2]; + unsigned char in[64]; } md5_state_t; -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -G_MODULE_EXPORT void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -G_MODULE_EXPORT void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); +G_MODULE_EXPORT void md5_init(struct MD5Context *context); +G_MODULE_EXPORT void md5_append(struct MD5Context *context, const md5_byte_t *buf, unsigned int len); +G_MODULE_EXPORT void md5_finish(struct MD5Context *context, md5_byte_t digest[16]); -/* Finish the message and return the digest. */ -G_MODULE_EXPORT void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ #endif - -#endif /* md5_INCLUDED */ -- cgit v1.2.3 From 77bfd077778c30c70f791752ce3a13d537aedd3b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 23 Nov 2007 23:07:44 +0000 Subject: Replaced GPL-incompatible SHA1 hashing code (and renamed the files in case I ever need SHA256 ;-)). --- lib/Makefile | 2 +- lib/sha.c | 173 --------------------------- lib/sha.h | 21 ---- lib/sha1.c | 375 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/sha1.h | 66 +++++++++++ 5 files changed, 442 insertions(+), 195 deletions(-) delete mode 100644 lib/sha.c delete mode 100644 lib/sha.h create mode 100644 lib/sha1.c create mode 100644 lib/sha1.h (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index bc1966d9..a79f7c4c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ -include ../Makefile.settings # [SH] Program variables -objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha.o $(SSL_CLIENT) url.o +objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha1.o $(SSL_CLIENT) url.o CFLAGS += -Wall LFLAGS += -r diff --git a/lib/sha.c b/lib/sha.c deleted file mode 100644 index 895505a1..00000000 --- a/lib/sha.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is SHA 180-1 Reference Implementation (Compact version) - * - * The Initial Developer of the Original Code is Paul Kocher of - * Cryptography Research. Portions created by Paul Kocher are - * Copyright (C) 1995-9 by Cryptography Research, Inc. All - * Rights Reserved. - * - * Contributor(s): - * - */ - -#define BITLBEE_CORE -#include "nogaim.h" - -static void shaHashBlock(SHA_CTX *ctx); - -void shaInit(SHA_CTX *ctx) { - int i; - - ctx->lenW = 0; - ctx->sizeHi = ctx->sizeLo = 0; - - /* Initialize H with the magic constants (see FIPS180 for constants) - */ - ctx->H[0] = 0x67452301L; - ctx->H[1] = 0xefcdab89L; - ctx->H[2] = 0x98badcfeL; - ctx->H[3] = 0x10325476L; - ctx->H[4] = 0xc3d2e1f0L; - - for (i = 0; i < 80; i++) - ctx->W[i] = 0; -} - - -void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len) { - int i; - - /* Read the data into W and process blocks as they get full - */ - for (i = 0; i < len; i++) { - ctx->W[ctx->lenW / 4] <<= 8; - ctx->W[ctx->lenW / 4] |= (guint32)dataIn[i]; - if ((++ctx->lenW) % 64 == 0) { - shaHashBlock(ctx); - ctx->lenW = 0; - } - ctx->sizeLo += 8; - ctx->sizeHi += (ctx->sizeLo < 8); - } -} - - -void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]) { - unsigned char pad0x80 = 0x80; - unsigned char pad0x00 = 0x00; - unsigned char padlen[8]; - int i; - - /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length - */ - padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); - padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); - padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); - padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); - padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); - padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); - padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); - padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); - shaUpdate(ctx, &pad0x80, 1); - while (ctx->lenW != 56) - shaUpdate(ctx, &pad0x00, 1); - shaUpdate(ctx, padlen, 8); - - /* Output hash - */ - for (i = 0; i < 20; i++) { - hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); - ctx->H[i / 4] <<= 8; - } - - /* - * Re-initialize the context (also zeroizes contents) - */ - shaInit(ctx); -} - - -void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]) { - SHA_CTX ctx; - - shaInit(&ctx); - shaUpdate(&ctx, dataIn, len); - shaFinal(&ctx, hashout); -} - - -#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL) - -static void shaHashBlock(SHA_CTX *ctx) { - int t; - guint32 A,B,C,D,E,TEMP; - - for (t = 16; t <= 79; t++) - ctx->W[t] = - SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); - - A = ctx->H[0]; - B = ctx->H[1]; - C = ctx->H[2]; - D = ctx->H[3]; - E = ctx->H[4]; - - for (t = 0; t <= 19; t++) { - TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 20; t <= 39; t++) { - TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 40; t <= 59; t++) { - TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 60; t <= 79; t++) { - TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - - ctx->H[0] += A; - ctx->H[1] += B; - ctx->H[2] += C; - ctx->H[3] += D; - ctx->H[4] += E; -} - -/*---------------------------------------------------------------------------- - * - * This code added by Thomas "temas" Muldowney for Jabber compatability - * - *---------------------------------------------------------------------------*/ -char *shahash(char *str) -{ - static char final[41]; - char *pos; - unsigned char hashval[20]; - int x; - - if(!str || strlen(str) == 0) - return NULL; - - shaBlock((unsigned char *)str, strlen(str), hashval); - - pos = final; - for(x=0;x<20;x++) - { - g_snprintf(pos, 3, "%02x", hashval[x]); - pos += 2; - } - return (char *)final; -} diff --git a/lib/sha.h b/lib/sha.h deleted file mode 100644 index e8152b1b..00000000 --- a/lib/sha.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __SHA_H__ -#define __SHA_H__ - -#include - -G_MODULE_EXPORT int strprintsha(char *dest, int *hashval); - -typedef struct { - guint32 H[5]; - guint32 W[80]; - int lenW; - guint32 sizeHi,sizeLo; -} SHA_CTX; - -G_MODULE_EXPORT void shaInit(SHA_CTX *ctx); -G_MODULE_EXPORT void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len); -G_MODULE_EXPORT void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]); -G_MODULE_EXPORT void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]); -G_MODULE_EXPORT char *shahash(char *str); - -#endif diff --git a/lib/sha1.c b/lib/sha1.c new file mode 100644 index 00000000..ee4fcc19 --- /dev/null +++ b/lib/sha1.c @@ -0,0 +1,375 @@ +/* + * SHA1 hashing code copied from Lepton's crack + * + * Adapted to be API-compatible with the previous (GPL-incompatible) code. + */ + +/* + * sha1.c + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses (included via "sha1.h" to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + +#include "sha1.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +static void sha1_pad(sha1_state_t *); +static void sha1_process_block(sha1_state_t *); + +/* + * sha1_init + * + * Description: + * This function will initialize the sha1_state_t in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int sha1_init(sha1_state_t * context) +{ + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * sha1_finish + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int sha1_finish(sha1_state_t * context, uint8_t Message_Digest[sha1_hash_size]) +{ + int i; + + if (!context || !Message_Digest) { + return shaNull; + } + + if (context->Corrupted) { + return context->Corrupted; + } + + if (!context->Computed) { + sha1_pad(context); + for (i = 0; i < 64; ++i) { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + + } + + for (i = 0; i < sha1_hash_size; ++i) { + Message_Digest[i] = context->Intermediate_Hash[i >> 2] + >> 8 * (3 - (i & 0x03)); + } + + return shaSuccess; +} + +/* + * sha1_append + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int +sha1_append(sha1_state_t * context, + const uint8_t * message_array, unsigned length) +{ + if (!length) { + return shaSuccess; + } + + if (!context || !message_array) { + return shaNull; + } + + if (context->Computed) { + context->Corrupted = shaStateError; + + return shaStateError; + } + + if (context->Corrupted) { + return context->Corrupted; + } + while (length-- && !context->Corrupted) { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) { + context->Length_High++; + if (context->Length_High == 0) { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) { + sha1_process_block(context); + } + + message_array++; + } + + return shaSuccess; +} + +/* + * sha1_process_block + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +static void sha1_process_block(sha1_state_t * context) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = 0; t < 16; t++) { + W[t] = context->Message_Block[t * 4] << 24; + W[t] |= context->Message_Block[t * 4 + 1] << 16; + W[t] |= context->Message_Block[t * 4 + 2] << 8; + W[t] |= context->Message_Block[t * 4 + 3]; + } + + for (t = 16; t < 80; t++) { + W[t] = + SHA1CircularShift(1, + W[t - 3] ^ W[t - 8] ^ W[t - + 14] ^ W[t - + 16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for (t = 0; t < 20; t++) { + temp = SHA1CircularShift(5, A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30, B); + + B = A; + A = temp; + } + + for (t = 20; t < 40; t++) { + temp = + SHA1CircularShift(5, + A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30, B); + B = A; + A = temp; + } + + for (t = 40; t < 60; t++) { + temp = SHA1CircularShift(5, A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30, B); + B = A; + A = temp; + } + + for (t = 60; t < 80; t++) { + temp = + SHA1CircularShift(5, + A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30, B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + +/* + * sha1_pad + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ + +static void sha1_pad(sha1_state_t * context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) { + context->Message_Block[context->Message_Block_Index++] = + 0x80; + while (context->Message_Block_Index < 64) { + context->Message_Block[context-> + Message_Block_Index++] = 0; + } + + sha1_process_block(context); + + while (context->Message_Block_Index < 56) { + context->Message_Block[context-> + Message_Block_Index++] = 0; + } + } else { + context->Message_Block[context->Message_Block_Index++] = + 0x80; + while (context->Message_Block_Index < 56) { + + context->Message_Block[context-> + Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = context->Length_High >> 24; + context->Message_Block[57] = context->Length_High >> 16; + context->Message_Block[58] = context->Length_High >> 8; + context->Message_Block[59] = context->Length_High; + context->Message_Block[60] = context->Length_Low >> 24; + context->Message_Block[61] = context->Length_Low >> 16; + context->Message_Block[62] = context->Length_Low >> 8; + context->Message_Block[63] = context->Length_Low; + + sha1_process_block(context); +} diff --git a/lib/sha1.h b/lib/sha1.h new file mode 100644 index 00000000..368c0669 --- /dev/null +++ b/lib/sha1.h @@ -0,0 +1,66 @@ +/* + * SHA1 hashing code copied from Lepton's crack + * + * Adapted to be API-compatible with the previous (GPL-incompatible) code. + */ + +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#include +#include + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum { + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif +#define sha1_hash_size 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context { + uint32_t Intermediate_Hash[sha1_hash_size/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + /* Index into message block array */ + int_least16_t Message_Block_Index; + uint8_t Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} sha1_state_t; + +/* + * Function Prototypes + */ + +G_MODULE_EXPORT int sha1_init(sha1_state_t *); +G_MODULE_EXPORT int sha1_append(sha1_state_t *, const uint8_t *, unsigned int); +G_MODULE_EXPORT int sha1_finish(sha1_state_t *, uint8_t Message_Digest[sha1_hash_size]); + +#endif -- cgit v1.2.3 From b6a2373c2c9a98594a87c54a4644f3c0e985e420 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 28 Nov 2007 23:24:26 +0000 Subject: Fixed the epoll+ForkDaemon combination. The libevent event handling didn't work very well on Linux 2.6 (and possibly others) in ForkDaemon mode. --- lib/events_libevent.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/events_libevent.c b/lib/events_libevent.c index f2b4d15c..d02ad6a6 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -36,7 +36,9 @@ #include #include -static guint id_next; +static void b_main_restart(); + +static guint id_next = 1; static GHashTable *id_hash; static int quitting = 0; @@ -47,6 +49,9 @@ static int quitting = 0; static GHashTable *read_hash; static GHashTable *write_hash; +struct event_base *leh; +struct event_base *old_leh; + struct b_event_data { guint id; @@ -58,9 +63,16 @@ struct b_event_data void b_main_init() { - event_init(); + if( leh != NULL ) + { + /* Clean up the hash tables? */ + + b_main_restart(); + old_leh = leh; + } + + leh = event_init(); - id_next = 1; id_hash = g_hash_table_new( g_int_hash, g_int_equal ); read_hash = g_hash_table_new( g_int_hash, g_int_equal ); write_hash = g_hash_table_new( g_int_hash, g_int_equal ); @@ -68,19 +80,40 @@ void b_main_init() void b_main_run() { - event_dispatch(); + /* This while loop is necessary to exit the event loop and start a + different one (necessary for ForkDaemon mode). */ + while( event_base_dispatch( leh ) == 0 && !quitting ) + { + if( old_leh != NULL ) + { + /* For some reason this just isn't allowed... + Possibly a bug in older versions, will see later. + event_base_free( old_leh ); */ + old_leh = NULL; + } + + printf( "New event loop.\n" ); + } } -void b_main_quit() +static void b_main_restart() { struct timeval tv; - /* libevent sometimes generates events before really quitting, + memset( &tv, 0, sizeof( struct timeval ) ); + event_base_loopexit( leh, &tv ); + + printf( "b_main_restart()\n" ); +} + +void b_main_quit() +{ + /* Tell b_main_run() that it shouldn't restart the loop. Also, + libevent sometimes generates events before really quitting, we want to stop them. */ quitting = 1; - memset( &tv, 0, sizeof( struct timeval ) ); - event_loopexit( &tv ); + b_main_restart(); } static void b_event_passthrough( int fd, short event, void *data ) -- cgit v1.2.3 From 9ff5737ec53cca2ba295b58fb74a8b97f496cd19 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 29 Nov 2007 21:55:14 +0000 Subject: printf() in daemons considered harmful. --- lib/events.h | 4 ++-- lib/events_libevent.c | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/events.h b/lib/events.h index 0588547f..4baea7b6 100644 --- a/lib/events.h +++ b/lib/events.h @@ -44,7 +44,7 @@ #include #include -/* The conditions you can pass to gaim_input_add()/that will be passed to +/* The conditions you can pass to b_input_add()/that will be passed to the given callback function. */ typedef enum { GAIM_INPUT_READ = 1 << 1, @@ -57,7 +57,7 @@ typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition co #define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) #define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) -// #define event_debug( x... ) printf( x ) +/* #define event_debug( x... ) printf( x ) */ #define event_debug( x... ) /* Call this once when the program starts. It'll initialize the event handler diff --git a/lib/events_libevent.c b/lib/events_libevent.c index d02ad6a6..d3403152 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -31,13 +31,11 @@ #include #include #include -#include "proxy.h" - #include #include +#include "proxy.h" static void b_main_restart(); - static guint id_next = 1; static GHashTable *id_hash; static int quitting = 0; @@ -92,7 +90,7 @@ void b_main_run() old_leh = NULL; } - printf( "New event loop.\n" ); + event_debug( "New event loop.\n" ); } } @@ -103,7 +101,7 @@ static void b_main_restart() memset( &tv, 0, sizeof( struct timeval ) ); event_base_loopexit( leh, &tv ); - printf( "b_main_restart()\n" ); + event_debug( "b_main_restart()\n" ); } void b_main_quit() -- cgit v1.2.3 From d52111a7b05657e4a4fa8417e6655389a50769cf Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 12 Dec 2007 21:36:33 +0000 Subject: Fixed sockerr_again() usage in Jabber module to (hopefully) fix a 100% CPU usage bug. --- lib/misc.c | 10 ++++++++++ lib/misc.h | 2 ++ 2 files changed, 12 insertions(+) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index c977029f..d6795ec9 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -44,6 +44,8 @@ #include #endif +#include "ssl_client.h" + void strip_linefeed(gchar *text) { int i, j; @@ -590,3 +592,11 @@ char *word_wrap( char *msg, int line_len ) return g_string_free( ret, FALSE ); } + +gboolean ssl_sockerr_again( void *ssl ) +{ + if( ssl ) + return ssl_errno == SSL_AGAIN; + else + return sockerr_again(); +} diff --git a/lib/misc.h b/lib/misc.h index 1d76f7f2..e0468d73 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -65,4 +65,6 @@ G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol, G_MODULE_EXPORT char *word_wrap( char *msg, int line_len ); +G_MODULE_EXPORT gboolean ssl_sockerr_again( void *ssl ); + #endif -- cgit v1.2.3 From 3e79889dceeac1432156dc5fb6ae4a1f20b86d69 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 12 Dec 2007 23:57:49 +0000 Subject: Checking conn->xcred before trying to clean it up since GnuTLS doesn't seem to check for NULL pointers here. (Closes #257) --- lib/ssl_gnutls.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index 221a2862..b964ab49 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -222,8 +222,10 @@ void ssl_disconnect( void *conn_ ) closesocket( conn->fd ); - gnutls_deinit( conn->session ); - gnutls_certificate_free_credentials( conn->xcred ); + if( conn->session ) + gnutls_deinit( conn->session ); + if( conn->xcred ) + gnutls_certificate_free_credentials( conn->xcred ); g_free( conn ); } -- cgit v1.2.3 From 6f7ac174bb8fbde5e07e1c7da3cf691ecb4e172b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 28 Dec 2007 23:27:45 +0000 Subject: Fixed return value check in proxy_connect(), since on some systems a non-blocking connect() can return immediately (when connecting to localhost, for example). Closes bug #233 and #340. --- lib/proxy.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/proxy.c b/lib/proxy.c index dff5d0a4..0e1c8f07 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -129,18 +129,17 @@ static int proxy_connect_none(const char *host, unsigned short port, struct PHB event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); - if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { - if (sockerr_again()) { - phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); - phb->fd = fd; - } else { - closesocket(fd); - g_free(phb); - return -1; - } + if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0 && !sockerr_again()) { + closesocket(fd); + g_free(phb); + + return -1; + } else { + phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); + phb->fd = fd; + + return fd; } - - return fd; } -- cgit v1.2.3 From f394500c46003237373a47c5a1dcb4af16029e4d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 5 Jan 2008 15:00:15 +0000 Subject: Removed closure->result. I was planning to add some more stuff, but will do that later. --- lib/events_glib.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/events_glib.c b/lib/events_glib.c index 38938380..1198dba6 100644 --- a/lib/events_glib.c +++ b/lib/events_glib.c @@ -47,7 +47,6 @@ typedef struct _GaimIOClosure { b_event_handler function; - guint result; gpointer data; } GaimIOClosure; @@ -100,6 +99,7 @@ gint b_input_add(gint source, b_input_condition condition, b_event_handler funct GaimIOClosure *closure = g_new0(GaimIOClosure, 1); GIOChannel *channel; GIOCondition cond = 0; + int st; closure->function = function; closure->data = data; @@ -110,13 +110,13 @@ gint b_input_add(gint source, b_input_condition condition, b_event_handler funct cond |= GAIM_WRITE_COND; channel = g_io_channel_unix_new(source); - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, - gaim_io_invoke, closure, gaim_io_destroy); + st = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, + gaim_io_invoke, closure, gaim_io_destroy); - event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d (0x%x)\n", source, condition, function, data, closure->result, closure ); + event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d (%p)\n", source, condition, function, data, st, closure ); g_io_channel_unref(channel); - return closure->result; + return st; } gint b_timeout_add(gint timeout, b_event_handler func, gpointer data) -- cgit v1.2.3 From e64de00bf2d99962182243983e8c09decaa36eb4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 12 Jan 2008 00:24:46 +0000 Subject: Killed info_string_append() and now showing the IP address of ICQ users in the "info" command response. --- lib/misc.c | 6 ------ lib/misc.h | 1 - 2 files changed, 7 deletions(-) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index d6795ec9..c2dd966e 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -244,12 +244,6 @@ char *escape_html( const char *html ) return( str ); } -void info_string_append(GString *str, char *newline, char *name, char *value) -{ - if( value && value[0] ) - g_string_sprintfa( str, "%s%s: %s", newline, name, value ); -} - /* Decode%20a%20file%20name */ void http_decode( char *s ) { diff --git a/lib/misc.h b/lib/misc.h index e0468d73..7804bfb1 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -41,7 +41,6 @@ G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); G_MODULE_EXPORT char *strip_newlines(char *source); G_MODULE_EXPORT char *normalize( const char *s ); -G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); double gettime( void ); -- cgit v1.2.3 From 52744f8f65a278a59a8903d5c594e057d63c7006 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 17 Jan 2008 22:06:55 +0000 Subject: Fixing some Solaris compiler warnings (u_int->uint, adding some typecasts for pid_t variables). --- lib/md5.c | 22 +++++++++++----------- lib/md5.h | 7 ++++--- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/md5.c b/lib/md5.c index 08c298a2..f1779794 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -25,7 +25,7 @@ #include /* for memcpy() */ #include "md5.h" -static void md5_transform(u_int32_t buf[4], u_int32_t const in[16]); +static void md5_transform(uint32_t buf[4], uint32_t const in[16]); /* * Wrapper function for all-in-one MD5 @@ -52,12 +52,12 @@ void md5_init(struct MD5Context *ctx) void md5_append(struct MD5Context *ctx, const md5_byte_t *buf, unsigned int len) { - u_int32_t t; + uint32_t t; /* Update bitcount */ t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((u_int32_t) len << 3)) < t) + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; @@ -74,7 +74,7 @@ void md5_append(struct MD5Context *ctx, const md5_byte_t *buf, return; } memcpy(p, buf, t); - md5_transform(ctx->buf, (u_int32_t *) ctx->in); + md5_transform(ctx->buf, (uint32_t *) ctx->in); buf += t; len -= t; } @@ -82,7 +82,7 @@ void md5_append(struct MD5Context *ctx, const md5_byte_t *buf, while (len >= 64) { memcpy(ctx->in, buf, 64); - md5_transform(ctx->buf, (u_int32_t *) ctx->in); + md5_transform(ctx->buf, (uint32_t *) ctx->in); buf += 64; len -= 64; } @@ -116,7 +116,7 @@ void md5_finish(struct MD5Context *ctx, md5_byte_t digest[16]) if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); - md5_transform(ctx->buf, (u_int32_t *) ctx->in); + md5_transform(ctx->buf, (uint32_t *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); @@ -126,10 +126,10 @@ void md5_finish(struct MD5Context *ctx, md5_byte_t digest[16]) } /* Append length in bits and transform */ - ((u_int32_t *) ctx->in)[14] = ctx->bits[0]; - ((u_int32_t *) ctx->in)[15] = ctx->bits[1]; + ((uint32_t *) ctx->in)[14] = ctx->bits[0]; + ((uint32_t *) ctx->in)[15] = ctx->bits[1]; - md5_transform(ctx->buf, (u_int32_t *) ctx->in); + md5_transform(ctx->buf, (uint32_t *) ctx->in); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } @@ -151,9 +151,9 @@ void md5_finish(struct MD5Context *ctx, md5_byte_t digest[16]) * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ -static void md5_transform(u_int32_t buf[4], u_int32_t const in[16]) +static void md5_transform(uint32_t buf[4], uint32_t const in[16]) { - register u_int32_t a, b, c, d; + register uint32_t a, b, c, d; a = buf[0]; b = buf[1]; diff --git a/lib/md5.h b/lib/md5.h index 86568b7a..094507b2 100644 --- a/lib/md5.h +++ b/lib/md5.h @@ -26,11 +26,12 @@ #include #include +#include -typedef u_int8_t md5_byte_t; +typedef uint8_t md5_byte_t; typedef struct MD5Context { - u_int32_t buf[4]; - u_int32_t bits[2]; + uint32_t buf[4]; + uint32_t bits[2]; unsigned char in[64]; } md5_state_t; -- cgit v1.2.3 From bea13052bf43e34b043d868dfdaa84241a8b163a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 19 Jan 2008 12:36:30 +0000 Subject: Added byte swapping code to the new MD5 checksumming code to make it work on big-endian machines. (If someone thinks BitlBee should work on PDPs, send me the fix. I don't care. :-P) This fixes bug #351 (MSN challenge- response failure) but might break backward compatibility if the broken MD5 code was used to save settings. (Somewhere between rev 266 and now.) --- lib/md5.c | 165 ++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 96 insertions(+), 69 deletions(-) (limited to 'lib') diff --git a/lib/md5.c b/lib/md5.c index f1779794..3c39eccd 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -34,6 +34,29 @@ static void md5_transform(uint32_t buf[4], uint32_t const in[16]); * 20021120 */ +/* Turns out MD5 was designed for little-endian machines. If we're running + on a big-endian machines, we have to swap some bytes. Since detecting + endianness at compile time reliably seems pretty hard, let's do it at + run-time. It's not like we're going to checksum megabytes of data... */ +static uint32_t cvt32(uint32_t val) +{ + static int little_endian = -1; + + if (little_endian == -1) + { + little_endian = 1; + little_endian = *((char*) &little_endian); + } + + if (little_endian) + return val; + else + return (val >> 24) | + ((val >> 8) & 0xff00) | + ((val << 8) & 0xff0000) | + (val << 24); +} + void md5_init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; @@ -126,10 +149,14 @@ void md5_finish(struct MD5Context *ctx, md5_byte_t digest[16]) } /* Append length in bits and transform */ - ((uint32_t *) ctx->in)[14] = ctx->bits[0]; - ((uint32_t *) ctx->in)[15] = ctx->bits[1]; + ((uint32_t *) ctx->in)[14] = cvt32(ctx->bits[0]); + ((uint32_t *) ctx->in)[15] = cvt32(ctx->bits[1]); md5_transform(ctx->buf, (uint32_t *) ctx->in); + ctx->buf[0] = cvt32(ctx->buf[0]); + ctx->buf[1] = cvt32(ctx->buf[1]); + ctx->buf[2] = cvt32(ctx->buf[2]); + ctx->buf[3] = cvt32(ctx->buf[3]); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } @@ -160,73 +187,73 @@ static void md5_transform(uint32_t buf[4], uint32_t const in[16]) c = buf[2]; d = buf[3]; - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + MD5STEP(F1, a, b, c, d, cvt32(in[0]) + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, cvt32(in[1]) + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, cvt32(in[2]) + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, cvt32(in[3]) + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, cvt32(in[4]) + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, cvt32(in[5]) + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, cvt32(in[6]) + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, cvt32(in[7]) + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, cvt32(in[8]) + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, cvt32(in[9]) + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, cvt32(in[10]) + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, cvt32(in[11]) + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, cvt32(in[12]) + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, cvt32(in[13]) + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, cvt32(in[14]) + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, cvt32(in[15]) + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, cvt32(in[1]) + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, cvt32(in[6]) + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, cvt32(in[11]) + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, cvt32(in[0]) + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, cvt32(in[5]) + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, cvt32(in[10]) + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, cvt32(in[15]) + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, cvt32(in[4]) + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, cvt32(in[9]) + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, cvt32(in[14]) + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, cvt32(in[3]) + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, cvt32(in[8]) + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, cvt32(in[13]) + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, cvt32(in[2]) + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, cvt32(in[7]) + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, cvt32(in[12]) + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, cvt32(in[5]) + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, cvt32(in[8]) + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, cvt32(in[11]) + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, cvt32(in[14]) + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, cvt32(in[1]) + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, cvt32(in[4]) + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, cvt32(in[7]) + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, cvt32(in[10]) + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, cvt32(in[13]) + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, cvt32(in[0]) + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, cvt32(in[3]) + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, cvt32(in[6]) + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, cvt32(in[9]) + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, cvt32(in[12]) + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, cvt32(in[15]) + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, cvt32(in[2]) + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, cvt32(in[0]) + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, cvt32(in[7]) + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, cvt32(in[14]) + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, cvt32(in[5]) + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, cvt32(in[12]) + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, cvt32(in[3]) + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, cvt32(in[10]) + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, cvt32(in[1]) + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, cvt32(in[8]) + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, cvt32(in[15]) + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, cvt32(in[6]) + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, cvt32(in[13]) + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, cvt32(in[4]) + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, cvt32(in[11]) + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, cvt32(in[2]) + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, cvt32(in[9]) + 0xeb86d391, 21); buf[0] += a; buf[1] += b; -- cgit v1.2.3 From 613cc5583465b2fa35288a2f28d0e408904c4fd9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 24 Jan 2008 22:22:46 +0000 Subject: Fixed two valgrind warnings (partially uninitialized "struct tm" vars.) --- lib/misc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index c2dd966e..18d98f9e 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -89,12 +89,14 @@ time_t get_time(int year, int month, int day, int hour, int min, int sec) { struct tm tm; + memset(&tm, 0, sizeof(struct tm)); tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; + return mktime(&tm); } -- cgit v1.2.3 From fc5cf88448d4337d1a5fde418df1c6206a9b0ea2 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 16 Feb 2008 16:45:12 +0100 Subject: Fix lcov dependencies. --- lib/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index a79f7c4c..975deceb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -17,7 +17,7 @@ LFLAGS += -r # [SH] Phony targets all: lib.o check: all -lcov: +lcov: check gcov: gcov *.c -- 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. --- lib/Makefile | 2 +- lib/xmltree.c | 589 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/xmltree.h | 97 ++++++++++ 3 files changed, 687 insertions(+), 1 deletion(-) create mode 100644 lib/xmltree.c create mode 100644 lib/xmltree.h (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 975deceb..03fef1ab 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ -include ../Makefile.settings # [SH] Program variables -objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha1.o $(SSL_CLIENT) url.o +objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o CFLAGS += -Wall LFLAGS += -r diff --git a/lib/xmltree.c b/lib/xmltree.c new file mode 100644 index 00000000..62549eb5 --- /dev/null +++ b/lib/xmltree.c @@ -0,0 +1,589 @@ +/***************************************************************************\ +* * +* 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/lib/xmltree.h b/lib/xmltree.h new file mode 100644 index 00000000..b8b61641 --- /dev/null +++ b/lib/xmltree.h @@ -0,0 +1,97 @@ +/***************************************************************************\ +* * +* 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(). --- lib/xmltree.c | 3 ++- lib/xmltree.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/xmltree.c b/lib/xmltree.c index 62549eb5..e65b4f41 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -110,11 +110,12 @@ GMarkupParser xt_parser_funcs = NULL }; -struct xt_parser *xt_new( gpointer data ) +struct xt_parser *xt_new( const struct xt_handler_entry *handlers, gpointer data ) { struct xt_parser *xt = g_new0( struct xt_parser, 1 ); xt->data = data; + xt->handlers = handlers; xt_reset( xt ); return xt; diff --git a/lib/xmltree.h b/lib/xmltree.h index b8b61641..10677412 100644 --- a/lib/xmltree.h +++ b/lib/xmltree.h @@ -70,13 +70,13 @@ struct xt_parser struct xt_node *root; struct xt_node *cur; - struct xt_handler_entry *handlers; + const struct xt_handler_entry *handlers; gpointer data; GError *gerr; }; -struct xt_parser *xt_new( gpointer data ); +struct xt_parser *xt_new( const struct xt_handler_entry *handlers, 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 ); -- cgit v1.2.3 From 9ad86bb22e53a40b3ad5bbc57f33d819d2748b0c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Mar 2008 16:09:50 +0000 Subject: Fixed issues with "long" URLs in url.c. Reusing code from 2001 wasn't a good idea... --- lib/url.c | 24 +++++++++++++----------- lib/url.h | 18 +++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/url.c b/lib/url.c index c6fdc4c8..de9966b4 100644 --- a/lib/url.c +++ b/lib/url.c @@ -25,13 +25,16 @@ #include "url.h" -/* Convert an URL to a url_t structure */ +/* Convert an URL to a url_t structure */ int url_set( url_t *url, char *set_url ) { - char s[MAX_STRING]; + char s[MAX_STRING+1]; char *i; - /* protocol:// */ + memset( url, 0, sizeof( url_t ) ); + memset( s, 0, sizeof( s ) ); + + /* protocol:// */ if( ( i = strstr( set_url, "://" ) ) == NULL ) { url->proto = PROTO_DEFAULT; @@ -48,13 +51,12 @@ int url_set( url_t *url, char *set_url ) else if( g_strncasecmp( set_url, "socks5", i - set_url ) == 0 ) url->proto = PROTO_SOCKS5; else - { - return( 0 ); - } + return 0; + strncpy( s, i + 3, MAX_STRING ); } - /* Split */ + /* Split */ if( ( i = strchr( s, '/' ) ) == NULL ) { strcpy( url->file, "/" ); @@ -66,7 +68,7 @@ int url_set( url_t *url, char *set_url ) } strncpy( url->host, s, MAX_STRING ); - /* Check for username in host field */ + /* Check for username in host field */ if( strrchr( url->host, '@' ) != NULL ) { strncpy( url->user, url->host, MAX_STRING ); @@ -75,19 +77,19 @@ int url_set( url_t *url, char *set_url ) strcpy( url->host, i + 1 ); *url->pass = 0; } - /* If not: Fill in defaults */ + /* If not: Fill in defaults */ else { *url->user = *url->pass = 0; } - /* Password? */ + /* Password? */ if( ( i = strchr( url->user, ':' ) ) != NULL ) { *i = 0; strcpy( url->pass, i + 1 ); } - /* Port number? */ + /* Port number? */ if( ( i = strchr( url->host, ':' ) ) != NULL ) { *i = 0; diff --git a/lib/url.h b/lib/url.h index e9e1ecfe..8c038c91 100644 --- a/lib/url.h +++ b/lib/url.h @@ -25,20 +25,20 @@ #include "bitlbee.h" -#define PROTO_HTTP 2 -#define PROTO_HTTPS 5 -#define PROTO_SOCKS4 3 -#define PROTO_SOCKS5 4 -#define PROTO_DEFAULT PROTO_HTTP +#define PROTO_HTTP 2 +#define PROTO_HTTPS 5 +#define PROTO_SOCKS4 3 +#define PROTO_SOCKS5 4 +#define PROTO_DEFAULT PROTO_HTTP typedef struct url { int proto; int port; - char host[MAX_STRING]; - char file[MAX_STRING]; - char user[MAX_STRING]; - char pass[MAX_STRING]; + char host[MAX_STRING+1]; + char file[MAX_STRING+1]; + char user[MAX_STRING+1]; + char pass[MAX_STRING+1]; } url_t; int url_set( url_t *url, char *set_url ); -- cgit v1.2.3 From ddcf491fa460fea612c240589c50da864dad6668 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 14:18:22 +0000 Subject: Adding padding to encrypted IM-passwords so the exact password length can't be guessed from the encrypted data anymore. --- lib/arc.c | 27 +++++++++++++++++++++++++-- lib/arc.h | 4 ++-- 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/arc.c b/lib/arc.c index 617f6b96..fd498454 100644 --- a/lib/arc.c +++ b/lib/arc.c @@ -130,18 +130,40 @@ unsigned char arc_getbyte( struct arc_state *st ) don't need it anymore. Both functions return the number of bytes in the result string. + + Note that if you use the pad_to argument, you will need zero-termi- + nation to find back the original string length after decryption. So + it shouldn't be used if your string contains \0s by itself! */ -int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password ) +int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password, int pad_to ) { struct arc_state *st; unsigned char *key; - int key_len, i; + char *padded = NULL; + int key_len, i, padded_len; key_len = strlen( password ) + ARC_IV_LEN; if( clear_len <= 0 ) clear_len = strlen( clear ); + /* Pad the string to the closest multiple of pad_to. This makes it + impossible to see the exact length of the password. */ + if( pad_to > 0 && ( clear_len % pad_to ) > 0 ) + { + padded_len = clear_len + pad_to - ( clear_len % pad_to ); + padded = g_malloc( padded_len ); + memcpy( padded, clear, clear_len ); + + /* First a \0 and then random data, so we don't have to do + anything special when decrypting. */ + padded[clear_len] = 0; + random_bytes( (unsigned char*) padded + clear_len + 1, padded_len - clear_len - 1 ); + + clear = padded; + clear_len = padded_len; + } + /* Prepare buffers and the key + IV */ *crypt = g_malloc( clear_len + ARC_IV_LEN ); key = g_malloc( key_len ); @@ -160,6 +182,7 @@ int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *passwor crypt[0][i+ARC_IV_LEN] = clear[i] ^ arc_getbyte( st ); g_free( st ); + g_free( padded ); return clear_len + ARC_IV_LEN; } diff --git a/lib/arc.h b/lib/arc.h index 882372ed..58f30d3d 100644 --- a/lib/arc.h +++ b/lib/arc.h @@ -30,7 +30,7 @@ struct arc_state unsigned char i, j; }; -struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles ); +G_GNUC_MALLOC struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles ); unsigned char arc_getbyte( struct arc_state *st ); -int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password ); +int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password, int pad_to ); int arc_decode( unsigned char *crypt, int crypt_len, char **clear, char *password ); -- cgit v1.2.3 From 50d26f33935aadc556dd3e79829b1ca01bbceab9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 15:28:37 +0000 Subject: Fixed base64_decode() to not barf on corrupted Base64 strings. --- lib/base64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/base64.c b/lib/base64.c index 64e9692a..ea0db6b9 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -117,7 +117,7 @@ int base64_decode_real(const unsigned char *in, unsigned char *out, char *b64rev { int i, outlen = 0; - for( i = 0; in[i]; i += 4 ) + for( i = 0; in[i] && in[i+1] && in[i+2] && in[i+3]; i += 4 ) { int sx; -- cgit v1.2.3 From 4e8db1c0141f74dc6156a57739613483344b358d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 16:03:52 +0000 Subject: Moved password hash verification to md5_verify_password() so this can be reused for IRC/OPER passwords (to have encrypted in bitlbee.conf). --- lib/misc.c | 41 +++++++++++++++++++++++++++++++++++++++++ lib/misc.h | 2 ++ 2 files changed, 43 insertions(+) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index 18d98f9e..ccf208b5 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -32,6 +32,7 @@ #define BITLBEE_CORE #include "nogaim.h" +#include "base64.h" #include #include #include @@ -596,3 +597,43 @@ gboolean ssl_sockerr_again( void *ssl ) else return sockerr_again(); } + +/* Returns values: -1 == Failure (base64-decoded to something unexpected) + 0 == Okay + 1 == Password doesn't match the hash. */ +int md5_verify_password( char *password, char *hash ) +{ + md5_byte_t *pass_dec = NULL; + md5_byte_t pass_md5[16]; + md5_state_t md5_state; + int ret, i; + + if( base64_decode( hash, &pass_dec ) != 21 ) + { + ret = -1; + } + else + { + md5_init( &md5_state ); + md5_append( &md5_state, (md5_byte_t*) password, strlen( password ) ); + md5_append( &md5_state, (md5_byte_t*) pass_dec + 16, 5 ); /* Hmmm, salt! */ + md5_finish( &md5_state, pass_md5 ); + + for( i = 0; i < 16; i ++ ) + { + if( pass_dec[i] != pass_md5[i] ) + { + ret = 1; + break; + } + } + + /* If we reached the end of the loop, it was a match! */ + if( i == 16 ) + ret = 0; + } + + g_free( pass_dec ); + + return ret; +} diff --git a/lib/misc.h b/lib/misc.h index 7804bfb1..a2acada6 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -66,4 +66,6 @@ G_MODULE_EXPORT char *word_wrap( char *msg, int line_len ); G_MODULE_EXPORT gboolean ssl_sockerr_again( void *ssl ); +G_MODULE_EXPORT int md5_verify_password( char *password, char *hash ); + #endif -- cgit v1.2.3 From 851a8c29c681cdc3c9838ed99486822cba927f60 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 22 Mar 2008 12:02:50 +0000 Subject: Taught GLib-mode subprocesses how to die. (Closes: #374) --- lib/events_glib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/events_glib.c b/lib/events_glib.c index 1198dba6..3e194e98 100644 --- a/lib/events_glib.c +++ b/lib/events_glib.c @@ -50,11 +50,12 @@ typedef struct _GaimIOClosure { gpointer data; } GaimIOClosure; -static GMainLoop *loop; +static GMainLoop *loop = NULL; void b_main_init() { - loop = g_main_new( FALSE ); + if( loop == NULL ) + loop = g_main_new( FALSE ); } void b_main_run() -- 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). --- lib/ssl_client.h | 3 +++ lib/ssl_gnutls.c | 6 ++++++ lib/ssl_nss.c | 6 ++++++ lib/ssl_openssl.c | 23 +++++++++++++++++++---- 4 files changed, 34 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/ssl_client.h b/lib/ssl_client.h index dcbf9a01..f91d0d70 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -59,6 +59,9 @@ G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer da G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); +/* See ssl_openssl.c for an explanation. */ +G_MODULE_EXPORT int ssl_pending( void *conn ); + /* Abort the SSL connection and disconnect the socket. Do not use close() directly, both the SSL library and the peer will be unhappy! */ G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index b964ab49..f5945442 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -210,6 +210,12 @@ int ssl_write( void *conn, const char *buf, int len ) return st; } +/* See ssl_openssl.c for an explanation. */ +int ssl_pending( void *conn ) +{ + return 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; diff --git a/lib/ssl_nss.c b/lib/ssl_nss.c index 218b3a80..eba3c441 100644 --- a/lib/ssl_nss.c +++ b/lib/ssl_nss.c @@ -168,6 +168,12 @@ int ssl_write( void *conn, const char *buf, int len ) return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) ); } +/* See ssl_openssl.c for an explanation. */ +int ssl_pending( void *conn ) +{ + return 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index b1ba1db9..fc6d433e 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -61,16 +61,16 @@ 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 ); - conn->func = func; - conn->data = data; - conn->inpa = -1; - if( conn->fd < 0 ) { g_free( conn ); return NULL; } + conn->func = func; + conn->data = data; + conn->inpa = -1; + return conn; } @@ -230,6 +230,21 @@ int ssl_write( void *conn, const char *buf, int len ) return st; } +/* Only OpenSSL *really* needs this (and well, maybe NSS). See for more info: + http://www.gnu.org/software/gnutls/manual/gnutls.html#index-gnutls_005frecord_005fcheck_005fpending-209 + http://www.openssl.org/docs/ssl/SSL_pending.html + + Required because OpenSSL empties the TCP buffer completely but doesn't + necessarily give us all the unencrypted data. + + Returns 0 if there's nothing left or if we don't have to care (GnuTLS), + 1 if there's more data. */ +int ssl_pending( void *conn ) +{ + return ( ((struct scd*)conn) && ((struct scd*)conn)->established ) ? + SSL_pending( ((struct scd*)conn)->ssl ) > 0 : 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; -- cgit v1.2.3 From 58a1449166ebc9c2913bf47a4bf05c4cf3e258b0 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 24 Mar 2008 11:01:02 +0000 Subject: Fixed a broken check in lib/proxy.c, this restores proxy support. Thanks to Miles Bader for reporting this in the Debian BTS. Apparently not many people use this functionality, it was broken in bzr for more than a year already... --- lib/proxy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/proxy.c b/lib/proxy.c index 0e1c8f07..53b89d64 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -529,7 +529,7 @@ int proxy_connect(const char *host, int port, b_event_handler func, gpointer dat { struct PHB *phb; - if (!host || !port || (port == -1) || !func || strlen(host) > 128) { + if (!host || port <= 0 || !func || strlen(host) > 128) { return -1; } @@ -537,7 +537,7 @@ int proxy_connect(const char *host, int port, b_event_handler func, gpointer dat phb->func = func; phb->data = data; - if ((proxytype == PROXY_NONE) || strlen(proxyhost) > 0 || !proxyport || (proxyport == -1)) + if (proxytype == PROXY_NONE || !proxyhost[0] || proxyport <= 0) return proxy_connect_none(host, port, phb); else if (proxytype == PROXY_HTTP) return proxy_connect_http(host, port, phb); -- cgit v1.2.3