tincctl: Avoid falling back to 1024 bits RSA key generation when an invalid key size...
[tinc] / src / tincctl.c
1 /*
2     tincctl.c -- Controlling a running tincd
3     Copyright (C) 2007-2016 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
22 #include <getopt.h>
23
24 #ifdef HAVE_READLINE
25 #include "readline/readline.h"
26 #include "readline/history.h"
27 #endif
28
29 #include "xalloc.h"
30 #include "protocol.h"
31 #include "control_common.h"
32 #include "crypto.h"
33 #include "ecdsagen.h"
34 #include "fsck.h"
35 #include "info.h"
36 #include "invitation.h"
37 #include "names.h"
38 #include "rsagen.h"
39 #include "utils.h"
40 #include "tincctl.h"
41 #include "top.h"
42 #include "version.h"
43
44 #ifndef MSG_NOSIGNAL
45 #define MSG_NOSIGNAL 0
46 #endif
47
48 static char **orig_argv;
49 static int orig_argc;
50
51 /* If nonzero, display usage information and exit. */
52 static bool show_help = false;
53
54 /* If nonzero, print the version on standard output and exit.  */
55 static bool show_version = false;
56
57 static char *name = NULL;
58 static char controlcookie[1025];
59 char *tinc_conf = NULL;
60 char *hosts_dir = NULL;
61 struct timeval now;
62
63 // Horrible global variables...
64 static int pid = 0;
65 int fd = -1;
66 char line[4096];
67 static int code;
68 static int req;
69 static int result;
70 bool force = false;
71 bool tty = true;
72 bool confbasegiven = false;
73 bool netnamegiven = false;
74 char *scriptinterpreter = NULL;
75 char *scriptextension = "";
76 static char *prompt;
77
78 static struct option const long_options[] = {
79         {"batch", no_argument, NULL, 'b'},
80         {"config", required_argument, NULL, 'c'},
81         {"net", required_argument, NULL, 'n'},
82         {"help", no_argument, NULL, 1},
83         {"version", no_argument, NULL, 2},
84         {"pidfile", required_argument, NULL, 3},
85         {"force", no_argument, NULL, 4},
86         {NULL, 0, NULL, 0}
87 };
88
89 static void version(void) {
90         printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
91                    BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
92         printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n"
93                         "See the AUTHORS file for a complete list.\n\n"
94                         "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
95                         "and you are welcome to redistribute it under certain conditions;\n"
96                         "see the file COPYING for details.\n");
97 }
98
99 static void usage(bool status) {
100         if(status) {
101                 fprintf(stderr, "Try `%s --help\' for more information.\n", program_name);
102         } else {
103                 printf("Usage: %s [options] command\n\n", program_name);
104                 printf("Valid options are:\n"
105                                 "  -b, --batch             Don't ask for anything (non-interactive mode).\n"
106                                 "  -c, --config=DIR        Read configuration options from DIR.\n"
107                                 "  -n, --net=NETNAME       Connect to net NETNAME.\n"
108                                 "      --pidfile=FILENAME  Read control cookie from FILENAME.\n"
109                                 "      --force             Force some commands to work despite warnings.\n"
110                                 "      --help              Display this help and exit.\n"
111                                 "      --version           Output version information and exit.\n"
112                                 "\n"
113                                 "Valid commands are:\n"
114                                 "  init [name]                Create initial configuration files.\n"
115                                 "  get VARIABLE               Print current value of VARIABLE\n"
116                                 "  set VARIABLE VALUE         Set VARIABLE to VALUE\n"
117                                 "  add VARIABLE VALUE         Add VARIABLE with the given VALUE\n"
118                                 "  del VARIABLE [VALUE]       Remove VARIABLE [only ones with watching VALUE]\n"
119                                 "  start [tincd options]      Start tincd.\n"
120                                 "  stop                       Stop tincd.\n"
121                                 "  restart [tincd options]    Restart tincd.\n"
122                                 "  reload                     Partially reload configuration of running tincd.\n"
123                                 "  pid                        Show PID of currently running tincd.\n"
124 #ifdef DISABLE_LEGACY
125                                 "  generate-keys              Generate a new Ed25519 public/private keypair.\n"
126 #else
127                                 "  generate-keys [bits]       Generate new RSA and Ed25519 public/private keypairs.\n"
128                                 "  generate-rsa-keys [bits]   Generate a new RSA public/private keypair.\n"
129 #endif
130                                 "  generate-ed25519-keys      Generate a new Ed25519 public/private keypair.\n"
131                                 "  dump                       Dump a list of one of the following things:\n"
132                                 "    [reachable] nodes        - all known nodes in the VPN\n"
133                                 "    edges                    - all known connections in the VPN\n"
134                                 "    subnets                  - all known subnets in the VPN\n"
135                                 "    connections              - all meta connections with ourself\n"
136                                 "    [di]graph                - graph of the VPN in dotty format\n"
137                                 "    invitations              - outstanding invitations\n"
138                                 "  info NODE|SUBNET|ADDRESS   Give information about a particular NODE, SUBNET or ADDRESS.\n"
139                                 "  purge                      Purge unreachable nodes\n"
140                                 "  debug N                    Set debug level\n"
141                                 "  retry                      Retry all outgoing connections\n"
142                                 "  disconnect NODE            Close meta connection with NODE\n"
143 #ifdef HAVE_CURSES
144                                 "  top                        Show real-time statistics\n"
145 #endif
146                                 "  pcap [snaplen]             Dump traffic in pcap format [up to snaplen bytes per packet]\n"
147                                 "  log [level]                Dump log output [up to the specified level]\n"
148                                 "  export                     Export host configuration of local node to standard output\n"
149                                 "  export-all                 Export all host configuration files to standard output\n"
150                                 "  import                     Import host configuration file(s) from standard input\n"
151                                 "  exchange                   Same as export followed by import\n"
152                                 "  exchange-all               Same as export-all followed by import\n"
153                                 "  invite NODE [...]          Generate an invitation for NODE\n"
154                                 "  join INVITATION            Join a VPN using an INVITATION\n"
155                                 "  network [NETNAME]          List all known networks, or switch to the one named NETNAME.\n"
156                                 "  fsck                       Check the configuration files for problems.\n"
157                                 "  sign [FILE]                Generate a signed version of a file.\n"
158                                 "  verify NODE [FILE]         Verify that a file was signed by the given NODE.\n"
159                                 "\n");
160                 printf("Report bugs to tinc@tinc-vpn.org.\n");
161         }
162 }
163
164 static bool parse_options(int argc, char **argv) {
165         int r;
166         int option_index = 0;
167
168         while((r = getopt_long(argc, argv, "+c:n:", long_options, &option_index)) != EOF) {
169                 switch (r) {
170                         case 0:   /* long option */
171                                 break;
172
173                         case 'b':
174                                 tty = false;
175                                 break;
176
177                         case 'c': /* config file */
178                                 confbase = xstrdup(optarg);
179                                 confbasegiven = true;
180                                 break;
181
182                         case 'n': /* net name given */
183                                 netname = xstrdup(optarg);
184                                 break;
185
186                         case 1:   /* show help */
187                                 show_help = true;
188                                 break;
189
190                         case 2:   /* show version */
191                                 show_version = true;
192                                 break;
193
194                         case 3:   /* open control socket here */
195                                 pidfilename = xstrdup(optarg);
196                                 break;
197
198                         case 4:   /* force */
199                                 force = true;
200                                 break;
201
202                         case '?': /* wrong options */
203                                 usage(true);
204                                 return false;
205
206                         default:
207                                 break;
208                 }
209         }
210
211         if(!netname && (netname = getenv("NETNAME")))
212                 netname = xstrdup(netname);
213
214         /* netname "." is special: a "top-level name" */
215
216         if(netname && (!*netname || !strcmp(netname, "."))) {
217                 free(netname);
218                 netname = NULL;
219         }
220
221         if(netname && (strpbrk(netname, "\\/") || *netname == '.')) {
222                 fprintf(stderr, "Invalid character in netname!\n");
223                 return false;
224         }
225
226         return true;
227 }
228
229 /* Open a file with the desired permissions, minus the umask.
230    Also, if we want to create an executable file, we call fchmod()
231    to set the executable bits. */
232
233 FILE *fopenmask(const char *filename, const char *mode, mode_t perms) {
234         mode_t mask = umask(0);
235         perms &= ~mask;
236         umask(~perms);
237         FILE *f = fopen(filename, mode);
238
239         if(!f) {
240                 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
241                 return NULL;
242         }
243
244 #ifdef HAVE_FCHMOD
245         if((perms & 0444) && f)
246                 fchmod(fileno(f), perms);
247 #endif
248         umask(mask);
249         return f;
250 }
251
252 static void disable_old_keys(const char *filename, const char *what) {
253         char tmpfile[PATH_MAX] = "";
254         char buf[1024];
255         bool disabled = false;
256         bool block = false;
257         bool error = false;
258         FILE *r, *w;
259
260         r = fopen(filename, "r");
261         if(!r)
262                 return;
263
264         snprintf(tmpfile, sizeof tmpfile, "%s.tmp", filename);
265
266         struct stat st = {.st_mode = 0600};
267         fstat(fileno(r), &st);
268         w = fopenmask(tmpfile, "w", st.st_mode);
269
270         while(fgets(buf, sizeof buf, r)) {
271                 if(!block && !strncmp(buf, "-----BEGIN ", 11)) {
272                         if((strstr(buf, " ED25519 ") && strstr(what, "Ed25519")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
273                                 disabled = true;
274                                 block = true;
275                         }
276                 }
277
278                 bool ed25519pubkey = !strncasecmp(buf, "Ed25519PublicKey", 16) && strchr(" \t=", buf[16]) && strstr(what, "Ed25519");
279
280                 if(ed25519pubkey)
281                         disabled = true;
282
283                 if(w) {
284                         if(block || ed25519pubkey)
285                                 fputc('#', w);
286                         if(fputs(buf, w) < 0) {
287                                 error = true;
288                                 break;
289                         }
290                 }
291
292                 if(block && !strncmp(buf, "-----END ", 9))
293                         block = false;
294         }
295
296         if(w)
297                 if(fclose(w) < 0)
298                         error = true;
299         if(ferror(r) || fclose(r) < 0)
300                 error = true;
301
302         if(disabled) {
303                 if(!w || error) {
304                         fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
305                         if(w)
306                                 unlink(tmpfile);
307                         return;
308                 }
309
310 #ifdef HAVE_MINGW
311                 // We cannot atomically replace files on Windows.
312                 char bakfile[PATH_MAX] = "";
313                 snprintf(bakfile, sizeof bakfile, "%s.bak", filename);
314                 if(rename(filename, bakfile) || rename(tmpfile, filename)) {
315                         rename(bakfile, filename);
316 #else
317                 if(rename(tmpfile, filename)) {
318 #endif
319                         fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
320                 } else  {
321 #ifdef HAVE_MINGW
322                         unlink(bakfile);
323 #endif
324                         fprintf(stderr, "Warning: old key(s) found and disabled.\n");
325                 }
326         }
327
328         unlink(tmpfile);
329 }
330
331 static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask, mode_t perms) {
332         FILE *r;
333         char directory[PATH_MAX] = ".";
334         char buf[PATH_MAX];
335         char buf2[PATH_MAX];
336
337         /* Check stdin and stdout */
338         if(ask && tty) {
339                 /* Ask for a file and/or directory name. */
340                 fprintf(stderr, "Please enter a file to save %s to [%s]: ", what, filename);
341
342                 if(fgets(buf, sizeof buf, stdin) == NULL) {
343                         fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
344                         return NULL;
345                 }
346
347                 size_t len = strlen(buf);
348                 if(len)
349                         buf[--len] = 0;
350
351                 if(len)
352                         filename = buf;
353         }
354
355 #ifdef HAVE_MINGW
356         if(filename[0] != '\\' && filename[0] != '/' && !strchr(filename, ':')) {
357 #else
358         if(filename[0] != '/') {
359 #endif
360                 /* The directory is a relative path or a filename. */
361                 getcwd(directory, sizeof directory);
362                 snprintf(buf2, sizeof buf2, "%s" SLASH "%s", directory, filename);
363                 filename = buf2;
364         }
365
366         disable_old_keys(filename, what);
367
368         /* Open it first to keep the inode busy */
369
370         r = fopenmask(filename, mode, perms);
371
372         if(!r) {
373                 fprintf(stderr, "Error opening file `%s': %s\n", filename, strerror(errno));
374                 return NULL;
375         }
376
377         return r;
378 }
379
380 /*
381   Generate a public/private Ed25519 keypair, and ask for a file to store
382   them in.
383 */
384 static bool ed25519_keygen(bool ask) {
385         ecdsa_t *key;
386         FILE *f;
387         char fname[PATH_MAX];
388
389         fprintf(stderr, "Generating Ed25519 keypair:\n");
390
391         if(!(key = ecdsa_generate())) {
392                 fprintf(stderr, "Error during key generation!\n");
393                 return false;
394         } else
395                 fprintf(stderr, "Done.\n");
396
397         snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase);
398         f = ask_and_open(fname, "private Ed25519 key", "a", ask, 0600);
399
400         if(!f)
401                 goto error;
402
403         if(!ecdsa_write_pem_private_key(key, f)) {
404                 fprintf(stderr, "Error writing private key!\n");
405                 goto error;
406         }
407
408         fclose(f);
409
410         if(name)
411                 snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
412         else
413                 snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.pub", confbase);
414
415         f = ask_and_open(fname, "public Ed25519 key", "a", ask, 0666);
416
417         if(!f)
418                 return false;
419
420         char *pubkey = ecdsa_get_base64_public_key(key);
421         fprintf(f, "Ed25519PublicKey = %s\n", pubkey);
422         free(pubkey);
423
424         fclose(f);
425         ecdsa_free(key);
426
427         return true;
428
429 error:
430         if(f)
431                 fclose(f);
432         ecdsa_free(key);
433         return false;
434 }
435
436 #ifndef DISABLE_LEGACY
437 /*
438   Generate a public/private RSA keypair, and ask for a file to store
439   them in.
440 */
441 static bool rsa_keygen(int bits, bool ask) {
442         rsa_t *key;
443         FILE *f;
444         char fname[PATH_MAX];
445
446         // Make sure the key size is a multiple of 8 bits.
447         bits &= ~0x7;
448
449         // Make sure that a valid key size is used.
450         if(bits < 1024 || bits > 8192) {
451                 fprintf(stderr, "Invalid key size %d specified! It should be between 1024 and 8192 bits.\n", bits);
452                 return false;
453         } else if(bits < 2048) {
454                 fprintf(stderr, "WARNING: generating a weak %d bits RSA key! 2048 or more bits are recommended.\n", bits);
455         }
456
457         fprintf(stderr, "Generating %d bits keys:\n", bits);
458
459         if(!(key = rsa_generate(bits, 0x10001))) {
460                 fprintf(stderr, "Error during key generation!\n");
461                 return false;
462         } else
463                 fprintf(stderr, "Done.\n");
464
465         snprintf(fname, sizeof fname, "%s" SLASH "rsa_key.priv", confbase);
466         f = ask_and_open(fname, "private RSA key", "a", ask, 0600);
467
468         if(!f)
469                 goto error;
470
471         if(!rsa_write_pem_private_key(key, f)) {
472                 fprintf(stderr, "Error writing private key!\n");
473                 goto error;
474         }
475
476         fclose(f);
477
478         if(name)
479                 snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
480         else
481                 snprintf(fname, sizeof fname, "%s" SLASH "rsa_key.pub", confbase);
482
483         f = ask_and_open(fname, "public RSA key", "a", ask, 0666);
484
485         if(!f)
486                 goto error;
487
488         if(!rsa_write_pem_public_key(key, f)) {
489                 fprintf(stderr, "Error writing public key!\n");
490                 goto error;
491         }
492
493         fclose(f);
494         rsa_free(key);
495
496         return true;
497
498 error:
499         if(f)
500                 fclose(f);
501         rsa_free(key);
502         return false;
503 }
504 #endif
505
506 char buffer[4096];
507 size_t blen = 0;
508
509 bool recvline(int fd, char *line, size_t len) {
510         char *newline = NULL;
511
512         if(!fd)
513                 abort();
514
515         while(!(newline = memchr(buffer, '\n', blen))) {
516                 int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
517                 if(result == -1 && sockerrno == EINTR)
518                         continue;
519                 else if(result <= 0)
520                         return false;
521                 blen += result;
522         }
523
524         if(newline - buffer >= len)
525                 return false;
526
527         len = newline - buffer;
528
529         memcpy(line, buffer, len);
530         line[len] = 0;
531         memmove(buffer, newline + 1, blen - len - 1);
532         blen -= len + 1;
533
534         return true;
535 }
536
537 bool recvdata(int fd, char *data, size_t len) {
538         if(len == -1)
539                 len = blen;
540
541         while(blen < len) {
542                 int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
543                 if(result == -1 && sockerrno == EINTR)
544                         continue;
545                 else if(result <= 0)
546                         return false;
547                 blen += result;
548         }
549
550         memcpy(data, buffer, len);
551         memmove(buffer, buffer + len, blen - len);
552         blen -= len;
553
554         return true;
555 }
556
557 bool sendline(int fd, char *format, ...) {
558         static char buffer[4096];
559         char *p = buffer;
560         int blen = 0;
561         va_list ap;
562
563         va_start(ap, format);
564         blen = vsnprintf(buffer, sizeof buffer, format, ap);
565         buffer[sizeof buffer - 1] = 0;
566         va_end(ap);
567
568         if(blen < 1 || blen >= sizeof buffer)
569                 return false;
570
571         buffer[blen] = '\n';
572         blen++;
573
574         while(blen) {
575                 int result = send(fd, p, blen, MSG_NOSIGNAL);
576                 if(result == -1 && sockerrno == EINTR)
577                         continue;
578                 else if(result <= 0)
579                         return false;
580                 p += result;
581                 blen -= result;
582         }
583
584         return true;
585 }
586
587 static void pcap(int fd, FILE *out, int snaplen) {
588         sendline(fd, "%d %d %d", CONTROL, REQ_PCAP, snaplen);
589         char data[9018];
590
591         struct {
592                 uint32_t magic;
593                 uint16_t major;
594                 uint16_t minor;
595                 uint32_t tz_offset;
596                 uint32_t tz_accuracy;
597                 uint32_t snaplen;
598                 uint32_t ll_type;
599         } header = {
600                 0xa1b2c3d4,
601                 2, 4,
602                 0, 0,
603                 snaplen ?: sizeof data,
604                 1,
605         };
606
607         struct {
608                 uint32_t tv_sec;
609                 uint32_t tv_usec;
610                 uint32_t len;
611                 uint32_t origlen;
612         } packet;
613
614         struct timeval tv;
615
616         fwrite(&header, sizeof header, 1, out);
617         fflush(out);
618
619         char line[32];
620         while(recvline(fd, line, sizeof line)) {
621                 int code, req, len;
622                 int n = sscanf(line, "%d %d %d", &code, &req, &len);
623                 gettimeofday(&tv, NULL);
624                 if(n != 3 || code != CONTROL || req != REQ_PCAP || len < 0 || len > sizeof data)
625                         break;
626                 if(!recvdata(fd, data, len))
627                         break;
628                 packet.tv_sec = tv.tv_sec;
629                 packet.tv_usec = tv.tv_usec;
630                 packet.len = len;
631                 packet.origlen = len;
632                 fwrite(&packet, sizeof packet, 1, out);
633                 fwrite(data, len, 1, out);
634                 fflush(out);
635         }
636 }
637
638 static void logcontrol(int fd, FILE *out, int level) {
639         sendline(fd, "%d %d %d", CONTROL, REQ_LOG, level);
640         char data[1024];
641         char line[32];
642
643         while(recvline(fd, line, sizeof line)) {
644                 int code, req, len;
645                 int n = sscanf(line, "%d %d %d", &code, &req, &len);
646                 if(n != 3 || code != CONTROL || req != REQ_LOG || len < 0 || len > sizeof data)
647                         break;
648                 if(!recvdata(fd, data, len))
649                         break;
650                 fwrite(data, len, 1, out);
651                 fputc('\n', out);
652                 fflush(out);
653         }
654 }
655
656 #ifdef HAVE_MINGW
657 static bool remove_service(void) {
658         SC_HANDLE manager = NULL;
659         SC_HANDLE service = NULL;
660         SERVICE_STATUS status = {0};
661
662         manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
663         if(!manager) {
664                 fprintf(stderr, "Could not open service manager: %s\n", winerror(GetLastError()));
665                 return false;
666         }
667
668         service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
669
670         if(!service) {
671                 fprintf(stderr, "Could not open %s service: %s\n", identname, winerror(GetLastError()));
672                 return false;
673         }
674
675         if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
676                 fprintf(stderr, "Could not stop %s service: %s\n", identname, winerror(GetLastError()));
677         else
678                 fprintf(stderr, "%s service stopped\n", identname);
679
680         if(!DeleteService(service)) {
681                 fprintf(stderr, "Could not remove %s service: %s\n", identname, winerror(GetLastError()));
682                 return false;
683         }
684
685         fprintf(stderr, "%s service removed\n", identname);
686
687         return true;
688 }
689 #endif
690
691 bool connect_tincd(bool verbose) {
692         if(fd >= 0) {
693                 fd_set r;
694                 FD_ZERO(&r);
695                 FD_SET(fd, &r);
696                 struct timeval tv = {0, 0};
697                 if(select(fd + 1, &r, NULL, NULL, &tv)) {
698                         fprintf(stderr, "Previous connection to tincd lost, reconnecting.\n");
699                         close(fd);
700                         fd = -1;
701                 } else {
702                         return true;
703                 }
704         }
705
706         FILE *f = fopen(pidfilename, "r");
707         if(!f) {
708                 if(verbose)
709                         fprintf(stderr, "Could not open pid file %s: %s\n", pidfilename, strerror(errno));
710                 return false;
711         }
712
713         char host[129];
714         char port[129];
715
716         if(fscanf(f, "%20d %1024s %128s port %128s", &pid, controlcookie, host, port) != 4) {
717                 if(verbose)
718                         fprintf(stderr, "Could not parse pid file %s\n", pidfilename);
719                 fclose(f);
720                 return false;
721         }
722
723         fclose(f);
724         if ((pid == 0) || (kill(pid, 0) && (errno == ESRCH))) {
725                 fprintf(stderr, "Could not find tincd running at pid %d\n", pid);
726                 /* clean up the stale socket and pid file */
727                 unlink(pidfilename);
728                 unlink(unixsocketname);
729                 return false;
730         }
731
732 #ifndef HAVE_MINGW
733         struct sockaddr_un sa;
734         sa.sun_family = AF_UNIX;
735         strncpy(sa.sun_path, unixsocketname, sizeof sa.sun_path);
736
737         fd = socket(AF_UNIX, SOCK_STREAM, 0);
738         if(fd < 0) {
739                 if(verbose)
740                         fprintf(stderr, "Cannot create UNIX socket: %s\n", sockstrerror(sockerrno));
741                 return false;
742         }
743
744         if(connect(fd, (struct sockaddr *)&sa, sizeof sa) < 0) {
745                 if(verbose)
746                         fprintf(stderr, "Cannot connect to UNIX socket %s: %s\n", unixsocketname, sockstrerror(sockerrno));
747                 close(fd);
748                 fd = -1;
749                 return false;
750         }
751 #else
752         struct addrinfo hints = {
753                 .ai_family = AF_UNSPEC,
754                 .ai_socktype = SOCK_STREAM,
755                 .ai_protocol = IPPROTO_TCP,
756                 .ai_flags = 0,
757         };
758
759         struct addrinfo *res = NULL;
760
761         if(getaddrinfo(host, port, &hints, &res) || !res) {
762                 if(verbose)
763                         fprintf(stderr, "Cannot resolve %s port %s: %s", host, port, sockstrerror(sockerrno));
764                 return false;
765         }
766
767         fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
768         if(fd < 0) {
769                 if(verbose)
770                         fprintf(stderr, "Cannot create TCP socket: %s\n", sockstrerror(sockerrno));
771                 return false;
772         }
773
774 #ifdef HAVE_MINGW
775         unsigned long arg = 0;
776
777         if(ioctlsocket(fd, FIONBIO, &arg) != 0) {
778                 if(verbose)
779                         fprintf(stderr, "ioctlsocket failed: %s", sockstrerror(sockerrno));
780         }
781 #endif
782
783         if(connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
784                 if(verbose)
785                         fprintf(stderr, "Cannot connect to %s port %s: %s\n", host, port, sockstrerror(sockerrno));
786                 close(fd);
787                 fd = -1;
788                 return false;
789         }
790
791         freeaddrinfo(res);
792 #endif
793
794 #ifdef SO_NOSIGPIPE
795         static const int one = 1;
796         setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof one);
797 #endif
798
799         char data[4096];
800         int version;
801
802         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %s %d", &code, data, &version) != 3 || code != 0) {
803                 if(verbose)
804                         fprintf(stderr, "Cannot read greeting from control socket: %s\n", sockstrerror(sockerrno));
805                 close(fd);
806                 fd = -1;
807                 return false;
808         }
809
810         sendline(fd, "%d ^%s %d", ID, controlcookie, TINC_CTL_VERSION_CURRENT);
811
812         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &version, &pid) != 3 || code != 4 || version != TINC_CTL_VERSION_CURRENT) {
813                 if(verbose)
814                         fprintf(stderr, "Could not fully establish control socket connection\n");
815                 close(fd);
816                 fd = -1;
817                 return false;
818         }
819
820         return true;
821 }
822
823
824 static int cmd_start(int argc, char *argv[]) {
825         if(connect_tincd(false)) {
826                 if(netname)
827                         fprintf(stderr, "A tincd is already running for net `%s' with pid %d.\n", netname, pid);
828                 else
829                         fprintf(stderr, "A tincd is already running with pid %d.\n", pid);
830                 return 0;
831         }
832
833         char *c;
834         char *slash = strrchr(program_name, '/');
835
836 #ifdef HAVE_MINGW
837         if ((c = strrchr(program_name, '\\')) > slash)
838                 slash = c;
839 #endif
840
841         if (slash++)
842                 xasprintf(&c, "%.*stincd", (int)(slash - program_name), program_name);
843         else
844                 c = "tincd";
845
846         int nargc = 0;
847         char **nargv = xzalloc((optind + argc) * sizeof *nargv);
848
849         char *arg0 = c;
850 #ifdef HAVE_MINGW
851         /*
852            Windows has no real concept of an "argv array". A command line is just one string.
853            The CRT of the new process will decode the command line string to generate argv before calling main(), and (by convention)
854            it uses quotes to handle spaces in arguments.
855            Therefore we need to quote all arguments that might contain spaces. No, execvp() won't do that for us (see MSDN).
856            If we don't do that, then execvp() will run fine but any spaces in the filename contained in arg0 will bleed
857            into the next arguments when the spawned process' CRT parses its command line, resulting in chaos.
858         */
859         xasprintf(&arg0, "\"%s\"", arg0);
860 #endif
861         nargv[nargc++] = arg0;
862         for(int i = 1; i < optind; i++)
863                 nargv[nargc++] = orig_argv[i];
864         for(int i = 1; i < argc; i++)
865                 nargv[nargc++] = argv[i];
866
867 #ifdef HAVE_MINGW
868         int status = spawnvp(_P_WAIT, c, nargv);
869         if (status == -1) {
870                 fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno));
871                 return 1;
872         }
873         return status;
874 #else
875         int pfd[2] = {-1, -1};
876         if(socketpair(AF_UNIX, SOCK_STREAM, 0, pfd)) {
877                 fprintf(stderr, "Could not create umbilical socket: %s\n", strerror(errno));
878                 free(nargv);
879                 return 1;
880         }
881
882         pid_t pid = fork();
883         if(pid == -1) {
884                 fprintf(stderr, "Could not fork: %s\n", strerror(errno));
885                 free(nargv);
886                 return 1;
887         }
888
889         if(!pid) {
890                 close(pfd[0]);
891                 char buf[100];
892                 snprintf(buf, sizeof buf, "%d", pfd[1]);
893                 setenv("TINC_UMBILICAL", buf, true);
894                 exit(execvp(c, nargv));
895         } else {
896                 close(pfd[1]);
897         }
898
899         free(nargv);
900
901         int status = -1, result;
902 #ifdef SIGINT
903         signal(SIGINT, SIG_IGN);
904 #endif
905
906         // Pass all log messages from the umbilical to stderr.
907         // A nul-byte right before closure means tincd started succesfully.
908         bool failure = true;
909         char buf[1024];
910         ssize_t len;
911
912         while((len = read(pfd[0], buf, sizeof buf)) > 0) {
913                 failure = buf[len - 1];
914                 if(!failure)
915                         len--;
916                 write(2, buf, len);
917         }
918
919         if(len)
920                 failure = true;
921
922         close(pfd[0]);
923
924         // Make sure the child process is really gone.
925         result = waitpid(pid, &status, 0);
926
927 #ifdef SIGINT
928         signal(SIGINT, SIG_DFL);
929 #endif
930
931         if(failure || result != pid || !WIFEXITED(status) || WEXITSTATUS(status)) {
932                 fprintf(stderr, "Error starting %s\n", c);
933                 return 1;
934         }
935
936         return 0;
937 #endif
938 }
939
940 static int cmd_stop(int argc, char *argv[]) {
941         if(argc > 1) {
942                 fprintf(stderr, "Too many arguments!\n");
943                 return 1;
944         }
945
946 #ifndef HAVE_MINGW
947         if(!connect_tincd(true)) {
948                 if(pid) {
949                         if(kill(pid, SIGTERM)) {
950                                 fprintf(stderr, "Could not send TERM signal to process with PID %u: %s\n", pid, strerror(errno));
951                                 return 1;
952                         }
953
954                         fprintf(stderr, "Sent TERM signal to process with PID %u.\n", pid);
955                         waitpid(pid, NULL, 0);
956                         return 0;
957                 }
958
959                 return 1;
960         }
961
962         sendline(fd, "%d %d", CONTROL, REQ_STOP);
963
964         while(recvline(fd, line, sizeof line)) {
965                 // Wait for tincd to close the connection...
966         }
967 #else
968         if(!remove_service())
969                 return 1;
970 #endif
971         close(fd);
972         pid = 0;
973         fd = -1;
974
975         return 0;
976 }
977
978 static int cmd_restart(int argc, char *argv[]) {
979         cmd_stop(1, argv);
980         return cmd_start(argc, argv);
981 }
982
983 static int cmd_reload(int argc, char *argv[]) {
984         if(argc > 1) {
985                 fprintf(stderr, "Too many arguments!\n");
986                 return 1;
987         }
988
989         if(!connect_tincd(true))
990                 return 1;
991
992         sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
993         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_RELOAD || result) {
994                 fprintf(stderr, "Could not reload configuration.\n");
995                 return 1;
996         }
997
998         return 0;
999
1000 }
1001
1002 static int dump_invitations(void) {
1003         char dname[PATH_MAX];
1004         snprintf(dname, sizeof dname, "%s" SLASH "invitations", confbase);
1005         DIR *dir = opendir(dname);
1006         if(!dir) {
1007                 if(errno == ENOENT) {
1008                         fprintf(stderr, "No outstanding invitations.\n");
1009                         return 0;
1010                 }
1011
1012                 fprintf(stderr, "Cannot not read directory %s: %s\n", dname, strerror(errno));
1013                 return 1;
1014         }
1015
1016         struct dirent *ent;
1017         bool found = false;
1018
1019         while((ent = readdir(dir))) {
1020                 char buf[MAX_STRING_SIZE];
1021                 if(b64decode(ent->d_name, buf, 24) != 18)
1022                         continue;
1023
1024                 char fname[PATH_MAX];
1025                 snprintf(fname, sizeof fname, "%s" SLASH "%s", dname, ent->d_name);
1026                 FILE *f = fopen(fname, "r");
1027                 if(!f) {
1028                         fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno));
1029                         fclose(f);
1030                         continue;
1031                 }
1032
1033                 buf[0] = 0;
1034                 if(!fgets(buf, sizeof buf, f)) {
1035                         fprintf(stderr, "Invalid invitation file %s", fname);
1036                         fclose(f);
1037                         continue;
1038                 }
1039                 fclose(f);
1040
1041                 char *eol = buf + strlen(buf);
1042                 while(strchr("\t \r\n", *--eol))
1043                         *eol = 0;
1044                 if(strncmp(buf, "Name = ", 7) || !check_id(buf + 7)) {
1045                         fprintf(stderr, "Invalid invitation file %s", fname);
1046                         continue;
1047                 }
1048
1049                 found = true;
1050                 printf("%s %s\n", ent->d_name, buf + 7);
1051         }
1052
1053         closedir(dir);
1054
1055         if(!found)
1056                 fprintf(stderr, "No outstanding invitations.\n");
1057
1058         return 0;
1059 }
1060
1061 static int cmd_dump(int argc, char *argv[]) {
1062         bool only_reachable = false;
1063
1064         if(argc > 2 && !strcasecmp(argv[1], "reachable")) {
1065                 if(strcasecmp(argv[2], "nodes")) {
1066                         fprintf(stderr, "`reachable' only supported for nodes.\n");
1067                         usage(true);
1068                         return 1;
1069                 }
1070                 only_reachable = true;
1071                 argv++;
1072                 argc--;
1073         }
1074
1075         if(argc != 2) {
1076                 fprintf(stderr, "Invalid number of arguments.\n");
1077                 usage(true);
1078                 return 1;
1079         }
1080
1081         if(!strcasecmp(argv[1], "invitations"))
1082                 return dump_invitations();
1083
1084         if(!connect_tincd(true))
1085                 return 1;
1086
1087         int do_graph = 0;
1088
1089         if(!strcasecmp(argv[1], "nodes"))
1090                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
1091         else if(!strcasecmp(argv[1], "edges"))
1092                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_EDGES);
1093         else if(!strcasecmp(argv[1], "subnets"))
1094                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
1095         else if(!strcasecmp(argv[1], "connections"))
1096                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_CONNECTIONS);
1097         else if(!strcasecmp(argv[1], "graph")) {
1098                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
1099                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_EDGES);
1100                 do_graph = 1;
1101         } else if(!strcasecmp(argv[1], "digraph")) {
1102                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
1103                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_EDGES);
1104                 do_graph = 2;
1105         } else {
1106                 fprintf(stderr, "Unknown dump type '%s'.\n", argv[1]);
1107                 usage(true);
1108                 return 1;
1109         }
1110
1111         if(do_graph == 1)
1112                 printf("graph {\n");
1113         else if(do_graph == 2)
1114                 printf("digraph {\n");
1115
1116         while(recvline(fd, line, sizeof line)) {
1117                 char node1[4096], node2[4096];
1118                 int n = sscanf(line, "%d %d %s %s", &code, &req, node1, node2);
1119                 if(n == 2) {
1120                         if(do_graph && req == REQ_DUMP_NODES)
1121                                 continue;
1122                         else {
1123                                 if(do_graph)
1124                                         printf("}\n");
1125                                 return 0;
1126                         }
1127                 }
1128                 if(n < 2)
1129                         break;
1130
1131                 char node[4096];
1132                 char id[4096];
1133                 char from[4096];
1134                 char to[4096];
1135                 char subnet[4096];
1136                 char host[4096];
1137                 char port[4096];
1138                 char local_host[4096];
1139                 char local_port[4096];
1140                 char via[4096];
1141                 char nexthop[4096];
1142                 int cipher, digest, maclength, compression, distance, socket, weight;
1143                 short int pmtu, minmtu, maxmtu;
1144                 unsigned int options, status_int;
1145                 node_status_t status;
1146                 long int last_state_change;
1147
1148                 switch(req) {
1149                         case REQ_DUMP_NODES: {
1150                                 int n = sscanf(line, "%*d %*d %s %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
1151                                 if(n != 17) {
1152                                         fprintf(stderr, "Unable to parse node dump from tincd: %s\n", line);
1153                                         return 1;
1154                                 }
1155
1156                                 memcpy(&status, &status_int, sizeof status);
1157
1158                                 if(do_graph) {
1159                                         const char *color = "black";
1160                                         if(!strcmp(host, "MYSELF"))
1161                                                 color = "green";
1162                                         else if(!status.reachable)
1163                                                 color = "red";
1164                                         else if(strcmp(via, node))
1165                                                 color = "orange";
1166                                         else if(!status.validkey)
1167                                                 color = "black";
1168                                         else if(minmtu > 0)
1169                                                 color = "green";
1170                                         printf(" %s [label = \"%s\", color = \"%s\"%s];\n", node, node, color, strcmp(host, "MYSELF") ? "" : ", style = \"filled\"");
1171                                 } else {
1172                                         if(only_reachable && !status.reachable)
1173                                                 continue;
1174                                         printf("%s id %s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)\n",
1175                                                         node, id, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu);
1176                                 }
1177                         } break;
1178
1179                         case REQ_DUMP_EDGES: {
1180                                 int n = sscanf(line, "%*d %*d %s %s %s port %s %s port %s %x %d", from, to, host, port, local_host, local_port, &options, &weight);
1181                                 if(n != 8) {
1182                                         fprintf(stderr, "Unable to parse edge dump from tincd.\n");
1183                                         return 1;
1184                                 }
1185
1186                                 if(do_graph) {
1187                                         float w = 1 + 65536.0 / weight;
1188                                         if(do_graph == 1 && strcmp(node1, node2) > 0)
1189                                                 printf(" %s -- %s [w = %f, weight = %f];\n", node1, node2, w, w);
1190                                         else if(do_graph == 2)
1191                                                 printf(" %s -> %s [w = %f, weight = %f];\n", node1, node2, w, w);
1192                                 } else {
1193                                         printf("%s to %s at %s port %s local %s port %s options %x weight %d\n", from, to, host, port, local_host, local_port, options, weight);
1194                                 }
1195                         } break;
1196
1197                         case REQ_DUMP_SUBNETS: {
1198                                 int n = sscanf(line, "%*d %*d %s %s", subnet, node);
1199                                 if(n != 2) {
1200                                         fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
1201                                         return 1;
1202                                 }
1203                                 printf("%s owner %s\n", strip_weight(subnet), node);
1204                         } break;
1205
1206                         case REQ_DUMP_CONNECTIONS: {
1207                                 int n = sscanf(line, "%*d %*d %s %s port %s %x %d %x", node, host, port, &options, &socket, &status_int);
1208                                 if(n != 6) {
1209                                         fprintf(stderr, "Unable to parse connection dump from tincd.\n");
1210                                         return 1;
1211                                 }
1212                                 printf("%s at %s port %s options %x socket %d status %x\n", node, host, port, options, socket, status_int);
1213                         } break;
1214
1215                         default:
1216                                 fprintf(stderr, "Unable to parse dump from tincd.\n");
1217                                 return 1;
1218                 }
1219         }
1220
1221         fprintf(stderr, "Error receiving dump.\n");
1222         return 1;
1223 }
1224
1225 static int cmd_purge(int argc, char *argv[]) {
1226         if(argc > 1) {
1227                 fprintf(stderr, "Too many arguments!\n");
1228                 return 1;
1229         }
1230
1231         if(!connect_tincd(true))
1232                 return 1;
1233
1234         sendline(fd, "%d %d", CONTROL, REQ_PURGE);
1235         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_PURGE || result) {
1236                 fprintf(stderr, "Could not purge old information.\n");
1237                 return 1;
1238         }
1239
1240         return 0;
1241 }
1242
1243 static int cmd_debug(int argc, char *argv[]) {
1244         if(argc != 2) {
1245                 fprintf(stderr, "Invalid number of arguments.\n");
1246                 return 1;
1247         }
1248
1249         if(!connect_tincd(true))
1250                 return 1;
1251
1252         int debuglevel = atoi(argv[1]);
1253         int origlevel;
1254
1255         sendline(fd, "%d %d %d", CONTROL, REQ_SET_DEBUG, debuglevel);
1256         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &origlevel) != 3 || code != CONTROL || req != REQ_SET_DEBUG) {
1257                 fprintf(stderr, "Could not set debug level.\n");
1258                 return 1;
1259         }
1260
1261         fprintf(stderr, "Old level %d, new level %d.\n", origlevel, debuglevel);
1262         return 0;
1263 }
1264
1265 static int cmd_retry(int argc, char *argv[]) {
1266         if(argc > 1) {
1267                 fprintf(stderr, "Too many arguments!\n");
1268                 return 1;
1269         }
1270
1271         if(!connect_tincd(true))
1272                 return 1;
1273
1274         sendline(fd, "%d %d", CONTROL, REQ_RETRY);
1275         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_RETRY || result) {
1276                 fprintf(stderr, "Could not retry outgoing connections.\n");
1277                 return 1;
1278         }
1279
1280         return 0;
1281 }
1282
1283 static int cmd_connect(int argc, char *argv[]) {
1284         if(argc != 2) {
1285                 fprintf(stderr, "Invalid number of arguments.\n");
1286                 return 1;
1287         }
1288
1289         if(!check_id(argv[1])) {
1290                 fprintf(stderr, "Invalid name for node.\n");
1291                 return 1;
1292         }
1293
1294         if(!connect_tincd(true))
1295                 return 1;
1296
1297         sendline(fd, "%d %d %s", CONTROL, REQ_CONNECT, argv[1]);
1298         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_CONNECT || result) {
1299                 fprintf(stderr, "Could not connect to %s.\n", argv[1]);
1300                 return 1;
1301         }
1302
1303         return 0;
1304 }
1305
1306 static int cmd_disconnect(int argc, char *argv[]) {
1307         if(argc != 2) {
1308                 fprintf(stderr, "Invalid number of arguments.\n");
1309                 return 1;
1310         }
1311
1312         if(!check_id(argv[1])) {
1313                 fprintf(stderr, "Invalid name for node.\n");
1314                 return 1;
1315         }
1316
1317         if(!connect_tincd(true))
1318                 return 1;
1319
1320         sendline(fd, "%d %d %s", CONTROL, REQ_DISCONNECT, argv[1]);
1321         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_DISCONNECT || result) {
1322                 fprintf(stderr, "Could not disconnect %s.\n", argv[1]);
1323                 return 1;
1324         }
1325
1326         return 0;
1327 }
1328
1329 static int cmd_top(int argc, char *argv[]) {
1330         if(argc > 1) {
1331                 fprintf(stderr, "Too many arguments!\n");
1332                 return 1;
1333         }
1334
1335 #ifdef HAVE_CURSES
1336         if(!connect_tincd(true))
1337                 return 1;
1338
1339         top(fd);
1340         return 0;
1341 #else
1342         fprintf(stderr, "This version of tinc was compiled without support for the curses library.\n");
1343         return 1;
1344 #endif
1345 }
1346
1347 static int cmd_pcap(int argc, char *argv[]) {
1348         if(argc > 2) {
1349                 fprintf(stderr, "Too many arguments!\n");
1350                 return 1;
1351         }
1352
1353         if(!connect_tincd(true))
1354                 return 1;
1355
1356         pcap(fd, stdout, argc > 1 ? atoi(argv[1]) : 0);
1357         return 0;
1358 }
1359
1360 #ifdef SIGINT
1361 static void sigint_handler(int sig) {
1362         fprintf(stderr, "\n");
1363         shutdown(fd, SHUT_RDWR);
1364 }
1365 #endif
1366
1367 static int cmd_log(int argc, char *argv[]) {
1368         if(argc > 2) {
1369                 fprintf(stderr, "Too many arguments!\n");
1370                 return 1;
1371         }
1372
1373         if(!connect_tincd(true))
1374                 return 1;
1375
1376 #ifdef SIGINT
1377         signal(SIGINT, sigint_handler);
1378 #endif
1379
1380         logcontrol(fd, stdout, argc > 1 ? atoi(argv[1]) : -1);
1381
1382 #ifdef SIGINT
1383         signal(SIGINT, SIG_DFL);
1384 #endif
1385
1386         close(fd);
1387         fd = -1;
1388         return 0;
1389 }
1390
1391 static int cmd_pid(int argc, char *argv[]) {
1392         if(argc > 1) {
1393                 fprintf(stderr, "Too many arguments!\n");
1394                 return 1;
1395         }
1396
1397         if(!connect_tincd(true) || !pid)
1398                 return 1;
1399
1400         printf("%d\n", pid);
1401         return 0;
1402 }
1403
1404 int rstrip(char *value) {
1405         int len = strlen(value);
1406         while(len && strchr("\t\r\n ", value[len - 1]))
1407                 value[--len] = 0;
1408         return len;
1409 }
1410
1411 char *get_my_name(bool verbose) {
1412         FILE *f = fopen(tinc_conf, "r");
1413         if(!f) {
1414                 if(verbose)
1415                         fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
1416                 return NULL;
1417         }
1418
1419         char buf[4096];
1420         char *value;
1421         while(fgets(buf, sizeof buf, f)) {
1422                 int len = strcspn(buf, "\t =");
1423                 value = buf + len;
1424                 value += strspn(value, "\t ");
1425                 if(*value == '=') {
1426                         value++;
1427                         value += strspn(value, "\t ");
1428                 }
1429                 if(!rstrip(value))
1430                         continue;
1431                 buf[len] = 0;
1432                 if(strcasecmp(buf, "Name"))
1433                         continue;
1434                 if(*value) {
1435                         fclose(f);
1436                         return replace_name(value);
1437                 }
1438         }
1439
1440         fclose(f);
1441         if(verbose)
1442                 fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
1443         return NULL;
1444 }
1445
1446 ecdsa_t *get_pubkey(FILE *f) {
1447         char buf[4096];
1448         char *value;
1449         while(fgets(buf, sizeof buf, f)) {
1450                 int len = strcspn(buf, "\t =");
1451                 value = buf + len;
1452                 value += strspn(value, "\t ");
1453                 if(*value == '=') {
1454                         value++;
1455                         value += strspn(value, "\t ");
1456                 }
1457                 if(!rstrip(value))
1458                         continue;
1459                 buf[len] = 0;
1460                 if(strcasecmp(buf, "Ed25519PublicKey"))
1461                         continue;
1462                 if(*value)
1463                         return ecdsa_set_base64_public_key(value);
1464         }
1465
1466         return NULL;
1467 }
1468
1469 const var_t variables[] = {
1470         /* Server configuration */
1471         {"AddressFamily", VAR_SERVER},
1472         {"AutoConnect", VAR_SERVER | VAR_SAFE},
1473         {"BindToAddress", VAR_SERVER | VAR_MULTIPLE},
1474         {"BindToInterface", VAR_SERVER},
1475         {"Broadcast", VAR_SERVER | VAR_SAFE},
1476         {"BroadcastSubnet", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
1477         {"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
1478         {"DecrementTTL", VAR_SERVER},
1479         {"Device", VAR_SERVER},
1480         {"DeviceStandby", VAR_SERVER},
1481         {"DeviceType", VAR_SERVER},
1482         {"DirectOnly", VAR_SERVER},
1483         {"Ed25519PrivateKeyFile", VAR_SERVER},
1484         {"ExperimentalProtocol", VAR_SERVER},
1485         {"Forwarding", VAR_SERVER},
1486         {"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE},
1487         {"Hostnames", VAR_SERVER},
1488         {"IffOneQueue", VAR_SERVER},
1489         {"Interface", VAR_SERVER},
1490         {"KeyExpire", VAR_SERVER},
1491         {"ListenAddress", VAR_SERVER | VAR_MULTIPLE},
1492         {"LocalDiscovery", VAR_SERVER},
1493         {"MACExpire", VAR_SERVER},
1494         {"MaxConnectionBurst", VAR_SERVER},
1495         {"MaxOutputBufferSize", VAR_SERVER},
1496         {"MaxTimeout", VAR_SERVER},
1497         {"Mode", VAR_SERVER | VAR_SAFE},
1498         {"Name", VAR_SERVER},
1499         {"PingInterval", VAR_SERVER},
1500         {"PingTimeout", VAR_SERVER},
1501         {"PriorityInheritance", VAR_SERVER},
1502         {"PrivateKey", VAR_SERVER | VAR_OBSOLETE},
1503         {"PrivateKeyFile", VAR_SERVER},
1504         {"ProcessPriority", VAR_SERVER},
1505         {"Proxy", VAR_SERVER},
1506         {"ReplayWindow", VAR_SERVER},
1507         {"ScriptsExtension", VAR_SERVER},
1508         {"ScriptsInterpreter", VAR_SERVER},
1509         {"StrictSubnets", VAR_SERVER},
1510         {"TunnelServer", VAR_SERVER},
1511         {"UDPDiscovery", VAR_SERVER},
1512         {"UDPDiscoveryKeepaliveInterval", VAR_SERVER},
1513         {"UDPDiscoveryInterval", VAR_SERVER},
1514         {"UDPDiscoveryTimeout", VAR_SERVER},
1515         {"MTUInfoInterval", VAR_SERVER},
1516         {"UDPInfoInterval", VAR_SERVER},
1517         {"UDPRcvBuf", VAR_SERVER},
1518         {"UDPSndBuf", VAR_SERVER},
1519         {"UPnP", VAR_SERVER},
1520         {"UPnPDiscoverWait", VAR_SERVER},
1521         {"UPnPRefreshPeriod", VAR_SERVER},
1522         {"VDEGroup", VAR_SERVER},
1523         {"VDEPort", VAR_SERVER},
1524         /* Host configuration */
1525         {"Address", VAR_HOST | VAR_MULTIPLE},
1526         {"Cipher", VAR_SERVER | VAR_HOST},
1527         {"ClampMSS", VAR_SERVER | VAR_HOST},
1528         {"Compression", VAR_SERVER | VAR_HOST},
1529         {"Digest", VAR_SERVER | VAR_HOST},
1530         {"Ed25519PublicKey", VAR_HOST},
1531         {"Ed25519PublicKeyFile", VAR_SERVER | VAR_HOST},
1532         {"IndirectData", VAR_SERVER | VAR_HOST},
1533         {"MACLength", VAR_SERVER | VAR_HOST},
1534         {"PMTU", VAR_SERVER | VAR_HOST},
1535         {"PMTUDiscovery", VAR_SERVER | VAR_HOST},
1536         {"Port", VAR_HOST},
1537         {"PublicKey", VAR_HOST | VAR_OBSOLETE},
1538         {"PublicKeyFile", VAR_SERVER | VAR_HOST | VAR_OBSOLETE},
1539         {"Subnet", VAR_HOST | VAR_MULTIPLE | VAR_SAFE},
1540         {"TCPOnly", VAR_SERVER | VAR_HOST},
1541         {"Weight", VAR_HOST | VAR_SAFE},
1542         {NULL, 0}
1543 };
1544
1545 static int cmd_config(int argc, char *argv[]) {
1546         if(argc < 2) {
1547                 fprintf(stderr, "Invalid number of arguments.\n");
1548                 return 1;
1549         }
1550
1551         if(strcasecmp(argv[0], "config"))
1552                 argv--, argc++;
1553
1554         int action = -2;
1555         if(!strcasecmp(argv[1], "get")) {
1556                 argv++, argc--;
1557         } else if(!strcasecmp(argv[1], "add")) {
1558                 argv++, argc--, action = 1;
1559         } else if(!strcasecmp(argv[1], "del")) {
1560                 argv++, argc--, action = -1;
1561         } else if(!strcasecmp(argv[1], "replace") || !strcasecmp(argv[1], "set") || !strcasecmp(argv[1], "change")) {
1562                 argv++, argc--, action = 0;
1563         }
1564
1565         if(argc < 2) {
1566                 fprintf(stderr, "Invalid number of arguments.\n");
1567                 return 1;
1568         }
1569
1570         // Concatenate the rest of the command line
1571         strncpy(line, argv[1], sizeof line - 1);
1572         for(int i = 2; i < argc; i++) {
1573                 strncat(line, " ", sizeof line - 1 - strlen(line));
1574                 strncat(line, argv[i], sizeof line - 1 - strlen(line));
1575         }
1576
1577         // Liberal parsing into node name, variable name and value.
1578         char *node = NULL;
1579         char *variable;
1580         char *value;
1581         int len;
1582
1583         len = strcspn(line, "\t =");
1584         value = line + len;
1585         value += strspn(value, "\t ");
1586         if(*value == '=') {
1587                 value++;
1588                 value += strspn(value, "\t ");
1589         }
1590         line[len] = '\0';
1591         variable = strchr(line, '.');
1592         if(variable) {
1593                 node = line;
1594                 *variable++ = 0;
1595         } else {
1596                 variable = line;
1597         }
1598
1599         if(!*variable) {
1600                 fprintf(stderr, "No variable given.\n");
1601                 return 1;
1602         }
1603
1604         if(action >= 0 && !*value) {
1605                 fprintf(stderr, "No value for variable given.\n");
1606                 return 1;
1607         }
1608
1609         if(action < -1 && *value)
1610                 action = 0;
1611
1612         /* Some simple checks. */
1613         bool found = false;
1614         bool warnonremove = false;
1615
1616         for(int i = 0; variables[i].name; i++) {
1617                 if(strcasecmp(variables[i].name, variable))
1618                         continue;
1619
1620                 found = true;
1621                 variable = (char *)variables[i].name;
1622
1623                 /* Discourage use of obsolete variables. */
1624
1625                 if(variables[i].type & VAR_OBSOLETE && action >= 0) {
1626                         if(force) {
1627                                 fprintf(stderr, "Warning: %s is an obsolete variable!\n", variable);
1628                         } else {
1629                                 fprintf(stderr, "%s is an obsolete variable! Use --force to use it anyway.\n", variable);
1630                                 return 1;
1631                         }
1632                 }
1633
1634                 /* Don't put server variables in host config files */
1635
1636                 if(node && !(variables[i].type & VAR_HOST) && action >= 0) {
1637                         if(force) {
1638                                 fprintf(stderr, "Warning: %s is not a host configuration variable!\n", variable);
1639                         } else {
1640                                 fprintf(stderr, "%s is not a host configuration variable! Use --force to use it anyway.\n", variable);
1641                                 return 1;
1642                         }
1643                 }
1644
1645                 /* Should this go into our own host config file? */
1646
1647                 if(!node && !(variables[i].type & VAR_SERVER)) {
1648                         node = get_my_name(true);
1649                         if(!node)
1650                                 return 1;
1651                 }
1652
1653                 /* Change "add" into "set" for variables that do not allow multiple occurences.
1654                    Turn on warnings when it seems variables might be removed unintentionally. */
1655
1656                 if(action == 1 && !(variables[i].type & VAR_MULTIPLE)) {
1657                         warnonremove = true;
1658                         action = 0;
1659                 } else if(action == 0 && (variables[i].type & VAR_MULTIPLE)) {
1660                         warnonremove = true;
1661                 }
1662
1663                 break;
1664         }
1665
1666         if(node && !check_id(node)) {
1667                 fprintf(stderr, "Invalid name for node.\n");
1668                 return 1;
1669         }
1670
1671         if(!found) {
1672                 if(force || action < 0) {
1673                         fprintf(stderr, "Warning: %s is not a known configuration variable!\n", variable);
1674                 } else {
1675                         fprintf(stderr, "%s: is not a known configuration variable! Use --force to use it anyway.\n", variable);
1676                         return 1;
1677                 }
1678         }
1679
1680         // Open the right configuration file.
1681         char filename[PATH_MAX];
1682         if(node)
1683                 snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, node);
1684         else
1685                 snprintf(filename, sizeof filename, "%s", tinc_conf);
1686
1687         FILE *f = fopen(filename, "r");
1688         if(!f) {
1689                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
1690                 return 1;
1691         }
1692
1693         char tmpfile[PATH_MAX];
1694         FILE *tf = NULL;
1695
1696         if(action >= -1) {
1697                 snprintf(tmpfile, sizeof tmpfile, "%s.config.tmp", filename);
1698                 tf = fopen(tmpfile, "w");
1699                 if(!tf) {
1700                         fprintf(stderr, "Could not open temporary file %s: %s\n", tmpfile, strerror(errno));
1701                         fclose(f);
1702                         return 1;
1703                 }
1704         }
1705
1706         // Copy the file, making modifications on the fly, unless we are just getting a value.
1707         char buf1[4096];
1708         char buf2[4096];
1709         bool set = false;
1710         bool removed = false;
1711         found = false;
1712
1713         while(fgets(buf1, sizeof buf1, f)) {
1714                 buf1[sizeof buf1 - 1] = 0;
1715                 strncpy(buf2, buf1, sizeof buf2);
1716
1717                 // Parse line in a simple way
1718                 char *bvalue;
1719                 int len;
1720
1721                 len = strcspn(buf2, "\t =");
1722                 bvalue = buf2 + len;
1723                 bvalue += strspn(bvalue, "\t ");
1724                 if(*bvalue == '=') {
1725                         bvalue++;
1726                         bvalue += strspn(bvalue, "\t ");
1727                 }
1728                 rstrip(bvalue);
1729                 buf2[len] = '\0';
1730
1731                 // Did it match?
1732                 if(!strcasecmp(buf2, variable)) {
1733                         // Get
1734                         if(action < -1) {
1735                                 found = true;
1736                                 printf("%s\n", bvalue);
1737                         // Del
1738                         } else if(action == -1) {
1739                                 if(!*value || !strcasecmp(bvalue, value)) {
1740                                         removed = true;
1741                                         continue;
1742                                 }
1743                         // Set
1744                         } else if(action == 0) {
1745                                 // Warn if "set" was used for variables that can occur multiple times
1746                                 if(warnonremove && strcasecmp(bvalue, value))
1747                                         fprintf(stderr, "Warning: removing %s = %s\n", variable, bvalue);
1748
1749                                 // Already set? Delete the rest...
1750                                 if(set)
1751                                         continue;
1752
1753                                 // Otherwise, replace.
1754                                 if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
1755                                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1756                                         return 1;
1757                                 }
1758                                 set = true;
1759                                 continue;
1760                         // Add
1761                         } else if(action > 0) {
1762                                 // Check if we've already seen this variable with the same value
1763                                 if(!strcasecmp(bvalue, value))
1764                                         found = true;
1765                         }
1766                 }
1767
1768                 if(action >= -1) {
1769                         // Copy original line...
1770                         if(fputs(buf1, tf) < 0) {
1771                                 fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1772                                 return 1;
1773                         }
1774
1775                         // Add newline if it is missing...
1776                         if(*buf1 && buf1[strlen(buf1) - 1] != '\n') {
1777                                 if(fputc('\n', tf) < 0) {
1778                                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1779                                         return 1;
1780                                 }
1781                         }
1782                 }
1783         }
1784
1785         // Make sure we read everything...
1786         if(ferror(f) || !feof(f)) {
1787                 fprintf(stderr, "Error while reading from configuration file %s: %s\n", filename, strerror(errno));
1788                 return 1;
1789         }
1790
1791         if(fclose(f)) {
1792                 fprintf(stderr, "Error closing configuration file %s: %s\n", filename, strerror(errno));
1793                 return 1;
1794         }
1795
1796         // Add new variable if necessary.
1797         if((action > 0 && !found)|| (action == 0 && !set)) {
1798                 if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
1799                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1800                         return 1;
1801                 }
1802         }
1803
1804         if(action < -1) {
1805                 if(found) {
1806                         return 0;
1807                 } else {
1808                         fprintf(stderr, "No matching configuration variables found.\n");
1809                         return 1;
1810                 }
1811         }
1812
1813         // Make sure we wrote everything...
1814         if(fclose(tf)) {
1815                 fprintf(stderr, "Error closing temporary file %s: %s\n", tmpfile, strerror(errno));
1816                 return 1;
1817         }
1818
1819         // Could we find what we had to remove?
1820         if(action < 0 && !removed) {
1821                 remove(tmpfile);
1822                 fprintf(stderr, "No configuration variables deleted.\n");
1823                 return 1;
1824         }
1825
1826         // Replace the configuration file with the new one
1827 #ifdef HAVE_MINGW
1828         if(remove(filename)) {
1829                 fprintf(stderr, "Error replacing file %s: %s\n", filename, strerror(errno));
1830                 return 1;
1831         }
1832 #endif
1833         if(rename(tmpfile, filename)) {
1834                 fprintf(stderr, "Error renaming temporary file %s to configuration file %s: %s\n", tmpfile, filename, strerror(errno));
1835                 return 1;
1836         }
1837
1838         // Silently try notifying a running tincd of changes.
1839         if(connect_tincd(false))
1840                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
1841
1842         return 0;
1843 }
1844
1845 static bool try_bind(int port) {
1846         struct addrinfo *ai = NULL, *aip;
1847         struct addrinfo hint = {
1848                 .ai_flags = AI_PASSIVE,
1849                 .ai_family = AF_UNSPEC,
1850                 .ai_socktype = SOCK_STREAM,
1851                 .ai_protocol = IPPROTO_TCP,
1852         };
1853
1854         bool success = true;
1855         char portstr[16];
1856         snprintf(portstr, sizeof portstr, "%d", port);
1857
1858         if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai)
1859                 return false;
1860
1861         for(aip = ai; aip; aip = aip->ai_next) {
1862                 int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
1863                 if(!fd) {
1864                         success = false;
1865                         break;
1866                 }
1867
1868                 int result = bind(fd, ai->ai_addr, ai->ai_addrlen);
1869                 closesocket(fd);
1870                 if(result) {
1871                         success = false;
1872                         break;
1873                 }
1874         }
1875
1876         freeaddrinfo(ai);
1877         return success;
1878 }
1879
1880 int check_port(char *name) {
1881         if(try_bind(655))
1882                 return 655;
1883
1884         fprintf(stderr, "Warning: could not bind to port 655. ");
1885
1886         for(int i = 0; i < 100; i++) {
1887                 int port = 0x1000 + (rand() & 0x7fff);
1888                 if(try_bind(port)) {
1889                         char filename[PATH_MAX];
1890                         snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
1891                         FILE *f = fopen(filename, "a");
1892                         if(!f) {
1893                                 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
1894                                 fprintf(stderr, "Please change tinc's Port manually.\n");
1895                                 return 0;
1896                         }
1897
1898                         fprintf(f, "Port = %d\n", port);
1899                         fclose(f);
1900                         fprintf(stderr, "Tinc will instead listen on port %d.\n", port);
1901                         return port;
1902                 }
1903         }
1904
1905         fprintf(stderr, "Please change tinc's Port manually.\n");
1906         return 0;
1907 }
1908
1909 static int cmd_init(int argc, char *argv[]) {
1910         if(!access(tinc_conf, F_OK)) {
1911                 fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
1912                 return 1;
1913         }
1914
1915         if(argc > 2) {
1916                 fprintf(stderr, "Too many arguments!\n");
1917                 return 1;
1918         } else if(argc < 2) {
1919                 if(tty) {
1920                         char buf[1024];
1921                         fprintf(stderr, "Enter the Name you want your tinc node to have: ");
1922                         if(!fgets(buf, sizeof buf, stdin)) {
1923                                 fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
1924                                 return 1;
1925                         }
1926                         int len = rstrip(buf);
1927                         if(!len) {
1928                                 fprintf(stderr, "No name given!\n");
1929                                 return 1;
1930                         }
1931                         name = strdup(buf);
1932                 } else {
1933                         fprintf(stderr, "No Name given!\n");
1934                         return 1;
1935                 }
1936         } else {
1937                 name = strdup(argv[1]);
1938                 if(!*name) {
1939                         fprintf(stderr, "No Name given!\n");
1940                         return 1;
1941                 }
1942         }
1943
1944         if(!check_id(name)) {
1945                 fprintf(stderr, "Invalid Name! Only a-z, A-Z, 0-9 and _ are allowed characters.\n");
1946                 return 1;
1947         }
1948
1949         if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) {
1950                 fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno));
1951                 return 1;
1952         }
1953
1954         if(mkdir(confbase, 0777) && errno != EEXIST) {
1955                 fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno));
1956                 return 1;
1957         }
1958
1959         if(mkdir(hosts_dir, 0777) && errno != EEXIST) {
1960                 fprintf(stderr, "Could not create directory %s: %s\n", hosts_dir, strerror(errno));
1961                 return 1;
1962         }
1963
1964         FILE *f = fopen(tinc_conf, "w");
1965         if(!f) {
1966                 fprintf(stderr, "Could not create file %s: %s\n", tinc_conf, strerror(errno));
1967                 return 1;
1968         }
1969
1970         fprintf(f, "Name = %s\n", name);
1971         fclose(f);
1972
1973 #ifndef DISABLE_LEGACY
1974         if(!rsa_keygen(2048, false))
1975                 return 1;
1976 #endif
1977
1978         if(!ed25519_keygen(false))
1979                 return 1;
1980
1981         check_port(name);
1982
1983 #ifndef HAVE_MINGW
1984         char filename[PATH_MAX];
1985         snprintf(filename, sizeof filename, "%s" SLASH "tinc-up", confbase);
1986         if(access(filename, F_OK)) {
1987                 FILE *f = fopenmask(filename, "w", 0777);
1988                 if(!f) {
1989                         fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
1990                         return 1;
1991                 }
1992                 fprintf(f, "#!/bin/sh\n\necho 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
1993                 fclose(f);
1994         }
1995 #endif
1996
1997         return 0;
1998
1999 }
2000
2001 static int cmd_generate_keys(int argc, char *argv[]) {
2002 #ifdef DISABLE_LEGACY
2003         if(argc > 1) {
2004 #else
2005         if(argc > 2) {
2006 #endif
2007                 fprintf(stderr, "Too many arguments!\n");
2008                 return 1;
2009         }
2010
2011         if(!name)
2012                 name = get_my_name(false);
2013
2014 #ifndef DISABLE_LEGACY
2015         if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true))
2016                 return 1;
2017 #endif
2018
2019         if(!ed25519_keygen(true))
2020                 return 1;
2021
2022         return 0;
2023 }
2024
2025 #ifndef DISABLE_LEGACY
2026 static int cmd_generate_rsa_keys(int argc, char *argv[]) {
2027         if(argc > 2) {
2028                 fprintf(stderr, "Too many arguments!\n");
2029                 return 1;
2030         }
2031
2032         if(!name)
2033                 name = get_my_name(false);
2034
2035         return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
2036 }
2037 #endif
2038
2039 static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
2040         if(argc > 1) {
2041                 fprintf(stderr, "Too many arguments!\n");
2042                 return 1;
2043         }
2044
2045         if(!name)
2046                 name = get_my_name(false);
2047
2048         return !ed25519_keygen(true);
2049 }
2050
2051 static int cmd_help(int argc, char *argv[]) {
2052         usage(false);
2053         return 0;
2054 }
2055
2056 static int cmd_version(int argc, char *argv[]) {
2057         if(argc > 1) {
2058                 fprintf(stderr, "Too many arguments!\n");
2059                 return 1;
2060         }
2061
2062         version();
2063         return 0;
2064 }
2065
2066 static int cmd_info(int argc, char *argv[]) {
2067         if(argc != 2) {
2068                 fprintf(stderr, "Invalid number of arguments.\n");
2069                 return 1;
2070         }
2071
2072         if(!connect_tincd(true))
2073                 return 1;
2074
2075         return info(fd, argv[1]);
2076 }
2077
2078 static const char *conffiles[] = {
2079         "tinc.conf",
2080         "tinc-up",
2081         "tinc-down",
2082         "subnet-up",
2083         "subnet-down",
2084         "host-up",
2085         "host-down",
2086         NULL,
2087 };
2088
2089 static int cmd_edit(int argc, char *argv[]) {
2090         if(argc != 2) {
2091                 fprintf(stderr, "Invalid number of arguments.\n");
2092                 return 1;
2093         }
2094
2095         char filename[PATH_MAX] = "";
2096
2097         if(strncmp(argv[1], "hosts" SLASH, 6)) {
2098                 for(int i = 0; conffiles[i]; i++) {
2099                         if(!strcmp(argv[1], conffiles[i])) {
2100                                 snprintf(filename, sizeof filename, "%s" SLASH "%s", confbase, argv[1]);
2101                                 break;
2102                         }
2103                 }
2104         } else {
2105                 argv[1] += 6;
2106         }
2107
2108         if(!*filename) {
2109                 snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, argv[1]);
2110                 char *dash = strchr(argv[1], '-');
2111                 if(dash) {
2112                         *dash++ = 0;
2113                         if((strcmp(dash, "up") && strcmp(dash, "down")) || !check_id(argv[1])) {
2114                                 fprintf(stderr, "Invalid configuration filename.\n");
2115                                 return 1;
2116                         }
2117                 }
2118         }
2119
2120         char *command;
2121 #ifndef HAVE_MINGW
2122         xasprintf(&command, "\"%s\" \"%s\"", getenv("VISUAL") ?: getenv("EDITOR") ?: "vi", filename);
2123 #else
2124         xasprintf(&command, "edit \"%s\"", filename);
2125 #endif
2126         int result = system(command);
2127         free(command);
2128         if(result)
2129                 return result;
2130
2131         // Silently try notifying a running tincd of changes.
2132         if(connect_tincd(false))
2133                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
2134
2135         return 0;
2136 }
2137
2138 static int export(const char *name, FILE *out) {
2139         char filename[PATH_MAX];
2140         snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
2141         FILE *in = fopen(filename, "r");
2142         if(!in) {
2143                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
2144                 return 1;
2145         }
2146
2147         fprintf(out, "Name = %s\n", name);
2148         char buf[4096];
2149         while(fgets(buf, sizeof buf, in)) {
2150                 if(strcspn(buf, "\t =") != 4 || strncasecmp(buf, "Name", 4))
2151                         fputs(buf, out);
2152         }
2153
2154         if(ferror(in)) {
2155                 fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));
2156                 fclose(in);
2157                 return 1;
2158         }
2159
2160         fclose(in);
2161         return 0;
2162 }
2163
2164 static int cmd_export(int argc, char *argv[]) {
2165         if(argc > 1) {
2166                 fprintf(stderr, "Too many arguments!\n");
2167                 return 1;
2168         }
2169
2170         char *name = get_my_name(true);
2171         if(!name)
2172                 return 1;
2173
2174         int result = export(name, stdout);
2175         if(!tty)
2176                 fclose(stdout);
2177
2178         free(name);
2179         return result;
2180 }
2181
2182 static int cmd_export_all(int argc, char *argv[]) {
2183         if(argc > 1) {
2184                 fprintf(stderr, "Too many arguments!\n");
2185                 return 1;
2186         }
2187
2188         DIR *dir = opendir(hosts_dir);
2189         if(!dir) {
2190                 fprintf(stderr, "Could not open host configuration directory %s: %s\n", hosts_dir, strerror(errno));
2191                 return 1;
2192         }
2193
2194         bool first = true;
2195         int result = 0;
2196         struct dirent *ent;
2197
2198         while((ent = readdir(dir))) {
2199                 if(!check_id(ent->d_name))
2200                         continue;
2201
2202                 if(first)
2203                         first = false;
2204                 else
2205                         printf("#---------------------------------------------------------------#\n");
2206
2207                 result |= export(ent->d_name, stdout);
2208         }
2209
2210         closedir(dir);
2211         if(!tty)
2212                 fclose(stdout);
2213         return result;
2214 }
2215
2216 static int cmd_import(int argc, char *argv[]) {
2217         if(argc > 1) {
2218                 fprintf(stderr, "Too many arguments!\n");
2219                 return 1;
2220         }
2221
2222         FILE *in = stdin;
2223         FILE *out = NULL;
2224
2225         char buf[4096];
2226         char name[4096];
2227         char filename[PATH_MAX] = "";
2228         int count = 0;
2229         bool firstline = true;
2230
2231         while(fgets(buf, sizeof buf, in)) {
2232                 if(sscanf(buf, "Name = %s", name) == 1) {
2233                         firstline = false;
2234
2235                         if(!check_id(name)) {
2236                                 fprintf(stderr, "Invalid Name in input!\n");
2237                                 return 1;
2238                         }
2239
2240                         if(out)
2241                                 fclose(out);
2242
2243                         snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
2244
2245                         if(!force && !access(filename, F_OK)) {
2246                                 fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename);
2247                                 out = NULL;
2248                                 continue;
2249                         }
2250
2251                         out = fopen(filename, "w");
2252                         if(!out) {
2253                                 fprintf(stderr, "Error creating configuration file %s: %s\n", filename, strerror(errno));
2254                                 return 1;
2255                         }
2256
2257                         count++;
2258                         continue;
2259                 } else if(firstline) {
2260                         fprintf(stderr, "Junk at the beginning of the input, ignoring.\n");
2261                         firstline = false;
2262                 }
2263
2264
2265                 if(!strcmp(buf, "#---------------------------------------------------------------#\n"))
2266                         continue;
2267
2268                 if(out) {
2269                         if(fputs(buf, out) < 0) {
2270                                 fprintf(stderr, "Error writing to host configuration file %s: %s\n", filename, strerror(errno));
2271                                 return 1;
2272                         }
2273                 }
2274         }
2275
2276         if(out)
2277                 fclose(out);
2278
2279         if(count) {
2280                 fprintf(stderr, "Imported %d host configuration files.\n", count);
2281                 return 0;
2282         } else {
2283                 fprintf(stderr, "No host configuration files imported.\n");
2284                 return 1;
2285         }
2286 }
2287
2288 static int cmd_exchange(int argc, char *argv[]) {
2289         return cmd_export(argc, argv) ?: cmd_import(argc, argv);
2290 }
2291
2292 static int cmd_exchange_all(int argc, char *argv[]) {
2293         return cmd_export_all(argc, argv) ?: cmd_import(argc, argv);
2294 }
2295
2296 static int switch_network(char *name) {
2297         if(strcmp(name, ".")) {
2298                 if(!check_netname(name, false)) {
2299                         fprintf(stderr, "Invalid character in netname!\n");
2300                         return 1;
2301                 }
2302
2303                 if(!check_netname(name, true))
2304                         fprintf(stderr, "Warning: unsafe character in netname!\n");
2305         }
2306
2307         if(fd >= 0) {
2308                 close(fd);
2309                 fd = -1;
2310         }
2311
2312         free_names();
2313         netname = strcmp(name, ".") ? xstrdup(name) : NULL;
2314         make_names(false);
2315
2316         free(tinc_conf);
2317         free(hosts_dir);
2318         free(prompt);
2319
2320         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
2321         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
2322         xasprintf(&prompt, "%s> ", identname);
2323
2324         return 0;
2325 }
2326
2327 static int cmd_network(int argc, char *argv[]) {
2328         if(argc > 2) {
2329                 fprintf(stderr, "Too many arguments!\n");
2330                 return 1;
2331         }
2332
2333         if(argc == 2)
2334                 return switch_network(argv[1]);
2335
2336         DIR *dir = opendir(confdir);
2337         if(!dir) {
2338                 fprintf(stderr, "Could not read directory %s: %s\n", confdir, strerror(errno));
2339                 return 1;
2340         }
2341
2342         struct dirent *ent;
2343         while((ent = readdir(dir))) {
2344                 if(*ent->d_name == '.')
2345                         continue;
2346
2347                 if(!strcmp(ent->d_name, "tinc.conf")) {
2348                         printf(".\n");
2349                         continue;
2350                 }
2351
2352                 char fname[PATH_MAX];
2353                 snprintf(fname, sizeof fname, "%s/%s/tinc.conf", confdir, ent->d_name);
2354                 if(!access(fname, R_OK))
2355                         printf("%s\n", ent->d_name);
2356         }
2357
2358         closedir(dir);
2359
2360         return 0;
2361 }
2362
2363 static int cmd_fsck(int argc, char *argv[]) {
2364         if(argc > 1) {
2365                 fprintf(stderr, "Too many arguments!\n");
2366                 return 1;
2367         }
2368
2369         return fsck(orig_argv[0]);
2370 }
2371
2372 static void *readfile(FILE *in, size_t *len) {
2373         size_t count = 0;
2374         size_t alloced = 4096;
2375         char *buf = xmalloc(alloced);
2376
2377         while(!feof(in)) {
2378                 size_t read = fread(buf + count, 1, alloced - count, in);
2379                 if(!read)
2380                         break;
2381                 count += read;
2382                 if(count >= alloced) {
2383                         alloced *= 2;
2384                         buf = xrealloc(buf, alloced);
2385                 }
2386         }
2387
2388         if(len)
2389                 *len = count;
2390
2391         return buf;
2392 }
2393
2394 static int cmd_sign(int argc, char *argv[]) {
2395         if(argc > 2) {
2396                 fprintf(stderr, "Too many arguments!\n");
2397                 return 1;
2398         }
2399
2400         if(!name) {
2401                 name = get_my_name(true);
2402                 if(!name)
2403                         return 1;
2404         }
2405
2406         char fname[PATH_MAX];
2407         snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase);
2408         FILE *fp = fopen(fname, "r");
2409         if(!fp) {
2410                 fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
2411                 return 1;
2412         }
2413
2414         ecdsa_t *key = ecdsa_read_pem_private_key(fp);
2415
2416         if(!key) {
2417                 fprintf(stderr, "Could not read private key from %s\n", fname);
2418                 fclose(fp);
2419                 return 1;
2420         }
2421
2422         fclose(fp);
2423
2424         FILE *in;
2425
2426         if(argc == 2) {
2427                 in = fopen(argv[1], "rb");
2428                 if(!in) {
2429                         fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
2430                         ecdsa_free(key);
2431                         return 1;
2432                 }
2433         } else {
2434                 in = stdin;
2435         }
2436
2437         size_t len;
2438         char *data = readfile(in, &len);
2439         if(in != stdin)
2440                 fclose(in);
2441         if(!data) {
2442                 fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
2443                 ecdsa_free(key);
2444                 return 1;
2445         }
2446
2447         // Ensure we sign our name and current time as well
2448         long t = time(NULL);
2449         char *trailer;
2450         xasprintf(&trailer, " %s %ld", name, t);
2451         int trailer_len = strlen(trailer);
2452
2453         data = xrealloc(data, len + trailer_len);
2454         memcpy(data + len, trailer, trailer_len);
2455         free(trailer);
2456
2457         char sig[87];
2458         if(!ecdsa_sign(key, data, len + trailer_len, sig)) {
2459                 fprintf(stderr, "Error generating signature\n");
2460                 free(data);
2461                 ecdsa_free(key);
2462                 return 1;
2463         }
2464         b64encode(sig, sig, 64);
2465         ecdsa_free(key);
2466
2467         fprintf(stdout, "Signature = %s %ld %s\n", name, t, sig);
2468         fwrite(data, len, 1, stdout);
2469
2470         free(data);
2471         return 0;
2472 }
2473
2474 static int cmd_verify(int argc, char *argv[]) {
2475         if(argc < 2) {
2476                 fprintf(stderr, "Not enough arguments!\n");
2477                 return 1;
2478         }
2479
2480         if(argc > 3) {
2481                 fprintf(stderr, "Too many arguments!\n");
2482                 return 1;
2483         }
2484
2485         char *node = argv[1];
2486         if(!strcmp(node, ".")) {
2487                 if(!name) {
2488                         name = get_my_name(true);
2489                         if(!name)
2490                                 return 1;
2491                 }
2492                 node = name;
2493         } else if(!strcmp(node, "*")) {
2494                 node = NULL;
2495         } else {
2496                 if(!check_id(node)) {
2497                         fprintf(stderr, "Invalid node name\n");
2498                         return 1;
2499                 }
2500         }
2501
2502         FILE *in;
2503
2504         if(argc == 3) {
2505                 in = fopen(argv[2], "rb");
2506                 if(!in) {
2507                         fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
2508                         return 1;
2509                 }
2510         } else {
2511                 in = stdin;
2512         }
2513
2514         size_t len;
2515         char *data = readfile(in, &len);
2516         if(in != stdin)
2517                 fclose(in);
2518         if(!data) {
2519                 fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
2520                 return 1;
2521         }
2522
2523         char *newline = memchr(data, '\n', len);
2524         if(!newline || (newline - data > MAX_STRING_SIZE - 1)) {
2525                 fprintf(stderr, "Invalid input\n");
2526                 free(data);
2527                 return 1;
2528         }
2529
2530         *newline++ = '\0';
2531         size_t skip = newline - data;
2532
2533         char signer[MAX_STRING_SIZE] = "";
2534         char sig[MAX_STRING_SIZE] = "";
2535         long t = 0;
2536
2537         if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) {
2538                 fprintf(stderr, "Invalid input\n");
2539                 free(data);
2540                 return 1;
2541         }
2542
2543         if(node && strcmp(node, signer)) {
2544                 fprintf(stderr, "Signature is not made by %s\n", node);
2545                 free(data);
2546                 return 1;
2547         }
2548
2549         if(!node)
2550                 node = signer;
2551
2552         char *trailer;
2553         xasprintf(&trailer, " %s %ld", signer, t);
2554         int trailer_len = strlen(trailer);
2555
2556         data = xrealloc(data, len + trailer_len);
2557         memcpy(data + len, trailer, trailer_len);
2558         free(trailer);
2559
2560         newline = data + skip;
2561
2562         char fname[PATH_MAX];
2563         snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, node);
2564         FILE *fp = fopen(fname, "r");
2565         if(!fp) {
2566                 fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
2567                 free(data);
2568                 return 1;
2569         }
2570
2571         ecdsa_t *key = get_pubkey(fp);
2572         if(!key) {
2573                 rewind(fp);
2574                 key = ecdsa_read_pem_public_key(fp);
2575         }
2576         if(!key) {
2577                 fprintf(stderr, "Could not read public key from %s\n", fname);
2578                 fclose(fp);
2579                 free(data);
2580                 return 1;
2581         }
2582
2583         fclose(fp);
2584
2585         if(b64decode(sig, sig, 86) != 64 || !ecdsa_verify(key, newline, len + trailer_len - (newline - data), sig)) {
2586                 fprintf(stderr, "Invalid signature\n");
2587                 free(data);
2588                 ecdsa_free(key);
2589                 return 1;
2590         }
2591
2592         ecdsa_free(key);
2593
2594         fwrite(newline, len - (newline - data), 1, stdout);
2595
2596         free(data);
2597         return 0;
2598 }
2599
2600 static const struct {
2601         const char *command;
2602         int (*function)(int argc, char *argv[]);
2603         bool hidden;
2604 } commands[] = {
2605         {"start", cmd_start},
2606         {"stop", cmd_stop},
2607         {"restart", cmd_restart},
2608         {"reload", cmd_reload},
2609         {"dump", cmd_dump},
2610         {"list", cmd_dump},
2611         {"purge", cmd_purge},
2612         {"debug", cmd_debug},
2613         {"retry", cmd_retry},
2614         {"connect", cmd_connect},
2615         {"disconnect", cmd_disconnect},
2616         {"top", cmd_top},
2617         {"pcap", cmd_pcap},
2618         {"log", cmd_log},
2619         {"pid", cmd_pid},
2620         {"config", cmd_config, true},
2621         {"add", cmd_config},
2622         {"del", cmd_config},
2623         {"get", cmd_config},
2624         {"set", cmd_config},
2625         {"init", cmd_init},
2626         {"generate-keys", cmd_generate_keys},
2627 #ifndef DISABLE_LEGACY
2628         {"generate-rsa-keys", cmd_generate_rsa_keys},
2629 #endif
2630         {"generate-ed25519-keys", cmd_generate_ed25519_keys},
2631         {"help", cmd_help},
2632         {"version", cmd_version},
2633         {"info", cmd_info},
2634         {"edit", cmd_edit},
2635         {"export", cmd_export},
2636         {"export-all", cmd_export_all},
2637         {"import", cmd_import},
2638         {"exchange", cmd_exchange},
2639         {"exchange-all", cmd_exchange_all},
2640         {"invite", cmd_invite},
2641         {"join", cmd_join},
2642         {"network", cmd_network},
2643         {"fsck", cmd_fsck},
2644         {"sign", cmd_sign},
2645         {"verify", cmd_verify},
2646         {NULL, NULL},
2647 };
2648
2649 #ifdef HAVE_READLINE
2650 static char *complete_command(const char *text, int state) {
2651         static int i;
2652
2653         if(!state)
2654                 i = 0;
2655         else
2656                 i++;
2657
2658         while(commands[i].command) {
2659                 if(!commands[i].hidden && !strncasecmp(commands[i].command, text, strlen(text)))
2660                         return xstrdup(commands[i].command);
2661                 i++;
2662         }
2663
2664         return NULL;
2665 }
2666
2667 static char *complete_dump(const char *text, int state) {
2668         const char *matches[] = {"reachable", "nodes", "edges", "subnets", "connections", "graph", NULL};
2669         static int i;
2670
2671         if(!state)
2672                 i = 0;
2673         else
2674                 i++;
2675
2676         while(matches[i]) {
2677                 if(!strncasecmp(matches[i], text, strlen(text)))
2678                         return xstrdup(matches[i]);
2679                 i++;
2680         }
2681
2682         return NULL;
2683 }
2684
2685 static char *complete_config(const char *text, int state) {
2686         static int i;
2687
2688         if(!state)
2689                 i = 0;
2690         else
2691                 i++;
2692
2693         while(variables[i].name) {
2694                 char *dot = strchr(text, '.');
2695                 if(dot) {
2696                         if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
2697                                 char *match;
2698                                 xasprintf(&match, "%.*s.%s", (int)(dot - text), text, variables[i].name);
2699                                 return match;
2700                         }
2701                 } else {
2702                         if(!strncasecmp(variables[i].name, text, strlen(text)))
2703                                 return xstrdup(variables[i].name);
2704                 }
2705                 i++;
2706         }
2707
2708         return NULL;
2709 }
2710
2711 static char *complete_info(const char *text, int state) {
2712         static int i;
2713         if(!state) {
2714                 i = 0;
2715                 if(!connect_tincd(false))
2716                         return NULL;
2717                 // Check the list of nodes
2718                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
2719                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
2720         }
2721
2722         while(recvline(fd, line, sizeof line)) {
2723                 char item[4096];
2724                 int n = sscanf(line, "%d %d %s", &code, &req, item);
2725                 if(n == 2) {
2726                         i++;
2727                         if(i >= 2)
2728                                 break;
2729                         else
2730                                 continue;
2731                 }
2732
2733                 if(n != 3) {
2734                         fprintf(stderr, "Unable to parse dump from tincd, n = %d, i = %d.\n", n, i);
2735                         break;
2736                 }
2737
2738                 if(!strncmp(item, text, strlen(text)))
2739                         return xstrdup(strip_weight(item));
2740         }
2741
2742         return NULL;
2743 }
2744
2745 static char *complete_nothing(const char *text, int state) {
2746         return NULL;
2747 }
2748
2749 static char **completion (const char *text, int start, int end) {
2750         char **matches = NULL;
2751
2752         if(!start)
2753                 matches = rl_completion_matches(text, complete_command);
2754         else if(!strncasecmp(rl_line_buffer, "dump ", 5))
2755                 matches = rl_completion_matches(text, complete_dump);
2756         else if(!strncasecmp(rl_line_buffer, "add ", 4))
2757                 matches = rl_completion_matches(text, complete_config);
2758         else if(!strncasecmp(rl_line_buffer, "del ", 4))
2759                 matches = rl_completion_matches(text, complete_config);
2760         else if(!strncasecmp(rl_line_buffer, "get ", 4))
2761                 matches = rl_completion_matches(text, complete_config);
2762         else if(!strncasecmp(rl_line_buffer, "set ", 4))
2763                 matches = rl_completion_matches(text, complete_config);
2764         else if(!strncasecmp(rl_line_buffer, "info ", 5))
2765                 matches = rl_completion_matches(text, complete_info);
2766
2767         return matches;
2768 }
2769 #endif
2770
2771 static int cmd_shell(int argc, char *argv[]) {
2772         xasprintf(&prompt, "%s> ", identname);
2773         int result = 0;
2774         char buf[4096];
2775         char *line = NULL;
2776         int maxargs = argc + 16;
2777         char **nargv = xmalloc(maxargs * sizeof *nargv);
2778
2779         for(int i = 0; i < argc; i++)
2780                 nargv[i] = argv[i];
2781
2782 #ifdef HAVE_READLINE
2783         rl_readline_name = "tinc";
2784         rl_completion_entry_function = complete_nothing;
2785         rl_attempted_completion_function = completion;
2786         rl_filename_completion_desired = 0;
2787         char *copy = NULL;
2788 #endif
2789
2790         while(true) {
2791 #ifdef HAVE_READLINE
2792                 if(tty) {
2793                         free(copy);
2794                         free(line);
2795                         rl_basic_word_break_characters = "\t\n ";
2796                         line = readline(prompt);
2797                         if(line)
2798                                 copy = xstrdup(line);
2799                 } else {
2800                         line = fgets(buf, sizeof buf, stdin);
2801                 }
2802 #else
2803                 if(tty)
2804                         fputs(prompt, stdout);
2805
2806                 line = fgets(buf, sizeof buf, stdin);
2807 #endif
2808
2809                 if(!line)
2810                         break;
2811
2812                 /* Ignore comments */
2813
2814                 if(*line == '#')
2815                         continue;
2816
2817                 /* Split */
2818
2819                 int nargc = argc;
2820                 char *p = line + strspn(line, " \t\n");
2821                 char *next = strtok(p, " \t\n");
2822
2823                 while(p && *p) {
2824                         if(nargc >= maxargs) {
2825                                 fprintf(stderr, "next %p '%s', p %p '%s'\n", next, next, p, p);
2826                                 abort();
2827                                 maxargs *= 2;
2828                                 nargv = xrealloc(nargv, maxargs * sizeof *nargv);
2829                         }
2830
2831                         nargv[nargc++] = p;
2832                         p = next;
2833                         next = strtok(NULL, " \t\n");
2834                 }
2835
2836                 if(nargc == argc)
2837                         continue;
2838
2839                 if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit")) {
2840                         free(nargv);
2841                         return result;
2842                 }
2843
2844                 bool found = false;
2845
2846                 for(int i = 0; commands[i].command; i++) {
2847                         if(!strcasecmp(nargv[argc], commands[i].command)) {
2848                                 result |= commands[i].function(nargc - argc - 1, nargv + argc + 1);
2849                                 found = true;
2850                                 break;
2851                         }
2852                 }
2853
2854 #ifdef HAVE_READLINE
2855                 if(tty && found)
2856                         add_history(copy);
2857 #endif
2858
2859                 if(!found) {
2860                         fprintf(stderr, "Unknown command `%s'.\n", nargv[argc]);
2861                         result |= 1;
2862                 }
2863         }
2864
2865         free(nargv);
2866
2867         if(tty)
2868                 printf("\n");
2869         return result;
2870 }
2871
2872
2873 int main(int argc, char *argv[]) {
2874         program_name = argv[0];
2875         orig_argv = argv;
2876         orig_argc = argc;
2877         tty = isatty(0) && isatty(1);
2878
2879         if(!parse_options(argc, argv))
2880                 return 1;
2881
2882         make_names(false);
2883         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
2884         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
2885
2886         if(show_version) {
2887                 version();
2888                 return 0;
2889         }
2890
2891         if(show_help) {
2892                 usage(false);
2893                 return 0;
2894         }
2895
2896 #ifdef HAVE_MINGW
2897         static struct WSAData wsa_state;
2898
2899         if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
2900                 fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
2901                 return false;
2902         }
2903 #endif
2904
2905         srand(time(NULL));
2906         crypto_init();
2907
2908         if(optind >= argc)
2909                 return cmd_shell(argc, argv);
2910
2911         for(int i = 0; commands[i].command; i++) {
2912                 if(!strcasecmp(argv[optind], commands[i].command))
2913                         return commands[i].function(argc - optind, argv + optind);
2914         }
2915
2916         fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
2917         usage(true);
2918         return 1;
2919 }