Merged from silc_1_0_branch.
[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
37 /* Long command line options */
38 static struct option long_opts[] =
39 {
40   { "config-file", 1, NULL, 'f' },
41   { "passphrase", 1, NULL, 'p' },
42   { "debug", 2, NULL, 'd' },
43   { "debug-level", 1, NULL, 'D' },
44   { "hexdump", 0, NULL, 'x' },
45   { "help", 0, NULL, 'h' },
46   { "foreground", 0, NULL, 'F' },
47   { "version", 0, NULL,'V' },
48
49   /* Key management options */
50   { "create-key-pair", 1, NULL, 'C' },
51   { "pkcs", 1, NULL, 10 },
52   { "bits", 1, NULL, 11 },
53   { "identifier", 1, NULL, 12 },
54
55   { NULL, 0, NULL, 0 }
56 };
57
58 /* Command line option variables */
59 static char *opt_keypath = NULL;
60 static char *opt_pkcs = "rsa";
61 static char *opt_identifier = NULL;
62 static int opt_bits = 2048;
63
64 /* Prints out the usage of silc client */
65
66 static void silc_usage(void)
67 {
68   printf(""
69 "Usage: silcd [options]\n"
70 "\n"
71 "  Generic Options:\n"
72 "  -f  --config-file=FILE        Alternate configuration file\n"
73 "  -d  --debug=string            Enable debugging (Implies --foreground)\n"
74 "  -D  --debug-level=level       Enable debugging (Implies --foreground)\n"
75 "  -x  --hexdump                 Enable hexdumps (Implies --debug)\n"
76 "  -h  --help                    Display this message\n"
77 "  -F  --foreground              Dont fork\n"
78 "  -V  --version                 Display version\n"
79 "\n"
80 "  Key Management Options:\n"
81 "  -C, --create-key-pair=PATH    Create new public key pair\n"
82 "      --pkcs=PKCS               Set the PKCS of the public key pair\n"
83 "      --bits=VALUE              Set length of the public key pair\n"
84 "      --identifier=IDENTIFIER   Public key identifier\n"
85 "\n"
86 "      The public key identifier may be of the following format:\n"
87 "\n"
88 "      UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n"
89 "      O=<organization>, C=<country>\n"
90 "\n"
91 "      The UN and HN must be provided, the others are optional.  If the\n"
92 "      --identifier option is not used an identifier will be created for\n"
93 "      the public key automatically.\n"
94 "\n"
95 "      Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n"
96 "                           E=foo@bar.com, C=FI\"\n"
97 "\n");
98   exit(0);
99 }
100
101 /* Die if a *valid* pid file exists already */
102
103 static void silc_server_checkpid(SilcServer silcd)
104 {
105   if (silcd->config->server_info->pid_file) {
106     int oldpid;
107     char *buf;
108     SilcUInt32 buf_len;
109
110     SILC_LOG_DEBUG(("Checking for another silcd running"));
111     buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
112     if (!buf)
113       return;
114     oldpid = atoi(buf);
115     silc_free(buf);
116     if (oldpid <= 0)
117       return;
118     kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */
119     if (errno != ESRCH) {
120       fprintf(stderr, "\nI detected another daemon running with the "
121               "same pid file.\n");
122       fprintf(stderr, "Please change the config file, or erase the %s\n",
123         silcd->config->server_info->pid_file);
124       exit(1);
125     }
126   }
127 }
128
129 /* Drop root privileges. If some system call fails, die. */
130
131 static void silc_server_drop_privs(SilcServer server)
132 {
133   /* Are we executing silcd as root or a regular user? */
134   if (geteuid()) {
135     SILC_LOG_DEBUG(("Server started as user"));
136   }
137   else {
138     struct passwd *pw;
139     struct group *gr;
140     char *user, *group;
141
142     SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
143
144     /* Get the values given for user and group in configuration file */
145     user = server->config->server_info->user;
146     group = server->config->server_info->group;
147
148     if (!user || !group) {
149       fprintf(stderr, "Error:"
150        "\tSILC server must not be run as root.  For the security of your\n"
151        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
152        "\tuser account.  Modify the ServerInfo configuration section to run\n"
153        "\tthe server as non-root user.\n");
154       exit(1);
155     }
156
157     /* Check whether the user/group does not begin with a number */
158     if (isdigit(user[0]) || isdigit(group[0])) {
159       SILC_LOG_DEBUG(("User and/or group starts with a number"));
160       fprintf(stderr, "Invalid user and/or group information\n");
161       fprintf(stderr, "Please assign them as names, not numbers\n");
162       exit(1);
163     }
164
165     if (!(pw = getpwnam(user))) {
166       fprintf(stderr, "Error: No such user %s found.\n", user);
167       exit(1);
168     }
169     if (!(gr = getgrnam(group))) {
170       fprintf(stderr, "Error: No such group %s found.\n", group);
171       exit(1);
172     }
173
174     /* Check whether user and/or group is set to root. If yes, exit
175        immediately. Otherwise, setgid and setuid server to user.group */
176     if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
177       fprintf(stderr, "Error:"
178        "\tSILC server must not be run as root.  For the security of your\n"
179        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
180        "\tuser account.  Modify the ServerInfo configuration section to run\n"
181        "\tthe server as non-root user.\n");
182       exit(1);
183     }
184
185     SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
186     if (setgid(gr->gr_gid) != 0) {
187       fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
188               group, gr->gr_gid);
189       exit(1);
190     }
191 #if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
192     SILC_LOG_DEBUG(("Removing supplementary groups"));
193     if (setgroups(0, NULL) != 0) {
194       fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
195       exit(1);
196     }
197     SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
198     if (initgroups(user, gr->gr_gid) != 0) {
199       fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
200               "Exiting.\n", user, gr->gr_gid);
201       exit(1);
202     }
203 #endif
204     SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
205     if (setuid(pw->pw_uid) != 0) {
206       fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
207               user, pw->pw_uid);
208       exit(1);
209     }
210   }
211 }
212
213 /* Fork server to background */
214
215 static void silc_server_daemonise(SilcServer server)
216 {
217   int i;
218
219   SILC_LOG_DEBUG(("Forking SILC server to background"));
220
221   if ((i = fork()) < 0) {
222     fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno));
223     exit(1);
224   }
225
226   if (i) /* Kill the parent */
227     exit(0);
228
229   server->background = TRUE;
230   setsid();
231
232   /* XXX close stdin, stdout, stderr -- before this, check that all writes
233      to stderr are changed to SILC_SERVER_LOG_ERROR() */
234 }
235
236 static void signal_handler(int sig)
237 {
238   /* Mark the signal to be caller after this signal is over. */
239   silc_schedule_signal_call(silcd->schedule, sig);
240 }
241
242 SILC_TASK_CALLBACK(got_hup)
243 {
244   /* First, reset all log files (they might have been deleted) */
245   silc_log_reset_all();
246
247   /* Rehash the configuration file */
248   silc_server_rehash(silcd);
249 }
250
251 SILC_TASK_CALLBACK(stop_server)
252 {
253   /* Stop scheduler, the program will stop eventually after noticing
254      that the scheduler is down. */
255   silc_schedule_stop(silcd->schedule);
256 }
257
258 /* Dump server statistics into a file into /tmp directory */
259
260 SILC_TASK_CALLBACK(dump_stats)
261 {
262   FILE *fdd;
263   char filename[256];
264
265   memset(filename, 0, sizeof(filename));
266   snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats", getpid());
267   fdd = fopen(filename, "w+");
268   if (!fdd)
269     return;
270
271 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
272
273   fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
274   fprintf(fdd, "Local Stats:\n");
275   STAT_OUTPUT("  My clients              : %d", silcd->stat.my_clients);
276   STAT_OUTPUT("  My servers              : %d", silcd->stat.my_servers);
277   STAT_OUTPUT("  My routers              : %d", silcd->stat.my_routers);
278   STAT_OUTPUT("  My channels             : %d", silcd->stat.my_channels);
279   STAT_OUTPUT("  My joined users         : %d", silcd->stat.my_chanclients);
280   STAT_OUTPUT("  My aways                : %d", silcd->stat.my_aways);
281   STAT_OUTPUT("  My detached clients     : %d", silcd->stat.my_detached);
282   STAT_OUTPUT("  My server operators     : %d", silcd->stat.my_server_ops);
283   STAT_OUTPUT("  My router operators     : %d", silcd->stat.my_router_ops);
284   fprintf(fdd, "\nGlobal Stats:\n");
285   STAT_OUTPUT("  Cell clients            : %d", silcd->stat.cell_clients);
286   STAT_OUTPUT("  Cell servers            : %d", silcd->stat.cell_servers);
287   STAT_OUTPUT("  Cell channels           : %d", silcd->stat.cell_channels);
288   STAT_OUTPUT("  Cell joined users       : %d", silcd->stat.cell_chanclients);
289   STAT_OUTPUT("  All clients             : %d", silcd->stat.clients);
290   STAT_OUTPUT("  All servers             : %d", silcd->stat.servers);
291   STAT_OUTPUT("  All routers             : %d", silcd->stat.routers);
292   STAT_OUTPUT("  All channels            : %d", silcd->stat.channels);
293   STAT_OUTPUT("  All joined users        : %d", silcd->stat.chanclients);
294   STAT_OUTPUT("  All aways               : %d", silcd->stat.aways);
295   STAT_OUTPUT("  All detached clients    : %d", silcd->stat.detached);
296   STAT_OUTPUT("  All server operators    : %d", silcd->stat.server_ops);
297   STAT_OUTPUT("  All router operators    : %d", silcd->stat.router_ops);
298   fprintf(fdd, "\nGeneral Stats:\n");
299   STAT_OUTPUT("  Connection attempts     : %d", silcd->stat.conn_attempts);
300   STAT_OUTPUT("  Connection failures     : %d", silcd->stat.conn_failures);
301   STAT_OUTPUT("  Authentication attempts : %d", silcd->stat.auth_attempts);
302   STAT_OUTPUT("  Authentication failures : %d", silcd->stat.auth_failures);
303   STAT_OUTPUT("  Packets sent            : %d", silcd->stat.packets_sent);
304   STAT_OUTPUT("  Packets received        : %d", silcd->stat.packets_received);
305
306 #undef STAT_OUTPUT
307
308 #ifdef SILC_DEBUG
309   /* Dump lists */
310   {
311     SilcIDCacheList list = NULL;
312     SilcIDCacheEntry id_cache = NULL;
313     SilcServerEntry server_entry;
314     SilcClientEntry client_entry;
315     SilcChannelEntry channel_entry;
316     int c;
317
318     fprintf(fdd, "\nDumping databases\n");
319     
320     if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
321       if (silc_idcache_list_first(list, &id_cache)) {
322         fprintf(fdd, "\nServers in local-list:\n");
323         c = 1;
324         while (id_cache) {
325           server_entry = (SilcServerEntry)id_cache->context;
326           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
327                   server_entry->server_name ? server_entry->server_name :
328                   "N/A", server_entry->id ?
329                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
330                   server_entry->data.status);
331           if (!silc_idcache_list_next(list, &id_cache))
332             break;
333           c++;
334         }
335       }
336       silc_idcache_list_free(list);
337     }
338     if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
339       if (silc_idcache_list_first(list, &id_cache)) {
340         fprintf(fdd, "\nServers in global-list:\n");
341         c = 1;
342         while (id_cache) {
343           server_entry = (SilcServerEntry)id_cache->context;
344           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
345                   server_entry->server_name ? server_entry->server_name :
346                   "N/A", server_entry->id ?
347                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
348                   server_entry->data.status);
349           if (!silc_idcache_list_next(list, &id_cache))
350             break;
351           c++;
352         }
353       }
354       silc_idcache_list_free(list);
355     }
356     if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
357       if (silc_idcache_list_first(list, &id_cache)) {
358         fprintf(fdd, "\nClients in local-list:\n");
359         c = 1;
360         while (id_cache) {
361           client_entry = (SilcClientEntry)id_cache->context;
362           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
363                   client_entry->nickname ? client_entry->nickname :
364                   (unsigned char *)"N/A", client_entry->id ?
365                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
366                   client_entry->data.status);
367           if (!silc_idcache_list_next(list, &id_cache))
368             break;
369           c++;
370         }
371       }
372       silc_idcache_list_free(list);
373     }
374     if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
375       if (silc_idcache_list_first(list, &id_cache)) {
376         fprintf(fdd, "\nClients in global-list:\n");
377         c = 1;
378         while (id_cache) {
379           client_entry = (SilcClientEntry)id_cache->context;
380           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
381                   client_entry->nickname ? client_entry->nickname :
382                   (unsigned char *)"N/A", client_entry->id ?
383                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
384                   client_entry->data.status);
385           if (!silc_idcache_list_next(list, &id_cache))
386             break;
387           c++;
388         }
389       }
390       silc_idcache_list_free(list);
391     }
392     if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
393       if (silc_idcache_list_first(list, &id_cache)) {
394         fprintf(fdd, "\nChannels in local-list:\n");
395         c = 1;
396         while (id_cache) {
397           channel_entry = (SilcChannelEntry)id_cache->context;
398           fprintf(fdd, "  %d: name %s id %s\n", c,
399                   channel_entry->channel_name ? channel_entry->channel_name :
400                   "N/A", channel_entry->id ?
401                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
402           if (!silc_idcache_list_next(list, &id_cache))
403             break;
404           c++;
405         }
406       }
407       silc_idcache_list_free(list);
408     }
409     if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
410       if (silc_idcache_list_first(list, &id_cache)) {
411         fprintf(fdd, "\nChannels in global-list:\n");
412         c = 1;
413         while (id_cache) {
414           channel_entry = (SilcChannelEntry)id_cache->context;
415           fprintf(fdd, "  %d: name %s id %s\n", c,
416                   channel_entry->channel_name ? channel_entry->channel_name :
417                   "N/A", channel_entry->id ?
418                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
419           if (!silc_idcache_list_next(list, &id_cache))
420             break;
421           c++;
422         }
423       }
424       silc_idcache_list_free(list);
425     }
426   }
427 #endif
428
429   fflush(fdd);
430   fclose(fdd);
431 }
432
433 typedef struct {
434   int level;
435   const char *string;
436 } DebugLevel;
437
438 static DebugLevel debug_levels[] = {
439   /* Very basic stuff from silcd/ */
440   { 3, "silcd\\.c,server\\.c" },
441
442   /* More stuff from silcd/ */
443   { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
444
445   /* All basic stuff from silcd/ */
446   { 10, "silc_server_*" },
447
448   /* All from silcd/ */
449   { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
450
451   /* All from silcd/ and basic stuff from libs */
452   { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,*silcske*" },
453
454   /* All from silcd/ and more stuff from libs */
455   { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
456     "*silcpacket*,*ske*,*silcrng*" },
457
458   /* All from silcd/ and even more stuff from libs */
459   { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
460     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
461
462   /* All from silcd/ and even more stuff from libs + all from silccore */
463   { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
464     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
465     "*silcid*,*argument*" },
466
467   /* All from silcd/, all from silccore, silccrypt and silcmath */
468   { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
469     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
470     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
471
472   /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
473      from silcutil */
474   { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
475     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
476     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
477     "*sockconn*" },
478
479   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
480      from silcutil */
481   { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
482     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
483     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
484     "*sockconn*,*net*" },
485
486   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
487      from silcutil */
488   { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
489     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
490     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
491     "*sockconn*,*net*,*log*,*config*" },
492
493   /* All */
494   { 90, "*" },
495
496   { -1, NULL },
497 };
498
499 static void silc_get_debug_level(int level)
500 {
501   int i;
502
503   if (level < 0)
504     return;
505
506   for (i = 0; debug_levels[i].string; i++)
507     if (level <= debug_levels[i].level) {
508       silc_log_set_debug_string(debug_levels[i].string);
509       break;
510     }
511 }
512
513 /* This function should not be called directly but through the appropriate
514    wrapper macro defined in server.h */
515
516 void silc_server_stderr(SilcLogType type, char *message)
517 {
518   if (silcd->background) {
519     char *p, *n = message;
520
521     /* remove newlines if we are going to output it to a log file */
522     for (p = n; *p; p++) {
523       if (*p != '\n') {
524         if (p != n)
525           *n = *p;
526         n++;
527       }
528     }
529     *n = 0;
530
531     /* the message is freed inside the logging function */
532     silc_log_output(type, message);
533   }
534   else {
535     fprintf(stderr, "%s\n", message);
536     silc_free(message);
537   }
538 }
539
540 int main(int argc, char **argv)
541 {
542   int ret, opt, option_index;
543   bool foreground = FALSE;
544   bool opt_create_keypair = FALSE;
545   char *silcd_config_file = NULL;
546   struct sigaction sa;
547
548   /* Parse command line arguments */
549   if (argc > 1) {
550     while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
551                               long_opts, &option_index)) != EOF) {
552       switch(opt) {
553         case 'h':
554           silc_usage();
555           break;
556         case 'V':
557           printf("SILCd Secure Internet Live Conferencing daemon, "
558                  "version %s (base: SILC Toolkit %s)\n",
559                  silc_dist_version, silc_version);
560           printf("(c) 1997 - 2002 Pekka Riikonen "
561                  "<priikone@silcnet.org>\n");
562           exit(0);
563           break;
564         case 'd':
565 #ifdef SILC_DEBUG
566           silc_debug = TRUE;
567           if (optarg)
568             silc_log_set_debug_string(optarg);
569           foreground = TRUE;        /* implied */
570           silc_log_quick = TRUE;    /* implied */
571 #else
572           fprintf(stderr,
573                   "Run-time debugging is not enabled. To enable it recompile\n"
574                   "the server with --enable-debug configuration option.\n");
575 #endif
576           break;
577         case 'D':
578 #ifdef SILC_DEBUG
579           silc_debug = TRUE;
580           if (optarg)
581             silc_get_debug_level(atoi(optarg));
582           foreground = TRUE;        /* implied */
583           silc_log_quick = TRUE;    /* implied */
584 #else
585           fprintf(stderr,
586                   "Run-time debugging is not enabled. To enable it recompile\n"
587                   "the server with --enable-debug configuration option.\n");
588 #endif
589           break;
590         case 'x':
591 #ifdef SILC_DEBUG
592           silc_debug_hexdump = TRUE;
593           silc_debug = TRUE; /* implied */
594           foreground = TRUE; /* implied */
595           silc_log_quick = TRUE; /* implied */
596 #else
597           fprintf(stderr,
598                   "Run-time debugging is not enabled. To enable it recompile\n"
599                   "the server with --enable-debug configuration option.\n");
600 #endif
601           break;
602         case 'f':
603           silcd_config_file = strdup(optarg);
604           break;
605         case 'F':
606           foreground = TRUE;
607           break;
608
609           /*
610            * Key management options
611            */
612         case 'C':
613           opt_create_keypair = TRUE;
614           if (optarg)
615             opt_keypath = strdup(optarg);
616           break;
617         case 10:
618           if (optarg)
619             opt_pkcs = strdup(optarg);
620           break;
621         case 11:
622           if (optarg)
623             opt_bits = atoi(optarg);
624           break;
625         case 12:
626           if (optarg)
627             opt_identifier = strdup(optarg);
628           break;
629
630         default:
631           silc_usage();
632           break;
633       }
634     }
635   }
636
637   if (opt_create_keypair == TRUE) {
638     /* Create new key pair and exit */
639     char pubfile[256], prvfile[256];
640
641     memset(pubfile, 0, sizeof(pubfile));
642     memset(prvfile, 0, sizeof(prvfile));
643     snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
644     snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
645
646     silc_cipher_register_default();
647     silc_pkcs_register_default();
648     silc_hash_register_default();
649     silc_hmac_register_default();
650     silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
651                          opt_identifier, "", NULL, NULL, NULL, FALSE);
652     exit(0);
653   }
654
655   /* Default configuration file */
656   if (!silcd_config_file)
657     silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
658
659   /* Create SILC Server object */
660   ret = silc_server_alloc(&silcd);
661   if (ret == FALSE)
662     goto fail;
663
664   /* Register default crypto stuff since we are going to need them 
665      in the configuration file parsing phase */
666   silc_cipher_register_default();
667   silc_pkcs_register_default();
668   silc_hash_register_default();
669   silc_hmac_register_default();
670
671   /* Read configuration files */
672   silcd->config = silc_server_config_alloc(silcd_config_file);
673   if (silcd->config == NULL)
674     goto fail;
675   silcd->config_file = silcd_config_file;
676
677   /* Unregister the default crypto stuff so that configuration takes effect */
678   silc_cipher_unregister_all();
679   silc_pkcs_unregister_all();
680   silc_hash_unregister_all();
681   silc_hmac_unregister_all();
682
683   /* Check for another silcd running */
684   silc_server_checkpid(silcd);
685
686   /* Initialize the server */
687   if (silc_server_init(silcd) == FALSE)
688     goto fail;
689
690   /* Ignore SIGPIPE */
691   sa.sa_handler = SIG_IGN;
692   sa.sa_flags = 0;
693   sigemptyset(&sa.sa_mask);
694   sigaction(SIGPIPE, &sa, NULL);
695   sa.sa_handler = signal_handler;
696   sigaction(SIGHUP, &sa, NULL);
697   sigaction(SIGTERM, &sa, NULL);
698   sigaction(SIGINT, &sa, NULL);
699   sigaction(SIGUSR1, &sa, NULL);
700   silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
701   silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
702   silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
703   silc_schedule_signal_register(silcd->schedule, SIGUSR1, dump_stats, NULL);
704
705   if (!foreground) {
706     /* Before running the server, fork to background. */
707     silc_server_daemonise(silcd);
708
709     /* If set, write pid to file */
710     if (silcd->config->server_info->pid_file) {
711       char buf[10], *pidfile = silcd->config->server_info->pid_file;
712       unlink(pidfile);
713       snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
714       silc_file_writefile(pidfile, buf, strlen(buf));
715     }
716   }
717
718   /* Drop root if we are not in debug mode, so you don't need to bother about
719      file writing permissions and so on */
720   if (!silc_debug)
721     silc_server_drop_privs(silcd);
722
723   /* Run the server. When this returns the server has been stopped
724      and we will exit. */
725   silc_server_run(silcd);
726
727   /* Stop the server and free it. */
728   silc_server_stop(silcd);
729   silc_server_config_destroy(silcd->config);
730   silc_server_free(silcd);
731
732   /* Flush the logging system */
733   silc_log_flush_all();
734
735   silc_free(silcd_config_file);
736   silc_free(opt_identifier);
737   silc_free(opt_keypath);
738   exit(0);
739
740  fail:
741   silc_free(silcd_config_file);
742   silc_free(opt_identifier);
743   silc_free(opt_keypath);
744   exit(1);
745 }