source: conf.c @ d797fb4

Last change on this file since d797fb4 was 34d16d5, checked in by anderspapitto <anderspapitto@…>, at 2015-09-06T02:26:41Z

Allow setting the plugin dir at runtime

This enables the use of bitlbee plugins in scenarios where there is no write access to the bitlbee lib/ directory.

One example is the NixOS linux distribution (which I'm currently packaging a bitlbee plugin for), where post-installation modification of a package (e.g. bitlbee) by another package (e.g. bitlbee-facebook) is not possible.

Another example would be a user without root access building and using a plugin with a system-provided (i.e. installed by root) bitlbee.

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