source: conf.c @ a6005da

Last change on this file since a6005da was a6005da, checked in by Dennis Kaarsemaker <dennis@…>, at 2016-03-25T18:07:53Z

Linux pam authentication backend

This backend authenticates users against pam.

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