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