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