source: conf.c @ b87e5dc

Last change on this file since b87e5dc was c2969f9, checked in by dequis <dx@…>, at 2015-10-08T04:58:59Z

conf, help: Fix minor leaks in error conditions

From coverity.

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