33
33
cli_runopts cli_opts; /* GLOBAL */
35
35
static void printhelp();
36
static void parsehostname(char* userhostarg);
36
static void parse_hostname(const char* orighostarg);
37
static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
38
static void fill_own_user();
37
39
#ifdef ENABLE_CLI_PUBKEY_AUTH
38
40
static void loadidentityfile(const char* filename);
40
42
#ifdef ENABLE_CLI_ANYTCPFWD
41
static void addforward(char* str, struct TCPFwdList** fwdlist);
43
static void addforward(const char* str, struct TCPFwdList** fwdlist);
45
#ifdef ENABLE_CLI_NETCAT
46
static void add_netcat(const char *str);
44
49
static void printhelp() {
46
51
fprintf(stderr, "Dropbear client v%s\n"
47
"Usage: %s [options] [user@]host [command]\n"
52
#ifdef ENABLE_CLI_MULTIHOP
53
"Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
55
"Usage: %s [options] [user@]host[/port] [command]\n"
49
58
"-p <remoteport>\n"
66
76
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
67
77
"-K <keepalive> (0 is never, default %d)\n"
78
"-I <idle_timeout> (0 is never, default %d)\n"
79
#ifdef ENABLE_CLI_NETCAT
80
"-B <endhost:endport> Netcat-alike forwarding\n"
82
#ifdef ENABLE_CLI_PROXYCMD
83
"-J <proxy_program> Use program pipe rather than TCP connection\n"
86
"-v verbose (compiled with DEBUG_TRACE)\n"
71
88
,DROPBEAR_VERSION, cli_opts.progname,
72
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE);
89
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
307
362
dropbear_exit("command required for -f");
365
if (recv_window_arg) {
312
366
opts.recv_window = atol(recv_window_arg);
313
if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW)
367
if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
315
368
dropbear_exit("Bad recv window '%s'", recv_window_arg);
318
371
if (keepalive_arg) {
319
opts.keepalive_secs = strtoul(keepalive_arg, NULL, 10);
320
if (opts.keepalive_secs == 0 && errno == EINVAL)
372
if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
322
373
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
377
if (idle_timeout_arg) {
378
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
379
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
383
#ifdef ENABLE_CLI_NETCAT
384
if (cli_opts.cmd && cli_opts.netcat_host) {
385
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
354
/* Parses a [user@]hostname argument. userhostarg is the argv[i] corresponding
355
* - note that it will be modified */
356
static void parsehostname(char* orighostarg) {
359
struct passwd *pw = NULL;
360
char *userhostarg = NULL;
362
/* We probably don't want to be editing argvs */
416
#ifdef ENABLE_CLI_MULTIHOP
418
/* Sets up 'onion-forwarding' connections. This will spawn
419
* a separate dbclient process for each hop.
420
* As an example, if the cmdline is
421
* dbclient wrt,madako,canyons
422
* then we want to run:
423
* dbclient -J "dbclient -B canyons:22 wrt,madako" canyons
424
* and then the inner dbclient will recursively run:
425
* dbclient -J "dbclient -B madako:22 wrt" madako
426
* etc for as many hosts as we want.
428
* Ports for hosts can be specified as host/port.
430
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
431
char *userhostarg = NULL;
432
char *last_hop = NULL;;
433
char *remainder = NULL;
435
/* both scp and rsync parse a user@host argument
436
* and turn it into "-l user host". This breaks
437
* for our multihop syntax, so we suture it back together.
438
* This will break usernames that have both '@' and ',' in them,
439
* though that should be fairly uncommon. */
440
if (cli_opts.username
441
&& strchr(cli_opts.username, ',')
442
&& strchr(cli_opts.username, '@')) {
443
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
444
userhostarg = m_malloc(len);
445
snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg);
447
userhostarg = m_strdup(orighostarg);
450
last_hop = strrchr(userhostarg, ',');
452
if (last_hop == userhostarg) {
453
dropbear_exit("Bad multi-hop hostnames");
457
remainder = userhostarg;
458
userhostarg = last_hop;
461
parse_hostname(userhostarg);
464
/* Set up the proxycmd */
465
unsigned int cmd_len = 0;
466
if (cli_opts.proxycmd) {
467
dropbear_exit("-J can't be used with multihop mode");
469
if (cli_opts.remoteport == NULL) {
470
cli_opts.remoteport = "22";
472
cmd_len = strlen(remainder)
473
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
474
+ strlen(argv0) + 30;
475
cli_opts.proxycmd = m_malloc(cmd_len);
476
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s",
477
argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
480
#endif /* !ENABLE_CLI_MULTIHOP */
482
/* Parses a [user@]hostname[/port] argument. */
483
static void parse_hostname(const char* orighostarg) {
484
char *userhostarg = NULL;
363
487
userhostarg = m_strdup(orighostarg);
365
489
cli_opts.remotehost = strchr(userhostarg, '@');
515
#ifdef ENABLE_CLI_NETCAT
516
static void add_netcat(const char* origstr) {
517
char *portstr = NULL;
519
char * str = m_strdup(origstr);
521
portstr = strchr(str, ':');
522
if (portstr == NULL) {
523
TRACE(("No netcat port"))
529
if (strchr(portstr, ':')) {
530
TRACE(("Multiple netcat colons"))
534
if (m_str_to_uint(portstr, &cli_opts.netcat_port) == DROPBEAR_FAILURE) {
535
TRACE(("bad netcat port"))
539
if (cli_opts.netcat_port > 65535) {
540
TRACE(("too large netcat port"))
544
cli_opts.netcat_host = str;
548
dropbear_exit("Bad netcat endpoint '%s'", origstr);
552
static void fill_own_user() {
554
struct passwd *pw = NULL;
559
if (pw == NULL || pw->pw_name == NULL) {
560
dropbear_exit("Unknown own user");
563
cli_opts.own_user = m_strdup(pw->pw_name);
392
566
#ifdef ENABLE_CLI_ANYTCPFWD
393
567
/* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding
394
568
* set, and add it to the forwarding list */
395
static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
569
static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
397
571
char * listenport = NULL;
398
572
char * connectport = NULL;
429
603
/* Now we check the ports - note that the port ints are unsigned,
430
604
* the check later only checks for >= MAX_PORT */
431
newfwd->listenport = strtol(listenport, NULL, 10);
433
TRACE(("bad listenport strtol"))
605
if (m_str_to_uint(listenport, &newfwd->listenport) == DROPBEAR_FAILURE) {
606
TRACE(("bad listenport strtoul"))
437
newfwd->connectport = strtol(connectport, NULL, 10);
439
TRACE(("bad connectport strtol"))
610
if (m_str_to_uint(connectport, &newfwd->connectport) == DROPBEAR_FAILURE) {
611
TRACE(("bad connectport strtoul"))