aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--account.c3
-rw-r--r--account.h1
-rw-r--r--bitlbee.c4
-rw-r--r--bitlbee.h2
-rw-r--r--conf.c5
-rwxr-xr-xconfigure71
-rw-r--r--doc/bitlbee.schema62
-rw-r--r--irc.c10
-rw-r--r--lib/Makefile37
-rw-r--r--lib/base64.c153
-rw-r--r--lib/base64.h33
-rw-r--r--lib/events.h (renamed from protocols/events.h)0
-rw-r--r--lib/events_glib.c (renamed from protocols/events_glib.c)0
-rw-r--r--lib/events_libevent.c (renamed from protocols/events_libevent.c)0
-rw-r--r--lib/http_client.c (renamed from protocols/http_client.c)0
-rw-r--r--lib/http_client.h (renamed from protocols/http_client.h)0
-rw-r--r--lib/ini.c (renamed from ini.c)0
-rw-r--r--lib/ini.h (renamed from ini.h)0
-rw-r--r--lib/md5.c (renamed from protocols/md5.c)0
-rw-r--r--lib/md5.h (renamed from protocols/md5.h)0
-rw-r--r--lib/misc.c (renamed from util.c)57
-rw-r--r--lib/misc.h (renamed from util.h)1
-rw-r--r--lib/proxy.c (renamed from protocols/proxy.c)1
-rw-r--r--lib/proxy.h (renamed from protocols/proxy.h)0
-rw-r--r--lib/rc4.c184
-rw-r--r--lib/rc4.h34
-rw-r--r--lib/sha.c (renamed from protocols/sha.c)0
-rw-r--r--lib/sha.h (renamed from protocols/sha.h)0
-rw-r--r--lib/ssl_bogus.c (renamed from protocols/ssl_bogus.c)0
-rw-r--r--lib/ssl_client.h (renamed from protocols/ssl_client.h)0
-rw-r--r--lib/ssl_gnutls.c (renamed from protocols/ssl_gnutls.c)0
-rw-r--r--lib/ssl_nss.c (renamed from protocols/ssl_nss.c)0
-rw-r--r--lib/ssl_openssl.c (renamed from protocols/ssl_openssl.c)0
-rw-r--r--lib/url.c (renamed from url.c)0
-rw-r--r--lib/url.h (renamed from url.h)0
-rw-r--r--protocols/Makefile2
-rw-r--r--protocols/nogaim.c1
-rw-r--r--protocols/yahoo/libyahoo2.c30
-rw-r--r--root_commands.c7
-rw-r--r--storage.c11
-rw-r--r--storage.h4
-rw-r--r--storage_ldap.c177
-rw-r--r--storage_xml.c506
-rw-r--r--unix.c14
45 files changed, 1300 insertions, 116 deletions
diff --git a/Makefile b/Makefile
index 6f1d2d4a..36afa236 100644
--- a/Makefile
+++ b/Makefile
@@ -9,9 +9,11 @@
-include Makefile.settings
# Program variables
-objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o unix.o url.o user.o util.o
+objects = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o storage_xml.o unix.o user.o
headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h
-subdirs = protocols
+subdirs = protocols lib
+
+objects += $(LDAP_OBJ)
# Expansion of variables
subdirobjs = $(foreach dir,$(subdirs),$(dir)/$(dir).o)
diff --git a/account.c b/account.c
index 168d18c0..b75afa51 100644
--- a/account.c
+++ b/account.c
@@ -34,7 +34,7 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
if( irc->accounts )
{
for( a = irc->accounts; a->next; a = a->next );
- a = a->next = g_new0 ( account_t, 1 );
+ a = a->next = g_new0( account_t, 1 );
}
else
{
@@ -44,6 +44,7 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
a->prpl = prpl;
a->user = g_strdup( user );
a->pass = g_strdup( pass );
+ a->auto_connect = 1;
a->irc = irc;
return( a );
diff --git a/account.h b/account.h
index 37cd8814..40efb101 100644
--- a/account.h
+++ b/account.h
@@ -33,6 +33,7 @@ typedef struct account
char *pass;
char *server;
+ int auto_connect;
int reconnect;
struct irc *irc;
diff --git a/bitlbee.c b/bitlbee.c
index 1d4e2b34..cbad61dc 100644
--- a/bitlbee.c
+++ b/bitlbee.c
@@ -290,6 +290,10 @@ static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition
{
irc_t *irc;
+ /* Since we're fork()ing here, let's make sure we won't
+ get the same random numbers as the parent/siblings. */
+ srand( time( NULL ) ^ getpid() );
+
/* Close the listening socket, we're a client. */
close( global.listen_socket );
b_event_remove( global.listen_watch_source_id );
diff --git a/bitlbee.h b/bitlbee.h
index 709856d8..1462316f 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -129,7 +129,7 @@ extern char *CONF_FILE;
#include "help.h"
#include "query.h"
#include "sock.h"
-#include "util.h"
+#include "misc.h"
#include "proxy.h"
typedef struct global {
diff --git a/conf.c b/conf.c
index 7538825d..d8b8be72 100644
--- a/conf.c
+++ b/conf.c
@@ -33,7 +33,7 @@
#include "url.h"
#include "ipc.h"
-#include "protocols/proxy.h"
+#include "proxy.h"
char *CONF_FILE;
@@ -54,7 +54,8 @@ conf_t *conf_load( int argc, char *argv[] )
conf->port = 6667;
conf->nofork = 0;
conf->verbose = 0;
- conf->primary_storage = "text";
+ conf->primary_storage = "xml";
+ conf->migrate_storage = g_strsplit( "text", ",", -1 );
conf->runmode = RUNMODE_INETD;
conf->authmode = AUTHMODE_OPEN;
conf->auth_pass = NULL;
diff --git a/configure b/configure
index a3c16e75..fc9caffe 100755
--- a/configure
+++ b/configure
@@ -30,6 +30,7 @@ strip=1
ipv6=1
events=glib
+ldap=auto
ssl=auto
arch=`uname -s`
@@ -66,6 +67,8 @@ Option Description Default
--ipv6=0/1 IPv6 socket support $ipv6
+--ldap=0/1/auto LDAP support $ldap
+
--events=... Event handler (glib, libevent) $events
--ssl=... SSL library to use (gnutls, nss, openssl, bogus, auto)
$ssl
@@ -140,21 +143,23 @@ else
echo 'CFLAGS=-O3' >> Makefile.settings
fi
-echo CFLAGS+=-I`pwd` -I`pwd`/protocols -I. >> Makefile.settings
+echo CFLAGS+=-I`pwd` -I`pwd`/lib -I`pwd`/protocols -I. >> Makefile.settings
echo CFLAGS+=-DHAVE_CONFIG_H >> Makefile.settings
if [ -n "$CC" ]; then
- echo "CC=$CC" >> Makefile.settings;
+ CC=$CC
elif type gcc > /dev/null 2> /dev/null; then
- echo "CC=gcc" >> Makefile.settings;
+ CC=gcc
elif type cc > /dev/null 2> /dev/null; then
- echo "CC=cc" >> Makefile.settings;
+ CC=cc
else
echo 'Cannot find a C compiler, aborting.'
exit 1;
fi
+echo "CC=$CC" >> Makefile.settings;
+
if [ -n "$LD" ]; then
echo "LD=$LD" >> Makefile.settings;
elif type ld > /dev/null 2> /dev/null; then
@@ -201,6 +206,29 @@ else
fi
echo 'EVENT_HANDLER=events_'$events'.o' >> Makefile.settings
+if [ "$events" = "libevent" ]; then
+ if ! [ -e "${libevent}include/event.h" ]; then
+ echo
+ echo 'Warning: Could not find event.h, you might have to install it and/or specify'
+ echo 'its location using the --libevent= argument. (Example: If event.h is in'
+ echo '/usr/local/include and binaries are in /usr/local/lib: --libevent=/usr/local)'
+ fi
+
+ echo '#define EVENTS_LIBEVENT' >> config.h
+ cat <<EOF>>Makefile.settings
+EFLAGS+=-levent -L${libevent}lib
+CFLAGS+=-I${libevent}include
+EOF
+elif [ "$events" = "glib" ]; then
+ ## We already use glib anyway, so this is all we need (and in fact not even this, but just to be sure...):
+ echo '#define EVENTS_GLIB' >> config.h
+else
+ echo
+ echo 'ERROR: Unknown event handler specified.'
+ exit 1
+fi
+echo 'EVENT_HANDLER=events_'$events'.o' >> Makefile.settings
+
detect_gnutls()
{
if libgnutls-config --version > /dev/null 2> /dev/null; then
@@ -231,6 +259,23 @@ EOF
fi;
}
+detect_ldap()
+{
+ TMPFILE=`mktemp`
+ if $CC -o $TMPFILE -shared -lldap 2>/dev/null >/dev/null; then
+ cat<<EOF>>Makefile.settings
+EFLAGS+=-lldap
+CFLAGS+=
+EOF
+ ldap=1
+ rm -f $TMPFILE
+ ret=1
+ else
+ ldap=0
+ ret=0
+ fi
+}
+
if [ "$msn" = 1 -o "$jabber" = 1 ]; then
if [ "$ssl" = "auto" ]; then
detect_gnutls
@@ -291,6 +336,18 @@ if [ "$msn" = 1 -o "$jabber" = 1 ]; then
echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings
fi
+if [ "$ldap" = "auto" ]; then
+ detect_ldap
+fi
+
+if [ "$ldap" = 0 ]; then
+ echo "LDAP_OBJ=" >> Makefile.settings
+ echo "#undef WITH_LDAP" >> config.h
+elif [ "$ldap" = 1 ]; then
+ echo "#define WITH_LDAP 1" >> config.h
+ echo "LDAP_OBJ=storage_ldap.o" >> Makefile.settings
+fi
+
if [ "$strip" = 0 ]; then
echo "STRIP=\# skip strip" >> Makefile.settings;
else
@@ -443,3 +500,9 @@ if [ -n "$protocols" ]; then
else
echo ' Building without IM-protocol support. We wish you a lot of fun...';
fi
+
+if [ "$ldap" = "0" ]; then
+ echo " LDAP storage backend disabled."
+else
+ echo " LDAP storage backend enabled."
+fi
diff --git a/doc/bitlbee.schema b/doc/bitlbee.schema
new file mode 100644
index 00000000..3322e057
--- /dev/null
+++ b/doc/bitlbee.schema
@@ -0,0 +1,62 @@
+## LDAP Schema file for BitlBee
+## Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org>
+##
+## We need the following object classes and related attributes:
+##
+## bitlBeeBuddy:
+## - nick
+## - handle
+
+## each bitlBeeNick has zero or more bitlBeeAccount subentries
+## and bitlBeeAccount entries contain zero or more bitlBeeBuddy entries
+
+## The admin needs to setup the LDAP server to:
+## - allow anonymous users to auth against bitlBeeNick objects on the
+## password field
+## - allow anonymous users to create new objects that start with nick=
+## - allow read/write for a user that is authenticated only to his/her own
+## object and subentries
+
+## - userid
+## - userPassword
+## - setting (multiple values)
+## depends: top, account
+
+attributetype ( 1.3.6.1.4.1.25873.2.1.1 NAME 'bitlBeeAutoConnect'
+ DESC 'Autoconnect setting'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.25873.2.1.2 NAME 'bitlBeeAccountNo'
+ DESC 'Account number'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeAccount' SUP account STRUCTURAL
+ DESC 'BitlBee User Account '
+ MUST ( userid, userPassword )
+ MAY ( ) )
+
+## bitlBeeAccount:
+## - accountNo 1.3.6.1.4.1.1466.115.121.1.27
+## - protocol (msn, oscar, jabber, yahoo, ...)
+## - username
+## - password
+## - server name
+## - autoconnect (true/false) 1.3.6.1.4.1.1466.115.121.1.7
+## depends: top
+
+objectclass ( 1.3.6.1.4.1.25873.2.2.1 NAME 'bitlBeeIMAccount' SUP account STRUCTURAL
+ DESC 'BitlBee IM Account '
+ MUST ( bitlBeeAccountNo, userid, userPassword )
+ MAY ( host, bitlBeeAutoconnect ) )
+
+objectclass ( 1.3.6.1.4.1.25873.2.2.2 NAME 'bitlBeeSetting' SUP top STRUCTURAL
+ DESC 'BitlBee Configuration Setting'
+ MUST ( bitlBeeSettingName )
+ MAY ( bitlBeeSettingValue ) )
+
+objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeBuddy' SUP top STRUCTURAL
+ DESC 'BitlBee Nick Mapping'
+ MUST ( bitlBeeBuddyHandle )
+ MAY ( ircNick ) )
diff --git a/irc.c b/irc.c
index c045d12b..c07a3ea3 100644
--- a/irc.c
+++ b/irc.c
@@ -32,10 +32,11 @@ static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
GSList *irc_connection_list = NULL;
-static char *passchange (irc_t *irc, void *set, char *value)
+static char *passchange( irc_t *irc, void *set, char *value )
{
- irc_setpass (irc, value);
- return (NULL);
+ irc_setpass( irc, value );
+ irc_usermsg( irc, "Password successfully changed" );
+ return NULL;
}
irc_t *irc_new( int fd )
@@ -328,11 +329,10 @@ void irc_free(irc_t * irc)
Sets pass without checking */
void irc_setpass (irc_t *irc, const char *pass)
{
- if (irc->password) g_free (irc->password);
+ g_free (irc->password);
if (pass) {
irc->password = g_strdup (pass);
- irc_usermsg (irc, "Password successfully changed");
} else {
irc->password = NULL;
}
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 00000000..6408c5ba
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,37 @@
+###########################
+## Makefile for BitlBee ##
+## ##
+## Copyright 2006 Lintux ##
+###########################
+
+### DEFINITIONS
+
+-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
+
+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/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 <wilmer@gaast.net> *
+* *
+* 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 <glib.h>
+#include <string.h>
+#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 <wilmer@gaast.net> *
+* *
+* 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 <glib.h>
+#include <gmodule.h>
+
+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/protocols/events.h b/lib/events.h
index 781fca6a..781fca6a 100644
--- a/protocols/events.h
+++ b/lib/events.h
diff --git a/protocols/events_glib.c b/lib/events_glib.c
index 620720cd..620720cd 100644
--- a/protocols/events_glib.c
+++ b/lib/events_glib.c
diff --git a/protocols/events_libevent.c b/lib/events_libevent.c
index 1119c2ab..1119c2ab 100644
--- a/protocols/events_libevent.c
+++ b/lib/events_libevent.c
diff --git a/protocols/http_client.c b/lib/http_client.c
index b00fcf98..b00fcf98 100644
--- a/protocols/http_client.c
+++ b/lib/http_client.c
diff --git a/protocols/http_client.h b/lib/http_client.h
index 50ee80cf..50ee80cf 100644
--- a/protocols/http_client.h
+++ b/lib/http_client.h
diff --git a/ini.c b/lib/ini.c
index c63a132e..c63a132e 100644
--- a/ini.c
+++ b/lib/ini.c
diff --git a/ini.h b/lib/ini.h
index 5eab472b..5eab472b 100644
--- a/ini.h
+++ b/lib/ini.h
diff --git a/protocols/md5.c b/lib/md5.c
index e6273585..e6273585 100644
--- a/protocols/md5.c
+++ b/lib/md5.c
diff --git a/protocols/md5.h b/lib/md5.h
index f24f2ff1..f24f2ff1 100644
--- a/protocols/md5.h
+++ b/lib/md5.h
diff --git a/util.c b/lib/misc.c
index dfa0906b..9f592289 100644
--- a/util.c
+++ b/lib/misc.c
@@ -83,63 +83,6 @@ char *add_cr(char *text)
return ret;
}
-static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789+/";
-
-/* XXX Find bug */
-char *tobase64(const char *text)
-{
- char *out = NULL;
- const char *c;
- unsigned int tmp = 0;
- int len = 0, n = 0;
-
- c = text;
-
- while (*c) {
- tmp = tmp << 8;
- tmp += *c;
- n++;
-
- if (n == 3) {
- out = g_realloc(out, len + 4);
- out[len] = alphabet[(tmp >> 18) & 0x3f];
- out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
- out[len + 2] = alphabet[(tmp >> 6) & 0x3f];
- out[len + 3] = alphabet[tmp & 0x3f];
- len += 4;
- tmp = 0;
- n = 0;
- }
- c++;
- }
- switch (n) {
-
- case 2:
- tmp <<= 8;
- out = g_realloc(out, len + 5);
- out[len] = alphabet[(tmp >> 18) & 0x3f];
- out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
- out[len + 2] = alphabet[(tmp >> 6) & 0x3f];
- out[len + 3] = '=';
- out[len + 4] = 0;
- break;
- case 1:
- tmp <<= 16;
- out = g_realloc(out, len + 5);
- out[len] = alphabet[(tmp >> 18) & 0x3f];
- out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
- out[len + 2] = '=';
- out[len + 3] = '=';
- out[len + 4] = 0;
- break;
- case 0:
- out = g_realloc(out, len + 1);
- out[len] = 0;
- break;
- }
- return out;
-}
-
char *normalize(const char *s)
{
static char buf[BUF_LEN];
diff --git a/util.h b/lib/misc.h
index 8e13d9dd..ed019bd8 100644
--- a/util.h
+++ b/lib/misc.h
@@ -29,7 +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 char *normalize( const char *s );
G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value );
diff --git a/protocols/proxy.c b/lib/proxy.c
index 70a2158d..7911b06f 100644
--- a/protocols/proxy.c
+++ b/lib/proxy.c
@@ -40,6 +40,7 @@
#include <errno.h>
#include "nogaim.h"
#include "proxy.h"
+#include "base64.h"
char proxyhost[128] = "";
int proxyport = 0;
diff --git a/protocols/proxy.h b/lib/proxy.h
index 680790a5..680790a5 100644
--- a/protocols/proxy.h
+++ b/lib/proxy.h
diff --git a/lib/rc4.c b/lib/rc4.c
new file mode 100644
index 00000000..cbe0e2c0
--- /dev/null
+++ b/lib/rc4.c
@@ -0,0 +1,184 @@
+/***************************************************************************\
+* *
+* BitlBee - An IRC to IM gateway *
+* Simple (but secure) RC4 implementation for safer password storage. *
+* *
+* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> *
+* *
+* 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 <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#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;
+
+ 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
new file mode 100644
index 00000000..6c9ea6b9
--- /dev/null
+++ b/lib/rc4.h
@@ -0,0 +1,34 @@
+/***************************************************************************\
+* *
+* BitlBee - An IRC to IM gateway *
+* Simple (but secure) RC4 implementation for safer password storage. *
+* *
+* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> *
+* *
+* 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/protocols/sha.c b/lib/sha.c
index 895505a1..895505a1 100644
--- a/protocols/sha.c
+++ b/lib/sha.c
diff --git a/protocols/sha.h b/lib/sha.h
index e8152b1b..e8152b1b 100644
--- a/protocols/sha.h
+++ b/lib/sha.h
diff --git a/protocols/ssl_bogus.c b/lib/ssl_bogus.c
index 00aaa7c4..00aaa7c4 100644
--- a/protocols/ssl_bogus.c
+++ b/lib/ssl_bogus.c
diff --git a/protocols/ssl_client.h b/lib/ssl_client.h
index 1a9c79e9..1a9c79e9 100644
--- a/protocols/ssl_client.h
+++ b/lib/ssl_client.h
diff --git a/protocols/ssl_gnutls.c b/lib/ssl_gnutls.c
index 3ebe1756..3ebe1756 100644
--- a/protocols/ssl_gnutls.c
+++ b/lib/ssl_gnutls.c
diff --git a/protocols/ssl_nss.c b/lib/ssl_nss.c
index 218b3a80..218b3a80 100644
--- a/protocols/ssl_nss.c
+++ b/lib/ssl_nss.c
diff --git a/protocols/ssl_openssl.c b/lib/ssl_openssl.c
index b6f6c520..b6f6c520 100644
--- a/protocols/ssl_openssl.c
+++ b/lib/ssl_openssl.c
diff --git a/url.c b/lib/url.c
index e4deac78..e4deac78 100644
--- a/url.c
+++ b/lib/url.c
diff --git a/url.h b/lib/url.h
index e9e1ecfe..e9e1ecfe 100644
--- a/url.h
+++ b/lib/url.h
diff --git a/protocols/Makefile b/protocols/Makefile
index b74212f4..cc45fb09 100644
--- a/protocols/Makefile
+++ b/protocols/Makefile
@@ -9,7 +9,7 @@
-include ../Makefile.settings
# [SH] Program variables
-objects = $(EVENT_HANDLER) http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT)
+objects = nogaim.o
# [SH] The next two lines should contain the directory name (in $(subdirs))
# and the name of the object file, which should be linked into
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index 78b51b53..04d1ee3e 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -296,6 +296,7 @@ void signoff( struct gaim_connection *gc )
b_event_remove( gc->keepalive );
gc->flags |= OPT_LOGGING_OUT;
+
gc->keepalive = 0;
gc->prpl->close( gc );
b_event_remove( gc->inpa );
diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c
index c691f18b..69b63baa 100644
--- a/protocols/yahoo/libyahoo2.c
+++ b/protocols/yahoo/libyahoo2.c
@@ -89,6 +89,8 @@ char *strchr (), *strrchr ();
#define vsnprintf _vsnprintf
#endif
+#include "base64.h"
+
#ifdef USE_STRUCT_CALLBACKS
struct yahoo_callbacks *yc=NULL;
@@ -694,34 +696,10 @@ static void yahoo_packet_dump(unsigned char *data, int len)
}
}
-static char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789._";
-static void to_y64(unsigned char *out, const unsigned char *in, int inlen)
/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
+static void to_y64(unsigned char *out, const unsigned char *in, int inlen)
{
- for (; inlen >= 3; inlen -= 3)
- {
- *out++ = base64digits[in[0] >> 2];
- *out++ = base64digits[((in[0]<<4) & 0x30) | (in[1]>>4)];
- *out++ = base64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)];
- *out++ = base64digits[in[2] & 0x3f];
- in += 3;
- }
- if (inlen > 0)
- {
- unsigned char fragment;
-
- *out++ = base64digits[in[0] >> 2];
- fragment = (in[0] << 4) & 0x30;
- if (inlen > 1)
- fragment |= in[1] >> 4;
- *out++ = base64digits[fragment];
- *out++ = (inlen < 2) ? '-'
- : base64digits[(in[1] << 2) & 0x3c];
- *out++ = '-';
- }
- *out = '\0';
+ base64_encode_real(in, inlen, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-");
}
static void yahoo_add_to_send_queue(struct yahoo_input_data *yid, void *data, int length)
diff --git a/root_commands.c b/root_commands.c
index 3d3584b3..e69b9981 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -138,11 +138,12 @@ static void cmd_identify( irc_t *irc, char **cmd )
irc_usermsg( irc, "The nick is (probably) not registered" );
break;
case STORAGE_OK:
- irc_usermsg( irc, "Password accepted" );
+ irc_usermsg( irc, "Password accepted, settings and accounts loaded" );
irc_umode_set( irc, "+R", 1 );
break;
+ case STORAGE_OTHER_ERROR:
default:
- irc_usermsg( irc, "Something very weird happened" );
+ irc_usermsg( irc, "Unknown error while loading configuration" );
break;
}
}
@@ -305,7 +306,7 @@ static void cmd_account( irc_t *irc, char **cmd )
irc_usermsg( irc, "Trying to get all accounts connected..." );
for( a = irc->accounts; a; a = a->next )
- if( !a->gc )
+ if( !a->gc && a->auto_connect )
account_on( irc, a );
}
else
diff --git a/storage.c b/storage.c
index b766c9e3..b8e07278 100644
--- a/storage.c
+++ b/storage.c
@@ -6,6 +6,8 @@
/* Support for multiple storage backends */
+/* Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org> */
+
/*
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
@@ -28,9 +30,9 @@
#include "crypting.h"
extern storage_t storage_text;
+extern storage_t storage_xml;
-static GList text_entry = { &storage_text, NULL, NULL };
-static GList *storage_backends = &text_entry;
+static GList *storage_backends = NULL;
void register_storage_backend(storage_t *backend)
{
@@ -62,7 +64,10 @@ GList *storage_init(const char *primary, char **migrate)
GList *ret = NULL;
int i;
storage_t *storage;
-
+
+ register_storage_backend(&storage_text);
+ register_storage_backend(&storage_xml);
+
storage = storage_init_single(primary);
if (storage == NULL)
return NULL;
diff --git a/storage.h b/storage.h
index 301b424c..3c641088 100644
--- a/storage.h
+++ b/storage.h
@@ -32,8 +32,8 @@ typedef enum {
STORAGE_INVALID_PASSWORD,
STORAGE_ALREADY_EXISTS,
STORAGE_OTHER_ERROR /* Error that isn't caused by user input, such as
- a database that is unreachable. log() will be
- used for the exact error message */
+ a database that is unreachable. log() will be
+ used for the exact error message */
} storage_status_t;
typedef struct {
diff --git a/storage_ldap.c b/storage_ldap.c
new file mode 100644
index 00000000..4bc99de5
--- /dev/null
+++ b/storage_ldap.c
@@ -0,0 +1,177 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2004 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Storage backend that uses a LDAP database */
+
+/* Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org> */
+
+/*
+ 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"
+#include <ldap.h>
+
+#define BB_LDAP_HOST "localhost"
+#define BB_LDAP_BASE ""
+
+static char *nick_dn(const char *nick)
+{
+ return g_strdup_printf("bitlBeeNick=%s%s%s", nick, BB_LDAP_BASE?",":"", BB_LDAP_BASE?BB_LDAP_BASE:"");
+}
+
+static storage_status_t nick_connect(const char *nick, const char *password, LDAP **ld)
+{
+ char *mydn;
+ int ret;
+ storage_status_t status;
+ *ld = ldap_init(BB_LDAP_HOST, LDAP_PORT);
+
+ if (!ld) {
+ log_message( LOGLVL_WARNING, "Unable to connect to LDAP server at %s", BB_LDAP_HOST );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ mydn = nick_dn(nick);
+
+ ret = ldap_simple_bind_s(*ld, mydn, password);
+
+ switch (ret) {
+ case LDAP_SUCCESS: status = STORAGE_OK; break;
+ case LDAP_INVALID_CREDENTIALS: status = STORAGE_INVALID_PASSWORD; break;
+ default:
+ log_message( LOGLVL_WARNING, "Unable to authenticate %s: %s", mydn, ldap_err2string(ret) );
+ status = STORAGE_OTHER_ERROR;
+ break;
+ }
+
+ g_free(mydn);
+
+ return status;
+}
+
+static storage_status_t sldap_load ( const char *my_nick, const char* password, irc_t *irc )
+{
+ LDAPMessage *res, *msg;
+ LDAP *ld;
+ int ret, i;
+ storage_status_t status;
+ char *mydn;
+
+ status = nick_connect(my_nick, password, &ld);
+ if (status != STORAGE_OK)
+ return status;
+
+ mydn = nick_dn(my_nick);
+
+ ret = ldap_search_s(ld, mydn, LDAP_SCOPE_BASE, "(objectClass=*)", NULL, 0, &res);
+
+ if (ret != LDAP_SUCCESS) {
+ log_message( LOGLVL_WARNING, "Unable to search for %s: %s", mydn, ldap_err2string(ret) );
+ ldap_unbind_s(ld);
+ return STORAGE_OTHER_ERROR;
+ }
+
+ g_free(mydn);
+
+ for (msg = ldap_first_entry(ld, res); msg; msg = ldap_next_entry(ld, msg)) {
+ }
+
+ /* FIXME: Store in irc_t */
+
+ ldap_unbind_s(ld);
+
+ return STORAGE_OK;
+}
+
+static storage_status_t sldap_check_pass( const char *nick, const char *password )
+{
+ LDAP *ld;
+ storage_status_t status;
+
+ status = nick_connect(nick, password, &ld);
+
+ ldap_unbind_s(ld);
+
+ return status;
+}
+
+static storage_status_t sldap_remove( const char *nick, const char *password )
+{
+ storage_status_t status;
+ LDAP *ld;
+ char *mydn;
+ int ret;
+
+ status = nick_connect(nick, password, &ld);
+
+ if (status != STORAGE_OK)
+ return status;
+
+ mydn = nick_dn(nick);
+
+ ret = ldap_delete(ld, mydn);
+
+ if (ret != LDAP_SUCCESS) {
+ log_message( LOGLVL_WARNING, "Error removing %s: %s", mydn, ldap_err2string(ret) );
+ ldap_unbind_s(ld);
+ return STORAGE_OTHER_ERROR;
+ }
+
+ ldap_unbind_s(ld);
+
+ g_free(mydn);
+ return STORAGE_OK;
+}
+
+static storage_status_t sldap_save( irc_t *irc, int overwrite )
+{
+ LDAP *ld;
+ char *mydn;
+ storage_status_t status;
+ LDAPMessage *msg;
+
+ status = nick_connect(irc->nick, irc->password, &ld);
+ if (status != STORAGE_OK)
+ return status;
+
+ mydn = nick_dn(irc->nick);
+
+ /* FIXME: Make this a bit more atomic? What if we crash after
+ * removing the old account but before adding the new one ? */
+ if (overwrite)
+ sldap_remove(irc->nick, irc->password);
+
+ g_free(mydn);
+
+ ldap_unbind_s(ld);
+
+ return STORAGE_OK;
+}
+
+
+
+storage_t storage_ldap = {
+ .name = "ldap",
+ .check_pass = sldap_check_pass,
+ .remove = sldap_remove,
+ .load = sldap_load,
+ .save = sldap_save
+};
diff --git a/storage_xml.c b/storage_xml.c
new file mode 100644
index 00000000..7d72c781
--- /dev/null
+++ b/storage_xml.c
@@ -0,0 +1,506 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2006 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Storage backend that uses an XMLish format for all data. */
+
+/*
+ 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"
+#include "base64.h"
+#include "rc4.h"
+#include "md5.h"
+
+typedef enum
+{
+ XML_PASS_CHECK_ONLY = -1,
+ XML_PASS_UNKNOWN = 0,
+ XML_PASS_OK
+} xml_pass_st;
+
+/* This isn't very clean, probably making a separate error class + code for
+ BitlBee would be a better solution. But this will work for now... */
+#define XML_PASS_ERRORMSG "Wrong username or password"
+#define XML_FORMAT_VERSION 1
+
+struct xml_parsedata
+{
+ irc_t *irc;
+ char *current_setting;
+ account_t *current_account;
+ char *given_nick;
+ char *given_pass;
+ xml_pass_st pass_st;
+};
+
+static char *xml_attr( const gchar **attr_names, const gchar **attr_values, const gchar *key )
+{
+ int i;
+
+ for( i = 0; attr_names[i]; i ++ )
+ if( g_strcasecmp( attr_names[i], key ) == 0 )
+ return (char*) attr_values[i];
+
+ return NULL;
+}
+
+static void xml_destroy_xd( gpointer data )
+{
+ struct xml_parsedata *xd = data;
+
+ g_free( xd->given_nick );
+ g_free( xd->given_pass );
+ g_free( xd );
+}
+
+static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error )
+{
+ struct xml_parsedata *xd = data;
+ irc_t *irc = xd->irc;
+
+ if( g_strcasecmp( element_name, "user" ) == 0 )
+ {
+ char *nick = xml_attr( attr_names, attr_values, "nick" );
+ char *pass = xml_attr( attr_names, attr_values, "password" );
+ md5_byte_t *pass_dec = NULL;
+
+ if( !nick || !pass )
+ {
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Missing attributes for %s element", element_name );
+ }
+ else if( base64_decode( pass, &pass_dec ) != 21 )
+ {
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Error while decoding password attribute" );
+ }
+ else
+ {
+ md5_byte_t pass_md5[16];
+ md5_state_t md5_state;
+ int i;
+
+ md5_init( &md5_state );
+ md5_append( &md5_state, (md5_byte_t*) xd->given_pass, strlen( xd->given_pass ) );
+ 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] )
+ {
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ XML_PASS_ERRORMSG );
+ break;
+ }
+ }
+
+ /* If we reached the end of the loop, it was a match! */
+ if( i == 16 )
+ {
+ if( xd->pass_st != XML_PASS_CHECK_ONLY )
+ xd->pass_st = XML_PASS_OK;
+ }
+ }
+
+ g_free( pass_dec );
+ }
+ else if( xd->pass_st < XML_PASS_OK )
+ {
+ /* Let's not parse anything else if we only have to check
+ the password. */
+ }
+ else if( g_strcasecmp( element_name, "account" ) == 0 )
+ {
+ char *protocol, *handle, *server, *password = NULL, *autoconnect;
+ char *pass_b64 = NULL, *pass_rc4 = NULL;
+ int pass_len;
+ struct prpl *prpl = NULL;
+
+ handle = xml_attr( attr_names, attr_values, "handle" );
+ pass_b64 = xml_attr( attr_names, attr_values, "password" );
+ server = xml_attr( attr_names, attr_values, "server" );
+ autoconnect = xml_attr( attr_names, attr_values, "autoconnect" );
+
+ protocol = xml_attr( attr_names, attr_values, "protocol" );
+ if( protocol )
+ prpl = find_protocol( protocol );
+
+ if( !handle || !pass_b64 || !protocol )
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Missing attributes for %s element", element_name );
+ else if( !prpl )
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Unknown protocol: %s", protocol );
+ else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_rc4 ) ) &&
+ rc4_decode( (unsigned char*) pass_rc4, pass_len,
+ (unsigned char**) &password, xd->given_pass ) )
+ {
+ xd->current_account = account_add( irc, prpl, handle, password );
+ if( server )
+ xd->current_account->server = g_strdup( server );
+ if( autoconnect )
+ /* Return value doesn't matter, since account_add() already sets
+ a default! */
+ sscanf( autoconnect, "%d", &xd->current_account->auto_connect );
+ }
+ else
+ {
+ /* Actually the _decode functions don't even return error codes,
+ but maybe they will later... */
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Error while decrypting account password" );
+ }
+
+ g_free( pass_rc4 );
+ g_free( password );
+ }
+ else if( g_strcasecmp( element_name, "setting" ) == 0 )
+ {
+ if( xd->current_account == NULL )
+ {
+ char *setting;
+
+ if( xd->current_setting )
+ {
+ g_free( xd->current_setting );
+ xd->current_setting = NULL;
+ }
+
+ if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
+ xd->current_setting = g_strdup( setting );
+ else
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Missing attributes for %s element", element_name );
+ }
+ }
+ else if( g_strcasecmp( element_name, "buddy" ) == 0 )
+ {
+ char *handle, *nick;
+
+ handle = xml_attr( attr_names, attr_values, "handle" );
+ nick = xml_attr( attr_names, attr_values, "nick" );
+
+ if( xd->current_account && handle && nick )
+ {
+ nick_set( irc, handle, xd->current_account->prpl, nick );
+ }
+ else
+ {
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Missing attributes for %s element", element_name );
+ }
+ }
+ else
+ {
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Unkown element: %s", element_name );
+ }
+}
+
+static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error )
+{
+ struct xml_parsedata *xd = data;
+
+ if( g_strcasecmp( element_name, "setting" ) == 0 && xd->current_setting )
+ {
+ g_free( xd->current_setting );
+ xd->current_setting = NULL;
+ }
+ else if( g_strcasecmp( element_name, "account" ) == 0 )
+ {
+ xd->current_account = NULL;
+ }
+}
+
+static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error )
+{
+ struct xml_parsedata *xd = data;
+ irc_t *irc = xd->irc;
+
+ if( xd->pass_st < XML_PASS_OK )
+ {
+ /* Let's not parse anything else if we only have to check
+ the password, or if we didn't get the chance to check it
+ yet. */
+ }
+ else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 &&
+ xd->current_setting && xd->current_account == NULL )
+ {
+ set_setstr( irc, xd->current_setting, (char*) text );
+ g_free( xd->current_setting );
+ xd->current_setting = NULL;
+ }
+}
+
+GMarkupParser xml_parser =
+{
+ xml_start_element,
+ xml_end_element,
+ xml_text,
+ NULL,
+ NULL
+};
+
+static void xml_init( void )
+{
+ if( access( global.conf->configdir, F_OK ) != 0 )
+ log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", CONFIG );
+ else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 )
+ log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir );
+}
+
+static storage_status_t xml_load_real( const char *my_nick, const char *password, irc_t *irc, xml_pass_st action )
+{
+ GMarkupParseContext *ctx;
+ struct xml_parsedata *xd;
+ char *fn, buf[512];
+ GError *gerr = NULL;
+ int fd, st;
+
+ if( irc && irc->status & USTATUS_IDENTIFIED )
+ return( 1 );
+
+ xd = g_new0( struct xml_parsedata, 1 );
+ xd->irc = irc;
+ xd->given_nick = g_strdup( my_nick );
+ xd->given_pass = g_strdup( password );
+ xd->pass_st = action;
+ nick_lc( xd->given_nick );
+
+ fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" );
+ if( ( fd = open( fn, O_RDONLY ) ) < 0 )
+ {
+ xml_destroy_xd( xd );
+ g_free( fn );
+ return STORAGE_NO_SUCH_USER;
+ }
+ g_free( fn );
+
+ ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd );
+
+ while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 )
+ {
+ if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr )
+ {
+ g_markup_parse_context_free( ctx );
+ close( fd );
+
+ /* Slightly dirty... */
+ if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 )
+ {
+ g_clear_error( &gerr );
+ return STORAGE_INVALID_PASSWORD;
+ }
+ else
+ {
+ if( gerr && irc )
+ irc_usermsg( irc, "Error from XML-parser: %s", gerr->message );
+
+ g_clear_error( &gerr );
+ return STORAGE_OTHER_ERROR;
+ }
+ }
+ }
+ /* Just to be sure... */
+ g_clear_error( &gerr );
+
+ g_markup_parse_context_free( ctx );
+ close( fd );
+
+ if( action == XML_PASS_CHECK_ONLY )
+ return STORAGE_OK;
+
+ irc->status |= USTATUS_IDENTIFIED;
+
+ if( set_getint( irc, "auto_connect" ) )
+ {
+ /* Can't do this directly because r_c_s alters the string */
+ strcpy( buf, "account on" );
+ root_command_string( irc, NULL, buf, 0 );
+ }
+
+ return STORAGE_OK;
+}
+
+static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc )
+{
+ return xml_load_real( my_nick, password, irc, XML_PASS_UNKNOWN );
+}
+
+static storage_status_t xml_check_pass( const char *my_nick, const char *password )
+{
+ /* This is a little bit risky because we have to pass NULL for the
+ irc_t argument. This *should* be fine, if I didn't miss anything... */
+ return xml_load_real( my_nick, password, NULL, XML_PASS_CHECK_ONLY );
+}
+
+static int xml_printf( int fd, char *fmt, ... )
+{
+ va_list params;
+ char *out;
+ int len;
+
+ va_start( params, fmt );
+ out = g_markup_vprintf_escaped( fmt, params );
+ va_end( params );
+
+ len = strlen( out );
+ len -= write( fd, out, len );
+ g_free( out );
+
+ return len == 0;
+}
+
+static storage_status_t xml_save( irc_t *irc, int overwrite )
+{
+ char path[512], *path2, *pass_buf = NULL;
+ set_t *set;
+ nick_t *nick;
+ account_t *acc;
+ int fd, i;
+ md5_byte_t pass_md5[21];
+ md5_state_t md5_state;
+
+ if( irc->password == NULL )
+ {
+ irc_usermsg( irc, "Please register yourself if you want to save your settings." );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, irc->nick, ".xml" );
+
+ if( !overwrite && access( path, F_OK ) != -1 )
+ return STORAGE_ALREADY_EXISTS;
+
+ strcat( path, "~" );
+ if( ( fd = open( path, O_WRONLY | O_CREAT, 0600 ) ) < 0 )
+ {
+ irc_usermsg( irc, "Error while opening configuration file." );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ /* Generate a salted md5sum of the password. Use 5 bytes for the salt
+ (to prevent dictionary lookups of passwords) to end up with a 21-
+ byte password hash, more convenient for base64 encoding. */
+ for( i = 0; i < 5; i ++ )
+ pass_md5[16+i] = rand() & 0xff;
+ md5_init( &md5_state );
+ md5_append( &md5_state, (md5_byte_t*) irc->password, strlen( irc->password ) );
+ md5_append( &md5_state, pass_md5 + 16, 5 ); /* Add the salt. */
+ md5_finish( &md5_state, pass_md5 );
+ /* Save the hash in base64-encoded form. */
+ pass_buf = base64_encode( (char*) pass_md5, 21 );
+
+ if( !xml_printf( fd, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) )
+ goto write_error;
+
+ g_free( pass_buf );
+
+ for( set = irc->set; set; set = set->next )
+ if( set->value && set->def )
+ if( !xml_printf( fd, "\t<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
+ goto write_error;
+
+ for( acc = irc->accounts; acc; acc = acc->next )
+ {
+ char *pass_rc4, *pass_b64;
+ int pass_len;
+
+ pass_len = rc4_encode( (unsigned char*) acc->pass, strlen( acc->pass ), (unsigned char**) &pass_rc4, irc->password );
+ pass_b64 = base64_encode( pass_rc4, pass_len );
+
+ if( !xml_printf( fd, "\t<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%d\"", acc->prpl->name, acc->user, pass_b64, acc->auto_connect ) )
+ {
+ g_free( pass_rc4 );
+ g_free( pass_b64 );
+ goto write_error;
+ }
+ g_free( pass_rc4 );
+ g_free( pass_b64 );
+
+ if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) )
+ goto write_error;
+ if( !xml_printf( fd, ">\n" ) )
+ goto write_error;
+
+ for( nick = irc->nicks; nick; nick = nick->next )
+ if( nick->proto == acc->prpl )
+ if( !xml_printf( fd, "\t\t<buddy handle=\"%s\" nick=\"%s\" />\n", nick->handle, nick->nick ) )
+ goto write_error;
+
+ if( !xml_printf( fd, "\t</account>\n" ) )
+ goto write_error;
+ }
+
+ if( !xml_printf( fd, "</user>\n" ) )
+ goto write_error;
+
+ close( fd );
+
+ path2 = g_strndup( path, strlen( path ) - 1 );
+ if( rename( path, path2 ) != 0 )
+ {
+ irc_usermsg( irc, "Error while renaming temporary configuration file." );
+
+ g_free( path2 );
+ unlink( path );
+
+ return STORAGE_OTHER_ERROR;
+ }
+
+ g_free( path2 );
+
+ return STORAGE_OK;
+
+write_error:
+ g_free( pass_buf );
+
+ irc_usermsg( irc, "Write error. Disk full?" );
+ close( fd );
+
+ return STORAGE_OTHER_ERROR;
+}
+
+static storage_status_t xml_remove( const char *nick, const char *password )
+{
+ char s[512];
+ storage_status_t status;
+
+ status = xml_check_pass( nick, password );
+ if( status != STORAGE_OK )
+ return status;
+
+ g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".xml" );
+ if( unlink( s ) == -1 )
+ return STORAGE_OTHER_ERROR;
+
+ return STORAGE_OK;
+}
+
+storage_t storage_xml = {
+ .name = "xml",
+ .init = xml_init,
+ .check_pass = xml_check_pass,
+ .remove = xml_remove,
+ .load = xml_load,
+ .save = xml_save
+};
diff --git a/unix.c b/unix.c
index 360281ee..23ae1b91 100644
--- a/unix.c
+++ b/unix.c
@@ -47,20 +47,18 @@ int main( int argc, char *argv[], char **envp )
memset( &global, 0, sizeof( global_t ) );
b_main_init();
-
log_init();
-
nogaim_init();
-
- CONF_FILE = g_strdup( CONF_FILE_DEF );
+ srand( time( NULL ) ^ getpid() );
+
+ CONF_FILE = g_strdup( CONF_FILE_DEF );
global.helpfile = g_strdup( HELP_FILE );
-
+
global.conf = conf_load( argc, argv );
if( global.conf == NULL )
return( 1 );
-
-
+
if( global.conf->runmode == RUNMODE_INETD )
{
i = bitlbee_inetd_init();
@@ -88,7 +86,7 @@ int main( int argc, char *argv[], char **envp )
}
if( i != 0 )
return( i );
-
+
global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
if ( global.storage == NULL) {
log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );