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.45 2001/10/27 12:13:17 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);
223 int get_config_port(config_t *cfg, port_t *result)
229 if(sscanf(cfg->value, "%hu", result) == 1)
232 syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
233 cfg->value, cfg->file, cfg->line);
237 int get_config_subnet(config_t *cfg, subnet_t **result)
245 ip = strtoip(cfg->value);
249 syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"),
250 cfg->value, cfg->file, cfg->line);
254 /* Teach newbies what subnets are... */
256 if((subnet->net.ipv4.address & subnet->net.ipv4.mask) != subnet->net.ipv4.address)
258 syslog(LOG_ERR, _("Network address and subnet mask for configuration variable %s in %s line %d"),
259 cfg->value, cfg->file, cfg->line);
264 subnet = new_subnet();
265 subnet->type = SUBNET_IPV4;
266 subnet->net.ipv4.address = ip->address;
267 subnet->net.ipv4.mask = ip->mask;
277 Read exactly one line and strip the trailing newline if any. If the
278 file was on EOF, return NULL. Otherwise, return all the data in a
279 dynamically allocated buffer.
281 If line is non-NULL, it will be used as an initial buffer, to avoid
282 unnecessary mallocing each time this function is called. If buf is
283 given, and buf needs to be expanded, the var pointed to by buflen
286 char *readline(FILE *fp, char **buf, size_t *buflen)
288 char *newline = NULL;
290 char *line; /* The array that contains everything that has been read
292 char *idx; /* Read into this pointer, which points to an offset
294 size_t size, newsize; /* The size of the current array pointed to by
296 size_t maxlen; /* Maximum number of characters that may be read with
297 fgets. This is newsize - oldsize. */
302 if((buf != NULL) && (buflen != NULL))
310 line = xmalloc(size);
319 p = fgets(idx, maxlen, fp);
320 if(p == NULL) /* EOF or error */
325 /* otherwise: error; let the calling function print an error
326 message if applicable */
331 newline = strchr(p, '\n');
333 /* We haven't yet read everything to the end of the line */
336 line = xrealloc(line, newsize);
337 idx = &line[size - 1];
338 maxlen = newsize - size + 1;
343 *newline = '\0'; /* kill newline */
348 if((buf != NULL) && (buflen != NULL))
357 Parse a configuration file and put the results in the configuration tree
360 int read_config_file(avl_tree_t *config_tree, const char *fname)
362 int err = -2; /* Parse error */
365 char *variable, *value;
366 int lineno = 0, ignore = 0;
371 if((fp = fopen (fname, "r")) == NULL)
373 syslog(LOG_ERR, _("Cannot open config file %s: %m"), fname);
378 buffer = xmalloc(bufsize);
382 if((line = readline(fp, &buffer, &bufsize)) == NULL)
396 if((variable = strtok(line, "\t =")) == NULL)
397 continue; /* no tokens on this line */
399 if(variable[0] == '#')
400 continue; /* comment: ignore */
402 if(!strcmp(variable, "-----BEGIN"))
407 if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
409 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
410 variable, lineno, fname);
415 cfg->variable = xstrdup(variable);
416 cfg->value = xstrdup(value);
417 cfg->file = xstrdup(fname);
420 config_add(config_tree, cfg);
423 if(!strcmp(variable, "-----END"))
433 int read_server_config()
438 asprintf(&fname, "%s/tinc.conf", confbase);
439 x = read_config_file(config_tree, fname);
440 if(x == -1) /* System error: complain */
442 syslog(LOG_ERR, _("Failed to read `%s': %m"),
450 int isadir(const char* f)
457 return S_ISDIR(s.st_mode);
460 int is_safe_path(const char *file)
470 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
474 p = strrchr(file, '/');
476 if(p == file) /* It's in the root */
486 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
491 if(s.st_uid != geteuid())
493 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
494 f, s.st_uid, geteuid());
498 if(S_ISLNK(s.st_mode))
500 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
503 if(readlink(f, l, MAXBUFSIZE) < 0)
505 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
517 if(lstat(f, &s) < 0 && errno != ENOENT)
519 syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
527 if(s.st_uid != geteuid())
529 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
530 f, s.st_uid, geteuid());
534 if(S_ISLNK(s.st_mode))
536 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
539 if(readlink(f, l, MAXBUFSIZE) < 0)
541 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
551 /* Accessible by others */
552 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
560 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
566 /* Check stdin and stdout */
567 if(!isatty(0) || !isatty(1))
569 /* Argh, they are running us from a script or something. Write
570 the files to the current directory and let them burn in hell
572 fn = xstrdup(filename);
576 /* Ask for a file and/or directory name. */
577 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
581 if((fn = readline(stdin, NULL, NULL)) == NULL)
583 fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
588 /* User just pressed enter. */
589 fn = xstrdup(filename);
592 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
594 /* The directory is a relative path or a filename. */
597 directory = get_current_dir_name();
598 asprintf(&p, "%s/%s", directory, fn);
604 umask(0077); /* Disallow everything for group and other */
606 /* Open it first to keep the inode busy */
607 if((r = fopen(fn, mode)) == NULL)
609 fprintf(stderr, _("Error opening file `%s': %s\n"),
610 fn, strerror(errno));
615 /* Then check the file for nasty attacks */
616 if(!is_safe_path(fn)) /* Do not permit any directories that are
617 readable or writeable by other users. */
619 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
620 "I will not create or overwrite this file.\n"),