Allow using key & configuration parser from tincd in tinc.
authorKirill Isakov <is-kir@ya.ru>
Tue, 27 Jul 2021 16:01:25 +0000 (22:01 +0600)
committerKirill Isakov <is-kir@ya.ru>
Thu, 29 Jul 2021 13:04:49 +0000 (19:04 +0600)
15 files changed:
src/Makefile.am
src/conf.c
src/conf.h
src/conf_net.c [new file with mode: 0644]
src/conf_net.h [new file with mode: 0644]
src/keys.c [new file with mode: 0644]
src/keys.h [new file with mode: 0644]
src/net.c
src/net.h
src/net_setup.c
src/protocol_auth.c
src/tincctl.c
src/tincd.c
src/utils.c
src/utils.h

index e0733be..306bbc4 100644 (file)
@@ -53,6 +53,7 @@ tincd_SOURCES = \
        buffer.c buffer.h \
        cipher.h \
        conf.c conf.h \
+       conf_net.c conf_net.h \
        connection.c connection.h \
        control.c control.h \
        control_common.h \
@@ -70,6 +71,7 @@ tincd_SOURCES = \
        fd_device.c \
        graph.c graph.h \
        hash.c hash.h \
+       keys.c keys.h \
        have.h \
        ipv4.h \
        ipv6.h \
@@ -118,6 +120,9 @@ tinc_SOURCES = \
        ifconfig.c ifconfig.h \
        info.c info.h \
        invitation.c invitation.h \
+       conf.c conf.h \
+       keys.c keys.h \
+       splay_tree.c splay_tree.h \
        list.c list.h \
        names.c names.h \
        netutl.c netutl.h \
index 4dd016c..cbf3bea 100644 (file)
@@ -193,29 +193,6 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) {
        return false;
 }
 
-bool get_config_subnet(const config_t *cfg, subnet_t **result) {
-       subnet_t subnet = {0};
-
-       if(!cfg) {
-               return false;
-       }
-
-       if(!str2net(&subnet, cfg->value)) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
-                      cfg->variable, cfg->file, cfg->line);
-               return false;
-       }
-
-       if(subnetcheck(subnet)) {
-               *(*result = new_subnet()) = subnet;
-               return true;
-       }
-
-       logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
-              cfg->variable, cfg->file, cfg->line);
-       return false;
-}
-
 /*
   Read exactly one line and strip the trailing newline if any.
 */
@@ -359,6 +336,10 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname, bool verbose
 }
 
 void read_config_options(splay_tree_t *config_tree, const char *prefix) {
+       if(!cmdline_conf) {
+               return;
+       }
+
        size_t prefix_len = prefix ? strlen(prefix) : 0;
 
        for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
@@ -392,7 +373,7 @@ void read_config_options(splay_tree_t *config_tree, const char *prefix) {
        }
 }
 
-bool read_server_config(void) {
+bool read_server_config(splay_tree_t *config_tree) {
        char fname[PATH_MAX];
        bool x;
 
index 8457124..d6479a2 100644 (file)
@@ -52,12 +52,11 @@ extern bool get_config_bool(const config_t *config, bool *result);
 extern bool get_config_int(const config_t *config, int *result);
 extern bool get_config_string(const config_t *config, char **result);
 extern bool get_config_address(const config_t *config, struct addrinfo **result);
-extern bool get_config_subnet(const config_t *config, struct subnet_t **result);
 
 extern config_t *parse_config_line(char *line, const char *fname, int lineno);
 extern bool read_config_file(splay_tree_t *config_tree, const char *filename, bool verbose);
 extern void read_config_options(splay_tree_t *config_tree, const char *prefix);
-extern bool read_server_config(void);
+extern bool read_server_config(splay_tree_t *config_tree);
 extern bool read_host_config(splay_tree_t *config_tree, const char *name, bool verbose);
 extern bool append_config_file(const char *name, const char *key, const char *value);
 
diff --git a/src/conf_net.c b/src/conf_net.c
new file mode 100644 (file)
index 0000000..79d5ff5
--- /dev/null
@@ -0,0 +1,26 @@
+#include "conf_net.h"
+#include "logger.h"
+
+bool get_config_subnet(const config_t *cfg, subnet_t **result) {
+       subnet_t subnet = {0};
+
+       if(!cfg) {
+               return false;
+       }
+
+       if(!str2net(&subnet, cfg->value)) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
+                      cfg->variable, cfg->file, cfg->line);
+               return false;
+       }
+
+       if(subnetcheck(subnet)) {
+               *(*result = new_subnet()) = subnet;
+               return true;
+       }
+
+       logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
+              cfg->variable, cfg->file, cfg->line);
+       return false;
+}
+
diff --git a/src/conf_net.h b/src/conf_net.h
new file mode 100644 (file)
index 0000000..90fcddd
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef TINC_NET_CONF_H
+#define TINC_NET_CONF_H
+
+#include "system.h"
+#include "conf.h"
+#include "subnet.h"
+
+extern bool get_config_subnet(const config_t *config, struct subnet_t **result);
+
+#endif // TINC_NET_CONF_H
diff --git a/src/keys.c b/src/keys.c
new file mode 100644 (file)
index 0000000..c857fb6
--- /dev/null
@@ -0,0 +1,336 @@
+#include "system.h"
+#include "keys.h"
+#include "conf.h"
+#include "logger.h"
+#include "names.h"
+#include "xalloc.h"
+#include "ecdsa.h"
+#include "utils.h"
+
+bool disable_old_keys(const char *filename, const char *what) {
+       char tmpfile[PATH_MAX] = "";
+       char buf[1024];
+       bool disabled = false;
+       bool block = false;
+       bool error = false;
+
+       FILE *r = fopen(filename, "r");
+       FILE *w = NULL;
+
+       if(!r) {
+               return false;
+       }
+
+       int result = snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
+
+       if(result < sizeof(tmpfile)) {
+               struct stat st = {.st_mode = 0600};
+               fstat(fileno(r), &st);
+               w = fopenmask(tmpfile, "w", st.st_mode);
+       }
+
+       while(fgets(buf, sizeof(buf), r)) {
+               if(!block && !strncmp(buf, "-----BEGIN ", 11)) {
+                       if((strstr(buf, " ED25519 ") && strstr(what, "Ed25519")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
+                               disabled = true;
+                               block = true;
+                       }
+               }
+
+               bool ed25519pubkey = !strncasecmp(buf, "Ed25519PublicKey", 16) && strchr(" \t=", buf[16]) && strstr(what, "Ed25519");
+
+               if(ed25519pubkey) {
+                       disabled = true;
+               }
+
+               if(w) {
+                       if(block || ed25519pubkey) {
+                               fputc('#', w);
+                       }
+
+                       if(fputs(buf, w) < 0) {
+                               error = true;
+                               break;
+                       }
+               }
+
+               if(block && !strncmp(buf, "-----END ", 9)) {
+                       block = false;
+               }
+       }
+
+       if(w)
+               if(fclose(w) < 0) {
+                       error = true;
+               }
+
+       if(ferror(r) || fclose(r) < 0) {
+               error = true;
+       }
+
+       if(disabled) {
+               if(!w || error) {
+                       fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
+
+                       if(w) {
+                               unlink(tmpfile);
+                       }
+
+                       return false;
+               }
+
+#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");
+                       unlink(tmpfile);
+                       return false;
+               }
+
+#ifdef HAVE_MINGW
+               unlink(bakfile);
+#endif
+               fprintf(stderr, "Warning: old key(s) found and disabled.\n");
+       }
+
+       unlink(tmpfile);
+       return true;
+}
+
+ecdsa_t *read_ecdsa_private_key(splay_tree_t *config_tree, char **keyfile) {
+       FILE *fp;
+       char *fname;
+
+       /* Check for PrivateKeyFile statement and read it */
+
+       if(!get_config_string(lookup_config(config_tree, "Ed25519PrivateKeyFile"), &fname)) {
+               xasprintf(&fname, "%s" SLASH "ed25519_key.priv", confbase);
+       }
+
+       fp = fopen(fname, "r");
+
+       if(!fp) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 private key file `%s': %s", fname, strerror(errno));
+
+               if(errno == ENOENT) {
+                       logger(DEBUG_ALWAYS, LOG_INFO, "Create an Ed25519 key pair with `tinc -n %s generate-ed25519-keys'.", netname ? netname : ".");
+               }
+
+               free(fname);
+               return NULL;
+       }
+
+#ifndef HAVE_MINGW
+       struct stat s;
+
+       if(fstat(fileno(fp), &s)) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat Ed25519 private key file `%s': %s'", fname, strerror(errno));
+               free(fname);
+               return false;
+       }
+
+       if(s.st_mode & ~0100700u) {
+               logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for Ed25519 private key file `%s'!", fname);
+       }
+
+#endif
+
+       ecdsa_t *key = ecdsa_read_pem_private_key(fp);
+       fclose(fp);
+
+       if(!key) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Reading Ed25519 private key file `%s' failed", fname);
+               free(fname);
+               return NULL;
+       }
+
+       if(keyfile) {
+               *keyfile = fname;
+       } else {
+               free(fname);
+       }
+
+       return key;
+}
+
+bool read_ecdsa_public_key(ecdsa_t **ecdsa, splay_tree_t **config_tree, const char *name) {
+       if(ecdsa_active(*ecdsa)) {
+               return true;
+       }
+
+       FILE *fp;
+       char *fname;
+       char *p;
+
+       if(!*config_tree) {
+               init_configuration(config_tree);
+
+               if(!read_host_config(*config_tree, name, true)) {
+                       return false;
+               }
+       }
+
+       /* First, check for simple Ed25519PublicKey statement */
+
+       if(get_config_string(lookup_config(*config_tree, "Ed25519PublicKey"), &p)) {
+               *ecdsa = ecdsa_set_base64_public_key(p);
+               free(p);
+               return *ecdsa != NULL;
+       }
+
+       /* Else, check for Ed25519PublicKeyFile statement and read it */
+
+       if(!get_config_string(lookup_config(*config_tree, "Ed25519PublicKeyFile"), &fname)) {
+               xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
+       }
+
+       fp = fopen(fname, "r");
+
+       if(!fp) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 public key file `%s': %s",
+                      fname, strerror(errno));
+               free(fname);
+               return false;
+       }
+
+       *ecdsa = ecdsa_read_pem_public_key(fp);
+
+       if(!*ecdsa && errno != ENOENT) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Parsing Ed25519 public key file `%s' failed.", fname);
+       }
+
+       fclose(fp);
+       free(fname);
+
+       return *ecdsa != NULL;
+}
+
+#ifndef DISABLE_LEGACY
+rsa_t *read_rsa_private_key(splay_tree_t *config_tree, char **keyfile) {
+       FILE *fp;
+       char *fname;
+       char *n, *d;
+       rsa_t *key;
+
+       /* First, check for simple PrivateKey statement */
+
+       config_t *rsa_priv_conf = lookup_config(config_tree, "PrivateKey");
+
+       if(get_config_string(rsa_priv_conf, &d)) {
+               if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
+                       logger(DEBUG_ALWAYS, LOG_ERR, "PrivateKey used but no PublicKey found!");
+                       free(d);
+                       return NULL;
+               }
+
+               key = rsa_set_hex_private_key(n, "FFFF", d);
+               free(n);
+               free(d);
+
+               if(key && keyfile && rsa_priv_conf->file) {
+                       *keyfile = xstrdup(rsa_priv_conf->file);
+               }
+
+               return key;
+       }
+
+       /* Else, check for PrivateKeyFile statement and read it */
+
+       if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) {
+               xasprintf(&fname, "%s" SLASH "rsa_key.priv", confbase);
+       }
+
+       fp = fopen(fname, "r");
+
+       if(!fp) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA private key file `%s': %s",
+                      fname, strerror(errno));
+
+               if(errno == ENOENT) {
+                       logger(DEBUG_ALWAYS, LOG_INFO, "Create an RSA key pair with `tinc -n %s generate-rsa-keys'.", netname ? netname : ".");
+               }
+
+               free(fname);
+               return NULL;
+       }
+
+#ifndef HAVE_MINGW
+       struct stat s;
+
+       if(fstat(fileno(fp), &s)) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
+               free(fname);
+               return NULL;
+       }
+
+       if(s.st_mode & ~0100700u) {
+               logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
+       }
+
+#endif
+
+       key = rsa_read_pem_private_key(fp);
+       fclose(fp);
+
+       if(!key) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
+               free(fname);
+               return NULL;
+       }
+
+       if(keyfile) {
+               *keyfile = fname;
+       } else {
+               free(fname);
+       }
+
+       return key;
+}
+
+bool read_rsa_public_key(rsa_t **rsa, splay_tree_t *config_tree, const char *name) {
+       FILE *fp;
+       char *fname;
+       char *n;
+
+       /* First, check for simple PublicKey statement */
+
+       if(get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
+               *rsa = rsa_set_hex_public_key(n, "FFFF");
+               free(n);
+               return *rsa != NULL;
+       }
+
+       /* Else, check for PublicKeyFile statement and read it */
+
+       if(!get_config_string(lookup_config(config_tree, "PublicKeyFile"), &fname)) {
+               xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
+       }
+
+       fp = fopen(fname, "r");
+
+       if(!fp) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
+               free(fname);
+               return false;
+       }
+
+       *rsa = rsa_read_pem_public_key(fp);
+       fclose(fp);
+
+       if(!*rsa) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
+       }
+
+       free(fname);
+
+       return *rsa != NULL;
+}
+#endif
diff --git a/src/keys.h b/src/keys.h
new file mode 100644 (file)
index 0000000..2c3ab40
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef TINC_KEYS_H
+#define TINC_KEYS_H
+
+#include "rsa.h"
+#include "ecdsa.h"
+#include "splay_tree.h"
+
+extern bool disable_old_keys(const char *filename, const char *what);
+
+extern ecdsa_t *read_ecdsa_private_key(splay_tree_t *config_tree, char **keyfile);
+extern bool read_ecdsa_public_key(ecdsa_t **ecdsa, splay_tree_t **config_tree, const char *name);
+
+#ifndef DISABLE_LEGACY
+extern rsa_t *read_rsa_private_key(splay_tree_t *config, char **keyfile);
+extern bool read_rsa_public_key(rsa_t **rsa, splay_tree_t *config_tree, const char *name);
+#endif
+
+#endif // TINC_KEYS_H
index ab4b635..de79b5e 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -23,6 +23,7 @@
 #include "system.h"
 
 #include "autoconnect.h"
