2 fsck.c -- Check the configuration files for problems
3 Copyright (C) 2014-2022 Guus Sliepen <guus@tinc-vpn.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #ifndef DISABLE_LEGACY
36 static const char *exe_name = NULL;
38 static bool ask_fix(void) {
48 fprintf(stderr, "Fix y/n? ");
51 if(!fgets(buf, sizeof(buf), stdin)) {
56 if(buf[0] == 'y' || buf[0] == 'Y') {
60 if(buf[0] == 'n' || buf[0] == 'N') {
67 static void print_tinc_cmd(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
68 static void print_tinc_cmd(const char *format, ...) {
70 fprintf(stderr, "%s -c %s ", exe_name, confbase);
72 fprintf(stderr, "%s -n %s ", exe_name, netname);
74 fprintf(stderr, "%s ", exe_name);
79 vfprintf(stderr, format, va);
90 static void print_new_keys_cmd(key_type_t key_type, const char *message) {
91 fprintf(stderr, "%s\n\n", message);
95 fprintf(stderr, "You can generate a new RSA keypair with:\n\n");
96 print_tinc_cmd("generate-rsa-keys");
100 fprintf(stderr, "You can generate a new Ed25519 keypair with:\n\n");
101 print_tinc_cmd("generate-ed25519-keys");
105 fprintf(stderr, "You can generate new keys with:\n\n");
106 print_tinc_cmd("generate-keys");
111 static int strtailcmp(const char *str, const char *tail) {
112 size_t slen = strlen(str);
113 size_t tlen = strlen(tail);
119 return memcmp(str + slen - tlen, tail, tlen);
122 static void check_conffile(const char *nodename, bool server) {
124 init_configuration(&config);
129 read = read_server_config(&config);
131 read = read_host_config(&config, nodename, true);
135 splay_empty_tree(&config);
139 size_t total_vars = 0;
141 while(variables[total_vars].name) {
145 const size_t countlen = total_vars * sizeof(int);
146 int *count = alloca(countlen);
147 memset(count, 0, countlen);
149 for splay_each(config_t, conf, &config) {
152 for(size_t i = 0; variables[i].name; ++i) {
153 if(strcasecmp(variables[i].name, conf->variable) == 0) {
155 var_type = variables[i].type;
163 if(var_type & VAR_OBSOLETE) {
164 fprintf(stderr, "WARNING: obsolete variable %s in %s line %d\n",
165 conf->variable, conf->file, conf->line);
168 if(server && !(var_type & VAR_SERVER)) {
169 fprintf(stderr, "WARNING: host variable %s found in server config %s line %d \n",
170 conf->variable, conf->file, conf->line);
173 if(!server && !(var_type & VAR_HOST)) {
174 fprintf(stderr, "WARNING: server variable %s found in host config %s line %d \n",
175 conf->variable, conf->file, conf->line);
179 for(size_t i = 0; i < total_vars; ++i) {
180 if(count[i] > 1 && !(variables[i].type & VAR_MULTIPLE)) {
181 fprintf(stderr, "WARNING: multiple instances of variable %s in %s\n",
182 variables[i].name, nodename ? nodename : "tinc.conf");
186 splay_empty_tree(&config);
192 static uid_t getuid(void) {
196 static void check_key_file_mode(const char *fname) {
200 static void check_key_file_mode(const char *fname) {
201 const uid_t uid = getuid();
204 if(stat(fname, &st)) {
205 fprintf(stderr, "ERROR: could not stat private key file %s\n", fname);
209 if(st.st_mode & 077) {
210 fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
212 if(st.st_uid != uid) {
213 fprintf(stderr, "You are not running %s as the same uid as %s.\n", exe_name, fname);
214 } else if(ask_fix()) {
215 if(chmod(fname, st.st_mode & ~077u)) {
216 fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
218 fprintf(stderr, "Fixed permissions of %s.\n", fname);
223 #endif // HAVE_WINDOWS
225 static char *read_node_name(void) {
226 if(access(tinc_conf, R_OK) == 0) {
227 return get_my_name(true);
230 fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno));
232 if(errno == ENOENT) {
233 fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n");
234 print_tinc_cmd("init");
238 if(errno == EACCES) {
239 uid_t uid = getuid();
242 fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n");
244 fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf);
251 static bool build_host_conf_path(char *fname, const size_t len) {
252 char *name = get_my_name(true);
255 fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
259 snprintf(fname, len, "%s/hosts/%s", confbase, name);
264 static bool ask_fix_ec_public_key(const char *fname, ecdsa_t *ec_priv) {
269 if(!disable_old_keys(fname, "public Ed25519 key")) {
273 FILE *f = fopen(fname, "a");
276 fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
280 bool success = ecdsa_write_pem_public_key(ec_priv, f);
284 fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname);
286 fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname);
292 #ifndef DISABLE_LEGACY
293 static bool ask_fix_rsa_public_key(const char *fname, rsa_t *rsa_priv) {
298 if(!disable_old_keys(fname, "public RSA key")) {
302 FILE *f = fopen(fname, "a");
305 fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
309 bool success = rsa_write_pem_public_key(rsa_priv, f);
313 fprintf(stderr, "Wrote RSA public key to %s.\n", fname);
315 fprintf(stderr, "ERROR: could not write RSA public key to %s.\n", fname);
321 static bool test_rsa_keypair(rsa_t *rsa_priv, rsa_t *rsa_pub, const char *host_file) {
322 size_t len = rsa_size(rsa_priv);
324 if(len != rsa_size(rsa_pub)) {
325 fprintf(stderr, "ERROR: public and private RSA key lengths do not match.\n");
329 bool success = false;
330 uint8_t *plaintext = xmalloc(len);
331 uint8_t *encrypted = xzalloc(len);
332 uint8_t *decrypted = xzalloc(len);
334 prng_randomize(plaintext, len);
335 plaintext[0] &= 0x7f;
337 if(rsa_public_encrypt(rsa_pub, plaintext, len, encrypted)) {
338 if(rsa_private_decrypt(rsa_priv, encrypted, len, decrypted)) {
339 if(memcmp(plaintext, decrypted, len) == 0) {
342 fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
343 success = ask_fix_rsa_public_key(host_file, rsa_priv);
346 print_new_keys_cmd(KEY_RSA, "ERROR: private RSA key does not work.");
349 fprintf(stderr, "ERROR: public RSA key does not work.\n");
350 success = ask_fix_rsa_public_key(host_file, rsa_priv);
360 static bool check_rsa_pubkey(rsa_t *rsa_priv, rsa_t *rsa_pub, const char *host_file) {
362 fprintf(stderr, "WARNING: No (usable) public RSA key found.\n");
363 return ask_fix_rsa_public_key(host_file, rsa_priv);
367 fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
371 return test_rsa_keypair(rsa_priv, rsa_pub, host_file);
373 #endif // DISABLE_LEGACY
375 static bool test_ec_keypair(ecdsa_t *ec_priv, ecdsa_t *ec_pub, const char *host_file) {
376 // base64-encoded public key obtained from the PRIVATE key.
377 char *b64_priv_pub = ecdsa_get_base64_public_key(ec_priv);
380 print_new_keys_cmd(KEY_ED25519, "ERROR: private Ed25519 key does not work.");
384 // base64-encoded public key obtained from the PUBLIC key.
385 char *b64_pub_pub = ecdsa_get_base64_public_key(ec_pub);
388 fprintf(stderr, "ERROR: public Ed25519 key does not work.\n");
390 return ask_fix_ec_public_key(host_file, ec_priv);
393 bool match = strcmp(b64_pub_pub, b64_priv_pub) == 0;
401 fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n");
402 return ask_fix_ec_public_key(host_file, ec_priv);
405 static bool check_ec_pubkey(ecdsa_t *ec_priv, ecdsa_t *ec_pub, const char *host_file) {
408 print_new_keys_cmd(KEY_ED25519, "WARNING: A public Ed25519 key was found but no private key is known.");
415 return test_ec_keypair(ec_priv, ec_pub, host_file);
418 fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n");
419 return ask_fix_ec_public_key(host_file, ec_priv);
422 static bool check_config_mode(const char *fname) {
423 if(access(fname, R_OK | X_OK) == 0) {
427 if(errno != EACCES) {
428 fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
432 fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
435 if(chmod(fname, 0755)) {
436 fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
443 static bool check_script_confdir(void) {
444 char fname[PATH_MAX];
445 DIR *dir = opendir(confbase);
448 fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno));
454 while((ent = readdir(dir))) {
455 if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
459 strncpy(fname, ent->d_name, sizeof(fname));
460 char *dash = strrchr(fname, '-');
468 if(strcmp(fname, "tinc") && strcmp(fname, "host") && strcmp(fname, "subnet")) {
469 static bool explained = false;
470 fprintf(stderr, "WARNING: Unknown script %s" SLASH "%s found.\n", confbase, ent->d_name);
473 fprintf(stderr, "The only scripts in %s executed by tinc are:\n", confbase);
474 fprintf(stderr, "tinc-up, tinc-down, host-up, host-down, subnet-up and subnet-down.\n");
481 snprintf(fname, sizeof(fname), "%s" SLASH "%s", confbase, ent->d_name);
482 check_config_mode(fname);
490 static bool check_script_hostdir(const char *host_dir) {
491 char fname[PATH_MAX];
492 DIR *dir = opendir(host_dir);
495 fprintf(stderr, "ERROR: cannot read directory %s: %s\n", host_dir, strerror(errno));
501 while((ent = readdir(dir))) {
502 if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
506 strncpy(fname, ent->d_name, sizeof(fname));
507 char *dash = strrchr(fname, '-');
515 snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
516 check_config_mode(fname);
524 #ifdef DISABLE_LEGACY
525 static bool check_public_keys(splay_tree_t *config, const char *name, ecdsa_t *ec_priv) {
527 static bool check_public_keys(splay_tree_t *config, const char *name, rsa_t *rsa_priv, ecdsa_t *ec_priv) {
529 // Check public keys.
530 char host_file[PATH_MAX];
532 if(!build_host_conf_path(host_file, sizeof(host_file))) {
536 if(access(host_file, R_OK)) {
537 fprintf(stderr, "WARNING: cannot read %s\n", host_file);
540 ecdsa_t *ec_pub = read_ecdsa_public_key(&config, name);
543 #ifndef DISABLE_LEGACY
544 rsa_t *rsa_pub = read_rsa_public_key(config, name);
545 success = check_rsa_pubkey(rsa_priv, rsa_pub, host_file);
549 if(!check_ec_pubkey(ec_priv, ec_pub, host_file)) {
558 static bool check_keypairs(splay_tree_t *config, const char *name) {
559 // Check private keys.
560 char *priv_keyfile = NULL;
561 ecdsa_t *ec_priv = read_ecdsa_private_key(config, &priv_keyfile);
564 check_key_file_mode(priv_keyfile);
569 #ifdef DISABLE_LEGACY
572 print_new_keys_cmd(KEY_ED25519, "ERROR: No Ed25519 private key found.");
577 rsa_t *rsa_priv = read_rsa_private_key(config, &priv_keyfile);
580 check_key_file_mode(priv_keyfile);
584 if(!rsa_priv && !ec_priv) {
585 print_new_keys_cmd(KEY_BOTH, "ERROR: Neither RSA or Ed25519 private key found.");
591 #ifdef DISABLE_LEGACY
592 bool success = check_public_keys(config, name, ec_priv);
594 bool success = check_public_keys(config, name, rsa_priv, ec_priv);
602 static void check_config_variables(const char *host_dir) {
603 check_conffile(NULL, true);
605 DIR *dir = opendir(host_dir);
608 for(struct dirent * ent; (ent = readdir(dir));) {
609 if(check_id(ent->d_name)) {
610 check_conffile(ent->d_name, false);
618 static bool check_scripts_and_configs(void) {
619 // Check whether scripts are executable.
620 if(!check_script_confdir()) {
624 char host_dir[PATH_MAX];
625 snprintf(host_dir, sizeof(host_dir), "%s" SLASH "hosts", confbase);
627 if(!check_script_hostdir(host_dir)) {
631 // Check for obsolete / unsafe / unknown configuration variables (and print warnings).
632 check_config_variables(host_dir);
637 int fsck(const char *argv0) {
640 // Check that tinc.conf is readable and read our name if it is.
641 char *name = read_node_name();
644 fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
649 // Avoid touching global configuration here. Read the config files into
650 // a temporary configuration tree, then throw it away after fsck is done.
652 init_configuration(&config);
654 // Read the server configuration file and append host configuration for our node.
655 bool success = read_server_config(&config) &&
656 read_host_config(&config, name, true);
658 // Check both RSA and EC key pairs.
659 // We need working configuration to run this check.
661 success = check_keypairs(&config, name);
664 // Check that scripts are executable and check the config for invalid variables.
665 // This check does not require working configuration, so run it always.
666 // This way, we can diagnose more issues on the first run.
667 success = success & check_scripts_and_configs();
669 splay_empty_tree(&config);
673 return success ? EXIT_SUCCESS : EXIT_FAILURE;