source: conf.c @ e9eee04

Last change on this file since e9eee04 was 2e5f594, checked in by dequis <dx@…>, at 2022-06-22T11:52:03Z

conf: Improve bitlbee -V output

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