source: conf.c @ 3c23681

Last change on this file since 3c23681 was 49f1105, checked in by dequis <dx@…>, at 2015-08-19T03:23:44Z

conf: Fix leak of members of conf_t when using -c to specify a config

Can only happen once, and it's just ~200 bytes.

But being valgrind-clean is good.

  • Property mode set to 100644
File size: 11.4 KB
RevLine 
[5ebff60]1/********************************************************************\
[b7d3cc34]2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[c92e6801]4  * Copyright 2002-2005 Wilmer van der Gaast and others                *
[b7d3cc34]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;
[6f10697]22  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
[b7d3cc34]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"
[54879ab]34#include "ipc.h"
[b7d3cc34]35
[df1694b]36#include "proxy.h"
[b7d3cc34]37
[5ebff60]38static int conf_loadini(conf_t *conf, char *file);
[49f1105]39static void conf_free(conf_t *conf);
[b7d3cc34]40
[5ebff60]41conf_t *conf_load(int argc, char *argv[])
[b7d3cc34]42{
43        conf_t *conf;
[eeb85a8]44        int opt, i, config_missing = 0;
[5ebff60]45
46        conf = g_new0(conf_t, 1);
47
[aefaac3a]48        conf->iface_in = NULL;
49        conf->iface_out = NULL;
[5ebff60]50        conf->port = g_strdup("6667");
[b7d3cc34]51        conf->nofork = 0;
52        conf->verbose = 0;
[5ebff60]53        conf->primary_storage = g_strdup("xml");
54        conf->migrate_storage = g_strsplit("text", ",", -1);
[b7d3cc34]55        conf->runmode = RUNMODE_INETD;
56        conf->authmode = AUTHMODE_OPEN;
[d25f6fc]57        conf->auth_pass = NULL;
58        conf->oper_pass = NULL;
[5ebff60]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");
[b7d3cc34]63        conf->ping_interval = 180;
64        conf->ping_timeout = 300;
[aaf92a9]65        conf->user = NULL;
[a02f34f]66        conf->ft_max_size = SIZE_MAX;
67        conf->ft_max_kbps = G_MAXUINT;
68        conf->ft_listen = NULL;
[90cd6c4]69        conf->protocols = NULL;
[486ddb5]70        conf->cafile = NULL;
[f4a5940]71        proxytype = 0;
[5ebff60]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);
[eeb85a8]76                return NULL;
[5ebff60]77        } else if (i == -1) {
78                config_missing++;
[eeb85a8]79                /* Whine after parsing the options if there was no -c pointing
80                   at a *valid* configuration file. */
[b7d3cc34]81        }
[5ebff60]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') {
[74c119d]94                        conf->nofork = 1;
[5ebff60]95                } else if (opt == 'v') {
[74c119d]96                        conf->verbose = 1;
[5ebff60]97                } else if (opt == 'I') {
[74c119d]98                        conf->runmode = RUNMODE_INETD;
[5ebff60]99                } else if (opt == 'D') {
[74c119d]100                        conf->runmode = RUNMODE_DAEMON;
[5ebff60]101                } else if (opt == 'F') {
[74c119d]102                        conf->runmode = RUNMODE_FORKDAEMON;
[5ebff60]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);
[49f1105]107                                conf_free(conf);
[5ebff60]108                                /* Re-evaluate arguments. Don't use this option twice,
[f4a5940]109                                   you'll end up in an infinite loop! Hope this trick
110                                   works with all libcs BTW.. */
[74c119d]111                                optind = 1;
[5ebff60]112                                return conf_load(argc, argv);
[b7d3cc34]113                        }
[5ebff60]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");
[3d1481f]138                        return NULL;
[5ebff60]139                } else if (opt == 'V') {
140                        printf("BitlBee %s\nAPI version %06x\n",
141                               BITLBEE_VERSION, BITLBEE_VERSION_CODE);
[eeb85a8]142                        return NULL;
[5ebff60]143                } else if (opt == 'u') {
144                        g_free(conf->user);
145                        conf->user = g_strdup(optarg);
[aaf92a9]146                }
[b7d3cc34]147        }
[5ebff60]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);
[b7d3cc34]154                conf->configdir = s;
155        }
[5ebff60]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) {
[af5764e]162                /* Let's treat this as a serious problem so people won't think
163                   they're secure when in fact they're not. */
[5ebff60]164                fprintf(stderr, "Error: Could not read CA file %s: %s\n", conf->cafile, strerror(errno));
[af5764e]165                return NULL;
166        }
[5ebff60]167
[eeb85a8]168        return conf;
[b7d3cc34]169}
170
[49f1105]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
[5ebff60]199static int conf_loadini(conf_t *conf, char *file)
[b7d3cc34]200{
201        ini_t *ini;
202        int i;
[5ebff60]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) {
[b7d3cc34]212                                        conf->runmode = RUNMODE_DAEMON;
[5ebff60]213                                } else if (g_strcasecmp(ini->value, "forkdaemon") == 0) {
[d25f6fc]214                                        conf->runmode = RUNMODE_FORKDAEMON;
[5ebff60]215                                } else {
[b7d3cc34]216                                        conf->runmode = RUNMODE_INETD;
[5ebff60]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) {
[b7d3cc34]232                                        conf->authmode = AUTHMODE_REGISTERED;
[5ebff60]233                                } else if (g_strcasecmp(ini->value, "closed") == 0) {
[b7d3cc34]234                                        conf->authmode = AUTHMODE_CLOSED;
[5ebff60]235                                } else {
[b7d3cc34]236                                        conf->authmode = AUTHMODE_OPEN;
[5ebff60]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, "motdfile") == 0) {
251                                g_free(conf->motdfile);
252                                conf->motdfile = g_strdup(ini->value);
253                        } else if (g_strcasecmp(ini->key, "account_storage") == 0) {
254                                g_free(conf->primary_storage);
255                                conf->primary_storage = g_strdup(ini->value);
256                        } else if (g_strcasecmp(ini->key, "account_storage_migrate") == 0) {
257                                g_strfreev(conf->migrate_storage);
258                                conf->migrate_storage = g_strsplit_set(ini->value, " \t,;", -1);
259                        } else if (g_strcasecmp(ini->key, "pinginterval") == 0) {
260                                if (sscanf(ini->value, "%d", &i) != 1) {
261                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
[eeb85a8]262                                        return 0;
[b7d3cc34]263                                }
264                                conf->ping_interval = i;
[5ebff60]265                        } else if (g_strcasecmp(ini->key, "pingtimeout") == 0) {
266                                if (sscanf(ini->value, "%d", &i) != 1) {
267                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
[eeb85a8]268                                        return 0;
[b7d3cc34]269                                }
270                                conf->ping_timeout = i;
[5ebff60]271                        } else if (g_strcasecmp(ini->key, "proxy") == 0) {
272                                url_t *url = g_new0(url_t, 1);
273
274                                if (!url_set(url, ini->value)) {
275                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
276                                        g_free(url);
[eeb85a8]277                                        return 0;
[b7d3cc34]278                                }
[5ebff60]279
280                                strncpy(proxyhost, url->host, sizeof(proxyhost));
281                                strncpy(proxyuser, url->user, sizeof(proxyuser));
282                                strncpy(proxypass, url->pass, sizeof(proxypass));
[b7d3cc34]283                                proxyport = url->port;
[5ebff60]284                                if (url->proto == PROTO_HTTP) {
[b7d3cc34]285                                        proxytype = PROXY_HTTP;
[5ebff60]286                                } else if (url->proto == PROTO_SOCKS4) {
[b7d3cc34]287                                        proxytype = PROXY_SOCKS4;
[5ebff60]288                                } else if (url->proto == PROTO_SOCKS5) {
[b7d3cc34]289                                        proxytype = PROXY_SOCKS5;
[5ebff60]290                                }
291
292                                g_free(url);
293                        } else if (g_strcasecmp(ini->key, "user") == 0) {
294                                g_free(conf->user);
295                                conf->user = g_strdup(ini->value);
296                        } else if (g_strcasecmp(ini->key, "ft_max_size") == 0) {
[a02f34f]297                                size_t ft_max_size;
[5ebff60]298                                if (sscanf(ini->value, "%zu", &ft_max_size) != 1) {
299                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
[a02f34f]300                                        return 0;
301                                }
302                                conf->ft_max_size = ft_max_size;
[5ebff60]303                        } else if (g_strcasecmp(ini->key, "ft_max_kbps") == 0) {
304                                if (sscanf(ini->value, "%d", &i) != 1) {
305                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
[a02f34f]306                                        return 0;
307                                }
308                                conf->ft_max_kbps = i;
[5ebff60]309                        } else if (g_strcasecmp(ini->key, "ft_listen") == 0) {
310                                g_free(conf->ft_listen);
311                                conf->ft_listen = g_strdup(ini->value);
312                        } else if (g_strcasecmp(ini->key, "protocols") == 0) {
313                                g_strfreev(conf->protocols);
314                                conf->protocols = g_strsplit_set(ini->value, " \t,;", -1);
315                        } else if (g_strcasecmp(ini->key, "cafile") == 0) {
316                                g_free(conf->cafile);
317                                conf->cafile = g_strdup(ini->value);
318                        } else {
319                                fprintf(stderr, "Error: Unknown setting `%s` in configuration file (line %d).\n",
320                                        ini->key, ini->line);
[eeb85a8]321                                return 0;
[b7d3cc34]322                                /* For now just ignore unknown keys... */
323                        }
[5ebff60]324                } else if (g_strcasecmp(ini->section, "defaults") != 0) {
325                        fprintf(stderr, "Error: Unknown section [%s] in configuration file (line %d). "
326                                "BitlBee configuration must be put in a [settings] section!\n", ini->section,
327                                ini->line);
[eeb85a8]328                        return 0;
[b7d3cc34]329                }
330        }
[5ebff60]331        ini_close(ini);
332
[eeb85a8]333        return 1;
[b7d3cc34]334}
335
[5ebff60]336void conf_loaddefaults(irc_t *irc)
[b7d3cc34]337{
338        ini_t *ini;
[5ebff60]339
340        ini = ini_open(global.conf_file);
341        if (ini == NULL) {
342                return;
343        }
344        while (ini_read(ini)) {
345                if (g_strcasecmp(ini->section, "defaults") == 0) {
346                        set_t *s = set_find(&irc->b->set, ini->key);
347
348                        if (s) {
349                                if (s->def) {
350                                        g_free(s->def);
351                                }
352                                s->def = g_strdup(ini->value);
[b7d3cc34]353                        }
354                }
355        }
[5ebff60]356        ini_close(ini);
[b7d3cc34]357}
Note: See TracBrowser for help on using the repository browser.