2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2003 Ivo Timmermans <ivo@o2w.nl>
5 2000-2003 Guus Sliepen <guus@sliepen.eu.org>
6 2000 Cris van Pelt <tribbel@arise.dhs.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 $Id: conf.c,v 1.9.4.77 2003/12/12 19:52:24 guus Exp $
30 #include "netutl.h" /* for str2address */
31 #include "utils.h" /* for cp */
34 avl_tree_t *config_tree;
36 int pingtimeout = 0; /* seconds before timeout */
37 char *confbase = NULL; /* directory in which all config files are */
38 char *netname = NULL; /* name of the vpn network */
40 static int config_compare(const config_t *a, const config_t *b)
44 result = strcasecmp(a->variable, b->variable);
49 result = a->line - b->line;
54 return strcmp(a->file, b->file);
57 void init_configuration(avl_tree_t ** config_tree)
61 *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
64 void exit_configuration(avl_tree_t ** config_tree)
68 avl_delete_tree(*config_tree);
72 config_t *new_config(void)
76 return xmalloc_and_zero(sizeof(config_t));
79 void free_config(config_t *cfg)
95 void config_add(avl_tree_t *config_tree, config_t *cfg)
99 avl_insert(config_tree, cfg);
102 config_t *lookup_config(const avl_tree_t *config_tree, char *variable)
104 config_t cfg, *found;
108 cfg.variable = variable;
112 found = avl_search_closest_greater(config_tree, &cfg);
117 if(strcasecmp(found->variable, variable))
123 config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg)
130 node = avl_search_node(config_tree, cfg);
134 found = node->next->data;
136 if(!strcasecmp(found->variable, cfg->variable))
144 bool get_config_bool(const config_t *cfg, bool *result)
151 if(!strcasecmp(cfg->value, "yes")) {
154 } else if(!strcasecmp(cfg->value, "no")) {
159 logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
160 cfg->variable, cfg->file, cfg->line);
165 bool get_config_int(const config_t *cfg, int *result)
172 if(sscanf(cfg->value, "%d", result) == 1)
175 logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
176 cfg->variable, cfg->file, cfg->line);
181 bool get_config_string(const config_t *cfg, char **result)
188 *result = xstrdup(cfg->value);
193 bool get_config_address(const config_t *cfg, struct addrinfo **result)
202 ai = str2addrinfo(cfg->value, NULL, 0);
209 logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
210 cfg->variable, cfg->file, cfg->line);
215 bool get_config_subnet(const config_t *cfg, subnet_t ** result)
217 subnet_t subnet = {0};
224 if(!str2net(&subnet, cfg->value)) {
225 logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
226 cfg->variable, cfg->file, cfg->line);
230 /* Teach newbies what subnets are... */
232 if(((subnet.type == SUBNET_IPV4)
233 && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
234 || ((subnet.type == SUBNET_IPV6)
235 && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
236 logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
237 cfg->variable, cfg->file, cfg->line);
241 *(*result = new_subnet()) = subnet;
247 Read exactly one line and strip the trailing newline if any. If the
248 file was on EOF, return NULL. Otherwise, return all the data in a
249 dynamically allocated buffer.
251 If line is non-NULL, it will be used as an initial buffer, to avoid
252 unnecessary mallocing each time this function is called. If buf is
253 given, and buf needs to be expanded, the var pointed to by buflen
256 static char *readline(FILE * fp, char **buf, size_t *buflen)
258 char *newline = NULL;
260 char *line; /* The array that contains everything that has been read so far */
261 char *idx; /* Read into this pointer, which points to an offset within line */
262 size_t size, newsize; /* The size of the current array pointed to by line */
263 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
273 line = xmalloc(size);
282 p = fgets(idx, maxlen, fp);
284 if(!p) { /* EOF or error */
288 /* otherwise: error; let the calling function print an error message if applicable */
293 newline = strchr(p, '\n');
295 if(!newline) { /* We haven't yet read everything to the end of the line */
297 line = xrealloc(line, newsize);
298 idx = &line[size - 1];
299 maxlen = newsize - size + 1;
302 *newline = '\0'; /* kill newline */
316 Parse a configuration file and put the results in the configuration tree
319 int read_config_file(avl_tree_t *config_tree, const char *fname)
321 int err = -2; /* Parse error */
324 char *variable, *value;
333 fp = fopen(fname, "r");
336 logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
342 buffer = xmalloc(bufsize);
345 line = readline(fp, &buffer, &bufsize);
359 if(!*line || *line == '#')
363 if(!strncmp(line, "-----END", 8))
368 if(!strncmp(line, "-----BEGIN", 10)) {
373 variable = value = line;
375 len = strcspn(value, "\t =");
377 value += strspn(value, "\t ");
380 value += strspn(value, "\t ");
382 variable[len] = '\0';
385 logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
386 variable, lineno, fname);
391 cfg->variable = xstrdup(variable);
392 cfg->value = xstrdup(value);
393 cfg->file = xstrdup(fname);
396 config_add(config_tree, cfg);
405 bool read_server_config()
412 asprintf(&fname, "%s/tinc.conf", confbase);
413 x = read_config_file(config_tree, fname);
415 if(x == -1) { /* System error: complain */
416 logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
424 FILE *ask_and_open(const char *filename, const char *what, const char *mode)
430 /* Check stdin and stdout */
431 if(!isatty(0) || !isatty(1)) {
432 /* Argh, they are running us from a script or something. Write
433 the files to the current directory and let them burn in hell
435 fn = xstrdup(filename);
437 /* Ask for a file and/or directory name. */
438 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
442 fn = readline(stdin, NULL, NULL);
445 fprintf(stderr, _("Error while reading stdin: %s\n"),
451 /* User just pressed enter. */
452 fn = xstrdup(filename);
456 if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
460 /* The directory is a relative path or a filename. */
463 directory = get_current_dir_name();
464 asprintf(&p, "%s/%s", directory, fn);
470 umask(0077); /* Disallow everything for group and other */
472 /* Open it first to keep the inode busy */
477 fprintf(stderr, _("Error opening file `%s': %s\n"),
478 fn, strerror(errno));