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) {
56 *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
59 void exit_configuration(avl_tree_t ** config_tree) {
60 avl_delete_tree(*config_tree);
64 config_t *new_config(void) {
65 return xmalloc_and_zero(sizeof(config_t));
68 void free_config(config_t *cfg) {
81 void config_add(avl_tree_t *config_tree, config_t *cfg) {
82 avl_insert(config_tree, cfg);
85 config_t *lookup_config(avl_tree_t *config_tree, char *variable) {
88 cfg.variable = variable;
92 found = avl_search_closest_greater(config_tree, &cfg);
97 if(strcasecmp(found->variable, variable))
103 config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg) {
107 node = avl_search_node(config_tree, cfg);
111 found = node->next->data;
113 if(!strcasecmp(found->variable, cfg->variable))
121 bool get_config_bool(const config_t *cfg, bool *result) {
125 if(!strcasecmp(cfg->value, "yes")) {
128 } else if(!strcasecmp(cfg->value, "no")) {
133 logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
134 cfg->variable, cfg->file, cfg->line);
139 bool get_config_int(const config_t *cfg, int *result) {
143 if(sscanf(cfg->value, "%d", result) == 1)
146 logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
147 cfg->variable, cfg->file, cfg->line);
152 bool get_config_string(const config_t *cfg, char **result) {
156 *result = xstrdup(cfg->value);
161 bool get_config_address(const config_t *cfg, struct addrinfo **result) {
167 ai = str2addrinfo(cfg->value, NULL, 0);
174 logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
175 cfg->variable, cfg->file, cfg->line);
180 bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
181 subnet_t subnet = {0};
186 if(!str2net(&subnet, cfg->value)) {
187 logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
188 cfg->variable, cfg->file, cfg->line);
192 /* Teach newbies what subnets are... */
194 if(((subnet.type == SUBNET_IPV4)
195 && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
196 || ((subnet.type == SUBNET_IPV6)
197 && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
198 logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
199 cfg->variable, cfg->file, cfg->line);
203 *(*result = new_subnet()) = subnet;
209 Read exactly one line and strip the trailing newline if any. If the
210 file was on EOF, return NULL. Otherwise, return all the data in a
211 dynamically allocated buffer.
213 If line is non-NULL, it will be used as an initial buffer, to avoid
214 unnecessary mallocing each time this function is called. If buf is
215 given, and buf needs to be expanded, the var pointed to by buflen
218 static char *readline(FILE * fp, char **buf, size_t *buflen) {
219 char *newline = NULL;
221 char *line; /* The array that contains everything that has been read so far */
222 char *idx; /* Read into this pointer, which points to an offset within line */
223 size_t size, newsize; /* The size of the current array pointed to by line */
224 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
234 line = xmalloc(size);
243 p = fgets(idx, maxlen, fp);
245 if(!p) { /* EOF or error */
249 /* otherwise: error; let the calling function print an error message if applicable */
254 newline = strchr(p, '\n');
256 if(!newline) { /* We haven't yet read everything to the end of the line */
258 line = xrealloc(line, newsize);
259 idx = &line[size - 1];
260 maxlen = newsize - size + 1;
263 *newline = '\0'; /* kill newline */
264 if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
279 Parse a configuration file and put the results in the configuration tree
282 int read_config_file(avl_tree_t *config_tree, const char *fname) {
283 int err = -2; /* Parse error */
286 char *variable, *value, *eol;
293 fp = fopen(fname, "r");
296 logger(LOG_ERR, "Cannot open config file %s: %s", fname,
302 buffer = xmalloc(bufsize);
310 line = readline(fp, &buffer, &bufsize);
319 if(!*line || *line == '#')
323 if(!strncmp(line, "-----END", 8))
328 if(!strncmp(line, "-----BEGIN", 10)) {
333 variable = value = line;
335 eol = line + strlen(line);
336 while(strchr("\t ", *--eol))
339 len = strcspn(value, "\t =");
341 value += strspn(value, "\t ");
344 value += strspn(value, "\t ");
346 variable[len] = '\0';
350 logger(LOG_ERR, "No value for variable `%s' on line %d while reading config file %s",
351 variable, lineno, fname);
356 cfg->variable = xstrdup(variable);
357 cfg->value = xstrdup(value);
358 cfg->file = xstrdup(fname);
361 config_add(config_tree, cfg);
370 bool read_server_config() {
374 xasprintf(&fname, "%s/tinc.conf", confbase);
375 x = read_config_file(config_tree, fname);
377 if(x == -1) { /* System error: complain */
378 logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
386 FILE *ask_and_open(const char *filename, const char *what) {
391 /* Check stdin and stdout */
392 if(!isatty(0) || !isatty(1)) {
393 /* Argh, they are running us from a script or something. Write
394 the files to the current directory and let them burn in hell
396 fn = xstrdup(filename);
398 /* Ask for a file and/or directory name. */
399 fprintf(stdout, "Please enter a file to save %s to [%s]: ",
403 fn = readline(stdin, NULL, NULL);
406 fprintf(stderr, "Error while reading stdin: %s\n",
412 /* User just pressed enter. */
413 fn = xstrdup(filename);
417 if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
421 /* The directory is a relative path or a filename. */
424 directory = get_current_dir_name();
425 xasprintf(&p, "%s/%s", directory, fn);
431 umask(0077); /* Disallow everything for group and other */
433 /* Open it first to keep the inode busy */
435 r = fopen(fn, "r+") ?: fopen(fn, "w+");
438 fprintf(stderr, "Error opening file `%s': %s\n",
439 fn, strerror(errno));
449 bool disable_old_keys(FILE *f) {
452 bool disabled = false;
457 while(fgets(buf, sizeof buf, f)) {
458 if(!strncmp(buf, "-----BEGIN RSA", 14)) {
462 fseek(f, pos, SEEK_SET);
466 else if(!strncmp(buf, "-----END RSA", 12)) {
470 fseek(f, pos, SEEK_SET);