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