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, ...) {
69 fprintf(stderr, "%s -c %s ", exe_name, confbase);
71 fprintf(stderr, "%s -n %s ", exe_name, netname);
73 fprintf(stderr, "%s ", exe_name);
78 vfprintf(stderr, format, va);
89 static void print_new_keys_cmd(key_type_t key_type, const char *message) {
90 fprintf(stderr, "%s\n\n", message);
94 fprintf(stderr, "You can generate a new RSA keypair with:\n\n");
95 print_tinc_cmd("generate-rsa-keys");
99 fprintf(stderr, "You can generate a new Ed25519 keypair with:\n\n");
100 print_tinc_cmd("generate-ed25519-keys");
104 fprintf(stderr, "You can generate new keys with:\n\n");
105 print_tinc_cmd("generate-keys");
110 static int strtailcmp(const char *str, const char *tail) {
111 size_t slen = strlen(str);
112 size_t tlen = strlen(tail);
118 return memcmp(str + slen - tlen, tail, tlen);
121 static void check_conffile(const char *nodename, bool server) {
123 init_configuration(&config);
128 read = read_server_config(&config);
130 read = read_host_config(&config, nodename, true);
134 splay_empty_tree(&config);
138 size_t total_vars = 0;
140 while(variables[total_vars].name) {
144 const size_t countlen = total_vars * sizeof(int);
145 int *count = alloca(countlen);
146 memset(count, 0, countlen);
148 for splay_each(config_t, conf, &config) {
151 for(size_t i = 0; variables[i].name; ++i) {
152 if(strcasecmp(variables[i].name, conf->variable) == 0) {
154 var_type = variables[i].type;
162 if(var_type & VAR_OBSOLETE) {
163 fprintf(stderr, "WARNING: obsolete variable %s in %s line %d\n",
164 conf->variable, conf->file, conf->line);
167 if(server && !(var_type & VAR_SERVER)) {
168 fprintf(stderr, "WARNING: host variable %s found in server config %s line %d \n",
169 conf->variable, conf->file, conf->line);
172 if(!server && !(var_type & VAR_HOST)) {
173 fprintf(stderr, "WARNING: server variable %s found in host config %s line %d \n",
174 conf->variable, conf->file, conf->line);
178 for(size_t i = 0; i < total_vars; ++i) {
179 if(count[i] > 1 && !(variables[i].type & VAR_MULTIPLE)) {
180 fprintf(stderr, "WARNING: multiple instances of variable %s in %s\n",
181 variables[i].name, nodename ? nodename : "tinc.conf");
185 splay_empty_tree(&config);
191 static uid_t getuid(void) {
195 static void check_key_file_mode(const char *fname) {
199 static void check_key_file_mode(const char *fname) {
200 const uid_t uid = getuid();
203 if(stat(fname, &st)) {
204 fprintf(stderr, "ERROR: could not stat private key file %s\n", fname);
208 if(st.st_mode & 077) {
209 fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
211 if(st.st_uid != uid) {
212 fprintf(stderr, "You are not running %s as the same uid as %s.\n", exe_name, fname);
213 } else if(ask_fix()) {
214 if(chmod(fname, st.st_mode & ~077u)) {
215 fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
217 fprintf(stderr, "Fixed permissions of %s.\n", fname);
222 #endif // HAVE_WINDOWS
224 static char *read_node_name(void) {
225 if(access(tinc_conf, R_OK) == 0) {
226 return get_my_name(true);
229 fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno));
231 if(errno == ENOENT) {
232 fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n");
233 print_tinc_cmd("init");
237 if(errno == EACCES) {
238 uid_t uid = getuid();
241 fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n");
243 fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf);
250 static bool build_host_conf_path(char *fname, const size_t len) {
251 char *name = get_my_name(true);
254 fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
258 snprintf(fname, len, "%s/hosts/%s", confbase, name);
263 static bool ask_fix_ec_public_key(const char *fname, ecdsa_t *ec_priv) {
268 if(!disable_old_keys(fname, "public Ed25519 key")) {
272 FILE *f = fopen(fname, "a");
275 fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
279 bool success = ecdsa_write_pem_public_key(ec_priv, f);
283 fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname);
285 fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname);
291 #ifndef DISABLE_LEGACY
292 static bool ask_fix_rsa_public_key(const char *fname, rsa_t *rsa_priv) {
297 if(!disable_old_keys(fname, "public RSA key")) {
301 FILE *f = fopen(fname, "a");
304 fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
308 bool success = rsa_write_pem_public_key(rsa_priv, f);
312 fprintf(stderr, "Wrote RSA public key to %s.\n", fname);
314 fprintf(stderr, "ERROR: could not write RSA public key to %s.\n", fname);
320 static bool test_rsa_keypair(rsa_t *rsa_priv, rsa_t *rsa_pub, const char *host_file) {
321 size_t len = rsa_size(rsa_priv);
323 if(len != rsa_size(rsa_pub)) {
324 fprintf(stderr, "ERROR: public and private RSA key lengths do not match.\n");
328 bool success = false;
329 uint8_t *plaintext = xmalloc(len);
330 uint8_t *encrypted = xzalloc(len);
331 uint8_t *decrypted = xzalloc(len);
333 prng_randomize(plaintext, len);
334 plaintext[0] &= 0x7f;
336 if(rsa_public_encrypt(rsa_pub, plaintext, len, encrypted)) {
337 if(rsa_private_decrypt(rsa_priv, encrypted, len, decrypted)) {
338 if(memcmp(plaintext, decrypted, len) == 0) {
341 fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
342 success = ask_fix_rsa_public_key(host_file, rsa_priv);
345 print_new_keys_cmd(KEY_RSA, "ERROR: private RSA key does not work.");
348 fprintf(stderr, "ERROR: public RSA key does not work.\n");
349 success = ask_fix_rsa_public_key(host_file, rsa_priv);
359 static bool check_rsa_pubkey(rsa_t *rsa_priv, rsa_t *rsa_pub, const char *host_file) {
361 fprintf(stderr, "WARNING: No (usable) public RSA key found.\n");
362 return ask_fix_rsa_public_key(host_file, rsa_priv);
366 fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
370 return test_rsa_keypair(rsa_priv, rsa_pub, host_file);
372 #endif // DISABLE_LEGACY
374 static bool test_ec_keypair(ecdsa_t *ec_priv, ecdsa_t *ec_pub, const char *host_file) {
375 // base64-encoded public key obtained from the PRIVATE key.
376 char *b64_priv_pub = ecdsa_get_base64_public_key(ec_priv);
379 print_new_keys_cmd(KEY_ED25519, "ERROR: private Ed25519 key does not work.");
383 // base64-encoded public key obtained from the PUBLIC key.
384 char *b64_pub_pub = ecdsa_get_base64_public_key(ec_pub);
387 fprintf(stderr, "ERROR: public Ed25519 key does not work.\n");
389 return ask_fix_ec_public_key(host_file, ec_priv);
392 bool match = strcmp(b64_pub_pub, b64_priv_pub) == 0;
400 fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n");
401 return ask_fix_ec_public_key(host_file, ec_priv);
404 static bool check_ec_pubkey(ecdsa_t *ec_priv, ecdsa_t *ec_pub, const char *host_file) {
407 print_new_keys_cmd(KEY_ED25519, "WARNING: A public Ed25519 key was found but no private key is known.");
414 return test_ec_keypair(ec_priv, ec_pub, host_file);
417 fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n");
418 return ask_fix_ec_public_key(host_file, ec_priv);
421 static bool check_config_mode(const char *fname) {
422 if(access(fname, R_OK | X_OK) == 0) {
426 if(errno != EACCES) {
427 fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
431 fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
434 if(chmod(fname, 0755)) {
435 fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
442 static bool check_script_confdir(void) {
443 char fname[PATH_MAX];
444 DIR *dir = opendir(confbase);
447 fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno));
453 while((ent = readdir(dir))) {
454 if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
458 strncpy(fname, ent->d_name, sizeof(fname));
459 char *dash = strrchr(fname, '-');
467 if(strcmp(fname, "tinc") && strcmp(fname, "host") && strcmp(fname, "subnet")) {
468 static bool explained = false;
469 fprintf(stderr, "WARNING: Unknown script %s" SLASH "%s found.\n", confbase, ent->d_name);
472 fprintf(stderr, "The only scripts in %s executed by tinc are:\n", confbase);
473 fprintf(stderr, "tinc-up, tinc-down, host-up, host-down, subnet-up and subnet-down.\n");
480 snprintf(fname, sizeof(fname), "%s" SLASH "%s", confbase, ent->d_name);
481 check_config_mode(fname);
489 static bool check_script_hostdir(const char *host_dir) {
490 char fname[PATH_MAX];
491 DIR *dir = opendir(host_dir);
494 fprintf(stderr, "ERROR: cannot read directory %s: %s\n", host_dir, strerror(errno));
500 while((ent = readdir(dir))) {
501 if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
505 strncpy(fname, ent->d_name, sizeof(fname));
506 char *dash = strrchr(fname, '-');
514 snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
515 check_config_mode(fname);
523 #ifdef DISABLE_LEGACY
524 static bool check_public_keys(splay_tree_t *config, const char *name, ecdsa_t *ec_priv) {
526 static bool check_public_keys(splay_tree_t *config, const char *name, rsa_t *rsa_priv, ecdsa_t *ec_priv) {
528 // Check public keys.
529 char host_file[PATH_MAX];
531 if(!build_host_conf_path(host_file, sizeof(host_file))) {
535 if(access(host_file, R_OK)) {
536 fprintf(stderr, "WARNING: cannot read %s\n", host_file);
539 ecdsa_t *ec_pub = NULL;
540 read_ecdsa_public_key(&ec_pub, &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;