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