X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fsilcd.c;h=d367328c6578fdb15942f922e108a2fc7525e4de;hp=616f50c43597a08070cda9af8e6a60a394705579;hb=b2d306dde2ce3eae11b4729eca5f3242b2109861;hpb=f50fab3886a56151079728daa678fed3b882b433 diff --git a/apps/silcd/silcd.c b/apps/silcd/silcd.c index 616f50c4..d367328c 100644 --- a/apps/silcd/silcd.c +++ b/apps/silcd/silcd.c @@ -4,12 +4,11 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 2007 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. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -32,19 +31,17 @@ /* 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); +static void silc_usage(void); +#ifdef HAVE_GETOPT_LONG /* Long command line options */ static struct option long_opts[] = { { "config-file", 1, NULL, 'f' }, - { "debug", 1, NULL, 'd' }, + { "passphrase", 1, NULL, 'p' }, + { "debug", 2, NULL, 'd' }, + { "debug-level", 1, NULL, 'D' }, + { "hexdump", 0, NULL, 'x' }, { "help", 0, NULL, 'h' }, { "foreground", 0, NULL, 'F' }, { "version", 0, NULL,'V' }, @@ -57,50 +54,52 @@ static struct option long_opts[] = { NULL, 0, NULL, 0 } }; +#endif /* HAVE_GETOPT_LONG */ /* 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; +static int opt_bits = 2048; /* Prints out the usage of silc client */ -static void silc_usage() +static void silc_usage(void) { - 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"); + 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" +" -D --debug-level=level Enable debugging (Implies --foreground)\n" +" -x --hexdump Enable hexdumps (Implies --debug)\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 */ +/* Die if a *valid* pid file exists already */ static void silc_server_checkpid(SilcServer silcd) { @@ -119,7 +118,8 @@ static void silc_server_checkpid(SilcServer silcd) 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, "\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); @@ -127,59 +127,504 @@ static void silc_server_checkpid(SilcServer silcd) } } -static void got_hup(int z) +/* Drop root privileges. If some system call fails, die. */ + +static void silc_server_drop_privs(SilcServer server) +{ + /* Are we executing silcd as root or a regular user? */ + if (geteuid()) { + SILC_LOG_DEBUG(("Server started as user")); + } + else { + struct passwd *pw; + struct group *gr; + char *user, *group; + + SILC_LOG_DEBUG(("Server started as root. Dropping privileges.")); + + /* Get the values given for user and group in configuration file */ + user = server->config->server_info->user; + group = server->config->server_info->group; + + if (!user || !group) { + fprintf(stderr, "Error:" + "\tSILC server must not be run as root. For the security of your\n" + "\tsystem it is strongly suggested that you run SILC under dedicated\n" + "\tuser account. Modify the ServerInfo configuration section to run\n" + "\tthe server as non-root user.\n"); + exit(1); + } + + /* Check whether the user/group does not begin with a number */ + if (isdigit(user[0]) || isdigit(group[0])) { + SILC_LOG_DEBUG(("User and/or group starts with a number")); + fprintf(stderr, "Invalid user and/or group information\n"); + fprintf(stderr, "Please assign them as names, not numbers\n"); + exit(1); + } + + if (!(pw = getpwnam(user))) { + fprintf(stderr, "Error: No such user %s found.\n", user); + exit(1); + } + if (!(gr = getgrnam(group))) { + fprintf(stderr, "Error: No such group %s found.\n", group); + exit(1); + } + + /* Check whether user and/or group is set to root. If yes, exit + immediately. Otherwise, setgid and setuid server to user.group */ + if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) { + fprintf(stderr, "Error:" + "\tSILC server must not be run as root. For the security of your\n" + "\tsystem it is strongly suggested that you run SILC under dedicated\n" + "\tuser account. Modify the ServerInfo configuration section to run\n" + "\tthe server as non-root user.\n"); + exit(1); + } + + SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid)); + if (setgid(gr->gr_gid) != 0) { + fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n", + group, gr->gr_gid); + exit(1); + } +#if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS + SILC_LOG_DEBUG(("Removing supplementary groups")); + if (setgroups(0, NULL) != 0) { + fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n"); + exit(1); + } + SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user)); + if (initgroups(user, gr->gr_gid) != 0) { + fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). " + "Exiting.\n", user, gr->gr_gid); + exit(1); + } +#endif + SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid)); + if (setuid(pw->pw_uid) != 0) { + fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n", + user, pw->pw_uid); + exit(1); + } + } +} + +/* Fork server to background */ + +static void silc_server_daemonise(SilcServer server) +{ + int i; + + SILC_LOG_DEBUG(("Forking SILC server to background")); + + if ((i = fork()) < 0) { + fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno)); + exit(1); + } + + if (i) /* Kill the parent */ + exit(0); + + server->background = TRUE; + setsid(); + + /* XXX close stdin, stdout, stderr -- before this, check that all writes + to stderr are changed to SILC_SERVER_LOG_ERROR() */ +} + +SILC_TASK_CALLBACK(got_hup) { /* First, reset all log files (they might have been deleted) */ silc_log_reset_all(); - silc_log_flush_all(); + + /* Rehash the configuration file */ + silc_server_rehash(silcd); } -static void stop_server(int z) +SILC_TASK_CALLBACK(stop_server) { - /* Stop scheduler, the program will stop eventually after noticing - that the scheduler is down. */ - silc_schedule_stop(silcd->schedule); + silc_server_stop(silcd); +} + +/* Dump server statistics into a file into /tmp directory */ + +SILC_TASK_CALLBACK(dump_stats) +{ + FILE *fdd; + int fild; + char filename[256]; + + memset(filename, 0, sizeof(filename)); + snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats-XXXXXX", getpid()); + fild = mkstemp(filename); + if (fild == -1) + return; + + fdd = fdopen(fild, "w"); + if (fdd == NULL) { + close(fild); + unlink(filename); + return; + } + +#define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat); + + fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name); + fprintf(fdd, "Local Stats:\n"); + STAT_OUTPUT(" My clients : %d", silcd->stat.my_clients); + STAT_OUTPUT(" My servers : %d", silcd->stat.my_servers); + STAT_OUTPUT(" My routers : %d", silcd->stat.my_routers); + STAT_OUTPUT(" My channels : %d", silcd->stat.my_channels); + STAT_OUTPUT(" My joined users : %d", silcd->stat.my_chanclients); + STAT_OUTPUT(" My aways : %d", silcd->stat.my_aways); + STAT_OUTPUT(" My detached clients : %d", silcd->stat.my_detached); + STAT_OUTPUT(" My server operators : %d", silcd->stat.my_server_ops); + STAT_OUTPUT(" My router operators : %d", silcd->stat.my_router_ops); + fprintf(fdd, "\nGlobal Stats:\n"); + STAT_OUTPUT(" Cell clients : %d", silcd->stat.cell_clients); + STAT_OUTPUT(" Cell servers : %d", silcd->stat.cell_servers); + STAT_OUTPUT(" Cell channels : %d", silcd->stat.cell_channels); + STAT_OUTPUT(" Cell joined users : %d", silcd->stat.cell_chanclients); + STAT_OUTPUT(" All clients : %d", silcd->stat.clients); + STAT_OUTPUT(" All servers : %d", silcd->stat.servers); + STAT_OUTPUT(" All routers : %d", silcd->stat.routers); + STAT_OUTPUT(" All channels : %d", silcd->stat.channels); + STAT_OUTPUT(" All joined users : %d", silcd->stat.chanclients); + STAT_OUTPUT(" All aways : %d", silcd->stat.aways); + STAT_OUTPUT(" All detached clients : %d", silcd->stat.detached); + STAT_OUTPUT(" All server operators : %d", silcd->stat.server_ops); + STAT_OUTPUT(" All router operators : %d", silcd->stat.router_ops); + fprintf(fdd, "\nGeneral Stats:\n"); + STAT_OUTPUT(" Connection attempts : %d", silcd->stat.conn_attempts); + STAT_OUTPUT(" Connection failures : %d", silcd->stat.conn_failures); + STAT_OUTPUT(" Authentication attempts : %d", silcd->stat.auth_attempts); + STAT_OUTPUT(" Authentication failures : %d", silcd->stat.auth_failures); + STAT_OUTPUT(" Packets sent : %d", silcd->stat.packets_sent); + STAT_OUTPUT(" Packets received : %d", silcd->stat.packets_received); + STAT_OUTPUT(" Commands sent : %d", silcd->stat.commands_sent); + STAT_OUTPUT(" Commands received : %d", silcd->stat.commands_received); + STAT_OUTPUT(" Connections : %d", silcd->stat.conn_num); + +#undef STAT_OUTPUT + +#ifdef SILC_DEBUG + /* Dump internal flags */ + fprintf(fdd, "\nDumping internal flags\n"); + fprintf(fdd, " server_type : %d\n", silcd->server_type); + fprintf(fdd, " standalone : %d\n", silcd->standalone); + fprintf(fdd, " listenning : %d\n", silcd->listenning); + fprintf(fdd, " background : %d\n", silcd->background); + fprintf(fdd, " backup_router : %d\n", silcd->backup_router); + fprintf(fdd, " backup_primary : %d\n", silcd->backup_primary); + fprintf(fdd, " backup_noswitch : %d\n", silcd->backup_noswitch); + fprintf(fdd, " backup_closed : %d\n", silcd->backup_closed); + fprintf(fdd, " wait_backup : %d\n", silcd->wait_backup); + if (silcd->router) + fprintf(fdd, " primary router : %s\n", + silcd->router->server_name ? silcd->router->server_name : ""); + + /* Dump connections */ + { + SilcPacketStream s; + SilcDList conns = silc_packet_engine_get_streams(silcd->packet_engine); + + fprintf(fdd, "\nDumping connections\n"); + silc_dlist_start(conns); + while ((s = silc_dlist_get(conns))) { + const char *hostname, *ip; + SilcUInt16 port; + SilcSocket sock; + SilcIDListData idata = silc_packet_get_context(s); + if (!silc_socket_stream_get_info(silc_packet_stream_get_stream(s), + &sock, &hostname, &ip, &port)) + continue; + fprintf(fdd, " %d: host %s ip %s port %d type %d\n", + sock, hostname ? hostname : "N/A", + ip ? ip : "N/A", port, idata ? idata->conn_type : 0); + } + silc_dlist_uninit(conns); + } + + /* Dump lists */ + { + SilcList list; + SilcIDCacheEntry id_cache = NULL; + SilcServerEntry server_entry; + SilcClientEntry client_entry; + SilcChannelEntry channel_entry; + int c; + + fprintf(fdd, "\nDumping databases\n"); + + if (silc_idcache_get_all(silcd->local_list->servers, &list)) { + c = 1; + fprintf(fdd, "\nServers in local-list:\n"); + while ((id_cache = silc_list_get(list))) { + server_entry = (SilcServerEntry)id_cache->context; + fprintf(fdd, " %d: name %s id %s status 0x%x\n", c, + server_entry->server_name ? server_entry->server_name : + "N/A", server_entry->id ? + silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A", + server_entry->data.status); + c++; + } + } + if (silc_idcache_get_all(silcd->global_list->servers, &list)) { + fprintf(fdd, "\nServers in global-list:\n"); + c = 1; + while ((id_cache = silc_list_get(list))) { + server_entry = (SilcServerEntry)id_cache->context; + fprintf(fdd, " %d: name %s id %s status 0x%x\n", c, + server_entry->server_name ? server_entry->server_name : + "N/A", server_entry->id ? + silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A", + server_entry->data.status); + c++; + } + } + if (silc_idcache_get_all(silcd->local_list->clients, &list)) { + fprintf(fdd, "\nClients in local-list:\n"); + c = 1; + while ((id_cache = silc_list_get(list))) { + client_entry = (SilcClientEntry)id_cache->context; + server_entry = client_entry->router; + fprintf(fdd, " %d: name %s id %s status 0x%x from %s\n", c, + client_entry->nickname ? client_entry->nickname : + (unsigned char *)"N/A", client_entry->id ? + silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A", + client_entry->data.status, server_entry ? + server_entry->server_name ? server_entry->server_name : + "N/A" : "local"); + c++; + } + } + if (silc_idcache_get_all(silcd->global_list->clients, &list)) { + fprintf(fdd, "\nClients in global-list:\n"); + c = 1; + while ((id_cache = silc_list_get(list))) { + client_entry = (SilcClientEntry)id_cache->context; + server_entry = client_entry->router; + fprintf(fdd, " %d: name %s id %s status 0x%x from %s\n", c, + client_entry->nickname ? client_entry->nickname : + (unsigned char *)"N/A", client_entry->id ? + silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A", + client_entry->data.status, server_entry ? + server_entry->server_name ? server_entry->server_name : + "N/A" : "local"); + c++; + } + } + if (silc_idcache_get_all(silcd->local_list->channels, &list)) { + fprintf(fdd, "\nChannels in local-list:\n"); + c = 1; + while ((id_cache = silc_list_get(list))) { + channel_entry = (SilcChannelEntry)id_cache->context; + fprintf(fdd, " %d: name %s id %s\n", c, + channel_entry->channel_name ? channel_entry->channel_name : + "N/A", channel_entry->id ? + silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A"); + c++; + } + } + if (silc_idcache_get_all(silcd->global_list->channels, &list)) { + fprintf(fdd, "\nChannels in global-list:\n"); + c = 1; + while ((id_cache = silc_list_get(list))) { + channel_entry = (SilcChannelEntry)id_cache->context; + fprintf(fdd, " %d: name %s id %s\n", c, + channel_entry->channel_name ? channel_entry->channel_name : + "N/A", channel_entry->id ? + silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A"); + c++; + } + } + } +#endif + + fflush(fdd); + fclose(fdd); +} + +#ifdef SILC_DEBUG + +typedef struct { + int level; + const char *string; +} DebugLevel; + +static DebugLevel debug_levels[] = { + /* Very basic stuff from silcd/ */ + { 3, "silcd\\.c,server\\.c" }, + + /* More stuff from silcd/ */ + { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" }, + + /* All basic stuff from silcd/ */ + { 10, "silc_server_*" }, + + /* All from silcd/ */ + { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" }, + + /* All from silcd/ and basic stuff from libs */ + { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*silcske*" }, + + /* All from silcd/ and more stuff from libs */ + { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*," + "*silcpacket*,*ske*,*silcrng*" }, + + /* All from silcd/ and even more stuff from libs */ + { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*," + "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" }, + + /* All from silcd/ and even more stuff from libs + all from silccore */ + { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*," + "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" + "*silcid*,*argument*" }, + + /* All from silcd/, all from silccore, silccrypt and silcmath */ + { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*," + "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" + "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" }, + + /* All from silcd/, all from silccore, silccrypt and silcmath + stuff + from silcutil */ + { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*," + "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" + "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*" + "*sockconn*" }, + + /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff + from silcutil */ + { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*," + "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" + "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*" + "*sockconn*,*net*" }, + + /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff + from silcutil */ + { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*," + "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" + "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*" + "*sockconn*,*net*,*log*,*config*" }, + + /* All */ + { 90, "*" }, + + { -1, NULL }, +}; + +static void silc_get_debug_level(int level) +{ + int i; + + if (level < 0) + return; + + for (i = 0; debug_levels[i].string; i++) + if (level <= debug_levels[i].level) { + silc_log_set_debug_string(debug_levels[i].string); + break; + } +} +#endif /* SILC_DEBUG */ + +/* This function should not be called directly but through the appropriate + wrapper macro defined in server.h */ + +void silc_server_stderr(SilcLogType type, char *message) +{ + if (silcd->background) { + char *p, *n = message; + + /* remove newlines if we are going to output it to a log file */ + for (p = n; *p; p++) { + if (*p != '\n') { + if (p != n) + *n = *p; + n++; + } + } + *n = 0; + + /* the message is freed inside the logging function */ + silc_log_output(type, message); + } + else { + fprintf(stderr, "%s\n", message); + silc_free(message); + } } int main(int argc, char **argv) { int ret, opt, option_index; - char *config_file = NULL; - bool foreground = FALSE; + SilcBool foreground = FALSE; + SilcBool opt_create_keypair = FALSE; + char *silcd_config_file = NULL; struct sigaction sa; /* Parse command line arguments */ if (argc > 1) { - while ((opt = getopt_long(argc, argv, "cf:d:hFVC:", +#ifdef HAVE_GETOPT_LONG + while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:", long_opts, &option_index)) != EOF) { - switch(opt) - { +#else + while ((opt = getopt(argc, argv, "f:p:d:D:xhFVC:")) != EOF) { +#endif /* HAVE_GETOPT_LONG */ + switch(opt) { case 'h': silc_usage(); break; case 'V': printf("SILCd Secure Internet Live Conferencing daemon, " "version %s (base: SILC Toolkit %s)\n", - silc_dist_version, silc_version); - printf("(c) 1997 - 2002 Pekka Riikonen " + silc_dist_version, silc_version); + printf("(c) 1997 - 2007 Pekka Riikonen " "\n"); exit(0); break; case 'd': #ifdef SILC_DEBUG - silc_debug = TRUE; - silc_debug_hexdump = TRUE; - silc_log_set_debug_string(optarg); - foreground = TRUE; - silc_log_quick = TRUE; + silc_log_debug(TRUE); + silc_log_quick(TRUE); + if (optarg) + silc_log_set_debug_string(optarg); + foreground = TRUE; /* implied */ +#else + fprintf(stderr, + "Run-time debugging is not enabled. To enable it recompile\n" + "the server with --enable-debug configuration option.\n"); +#endif + break; + case 'D': +#ifdef SILC_DEBUG + silc_log_debug(TRUE); + silc_log_quick(TRUE); + if (optarg) + silc_get_debug_level(atoi(optarg)); + foreground = TRUE; /* implied */ +#else + fprintf(stderr, + "Run-time debugging is not enabled. To enable it recompile\n" + "the server with --enable-debug configuration option.\n"); +#endif + break; + case 'x': +#ifdef SILC_DEBUG + silc_log_debug(TRUE); + silc_log_debug_hexdump(TRUE); + silc_log_quick(TRUE); + foreground = TRUE; /* implied */ #else - fprintf(stdout, + fprintf(stderr, "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); + silcd_config_file = strdup(optarg); break; case 'F': foreground = TRUE; @@ -209,189 +654,119 @@ int main(int argc, char **argv) default: silc_usage(); break; - } + } } } if (opt_create_keypair == TRUE) { /* Create new key pair and exit */ + char pubfile[256], prvfile[256]; + + memset(pubfile, 0, sizeof(pubfile)); + memset(prvfile, 0, sizeof(prvfile)); + snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath); + snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath); + 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); + if (!silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile, + opt_identifier, "", NULL, NULL, FALSE)) + exit(1); exit(0); } /* Default configuration file */ - if (!config_file) - config_file = strdup(SILC_SERVER_CONFIG_FILE); + if (!silcd_config_file) + silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE); /* Create SILC Server object */ ret = silc_server_alloc(&silcd); if (ret == FALSE) goto fail; + /* Register default crypto stuff since we are going to need them + in the configuration file parsing phase */ + silc_cipher_register_default(); + silc_pkcs_register_default(); + silc_hash_register_default(); + silc_hmac_register_default(); + /* Read configuration files */ - silcd->config = silc_server_config_alloc(config_file); + silcd->config = silc_server_config_alloc(silcd_config_file, silcd); if (silcd->config == NULL) goto fail; + silcd->config_file = silcd_config_file; + + /* Unregister the default crypto stuff so that configuration takes effect */ + silc_cipher_unregister_all(); + /* silc_pkcs_unregister_all(); MUST NOT do this anymore; SilcPublicKey + parsed from config file references pointers so we cannot unregister */ + silc_hash_unregister_all(); + silc_hmac_unregister_all(); /* Check for another silcd running */ silc_server_checkpid(silcd); /* Initialize the server */ - ret = silc_server_init(silcd); - if (ret == FALSE) + if (silc_server_init(silcd) == FALSE) goto fail; - /* Ignore SIGPIPE */ + /* Ignore some signals */ 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); - silc_schedule_signal_register(silcd->schedule, SIGHUP); - silc_schedule_signal_register(silcd->schedule, SIGTERM); - silc_schedule_signal_register(silcd->schedule, SIGINT); - - /* Before running the server, fork to background. */ - if (!foreground) +#if defined(SIGPIPE) + sigaction(SIGPIPE, &sa, NULL); /* Ignore broken pipes */ +#endif /* SIGPIPE*/ +#if defined(SIGXFSZ) + sigaction(SIGXFSZ, &sa, NULL); /* Ignore file limit exceeds */ +#endif /* SIGXFSZ */ +#if defined(SIGXCPU) + sigaction(SIGXCPU, &sa, NULL); /* Ignore CPU time limit exceeds */ +#endif /* SIGXCPU */ + + /* Handle specificly some other signals. */ + silc_schedule_task_add_signal(silcd->schedule, SIGHUP, got_hup, NULL); + silc_schedule_task_add_signal(silcd->schedule, SIGTERM, stop_server, NULL); + silc_schedule_task_add_signal(silcd->schedule, SIGINT, stop_server, NULL); + silc_schedule_task_add_signal(silcd->schedule, SIGUSR1, dump_stats, NULL); + + if (!foreground) { + /* Before running the server, fork to background. */ 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)); - } + /* 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); + } + silc_server_drop_privs(silcd); /* Run the server. When this returns the server has been stopped and we will exit. */ silc_server_run(silcd); - - /* Stop the server and free it. */ - silc_server_stop(silcd); + + /* Free server */ + silc_server_config_destroy(silcd->config); silc_server_free(silcd); /* Flush the logging system */ silc_log_flush_all(); + silc_free(silcd_config_file); + silc_free(opt_identifier); + silc_free(opt_keypath); exit(0); + fail: + silc_free(silcd_config_file); + silc_free(opt_identifier); + silc_free(opt_keypath); 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; - SilcUInt32 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); - silc_pkcs_generate_key(pkcs, 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; -}