Do not user socket as number of socket connections.
[silc.git] / apps / silcd / silcd.c
1 /*
2
3   silcd.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2003 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   STAT_OUTPUT("  Connections             : %d", silcd->stat.conn_num);
306
307 #undef STAT_OUTPUT
308
309 #ifdef SILC_DEBUG
310   /* Dump internal flags */
311   fprintf(fdd, "\nDumping internal flags\n");
312   fprintf(fdd, "  server_type            : %d\n", silcd->server_type);
313   fprintf(fdd, "  standalone             : %d\n", silcd->standalone);
314   fprintf(fdd, "  listenning             : %d\n", silcd->listenning);
315   fprintf(fdd, "  background             : %d\n", silcd->background);
316   fprintf(fdd, "  backup_router          : %d\n", silcd->backup_router);
317   fprintf(fdd, "  backup_primary         : %d\n", silcd->backup_primary);
318   fprintf(fdd, "  backup_noswitch        : %d\n", silcd->backup_noswitch);
319   fprintf(fdd, "  wait_backup            : %d\n", silcd->wait_backup);
320   if (silcd->router)
321     fprintf(fdd, "  primary router         : %s\n",
322       silcd->router->server_name ? silcd->router->server_name : "");
323
324   /* Dump socket connections */
325   {
326     int i;
327     SilcSocketConnection s;
328
329     fprintf(fdd, "\nDumping socket connections\n");
330     for (i = 0; i < silcd->config->param.connections_max; i++) {
331       s = silcd->sockets[i];
332       if (!s)
333         continue;
334       fprintf(fdd, "  %d: host %s ip %s port %d type %d flags 0x%x\n",
335               s->sock, s->hostname ? s->hostname : "N/A",
336               s->ip ? s->ip : "N/A", s->port, s->type,
337               (unsigned int)s->flags);
338     }
339   }
340
341   /* Dump lists */
342   {
343     SilcIDCacheList list = NULL;
344     SilcIDCacheEntry id_cache = NULL;
345     SilcServerEntry server_entry;
346     SilcClientEntry client_entry;
347     SilcChannelEntry channel_entry;
348     int c;
349
350     fprintf(fdd, "\nDumping databases\n");
351
352     if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
353       if (silc_idcache_list_first(list, &id_cache)) {
354         fprintf(fdd, "\nServers in local-list:\n");
355         c = 1;
356         while (id_cache) {
357           server_entry = (SilcServerEntry)id_cache->context;
358           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
359                   server_entry->server_name ? server_entry->server_name :
360                   "N/A", server_entry->id ?
361                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
362                   server_entry->data.status);
363           if (!silc_idcache_list_next(list, &id_cache))
364             break;
365           c++;
366         }
367       }
368       silc_idcache_list_free(list);
369     }
370     if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
371       if (silc_idcache_list_first(list, &id_cache)) {
372         fprintf(fdd, "\nServers in global-list:\n");
373         c = 1;
374         while (id_cache) {
375           server_entry = (SilcServerEntry)id_cache->context;
376           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
377                   server_entry->server_name ? server_entry->server_name :
378                   "N/A", server_entry->id ?
379                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
380                   server_entry->data.status);
381           if (!silc_idcache_list_next(list, &id_cache))
382             break;
383           c++;
384         }
385       }
386       silc_idcache_list_free(list);
387     }
388     if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
389       if (silc_idcache_list_first(list, &id_cache)) {
390         fprintf(fdd, "\nClients in local-list:\n");
391         c = 1;
392         while (id_cache) {
393           client_entry = (SilcClientEntry)id_cache->context;
394           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
395                   client_entry->nickname ? client_entry->nickname :
396                   (unsigned char *)"N/A", client_entry->id ?
397                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
398                   client_entry->data.status);
399           if (!silc_idcache_list_next(list, &id_cache))
400             break;
401           c++;
402         }
403       }
404       silc_idcache_list_free(list);
405     }
406     if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
407       if (silc_idcache_list_first(list, &id_cache)) {
408         fprintf(fdd, "\nClients in global-list:\n");
409         c = 1;
410         while (id_cache) {
411           client_entry = (SilcClientEntry)id_cache->context;
412           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
413                   client_entry->nickname ? client_entry->nickname :
414                   (unsigned char *)"N/A", client_entry->id ?
415                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
416                   client_entry->data.status);
417           if (!silc_idcache_list_next(list, &id_cache))
418             break;
419           c++;
420         }
421       }
422       silc_idcache_list_free(list);
423     }
424     if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
425       if (silc_idcache_list_first(list, &id_cache)) {
426         fprintf(fdd, "\nChannels in local-list:\n");
427         c = 1;
428         while (id_cache) {
429           channel_entry = (SilcChannelEntry)id_cache->context;
430           fprintf(fdd, "  %d: name %s id %s\n", c,
431                   channel_entry->channel_name ? channel_entry->channel_name :
432                   "N/A", channel_entry->id ?
433                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
434           if (!silc_idcache_list_next(list, &id_cache))
435             break;
436           c++;
437         }
438       }
439       silc_idcache_list_free(list);
440     }
441     if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
442       if (silc_idcache_list_first(list, &id_cache)) {
443         fprintf(fdd, "\nChannels in global-list:\n");
444         c = 1;
445         while (id_cache) {
446           channel_entry = (SilcChannelEntry)id_cache->context;
447           fprintf(fdd, "  %d: name %s id %s\n", c,
448                   channel_entry->channel_name ? channel_entry->channel_name :
449                   "N/A", channel_entry->id ?
450                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
451           if (!silc_idcache_list_next(list, &id_cache))
452             break;
453           c++;
454         }
455       }
456       silc_idcache_list_free(list);
457     }
458   }
459 #endif
460
461   fflush(fdd);
462   fclose(fdd);
463 }
464
465 #ifdef SILC_DEBUG
466
467 typedef struct {
468   int level;
469   const char *string;
470 } DebugLevel;
471
472 static DebugLevel debug_levels[] = {
473   /* Very basic stuff from silcd/ */
474   { 3, "silcd\\.c,server\\.c" },
475
476   /* More stuff from silcd/ */
477   { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
478
479   /* All basic stuff from silcd/ */
480   { 10, "silc_server_*" },
481
482   /* All from silcd/ */
483   { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
484
485   /* All from silcd/ and basic stuff from libs */
486   { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,*silcske*" },
487
488   /* All from silcd/ and more stuff from libs */
489   { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
490     "*silcpacket*,*ske*,*silcrng*" },
491
492   /* All from silcd/ and even more stuff from libs */
493   { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
494     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
495
496   /* All from silcd/ and even more stuff from libs + all from silccore */
497   { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
498     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
499     "*silcid*,*argument*" },
500
501   /* All from silcd/, all from silccore, silccrypt and silcmath */
502   { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
503     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
504     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
505
506   /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
507      from silcutil */
508   { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
509     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
510     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
511     "*sockconn*" },
512
513   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
514      from silcutil */
515   { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
516     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
517     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
518     "*sockconn*,*net*" },
519
520   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
521      from silcutil */
522   { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
523     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
524     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
525     "*sockconn*,*net*,*log*,*config*" },
526
527   /* All */
528   { 90, "*" },
529
530   { -1, NULL },
531 };
532
533 static void silc_get_debug_level(int level)
534 {
535   int i;
536
537   if (level < 0)
538     return;
539
540   for (i = 0; debug_levels[i].string; i++)
541     if (level <= debug_levels[i].level) {
542       silc_log_set_debug_string(debug_levels[i].string);
543       break;
544     }
545 }
546 #endif /* SILC_DEBUG */
547
548 /* This function should not be called directly but through the appropriate
549    wrapper macro defined in server.h */
550
551 void silc_server_stderr(SilcLogType type, char *message)
552 {
553   if (silcd->background) {
554     char *p, *n = message;
555
556     /* remove newlines if we are going to output it to a log file */
557     for (p = n; *p; p++) {
558       if (*p != '\n') {
559         if (p != n)
560           *n = *p;
561         n++;
562       }
563     }
564     *n = 0;
565
566     /* the message is freed inside the logging function */
567     silc_log_output(type, message);
568   }
569   else {
570     fprintf(stderr, "%s\n", message);
571     silc_free(message);
572   }
573 }
574
575 int main(int argc, char **argv)
576 {
577   int ret, opt, option_index;
578   bool foreground = FALSE;
579   bool opt_create_keypair = FALSE;
580   char *silcd_config_file = NULL;
581   struct sigaction sa;
582
583   /* Parse command line arguments */
584   if (argc > 1) {
585     while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
586                               long_opts, &option_index)) != EOF) {
587       switch(opt) {
588         case 'h':
589           silc_usage();
590           break;
591         case 'V':
592           printf("SILCd Secure Internet Live Conferencing daemon, "
593                  "version %s (base: SILC Toolkit %s)\n",
594                  silc_dist_version, silc_version);
595           printf("(c) 1997 - 2004 Pekka Riikonen "
596                  "<priikone@silcnet.org>\n");
597           exit(0);
598           break;
599         case 'd':
600 #ifdef SILC_DEBUG
601           silc_debug = TRUE;
602           if (optarg)
603             silc_log_set_debug_string(optarg);
604           foreground = TRUE;        /* implied */
605           silc_log_quick = TRUE;    /* implied */
606 #else
607           fprintf(stderr,
608                   "Run-time debugging is not enabled. To enable it recompile\n"
609                   "the server with --enable-debug configuration option.\n");
610 #endif
611           break;
612         case 'D':
613 #ifdef SILC_DEBUG
614           silc_debug = TRUE;
615           if (optarg)
616             silc_get_debug_level(atoi(optarg));
617           foreground = TRUE;        /* implied */
618           silc_log_quick = TRUE;    /* implied */
619 #else
620           fprintf(stderr,
621                   "Run-time debugging is not enabled. To enable it recompile\n"
622                   "the server with --enable-debug configuration option.\n");
623 #endif
624           break;
625         case 'x':
626 #ifdef SILC_DEBUG
627           silc_debug_hexdump = TRUE;
628           silc_debug = TRUE; /* implied */
629           foreground = TRUE; /* implied */
630           silc_log_quick = TRUE; /* implied */
631 #else
632           fprintf(stderr,
633                   "Run-time debugging is not enabled. To enable it recompile\n"
634                   "the server with --enable-debug configuration option.\n");
635 #endif
636           break;
637         case 'f':
638           silcd_config_file = strdup(optarg);
639           break;
640         case 'F':
641           foreground = TRUE;
642           break;
643
644           /*
645            * Key management options
646            */
647         case 'C':
648           opt_create_keypair = TRUE;
649           if (optarg)
650             opt_keypath = strdup(optarg);
651           break;
652         case 10:
653           if (optarg)
654             opt_pkcs = strdup(optarg);
655           break;
656         case 11:
657           if (optarg)
658             opt_bits = atoi(optarg);
659           break;
660         case 12:
661           if (optarg)
662             opt_identifier = strdup(optarg);
663           break;
664
665         default:
666           silc_usage();
667           break;
668       }
669     }
670   }
671
672   if (opt_create_keypair == TRUE) {
673     /* Create new key pair and exit */
674     char pubfile[256], prvfile[256];
675
676     memset(pubfile, 0, sizeof(pubfile));
677     memset(prvfile, 0, sizeof(prvfile));
678     snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
679     snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
680
681     silc_cipher_register_default();
682     silc_pkcs_register_default();
683     silc_hash_register_default();
684     silc_hmac_register_default();
685     silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
686                          opt_identifier, "", NULL, NULL, NULL, FALSE);
687     exit(0);
688   }
689
690   /* Default configuration file */
691   if (!silcd_config_file)
692     silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
693
694   /* Create SILC Server object */
695   ret = silc_server_alloc(&silcd);
696   if (ret == FALSE)
697     goto fail;
698
699   /* Register default crypto stuff since we are going to need them
700      in the configuration file parsing phase */
701   silc_cipher_register_default();
702   silc_pkcs_register_default();
703   silc_hash_register_default();
704   silc_hmac_register_default();
705
706   /* Read configuration files */
707   silcd->config = silc_server_config_alloc(silcd_config_file);
708   if (silcd->config == NULL)
709     goto fail;
710   silcd->config_file = silcd_config_file;
711
712   /* Unregister the default crypto stuff so that configuration takes effect */
713   silc_cipher_unregister_all();
714   silc_pkcs_unregister_all();
715   silc_hash_unregister_all();
716   silc_hmac_unregister_all();
717
718   /* Check for another silcd running */
719   silc_server_checkpid(silcd);
720
721   /* Initialize the server */
722   if (silc_server_init(silcd) == FALSE)
723     goto fail;
724
725   /* Ignore some signals */
726   sa.sa_handler = SIG_IGN;
727   sa.sa_flags = 0;
728   sigemptyset(&sa.sa_mask);
729 #if defined(SIGPIPE)
730   sigaction(SIGPIPE, &sa, NULL);      /* Ignore broken pipes */
731 #endif /* SIGPIPE*/
732 #if defined(SIGXFSZ)
733   sigaction(SIGXFSZ, &sa, NULL);      /* Ignore file limit exceeds */
734 #endif /* SIGXFSZ */
735 #if defined(SIGXCPU)
736   sigaction(SIGXCPU, &sa, NULL);      /* Ignore CPU time limit exceeds */
737 #endif /* SIGXCPU */
738
739   /* Handle specificly some other signals. */
740   sa.sa_handler = signal_handler;
741   sigaction(SIGHUP, &sa, NULL);
742   sigaction(SIGTERM, &sa, NULL);
743   sigaction(SIGINT, &sa, NULL);
744   sigaction(SIGUSR1, &sa, NULL);
745   silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
746   silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
747   silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
748   silc_schedule_signal_register(silcd->schedule, SIGUSR1, dump_stats, NULL);
749
750   if (!foreground) {
751     /* Before running the server, fork to background. */
752     silc_server_daemonise(silcd);
753
754     /* If set, write pid to file */
755     if (silcd->config->server_info->pid_file) {
756       char buf[10], *pidfile = silcd->config->server_info->pid_file;
757       unlink(pidfile);
758       snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
759       silc_file_writefile(pidfile, buf, strlen(buf));
760     }
761   }
762
763   /* Drop root if we are not in debug mode, so you don't need to bother about
764      file writing permissions and so on */
765   if (!silc_debug)
766     silc_server_drop_privs(silcd);
767
768   /* Run the server. When this returns the server has been stopped
769      and we will exit. */
770   silc_server_run(silcd);
771
772   /* Stop the server and free it. */
773   silc_server_stop(silcd);
774   silc_server_config_destroy(silcd->config);
775   silc_server_free(silcd);
776
777   /* Flush the logging system */
778   silc_log_flush_all();
779
780   silc_free(silcd_config_file);
781   silc_free(opt_identifier);
782   silc_free(opt_keypath);
783   exit(0);
784
785  fail:
786   silc_free(silcd_config_file);
787   silc_free(opt_identifier);
788   silc_free(opt_keypath);
789   exit(1);
790 }