2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2001 Ivo Timmermans <itimmermans@bigfoot.com>
5 2000,2001 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.46 2001/10/27 15:19:13 guus Exp $
35 #include <sys/types.h>
41 #include <utils.h> /* for cp */
45 #include "netutl.h" /* for strtoip */
49 avl_tree_t *config_tree;
52 int timeout = 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 /* Will be set if HUP signal is received. It will be processed when it is safe. */
59 int config_compare(config_t *a, config_t *b)
63 result = strcmp(a->variable, b->variable);
68 result = a->line - b->line;
73 return strcmp(a->file, b->file);
76 void init_configuration(avl_tree_t **config_tree)
79 *config_tree = avl_alloc_tree((avl_compare_t)config_compare, (avl_action_t)free_config);
83 void exit_configuration(avl_tree_t **config_tree)
86 avl_delete_tree(*config_tree);
91 config_t *new_config(void)
95 cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg));
100 void free_config(config_t *cfg)
113 void config_add(avl_tree_t *config_tree, config_t *cfg)
116 avl_insert(config_tree, cfg);
120 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
122 config_t cfg, *found;
124 cfg.variable = variable;
128 found = avl_search_closest_greater(config_tree, &cfg);
133 if(strcmp(found->variable, variable))
139 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
144 node = avl_search_node(config_tree, cfg);
150 found = (config_t *)node->next->data;
151 if(!strcmp(found->variable, cfg->variable))
159 int get_config_bool(config_t *cfg, int *result)
165 if(!strcasecmp(cfg->value, "yes"))
170 else if(!strcasecmp(cfg->value, "np"))
176 syslog(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
177 cfg->value, cfg->file, cfg->line);
182 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->value, cfg->file, cfg->line);
196 int get_config_string(config_t *cfg, char **result)
202 *result = cfg->value;
206 int get_config_ip(config_t *cfg, ip_mask_t **result)
213 ip = strtoip(cfg->value);
221 syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"),
222 cfg->value, cfg->file, cfg->line);
226 int get_config_port(config_t *cfg, port_t *result)
232 if(sscanf(cfg->value, "%hu", result) == 1)
235 syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
236 cfg->value, cfg->file, cfg->line);
240 int get_config_subnet(config_t *cfg, subnet_t **result)
248 ip = strtoip(cfg->value);
252 syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"),
253 cfg->value, cfg->file, cfg->line);
257 /* Teach newbies what subnets are... */
259 if((ip->address & ip->mask) != ip->address)
261 syslog(LOG_ERR, _("Network address and subnet mask for configuration variable %s in %s line %d"),
262 cfg->value, cfg->file, cfg->line);
267 subnet = new_subnet();
268 subnet->type = SUBNET_IPV4;
269 subnet->net.ipv4.address = ip->address;
270 subnet->net.ipv4.mask = ip->mask;
280 Read exactly one line and strip the trailing newline if any. If the
281 file was on EOF, return NULL. Otherwise, return all the data in a
282 dynamically allocated buffer.
284 If line is non-NULL, it will be used as an initial buffer, to avoid
285 unnecessary mallocing each time this function is called. If buf is
286 given, and buf needs to be expanded, the var pointed to by buflen
289 char *readline(FILE *fp, char **buf, size_t *buflen)
291 char *newline = NULL;
293 char *line; /* The array that contains everything that has been read
295 char *idx; /* Read into this pointer, which points to an offset
297 size_t size, newsize; /* The size of the current array pointed to by
299 size_t maxlen; /* Maximum number of characters that may be read with
300 fgets. This is newsize - oldsize. */
305 if((buf != NULL) && (buflen != NULL))
313 line = xmalloc(size);
322 p = fgets(idx, maxlen, fp);
323 if(p == NULL) /* EOF or error */
328 /* otherwise: error; let the calling function print an error
329 message if applicable */
334 newline = strchr(p, '\n');
336 /* We haven't yet read everything to the end of the line */
339 line = xrealloc(line, newsize);
340 idx = &line[size - 1];
341 maxlen = newsize - size + 1;
346 *newline = '\0'; /* kill newline */
351 if((buf != NULL) && (buflen != NULL))
360 Parse a configuration file and put the results in the configuration tree
363 int read_config_file(avl_tree_t *config_tree, const char *fname)
365 int err = -2; /* Parse error */
368 char *variable, *value;
369 int lineno = 0, ignore = 0;
374 if((fp = fopen (fname, "r")) == NULL)
376 syslog(LOG_ERR, _("Cannot open config file %s: %m"), fname);
381 buffer = xmalloc(bufsize);
385 if((line = readline(fp, &buffer, &bufsize)) == NULL)
399 if((variable = strtok(line, "\t =")) == NULL)
400 continue; /* no tokens on this line */
402 if(variable[0] == '#')
403 continue; /* comment: ignore */
405 if(!strcmp(variable, "-----BEGIN"))
410 if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
412 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
413 variable, lineno, fname);
418 cfg->variable = xstrdup(variable);
419 cfg->value = xstrdup(value);
420 cfg->file = xstrdup(fname);
423 config_add(config_tree, cfg);
426 if(!strcmp(variable, "-----END"))
436 int read_server_config()
441 asprintf(&fname, "%s/tinc.conf", confbase);
442 x = read_config_file(config_tree, fname);
443 if(x == -1) /* System error: complain */
445 syslog(LOG_ERR, _("Failed to read `%s': %m"),
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': %m"),
494 if(s.st_uid != geteuid())
496 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
497 f, s.st_uid, geteuid());
501 if(S_ISLNK(s.st_mode))
503 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
506 if(readlink(f, l, MAXBUFSIZE) < 0)
508 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
520 if(lstat(f, &s) < 0 && errno != ENOENT)
522 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
530 if(s.st_uid != geteuid())
532 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
533 f, s.st_uid, geteuid());
537 if(S_ISLNK(s.st_mode))
539 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
542 if(readlink(f, l, MAXBUFSIZE) < 0)
544 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
554 /* Accessible by others */
555 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
563 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
569 /* Check stdin and stdout */
570 if(!isatty(0) || !isatty(1))
572 /* Argh, they are running us from a script or something. Write
573 the files to the current directory and let them burn in hell
575 fn = xstrdup(filename);
579 /* Ask for a file and/or directory name. */
580 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
584 if((fn = readline(stdin, NULL, 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, '/') == NULL) || (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 */
610 if((r = fopen(fn, mode)) == NULL)
612 fprintf(stderr, _("Error opening file `%s': %s\n"),
613 fn, strerror(errno));
618 /* Then check the file for nasty attacks */
619 if(!is_safe_path(fn)) /* Do not permit any directories that are
620 readable or writeable by other users. */
622 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
623 "I will not create or overwrite this file.\n"),