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.44 2001/10/10 20:34:27 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);
130 if(!strcmp(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(!strcmp(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, "np"))
173 syslog(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
174 cfg->value, 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->value, cfg->file, cfg->line);
193 int get_config_string(config_t *cfg, char **result)
199 *result = cfg->value;
203 int get_config_ip(config_t *cfg, ip_mask_t **result)
210 ip = strtoip(cfg->value);
218 syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"),
219 cfg->value, cfg->file, cfg->line);
224 Read exactly one line and strip the trailing newline if any. If the
225 file was on EOF, return NULL. Otherwise, return all the data in a
226 dynamically allocated buffer.
228 If line is non-NULL, it will be used as an initial buffer, to avoid
229 unnecessary mallocing each time this function is called. If buf is
230 given, and buf needs to be expanded, the var pointed to by buflen
233 char *readline(FILE *fp, char **buf, size_t *buflen)
235 char *newline = NULL;
237 char *line; /* The array that contains everything that has been read
239 char *idx; /* Read into this pointer, which points to an offset
241 size_t size, newsize; /* The size of the current array pointed to by
243 size_t maxlen; /* Maximum number of characters that may be read with
244 fgets. This is newsize - oldsize. */
249 if((buf != NULL) && (buflen != NULL))
257 line = xmalloc(size);
266 p = fgets(idx, maxlen, fp);
267 if(p == NULL) /* EOF or error */
272 /* otherwise: error; let the calling function print an error
273 message if applicable */
278 newline = strchr(p, '\n');
280 /* We haven't yet read everything to the end of the line */
283 line = xrealloc(line, newsize);
284 idx = &line[size - 1];
285 maxlen = newsize - size + 1;
290 *newline = '\0'; /* kill newline */
295 if((buf != NULL) && (buflen != NULL))
304 Parse a configuration file and put the results in the configuration tree
307 int read_config_file(avl_tree_t *config_tree, const char *fname)
309 int err = -2; /* Parse error */
312 char *variable, *value;
313 int lineno = 0, ignore = 0;
318 if((fp = fopen (fname, "r")) == NULL)
320 syslog(LOG_ERR, _("Cannot open config file %s: %m"), fname);
325 buffer = xmalloc(bufsize);
329 if((line = readline(fp, &buffer, &bufsize)) == NULL)
343 if((variable = strtok(line, "\t =")) == NULL)
344 continue; /* no tokens on this line */
346 if(variable[0] == '#')
347 continue; /* comment: ignore */
349 if(!strcmp(variable, "-----BEGIN"))
354 if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
356 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
357 variable, lineno, fname);
362 cfg->variable = xstrdup(variable);
363 cfg->value = xstrdup(value);
364 cfg->file = xstrdup(fname);
367 config_add(config_tree, cfg);
370 if(!strcmp(variable, "-----END"))
380 int read_server_config()
385 asprintf(&fname, "%s/tinc.conf", confbase);
386 x = read_config_file(config_tree, fname);
387 if(x == -1) /* System error: complain */
389 syslog(LOG_ERR, _("Failed to read `%s': %m"),
397 int isadir(const char* f)
404 return S_ISDIR(s.st_mode);
407 int is_safe_path(const char *file)
417 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
421 p = strrchr(file, '/');
423 if(p == file) /* It's in the root */
433 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
438 if(s.st_uid != geteuid())
440 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
441 f, s.st_uid, geteuid());
445 if(S_ISLNK(s.st_mode))
447 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
450 if(readlink(f, l, MAXBUFSIZE) < 0)
452 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
464 if(lstat(f, &s) < 0 && errno != ENOENT)
466 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
474 if(s.st_uid != geteuid())
476 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
477 f, s.st_uid, geteuid());
481 if(S_ISLNK(s.st_mode))
483 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
486 if(readlink(f, l, MAXBUFSIZE) < 0)
488 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
498 /* Accessible by others */
499 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
507 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
513 /* Check stdin and stdout */
514 if(!isatty(0) || !isatty(1))
516 /* Argh, they are running us from a script or something. Write
517 the files to the current directory and let them burn in hell
519 fn = xstrdup(filename);
523 /* Ask for a file and/or directory name. */
524 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
528 if((fn = readline(stdin, NULL, NULL)) == NULL)
530 fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
535 /* User just pressed enter. */
536 fn = xstrdup(filename);
539 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
541 /* The directory is a relative path or a filename. */
544 directory = get_current_dir_name();
545 asprintf(&p, "%s/%s", directory, fn);
551 umask(0077); /* Disallow everything for group and other */
553 /* Open it first to keep the inode busy */
554 if((r = fopen(fn, mode)) == NULL)
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
564 readable or writeable by other users. */
566 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
567 "I will not create or overwrite this file.\n"),