2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2003 Ivo Timmermans <ivo@o2w.nl>
5 2000-2003 Guus Sliepen <guus@sliepen.eu.org>
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.66 2003/07/17 15:06:26 guus Exp $
30 #include "netutl.h" /* for str2address */
31 #include "utils.h" /* for cp */
34 avl_tree_t *config_tree;
36 int pingtimeout = 0; /* seconds before timeout */
37 char *confbase = NULL; /* directory in which all config files are */
38 char *netname = NULL; /* name of the vpn network */
40 static int config_compare(config_t *a, config_t *b)
44 result = strcasecmp(a->variable, b->variable);
49 result = a->line - b->line;
54 return strcmp(a->file, b->file);
57 void init_configuration(avl_tree_t ** config_tree)
61 *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
64 void exit_configuration(avl_tree_t ** config_tree)
68 avl_delete_tree(*config_tree);
72 config_t *new_config(void)
76 return (config_t *) xmalloc_and_zero(sizeof(config_t));
79 void free_config(config_t *cfg)
95 void config_add(avl_tree_t *config_tree, config_t *cfg)
99 avl_insert(config_tree, cfg);
102 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
104 config_t cfg, *found;
108 cfg.variable = variable;
112 found = avl_search_closest_greater(config_tree, &cfg);
117 if(strcasecmp(found->variable, variable))
123 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
130 node = avl_search_node(config_tree, cfg);
134 found = (config_t *) node->next->data;
136 if(!strcasecmp(found->variable, cfg->variable))
144 int get_config_bool(config_t *cfg, int *result)
151 if(!strcasecmp(cfg->value, "yes")) {
154 } else if(!strcasecmp(cfg->value, "no")) {
159 logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
160 cfg->variable, cfg->file, cfg->line);
165 int get_config_int(config_t *cfg, int *result)
172 if(sscanf(cfg->value, "%d", result) == 1)
175 logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
176 cfg->variable, cfg->file, cfg->line);
181 int get_config_string(config_t *cfg, char **result)
188 *result = xstrdup(cfg->value);
193 int get_config_address(config_t *cfg, struct addrinfo **result)
202 ai = str2addrinfo(cfg->value, NULL, 0);
209 logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
210 cfg->variable, cfg->file, cfg->line);
215 int get_config_subnet(config_t *cfg, subnet_t ** result)
224 subnet = str2net(cfg->value);
227 logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
228 cfg->variable, cfg->file, cfg->line);
232 /* Teach newbies what subnets are... */
234 if(((subnet->type == SUBNET_IPV4)
235 && maskcheck(&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
236 || ((subnet->type == SUBNET_IPV6)
237 && maskcheck(&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t)))) {
238 logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
239 cfg->variable, cfg->file, cfg->line);
250 Read exactly one line and strip the trailing newline if any. If the
251 file was on EOF, return NULL. Otherwise, return all the data in a
252 dynamically allocated buffer.
254 If line is non-NULL, it will be used as an initial buffer, to avoid
255 unnecessary mallocing each time this function is called. If buf is
256 given, and buf needs to be expanded, the var pointed to by buflen
259 static char *readline(FILE * fp, char **buf, size_t *buflen)
261 char *newline = NULL;
263 char *line; /* The array that contains everything that has been read so far */
264 char *idx; /* Read into this pointer, which points to an offset within line */
265 size_t size, newsize; /* The size of the current array pointed to by line */
266 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
276 line = xmalloc(size);
285 p = fgets(idx, maxlen, fp);
287 if(!p) { /* EOF or error */
291 /* otherwise: error; let the calling function print an error message if applicable */
296 newline = strchr(p, '\n');
298 if(!newline) { /* We haven't yet read everything to the end of the line */
300 line = xrealloc(line, newsize);
301 idx = &line[size - 1];
302 maxlen = newsize - size + 1;
305 *newline = '\0'; /* kill newline */
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;
328 int lineno = 0, ignore = 0;
334 fp = fopen(fname, "r");
337 logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
343 buffer = xmalloc(bufsize);
346 line = readline(fp, &buffer, &bufsize);
360 variable = strtok(line, "\t =");
363 continue; /* no tokens on this line */
365 if(variable[0] == '#')
366 continue; /* comment: ignore */
368 if(!strcmp(variable, "-----BEGIN"))
372 value = strtok(NULL, "\t\n\r =");
374 if(!value || value[0] == '#') {
375 logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
376 variable, lineno, fname);
381 cfg->variable = xstrdup(variable);
382 cfg->value = xstrdup(value);
383 cfg->file = xstrdup(fname);
386 config_add(config_tree, cfg);
389 if(!strcmp(variable, "-----END"))
399 int read_server_config()
406 asprintf(&fname, "%s/tinc.conf", confbase);
407 x = read_config_file(config_tree, fname);
409 if(x == -1) { /* System error: complain */
410 logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
418 int is_safe_path(const char *file)
427 logger(LOG_ERR, _("`%s' is not an absolute path"), file);
431 p = strrchr(file, '/');
433 if(p == file) /* It's in the root */
442 if(lstat(f, &s) < 0) {
443 logger(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
447 if(s.st_uid != geteuid()) {
448 logger(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
449 f, s.st_uid, geteuid());
453 if(S_ISLNK(s.st_mode)) {
454 logger(LOG_WARNING, _("Warning: `%s' is a symlink"), f);
456 if(readlink(f, l, MAXBUFSIZE) < 0) {
457 logger(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f,
470 if(lstat(f, &s) < 0 && errno != ENOENT) {
471 logger(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
478 if(s.st_uid != geteuid()) {
479 logger(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
480 f, s.st_uid, geteuid());
484 if(S_ISLNK(s.st_mode)) {
485 logger(LOG_WARNING, _("Warning: `%s' is a symlink"), f);
487 if(readlink(f, l, MAXBUFSIZE) < 0) {
488 logger(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f,
497 if(s.st_mode & 0007) {
498 /* Accessible by others */
499 logger(LOG_ERR, _("`%s' has unsecure permissions"), f);
506 FILE *ask_and_safe_open(const char *filename, const char *what,
513 /* Check stdin and stdout */
514 if(!isatty(0) || !isatty(1)) {
515 /* Argh, they are running us from a script or something. Write
516 the files to the current directory and let them burn in hell
518 fn = xstrdup(filename);
520 /* Ask for a file and/or directory name. */
521 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
525 fn = readline(stdin, NULL, NULL);
528 fprintf(stderr, _("Error while reading stdin: %s\n"),
534 /* User just pressed enter. */
535 fn = xstrdup(filename);
538 if(!strchr(fn, '/') || fn[0] != '/') {
539 /* The directory is a relative path or a filename. */
542 directory = get_current_dir_name();
543 asprintf(&p, "%s/%s", directory, fn);
549 umask(0077); /* Disallow everything for group and other */
551 /* Open it first to keep the inode busy */
556 fprintf(stderr, _("Error opening file `%s': %s\n"),
557 fn, strerror(errno));
562 /* Then check the file for nasty attacks */
563 if(!is_safe_path(fn)) { /* Do not permit any directories that are readable or writeable by other users. */
564 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
565 "I will not create or overwrite this file.\n"), fn);