2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2005 Ivo Timmermans
5 2000-2009 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.
28 #include "netutl.h" /* for str2address */
29 #include "utils.h" /* for cp */
32 avl_tree_t *config_tree;
34 int pinginterval = 0; /* seconds between pings */
35 int pingtimeout = 0; /* seconds to wait for response */
36 char *confbase = NULL; /* directory in which all config files are */
37 char *netname = NULL; /* name of the vpn network */
39 static int config_compare(const config_t *a, const config_t *b)
43 result = strcasecmp(a->variable, b->variable);
48 result = a->line - b->line;
53 return strcmp(a->file, b->file);
56 void init_configuration(avl_tree_t ** config_tree)
60 *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
63 void exit_configuration(avl_tree_t ** config_tree)
67 avl_delete_tree(*config_tree);
71 config_t *new_config(void)
75 return xmalloc_and_zero(sizeof(config_t));
78 void free_config(config_t *cfg)
94 void config_add(avl_tree_t *config_tree, config_t *cfg)
98 avl_insert(config_tree, cfg);
101 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
103 config_t cfg, *found;
107 cfg.variable = variable;
111 found = avl_search_closest_greater(config_tree, &cfg);
116 if(strcasecmp(found->variable, variable))
122 config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg)
129 node = avl_search_node(config_tree, cfg);
133 found = node->next->data;
135 if(!strcasecmp(found->variable, cfg->variable))
143 bool get_config_bool(const config_t *cfg, bool *result)
150 if(!strcasecmp(cfg->value, "yes")) {
153 } else if(!strcasecmp(cfg->value, "no")) {
158 logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
159 cfg->variable, cfg->file, cfg->line);
164 bool get_config_int(const config_t *cfg, int *result)
171 if(sscanf(cfg->value, "%d", result) == 1)
174 logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
175 cfg->variable, cfg->file, cfg->line);
180 bool get_config_string(const config_t *cfg, char **result)
187 *result = xstrdup(cfg->value);
192 bool get_config_address(const config_t *cfg, struct addrinfo **result)
201 ai = str2addrinfo(cfg->value, NULL, 0);
208 logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
209 cfg->variable, cfg->file, cfg->line);
214 bool get_config_subnet(const config_t *cfg, subnet_t ** result)
216 subnet_t subnet = {0};
223 if(!str2net(&subnet, cfg->value)) {
224 logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
225 cfg->variable, cfg->file, cfg->line);
229 /* Teach newbies what subnets are... */
231 if(((subnet.type == SUBNET_IPV4)
232 && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
233 || ((subnet.type == SUBNET_IPV6)
234 && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
235 logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
236 cfg->variable, cfg->file, cfg->line);
240 *(*result = new_subnet()) = subnet;
246 Read exactly one line and strip the trailing newline if any. If the
247 file was on EOF, return NULL. Otherwise, return all the data in a
248 dynamically allocated buffer.
250 If line is non-NULL, it will be used as an initial buffer, to avoid
251 unnecessary mallocing each time this function is called. If buf is
252 given, and buf needs to be expanded, the var pointed to by buflen
255 static char *readline(FILE * fp, char **buf, size_t *buflen)
257 char *newline = NULL;
259 char *line; /* The array that contains everything that has been read so far */
260 char *idx; /* Read into this pointer, which points to an offset within line */
261 size_t size, newsize; /* The size of the current array pointed to by line */
262 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
272 line = xmalloc(size);
281 p = fgets(idx, maxlen, fp);
283 if(!p) { /* EOF or error */
287 /* otherwise: error; let the calling function print an error message if applicable */
292 newline = strchr(p, '\n');
294 if(!newline) { /* We haven't yet read everything to the end of the line */
296 line = xrealloc(line, newsize);
297 idx = &line[size - 1];
298 maxlen = newsize - size + 1;
301 *newline = '\0'; /* kill newline */
302 if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
317 Parse a configuration file and put the results in the configuration tree
320 int read_config_file(avl_tree_t *config_tree, const char *fname)
322 int err = -2; /* Parse error */
325 char *variable, *value, *eol;
334 fp = fopen(fname, "r");
337 logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
343 buffer = xmalloc(bufsize);
351 line = readline(fp, &buffer, &bufsize);
360 if(!*line || *line == '#')
364 if(!strncmp(line, "-----END", 8))
369 if(!strncmp(line, "-----BEGIN", 10)) {
374 variable = value = line;
376 eol = line + strlen(line);
377 while(strchr("\t ", *--eol))
380 len = strcspn(value, "\t =");
382 value += strspn(value, "\t ");
385 value += strspn(value, "\t ");
387 variable[len] = '\0';
391 logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
392 variable, lineno, fname);
397 cfg->variable = xstrdup(variable);
398 cfg->value = xstrdup(value);
399 cfg->file = xstrdup(fname);
402 config_add(config_tree, cfg);
411 bool read_server_config()
418 xasprintf(&fname, "%s/tinc.conf", confbase);
419 x = read_config_file(config_tree, fname);
421 if(x == -1) { /* System error: complain */
422 logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
430 FILE *ask_and_open(const char *filename, const char *what)
436 /* Check stdin and stdout */
437 if(!isatty(0) || !isatty(1)) {
438 /* Argh, they are running us from a script or something. Write
439 the files to the current directory and let them burn in hell
441 fn = xstrdup(filename);
443 /* Ask for a file and/or directory name. */
444 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
448 fn = readline(stdin, NULL, NULL);
451 fprintf(stderr, _("Error while reading stdin: %s\n"),
457 /* User just pressed enter. */
458 fn = xstrdup(filename);
462 if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
466 /* The directory is a relative path or a filename. */
469 directory = get_current_dir_name();
470 xasprintf(&p, "%s/%s", directory, fn);
476 umask(0077); /* Disallow everything for group and other */
478 /* Open it first to keep the inode busy */
480 r = fopen(fn, "r+") ?: fopen(fn, "w+");
483 fprintf(stderr, _("Error opening file `%s': %s\n"),
484 fn, strerror(errno));
494 bool disable_old_keys(FILE *f) {
497 bool disabled = false;
502 while(fgets(buf, sizeof buf, f)) {
503 if(!strncmp(buf, "-----BEGIN RSA", 14)) {
507 fseek(f, pos, SEEK_SET);
511 else if(!strncmp(buf, "-----END RSA", 12)) {
515 fseek(f, pos, SEEK_SET);