source: storage.c @ 9e768da

Last change on this file since 9e768da was 3183c21, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-09-06T22:59:32Z

Completely reviewed all uses of irc->password, irc_setpass() and
USTATUS_IDENTIFIED after another account overwriting vulnerability was
found by Tero Marttila.

  • Property mode set to 100644
File size: 5.2 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/* Support for multiple storage backends */
8
9/* Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org> */
10
11/*
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  GNU General Public License for more details.
21
22  You should have received a copy of the GNU General Public License with
23  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
24  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
25  Suite 330, Boston, MA  02111-1307  USA
26*/
27
28#define BITLBEE_CORE
29#include "bitlbee.h"
30#include "crypting.h"
31
32extern storage_t storage_text;
33extern storage_t storage_xml;
34
35static GList *storage_backends = NULL;
36
37void register_storage_backend(storage_t *backend)
38{
39        storage_backends = g_list_append(storage_backends, backend);
40}
41
42static storage_t *storage_init_single(const char *name)
43{
44        GList *gl;
45        storage_t *st = NULL;
46
47        for (gl = storage_backends; gl; gl = gl->next) {
48                st = gl->data;
49                if (strcmp(st->name, name) == 0)
50                        break;
51        }
52
53        if (gl == NULL) 
54                return NULL;
55
56        if (st->init)
57                st->init();
58
59        return st;
60}
61
62GList *storage_init(const char *primary, char **migrate)
63{
64        GList *ret = NULL;
65        int i;
66        storage_t *storage;
67       
68        register_storage_backend(&storage_text);
69        register_storage_backend(&storage_xml);
70       
71        storage = storage_init_single(primary);
72        if (storage == NULL && storage->save == NULL)
73                return NULL;
74
75        ret = g_list_append(ret, storage);
76
77        for (i = 0; migrate && migrate[i]; i++) {
78                storage = storage_init_single(migrate[i]);
79       
80                if (storage)
81                        ret = g_list_append(ret, storage);
82        }
83
84        return ret;
85}
86
87storage_status_t storage_check_pass (const char *nick, const char *password)
88{
89        GList *gl;
90       
91        /* Loop until we don't get NO_SUCH_USER */
92
93        for (gl = global.storage; gl; gl = gl->next) {
94                storage_t *st = gl->data;
95                storage_status_t status;
96
97                status = st->check_pass(nick, password);
98                if (status != STORAGE_NO_SUCH_USER)
99                        return status;
100        }
101       
102        return STORAGE_NO_SUCH_USER;
103}
104
105storage_status_t storage_load (irc_t * irc, const char *password)
106{
107        GList *gl;
108       
109        if (irc && irc->status & USTATUS_IDENTIFIED)
110                return STORAGE_OTHER_ERROR;
111       
112        /* Loop until we don't get NO_SUCH_USER */
113        for (gl = global.storage; gl; gl = gl->next) {
114                storage_t *st = gl->data;
115                storage_status_t status;
116
117                status = st->load(irc, password);
118                if (status == STORAGE_OK)
119                        return status;
120               
121                if (status != STORAGE_NO_SUCH_USER) 
122                        return status;
123        }
124       
125        return STORAGE_NO_SUCH_USER;
126}
127
128storage_status_t storage_save (irc_t *irc, char *password, int overwrite)
129{
130        storage_status_t st;
131       
132        if (password != NULL) {
133                /* Should only use this in the "register" command. */
134                if (irc->password || overwrite)
135                        return STORAGE_OTHER_ERROR;
136               
137                irc_setpass(irc, password);
138        } else if ((irc->status & USTATUS_IDENTIFIED) == 0) {
139                return STORAGE_NO_SUCH_USER;
140        }
141       
142        st = ((storage_t *)global.storage->data)->save(irc, overwrite);
143       
144        if (password != NULL) {
145                irc_setpass(irc, NULL);
146        }
147       
148        return st;
149}
150
151storage_status_t storage_remove (const char *nick, const char *password)
152{
153        GList *gl;
154        storage_status_t ret = STORAGE_OK;
155       
156        /* Remove this account from all storage backends. If this isn't
157         * done, the account will still be usable, it'd just be
158         * loaded from a different backend. */
159        for (gl = global.storage; gl; gl = gl->next) {
160                storage_t *st = gl->data;
161                storage_status_t status;
162
163                status = st->remove(nick, password);
164                if (status != STORAGE_NO_SUCH_USER && status != STORAGE_OK)
165                        ret = status;
166        }
167       
168        return ret;
169}
170
171#if 0
172Not using this yet. Test thoroughly before adding UI hooks to this function.
173
174storage_status_t storage_rename (const char *onick, const char *nnick, const char *password)
175{
176        storage_status_t status;
177        GList *gl = global.storage;
178        storage_t *primary_storage = gl->data;
179        irc_t *irc;
180
181        /* First, try to rename in the current write backend, assuming onick
182         * is stored there */
183        status = primary_storage->rename(onick, nnick, password);
184        if (status != STORAGE_NO_SUCH_USER)
185                return status;
186
187        /* Try to load from a migration backend and save to the current backend.
188         * Explicitly remove the account from the migration backend as otherwise
189         * it'd still be usable under the old name */
190       
191        irc = g_new0(irc_t, 1);
192        status = storage_load(onick, password, irc);
193        if (status != STORAGE_OK) {
194                irc_free(irc);
195                return status;
196        }
197
198        g_free(irc->nick);
199        irc->nick = g_strdup(nnick);
200
201        status = storage_save(irc, FALSE);
202        if (status != STORAGE_OK) {
203                irc_free(irc);
204                return status;
205        }
206        irc_free(irc);
207
208        storage_remove(onick, password);
209
210        return STORAGE_OK;
211}
212#endif
Note: See TracBrowser for help on using the repository browser.