+#include "conf_net.h"
 #include "conf.h"
 #include "connection.h"
 #include "device.h"
@@ -340,7 +341,7 @@ int reload_configuration(void) {
        exit_configuration(&config_tree);
        init_configuration(&config_tree);
 
-       if(!read_server_config()) {
+       if(!read_server_config(config_tree)) {
                logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reread configuration file.");
                return EINVAL;
        }
index 1bb267f..ba4cdb4 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -205,8 +205,6 @@ extern void close_network_connections(void);
 extern int main_loop(void);
 extern void terminate_connection(struct connection_t *c, bool report);
 extern bool node_read_ecdsa_public_key(struct node_t *n);
-extern bool read_ecdsa_public_key(struct connection_t *c);
-extern bool read_rsa_public_key(struct connection_t *c);
 extern void handle_device_data(void *data, int flags);
 extern void handle_meta_connection_data(struct connection_t *c);
 extern void regenerate_key(void);
index f1a70f3..f253ccd 100644 (file)
@@ -23,6 +23,7 @@
 #include "system.h"
 
 #include "cipher.h"
+#include "conf_net.h"
 #include "conf.h"
 #include "connection.h"
 #include "control.h"
@@ -42,6 +43,7 @@
 #include "subnet.h"
 #include "utils.h"
 #include "xalloc.h"
+#include "keys.h"
 
 #ifdef HAVE_MINIUPNPC
 #include "upnp.h"
@@ -109,146 +111,6 @@ exit:
        return n->ecdsa;
 }
 
-bool read_ecdsa_public_key(connection_t *c) {
-       if(ecdsa_active(c->ecdsa)) {
-               return true;
-       }
-
-       FILE *fp;
-       char *fname;
-       char *p;
-
-       if(!c->config_tree) {
-               init_configuration(&c->config_tree);
-
-               if(!read_host_config(c->config_tree, c->name, true)) {
-                       return false;
-               }
-       }
-
-       /* First, check for simple Ed25519PublicKey statement */
-
-       if(get_config_string(lookup_config(c->config_tree, "Ed25519PublicKey"), &p)) {
-               c->ecdsa = ecdsa_set_base64_public_key(p);
-               free(p);
-               return c->ecdsa;
-       }
-
-       /* Else, check for Ed25519PublicKeyFile statement and read it */
-
-       if(!get_config_string(lookup_config(c->config_tree, "Ed25519PublicKeyFile"), &fname)) {
-               xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
-       }
-
-       fp = fopen(fname, "r");
-
-       if(!fp) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 public key file `%s': %s",
-                      fname, strerror(errno));
-               free(fname);
-               return false;
-       }
-
-       c->ecdsa = ecdsa_read_pem_public_key(fp);
-
-       if(!c->ecdsa && errno != ENOENT) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Parsing Ed25519 public key file `%s' failed.", fname);
-       }
-
-       fclose(fp);
-       free(fname);
-       return c->ecdsa;
-}
-
-#ifndef DISABLE_LEGACY
-bool read_rsa_public_key(connection_t *c) {
-       FILE *fp;
-       char *fname;
-       char *n;
-
-       /* First, check for simple PublicKey statement */
-
-       if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &n)) {
-               c->rsa = rsa_set_hex_public_key(n, "FFFF");
-               free(n);
-               return c->rsa;
-       }
-
-       /* Else, check for PublicKeyFile statement and read it */
-
-       if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) {
-               xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
-       }
-
-       fp = fopen(fname, "r");
-
-       if(!fp) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
-               free(fname);
-               return false;
-       }
-
-       c->rsa = rsa_read_pem_public_key(fp);
-       fclose(fp);
-
-       if(!c->rsa) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
-       }
-
-       free(fname);
-       return c->rsa;
-}
-#endif
-
-static bool read_ecdsa_private_key(void) {
-       FILE *fp;
-       char *fname;
-
-       /* Check for PrivateKeyFile statement and read it */
-
-       if(!get_config_string(lookup_config(config_tree, "Ed25519PrivateKeyFile"), &fname)) {
-               xasprintf(&fname, "%s" SLASH "ed25519_key.priv", confbase);
-       }
-
-       fp = fopen(fname, "r");
-
-       if(!fp) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 private key file `%s': %s", fname, strerror(errno));
-
-               if(errno == ENOENT) {
-                       logger(DEBUG_ALWAYS, LOG_INFO, "Create an Ed25519 key pair with `tinc -n %s generate-ed25519-keys'.", netname ? netname : ".");
-               }
-
-               free(fname);
-               return false;
-       }
-
-#ifndef HAVE_MINGW
-       struct stat s;
-
-       if(fstat(fileno(fp), &s)) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat Ed25519 private key file `%s': %s'", fname, strerror(errno));
-               free(fname);
-               return false;
-       }
-
-       if(s.st_mode & ~0100700u) {
-               logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for Ed25519 private key file `%s'!", fname);
-       }
-
-#endif
-
-       myself->connection->ecdsa = ecdsa_read_pem_private_key(fp);
-       fclose(fp);
-
-       if(!myself->connection->ecdsa) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Reading Ed25519 private key file `%s' failed", fname);
-       }
-
-       free(fname);
-       return myself->connection->ecdsa;
-}
-
 static bool read_invitation_key(void) {
        FILE *fp;
        char fname[PATH_MAX];
@@ -274,74 +136,6 @@ static bool read_invitation_key(void) {
        return invitation_key;
 }
 
-#ifndef DISABLE_LEGACY
-static bool read_rsa_private_key(void) {
-       FILE *fp;
-       char *fname;
-       char *n, *d;
-
-       /* First, check for simple PrivateKey statement */
-
-       if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) {
-               if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
-                       logger(DEBUG_ALWAYS, LOG_ERR, "PrivateKey used but no PublicKey found!");
-                       free(d);
-                       return false;
-               }
-
-               myself->connection->rsa = rsa_set_hex_private_key(n, "FFFF", d);
-               free(n);
-               free(d);
-               return myself->connection->rsa;
-       }
-
-       /* Else, check for PrivateKeyFile statement and read it */
-
-       if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) {
-               xasprintf(&fname, "%s" SLASH "rsa_key.priv", confbase);
-       }
-
-       fp = fopen(fname, "r");
-
-       if(!fp) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA private key file `%s': %s",
-                      fname, strerror(errno));
-
-               if(errno == ENOENT) {
-                       logger(DEBUG_ALWAYS, LOG_INFO, "Create an RSA key pair with `tinc -n %s generate-rsa-keys'.", netname ? netname : ".");
-               }
-
-               free(fname);
-               return false;
-       }
-
-#ifndef HAVE_MINGW
-       struct stat s;
-
-       if(fstat(fileno(fp), &s)) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
-               free(fname);
-               return false;
-       }
-
-       if(s.st_mode & ~0100700u) {
-               logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
-       }
-
-#endif
-
-       myself->connection->rsa = rsa_read_pem_private_key(fp);
-       fclose(fp);
-
-       if(!myself->connection->rsa) {
-               logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
-       }
-
-       free(fname);
-       return myself->connection->rsa;
-}
-#endif
-
 #ifndef DISABLE_LEGACY
 static timeout_t keyexpire_timeout;
 
