From a312b6bcbc6aa836850d94fc2abc70ceffe275cd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 7 Jun 2006 13:25:46 +0200 Subject: Added storage_xml.c --- storage_xml.c | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 storage_xml.c (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c new file mode 100644 index 00000000..b27e63ad --- /dev/null +++ b/storage_xml.c @@ -0,0 +1,412 @@ + /********************************************************************\ + * 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" + +struct xml_parsedata +{ + irc_t *irc; + char *current_setting; + account_t *current_account; +}; + +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 attr_values[i]; + + return NULL; +} + +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 = data->irc; + + if( g_strcasecmp( element_name, "user" ) == 0 ) + { + char *nick = xml_attr( attr_names, attr_values, "nick" ); + + if( nick && g_strcasecmp( nick, irc->nick ) == 0 ) + { + /* Okay! */ + } + } + else if( g_strcasecmp( element_name, "account" ) == 0 ) + { + char *protocol, *handle, *password; + struct prpl *prpl = NULL; + + handle = xml_attr( attr_names, attr_values, "handle" ); + password = xml_attr( attr_names, attr_values, "password" ); + + protocol = xml_attr( attr_names, attr_values, "protocol" ); + if( protocol ) + prpl = find_protocol( protocol ); + + if( handle && password && prpl ) + { + xd->current_account = account_add( irc, prpl, handle, password ) + } + } + else if( g_strcasecmp( element_name, "setting" ) == 0 ) + { + if( xd->current_account == NULL ) + { + current_setting = xml_attr( attr_names, attr_values, "name" ); + } + } + else if( g_strcasecmp( element_name, "buddy" ) == 0 ) + { + } + else if( g_strcasecmp( element_name, "password" ) == 0 ) + { + } + else + { + /* Return "unknown element" error. */ + } +} + +static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) +{ +} + +static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) +{ + struct xml_parsedata *xd = data; + irc_t *irc = data->irc; + + if( xd->current_setting ) + { + set_setstr( irc, xd->current_setting, text ); + } +} + +static void xml_error( GMarkupParseContext *ctx, GError *error, gpointer data ) +{ +} + +GMarkupParser xml_parser = +{ + xml_start_element, + xml_end_element, + xml_text, + NULL, + xml_error +}; + +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 ( const char *my_nick, const char* password, irc_t *irc ) +{ + GMarkupParseContext *ctx; + + ctx = g_markup_parse_context_new( parser, 0, xd, NULL ); + 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( s, password ); + if (line == NULL) return STORAGE_OTHER_ERROR; + 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 ) + { + struct prpl *prpl; + + prpl = find_protocol_by_id(proto); + + if (!prpl) + continue; + + http_decode( s ); + nick_set( irc, s, prpl, 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->password ); + if( hash == NULL ) + { + irc_usermsg( irc, "Please register yourself if you want to save your settings." ); + return STORAGE_OTHER_ERROR; + } + + 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", find_protocol_id(n->proto->name), 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( !strcmp(a->prpl->name, "oscar") ) + 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\"", + a->prpl->name, a->user, a->pass, a->server ? a->server : "" ); + + line = obfucrypt( s, irc->password ); + 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( s, irc->password ); + 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( s, irc->password ); + 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, ".accounts" ); + 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_xml = { + .name = "xml", + .init = xml_init, + .check_pass = xml_check_pass, + .remove = xml_remove, + .load = xml_load, + .save = xml_save +}; -- cgit v1.2.3 From c121f8945f7249520342ad86ff00f4986642ca0a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 14 Jun 2006 22:30:25 +0200 Subject: xml_load() works pretty well now. --- storage_xml.c | 390 ++++++++++++++++++++-------------------------------------- 1 file changed, 135 insertions(+), 255 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index b27e63ad..29c01e07 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -26,11 +26,23 @@ #define BITLBEE_CORE #include "bitlbee.h" +typedef enum +{ + XML_PASS_CHECK_ONLY = -1, + XML_PASS_UNKNOWN = 0, + XML_PASS_OK +} xml_pass_st; + +#define XML_PASS_ERRORMSG "Wrong username or password" + 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 ) @@ -39,58 +51,118 @@ static char *xml_attr( const gchar **attr_names, const gchar **attr_values, cons for( i = 0; attr_names[i]; i ++ ) if( g_strcasecmp( attr_names[i], key ) == 0 ) - return attr_values[i]; + 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 = data->irc; + 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" ); - if( nick && g_strcasecmp( nick, irc->nick ) == 0 ) + if( !nick || !pass ) { - /* Okay! */ + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); } + else if( strcmp( nick, xd->given_nick ) == 0 && + strcmp( pass, xd->given_pass ) == 0 ) + { + if( xd->pass_st != XML_PASS_CHECK_ONLY ) + xd->pass_st = XML_PASS_OK; + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + XML_PASS_ERRORMSG ); + } + } + 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, *password; + char *protocol, *handle, *server, *password; struct prpl *prpl = NULL; handle = xml_attr( attr_names, attr_values, "handle" ); password = xml_attr( attr_names, attr_values, "password" ); + server = xml_attr( attr_names, attr_values, "server" ); protocol = xml_attr( attr_names, attr_values, "protocol" ); if( protocol ) prpl = find_protocol( protocol ); - if( handle && password && prpl ) + if( !handle || !password ) + 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, + "Missing or unknown protocol %s element", element_name ); + else { - xd->current_account = account_add( irc, prpl, handle, password ) + xd->current_account = account_add( irc, prpl, handle, password ); + if( server ) + xd->current_account->server = g_strdup( server ); } } else if( g_strcasecmp( element_name, "setting" ) == 0 ) { if( xd->current_account == NULL ) { - current_setting = xml_attr( attr_names, attr_values, "name" ); + 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 ) { - } - else if( g_strcasecmp( element_name, "password" ) == 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 { - /* Return "unknown element" error. */ + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unkown element: %s", element_name ); } } @@ -101,11 +173,19 @@ static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) { struct xml_parsedata *xd = data; - irc_t *irc = data->irc; + irc_t *irc = xd->irc; - if( xd->current_setting ) + 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( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && + xd->current_setting && xd->current_account == NULL ) { - set_setstr( irc, xd->current_setting, text ); + set_setstr( irc, xd->current_setting, (char*) text ); + g_free( xd->current_setting ); + xd->current_setting = NULL; } } @@ -130,79 +210,66 @@ static void xml_init( void ) log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); } -static storage_status_t xml_load ( const char *my_nick, const char* password, irc_t *irc ) +static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc ) { GMarkupParseContext *ctx; + struct xml_parsedata *xd; + char *fn, buf[512]; + GError *gerr = NULL; + int fd, st; - ctx = g_markup_parse_context_new( parser, 0, xd, NULL ); 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; + xd = g_new0( struct xml_parsedata, 1 ); + xd->irc = irc; + xd->given_nick = g_strdup( my_nick ); + xd->given_pass = g_strdup( password ); + nick_lc( xd->given_nick ); - fscanf( fp, "%32[^\n]s", s ); - - if (checkpass (password, s) != 0) + fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" ); + if( ( fd = open( fn, O_RDONLY ) ) < 0 ) { - fclose( fp ); - return STORAGE_INVALID_PASSWORD; + xml_destroy_xd( xd ); + g_free( fn ); + return STORAGE_NO_SUCH_USER; } + g_free( fn ); - /* Do this now. If the user runs with AuthMode = Registered, the - account command will not work otherwise. */ - irc->status = USTATUS_IDENTIFIED; + ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd ); - while( fscanf( fp, "%511[^\n]s", s ) > 0 ) + while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 ) { - fgetc( fp ); - line = deobfucrypt( s, password ); - if (line == NULL) return STORAGE_OTHER_ERROR; - root_command_string( irc, ru, line, 0 ); - g_free( line ); + if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr ) + { + g_markup_parse_context_free( ctx ); + + /* TODO: Display useful error msg */ + + if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 ) + return STORAGE_INVALID_PASSWORD; + else + return STORAGE_OTHER_ERROR; + } } - 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 ) - { - struct prpl *prpl; - - prpl = find_protocol_by_id(proto); - - if (!prpl) - continue; - - http_decode( s ); - nick_set( irc, s, prpl, nick ); - } - fclose( fp ); + g_markup_parse_context_free( ctx ); + + irc->status = USTATUS_IDENTIFIED; 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 ); + /* 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 text_save( irc_t *irc, int overwrite ) +static storage_status_t xml_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) { +/* 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; @@ -211,202 +278,15 @@ static storage_status_t text_save( irc_t *irc, int overwrite ) 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->password ); - if( hash == NULL ) - { - irc_usermsg( irc, "Please register yourself if you want to save your settings." ); - return STORAGE_OTHER_ERROR; - } - - 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", find_protocol_id(n->proto->name), 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( !strcmp(a->prpl->name, "oscar") ) - 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\"", - a->prpl->name, a->user, a->pass, a->server ? a->server : "" ); - - line = obfucrypt( s, irc->password ); - 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( s, irc->password ); - 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( s, irc->password ); - 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, ".accounts" ); - 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_xml = { .name = "xml", .init = xml_init, - .check_pass = xml_check_pass, - .remove = xml_remove, +// .check_pass = xml_check_pass, +// .remove = xml_remove, .load = xml_load, .save = xml_save }; -- cgit v1.2.3 From d28f3b35855c8f8de0be9589334004b30d1ac394 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 19 Jun 2006 01:07:28 +0200 Subject: Now saving the password's md5sum instead of the plaintext version. --- storage_xml.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 5eda46cc..12afe472 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -25,6 +25,7 @@ #define BITLBEE_CORE #include "bitlbee.h" +#include "md5.h" typedef enum { @@ -80,16 +81,35 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Missing attributes for %s element", element_name ); } - else if( strcmp( nick, xd->given_nick ) == 0 && - strcmp( pass, xd->given_pass ) == 0 ) - { - if( xd->pass_st != XML_PASS_CHECK_ONLY ) - xd->pass_st = XML_PASS_OK; - } else { - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - XML_PASS_ERRORMSG ); + md5_byte_t pass_md5[16]; + md5_state_t md5_state; + int pass_match, i, j; + + md5_init( &md5_state ); + md5_append( &md5_state, xd->given_pass, strlen( xd->given_pass ) ); + md5_finish( &md5_state, pass_md5 ); + + for( i = 0; i < 16 && pass[i*2] && pass[i*2+1]; i ++ ) + { + sscanf( pass + i * 2, "%2x", &j ); + if( j != pass_md5[i] ) + break; + } + /* If we reached the end of the loop, it was a match! */ + pass_match = i == 16; + + if( strcmp( nick, xd->given_nick ) == 0 && pass_match ) + { + if( xd->pass_st != XML_PASS_CHECK_ONLY ) + xd->pass_st = XML_PASS_OK; + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + XML_PASS_ERRORMSG ); + } } } else if( xd->pass_st < XML_PASS_OK ) -- cgit v1.2.3 From d028a77c97eeccc8d1345af008e2d8920116b637 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 19 Jun 2006 13:52:34 +0200 Subject: Better detection of incorrect MD5 password hashes. --- storage_xml.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 12afe472..ff8f1351 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -85,31 +85,35 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { md5_byte_t pass_md5[16]; md5_state_t md5_state; - int pass_match, i, j; + int i, j; md5_init( &md5_state ); - md5_append( &md5_state, xd->given_pass, strlen( xd->given_pass ) ); + md5_append( &md5_state, (md5_byte_t*) xd->given_pass, strlen( xd->given_pass ) ); md5_finish( &md5_state, pass_md5 ); - for( i = 0; i < 16 && pass[i*2] && pass[i*2+1]; i ++ ) + for( i = 0; i < 16; i ++ ) { - sscanf( pass + i * 2, "%2x", &j ); + if( !isxdigit( pass[i*2] ) || !isxdigit( pass[i*2+1] ) || + sscanf( pass + i * 2, "%2x", &j ) != 1 ) + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Incorrect password MD5-hash" ); + break; + } if( j != 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! */ - pass_match = i == 16; - if( strcmp( nick, xd->given_nick ) == 0 && pass_match ) + /* 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; } - else - { - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - XML_PASS_ERRORMSG ); - } } } else if( xd->pass_st < XML_PASS_OK ) -- cgit v1.2.3 From 84e9cea2a80d4e8b05bbadbde923301685d05497 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 20 Jun 2006 23:36:53 +0200 Subject: Added xml_remove() and xml_check_pass(). --- storage_xml.c | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index ff8f1351..57388f67 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -34,6 +34,8 @@ typedef enum 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" struct xml_parsedata @@ -193,7 +195,6 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) { struct xml_parsedata *xd = data; - // irc_t *irc = xd->irc; if( g_strcasecmp( element_name, "setting" ) == 0 && xd->current_setting ) { @@ -214,7 +215,8 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_le if( xd->pass_st < XML_PASS_OK ) { /* Let's not parse anything else if we only have to check - the password. */ + 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 ) @@ -242,7 +244,7 @@ static void xml_init( void ) log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); } -static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc ) +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; @@ -250,13 +252,14 @@ static storage_status_t xml_load( const char *my_nick, const char *password, irc GError *gerr = NULL; int fd, st; - if( irc->status & USTATUS_IDENTIFIED ) + 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" ); @@ -282,7 +285,7 @@ static storage_status_t xml_load( const char *my_nick, const char *password, irc return STORAGE_INVALID_PASSWORD; else { - if( gerr ) + if( gerr && irc ) irc_usermsg( irc, "Error from XML-parser: %s", gerr->message ); return STORAGE_OTHER_ERROR; @@ -293,6 +296,9 @@ static storage_status_t xml_load( const char *my_nick, const char *password, irc 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" ) ) @@ -305,6 +311,18 @@ static storage_status_t xml_load( const char *my_nick, const char *password, irc 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; @@ -395,11 +413,27 @@ write_error: 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, + .check_pass = xml_check_pass, + .remove = xml_remove, .load = xml_load, .save = xml_save }; -- cgit v1.2.3 From ece2cd2eba78088a8cf9d4744aafb3f34dc97c5b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 20 Jun 2006 23:48:28 +0200 Subject: xml_save() now stores the password's md5sum too. Kind of ... important.. --- storage_xml.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 57388f67..87fbb693 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -342,11 +342,19 @@ static int xml_printf( int fd, char *fmt, ... ) static storage_status_t xml_save( irc_t *irc, int overwrite ) { - char path[512], *path2; + char path[512], *path2, md5_buf[33]; set_t *set; nick_t *nick; account_t *acc; - int fd; + int fd, i; + md5_byte_t pass_md5[16]; + 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" ); @@ -360,7 +368,13 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_OTHER_ERROR; } - if( !xml_printf( fd, "\n", irc->nick, irc->password ) ) + md5_init( &md5_state ); + md5_append( &md5_state, (md5_byte_t*) irc->password, strlen( irc->password ) ); + md5_finish( &md5_state, pass_md5 ); + for( i = 0; i < 16; i ++ ) + g_snprintf( md5_buf + i * 2, 3, "%02x", pass_md5[i] ); + + if( !xml_printf( fd, "\n", irc->nick, md5_buf ) ) goto write_error; for( set = irc->set; set; set = set->next ) -- cgit v1.2.3 From 9b46b64b83314a177a7ca3f9f990ff8c78282a5a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 21 Jun 2006 00:05:04 +0200 Subject: Fixed error message for unknown protocols. --- storage_xml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 87fbb693..737f2091 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -136,12 +136,12 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na if( protocol ) prpl = find_protocol( protocol ); - if( !handle || !password ) + if( !handle || !password || !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, - "Missing or unknown protocol %s element", element_name ); + "Unknown protocol: %s", protocol ); else { xd->current_account = account_add( irc, prpl, handle, password ); -- cgit v1.2.3 From 2b14eef99faf7e113cc6c17d68bf6402f87ddd66 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 21 Jun 2006 00:14:46 +0200 Subject: Implemented handling of autoconnect attribute. --- storage_xml.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 737f2091..69e991d2 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -125,12 +125,13 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na } else if( g_strcasecmp( element_name, "account" ) == 0 ) { - char *protocol, *handle, *server, *password; + char *protocol, *handle, *server, *password, *autoconnect; struct prpl *prpl = NULL; handle = xml_attr( attr_names, attr_values, "handle" ); password = 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 ) @@ -147,6 +148,10 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na 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 if( g_strcasecmp( element_name, "setting" ) == 0 ) @@ -384,7 +389,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) for( acc = irc->accounts; acc; acc = acc->next ) { - if( !xml_printf( fd, "\tprpl->name, acc->user, acc->pass, "yes" ) ) + if( !xml_printf( fd, "\tprpl->name, acc->user, acc->pass, acc->auto_connect ) ) goto write_error; if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) ) goto write_error; -- cgit v1.2.3 From 00ab35016e3646aa936ae0c3d7a8531ec68d6f24 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 21 Jun 2006 19:14:49 +0200 Subject: Fixed GError memory leak, correctly setting the migrate_storage default. --- storage_xml.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 69e991d2..41a50d8c 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -287,16 +287,22 @@ static storage_status_t xml_load_real( const char *my_nick, const char *password /* 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 ); -- cgit v1.2.3 From 6e1fed7057ee26f21b0e59a5aeb292d4f3f0e8ae Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 19:07:25 +0200 Subject: Using salted MD5 checksums for the user's BitlBee password and salted RC4 encryption for the IM account passwords, plus some calls to srand() to keep the salts secure and unique. --- storage_xml.c | 77 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 18 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 41a50d8c..35d74935 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -25,6 +25,8 @@ #define BITLBEE_CORE #include "bitlbee.h" +#include "base64.h" +#include "rc4.h" #include "md5.h" typedef enum @@ -77,32 +79,32 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { 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, j; + 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( !isxdigit( pass[i*2] ) || !isxdigit( pass[i*2+1] ) || - sscanf( pass + i * 2, "%2x", &j ) != 1 ) - { - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - "Incorrect password MD5-hash" ); - break; - } - if( j != pass_md5[i] ) + if( pass_dec[i] != pass_md5[i] ) { g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, XML_PASS_ERRORMSG ); @@ -117,6 +119,8 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na xd->pass_st = XML_PASS_OK; } } + + g_free( pass_dec ); } else if( xd->pass_st < XML_PASS_OK ) { @@ -126,10 +130,12 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na else if( g_strcasecmp( element_name, "account" ) == 0 ) { char *protocol, *handle, *server, *password, *autoconnect; + char *pass_b64 = NULL, *pass_rc4 = NULL; + int pass_len; struct prpl *prpl = NULL; handle = xml_attr( attr_names, attr_values, "handle" ); - password = xml_attr( attr_names, attr_values, "password" ); + 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" ); @@ -137,13 +143,15 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na if( protocol ) prpl = find_protocol( protocol ); - if( !handle || !password || !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 + 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 ) @@ -153,6 +161,16 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na 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 ) { @@ -353,12 +371,12 @@ static int xml_printf( int fd, char *fmt, ... ) static storage_status_t xml_save( irc_t *irc, int overwrite ) { - char path[512], *path2, md5_buf[33]; + char path[512], *path2, *pass_buf = NULL; set_t *set; nick_t *nick; account_t *acc; int fd, i; - md5_byte_t pass_md5[16]; + md5_byte_t pass_md5[21]; md5_state_t md5_state; if( irc->password == NULL ) @@ -379,15 +397,23 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) 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 ); - for( i = 0; i < 16; i ++ ) - g_snprintf( md5_buf + i * 2, 3, "%02x", pass_md5[i] ); + /* Save the hash in base64-encoded form. */ + pass_buf = base64_encode( (char*) pass_md5, 21 ); - if( !xml_printf( fd, "\n", irc->nick, md5_buf ) ) + if( !xml_printf( fd, "\n", irc->nick, pass_buf ) ) 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%s\n", set->key, set->value ) ) @@ -395,8 +421,21 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) for( acc = irc->accounts; acc; acc = acc->next ) { - if( !xml_printf( fd, "\tprpl->name, acc->user, acc->pass, acc->auto_connect ) ) + 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, "\tprpl->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" ) ) @@ -432,6 +471,8 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_OK; write_error: + g_free( pass_buf ); + irc_usermsg( irc, "Write error. Disk full?" ); close( fd ); -- 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. --- storage_xml.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 35d74935..0bbcd99a 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -39,6 +39,7 @@ typedef enum /* 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 { @@ -409,7 +410,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) /* Save the hash in base64-encoded form. */ pass_buf = base64_encode( (char*) pass_md5, 21 ); - if( !xml_printf( fd, "\n", irc->nick, pass_buf ) ) + if( !xml_printf( fd, "\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) ) goto write_error; g_free( pass_buf ); -- cgit v1.2.3 From 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 20:25:13 +0200 Subject: Forgot to initialize pass_rc4 (which caused memory management mess when trying to load a damaged XML-file). --- storage_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 0bbcd99a..7d72c781 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -130,7 +130,7 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na } else if( g_strcasecmp( element_name, "account" ) == 0 ) { - char *protocol, *handle, *server, *password, *autoconnect; + char *protocol, *handle, *server, *password = NULL, *autoconnect; char *pass_b64 = NULL, *pass_rc4 = NULL; int pass_len; struct prpl *prpl = NULL; -- cgit v1.2.3 From c9f0c79af4d1d02e3e37c3d98c0ed33355bce113 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Jun 2006 14:04:21 +0200 Subject: Implemented cleaner way of passing the "Incorrect password" error. --- storage_xml.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 7d72c781..20f3c6a9 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -33,12 +33,11 @@ typedef enum { XML_PASS_CHECK_ONLY = -1, XML_PASS_UNKNOWN = 0, + XML_PASS_WRONG, 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" +/* To make it easier later when extending the format: */ #define XML_FORMAT_VERSION 1 struct xml_parsedata @@ -107,8 +106,9 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { if( pass_dec[i] != pass_md5[i] ) { + xd->pass_st = XML_PASS_WRONG; g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - XML_PASS_ERRORMSG ); + "Password mismatch" ); break; } } @@ -301,11 +301,12 @@ static storage_status_t xml_load_real( const char *my_nick, const char *password { if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr ) { + xml_pass_st pass_st = xd->pass_st; + g_markup_parse_context_free( ctx ); close( fd ); - /* Slightly dirty... */ - if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 ) + if( pass_st == XML_PASS_WRONG ) { g_clear_error( &gerr ); return STORAGE_INVALID_PASSWORD; @@ -331,6 +332,7 @@ static storage_status_t xml_load_real( const char *my_nick, const char *password irc->status |= USTATUS_IDENTIFIED; + /* TODO: This really shouldn't be here, I think... */ if( set_getint( irc, "auto_connect" ) ) { /* Can't do this directly because r_c_s alters the string */ -- cgit v1.2.3 From 90bbb0efeae19bcc6a1096d8c89fbf3981c83503 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Jun 2006 18:50:47 +0200 Subject: Moved the call to "account on" to the right place. --- storage_xml.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 20f3c6a9..cc3498af 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -332,14 +332,6 @@ static storage_status_t xml_load_real( const char *my_nick, const char *password irc->status |= USTATUS_IDENTIFIED; - /* TODO: This really shouldn't be here, I think... */ - 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; } -- 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. --- storage_xml.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index cc3498af..5a8b51ef 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -370,7 +370,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) set_t *set; nick_t *nick; account_t *acc; - int fd, i; + int fd; md5_byte_t pass_md5[21]; md5_state_t md5_state; @@ -395,8 +395,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) /* 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; + random_bytes( pass_md5 + 16, 5 ); 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. */ -- cgit v1.2.3 From 5c9512ffa716f2bc8bbf9e2c31ee40624a0ff842 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 30 Jun 2006 11:17:18 +0200 Subject: Made set.c API more generic so it's not specific to irc_t structures anymore, but can be used for account_t structures too, for example. --- storage_xml.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 5a8b51ef..e0ffc481 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -245,7 +245,7 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_le 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 ); + set_setstr( &irc->set, xd->current_setting, (char*) text ); g_free( xd->current_setting ); xd->current_setting = NULL; } @@ -420,14 +420,13 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) 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 ); + g_free( pass_rc4 ); if( !xml_printf( fd, "\tprpl->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 ) ) -- 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. --- storage_xml.c | 65 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 30 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index e0ffc481..701d5144 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -156,11 +156,9 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { xd->current_account = account_add( irc, prpl, handle, password ); if( server ) - xd->current_account->server = g_strdup( server ); + set_setstr( &xd->current_account->set, "server", server ); if( autoconnect ) - /* Return value doesn't matter, since account_add() already sets - a default! */ - sscanf( autoconnect, "%d", &xd->current_account->auto_connect ); + set_setstr( &xd->current_account->set, "auto_connect", autoconnect ); } else { @@ -175,22 +173,19 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na } else if( g_strcasecmp( element_name, "setting" ) == 0 ) { - if( xd->current_account == NULL ) + char *setting; + + if( xd->current_setting ) { - 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 ); + 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 ) { @@ -242,10 +237,10 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_le 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 ) + else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting ) { - set_setstr( &irc->set, xd->current_setting, (char*) text ); + set_setstr( xd->current_account ? &xd->current_account->set : &irc->set, + xd->current_setting, (char*) text ); g_free( xd->current_setting ); xd->current_setting = NULL; } @@ -347,12 +342,17 @@ static storage_status_t xml_check_pass( const char *my_nick, const char *passwor return xml_load_real( my_nick, password, NULL, XML_PASS_CHECK_ONLY ); } -static int xml_printf( int fd, char *fmt, ... ) +static int xml_printf( int fd, int indent, char *fmt, ... ) { va_list params; char *out; + char tabs[9] = "\t\t\t\t\t\t\t\t"; int len; + /* Maybe not very clean, but who needs more than 8 levels of indentation anyway? */ + if( write( fd, tabs, indent <= 8 ? indent : 8 ) != indent ) + return 0; + va_start( params, fmt ); out = g_markup_vprintf_escaped( fmt, params ); va_end( params ); @@ -403,14 +403,14 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) /* Save the hash in base64-encoded form. */ pass_buf = base64_encode( (char*) pass_md5, 21 ); - if( !xml_printf( fd, "\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) ) + if( !xml_printf( fd, 0, "\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%s\n", set->key, set->value ) ) + if( !xml_printf( fd, 1, "%s\n", set->key, set->value ) ) goto write_error; for( acc = irc->accounts; acc; acc = acc->next ) @@ -422,28 +422,33 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) pass_b64 = base64_encode( pass_rc4, pass_len ); g_free( pass_rc4 ); - if( !xml_printf( fd, "\tprpl->name, acc->user, pass_b64, acc->auto_connect ) ) + if( !xml_printf( fd, 1, "prpl->name, acc->user, pass_b64, acc->auto_connect ) ) { g_free( pass_b64 ); goto write_error; } g_free( pass_b64 ); - if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) ) + if( acc->server && acc->server[0] && !xml_printf( fd, 0, " server=\"%s\"", acc->server ) ) goto write_error; - if( !xml_printf( fd, ">\n" ) ) + if( !xml_printf( fd, 0, ">\n" ) ) goto write_error; + for( set = acc->set; set; set = set->next ) + if( set->value && set->def && !( set->flags & ACC_SET_NOSAVE ) ) + if( !xml_printf( fd, 2, "%s\n", set->key, set->value ) ) + goto write_error; + for( nick = irc->nicks; nick; nick = nick->next ) if( nick->proto == acc->prpl ) - if( !xml_printf( fd, "\t\t\n", nick->handle, nick->nick ) ) + if( !xml_printf( fd, 2, "\n", nick->handle, nick->nick ) ) goto write_error; - if( !xml_printf( fd, "\t\n" ) ) + if( !xml_printf( fd, 1, "\n" ) ) goto write_error; } - if( !xml_printf( fd, "\n" ) ) + if( !xml_printf( fd, 0, "\n" ) ) goto write_error; close( fd ); -- cgit v1.2.3 From 5b52a4895e5a59ff6509f7771f4d8665737688c3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 3 Jul 2006 23:22:45 +0200 Subject: Implemented per-account nick lists instead of per-protocol nick lists. nick_t is dead, instead nicks are just saves in a per-account_t GLib hash table. While doing this, the import_buddies command finally died and text_save() disappeared, because the old file format can't handle most of the new features in this branch anyway. Still have to implement support for the new nick lists in text_load()! --- storage_xml.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 701d5144..b01f35d6 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -196,7 +196,7 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na if( xd->current_account && handle && nick ) { - nick_set( irc, handle, xd->current_account->prpl, nick ); + nick_set( xd->current_account, handle, nick ); } else { @@ -364,11 +364,12 @@ static int xml_printf( int fd, int indent, char *fmt, ... ) return len == 0; } +static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ); + 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; md5_byte_t pass_md5[21]; @@ -439,10 +440,15 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) if( !xml_printf( fd, 2, "%s\n", set->key, set->value ) ) goto write_error; - for( nick = irc->nicks; nick; nick = nick->next ) - if( nick->proto == acc->prpl ) - if( !xml_printf( fd, 2, "\n", nick->handle, nick->nick ) ) - goto write_error; + /* This probably looks pretty strange. g_hash_table_foreach + is quite a PITA already (but it can't get much better in + C without using #define, I'm afraid), and since it + doesn't seem to be possible to abort the foreach on write + errors, so instead let's use the _find function and + return TRUE on write errors. Which means, if we found + something, there was an error. :-) */ + if( g_hash_table_find( acc->nicks, xml_save_nick, (gpointer) fd ) ) + goto write_error; if( !xml_printf( fd, 1, "\n" ) ) goto write_error; @@ -477,6 +483,11 @@ write_error: return STORAGE_OTHER_ERROR; } +static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ) +{ + return !xml_printf( (int) data, 2, "\n", key, value ); +} + static storage_status_t xml_remove( const char *nick, const char *password ) { char s[512]; -- cgit v1.2.3 From 7e3592e96b27ec8375e4b28354bcf9ed4cf5943b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 5 Jul 2006 20:34:31 +0200 Subject: Fixed text_load(), added detection of primary storage backends without save support (which shouldn't be allowed) and added a call to nick_lc() to xml_save() so at least nicks should now be case-insensitive. --- storage_xml.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index b01f35d6..2585b475 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -381,7 +381,10 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_OTHER_ERROR; } - g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, irc->nick, ".xml" ); + path2 = g_strdup( irc->nick ); + nick_lc( path2 ); + g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" ); + g_free( path2 ); if( !overwrite && access( path, F_OK ) != -1 ) return STORAGE_ALREADY_EXISTS; -- cgit v1.2.3 From 8320a7a0012f868e5878a5a9f52676a5fece02e1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 17 Sep 2006 17:30:35 +0200 Subject: Strings passed to xml_text aren't necessarily \0-terminated, so don't count on that anymore. --- storage_xml.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 2585b475..52240a36 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -226,11 +226,15 @@ static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name } } -static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) +static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize text_len, gpointer data, GError **error ) { + char text[text_len+1]; struct xml_parsedata *xd = data; irc_t *irc = xd->irc; + strncpy( text, text_orig, text_len ); + text[text_len] = 0; + if( xd->pass_st < XML_PASS_OK ) { /* Let's not parse anything else if we only have to check -- cgit v1.2.3 From 28eda862ffd1f59ac3cd214295c366ab939afd46 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Oct 2006 15:53:55 +0200 Subject: Fixed #181. (Using wrong (static) variable in error messages.) --- storage_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 52240a36..ba311120 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -262,7 +262,7 @@ GMarkupParser xml_parser = 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 ); + log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", global.conf->configdir ); 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 ); } -- cgit v1.2.3 From 55078f59c8e9f52f1d10bed55511e5e58ec3e53b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 25 Nov 2006 10:20:29 +0100 Subject: Forgot to pass O_CREAT to open() which can cause problems if there's a stale .xml~ file. --- storage_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index ba311120..00fca425 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -394,7 +394,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_ALREADY_EXISTS; strcat( path, "~" ); - if( ( fd = open( path, O_WRONLY | O_CREAT, 0600 ) ) < 0 ) + if( ( fd = open( path, O_WRONLY | O_CREAT | O_TRUNC, 0600 ) ) < 0 ) { irc_usermsg( irc, "Error while opening configuration file." ); return STORAGE_OTHER_ERROR; -- 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. --- storage_xml.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 00fca425..97379b29 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -131,7 +131,8 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na else if( g_strcasecmp( element_name, "account" ) == 0 ) { char *protocol, *handle, *server, *password = NULL, *autoconnect; - char *pass_b64 = NULL, *pass_rc4 = NULL; + char *pass_b64 = NULL; + unsigned char *pass_rc4 = NULL; int pass_len; struct prpl *prpl = NULL; @@ -151,8 +152,9 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na 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 ) ) + rc4_decode( pass_rc4, pass_len, + &password, + xd->given_pass ) ) { xd->current_account = account_add( irc, prpl, handle, password ); if( server ) @@ -409,7 +411,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) 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 ); + pass_buf = base64_encode( pass_md5, 21 ); if( !xml_printf( fd, 0, "\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) ) goto write_error; @@ -423,10 +425,11 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) for( acc = irc->accounts; acc; acc = acc->next ) { - char *pass_rc4, *pass_b64; + unsigned char *pass_rc4; + char *pass_b64; int pass_len; - pass_len = rc4_encode( (unsigned char*) acc->pass, strlen( acc->pass ), (unsigned char**) &pass_rc4, irc->password ); + pass_len = rc4_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_rc4, irc->password ); pass_b64 = base64_encode( pass_rc4, pass_len ); g_free( pass_rc4 ); -- 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). --- storage_xml.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index e45c4252..8618c5fe 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -26,7 +26,7 @@ #define BITLBEE_CORE #include "bitlbee.h" #include "base64.h" -#include "rc4.h" +#include "arc.h" #include "md5.h" typedef enum @@ -132,7 +132,7 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { char *protocol, *handle, *server, *password = NULL, *autoconnect; char *pass_b64 = NULL; - unsigned char *pass_rc4 = NULL; + unsigned char *pass_cr = NULL; int pass_len; struct prpl *prpl = NULL; @@ -151,8 +151,8 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na 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( pass_rc4, pass_len, &password, xd->given_pass ) ) + else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_cr ) ) && + arc_decode( pass_cr, pass_len, &password, xd->given_pass ) ) { xd->current_account = account_add( irc, prpl, handle, password ); if( server ) @@ -168,7 +168,7 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na "Error while decrypting account password" ); } - g_free( pass_rc4 ); + g_free( pass_cr ); g_free( password ); } else if( g_strcasecmp( element_name, "setting" ) == 0 ) @@ -423,13 +423,13 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) for( acc = irc->accounts; acc; acc = acc->next ) { - unsigned char *pass_rc4; + unsigned char *pass_cr; char *pass_b64; int pass_len; - pass_len = rc4_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_rc4, irc->password ); - pass_b64 = base64_encode( pass_rc4, pass_len ); - g_free( pass_rc4 ); + pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password ); + pass_b64 = base64_encode( pass_cr, pass_len ); + g_free( pass_cr ); if( !xml_printf( fd, 1, "prpl->name, acc->user, pass_b64, acc->auto_connect ) ) { -- 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) --- storage_xml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 8618c5fe..4c372cde 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -455,7 +455,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) errors, so instead let's use the _find function and return TRUE on write errors. Which means, if we found something, there was an error. :-) */ - if( g_hash_table_find( acc->nicks, xml_save_nick, (gpointer) fd ) ) + if( g_hash_table_find( acc->nicks, xml_save_nick, & fd ) ) goto write_error; if( !xml_printf( fd, 1, "\n" ) ) @@ -493,7 +493,7 @@ write_error: static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ) { - return !xml_printf( (int) data, 2, "\n", key, value ); + return !xml_printf( *( (int*) data ), 2, "\n", key, value ); } static storage_status_t xml_remove( const char *nick, const char *password ) -- cgit v1.2.3 From eeb85a8a880fefe655eb31b6322136b61ee969e2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 11 Feb 2008 12:35:01 +0000 Subject: Got rid of some noise at startup: complaining when the default configuration file couldn't be found while the user specified an alternative location with the -c option, and double complaints about /var/lib/bitlbee/ permissions. --- storage_xml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 4c372cde..19070a74 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -262,9 +262,9 @@ GMarkupParser xml_parser = 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.", global.conf->configdir ); + log_message( LOGLVL_WARNING, "The configuration directory `%s' does not exist. Configuration won't be saved.", global.conf->configdir ); 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 ); + 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 ) -- 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. --- storage_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 19070a74..6ea4d442 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -427,7 +427,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) char *pass_b64; int pass_len; - pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password ); + pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password, 12 ); pass_b64 = base64_encode( pass_cr, pass_len ); g_free( pass_cr ); -- 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). --- storage_xml.c | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) (limited to 'storage_xml.c') diff --git a/storage_xml.c b/storage_xml.c index 6ea4d442..f37fce44 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -79,49 +79,30 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { char *nick = xml_attr( attr_names, attr_values, "nick" ); char *pass = xml_attr( attr_names, attr_values, "password" ); - md5_byte_t *pass_dec = NULL; + int st; 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 ) + else if( ( st = md5_verify_password( xd->given_pass, pass ) ) == -1 ) { + xd->pass_st = XML_PASS_WRONG; g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Error while decoding password attribute" ); } + else if( st == 0 ) + { + if( xd->pass_st != XML_PASS_CHECK_ONLY ) + xd->pass_st = XML_PASS_OK; + } 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] ) - { - xd->pass_st = XML_PASS_WRONG; - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - "Password mismatch" ); - 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; - } + xd->pass_st = XML_PASS_WRONG; + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Password mismatch" ); } - - g_free( pass_dec ); } else if( xd->pass_st < XML_PASS_OK ) { -- cgit v1.2.3