summaryrefslogtreecommitdiff
path: root/src/svr-runopts.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/svr-runopts.c')
-rw-r--r--src/svr-runopts.c704
1 files changed, 704 insertions, 0 deletions
diff --git a/src/svr-runopts.c b/src/svr-runopts.c
new file mode 100644
index 0000000..48d6cbf
--- /dev/null
+++ b/src/svr-runopts.c
@@ -0,0 +1,704 @@
+/*
+ * Dropbear - a SSH2 server
+ *
+ * Copyright (c) 2002,2003 Matt Johnston
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
+
+#include "includes.h"
+#include "runopts.h"
+#include "signkey.h"
+#include "buffer.h"
+#include "dbutil.h"
+#include "algo.h"
+#include "ecdsa.h"
+
+#include <grp.h>
+
+svr_runopts svr_opts; /* GLOBAL */
+
+static void printhelp(const char * progname);
+static void addportandaddress(const char* spec);
+static void loadhostkey(const char *keyfile, int fatal_duplicate);
+static void addhostkey(const char *keyfile);
+
+static void printhelp(const char * progname) {
+
+ fprintf(stderr, "Dropbear server v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
+ "Usage: %s [options]\n"
+ "-b bannerfile Display the contents of bannerfile"
+ " before user login\n"
+ " (default: none)\n"
+ "-r keyfile Specify hostkeys (repeatable)\n"
+ " defaults: \n"
+#if DROPBEAR_DSS
+ " - dss %s\n"
+#endif
+#if DROPBEAR_RSA
+ " - rsa %s\n"
+#endif
+#if DROPBEAR_ECDSA
+ " - ecdsa %s\n"
+#endif
+#if DROPBEAR_ED25519
+ " - ed25519 %s\n"
+#endif
+#if DROPBEAR_DELAY_HOSTKEY
+ "-R Create hostkeys as required\n"
+#endif
+ "-F Don't fork into background\n"
+ "-e Pass on server process environment to child process\n"
+#ifdef DISABLE_SYSLOG
+ "(Syslog support not compiled in, using stderr)\n"
+#else
+ "-E Log to stderr rather than syslog\n"
+#endif
+#if DO_MOTD
+ "-m Don't display the motd on login\n"
+#endif
+ "-w Disallow root logins\n"
+#ifdef HAVE_GETGROUPLIST
+ "-G Restrict logins to members of specified group\n"
+#endif
+#if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH
+ "-s Disable password logins\n"
+ "-g Disable password logins for root\n"
+ "-B Allow blank password logins\n"
+ "-t Enable two-factor authentication (both password and public key required)\n"
+#endif
+ "-T Maximum authentication tries (default %d)\n"
+#if DROPBEAR_SVR_LOCALTCPFWD
+ "-j Disable local port forwarding\n"
+#endif
+#if DROPBEAR_SVR_REMOTETCPFWD
+ "-k Disable remote port forwarding\n"
+ "-a Allow connections to forwarded ports from any host\n"
+ "-c command Force executed command\n"
+#endif
+ "-p [address:]port\n"
+ " Listen on specified tcp port (and optionally address),\n"
+ " up to %d can be specified\n"
+ " (default port is %s if none specified)\n"
+ "-P PidFile Create pid file PidFile\n"
+ " (default %s)\n"
+#if INETD_MODE
+ "-i Start for inetd\n"
+#endif
+ "-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n"
+ "-K <keepalive> (0 is never, default %d, in seconds)\n"
+ "-I <idle_timeout> (0 is never, default %d, in seconds)\n"
+ "-z disable QoS\n"
+#if DROPBEAR_PLUGIN
+ "-A <authplugin>[,<options>]\n"
+ " Enable external public key auth through <authplugin>\n"
+#endif
+ "-V Version\n"
+#if DEBUG_TRACE
+ "-v verbose (repeat for more verbose)\n"
+#endif
+ ,DROPBEAR_VERSION, progname,
+#if DROPBEAR_DSS
+ DSS_PRIV_FILENAME,
+#endif
+#if DROPBEAR_RSA
+ RSA_PRIV_FILENAME,
+#endif
+#if DROPBEAR_ECDSA
+ ECDSA_PRIV_FILENAME,
+#endif
+#if DROPBEAR_ED25519
+ ED25519_PRIV_FILENAME,
+#endif
+ MAX_AUTH_TRIES,
+ DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
+ DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
+}
+
+void svr_getopts(int argc, char ** argv) {
+
+ unsigned int i, j;
+ char ** next = NULL;
+ int nextisport = 0;
+ char* recv_window_arg = NULL;
+ char* keepalive_arg = NULL;
+ char* idle_timeout_arg = NULL;
+ char* maxauthtries_arg = NULL;
+ char* reexec_fd_arg = NULL;
+ char* keyfile = NULL;
+ char c;
+#if DROPBEAR_PLUGIN
+ char* pubkey_plugin = NULL;
+#endif
+
+
+ /* see printhelp() for options */
+ svr_opts.bannerfile = NULL;
+ svr_opts.banner = NULL;
+ svr_opts.forced_command = NULL;
+ svr_opts.forkbg = 1;
+ svr_opts.norootlogin = 0;
+#ifdef HAVE_GETGROUPLIST
+ svr_opts.restrict_group = NULL;
+ svr_opts.restrict_group_gid = 0;
+#endif
+ svr_opts.noauthpass = 0;
+ svr_opts.norootpass = 0;
+ svr_opts.allowblankpass = 0;
+ svr_opts.multiauthmethod = 0;
+ svr_opts.maxauthtries = MAX_AUTH_TRIES;
+ svr_opts.inetdmode = 0;
+ svr_opts.portcount = 0;
+ svr_opts.hostkey = NULL;
+ svr_opts.delay_hostkey = 0;
+ svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE);
+#if DROPBEAR_SVR_LOCALTCPFWD
+ svr_opts.nolocaltcp = 0;
+#endif
+#if DROPBEAR_SVR_REMOTETCPFWD
+ svr_opts.noremotetcp = 0;
+#endif
+#if DROPBEAR_PLUGIN
+ svr_opts.pubkey_plugin = NULL;
+ svr_opts.pubkey_plugin_options = NULL;
+#endif
+ svr_opts.pass_on_env = 0;
+ svr_opts.reexec_childpipe = -1;
+
+#ifndef DISABLE_ZLIB
+ opts.compress_mode = DROPBEAR_COMPRESS_DELAYED;
+#endif
+
+ /* not yet
+ opts.ipv4 = 1;
+ opts.ipv6 = 1;
+ */
+#if DO_MOTD
+ svr_opts.domotd = 1;
+#endif
+#ifndef DISABLE_SYSLOG
+ opts.usingsyslog = 1;
+#endif
+ opts.recv_window = DEFAULT_RECV_WINDOW;
+ opts.keepalive_secs = DEFAULT_KEEPALIVE;
+ opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
+
+#if DROPBEAR_SVR_REMOTETCPFWD
+ opts.listen_fwd_all = 0;
+#endif
+ opts.disable_ip_tos = 0;
+
+ for (i = 1; i < (unsigned int)argc; i++) {
+ if (argv[i][0] != '-' || argv[i][1] == '\0')
+ dropbear_exit("Invalid argument: %s", argv[i]);
+
+ for (j = 1; (c = argv[i][j]) != '\0' && !next && !nextisport; j++) {
+ switch (c) {
+ case 'b':
+ next = &svr_opts.bannerfile;
+ break;
+ case 'c':
+ next = &svr_opts.forced_command;
+ break;
+ case 'd':
+ case 'r':
+ next = &keyfile;
+ break;
+ case 'R':
+ svr_opts.delay_hostkey = 1;
+ break;
+ case 'F':
+ svr_opts.forkbg = 0;
+ break;
+#ifndef DISABLE_SYSLOG
+ case 'E':
+ opts.usingsyslog = 0;
+ break;
+#endif
+ case 'e':
+ svr_opts.pass_on_env = 1;
+ break;
+
+#if DROPBEAR_SVR_LOCALTCPFWD
+ case 'j':
+ svr_opts.nolocaltcp = 1;
+ break;
+#endif
+#if DROPBEAR_SVR_REMOTETCPFWD
+ case 'k':
+ svr_opts.noremotetcp = 1;
+ break;
+ case 'a':
+ opts.listen_fwd_all = 1;
+ break;
+#endif
+#if INETD_MODE
+ case 'i':
+ svr_opts.inetdmode = 1;
+ break;
+#endif
+#if DROPBEAR_DO_REEXEC && NON_INETD_MODE
+ /* For internal use by re-exec */
+ case '2':
+ next = &reexec_fd_arg;
+ break;
+#endif
+ case 'p':
+ nextisport = 1;
+ break;
+ case 'P':
+ next = &svr_opts.pidfile;
+ break;
+#if DO_MOTD
+ /* motd is displayed by default, -m turns it off */
+ case 'm':
+ svr_opts.domotd = 0;
+ break;
+#endif
+ case 'w':
+ svr_opts.norootlogin = 1;
+ break;
+#ifdef HAVE_GETGROUPLIST
+ case 'G':
+ next = &svr_opts.restrict_group;
+ break;
+#endif
+ case 'W':
+ next = &recv_window_arg;
+ break;
+ case 'K':
+ next = &keepalive_arg;
+ break;
+ case 'I':
+ next = &idle_timeout_arg;
+ break;
+ case 'T':
+ next = &maxauthtries_arg;
+ break;
+#if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH
+ case 's':
+ svr_opts.noauthpass = 1;
+ break;
+ case 'g':
+ svr_opts.norootpass = 1;
+ break;
+ case 'B':
+ svr_opts.allowblankpass = 1;
+ break;
+ case 't':
+ svr_opts.multiauthmethod = 1;
+ break;
+#endif
+ case 'h':
+ printhelp(argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+ case 'u':
+ /* backwards compatibility with old urandom option */
+ break;
+#if DROPBEAR_PLUGIN
+ case 'A':
+ next = &pubkey_plugin;
+ break;
+#endif
+#if DEBUG_TRACE
+ case 'v':
+ debug_trace++;
+ break;
+#endif
+ case 'V':
+ print_version();
+ exit(EXIT_SUCCESS);
+ break;
+ case 'z':
+ opts.disable_ip_tos = 1;
+ break;
+ default:
+ fprintf(stderr, "Invalid option -%c\n", c);
+ printhelp(argv[0]);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ if (!next && !nextisport)
+ continue;
+
+ if (c == '\0') {
+ i++;
+ j = 0;
+ if (!argv[i]) {
+ dropbear_exit("Missing argument");
+ }
+ }
+
+ if (nextisport) {
+ addportandaddress(&argv[i][j]);
+ nextisport = 0;
+ } else if (next) {
+ *next = &argv[i][j];
+ if (*next == NULL) {
+ dropbear_exit("Invalid null argument");
+ }
+ next = NULL;
+
+ if (keyfile) {
+ addhostkey(keyfile);
+ keyfile = NULL;
+ }
+ }
+ }
+
+ /* Set up listening ports */
+ if (svr_opts.portcount == 0) {
+ svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
+ svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
+ svr_opts.portcount = 1;
+ }
+
+ if (svr_opts.bannerfile) {
+ struct stat buf;
+ if (stat(svr_opts.bannerfile, &buf) != 0) {
+ dropbear_exit("Error opening banner file '%s'",
+ svr_opts.bannerfile);
+ }
+
+ if (buf.st_size > MAX_BANNER_SIZE) {
+ dropbear_exit("Banner file too large, max is %d bytes",
+ MAX_BANNER_SIZE);
+ }
+
+ svr_opts.banner = buf_new(buf.st_size);
+ if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
+ dropbear_exit("Error reading banner file '%s'",
+ svr_opts.bannerfile);
+ }
+ buf_setpos(svr_opts.banner, 0);
+ }
+
+#ifdef HAVE_GETGROUPLIST
+ if (svr_opts.restrict_group) {
+ struct group *restrictedgroup = getgrnam(svr_opts.restrict_group);
+
+ if (restrictedgroup){
+ svr_opts.restrict_group_gid = restrictedgroup->gr_gid;
+ } else {
+ dropbear_exit("Cannot restrict logins to group '%s' as the group does not exist", svr_opts.restrict_group);
+ }
+ }
+#endif
+
+ if (recv_window_arg) {
+ parse_recv_window(recv_window_arg);
+ }
+
+ if (maxauthtries_arg) {
+ unsigned int val = 0;
+ if (m_str_to_uint(maxauthtries_arg, &val) == DROPBEAR_FAILURE
+ || val == 0) {
+ dropbear_exit("Bad maxauthtries '%s'", maxauthtries_arg);
+ }
+ svr_opts.maxauthtries = val;
+ }
+
+
+ if (keepalive_arg) {
+ unsigned int val;
+ if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
+ dropbear_exit("Bad keepalive '%s'", keepalive_arg);
+ }
+ opts.keepalive_secs = val;
+ }
+
+ if (idle_timeout_arg) {
+ unsigned int val;
+ if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
+ dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
+ }
+ opts.idle_timeout_secs = val;
+ }
+
+ if (svr_opts.forced_command) {
+ dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
+ }
+
+ if (reexec_fd_arg) {
+ if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
+ || svr_opts.reexec_childpipe < 0) {
+ dropbear_exit("Bad -2");
+ }
+ }
+
+#if INETD_MODE
+ if (svr_opts.inetdmode && (
+ opts.usingsyslog == 0
+#if DEBUG_TRACE
+ || debug_trace
+#endif
+ )) {
+ /* log output goes to stderr which would get sent over the inetd network socket */
+ dropbear_exit("Dropbear inetd mode is incompatible with debug -v or non-syslog");
+ }
+#endif
+
+ if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
+ dropbear_exit("-t and -s are incompatible");
+ }
+
+#if DROPBEAR_PLUGIN
+ if (pubkey_plugin) {
+ svr_opts.pubkey_plugin = m_strdup(pubkey_plugin);
+ char *args = strchr(svr_opts.pubkey_plugin, ',');
+ if (args) {
+ *args='\0';
+ ++args;
+ }
+ svr_opts.pubkey_plugin_options = args;
+ }
+#endif
+}
+
+static void addportandaddress(const char* spec) {
+ char *port = NULL, *address = NULL;
+
+ if (svr_opts.portcount >= DROPBEAR_MAX_PORTS) {
+ return;
+ }
+
+ if (split_address_port(spec, &address, &port) == DROPBEAR_FAILURE) {
+ dropbear_exit("Bad -p argument");
+ }
+
+ /* A bare port */
+ if (!port) {
+ port = address;
+ address = NULL;
+ }
+
+ if (!address) {
+ /* no address given -> fill in the default address */
+ address = m_strdup(DROPBEAR_DEFADDRESS);
+ }
+
+ if (port[0] == '\0') {
+ /* empty port -> exit */
+ dropbear_exit("Bad port");
+ }
+ svr_opts.ports[svr_opts.portcount] = port;
+ svr_opts.addresses[svr_opts.portcount] = address;
+ svr_opts.portcount++;
+}
+
+static void disablekey(enum signature_type type) {
+ int i;
+ TRACE(("Disabling key type %d", type))
+ for (i = 0; sigalgs[i].name != NULL; i++) {
+ if ((int)sigalgs[i].val == (int)type) {
+ sigalgs[i].usable = 0;
+ break;
+ }
+ }
+}
+
+static void loadhostkey_helper(const char *name, void** src, void** dst, int fatal_duplicate) {
+ if (*dst) {
+ if (fatal_duplicate) {
+ dropbear_exit("Only one %s key can be specified", name);
+ }
+ } else {
+ *dst = *src;
+ *src = NULL;
+ }
+
+}
+
+/* Must be called after syslog/etc is working */
+static void loadhostkey(const char *keyfile, int fatal_duplicate) {
+ sign_key * read_key = new_sign_key();
+ char *expand_path = expand_homedir_path(keyfile);
+ enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
+ if (readhostkey(expand_path, read_key, &type) == DROPBEAR_FAILURE) {
+ if (!svr_opts.delay_hostkey) {
+ dropbear_log(LOG_WARNING, "Failed loading %s", expand_path);
+ }
+ }
+ m_free(expand_path);
+
+#if DROPBEAR_RSA
+ if (type == DROPBEAR_SIGNKEY_RSA) {
+ loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate);
+ }
+#endif
+
+#if DROPBEAR_DSS
+ if (type == DROPBEAR_SIGNKEY_DSS) {
+ loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate);
+ }
+#endif
+
+#if DROPBEAR_ECDSA
+#if DROPBEAR_ECC_256
+ if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
+ loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate);
+ }
+#endif
+#if DROPBEAR_ECC_384
+ if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
+ loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate);
+ }
+#endif
+#if DROPBEAR_ECC_521
+ if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+ loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate);
+ }
+#endif
+#endif /* DROPBEAR_ECDSA */
+
+#if DROPBEAR_ED25519
+ if (type == DROPBEAR_SIGNKEY_ED25519) {
+ loadhostkey_helper("ed25519", (void**)&read_key->ed25519key, (void**)&svr_opts.hostkey->ed25519key, fatal_duplicate);
+ }
+#endif
+
+ sign_key_free(read_key);
+ TRACE(("leave loadhostkey"))
+}
+
+static void addhostkey(const char *keyfile) {
+ if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
+ dropbear_exit("Too many hostkeys");
+ }
+ svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
+ svr_opts.num_hostkey_files++;
+}
+
+
+void load_all_hostkeys() {
+ int i;
+ int any_keys = 0;
+#if DROPBEAR_ECDSA
+ int loaded_any_ecdsa = 0;
+#endif
+
+ svr_opts.hostkey = new_sign_key();
+
+ for (i = 0; i < svr_opts.num_hostkey_files; i++) {
+ char *hostkey_file = svr_opts.hostkey_files[i];
+ loadhostkey(hostkey_file, 1);
+ m_free(hostkey_file);
+ }
+
+ /* Only load default host keys if a host key is not specified by the user */
+ if (svr_opts.num_hostkey_files == 0) {
+#if DROPBEAR_RSA
+ loadhostkey(RSA_PRIV_FILENAME, 0);
+#endif
+
+#if DROPBEAR_DSS
+ loadhostkey(DSS_PRIV_FILENAME, 0);
+#endif
+
+#if DROPBEAR_ECDSA
+ loadhostkey(ECDSA_PRIV_FILENAME, 0);
+#endif
+#if DROPBEAR_ED25519
+ loadhostkey(ED25519_PRIV_FILENAME, 0);
+#endif
+ }
+
+#if DROPBEAR_RSA
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
+ disablekey(DROPBEAR_SIGNATURE_RSA_SHA256);
+ disablekey(DROPBEAR_SIGNATURE_RSA_SHA1);
+ } else {
+ any_keys = 1;
+ }
+#endif
+
+#if DROPBEAR_DSS
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
+ disablekey(DROPBEAR_SIGNATURE_DSS);
+ } else {
+ any_keys = 1;
+ }
+#endif
+
+#if DROPBEAR_ECDSA
+ /* We want to advertise a single ecdsa algorithm size.
+ - If there is a ecdsa hostkey at startup we choose that that size.
+ - If we generate at runtime we choose the default ecdsa size.
+ - Otherwise no ecdsa keys will be advertised */
+
+ /* check if any keys were loaded at startup */
+ loaded_any_ecdsa =
+ 0
+#if DROPBEAR_ECC_256
+ || svr_opts.hostkey->ecckey256
+#endif
+#if DROPBEAR_ECC_384
+ || svr_opts.hostkey->ecckey384
+#endif
+#if DROPBEAR_ECC_521
+ || svr_opts.hostkey->ecckey521
+#endif
+ ;
+ any_keys |= loaded_any_ecdsa;
+
+ /* Or an ecdsa key could be generated at runtime */
+ any_keys |= svr_opts.delay_hostkey;
+
+ /* At most one ecdsa key size will be left enabled */
+#if DROPBEAR_ECC_256
+ if (!svr_opts.hostkey->ecckey256
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256);
+ }
+#endif
+#if DROPBEAR_ECC_384
+ if (!svr_opts.hostkey->ecckey384
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384);
+ }
+#endif
+#if DROPBEAR_ECC_521
+ if (!svr_opts.hostkey->ecckey521
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521);
+ }
+#endif
+#endif /* DROPBEAR_ECDSA */
+
+#if DROPBEAR_ED25519
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
+ disablekey(DROPBEAR_SIGNATURE_ED25519);
+ } else {
+ any_keys = 1;
+ }
+#endif
+#if DROPBEAR_SK_ECDSA
+ disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
+#endif
+#if DROPBEAR_SK_ED25519
+ disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
+#endif
+
+ if (!any_keys) {
+ dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
+ }
+}