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 int count[total_vars];
145 memset(count, 0, sizeof(count));
147 for splay_each(config_t, conf, &config) {
150 for(size_t i = 0; variables[i].name; ++i) {
151 if(strcasecmp(variables[i].name, conf->variable) == 0) {
153 var_type = variables[i].type;
161 if(var_type & VAR_OBSOLETE) {
162 fprintf(stderr, "WARNING: obsolete variable %s in %s line %d\n",
163 conf->variable, conf->file, conf->line);
166 if(server && !(var_type & VAR_SERVER)) {
167 fprintf(stderr, "WARNING: host variable %s found in server config %s line %d \n",
168 conf->variable, conf->file, conf->line);
171 if(!server && !(var_type & VAR_HOST)) {
172 fprintf(stderr, "WARNING: server variable %s found in host config %s line %d \n",
173 conf->variable, conf->file, conf->line);
177 for(size_t i = 0; i < total_vars; ++i) {
178 if(count[i] > 1 && !(variables[i].type & VAR_MULTIPLE)) {
179 fprintf(stderr, "WARNING: multiple instances of variable %s in %s\n",
180 variables[i].name, nodename ? nodename : "tinc.conf");
184 splay_empty_tree(&config);
190 static uid_t getuid(void) {
194 static void check_key_file_mode(const char *fname) {
198 static void check_key_file_mode(const char *fname) {
199 const uid_t uid = getuid();
202 if(stat(fname, &st)) {
203 fprintf(stderr, "ERROR: could not stat private key file %s\n", fname);
207 if(st.st_mode & 077) {
208 fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
210 if(st.st_uid != uid) {
211 fprintf(stderr, "You are not running %s as the same uid as %s.\n", exe_name, fname);
212 } else if(ask_fix()) {
213 if(chmod(fname, st.st_mode & ~077u)) {
214 fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
216 fprintf(stderr, "Fixed permissions of %s.\n", fname);
223 static char *read_node_name(void) {
224 if(access(tinc_conf, R_OK) == 0) {
225 return get_my_name(true);
228 fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno));
230 if(errno == ENOENT) {
231 fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n");
232 print_tinc_cmd("init");
236 if(errno == EACCES) {
237 uid_t uid = getuid();
240 fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n");
242 fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf);
249 static bool build_host_conf_path(char *fname, const size_t len) {
250 char *name = get_my_name(true);
253 fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
257 snprintf(fname, len, "%s/hosts/%s", confbase, name);
262 static bool ask_fix_ec_public_key(const char *fname, ecdsa_t *ec_priv) {
267 if(!disable_old_keys(fname, "public Ed25519 key")) {
271 FILE *f = fopen(fname, "a");
274 fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
278 bool success = ecdsa_write_pem_public_key(ec_priv, f);
282 fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname);
284 fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname);
290 #ifndef DISABLE_LEGACY
291 static bool ask_fix_rsa_public_key(const char *fname, rsa_t *rsa_priv) {
296 if(!disable_old_keys(fname, "public RSA key")) {
300 FILE *f = fopen(fname, "a");
303 fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
307 bool success = rsa_write_pem_public_key(rsa_priv, f);
311 fprintf(stderr, "Wrote RSA public key to %s.\n", fname);
313 fprintf(stderr, "ERROR: could not write RSA public key to %s.\n", fname);
319 static bool test_rsa_keypair(rsa_t *rsa_priv, rsa_t *rsa_pub, const char *host_file) {
320 size_t len = rsa_size(rsa_priv);
322 if(len != rsa_size(rsa_pub)) {
323 fprintf(stderr, "ERROR: public and private RSA key lengths do not match.\n");
327 bool success = false;
328 uint8_t *plaintext = xmalloc(len);
329 uint8_t *encrypted = xzalloc(len);
330 uint8_t *decrypted = xzalloc(len);
332 prng_randomize(plaintext, len);
333 plaintext[0] &= 0x7f;
335 if(rsa_public_encrypt(rsa_pub, plaintext, len, encrypted)) {
336 if(rsa_private_decrypt(rsa_priv, encrypted, len, decrypted)) {
337 if(memcmp(plaintext, decrypted, len) == 0) {
340 fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
341 success = ask_fix_rsa_public_key(host_file, rsa_priv);
344 print_new_keys_cmd(KEY_RSA, "ERROR: private RSA key does not work.");
347 fprintf(stderr, "ERROR: public RSA key does not work.\n");
348 success = ask_fix_rsa_public_key(host_file, rsa_priv);
358 static bool check_rsa_pubkey(rsa_t *rsa_priv, rsa_t *rsa_pub, const char *host_file) {
360 fprintf(stderr, "WARNING: No (usable) public RSA key found.\n");
361 return ask_fix_rsa_public_key(host_file, rsa_priv);
365 fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
369 return test_rsa_keypair(rsa_priv, rsa_pub, host_file);
371 #endif // DISABLE_LEGACY
373 static bool test_ec_keypair(ecdsa_t *ec_priv, ecdsa_t *ec_pub, const char *host_file) {
374 // base64-encoded public key obtained from the PRIVATE key.
375 char *b64_priv_pub = ecdsa_get_base64_public_key(ec_priv);
378 print_new_keys_cmd(KEY_ED25519, "ERROR: private Ed25519 key does not work.");
382 // base64-encoded public key obtained from the PUBLIC key.
383 char *b64_pub_pub = ecdsa_get_base64_public_key(ec_pub);
386 fprintf(stderr, "ERROR: public Ed25519 key does not work.\n");
388 return ask_fix_ec_public_key(host_file, ec_priv);
391 bool match = strcmp(b64_pub_pub, b64_priv_pub) == 0;
399 fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n");
400 return ask_fix_ec_public_key(host_file, ec_priv);
403 static bool check_ec_pubkey(ecdsa_t *ec_priv, ecdsa_t *ec_pub, const char *host_file) {
406 print_new_keys_cmd(KEY_ED25519, "WARNING: A public Ed25519 key was found but no private key is known.");
413 return test_ec_keypair(ec_priv, ec_pub, host_file);
416 fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n");
417 return ask_fix_ec_public_key(host_file, ec_priv);
420 static bool check_config_mode(const char *fname) {
421 if(access(fname, R_OK | X_OK) == 0) {
425 if(errno != EACCES) {
426 fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
430 fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
433 if(chmod(fname, 0755)) {
434 fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
441 static bool check_script_confdir(void) {
442 char fname[PATH_MAX];
443 DIR *dir = opendir(confbase);
446 fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno));
452 while((ent = readdir(dir))) {
453 if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
457 strncpy(fname, ent->d_name, sizeof(fname));
458 char *dash = strrchr(fname, '-');
466 if(strcmp(fname, "tinc") && strcmp(fname, "host") && strcmp(fname, "subnet")) {
467 static bool explained = false;
468 fprintf(stderr, "WARNING: Unknown script %s" SLASH "%s found.\n", confbase, ent->d_name);
471 fprintf(stderr, "The only scripts in %s executed by tinc are:\n", confbase);
472 fprintf(stderr, "tinc-up, tinc-down, host-up, host-down, subnet-up and subnet-down.\n");
479 snprintf(fname, sizeof(fname), "%s" SLASH "%s", confbase, ent->d_name);
480 check_config_mode(fname);
488 static bool check_script_hostdir(const char *host_dir) {
489 char fname[PATH_MAX];
490 DIR *dir = opendir(host_dir);
493 fprintf(stderr, "ERROR: cannot read directory %s: %s\n", host_dir, strerror(errno));
499 while((ent = readdir(dir))) {
500 if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
504 strncpy(fname, ent->d_name, sizeof(fname));
505 char *dash = strrchr(fname, '-');
513 snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
514 check_config_mode(fname);
522 #ifdef DISABLE_LEGACY
523 static bool check_public_keys(splay_tree_t *config, const char *name, ecdsa_t *ec_priv) {
525 static bool check_public_keys(splay_tree_t *config, const char *name, rsa_t *rsa_priv, ecdsa_t *ec_priv) {
527 // Check public keys.
528 char host_file[PATH_MAX];
530 if(!build_host_conf_path(host_file, sizeof(host_file))) {
534 if(access(host_file, R_OK)) {
535 fprintf(stderr, "WARNING: cannot read %s\n", host_file);
538 ecdsa_t *ec_pub = NULL;
539 read_ecdsa_public_key(&ec_pub, &config, name);
542 #ifndef DISABLE_LEGACY
543 rsa_t *rsa_pub = NULL;
544 read_rsa_public_key(&rsa_pub, config, name);
546 success = check_rsa_pubkey(rsa_priv, rsa_pub, host_file);
550 if(!check_ec_pubkey(ec_priv, ec_pub, host_file)) {
559 static bool check_keypairs(splay_tree_t *config, const char *name) {
560 // Check private keys.
561 char *priv_keyfile = NULL;
562 ecdsa_t *ec_priv = read_ecdsa_private_key(config, &priv_keyfile);
565 check_key_file_mode(priv_keyfile);
570 #ifdef DISABLE_LEGACY
573 print_new_keys_cmd(KEY_ED25519, "ERROR: No Ed25519 private key found.");
578 rsa_t *rsa_priv = read_rsa_private_key(config, &priv_keyfile);
581 check_key_file_mode(priv_keyfile);
585 if(!rsa_priv && !ec_priv) {
586 print_new_keys_cmd(KEY_BOTH, "ERROR: Neither RSA or Ed25519 private key found.");
592 #ifdef DISABLE_LEGACY
593 bool success = check_public_keys(config, name, ec_priv);
595 bool success = check_public_keys(config, name, rsa_priv, ec_priv);
603 static void check_config_variables(const char *host_dir) {
604 check_conffile(NULL, true);
606 DIR *dir = opendir(host_dir);
609 for(struct dirent * ent; (ent = readdir(dir));) {
610 if(check_id(ent->d_name)) {
611 check_conffile(ent->d_name, false);
619 static bool check_scripts_and_configs(void) {
620 // Check whether scripts are executable.
621 if(!check_script_confdir()) {
625 char host_dir[PATH_MAX];
626 snprintf(host_dir, sizeof(host_dir), "%s" SLASH "hosts", confbase);
628 if(!check_script_hostdir(host_dir)) {
632 // Check for obsolete / unsafe / unknown configuration variables (and print warnings).
633 check_config_variables(host_dir);
638 int fsck(const char *argv0) {
641 // Check that tinc.conf is readable and read our name if it is.
642 char *name = read_node_name();
645 fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
650 // Avoid touching global configuration here. Read the config files into
651 // a temporary configuration tree, then throw it away after fsck is done.
653 init_configuration(&config);
655 // Read the server configuration file and append host configuration for our node.
656 bool success = read_server_config(&config) &&
657 read_host_config(&config, name, true);
659 // Check both RSA and EC key pairs.
660 // We need working configuration to run this check.
662 success = check_keypairs(&config, name);
665 // Check that scripts are executable and check the config for invalid variables.
666 // This check does not require working configuration, so run it always.
667 // This way, we can diagnose more issues on the first run.
668 success = success & check_scripts_and_configs();
670 splay_empty_tree(&config);
674 return success ? EXIT_SUCCESS : EXIT_FAILURE;