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