Replace getrandom() with getentropy()
[tinc] / src / fsck.c
1 /*
2     fsck.c -- Check the configuration files for problems
3     Copyright (C) 2014-2022 Guus Sliepen <guus@tinc-vpn.org>
4
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.
9
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.
14
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.
18 */
19
20 #include "system.h"
21 #include "crypto.h"
22 #include "ecdsa.h"
23 #include "ecdsagen.h"
24 #include "fsck.h"
25 #include "names.h"
26 #ifndef DISABLE_LEGACY
27 #include "rsa.h"
28 #include "rsagen.h"
29 #endif
30 #include "tincctl.h"
31 #include "utils.h"
32 #include "xalloc.h"
33 #include "keys.h"
34 #include "conf.h"
35
36 static const char *exe_name = NULL;
37
38 static bool ask_fix(void) {
39         if(force) {
40                 return true;
41         }
42
43         if(!tty) {
44                 return false;
45         }
46
47 again:
48         fprintf(stderr, "Fix y/n? ");
49         char buf[1024];
50
51         if(!fgets(buf, sizeof(buf), stdin)) {
52                 tty = false;
53                 return false;
54         }
55
56         if(buf[0] == 'y' || buf[0] == 'Y') {
57                 return true;
58         }
59
60         if(buf[0] == 'n' || buf[0] == 'N') {
61                 return false;
62         }
63
64         goto again;
65 }
66
67 static void print_tinc_cmd(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
68 static void print_tinc_cmd(const char *format, ...) {
69         if(confbasegiven) {
70                 fprintf(stderr, "%s -c %s ", exe_name, confbase);
71         } else if(netname) {
72                 fprintf(stderr, "%s -n %s ", exe_name, netname);
73         } else {
74                 fprintf(stderr, "%s ", exe_name);
75         }
76
77         va_list va;
78         va_start(va, format);
79         vfprintf(stderr, format, va);
80         va_end(va);
81         fputc('\n', stderr);
82 }
83
84 typedef enum {
85         KEY_RSA,
86         KEY_ED25519,
87         KEY_BOTH,
88 } key_type_t;
89
90 static void print_new_keys_cmd(key_type_t key_type, const char *message) {
91         fprintf(stderr, "%s\n\n", message);
92
93         switch(key_type) {
94         case KEY_RSA:
95                 fprintf(stderr, "You can generate a new RSA keypair with:\n\n");
96                 print_tinc_cmd("generate-rsa-keys");
97                 break;
98
99         case KEY_ED25519:
100                 fprintf(stderr, "You can generate a new Ed25519 keypair with:\n\n");
101                 print_tinc_cmd("generate-ed25519-keys");
102                 break;
103
104         case KEY_BOTH:
105                 fprintf(stderr, "You can generate new keys with:\n\n");
106                 print_tinc_cmd("generate-keys");
107                 break;
108         }
109 }
110
111 static int strtailcmp(const char *str, const char *tail) {
112         size_t slen = strlen(str);
113         size_t tlen = strlen(tail);
114
115         if(tlen > slen) {
116                 return -1;
117         }
118
119         return memcmp(str + slen - tlen, tail, tlen);
120 }
121
122 static void check_conffile(const char *nodename, bool server) {
123         splay_tree_t config;
124         init_configuration(&config);
125
126         bool read;
127
128         if(server) {
129                 read = read_server_config(&config);
130         } else {
131                 read = read_host_config(&config, nodename, true);
132         }
133
134         if(!read) {
135                 splay_empty_tree(&config);
136                 return;
137         }
138
139         size_t total_vars = 0;
140
141         while(variables[total_vars].name) {
142                 ++total_vars;
143         }
144
145         const size_t countlen = total_vars * sizeof(int);
146         int *count = alloca(countlen);
147         memset(count, 0, countlen);
148
149         for splay_each(config_t, conf, &config) {
150                 int var_type = 0;
151
152                 for(size_t i = 0; variables[i].name; ++i) {
153                         if(strcasecmp(variables[i].name, conf->variable) == 0) {
154                                 count[i]++;
155                                 var_type = variables[i].type;
156                         }
157                 }
158
159                 if(var_type == 0) {
160                         continue;
161                 }
162
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);
166                 }
167
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);
171                 }
172
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);
176                 }
177         }
178
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");
183                 }
184         }
185
186         splay_empty_tree(&config);
187 }
188
189 #ifdef HAVE_WINDOWS
190 typedef int uid_t;
191
192 static uid_t getuid(void) {
193         return 0;
194 }
195
196 static void check_key_file_mode(const char *fname) {
197         (void)fname;
198 }
199 #else
200 static void check_key_file_mode(const char *fname) {
201         const uid_t uid = getuid();
202         struct stat st;
203
204         if(stat(fname, &st)) {
205                 fprintf(stderr, "ERROR: could not stat private key file %s\n", fname);
206                 return;
207         }
208
209         if(st.st_mode & 077) {
210                 fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
211
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));
217                         } else {
218                                 fprintf(stderr, "Fixed permissions of %s.\n", fname);
219                         }
220                 }
221         }
222 }
223 #endif // HAVE_WINDOWS
224
225 static char *read_node_name(void) {
226         if(access(tinc_conf, R_OK) == 0) {
227                 return get_my_name(true);
228         }
229
230         fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno));
231
232         if(errno == ENOENT) {
233                 fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n");
234                 print_tinc_cmd("init");
235                 return NULL;
236         }
237
238         if(errno == EACCES) {
239                 uid_t uid = getuid();
240
241                 if(uid != 0) {
242                         fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n");
243                 } else {
244                         fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf);
245                 }
246         }
247
248         return NULL;
249 }
250
251 static bool build_host_conf_path(char *fname, const size_t len) {
252         char *name = get_my_name(true);
253
254         if(!name) {
255                 fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
256                 return false;
257         }
258
259         snprintf(fname, len, "%s/hosts/%s", confbase, name);
260         free(name);
261         return true;
262 }
263
264 static bool ask_fix_ec_public_key(const char *fname, ecdsa_t *ec_priv) {
265         if(!ask_fix()) {
266                 return true;
267         }
268
269         if(!disable_old_keys(fname, "public Ed25519 key")) {
270                 return false;
271         }
272
273         FILE *f = fopen(fname, "a");
274
275         if(!f) {
276                 fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
277                 return false;
278         }
279
280         bool success = ecdsa_write_pem_public_key(ec_priv, f);
281         fclose(f);
282
283         if(success) {
284                 fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname);
285         } else {
286                 fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname);
287         }
288
289         return success;
290 }
291
292 #ifndef DISABLE_LEGACY
293 static bool ask_fix_rsa_public_key(const char *fname, rsa_t *rsa_priv) {
294         if(!ask_fix()) {
295                 return true;
296         }
297
298         if(!disable_old_keys(fname, "public RSA key")) {
299                 return false;
300         }
301
302         FILE *f = fopen(fname, "a");
303
304         if(!f) {
305                 fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
306                 return false;
307         }
308
309         bool success = rsa_write_pem_public_key(rsa_priv, f);
310         fclose(f);
311
312         if(success) {
313                 fprintf(stderr, "Wrote RSA public key to %s.\n", fname);
314         } else {
315                 fprintf(stderr, "ERROR: could not write RSA public key to %s.\n", fname);
316         }
317
318         return success;
319 }
320
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);
323
324         if(len != rsa_size(rsa_pub)) {
325                 fprintf(stderr, "ERROR: public and private RSA key lengths do not match.\n");
326                 return false;
327         }
328
329         bool success = false;
330         uint8_t *plaintext = xmalloc(len);
331         uint8_t *encrypted = xzalloc(len);
332         uint8_t *decrypted = xzalloc(len);
333
334         prng_randomize(plaintext, len);
335         plaintext[0] &= 0x7f;
336
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) {
340                                 success = true;
341                         } else {
342                                 fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
343                                 success = ask_fix_rsa_public_key(host_file, rsa_priv);
344                         }
345                 } else {
346                         print_new_keys_cmd(KEY_RSA, "ERROR: private RSA key does not work.");
347                 }
348         } else {
349                 fprintf(stderr, "ERROR: public RSA key does not work.\n");
350                 success = ask_fix_rsa_public_key(host_file, rsa_priv);
351         }
352
353         free(decrypted);
354         free(encrypted);
355         free(plaintext);
356
357         return success;
358 }
359
360 static bool check_rsa_pubkey(rsa_t *rsa_priv, rsa_t *rsa_pub, const char *host_file) {
361         if(!rsa_pub) {
362                 fprintf(stderr, "WARNING: No (usable) public RSA key found.\n");
363                 return ask_fix_rsa_public_key(host_file, rsa_priv);
364         }
365
366         if(!rsa_priv) {
367                 fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
368                 return true;
369         }
370
371         return test_rsa_keypair(rsa_priv, rsa_pub, host_file);
372 }
373 #endif // DISABLE_LEGACY
374
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);
378
379         if(!b64_priv_pub) {
380                 print_new_keys_cmd(KEY_ED25519, "ERROR: private Ed25519 key does not work.");
381                 return false;
382         }
383
384         // base64-encoded public key obtained from the PUBLIC key.
385         char *b64_pub_pub = ecdsa_get_base64_public_key(ec_pub);
386
387         if(!b64_pub_pub) {
388                 fprintf(stderr, "ERROR: public Ed25519 key does not work.\n");
389                 free(b64_priv_pub);
390                 return ask_fix_ec_public_key(host_file, ec_priv);
391         }
392
393         bool match = strcmp(b64_pub_pub, b64_priv_pub) == 0;
394         free(b64_pub_pub);
395         free(b64_priv_pub);
396
397         if(match) {
398                 return true;
399         }
400
401         fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n");
402         return ask_fix_ec_public_key(host_file, ec_priv);
403 }
404
405 static bool check_ec_pubkey(ecdsa_t *ec_priv, ecdsa_t *ec_pub, const char *host_file) {
406         if(!ec_priv) {
407                 if(ec_pub) {
408                         print_new_keys_cmd(KEY_ED25519, "WARNING: A public Ed25519 key was found but no private key is known.");
409                 }
410
411                 return true;
412         }
413
414         if(ec_pub) {
415                 return test_ec_keypair(ec_priv, ec_pub, host_file);
416         }
417
418         fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n");
419         return ask_fix_ec_public_key(host_file, ec_priv);
420 }
421
422 static bool check_config_mode(const char *fname) {
423         if(access(fname, R_OK | X_OK) == 0) {
424                 return true;
425         }
426
427         if(errno != EACCES) {
428                 fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
429                 return false;
430         }
431
432         fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
433
434         if(ask_fix()) {
435                 if(chmod(fname, 0755)) {
436                         fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
437                 }
438         }
439
440         return true;
441 }
442
443 static bool check_script_confdir(void) {
444         char fname[PATH_MAX];
445         DIR *dir = opendir(confbase);
446
447         if(!dir) {
448                 fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno));
449                 return false;
450         }
451
452         struct dirent *ent;
453
454         while((ent = readdir(dir))) {
455                 if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
456                         continue;
457                 }
458
459                 strncpy(fname, ent->d_name, sizeof(fname));
460                 char *dash = strrchr(fname, '-');
461
462                 if(!dash) {
463                         continue;
464                 }
465
466                 *dash = 0;
467
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);
471
472                         if(!explained) {
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");
475                                 explained = true;
476                         }
477
478                         continue;
479                 }
480
481                 snprintf(fname, sizeof(fname), "%s" SLASH "%s", confbase, ent->d_name);
482                 check_config_mode(fname);
483         }
484
485         closedir(dir);
486
487         return true;
488 }
489
490 static bool check_script_hostdir(const char *host_dir) {
491         char fname[PATH_MAX];
492         DIR *dir = opendir(host_dir);
493
494         if(!dir) {
495                 fprintf(stderr, "ERROR: cannot read directory %s: %s\n", host_dir, strerror(errno));
496                 return false;
497         }
498
499         struct dirent *ent;
500
501         while((ent = readdir(dir))) {
502                 if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
503                         continue;
504                 }
505
506                 strncpy(fname, ent->d_name, sizeof(fname));
507                 char *dash = strrchr(fname, '-');
508
509                 if(!dash) {
510                         continue;
511                 }
512
513                 *dash = 0;
514
515                 snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
516                 check_config_mode(fname);
517         }
518
519         closedir(dir);
520
521         return true;
522 }
523
524 #ifdef DISABLE_LEGACY
525 static bool check_public_keys(splay_tree_t *config, const char *name, ecdsa_t *ec_priv) {
526 #else
527 static bool check_public_keys(splay_tree_t *config, const char *name, rsa_t *rsa_priv, ecdsa_t *ec_priv) {
528 #endif
529         // Check public keys.
530         char host_file[PATH_MAX];
531
532         if(!build_host_conf_path(host_file, sizeof(host_file))) {
533                 return false;
534         }
535
536         if(access(host_file, R_OK)) {
537                 fprintf(stderr, "WARNING: cannot read %s\n", host_file);
538         }
539
540         ecdsa_t *ec_pub = read_ecdsa_public_key(&config, name);
541
542         bool success = true;
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);
546         rsa_free(rsa_pub);
547 #endif
548
549         if(!check_ec_pubkey(ec_priv, ec_pub, host_file)) {
550                 success = false;
551         }
552
553         ecdsa_free(ec_pub);
554
555         return success;
556 }
557
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);
562
563         if(priv_keyfile) {
564                 check_key_file_mode(priv_keyfile);
565                 free(priv_keyfile);
566                 priv_keyfile = NULL;
567         }
568
569 #ifdef DISABLE_LEGACY
570
571         if(!ec_priv) {
572                 print_new_keys_cmd(KEY_ED25519, "ERROR: No Ed25519 private key found.");
573                 return false;
574         }
575
576 #else
577         rsa_t *rsa_priv = read_rsa_private_key(config, &priv_keyfile);
578
579         if(priv_keyfile) {
580                 check_key_file_mode(priv_keyfile);
581                 free(priv_keyfile);
582         }
583
584         if(!rsa_priv && !ec_priv) {
585                 print_new_keys_cmd(KEY_BOTH, "ERROR: Neither RSA or Ed25519 private key found.");
586                 return false;
587         }
588
589 #endif
590
591 #ifdef DISABLE_LEGACY
592         bool success = check_public_keys(config, name, ec_priv);
593 #else
594         bool success = check_public_keys(config, name, rsa_priv, ec_priv);
595         rsa_free(rsa_priv);
596 #endif
597         ecdsa_free(ec_priv);
598
599         return success;
600 }
601
602 static void check_config_variables(const char *host_dir) {
603         check_conffile(NULL, true);
604
605         DIR *dir = opendir(host_dir);
606
607         if(dir) {
608                 for(struct dirent * ent; (ent = readdir(dir));) {
609                         if(check_id(ent->d_name)) {
610                                 check_conffile(ent->d_name, false);
611                         }
612                 }
613
614                 closedir(dir);
615         }
616 }
617
618 static bool check_scripts_and_configs(void) {
619         // Check whether scripts are executable.
620         if(!check_script_confdir()) {
621                 return false;
622         }
623
624         char host_dir[PATH_MAX];
625         snprintf(host_dir, sizeof(host_dir), "%s" SLASH "hosts", confbase);
626
627         if(!check_script_hostdir(host_dir)) {
628                 return false;
629         }
630
631         // Check for obsolete / unsafe / unknown configuration variables (and print warnings).
632         check_config_variables(host_dir);
633
634         return true;
635 }
636
637 int fsck(const char *argv0) {
638         exe_name = argv0;
639
640         // Check that tinc.conf is readable and read our name if it is.
641         char *name = read_node_name();
642
643         if(!name) {
644                 fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
645                 exe_name = NULL;
646                 return EXIT_FAILURE;
647         }
648
649         // Avoid touching global configuration here. Read the config files into
650         // a temporary configuration tree, then throw it away after fsck is done.
651         splay_tree_t config;
652         init_configuration(&config);
653
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);
657
658         // Check both RSA and EC key pairs.
659         // We need working configuration to run this check.
660         if(success) {
661                 success = check_keypairs(&config, name);
662         }
663
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();
668
669         splay_empty_tree(&config);
670         free(name);
671         exe_name = NULL;
672
673         return success ? EXIT_SUCCESS : EXIT_FAILURE;
674 }