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