diff options
| -rw-r--r-- | .bzrignore | 2 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | bitlbee.c | 219 | ||||
| -rw-r--r-- | bitlbee.h | 4 | ||||
| -rw-r--r-- | commands.c | 94 | ||||
| -rw-r--r-- | conf.c | 6 | ||||
| -rw-r--r-- | conf.h | 1 | ||||
| -rw-r--r-- | crypting.c | 26 | ||||
| -rw-r--r-- | crypting.h | 3 | ||||
| -rw-r--r-- | irc.c | 20 | ||||
| -rw-r--r-- | irc.h | 1 | ||||
| -rw-r--r-- | storage.c | 58 | ||||
| -rw-r--r-- | storage.h | 58 | ||||
| -rw-r--r-- | storage_text.c | 313 | ||||
| -rw-r--r-- | unix.c | 16 | 
15 files changed, 512 insertions, 311 deletions
| @@ -7,3 +7,5 @@ help.txt  debian  build-arch-stamp  tags +decode +encode @@ -9,7 +9,7 @@  -include Makefile.settings  # Program variables -objects = account.o bitlbee.o commands.o conf.o crypting.o help.o ini.o irc.o log.o nick.o query.o set.o unix.o url.o user.o +objects = account.o bitlbee.o commands.o conf.o crypting.o help.o ini.o irc.o log.o nick.o query.o set.o unix.o url.o user.o storage_text.o storage.o  subdirs = protocols  # Expansion of variables @@ -26,7 +26,6 @@  #define BITLBEE_CORE  #include "bitlbee.h"  #include "commands.h" -#include "crypting.h"  #include "protocols/nogaim.h"  #include "help.h"  #include <signal.h> @@ -243,224 +242,6 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi  	}  } -int bitlbee_load( irc_t *irc, const char* password ) -{ -	char s[512]; -	char *line; -	int proto; -	char nick[MAX_NICK_LENGTH+1]; -	FILE *fp; -	user_t *ru = user_find( irc, ROOT_NICK ); -	 -	if( irc->status == USTATUS_IDENTIFIED ) -		return( 1 ); -	 -	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); -   	fp = fopen( s, "r" ); -   	if( !fp ) return( 0 ); -	 -	fscanf( fp, "%32[^\n]s", s ); -	if( setpass( irc, password, s ) < 0 ) -	{ -		fclose( fp ); -		return( -1 ); -	} -	 -	/* Do this now. If the user runs with AuthMode = Registered, the -	   account command will not work otherwise. */ -	irc->status = USTATUS_IDENTIFIED; -	 -	while( fscanf( fp, "%511[^\n]s", s ) > 0 ) -	{ -		fgetc( fp ); -		line = deobfucrypt( irc, s ); -		root_command_string( irc, ru, line, 0 ); -		g_free( line ); -	} -	fclose( fp ); -	 -	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); -	fp = fopen( s, "r" ); -	if( !fp ) return( 0 ); -	while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 ) -	{ -		http_decode( s ); -		nick_set( irc, s, proto, nick ); -	} -	fclose( fp ); -	 -	if( set_getint( irc, "auto_connect" ) ) -	{ -		strcpy( s, "account on" );	/* Can't do this directly because r_c_s alters the string */ -		root_command_string( irc, ru, s, 0 ); -	} -	 -	return( 1 ); -} - -int bitlbee_save( irc_t *irc ) -{ -	char s[512]; -	char path[512], new_path[512]; -	char *line; -	nick_t *n; -	set_t *set; -	mode_t ou = umask( 0077 ); -	account_t *a; -	FILE *fp; -	char *hash; -	 -	/*\ -	 *  [SH] Nothing should be saved if no password is set, because the -	 *  password is not set if it was wrong, or if one is not identified -	 *  yet. This means that a malicious user could easily overwrite -	 *  files owned by someone else: -	 *  a Bad Thing, methinks -	\*/ - -	/* [WVG] No? Really? */ - -	/*\ -	 *  [SH] Okay, okay, it wasn't really Wilmer who said that, it was -	 *  me. I just thought it was funny. -	\*/ -	 -	hash = hashpass( irc ); -	if( hash == NULL ) -	{ -		irc_usermsg( irc, "Please register yourself if you want to save your settings." ); -		return( 0 ); -	} -	 -	g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" ); -	fp = fopen( path, "w" ); -	if( !fp ) return( 0 ); -	for( n = irc->nicks; n; n = n->next ) -	{ -		strcpy( s, n->handle ); -		s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */ -		http_encode( s ); -		g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", n->proto, n->nick ); -		if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 ) -		{ -			irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); -			fclose( fp ); -			return( 0 ); -		} -	} -	if( fclose( fp ) != 0 ) -	{ -		irc_usermsg( irc, "fclose() reported an error. Disk full?" ); -		return( 0 ); -	} -   -	g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); -	if( unlink( new_path ) != 0 ) -	{ -		if( errno != ENOENT ) -		{ -			irc_usermsg( irc, "Error while removing old .nicks file" ); -			return( 0 ); -		} -	} -	if( rename( path, new_path ) != 0 ) -	{ -		irc_usermsg( irc, "Error while renaming new .nicks file" ); -		return( 0 ); -	} -	 -	g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" ); -	fp = fopen( path, "w" ); -	if( !fp ) return( 0 ); -	if( fprintf( fp, "%s", hash ) != strlen( hash ) ) -	{ -		irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); -		fclose( fp ); -		return( 0 ); -	} -	g_free( hash ); - -	for( a = irc->accounts; a; a = a->next ) -	{ -		if( a->protocol == PROTO_OSCAR || a->protocol == PROTO_ICQ || a->protocol == PROTO_TOC ) -			g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server ); -		else -			g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"", -			            proto_name[a->protocol], a->user, a->pass, a->server ? a->server : "" ); -		 -		line = obfucrypt( irc, s ); -		if( *line ) -		{ -			if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) -			{ -				irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); -				fclose( fp ); -				return( 0 ); -			} -		} -		g_free( line ); -	} -	 -	for( set = irc->set; set; set = set->next ) -	{ -		if( set->value && set->def ) -		{ -			g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value ); -			line = obfucrypt( irc, s ); -			if( *line ) -			{ -				if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) -				{ -					irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); -					fclose( fp ); -					return( 0 ); -				} -			} -			g_free( line ); -		} -	} -	 -	if( strcmp( irc->mynick, ROOT_NICK ) != 0 ) -	{ -		g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick ); -		line = obfucrypt( irc, s ); -		if( *line ) -		{ -			if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) -			{ -				irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); -				fclose( fp ); -				return( 0 ); -			} -		} -		g_free( line ); -	} -	if( fclose( fp ) != 0 ) -	{ -		irc_usermsg( irc, "fclose() reported an error. Disk full?" ); -		return( 0 ); -	} -	 - 	g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); - 	if( unlink( new_path ) != 0 ) -	{ -		if( errno != ENOENT ) -		{ -			irc_usermsg( irc, "Error while removing old .accounts file" ); -			return( 0 ); -		} -	} -	if( rename( path, new_path ) != 0 ) -	{ -		irc_usermsg( irc, "Error while renaming new .accounts file" ); -		return( 0 ); -	} -	 -	umask( ou ); -	 -	return( 1 ); -} -  void bitlbee_shutdown( gpointer data )  {  	/* Try to save data for all active connections (if desired). */ @@ -99,6 +99,7 @@  extern char *CONF_FILE;  #include "irc.h" +#include "storage.h"  #include "set.h"  #include "protocols/nogaim.h"  #include "commands.h" @@ -114,6 +115,7 @@ typedef struct global_t {  	int listen_socket;  	help_t *help;  	conf_t *conf; +	storage_t *storage;  	char *helpfile;  	GMainLoop *loop;  } global_t; @@ -126,8 +128,6 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi  int root_command_string( irc_t *irc, user_t *u, char *command, int flags );  int root_command( irc_t *irc, char *command[] ); -int bitlbee_load( irc_t *irc, const char *password ); -int bitlbee_save( irc_t *irc );  void bitlbee_shutdown( gpointer data );  double gettime( void );  G_MODULE_EXPORT void http_encode( char *s ); @@ -85,23 +85,21 @@ int cmd_help( irc_t *irc, char **cmd )  int cmd_identify( irc_t *irc, char **cmd )  { -	int checkie = bitlbee_load( irc, cmd[1] ); +	storage_status_t status = global.storage->load( irc->nick, cmd[1], irc ); -	if( checkie == -1 ) -	{ +	switch (status) { +	case STORAGE_INVALID_PASSWORD:  		irc_usermsg( irc, "Incorrect password" ); -	} -	else if( checkie == 0 ) -	{ +		break; +	case STORAGE_NO_SUCH_USER:  		irc_usermsg( irc, "The nick is (probably) not registered" ); -	} -	else if( checkie == 1 ) -	{ +		break; +	case STORAGE_OK:  		irc_usermsg( irc, "Password accepted" ); -	} -	else -	{ +		break; +	default:  		irc_usermsg( irc, "Something very weird happened" ); +		break;  	}  	return( 0 ); @@ -109,30 +107,25 @@ int cmd_identify( irc_t *irc, char **cmd )  int cmd_register( irc_t *irc, char **cmd )  { -	int checkie; -	char path[512]; -	  	if( global.conf->authmode == AUTHMODE_REGISTERED )  	{  		irc_usermsg( irc, "This server does not allow registering new accounts" );  		return( 0 );  	} -	 -	g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); -	checkie = access( path, F_OK ); -	 -	g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); -	checkie += access( path, F_OK ); -	 -	if( checkie == -2 ) -	{ -		setpassnc( irc, cmd[1] ); -		root_command_string( irc, user_find( irc, irc->mynick ), "save", 0 ); -		irc->status = USTATUS_IDENTIFIED; -	} -	else -	{ -		irc_usermsg( irc, "Nick is already registered" ); + +	irc_setpass( irc, cmd[1] ); +	switch( global.storage->save( irc, FALSE )) { +		case STORAGE_ALREADY_EXISTS: +			irc_usermsg( irc, "Nick is already registered" ); +			break; +			 +		case STORAGE_OK: +			irc->status = USTATUS_IDENTIFIED; +			break; + +		default: +			irc_usermsg( irc, "Error registering" ); +			break;  	}  	return( 0 ); @@ -140,35 +133,24 @@ int cmd_register( irc_t *irc, char **cmd )  int cmd_drop( irc_t *irc, char **cmd )  { -	char s[512]; -	FILE *fp; +	storage_status_t status; -	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); -	fp = fopen( s, "r" ); -	if( !fp ) -	{ +	status = global.storage->remove (irc->nick, cmd[1]); +	switch (status) { +	case STORAGE_NO_SUCH_USER:  		irc_usermsg( irc, "That account does not exist" );  		return( 0 ); -	} -	 -	fscanf( fp, "%32[^\n]s", s ); -	fclose( fp ); -	if( setpass( irc, cmd[1], s ) < 0 ) -	{ -		irc_usermsg( irc, "Incorrect password" ); +	case STORAGE_INVALID_PASSWORD: +		irc_usermsg( irc, "Password invalid" ); +		return( 0 ); +	case STORAGE_OK: +		irc_setpass( irc, NULL ); +		irc_usermsg( irc, "Account `%s' removed", irc->nick ); +		return( 0 ); +	default: +		irc_usermsg( irc, "Error: '%d'", status );  		return( 0 );  	} -	 -	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); -	unlink( s ); -	 -	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); -	unlink( s ); -	 -	setpassnc( irc, NULL ); -	irc_usermsg( irc, "Files belonging to account `%s' removed", irc->nick ); -	 -	return( 0 );  }  int cmd_account( irc_t *irc, char **cmd ) @@ -633,7 +615,7 @@ int cmd_set( irc_t *irc, char **cmd )  int cmd_save( irc_t *irc, char **cmd )  { -	if( bitlbee_save( irc ) ) +	if( global.storage->save( irc, TRUE ) == STORAGE_OK )  		irc_usermsg( irc, "Configuration saved" );  	else  		irc_usermsg( irc, "Configuration could not be saved!" ); @@ -49,6 +49,7 @@ conf_t *conf_load( int argc, char *argv[] )  	conf->port = 6667;  	conf->nofork = 0;  	conf->verbose = 0; +	conf->storage = "text";  	conf->runmode = RUNMODE_INETD;  	conf->authmode = AUTHMODE_OPEN;  	conf->password = NULL; @@ -197,6 +198,11 @@ static int conf_loadini( conf_t *conf, char *file )  				g_free( conf->motdfile );  				conf->motdfile = g_strdup( ini->value );  			} +			else if( g_strcasecmp( ini->key, "storage" ) == 0 ) +			{ +				g_free( conf->storage ); +				conf->storage = g_strdup( ini->value ); +			}  			else if( g_strcasecmp( ini->key, "pinginterval" ) == 0 )  			{  				if( sscanf( ini->value, "%d", &i ) != 1 ) @@ -41,6 +41,7 @@ typedef struct conf  	char *hostname;  	char *configdir;  	char *motdfile; +	char *storage;  	int ping_interval;  	int ping_timeout;  } conf_t; @@ -51,8 +51,6 @@ typedef struct irc  #include <stdio.h>  #include <stdlib.h> -#define irc_usermsg -  #endif  /*\ @@ -61,21 +59,7 @@ typedef struct irc   * correctness.  \*/ -/* USE WITH CAUTION! -   Sets pass without checking */ -void setpassnc (irc_t *irc, const char *pass)  -{ -	if (irc->password) g_free (irc->password); -	 -	if (pass) { -		irc->password = g_strdup (pass); -		irc_usermsg (irc, "Password successfully changed"); -	} else { -		irc->password = NULL; -	} -} - -int setpass (irc_t *irc, const char *pass, const char* md5sum)  +int checkpass (const char *pass, const char *md5sum)  {  	md5_state_t md5state;  	md5_byte_t digest[16]; @@ -93,13 +77,11 @@ int setpass (irc_t *irc, const char *pass, const char* md5sum)  		if (digits[0] != md5sum[j]) return (-1);  		if (digits[1] != md5sum[j + 1]) return (-1);  	} -	 -	/* If pass is correct, we end up here and we set the pass */ -	setpassnc (irc, pass); -	 -	return (0); + +	return( 0 );  } +  char *hashpass (irc_t *irc) {  	md5_state_t md5state;  	md5_byte_t digest[16]; @@ -23,8 +23,7 @@    Suite 330, Boston, MA  02111-1307  USA  */ -void setpassnc (irc_t *irc, const char *pass); /* USE WITH CAUTION! */ -int setpass (irc_t *irc, const char *pass, const char* md5sum); +int checkpass (const char *password, const char *md5sum);  char *hashpass (irc_t *irc);  char *obfucrypt (irc_t *irc, char *line);  char *deobfucrypt (irc_t *irc, char *line); @@ -31,9 +31,9 @@ static gboolean irc_userping( gpointer _irc );  GSList *irc_connection_list = NULL; -char *passchange (irc_t *irc, void *set, char *value)  +static char *passchange (irc_t *irc, void *set, char *value)   { -	setpassnc (irc, value); +	irc_setpass (irc, value);  	return (NULL);  } @@ -160,7 +160,7 @@ void irc_free(irc_t * irc)  	log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );  	if( irc->status >= USTATUS_IDENTIFIED && set_getint( irc, "save_on_quit" ) )  -		if( !bitlbee_save( irc ) ) +		if( !global.storage->save( irc, TRUE ) )  			irc_usermsg( irc, "Error while saving settings!" );  	if( irc->ping_source_id > 0 ) @@ -267,6 +267,20 @@ void irc_free(irc_t * irc)  		g_main_quit( global.loop );  } +/* USE WITH CAUTION! +   Sets pass without checking */ +void irc_setpass (irc_t *irc, const char *pass)  +{ +	if (irc->password) g_free (irc->password); +	 +	if (pass) { +		irc->password = g_strdup (pass); +		irc_usermsg (irc, "Password successfully changed"); +	} else { +		irc->password = NULL; +	} +} +  int irc_process( irc_t *irc )  {  	char **lines, *temp;	 @@ -136,6 +136,7 @@ void irc_kill( irc_t *irc, user_t *u );  void irc_invite( irc_t *irc, char *nick, char *channel );  void irc_whois( irc_t *irc, char *nick );  int irc_away( irc_t *irc, char *away ); +void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */  int irc_send( irc_t *irc, char *nick, char *s, int flags );  int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg ); diff --git a/storage.c b/storage.c new file mode 100644 index 00000000..8738a58f --- /dev/null +++ b/storage.c @@ -0,0 +1,58 @@ +  /********************************************************************\ +  * BitlBee -- An IRC to other IM-networks gateway                     * +  *                                                                    * +  * Copyright 2002-2004 Wilmer van der Gaast and others                * +  \********************************************************************/ + +/* Support for multiple storage backends */ + +/* +  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 "crypting.h" + +extern storage_t storage_text; + +static GList text_entry = { &storage_text, NULL, NULL }; +static GList *storage_backends = &text_entry; + +void register_storage_backend(storage_t *backend) +{ +	storage_backends = g_list_append(storage_backends, backend); +} + +storage_t *storage_init(const char *name) +{ +	GList *gl; +	storage_t *st; + +	for (gl = storage_backends; gl; gl = gl->next) { +		st = gl->data; +		if (strcmp(st->name, name) == 0) +			break; +	} + +	if (gl == NULL)  +		return NULL; + +	if (st->init) +		st->init(); + +	return st; +} diff --git a/storage.h b/storage.h new file mode 100644 index 00000000..3139d63b --- /dev/null +++ b/storage.h @@ -0,0 +1,58 @@ +  /********************************************************************\ +  * BitlBee -- An IRC to other IM-networks gateway                     * +  *                                                                    * +  * Copyright 2002-2004 Wilmer van der Gaast and others                * +  \********************************************************************/ + +/* Layer for retrieving and storing buddy information */ + +/* +  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 __STORAGE_H__ +#define __STORAGE_H__ + +typedef enum { +	STORAGE_OK = 0, +	STORAGE_NO_SUCH_USER, +	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 */ +} storage_status_t; + +typedef struct { +	const char *name; +	 +	/* May be set to NULL if not required */ +	void (*init) (void); + +	storage_status_t (*check_pass) (const char *nick, const char *password); + +	storage_status_t (*load) (const char *nick, const char *password, irc_t * irc); +	storage_status_t (*save) (irc_t *irc, int overwrite); +	storage_status_t (*remove) (const char *nick, const char *password); + +	/* May be NULL if not supported by backend */ +	storage_status_t (*rename) (const char *onick, const char *nnick, const char *password); +} storage_t; + +void register_storage_backend(storage_t *); +storage_t *storage_init(const char *name); + +#endif /* __STORAGE_H__ */ diff --git a/storage_text.c b/storage_text.c new file mode 100644 index 00000000..f3ca8a38 --- /dev/null +++ b/storage_text.c @@ -0,0 +1,313 @@ +  /********************************************************************\ +  * BitlBee -- An IRC to other IM-networks gateway                     * +  *                                                                    * +  * Copyright 2002-2004 Wilmer van der Gaast and others                * +  \********************************************************************/ + +/* Storage backend that uses the same file format as <=1.0 */ + +/* +  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 "crypting.h" + +static void text_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 text_load ( const char *my_nick, const char* password, irc_t *irc ) +{ +	char s[512]; +	char *line; +	int proto; +	char nick[MAX_NICK_LENGTH+1]; +	FILE *fp; +	user_t *ru = user_find( irc, ROOT_NICK ); +	 +	if( irc->status == USTATUS_IDENTIFIED ) +		return( 1 ); +	 +	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" ); +   	fp = fopen( s, "r" ); +   	if( !fp ) return STORAGE_NO_SUCH_USER; +	 +	fscanf( fp, "%32[^\n]s", s ); + +	if (checkpass (password, s) != 0)  +	{ +		fclose( fp ); +		return STORAGE_INVALID_PASSWORD; +	} +	 +	/* Do this now. If the user runs with AuthMode = Registered, the +	   account command will not work otherwise. */ +	irc->status = USTATUS_IDENTIFIED; +	 +	while( fscanf( fp, "%511[^\n]s", s ) > 0 ) +	{ +		fgetc( fp ); +		line = deobfucrypt( irc, s ); +		root_command_string( irc, ru, line, 0 ); +		g_free( line ); +	} +	fclose( fp ); +	 +	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" ); +	fp = fopen( s, "r" ); +	if( !fp ) return STORAGE_NO_SUCH_USER; +	while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 ) +	{ +		http_decode( s ); +		nick_set( irc, s, proto, nick ); +	} +	fclose( fp ); +	 +	if( set_getint( irc, "auto_connect" ) ) +	{ +		strcpy( s, "account on" );	/* Can't do this directly because r_c_s alters the string */ +		root_command_string( irc, ru, s, 0 ); +	} +	 +	return STORAGE_OK; +} + +static storage_status_t text_save( irc_t *irc, int overwrite ) +{ +	char s[512]; +	char path[512], new_path[512]; +	char *line; +	nick_t *n; +	set_t *set; +	mode_t ou = umask( 0077 ); +	account_t *a; +	FILE *fp; +	char *hash; + +	if (!overwrite) { +		g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); +		if (access( path, F_OK ) != -1) +			return STORAGE_ALREADY_EXISTS; +	 +		g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); +		if (access( path, F_OK ) != -1) +			return STORAGE_ALREADY_EXISTS; +	} +	 +	/*\ +	 *  [SH] Nothing should be saved if no password is set, because the +	 *  password is not set if it was wrong, or if one is not identified +	 *  yet. This means that a malicious user could easily overwrite +	 *  files owned by someone else: +	 *  a Bad Thing, methinks +	\*/ + +	/* [WVG] No? Really? */ + +	/*\ +	 *  [SH] Okay, okay, it wasn't really Wilmer who said that, it was +	 *  me. I just thought it was funny. +	\*/ +	 +	hash = hashpass( irc ); +	if( hash == NULL ) +	{ +		irc_usermsg( irc, "Please register yourself if you want to save your settings." ); +		return( 0 ); +	} +	 +	g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" ); +	fp = fopen( path, "w" ); +	if( !fp ) return STORAGE_OTHER_ERROR; +	for( n = irc->nicks; n; n = n->next ) +	{ +		strcpy( s, n->handle ); +		s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */ +		http_encode( s ); +		g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", n->proto, n->nick ); +		if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 ) +		{ +			irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); +			fclose( fp ); +			return STORAGE_OTHER_ERROR; +		} +	} +	if( fclose( fp ) != 0 ) +	{ +		irc_usermsg( irc, "fclose() reported an error. Disk full?" ); +		return STORAGE_OTHER_ERROR; +	} +   +	g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); +	if( unlink( new_path ) != 0 ) +	{ +		if( errno != ENOENT ) +		{ +			irc_usermsg( irc, "Error while removing old .nicks file" ); +			return STORAGE_OTHER_ERROR; +		} +	} +	if( rename( path, new_path ) != 0 ) +	{ +		irc_usermsg( irc, "Error while renaming new .nicks file" ); +		return STORAGE_OTHER_ERROR; +	} +	 +	g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" ); +	fp = fopen( path, "w" ); +	if( !fp ) return STORAGE_OTHER_ERROR; +	if( fprintf( fp, "%s", hash ) != strlen( hash ) ) +	{ +		irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); +		fclose( fp ); +		return STORAGE_OTHER_ERROR; +	} +	g_free( hash ); + +	for( a = irc->accounts; a; a = a->next ) +	{ +		if( a->protocol == PROTO_OSCAR || a->protocol == PROTO_ICQ || a->protocol == PROTO_TOC ) +			g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server ); +		else +			g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"", +			            proto_name[a->protocol], a->user, a->pass, a->server ? a->server : "" ); +		 +		line = obfucrypt( irc, s ); +		if( *line ) +		{ +			if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) +			{ +				irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); +				fclose( fp ); +				return STORAGE_OTHER_ERROR; +			} +		} +		g_free( line ); +	} +	 +	for( set = irc->set; set; set = set->next ) +	{ +		if( set->value && set->def ) +		{ +			g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value ); +			line = obfucrypt( irc, s ); +			if( *line ) +			{ +				if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) +				{ +					irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); +					fclose( fp ); +					return STORAGE_OTHER_ERROR; +				} +			} +			g_free( line ); +		} +	} +	 +	if( strcmp( irc->mynick, ROOT_NICK ) != 0 ) +	{ +		g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick ); +		line = obfucrypt( irc, s ); +		if( *line ) +		{ +			if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) +			{ +				irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); +				fclose( fp ); +				return STORAGE_OTHER_ERROR; +			} +		} +		g_free( line ); +	} +	if( fclose( fp ) != 0 ) +	{ +		irc_usermsg( irc, "fclose() reported an error. Disk full?" ); +		return STORAGE_OTHER_ERROR; +	} +	 + 	g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); + 	if( unlink( new_path ) != 0 ) +	{ +		if( errno != ENOENT ) +		{ +			irc_usermsg( irc, "Error while removing old .accounts file" ); +			return STORAGE_OTHER_ERROR; +		} +	} +	if( rename( path, new_path ) != 0 ) +	{ +		irc_usermsg( irc, "Error while renaming new .accounts file" ); +		return STORAGE_OTHER_ERROR; +	} +	 +	umask( ou ); +	 +	return STORAGE_OK; +} + +static storage_status_t text_check_pass( const char *nick, const char *password ) +{ +	char s[512]; +	FILE *fp; +	 +	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" ); +	fp = fopen( s, "r" ); +	if (!fp) +		return STORAGE_NO_SUCH_USER; + +	fscanf( fp, "%32[^\n]s", s ); +	fclose( fp ); + +	if (checkpass( password, s) == -1) +		return STORAGE_INVALID_PASSWORD; + +	return STORAGE_OK; +} + +static storage_status_t text_remove( const char *nick, const char *password ) +{ +	char s[512]; +	storage_status_t status; + +	status = text_check_pass( nick, password ); +	if (status != STORAGE_OK) +		return status; + +	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" ); +	if (unlink( s ) == -1) +		return STORAGE_OTHER_ERROR; +	 +	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" ); +	if (unlink( s ) == -1) +		return STORAGE_OTHER_ERROR; + +	return STORAGE_OK; +} + +storage_t storage_text = { +	.name = "text", +	.init = text_init, +	.check_pass = text_check_pass, +	.remove = text_remove, +	.load = text_load, +	.save = text_save +}; @@ -51,11 +51,12 @@ int main( int argc, char *argv[] )  	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(); @@ -69,6 +70,13 @@ int main( int argc, char *argv[] )  	}  	if( i != 0 )  		return( i ); + +	global.storage = storage_init( global.conf->storage ); +	if ( global.storage == NULL) { +		log_message( LOGLVL_ERROR, "No such storage backend '%s'", global.conf->storage ); +		return( 1 ); +	} +	  	/* Catch some signals to tell the user what's happening before quitting */  	memset( &sig, 0, sizeof( sig ) ); @@ -86,10 +94,6 @@ int main( int argc, char *argv[] )  	if( !getuid() || !geteuid() )  		log_message( LOGLVL_WARNING, "BitlBee is running with root privileges. Why?" ); -	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 );  	if( help_init( &(global.help) ) == NULL )  		log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE ); | 
