From: Kirill Isakov Date: Tue, 27 Jul 2021 16:01:25 +0000 (+0600) Subject: Allow using key & configuration parser from tincd in tinc. X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=commitdiff_plain;h=7208397398f7e08d741bfa83594a88e5d01b6220 Allow using key & configuration parser from tincd in tinc. --- diff --git a/src/Makefile.am b/src/Makefile.am index e0733beb..306bbc42 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/conf.c b/src/conf.c index 4dd016cd..cbf3bea0 100644 --- a/src/conf.c +++ b/src/conf.c @@ -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; diff --git a/src/conf.h b/src/conf.h index 84571247..d6479a2e 100644 --- a/src/conf.h +++ b/src/conf.h @@ -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 index 00000000..79d5ff5d --- /dev/null +++ b/src/conf_net.c @@ -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 index 00000000..90fcddd7 --- /dev/null +++ b/src/conf_net.h @@ -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 index 00000000..c857fb63 --- /dev/null +++ b/src/keys.c @@ -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 index 00000000..2c3ab408 --- /dev/null +++ b/src/keys.h @@ -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 diff --git a/src/net.c b/src/net.c index ab4b635b..de79b5e8 100644 --- 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; } diff --git a/src/net.h b/src/net.h index 1bb267f8..ba4cdb44 100644 --- 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); diff --git a/src/net_setup.c b/src/net_setup.c index f1a70f34..f253ccd2 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -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 { diff --git a/src/protocol_auth.c b/src/protocol_auth.c index de3d70dd..fc39b64e 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -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); diff --git a/src/tincctl.c b/src/tincctl.c index f2b587c9..14faf645 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -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] = "."; diff --git a/src/tincd.c b/src/tincd.c index e0e03885..d8ab0ac0 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -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; } diff --git a/src/utils.c b/src/utils.c index f14094f6..d0d10627 100644 --- a/src/utils.c +++ b/src/utils.c @@ -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; +} + diff --git a/src/utils.h b/src/utils.h index 25e8cc95..a0cb4d23 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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