5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * Created: Wed Mar 19 00:17:12 1997
23 * This is the main program for the SILC daemon. This parses command
24 * line arguments and creates the server object.
28 #include "serverincludes.h"
29 #include "server_internal.h"
30 #include "silcversion.h"
32 /* For now, we'll have this one server context global for this module. */
33 static SilcServer silcd;
35 static void silc_usage(void);
36 static char *silc_server_create_identifier(void);
37 static int silc_server_create_key_pair(char *pkcs_name, int bits, char *path,
39 SilcPublicKey *ret_pub_key,
40 SilcPrivateKey *ret_prv_key);
42 /* Long command line options */
43 static struct option long_opts[] =
45 { "config-file", 1, NULL, 'f' },
46 { "passphrase", 1, NULL, 'p' },
47 { "debug", 2, NULL, 'd' },
48 { "debug-level", 1, NULL, 'D' },
49 { "hexdump", 0, NULL, 'x' },
50 { "help", 0, NULL, 'h' },
51 { "foreground", 0, NULL, 'F' },
52 { "version", 0, NULL,'V' },
54 /* Key management options */
55 { "create-key-pair", 1, NULL, 'C' },
56 { "pkcs", 1, NULL, 10 },
57 { "bits", 1, NULL, 11 },
58 { "identifier", 1, NULL, 12 },
63 /* Command line option variables */
64 static char *opt_keypath = NULL;
65 static char *opt_pkcs = "rsa";
66 static char *opt_identifier = NULL;
67 static int opt_bits = 2048;
69 /* Prints out the usage of silc client */
71 static void silc_usage(void)
74 "Usage: silcd [options]\n"
77 " -f --config-file=FILE Alternate configuration file\n"
78 " -d --debug=string Enable debugging (Implies --foreground)\n"
79 " -D --debug-level=level Enable debugging (Implies --foreground)\n"
80 " -x --hexdump Enable hexdumps (Implies --debug)\n"
81 " -h --help Display this message\n"
82 " -F --foreground Dont fork\n"
83 " -V --version Display version\n"
85 " Key Management Options:\n"
86 " -C, --create-key-pair=PATH Create new public key pair\n"
87 " --pkcs=PKCS Set the PKCS of the public key pair\n"
88 " --bits=VALUE Set length of the public key pair\n"
89 " --identifier=IDENTIFIER Public key identifier\n"
91 " The public key identifier may be of the following format:\n"
93 " UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n"
94 " O=<organization>, C=<country>\n"
96 " The UN and HN must be provided, the others are optional. If the\n"
97 " --identifier option is not used an identifier will be created for\n"
98 " the public key automatically.\n"
100 " Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n"
101 " E=foo@bar.com, C=FI\"\n"
106 /* Die if a *valid* pid file exists already */
108 static void silc_server_checkpid(SilcServer silcd)
110 if (silcd->config->server_info->pid_file) {
115 SILC_LOG_DEBUG(("Checking for another silcd running"));
116 buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
123 kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */
124 if (errno != ESRCH) {
125 fprintf(stderr, "\nI detected another daemon running with the "
127 fprintf(stderr, "Please change the config file, or erase the %s\n",
128 silcd->config->server_info->pid_file);
134 /* Drop root privileges. If some system call fails, die. */
136 static void silc_server_drop_privs(SilcServer server)
138 /* Are we executing silcd as root or a regular user? */
140 SILC_LOG_DEBUG(("Server started as user"));
147 SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
149 /* Get the values given for user and group in configuration file */
150 user = server->config->server_info->user;
151 group = server->config->server_info->group;
153 if (!user || !group) {
154 fprintf(stderr, "Error:"
155 "\tSILC server must not be run as root. For the security of your\n"
156 "\tsystem it is strongly suggested that you run SILC under dedicated\n"
157 "\tuser account. Modify the ServerInfo configuration section to run\n"
158 "\tthe server as non-root user.\n");
162 /* Check whether the user/group does not begin with a number */
163 if (isdigit(user[0]) || isdigit(group[0])) {
164 SILC_LOG_DEBUG(("User and/or group starts with a number"));
165 fprintf(stderr, "Invalid user and/or group information\n");
166 fprintf(stderr, "Please assign them as names, not numbers\n");
170 if (!(pw = getpwnam(user))) {
171 fprintf(stderr, "Error: No such user %s found.\n", user);
174 if (!(gr = getgrnam(group))) {
175 fprintf(stderr, "Error: No such group %s found.\n", group);
179 /* Check whether user and/or group is set to root. If yes, exit
180 immediately. Otherwise, setgid and setuid server to user.group */
181 if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
182 fprintf(stderr, "Error:"
183 "\tSILC server must not be run as root. For the security of your\n"
184 "\tsystem it is strongly suggested that you run SILC under dedicated\n"
185 "\tuser account. Modify the ServerInfo configuration section to run\n"
186 "\tthe server as non-root user.\n");
190 SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
191 if (setgid(gr->gr_gid) != 0) {
192 fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
196 #if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
197 SILC_LOG_DEBUG(("Removing supplementary groups"));
198 if (setgroups(0, NULL) != 0) {
199 fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
202 SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
203 if (initgroups(user, gr->gr_gid) != 0) {
204 fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
205 "Exiting.\n", user, gr->gr_gid);
209 SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
210 if (setuid(pw->pw_uid) != 0) {
211 fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
218 /* Fork server to background */
220 static void silc_server_daemonise(SilcServer server)
224 SILC_LOG_DEBUG(("Forking SILC server to background"));
226 if ((i = fork()) < 0) {
227 fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno));
231 if (i) /* Kill the parent */
234 server->background = TRUE;
237 /* XXX close stdin, stdout, stderr -- before this, check that all writes
238 to stderr are changed to SILC_SERVER_LOG_ERROR() */
241 static void signal_handler(int sig)
243 /* Mark the signal to be caller after this signal is over. */
244 silc_schedule_signal_call(silcd->schedule, sig);
247 SILC_TASK_CALLBACK(got_hup)
249 /* First, reset all log files (they might have been deleted) */
250 silc_log_reset_all();
252 /* Rehash the configuration file */
253 silc_server_rehash(silcd);
256 SILC_TASK_CALLBACK(stop_server)
258 /* Stop scheduler, the program will stop eventually after noticing
259 that the scheduler is down. */
260 silc_schedule_stop(silcd->schedule);
263 /* Dump server statistics into a file into /tmp directory */
265 SILC_TASK_CALLBACK(dump_stats)
270 memset(filename, 0, sizeof(filename));
271 snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats", getpid());
272 fdd = fopen(filename, "w+");
276 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
278 fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
279 fprintf(fdd, "Local Stats:\n");
280 STAT_OUTPUT(" My clients : %d", silcd->stat.my_clients);
281 STAT_OUTPUT(" My servers : %d", silcd->stat.my_servers);
282 STAT_OUTPUT(" My routers : %d", silcd->stat.my_routers);
283 STAT_OUTPUT(" My channels : %d", silcd->stat.my_channels);
284 STAT_OUTPUT(" My joined users : %d", silcd->stat.my_chanclients);
285 STAT_OUTPUT(" My aways : %d", silcd->stat.my_aways);
286 STAT_OUTPUT(" My detached clients : %d", silcd->stat.my_detached);
287 STAT_OUTPUT(" My server operators : %d", silcd->stat.my_server_ops);
288 STAT_OUTPUT(" My router operators : %d", silcd->stat.my_router_ops);
289 fprintf(fdd, "\nGlobal Stats:\n");
290 STAT_OUTPUT(" Cell clients : %d", silcd->stat.cell_clients);
291 STAT_OUTPUT(" Cell servers : %d", silcd->stat.cell_servers);
292 STAT_OUTPUT(" Cell channels : %d", silcd->stat.cell_channels);
293 STAT_OUTPUT(" Cell joined users : %d", silcd->stat.cell_chanclients);
294 STAT_OUTPUT(" All clients : %d", silcd->stat.clients);
295 STAT_OUTPUT(" All servers : %d", silcd->stat.servers);
296 STAT_OUTPUT(" All routers : %d", silcd->stat.routers);
297 STAT_OUTPUT(" All channels : %d", silcd->stat.channels);
298 STAT_OUTPUT(" All joined users : %d", silcd->stat.chanclients);
299 STAT_OUTPUT(" All aways : %d", silcd->stat.aways);
300 STAT_OUTPUT(" All detached clients : %d", silcd->stat.detached);
301 STAT_OUTPUT(" All server operators : %d", silcd->stat.server_ops);
302 STAT_OUTPUT(" All router operators : %d", silcd->stat.router_ops);
303 fprintf(fdd, "\nGeneral Stats:\n");
304 STAT_OUTPUT(" Connection attempts : %d", silcd->stat.conn_attempts);
305 STAT_OUTPUT(" Connection failures : %d", silcd->stat.conn_failures);
306 STAT_OUTPUT(" Authentication attempts : %d", silcd->stat.auth_attempts);
307 STAT_OUTPUT(" Authentication failures : %d", silcd->stat.auth_failures);
308 STAT_OUTPUT(" Packets sent : %d", silcd->stat.packets_sent);
309 STAT_OUTPUT(" Packets received : %d", silcd->stat.packets_received);
322 static DebugLevel debug_levels[] = {
323 /* Very basic stuff from silcd/ */
324 { 3, "silcd\\.c,server\\.c" },
326 /* More stuff from silcd/ */
327 { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
329 /* All basic stuff from silcd/ */
330 { 10, "silc_server_*" },
332 /* All from silcd/ */
333 { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
335 /* All from silcd/ and basic stuff from libs */
336 { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,*silcske*" },
338 /* All from silcd/ and more stuff from libs */
339 { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
340 "*silcpacket*,*ske*,*silcrng*" },
342 /* All from silcd/ and even more stuff from libs */
343 { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
344 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
346 /* All from silcd/ and even more stuff from libs + all from silccore */
347 { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
348 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
349 "*silcid*,*argument*" },
351 /* All from silcd/, all from silccore, silccrypt and silcmath */
352 { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
353 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
354 "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
356 /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
358 { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
359 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
360 "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
363 /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
365 { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
366 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
367 "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
368 "*sockconn*,*net*" },
370 /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
372 { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
373 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
374 "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
375 "*sockconn*,*net*,*log*,*config*" },
383 static void silc_get_debug_level(int level)
390 for (i = 0; debug_levels[i].string; i++)
391 if (level <= debug_levels[i].level) {
392 silc_log_set_debug_string(debug_levels[i].string);
397 /* This function should not be called directly but thru the wrapper
398 macro SILC_SERVER_LOG_STDERR() */
400 void silc_server_stderr(char *message)
402 if (silcd->background) {
403 char *p, *n = message;
405 /* remove newlines if we are going to output it to a log file */
406 for (p = n; *p; p++) {
415 silc_log_output(SILC_LOG_ERROR, message);
418 fprintf(stderr, "%s\n", message);
423 int main(int argc, char **argv)
425 int ret, opt, option_index;
426 bool foreground = FALSE;
427 bool opt_create_keypair = FALSE;
428 char *silcd_config_file = NULL;
431 /* Parse command line arguments */
433 while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
434 long_opts, &option_index)) != EOF) {
440 printf("SILCd Secure Internet Live Conferencing daemon, "
441 "version %s (base: SILC Toolkit %s)\n",
442 silc_dist_version, silc_version);
443 printf("(c) 1997 - 2002 Pekka Riikonen "
444 "<priikone@silcnet.org>\n");
451 silc_log_set_debug_string(optarg);
452 foreground = TRUE; /* implied */
453 silc_log_quick = TRUE; /* implied */
456 "Run-time debugging is not enabled. To enable it recompile\n"
457 "the server with --enable-debug configuration option.\n");
464 silc_get_debug_level(atoi(optarg));
465 foreground = TRUE; /* implied */
466 silc_log_quick = TRUE; /* implied */
469 "Run-time debugging is not enabled. To enable it recompile\n"
470 "the server with --enable-debug configuration option.\n");
475 silc_debug_hexdump = TRUE;
476 silc_debug = TRUE; /* implied */
477 foreground = TRUE; /* implied */
478 silc_log_quick = TRUE; /* implied */
481 "Run-time debugging is not enabled. To enable it recompile\n"
482 "the server with --enable-debug configuration option.\n");
486 silcd_config_file = strdup(optarg);
493 * Key management options
496 opt_create_keypair = TRUE;
498 opt_keypath = strdup(optarg);
502 opt_pkcs = strdup(optarg);
506 opt_bits = atoi(optarg);
510 opt_identifier = strdup(optarg);
520 if (opt_create_keypair == TRUE) {
521 /* Create new key pair and exit */
522 silc_cipher_register_default();
523 silc_pkcs_register_default();
524 silc_hash_register_default();
525 silc_hmac_register_default();
526 silc_server_create_key_pair(opt_pkcs, opt_bits, opt_keypath,
527 opt_identifier, NULL, NULL);
531 /* Default configuration file */
532 if (!silcd_config_file)
533 silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
535 /* Create SILC Server object */
536 ret = silc_server_alloc(&silcd);
540 /* Read configuration files */
541 silcd->config = silc_server_config_alloc(silcd_config_file);
542 if (silcd->config == NULL)
544 silcd->config_file = silcd_config_file;
546 /* Check for another silcd running */
547 silc_server_checkpid(silcd);
549 /* Initialize the server */
550 if (silc_server_init(silcd) == FALSE)
554 sa.sa_handler = SIG_IGN;
556 sigemptyset(&sa.sa_mask);
557 sigaction(SIGPIPE, &sa, NULL);
558 sa.sa_handler = signal_handler;
559 sigaction(SIGHUP, &sa, NULL);
560 sigaction(SIGTERM, &sa, NULL);
561 sigaction(SIGINT, &sa, NULL);
562 sigaction(SIGUSR1, &sa, NULL);
563 silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
564 silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
565 silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
566 silc_schedule_signal_register(silcd->schedule, SIGUSR1, dump_stats, NULL);
569 /* Before running the server, fork to background. */
570 silc_server_daemonise(silcd);
572 /* If set, write pid to file */
573 if (silcd->config->server_info->pid_file) {
574 char buf[10], *pidfile = silcd->config->server_info->pid_file;
576 snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
577 silc_file_writefile(pidfile, buf, strlen(buf));
581 /* Drop root if we are not in debug mode, so you don't need to bother about
582 file writing permissions and so on */
584 silc_server_drop_privs(silcd);
586 /* Run the server. When this returns the server has been stopped
588 silc_server_run(silcd);
590 /* Stop the server and free it. */
591 silc_server_stop(silcd);
592 silc_server_config_destroy(silcd->config);
593 silc_server_free(silcd);
595 /* Flush the logging system */
596 silc_log_flush_all();
598 silc_free(silcd_config_file);
599 silc_free(opt_identifier);
600 silc_free(opt_keypath);
604 silc_free(silcd_config_file);
605 silc_free(opt_identifier);
606 silc_free(opt_keypath);
610 /* Returns identifier string for public key generation. */
612 static char *silc_server_create_identifier(void)
614 char *username = NULL, *realname = NULL;
615 char hostname[256], email[256];
618 realname = silc_get_real_name();
621 memset(hostname, 0, sizeof(hostname));
622 gethostname(hostname, sizeof(hostname));
624 /* Get username (mandatory) */
625 username = silc_get_username();
629 /* Create default email address, whether it is right or not */
630 snprintf(email, sizeof(email), "%s@%s", username, hostname);
632 return silc_pkcs_encode_identifier(username, hostname, realname, email,
636 /* Creates new public key and private key pair. This is used only
637 when user wants to create new key pair from command line. */
640 silc_server_create_key_pair(char *pkcs_name, int bits, char *path,
642 SilcPublicKey *ret_pub_key,
643 SilcPrivateKey *ret_prv_key)
646 SilcPublicKey pub_key;
647 SilcPrivateKey prv_key;
651 char pkfile[256], prvfile[256];
653 if (!pkcs_name || !path)
656 if (!silc_pkcs_is_supported(pkcs_name)) {
657 fprintf(stderr, "Unsupported PKCS `%s'", pkcs_name);
665 identifier = silc_server_create_identifier();
667 rng = silc_rng_alloc();
669 silc_rng_global_init(rng);
671 snprintf(pkfile, sizeof(pkfile) - 1, "%s%s", path,
672 SILC_SERVER_PUBLIC_KEY_NAME);
673 snprintf(prvfile, sizeof(prvfile) - 1, "%s%s", path,
674 SILC_SERVER_PRIVATE_KEY_NAME);
677 silc_pkcs_alloc(pkcs_name, &pkcs);
678 silc_pkcs_generate_key(pkcs, bits, rng);
680 /* Save public key into file */
681 key = silc_pkcs_get_public_key(pkcs, &key_len);
682 pub_key = silc_pkcs_public_key_alloc(silc_pkcs_get_name(pkcs), identifier,
684 silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
686 *ret_pub_key = pub_key;
688 silc_pkcs_public_key_free(pub_key);
690 memset(key, 0, sizeof(key_len));
693 /* Save private key into file */
694 key = silc_pkcs_get_private_key(pkcs, &key_len);
695 prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs),
697 silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
699 *ret_prv_key = prv_key;
701 silc_pkcs_private_key_free(prv_key);
703 printf("Public key has been saved into `%s'\n", pkfile);
704 printf("Private key has been saved into `%s'\n", prvfile);
706 memset(key, 0, sizeof(key_len));
710 silc_pkcs_free(pkcs);