source: storage_text.c @ 15832cc

Last change on this file since 15832cc was 15832cc, checked in by Wilmer van der Gaast <wilmer@…>, at 2005-12-16T09:45:34Z

Added the ICQ and AIM protocol numbers to find_protocol_by_id in storage_text.c, because those numbers are used by old versions.

  • Property mode set to 100644
File size: 9.3 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
30/* DO NOT USE THIS FUNCTION IN NEW CODE. This
31 * function is here merely because the save/load code still uses
32 * ids rather than names */
33static struct prpl *find_protocol_by_id(int id)
34{
35        switch (id) {
36        case 0: return find_protocol("oscar");
37        case 1: return find_protocol("oscar");
38        case 3: return find_protocol("oscar");
39        case 4: return find_protocol("msn");
40        case 2: return find_protocol("yahoo");
41        case 8: return find_protocol("jabber");
42        default: break;
43        }
44        return NULL;
45}
46
47static int find_protocol_id(const char *name)
48{
49        if (!strcmp(name, "oscar")) return 1;
50        if (!strcmp(name, "msn")) return 4;
51        if (!strcmp(name, "yahoo")) return 2;
52        if (!strcmp(name, "jabber")) return 8;
53
54        return -1;
55}
56
57
58static void text_init (void)
59{
60        if( access( global.conf->configdir, F_OK ) != 0 )
61                log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", CONFIG );
62        else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 )
63                log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir );
64}
65
66static storage_status_t text_load ( const char *my_nick, const char* password, irc_t *irc )
67{
68        char s[512];
69        char *line;
70        int proto;
71        char nick[MAX_NICK_LENGTH+1];
72        FILE *fp;
73        user_t *ru = user_find( irc, ROOT_NICK );
74       
75        if( irc->status == USTATUS_IDENTIFIED )
76                return( 1 );
77       
78        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" );
79        fp = fopen( s, "r" );
80        if( !fp ) return STORAGE_NO_SUCH_USER;
81       
82        fscanf( fp, "%32[^\n]s", s );
83
84        if (checkpass (password, s) != 0) 
85        {
86                fclose( fp );
87                return STORAGE_INVALID_PASSWORD;
88        }
89       
90        /* Do this now. If the user runs with AuthMode = Registered, the
91           account command will not work otherwise. */
92        irc->status = USTATUS_IDENTIFIED;
93       
94        while( fscanf( fp, "%511[^\n]s", s ) > 0 )
95        {
96                fgetc( fp );
97                line = deobfucrypt( s, password );
98                if (line == NULL) return STORAGE_OTHER_ERROR;
99                root_command_string( irc, ru, line, 0 );
100                g_free( line );
101        }
102        fclose( fp );
103       
104        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" );
105        fp = fopen( s, "r" );
106        if( !fp ) return STORAGE_NO_SUCH_USER;
107        while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 )
108        {
109                struct prpl *prpl;
110
111                prpl = find_protocol_by_id(proto);
112
113                if (!prpl)
114                        continue;
115
116                http_decode( s );
117                nick_set( irc, s, prpl, nick );
118        }
119        fclose( fp );
120       
121        if( set_getint( irc, "auto_connect" ) )
122        {
123                strcpy( s, "account on" );      /* Can't do this directly because r_c_s alters the string */
124                root_command_string( irc, ru, s, 0 );
125        }
126       
127        return STORAGE_OK;
128}
129
130static storage_status_t text_save( irc_t *irc, int overwrite )
131{
132        char s[512];
133        char path[512], new_path[512];
134        char *line;
135        nick_t *n;
136        set_t *set;
137        mode_t ou = umask( 0077 );
138        account_t *a;
139        FILE *fp;
140        char *hash;
141
142        if (!overwrite) {
143                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
144                if (access( path, F_OK ) != -1)
145                        return STORAGE_ALREADY_EXISTS;
146       
147                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
148                if (access( path, F_OK ) != -1)
149                        return STORAGE_ALREADY_EXISTS;
150        }
151       
152        /*\
153         *  [SH] Nothing should be saved if no password is set, because the
154         *  password is not set if it was wrong, or if one is not identified
155         *  yet. This means that a malicious user could easily overwrite
156         *  files owned by someone else:
157         *  a Bad Thing, methinks
158        \*/
159
160        /* [WVG] No? Really? */
161
162        /*\
163         *  [SH] Okay, okay, it wasn't really Wilmer who said that, it was
164         *  me. I just thought it was funny.
165        \*/
166       
167        hash = hashpass( irc->password );
168        if( hash == NULL )
169        {
170                irc_usermsg( irc, "Please register yourself if you want to save your settings." );
171                return STORAGE_OTHER_ERROR;
172        }
173       
174        g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" );
175        fp = fopen( path, "w" );
176        if( !fp ) return STORAGE_OTHER_ERROR;
177        for( n = irc->nicks; n; n = n->next )
178        {
179                strcpy( s, n->handle );
180                s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
181                http_encode( s );
182                g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", find_protocol_id(n->proto->name), n->nick );
183                if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
184                {
185                        irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
186                        fclose( fp );
187                        return STORAGE_OTHER_ERROR;
188                }
189        }
190        if( fclose( fp ) != 0 )
191        {
192                irc_usermsg( irc, "fclose() reported an error. Disk full?" );
193                return STORAGE_OTHER_ERROR;
194        }
195 
196        g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
197        if( unlink( new_path ) != 0 )
198        {
199                if( errno != ENOENT )
200                {
201                        irc_usermsg( irc, "Error while removing old .nicks file" );
202                        return STORAGE_OTHER_ERROR;
203                }
204        }
205        if( rename( path, new_path ) != 0 )
206        {
207                irc_usermsg( irc, "Error while renaming new .nicks file" );
208                return STORAGE_OTHER_ERROR;
209        }
210       
211        g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" );
212        fp = fopen( path, "w" );
213        if( !fp ) return STORAGE_OTHER_ERROR;
214        if( fprintf( fp, "%s", hash ) != strlen( hash ) )
215        {
216                irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
217                fclose( fp );
218                return STORAGE_OTHER_ERROR;
219        }
220        g_free( hash );
221
222        for( a = irc->accounts; a; a = a->next )
223        {
224                if( !strcmp(a->prpl->name, "oscar") )
225                        g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
226                else
227                        g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
228                                    a->prpl->name, a->user, a->pass, a->server ? a->server : "" );
229               
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       
243        for( set = irc->set; set; set = set->next )
244        {
245                if( set->value && set->def )
246                {
247                        g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
248                        line = obfucrypt( s, irc->password );
249                        if( *line )
250                        {
251                                if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
252                                {
253                                        irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
254                                        fclose( fp );
255                                        return STORAGE_OTHER_ERROR;
256                                }
257                        }
258                        g_free( line );
259                }
260        }
261       
262        if( strcmp( irc->mynick, ROOT_NICK ) != 0 )
263        {
264                g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
265                line = obfucrypt( s, irc->password );
266                if( *line )
267                {
268                        if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
269                        {
270                                irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
271                                fclose( fp );
272                                return STORAGE_OTHER_ERROR;
273                        }
274                }
275                g_free( line );
276        }
277        if( fclose( fp ) != 0 )
278        {
279                irc_usermsg( irc, "fclose() reported an error. Disk full?" );
280                return STORAGE_OTHER_ERROR;
281        }
282       
283        g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
284        if( unlink( new_path ) != 0 )
285        {
286                if( errno != ENOENT )
287                {
288                        irc_usermsg( irc, "Error while removing old .accounts file" );
289                        return STORAGE_OTHER_ERROR;
290                }
291        }
292        if( rename( path, new_path ) != 0 )
293        {
294                irc_usermsg( irc, "Error while renaming new .accounts file" );
295                return STORAGE_OTHER_ERROR;
296        }
297       
298        umask( ou );
299       
300        return STORAGE_OK;
301}
302
303static storage_status_t text_check_pass( const char *nick, const char *password )
304{
305        char s[512];
306        FILE *fp;
307       
308        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
309        fp = fopen( s, "r" );
310        if (!fp)
311                return STORAGE_NO_SUCH_USER;
312
313        fscanf( fp, "%32[^\n]s", s );
314        fclose( fp );
315
316        if (checkpass( password, s) == -1)
317                return STORAGE_INVALID_PASSWORD;
318
319        return STORAGE_OK;
320}
321
322static storage_status_t text_remove( const char *nick, const char *password )
323{
324        char s[512];
325        storage_status_t status;
326
327        status = text_check_pass( nick, password );
328        if (status != STORAGE_OK)
329                return status;
330
331        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
332        if (unlink( s ) == -1)
333                return STORAGE_OTHER_ERROR;
334       
335        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" );
336        if (unlink( s ) == -1)
337                return STORAGE_OTHER_ERROR;
338
339        return STORAGE_OK;
340}
341
342storage_t storage_text = {
343        .name = "text",
344        .init = text_init,
345        .check_pass = text_check_pass,
346        .remove = text_remove,
347        .load = text_load,
348        .save = text_save
349};
Note: See TracBrowser for help on using the repository browser.