X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fsilcd.c;h=cf3315a2cd126100a2611548ee6e1c271d797dda;hp=0de8874a5d8fe8353af8c4b64958b6ebb7162cca;hb=d47a87b03b846e2333ef57b2c0d81f1644992964;hpb=23c5df1c8b0bfe539d3fa65802186e6e09e044aa diff --git a/apps/silcd/silcd.c b/apps/silcd/silcd.c index 0de8874a..cf3315a2 100644 --- a/apps/silcd/silcd.c +++ b/apps/silcd/silcd.c @@ -1,96 +1,211 @@ /* silcd.c - - Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + Author: Pekka Riikonen + + Copyright (C) 1997 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ -/* +/* * Created: Wed Mar 19 00:17:12 1997 * * This is the main program for the SILC daemon. This parses command * line arguments and creates the server object. */ -/* - * $Id$ - * $Log$ - * Revision 1.1.1.1 2000/06/27 11:36:56 priikone - * Importet from internal CVS/Added Log headers. - * - * - */ +/* $Id$ */ #include "serverincludes.h" #include "server_internal.h" #include "version.h" +/* For now, we'll have this one server context global for this module. */ +static SilcServer silcd; + +static void silc_usage(); +static char *silc_server_create_identifier(); +static int +silc_server_create_key_pair(char *pkcs_name, int bits, char *path, + char *identifier, + SilcPublicKey *ret_pub_key, + SilcPrivateKey *ret_prv_key); + /* Long command line options */ -static struct option long_opts[] = +static struct option long_opts[] = { { "config-file", 1, NULL, 'f' }, - { "generate-config-file", 0, NULL, 'c' }, + { "debug", 1, NULL, 'd' }, { "help", 0, NULL, 'h' }, + { "foreground", 0, NULL, 'F' }, { "version", 0, NULL,'V' }, + + /* Key management options */ + { "create-key-pair", 1, NULL, 'C' }, + { "pkcs", 1, NULL, 10 }, + { "bits", 1, NULL, 11 }, + { "identifier", 1, NULL, 12 }, + { NULL, 0, NULL, 0 } }; +/* Command line option variables */ +static bool opt_create_keypair = FALSE; +static char *opt_keypath = NULL; +static char *opt_pkcs = "rsa"; +static char *opt_identifier = NULL; +static int opt_bits = 1024; + /* Prints out the usage of silc client */ -void silc_usage() +static void silc_usage() { - printf("Usage: silcd [options]\n"); - printf("Options:\n"); - printf(" -f --config-file=FILE Alternate configuration file\n"); - printf(" -c --generate-config-file Generate example configuration " - "file\n"); - printf(" -h --help Display this message\n"); - printf(" -V --version Display version\n"); + printf("\ +Usage: silcd [options]\n\ +\n\ + Generic Options:\n\ + -f --config-file=FILE Alternate configuration file\n\ + -d --debug=string Enable debugging (Implies --foreground)\n\ + -h --help Display this message\n\ + -F --foreground Dont fork\n\ + -V --version Display version\n\ +\n\ + Key Management Options:\n\ + -C, --create-key-pair=PATH Create new public key pair\n\ + --pkcs=PKCS Set the PKCS of the public key pair\n\ + --bits=VALUE Set length of the public key pair\n\ + --identifier=IDENTIFIER Public key identifier\n\ +\n\ + The public key identifier may be of the following format:\n\ +\n\ + UN=, HN=, RN=, E=,\n\ + O=, C=\n\ +\n\ + The UN and HN must be provided, the others are optional. If the\n\ + --identifier option is not used an identifier will be created for\n\ + the public key automatically.\n\ +\n\ + Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n\ + E=foo@bar.com, C=FI\"\n\ +\n"); exit(0); } +/* Dies if a *valid* pid file exists already */ + +static void silc_server_checkpid(SilcServer silcd) +{ + if (silcd->config->server_info->pid_file) { + int oldpid; + char *buf; + uint32 buf_len; + + SILC_LOG_DEBUG(("Checking for another silcd running")); + buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len); + if (!buf) + return; + oldpid = atoi(buf); + silc_free(buf); + if (oldpid <= 0) + return; + kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */ + if (errno != ESRCH) { + fprintf(stderr, "\nI detected another daemon running with the same pid file.\n"); + fprintf(stderr, "Please change the config file, or erase the %s\n", + silcd->config->server_info->pid_file); + exit(1); + } + } +} + +static void got_hup(int z) +{ + /* First, reset all log files (they might have been deleted) */ + silc_log_reset_all(); + silc_log_flush_all(); +} + +static void stop_server(int z) +{ + /* Stop scheduler, the program will stop eventually after noticing + that the scheduler is down. */ + silc_schedule_stop(silcd->schedule); +} + int main(int argc, char **argv) { - int ret; - int opt, option_index; + int ret, opt, option_index; char *config_file = NULL; - SilcServer silcd; + bool foreground = FALSE; + struct sigaction sa; /* Parse command line arguments */ if (argc > 1) { - while ((opt = getopt_long(argc, argv, "cf:hV", + while ((opt = getopt_long(argc, argv, "cf:d:hFVC:", long_opts, &option_index)) != EOF) { - switch(opt) + switch(opt) { case 'h': silc_usage(); break; case 'V': printf("SILCd Secure Internet Live Conferencing daemon, " - "version %s\n", silc_version); - printf("(c) 1997 - 2000 Pekka Riikonen " - "\n"); + "version %s (base: SILC Toolkit %s)\n", + silc_dist_version, silc_version); + printf("(c) 1997 - 2001 Pekka Riikonen " + "\n"); exit(0); break; - case 'c': - /* Print out example configuration file */ - silc_config_server_print(); - exit(0); + case 'd': +#ifdef SILC_DEBUG + silc_debug = TRUE; + silc_debug_hexdump = TRUE; + silc_log_set_debug_string(optarg); + foreground = TRUE; + silc_log_quick = TRUE; +#else + fprintf(stdout, + "Run-time debugging is not enabled. To enable it recompile\n" + "the server with --enable-debug configuration option.\n"); +#endif break; case 'f': config_file = strdup(optarg); break; + case 'F': + foreground = TRUE; + break; + + /* + * Key management options + */ + case 'C': + opt_create_keypair = TRUE; + if (optarg) + opt_keypath = strdup(optarg); + break; + case 10: + if (optarg) + opt_pkcs = strdup(optarg); + break; + case 11: + if (optarg) + opt_bits = atoi(optarg); + break; + case 12: + if (optarg) + opt_identifier = strdup(optarg); + break; + default: silc_usage(); break; @@ -98,6 +213,17 @@ int main(int argc, char **argv) } } + if (opt_create_keypair == TRUE) { + /* Create new key pair and exit */ + silc_cipher_register_default(); + silc_pkcs_register_default(); + silc_hash_register_default(); + silc_hmac_register_default(); + silc_server_create_key_pair(opt_pkcs, opt_bits, opt_keypath, + opt_identifier, NULL, NULL); + exit(0); + } + /* Default configuration file */ if (!config_file) config_file = strdup(SILC_SERVER_CONFIG_FILE); @@ -108,25 +234,161 @@ int main(int argc, char **argv) goto fail; /* Read configuration files */ - silcd->config = silc_config_server_alloc(config_file); + silcd->config = silc_server_config_alloc(config_file); if (silcd->config == NULL) goto fail; + /* Check for another silcd running */ + silc_server_checkpid(silcd); + /* Initialize the server */ ret = silc_server_init(silcd); if (ret == FALSE) goto fail; - + + /* Ignore SIGPIPE */ + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(SIGPIPE, &sa, NULL); + sa.sa_handler = got_hup; + sigaction(SIGHUP, &sa, NULL); + sa.sa_handler = stop_server; + sigaction(SIGTERM, &sa, NULL); + sa.sa_handler = stop_server; + sigaction(SIGINT, &sa, NULL); + + /* Before running the server, fork to background. */ + if (!foreground) + silc_server_daemonise(silcd); + + /* If set, write pid to file */ + if (silcd->config->server_info->pid_file) { + char buf[10], *pidfile = silcd->config->server_info->pid_file; + unlink(pidfile); + snprintf(buf, sizeof(buf) - 1, "%d\n", getpid()); + silc_file_writefile(pidfile, buf, strlen(buf)); + } + + /* Drop root. */ + silc_server_drop(silcd); + /* Run the server. When this returns the server has been stopped and we will exit. */ silc_server_run(silcd); - /* Stop the server. This probably has been done already but it - doesn't hurt to do it here again. */ + /* Stop the server and free it. */ silc_server_stop(silcd); silc_server_free(silcd); - + + /* Flush the logging system */ + silc_log_flush_all(); + exit(0); fail: exit(1); } + +/* Returns identifier string for public key generation. */ + +static char *silc_server_create_identifier() +{ + char *username = NULL, *realname = NULL; + char hostname[256], email[256]; + + /* Get realname */ + realname = silc_get_real_name(); + + /* Get hostname */ + memset(hostname, 0, sizeof(hostname)); + gethostname(hostname, sizeof(hostname)); + + /* Get username (mandatory) */ + username = silc_get_username(); + if (!username) + return NULL; + + /* Create default email address, whether it is right or not */ + snprintf(email, sizeof(email), "%s@%s", username, hostname); + + return silc_pkcs_encode_identifier(username, hostname, realname, email, + NULL, NULL); +} + +/* Creates new public key and private key pair. This is used only + when user wants to create new key pair from command line. */ + +static int +silc_server_create_key_pair(char *pkcs_name, int bits, char *path, + char *identifier, + SilcPublicKey *ret_pub_key, + SilcPrivateKey *ret_prv_key) +{ + SilcPKCS pkcs; + SilcPublicKey pub_key; + SilcPrivateKey prv_key; + SilcRng rng; + unsigned char *key; + uint32 key_len; + char pkfile[256], prvfile[256]; + + if (!pkcs_name || !path) + return FALSE; + + if (!silc_pkcs_is_supported(pkcs_name)) { + fprintf(stderr, "Unsupported PKCS `%s'", pkcs_name); + return FALSE; + } + + if (!bits) + bits = 1024; + + if (!identifier) + identifier = silc_server_create_identifier(); + + rng = silc_rng_alloc(); + silc_rng_init(rng); + silc_rng_global_init(rng); + + snprintf(pkfile, sizeof(pkfile) - 1, "%s%s", path, + SILC_SERVER_PUBLIC_KEY_NAME); + snprintf(prvfile, sizeof(prvfile) - 1, "%s%s", path, + SILC_SERVER_PRIVATE_KEY_NAME); + + /* Generate keys */ + silc_pkcs_alloc(pkcs_name, &pkcs); + pkcs->pkcs->init(pkcs->context, bits, rng); + + /* Save public key into file */ + key = silc_pkcs_get_public_key(pkcs, &key_len); + pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier, + key, key_len); + silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM); + if (ret_pub_key) + *ret_pub_key = pub_key; + else + silc_pkcs_public_key_free(pub_key); + + memset(key, 0, sizeof(key_len)); + silc_free(key); + + /* Save private key into file */ + key = silc_pkcs_get_private_key(pkcs, &key_len); + prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len); + silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN); + if (ret_prv_key) + *ret_prv_key = prv_key; + else + silc_pkcs_private_key_free(prv_key); + + printf("Public key has been saved into `%s'\n", pkfile); + printf("Private key has been saved into `%s'\n", prvfile); + + memset(key, 0, sizeof(key_len)); + silc_free(key); + + silc_rng_free(rng); + silc_pkcs_free(pkcs); + + return TRUE; +}