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 2002/04/13 10:04:14 zarq Exp $
35 #include <sys/types.h>
41 #include <utils.h> /* for cp */
45 #include "netutl.h" /* for str2address */
49 avl_tree_t *config_tree;
51 int pingtimeout = 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 int config_compare(config_t *a, config_t *b)
59 result = strcasecmp(a->variable, b->variable);
64 result = a->line - b->line;
69 return strcmp(a->file, b->file);
72 void init_configuration(avl_tree_t **config_tree)
75 *config_tree = avl_alloc_tree((avl_compare_t)config_compare, (avl_action_t)free_config);
79 void exit_configuration(avl_tree_t **config_tree)
82 avl_delete_tree(*config_tree);
87 config_t *new_config(void)
91 cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg));
96 void free_config(config_t *cfg)
109 void config_add(avl_tree_t *config_tree, config_t *cfg)
112 avl_insert(config_tree, cfg);
116 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
118 config_t cfg, *found;
120 cfg.variable = variable;
124 found = avl_search_closest_greater(config_tree, &cfg);
129 if(strcasecmp(found->variable, variable))
135 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
140 node = avl_search_node(config_tree, cfg);
146 found = (config_t *)node->next->data;
147 if(!strcasecmp(found->variable, cfg->variable))
155 int get_config_bool(config_t *cfg, int *result)
161 if(!strcasecmp(cfg->value, "yes"))
166 else if(!strcasecmp(cfg->value, "no"))
172 syslog(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
173 cfg->variable, cfg->file, cfg->line);
178 int get_config_int(config_t *cfg, int *result)
184 if(sscanf(cfg->value, "%d", result) == 1)
187 syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
188 cfg->variable, cfg->file, cfg->line);
192 int get_config_string(config_t *cfg, char **result)
198 *result = xstrdup(cfg->value);
202 int get_config_address(config_t *cfg, struct addrinfo **result)
209 ai = str2addrinfo(cfg->value, NULL, 0);
217 syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
218 cfg->variable, cfg->file, cfg->line);
222 int get_config_port(config_t *cfg, port_t *result)
228 if(sscanf(cfg->value, "%hu", result) == 1)
230 *result = htons(*result);
234 syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
235 cfg->variable, cfg->file, cfg->line);
239 int get_config_subnet(config_t *cfg, subnet_t **result)
246 subnet = str2net(cfg->value);
250 syslog(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
251 cfg->variable, cfg->file, cfg->line);
255 /* Teach newbies what subnets are... */
257 if(((subnet->type == SUBNET_IPV4) && maskcheck((char *)&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
258 || ((subnet->type == SUBNET_IPV6) && maskcheck((char *)&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t))))
260 syslog(LOG_ERR, _("Network address and prefix length do not match for configuration variable %s in %s line %d"),
261 cfg->variable, cfg->file, cfg->line);
272 Read exactly one line and strip the trailing newline if any. If the
273 file was on EOF, return NULL. Otherwise, return all the data in a
274 dynamically allocated buffer.
276 If line is non-NULL, it will be used as an initial buffer, to avoid
277 unnecessary mallocing each time this function is called. If buf is
278 given, and buf needs to be expanded, the var pointed to by buflen
281 char *readline(FILE *fp, char **buf, size_t *buflen)
283 char *newline = NULL;
285 char *line; /* The array that contains everything that has been read
287 char *idx; /* Read into this pointer, which points to an offset
289 size_t size, newsize; /* The size of the current array pointed to by
291 size_t maxlen; /* Maximum number of characters that may be read with
292 fgets. This is newsize - oldsize. */
297 if((buf != NULL) && (buflen != NULL))
305 line = xmalloc(size);
314 p = fgets(idx, maxlen, fp);
315 if(p == NULL) /* EOF or error */
320 /* otherwise: error; let the calling function print an error
321 message if applicable */
326 newline = strchr(p, '\n');
328 /* We haven't yet read everything to the end of the line */
331 line = xrealloc(line, newsize);
332 idx = &line[size - 1];
333 maxlen = newsize - size + 1;
338 *newline = '\0'; /* kill newline */
343 if((buf != NULL) && (buflen != NULL))
352 Parse a configuration file and put the results in the configuration tree
355 int read_config_file(avl_tree_t *config_tree, const char *fname)
357 int err = -2; /* Parse error */
360 char *variable, *value;
361 int lineno = 0, ignore = 0;
366 if((fp = fopen (fname, "r")) == NULL)
368 syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname, strerror(errno));
373 buffer = xmalloc(bufsize);
377 if((line = readline(fp, &buffer, &bufsize)) == NULL)
391 if((variable = strtok(line, "\t =")) == NULL)
392 continue; /* no tokens on this line */
394 if(variable[0] == '#')
395 continue; /* comment: ignore */
397 if(!strcmp(variable, "-----BEGIN"))
402 if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
404 syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
405 variable, lineno, fname);
410 cfg->variable = xstrdup(variable);
411 cfg->value = xstrdup(value);
412 cfg->file = xstrdup(fname);
415 config_add(config_tree, cfg);
418 if(!strcmp(variable, "-----END"))
428 int read_server_config()
433 asprintf(&fname, "%s/tinc.conf", confbase);
434 x = read_config_file(config_tree, fname);
435 if(x == -1) /* System error: complain */
437 syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
444 int isadir(const char* f)
451 return S_ISDIR(s.st_mode);
454 int is_safe_path(const char *file)
464 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
468 p = strrchr(file, '/');
470 if(p == file) /* It's in the root */
480 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
484 if(s.st_uid != geteuid())
486 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
487 f, s.st_uid, geteuid());
491 if(S_ISLNK(s.st_mode))
493 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
496 if(readlink(f, l, MAXBUFSIZE) < 0)
498 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
510 if(lstat(f, &s) < 0 && errno != ENOENT)
512 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
519 if(s.st_uid != geteuid())
521 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
522 f, s.st_uid, geteuid());
526 if(S_ISLNK(s.st_mode))
528 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"),
531 if(readlink(f, l, MAXBUFSIZE) < 0)
533 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
543 /* Accessible by others */
544 syslog(LOG_ERR, _("`%s' has unsecure permissions"),
552 FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode)
558 /* Check stdin and stdout */
559 if(!isatty(0) || !isatty(1))
561 /* Argh, they are running us from a script or something. Write
562 the files to the current directory and let them burn in hell
564 fn = xstrdup(filename);
568 /* Ask for a file and/or directory name. */
569 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
573 if((fn = readline(stdin, NULL, NULL)) == NULL)
575 fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno));
580 /* User just pressed enter. */
581 fn = xstrdup(filename);
584 if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
586 /* The directory is a relative path or a filename. */
589 directory = get_current_dir_name();
590 asprintf(&p, "%s/%s", directory, fn);
596 umask(0077); /* Disallow everything for group and other */
598 /* Open it first to keep the inode busy */
599 if((r = fopen(fn, mode)) == NULL)
601 fprintf(stderr, _("Error opening file `%s': %s\n"),
602 fn, strerror(errno));
607 /* Then check the file for nasty attacks */
608 if(!is_safe_path(fn)) /* Do not permit any directories that are
609 readable or writeable by other users. */
611 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
612 "I will not create or overwrite this file.\n"),