dropbear: update to 2015.67
[tomato.git] / release / src-rt-6.x.4708 / router / dropbear / cli-runopts.c
blob467776b5bc79455c6d925cb06f5ee92340e30b5c
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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. */
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"
34 cli_runopts cli_opts; /* GLOBAL */
36 static void printhelp();
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();
40 #ifdef ENABLE_CLI_PUBKEY_AUTH
41 static void loadidentityfile(const char* filename, int warnfail);
42 #endif
43 #ifdef ENABLE_CLI_ANYTCPFWD
44 static void addforward(const char* str, m_list *fwdlist);
45 #endif
46 #ifdef ENABLE_CLI_NETCAT
47 static void add_netcat(const char *str);
48 #endif
50 static void printhelp() {
52 fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
53 #ifdef ENABLE_CLI_MULTIHOP
54 "Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
55 #else
56 "Usage: %s [options] [user@]host[/port] [command]\n"
57 #endif
58 "-p <remoteport>\n"
59 "-l <username>\n"
60 "-t Allocate a pty\n"
61 "-T Don't allocate a pty\n"
62 "-N Don't run a remote command\n"
63 "-f Run in background after auth\n"
64 "-y Always accept remote host key if unknown\n"
65 "-y -y Don't perform any remote host key checking (caution)\n"
66 "-s Request a subsystem (use by external sftp)\n"
67 #ifdef ENABLE_CLI_PUBKEY_AUTH
68 "-i <identityfile> (multiple allowed, default %s)\n"
69 #endif
70 #ifdef ENABLE_CLI_AGENTFWD
71 "-A Enable agent auth forwarding\n"
72 #endif
73 #ifdef ENABLE_CLI_LOCALTCPFWD
74 "-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n"
75 "-g Allow remote hosts to connect to forwarded ports\n"
76 #endif
77 #ifdef ENABLE_CLI_REMOTETCPFWD
78 "-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n"
79 #endif
80 "-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
81 "-K <keepalive> (0 is never, default %d)\n"
82 "-I <idle_timeout> (0 is never, default %d)\n"
83 #ifdef ENABLE_CLI_NETCAT
84 "-B <endhost:endport> Netcat-alike forwarding\n"
85 #endif
86 #ifdef ENABLE_CLI_PROXYCMD
87 "-J <proxy_program> Use program pipe rather than TCP connection\n"
88 #endif
89 #ifdef ENABLE_USER_ALGO_LIST
90 "-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
91 "-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
92 #endif
93 "-V Version\n"
94 #ifdef DEBUG_TRACE
95 "-v verbose (compiled with DEBUG_TRACE)\n"
96 #endif
97 ,DROPBEAR_VERSION, cli_opts.progname,
98 #ifdef ENABLE_CLI_PUBKEY_AUTH
99 DROPBEAR_DEFAULT_CLI_AUTHKEY,
100 #endif
101 DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
105 void cli_getopts(int argc, char ** argv) {
106 unsigned int i, j;
107 char ** next = 0;
108 unsigned int cmdlen;
109 #ifdef ENABLE_CLI_PUBKEY_AUTH
110 int nextiskey = 0; /* A flag if the next argument is a keyfile */
111 #endif
112 #ifdef ENABLE_CLI_LOCALTCPFWD
113 int nextislocal = 0;
114 #endif
115 #ifdef ENABLE_CLI_REMOTETCPFWD
116 int nextisremote = 0;
117 #endif
118 #ifdef ENABLE_CLI_NETCAT
119 int nextisnetcat = 0;
120 #endif
121 char* dummy = NULL; /* Not used for anything real */
123 char* recv_window_arg = NULL;
124 char* keepalive_arg = NULL;
125 char* idle_timeout_arg = NULL;
126 char *host_arg = NULL;
128 /* see printhelp() for options */
129 cli_opts.progname = argv[0];
130 cli_opts.remotehost = NULL;
131 cli_opts.remoteport = NULL;
132 cli_opts.username = NULL;
133 cli_opts.cmd = NULL;
134 cli_opts.no_cmd = 0;
135 cli_opts.backgrounded = 0;
136 cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
137 cli_opts.always_accept_key = 0;
138 cli_opts.no_hostkey_check = 0;
139 cli_opts.is_subsystem = 0;
140 #ifdef ENABLE_CLI_PUBKEY_AUTH
141 cli_opts.privkeys = list_new();
142 #endif
143 #ifdef ENABLE_CLI_LOCALTCPFWD
144 cli_opts.localfwds = list_new();
145 opts.listen_fwd_all = 0;
146 #endif
147 #ifdef ENABLE_CLI_REMOTETCPFWD
148 cli_opts.remotefwds = list_new();
149 #endif
150 #ifdef ENABLE_CLI_AGENTFWD
151 cli_opts.agent_fwd = 0;
152 cli_opts.agent_fd = -1;
153 cli_opts.agent_keys_loaded = 0;
154 #endif
155 #ifdef ENABLE_CLI_PROXYCMD
156 cli_opts.proxycmd = NULL;
157 #endif
158 #ifndef DISABLE_ZLIB
159 opts.compress_mode = DROPBEAR_COMPRESS_ON;
160 #endif
161 #ifdef ENABLE_USER_ALGO_LIST
162 opts.cipher_list = NULL;
163 opts.mac_list = NULL;
164 #endif
165 /* not yet
166 opts.ipv4 = 1;
167 opts.ipv6 = 1;
169 opts.recv_window = DEFAULT_RECV_WINDOW;
170 opts.keepalive_secs = DEFAULT_KEEPALIVE;
171 opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
173 fill_own_user();
175 /* Iterate all the arguments */
176 for (i = 1; i < (unsigned int)argc; i++) {
177 #ifdef ENABLE_CLI_PUBKEY_AUTH
178 if (nextiskey) {
179 /* Load a hostkey since the previous argument was "-i" */
180 loadidentityfile(argv[i], 1);
181 nextiskey = 0;
182 continue;
184 #endif
185 #ifdef ENABLE_CLI_REMOTETCPFWD
186 if (nextisremote) {
187 TRACE(("nextisremote true"))
188 addforward(argv[i], cli_opts.remotefwds);
189 nextisremote = 0;
190 continue;
192 #endif
193 #ifdef ENABLE_CLI_LOCALTCPFWD
194 if (nextislocal) {
195 TRACE(("nextislocal true"))
196 addforward(argv[i], cli_opts.localfwds);
197 nextislocal = 0;
198 continue;
200 #endif
201 #ifdef ENABLE_CLI_NETCAT
202 if (nextisnetcat) {
203 TRACE(("nextisnetcat true"))
204 add_netcat(argv[i]);
205 nextisnetcat = 0;
206 continue;
208 #endif
209 if (next) {
210 /* The previous flag set a value to assign */
211 *next = argv[i];
212 if (*next == NULL) {
213 dropbear_exit("Invalid null argument");
215 next = NULL;
216 continue;
219 if (argv[i][0] == '-') {
220 /* A flag *waves* */
222 switch (argv[i][1]) {
223 case 'y': /* always accept the remote hostkey */
224 if (cli_opts.always_accept_key) {
225 /* twice means no checking at all */
226 cli_opts.no_hostkey_check = 1;
228 cli_opts.always_accept_key = 1;
229 break;
230 case 'p': /* remoteport */
231 next = &cli_opts.remoteport;
232 break;
233 #ifdef ENABLE_CLI_PUBKEY_AUTH
234 case 'i': /* an identityfile */
235 /* Keep scp happy when it changes "-i file" to "-ifile" */
236 if (strlen(argv[i]) > 2) {
237 loadidentityfile(&argv[i][2], 1);
238 } else {
239 nextiskey = 1;
241 break;
242 #endif
243 case 't': /* we want a pty */
244 cli_opts.wantpty = 1;
245 break;
246 case 'T': /* don't want a pty */
247 cli_opts.wantpty = 0;
248 break;
249 case 'N':
250 cli_opts.no_cmd = 1;
251 break;
252 case 'f':
253 cli_opts.backgrounded = 1;
254 break;
255 case 's':
256 cli_opts.is_subsystem = 1;
257 break;
258 #ifdef ENABLE_CLI_LOCALTCPFWD
259 case 'L':
260 nextislocal = 1;
261 break;
262 case 'g':
263 opts.listen_fwd_all = 1;
264 break;
265 #endif
266 #ifdef ENABLE_CLI_REMOTETCPFWD
267 case 'R':
268 nextisremote = 1;
269 break;
270 #endif
271 #ifdef ENABLE_CLI_NETCAT
272 case 'B':
273 nextisnetcat = 1;
274 break;
275 #endif
276 #ifdef ENABLE_CLI_PROXYCMD
277 case 'J':
278 next = &cli_opts.proxycmd;
279 break;
280 #endif
281 case 'l':
282 next = &cli_opts.username;
283 break;
284 case 'h':
285 printhelp();
286 exit(EXIT_SUCCESS);
287 break;
288 case 'u':
289 /* backwards compatibility with old urandom option */
290 break;
291 case 'W':
292 next = &recv_window_arg;
293 break;
294 case 'K':
295 next = &keepalive_arg;
296 break;
297 case 'I':
298 next = &idle_timeout_arg;
299 break;
300 #ifdef ENABLE_CLI_AGENTFWD
301 case 'A':
302 cli_opts.agent_fwd = 1;
303 break;
304 #endif
305 #ifdef ENABLE_USER_ALGO_LIST
306 case 'c':
307 next = &opts.cipher_list;
308 break;
309 case 'm':
310 next = &opts.mac_list;
311 break;
312 #endif
313 #ifdef DEBUG_TRACE
314 case 'v':
315 debug_trace = 1;
316 break;
317 #endif
318 case 'F':
319 case 'e':
320 #ifndef ENABLE_USER_ALGO_LIST
321 case 'c':
322 case 'm':
323 #endif
324 case 'D':
325 #ifndef ENABLE_CLI_REMOTETCPFWD
326 case 'R':
327 #endif
328 #ifndef ENABLE_CLI_LOCALTCPFWD
329 case 'L':
330 #endif
331 case 'V':
332 print_version();
333 exit(EXIT_SUCCESS);
334 break;
335 case 'o':
336 case 'b':
337 next = &dummy;
338 default:
339 fprintf(stderr,
340 "WARNING: Ignoring unknown argument '%s'\n", argv[i]);
341 break;
342 } /* Switch */
344 /* Now we handle args where they might be "-luser" (no spaces)*/
345 if (next && strlen(argv[i]) > 2) {
346 *next = &argv[i][2];
347 next = NULL;
350 continue; /* next argument */
352 } else {
353 TRACE(("non-flag arg: '%s'", argv[i]))
355 /* Either the hostname or commands */
357 if (host_arg == NULL) {
358 host_arg = argv[i];
359 } else {
361 /* this is part of the commands to send - after this we
362 * don't parse any more options, and flags are sent as the
363 * command */
364 cmdlen = 0;
365 for (j = i; j < (unsigned int)argc; j++) {
366 cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
368 /* Allocate the space */
369 cli_opts.cmd = (char*)m_malloc(cmdlen);
370 cli_opts.cmd[0] = '\0';
372 /* Append all the bits */
373 for (j = i; j < (unsigned int)argc; j++) {
374 strlcat(cli_opts.cmd, argv[j], cmdlen);
375 strlcat(cli_opts.cmd, " ", cmdlen);
377 /* It'll be null-terminated here */
379 /* We've eaten all the options and flags */
380 break;
385 /* And now a few sanity checks and setup */
387 #ifdef ENABLE_USER_ALGO_LIST
388 parse_ciphers_macs();
389 #endif
391 if (host_arg == NULL) {
392 printhelp();
393 exit(EXIT_FAILURE);
396 #ifdef ENABLE_CLI_PROXYCMD
397 if (cli_opts.proxycmd) {
398 /* To match the common path of m_freeing it */
399 cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
401 #endif
403 if (cli_opts.remoteport == NULL) {
404 cli_opts.remoteport = "22";
407 /* If not explicitly specified with -t or -T, we don't want a pty if
408 * there's a command, but we do otherwise */
409 if (cli_opts.wantpty == 9) {
410 if (cli_opts.cmd == NULL) {
411 cli_opts.wantpty = 1;
412 } else {
413 cli_opts.wantpty = 0;
417 if (cli_opts.backgrounded && cli_opts.cmd == NULL
418 && cli_opts.no_cmd == 0) {
419 dropbear_exit("Command required for -f");
422 if (recv_window_arg) {
423 opts.recv_window = atol(recv_window_arg);
424 if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
425 dropbear_exit("Bad recv window '%s'", recv_window_arg);
428 if (keepalive_arg) {
429 unsigned int val;
430 if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
431 dropbear_exit("Bad keepalive '%s'", keepalive_arg);
433 opts.keepalive_secs = val;
436 if (idle_timeout_arg) {
437 unsigned int val;
438 if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
439 dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
441 opts.idle_timeout_secs = val;
444 #ifdef ENABLE_CLI_NETCAT
445 if (cli_opts.cmd && cli_opts.netcat_host) {
446 dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
448 #endif
450 #ifdef DROPBEAR_DEFAULT_CLI_AUTHKEY
452 char *expand_path = expand_tilde(DROPBEAR_DEFAULT_CLI_AUTHKEY);
453 loadidentityfile(expand_path, 0);
454 m_free(expand_path);
456 #endif
458 /* The hostname gets set up last, since
459 * in multi-hop mode it will require knowledge
460 * of other flags such as -i */
461 #ifdef ENABLE_CLI_MULTIHOP
462 parse_multihop_hostname(host_arg, argv[0]);
463 #else
464 parse_hostname(host_arg);
465 #endif
468 #ifdef ENABLE_CLI_PUBKEY_AUTH
469 static void loadidentityfile(const char* filename, int warnfail) {
470 sign_key *key;
471 enum signkey_type keytype;
473 TRACE(("loadidentityfile %s", filename))
475 key = new_sign_key();
476 keytype = DROPBEAR_SIGNKEY_ANY;
477 if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
478 if (warnfail) {
479 fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
481 sign_key_free(key);
482 } else {
483 key->type = keytype;
484 key->source = SIGNKEY_SOURCE_RAW_FILE;
485 key->filename = m_strdup(filename);
486 list_append(cli_opts.privkeys, key);
489 #endif
491 #ifdef ENABLE_CLI_MULTIHOP
493 static char*
494 multihop_passthrough_args() {
495 char *ret;
496 int total;
497 unsigned int len = 0;
498 m_list_elem *iter;
499 /* Fill out -i, -y, -W options that make sense for all
500 * the intermediate processes */
501 for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
503 sign_key * key = (sign_key*)iter->item;
504 len += 3 + strlen(key->filename);
506 len += 30; /* space for -W <size>, terminator. */
507 ret = m_malloc(len);
508 total = 0;
510 if (cli_opts.no_hostkey_check)
512 int written = snprintf(ret+total, len-total, "-y -y ");
513 total += written;
515 else if (cli_opts.always_accept_key)
517 int written = snprintf(ret+total, len-total, "-y ");
518 total += written;
521 if (opts.recv_window != DEFAULT_RECV_WINDOW)
523 int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window);
524 total += written;
527 for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
529 sign_key * key = (sign_key*)iter->item;
530 const size_t size = len - total;
531 int written = snprintf(ret+total, size, "-i %s ", key->filename);
532 dropbear_assert((unsigned int)written < size);
533 total += written;
536 /* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
537 if (total > 0)
539 total--;
542 return ret;
545 /* Sets up 'onion-forwarding' connections. This will spawn
546 * a separate dbclient process for each hop.
547 * As an example, if the cmdline is
548 * dbclient wrt,madako,canyons
549 * then we want to run:
550 * dbclient -J "dbclient -B canyons:22 wrt,madako" canyons
551 * and then the inner dbclient will recursively run:
552 * dbclient -J "dbclient -B madako:22 wrt" madako
553 * etc for as many hosts as we want.
555 * Ports for hosts can be specified as host/port.
557 static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
558 char *userhostarg = NULL;
559 char *hostbuf = NULL;
560 char *last_hop = NULL;
561 char *remainder = NULL;
563 /* both scp and rsync parse a user@host argument
564 * and turn it into "-l user host". This breaks
565 * for our multihop syntax, so we suture it back together.
566 * This will break usernames that have both '@' and ',' in them,
567 * though that should be fairly uncommon. */
568 if (cli_opts.username
569 && strchr(cli_opts.username, ',')
570 && strchr(cli_opts.username, '@')) {
571 unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
572 hostbuf = m_malloc(len);
573 snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
574 } else {
575 hostbuf = m_strdup(orighostarg);
577 userhostarg = hostbuf;
579 last_hop = strrchr(userhostarg, ',');
580 if (last_hop) {
581 if (last_hop == userhostarg) {
582 dropbear_exit("Bad multi-hop hostnames");
584 *last_hop = '\0';
585 last_hop++;
586 remainder = userhostarg;
587 userhostarg = last_hop;
590 parse_hostname(userhostarg);
592 if (last_hop) {
593 /* Set up the proxycmd */
594 unsigned int cmd_len = 0;
595 char *passthrough_args = multihop_passthrough_args();
596 if (cli_opts.proxycmd) {
597 dropbear_exit("-J can't be used with multihop mode");
599 if (cli_opts.remoteport == NULL) {
600 cli_opts.remoteport = "22";
602 cmd_len = strlen(argv0) + strlen(remainder)
603 + strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
604 + strlen(passthrough_args)
605 + 30;
606 cli_opts.proxycmd = m_malloc(cmd_len);
607 snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
608 argv0, cli_opts.remotehost, cli_opts.remoteport,
609 passthrough_args, remainder);
610 #ifndef DISABLE_ZLIB
611 /* The stream will be incompressible since it's encrypted. */
612 opts.compress_mode = DROPBEAR_COMPRESS_OFF;
613 #endif
614 m_free(passthrough_args);
616 m_free(hostbuf);
618 #endif /* !ENABLE_CLI_MULTIHOP */
620 /* Parses a [user@]hostname[/port] argument. */
621 static void parse_hostname(const char* orighostarg) {
622 char *userhostarg = NULL;
623 char *port = NULL;
625 userhostarg = m_strdup(orighostarg);
627 cli_opts.remotehost = strchr(userhostarg, '@');
628 if (cli_opts.remotehost == NULL) {
629 /* no username portion, the cli-auth.c code can figure the
630 * local user's name */
631 cli_opts.remotehost = userhostarg;
632 } else {
633 cli_opts.remotehost[0] = '\0'; /* Split the user/host */
634 cli_opts.remotehost++;
635 cli_opts.username = userhostarg;
638 if (cli_opts.username == NULL) {
639 cli_opts.username = m_strdup(cli_opts.own_user);
642 port = strchr(cli_opts.remotehost, '^');
643 if (!port) {
644 /* legacy separator */
645 port = strchr(cli_opts.remotehost, '/');
647 if (port) {
648 *port = '\0';
649 cli_opts.remoteport = port+1;
652 if (cli_opts.remotehost[0] == '\0') {
653 dropbear_exit("Bad hostname");
657 #ifdef ENABLE_CLI_NETCAT
658 static void add_netcat(const char* origstr) {
659 char *portstr = NULL;
661 char * str = m_strdup(origstr);
663 portstr = strchr(str, ':');
664 if (portstr == NULL) {
665 TRACE(("No netcat port"))
666 goto fail;
668 *portstr = '\0';
669 portstr++;
671 if (strchr(portstr, ':')) {
672 TRACE(("Multiple netcat colons"))
673 goto fail;
676 if (m_str_to_uint(portstr, &cli_opts.netcat_port) == DROPBEAR_FAILURE) {
677 TRACE(("bad netcat port"))
678 goto fail;
681 if (cli_opts.netcat_port > 65535) {
682 TRACE(("too large netcat port"))
683 goto fail;
686 cli_opts.netcat_host = str;
687 return;
689 fail:
690 dropbear_exit("Bad netcat endpoint '%s'", origstr);
692 #endif
694 static void fill_own_user() {
695 uid_t uid;
696 struct passwd *pw = NULL;
698 uid = getuid();
700 pw = getpwuid(uid);
701 if (pw && pw->pw_name != NULL) {
702 cli_opts.own_user = m_strdup(pw->pw_name);
703 } else {
704 dropbear_log(LOG_INFO, "Warning: failed to identify current user. Trying anyway.");
705 cli_opts.own_user = m_strdup("unknown");
710 #ifdef ENABLE_CLI_ANYTCPFWD
711 /* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
712 * set, and add it to the forwarding list */
713 static void addforward(const char* origstr, m_list *fwdlist) {
715 char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
716 char * listenaddr = NULL;
717 char * listenport = NULL;
718 char * connectaddr = NULL;
719 char * connectport = NULL;
720 struct TCPFwdEntry* newfwd = NULL;
721 char * str = NULL;
723 TRACE(("enter addforward"))
725 /* We need to split the original argument up. This var
726 is never free()d. */
727 str = m_strdup(origstr);
729 part1 = str;
731 part2 = strchr(str, ':');
732 if (part2 == NULL) {
733 TRACE(("part2 == NULL"))
734 goto fail;
736 *part2 = '\0';
737 part2++;
739 part3 = strchr(part2, ':');
740 if (part3 == NULL) {
741 TRACE(("part3 == NULL"))
742 goto fail;
744 *part3 = '\0';
745 part3++;
747 part4 = strchr(part3, ':');
748 if (part4) {
749 *part4 = '\0';
750 part4++;
753 if (part4) {
754 listenaddr = part1;
755 listenport = part2;
756 connectaddr = part3;
757 connectport = part4;
758 } else {
759 listenaddr = NULL;
760 listenport = part1;
761 connectaddr = part2;
762 connectport = part3;
765 newfwd = m_malloc(sizeof(struct TCPFwdEntry));
767 /* Now we check the ports - note that the port ints are unsigned,
768 * the check later only checks for >= MAX_PORT */
769 if (m_str_to_uint(listenport, &newfwd->listenport) == DROPBEAR_FAILURE) {
770 TRACE(("bad listenport strtoul"))
771 goto fail;
774 if (m_str_to_uint(connectport, &newfwd->connectport) == DROPBEAR_FAILURE) {
775 TRACE(("bad connectport strtoul"))
776 goto fail;
779 newfwd->listenaddr = listenaddr;
780 newfwd->connectaddr = connectaddr;
782 if (newfwd->listenport > 65535) {
783 TRACE(("listenport > 65535"))
784 goto badport;
787 if (newfwd->connectport > 65535) {
788 TRACE(("connectport > 65535"))
789 goto badport;
792 newfwd->have_reply = 0;
793 list_append(fwdlist, newfwd);
795 TRACE(("leave addforward: done"))
796 return;
798 fail:
799 dropbear_exit("Bad TCP forward '%s'", origstr);
801 badport:
802 dropbear_exit("Bad TCP port in '%s'", origstr);
804 #endif