source: conf.c @ 129e282

Last change on this file since 129e282 was 12f041d, checked in by dequis <dx@…>, at 2015-10-21T13:14:17Z

socks4a proxy support (like socks4 with remote DNS)

Fixes trac ticket 995 https://bugs.bitlbee.org/bitlbee/ticket/995

This is slightly pointless for the suggested use case (tor), since with
socks5 we already send a hostname instead of an IP address.

Either way, it was easy to implement, so I hope it helps.

  • Property mode set to 100644
File size: 11.7 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                                } else if (url->proto == PROTO_SOCKS4A) {
298                                        proxytype = PROXY_SOCKS4A;
299                                }
300
301                                g_free(url);
302                        } else if (g_strcasecmp(ini->key, "user") == 0) {
303                                g_free(conf->user);
304                                conf->user = g_strdup(ini->value);
305                        } else if (g_strcasecmp(ini->key, "ft_max_size") == 0) {
306                                size_t ft_max_size;
307                                if (sscanf(ini->value, "%zu", &ft_max_size) != 1) {
308                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
309                                        return 0;
310                                }
311                                conf->ft_max_size = ft_max_size;
312                        } else if (g_strcasecmp(ini->key, "ft_max_kbps") == 0) {
313                                if (sscanf(ini->value, "%d", &i) != 1) {
314                                        fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value);
315                                        return 0;
316                                }
317                                conf->ft_max_kbps = i;
318                        } else if (g_strcasecmp(ini->key, "ft_listen") == 0) {
319                                g_free(conf->ft_listen);
320                                conf->ft_listen = g_strdup(ini->value);
321                        } else if (g_strcasecmp(ini->key, "protocols") == 0) {
322                                g_strfreev(conf->protocols);
323                                conf->protocols = g_strsplit_set(ini->value, " \t,;", -1);
324                        } else if (g_strcasecmp(ini->key, "cafile") == 0) {
325                                g_free(conf->cafile);
326                                conf->cafile = g_strdup(ini->value);
327                        } else {
328                                fprintf(stderr, "Error: Unknown setting `%s` in configuration file (line %d).\n",
329                                        ini->key, ini->line);
330                                return 0;
331                                /* For now just ignore unknown keys... */
332                        }
333                } else if (g_strcasecmp(ini->section, "defaults") != 0) {
334                        fprintf(stderr, "Error: Unknown section [%s] in configuration file (line %d). "
335                                "BitlBee configuration must be put in a [settings] section!\n", ini->section,
336                                ini->line);
337                        return 0;
338                }
339        }
340        ini_close(ini);
341
342        return 1;
343}
344
345void conf_loaddefaults(irc_t *irc)
346{
347        ini_t *ini;
348
349        ini = ini_open(global.conf_file);
350        if (ini == NULL) {
351                return;
352        }
353        while (ini_read(ini)) {
354                if (g_strcasecmp(ini->section, "defaults") == 0) {
355                        set_t *s = set_find(&irc->b->set, ini->key);
356
357                        if (s) {
358                                if (s->def) {
359                                        g_free(s->def);
360                                }
361                                s->def = g_strdup(ini->value);
362                        }
363                }
364        }
365        ini_close(ini);
366}
Note: See TracBrowser for help on using the repository browser.