source: storage.c @ 50bb490

Last change on this file since 50bb490 was 8e6ecfe, checked in by Dennis Kaarsemaker <dennis@…>, at 2016-03-25T18:07:53Z

Authentication: scaffolding for multiple authentication backends

Instead of always putting users passwords in XML files, allow site
admins to configure a different authentication method to integrate
authentication with other systems.

This doesn't add any authentication backends yet, merely the
scaffolding. Notably:

  • Password checking and loading/removing from storage has been decoupled. A new auth_check_pass function is used to check passwords. It does check against the configured storage first, but will handle the authentication backends as well. The XML storage merely signals that a user's password should be checked using an authentication backend.
  • If unknown-to-bitlbee users identify using an authentication backend, they are automatically registered.
  • If an authentication backend is used, that fact is stored in the XML file, the password is not. Passwords are also stored unencrypted in this case, as the password used to encrypt them can change underneath us.
  • configure and Makefile changes for the backend objects
  • Property mode set to 100644
File size: 4.6 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., 51 Franklin St.,
25  Fifth Floor, Boston, MA  02110-1301  USA
26*/
27
28#define BITLBEE_CORE
29#include "bitlbee.h"
30
31extern storage_t storage_xml;
32
33static GList *storage_backends = NULL;
34
35void register_storage_backend(storage_t *backend)
36{
37        storage_backends = g_list_append(storage_backends, backend);
38}
39
40static storage_t *storage_init_single(const char *name)
41{
42        GList *gl;
43        storage_t *st = NULL;
44
45        for (gl = storage_backends; gl; gl = gl->next) {
46                st = gl->data;
47                if (strcmp(st->name, name) == 0) {
48                        break;
49                }
50        }
51
52        if (gl == NULL) {
53                return NULL;
54        }
55
56        if (st->init) {
57                st->init();
58        }
59
60        return st;
61}
62
63GList *storage_init(const char *primary, char **migrate)
64{
65        GList *ret = NULL;
66        int i;
67        storage_t *storage;
68
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
76        ret = g_list_append(ret, storage);
77
78        for (i = 0; migrate && migrate[i]; i++) {
79                storage = storage_init_single(migrate[i]);
80
81                if (storage) {
82                        ret = g_list_append(ret, storage);
83                }
84        }
85
86        return ret;
87}
88
89storage_status_t storage_check_pass(irc_t *irc, const char *nick, const char *password)
90{
91        GList *gl;
92
93        /* Loop until we don't get NO_SUCH_USER */
94
95        for (gl = global.storage; gl; gl = gl->next) {
96                storage_t *st = gl->data;
97                storage_status_t status;
98
99                status = st->check_pass(irc, nick, password);
100                if (status != STORAGE_NO_SUCH_USER) {
101                        return status;
102                }
103        }
104
105        return STORAGE_NO_SUCH_USER;
106}
107
108storage_status_t storage_load(irc_t * irc, const char *password)
109{
110        GList *gl;
111
112        if (irc && irc->status & USTATUS_IDENTIFIED) {
113                return STORAGE_OTHER_ERROR;
114        }
115
116        /* Loop until we don't get NO_SUCH_USER */
117        for (gl = global.storage; gl; gl = gl->next) {
118                storage_t *st = gl->data;
119                storage_status_t status;
120
121                status = st->load(irc, password);
122                if (status == STORAGE_OK) {
123                        GSList *l;
124                        for (l = irc_plugins; l; l = l->next) {
125                                irc_plugin_t *p = l->data;
126                                if (p->storage_load) {
127                                        p->storage_load(irc);
128                                }
129                        }
130                        return status;
131                }
132
133                if (status != STORAGE_NO_SUCH_USER) {
134                        return status;
135                }
136        }
137
138        return STORAGE_NO_SUCH_USER;
139}
140
141storage_status_t storage_save(irc_t *irc, char *password, int overwrite)
142{
143        storage_status_t st;
144        GSList *l;
145
146        if (password != NULL) {
147                /* Should only use this in the "register" command. */
148                if (irc->password || overwrite) {
149                        return STORAGE_OTHER_ERROR;
150                }
151
152                irc_setpass(irc, password);
153        } else if ((irc->status & USTATUS_IDENTIFIED) == 0) {
154                return STORAGE_NO_SUCH_USER;
155        }
156
157        st = ((storage_t *) global.storage->data)->save(irc, overwrite);
158
159        for (l = irc_plugins; l; l = l->next) {
160                irc_plugin_t *p = l->data;
161                if (p->storage_save) {
162                        p->storage_save(irc);
163                }
164        }
165
166        if (password != NULL) {
167                irc_setpass(irc, NULL);
168        }
169
170        return st;
171}
172
173storage_status_t storage_remove(const char *nick)
174{
175        GList *gl;
176        storage_status_t ret = STORAGE_OK;
177        gboolean ok = FALSE;
178        GSList *l;
179
180        /* Remove this account from all storage backends. If this isn't
181         * done, the account will still be usable, it'd just be
182         * loaded from a different backend. */
183        for (gl = global.storage; gl; gl = gl->next) {
184                storage_t *st = gl->data;
185                storage_status_t status;
186
187                status = st->remove(nick);
188                ok |= status == STORAGE_OK;
189                if (status != STORAGE_NO_SUCH_USER && status != STORAGE_OK) {
190                        ret = status;
191                }
192        }
193
194        /* If at least one succeeded, remove plugin data. */
195        if (ok) {
196                for (l = irc_plugins; l; l = l->next) {
197                        irc_plugin_t *p = l->data;
198                        if (p->storage_remove) {
199                                p->storage_remove(nick);
200                        }
201                }
202        }
203
204        return ret;
205}
Note: See TracBrowser for help on using the repository browser.