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 { "hexdump", 0, NULL, 'x' },
49 { "help", 0, NULL, 'h' },
50 { "foreground", 0, NULL, 'F' },
51 { "version", 0, NULL,'V' },
53 /* Key management options */
54 { "create-key-pair", 1, NULL, 'C' },
55 { "pkcs", 1, NULL, 10 },
56 { "bits", 1, NULL, 11 },
57 { "identifier", 1, NULL, 12 },
62 /* Command line option variables */
63 static char *opt_keypath = NULL;
64 static char *opt_pkcs = "rsa";
65 static char *opt_identifier = NULL;
66 static int opt_bits = 2048;
68 /* Prints out the usage of silc client */
70 static void silc_usage(void)
73 "Usage: silcd [options]\n"
76 " -f --config-file=FILE Alternate configuration file\n"
77 " -d --debug=string Enable debugging (Implies --foreground)\n"
78 " -x --hexdump Enable hexdumps (Implies --debug)\n"
79 " -h --help Display this message\n"
80 " -F --foreground Dont fork\n"
81 " -V --version Display version\n"
83 " Key Management Options:\n"
84 " -C, --create-key-pair=PATH Create new public key pair\n"
85 " --pkcs=PKCS Set the PKCS of the public key pair\n"
86 " --bits=VALUE Set length of the public key pair\n"
87 " --identifier=IDENTIFIER Public key identifier\n"
89 " The public key identifier may be of the following format:\n"
91 " UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n"
92 " O=<organization>, C=<country>\n"
94 " The UN and HN must be provided, the others are optional. If the\n"
95 " --identifier option is not used an identifier will be created for\n"
96 " the public key automatically.\n"
98 " Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n"
99 " E=foo@bar.com, C=FI\"\n"
104 /* Die if a *valid* pid file exists already */
106 static void silc_server_checkpid(SilcServer silcd)
108 if (silcd->config->server_info->pid_file) {
113 SILC_LOG_DEBUG(("Checking for another silcd running"));
114 buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
121 kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */
122 if (errno != ESRCH) {
123 fprintf(stderr, "\nI detected another daemon running with the "
125 fprintf(stderr, "Please change the config file, or erase the %s\n",
126 silcd->config->server_info->pid_file);
132 /* Drop root privileges. If some system call fails, die. */
134 static void silc_server_drop_privs(SilcServer server)
136 /* Are we executing silcd as root or a regular user? */
138 SILC_LOG_DEBUG(("Server started as user"));
145 SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
147 /* Get the values given for user and group in configuration file */
148 user = server->config->server_info->user;
149 group = server->config->server_info->group;
151 if (!user || !group) {
152 fprintf(stderr, "Error:"
153 "\tSILC server must not be run as root. For the security of your\n"
154 "\tsystem it is strongly suggested that you run SILC under dedicated\n"
155 "\tuser account. Modify the ServerInfo configuration section to run\n"
156 "\tthe server as non-root user.\n");
160 /* Check whether the user/group does not begin with a number */
161 if (isdigit(user[0]) || isdigit(group[0])) {
162 SILC_LOG_DEBUG(("User and/or group starts with a number"));
163 fprintf(stderr, "Invalid user and/or group information\n");
164 fprintf(stderr, "Please assign them as names, not numbers\n");
168 if (!(pw = getpwnam(user))) {
169 fprintf(stderr, "Error: No such user %s found.\n", user);
172 if (!(gr = getgrnam(group))) {
173 fprintf(stderr, "Error: No such group %s found.\n", group);
177 /* Check whether user and/or group is set to root. If yes, exit
178 immediately. Otherwise, setgid and setuid server to user.group */
179 if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
180 fprintf(stderr, "Error:"
181 "\tSILC server must not be run as root. For the security of your\n"
182 "\tsystem it is strongly suggested that you run SILC under dedicated\n"
183 "\tuser account. Modify the ServerInfo configuration section to run\n"
184 "\tthe server as non-root user.\n");
188 SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
189 if (setgid(gr->gr_gid) != 0) {
190 fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
194 #if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
195 SILC_LOG_DEBUG(("Removing supplementary groups"));
196 if (setgroups(0, NULL) != 0) {
197 fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
200 SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
201 if (initgroups(user, gr->gr_gid) != 0) {
202 fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
203 "Exiting.\n", user, gr->gr_gid);
207 SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
208 if (setuid(pw->pw_uid) != 0) {
209 fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
216 /* Fork server to background */
218 static void silc_server_daemonise(SilcServer server)
222 SILC_LOG_DEBUG(("Forking SILC server to background"));
224 if ((i = fork()) < 0) {
225 fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno));
229 if (i) /* Kill the parent */
232 server->background = TRUE;
235 /* XXX close stdin, stdout, stderr -- before this, check that all writes
236 to stderr are changed to SILC_SERVER_LOG_ERROR() */
239 static void signal_handler(int sig)
241 /* Mark the signal to be caller after this signal is over. */
242 silc_schedule_signal_call(silcd->schedule, sig);
245 SILC_TASK_CALLBACK(got_hup)
247 /* First, reset all log files (they might have been deleted) */
248 silc_log_reset_all();
250 /* Rehash the configuration file */
251 silc_server_rehash(silcd);
254 SILC_TASK_CALLBACK(stop_server)
256 /* Stop scheduler, the program will stop eventually after noticing
257 that the scheduler is down. */
258 silc_schedule_stop(silcd->schedule);
261 /* Dump server statistics into a file into /tmp directory */
263 SILC_TASK_CALLBACK(dump_stats)
268 memset(filename, 0, sizeof(filename));
269 snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats", getpid());
270 fdd = fopen(filename, "w+");
274 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
276 fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
277 fprintf(fdd, "Local Stats:\n");
278 STAT_OUTPUT(" My clients : %d", silcd->stat.my_clients);
279 STAT_OUTPUT(" My servers : %d", silcd->stat.my_servers);
280 STAT_OUTPUT(" My routers : %d", silcd->stat.my_routers);
281 STAT_OUTPUT(" My channels : %d", silcd->stat.my_channels);
282 STAT_OUTPUT(" My joined users : %d", silcd->stat.my_chanclients);
283 STAT_OUTPUT(" My aways : %d", silcd->stat.my_aways);
284 STAT_OUTPUT(" My detached clients : %d", silcd->stat.my_detached);
285 STAT_OUTPUT(" My server operators : %d", silcd->stat.my_server_ops);
286 STAT_OUTPUT(" My router operators : %d", silcd->stat.my_router_ops);
287 fprintf(fdd, "\nGlobal Stats:\n");
288 STAT_OUTPUT(" Cell clients : %d", silcd->stat.cell_clients);
289 STAT_OUTPUT(" Cell servers : %d", silcd->stat.cell_servers);
290 STAT_OUTPUT(" Cell channels : %d", silcd->stat.cell_channels);
291 STAT_OUTPUT(" Cell joined users : %d", silcd->stat.cell_chanclients);
292 STAT_OUTPUT(" All clients : %d", silcd->stat.clients);
293 STAT_OUTPUT(" All servers : %d", silcd->stat.servers);
294 STAT_OUTPUT(" All routers : %d", silcd->stat.routers);
295 STAT_OUTPUT(" All channels : %d", silcd->stat.channels);
296 STAT_OUTPUT(" All joined users : %d", silcd->stat.chanclients);
297 STAT_OUTPUT(" All aways : %d", silcd->stat.aways);
298 STAT_OUTPUT(" All detached clients : %d", silcd->stat.detached);
299 STAT_OUTPUT(" All server operators : %d", silcd->stat.server_ops);
300 STAT_OUTPUT(" All router operators : %d", silcd->stat.router_ops);
301 fprintf(fdd, "\nGeneral Stats:\n");
302 STAT_OUTPUT(" Connection attempts : %d", silcd->stat.conn_attempts);
303 STAT_OUTPUT(" Connection failures : %d", silcd->stat.conn_failures);
304 STAT_OUTPUT(" Authentication attempts : %d", silcd->stat.auth_attempts);
305 STAT_OUTPUT(" Authentication failures : %d", silcd->stat.auth_failures);
306 STAT_OUTPUT(" Packets sent : %d", silcd->stat.packets_sent);
307 STAT_OUTPUT(" Packets received : %d", silcd->stat.packets_received);
313 /* This function should not be called directly but throught the wrapper
314 macro SILC_SERVER_LOG_STDERR() */
316 void silc_server_stderr(char *message)
318 if (silcd->background)
319 silc_log_output(SILC_LOG_ERROR, message);
321 fprintf(stderr, "%s", message);
326 int main(int argc, char **argv)
328 int ret, opt, option_index;
329 bool foreground = FALSE;
330 bool opt_create_keypair = FALSE;
331 char *silcd_config_file = NULL;
334 /* Parse command line arguments */
336 while ((opt = getopt_long(argc, argv, "f:p:d:xhFVC:",
337 long_opts, &option_index)) != EOF) {
343 printf("SILCd Secure Internet Live Conferencing daemon, "
344 "version %s (base: SILC Toolkit %s)\n",
345 silc_dist_version, silc_version);
346 printf("(c) 1997 - 2002 Pekka Riikonen "
347 "<priikone@silcnet.org>\n");
354 silc_log_set_debug_string(optarg);
355 foreground = TRUE; /* implied */
356 silc_log_quick = TRUE; /* implied */
359 "Run-time debugging is not enabled. To enable it recompile\n"
360 "the server with --enable-debug configuration option.\n");
365 silc_debug_hexdump = TRUE;
366 silc_debug = TRUE; /* implied */
367 foreground = TRUE; /* implied */
368 silc_log_quick = TRUE; /* implied */
371 "Run-time debugging is not enabled. To enable it recompile\n"
372 "the server with --enable-debug configuration option.\n");
376 silcd_config_file = strdup(optarg);
383 * Key management options
386 opt_create_keypair = TRUE;
388 opt_keypath = strdup(optarg);
392 opt_pkcs = strdup(optarg);
396 opt_bits = atoi(optarg);
400 opt_identifier = strdup(optarg);
410 if (opt_create_keypair == TRUE) {
411 /* Create new key pair and exit */
412 silc_cipher_register_default();
413 silc_pkcs_register_default();
414 silc_hash_register_default();
415 silc_hmac_register_default();
416 silc_server_create_key_pair(opt_pkcs, opt_bits, opt_keypath,
417 opt_identifier, NULL, NULL);
421 /* Default configuration file */
422 if (!silcd_config_file)
423 silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
425 /* Create SILC Server object */
426 ret = silc_server_alloc(&silcd);
430 /* Read configuration files */
431 silcd->config = silc_server_config_alloc(silcd_config_file);
432 if (silcd->config == NULL)
434 silcd->config_file = silcd_config_file;
436 /* Check for another silcd running */
437 silc_server_checkpid(silcd);
439 /* Initialize the server */
440 if (silc_server_init(silcd) == FALSE)
444 sa.sa_handler = SIG_IGN;
446 sigemptyset(&sa.sa_mask);
447 sigaction(SIGPIPE, &sa, NULL);
448 sa.sa_handler = signal_handler;
449 sigaction(SIGHUP, &sa, NULL);
450 sigaction(SIGTERM, &sa, NULL);
451 sigaction(SIGINT, &sa, NULL);
452 sigaction(SIGUSR1, &sa, NULL);
453 silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
454 silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
455 silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
456 silc_schedule_signal_register(silcd->schedule, SIGUSR1, dump_stats, NULL);
459 /* Before running the server, fork to background. */
460 silc_server_daemonise(silcd);
462 /* If set, write pid to file */
463 if (silcd->config->server_info->pid_file) {
464 char buf[10], *pidfile = silcd->config->server_info->pid_file;
466 snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
467 silc_file_writefile(pidfile, buf, strlen(buf));
471 /* Drop root if we are not in debug mode, so you don't need to bother about
472 file writing permissions and so on */
474 silc_server_drop_privs(silcd);
476 /* Run the server. When this returns the server has been stopped
478 silc_server_run(silcd);
480 /* Stop the server and free it. */
481 silc_server_stop(silcd);
482 silc_server_config_destroy(silcd->config);
483 silc_server_free(silcd);
485 /* Flush the logging system */
486 silc_log_flush_all();
488 silc_free(silcd_config_file);
489 silc_free(opt_identifier);
490 silc_free(opt_keypath);
494 silc_free(silcd_config_file);
495 silc_free(opt_identifier);
496 silc_free(opt_keypath);
500 /* Returns identifier string for public key generation. */
502 static char *silc_server_create_identifier(void)
504 char *username = NULL, *realname = NULL;
505 char hostname[256], email[256];
508 realname = silc_get_real_name();
511 memset(hostname, 0, sizeof(hostname));
512 gethostname(hostname, sizeof(hostname));
514 /* Get username (mandatory) */
515 username = silc_get_username();
519 /* Create default email address, whether it is right or not */
520 snprintf(email, sizeof(email), "%s@%s", username, hostname);
522 return silc_pkcs_encode_identifier(username, hostname, realname, email,
526 /* Creates new public key and private key pair. This is used only
527 when user wants to create new key pair from command line. */
530 silc_server_create_key_pair(char *pkcs_name, int bits, char *path,
532 SilcPublicKey *ret_pub_key,
533 SilcPrivateKey *ret_prv_key)
536 SilcPublicKey pub_key;
537 SilcPrivateKey prv_key;
541 char pkfile[256], prvfile[256];
543 if (!pkcs_name || !path)
546 if (!silc_pkcs_is_supported(pkcs_name)) {
547 fprintf(stderr, "Unsupported PKCS `%s'", pkcs_name);
555 identifier = silc_server_create_identifier();
557 rng = silc_rng_alloc();
559 silc_rng_global_init(rng);
561 snprintf(pkfile, sizeof(pkfile) - 1, "%s%s", path,
562 SILC_SERVER_PUBLIC_KEY_NAME);
563 snprintf(prvfile, sizeof(prvfile) - 1, "%s%s", path,
564 SILC_SERVER_PRIVATE_KEY_NAME);
567 silc_pkcs_alloc(pkcs_name, &pkcs);
568 silc_pkcs_generate_key(pkcs, bits, rng);
570 /* Save public key into file */
571 key = silc_pkcs_get_public_key(pkcs, &key_len);
572 pub_key = silc_pkcs_public_key_alloc(silc_pkcs_get_name(pkcs), identifier,
574 silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
576 *ret_pub_key = pub_key;
578 silc_pkcs_public_key_free(pub_key);
580 memset(key, 0, sizeof(key_len));
583 /* Save private key into file */
584 key = silc_pkcs_get_private_key(pkcs, &key_len);
585 prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs),
587 silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
589 *ret_prv_key = prv_key;
591 silc_pkcs_private_key_free(prv_key);
593 printf("Public key has been saved into `%s'\n", pkfile);
594 printf("Private key has been saved into `%s'\n", prvfile);
596 memset(key, 0, sizeof(key_len));
600 silc_pkcs_free(pkcs);