Changeset c121f89 for storage_xml.c


Ignore:
Timestamp:
2006-06-14T20:30:25Z (18 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
5898ef8
Parents:
85e9644
Message:

xml_load() works pretty well now.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • storage_xml.c

    r85e9644 rc121f89  
    2727#include "bitlbee.h"
    2828
     29typedef enum
     30{
     31        XML_PASS_CHECK_ONLY = -1,
     32        XML_PASS_UNKNOWN = 0,
     33        XML_PASS_OK
     34} xml_pass_st;
     35
     36#define XML_PASS_ERRORMSG "Wrong username or password"
     37
    2938struct xml_parsedata
    3039{
     
    3241        char *current_setting;
    3342        account_t *current_account;
     43        char *given_nick;
     44        char *given_pass;
     45        xml_pass_st pass_st;
    3446};
    3547
     
    4052        for( i = 0; attr_names[i]; i ++ )
    4153                if( g_strcasecmp( attr_names[i], key ) == 0 )
    42                         return attr_values[i];
     54                        return (char*) attr_values[i];
    4355       
    4456        return NULL;
    4557}
    4658
     59static void xml_destroy_xd( gpointer data )
     60{
     61        struct xml_parsedata *xd = data;
     62       
     63        g_free( xd->given_nick );
     64        g_free( xd->given_pass );
     65        g_free( xd );
     66}
     67
    4768static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error )
    4869{
    4970        struct xml_parsedata *xd = data;
    50         irc_t *irc = data->irc;
     71        irc_t *irc = xd->irc;
    5172       
    5273        if( g_strcasecmp( element_name, "user" ) == 0 )
    5374        {
    5475                char *nick = xml_attr( attr_names, attr_values, "nick" );
    55                
    56                 if( nick && g_strcasecmp( nick, irc->nick ) == 0 )
    57                 {
    58                         /* Okay! */
    59                 }
     76                char *pass = xml_attr( attr_names, attr_values, "password" );
     77               
     78                if( !nick || !pass )
     79                {
     80                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     81                                     "Missing attributes for %s element", element_name );
     82                }
     83                else if( strcmp( nick, xd->given_nick ) == 0 &&
     84                         strcmp( pass, xd->given_pass ) == 0 )
     85                {
     86                        if( xd->pass_st != XML_PASS_CHECK_ONLY )
     87                                xd->pass_st = XML_PASS_OK;
     88                }
     89                else
     90                {
     91                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     92                                     XML_PASS_ERRORMSG );
     93                }
     94        }
     95        else if( xd->pass_st < XML_PASS_OK )
     96        {
     97                /* Let's not parse anything else if we only have to check
     98                   the password. */
    6099        }
    61100        else if( g_strcasecmp( element_name, "account" ) == 0 )
    62101        {
    63                 char *protocol, *handle, *password;
     102                char *protocol, *handle, *server, *password;
    64103                struct prpl *prpl = NULL;
    65104               
    66105                handle = xml_attr( attr_names, attr_values, "handle" );
    67106                password = xml_attr( attr_names, attr_values, "password" );
     107                server = xml_attr( attr_names, attr_values, "server" );
    68108               
    69109                protocol = xml_attr( attr_names, attr_values, "protocol" );
     
    71111                        prpl = find_protocol( protocol );
    72112               
    73                 if( handle && password && prpl )
    74                 {
    75                         xd->current_account = account_add( irc, prpl, handle, password )
     113                if( !handle || !password )
     114                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     115                                     "Missing attributes for %s element", element_name );
     116                else if( !prpl )
     117                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     118                                     "Missing or unknown protocol %s element", element_name );
     119                else
     120                {
     121                        xd->current_account = account_add( irc, prpl, handle, password );
     122                        if( server )
     123                                xd->current_account->server = g_strdup( server );
    76124                }
    77125        }
     
    80128                if( xd->current_account == NULL )
    81129                {
    82                         current_setting = xml_attr( attr_names, attr_values, "name" );
     130                        char *setting;
     131                       
     132                        if( xd->current_setting )
     133                        {
     134                                g_free( xd->current_setting );
     135                                xd->current_setting = NULL;
     136                        }
     137                       
     138                        if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
     139                                xd->current_setting = g_strdup( setting );
     140                        else
     141                                g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     142                                             "Missing attributes for %s element", element_name );
    83143                }
    84144        }
    85145        else if( g_strcasecmp( element_name, "buddy" ) == 0 )
    86146        {
    87         }
    88         else if( g_strcasecmp( element_name, "password" ) == 0 )
    89         {
     147                char *handle, *nick;
     148               
     149                handle = xml_attr( attr_names, attr_values, "handle" );
     150                nick = xml_attr( attr_names, attr_values, "nick" );
     151               
     152                if( xd->current_account && handle && nick )
     153                {
     154                        nick_set( irc, handle, xd->current_account->prpl, nick );
     155                }
     156                else
     157                {
     158                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     159                                     "Missing attributes for %s element", element_name );
     160                }
    90161        }
    91162        else
    92163        {
    93                 /* Return "unknown element" error. */
     164                g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
     165                             "Unkown element: %s", element_name );
    94166        }
    95167}
     
    102174{
    103175        struct xml_parsedata *xd = data;
    104         irc_t *irc = data->irc;
    105        
    106         if( xd->current_setting )
    107         {
    108                 set_setstr( irc, xd->current_setting, text );
     176        irc_t *irc = xd->irc;
     177       
     178        if( xd->pass_st < XML_PASS_OK )
     179        {
     180                /* Let's not parse anything else if we only have to check
     181                   the password. */
     182        }
     183        else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 &&
     184                 xd->current_setting && xd->current_account == NULL )
     185        {
     186                set_setstr( irc, xd->current_setting, (char*) text );
     187                g_free( xd->current_setting );
     188                xd->current_setting = NULL;
    109189        }
    110190}
     
    131211}
    132212
    133 static storage_status_t xml_load ( const char *my_nick, const char* password, irc_t *irc )
     213static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc )
    134214{
    135215        GMarkupParseContext *ctx;
    136        
    137         ctx = g_markup_parse_context_new( parser, 0, xd, NULL );
     216        struct xml_parsedata *xd;
     217        char *fn, buf[512];
     218        GError *gerr = NULL;
     219        int fd, st;
     220       
    138221        if( irc->status >= USTATUS_IDENTIFIED )
    139222                return( 1 );
    140223       
    141         g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" );
    142         fp = fopen( s, "r" );
    143         if( !fp ) return STORAGE_NO_SUCH_USER;
    144        
    145         fscanf( fp, "%32[^\n]s", s );
    146 
    147         if (checkpass (password, s) != 0)
    148         {
    149                 fclose( fp );
    150                 return STORAGE_INVALID_PASSWORD;
    151         }
    152        
    153         /* Do this now. If the user runs with AuthMode = Registered, the
    154            account command will not work otherwise. */
     224        xd = g_new0( struct xml_parsedata, 1 );
     225        xd->irc = irc;
     226        xd->given_nick = g_strdup( my_nick );
     227        xd->given_pass = g_strdup( password );
     228        nick_lc( xd->given_nick );
     229       
     230        fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" );
     231        if( ( fd = open( fn, O_RDONLY ) ) < 0 )
     232        {
     233                xml_destroy_xd( xd );
     234                g_free( fn );
     235                return STORAGE_NO_SUCH_USER;
     236        }
     237        g_free( fn );
     238       
     239        ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd );
     240       
     241        while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 )
     242        {
     243                if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr )
     244                {
     245                        g_markup_parse_context_free( ctx );
     246                       
     247                        /* TODO: Display useful error msg */
     248                       
     249                        if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 )
     250                                return STORAGE_INVALID_PASSWORD;
     251                        else
     252                                return STORAGE_OTHER_ERROR;
     253                }
     254        }
     255       
     256        g_markup_parse_context_free( ctx );
     257       
    155258        irc->status = USTATUS_IDENTIFIED;
    156259       
    157         while( fscanf( fp, "%511[^\n]s", s ) > 0 )
    158         {
    159                 fgetc( fp );
    160                 line = deobfucrypt( s, password );
    161                 if (line == NULL) return STORAGE_OTHER_ERROR;
    162                 root_command_string( irc, ru, line, 0 );
    163                 g_free( line );
    164         }
    165         fclose( fp );
    166        
    167         g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" );
    168         fp = fopen( s, "r" );
    169         if( !fp ) return STORAGE_NO_SUCH_USER;
    170         while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 )
    171         {
    172                 struct prpl *prpl;
    173 
    174                 prpl = find_protocol_by_id(proto);
    175 
    176                 if (!prpl)
    177                         continue;
    178 
    179                 http_decode( s );
    180                 nick_set( irc, s, prpl, nick );
    181         }
    182         fclose( fp );
    183        
    184260        if( set_getint( irc, "auto_connect" ) )
    185261        {
    186                 strcpy( s, "account on" );      /* Can't do this directly because r_c_s alters the string */
    187                 root_command_string( irc, ru, s, 0 );
     262                /* Can't do this directly because r_c_s alters the string */
     263                strcpy( buf, "account on" );
     264                root_command_string( irc, NULL, buf, 0 );
    188265        }
    189266       
     
    191268}
    192269
    193 static storage_status_t text_save( irc_t *irc, int overwrite )
    194 {
    195         char s[512];
    196         char path[512], new_path[512];
    197         char *line;
    198         nick_t *n;
    199         set_t *set;
    200         mode_t ou = umask( 0077 );
    201         account_t *a;
    202         FILE *fp;
    203         char *hash;
    204 
    205         if (!overwrite) {
     270static storage_status_t xml_save( irc_t *irc, int overwrite )
     271{
     272/*      if (!overwrite) {
    206273                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
    207274                if (access( path, F_OK ) != -1)
     
    212279                        return STORAGE_ALREADY_EXISTS;
    213280        }
    214        
    215         /*\
    216          *  [SH] Nothing should be saved if no password is set, because the
    217          *  password is not set if it was wrong, or if one is not identified
    218          *  yet. This means that a malicious user could easily overwrite
    219          *  files owned by someone else:
    220          *  a Bad Thing, methinks
    221         \*/
    222 
    223         /* [WVG] No? Really? */
    224 
    225         /*\
    226          *  [SH] Okay, okay, it wasn't really Wilmer who said that, it was
    227          *  me. I just thought it was funny.
    228         \*/
    229        
    230         hash = hashpass( irc->password );
    231         if( hash == NULL )
    232         {
    233                 irc_usermsg( irc, "Please register yourself if you want to save your settings." );
    234                 return STORAGE_OTHER_ERROR;
    235         }
    236        
    237         g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" );
    238         fp = fopen( path, "w" );
    239         if( !fp ) return STORAGE_OTHER_ERROR;
    240         for( n = irc->nicks; n; n = n->next )
    241         {
    242                 strcpy( s, n->handle );
    243                 s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
    244                 http_encode( s );
    245                 g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", find_protocol_id(n->proto->name), n->nick );
    246                 if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
    247                 {
    248                         irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
    249                         fclose( fp );
    250                         return STORAGE_OTHER_ERROR;
    251                 }
    252         }
    253         if( fclose( fp ) != 0 )
    254         {
    255                 irc_usermsg( irc, "fclose() reported an error. Disk full?" );
    256                 return STORAGE_OTHER_ERROR;
    257         }
    258  
    259         g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
    260         if( unlink( new_path ) != 0 )
    261         {
    262                 if( errno != ENOENT )
    263                 {
    264                         irc_usermsg( irc, "Error while removing old .nicks file" );
    265                         return STORAGE_OTHER_ERROR;
    266                 }
    267         }
    268         if( rename( path, new_path ) != 0 )
    269         {
    270                 irc_usermsg( irc, "Error while renaming new .nicks file" );
    271                 return STORAGE_OTHER_ERROR;
    272         }
    273        
    274         g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" );
    275         fp = fopen( path, "w" );
    276         if( !fp ) return STORAGE_OTHER_ERROR;
    277         if( fprintf( fp, "%s", hash ) != strlen( hash ) )
    278         {
    279                 irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
    280                 fclose( fp );
    281                 return STORAGE_OTHER_ERROR;
    282         }
    283         g_free( hash );
    284 
    285         for( a = irc->accounts; a; a = a->next )
    286         {
    287                 if( !strcmp(a->prpl->name, "oscar") )
    288                         g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
    289                 else
    290                         g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
    291                                     a->prpl->name, a->user, a->pass, a->server ? a->server : "" );
    292                
    293                 line = obfucrypt( s, irc->password );
    294                 if( *line )
    295                 {
    296                         if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
    297                         {
    298                                 irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
    299                                 fclose( fp );
    300                                 return STORAGE_OTHER_ERROR;
    301                         }
    302                 }
    303                 g_free( line );
    304         }
    305        
    306         for( set = irc->set; set; set = set->next )
    307         {
    308                 if( set->value && set->def )
    309                 {
    310                         g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
    311                         line = obfucrypt( s, irc->password );
    312                         if( *line )
    313                         {
    314                                 if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
    315                                 {
    316                                         irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
    317                                         fclose( fp );
    318                                         return STORAGE_OTHER_ERROR;
    319                                 }
    320                         }
    321                         g_free( line );
    322                 }
    323         }
    324        
    325         if( strcmp( irc->mynick, ROOT_NICK ) != 0 )
    326         {
    327                 g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
    328                 line = obfucrypt( s, irc->password );
    329                 if( *line )
    330                 {
    331                         if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
    332                         {
    333                                 irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
    334                                 fclose( fp );
    335                                 return STORAGE_OTHER_ERROR;
    336                         }
    337                 }
    338                 g_free( line );
    339         }
    340         if( fclose( fp ) != 0 )
    341         {
    342                 irc_usermsg( irc, "fclose() reported an error. Disk full?" );
    343                 return STORAGE_OTHER_ERROR;
    344         }
    345        
    346         g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
    347         if( unlink( new_path ) != 0 )
    348         {
    349                 if( errno != ENOENT )
    350                 {
    351                         irc_usermsg( irc, "Error while removing old .accounts file" );
    352                         return STORAGE_OTHER_ERROR;
    353                 }
    354         }
    355         if( rename( path, new_path ) != 0 )
    356         {
    357                 irc_usermsg( irc, "Error while renaming new .accounts file" );
    358                 return STORAGE_OTHER_ERROR;
    359         }
    360        
    361         umask( ou );
    362        
    363         return STORAGE_OK;
    364 }
    365 
    366 static storage_status_t text_check_pass( const char *nick, const char *password )
    367 {
    368         char s[512];
    369         FILE *fp;
    370        
    371         g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
    372         fp = fopen( s, "r" );
    373         if (!fp)
    374                 return STORAGE_NO_SUCH_USER;
    375 
    376         fscanf( fp, "%32[^\n]s", s );
    377         fclose( fp );
    378 
    379         if (checkpass( password, s) == -1)
    380                 return STORAGE_INVALID_PASSWORD;
    381 
    382         return STORAGE_OK;
    383 }
    384 
    385 static storage_status_t text_remove( const char *nick, const char *password )
    386 {
    387         char s[512];
    388         storage_status_t status;
    389 
    390         status = text_check_pass( nick, password );
    391         if (status != STORAGE_OK)
    392                 return status;
    393 
    394         g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
    395         if (unlink( s ) == -1)
    396                 return STORAGE_OTHER_ERROR;
    397        
    398         g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" );
    399         if (unlink( s ) == -1)
    400                 return STORAGE_OTHER_ERROR;
    401 
     281*/     
    402282        return STORAGE_OK;
    403283}
     
    406286        .name = "xml",
    407287        .init = xml_init,
    408         .check_pass = xml_check_pass,
    409         .remove = xml_remove,
     288//      .check_pass = xml_check_pass,
     289//      .remove = xml_remove,
    410290        .load = xml_load,
    411291        .save = xml_save
Note: See TracChangeset for help on using the changeset viewer.