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