/src/dropbear/src/cli-runopts.c
Line | Count | Source |
1 | | /* |
2 | | * Dropbear - a SSH2 server |
3 | | * |
4 | | * Copyright (c) 2002,2003 Matt Johnston |
5 | | * All rights reserved. |
6 | | * |
7 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | * of this software and associated documentation files (the "Software"), to deal |
9 | | * in the Software without restriction, including without limitation the rights |
10 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | * copies of the Software, and to permit persons to whom the Software is |
12 | | * furnished to do so, subject to the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be included in |
15 | | * all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | * SOFTWARE. */ |
24 | | |
25 | | #include "includes.h" |
26 | | #include "runopts.h" |
27 | | #include "signkey.h" |
28 | | #include "buffer.h" |
29 | | #include "dbutil.h" |
30 | | #include "algo.h" |
31 | | #include "forward.h" |
32 | | #include "list.h" |
33 | | |
34 | | cli_runopts cli_opts; /* GLOBAL */ |
35 | | |
36 | | static void printhelp(void); |
37 | | static void parse_hostname(const char* orighostarg); |
38 | | static void parse_multihop_hostname(const char* orighostarg, const char* argv0); |
39 | | static void fill_own_user(void); |
40 | | #if DROPBEAR_CLI_ANYTCPFWD |
41 | | static void addforward(const char* str, m_list *fwdlist); |
42 | | #endif |
43 | | #if DROPBEAR_CLI_NETCAT |
44 | | static void add_netcat(const char *str); |
45 | | #endif |
46 | | static void add_extendedopt(const char *str); |
47 | | |
48 | | #if DROPBEAR_USE_SSH_CONFIG |
49 | | static void apply_config_settings(const char* cli_host_arg); |
50 | | #endif |
51 | | |
52 | 0 | static void printhelp() { |
53 | |
|
54 | 0 | fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n" |
55 | 0 | #if DROPBEAR_CLI_MULTIHOP |
56 | 0 | "Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n" |
57 | | #else |
58 | | "Usage: %s [options] [user@]host[/port] [command]\n" |
59 | | #endif |
60 | 0 | "-p <remoteport>\n" |
61 | 0 | "-l <username>\n" |
62 | 0 | "-t Allocate a pty\n" |
63 | 0 | "-T Don't allocate a pty\n" |
64 | 0 | "-N Don't run a remote command\n" |
65 | 0 | "-f Run in background after auth\n" |
66 | 0 | "-q quiet, don't show remote banner\n" |
67 | 0 | "-y Always accept remote host key if unknown\n" |
68 | 0 | "-y -y Don't perform any remote host key checking (caution)\n" |
69 | 0 | "-s Request a subsystem (use by external sftp)\n" |
70 | 0 | "-o option Set option in OpenSSH-like format ('-o help' to list options)\n" |
71 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
72 | 0 | "-i <identityfile> (multiple allowed, default %s)\n" |
73 | 0 | #endif |
74 | 0 | #if DROPBEAR_CLI_AGENTFWD |
75 | 0 | "-A Enable agent auth forwarding\n" |
76 | 0 | #endif |
77 | 0 | #if DROPBEAR_CLI_LOCALTCPFWD |
78 | 0 | "-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n" |
79 | 0 | "-g Allow remote hosts to connect to forwarded ports\n" |
80 | 0 | #endif |
81 | 0 | #if DROPBEAR_CLI_REMOTETCPFWD |
82 | 0 | "-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n" |
83 | 0 | #endif |
84 | 0 | "-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n" |
85 | 0 | "-K <keepalive> (0 is never, default %d)\n" |
86 | 0 | "-I <idle_timeout> (0 is never, default %d)\n" |
87 | 0 | "-M <max_duration> (0 is off, default %d, in seconds)\n" |
88 | 0 | "-z disable QoS\n" |
89 | 0 | #if DROPBEAR_CLI_NETCAT |
90 | 0 | "-B <endhost:endport> Netcat-alike forwarding\n" |
91 | 0 | #endif |
92 | 0 | #if DROPBEAR_CLI_PROXYCMD |
93 | 0 | "-J <proxy_program> Use program pipe rather than TCP connection\n" |
94 | 0 | #endif |
95 | 0 | #if DROPBEAR_USER_ALGO_LIST |
96 | 0 | "-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n" |
97 | 0 | "-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n" |
98 | 0 | #endif |
99 | 0 | "-b [bind_address][:bind_port]\n" |
100 | 0 | "-Q <algo> Print supported algorithms, or -Q help\n" |
101 | 0 | "-V Version\n" |
102 | | #if DEBUG_TRACE |
103 | | "-v verbose (repeat for more verbose)\n" |
104 | | #endif |
105 | 0 | ,DROPBEAR_VERSION, cli_opts.progname, |
106 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
107 | 0 | DROPBEAR_DEFAULT_CLI_AUTHKEY, |
108 | 0 | #endif |
109 | 0 | DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT, |
110 | 0 | DEFAULT_MAX_DURATION); |
111 | |
|
112 | 0 | } |
113 | | |
114 | 1 | void cli_getopts(int argc, char ** argv) { |
115 | 1 | unsigned int i, j; |
116 | 1 | const char ** next = NULL; |
117 | 1 | enum { |
118 | 1 | OPT_EXTENDED_OPTIONS, |
119 | 1 | #if DROPBEAR_CLI_PUBKEY_AUTH |
120 | 1 | OPT_AUTHKEY, |
121 | 1 | #endif |
122 | 1 | #if DROPBEAR_CLI_LOCALTCPFWD |
123 | 1 | OPT_LOCALTCPFWD, |
124 | 1 | #endif |
125 | 1 | #if DROPBEAR_CLI_REMOTETCPFWD |
126 | 1 | OPT_REMOTETCPFWD, |
127 | 1 | #endif |
128 | 1 | #if DROPBEAR_CLI_NETCAT |
129 | 1 | OPT_NETCAT, |
130 | 1 | #endif |
131 | | /* a flag (no arg) if 'next' is NULL, a string-valued option otherwise */ |
132 | 1 | OPT_OTHER |
133 | 1 | } opt; |
134 | 1 | unsigned int cmdlen; |
135 | | |
136 | 1 | const char* recv_window_arg = NULL; |
137 | 1 | const char* idle_timeout_arg = NULL; |
138 | 1 | const char* max_duration_arg = NULL; |
139 | 1 | const char *host_arg = NULL; |
140 | 1 | const char *proxycmd_arg = NULL; |
141 | 1 | const char *remoteport_arg = NULL; |
142 | 1 | const char *username_arg = NULL; |
143 | 1 | const char *algo_print_arg = NULL; |
144 | 1 | char c; |
145 | | |
146 | | /* see printhelp() for options */ |
147 | 1 | cli_opts.progname = argv[0]; |
148 | 1 | cli_opts.remotehost = NULL; |
149 | 1 | cli_opts.remotehostfixed = 0; |
150 | 1 | cli_opts.remoteport = NULL; |
151 | 1 | cli_opts.username = NULL; |
152 | 1 | cli_opts.cmd = NULL; |
153 | 1 | cli_opts.no_cmd = 0; |
154 | 1 | cli_opts.quiet = 0; |
155 | 1 | cli_opts.backgrounded = 0; |
156 | 1 | cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ |
157 | 1 | cli_opts.always_accept_key = 0; |
158 | 1 | cli_opts.ask_hostkey = 1; |
159 | 1 | cli_opts.no_hostkey_check = 0; |
160 | 1 | cli_opts.is_subsystem = 0; |
161 | 1 | #if DROPBEAR_CLI_PUBKEY_AUTH |
162 | 1 | cli_opts.privkeys = list_new(); |
163 | 1 | #endif |
164 | 1 | #if DROPBEAR_CLI_ANYTCPFWD |
165 | 1 | cli_opts.exit_on_fwd_failure = 0; |
166 | 1 | #endif |
167 | 1 | cli_opts.disable_trivial_auth = 0; |
168 | 1 | cli_opts.password_authentication = 1; |
169 | 1 | cli_opts.batch_mode = 0; |
170 | 1 | #if DROPBEAR_CLI_LOCALTCPFWD |
171 | 1 | cli_opts.localfwds = list_new(); |
172 | 1 | opts.listen_fwd_all = 0; |
173 | 1 | #endif |
174 | 1 | #if DROPBEAR_CLI_REMOTETCPFWD |
175 | 1 | cli_opts.remotefwds = list_new(); |
176 | 1 | #endif |
177 | 1 | #if DROPBEAR_CLI_AGENTFWD |
178 | 1 | cli_opts.agent_fwd = 0; |
179 | 1 | cli_opts.agent_fd = -1; |
180 | 1 | cli_opts.agent_keys_loaded = 0; |
181 | 1 | #endif |
182 | 1 | #if DROPBEAR_CLI_PROXYCMD |
183 | 1 | cli_opts.proxycmd = NULL; |
184 | 1 | #endif |
185 | 1 | cli_opts.bind_arg = NULL; |
186 | 1 | cli_opts.bind_address = NULL; |
187 | 1 | cli_opts.bind_port = NULL; |
188 | 1 | cli_opts.keepalive_arg = NULL; |
189 | | #ifndef DISABLE_ZLIB |
190 | | opts.compression = DROPBEAR_CLI_COMPRESSION; |
191 | | #endif |
192 | 1 | #if DROPBEAR_USER_ALGO_LIST |
193 | 1 | opts.cipher_list = NULL; |
194 | 1 | opts.mac_list = NULL; |
195 | 1 | #endif |
196 | 1 | #ifndef DISABLE_SYSLOG |
197 | 1 | opts.usingsyslog = 0; |
198 | 1 | #endif |
199 | | /* not yet |
200 | | opts.ipv4 = 1; |
201 | | opts.ipv6 = 1; |
202 | | */ |
203 | 1 | opts.recv_window = DEFAULT_RECV_WINDOW; |
204 | 1 | opts.keepalive_secs = DEFAULT_KEEPALIVE; |
205 | 1 | opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT; |
206 | 1 | opts.max_duration_secs = DEFAULT_MAX_DURATION; |
207 | | |
208 | 1 | fill_own_user(); |
209 | | |
210 | 2 | for (i = 1; i < (unsigned int)argc; i++) { |
211 | | /* Handle non-flag arguments such as hostname or commands for the remote host */ |
212 | 1 | if (argv[i][0] != '-') |
213 | 1 | { |
214 | 1 | if (host_arg == NULL) { |
215 | 1 | host_arg = argv[i]; |
216 | 1 | continue; |
217 | 1 | } |
218 | | /* Commands to pass to the remote host. No more flag handling, |
219 | | commands are consumed below */ |
220 | 0 | break; |
221 | 1 | } |
222 | | |
223 | | /* Begins with '-' */ |
224 | 0 | opt = OPT_OTHER; |
225 | 0 | for (j = 1; (c = argv[i][j]) != '\0' && !next && opt == OPT_OTHER; j++) { |
226 | 0 | switch (c) { |
227 | 0 | case 'y': |
228 | | /* once is always accept the remote hostkey, |
229 | | * the same as stricthostkeychecking=accept-new */ |
230 | 0 | if (cli_opts.always_accept_key) { |
231 | | /* twice means no checking at all |
232 | | * (stricthostkeychecking=no) */ |
233 | 0 | cli_opts.no_hostkey_check = 1; |
234 | 0 | } |
235 | 0 | cli_opts.always_accept_key = 1; |
236 | 0 | break; |
237 | 0 | case 'q': /* quiet */ |
238 | 0 | cli_opts.quiet = 1; |
239 | 0 | break; |
240 | 0 | case 'p': /* remoteport */ |
241 | 0 | next = &remoteport_arg; |
242 | 0 | break; |
243 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
244 | 0 | case 'i': /* an identityfile */ |
245 | 0 | opt = OPT_AUTHKEY; |
246 | 0 | break; |
247 | 0 | #endif |
248 | 0 | case 't': /* we want a pty */ |
249 | 0 | cli_opts.wantpty = 1; |
250 | 0 | break; |
251 | 0 | case 'T': /* don't want a pty */ |
252 | 0 | cli_opts.wantpty = 0; |
253 | 0 | break; |
254 | 0 | case 'N': |
255 | 0 | cli_opts.no_cmd = 1; |
256 | 0 | break; |
257 | 0 | case 'f': |
258 | 0 | cli_opts.backgrounded = 1; |
259 | 0 | break; |
260 | 0 | case 's': |
261 | 0 | cli_opts.is_subsystem = 1; |
262 | 0 | break; |
263 | 0 | case 'o': |
264 | 0 | opt = OPT_EXTENDED_OPTIONS; |
265 | 0 | break; |
266 | 0 | #if DROPBEAR_CLI_LOCALTCPFWD |
267 | 0 | case 'L': |
268 | 0 | opt = OPT_LOCALTCPFWD; |
269 | 0 | break; |
270 | 0 | case 'g': |
271 | 0 | opts.listen_fwd_all = 1; |
272 | 0 | break; |
273 | 0 | #endif |
274 | 0 | #if DROPBEAR_CLI_REMOTETCPFWD |
275 | 0 | case 'R': |
276 | 0 | opt = OPT_REMOTETCPFWD; |
277 | 0 | break; |
278 | 0 | #endif |
279 | 0 | #if DROPBEAR_CLI_NETCAT |
280 | 0 | case 'B': |
281 | 0 | opt = OPT_NETCAT; |
282 | 0 | break; |
283 | 0 | #endif |
284 | 0 | #if DROPBEAR_CLI_PROXYCMD |
285 | 0 | case 'J': |
286 | 0 | next = &proxycmd_arg; |
287 | 0 | break; |
288 | 0 | #endif |
289 | 0 | case 'l': |
290 | 0 | next = &username_arg; |
291 | 0 | break; |
292 | 0 | case 'Q': |
293 | 0 | next = &algo_print_arg; |
294 | 0 | break; |
295 | 0 | case 'h': |
296 | 0 | printhelp(); |
297 | 0 | exit(EXIT_SUCCESS); |
298 | 0 | break; |
299 | 0 | case 'u': |
300 | | /* backwards compatibility with old urandom option */ |
301 | 0 | break; |
302 | 0 | case 'W': |
303 | 0 | next = &recv_window_arg; |
304 | 0 | break; |
305 | 0 | case 'K': |
306 | 0 | next = &cli_opts.keepalive_arg; |
307 | 0 | break; |
308 | 0 | case 'I': |
309 | 0 | next = &idle_timeout_arg; |
310 | 0 | break; |
311 | 0 | case 'M': |
312 | 0 | next = &max_duration_arg; |
313 | 0 | break; |
314 | 0 | #if DROPBEAR_CLI_AGENTFWD |
315 | 0 | case 'A': |
316 | 0 | cli_opts.agent_fwd = 1; |
317 | 0 | break; |
318 | 0 | #endif |
319 | 0 | #if DROPBEAR_USER_ALGO_LIST |
320 | 0 | case 'c': |
321 | 0 | next = &opts.cipher_list; |
322 | 0 | break; |
323 | 0 | case 'm': |
324 | 0 | next = &opts.mac_list; |
325 | 0 | break; |
326 | 0 | #endif |
327 | | #if DEBUG_TRACE |
328 | | case 'v': |
329 | | debug_trace++; |
330 | | break; |
331 | | #endif |
332 | 0 | case 'F': |
333 | 0 | case 'e': |
334 | | #if !DROPBEAR_USER_ALGO_LIST |
335 | | case 'c': |
336 | | case 'm': |
337 | | #endif |
338 | 0 | case 'D': |
339 | | #if !DROPBEAR_CLI_REMOTETCPFWD |
340 | | case 'R': |
341 | | #endif |
342 | | #if !DROPBEAR_CLI_LOCALTCPFWD |
343 | | case 'L': |
344 | | #endif |
345 | 0 | case 'V': |
346 | 0 | print_version(); |
347 | 0 | exit(EXIT_SUCCESS); |
348 | 0 | break; |
349 | 0 | case 'b': |
350 | 0 | next = &cli_opts.bind_arg; |
351 | 0 | break; |
352 | 0 | case 'z': |
353 | 0 | opts.disable_ip_tos = 1; |
354 | 0 | break; |
355 | 0 | default: |
356 | 0 | fprintf(stderr, |
357 | 0 | "WARNING: Ignoring unknown option -%c\n", c); |
358 | 0 | break; |
359 | 0 | } /* Switch */ |
360 | 0 | } |
361 | | |
362 | 0 | if (!next && opt == OPT_OTHER) /* got a flag */ |
363 | 0 | continue; |
364 | | |
365 | 0 | if (c == '\0') { |
366 | 0 | i++; |
367 | 0 | j = 0; |
368 | 0 | if (!argv[i]) |
369 | 0 | dropbear_exit("Missing argument"); |
370 | 0 | } |
371 | | |
372 | 0 | if (opt == OPT_EXTENDED_OPTIONS) { |
373 | 0 | TRACE(("opt extended")) |
374 | 0 | add_extendedopt(&argv[i][j]); |
375 | 0 | } |
376 | 0 | else |
377 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
378 | 0 | if (opt == OPT_AUTHKEY) { |
379 | 0 | TRACE(("opt authkey")) |
380 | 0 | loadidentityfile(&argv[i][j], 1); |
381 | 0 | } |
382 | 0 | else |
383 | 0 | #endif |
384 | 0 | #if DROPBEAR_CLI_REMOTETCPFWD |
385 | 0 | if (opt == OPT_REMOTETCPFWD) { |
386 | 0 | TRACE(("opt remotetcpfwd")) |
387 | 0 | addforward(&argv[i][j], cli_opts.remotefwds); |
388 | 0 | } |
389 | 0 | else |
390 | 0 | #endif |
391 | 0 | #if DROPBEAR_CLI_LOCALTCPFWD |
392 | 0 | if (opt == OPT_LOCALTCPFWD) { |
393 | 0 | TRACE(("opt localtcpfwd")) |
394 | 0 | addforward(&argv[i][j], cli_opts.localfwds); |
395 | 0 | } |
396 | 0 | else |
397 | 0 | #endif |
398 | 0 | #if DROPBEAR_CLI_NETCAT |
399 | 0 | if (opt == OPT_NETCAT) { |
400 | 0 | TRACE(("opt netcat")) |
401 | 0 | add_netcat(&argv[i][j]); |
402 | 0 | } |
403 | 0 | else |
404 | 0 | #endif |
405 | 0 | if (next) { |
406 | | /* The previous flag set a value to assign */ |
407 | 0 | *next = &argv[i][j]; |
408 | 0 | if (*next == NULL) |
409 | 0 | dropbear_exit("Invalid null argument"); |
410 | 0 | next = NULL; |
411 | 0 | } |
412 | 0 | } |
413 | | |
414 | 1 | #if DROPBEAR_USER_ALGO_LIST |
415 | | /* -c help doesn't need a hostname */ |
416 | 1 | parse_ciphers_macs(); |
417 | 1 | #endif |
418 | | |
419 | 1 | if (algo_print_arg) { |
420 | 0 | print_algos(algo_print_arg); |
421 | | /* No return */ |
422 | 0 | } |
423 | | |
424 | 1 | if (host_arg == NULL) { /* missing hostname */ |
425 | 0 | printhelp(); |
426 | 0 | dropbear_exit("Remote host needs to provided."); |
427 | 0 | } |
428 | 1 | TRACE(("host is: %s", host_arg)) |
429 | | |
430 | 1 | #if DROPBEAR_USE_SSH_CONFIG |
431 | 1 | apply_config_settings(host_arg); |
432 | 1 | #endif |
433 | | |
434 | | /* Apply needed defaults if missing from command line or config file. */ |
435 | 1 | if (remoteport_arg) { |
436 | 0 | m_free(cli_opts.remoteport); |
437 | 0 | cli_opts.remoteport = m_strdup(remoteport_arg); |
438 | 1 | } else if (!cli_opts.remoteport) { |
439 | 1 | cli_opts.remoteport = m_strdup("22"); |
440 | 1 | } |
441 | | |
442 | 1 | if (username_arg) { |
443 | 0 | m_free(cli_opts.username); |
444 | 0 | cli_opts.username = m_strdup(username_arg); |
445 | 1 | } else if(!cli_opts.username) { |
446 | 1 | cli_opts.username = m_strdup(cli_opts.own_user); |
447 | 1 | } |
448 | | |
449 | | /* Done with options/flags; now handle the hostname (which may not |
450 | | * start with a hyphen) and optional command */ |
451 | | |
452 | 1 | if (i < (unsigned int)argc) { |
453 | | /* Build the command to send */ |
454 | 0 | cmdlen = 0; |
455 | 0 | for (j = i; j < (unsigned int)argc; j++) |
456 | 0 | cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */ |
457 | | |
458 | | /* Allocate the space */ |
459 | 0 | cli_opts.cmd = (char*)m_malloc(cmdlen); |
460 | 0 | cli_opts.cmd[0] = '\0'; |
461 | | |
462 | | /* Append all the bits */ |
463 | 0 | for (j = i; j < (unsigned int)argc; j++) { |
464 | 0 | strlcat(cli_opts.cmd, argv[j], cmdlen); |
465 | 0 | strlcat(cli_opts.cmd, " ", cmdlen); |
466 | 0 | } |
467 | | /* It'll be null-terminated here */ |
468 | 0 | TRACE(("cmd is: %s", cli_opts.cmd)) |
469 | 0 | } |
470 | | |
471 | | /* And now a few sanity checks and setup */ |
472 | | |
473 | 1 | #if DROPBEAR_CLI_PROXYCMD |
474 | 1 | if (proxycmd_arg) { |
475 | | /* To match the common path of m_freeing it */ |
476 | 0 | cli_opts.proxycmd = m_strdup(proxycmd_arg); |
477 | 0 | } |
478 | 1 | #endif |
479 | | |
480 | 1 | if (cli_opts.bind_arg) { |
481 | 0 | if (split_address_port(cli_opts.bind_arg, |
482 | 0 | &cli_opts.bind_address, &cli_opts.bind_port) |
483 | 0 | == DROPBEAR_FAILURE) { |
484 | 0 | dropbear_exit("Bad -b argument"); |
485 | 0 | } |
486 | 0 | } |
487 | | |
488 | | /* If not explicitly specified with -t or -T, we don't want a pty if |
489 | | * there's a command, but we do otherwise */ |
490 | 1 | if (cli_opts.wantpty == 9) { |
491 | 1 | if (cli_opts.cmd == NULL) { |
492 | 1 | if (isatty(STDIN_FILENO)) { |
493 | 0 | cli_opts.wantpty = 1; |
494 | 1 | } else { |
495 | 1 | TRACE(("Not a TTY")); |
496 | 1 | cli_opts.wantpty = 0; |
497 | 1 | } |
498 | 1 | } else { |
499 | 0 | cli_opts.wantpty = 0; |
500 | 0 | } |
501 | 1 | } |
502 | | |
503 | 1 | if (cli_opts.backgrounded && cli_opts.cmd == NULL |
504 | 0 | && cli_opts.no_cmd == 0) { |
505 | 0 | dropbear_exit("Command required for -f"); |
506 | 0 | } |
507 | | |
508 | 1 | if (recv_window_arg) { |
509 | 0 | parse_recv_window(recv_window_arg); |
510 | 0 | } |
511 | 1 | if (cli_opts.keepalive_arg) { |
512 | 0 | unsigned int val; |
513 | 0 | if (m_str_to_uint(cli_opts.keepalive_arg, &val) == DROPBEAR_FAILURE) { |
514 | 0 | dropbear_exit("Bad keepalive '%s'", cli_opts.keepalive_arg); |
515 | 0 | } |
516 | 0 | opts.keepalive_secs = val; |
517 | 0 | } |
518 | | |
519 | 1 | if (idle_timeout_arg) { |
520 | 0 | unsigned int val; |
521 | 0 | if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) { |
522 | 0 | dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg); |
523 | 0 | } |
524 | 0 | opts.idle_timeout_secs = val; |
525 | 0 | } |
526 | | |
527 | 1 | if (max_duration_arg) { |
528 | 0 | unsigned int val; |
529 | 0 | if (m_str_to_uint(max_duration_arg, &val) == DROPBEAR_FAILURE) { |
530 | 0 | dropbear_exit("Bad max_duration '%s'", max_duration_arg); |
531 | 0 | } |
532 | 0 | opts.max_duration_secs = val; |
533 | 0 | } |
534 | | |
535 | 1 | #if DROPBEAR_CLI_NETCAT |
536 | 1 | if (cli_opts.cmd && cli_opts.netcat_host) { |
537 | 0 | dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd); |
538 | 0 | } |
539 | 1 | #endif |
540 | | |
541 | | /* The hostname gets set up last, since |
542 | | * in multi-hop mode it will require knowledge |
543 | | * of other flags such as -i */ |
544 | 1 | #if DROPBEAR_CLI_MULTIHOP |
545 | 1 | parse_multihop_hostname(host_arg, argv[0]); |
546 | | #else |
547 | | parse_hostname(host_arg); |
548 | | #endif |
549 | | |
550 | | /* We don't want to include default id_dropbear as a |
551 | | -i argument for multihop, so handle it later. */ |
552 | 1 | #if (DROPBEAR_CLI_PUBKEY_AUTH) |
553 | 1 | { |
554 | 1 | loadidentityfile(DROPBEAR_DEFAULT_CLI_AUTHKEY, 0); |
555 | 1 | } |
556 | 1 | #endif |
557 | 1 | } |
558 | | |
559 | | #if DROPBEAR_CLI_PUBKEY_AUTH |
560 | 1.55k | void loadidentityfile(const char* filename, int warnfail) { |
561 | 1.55k | sign_key *key; |
562 | 1.55k | enum signkey_type keytype; |
563 | | |
564 | 1.55k | char *id_key_path = expand_homedir_path(filename); |
565 | 1.55k | TRACE(("loadidentityfile %s", id_key_path)) |
566 | | |
567 | 1.55k | key = new_sign_key(); |
568 | 1.55k | keytype = DROPBEAR_SIGNKEY_ANY; |
569 | 1.55k | if ( readhostkey(id_key_path, key, &keytype) != DROPBEAR_SUCCESS ) { |
570 | 1.55k | if (warnfail) { |
571 | 1.55k | dropbear_log(LOG_WARNING, "Failed loading keyfile '%s'\n", id_key_path); |
572 | 1.55k | } |
573 | 1.55k | sign_key_free(key); |
574 | 1.55k | m_free(id_key_path); |
575 | 1.55k | } else { |
576 | 0 | key->type = keytype; |
577 | 0 | key->source = SIGNKEY_SOURCE_RAW_FILE; |
578 | 0 | key->filename = id_key_path; |
579 | 0 | list_append(cli_opts.privkeys, key); |
580 | 0 | } |
581 | 1.55k | } |
582 | | #endif |
583 | | |
584 | | #if DROPBEAR_CLI_MULTIHOP |
585 | | |
586 | | /* Fill out -i, -y, -W options that make sense for all |
587 | | * the intermediate processes */ |
588 | 0 | static char** multihop_args(const char* argv0, const char* prior_hops) { |
589 | | /* null terminated array */ |
590 | 0 | char **args = NULL; |
591 | 0 | size_t max_args = 16, pos = 0, len; |
592 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
593 | 0 | m_list_elem *iter; |
594 | 0 | #endif |
595 | |
|
596 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
597 | 0 | for (iter = cli_opts.privkeys->first; iter; iter = iter->next) |
598 | 0 | { |
599 | | /* "-i file" for each */ |
600 | 0 | max_args += 2; |
601 | 0 | } |
602 | 0 | #endif |
603 | |
|
604 | 0 | args = m_malloc(sizeof(char*) * max_args); |
605 | 0 | pos = 0; |
606 | |
|
607 | 0 | args[pos] = m_strdup(argv0); |
608 | 0 | pos++; |
609 | |
|
610 | 0 | if (cli_opts.quiet) { |
611 | 0 | args[pos] = m_strdup("-q"); |
612 | 0 | pos++; |
613 | 0 | } |
614 | |
|
615 | 0 | if (cli_opts.no_hostkey_check) { |
616 | 0 | args[pos] = m_strdup("-y"); |
617 | 0 | pos++; |
618 | 0 | args[pos] = m_strdup("-y"); |
619 | 0 | pos++; |
620 | 0 | } else if (cli_opts.always_accept_key) { |
621 | 0 | args[pos] = m_strdup("-y"); |
622 | 0 | pos++; |
623 | 0 | } |
624 | |
|
625 | 0 | if (cli_opts.batch_mode) { |
626 | 0 | args[pos] = m_strdup("-o"); |
627 | 0 | pos++; |
628 | 0 | args[pos] = m_strdup("BatchMode=yes"); |
629 | 0 | pos++; |
630 | 0 | } |
631 | |
|
632 | | #ifndef DISABLE_ZLIB |
633 | | if (opts.compression) { |
634 | | args[pos] = m_strdup("-o"); |
635 | | pos++; |
636 | | args[pos] = m_strdup("Compression=yes"); |
637 | | pos++; |
638 | | } |
639 | | #endif |
640 | |
|
641 | 0 | if (cli_opts.proxycmd) { |
642 | 0 | args[pos] = m_strdup("-J"); |
643 | 0 | pos++; |
644 | 0 | args[pos] = m_strdup(cli_opts.proxycmd); |
645 | 0 | pos++; |
646 | 0 | } |
647 | |
|
648 | 0 | if (opts.recv_window != DEFAULT_RECV_WINDOW) { |
649 | 0 | args[pos] = m_strdup("-W"); |
650 | 0 | pos++; |
651 | 0 | args[pos] = m_malloc(11); |
652 | 0 | m_snprintf(args[pos], 11, "%u", opts.recv_window); |
653 | 0 | pos++; |
654 | 0 | } |
655 | |
|
656 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
657 | 0 | for (iter = cli_opts.privkeys->first; iter; iter = iter->next) |
658 | 0 | { |
659 | 0 | sign_key * key = (sign_key*)iter->item; |
660 | 0 | args[pos] = m_strdup("-i"); |
661 | 0 | pos++; |
662 | 0 | args[pos] = m_strdup(key->filename); |
663 | 0 | pos++; |
664 | 0 | } |
665 | 0 | #endif /* DROPBEAR_CLI_PUBKEY_AUTH */ |
666 | | |
667 | | /* last hop */ |
668 | 0 | args[pos] = m_strdup("-B"); |
669 | 0 | pos++; |
670 | 0 | len = strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport) + 2; |
671 | 0 | args[pos] = m_malloc(len); |
672 | 0 | snprintf(args[pos], len, "%s:%s", cli_opts.remotehost, cli_opts.remoteport); |
673 | 0 | pos++; |
674 | | |
675 | | /* hostnames of prior hops */ |
676 | 0 | args[pos] = m_strdup(prior_hops); |
677 | 0 | pos++; |
678 | |
|
679 | 0 | return args; |
680 | 0 | } |
681 | | |
682 | | /* Sets up 'onion-forwarding' connections. This will spawn |
683 | | * a separate dbclient process for each hop. |
684 | | * As an example, if the cmdline is |
685 | | * dbclient wrt,madako,canyons |
686 | | * then we want to run: |
687 | | * dbclient -J "dbclient -B canyons:22 wrt,madako" canyons |
688 | | * and then the inner dbclient will recursively run: |
689 | | * dbclient -J "dbclient -B madako:22 wrt" madako |
690 | | * etc for as many hosts as we want. |
691 | | * |
692 | | * Note that "-J" arguments aren't actually used, instead |
693 | | * below sets cli_opts.proxyexec directly. |
694 | | * |
695 | | * Ports for hosts can be specified as host/port. |
696 | | */ |
697 | 1 | static void parse_multihop_hostname(const char* orighostarg, const char* argv0) { |
698 | 1 | char *userhostarg = NULL; |
699 | 1 | char *hostbuf = NULL; |
700 | 1 | char *last_hop = NULL; |
701 | 1 | char *prior_hops = NULL; |
702 | | |
703 | | /* both scp and rsync parse a user@host argument |
704 | | * and turn it into "-l user host". This breaks |
705 | | * for our multihop syntax, so we suture it back together. |
706 | | * This will break usernames that have both '@' and ',' in them, |
707 | | * though that should be fairly uncommon. */ |
708 | 1 | if (cli_opts.username |
709 | 1 | && strchr(cli_opts.username, ',') |
710 | 0 | && strchr(cli_opts.username, '@')) { |
711 | 0 | unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2; |
712 | 0 | hostbuf = m_malloc(len); |
713 | 0 | m_snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg); |
714 | 1 | } else { |
715 | 1 | hostbuf = m_strdup(orighostarg); |
716 | 1 | } |
717 | 1 | userhostarg = hostbuf; |
718 | | |
719 | | /* Split off any last hostname and use that as remotehost/remoteport. |
720 | | * That is used for authorized_keys checking etc */ |
721 | 1 | last_hop = strrchr(userhostarg, ','); |
722 | 1 | if (last_hop) { |
723 | 0 | if (last_hop == userhostarg) { |
724 | 0 | dropbear_exit("Bad multi-hop hostnames"); |
725 | 0 | } |
726 | 0 | *last_hop = '\0'; |
727 | 0 | last_hop++; |
728 | 0 | prior_hops = userhostarg; |
729 | 0 | userhostarg = last_hop; |
730 | 0 | } |
731 | | |
732 | | /* Update cli_opts.remotehost and cli_opts.remoteport */ |
733 | 1 | parse_hostname(userhostarg); |
734 | | |
735 | | /* Construct any multihop proxy command. Use proxyexec to |
736 | | * avoid worrying about shell escaping. */ |
737 | 1 | if (prior_hops) { |
738 | 0 | cli_opts.proxyexec = multihop_args(argv0, prior_hops); |
739 | | /* Any -J argument has been copied to proxyexec */ |
740 | 0 | if (cli_opts.proxycmd) { |
741 | 0 | m_free(cli_opts.proxycmd); |
742 | 0 | } |
743 | |
|
744 | | #ifndef DISABLE_ZLIB |
745 | | /* This outer stream will be incompressible since it's encrypted. */ |
746 | | opts.compression = 0; |
747 | | #endif |
748 | 0 | } |
749 | | |
750 | 1 | m_free(hostbuf); |
751 | 1 | } |
752 | | #endif /* DROPBEAR_CLI_MULTIHOP */ |
753 | | |
754 | | /* Parses a [user@]hostname[/port] argument. */ |
755 | 1 | static void parse_hostname(const char* orighostarg) { |
756 | 1 | char *userhostarg = NULL; |
757 | 1 | char *port = NULL; |
758 | 1 | char* remotehost = NULL; |
759 | | |
760 | 1 | userhostarg = m_strdup(orighostarg); |
761 | | |
762 | 1 | remotehost = strchr(userhostarg, '@'); |
763 | 1 | if (remotehost == NULL) { |
764 | | /* no username portion, the cli-auth.c code can figure the |
765 | | * local user's name */ |
766 | 1 | remotehost = userhostarg; |
767 | 1 | } else { |
768 | 0 | remotehost[0] = '\0'; /* Split the user/host */ |
769 | 0 | remotehost++; |
770 | 0 | cli_opts.username = m_strdup(userhostarg); |
771 | 0 | } |
772 | | |
773 | 1 | port = strchr(remotehost, '^'); |
774 | 1 | if (!port) { |
775 | | /* legacy separator */ |
776 | 1 | port = strchr(remotehost, '/'); |
777 | 1 | } |
778 | 1 | if (port) { |
779 | 0 | *port = '\0'; |
780 | 0 | cli_opts.remoteport = m_strdup(port+1); |
781 | 0 | } |
782 | | |
783 | 1 | if (remotehost[0] == '\0') { |
784 | 0 | dropbear_exit("Bad hostname."); |
785 | 0 | } |
786 | | |
787 | 1 | if (!cli_opts.remotehostfixed) { |
788 | 1 | cli_opts.remotehost = m_strdup(remotehost); |
789 | 1 | } |
790 | 1 | m_free(userhostarg); |
791 | 1 | } |
792 | | |
793 | | #if DROPBEAR_CLI_NETCAT |
794 | 0 | static void add_netcat(const char* origstr) { |
795 | 0 | char *portstr = NULL; |
796 | |
|
797 | 0 | char * str = m_strdup(origstr); |
798 | |
|
799 | 0 | portstr = strchr(str, ':'); |
800 | 0 | if (portstr == NULL) { |
801 | 0 | TRACE(("No netcat port")) |
802 | 0 | goto fail; |
803 | 0 | } |
804 | 0 | *portstr = '\0'; |
805 | 0 | portstr++; |
806 | |
|
807 | 0 | if (strchr(portstr, ':')) { |
808 | 0 | TRACE(("Multiple netcat colons")) |
809 | 0 | goto fail; |
810 | 0 | } |
811 | | |
812 | 0 | if (m_str_to_uint(portstr, &cli_opts.netcat_port) == DROPBEAR_FAILURE) { |
813 | 0 | TRACE(("bad netcat port")) |
814 | 0 | goto fail; |
815 | 0 | } |
816 | | |
817 | 0 | if (cli_opts.netcat_port > 65535) { |
818 | 0 | TRACE(("too large netcat port")) |
819 | 0 | goto fail; |
820 | 0 | } |
821 | | |
822 | 0 | cli_opts.netcat_host = str; |
823 | 0 | return; |
824 | | |
825 | 0 | fail: |
826 | 0 | dropbear_exit("Bad netcat endpoint '%s'", origstr); |
827 | 0 | } |
828 | | #endif |
829 | | |
830 | 1 | static void fill_own_user() { |
831 | 1 | uid_t uid; |
832 | 1 | struct passwd *pw = NULL; |
833 | | |
834 | 1 | uid = getuid(); |
835 | | |
836 | 1 | pw = getpwuid(uid); |
837 | 1 | if (pw && pw->pw_name != NULL) { |
838 | 1 | cli_opts.own_user = m_strdup(pw->pw_name); |
839 | 1 | } else { |
840 | 0 | dropbear_log(LOG_INFO, "Warning: failed to identify current user. Trying anyway."); |
841 | 0 | cli_opts.own_user = m_strdup("unknown"); |
842 | 0 | } |
843 | | |
844 | 1 | } |
845 | | |
846 | | #if DROPBEAR_CLI_ANYTCPFWD |
847 | | /* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding |
848 | | * set, and add it to the forwarding list */ |
849 | 0 | static void addforward(const char* origstr, m_list *fwdlist) { |
850 | |
|
851 | 0 | char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL; |
852 | 0 | char * listenaddr = NULL; |
853 | 0 | char * listenport = NULL; |
854 | 0 | char * connectaddr = NULL; |
855 | 0 | char * connectport = NULL; |
856 | 0 | struct TCPFwdEntry* newfwd = NULL; |
857 | 0 | char * str = NULL; |
858 | |
|
859 | 0 | TRACE(("enter addforward")) |
860 | | |
861 | | /* We need to split the original argument up. This var |
862 | | is never free()d. */ |
863 | 0 | str = m_strdup(origstr); |
864 | |
|
865 | 0 | part1 = str; |
866 | |
|
867 | 0 | part2 = strchr(str, ':'); |
868 | 0 | if (part2 == NULL) { |
869 | 0 | TRACE(("part2 == NULL")) |
870 | 0 | goto fail; |
871 | 0 | } |
872 | 0 | *part2 = '\0'; |
873 | 0 | part2++; |
874 | |
|
875 | 0 | part3 = strchr(part2, ':'); |
876 | 0 | if (part3 == NULL) { |
877 | 0 | TRACE(("part3 == NULL")) |
878 | 0 | goto fail; |
879 | 0 | } |
880 | 0 | *part3 = '\0'; |
881 | 0 | part3++; |
882 | |
|
883 | 0 | part4 = strchr(part3, ':'); |
884 | 0 | if (part4) { |
885 | 0 | *part4 = '\0'; |
886 | 0 | part4++; |
887 | 0 | } |
888 | |
|
889 | 0 | if (part4) { |
890 | 0 | listenaddr = part1; |
891 | 0 | listenport = part2; |
892 | 0 | connectaddr = part3; |
893 | 0 | connectport = part4; |
894 | 0 | } else { |
895 | 0 | listenaddr = NULL; |
896 | 0 | listenport = part1; |
897 | 0 | connectaddr = part2; |
898 | 0 | connectport = part3; |
899 | 0 | } |
900 | |
|
901 | 0 | newfwd = m_malloc(sizeof(struct TCPFwdEntry)); |
902 | | |
903 | | /* Now we check the ports - note that the port ints are unsigned, |
904 | | * the check later only checks for >= MAX_PORT */ |
905 | 0 | if (m_str_to_uint(listenport, &newfwd->listenport) == DROPBEAR_FAILURE) { |
906 | 0 | TRACE(("bad listenport strtoul")) |
907 | 0 | goto fail; |
908 | 0 | } |
909 | | |
910 | 0 | if (m_str_to_uint(connectport, &newfwd->connectport) == DROPBEAR_FAILURE) { |
911 | 0 | TRACE(("bad connectport strtoul")) |
912 | 0 | goto fail; |
913 | 0 | } |
914 | | |
915 | 0 | newfwd->listenaddr = listenaddr; |
916 | 0 | newfwd->connectaddr = connectaddr; |
917 | |
|
918 | 0 | if (newfwd->listenport > 65535) { |
919 | 0 | TRACE(("listenport > 65535")) |
920 | 0 | goto badport; |
921 | 0 | } |
922 | | |
923 | 0 | if (newfwd->connectport > 65535) { |
924 | 0 | TRACE(("connectport > 65535")) |
925 | 0 | goto badport; |
926 | 0 | } |
927 | | |
928 | 0 | newfwd->have_reply = 0; |
929 | 0 | list_append(fwdlist, newfwd); |
930 | |
|
931 | 0 | TRACE(("leave addforward: done")) |
932 | 0 | return; |
933 | | |
934 | 0 | fail: |
935 | 0 | dropbear_exit("Bad TCP forward '%s'", origstr); |
936 | | |
937 | 0 | badport: |
938 | 0 | dropbear_exit("Bad TCP port in '%s'", origstr); |
939 | 0 | } |
940 | | #endif |
941 | | |
942 | 0 | static int match_extendedopt(const char** strptr, const char *optname) { |
943 | 0 | int seen_eq = 0; |
944 | 0 | int optlen = strlen(optname); |
945 | 0 | const char *str = *strptr; |
946 | |
|
947 | 0 | while (isspace(*str)) { |
948 | 0 | ++str; |
949 | 0 | } |
950 | |
|
951 | 0 | if (strncasecmp(str, optname, optlen) != 0) { |
952 | 0 | return DROPBEAR_FAILURE; |
953 | 0 | } |
954 | | |
955 | 0 | str += optlen; |
956 | |
|
957 | 0 | while (isspace(*str) || (!seen_eq && *str == '=')) { |
958 | 0 | if (*str == '=') { |
959 | 0 | seen_eq = 1; |
960 | 0 | } |
961 | 0 | ++str; |
962 | 0 | } |
963 | |
|
964 | 0 | if (str-*strptr == optlen) { |
965 | | /* matched just a prefix of optname */ |
966 | 0 | return DROPBEAR_FAILURE; |
967 | 0 | } |
968 | | |
969 | 0 | *strptr = str; |
970 | 0 | return DROPBEAR_SUCCESS; |
971 | 0 | } |
972 | | |
973 | 0 | static int parse_flag_value(const char *value) { |
974 | 0 | if (strcmp(value, "yes") == 0 |
975 | 0 | || strcmp(value, "y") == 0 |
976 | 0 | || strcmp(value, "true") == 0 |
977 | 0 | ) { |
978 | 0 | return 1; |
979 | 0 | } else if (strcmp(value, "no") == 0 |
980 | 0 | || strcmp(value, "n") == 0 |
981 | 0 | || strcmp(value, "false") == 0) { |
982 | 0 | return 0; |
983 | 0 | } |
984 | | |
985 | 0 | dropbear_exit("Bad yes/no argument '%s'", value); |
986 | 0 | } |
987 | | |
988 | 0 | static void add_extendedopt(const char* origstr) { |
989 | 0 | const char *optstr = origstr; |
990 | |
|
991 | 0 | if (strcmp(origstr, "help") == 0) { |
992 | 0 | dropbear_log(LOG_INFO, "Available options:\n" |
993 | 0 | "\tBatchMode\n" |
994 | 0 | "\tBindAddress\n" |
995 | | #ifndef DISABLE_ZLIB |
996 | | "\tCompression\n" |
997 | | #endif |
998 | 0 | "\tDisableTrivialAuth\n" |
999 | 0 | #if DROPBEAR_CLI_ANYTCPFWD |
1000 | 0 | "\tExitOnForwardFailure\n" |
1001 | 0 | #endif |
1002 | 0 | #if DROPBEAR_CLI_AGENTFWD |
1003 | 0 | "\tForwardAgent\n" |
1004 | 0 | #endif |
1005 | 0 | #if DROPBEAR_CLI_LOCALTCPFWD |
1006 | 0 | "\tGatewayPorts\n" |
1007 | 0 | #endif |
1008 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
1009 | 0 | "\tIdentityFile\n" |
1010 | 0 | #endif |
1011 | 0 | "\tPasswordAuthentication\n" |
1012 | 0 | "\tPort\n" |
1013 | 0 | #if DROPBEAR_CLI_PROXYCMD |
1014 | 0 | "\tProxyCommand\n" |
1015 | 0 | #endif |
1016 | 0 | "\tServerAliveInterval\n" |
1017 | 0 | "\tStrictHostKeyChecking\n" |
1018 | 0 | #ifndef DISABLE_SYSLOG |
1019 | 0 | "\tUseSyslog\n" |
1020 | 0 | #endif |
1021 | 0 | ); |
1022 | 0 | exit(EXIT_SUCCESS); |
1023 | 0 | } |
1024 | | |
1025 | 0 | if (match_extendedopt(&optstr, "BatchMode") == DROPBEAR_SUCCESS) { |
1026 | 0 | cli_opts.batch_mode = parse_flag_value(optstr); |
1027 | 0 | return; |
1028 | 0 | } |
1029 | | |
1030 | 0 | if (match_extendedopt(&optstr, "BindAddress") == DROPBEAR_SUCCESS) { |
1031 | 0 | cli_opts.bind_arg = optstr; |
1032 | 0 | return; |
1033 | 0 | } |
1034 | | |
1035 | 0 | if (match_extendedopt(&optstr, "Compression") == DROPBEAR_SUCCESS) { |
1036 | 0 | int flag = parse_flag_value(optstr); |
1037 | | #ifndef DISABLE_ZLIB |
1038 | | /* Compression compiled in */ |
1039 | | opts.compression = flag; |
1040 | | #else |
1041 | 0 | if (flag) { |
1042 | 0 | dropbear_log(LOG_WARNING, "compression is not supported"); |
1043 | 0 | } |
1044 | 0 | #endif |
1045 | 0 | return; |
1046 | 0 | } |
1047 | | |
1048 | 0 | if (match_extendedopt(&optstr, "DisableTrivialAuth") == DROPBEAR_SUCCESS) { |
1049 | 0 | cli_opts.disable_trivial_auth = parse_flag_value(optstr); |
1050 | 0 | return; |
1051 | 0 | } |
1052 | | |
1053 | 0 | #if DROPBEAR_CLI_ANYTCPFWD |
1054 | 0 | if (match_extendedopt(&optstr, "ExitOnForwardFailure") == DROPBEAR_SUCCESS) { |
1055 | 0 | cli_opts.exit_on_fwd_failure = parse_flag_value(optstr); |
1056 | 0 | return; |
1057 | 0 | } |
1058 | 0 | #endif |
1059 | | |
1060 | 0 | #if DROPBEAR_CLI_AGENTFWD |
1061 | 0 | if (match_extendedopt(&optstr, "ForwardAgent") == DROPBEAR_SUCCESS) { |
1062 | 0 | cli_opts.agent_fwd = parse_flag_value(optstr); |
1063 | 0 | return; |
1064 | 0 | } |
1065 | 0 | #endif |
1066 | | |
1067 | 0 | #if DROPBEAR_CLI_LOCALTCPFWD |
1068 | 0 | if (match_extendedopt(&optstr, "GatewayPorts") == DROPBEAR_SUCCESS) { |
1069 | 0 | opts.listen_fwd_all = 1; |
1070 | 0 | return; |
1071 | 0 | } |
1072 | 0 | #endif |
1073 | | |
1074 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
1075 | 0 | if (match_extendedopt(&optstr, "IdentityFile") == DROPBEAR_SUCCESS) { |
1076 | 0 | loadidentityfile(optstr, 1); |
1077 | 0 | return; |
1078 | 0 | } |
1079 | 0 | #endif |
1080 | | |
1081 | 0 | #if DROPBEAR_CLI_PASSWORD_AUTH |
1082 | 0 | if (match_extendedopt(&optstr, "PasswordAuthentication") == DROPBEAR_SUCCESS) { |
1083 | 0 | cli_opts.password_authentication = parse_flag_value(optstr); |
1084 | 0 | return; |
1085 | 0 | } |
1086 | 0 | #endif |
1087 | | |
1088 | 0 | if (match_extendedopt(&optstr, "BatchMode") == DROPBEAR_SUCCESS) { |
1089 | 0 | cli_opts.batch_mode = parse_flag_value(optstr); |
1090 | 0 | return; |
1091 | 0 | } |
1092 | | |
1093 | 0 | if (match_extendedopt(&optstr, "Port") == DROPBEAR_SUCCESS) { |
1094 | 0 | cli_opts.remoteport = m_strdup(optstr); |
1095 | 0 | return; |
1096 | 0 | } |
1097 | | |
1098 | 0 | #if DROPBEAR_CLI_PROXYCMD |
1099 | 0 | if (match_extendedopt(&optstr, "ProxyCommand") == DROPBEAR_SUCCESS) { |
1100 | 0 | cli_opts.proxycmd = m_strdup(optstr); |
1101 | 0 | return; |
1102 | 0 | } |
1103 | 0 | #endif |
1104 | | |
1105 | 0 | if (match_extendedopt(&optstr, "ServerAliveInterval") == DROPBEAR_SUCCESS) { |
1106 | 0 | cli_opts.keepalive_arg = optstr; |
1107 | 0 | return; |
1108 | 0 | } |
1109 | | |
1110 | 0 | if (match_extendedopt(&optstr, "StrictHostKeyChecking") == DROPBEAR_SUCCESS) { |
1111 | 0 | if (strcmp(optstr, "accept-new") == 0) { |
1112 | 0 | cli_opts.always_accept_key = 1; |
1113 | 0 | } else if (strcmp(optstr, "ask") == 0) { |
1114 | | /* the default */ |
1115 | 0 | } else { |
1116 | 0 | int opt = parse_flag_value(optstr); |
1117 | 0 | if (opt) { |
1118 | | /* "yes" means entry must already exist in |
1119 | | * known_hosts for success. */ |
1120 | 0 | cli_opts.ask_hostkey = 0; |
1121 | 0 | } else { |
1122 | | /* "no" means no check at all */ |
1123 | 0 | cli_opts.no_hostkey_check = 1; |
1124 | 0 | } |
1125 | 0 | } |
1126 | 0 | return; |
1127 | 0 | } |
1128 | | |
1129 | 0 | #ifndef DISABLE_SYSLOG |
1130 | 0 | if (match_extendedopt(&optstr, "UseSyslog") == DROPBEAR_SUCCESS) { |
1131 | 0 | opts.usingsyslog = parse_flag_value(optstr); |
1132 | 0 | return; |
1133 | 0 | } |
1134 | 0 | #endif |
1135 | | |
1136 | 0 | dropbear_log(LOG_WARNING, "Ignoring unknown configuration option '%s'", origstr); |
1137 | 0 | } |
1138 | | |
1139 | | #if DROPBEAR_USE_SSH_CONFIG |
1140 | 1 | static void apply_config_settings(const char* cli_host_arg) { |
1141 | 1 | char* is_multi_hop_host_target = strchr(cli_host_arg, ','); |
1142 | 1 | if (!is_multi_hop_host_target) { |
1143 | 1 | char* config_path = expand_homedir_path(DROPBEAR_DEFAULT_SSH_CONFIG); |
1144 | 1 | FILE* f; |
1145 | 1 | if ((f = fopen(config_path, "r")) == NULL) { |
1146 | 1 | DEBUG1(("Configuration file '%.200s' not found.", config_path)); |
1147 | 1 | } |
1148 | 0 | else { |
1149 | 0 | parse_hostname(cli_host_arg); /* Needed as key into the config. */ |
1150 | 0 | read_config_file(config_path, f, &cli_opts); |
1151 | 0 | fclose(f); |
1152 | 0 | } |
1153 | | m_free(config_path); |
1154 | 1 | } |
1155 | 1 | } |
1156 | | #endif |