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; | ||