dropbear: update to 2013.62
[tomato.git] / release / src / router / dropbear / cli-runopts.c
blob9877740e55f760555f8fe7a0d034a1e7f02ebb7d
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);
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)\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 #ifdef DEBUG_TRACE
94 "-v verbose (compiled with DEBUG_TRACE)\n"
95 #endif
96 ,DROPBEAR_VERSION, cli_opts.progname,
97 DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
101 void cli_getopts(int argc, char ** argv) {
102 unsigned int i, j;
103 char ** next = 0;
104 unsigned int cmdlen;
105 #ifdef ENABLE_CLI_PUBKEY_AUTH
106 int nextiskey = 0; /* A flag if the next argument is a keyfile */
107 #endif
108 #ifdef ENABLE_CLI_LOCALTCPFWD
109 int nextislocal = 0;
110 #endif
111 #ifdef ENABLE_CLI_REMOTETCPFWD
112 int nextisremote = 0;
113 #endif
114 #ifdef ENABLE_CLI_NETCAT
115 int nextisnetcat = 0;
116 #endif
117 char* dummy = NULL; /* Not used for anything real */
119 char* recv_window_arg = NULL;
120 char* keepalive_arg = NULL;
121 char* idle_timeout_arg = NULL;
122 char *host_arg = NULL;
124 /* see printhelp() for options */
125 cli_opts.progname = argv[0];
126 cli_opts.remotehost = NULL;
127 cli_opts.remoteport = NULL;
128 cli_opts.username = NULL;
129 cli_opts.cmd = NULL;
130 cli_opts.no_cmd = 0;
131 cli_opts.backgrounded = 0;
132 cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
133 cli_opts.always_accept_key = 0;
134 cli_opts.no_hostkey_check = 0;
135 cli_opts.is_subsystem = 0;
136 #ifdef ENABLE_CLI_PUBKEY_AUTH
137 cli_opts.privkeys = list_new();
138 #endif
139 #ifdef ENABLE_CLI_LOCALTCPFWD
140 cli_opts.localfwds = list_new();
141 opts.listen_fwd_all = 0;
142 #endif
143 #ifdef ENABLE_CLI_REMOTETCPFWD
144 cli_opts.remotefwds = list_new();
145 #endif
146 #ifdef ENABLE_CLI_AGENTFWD
147 cli_opts.agent_fwd = 0;
148 cli_opts.agent_fd = -1;
149 cli_opts.agent_keys_loaded = 0;
150 #endif
151 #ifdef ENABLE_CLI_PROXYCMD
152 cli_opts.proxycmd = NULL;
153 #endif
154 #ifndef DISABLE_ZLIB
155 opts.enable_compress = 1;
156 #endif
157 #ifdef ENABLE_USER_ALGO_LIST
158 opts.cipher_list = NULL;
159 opts.mac_list = NULL;
160 #endif
161 /* not yet
162 opts.ipv4 = 1;
163 opts.ipv6 = 1;
165 opts.recv_window = DEFAULT_RECV_WINDOW;
167 fill_own_user();
169 /* Iterate all the arguments */
170 for (i = 1; i < (unsigned int)argc; i++) {
171 #ifdef ENABLE_CLI_PUBKEY_AUTH
172 if (nextiskey) {
173 /* Load a hostkey since the previous argument was "-i" */
174 loadidentityfile(argv[i]);
175 nextiskey = 0;
176 continue;
178 #endif
179 #ifdef ENABLE_CLI_REMOTETCPFWD
180 if (nextisremote) {
181 TRACE(("nextisremote true"))
182 addforward(argv[i], cli_opts.remotefwds);
183 nextisremote = 0;
184 continue;
186 #endif
187 #ifdef ENABLE_CLI_LOCALTCPFWD
188 if (nextislocal) {
189 TRACE(("nextislocal true"))
190 addforward(argv[i], cli_opts.localfwds);
191 nextislocal = 0;
192 continue;
194 #endif
195 #ifdef ENABLE_CLI_NETCAT
196 if (nextisnetcat) {
197 TRACE(("nextisnetcat true"))
198 add_netcat(argv[i]);
199 nextisnetcat = 0;
200 continue;
202 #endif
203 if (next) {
204 /* The previous flag set a value to assign */
205 *next = argv[i];
206 if (*next == NULL) {
207 dropbear_exit("Invalid null argument");
209 next = NULL;
210 continue;
213 if (argv[i][0] == '-') {
214 /* A flag *waves* */
216 switch (argv[i][1]) {
217 case 'y': /* always accept the remote hostkey */
218 if (cli_opts.always_accept_key) {
219 /* twice means no checking at all */
220 cli_opts.no_hostkey_check = 1;
222 cli_opts.always_accept_key = 1;
223 break;
224 case 'p': /* remoteport */
225 next = &cli_opts.remoteport;
226 break;
227 #ifdef ENABLE_CLI_PUBKEY_AUTH
228 case 'i': /* an identityfile */
229 /* Keep scp happy when it changes "-i file" to "-ifile" */
230 if (strlen(argv[i]) > 2) {
231 loadidentityfile(&argv[i][2]);
232 } else {
233 nextiskey = 1;
235 break;
236 #endif
237 case 't': /* we want a pty */
238 cli_opts.wantpty = 1;
239 break;
240 case 'T': /* don't want a pty */
241 cli_opts.wantpty = 0;
242 break;
243 case 'N':
244 cli_opts.no_cmd = 1;
245 break;
246 case 'f':
247 cli_opts.backgrounded = 1;
248 break;
249 case 's':
250 cli_opts.is_subsystem = 1;
251 break;
252 #ifdef ENABLE_CLI_LOCALTCPFWD
253 case 'L':
254 nextislocal = 1;
255 break;
256 case 'g':
257 opts.listen_fwd_all = 1;
258 break;
259 #endif
260 #ifdef ENABLE_CLI_REMOTETCPFWD
261 case 'R':
262 nextisremote = 1;
263 break;
264 #endif
265 #ifdef ENABLE_CLI_NETCAT
266 case 'B':
267 nextisnetcat = 1;
268 break;
269 #endif
270 #ifdef ENABLE_CLI_PROXYCMD
271 case 'J':
272 next = &cli_opts.proxycmd;
273 break;
274 #endif
275 case 'l':
276 next = &cli_opts.username;
277 break;
278 case 'h':
279 printhelp();
280 exit(EXIT_SUCCESS);
281 break;
282 case 'u':
283 /* backwards compatibility with old urandom option */
284 break;
285 case 'W':
286 next = &recv_window_arg;
287 break;
288 case 'K':
289 next = &keepalive_arg;
290 break;
291 case 'I':
292 next = &idle_timeout_arg;
293 break;
294 #ifdef ENABLE_CLI_AGENTFWD
295 case 'A':
296 cli_opts.agent_fwd = 1;
297 break;
298 #endif
299 #ifdef ENABLE_USER_ALGO_LIST
300 case 'c':
301 next = &opts.cipher_list;
302 break;
303 case 'm':
304 next = &opts.mac_list;
305 break;
306 #endif
307 #ifdef DEBUG_TRACE
308 case 'v':
309 debug_trace = 1;
310 break;
311 #endif
312 case 'F':
313 case 'e':
314 #ifndef ENABLE_USER_ALGO_LIST
315 case 'c':
316 case 'm':
317 #endif
318 case 'D':
319 #ifndef ENABLE_CLI_REMOTETCPFWD
320 case 'R':
321 #endif
322 #ifndef ENABLE_CLI_LOCALTCPFWD
323 case 'L':
324 #endif
325 case 'o':
326 case 'b':
327 next = &dummy;
328 default:
329 fprintf(stderr,
330 "WARNING: Ignoring unknown argument '%s'\n", argv[i]);
331 break;
332 } /* Switch */
334 /* Now we handle args where they might be "-luser" (no spaces)*/
335 if (next && strlen(argv[i]) > 2) {
336 *next = &argv[i][2];
337 next = NULL;
340 continue; /* next argument */
342 } else {
343 TRACE(("non-flag arg: '%s'", argv[i]))
345 /* Either the hostname or commands */
347 if (host_arg == NULL) {
348 host_arg = argv[i];
349 } else {
351 /* this is part of the commands to send - after this we
352 * don't parse any more options, and flags are sent as the
353 * command */
354 cmdlen = 0;
355 for (j = i; j < (unsigned int)argc; j++) {
356 cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
358 /* Allocate the space */
359 cli_opts.cmd = (char*)m_malloc(cmdlen);
360 cli_opts.cmd[0] = '\0';
362 /* Append all the bits */
363 for (j = i; j < (unsigned int)argc; j++) {
364 strlcat(cli_opts.cmd, argv[j], cmdlen);
365 strlcat(cli_opts.cmd, " ", cmdlen);
367 /* It'll be null-terminated here */
369 /* We've eaten all the options and flags */
370 break;
375 /* And now a few sanity checks and setup */
377 #ifdef ENABLE_USER_ALGO_LIST
378 parse_ciphers_macs();
379 #endif
381 if (host_arg == NULL) {
382 printhelp();
383 exit(EXIT_FAILURE);
386 #ifdef ENABLE_CLI_PROXYCMD
387 if (cli_opts.proxycmd) {
388 /* To match the common path of m_freeing it */
389 cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
391 #endif
393 if (cli_opts.remoteport == NULL) {
394 cli_opts.remoteport = "22";
397 /* If not explicitly specified with -t or -T, we don't want a pty if
398 * there's a command, but we do otherwise */
399 if (cli_opts.wantpty == 9) {
400 if (cli_opts.cmd == NULL) {
401 cli_opts.wantpty = 1;
402 } else {
403 cli_opts.wantpty = 0;
407 if (cli_opts.backgrounded && cli_opts.cmd == NULL
408 && cli_opts.no_cmd == 0) {
409 dropbear_exit("Command required for -f");
412 if (recv_window_arg) {
413 opts.recv_window = atol(recv_window_arg);
414 if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
415 dropbear_exit("Bad recv window '%s'", recv_window_arg);
418 if (keepalive_arg) {
419 unsigned int val;
420 if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
421 dropbear_exit("Bad keepalive '%s'", keepalive_arg);
423 opts.keepalive_secs = val;
426 if (idle_timeout_arg) {
427 unsigned int val;
428 if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
429 dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
431 opts.idle_timeout_secs = val;
434 #ifdef ENABLE_CLI_NETCAT
435 if (cli_opts.cmd && cli_opts.netcat_host) {
436 dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
438 #endif
440 /* The hostname gets set up last, since
441 * in multi-hop mode it will require knowledge
442 * of other flags such as -i */
443 #ifdef ENABLE_CLI_MULTIHOP
444 parse_multihop_hostname(host_arg, argv[0]);
445 #else
446 parse_hostname(host_arg);
447 #endif
450 #ifdef ENABLE_CLI_PUBKEY_AUTH
451 static void loadidentityfile(const char* filename) {
452 sign_key *key;
453 enum signkey_type keytype;
455 key = new_sign_key();
456 keytype = DROPBEAR_SIGNKEY_ANY;
457 if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
458 fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
459 sign_key_free(key);
460 } else {
461 key->type = keytype;
462 key->source = SIGNKEY_SOURCE_RAW_FILE;
463 key->filename = m_strdup(filename);
464 list_append(cli_opts.privkeys, key);
467 #endif
469 #ifdef ENABLE_CLI_MULTIHOP
471 static char*
472 multihop_passthrough_args() {
473 char *ret;
474 int total;
475 unsigned int len = 0;
476 m_list_elem *iter;
477 /* Fill out -i, -y, -W options that make sense for all
478 * the intermediate processes */
479 for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
481 sign_key * key = (sign_key*)iter->item;
482 len += 3 + strlen(key->filename);
484 len += 30; /* space for -W <size>, terminator. */
485 ret = m_malloc(len);
486 total = 0;
488 if (cli_opts.no_hostkey_check)
490 int written = snprintf(ret+total, len-total, "-y -y ");
491 total += written;
493 else if (cli_opts.always_accept_key)
495 int written = snprintf(ret+total, len-total, "-y ");
496 total += written;
499 if (opts.recv_window != DEFAULT_RECV_WINDOW)
501 int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window);
502 total += written;
505 for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
507 sign_key * key = (sign_key*)iter->item;
508 const size_t size = len - total;
509 int written = snprintf(ret+total, size, "-i %s ", key->filename);
510 dropbear_assert((unsigned int)written < size);
511 total += written;
514 /* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
515 if (total > 0)
517 total--;
520 return ret;
523 /* Sets up 'onion-forwarding' connections. This will spawn
524 * a separate dbclient process for each hop.
525 * As an example, if the cmdline is
526 * dbclient wrt,madako,canyons
527 * then we want to run:
528 * dbclient -J "dbclient -B canyons:22 wrt,madako" canyons
529 * and then the inner dbclient will recursively run:
530 * dbclient -J "dbclient -B madako:22 wrt" madako
531 * etc for as many hosts as we want.
533 * Ports for hosts can be specified as host/port.
535 static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
536 char *userhostarg = NULL;
537 char *hostbuf = NULL;
538 char *last_hop = NULL;
539 char *remainder = NULL;
541 /* both scp and rsync parse a user@host argument
542 * and turn it into "-l user host". This breaks
543 * for our multihop syntax, so we suture it back together.
544 * This will break usernames that have both '@' and ',' in them,
545 * though that should be fairly uncommon. */
546 if (cli_opts.username
547 && strchr(cli_opts.username, ',')
548 && strchr(cli_opts.username, '@')) {
549 unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
550 hostbuf = m_malloc(len);
551 snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
552 } else {
553 hostbuf = m_strdup(orighostarg);
555 userhostarg = hostbuf;
557 last_hop = strrchr(userhostarg, ',');
558 if (last_hop) {
559 if (last_hop == userhostarg) {
560 dropbear_exit("Bad multi-hop hostnames");
562 *last_hop = '\0';
563 last_hop++;
564 remainder = userhostarg;
565 userhostarg = last_hop;
568 parse_hostname(userhostarg);
570 if (last_hop) {
571 /* Set up the proxycmd */
572 unsigned int cmd_len = 0;
573 char *passthrough_args = multihop_passthrough_args();
574 if (cli_opts.proxycmd) {
575 dropbear_exit("-J can't be used with multihop mode");
577 if (cli_opts.remoteport == NULL) {
578 cli_opts.remoteport = "22";
580 cmd_len = strlen(argv0) + strlen(remainder)
581 + strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
582 + strlen(passthrough_args)
583 + 30;
584 cli_opts.proxycmd = m_malloc(cmd_len);
585 snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
586 argv0, cli_opts.remotehost, cli_opts.remoteport,
587 passthrough_args, remainder);
588 #ifndef DISABLE_ZLIB
589 /* The stream will be incompressible since it's encrypted. */
590 opts.enable_compress = 0;
591 #endif
592 m_free(passthrough_args);
594 m_free(hostbuf);
596 #endif /* !ENABLE_CLI_MULTIHOP */
598 /* Parses a [user@]hostname[/port] argument. */
599 static void parse_hostname(const char* orighostarg) {
600 char *userhostarg = NULL;
601 char *port = NULL;
603 userhostarg = m_strdup(orighostarg);
605 cli_opts.remotehost = strchr(userhostarg, '@');
606 if (cli_opts.remotehost == NULL) {
607 /* no username portion, the cli-auth.c code can figure the
608 * local user's name */
609 cli_opts.remotehost = userhostarg;
610 } else {
611 cli_opts.remotehost[0] = '\0'; /* Split the user/host */
612 cli_opts.remotehost++;
613 cli_opts.username = userhostarg;
616 if (cli_opts.username == NULL) {
617 cli_opts.username = m_strdup(cli_opts.own_user);
620 port = strchr(cli_opts.remotehost, '%');
621 if (!port) {
622 /* legacy separator */
623 port = strchr(cli_opts.remotehost, '/');
625 if (port) {
626 *port = '\0';
627 cli_opts.remoteport = port+1;
630 if (cli_opts.remotehost[0] == '\0') {
631 dropbear_exit("Bad hostname");
635 #ifdef ENABLE_CLI_NETCAT
636 static void add_netcat(const char* origstr) {
637 char *portstr = NULL;
639 char * str = m_strdup(origstr);
641 portstr = strchr(str, ':');
642 if (portstr == NULL) {
643 TRACE(("No netcat port"))
644 goto fail;
646 *portstr = '\0';
647 portstr++;
649 if (strchr(portstr, ':')) {
650 TRACE(("Multiple netcat colons"))
651 goto fail;
654 if (m_str_to_uint(portstr, &cli_opts.netcat_port) == DROPBEAR_FAILURE) {
655 TRACE(("bad netcat port"))
656 goto fail;
659 if (cli_opts.netcat_port > 65535) {
660 TRACE(("too large netcat port"))
661 goto fail;
664 cli_opts.netcat_host = str;
665 return;
667 fail:
668 dropbear_exit("Bad netcat endpoint '%s'", origstr);
670 #endif
672 static void fill_own_user() {
673 uid_t uid;
674 struct passwd *pw = NULL;
676 uid = getuid();
678 pw = getpwuid(uid);
679 if (pw == NULL || pw->pw_name == NULL) {
680 dropbear_exit("Unknown own user");
683 cli_opts.own_user = m_strdup(pw->pw_name);
686 #ifdef ENABLE_CLI_ANYTCPFWD
687 /* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
688 * set, and add it to the forwarding list */
689 static void addforward(const char* origstr, m_list *fwdlist) {
691 char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
692 char * listenaddr = NULL;
693 char * listenport = NULL;
694 char * connectaddr = NULL;
695 char * connectport = NULL;
696 struct TCPFwdEntry* newfwd = NULL;
697 char * str = NULL;
699 TRACE(("enter addforward"))
701 /* We need to split the original argument up. This var
702 is never free()d. */
703 str = m_strdup(origstr);
705 part1 = str;
707 part2 = strchr(str, ':');
708 if (part2 == NULL) {
709 TRACE(("part2 == NULL"))
710 goto fail;
712 *part2 = '\0';
713 part2++;
715 part3 = strchr(part2, ':');
716 if (part3 == NULL) {
717 TRACE(("part3 == NULL"))
718 goto fail;
720 *part3 = '\0';
721 part3++;
723 part4 = strchr(part3, ':');
724 if (part4) {
725 *part4 = '\0';
726 part4++;
729 if (part4) {
730 listenaddr = part1;
731 listenport = part2;
732 connectaddr = part3;
733 connectport = part4;
734 } else {
735 listenaddr = NULL;
736 listenport = part1;
737 connectaddr = part2;
738 connectport = part3;
741 newfwd = m_malloc(sizeof(struct TCPFwdEntry));
743 /* Now we check the ports - note that the port ints are unsigned,
744 * the check later only checks for >= MAX_PORT */
745 if (m_str_to_uint(listenport, &newfwd->listenport) == DROPBEAR_FAILURE) {
746 TRACE(("bad listenport strtoul"))
747 goto fail;
750 if (m_str_to_uint(connectport, &newfwd->connectport) == DROPBEAR_FAILURE) {
751 TRACE(("bad connectport strtoul"))
752 goto fail;
755 newfwd->listenaddr = listenaddr;
756 newfwd->connectaddr = connectaddr;
758 if (newfwd->listenport > 65535) {
759 TRACE(("listenport > 65535"))
760 goto badport;
763 if (newfwd->connectport > 65535) {
764 TRACE(("connectport > 65535"))
765 goto badport;
768 newfwd->have_reply = 0;
769 list_append(fwdlist, newfwd);
771 TRACE(("leave addforward: done"))
772 return;
774 fail:
775 dropbear_exit("Bad TCP forward '%s'", origstr);
777 badport:
778 dropbear_exit("Bad TCP port in '%s'", origstr);
780 #endif