diff options
4 files changed, 521 insertions, 0 deletions
diff --git a/meta/recipes-core/dropbear/dropbear.inc b/meta/recipes-core/dropbear/dropbear.inc index a32242949b..94059df258 100644 --- a/meta/recipes-core/dropbear/dropbear.inc +++ b/meta/recipes-core/dropbear/dropbear.inc | |||
| @@ -31,6 +31,9 @@ SRC_URI = "http://matt.ucc.asn.au/dropbear/releases/dropbear-${PV}.tar.bz2 \ | |||
| 31 | file://CVE-2021-36369.patch \ | 31 | file://CVE-2021-36369.patch \ |
| 32 | file://CVE-2023-36328.patch \ | 32 | file://CVE-2023-36328.patch \ |
| 33 | file://CVE-2023-48795.patch \ | 33 | file://CVE-2023-48795.patch \ |
| 34 | file://0001-Add-m_snprintf-that-won-t-return-negative.patch \ | ||
| 35 | file://0001-Handle-arbitrary-length-paths-and-commands-in-multih.patch \ | ||
| 36 | file://CVE-2025-47203.patch \ | ||
| 34 | " | 37 | " |
| 35 | 38 | ||
| 36 | PAM_SRC_URI = "file://0005-dropbear-enable-pam.patch \ | 39 | PAM_SRC_URI = "file://0005-dropbear-enable-pam.patch \ |
diff --git a/meta/recipes-core/dropbear/dropbear/0001-Add-m_snprintf-that-won-t-return-negative.patch b/meta/recipes-core/dropbear/dropbear/0001-Add-m_snprintf-that-won-t-return-negative.patch new file mode 100644 index 0000000000..ec75fcbc61 --- /dev/null +++ b/meta/recipes-core/dropbear/dropbear/0001-Add-m_snprintf-that-won-t-return-negative.patch | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | From ac2433cb8daa1279d14f8b2cd4c7e1f3405787d4 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Matt Johnston <matt@ucc.asn.au> | ||
| 3 | Date: Fri, 1 Apr 2022 12:10:48 +0800 | ||
| 4 | Subject: [PATCH] Add m_snprintf() that won't return negative | ||
| 5 | |||
| 6 | Origin: https://github.com/mkj/dropbear/commit/ac2433cb8daa1279d14f8b2cd4c7e1f3405787d4 | ||
| 7 | |||
| 8 | Upstream-Status: Backport [https://github.com/mkj/dropbear/commit/ac2433cb8daa1279d14f8b2cd4c7e1f3405787d4] | ||
| 9 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 10 | --- | ||
| 11 | dbutil.c | 13 +++++++++++++ | ||
| 12 | dbutil.h | 2 ++ | ||
| 13 | 2 files changed, 15 insertions(+) | ||
| 14 | |||
| 15 | diff --git a/dbutil.c b/dbutil.c | ||
| 16 | index 5af6330..d4c3298 100644 | ||
| 17 | --- a/dbutil.c | ||
| 18 | +++ b/dbutil.c | ||
| 19 | @@ -691,3 +691,16 @@ void fsync_parent_dir(const char* fn) { | ||
| 20 | m_free(fn_dir); | ||
| 21 | #endif | ||
| 22 | } | ||
| 23 | + | ||
| 24 | +int m_snprintf(char *str, size_t size, const char *format, ...) { | ||
| 25 | + va_list param; | ||
| 26 | + int ret; | ||
| 27 | + | ||
| 28 | + va_start(param, format); | ||
| 29 | + ret = vsnprintf(str, size, format, param); | ||
| 30 | + va_end(param); | ||
| 31 | + if (ret < 0) { | ||
| 32 | + dropbear_exit("snprintf failed"); | ||
| 33 | + } | ||
| 34 | + return ret; | ||
| 35 | +} | ||
| 36 | diff --git a/dbutil.h b/dbutil.h | ||
| 37 | index 2a1c82c..71cffe8 100644 | ||
| 38 | --- a/dbutil.h | ||
| 39 | +++ b/dbutil.h | ||
| 40 | @@ -70,6 +70,8 @@ void m_close(int fd); | ||
| 41 | void setnonblocking(int fd); | ||
| 42 | void disallow_core(void); | ||
| 43 | int m_str_to_uint(const char* str, unsigned int *val); | ||
| 44 | +/* The same as snprintf() but exits rather than returning negative */ | ||
| 45 | +int m_snprintf(char *str, size_t size, const char *format, ...); | ||
| 46 | |||
| 47 | /* Used to force mp_ints to be initialised */ | ||
| 48 | #define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL} | ||
diff --git a/meta/recipes-core/dropbear/dropbear/0001-Handle-arbitrary-length-paths-and-commands-in-multih.patch b/meta/recipes-core/dropbear/dropbear/0001-Handle-arbitrary-length-paths-and-commands-in-multih.patch new file mode 100644 index 0000000000..dbc457209d --- /dev/null +++ b/meta/recipes-core/dropbear/dropbear/0001-Handle-arbitrary-length-paths-and-commands-in-multih.patch | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | From fe15c36664a984de9e1b2386ac52d4b8577cac93 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Matt Johnston <matt@ucc.asn.au> | ||
| 3 | Date: Mon, 1 Apr 2024 11:50:26 +0800 | ||
| 4 | Subject: [PATCH] Handle arbitrary length paths and commands in | ||
| 5 | multihop_passthrough_args() | ||
| 6 | |||
| 7 | Origin: https://github.com/mkj/dropbear/commit/7894254afa9b1d3a836911b7ccea1fe18391b881 | ||
| 8 | Origin: https://github.com/mkj/dropbear/commit/2f1177e55f33afd676e08c9449ab7ab517fc3b30 | ||
| 9 | Origin: https://github.com/mkj/dropbear/commit/697b1f86c0b2b0caf12e9e32bab29161093ab5d4 | ||
| 10 | Origin: https://github.com/mkj/dropbear/commit/dd03da772bfad6174425066ff9752b60e25ed183 | ||
| 11 | Origin: https://github.com/mkj/dropbear/commit/d59436a4d56de58b856142a5d489a4a8fc7382ed | ||
| 12 | |||
| 13 | Upstream-Status: Backport [see commits above] | ||
| 14 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 15 | --- | ||
| 16 | cli-runopts.c | 63 +++++++++++++++++++++------------------------------ | ||
| 17 | 1 file changed, 26 insertions(+), 37 deletions(-) | ||
| 18 | |||
| 19 | diff --git a/cli-runopts.c b/cli-runopts.c | ||
| 20 | index 255b47e..9798f62 100644 | ||
| 21 | --- a/cli-runopts.c | ||
| 22 | +++ b/cli-runopts.c | ||
| 23 | @@ -523,61 +523,50 @@ static void loadidentityfile(const char* filename, int warnfail) { | ||
| 24 | |||
| 25 | #if DROPBEAR_CLI_MULTIHOP | ||
| 26 | |||
| 27 | -static char* | ||
| 28 | -multihop_passthrough_args() { | ||
| 29 | - char *ret; | ||
| 30 | - int total; | ||
| 31 | - unsigned int len = 0; | ||
| 32 | +/* Fill out -i, -y, -W options that make sense for all | ||
| 33 | + * the intermediate processes */ | ||
| 34 | +static char* multihop_passthrough_args(void) { | ||
| 35 | + char *args = NULL; | ||
| 36 | + unsigned int len, total; | ||
| 37 | +#if DROPBEAR_CLI_PUBKEY_AUTH | ||
| 38 | m_list_elem *iter; | ||
| 39 | - /* Fill out -i, -y, -W options that make sense for all | ||
| 40 | - * the intermediate processes */ | ||
| 41 | +#endif | ||
| 42 | + /* Sufficient space for non-string args */ | ||
| 43 | + len = 100; | ||
| 44 | + | ||
| 45 | + /* String arguments have arbitrary length, so determine space required */ | ||
| 46 | #if DROPBEAR_CLI_PUBKEY_AUTH | ||
| 47 | for (iter = cli_opts.privkeys->first; iter; iter = iter->next) | ||
| 48 | { | ||
| 49 | sign_key * key = (sign_key*)iter->item; | ||
| 50 | - len += 3 + strlen(key->filename); | ||
| 51 | + len += 4 + strlen(key->filename); | ||
| 52 | } | ||
| 53 | -#endif /* DROPBEAR_CLI_PUBKEY_AUTH */ | ||
| 54 | +#endif | ||
| 55 | |||
| 56 | - len += 30; /* space for -W <size>, terminator. */ | ||
| 57 | - ret = m_malloc(len); | ||
| 58 | + args = m_malloc(len); | ||
| 59 | total = 0; | ||
| 60 | |||
| 61 | - if (cli_opts.no_hostkey_check) | ||
| 62 | - { | ||
| 63 | - int written = snprintf(ret+total, len-total, "-y -y "); | ||
| 64 | - total += written; | ||
| 65 | - } | ||
| 66 | - else if (cli_opts.always_accept_key) | ||
| 67 | - { | ||
| 68 | - int written = snprintf(ret+total, len-total, "-y "); | ||
| 69 | - total += written; | ||
| 70 | + /* Create new argument string */ | ||
| 71 | + | ||
| 72 | + if (cli_opts.no_hostkey_check) { | ||
| 73 | + total += m_snprintf(args+total, len-total, "-y -y "); | ||
| 74 | + } else if (cli_opts.always_accept_key) { | ||
| 75 | + total += m_snprintf(args+total, len-total, "-y "); | ||
| 76 | } | ||
| 77 | |||
| 78 | - if (opts.recv_window != DEFAULT_RECV_WINDOW) | ||
| 79 | - { | ||
| 80 | - int written = snprintf(ret+total, len-total, "-W %u ", opts.recv_window); | ||
| 81 | - total += written; | ||
| 82 | + if (opts.recv_window != DEFAULT_RECV_WINDOW) { | ||
| 83 | + total += m_snprintf(args+total, len-total, "-W %u ", opts.recv_window); | ||
| 84 | } | ||
| 85 | |||
| 86 | #if DROPBEAR_CLI_PUBKEY_AUTH | ||
| 87 | for (iter = cli_opts.privkeys->first; iter; iter = iter->next) | ||
| 88 | { | ||
| 89 | sign_key * key = (sign_key*)iter->item; | ||
| 90 | - const size_t size = len - total; | ||
| 91 | - int written = snprintf(ret+total, size, "-i %s ", key->filename); | ||
| 92 | - dropbear_assert((unsigned int)written < size); | ||
| 93 | - total += written; | ||
| 94 | + total += m_snprintf(args+total, len-total, "-i %s ", key->filename); | ||
| 95 | } | ||
| 96 | #endif /* DROPBEAR_CLI_PUBKEY_AUTH */ | ||
| 97 | |||
| 98 | - /* if args were passed, total will be not zero, and it will have a space at the end, so remove that */ | ||
| 99 | - if (total > 0) | ||
| 100 | - { | ||
| 101 | - total--; | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | - return ret; | ||
| 105 | + return args; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* Sets up 'onion-forwarding' connections. This will spawn | ||
| 109 | @@ -608,7 +597,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0) | ||
| 110 | && strchr(cli_opts.username, '@')) { | ||
| 111 | unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2; | ||
| 112 | hostbuf = m_malloc(len); | ||
| 113 | - snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg); | ||
| 114 | + m_snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg); | ||
| 115 | } else { | ||
| 116 | hostbuf = m_strdup(orighostarg); | ||
| 117 | } | ||
| 118 | @@ -642,7 +631,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0) | ||
| 119 | + strlen(passthrough_args) | ||
| 120 | + 30; | ||
| 121 | cli_opts.proxycmd = m_malloc(cmd_len); | ||
| 122 | - snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s", | ||
| 123 | + m_snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s", | ||
| 124 | argv0, cli_opts.remotehost, cli_opts.remoteport, | ||
| 125 | passthrough_args, remainder); | ||
| 126 | #ifndef DISABLE_ZLIB | ||
diff --git a/meta/recipes-core/dropbear/dropbear/CVE-2025-47203.patch b/meta/recipes-core/dropbear/dropbear/CVE-2025-47203.patch new file mode 100644 index 0000000000..3a51927cfe --- /dev/null +++ b/meta/recipes-core/dropbear/dropbear/CVE-2025-47203.patch | |||
| @@ -0,0 +1,344 @@ | |||
| 1 | From e5a0ef27c227f7ae69d9a9fec98a056494409b9b Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Matt Johnston <matt@ucc.asn.au> | ||
| 3 | Date: Mon, 5 May 2025 23:14:19 +0800 | ||
| 4 | Subject: [PATCH] Execute multihop commands directly, no shell | ||
| 5 | |||
| 6 | This avoids problems with shell escaping if arguments contain special | ||
| 7 | characters. | ||
| 8 | |||
| 9 | Origin: https://github.com/mkj/dropbear/commit/e5a0ef27c227f7ae69d9a9fec98a056494409b9b | ||
| 10 | Bug: https://www.openwall.com/lists/oss-security/2025/05/13/1 | ||
| 11 | Bug-Debian: https://deb.freexian.com/extended-lts/tracker/CVE-2025-47203 | ||
| 12 | |||
| 13 | CVE: CVE-2025-47203 | ||
| 14 | Upstream-Status: Backport [https://github.com/mkj/dropbear/commit/e5a0ef27c227f7ae69d9a9fec98a056494409b9b] | ||
| 15 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 16 | --- | ||
| 17 | cli-main.c | 60 ++++++++++++++++++++++++++++-------------- | ||
| 18 | cli-runopts.c | 84 +++++++++++++++++++++++++++++++++++------------------------ | ||
| 19 | dbutil.c | 9 +++++-- | ||
| 20 | dbutil.h | 1 + | ||
| 21 | runopts.h | 5 ++++ | ||
| 22 | 5 files changed, 104 insertions(+), 55 deletions(-) | ||
| 23 | |||
| 24 | diff --git a/cli-main.c b/cli-main.c | ||
| 25 | index 7f455d1..53c55c1 100644 | ||
| 26 | --- a/cli-main.c | ||
| 27 | +++ b/cli-main.c | ||
| 28 | @@ -73,9 +73,8 @@ int main(int argc, char ** argv) { | ||
| 29 | |||
| 30 | pid_t proxy_cmd_pid = 0; | ||
| 31 | #if DROPBEAR_CLI_PROXYCMD | ||
| 32 | - if (cli_opts.proxycmd) { | ||
| 33 | + if (cli_opts.proxycmd || cli_opts.proxyexec) { | ||
| 34 | cli_proxy_cmd(&sock_in, &sock_out, &proxy_cmd_pid); | ||
| 35 | - m_free(cli_opts.proxycmd); | ||
| 36 | if (signal(SIGINT, kill_proxy_sighandler) == SIG_ERR || | ||
| 37 | signal(SIGTERM, kill_proxy_sighandler) == SIG_ERR || | ||
| 38 | signal(SIGHUP, kill_proxy_sighandler) == SIG_ERR) { | ||
| 39 | @@ -96,7 +95,8 @@ int main(int argc, char ** argv) { | ||
| 40 | } | ||
| 41 | #endif /* DBMULTI stuff */ | ||
| 42 | |||
| 43 | -static void exec_proxy_cmd(const void *user_data_cmd) { | ||
| 44 | +#if DROPBEAR_CLI_PROXYCMD | ||
| 45 | +static void shell_proxy_cmd(const void *user_data_cmd) { | ||
| 46 | const char *cmd = user_data_cmd; | ||
| 47 | char *usershell; | ||
| 48 | |||
| 49 | @@ -105,40 +105,62 @@ static void exec_proxy_cmd(const void *user_data_cmd) { | ||
| 50 | dropbear_exit("Failed to run '%s'\n", cmd); | ||
| 51 | } | ||
| 52 | |||
| 53 | -#if DROPBEAR_CLI_PROXYCMD | ||
| 54 | +static void exec_proxy_cmd(const void *unused) { | ||
| 55 | + (void)unused; | ||
| 56 | + run_command(cli_opts.proxyexec[0], cli_opts.proxyexec, ses.maxfd); | ||
| 57 | + dropbear_exit("Failed to run '%s'\n", cli_opts.proxyexec[0]); | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out) { | ||
| 61 | - char * ex_cmd = NULL; | ||
| 62 | - size_t ex_cmdlen; | ||
| 63 | + char * cmd_arg = NULL; | ||
| 64 | + void (*exec_fn)(const void *user_data) = NULL; | ||
| 65 | int ret; | ||
| 66 | |||
| 67 | + /* exactly one of cli_opts.proxycmd or cli_opts.proxyexec should be set */ | ||
| 68 | + | ||
| 69 | /* File descriptor "-j &3" */ | ||
| 70 | - if (*cli_opts.proxycmd == '&') { | ||
| 71 | + if (cli_opts.proxycmd && *cli_opts.proxycmd == '&') { | ||
| 72 | char *p = cli_opts.proxycmd + 1; | ||
| 73 | int sock = strtoul(p, &p, 10); | ||
| 74 | /* must be a single number, and not stdin/stdout/stderr */ | ||
| 75 | if (sock > 2 && sock < 1024 && *p == '\0') { | ||
| 76 | *sock_in = sock; | ||
| 77 | *sock_out = sock; | ||
| 78 | - return; | ||
| 79 | + goto cleanup; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | - /* Normal proxycommand */ | ||
| 84 | - | ||
| 85 | - /* So that spawn_command knows which shell to run */ | ||
| 86 | - fill_passwd(cli_opts.own_user); | ||
| 87 | - | ||
| 88 | - ex_cmdlen = strlen(cli_opts.proxycmd) + 6; /* "exec " + command + '\0' */ | ||
| 89 | - ex_cmd = m_malloc(ex_cmdlen); | ||
| 90 | - snprintf(ex_cmd, ex_cmdlen, "exec %s", cli_opts.proxycmd); | ||
| 91 | + if (cli_opts.proxycmd) { | ||
| 92 | + /* Normal proxycommand */ | ||
| 93 | + size_t shell_cmdlen; | ||
| 94 | + /* So that spawn_command knows which shell to run */ | ||
| 95 | + fill_passwd(cli_opts.own_user); | ||
| 96 | + | ||
| 97 | + shell_cmdlen = strlen(cli_opts.proxycmd) + 6; /* "exec " + command + '\0' */ | ||
| 98 | + cmd_arg = m_malloc(shell_cmdlen); | ||
| 99 | + snprintf(cmd_arg, shell_cmdlen, "exec %s", cli_opts.proxycmd); | ||
| 100 | + exec_fn = shell_proxy_cmd; | ||
| 101 | + } else { | ||
| 102 | + /* No shell */ | ||
| 103 | + exec_fn = exec_proxy_cmd; | ||
| 104 | + } | ||
| 105 | |||
| 106 | - ret = spawn_command(exec_proxy_cmd, ex_cmd, | ||
| 107 | - sock_out, sock_in, NULL, pid_out); | ||
| 108 | - m_free(ex_cmd); | ||
| 109 | + ret = spawn_command(exec_fn, cmd_arg, sock_out, sock_in, NULL, pid_out); | ||
| 110 | if (ret == DROPBEAR_FAILURE) { | ||
| 111 | dropbear_exit("Failed running proxy command"); | ||
| 112 | *sock_in = *sock_out = -1; | ||
| 113 | } | ||
| 114 | + | ||
| 115 | +cleanup: | ||
| 116 | + m_free(cli_opts.proxycmd); | ||
| 117 | + m_free(cmd_arg); | ||
| 118 | + if (cli_opts.proxyexec) { | ||
| 119 | + char **a = NULL; | ||
| 120 | + for (a = cli_opts.proxyexec; *a; a++) { | ||
| 121 | + m_free_direct(*a); | ||
| 122 | + } | ||
| 123 | + m_free(cli_opts.proxyexec); | ||
| 124 | + } | ||
| 125 | } | ||
| 126 | |||
| 127 | static void kill_proxy_sighandler(int UNUSED(signo)) { | ||
| 128 | diff --git a/cli-runopts.c b/cli-runopts.c | ||
| 129 | index 9798f62..0f3dcd0 100644 | ||
| 130 | --- a/cli-runopts.c | ||
| 131 | +++ b/cli-runopts.c | ||
| 132 | @@ -525,47 +525,69 @@ static void loadidentityfile(const char* filename, int warnfail) { | ||
| 133 | |||
| 134 | /* Fill out -i, -y, -W options that make sense for all | ||
| 135 | * the intermediate processes */ | ||
| 136 | -static char* multihop_passthrough_args(void) { | ||
| 137 | - char *args = NULL; | ||
| 138 | - unsigned int len, total; | ||
| 139 | +static char** multihop_args(const char* argv0, const char* prior_hops) { | ||
| 140 | + /* null terminated array */ | ||
| 141 | + char **args = NULL; | ||
| 142 | + size_t max_args = 14, pos = 0, len; | ||
| 143 | #if DROPBEAR_CLI_PUBKEY_AUTH | ||
| 144 | m_list_elem *iter; | ||
| 145 | #endif | ||
| 146 | - /* Sufficient space for non-string args */ | ||
| 147 | - len = 100; | ||
| 148 | |||
| 149 | - /* String arguments have arbitrary length, so determine space required */ | ||
| 150 | #if DROPBEAR_CLI_PUBKEY_AUTH | ||
| 151 | for (iter = cli_opts.privkeys->first; iter; iter = iter->next) | ||
| 152 | { | ||
| 153 | - sign_key * key = (sign_key*)iter->item; | ||
| 154 | - len += 4 + strlen(key->filename); | ||
| 155 | + /* "-i file" for each */ | ||
| 156 | + max_args += 2; | ||
| 157 | } | ||
| 158 | #endif | ||
| 159 | |||
| 160 | - args = m_malloc(len); | ||
| 161 | - total = 0; | ||
| 162 | + args = m_malloc(sizeof(char*) * max_args); | ||
| 163 | + pos = 0; | ||
| 164 | |||
| 165 | - /* Create new argument string */ | ||
| 166 | + args[pos] = m_strdup(argv0); | ||
| 167 | + pos++; | ||
| 168 | |||
| 169 | if (cli_opts.no_hostkey_check) { | ||
| 170 | - total += m_snprintf(args+total, len-total, "-y -y "); | ||
| 171 | + args[pos] = m_strdup("-y"); | ||
| 172 | + pos++; | ||
| 173 | + args[pos] = m_strdup("-y"); | ||
| 174 | + pos++; | ||
| 175 | } else if (cli_opts.always_accept_key) { | ||
| 176 | - total += m_snprintf(args+total, len-total, "-y "); | ||
| 177 | + args[pos] = m_strdup("-y"); | ||
| 178 | + pos++; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (opts.recv_window != DEFAULT_RECV_WINDOW) { | ||
| 182 | - total += m_snprintf(args+total, len-total, "-W %u ", opts.recv_window); | ||
| 183 | + args[pos] = m_strdup("-W"); | ||
| 184 | + pos++; | ||
| 185 | + args[pos] = m_malloc(11); | ||
| 186 | + m_snprintf(args[pos], 11, "%u", opts.recv_window); | ||
| 187 | + pos++; | ||
| 188 | } | ||
| 189 | |||
| 190 | #if DROPBEAR_CLI_PUBKEY_AUTH | ||
| 191 | for (iter = cli_opts.privkeys->first; iter; iter = iter->next) | ||
| 192 | { | ||
| 193 | sign_key * key = (sign_key*)iter->item; | ||
| 194 | - total += m_snprintf(args+total, len-total, "-i %s ", key->filename); | ||
| 195 | + args[pos] = m_strdup("-i"); | ||
| 196 | + pos++; | ||
| 197 | + args[pos] = m_strdup(key->filename); | ||
| 198 | + pos++; | ||
| 199 | } | ||
| 200 | #endif /* DROPBEAR_CLI_PUBKEY_AUTH */ | ||
| 201 | |||
| 202 | + /* last hop */ | ||
| 203 | + args[pos] = m_strdup("-B"); | ||
| 204 | + pos++; | ||
| 205 | + len = strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport) + 2; | ||
| 206 | + args[pos] = m_malloc(len); | ||
| 207 | + snprintf(args[pos], len, "%s:%s", cli_opts.remotehost, cli_opts.remoteport); | ||
| 208 | + pos++; | ||
| 209 | + | ||
| 210 | + /* hostnames of prior hops */ | ||
| 211 | + args[pos] = m_strdup(prior_hops); | ||
| 212 | + pos++; | ||
| 213 | + | ||
| 214 | return args; | ||
| 215 | } | ||
| 216 | |||
| 217 | @@ -585,7 +607,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0) | ||
| 218 | char *userhostarg = NULL; | ||
| 219 | char *hostbuf = NULL; | ||
| 220 | char *last_hop = NULL; | ||
| 221 | - char *remainder = NULL; | ||
| 222 | + char *prior_hops = NULL; | ||
| 223 | |||
| 224 | /* both scp and rsync parse a user@host argument | ||
| 225 | * and turn it into "-l user host". This breaks | ||
| 226 | @@ -603,6 +625,8 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0) | ||
| 227 | } | ||
| 228 | userhostarg = hostbuf; | ||
| 229 | |||
| 230 | + /* Split off any last hostname and use that as remotehost/remoteport. | ||
| 231 | + * That is used for authorized_keys checking etc */ | ||
| 232 | last_hop = strrchr(userhostarg, ','); | ||
| 233 | if (last_hop) { | ||
| 234 | if (last_hop == userhostarg) { | ||
| 235 | @@ -610,36 +634,28 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0) | ||
| 236 | } | ||
| 237 | *last_hop = '\0'; | ||
| 238 | last_hop++; | ||
| 239 | - remainder = userhostarg; | ||
| 240 | + prior_hops = userhostarg; | ||
| 241 | userhostarg = last_hop; | ||
| 242 | } | ||
| 243 | |||
| 244 | + /* Update cli_opts.remotehost and cli_opts.remoteport */ | ||
| 245 | parse_hostname(userhostarg); | ||
| 246 | |||
| 247 | - if (last_hop) { | ||
| 248 | - /* Set up the proxycmd */ | ||
| 249 | - unsigned int cmd_len = 0; | ||
| 250 | - char *passthrough_args = multihop_passthrough_args(); | ||
| 251 | + /* Construct any multihop proxy command. Use proxyexec to | ||
| 252 | + * avoid worrying about shell escaping. */ | ||
| 253 | + if (prior_hops) { | ||
| 254 | + cli_opts.proxyexec = multihop_args(argv0, prior_hops); | ||
| 255 | + /* Any -J argument has been copied to proxyexec */ | ||
| 256 | if (cli_opts.proxycmd) { | ||
| 257 | dropbear_exit("-J can't be used with multihop mode"); | ||
| 258 | } | ||
| 259 | - if (cli_opts.remoteport == NULL) { | ||
| 260 | - cli_opts.remoteport = "22"; | ||
| 261 | - } | ||
| 262 | - cmd_len = strlen(argv0) + strlen(remainder) | ||
| 263 | - + strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport) | ||
| 264 | - + strlen(passthrough_args) | ||
| 265 | - + 30; | ||
| 266 | - cli_opts.proxycmd = m_malloc(cmd_len); | ||
| 267 | - m_snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s", | ||
| 268 | - argv0, cli_opts.remotehost, cli_opts.remoteport, | ||
| 269 | - passthrough_args, remainder); | ||
| 270 | + | ||
| 271 | #ifndef DISABLE_ZLIB | ||
| 272 | - /* The stream will be incompressible since it's encrypted. */ | ||
| 273 | + /* This outer stream will be incompressible since it's encrypted. */ | ||
| 274 | opts.compress_mode = DROPBEAR_COMPRESS_OFF; | ||
| 275 | #endif | ||
| 276 | - m_free(passthrough_args); | ||
| 277 | } | ||
| 278 | + | ||
| 279 | m_free(hostbuf); | ||
| 280 | } | ||
| 281 | #endif /* !DROPBEAR_CLI_MULTIHOP */ | ||
| 282 | diff --git a/dbutil.c b/dbutil.c | ||
| 283 | index d4c3298..a51c1f9 100644 | ||
| 284 | --- a/dbutil.c | ||
| 285 | +++ b/dbutil.c | ||
| 286 | @@ -347,7 +347,6 @@ int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data, | ||
| 287 | void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) { | ||
| 288 | char * argv[4]; | ||
| 289 | char * baseshell = NULL; | ||
| 290 | - unsigned int i; | ||
| 291 | |||
| 292 | baseshell = basename(usershell); | ||
| 293 | |||
| 294 | @@ -369,6 +368,12 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) { | ||
| 295 | argv[1] = NULL; | ||
| 296 | } | ||
| 297 | |||
| 298 | + run_command(usershell, argv, maxfd); | ||
| 299 | +} | ||
| 300 | + | ||
| 301 | +void run_command(const char* argv0, char** args, unsigned int maxfd) { | ||
| 302 | + unsigned int i; | ||
| 303 | + | ||
| 304 | /* Re-enable SIGPIPE for the executed process */ | ||
| 305 | if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) { | ||
| 306 | dropbear_exit("signal() error"); | ||
| 307 | @@ -380,7 +385,7 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) { | ||
| 308 | m_close(i); | ||
| 309 | } | ||
| 310 | |||
| 311 | - execv(usershell, argv); | ||
| 312 | + execv(argv0, args); | ||
| 313 | } | ||
| 314 | |||
| 315 | #if DEBUG_TRACE | ||
| 316 | diff --git a/dbutil.h b/dbutil.h | ||
| 317 | index 71cffe8..5d86485 100644 | ||
| 318 | --- a/dbutil.h | ||
| 319 | +++ b/dbutil.h | ||
| 320 | @@ -60,6 +60,7 @@ char * stripcontrol(const char * text); | ||
| 321 | int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data, | ||
| 322 | int *writefd, int *readfd, int *errfd, pid_t *pid); | ||
| 323 | void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell); | ||
| 324 | +void run_command(const char* argv0, char** args, unsigned int maxfd); | ||
| 325 | #if ENABLE_CONNECT_UNIX | ||
| 326 | int connect_unix(const char* addr); | ||
| 327 | #endif | ||
| 328 | diff --git a/runopts.h b/runopts.h | ||
| 329 | index 01201d2..b49dc13 100644 | ||
| 330 | --- a/runopts.h | ||
| 331 | +++ b/runopts.h | ||
| 332 | @@ -179,7 +179,12 @@ typedef struct cli_runopts { | ||
| 333 | unsigned int netcat_port; | ||
| 334 | #endif | ||
| 335 | #if DROPBEAR_CLI_PROXYCMD | ||
| 336 | + /* A proxy command to run via the user's shell */ | ||
| 337 | char *proxycmd; | ||
| 338 | +#endif | ||
| 339 | +#if DROPBEAR_CLI_MULTIHOP | ||
| 340 | + /* Similar to proxycmd, but is arguments for execve(), not shell */ | ||
| 341 | + char **proxyexec; | ||
| 342 | #endif | ||
| 343 | char *bind_address; | ||
| 344 | char *bind_port; | ||
