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