2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2002 Ivo Timmermans <ivo@o2w.nl>
5 2000-2002 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.58 2002/09/09 19:39:55 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. */
306 line = xmalloc(size);
315 p = fgets(idx, maxlen, fp);
316 if(!p) /* 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 */
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 fp = fopen (fname, "r");
371 syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname, strerror(errno));
376 buffer = xmalloc(bufsize);
380 line = readline(fp, &buffer, &bufsize);
396 variable = strtok(line, "\t =");
399 continue; /* no tokens on this line */
401 if(variable[0] == '#')
402 continue; /* comment: ignore */
404 if(!strcmp(variable, "-----BEGIN"))
409 value = strtok(NULL, "\t\n\r =");
411 if(!value || value[0] == '#')
413 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
414 variable, lineno, fname);
419 cfg->variable = xstrdup(variable);
420 cfg->value = xstrdup(value);
421 cfg->file = xstrdup(fname);
424 config_add(config_tree, cfg);
427 if(!strcmp(variable, "-----END"))
437 int read_server_config()
442 asprintf(&fname, "%s/tinc.conf", confbase);
443 x = read_config_file(config_tree, fname);
444 if(x == -1) /* System error: complain */
446 syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
453 int isadir(const char* f)
460 return S_ISDIR(s.st_mode);
463 int is_safe_path(const char *file)
473 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
477 p = strrchr(file, '/');
479 if(p == file) /* It's in the root */
489 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
493 if(s.st_uid != geteuid())
495 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
496 f, s.st_uid, geteuid());
500 if(S_ISLNK(s.st_mode))
502 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
505 if(readlink(f, l, MAXBUFSIZE) < 0)
507 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
519 if(lstat(f, &s) < 0 && errno != ENOENT)
521 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
528 if(s.st_uid != geteuid())
530 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
531 f, s.st_uid, geteuid());
535 if(S_ISLNK(s.st_mode))
537 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
540 if(readlink(f, l, MAXBUFSIZE) < 0)
542 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
552 /* Accessible by others */
553 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
561 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
567 /* Check stdin and stdout */
568 if(!isatty(0) || !isatty(1))
570 /* Argh, they are running us from a script or something. Write
571 the files to the current directory and let them burn in hell
573 fn = xstrdup(filename);
577 /* Ask for a file and/or directory name. */
578 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
582 fn = readline(stdin, NULL, NULL);
586 fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
591 /* User just pressed enter. */
592 fn = xstrdup(filename);
595 if(!strchr(fn, '/') || fn[0] != '/')
597 /* The directory is a relative path or a filename. */
600 directory = get_current_dir_name();
601 asprintf(&p, "%s/%s", directory, fn);
607 umask(0077); /* Disallow everything for group and other */
609 /* Open it first to keep the inode busy */
615 fprintf(stderr, _("Error opening file `%s': %s\n"),
616 fn, strerror(errno));
621 /* Then check the file for nasty attacks */
622 if(!is_safe_path(fn)) /* Do not permit any directories that are
623 readable or writeable by other users. */
625 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
626 "I will not create or overwrite this file.\n"),