2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>
5 2000-2002 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.12.2.1 2002/04/14 09:30:16 zarq Exp $
34 #include <sys/types.h>
39 #include <utils.h> /* for cp */
43 #include "netutl.h" /* for str2address */
48 avl_tree_t *config_tree;
50 int pingtimeout = 0; /* seconds before timeout */
51 char *confbase = NULL; /* directory in which all config files are */
52 char *netname = NULL; /* name of the vpn network */
54 int config_compare(config_t *a, config_t *b)
58 result = strcasecmp(a->variable, b->variable);
63 result = a->line - b->line;
68 return strcmp(a->file, b->file);
71 void init_configuration(avl_tree_t **config_tree)
74 *config_tree = avl_alloc_tree((avl_compare_t)config_compare, (avl_action_t)free_config);
78 void exit_configuration(avl_tree_t **config_tree)
81 avl_delete_tree(*config_tree);
86 config_t *new_config(void)
90 cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg));
95 void free_config(config_t *cfg)
108 void config_add(avl_tree_t *config_tree, config_t *cfg)
111 avl_insert(config_tree, cfg);
115 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
117 config_t cfg, *found;
119 cfg.variable = variable;
123 found = avl_search_closest_greater(config_tree, &cfg);
128 if(strcasecmp(found->variable, variable))
134 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
139 node = avl_search_node(config_tree, cfg);
145 found = (config_t *)node->next->data;
146 if(!strcasecmp(found->variable, cfg->variable))
154 int get_config_bool(config_t *cfg, int *result)
160 if(!strcasecmp(cfg->value, "yes"))
165 else if(!strcasecmp(cfg->value, "no"))
171 syslog(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
172 cfg->variable, cfg->file, cfg->line);
177 int get_config_int(config_t *cfg, int *result)
183 if(sscanf(cfg->value, "%d", result) == 1)
186 syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
187 cfg->variable, cfg->file, cfg->line);
191 int get_config_string(config_t *cfg, char **result)
197 *result = xstrdup(cfg->value);
201 int get_config_address(config_t *cfg, struct addrinfo **result)
208 ai = str2addrinfo(cfg->value, NULL, 0);
216 syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
217 cfg->variable, cfg->file, cfg->line);
221 int get_config_port(config_t *cfg, port_t *result)
227 if(sscanf(cfg->value, "%hu", result) == 1)
229 *result = htons(*result);
233 syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
234 cfg->variable, cfg->file, cfg->line);
238 int get_config_subnet(config_t *cfg, subnet_t **result)
245 subnet = str2net(cfg->value);
249 syslog(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
250 cfg->variable, cfg->file, cfg->line);
254 /* Teach newbies what subnets are... */
256 if(((subnet->type == SUBNET_IPV4) && maskcheck((char *)&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
257 || ((subnet->type == SUBNET_IPV6) && maskcheck((char *)&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t))))
259 syslog(LOG_ERR, _("Network address and prefix length do not match for configuration variable %s in %s line %d"),
260 cfg->variable, cfg->file, cfg->line);
271 Read exactly one line and strip the trailing newline if any. If the
272 file was on EOF, return NULL. Otherwise, return all the data in a
273 dynamically allocated buffer.
275 If line is non-NULL, it will be used as an initial buffer, to avoid
276 unnecessary mallocing each time this function is called. If buf is
277 given, and buf needs to be expanded, the var pointed to by buflen
280 char *readline(FILE *fp, char **buf, size_t *buflen)
282 char *newline = NULL;
284 char *line; /* The array that contains everything that has been read
286 char *idx; /* Read into this pointer, which points to an offset
288 size_t size, newsize; /* The size of the current array pointed to by
290 size_t maxlen; /* Maximum number of characters that may be read with
291 fgets. This is newsize - oldsize. */
296 if((buf != NULL) && (buflen != NULL))
304 line = xmalloc(size);
313 p = fgets(idx, maxlen, fp);
314 if(p == NULL) /* EOF or error */
319 /* otherwise: error; let the calling function print an error
320 message if applicable */
325 newline = strchr(p, '\n');
327 /* We haven't yet read everything to the end of the line */
330 line = xrealloc(line, newsize);
331 idx = &line[size - 1];
332 maxlen = newsize - size + 1;
337 *newline = '\0'; /* kill newline */
342 if((buf != NULL) && (buflen != NULL))
351 Parse a configuration file and put the results in the configuration tree
354 int read_config_file(avl_tree_t *config_tree, const char *fname)
356 int err = -2; /* Parse error */
359 char *variable, *value;
360 int lineno = 0, ignore = 0;
365 if((fp = fopen (fname, "r")) == NULL)
367 syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname, strerror(errno));
372 buffer = xmalloc(bufsize);
376 if((line = readline(fp, &buffer, &bufsize)) == NULL)
390 if((variable = strtok(line, "\t =")) == NULL)
391 continue; /* no tokens on this line */
393 if(variable[0] == '#')
394 continue; /* comment: ignore */
396 if(!strcmp(variable, "-----BEGIN"))
401 if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
403 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
404 variable, lineno, fname);
409 cfg->variable = xstrdup(variable);
410 cfg->value = xstrdup(value);
411 cfg->file = xstrdup(fname);
414 config_add(config_tree, cfg);
417 if(!strcmp(variable, "-----END"))
427 int read_server_config()
432 asprintf(&fname, "%s/tinc.conf", confbase);
433 x = read_config_file(config_tree, fname);
434 if(x == -1) /* System error: complain */
436 syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
443 int isadir(const char* f)
450 return S_ISDIR(s.st_mode);
453 int is_safe_path(const char *file)
463 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
467 p = strrchr(file, '/');
469 if(p == file) /* It's in the root */
479 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
483 if(s.st_uid != geteuid())
485 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
486 f, s.st_uid, geteuid());
490 if(S_ISLNK(s.st_mode))
492 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
495 if(readlink(f, l, MAXBUFSIZE) < 0)
497 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
509 if(lstat(f, &s) < 0 && errno != ENOENT)
511 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
518 if(s.st_uid != geteuid())
520 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
521 f, s.st_uid, geteuid());
525 if(S_ISLNK(s.st_mode))
527 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
530 if(readlink(f, l, MAXBUFSIZE) < 0)
532 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
542 /* Accessible by others */
543 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
551 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
557 /* Check stdin and stdout */
558 if(!isatty(0) || !isatty(1))
560 /* Argh, they are running us from a script or something. Write
561 the files to the current directory and let them burn in hell
563 fn = xstrdup(filename);
567 /* Ask for a file and/or directory name. */
568 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
572 if((fn = readline(stdin, NULL, NULL)) == NULL)
574 fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
579 /* User just pressed enter. */
580 fn = xstrdup(filename);
583 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
585 /* The directory is a relative path or a filename. */
588 directory = get_current_dir_name();
589 asprintf(&p, "%s/%s", directory, fn);
595 umask(0077); /* Disallow everything for group and other */
597 /* Open it first to keep the inode busy */
598 if((r = fopen(fn, mode)) == NULL)
600 fprintf(stderr, _("Error opening file `%s': %s\n"),
601 fn, strerror(errno));
606 /* Then check the file for nasty attacks */
607 if(!is_safe_path(fn)) /* Do not permit any directories that are
608 readable or writeable by other users. */
610 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
611 "I will not create or overwrite this file.\n"),