@@ -890,7 +684,8 @@ static bool setup_myself(void) {
        myself->options |= PROT_MINOR << 24;
 
 #ifdef DISABLE_LEGACY
-       experimental = read_ecdsa_private_key();
+       myself->connection->ecdsa = read_ecdsa_private_key(config_tree, NULL);
+       experimental = myself->connection->ecdsa != NULL;
 
        if(!experimental) {
                logger(DEBUG_ALWAYS, LOG_ERR, "No private key available, cannot start tinc!");
@@ -900,18 +695,25 @@ static bool setup_myself(void) {
 #else
 
        if(!get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental)) {
-               experimental = read_ecdsa_private_key();
+               myself->connection->ecdsa = read_ecdsa_private_key(config_tree, NULL);
+               experimental = myself->connection->ecdsa != NULL;
 
                if(!experimental) {
                        logger(DEBUG_ALWAYS, LOG_WARNING, "Support for SPTPS disabled.");
                }
        } else {
-               if(experimental && !read_ecdsa_private_key()) {
-                       return false;
+               if(experimental) {
+                       myself->connection->ecdsa = read_ecdsa_private_key(config_tree, NULL);
+
+                       if(!myself->connection->ecdsa) {
+                               return false;
+                       }
                }
        }
 
-       if(!read_rsa_private_key()) {
+       myself->connection->rsa = read_rsa_private_key(config_tree, NULL);
+
+       if(!myself->connection->rsa) {
                if(experimental) {
                        logger(DEBUG_ALWAYS, LOG_WARNING, "Support for legacy protocol disabled.");
                } else {
index de3d70d..fc39b64 100644 (file)
@@ -46,6 +46,7 @@
 #include "xalloc.h"
 
 #include "ed25519/sha512.h"
+#include "keys.h"
 
 int invitation_lifetime;
 ecdsa_t *invitation_key = NULL;
@@ -160,7 +161,7 @@ bool send_id(connection_t *c) {
        int minor = 0;
 
        if(experimental) {
-               if(c->outgoing && !read_ecdsa_public_key(c)) {
+               if(c->outgoing && !read_ecdsa_public_key(&c->ecdsa, &c->config_tree, c->name)) {
                        minor = 1;
                } else {
                        minor = myself->connection->protocol_minor;
@@ -453,7 +454,7 @@ bool id_h(connection_t *c, const char *request) {
                }
 
                if(experimental) {
-                       read_ecdsa_public_key(c);
+                       read_ecdsa_public_key(&c->ecdsa, &c->config_tree, c->name);
                }
 
                /* Ignore failures if no key known yet */
@@ -500,7 +501,7 @@ bool send_metakey(connection_t *c) {
                return false;
        }
 
-       if(!read_rsa_public_key(c)) {
+       if(!read_rsa_public_key(&c->rsa, c->config_tree, c->name)) {
                return false;
        }
 
@@ -917,7 +918,7 @@ static bool upgrade_h(connection_t *c, const char *request) {
                return false;
        }
 
-       if(ecdsa_active(c->ecdsa) || read_ecdsa_public_key(c)) {
+       if(ecdsa_active(c->ecdsa) || read_ecdsa_public_key(&c->ecdsa, &c->config_tree, c->name)) {
                char *knownkey = ecdsa_get_base64_public_key(c->ecdsa);
                bool different = strcmp(knownkey, pubkey);
                free(knownkey);
index f2b587c..14faf64 100644 (file)
@@ -41,6 +41,7 @@
 #include "top.h"
 #include "version.h"
 #include "subnet.h"
+#include "keys.h"
 
 #ifndef MSG_NOSIGNAL
 #define MSG_NOSIGNAL 0
@@ -247,127 +248,6 @@ static bool parse_options(int argc, char **argv) {
        return true;
 }
 
-/* Open a file with the desired permissions, minus the umask.
-   Also, if we want to create an executable file, we call fchmod()
-   to set the executable bits. */
-
-FILE *fopenmask(const char *filename, const char *mode, mode_t perms) {
-       mode_t mask = umask(0);
-       perms &= ~mask;
-       umask(~perms & 0777);
-       FILE *f = fopen(filename, mode);
-
-       if(!f) {
-               fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
-               return NULL;
-       }
-
-#ifdef HAVE_FCHMOD
-
-       if((perms & 0444) && f) {
-               fchmod(fileno(f), perms);
-       }
-
-#endif
-       umask(mask);
-       return f;
-}
-
-static void disable_old_keys(const char *filename, const char *what) {
-       char tmpfile[PATH_MAX] = "";
-       char buf[1024];
-       bool disabled = false;
-       bool block = false;
-       bool error = false;
-
-       FILE *r = fopen(filename, "r");
-       FILE *w = NULL;
-
-       if(!r) {
-               return;
-       }
-
-       int result = snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
-
-       if(result < sizeof(tmpfile)) {
-               struct stat st = {.st_mode = 0600};
-               fstat(fileno(r), &st);
-               w = fopenmask(tmpfile, "w", st.st_mode);
-       }
-
-       while(fgets(buf, sizeof(buf), r)) {
-               if(!block && !strncmp(buf, "-----BEGIN ", 11)) {
-                       if((strstr(buf, " ED25519 ") && strstr(what, "Ed25519")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
-                               disabled = true;
-                               block = true;
-                       }
-               }
-
-               bool ed25519pubkey = !strncasecmp(buf, "Ed25519PublicKey", 16) && strchr(" \t=", buf[16]) && strstr(what, "Ed25519");
-
-               if(ed25519pubkey) {
-                       disabled = true;
-               }
-
-               if(w) {
-                       if(block || ed25519pubkey) {
-                               fputc('#', w);
-                       }
-
-                       if(fputs(buf, w) < 0) {
-                               error = true;
-                               break;
-                       }
-               }
-
-               if(block && !strncmp(buf, "-----END ", 9)) {
-                       block = false;
-               }
-       }
-
-       if(w)
-               if(fclose(w) < 0) {
-                       error = true;
-               }
-
-       if(ferror(r) || fclose(r) < 0) {
-               error = true;
-       }
-
-       if(disabled) {
-               if(!w || error) {
-                       fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
-
-                       if(w) {
-                               unlink(tmpfile);
-                       }
-
-                       return;
-               }
-
-#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);
-}
-
 static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask, mode_t perms) {
        FILE *r;
        char directory[PATH_MAX] = ".";
index e0e0388..d8ab0ac 100644 (file)
@@ -297,7 +297,7 @@ static bool parse_options(int argc, char **argv) {
 
 exit_fail:
        free_names();
-       free(cmdline_conf);
+       list_delete_list(cmdline_conf);
        cmdline_conf = NULL;
        return false;
 }
@@ -387,7 +387,7 @@ static void cleanup() {
                exit_configuration(&config_tree);
        }
 
-       free(cmdline_conf);
+       list_delete_list(cmdline_conf);
        free_names();
 }
 
@@ -504,7 +504,7 @@ int main(int argc, char **argv) {
        srand(now.tv_sec + now.tv_usec);
        crypto_init();
 
-       if(!read_server_config()) {
+       if(!read_server_config(config_tree)) {
                return 1;
        }
 
index f14094f..d0d1062 100644 (file)
@@ -284,3 +284,30 @@ char *replace_name(const char *name) {
 
        return ret_name;
 }
+
+/* Open a file with the desired permissions, minus the umask.
+   Also, if we want to create an executable file, we call fchmod()
+   to set the executable bits. */
+
+FILE *fopenmask(const char *filename, const char *mode, mode_t perms) {
+       mode_t mask = umask(0);
+       perms &= ~mask;
+       umask(~perms & 0777);
+       FILE *f = fopen(filename, mode);
+
+       if(!f) {
+               fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
+               return NULL;
+       }
+
+#ifdef HAVE_FCHMOD
+
+       if((perms & 0444) && f) {
+               fchmod(fileno(f), perms);
+       }
+
+#endif
+       umask(mask);
+       return f;
+}
+
index 25e8cc9..a0cb4d2 100644 (file)
@@ -55,4 +55,6 @@ extern bool check_id(const char *id);
 extern bool check_netname(const char *netname, bool strict);
 char *replace_name(const char *name);
 
+extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms);
+
 #endif