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