2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2005 Ivo Timmermans
5 2000-2008 Guus Sliepen <guus@tinc-vpn.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.
30 #include "netutl.h" /* for str2address */
31 #include "utils.h" /* for cp */
34 avl_tree_t *config_tree;
36 int pinginterval = 0; /* seconds between pings */
37 int pingtimeout = 0; /* seconds to wait for response */
38 char *confbase = NULL; /* directory in which all config files are */
39 char *netname = NULL; /* name of the vpn network */
41 static int config_compare(const config_t *a, const config_t *b)
45 result = strcasecmp(a->variable, b->variable);
50 result = a->line - b->line;
55 return strcmp(a->file, b->file);
58 void init_configuration(avl_tree_t ** config_tree)
62 *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
65 void exit_configuration(avl_tree_t ** config_tree)
69 avl_delete_tree(*config_tree);
73 config_t *new_config(void)
77 return xmalloc_and_zero(sizeof(config_t));
80 void free_config(config_t *cfg)
96 void config_add(avl_tree_t *config_tree, config_t *cfg)
100 avl_insert(config_tree, cfg);
103 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
105 config_t cfg, *found;
109 cfg.variable = variable;
113 found = avl_search_closest_greater(config_tree, &cfg);
118 if(strcasecmp(found->variable, variable))
124 config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg)
131 node = avl_search_node(config_tree, cfg);
135 found = node->next->data;
137 if(!strcasecmp(found->variable, cfg->variable))
145 bool get_config_bool(const config_t *cfg, bool *result)
152 if(!strcasecmp(cfg->value, "yes")) {
155 } else if(!strcasecmp(cfg->value, "no")) {
160 logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
161 cfg->variable, cfg->file, cfg->line);
166 bool get_config_int(const config_t *cfg, int *result)
173 if(sscanf(cfg->value, "%d", result) == 1)
176 logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
177 cfg->variable, cfg->file, cfg->line);
182 bool get_config_string(const config_t *cfg, char **result)
189 *result = xstrdup(cfg->value);
194 bool get_config_address(const config_t *cfg, struct addrinfo **result)
203 ai = str2addrinfo(cfg->value, NULL, 0);
210 logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
211 cfg->variable, cfg->file, cfg->line);
216 bool get_config_subnet(const config_t *cfg, subnet_t ** result)
218 subnet_t subnet = {0};
225 if(!str2net(&subnet, cfg->value)) {
226 logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
227 cfg->variable, cfg->file, cfg->line);
231 /* Teach newbies what subnets are... */
233 if(((subnet.type == SUBNET_IPV4)
234 && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
235 || ((subnet.type == SUBNET_IPV6)
236 && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
237 logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
238 cfg->variable, cfg->file, cfg->line);
242 *(*result = new_subnet()) = subnet;
248 Read exactly one line and strip the trailing newline if any. If the
249 file was on EOF, return NULL. Otherwise, return all the data in a
250 dynamically allocated buffer.
252 If line is non-NULL, it will be used as an initial buffer, to avoid
253 unnecessary mallocing each time this function is called. If buf is
254 given, and buf needs to be expanded, the var pointed to by buflen
257 static char *readline(FILE * fp, char **buf, size_t *buflen)
259 char *newline = NULL;
261 char *line; /* The array that contains everything that has been read so far */
262 char *idx; /* Read into this pointer, which points to an offset within line */
263 size_t size, newsize; /* The size of the current array pointed to by line */
264 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
274 line = xmalloc(size);
283 p = fgets(idx, maxlen, fp);
285 if(!p) { /* EOF or error */
289 /* otherwise: error; let the calling function print an error message if applicable */
294 newline = strchr(p, '\n');
296 if(!newline) { /* We haven't yet read everything to the end of the line */
298 line = xrealloc(line, newsize);
299 idx = &line[size - 1];
300 maxlen = newsize - size + 1;
303 *newline = '\0'; /* kill newline */
304 if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
319 Parse a configuration file and put the results in the configuration tree
322 int read_config_file(avl_tree_t *config_tree, const char *fname)
324 int err = -2; /* Parse error */
327 char *variable, *value, *eol;
336 fp = fopen(fname, "r");
339 logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
345 buffer = xmalloc(bufsize);
353 line = readline(fp, &buffer, &bufsize);
362 if(!*line || *line == '#')
366 if(!strncmp(line, "-----END", 8))
371 if(!strncmp(line, "-----BEGIN", 10)) {
376 variable = value = line;
378 eol = line + strlen(line);
379 while(strchr("\t ", *--eol))
382 len = strcspn(value, "\t =");
384 value += strspn(value, "\t ");
387 value += strspn(value, "\t ");
389 variable[len] = '\0';
393 logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
394 variable, lineno, fname);
399 cfg->variable = xstrdup(variable);
400 cfg->value = xstrdup(value);
401 cfg->file = xstrdup(fname);
404 config_add(config_tree, cfg);
413 bool read_server_config()
420 asprintf(&fname, "%s/tinc.conf", confbase);
421 x = read_config_file(config_tree, fname);
423 if(x == -1) { /* System error: complain */
424 logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
432 FILE *ask_and_open(const char *filename, const char *what, const char *mode)
438 /* Check stdin and stdout */
439 if(!isatty(0) || !isatty(1)) {
440 /* Argh, they are running us from a script or something. Write
441 the files to the current directory and let them burn in hell
443 fn = xstrdup(filename);
445 /* Ask for a file and/or directory name. */
446 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
450 fn = readline(stdin, NULL, NULL);
453 fprintf(stderr, _("Error while reading stdin: %s\n"),
459 /* User just pressed enter. */
460 fn = xstrdup(filename);
464 if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
468 /* The directory is a relative path or a filename. */
471 directory = get_current_dir_name();
472 asprintf(&p, "%s/%s", directory, fn);
478 umask(0077); /* Disallow everything for group and other */
480 /* Open it first to keep the inode busy */
485 fprintf(stderr, _("Error opening file `%s': %s\n"),
486 fn, strerror(errno));