- Various small fixes.
[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.32 2000/11/20 22:13:14 guus 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 <utils.h>
62 #include <xalloc.h>
63
64 #include "conf.h"
65 #include "net.h"
66 #include "netutl.h"
67 #include "process.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 extern int do_detach;
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 char **g_argv;                   /* a copy of the cmdline arguments */
94 char **environment;              /* A pointer to the environment on
95                                     startup */
96
97 void cleanup_and_exit(int);
98 int kill_other(void);
99 void make_names(void);
100 int write_pidfile(void);
101
102 static struct option const long_options[] =
103 {
104   { "config", required_argument, NULL, 'c' },
105   { "kill", no_argument, NULL, 'k' },
106   { "net", required_argument, NULL, 'n' },
107   { "help", no_argument, &show_help, 1 },
108   { "version", no_argument, &show_version, 1 },
109   { "no-detach", no_argument, &do_detach, 0 },
110   { "generate-keys", optional_argument, NULL, 'K'},
111   { NULL, 0, NULL, 0 }
112 };
113
114 static void
115 usage(int status)
116 {
117   if(status != 0)
118     fprintf(stderr, _("Try `%s --help\' for more information.\n"), program_name);
119   else
120     {
121       printf(_("Usage: %s [option]...\n\n"), program_name);
122       printf(_("  -c, --config=DIR           Read configuration options from DIR.\n"
123                "  -D, --no-detach            Don't fork and detach.\n"
124                "  -d                         Increase debug level.\n"
125                "  -k, --kill                 Attempt to kill a running tincd and exit.\n"
126                "  -n, --net=NETNAME          Connect to net NETNAME.\n"));
127       printf(_("  -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n"
128                "      --help                 Display this help and exit.\n"
129                "      --version              Output version information and exit.\n\n"));
130       printf(_("Report bugs to tinc@nl.linux.org.\n"));
131     }
132   exit(status);
133 }
134
135 void
136 parse_options(int argc, char **argv, char **envp)
137 {
138   int r;
139   int option_index = 0;
140   
141   while((r = getopt_long(argc, argv, "c:Ddkn:K::", long_options, &option_index)) != EOF)
142     {
143       switch(r)
144         {
145         case 0: /* long option */
146           break;
147         case 'c': /* config file */
148           confbase = xmalloc(strlen(optarg)+1);
149           strcpy(confbase, optarg);
150           break;
151         case 'D': /* no detach */
152           do_detach = 0;
153           break;
154         case 'd': /* inc debug level */
155           debug_lvl++;
156           break;
157         case 'k': /* kill old tincds */
158           kill_tincd = 1;
159           break;
160         case 'n': /* net name given */
161           netname = xmalloc(strlen(optarg)+1);
162           strcpy(netname, optarg);
163           break;
164         case 'K': /* generate public/private keypair */
165           if(optarg)
166             {
167               generate_keys = atoi(optarg);
168               if(generate_keys < 512)
169                 {
170                   fprintf(stderr, _("Invalid argument! BITS must be a number equal to or greater than 512.\n"));
171                   usage(1);
172                 }
173               generate_keys &= ~7;      /* Round it to bytes */
174             }
175           else
176             generate_keys = 1024;
177           break;
178         case '?':
179           usage(1);
180         default:
181           break;
182         }
183     }
184 }
185
186 /* This function prettyprints the key generation process */
187
188 void indicator(int a, int b, void *p)
189 {
190   switch(a)
191   {
192     case 0:
193       fprintf(stderr, ".");
194       break;
195     case 1:
196       fprintf(stderr, "+");
197       break;
198     case 2:
199       fprintf(stderr, "-");
200       break;
201     case 3:
202       switch(b)
203         {
204           case 0:
205             fprintf(stderr, " p\n");      
206             break;
207           case 1:
208             fprintf(stderr, " q\n");
209             break;
210           default:
211             fprintf(stderr, "?");
212          }
213        break;
214     default:
215       fprintf(stderr, "?");
216   }
217 }
218
219 /* Generate a public/private RSA keypair, and possibly store it into the configuration file. */
220
221 int keygen(int bits)
222 {
223   RSA *rsa_key;
224
225   fprintf(stderr, _("Generating %d bits keys:\n"), bits);
226   rsa_key = RSA_generate_key(bits, 0xFFFF, indicator, NULL);
227   if(!rsa_key)
228     {
229       fprintf(stderr, _("Error during key generation!"));
230       return -1;
231      }
232   else
233     fprintf(stderr, _("Done.\n"));
234
235   fprintf(stderr, _("Please copy the private key to tinc.conf and the\npublic key to your host configuration file:\n\n"));
236   printf("PublicKey = %s\n", BN_bn2hex(rsa_key->n));
237   printf("PrivateKey = %s\n", BN_bn2hex(rsa_key->d));
238   
239   fflush(stdin);
240   return 0;
241 }
242
243 /*
244   Set all files and paths according to netname
245 */
246 void make_names(void)
247 {
248   if(netname)
249     {
250       if(!pidfilename)
251         asprintf(&pidfilename, "/var/run/tinc.%s.pid", netname);
252       if(!confbase)
253         asprintf(&confbase, "%s/tinc/%s", CONFDIR, netname);
254       else
255         fprintf(stderr, _("Both netname and configuration directory given, using the latter...\n"));
256       if(!identname)
257         asprintf(&identname, "tinc.%s", netname);
258     }
259   else
260     {
261       if(!pidfilename)
262         pidfilename = "/var/run/tinc.pid";
263       if(!confbase)
264         asprintf(&confbase, "%s/tinc", CONFDIR);
265       if(!identname)
266         identname = "tinc";
267     }
268 }
269
270 int
271 main(int argc, char **argv, char **envp)
272 {
273   program_name = argv[0];
274
275   setlocale (LC_ALL, "");
276   bindtextdomain (PACKAGE, LOCALEDIR);
277   textdomain (PACKAGE);
278
279   /* Do some intl stuff right now */
280   
281   unknown = _("unknown");
282
283   environment = envp;
284   parse_options(argc, argv, envp);
285
286   if(show_version)
287     {
288       printf(_("%s version %s (built %s %s, protocol %d)\n"), PACKAGE, VERSION, __DATE__, __TIME__, PROT_CURRENT);
289       printf(_("Copyright (C) 1998,1999,2000 Ivo Timmermans, Guus Sliepen and others.\n"
290                "See the AUTHORS file for a complete list.\n\n"
291                "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
292                "and you are welcome to redistribute it under certain conditions;\n"
293                "see the file COPYING for details.\n"));
294
295       return 0;
296     }
297
298   if(show_help)
299     usage(0);
300
301   if(geteuid())
302     {
303       fprintf(stderr, _("You must be root to run this program. Sorry.\n"));
304       return 1;
305     }
306
307   g_argv = argv;
308
309   make_names();
310
311   /* Slllluuuuuuurrrrp! */
312
313   RAND_load_file("/dev/urandom", 1024);
314
315   if(generate_keys)
316     exit(keygen(generate_keys));
317
318   if(kill_tincd)
319     exit(kill_other());
320
321   if(read_server_config())
322     return 1;
323
324   init_processes();
325
326   if(detach())
327     exit(0);
328
329   if(debug_lvl >= DEBUG_ERROR)
330     ERR_load_crypto_strings();
331     
332   for(;;)
333     {
334       if(!setup_network_connections())
335         {
336           main_loop();
337           cleanup_and_exit(1);
338         }
339       
340       syslog(LOG_ERR, _("Unrecoverable error"));
341       cp_trace();
342
343       if(do_detach)
344         {
345           syslog(LOG_NOTICE, _("Restarting in %d seconds!"), MAXTIMEOUT);
346           sleep(MAXTIMEOUT);
347         }
348       else
349         {
350           syslog(LOG_ERR, _("Not restarting."));
351           exit(0);
352         }
353     }
354 }
355