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