source: conf.c @ 297d2129

Last change on this file since 297d2129 was 365dd59, checked in by Ævar Arnfjörð Bjarmason <avarab@…>, at 2019-05-23T08:57:02Z

conf: support AccountStorage as well as Account_Storage

These variables added way back in b73ac9c3 ("Add support for 'primary'
and 'migrate' account storages. [...]", 2005-12-14). I think that
these have never been used by anyone, I think Dennis's out-of-tree
MySQL backend is the only storage backend anyone bothered to write.

That backend uses "AccountStorage" in the config, not
"Account_Storage". Let's support that, we could just change this over,
but *maybe* someone uses it out of tree, and supporting their config
in that case is easy.

I'm forward-porting https://github.com/bitlbee/bitlbee/pull/67 there's
production code that uses the CamelCase variant, and it would be handy
if it worked as-is without needing to fiddle with the config.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@…>

  • Property mode set to 100644
File size: 12.6 KB
Line 
1/********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2005 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Configuration reading code                                           */
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., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
24*/
25
26#include "bitlbee.h"
27
28#include <stdio.h>
29#include <string.h>
30#include <stdlib.h>
31#include "conf.h"
32#include "ini.h"
33#include "url.h"
34#include "ipc.h"
35
36#include "proxy.h"
37
38static int conf_loadini(conf_t *conf, char *file);
39static void conf_free(conf_t *conf);
40
41conf_t *conf_load(int argc, char *argv[])
42{
43        conf_t *conf;
44        int opt, i, config_missing = 0;
45
46        conf = g_new0(conf_t, 1);
47
48        conf->iface_in = NULL;
49        conf->iface_out = NULL;
50        conf->port = g_strdup("6667");
51        conf->nofork = 0;
52        conf->verbose = 0;
53        conf->primary_storage = g_strdup("xml");
54        conf->migrate_storage = g_strsplit("text", ",", -1);
55        conf->runmode = RUNMODE_INETD;
56        conf->authmode = AUTHMODE_OPEN;
57        conf->auth_backend = NULL;
58        conf->auth_pass = NULL;
59        conf->oper_pass = NULL;
60        conf->allow_account_add = 1;
61        conf->configdir = g_strdup(CONFIG);
62        conf->plugindir = g_strdup(PLUGINDIR);
63        conf->pidfile = g_strdup(PIDFILE);
64        conf->motdfile = g_strdup(ETCDIR "/motd.txt");
65        conf->ping_interval = 180;
66        conf->ping_timeout = 300;
67        conf->user = NULL;
68        conf->ft_max_size = SIZE_MAX;
69        conf->ft_max_kbps = G_MAXUINT;
70        conf->ft_listen = NULL;
71        conf->protocols = NULL;
72        conf->cafile = NULL;
73        proxytype = 0;
74
75        i = conf_loadini(conf, global.conf_file);
76        if (i == 0) {
77                fprintf(stderr, "Error: Syntax error in configuration file `%s'.\n", global.conf_file);
78                conf_free(conf);
79                return NULL;
80        } else if (i == -1) {
81                config_missing++;
82                /* Whine after parsing the options if there was no -c pointing
83                   at a *valid* configuration file. */
84        }
85
86        while (argc > 0 && (opt = getopt(argc, argv, "i:p:P:nvIDFc:d:hu:V")) >= 0) {
87                /*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
88                if (opt == 'i') {
89                        conf->iface_in = g_strdup(optarg);
90                } else if (opt == 'p') {
91                        g_free(conf->port);
92                        conf->port = g_strdup(optarg);
93                } else if (opt == 'P') {
94                        g_free(conf->pidfile);
95                        conf->pidfile = g_strdup(optarg);
96                } else if (opt == 'n') {
97                        conf->nofork = 1;
98                } else if (opt == 'v') {
99                        conf->verbose = 1;
100                } else if (opt == 'I') {
101                        conf->runmode = RUNMODE_INETD;
102                } else if (opt == 'D') {
103                        conf->runmode = RUNMODE_DAEMON;
104                } else if (opt == 'F') {
105                        conf->runmode = RUNMODE_FORKDAEMON;
106                } else if (opt == 'c') {
107                        if (strcmp(global.conf_file, optarg) != 0) {
108                                g_free(global.conf_file);
109                                global.conf_file = g_strdup(optarg);
110                                conf_free(conf);
111                                /* Re-evaluate arguments. Don't use this option twice,
112                                   you'll end up in an infinite loop! Hope this trick
113                                   works with all libcs BTW.. */
114                                optind = 1;
115                                return conf_load(argc, argv);
116                        }
117                } else if (opt == 'd') {
118                        g_free(conf->configdir);
119                        conf->configdir = g_strdup(optarg);
120                } else if (opt == 'h') {
121                        printf("Usage: bitlbee [-D/-F [-i <interface>] [-p <port>] [-n] [-v]] [-I]\n"
122                               "               [-c <file>] [-d <dir>] [-x] [-h]\n"
123                               "\n"
124                               "An IRC-to-other-chat-networks gateway\n"
125                               "\n"
126                               "  -I  Classic/InetD mode. (Default)\n"
127                               "  -D  Daemon mode. (one process serves all)\n"
128                               "  -F  Forking daemon. (one process per client)\n"
129                               "  -u  Run daemon as specified user.\n"
130                               "  -P  Specify PID-file (not for inetd mode)\n"
131                               "  -i  Specify the interface (by IP address) to listen on.\n"
132                               "      (Default: 0.0.0.0 (any interface))\n"
133                               "  -p  Port number to listen on. (Default: 6667)\n"
134                               "  -n  Don't fork.\n"
135                               "  -v  Be verbose (only works in combination with -n)\n"
136                               "  -c  Load alternative configuration file\n"
137                               "  -d  Specify alternative user configuration directory\n"
138                               "  -x  Command-line interface to password encryption/hashing\n"
139                               "  -h  Show this help page.\n"
140                               "  -V  Show version info.\n");
141                        conf_free(conf);
142                        return NULL;
143                } else if (opt == 'V') {
144                        printf("BitlBee %s\nAPI version %06x\nConfigure args: %s\n",
145                               BITLBEE_VERSION, BITLBEE_VERSION_CODE, BITLBEE_CONFIGURE_ARGS);
146                        conf_free(conf);
147                        return NULL;
148                } else if (opt == 'u') {
149                        g_free(conf->user);
150                        conf->user = g_strdup(optarg);
151                }
152        }
153
154        if (conf->configdir[strlen(conf->configdir) - 1] != '/') {
155                char *s = g_new(char, strlen(conf->configdir) + 2);
156
157                sprintf(s, "%s/", conf->configdir);
158                g_free(conf->configdir);
159                conf->configdir = s;
160        }
161
162        if (config_missing) {
163                fprintf(stderr, "Warning: Unable to read configuration file `%s'.\n", global.conf_file);
164        }
165
166        if (conf->cafile && access(conf->cafile, R_OK) != 0) {
167                /* Let's treat this as a serious problem so people won't think
168                   they're secure when in fact they're not. */
169                fprintf(stderr, "Error: Could not read CA file %s: %s\n", conf->cafile, strerror(errno));
170                conf_free(conf);
171                return NULL;
172        }
173
174        return conf;
175}
176
177static void conf_free(conf_t *conf)
178{
179        /* Free software means users have the four essential freedoms:
180           0. to run the program,
181           2. to study and change the program in source code form,
182           2. to redistribute exact copies, and
183           3. to distribute modified versions
184        */
185        g_free(conf->auth_pass);
186        g_free(conf->cafile);
187        g_free(conf->configdir);
188        g_free(conf->ft_listen);
189        g_free(conf->hostname);
190        g_free(conf->iface_in);
191        g_free(conf->iface_out);
192        g_free(conf->motdfile);
193        g_free(conf->oper_pass);
194        g_free(conf->pidfile);
195        g_free(conf->plugindir);
196        g_free(conf->port);
197        g_free(conf->primary_storage);
198        g_free(conf->user);
199        g_strfreev(conf->migrate_storage);
200        g_strfreev(conf->protocols);
201        g_free(conf);
202
203}
204
205static int conf_loadini(conf_t *conf, char *file)
206{
207        ini_t *ini;
208        int i;
209
210        ini = ini_open(file);
211        if (ini == NULL) {
212                return -1;
213        }
214        while (ini_read(ini)) {
215                if (g_strcasecmp(ini->section, "settings") == 0) {
216                        if (g_strcasecmp(ini->key, "runmode") == 0) {
217                                if (g_strcasecmp(ini->value, "daemon") == 0) {
218                                        conf->runmode = RUNMODE_DAEMON;
219                                } else if (g_strcasecmp(ini->value, "forkdaemon") == 0) {
220                                        conf->runmode = RUNMODE_FORKDAEMON;
221                                } else {
222                                        conf->runmode = RUNMODE_INETD;
223                                }
224                        } else if (g_strcasecmp(ini->key, "pidfile") == 0) {
225                                g_free(conf->pidfile);
226                                conf->pidfile = g_strdup(ini->value);
227                        } else if (g_strcasecmp(ini->key, "daemoninterface") == 0) {
228                                g_free(conf->iface_in);
229                                conf->iface_in = g_strdup(ini->value);
230                        } else if (g_strcasecmp(ini->key, "daemonport") == 0) {
231                                g_free(conf->port);
232                                conf->port = g_strdup(ini->value);
233                        } else if (g_strcasecmp(ini->key, "clientinterface") == 0) {
234                                g_free(conf->iface_out);
235                                conf->iface_out = g_strdup(ini->value);
236                        } else if (g_strcasecmp(ini->key, "authmode") == 0) {
237                                if (g_strcasecmp(ini->value, "registered") == 0) {
238                                        conf->authmode = AUTHMODE_REGISTERED;
239                                } else if (g_strcasecmp(ini->value, "closed") == 0) {
240                                        conf->authmode = AUTHMODE_CLOSED;
241                                } else {
242                                        conf->authmode = AUTHMODE_OPEN;
243                                }
244                        } else if (g_strcasecmp(ini->key, "authbackend") == 0) {
245                                if (g_strcasecmp(ini->value, "storage") == 0) {
246                                        conf->auth_backend = NULL;
247                                } else if (g_strcasecmp(ini->value, "pam") == 0 ||
248                                         g_strcasecmp(ini->value, "ldap") == 0) {
249                                        g_free(conf->auth_backend);
250                                        conf->auth_backend = g_strdup(ini->value);
251                                } else {
252                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
253                                        return 0;
254                                }
255                        } else if (g_strcasecmp(ini->key, "authpassword") == 0) {
256                                g_free(conf->auth_pass);
257                                conf->auth_pass = g_strdup(ini->value);
258                        } else if (g_strcasecmp(ini->key, "operpassword") == 0) {
259                                g_free(conf->oper_pass);
260                                conf->oper_pass = g_strdup(ini->value);
261                        } else if (g_strcasecmp(ini->key, "allowaccountadd") == 0) {
262                                if (!is_bool(ini->value)) {
263                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
264                                        return 0;
265                                }
266                                conf->allow_account_add = bool2int(ini->value);
267                        } else if (g_strcasecmp(ini->key, "hostname") == 0) {
268                                g_free(conf->hostname);
269                                conf->hostname = g_strdup(ini->value);
270                        } else if (g_strcasecmp(ini->key, "configdir") == 0) {
271                                g_free(conf->configdir);
272                                conf->configdir = g_strdup(ini->value);
273                        } else if (g_strcasecmp(ini->key, "plugindir") == 0) {
274                                g_free(conf->plugindir);
275                                conf->plugindir = g_strdup(ini->value);
276                        } else if (g_strcasecmp(ini->key, "motdfile") == 0) {
277                                g_free(conf->motdfile);
278                                conf->motdfile = g_strdup(ini->value);
279                        } else if (g_strcasecmp(ini->key, "accountstorage") == 0 ||
280                                   g_strcasecmp(ini->key, "account_storage") == 0) {
281                                g_free(conf->primary_storage);
282                                conf->primary_storage = g_strdup(ini->value);
283                        } else if (g_strcasecmp(ini->key, "accountstoragemigrate") == 0 ||
284                                   g_strcasecmp(ini->key, "account_storage_migrate") == 0) {
285                                g_strfreev(conf->migrate_storage);
286                                conf->migrate_storage = g_strsplit_set(ini->value, " \t,;", -1);
287                        } else if (g_strcasecmp(ini->key, "pinginterval") == 0) {
288                                if (sscanf(ini->value, "%d", &i) != 1) {
289                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
290                                        return 0;
291                                }
292                                conf->ping_interval = i;
293                        } else if (g_strcasecmp(ini->key, "pingtimeout") == 0) {
294                                if (sscanf(ini->value, "%d", &i) != 1) {
295                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
296                                        return 0;
297                                }
298                                conf->ping_timeout = i;
299                        } else if (g_strcasecmp(ini->key, "proxy") == 0) {
300                                url_t *url = g_new0(url_t, 1);
301
302                                if (!url_set(url, ini->value)) {
303                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
304                                        g_free(url);
305                                        return 0;
306                                }
307
308                                strncpy(proxyhost, url->host, sizeof(proxyhost));
309                                strncpy(proxyuser, url->user, sizeof(proxyuser));
310                                strncpy(proxypass, url->pass, sizeof(proxypass));
311                                proxyport = url->port;
312                                if (url->proto == PROTO_HTTP) {
313                                        proxytype = PROXY_HTTP;
314                                } else if (url->proto == PROTO_SOCKS4) {
315                                        proxytype = PROXY_SOCKS4;
316                                } else if (url->proto == PROTO_SOCKS5) {
317                                        proxytype = PROXY_SOCKS5;
318                                } else if (url->proto == PROTO_SOCKS4A) {
319                                        proxytype = PROXY_SOCKS4A;
320                                }
321
322                                g_free(url);
323                        } else if (g_strcasecmp(ini->key, "user") == 0) {
324                                g_free(conf->user);
325                                conf->user = g_strdup(ini->value);
326                        } else if (g_strcasecmp(ini->key, "ft_max_size") == 0) {
327                                size_t ft_max_size;
328                                if (sscanf(ini->value, "%zu", &ft_max_size) != 1) {
329                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
330                                        return 0;
331                                }
332                                conf->ft_max_size = ft_max_size;
333                        } else if (g_strcasecmp(ini->key, "ft_max_kbps") == 0) {
334                                if (sscanf(ini->value, "%d", &i) != 1) {
335                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
336                                        return 0;
337                                }
338                                conf->ft_max_kbps = i;
339                        } else if (g_strcasecmp(ini->key, "ft_listen") == 0) {
340                                g_free(conf->ft_listen);
341                                conf->ft_listen = g_strdup(ini->value);
342                        } else if (g_strcasecmp(ini->key, "protocols") == 0) {
343                                g_strfreev(conf->protocols);
344                                conf->protocols = g_strsplit_set(ini->value, " \t,;", -1);
345                        } else if (g_strcasecmp(ini->key, "cafile") == 0) {
346                                g_free(conf->cafile);
347                                conf->cafile = g_strdup(ini->value);
348                        } else {
349                                fprintf(stderr, "Error: Unknown setting `%s` in configuration file (line %d).\n",
350                                        ini->key, ini->line);
351                                return 0;
352                                /* For now just ignore unknown keys... */
353                        }
354                } else if (g_strcasecmp(ini->section, "defaults") != 0) {
355                        fprintf(stderr, "Error: Unknown section [%s] in configuration file (line %d). "
356                                "BitlBee configuration must be put in a [settings] section!\n", ini->section,
357                                ini->line);
358                        return 0;
359                }
360        }
361        ini_close(ini);
362
363        return 1;
364}
365
366void conf_loaddefaults(irc_t *irc)
367{
368        ini_t *ini;
369
370        ini = ini_open(global.conf_file);
371        if (ini == NULL) {
372                return;
373        }
374        while (ini_read(ini)) {
375                if (g_strcasecmp(ini->section, "defaults") == 0) {
376                        set_t *s = set_find(&irc->b->set, ini->key);
377
378                        if (s) {
379                                if (s->def) {
380                                        g_free(s->def);
381                                }
382                                s->def = g_strdup(ini->value);
383                        }
384                }
385        }
386        ini_close(ini);
387}
Note: See TracBrowser for help on using the repository browser.