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 along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) {
42 result = strcasecmp(a->variable, b->variable);
47 result = a->line - b->line;
52 return strcmp(a->file, b->file);
55 void init_configuration(avl_tree_t ** config_tree) {
58 *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
61 void exit_configuration(avl_tree_t ** config_tree) {
64 avl_delete_tree(*config_tree);
68 config_t *new_config(void) {
71 return xmalloc_and_zero(sizeof(config_t));
74 void free_config(config_t *cfg) {
89 void config_add(avl_tree_t *config_tree, config_t *cfg) {
92 avl_insert(config_tree, cfg);
95 config_t *lookup_config(avl_tree_t *config_tree, char *variable) {
100 cfg.variable = variable;
104 found = avl_search_closest_greater(config_tree, &cfg);
109 if(strcasecmp(found->variable, variable))
115 config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg) {
121 node = avl_search_node(config_tree, cfg);
125 found = node->next->data;
127 if(!strcasecmp(found->variable, cfg->variable))
135 bool get_config_bool(const config_t *cfg, bool *result) {
141 if(!strcasecmp(cfg->value, "yes")) {
144 } else if(!strcasecmp(cfg->value, "no")) {
149 logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
150 cfg->variable, cfg->file, cfg->line);
155 bool get_config_int(const config_t *cfg, int *result) {
161 if(sscanf(cfg->value, "%d", result) == 1)
164 logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
165 cfg->variable, cfg->file, cfg->line);
170 bool get_config_string(const config_t *cfg, char **result) {
176 *result = xstrdup(cfg->value);
181 bool get_config_address(const config_t *cfg, struct addrinfo **result) {
189 ai = str2addrinfo(cfg->value, NULL, 0);
196 logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
197 cfg->variable, cfg->file, cfg->line);
202 bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
203 subnet_t subnet = {0};
210 if(!str2net(&subnet, cfg->value)) {
211 logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
212 cfg->variable, cfg->file, cfg->line);
216 /* Teach newbies what subnets are... */
218 if(((subnet.type == SUBNET_IPV4)
219 && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
220 || ((subnet.type == SUBNET_IPV6)
221 && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
222 logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
223 cfg->variable, cfg->file, cfg->line);
227 *(*result = new_subnet()) = subnet;
233 Read exactly one line and strip the trailing newline if any. If the
234 file was on EOF, return NULL. Otherwise, return all the data in a
235 dynamically allocated buffer.
237 If line is non-NULL, it will be used as an initial buffer, to avoid
238 unnecessary mallocing each time this function is called. If buf is
239 given, and buf needs to be expanded, the var pointed to by buflen
242 static char *readline(FILE * fp, char **buf, size_t *buflen) {
243 char *newline = NULL;
245 char *line; /* The array that contains everything that has been read so far */
246 char *idx; /* Read into this pointer, which points to an offset within line */
247 size_t size, newsize; /* The size of the current array pointed to by line */
248 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
258 line = xmalloc(size);
267 p = fgets(idx, maxlen, fp);
269 if(!p) { /* EOF or error */
273 /* otherwise: error; let the calling function print an error message if applicable */
278 newline = strchr(p, '\n');
280 if(!newline) { /* We haven't yet read everything to the end of the line */
282 line = xrealloc(line, newsize);
283 idx = &line[size - 1];
284 maxlen = newsize - size + 1;
287 *newline = '\0'; /* kill newline */
288 if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
303 Parse a configuration file and put the results in the configuration tree
306 int read_config_file(avl_tree_t *config_tree, const char *fname) {
307 int err = -2; /* Parse error */
310 char *variable, *value, *eol;
319 fp = fopen(fname, "r");
322 logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
328 buffer = xmalloc(bufsize);
336 line = readline(fp, &buffer, &bufsize);
345 if(!*line || *line == '#')
349 if(!strncmp(line, "-----END", 8))
354 if(!strncmp(line, "-----BEGIN", 10)) {
359 variable = value = line;
361 eol = line + strlen(line);
362 while(strchr("\t ", *--eol))
365 len = strcspn(value, "\t =");
367 value += strspn(value, "\t ");
370 value += strspn(value, "\t ");
372 variable[len] = '\0';
376 logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
377 variable, lineno, fname);
382 cfg->variable = xstrdup(variable);
383 cfg->value = xstrdup(value);
384 cfg->file = xstrdup(fname);
387 config_add(config_tree, cfg);
396 bool read_server_config() {
402 xasprintf(&fname, "%s/tinc.conf", confbase);
403 x = read_config_file(config_tree, fname);
405 if(x == -1) { /* System error: complain */
406 logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
414 FILE *ask_and_open(const char *filename, const char *what) {
419 /* Check stdin and stdout */
420 if(!isatty(0) || !isatty(1)) {
421 /* Argh, they are running us from a script or something. Write
422 the files to the current directory and let them burn in hell
424 fn = xstrdup(filename);
426 /* Ask for a file and/or directory name. */
427 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
431 fn = readline(stdin, NULL, NULL);
434 fprintf(stderr, _("Error while reading stdin: %s\n"),
440 /* User just pressed enter. */
441 fn = xstrdup(filename);
445 if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
449 /* The directory is a relative path or a filename. */
452 directory = get_current_dir_name();
453 xasprintf(&p, "%s/%s", directory, fn);
459 umask(0077); /* Disallow everything for group and other */
461 /* Open it first to keep the inode busy */
463 r = fopen(fn, "r+") ?: fopen(fn, "w+");
466 fprintf(stderr, _("Error opening file `%s': %s\n"),
467 fn, strerror(errno));
477 bool disable_old_keys(FILE *f) {
480 bool disabled = false;
485 while(fgets(buf, sizeof buf, f)) {
486 if(!strncmp(buf, "-----BEGIN RSA", 14)) {
490 fseek(f, pos, SEEK_SET);
494 else if(!strncmp(buf, "-----END RSA", 12)) {
498 fseek(f, pos, SEEK_SET);