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.48 2001/11/16 00:13:08 zarq 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->variable, 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->variable, cfg->file, cfg->line);
196 int get_config_string(config_t *cfg, char **result)
202 *result = cfg->value;
206 int get_config_subnet(config_t *cfg, subnet_t **result)
214 ip = strtoip(cfg->value);
218 syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"),
219 cfg->variable, cfg->file, cfg->line);
223 /* Teach newbies what subnets are... */
225 if((ip->address & ip->mask) != ip->address)
227 syslog(LOG_ERR, _("Network address and subnet mask for configuration variable %s in %s line %d"),
228 cfg->variable, cfg->file, cfg->line);
233 subnet = new_subnet();
234 subnet->type = SUBNET_IPV4;
235 subnet->net.ipv4.address = ip->address;
236 subnet->net.ipv4.mask = ip->mask;
246 Read exactly one line and strip the trailing newline if any. If the
247 file was on EOF, return NULL. Otherwise, return all the data in a
248 dynamically allocated buffer.
250 If line is non-NULL, it will be used as an initial buffer, to avoid
251 unnecessary mallocing each time this function is called. If buf is
252 given, and buf needs to be expanded, the var pointed to by buflen
255 char *readline(FILE *fp, char **buf, size_t *buflen)
257 char *newline = NULL;
259 char *line; /* The array that contains everything that has been read
261 char *idx; /* Read into this pointer, which points to an offset
263 size_t size, newsize; /* The size of the current array pointed to by
265 size_t maxlen; /* Maximum number of characters that may be read with
266 fgets. This is newsize - oldsize. */
271 if((buf != NULL) && (buflen != NULL))
279 line = xmalloc(size);
288 p = fgets(idx, maxlen, fp);
289 if(p == NULL) /* EOF or error */
294 /* otherwise: error; let the calling function print an error
295 message if applicable */
300 newline = strchr(p, '\n');
302 /* We haven't yet read everything to the end of the line */
305 line = xrealloc(line, newsize);
306 idx = &line[size - 1];
307 maxlen = newsize - size + 1;
312 *newline = '\0'; /* kill newline */
317 if((buf != NULL) && (buflen != NULL))
326 Parse a configuration file and put the results in the configuration tree
329 int read_config_file(avl_tree_t *config_tree, const char *fname)
331 int err = -2; /* Parse error */
334 char *variable, *value;
335 int lineno = 0, ignore = 0;
340 if((fp = fopen (fname, "r")) == NULL)
342 syslog(LOG_ERR, _("Cannot open config file %s: %m"), fname);
347 buffer = xmalloc(bufsize);
351 if((line = readline(fp, &buffer, &bufsize)) == NULL)
365 if((variable = strtok(line, "\t =")) == NULL)
366 continue; /* no tokens on this line */
368 if(variable[0] == '#')
369 continue; /* comment: ignore */
371 if(!strcmp(variable, "-----BEGIN"))
376 if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
378 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
379 variable, lineno, fname);
384 cfg->variable = xstrdup(variable);
385 cfg->value = xstrdup(value);
386 cfg->file = xstrdup(fname);
389 config_add(config_tree, cfg);
392 if(!strcmp(variable, "-----END"))
402 int read_server_config()
407 asprintf(&fname, "%s/tinc.conf", confbase);
408 x = read_config_file(config_tree, fname);
409 if(x == -1) /* System error: complain */
411 syslog(LOG_ERR, _("Failed to read `%s': %m"),
419 int isadir(const char* f)
426 return S_ISDIR(s.st_mode);
429 int is_safe_path(const char *file)
439 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
443 p = strrchr(file, '/');
445 if(p == file) /* It's in the root */
455 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
460 if(s.st_uid != geteuid())
462 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
463 f, s.st_uid, geteuid());
467 if(S_ISLNK(s.st_mode))
469 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
472 if(readlink(f, l, MAXBUFSIZE) < 0)
474 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
486 if(lstat(f, &s) < 0 && errno != ENOENT)
488 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
496 if(s.st_uid != geteuid())
498 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
499 f, s.st_uid, geteuid());
503 if(S_ISLNK(s.st_mode))
505 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
508 if(readlink(f, l, MAXBUFSIZE) < 0)
510 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
520 /* Accessible by others */
521 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
529 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
535 /* Check stdin and stdout */
536 if(!isatty(0) || !isatty(1))
538 /* Argh, they are running us from a script or something. Write
539 the files to the current directory and let them burn in hell
541 fn = xstrdup(filename);
545 /* Ask for a file and/or directory name. */
546 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
550 if((fn = readline(stdin, NULL, NULL)) == NULL)
552 fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
557 /* User just pressed enter. */
558 fn = xstrdup(filename);
561 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
563 /* The directory is a relative path or a filename. */
566 directory = get_current_dir_name();
567 asprintf(&p, "%s/%s", directory, fn);
573 umask(0077); /* Disallow everything for group and other */
575 /* Open it first to keep the inode busy */
576 if((r = fopen(fn, mode)) == NULL)
578 fprintf(stderr, _("Error opening file `%s': %s\n"),
579 fn, strerror(errno));
584 /* Then check the file for nasty attacks */
585 if(!is_safe_path(fn)) /* Do not permit any directories that are
586 readable or writeable by other users. */
588 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
589 "I will not create or overwrite this file.\n"),