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