source: storage_text.c @ eecccf1

Last change on this file since eecccf1 was 8e419cb, checked in by Jelmer Vernooij <jelmer@…>, at 2006-01-10T21:35:08Z

Merge Wilmer

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