Added signals suppor to shceduler.
[silc.git] / apps / silcd / silcd.c
1 /*
2
3   silcd.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * Created: Wed Mar 19 00:17:12 1997
22  *
23  * This is the main program for the SILC daemon. This parses command
24  * line arguments and creates the server object.
25  */
26 /* $Id$ */
27
28 #include "serverincludes.h"
29 #include "server_internal.h"
30 #include "silcversion.h"
31
32 /* For now, we'll have this one server context global for this module. */
33 static SilcServer silcd;
34
35 static void silc_usage();
36 static char *silc_server_create_identifier();
37 static int
38 silc_server_create_key_pair(char *pkcs_name, int bits, char *path,
39                             char *identifier,
40                             SilcPublicKey *ret_pub_key,
41                             SilcPrivateKey *ret_prv_key);
42
43 /* Long command line options */
44 static struct option long_opts[] =
45 {
46   { "config-file", 1, NULL, 'f' },
47   { "debug", 1, NULL, 'd' },
48   { "help", 0, NULL, 'h' },
49   { "foreground", 0, NULL, 'F' },
50   { "version", 0, NULL,'V' },
51
52   /* Key management options */
53   { "create-key-pair", 1, NULL, 'C' },
54   { "pkcs", 1, NULL, 10 },
55   { "bits", 1, NULL, 11 },
56   { "identifier", 1, NULL, 12 },
57
58   { NULL, 0, NULL, 0 }
59 };
60
61 /* Command line option variables */
62 static bool opt_create_keypair = FALSE;
63 static char *opt_keypath = NULL;
64 static char *opt_pkcs = "rsa";
65 static char *opt_identifier = NULL;
66 static int opt_bits = 1024;
67
68 /* Prints out the usage of silc client */
69
70 static void silc_usage()
71 {
72   printf("\
73 Usage: silcd [options]\n\
74 \n\
75   Generic Options:\n\
76   -f  --config-file=FILE        Alternate configuration file\n\
77   -d  --debug=string            Enable debugging (Implies --foreground)\n\
78   -h  --help                    Display this message\n\
79   -F  --foreground              Dont fork\n\
80   -V  --version                 Display version\n\
81 \n\
82   Key Management Options:\n\
83   -C, --create-key-pair=PATH    Create new public key pair\n\
84       --pkcs=PKCS               Set the PKCS of the public key pair\n\
85       --bits=VALUE              Set length of the public key pair\n\
86       --identifier=IDENTIFIER   Public key identifier\n\
87 \n\
88       The public key identifier may be of the following format:\n\
89 \n\
90       UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n\
91       O=<organization>, C=<country>\n\
92 \n\
93       The UN and HN must be provided, the others are optional.  If the\n\
94       --identifier option is not used an identifier will be created for\n\
95       the public key automatically.\n\
96 \n\
97       Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n\
98                            E=foo@bar.com, C=FI\"\n\
99 \n");
100   exit(0);
101 }
102
103 /* Dies if a *valid* pid file exists already */
104
105 static void silc_server_checkpid(SilcServer silcd)
106 {
107   if (silcd->config->server_info->pid_file) {
108     int oldpid;
109     char *buf;
110     SilcUInt32 buf_len;
111
112     SILC_LOG_DEBUG(("Checking for another silcd running"));
113     buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
114     if (!buf)
115       return;
116     oldpid = atoi(buf);
117     silc_free(buf);
118     if (oldpid <= 0)
119       return;
120     kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */
121     if (errno != ESRCH) {
122       fprintf(stderr, "\nI detected another daemon running with the same pid file.\n");
123       fprintf(stderr, "Please change the config file, or erase the %s\n",
124         silcd->config->server_info->pid_file);
125       exit(1);
126     }
127   }
128 }
129
130 static void got_hup(int z)
131 {
132   /* First, reset all log files (they might have been deleted) */
133   silc_log_reset_all();
134   silc_log_flush_all();
135 }
136
137 static void stop_server(int z)
138 {
139   /* Stop scheduler, the program will stop eventually after noticing
140      that the scheduler is down. */
141   silc_schedule_stop(silcd->schedule); 
142 }
143
144 int main(int argc, char **argv)
145 {
146   int ret, opt, option_index;
147   char *config_file = NULL;
148   bool foreground = FALSE;
149   struct sigaction sa;
150
151   /* Parse command line arguments */
152   if (argc > 1) {
153     while ((opt = getopt_long(argc, argv, "cf:d:hFVC:",
154                               long_opts, &option_index)) != EOF) {
155       switch(opt)
156         {
157         case 'h':
158           silc_usage();
159           break;
160         case 'V':
161           printf("SILCd Secure Internet Live Conferencing daemon, "
162                  "version %s (base: SILC Toolkit %s)\n",
163                  silc_dist_version, silc_version);
164           printf("(c) 1997 - 2002 Pekka Riikonen "
165                  "<priikone@silcnet.org>\n");
166           exit(0);
167           break;
168         case 'd':
169 #ifdef SILC_DEBUG
170           silc_debug = TRUE;
171           silc_debug_hexdump = TRUE;
172           silc_log_set_debug_string(optarg);
173           foreground = TRUE;
174           silc_log_quick = TRUE;
175 #else
176           fprintf(stdout,
177                   "Run-time debugging is not enabled. To enable it recompile\n"
178                   "the server with --enable-debug configuration option.\n");
179 #endif
180           break;
181         case 'f':
182           config_file = strdup(optarg);
183           break;
184         case 'F':
185           foreground = TRUE;
186           break;
187
188           /*
189            * Key management options
190            */
191         case 'C':
192           opt_create_keypair = TRUE;
193           if (optarg)
194             opt_keypath = strdup(optarg);
195           break;
196         case 10:
197           if (optarg)
198             opt_pkcs = strdup(optarg);
199           break;
200         case 11:
201           if (optarg)
202             opt_bits = atoi(optarg);
203           break;
204         case 12:
205           if (optarg)
206             opt_identifier = strdup(optarg);
207           break;
208
209         default:
210           silc_usage();
211           break;
212         }
213     }
214   }
215
216   if (opt_create_keypair == TRUE) {
217     /* Create new key pair and exit */
218     silc_cipher_register_default();
219     silc_pkcs_register_default();
220     silc_hash_register_default();
221     silc_hmac_register_default();
222     silc_server_create_key_pair(opt_pkcs, opt_bits, opt_keypath,
223                                 opt_identifier, NULL, NULL);
224     exit(0);
225   }
226
227   /* Default configuration file */
228   if (!config_file)
229     config_file = strdup(SILC_SERVER_CONFIG_FILE);
230
231   /* Create SILC Server object */
232   ret = silc_server_alloc(&silcd);
233   if (ret == FALSE)
234     goto fail;
235
236   /* Read configuration files */
237   silcd->config = silc_server_config_alloc(config_file);
238   if (silcd->config == NULL)
239     goto fail;
240
241   /* Check for another silcd running */
242   silc_server_checkpid(silcd);
243
244   /* Initialize the server */
245   ret = silc_server_init(silcd);
246   if (ret == FALSE)
247     goto fail;
248
249   /* Ignore SIGPIPE */
250   sa.sa_handler = SIG_IGN;
251   sa.sa_flags = 0;
252   sigemptyset(&sa.sa_mask);
253   sigaction(SIGPIPE, &sa, NULL);
254   sa.sa_handler = got_hup;
255   sigaction(SIGHUP, &sa, NULL);
256   sa.sa_handler = stop_server;
257   sigaction(SIGTERM, &sa, NULL);
258   sa.sa_handler = stop_server;
259   sigaction(SIGINT, &sa, NULL);
260   silc_schedule_signal_register(silcd->schedule, SIGHUP);
261   silc_schedule_signal_register(silcd->schedule, SIGTERM);
262   silc_schedule_signal_register(silcd->schedule, SIGINT);
263
264   /* Before running the server, fork to background. */
265   if (!foreground)
266     silc_server_daemonise(silcd);
267
268   /* If set, write pid to file */
269   if (silcd->config->server_info->pid_file) {
270     char buf[10], *pidfile = silcd->config->server_info->pid_file;
271     unlink(pidfile);
272     snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
273     silc_file_writefile(pidfile, buf, strlen(buf));
274   }
275
276   /* Drop root. */
277   silc_server_drop(silcd);
278
279   /* Run the server. When this returns the server has been stopped
280      and we will exit. */
281   silc_server_run(silcd);
282   
283   /* Stop the server and free it. */
284   silc_server_stop(silcd);
285   silc_server_free(silcd);
286
287   /* Flush the logging system */
288   silc_log_flush_all();
289
290   exit(0);
291  fail:
292   exit(1);
293 }
294
295 /* Returns identifier string for public key generation. */
296
297 static char *silc_server_create_identifier()
298 {
299   char *username = NULL, *realname = NULL;
300   char hostname[256], email[256];
301   
302   /* Get realname */
303   realname = silc_get_real_name();
304
305   /* Get hostname */
306   memset(hostname, 0, sizeof(hostname));
307   gethostname(hostname, sizeof(hostname));
308
309   /* Get username (mandatory) */
310   username = silc_get_username();
311   if (!username)
312     return NULL;
313
314   /* Create default email address, whether it is right or not */
315   snprintf(email, sizeof(email), "%s@%s", username, hostname);
316
317   return silc_pkcs_encode_identifier(username, hostname, realname, email,
318                                      NULL, NULL);
319 }
320
321 /* Creates new public key and private key pair. This is used only
322    when user wants to create new key pair from command line. */
323
324 static int 
325 silc_server_create_key_pair(char *pkcs_name, int bits, char *path,
326                             char *identifier, 
327                             SilcPublicKey *ret_pub_key,
328                             SilcPrivateKey *ret_prv_key)
329 {
330   SilcPKCS pkcs;
331   SilcPublicKey pub_key;
332   SilcPrivateKey prv_key;
333   SilcRng rng;
334   unsigned char *key;
335   SilcUInt32 key_len;
336   char pkfile[256], prvfile[256];
337
338   if (!pkcs_name || !path)
339     return FALSE;
340
341   if (!silc_pkcs_is_supported(pkcs_name)) {
342     fprintf(stderr, "Unsupported PKCS `%s'", pkcs_name);
343     return FALSE;
344   }
345
346   if (!bits)
347     bits = 1024;
348
349   if (!identifier)
350     identifier = silc_server_create_identifier();
351
352   rng = silc_rng_alloc();
353   silc_rng_init(rng);
354   silc_rng_global_init(rng);
355
356   snprintf(pkfile, sizeof(pkfile) - 1, "%s%s", path,
357            SILC_SERVER_PUBLIC_KEY_NAME);
358   snprintf(prvfile, sizeof(prvfile) - 1, "%s%s", path,
359            SILC_SERVER_PRIVATE_KEY_NAME);
360
361   /* Generate keys */
362   silc_pkcs_alloc(pkcs_name, &pkcs);
363   silc_pkcs_generate_key(pkcs, bits, rng);
364
365   /* Save public key into file */
366   key = silc_pkcs_get_public_key(pkcs, &key_len);
367   pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
368                                        key, key_len);
369   silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
370   if (ret_pub_key)
371     *ret_pub_key = pub_key;
372   else
373     silc_pkcs_public_key_free(pub_key);
374
375   memset(key, 0, sizeof(key_len));
376   silc_free(key);
377
378   /* Save private key into file */
379   key = silc_pkcs_get_private_key(pkcs, &key_len);
380   prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
381   silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
382   if (ret_prv_key)
383     *ret_prv_key = prv_key;
384   else
385     silc_pkcs_private_key_free(prv_key);
386
387   printf("Public key has been saved into `%s'\n", pkfile);
388   printf("Private key has been saved into `%s'\n", prvfile);
389
390   memset(key, 0, sizeof(key_len));
391   silc_free(key);
392
393   silc_rng_free(rng);
394   silc_pkcs_free(pkcs);
395
396   return TRUE;
397 }