X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fconf.c;h=1c250d7bc3c76f4846d6de58351936a2cf48b6a5;hp=dc5d2dc21f705b4d4e1e745523e495db9b75fb0e;hb=acd018074972f9c13ffecffb618f799d914bbe97;hpb=8c3105283ac53f8cc9cc4dde25957ec1cf6b53a0 diff --git a/src/conf.c b/src/conf.c index dc5d2dc2..1c250d7b 100644 --- a/src/conf.c +++ b/src/conf.c @@ -2,7 +2,8 @@ conf.c -- configuration code Copyright (C) 1998 Robert van der Meulen 1998-2005 Ivo Timmermans - 2000-2009 Guus Sliepen + 2000-2014 Guus Sliepen + 2010-2011 Julien Muchembled 2000 Cris van Pelt This program is free software; you can redistribute it and/or modify @@ -23,7 +24,9 @@ #include "system.h" #include "avl_tree.h" +#include "connection.h" #include "conf.h" +#include "list.h" #include "logger.h" #include "netutl.h" /* for str2address */ #include "protocol.h" @@ -90,7 +93,7 @@ void config_add(avl_tree_t *config_tree, config_t *cfg) { avl_insert(config_tree, cfg); } -config_t *lookup_config(avl_tree_t *config_tree, char *variable) { +config_t *lookup_config(const avl_tree_t *config_tree, char *variable) { config_t cfg, *found; cfg.variable = variable; @@ -108,7 +111,7 @@ config_t *lookup_config(avl_tree_t *config_tree, char *variable) { return found; } -config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg) { +config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg) { avl_node_t *node; config_t *found; @@ -186,7 +189,7 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) { } bool get_config_subnet(const config_t *cfg, subnet_t ** result) { - subnet_t subnet = {0}; + subnet_t subnet = {NULL}; if(!cfg) return false; @@ -335,37 +338,156 @@ bool read_config_file(avl_tree_t *config_tree, const char *fname) { return result; } -bool read_server_config() { - list_node_t *node, *next; - char *fname; - bool x; +void read_config_options(avl_tree_t *config_tree, const char *prefix) { + size_t prefix_len = prefix ? strlen(prefix) : 0; + + for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) { + const config_t *cfg = node->data; + + if(!prefix) { + if(strchr(cfg->variable, '.')) + continue; + } else { + if(strncmp(prefix, cfg->variable, prefix_len) || + cfg->variable[prefix_len] != '.') + continue; + } + + config_t *new = new_config(); - for(node = cmdline_conf->tail; node; node = next) { - config_t *cfg = (config_t *)node->data; - next = node->prev; - if (!strchr(cfg->variable, '.')) { - config_add(config_tree, cfg); - node->data = NULL; - list_unlink_node(cmdline_conf, node); + if(prefix) { + new->variable = xstrdup(cfg->variable + prefix_len + 1); + } else { + new->variable = xstrdup(cfg->variable); } + + new->value = xstrdup(cfg->value); + new->file = NULL; + new->line = cfg->line; + + config_add(config_tree, new); } +} + +bool read_server_config(void) { + char fname[PATH_MAX]; + bool x; - xasprintf(&fname, "%s/tinc.conf", confbase); + read_config_options(config_tree, NULL); + + snprintf(fname, sizeof fname, "%s/tinc.conf", confbase); + errno = 0; x = read_config_file(config_tree, fname); - if(!x) { /* System error: complain */ + // We will try to read the conf files in the "conf.d" dir + if (x) { + char dname[PATH_MAX]; + snprintf(dname, sizeof dname, "%s/conf.d", confbase); + DIR *dir = opendir (dname); + // If we can find this dir + if (dir) { + struct dirent *ep; + // We list all the files in it + while (x && (ep = readdir (dir))) { + size_t l = strlen(ep->d_name); + // And we try to read the ones that end with ".conf" + if (l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) { + snprintf(fname, sizeof fname, "%s/%s", dname, ep->d_name); + x = read_config_file(config_tree, fname); + } + } + closedir (dir); + } + } + + if(!x && errno) { logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno)); } - free(fname); + return x; +} + +bool read_connection_config(connection_t *c) { + char fname[PATH_MAX]; + bool x; + + read_config_options(c->config_tree, c->name); + + snprintf(fname, sizeof fname, "%s/hosts/%s", confbase, c->name); + x = read_config_file(c->config_tree, fname); return x; } +static void disable_old_keys(const char *filename) { + char tmpfile[PATH_MAX] = ""; + char buf[1024]; + bool disabled = false; + FILE *r, *w; + + r = fopen(filename, "r"); + if(!r) + return; + + snprintf(tmpfile, sizeof tmpfile, "%s.tmp", filename); + + w = fopen(tmpfile, "w"); + + while(fgets(buf, sizeof buf, r)) { + if(!strncmp(buf, "-----BEGIN RSA", 14)) { + buf[11] = 'O'; + buf[12] = 'L'; + buf[13] = 'D'; + disabled = true; + } + else if(!strncmp(buf, "-----END RSA", 12)) { + buf[ 9] = 'O'; + buf[10] = 'L'; + buf[11] = 'D'; + disabled = true; + } + if(w && fputs(buf, w) < 0) { + disabled = false; + break; + } + } + + if(w) + fclose(w); + fclose(r); + + if(!w && disabled) { + fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n"); + return; + } + + if(disabled) { +#ifdef HAVE_MINGW + // We cannot atomically replace files on Windows. + char bakfile[PATH_MAX] = ""; + snprintf(bakfile, sizeof bakfile, "%s.bak", filename); + if(rename(filename, bakfile) || rename(tmpfile, filename)) { + rename(bakfile, filename); +#else + if(rename(tmpfile, filename)) { +#endif + fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n"); + } else { +#ifdef HAVE_MINGW + unlink(bakfile); +#endif + fprintf(stderr, "Warning: old key(s) found and disabled.\n"); + } + } + + unlink(tmpfile); +} + FILE *ask_and_open(const char *filename, const char *what) { FILE *r; - char *directory; + char directory[PATH_MAX]; char line[PATH_MAX]; + char abspath[PATH_MAX]; const char *fn; /* Check stdin and stdout */ @@ -399,19 +521,18 @@ FILE *ask_and_open(const char *filename, const char *what) { if(fn[0] != '/') { #endif /* The directory is a relative path or a filename. */ - char *p; - - directory = get_current_dir_name(); - xasprintf(&p, "%s/%s", directory, fn); - free(directory); - fn = p; + getcwd(directory, sizeof directory); + snprintf(abspath, sizeof abspath, "%s/%s", directory, fn); + fn = abspath; } umask(0077); /* Disallow everything for group and other */ + disable_old_keys(fn); + /* Open it first to keep the inode busy */ - r = fopen(fn, "r+") ?: fopen(fn, "w+"); + r = fopen(fn, "a"); if(!r) { fprintf(stderr, "Error opening file `%s': %s\n", @@ -422,33 +543,4 @@ FILE *ask_and_open(const char *filename, const char *what) { return r; } -bool disable_old_keys(FILE *f) { - char buf[100]; - long pos; - bool disabled = false; - - rewind(f); - pos = ftell(f); - - while(fgets(buf, sizeof buf, f)) { - if(!strncmp(buf, "-----BEGIN RSA", 14)) { - buf[11] = 'O'; - buf[12] = 'L'; - buf[13] = 'D'; - fseek(f, pos, SEEK_SET); - fputs(buf, f); - disabled = true; - } - else if(!strncmp(buf, "-----END RSA", 12)) { - buf[ 9] = 'O'; - buf[10] = 'L'; - buf[11] = 'D'; - fseek(f, pos, SEEK_SET); - fputs(buf, f); - disabled = true; - } - pos = ftell(f); - } - return disabled; -}