5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
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.
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.
20 * Created: Wed Mar 19 00:17:12 1997
22 * This is the main program for the SILC daemon. This parses command
23 * line arguments and creates the server object.
27 #include "serverincludes.h"
28 #include "server_internal.h"
29 #include "silcversion.h"
31 /* For now, we'll have this one server context global for this module. */
32 static SilcServer silcd;
34 static void silc_usage(void);
36 #ifdef HAVE_GETOPT_LONG
37 /* Long command line options */
38 static struct option long_opts[] =
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' },
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 },
57 #endif /* HAVE_GETOPT_LONG */
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;
65 /* Prints out the usage of silc client */
67 static void silc_usage(void)
70 "Usage: silcd [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"
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"
87 " The public key identifier may be of the following format:\n"
89 " UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n"
90 " O=<organization>, C=<country>\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"
96 " Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n"
97 " E=foo@bar.com, C=FI\"\n"
102 /* Die if a *valid* pid file exists already */
104 static void silc_server_checkpid(SilcServer silcd)
106 if (silcd->config->server_info->pid_file) {
111 SILC_LOG_DEBUG(("Checking for another silcd running"));
112 buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
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 "
123 fprintf(stderr, "Please change the config file, or erase the %s\n",
124 silcd->config->server_info->pid_file);
130 /* Drop root privileges. If some system call fails, die. */
132 static void silc_server_drop_privs(SilcServer server)
134 /* Are we executing silcd as root or a regular user? */
136 SILC_LOG_DEBUG(("Server started as user"));
143 SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
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;
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");
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");
166 if (!(pw = getpwnam(user))) {
167 fprintf(stderr, "Error: No such user %s found.\n", user);
170 if (!(gr = getgrnam(group))) {
171 fprintf(stderr, "Error: No such group %s found.\n", group);
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");
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",
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");
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);
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",
214 /* Fork server to background */
216 static void silc_server_daemonise(SilcServer server)
220 SILC_LOG_DEBUG(("Forking SILC server to background"));
222 if ((i = fork()) < 0) {
223 fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno));
227 if (i) /* Kill the parent */
230 server->background = TRUE;
233 /* XXX close stdin, stdout, stderr -- before this, check that all writes
234 to stderr are changed to SILC_SERVER_LOG_ERROR() */
237 SILC_TASK_CALLBACK(got_hup)
239 /* First, reset all log files (they might have been deleted) */
240 silc_log_reset_all();
242 /* Rehash the configuration file */
243 silc_server_rehash(silcd);
246 SILC_TASK_CALLBACK(stop_server)
248 silc_server_stop(silcd);
251 /* Dump server statistics into a file into /tmp directory */
253 SILC_TASK_CALLBACK(dump_stats)
259 memset(filename, 0, sizeof(filename));
260 snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats-XXXXXX", getpid());
261 fild = mkstemp(filename);
265 fdd = fdopen(fild, "w");
272 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
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);
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);
325 fprintf(fdd, " primary router : %s\n",
326 silcd->router->server_name ? silcd->router->server_name : "");
328 /* Dump connections */
331 SilcDList conns = silc_packet_engine_get_streams(silcd->packet_engine);
333 fprintf(fdd, "\nDumping connections\n");
334 silc_dlist_start(conns);
335 while ((s = silc_dlist_get(conns))) {
336 const char *hostname, *ip;
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))
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);
347 silc_dlist_uninit(conns);
353 SilcIDCacheEntry id_cache = NULL;
354 SilcServerEntry server_entry;
355 SilcClientEntry client_entry;
356 SilcChannelEntry channel_entry;
359 fprintf(fdd, "\nDumping databases\n");
361 if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
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);
374 if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
375 fprintf(fdd, "\nServers in global-list:\n");
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);
387 if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
388 fprintf(fdd, "\nClients in local-list:\n");
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 :
403 if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
404 fprintf(fdd, "\nClients in global-list:\n");
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 :
419 if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
420 fprintf(fdd, "\nChannels in local-list:\n");
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");
431 if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
432 fprintf(fdd, "\nChannels in global-list:\n");
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");
457 static DebugLevel debug_levels[] = {
458 /* Very basic stuff from silcd/ */
459 { 3, "silcd\\.c,server\\.c" },
461 /* More stuff from silcd/ */
462 { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
464 /* All basic stuff from silcd/ */
465 { 10, "silc_server_*" },
467 /* All from silcd/ */
468 { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
470 /* All from silcd/ and basic stuff from libs */
471 { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*silcske*" },
473 /* All from silcd/ and more stuff from libs */
474 { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
475 "*silcpacket*,*ske*,*silcrng*" },
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*" },
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*" },
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*" },
491 /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
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*"
498 /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
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*" },
505 /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
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*" },
518 static void silc_get_debug_level(int level)
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);
531 #endif /* SILC_DEBUG */
533 /* This function should not be called directly but through the appropriate
534 wrapper macro defined in server.h */
536 void silc_server_stderr(SilcLogType type, char *message)
538 if (silcd->background) {
539 char *p, *n = message;
541 /* remove newlines if we are going to output it to a log file */
542 for (p = n; *p; p++) {
551 /* the message is freed inside the logging function */
552 silc_log_output(type, message);
555 fprintf(stderr, "%s\n", message);
560 int main(int argc, char **argv)
562 int ret, opt, option_index;
563 SilcBool foreground = FALSE;
564 SilcBool opt_create_keypair = FALSE;
565 char *silcd_config_file = NULL;
568 /* Parse command line arguments */
570 #ifdef HAVE_GETOPT_LONG
571 while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
572 long_opts, &option_index)) != EOF) {
574 while ((opt = getopt(argc, argv, "f:p:d:D:xhFVC:")) != EOF) {
575 #endif /* HAVE_GETOPT_LONG */
581 printf("SILCd Secure Internet Live Conferencing daemon, "
582 "version %s (base: SILC Toolkit %s)\n",
583 silc_dist_version, silc_version);
584 printf("(c) 1997 - 2007 Pekka Riikonen "
585 "<priikone@silcnet.org>\n");
590 silc_log_debug(TRUE);
591 silc_log_quick(TRUE);
593 silc_log_set_debug_string(optarg);
594 foreground = TRUE; /* implied */
597 "Run-time debugging is not enabled. To enable it recompile\n"
598 "the server with --enable-debug configuration option.\n");
603 silc_log_debug(TRUE);
604 silc_log_quick(TRUE);
606 silc_get_debug_level(atoi(optarg));
607 foreground = TRUE; /* implied */
610 "Run-time debugging is not enabled. To enable it recompile\n"
611 "the server with --enable-debug configuration option.\n");
616 silc_log_debug(TRUE);
617 silc_log_debug_hexdump(TRUE);
618 silc_log_quick(TRUE);
619 foreground = TRUE; /* implied */
622 "Run-time debugging is not enabled. To enable it recompile\n"
623 "the server with --enable-debug configuration option.\n");
627 silcd_config_file = strdup(optarg);
634 * Key management options
637 opt_create_keypair = TRUE;
639 opt_keypath = strdup(optarg);
643 opt_pkcs = strdup(optarg);
647 opt_bits = atoi(optarg);
651 opt_identifier = strdup(optarg);
661 if (opt_create_keypair == TRUE) {
662 /* Create new key pair and exit */
663 char pubfile[256], prvfile[256];
665 memset(pubfile, 0, sizeof(pubfile));
666 memset(prvfile, 0, sizeof(prvfile));
667 snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
668 snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
670 silc_cipher_register_default();
671 silc_pkcs_register_default();
672 silc_hash_register_default();
673 silc_hmac_register_default();
674 if (!silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
675 opt_identifier, "", NULL, NULL, FALSE))
680 /* Default configuration file */
681 if (!silcd_config_file)
682 silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
684 /* Create SILC Server object */
685 ret = silc_server_alloc(&silcd);
689 /* Register default crypto stuff since we are going to need them
690 in the configuration file parsing phase */
691 silc_cipher_register_default();
692 silc_pkcs_register_default();
693 silc_hash_register_default();
694 silc_hmac_register_default();
696 /* Read configuration files */
697 silcd->config = silc_server_config_alloc(silcd_config_file, silcd);
698 if (silcd->config == NULL)
700 silcd->config_file = silcd_config_file;
702 /* Unregister the default crypto stuff so that configuration takes effect */
703 silc_cipher_unregister_all();
704 /* silc_pkcs_unregister_all(); MUST NOT do this anymore; SilcPublicKey
705 parsed from config file references pointers so we cannot unregister */
706 silc_hash_unregister_all();
707 silc_hmac_unregister_all();
709 /* Check for another silcd running */
710 silc_server_checkpid(silcd);
712 /* Initialize the server */
713 if (silc_server_init(silcd) == FALSE)
716 /* Ignore some signals */
717 sa.sa_handler = SIG_IGN;
719 sigemptyset(&sa.sa_mask);
721 sigaction(SIGPIPE, &sa, NULL); /* Ignore broken pipes */
724 sigaction(SIGXFSZ, &sa, NULL); /* Ignore file limit exceeds */
727 sigaction(SIGXCPU, &sa, NULL); /* Ignore CPU time limit exceeds */
730 /* Handle specificly some other signals. */
731 silc_schedule_task_add_signal(silcd->schedule, SIGHUP, got_hup, NULL);
732 silc_schedule_task_add_signal(silcd->schedule, SIGTERM, stop_server, NULL);
733 silc_schedule_task_add_signal(silcd->schedule, SIGINT, stop_server, NULL);
734 silc_schedule_task_add_signal(silcd->schedule, SIGUSR1, dump_stats, NULL);
737 /* Before running the server, fork to background. */
738 silc_server_daemonise(silcd);
740 /* If set, write pid to file */
741 if (silcd->config->server_info->pid_file) {
742 char buf[10], *pidfile = silcd->config->server_info->pid_file;
744 snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
745 silc_file_writefile(pidfile, buf, strlen(buf));
749 silc_server_drop_privs(silcd);
751 /* Run the server. When this returns the server has been stopped
753 silc_server_run(silcd);
756 silc_server_config_destroy(silcd->config);
757 silc_server_free(silcd);
759 /* Flush the logging system */
760 silc_log_flush_all();
762 silc_free(silcd_config_file);
763 silc_free(opt_identifier);
764 silc_free(opt_keypath);
768 silc_free(silcd_config_file);
769 silc_free(opt_identifier);
770 silc_free(opt_keypath);