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.51 2001/11/16 22:31:41 zarq Exp $
35 #include <sys/types.h>
41 #include <utils.h> /* for cp */
48 avl_tree_t *config_tree;
51 int timeout = 0; /* seconds before timeout */
52 char *confbase = NULL; /* directory in which all config files are */
53 char *netname = NULL; /* name of the vpn network */
55 /* Will be set if HUP signal is received. It will be processed when it is safe. */
58 int config_compare(config_t *a, config_t *b)
62 result = strcmp(a->variable, b->variable);
67 result = a->line - b->line;
72 return strcmp(a->file, b->file);
75 void init_configuration(avl_tree_t **config_tree)
78 *config_tree = avl_alloc_tree((avl_compare_t)config_compare, (avl_action_t)free_config);
82 void exit_configuration(avl_tree_t **config_tree)
85 avl_delete_tree(*config_tree);
90 config_t *new_config(void)
94 cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg));
99 void free_config(config_t *cfg)
112 void config_add(avl_tree_t *config_tree, config_t *cfg)
115 avl_insert(config_tree, cfg);
119 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
121 config_t cfg, *found;
123 cfg.variable = variable;
127 found = avl_search_closest_greater(config_tree, &cfg);
132 if(strcmp(found->variable, variable))
138 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
143 node = avl_search_node(config_tree, cfg);
149 found = (config_t *)node->next->data;
150 if(!strcmp(found->variable, cfg->variable))
158 int get_config_bool(config_t *cfg, int *result)
164 if(!strcasecmp(cfg->value, "yes"))
169 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)
187 if(sscanf(cfg->value, "%d", result) == 1)
190 syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
191 cfg->variable, cfg->file, cfg->line);
195 int get_config_string(config_t *cfg, char **result)
201 *result = cfg->value;
205 int get_config_subnet(config_t *cfg, subnet_t **result)
213 /* ip = strtoip(cfg->value); */
217 /* syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"), */
218 /* cfg->variable, cfg->file, cfg->line); */
222 /* Teach newbies what subnets are... */
224 /* if((ip->address & ip->mask) != ip->address) */
226 /* syslog(LOG_ERR, _("Network address and subnet mask for configuration variable %s in %s line %d"), */
227 /* cfg->variable, cfg->file, cfg->line); */
232 /* subnet = new_subnet(); */
233 /* subnet->type = SUBNET_IP; */
234 /* subnet->net.ip.address = ip->address; */
235 /* subnet->net.ip.mask = ip->mask; */
239 /* *result = subnet; */
245 Read exactly one line and strip the trailing newline if any. If the
246 file was on EOF, return NULL. Otherwise, return all the data in a
247 dynamically allocated buffer.
249 If line is non-NULL, it will be used as an initial buffer, to avoid
250 unnecessary mallocing each time this function is called. If buf is
251 given, and buf needs to be expanded, the var pointed to by buflen
254 char *readline(FILE *fp, char **buf, size_t *buflen)
256 char *newline = NULL;
258 char *line; /* The array that contains everything that has been read
260 char *idx; /* Read into this pointer, which points to an offset
262 size_t size, newsize; /* The size of the current array pointed to by
264 size_t maxlen; /* Maximum number of characters that may be read with
265 fgets. This is newsize - oldsize. */
270 if((buf != NULL) && (buflen != NULL))
278 line = xmalloc(size);
287 p = fgets(idx, maxlen, fp);
288 if(p == NULL) /* EOF or error */
293 /* otherwise: error; let the calling function print an error
294 message if applicable */
299 newline = strchr(p, '\n');
301 /* We haven't yet read everything to the end of the line */
304 line = xrealloc(line, newsize);
305 idx = &line[size - 1];
306 maxlen = newsize - size + 1;
311 *newline = '\0'; /* kill newline */
316 if((buf != NULL) && (buflen != NULL))
325 Parse a configuration file and put the results in the configuration tree
328 int read_config_file(avl_tree_t *config_tree, const char *fname)
330 int err = -2; /* Parse error */
333 char *variable, *value;
334 int lineno = 0, ignore = 0;
339 if((fp = fopen (fname, "r")) == NULL)
341 syslog(LOG_ERR, _("Cannot open config file %s: %m"), fname);
346 buffer = xmalloc(bufsize);
350 if((line = readline(fp, &buffer, &bufsize)) == NULL)
364 if((variable = strtok(line, "\t =")) == NULL)
365 continue; /* no tokens on this line */
367 if(variable[0] == '#')
368 continue; /* comment: ignore */
370 if(!strcmp(variable, "-----BEGIN"))
375 if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
377 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
378 variable, lineno, fname);
383 cfg->variable = xstrdup(variable);
384 cfg->value = xstrdup(value);
385 cfg->file = xstrdup(fname);
388 config_add(config_tree, cfg);
391 if(!strcmp(variable, "-----END"))
401 int read_server_config()
406 asprintf(&fname, "%s/tinc.conf", confbase);
407 x = read_config_file(config_tree, fname);
408 if(x == -1) /* System error: complain */
410 syslog(LOG_ERR, _("Failed to read `%s': %m"),
418 int isadir(const char* f)
425 return S_ISDIR(s.st_mode);
428 int is_safe_path(const char *file)
438 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
442 p = strrchr(file, '/');
444 if(p == file) /* It's in the root */
454 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
459 if(s.st_uid != geteuid())
461 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
462 f, s.st_uid, geteuid());
466 if(S_ISLNK(s.st_mode))
468 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
471 if(readlink(f, l, MAXBUFSIZE) < 0)
473 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
485 if(lstat(f, &s) < 0 && errno != ENOENT)
487 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
495 if(s.st_uid != geteuid())
497 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
498 f, s.st_uid, geteuid());
502 if(S_ISLNK(s.st_mode))
504 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
507 if(readlink(f, l, MAXBUFSIZE) < 0)
509 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
519 /* Accessible by others */
520 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
528 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
534 /* Check stdin and stdout */
535 if(!isatty(0) || !isatty(1))
537 /* Argh, they are running us from a script or something. Write
538 the files to the current directory and let them burn in hell
540 fn = xstrdup(filename);
544 /* Ask for a file and/or directory name. */
545 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
549 if((fn = readline(stdin, NULL, NULL)) == NULL)
551 fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
556 /* User just pressed enter. */
557 fn = xstrdup(filename);
560 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
562 /* The directory is a relative path or a filename. */
565 directory = get_current_dir_name();
566 asprintf(&p, "%s/%s", directory, fn);
572 umask(0077); /* Disallow everything for group and other */
574 /* Open it first to keep the inode busy */
575 if((r = fopen(fn, mode)) == NULL)
577 fprintf(stderr, _("Error opening file `%s': %s\n"),
578 fn, strerror(errno));
583 /* Then check the file for nasty attacks */
584 if(!is_safe_path(fn)) /* Do not permit any directories that are
585 readable or writeable by other users. */
587 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
588 "I will not create or overwrite this file.\n"),