4e766a8c255440d72af57492f8cf1ba7d63d537d
[tinc] / src / tincd.c
1 /*
2     tincd.c -- the main file for tincd
3     Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>
4                   2000-2002 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.14 2002/04/13 11:07:12 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 <unistd.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <termios.h>
35
36 #ifdef HAVE_SYS_IOCTL_H
37 # include <sys/ioctl.h>
38 #endif
39
40 #include <openssl/rand.h>
41 #include <openssl/rsa.h>
42 #include <openssl/pem.h>
43 #include <openssl/evp.h>
44
45 #include <utils.h>
46 #include <xalloc.h>
47
48 #include "conf.h"
49 #include "net.h"
50 #include "netutl.h"
51 #include "process.h"
52 #include "protocol.h"
53 #include "subnet.h"
54 #include "logging.h"
55
56 #include "system.h"
57
58 /* The name this program was run with. */
59 char *program_name;
60
61 /* If nonzero, display usage information and exit. */
62 int show_help;
63
64 /* If nonzero, print the version on standard output and exit.  */
65 int show_version;
66
67 /* If nonzero, it will attempt to kill a running tincd and exit. */
68 int kill_tincd = 0;
69
70 /* If nonzero, generate public/private keypair for this host/net. */
71 int generate_keys = 0;
72
73 /* If nonzero, use null ciphers and skip all key exchanges. */
74 int bypass_security = 0;
75
76 char *identname;                 /* program name for syslog */
77 char *pidfilename;               /* pid file location */
78 char **g_argv;                   /* a copy of the cmdline arguments */
79 char **environment;              /* A pointer to the environment on
80                                     startup */
81
82 static struct option const long_options[] =
83 {
84   { "config", required_argument, NULL, 'c' },
85   { "kill", optional_argument, NULL, 'k' },
86   { "net", required_argument, NULL, 'n' },
87   { "help", no_argument, &show_help, 1 },
88   { "version", no_argument, &show_version, 1 },
89   { "no-detach", no_argument, &do_detach, 0 },
90   { "generate-keys", optional_argument, NULL, 'K'},
91   { "debug", optional_argument, NULL, 'd'},
92   { "bypass-security", no_argument, &bypass_security, 1 },
93   { NULL, 0, NULL, 0 }
94 };
95
96 static void
97 usage(int status)
98 {
99   if(status != 0)
100     fprintf(stderr, _("Try `%s --help\' for more information.\n"), program_name);
101   else
102     {
103       printf(_("Usage: %s [option]...\n\n"), program_name);
104       printf(_("  -c, --config=DIR           Read configuration options from DIR.\n"
105                "  -D, --no-detach            Don't fork and detach.\n"
106                "  -d, --debug[=LEVEL]        Increase debug level or set it to LEVEL.\n"
107                "  -k, --kill[=SIGNAL]        Attempt to kill a running tincd and exit.\n"
108                "  -n, --net=NETNAME          Connect to net NETNAME.\n"));
109       printf(_("  -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n"
110                "      --help                 Display this help and exit.\n"
111                "      --version              Output version information and exit.\n\n"));
112       printf(_("Report bugs to tinc@nl.linux.org.\n"));
113     }
114   exit(status);
115 }
116
117 void
118 parse_options(int argc, char **argv, char **envp)
119 {
120   int r;
121   int option_index = 0;
122
123   while((r = getopt_long(argc, argv, "c:Dd::k::n:K::", long_options, &option_index)) != EOF)
124     {
125       switch(r)
126         {
127         case 0: /* long option */
128           break;
129         case 'c': /* config file */
130           confbase = xmalloc(strlen(optarg)+1);
131           strcpy(confbase, optarg);
132           break;
133         case 'D': /* no detach */
134           do_detach = 0;
135           break;
136         case 'd': /* inc debug level */
137           if(optarg)
138             debug_lvl = atoi(optarg);
139           else
140             debug_lvl++;
141           break;
142         case 'k': /* kill old tincds */
143           if(optarg)
144             {
145               if(!strcasecmp(optarg, "HUP"))
146                 kill_tincd = SIGHUP;
147               else if(!strcasecmp(optarg, "TERM"))
148                 kill_tincd = SIGTERM;
149               else if(!strcasecmp(optarg, "KILL"))
150                 kill_tincd = SIGKILL;
151               else if(!strcasecmp(optarg, "USR1"))
152                 kill_tincd = SIGUSR1;
153               else if(!strcasecmp(optarg, "USR2"))
154                 kill_tincd = SIGUSR2;
155               else if(!strcasecmp(optarg, "WINCH"))
156                 kill_tincd = SIGWINCH;
157               else if(!strcasecmp(optarg, "INT"))
158                 kill_tincd = SIGINT;
159               else if(!strcasecmp(optarg, "ALRM"))
160                 kill_tincd = SIGALRM;
161               else
162                 {
163                   kill_tincd = atoi(optarg);
164                   if(!kill_tincd)
165                     {
166                       fprintf(stderr, _("Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n"), optarg);
167                       usage(1);
168                     }
169                 }
170             }
171           else
172             kill_tincd = SIGTERM;
173           break;
174         case 'n': /* net name given */
175           netname = xmalloc(strlen(optarg)+1);
176           strcpy(netname, optarg);
177           break;
178         case 'K': /* generate public/private keypair */
179           if(optarg)
180             {
181               generate_keys = atoi(optarg);
182               if(generate_keys < 512)
183                 {
184                   fprintf(stderr, _("Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n"),
185                           optarg);
186                   usage(1);
187                 }
188               generate_keys &= ~7;      /* Round it to bytes */
189             }
190           else
191             generate_keys = 1024;
192           break;
193         case '?':
194           usage(1);
195         default:
196           break;
197         }
198     }
199 }
200
201 /* This function prettyprints the key generation process */
202
203 void indicator(int a, int b, void *p)
204 {
205   switch(a)
206   {
207     case 0:
208       fprintf(stderr, ".");
209       break;
210     case 1:
211       fprintf(stderr, "+");
212       break;
213     case 2:
214       fprintf(stderr, "-");
215       break;
216     case 3:
217       switch(b)
218         {
219           case 0:
220             fprintf(stderr, " p\n");
221             break;
222           case 1:
223             fprintf(stderr, " q\n");
224             break;
225           default:
226             fprintf(stderr, "?");
227          }
228        break;
229     default:
230       fprintf(stderr, "?");
231   }
232 }
233
234 /*
235   Generate a public/private RSA keypair, and ask for a file to store
236   them in.
237 */
238 int keygen(int bits)
239 {
240   RSA *rsa_key;
241   FILE *f;
242   char *name = NULL;
243   char *filename;
244
245   fprintf(stderr, _("Generating %d bits keys:\n"), bits);
246   rsa_key = RSA_generate_key(bits, 0xFFFF, indicator, NULL);
247
248   if(!rsa_key)
249     {
250       fprintf(stderr, _("Error during key generation!\n"));
251       return -1;
252     }
253   else
254     fprintf(stderr, _("Done.\n"));
255
256   get_config_string(lookup_config(config_tree, "Name"), &name);
257
258   if(name)
259     asprintf(&filename, "%s/hosts/%s", confbase, name);
260   else
261     asprintf(&filename, "%s/rsa_key.pub", confbase);
262
263   if((f = ask_and_safe_open(filename, _("public RSA key"), "a")) == NULL)
264     return -1;
265
266   if(ftell(f))
267     fprintf(stderr, _("Appending key to existing contents.\nMake sure only one key is stored in the file.\n"));
268
269   PEM_write_RSAPublicKey(f, rsa_key);
270   fclose(f);
271   free(filename);
272
273   asprintf(&filename, "%s/rsa_key.priv", confbase);
274   if((f = ask_and_safe_open(filename, _("private RSA key"), "a")) == NULL)
275     return -1;
276
277   if(ftell(f))
278     fprintf(stderr, _("Appending key to existing contents.\nMake sure only one key is stored in the file.\n"));
279
280   PEM_write_RSAPrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL);
281   fclose(f);
282   free(filename);
283
284   return 0;
285 }
286
287 /*
288   Set all files and paths according to netname
289 */
290 void make_names(void)
291 {
292   if(netname)
293     {
294       if(!pidfilename)
295         asprintf(&pidfilename, LOCALSTATEDIR "/run/tinc.%s.pid", netname);
296       if(!confbase)
297         asprintf(&confbase, "%s/tinc/%s", CONFDIR, netname);
298       else
299         log(0, TLOG_INFO, _("Both netname and configuration directory given, using the latter..."));
300       if(!identname)
301         asprintf(&identname, "tinc.%s", netname);
302     }
303   else
304     {
305       if(!pidfilename)
306         pidfilename = LOCALSTATEDIR "/run/tinc.pid";
307       if(!confbase)
308         asprintf(&confbase, "%s/tinc", CONFDIR);
309       if(!identname)
310         identname = "tinc";
311     }
312 }
313
314 int
315 main(int argc, char **argv, char **envp)
316 {
317   program_name = argv[0];
318
319   setlocale (LC_ALL, "");
320   bindtextdomain (PACKAGE, LOCALEDIR);
321   textdomain (PACKAGE);
322
323   environment = envp;
324   parse_options(argc, argv, envp);
325
326   if(show_version)
327     {
328       printf(_("%s version %s (built %s %s, protocol %d)\n"), PACKAGE, VERSION, __DATE__, __TIME__, PROT_CURRENT);
329       printf(_("Copyright (C) 1998-2002 Ivo Timmermans, Guus Sliepen and others.\n"
330                "See the AUTHORS file for a complete list.\n\n"
331                "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
332                "and you are welcome to redistribute it under certain conditions;\n"
333                "see the file COPYING for details.\n"));
334
335       return 0;
336     }
337
338   if(show_help)
339     usage(0);
340
341   log_add_hook(log_default);
342
343   g_argv = argv;
344
345   make_names();
346   init_configuration(&config_tree);
347
348   /* Slllluuuuuuurrrrp! */
349 cp
350   RAND_load_file("/dev/urandom", 1024);
351
352 #ifdef HAVE_SSLEAY_ADD_ALL_ALGORITHMS
353   SSLeay_add_all_algorithms();
354 #else
355   OpenSSL_add_all_algorithms();
356 #endif
357
358 cp
359   if(generate_keys)
360     {
361       read_server_config();
362       exit(keygen(generate_keys));
363     }
364
365   if(kill_tincd)
366     exit(kill_other(kill_tincd));
367
368   if(read_server_config())
369     exit(1);
370 cp
371   if(detach())
372     exit(0);
373 cp
374   for(;;)
375     {
376       if(!setup_network_connections())
377         {
378           main_loop();
379           cleanup_and_exit(1);
380         }
381
382       log(0, TLOG_ERROR, _("Unrecoverable error"));
383       cp_trace();
384
385       if(do_detach)
386         {
387           log(0, TLOG_NOTICE, _("Restarting in %d seconds!"), maxtimeout);
388           sleep(maxtimeout);
389         }
390       else
391         {
392           log(0, TLOG_ERROR, _("Not restarting."));
393           exit(1);
394         }
395     }
396 }