9c337f88cf9f438255a561dd07c4478f39e53692
[tinc] / src / tincd.c
1 /*
2     tincd.c -- the main file for tincd
3     Copyright (C) 1998,1999,2000 Ivo Timmermans <itimmermans@bigfoot.com>
4                             2000 Guus Sliepen <guus@sliepen.warande.net>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: tincd.c,v 1.10.4.28 2000/11/15 01:06:13 zarq Exp $
21 */
22
23 #include "config.h"
24
25 #include <errno.h>
26 #include <fcntl.h> 
27 #include <getopt.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <syslog.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #include <string.h>
35 #include <termios.h>
36
37 #ifdef HAVE_SYS_IOCTL_H
38 # include <sys/ioctl.h>
39 #endif
40
41 #ifdef HAVE_OPENSSL_RAND_H
42 # include <openssl/rand.h>
43 #else
44 # include <rand.h>
45 #endif
46
47 #ifdef HAVE_OPENSSL_RSA_H
48 # include <openssl/rsa.h>
49 #else
50 # include <rsa.h>
51 #endif
52
53 #ifdef HAVE_OPENSSL_ERR_H
54 # include <openssl/err.h>
55 #else
56 # include <err.h>
57 #endif
58
59
60
61 #include <pidfile.h>
62 #include <utils.h>
63 #include <xalloc.h>
64
65 #include "conf.h"
66 #include "net.h"
67 #include "netutl.h"
68 #include "protocol.h"
69 #include "subnet.h"
70
71 #include "system.h"
72
73 /* The name this program was run with. */
74 char *program_name;
75
76 /* If nonzero, display usage information and exit. */
77 static int show_help;
78
79 /* If nonzero, print the version on standard output and exit.  */
80 static int show_version;
81
82 /* If nonzero, it will attempt to kill a running tincd and exit. */
83 static int kill_tincd = 0;
84
85 /* If zero, don't detach from the terminal. */
86 static int do_detach = 1;
87
88 /* If nonzero, generate public/private keypair for this host/net. */
89 static int generate_keys = 0;
90
91 char *identname;                 /* program name for syslog */
92 char *pidfilename;               /* pid file location */
93 static pid_t ppid;               /* pid of non-detached part */
94 char **g_argv;                   /* a copy of the cmdline arguments */
95 char **environment;              /* A pointer to the environment on
96                                     startup */
97
98 void cleanup_and_exit(int);
99 int detach(void);
100 int kill_other(void);
101 void make_names(void);
102 RETSIGTYPE parent_exit(int a);
103 void setup_signals(void);
104 int write_pidfile(void);
105
106 static struct option const long_options[] =
107 {
108   { "config", required_argument, NULL, 'c' },
109   { "kill", no_argument, NULL, 'k' },
110   { "net", required_argument, NULL, 'n' },
111   { "help", no_argument, &show_help, 1 },
112   { "version", no_argument, &show_version, 1 },
113   { "no-detach", no_argument, &do_detach, 0 },
114   { "generate-keys", optional_argument, NULL, 'K'},
115   { NULL, 0, NULL, 0 }
116 };
117
118 static void
119 usage(int status)
120 {
121   if(status != 0)
122     fprintf(stderr, _("Try `%s --help\' for more information.\n"), program_name);
123   else
124     {
125       printf(_("Usage: %s [option]...\n\n"), program_name);
126       printf(_("  -c, --config=DIR           Read configuration options from DIR.\n"
127                "  -D, --no-detach            Don't fork and detach.\n"
128                "  -d                         Increase debug level.\n"
129                "  -k, --kill                 Attempt to kill a running tincd and exit.\n"
130                "  -n, --net=NETNAME          Connect to net NETNAME.\n"));
131       printf(_("  -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n"
132                "      --help                 Display this help and exit.\n"
133                "      --version              Output version information and exit.\n\n"));
134       printf(_("Report bugs to tinc@nl.linux.org.\n"));
135     }
136   exit(status);
137 }
138
139 void
140 parse_options(int argc, char **argv, char **envp)
141 {
142   int r;
143   int option_index = 0;
144   
145   while((r = getopt_long(argc, argv, "c:Ddkn:K::", long_options, &option_index)) != EOF)
146     {
147       switch(r)
148         {
149         case 0: /* long option */
150           break;
151         case 'c': /* config file */
152           confbase = xmalloc(strlen(optarg)+1);
153           strcpy(confbase, optarg);
154           break;
155         case 'D': /* no detach */
156           do_detach = 0;
157           break;
158         case 'd': /* inc debug level */
159           debug_lvl++;
160           break;
161         case 'k': /* kill old tincds */
162           kill_tincd = 1;
163           break;
164         case 'n': /* net name given */
165           netname = xmalloc(strlen(optarg)+1);
166           strcpy(netname, optarg);
167           break;
168         case 'K': /* generate public/private keypair */
169           if(optarg)
170             {
171               generate_keys = atoi(optarg);
172               if(generate_keys < 512)
173                 {
174                   fprintf(stderr, _("Invalid argument! BITS must be a number equal to or greater than 512.\n"));
175                   usage(1);
176                 }
177               generate_keys &= ~7;      /* Round it to bytes */
178             }
179           else
180             generate_keys = 1024;
181           break;
182         case '?':
183           usage(1);
184         default:
185           break;
186         }
187     }
188 }
189
190 /* This function prettyprints the key generation process */
191
192 void indicator(int a, int b, void *p)
193 {
194   switch(a)
195   {
196     case 0:
197       fprintf(stderr, ".");
198       break;
199     case 1:
200       fprintf(stderr, "+");
201       break;
202     case 2:
203       fprintf(stderr, "-");
204       break;
205     case 3:
206       switch(b)
207         {
208           case 0:
209             fprintf(stderr, " p\n");      
210             break;
211           case 1:
212             fprintf(stderr, " q\n");
213             break;
214           default:
215             fprintf(stderr, "?");
216          }
217        break;
218     default:
219       fprintf(stderr, "?");
220   }
221 }
222
223 /* Generate a public/private RSA keypair, and possibly store it into the configuration file. */
224
225 int keygen(int bits)
226 {
227   RSA *rsa_key;
228
229   fprintf(stderr, _("Generating %d bits keys:\n"), bits);
230   rsa_key = RSA_generate_key(bits, 0xFFFF, indicator, NULL);
231   if(!rsa_key)
232     {
233       fprintf(stderr, _("Error during key generation!"));
234       return -1;
235      }
236   else
237     fprintf(stderr, _("Done.\n"));
238
239   fprintf(stderr, _("Please copy the private key to tinc.conf and the\npublic key to your host configuration file:\n\n"));
240   printf("PublicKey = %s\n", BN_bn2hex(rsa_key->n));
241   printf("PrivateKey = %s\n", BN_bn2hex(rsa_key->d));
242   
243   fflush(stdin);
244   return 0;
245 }
246
247 void memory_full(int size)
248 {
249   syslog(LOG_ERR, _("Memory exhausted (couldn't allocate %d bytes), exiting."), size);
250   cp_trace();
251   exit(1);
252 }
253
254 /*
255   Detach from current terminal, write pidfile, kill parent
256 */
257 int detach(void)
258 {
259   int fd;
260   pid_t pid;
261
262   if(do_detach)
263     {
264       ppid = getpid();
265
266       if((pid = fork()) < 0)
267         {
268           perror("fork");
269           return -1;
270         }
271       if(pid) /* parent process */
272         {
273           signal(SIGTERM, parent_exit);
274           sleep(600); /* wait 10 minutes */
275           exit(1);
276         }
277     }
278   
279   if(write_pidfile())
280     return -1;
281
282   if(do_detach)
283     {
284       if((fd = open("/dev/tty", O_RDWR)) >= 0)
285         {
286           if(ioctl(fd, TIOCNOTTY, NULL))
287             {
288               perror("ioctl");
289               return -1;
290             }
291           close(fd);
292         }
293
294       if(setsid() < 0)
295         return -1;
296
297       kill(ppid, SIGTERM);
298     }
299   
300   chdir("/"); /* avoid keeping a mointpoint busy */
301
302   openlog(identname, LOG_CONS | LOG_PID, LOG_DAEMON);
303
304   if(debug_lvl > DEBUG_NOTHING)
305     syslog(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"),
306            VERSION, __DATE__, __TIME__, debug_lvl);
307   else
308     syslog(LOG_NOTICE, _("tincd %s starting"), VERSION);
309
310   xalloc_fail_func = memory_full;
311
312   return 0;
313 }
314
315 /*
316   Close network connections, and terminate neatly
317 */
318 void cleanup_and_exit(int c)
319 {
320   close_network_connections();
321
322   if(debug_lvl > DEBUG_NOTHING)
323     syslog(LOG_INFO, _("Total bytes written: tap %d, socket %d; bytes read: tap %d, socket %d"),
324            total_tap_out, total_socket_out, total_tap_in, total_socket_in);
325
326   closelog();
327   kill(ppid, SIGTERM);
328   exit(c);
329 }
330
331 /*
332   check for an existing tinc for this net, and write pid to pidfile
333 */
334 int write_pidfile(void)
335 {
336   int pid;
337
338   if((pid = check_pid(pidfilename)))
339     {
340       if(netname)
341         fprintf(stderr, _("A tincd is already running for net `%s' with pid %d.\n"),
342                 netname, pid);
343       else
344         fprintf(stderr, _("A tincd is already running with pid %d.\n"), pid);
345       return 1;
346     }
347
348   /* if it's locked, write-protected, or whatever */
349   if(!write_pid(pidfilename))
350     return 1;
351
352   return 0;
353 }
354
355 /*
356   kill older tincd for this net
357 */
358 int kill_other(void)
359 {
360   int pid;
361
362   if(!(pid = read_pid(pidfilename)))
363     {
364       if(netname)
365         fprintf(stderr, _("No other tincd is running for net `%s'.\n"), netname);
366       else
367         fprintf(stderr, _("No other tincd is running.\n"));
368       return 1;
369     }
370
371   errno = 0;    /* No error, sometimes errno is only changed on error */
372   /* ESRCH is returned when no process with that pid is found */
373   if(kill(pid, SIGTERM) && errno == ESRCH)
374     fprintf(stderr, _("Removing stale lock file.\n"));
375   remove_pid(pidfilename);
376
377   return 0;
378 }
379
380 /*
381   Set all files and paths according to netname
382 */
383 void make_names(void)
384 {
385   if(netname)
386     {
387       if(!pidfilename)
388         asprintf(&pidfilename, "/var/run/tinc.%s.pid", netname);
389       if(!confbase)
390         asprintf(&confbase, "%s/tinc/%s", CONFDIR, netname);
391       else
392         fprintf(stderr, _("Both netname and configuration directory given, using the latter...\n"));
393       if(!identname)
394         asprintf(&identname, "tinc.%s", netname);
395     }
396   else
397     {
398       if(!pidfilename)
399         pidfilename = "/var/run/tinc.pid";
400       if(!confbase)
401         asprintf(&confbase, "%s/tinc", CONFDIR);
402       if(!identname)
403         identname = "tinc";
404     }
405 }
406
407 int
408 main(int argc, char **argv, char **envp)
409 {
410   program_name = argv[0];
411
412   setlocale (LC_ALL, "");
413   bindtextdomain (PACKAGE, LOCALEDIR);
414   textdomain (PACKAGE);
415
416   /* Do some intl stuff right now */
417   
418   unknown = _("unknown");
419
420   environment = envp;
421   parse_options(argc, argv, envp);
422
423   if(show_version)
424     {
425       printf(_("%s version %s (built %s %s, protocol %d)\n"), PACKAGE, VERSION, __DATE__, __TIME__, PROT_CURRENT);
426       printf(_("Copyright (C) 1998,1999,2000 Ivo Timmermans, Guus Sliepen and others.\n"
427                "See the AUTHORS file for a complete list.\n\n"
428                "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
429                "and you are welcome to redistribute it under certain conditions;\n"
430                "see the file COPYING for details.\n"));
431
432       return 0;
433     }
434
435   if(show_help)
436     usage(0);
437
438   if(geteuid())
439     {
440       fprintf(stderr, _("You must be root to run this program. Sorry.\n"));
441       return 1;
442     }
443
444   g_argv = argv;
445
446   make_names();
447
448   /* Slllluuuuuuurrrrp! */
449
450   RAND_load_file("/dev/urandom", 1024);
451
452   if(generate_keys)
453     exit(keygen(generate_keys));
454
455   if(kill_tincd)
456     exit(kill_other());
457
458   if(read_server_config())
459     return 1;
460
461   setup_signals();
462
463   if(detach())
464     exit(0);
465
466   if(debug_lvl >= DEBUG_ERROR)
467     ERR_load_crypto_strings();
468     
469   for(;;)
470     {
471       if(!setup_network_connections())
472         {
473           main_loop();
474           cleanup_and_exit(1);
475         }
476       
477       syslog(LOG_ERR, _("Unrecoverable error"));
478       cp_trace();
479
480       if(do_detach)
481         {
482           syslog(LOG_NOTICE, _("Restarting in %d seconds!"), MAXTIMEOUT);
483           sleep(MAXTIMEOUT);
484         }
485       else
486         {
487           syslog(LOG_ERR, _("Not restarting."));
488           exit(0);
489         }
490     }
491 }
492
493 RETSIGTYPE
494 sigterm_handler(int a)
495 {
496   if(debug_lvl > DEBUG_NOTHING)
497     syslog(LOG_NOTICE, _("Got TERM signal"));
498
499   cleanup_and_exit(0);
500 }
501
502 RETSIGTYPE
503 sigquit_handler(int a)
504 {
505   if(debug_lvl > DEBUG_NOTHING)
506     syslog(LOG_NOTICE, _("Got QUIT signal"));
507   cleanup_and_exit(0);
508 }
509
510 RETSIGTYPE
511 sigsegv_square(int a)
512 {
513   syslog(LOG_ERR, _("Got another SEGV signal: not restarting"));
514   exit(0);
515 }
516
517 RETSIGTYPE
518 sigsegv_handler(int a)
519 {
520   syslog(LOG_ERR, _("Got SEGV signal"));
521   cp_trace();
522
523   if(do_detach)
524     {
525       syslog(LOG_NOTICE, _("Trying to re-execute in 5 seconds..."));
526       signal(SIGSEGV, sigsegv_square);
527       close_network_connections();
528       sleep(5);
529       remove_pid(pidfilename);
530       execvp(g_argv[0], g_argv);
531     }
532   else
533     {
534       syslog(LOG_NOTICE, _("Not restarting."));
535       exit(0);
536     }
537 }
538
539 RETSIGTYPE
540 sighup_handler(int a)
541 {
542   if(debug_lvl > DEBUG_NOTHING)
543     syslog(LOG_NOTICE, _("Got HUP signal"));
544   sighup = 1;
545 }
546
547 RETSIGTYPE
548 sigint_handler(int a)
549 {
550   if(debug_lvl > DEBUG_NOTHING)
551     syslog(LOG_NOTICE, _("Got INT signal, exiting"));
552   cleanup_and_exit(0);
553 }
554
555 RETSIGTYPE
556 sigusr1_handler(int a)
557 {
558   dump_conn_list();
559 }
560
561 RETSIGTYPE
562 sigusr2_handler(int a)
563 {
564   dump_subnet_list();
565 }
566
567 RETSIGTYPE
568 sighuh(int a)
569 {
570   syslog(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
571   cp_trace();
572 }
573
574 void
575 setup_signals(void)
576 {
577   int i;
578
579   for(i=0;i<32;i++)
580     signal(i,sighuh);
581
582   if(signal(SIGTERM, SIG_IGN) != SIG_ERR)
583     signal(SIGTERM, sigterm_handler);
584   if(signal(SIGQUIT, SIG_IGN) != SIG_ERR)
585     signal(SIGQUIT, sigquit_handler);
586   if(signal(SIGSEGV, SIG_IGN) != SIG_ERR)
587     signal(SIGSEGV, sigsegv_handler);
588   if(signal(SIGHUP, SIG_IGN) != SIG_ERR)
589     signal(SIGHUP, sighup_handler);
590   signal(SIGPIPE, SIG_IGN);
591   if(signal(SIGINT, SIG_IGN) != SIG_ERR)
592     signal(SIGINT, sigint_handler);
593   signal(SIGUSR1, sigusr1_handler);
594   signal(SIGUSR2, sigusr2_handler);
595   signal(SIGCHLD, SIG_IGN);
596 }
597
598 RETSIGTYPE parent_exit(int a)
599 {
600   exit(0);
601 }