source: storage_text.c @ 87c24ba

Last change on this file since 87c24ba was 7cad7b4, checked in by Jelmer Vernooij <jelmer@…>, at 2005-12-08T16:00:08Z

Clearer seperation between crypting and generic password code

  • Property mode set to 100644
File size: 8.4 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( irc, s );
70                root_command_string( irc, ru, line, 0 );
71                g_free( line );
72        }
73        fclose( fp );
74       
75        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" );
76        fp = fopen( s, "r" );
77        if( !fp ) return STORAGE_NO_SUCH_USER;
78        while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 )
79        {
80                http_decode( s );
81                nick_set( irc, s, proto, nick );
82        }
83        fclose( fp );
84       
85        if( set_getint( irc, "auto_connect" ) )
86        {
87                strcpy( s, "account on" );      /* Can't do this directly because r_c_s alters the string */
88                root_command_string( irc, ru, s, 0 );
89        }
90       
91        return STORAGE_OK;
92}
93
94static storage_status_t text_save( irc_t *irc, int overwrite )
95{
96        char s[512];
97        char path[512], new_path[512];
98        char *line;
99        nick_t *n;
100        set_t *set;
101        mode_t ou = umask( 0077 );
102        account_t *a;
103        FILE *fp;
104        char *hash;
105
106        if (!overwrite) {
107                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
108                if (access( path, F_OK ) != -1)
109                        return STORAGE_ALREADY_EXISTS;
110       
111                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
112                if (access( path, F_OK ) != -1)
113                        return STORAGE_ALREADY_EXISTS;
114        }
115       
116        /*\
117         *  [SH] Nothing should be saved if no password is set, because the
118         *  password is not set if it was wrong, or if one is not identified
119         *  yet. This means that a malicious user could easily overwrite
120         *  files owned by someone else:
121         *  a Bad Thing, methinks
122        \*/
123
124        /* [WVG] No? Really? */
125
126        /*\
127         *  [SH] Okay, okay, it wasn't really Wilmer who said that, it was
128         *  me. I just thought it was funny.
129        \*/
130       
131        hash = hashpass( irc );
132        if( hash == NULL )
133        {
134                irc_usermsg( irc, "Please register yourself if you want to save your settings." );
135                return( 0 );
136        }
137       
138        g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" );
139        fp = fopen( path, "w" );
140        if( !fp ) return STORAGE_OTHER_ERROR;
141        for( n = irc->nicks; n; n = n->next )
142        {
143                strcpy( s, n->handle );
144                s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
145                http_encode( s );
146                g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", n->proto, n->nick );
147                if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
148                {
149                        irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
150                        fclose( fp );
151                        return STORAGE_OTHER_ERROR;
152                }
153        }
154        if( fclose( fp ) != 0 )
155        {
156                irc_usermsg( irc, "fclose() reported an error. Disk full?" );
157                return STORAGE_OTHER_ERROR;
158        }
159 
160        g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
161        if( unlink( new_path ) != 0 )
162        {
163                if( errno != ENOENT )
164                {
165                        irc_usermsg( irc, "Error while removing old .nicks file" );
166                        return STORAGE_OTHER_ERROR;
167                }
168        }
169        if( rename( path, new_path ) != 0 )
170        {
171                irc_usermsg( irc, "Error while renaming new .nicks file" );
172                return STORAGE_OTHER_ERROR;
173        }
174       
175        g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" );
176        fp = fopen( path, "w" );
177        if( !fp ) return STORAGE_OTHER_ERROR;
178        if( fprintf( fp, "%s", hash ) != strlen( hash ) )
179        {
180                irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
181                fclose( fp );
182                return STORAGE_OTHER_ERROR;
183        }
184        g_free( hash );
185
186        for( a = irc->accounts; a; a = a->next )
187        {
188                if( a->protocol == PROTO_OSCAR || a->protocol == PROTO_ICQ || a->protocol == PROTO_TOC )
189                        g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
190                else
191                        g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
192                                    proto_name[a->protocol], a->user, a->pass, a->server ? a->server : "" );
193               
194                line = obfucrypt( irc, s );
195                if( *line )
196                {
197                        if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
198                        {
199                                irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
200                                fclose( fp );
201                                return STORAGE_OTHER_ERROR;
202                        }
203                }
204                g_free( line );
205        }
206       
207        for( set = irc->set; set; set = set->next )
208        {
209                if( set->value && set->def )
210                {
211                        g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
212                        line = obfucrypt( irc, s );
213                        if( *line )
214                        {
215                                if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
216                                {
217                                        irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
218                                        fclose( fp );
219                                        return STORAGE_OTHER_ERROR;
220                                }
221                        }
222                        g_free( line );
223                }
224        }
225       
226        if( strcmp( irc->mynick, ROOT_NICK ) != 0 )
227        {
228                g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
229                line = obfucrypt( irc, s );
230                if( *line )
231                {
232                        if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
233                        {
234                                irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
235                                fclose( fp );
236                                return STORAGE_OTHER_ERROR;
237                        }
238                }
239                g_free( line );
240        }
241        if( fclose( fp ) != 0 )
242        {
243                irc_usermsg( irc, "fclose() reported an error. Disk full?" );
244                return STORAGE_OTHER_ERROR;
245        }
246       
247        g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
248        if( unlink( new_path ) != 0 )
249        {
250                if( errno != ENOENT )
251                {
252                        irc_usermsg( irc, "Error while removing old .accounts file" );
253                        return STORAGE_OTHER_ERROR;
254                }
255        }
256        if( rename( path, new_path ) != 0 )
257        {
258                irc_usermsg( irc, "Error while renaming new .accounts file" );
259                return STORAGE_OTHER_ERROR;
260        }
261       
262        umask( ou );
263       
264        return STORAGE_OK;
265}
266
267static storage_status_t text_check_pass( const char *nick, const char *password )
268{
269        char s[512];
270        FILE *fp;
271       
272        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" );
273        fp = fopen( s, "r" );
274        if (!fp)
275                return STORAGE_NO_SUCH_USER;
276
277        fscanf( fp, "%32[^\n]s", s );
278        fclose( fp );
279
280        if (checkpass( password, s) == -1)
281                return STORAGE_INVALID_PASSWORD;
282
283        return STORAGE_OK;
284}
285
286static storage_status_t text_remove( const char *nick, const char *password )
287{
288        char s[512];
289        storage_status_t status;
290
291        status = text_check_pass( nick, password );
292        if (status != STORAGE_OK)
293                return status;
294
295        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
296        if (unlink( s ) == -1)
297                return STORAGE_OTHER_ERROR;
298       
299        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" );
300        if (unlink( s ) == -1)
301                return STORAGE_OTHER_ERROR;
302
303        return STORAGE_OK;
304}
305
306storage_t storage_text = {
307        .name = "text",
308        .init = text_init,
309        .check_pass = text_check_pass,
310        .remove = text_remove,
311        .load = text_load,
312        .save = text_save
313};
Note: See TracBrowser for help on using the repository browser.