2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>
5 2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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.56 2002/06/08 12:57:09 guus Exp $
35 #include <sys/types.h>
41 #include <utils.h> /* for cp */
45 #include "netutl.h" /* for str2address */
49 avl_tree_t *config_tree;
52 int pingtimeout = 0; /* seconds before timeout */
53 char *confbase = NULL; /* directory in which all config files are */
54 char *netname = NULL; /* name of the vpn network */
56 int config_compare(config_t *a, config_t *b)
60 result = strcasecmp(a->variable, b->variable);
65 result = a->line - b->line;
70 return strcmp(a->file, b->file);
73 void init_configuration(avl_tree_t **config_tree)
76 *config_tree = avl_alloc_tree((avl_compare_t)config_compare, (avl_action_t)free_config);
80 void exit_configuration(avl_tree_t **config_tree)
83 avl_delete_tree(*config_tree);
88 config_t *new_config(void)
92 cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg));
97 void free_config(config_t *cfg)
110 void config_add(avl_tree_t *config_tree, config_t *cfg)
113 avl_insert(config_tree, cfg);
117 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
119 config_t cfg, *found;
121 cfg.variable = variable;
125 found = avl_search_closest_greater(config_tree, &cfg);
130 if(strcasecmp(found->variable, variable))
136 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
141 node = avl_search_node(config_tree, cfg);
147 found = (config_t *)node->next->data;
148 if(!strcasecmp(found->variable, cfg->variable))
156 int get_config_bool(config_t *cfg, int *result)
162 if(!strcasecmp(cfg->value, "yes"))
167 else if(!strcasecmp(cfg->value, "no"))
173 syslog(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
174 cfg->variable, cfg->file, cfg->line);
179 int get_config_int(config_t *cfg, int *result)
185 if(sscanf(cfg->value, "%d", result) == 1)
188 syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
189 cfg->variable, cfg->file, cfg->line);
193 int get_config_string(config_t *cfg, char **result)
199 *result = xstrdup(cfg->value);
203 int get_config_address(config_t *cfg, struct addrinfo **result)
210 ai = str2addrinfo(cfg->value, NULL, 0);
218 syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
219 cfg->variable, cfg->file, cfg->line);
223 int get_config_port(config_t *cfg, port_t *result)
229 if(sscanf(cfg->value, "%hu", result) == 1)
231 *result = htons(*result);
235 syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
236 cfg->variable, cfg->file, cfg->line);
240 int get_config_subnet(config_t *cfg, subnet_t **result)
247 subnet = str2net(cfg->value);
251 syslog(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
252 cfg->variable, cfg->file, cfg->line);
256 /* Teach newbies what subnets are... */
258 if(((subnet->type == SUBNET_IPV4) && maskcheck(&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
259 || ((subnet->type == SUBNET_IPV6) && maskcheck(&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t))))
261 syslog(LOG_ERR, _("Network address and prefix length do not match for configuration variable %s in %s line %d"),
262 cfg->variable, cfg->file, cfg->line);
273 Read exactly one line and strip the trailing newline if any. If the
274 file was on EOF, return NULL. Otherwise, return all the data in a
275 dynamically allocated buffer.
277 If line is non-NULL, it will be used as an initial buffer, to avoid
278 unnecessary mallocing each time this function is called. If buf is
279 given, and buf needs to be expanded, the var pointed to by buflen
282 char *readline(FILE *fp, char **buf, size_t *buflen)
284 char *newline = NULL;
286 char *line; /* The array that contains everything that has been read
288 char *idx; /* Read into this pointer, which points to an offset
290 size_t size, newsize; /* The size of the current array pointed to by
292 size_t maxlen; /* Maximum number of characters that may be read with
293 fgets. This is newsize - oldsize. */
298 if((buf != NULL) && (buflen != NULL))
306 line = xmalloc(size);
315 p = fgets(idx, maxlen, fp);
316 if(p == NULL) /* EOF or error */
321 /* otherwise: error; let the calling function print an error
322 message if applicable */
327 newline = strchr(p, '\n');
329 /* We haven't yet read everything to the end of the line */
332 line = xrealloc(line, newsize);
333 idx = &line[size - 1];
334 maxlen = newsize - size + 1;
339 *newline = '\0'; /* kill newline */
344 if((buf != NULL) && (buflen != NULL))
353 Parse a configuration file and put the results in the configuration tree
356 int read_config_file(avl_tree_t *config_tree, const char *fname)
358 int err = -2; /* Parse error */
361 char *variable, *value;
362 int lineno = 0, ignore = 0;
367 if((fp = fopen (fname, "r")) == NULL)
369 syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname, strerror(errno));
374 buffer = xmalloc(bufsize);
378 if((line = readline(fp, &buffer, &bufsize)) == NULL)
392 if((variable = strtok(line, "\t =")) == NULL)
393 continue; /* no tokens on this line */
395 if(variable[0] == '#')
396 continue; /* comment: ignore */
398 if(!strcmp(variable, "-----BEGIN"))
403 if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
405 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
406 variable, lineno, fname);
411 cfg->variable = xstrdup(variable);
412 cfg->value = xstrdup(value);
413 cfg->file = xstrdup(fname);
416 config_add(config_tree, cfg);
419 if(!strcmp(variable, "-----END"))
429 int read_server_config()
434 asprintf(&fname, "%s/tinc.conf", confbase);
435 x = read_config_file(config_tree, fname);
436 if(x == -1) /* System error: complain */
438 syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
445 int isadir(const char* f)
452 return S_ISDIR(s.st_mode);
455 int is_safe_path(const char *file)
465 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
469 p = strrchr(file, '/');
471 if(p == file) /* It's in the root */
481 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
485 if(s.st_uid != geteuid())
487 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
488 f, s.st_uid, geteuid());
492 if(S_ISLNK(s.st_mode))
494 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
497 if(readlink(f, l, MAXBUFSIZE) < 0)
499 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
511 if(lstat(f, &s) < 0 && errno != ENOENT)
513 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
520 if(s.st_uid != geteuid())
522 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
523 f, s.st_uid, geteuid());
527 if(S_ISLNK(s.st_mode))
529 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
532 if(readlink(f, l, MAXBUFSIZE) < 0)
534 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
544 /* Accessible by others */
545 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
553 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
559 /* Check stdin and stdout */
560 if(!isatty(0) || !isatty(1))
562 /* Argh, they are running us from a script or something. Write
563 the files to the current directory and let them burn in hell
565 fn = xstrdup(filename);
569 /* Ask for a file and/or directory name. */
570 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
574 if((fn = readline(stdin, NULL, NULL)) == NULL)
576 fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
581 /* User just pressed enter. */
582 fn = xstrdup(filename);
585 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
587 /* The directory is a relative path or a filename. */
590 directory = get_current_dir_name();
591 asprintf(&p, "%s/%s", directory, fn);
597 umask(0077); /* Disallow everything for group and other */
599 /* Open it first to keep the inode busy */
600 if((r = fopen(fn, mode)) == NULL)
602 fprintf(stderr, _("Error opening file `%s': %s\n"),
603 fn, strerror(errno));
608 /* Then check the file for nasty attacks */
609 if(!is_safe_path(fn)) /* Do not permit any directories that are
610 readable or writeable by other users. */
612 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
613 "I will not create or overwrite this file.\n"),