2 conf.c -- configuration code
3 Copyright (C) 1998 Robert van der Meulen
4 1998-2002 Ivo Timmermans <ivo@o2w.nl>
5 2000-2002 Guus Sliepen <guus@sliepen.eu.org>
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.60 2002/09/09 22:32:30 guus Exp $
35 #include <sys/types.h>
41 #include <utils.h> /* for cp */
45 #include "netutl.h" /* for str2address */
49 avl_tree_t *config_tree;
52 int pingtimeout = 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 int config_compare(config_t *a, config_t *b)
60 result = strcasecmp(a->variable, b->variable);
65 result = a->line - b->line;
70 return strcmp(a->file, b->file);
73 void init_configuration(avl_tree_t ** config_tree)
77 *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
80 void exit_configuration(avl_tree_t ** config_tree)
84 avl_delete_tree(*config_tree);
88 config_t *new_config(void)
92 return (config_t *) xmalloc_and_zero(sizeof(config_t));
95 void free_config(config_t *cfg)
111 void config_add(avl_tree_t *config_tree, config_t *cfg)
115 avl_insert(config_tree, cfg);
118 config_t *lookup_config(avl_tree_t *config_tree, char *variable)
120 config_t cfg, *found;
124 cfg.variable = variable;
128 found = avl_search_closest_greater(config_tree, &cfg);
133 if(strcasecmp(found->variable, variable))
139 config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
146 node = avl_search_node(config_tree, cfg);
150 found = (config_t *) node->next->data;
152 if(!strcasecmp(found->variable, cfg->variable))
160 int get_config_bool(config_t *cfg, int *result)
167 if(!strcasecmp(cfg->value, "yes")) {
170 } 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)
188 if(sscanf(cfg->value, "%d", result) == 1)
191 syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
192 cfg->variable, cfg->file, cfg->line);
197 int get_config_string(config_t *cfg, char **result)
204 *result = xstrdup(cfg->value);
209 int get_config_address(config_t *cfg, struct addrinfo **result)
218 ai = str2addrinfo(cfg->value, NULL, 0);
225 syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
226 cfg->variable, cfg->file, cfg->line);
231 int get_config_port(config_t *cfg, port_t *result)
238 if(sscanf(cfg->value, "%hu", result) == 1) {
239 *result = htons(*result);
243 syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
244 cfg->variable, cfg->file, cfg->line);
249 int get_config_subnet(config_t *cfg, subnet_t ** result)
258 subnet = str2net(cfg->value);
261 syslog(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
262 cfg->variable, cfg->file, cfg->line);
266 /* Teach newbies what subnets are... */
268 if(((subnet->type == SUBNET_IPV4)
269 && maskcheck(&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
270 || ((subnet->type == SUBNET_IPV6)
271 && maskcheck(&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t)))) {
272 syslog(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
273 cfg->variable, cfg->file, cfg->line);
284 Read exactly one line and strip the trailing newline if any. If the
285 file was on EOF, return NULL. Otherwise, return all the data in a
286 dynamically allocated buffer.
288 If line is non-NULL, it will be used as an initial buffer, to avoid
289 unnecessary mallocing each time this function is called. If buf is
290 given, and buf needs to be expanded, the var pointed to by buflen
293 char *readline(FILE * fp, char **buf, size_t *buflen)
295 char *newline = NULL;
297 char *line; /* The array that contains everything that has been read so far */
298 char *idx; /* Read into this pointer, which points to an offset within line */
299 size_t size, newsize; /* The size of the current array pointed to by line */
300 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
310 line = xmalloc(size);
319 p = fgets(idx, maxlen, fp);
321 if(!p) { /* EOF or error */
325 /* otherwise: error; let the calling function print an error message if applicable */
330 newline = strchr(p, '\n');
332 if(!newline) { /* We haven't yet read everything to the end of the line */
334 line = xrealloc(line, newsize);
335 idx = &line[size - 1];
336 maxlen = newsize - size + 1;
339 *newline = '\0'; /* kill newline */
353 Parse a configuration file and put the results in the configuration tree
356 int read_config_file(avl_tree_t *config_tree, const char *fname)
358 int err = -2; /* Parse error */
361 char *variable, *value;
362 int lineno = 0, ignore = 0;
368 fp = fopen(fname, "r");
371 syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname,
377 buffer = xmalloc(bufsize);
380 line = readline(fp, &buffer, &bufsize);
394 variable = strtok(line, "\t =");
397 continue; /* no tokens on this line */
399 if(variable[0] == '#')
400 continue; /* comment: ignore */
402 if(!strcmp(variable, "-----BEGIN"))
406 value = strtok(NULL, "\t\n\r =");
408 if(!value || 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()
440 asprintf(&fname, "%s/tinc.conf", confbase);
441 x = read_config_file(config_tree, fname);
443 if(x == -1) { /* System error: complain */
444 syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
452 int isadir(const char *f)
459 return S_ISDIR(s.st_mode);
462 int is_safe_path(const char *file)
471 syslog(LOG_ERR, _("`%s' is not an absolute path"), file);
475 p = strrchr(file, '/');
477 if(p == file) /* It's in the root */
486 if(lstat(f, &s) < 0) {
487 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
491 if(s.st_uid != geteuid()) {
492 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
493 f, s.st_uid, geteuid());
497 if(S_ISLNK(s.st_mode)) {
498 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"), f);
500 if(readlink(f, l, MAXBUFSIZE) < 0) {
501 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f,
514 if(lstat(f, &s) < 0 && errno != ENOENT) {
515 syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
522 if(s.st_uid != geteuid()) {
523 syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
524 f, s.st_uid, geteuid());
528 if(S_ISLNK(s.st_mode)) {
529 syslog(LOG_WARNING, _("Warning: `%s' is a symlink"), f);
531 if(readlink(f, l, MAXBUFSIZE) < 0) {
532 syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f,
541 if(s.st_mode & 0007) {
542 /* Accessible by others */
543 syslog(LOG_ERR, _("`%s' has unsecure permissions"), f);
550 FILE *ask_and_safe_open(const char *filename, const char *what,
557 /* Check stdin and stdout */
558 if(!isatty(0) || !isatty(1)) {
559 /* Argh, they are running us from a script or something. Write
560 the files to the current directory and let them burn in hell
562 fn = xstrdup(filename);
564 /* Ask for a file and/or directory name. */
565 fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
569 fn = readline(stdin, NULL, NULL);
572 fprintf(stderr, _("Error while reading stdin: %s\n"),
578 /* User just pressed enter. */
579 fn = xstrdup(filename);
582 if(!strchr(fn, '/') || fn[0] != '/') {
583 /* The directory is a relative path or a filename. */
586 directory = get_current_dir_name();
587 asprintf(&p, "%s/%s", directory, fn);
593 umask(0077); /* Disallow everything for group and other */
595 /* Open it first to keep the inode busy */
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 readable or writeable by other users. */
608 fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
609 "I will not create or overwrite this file.\n"), fn);