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.61 2002/09/15 12:26:24 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)
77 *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
80 void exit_configuration(avl_tree_t ** config_tree)
84 avl_delete_tree(*config_tree);
88 config_t *new_config(void)
92 return (config_t *) xmalloc_and_zero(sizeof(config_t));
95 void free_config(config_t *cfg)
111 void config_add(avl_tree_t *config_tree, config_t *cfg)
115 avl_insert(config_tree, cfg);
118 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
120 config_t cfg, *found;
124 cfg.variable = variable;
128 found = avl_search_closest_greater(config_tree, &cfg);
133 if(strcasecmp(found->variable, variable))
139 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
146 node = avl_search_node(config_tree, cfg);
150 found = (config_t *) node->next->data;
152 if(!strcasecmp(found->variable, cfg->variable))
160 int get_config_bool(config_t *cfg, int *result)
167 if(!strcasecmp(cfg->value, "yes")) {
170 } else if(!strcasecmp(cfg->value, "no")) {
175 syslog(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
176 cfg->variable, cfg->file, cfg->line);
181 int get_config_int(config_t *cfg, int *result)
188 if(sscanf(cfg->value, "%d", result) == 1)
191 syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
192 cfg->variable, cfg->file, cfg->line);
197 int get_config_string(config_t *cfg, char **result)
204 *result = xstrdup(cfg->value);
209 int get_config_address(config_t *cfg, struct addrinfo **result)
218 ai = str2addrinfo(cfg->value, NULL, 0);
225 syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
226 cfg->variable, cfg->file, cfg->line);
231 int get_config_subnet(config_t *cfg, subnet_t ** result)
240 subnet = str2net(cfg->value);
243 syslog(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
244 cfg->variable, cfg->file, cfg->line);
248 /* Teach newbies what subnets are... */
250 if(((subnet->type == SUBNET_IPV4)
251 && maskcheck(&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
252 || ((subnet->type == SUBNET_IPV6)
253 && maskcheck(&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t)))) {
254 syslog(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
255 cfg->variable, cfg->file, cfg->line);
266 Read exactly one line and strip the trailing newline if any. If the
267 file was on EOF, return NULL. Otherwise, return all the data in a
268 dynamically allocated buffer.
270 If line is non-NULL, it will be used as an initial buffer, to avoid
271 unnecessary mallocing each time this function is called. If buf is
272 given, and buf needs to be expanded, the var pointed to by buflen
275 char *readline(FILE * fp, char **buf, size_t *buflen)
277 char *newline = NULL;
279 char *line; /* The array that contains everything that has been read so far */
280 char *idx; /* Read into this pointer, which points to an offset within line */
281 size_t size, newsize; /* The size of the current array pointed to by line */
282 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
292 line = xmalloc(size);
301 p = fgets(idx, maxlen, fp);
303 if(!p) { /* EOF or error */
307 /* otherwise: error; let the calling function print an error message if applicable */
312 newline = strchr(p, '\n');
314 if(!newline) { /* We haven't yet read everything to the end of the line */
316 line = xrealloc(line, newsize);
317 idx = &line[size - 1];
318 maxlen = newsize - size + 1;
321 *newline = '\0'; /* kill newline */
335 Parse a configuration file and put the results in the configuration tree
338 int read_config_file(avl_tree_t *config_tree, const char *fname)
340 int err = -2; /* Parse error */
343 char *variable, *value;
344 int lineno = 0, ignore = 0;
350 fp = fopen(fname, "r");
353 syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname,
359 buffer = xmalloc(bufsize);
362 line = readline(fp, &buffer, &bufsize);
376 variable = strtok(line, "\t =");
379 continue; /* no tokens on this line */
381 if(variable[0] == '#')
382 continue; /* comment: ignore */
384 if(!strcmp(variable, "-----BEGIN"))
388 value = strtok(NULL, "\t\n\r =");
390 if(!value || value[0] == '#') {
391 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
392 variable, lineno, fname);
397 cfg->variable = xstrdup(variable);
398 cfg->value = xstrdup(value);
399 cfg->file = xstrdup(fname);
402 config_add(config_tree, cfg);
405 if(!strcmp(variable, "-----END"))
415 int read_server_config()
422 asprintf(&fname, "%s/tinc.conf", confbase);
423 x = read_config_file(config_tree, fname);
425 if(x == -1) { /* System error: complain */
426 syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
434 int isadir(const char *f)
441 return S_ISDIR(s.st_mode);
444 int is_safe_path(const char *file)
453 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
457 p = strrchr(file, '/');
459 if(p == file) /* It's in the root */
468 if(lstat(f, &s) < 0) {
469 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
473 if(s.st_uid != geteuid()) {
474 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
475 f, s.st_uid, geteuid());
479 if(S_ISLNK(s.st_mode)) {
480 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"), f);
482 if(readlink(f, l, MAXBUFSIZE) < 0) {
483 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f,
496 if(lstat(f, &s) < 0 && errno != ENOENT) {
497 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
504 if(s.st_uid != geteuid()) {
505 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
506 f, s.st_uid, geteuid());
510 if(S_ISLNK(s.st_mode)) {
511 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"), f);
513 if(readlink(f, l, MAXBUFSIZE) < 0) {
514 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f,
523 if(s.st_mode & 0007) {
524 /* Accessible by others */
525 syslog(LOG_ERR, _("`%s' has unsecure permissions"), f);
532 FILE *ask_and_safe_open(const char *filename, const char *what,
539 /* Check stdin and stdout */
540 if(!isatty(0) || !isatty(1)) {
541 /* Argh, they are running us from a script or something. Write
542 the files to the current directory and let them burn in hell
544 fn = xstrdup(filename);
546 /* Ask for a file and/or directory name. */
547 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
551 fn = readline(stdin, NULL, NULL);
554 fprintf(stderr, _("Error while reading stdin: %s\n"),
560 /* User just pressed enter. */
561 fn = xstrdup(filename);
564 if(!strchr(fn, '/') || fn[0] != '/') {
565 /* The directory is a relative path or a filename. */
568 directory = get_current_dir_name();
569 asprintf(&p, "%s/%s", directory, fn);
575 umask(0077); /* Disallow everything for group and other */
577 /* Open it first to keep the inode busy */
582 fprintf(stderr, _("Error opening file `%s': %s\n"),
583 fn, strerror(errno));
588 /* Then check the file for nasty attacks */
589 if(!is_safe_path(fn)) { /* Do not permit any directories that are readable or writeable by other users. */
590 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
591 "I will not create or overwrite this file.\n"), fn);