Mon Sep 12 18:13:38 CEST 2005 Jochen Eisinger <c0ffee@penguin-breeder.org>
[silc.git] / apps / silcd / silcd.c
1 /*
2
3   silcd.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2005 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 static void signal_handler(int sig)
238 {
239   /* Mark the signal to be caller after this signal is over. */
240   silc_schedule_signal_call(silcd->schedule, sig);
241 }
242
243 SILC_TASK_CALLBACK(got_hup)
244 {
245   /* First, reset all log files (they might have been deleted) */
246   silc_log_reset_all();
247
248   /* Rehash the configuration file */
249   silc_server_rehash(silcd);
250 }
251
252 SILC_TASK_CALLBACK(stop_server)
253 {
254   /* Stop scheduler, the program will stop eventually after noticing
255      that the scheduler is down. */
256   silc_schedule_stop(silcd->schedule);
257 }
258
259 /* Dump server statistics into a file into /tmp directory */
260
261 SILC_TASK_CALLBACK(dump_stats)
262 {
263   FILE *fdd;
264   int fd;
265   char filename[256];
266
267   memset(filename, 0, sizeof(filename));
268   snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats-XXXXXX", getpid());
269   fd = mkstemp(filename);
270   if (fd == -1)
271     return;
272
273   fdd = fdopen(fd, "w");
274
275 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
276
277   fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
278   fprintf(fdd, "Local Stats:\n");
279   STAT_OUTPUT("  My clients              : %d", silcd->stat.my_clients);
280   STAT_OUTPUT("  My servers              : %d", silcd->stat.my_servers);
281   STAT_OUTPUT("  My routers              : %d", silcd->stat.my_routers);
282   STAT_OUTPUT("  My channels             : %d", silcd->stat.my_channels);
283   STAT_OUTPUT("  My joined users         : %d", silcd->stat.my_chanclients);
284   STAT_OUTPUT("  My aways                : %d", silcd->stat.my_aways);
285   STAT_OUTPUT("  My detached clients     : %d", silcd->stat.my_detached);
286   STAT_OUTPUT("  My server operators     : %d", silcd->stat.my_server_ops);
287   STAT_OUTPUT("  My router operators     : %d", silcd->stat.my_router_ops);
288   fprintf(fdd, "\nGlobal Stats:\n");
289   STAT_OUTPUT("  Cell clients            : %d", silcd->stat.cell_clients);
290   STAT_OUTPUT("  Cell servers            : %d", silcd->stat.cell_servers);
291   STAT_OUTPUT("  Cell channels           : %d", silcd->stat.cell_channels);
292   STAT_OUTPUT("  Cell joined users       : %d", silcd->stat.cell_chanclients);
293   STAT_OUTPUT("  All clients             : %d", silcd->stat.clients);
294   STAT_OUTPUT("  All servers             : %d", silcd->stat.servers);
295   STAT_OUTPUT("  All routers             : %d", silcd->stat.routers);
296   STAT_OUTPUT("  All channels            : %d", silcd->stat.channels);
297   STAT_OUTPUT("  All joined users        : %d", silcd->stat.chanclients);
298   STAT_OUTPUT("  All aways               : %d", silcd->stat.aways);
299   STAT_OUTPUT("  All detached clients    : %d", silcd->stat.detached);
300   STAT_OUTPUT("  All server operators    : %d", silcd->stat.server_ops);
301   STAT_OUTPUT("  All router operators    : %d", silcd->stat.router_ops);
302   fprintf(fdd, "\nGeneral Stats:\n");
303   STAT_OUTPUT("  Connection attempts     : %d", silcd->stat.conn_attempts);
304   STAT_OUTPUT("  Connection failures     : %d", silcd->stat.conn_failures);
305   STAT_OUTPUT("  Authentication attempts : %d", silcd->stat.auth_attempts);
306   STAT_OUTPUT("  Authentication failures : %d", silcd->stat.auth_failures);
307   STAT_OUTPUT("  Packets sent            : %d", silcd->stat.packets_sent);
308   STAT_OUTPUT("  Packets received        : %d", silcd->stat.packets_received);
309   STAT_OUTPUT("  Commands sent           : %d", silcd->stat.commands_sent);
310   STAT_OUTPUT("  Commands received       : %d", silcd->stat.commands_received);
311   STAT_OUTPUT("  Connections             : %d", silcd->stat.conn_num);
312
313 #undef STAT_OUTPUT
314
315 #ifdef SILC_DEBUG
316   /* Dump internal flags */
317   fprintf(fdd, "\nDumping internal flags\n");
318   fprintf(fdd, "  server_type            : %d\n", silcd->server_type);
319   fprintf(fdd, "  standalone             : %d\n", silcd->standalone);
320   fprintf(fdd, "  listenning             : %d\n", silcd->listenning);
321   fprintf(fdd, "  background             : %d\n", silcd->background);
322   fprintf(fdd, "  backup_router          : %d\n", silcd->backup_router);
323   fprintf(fdd, "  backup_primary         : %d\n", silcd->backup_primary);
324   fprintf(fdd, "  backup_noswitch        : %d\n", silcd->backup_noswitch);
325   fprintf(fdd, "  backup_closed          : %d\n", silcd->backup_closed);
326   fprintf(fdd, "  wait_backup            : %d\n", silcd->wait_backup);
327   if (silcd->router)
328     fprintf(fdd, "  primary router         : %s\n",
329       silcd->router->server_name ? silcd->router->server_name : "");
330
331   /* Dump socket connections */
332   {
333     int i;
334     SilcSocketConnection 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
348   /* Dump lists */
349   {
350     SilcIDCacheList list = NULL;
351     SilcIDCacheEntry id_cache = NULL;
352     SilcServerEntry server_entry;
353     SilcClientEntry client_entry;
354     SilcChannelEntry channel_entry;
355     int c;
356
357     fprintf(fdd, "\nDumping databases\n");
358
359     if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
360       if (silc_idcache_list_first(list, &id_cache)) {
361         fprintf(fdd, "\nServers in local-list:\n");
362         c = 1;
363         while (id_cache) {
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           if (!silc_idcache_list_next(list, &id_cache))
371             break;
372           c++;
373         }
374       }
375       silc_idcache_list_free(list);
376     }
377     if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
378       if (silc_idcache_list_first(list, &id_cache)) {
379         fprintf(fdd, "\nServers in global-list:\n");
380         c = 1;
381         while (id_cache) {
382           server_entry = (SilcServerEntry)id_cache->context;
383           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
384                   server_entry->server_name ? server_entry->server_name :
385                   "N/A", server_entry->id ?
386                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
387                   server_entry->data.status);
388           if (!silc_idcache_list_next(list, &id_cache))
389             break;
390           c++;
391         }
392       }
393       silc_idcache_list_free(list);
394     }
395     if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
396       if (silc_idcache_list_first(list, &id_cache)) {
397         fprintf(fdd, "\nClients in local-list:\n");
398         c = 1;
399         while (id_cache) {
400           client_entry = (SilcClientEntry)id_cache->context;
401           server_entry = client_entry->router;
402           fprintf(fdd, "  %d: name %s id %s status 0x%x from %s\n", c,
403                   client_entry->nickname ? client_entry->nickname :
404                   (unsigned char *)"N/A", client_entry->id ?
405                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
406                   client_entry->data.status, server_entry ?
407                   server_entry->server_name ? server_entry->server_name :
408                   "N/A" : "local");
409           if (!silc_idcache_list_next(list, &id_cache))
410             break;
411           c++;
412         }
413       }
414       silc_idcache_list_free(list);
415     }
416     if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
417       if (silc_idcache_list_first(list, &id_cache)) {
418         fprintf(fdd, "\nClients in global-list:\n");
419         c = 1;
420         while (id_cache) {
421           client_entry = (SilcClientEntry)id_cache->context;
422           server_entry = client_entry->router;
423           fprintf(fdd, "  %d: name %s id %s status 0x%x from %s\n", c,
424                   client_entry->nickname ? client_entry->nickname :
425                   (unsigned char *)"N/A", client_entry->id ?
426                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
427                   client_entry->data.status, server_entry ?
428                   server_entry->server_name ? server_entry->server_name :
429                   "N/A" : "local");
430           if (!silc_idcache_list_next(list, &id_cache))
431             break;
432           c++;
433         }
434       }
435       silc_idcache_list_free(list);
436     }
437     if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
438       if (silc_idcache_list_first(list, &id_cache)) {
439         fprintf(fdd, "\nChannels in local-list:\n");
440         c = 1;
441         while (id_cache) {
442           channel_entry = (SilcChannelEntry)id_cache->context;
443           fprintf(fdd, "  %d: name %s id %s\n", c,
444                   channel_entry->channel_name ? channel_entry->channel_name :
445                   "N/A", channel_entry->id ?
446                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
447           if (!silc_idcache_list_next(list, &id_cache))
448             break;
449           c++;
450         }
451       }
452       silc_idcache_list_free(list);
453     }
454     if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
455       if (silc_idcache_list_first(list, &id_cache)) {
456         fprintf(fdd, "\nChannels in global-list:\n");
457         c = 1;
458         while (id_cache) {
459           channel_entry = (SilcChannelEntry)id_cache->context;
460           fprintf(fdd, "  %d: name %s id %s\n", c,
461                   channel_entry->channel_name ? channel_entry->channel_name :
462                   "N/A", channel_entry->id ?
463                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
464           if (!silc_idcache_list_next(list, &id_cache))
465             break;
466           c++;
467         }
468       }
469       silc_idcache_list_free(list);
470     }
471   }
472 #endif
473
474   fflush(fdd);
475   fclose(fdd);
476 }
477
478 #ifdef SILC_DEBUG
479
480 typedef struct {
481   int level;
482   const char *string;
483 } DebugLevel;
484
485 static DebugLevel debug_levels[] = {
486   /* Very basic stuff from silcd/ */
487   { 3, "silcd\\.c,server\\.c" },
488
489   /* More stuff from silcd/ */
490   { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
491
492   /* All basic stuff from silcd/ */
493   { 10, "silc_server_*" },
494
495   /* All from silcd/ */
496   { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
497
498   /* All from silcd/ and basic stuff from libs */
499   { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,*silcske*" },
500
501   /* All from silcd/ and more stuff from libs */
502   { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
503     "*silcpacket*,*ske*,*silcrng*" },
504
505   /* All from silcd/ and even more stuff from libs */
506   { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
507     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
508
509   /* All from silcd/ and even more stuff from libs + all from silccore */
510   { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
511     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
512     "*silcid*,*argument*" },
513
514   /* All from silcd/, all from silccore, silccrypt and silcmath */
515   { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
516     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
517     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
518
519   /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
520      from silcutil */
521   { 45, "*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*" },
525
526   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
527      from silcutil */
528   { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
529     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
530     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
531     "*sockconn*,*net*" },
532
533   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
534      from silcutil */
535   { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
536     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
537     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
538     "*sockconn*,*net*,*log*,*config*" },
539
540   /* All */
541   { 90, "*" },
542
543   { -1, NULL },
544 };
545
546 static void silc_get_debug_level(int level)
547 {
548   int i;
549
550   if (level < 0)
551     return;
552
553   for (i = 0; debug_levels[i].string; i++)
554     if (level <= debug_levels[i].level) {
555       silc_log_set_debug_string(debug_levels[i].string);
556       break;
557     }
558 }
559 #endif /* SILC_DEBUG */
560
561 /* This function should not be called directly but through the appropriate
562    wrapper macro defined in server.h */
563
564 void silc_server_stderr(SilcLogType type, char *message)
565 {
566   if (silcd->background) {
567     char *p, *n = message;
568
569     /* remove newlines if we are going to output it to a log file */
570     for (p = n; *p; p++) {
571       if (*p != '\n') {
572         if (p != n)
573           *n = *p;
574         n++;
575       }
576     }
577     *n = 0;
578
579     /* the message is freed inside the logging function */
580     silc_log_output(type, message);
581   }
582   else {
583     fprintf(stderr, "%s\n", message);
584     silc_free(message);
585   }
586 }
587
588 int main(int argc, char **argv)
589 {
590   int ret, opt, option_index;
591   bool foreground = FALSE;
592   bool opt_create_keypair = FALSE;
593   char *silcd_config_file = NULL;
594   struct sigaction sa;
595
596   /* Parse command line arguments */
597   if (argc > 1) {
598 #ifdef HAVE_GETOPT_LONG
599     while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
600                               long_opts, &option_index)) != EOF) {
601 #else
602     while ((opt = getopt(argc, argv, "f:p:d:D:xhFVC:")) != EOF) {
603 #endif /* HAVE_GETOPT_LONG */
604       switch(opt) {
605         case 'h':
606           silc_usage();
607           break;
608         case 'V':
609           printf("SILCd Secure Internet Live Conferencing daemon, "
610                  "version %s (base: SILC Toolkit %s)\n",
611                  silc_dist_version, silc_version);
612           printf("(c) 1997 - 2005 Pekka Riikonen "
613                  "<priikone@silcnet.org>\n");
614           exit(0);
615           break;
616         case 'd':
617 #ifdef SILC_DEBUG
618           silc_log_debug(TRUE);
619           silc_log_quick(TRUE);
620           if (optarg)
621             silc_log_set_debug_string(optarg);
622           foreground = TRUE;        /* implied */
623 #else
624           fprintf(stderr,
625                   "Run-time debugging is not enabled. To enable it recompile\n"
626                   "the server with --enable-debug configuration option.\n");
627 #endif
628           break;
629         case 'D':
630 #ifdef SILC_DEBUG
631           silc_log_debug(TRUE);
632           silc_log_quick(TRUE);
633           if (optarg)
634             silc_get_debug_level(atoi(optarg));
635           foreground = TRUE;        /* implied */
636 #else
637           fprintf(stderr,
638                   "Run-time debugging is not enabled. To enable it recompile\n"
639                   "the server with --enable-debug configuration option.\n");
640 #endif
641           break;
642         case 'x':
643 #ifdef SILC_DEBUG
644           silc_log_debug(TRUE);
645           silc_log_debug_hexdump(TRUE);
646           silc_log_quick(TRUE);
647           foreground = TRUE; /* implied */
648 #else
649           fprintf(stderr,
650                   "Run-time debugging is not enabled. To enable it recompile\n"
651                   "the server with --enable-debug configuration option.\n");
652 #endif
653           break;
654         case 'f':
655           silcd_config_file = strdup(optarg);
656           break;
657         case 'F':
658           foreground = TRUE;
659           break;
660
661           /*
662            * Key management options
663            */
664         case 'C':
665           opt_create_keypair = TRUE;
666           if (optarg)
667             opt_keypath = strdup(optarg);
668           break;
669         case 10:
670           if (optarg)
671             opt_pkcs = strdup(optarg);
672           break;
673         case 11:
674           if (optarg)
675             opt_bits = atoi(optarg);
676           break;
677         case 12:
678           if (optarg)
679             opt_identifier = strdup(optarg);
680           break;
681
682         default:
683           silc_usage();
684           break;
685       }
686     }
687   }
688
689   if (opt_create_keypair == TRUE) {
690     /* Create new key pair and exit */
691     char pubfile[256], prvfile[256];
692
693     memset(pubfile, 0, sizeof(pubfile));
694     memset(prvfile, 0, sizeof(prvfile));
695     snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
696     snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
697
698     silc_cipher_register_default();
699     silc_pkcs_register_default();
700     silc_hash_register_default();
701     silc_hmac_register_default();
702     silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
703                          opt_identifier, "", NULL, NULL, NULL, FALSE);
704     exit(0);
705   }
706
707   /* Default configuration file */
708   if (!silcd_config_file)
709     silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
710
711   /* Create SILC Server object */
712   ret = silc_server_alloc(&silcd);
713   if (ret == FALSE)
714     goto fail;
715
716   /* Register default crypto stuff since we are going to need them
717      in the configuration file parsing phase */
718   silc_cipher_register_default();
719   silc_pkcs_register_default();
720   silc_hash_register_default();
721   silc_hmac_register_default();
722
723   /* Read configuration files */
724   silcd->config = silc_server_config_alloc(silcd_config_file);
725   if (silcd->config == NULL)
726     goto fail;
727   silcd->config_file = silcd_config_file;
728
729   /* Unregister the default crypto stuff so that configuration takes effect */
730   silc_cipher_unregister_all();
731   silc_pkcs_unregister_all();
732   silc_hash_unregister_all();
733   silc_hmac_unregister_all();
734
735   /* Check for another silcd running */
736   silc_server_checkpid(silcd);
737
738   /* Initialize the server */
739   if (silc_server_init(silcd) == FALSE)
740     goto fail;
741
742   /* Ignore some signals */
743   sa.sa_handler = SIG_IGN;
744   sa.sa_flags = 0;
745   sigemptyset(&sa.sa_mask);
746 #if defined(SIGPIPE)
747   sigaction(SIGPIPE, &sa, NULL);      /* Ignore broken pipes */
748 #endif /* SIGPIPE*/
749 #if defined(SIGXFSZ)
750   sigaction(SIGXFSZ, &sa, NULL);      /* Ignore file limit exceeds */
751 #endif /* SIGXFSZ */
752 #if defined(SIGXCPU)
753   sigaction(SIGXCPU, &sa, NULL);      /* Ignore CPU time limit exceeds */
754 #endif /* SIGXCPU */
755
756   /* Handle specificly some other signals. */
757   sa.sa_handler = signal_handler;
758   sigaction(SIGHUP, &sa, NULL);
759   sigaction(SIGTERM, &sa, NULL);
760   sigaction(SIGINT, &sa, NULL);
761   sigaction(SIGUSR1, &sa, NULL);
762   silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
763   silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
764   silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
765   silc_schedule_signal_register(silcd->schedule, SIGUSR1, dump_stats, NULL);
766
767   if (!foreground) {
768     /* Before running the server, fork to background. */
769     silc_server_daemonise(silcd);
770
771     /* If set, write pid to file */
772     if (silcd->config->server_info->pid_file) {
773       char buf[10], *pidfile = silcd->config->server_info->pid_file;
774       unlink(pidfile);
775       snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
776       silc_file_writefile(pidfile, buf, strlen(buf));
777     }
778
779     silc_server_drop_privs(silcd);
780   }
781
782   /* Run the server. When this returns the server has been stopped
783      and we will exit. */
784   silc_server_run(silcd);
785
786   /* Stop the server and free it. */
787   silc_server_stop(silcd);
788   silc_server_config_destroy(silcd->config);
789   silc_server_free(silcd);
790
791   /* Flush the logging system */
792   silc_log_flush_all();
793
794   silc_free(silcd_config_file);
795   silc_free(opt_identifier);
796   silc_free(opt_keypath);
797   exit(0);
798
799  fail:
800   silc_free(silcd_config_file);
801   silc_free(opt_identifier);
802   silc_free(opt_keypath);
803   exit(1);
804 }