source: storage_text.c @ 22bf64e

Last change on this file since 22bf64e was b73ac9c, checked in by Jelmer Vernooij <jelmer@…>, at 2005-12-13T23:05:27Z

Add support for 'primary' and 'migrate' account storages.
Fix two bugs in the text storage backend that were introduced by my previous
changes.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Storage backend that uses the same file format as <=1.0 */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28#include "crypting.h"
29
30static void text_init (void)
31{
32        if( access( global.conf->configdir, F_OK ) != 0 )
33                log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", CONFIG );
34        else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 )
35                log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir );
36}
37
38static storage_status_t text_load ( const char *my_nick, const char* password, irc_t *irc )
39{
40        char s[512];
41        char *line;
42        int proto;
43        char nick[MAX_NICK_LENGTH+1];
44        FILE *fp;
45        user_t *ru = user_find( irc, ROOT_NICK );
46       
47        if( irc->status == USTATUS_IDENTIFIED )
48                return( 1 );
49       
50        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" );
51        fp = fopen( s, "r" );
52        if( !fp ) return STORAGE_NO_SUCH_USER;
53       
54        fscanf( fp, "%32[^\n]s", s );
55
56        if (checkpass (password, s) != 0) 
57        {
58                fclose( fp );
59                return STORAGE_INVALID_PASSWORD;
60        }
61       
62        /* Do this now. If the user runs with AuthMode = Registered, the
63           account command will not work otherwise. */
64        irc->status = USTATUS_IDENTIFIED;
65       
66        while( fscanf( fp, "%511[^\n]s", s ) > 0 )
67        {
68                fgetc( fp );
69                line = deobfucrypt( s, password );
70                if (line == NULL) return STORAGE_OTHER_ERROR;
71                root_command_string( irc, ru, line, 0 );
72                g_free( line );
73        }
74        fclose( fp );
75       
76        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" );
77        fp = fopen( s, "r" );
78        if( !fp ) return STORAGE_NO_SUCH_USER;
79        while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 )
80        {
81                http_decode( s );
82                nick_set( irc, s, proto, nick );
83        }
84        fclose( fp );
85       
86        if( set_getint( irc, "auto_connect" ) )
87        {
88                strcpy( s, "account on" );      /* Can't do this directly because r_c_s alters the string */
89                root_command_string( irc, ru, s, 0 );
90        }
91       
92        return STORAGE_OK;
93}
94
95static storage_status_t text_save( irc_t *irc, int overwrite )
96{
97        char s[512];
98        char path[512], new_path[512];
99        char *line;
100        nick_t *n;
101        set_t *set;
102        mode_t ou = umask( 0077 );
103        account_t *a;
104        FILE *fp;
105        char *hash;
106
107        if (!overwrite) {
108                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
109                if (access( path, F_OK ) != -1)
110                        return STORAGE_ALREADY_EXISTS;
111       
112                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
113                if (access( path, F_OK ) != -1)
114                        return STORAGE_ALREADY_EXISTS;
115        }
116       
117        /*\
118         *  [SH] Nothing should be saved if no password is set, because the
119         *  password is not set if it was wrong, or if one is not identified
120         *  yet. This means that a malicious user could easily overwrite
121         *  files owned by someone else:
122         *  a Bad Thing, methinks
123        \*/
124
125        /* [WVG] No? Really? */
126
127        /*\
128         *  [SH] Okay, okay, it wasn't really Wilmer who said that, it was
129         *  me. I just thought it was funny.
130        \*/
131       
132        hash = hashpass( irc->password );
133        if( hash == NULL )
134        {
135                irc_usermsg( irc, "Please register yourself if you want to save your settings." );
136                return STORAGE_OTHER_ERROR;
137        }
138       
139        g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" );
140        fp = fopen( path, "w" );
141        if( !fp ) return STORAGE_OTHER_ERROR;
142        for( n = irc->nicks; n; n = n->next )
143        {
144                strcpy( s, n->handle );
145                s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
146                http_encode( s );
147                g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", n->proto, n->nick );
148                if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
149                {
150                        irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
151                        fclose( fp );
152                        return STORAGE_OTHER_ERROR;
153                }
154        }
155        if( fclose( fp ) != 0 )
156        {
157                irc_usermsg( irc, "fclose() reported an error. Disk full?" );
158                return STORAGE_OTHER_ERROR;
159        }
160 
161        g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
162        if( unlink( new_path ) != 0 )
163        {
164                if( errno != ENOENT )
165                {
166                        irc_usermsg( irc, "Error while removing old .nicks file" );
167                        return STORAGE_OTHER_ERROR;
168                }
169        }
170        if( rename( path, new_path ) != 0 )
171        {
172                irc_usermsg( irc, "Error while renaming new .nicks file" );
173                return STORAGE_OTHER_ERROR;
174        }
175       
176        g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" );
177        fp = fopen( path, "w" );
178        if( !fp ) return STORAGE_OTHER_ERROR;
179        if( fprintf( fp, "%s", hash ) != strlen( hash ) )
180        {
181                irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
182                fclose( fp );
183                return STORAGE_OTHER_ERROR;
184        }
185        g_free( hash );
186
187        for( a = irc->accounts; a; a = a->next )
188        {
189                if( a->protocol == PROTO_OSCAR || a->protocol == PROTO_ICQ || a->protocol == PROTO_TOC )
190                        g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
191                else
192                        g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
193                                    proto_name[a->protocol], a->user, a->pass, a->server ? a->server : "" );
194               
195                line = obfucrypt( s, irc->password );
196                if( *line )
197                {
198                        if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
199                        {
200                                irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
201                                fclose( fp );
202                                return STORAGE_OTHER_ERROR;
203                        }
204                }
205                g_free( line );
206        }
207       
208        for( set = irc->set; set; set = set->next )
209        {
210                if( set->value && set->def )
211                {
212                        g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
213                        line = obfucrypt( s, irc->password );
214                        if( *line )
215                        {
216                                if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
217                                {
218                                        irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
219                                        fclose( fp );
220                                        return STORAGE_OTHER_ERROR;
221                                }
222                        }
223                        g_free( line );
224                }
225        }
226       
227        if( strcmp( irc->mynick, ROOT_NICK ) != 0 )
228        {
229                g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
230                line = obfucrypt( s, irc->password );
231                if( *line )
232                {
233                        if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
234                        {
235                                irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
236                                fclose( fp );
237                                return STORAGE_OTHER_ERROR;
238                        }
239                }
240                g_free( line );
241        }
242        if( fclose( fp ) != 0 )
243        {
244                irc_usermsg( irc, "fclose() reported an error. Disk full?" );
245                return STORAGE_OTHER_ERROR;
246        }
247       
248        g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
249        if( unlink( new_path ) != 0 )
250        {
251                if( errno != ENOENT )
252                {
253                        irc_usermsg( irc, "Error while removing old .accounts file" );
254                        return STORAGE_OTHER_ERROR;
255                }
256        }
257        if( rename( path, new_path ) != 0 )
258        {
259                irc_usermsg( irc, "Error while renaming new .accounts file" );
260                return STORAGE_OTHER_ERROR;
261        }
262       
263        umask( ou );
264       
265        return STORAGE_OK;
266}
267
268static storage_status_t text_check_pass( const char *nick, const char *password )
269{
270        char s[512];
271        FILE *fp;
272       
273        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
274        fp = fopen( s, "r" );
275        if (!fp)
276                return STORAGE_NO_SUCH_USER;
277
278        fscanf( fp, "%32[^\n]s", s );
279        fclose( fp );
280
281        if (checkpass( password, s) == -1)
282                return STORAGE_INVALID_PASSWORD;
283
284        return STORAGE_OK;
285}
286
287static storage_status_t text_remove( const char *nick, const char *password )
288{
289        char s[512];
290        storage_status_t status;
291
292        status = text_check_pass( nick, password );
293        if (status != STORAGE_OK)
294                return status;
295
296        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
297        if (unlink( s ) == -1)
298                return STORAGE_OTHER_ERROR;
299       
300        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" );
301        if (unlink( s ) == -1)
302                return STORAGE_OTHER_ERROR;
303
304        return STORAGE_OK;
305}
306
307storage_t storage_text = {
308        .name = "text",
309        .init = text_init,
310        .check_pass = text_check_pass,
311        .remove = text_remove,
312        .load = text_load,
313        .save = text_save
314};
Note: See TracBrowser for help on using the repository browser.