Mercurial > dropbear
comparison cli-runopts.c @ 546:568638be7203 agent-client
propagate from branch 'au.asn.ucc.matt.dropbear' (head 899a8851a5edf840b2f7925bcc26ffe99dcac54d)
to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 6bbab8364de17bd9ecb1dee5ffb796e48c0380d2)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 01 Jul 2009 04:16:32 +0000 |
parents | d588e3ea557a 9e51707cd6f2 |
children | c3f2ec71e3d4 |
comparison
equal
deleted
inserted
replaced
500:d588e3ea557a | 546:568638be7203 |
---|---|
47 #endif | 47 #endif |
48 | 48 |
49 static void printhelp() { | 49 static void printhelp() { |
50 | 50 |
51 fprintf(stderr, "Dropbear client v%s\n" | 51 fprintf(stderr, "Dropbear client v%s\n" |
52 #ifdef ENABLE_CLI_MULTIHOP | |
53 "Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n" | |
54 #else | |
52 "Usage: %s [options] [user@]host[/port] [command]\n" | 55 "Usage: %s [options] [user@]host[/port] [command]\n" |
56 #endif | |
53 "Options are:\n" | 57 "Options are:\n" |
54 "-p <remoteport>\n" | 58 "-p <remoteport>\n" |
55 "-l <username>\n" | 59 "-l <username>\n" |
56 "-t Allocate a pty\n" | 60 "-t Allocate a pty\n" |
57 "-T Don't allocate a pty\n" | 61 "-T Don't allocate a pty\n" |
72 #ifdef ENABLE_CLI_REMOTETCPFWD | 76 #ifdef ENABLE_CLI_REMOTETCPFWD |
73 "-R <listenport:remotehost:remoteport> Remote port forwarding\n" | 77 "-R <listenport:remotehost:remoteport> Remote port forwarding\n" |
74 #endif | 78 #endif |
75 "-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n" | 79 "-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n" |
76 "-K <keepalive> (0 is never, default %d)\n" | 80 "-K <keepalive> (0 is never, default %d)\n" |
81 "-I <idle_timeout> (0 is never, default %d)\n" | |
77 #ifdef ENABLE_CLI_NETCAT | 82 #ifdef ENABLE_CLI_NETCAT |
78 "-B <endhost:endport> Netcat-alike bouncing\n" | 83 "-B <endhost:endport> Netcat-alike forwarding\n" |
79 #endif | 84 #endif |
80 #ifdef ENABLE_CLI_PROXYCMD | 85 #ifdef ENABLE_CLI_PROXYCMD |
81 "-J <proxy_program> Use program rather than tcp connection\n" | 86 "-J <proxy_program> Use program pipe rather than TCP connection\n" |
82 #endif | 87 #endif |
83 #ifdef DEBUG_TRACE | 88 #ifdef DEBUG_TRACE |
84 "-v verbose\n" | 89 "-v verbose (compiled with DEBUG_TRACE)\n" |
85 #endif | 90 #endif |
86 ,DROPBEAR_VERSION, cli_opts.progname, | 91 ,DROPBEAR_VERSION, cli_opts.progname, |
87 DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE); | 92 DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT); |
88 | 93 |
89 } | 94 } |
90 | 95 |
91 void cli_getopts(int argc, char ** argv) { | 96 void cli_getopts(int argc, char ** argv) { |
92 | |
93 unsigned int i, j; | 97 unsigned int i, j; |
94 char ** next = 0; | 98 char ** next = 0; |
95 unsigned int cmdlen; | 99 unsigned int cmdlen; |
96 #ifdef ENABLE_CLI_PUBKEY_AUTH | 100 #ifdef ENABLE_CLI_PUBKEY_AUTH |
97 int nextiskey = 0; /* A flag if the next argument is a keyfile */ | 101 int nextiskey = 0; /* A flag if the next argument is a keyfile */ |
107 #endif | 111 #endif |
108 char* dummy = NULL; /* Not used for anything real */ | 112 char* dummy = NULL; /* Not used for anything real */ |
109 | 113 |
110 char* recv_window_arg = NULL; | 114 char* recv_window_arg = NULL; |
111 char* keepalive_arg = NULL; | 115 char* keepalive_arg = NULL; |
116 char* idle_timeout_arg = NULL; | |
117 char *host_arg = NULL; | |
112 | 118 |
113 /* see printhelp() for options */ | 119 /* see printhelp() for options */ |
114 cli_opts.progname = argv[0]; | 120 cli_opts.progname = argv[0]; |
115 cli_opts.remotehost = NULL; | 121 cli_opts.remotehost = NULL; |
116 cli_opts.remoteport = NULL; | 122 cli_opts.remoteport = NULL; |
262 next = &recv_window_arg; | 268 next = &recv_window_arg; |
263 break; | 269 break; |
264 case 'K': | 270 case 'K': |
265 next = &keepalive_arg; | 271 next = &keepalive_arg; |
266 break; | 272 break; |
273 case 'I': | |
274 next = &idle_timeout_arg; | |
275 break; | |
267 #ifdef ENABLE_CLI_AGENTFWD | 276 #ifdef ENABLE_CLI_AGENTFWD |
268 case 'A': | 277 case 'A': |
269 cli_opts.agent_fwd = 1; | 278 cli_opts.agent_fwd = 1; |
270 break; | 279 break; |
271 #endif | 280 #endif |
305 } else { | 314 } else { |
306 TRACE(("non-flag arg: '%s'", argv[i])) | 315 TRACE(("non-flag arg: '%s'", argv[i])) |
307 | 316 |
308 /* Either the hostname or commands */ | 317 /* Either the hostname or commands */ |
309 | 318 |
310 if (cli_opts.remotehost == NULL) { | 319 if (host_arg == NULL) { |
311 #ifdef ENABLE_CLI_MULTIHOP | 320 host_arg = argv[i]; |
312 parse_multihop_hostname(argv[i], argv[0]); | |
313 #else | |
314 parse_hostname(argv[i]); | |
315 #endif | |
316 } else { | 321 } else { |
317 | 322 |
318 /* this is part of the commands to send - after this we | 323 /* this is part of the commands to send - after this we |
319 * don't parse any more options, and flags are sent as the | 324 * don't parse any more options, and flags are sent as the |
320 * command */ | 325 * command */ |
339 } | 344 } |
340 } | 345 } |
341 | 346 |
342 /* And now a few sanity checks and setup */ | 347 /* And now a few sanity checks and setup */ |
343 | 348 |
344 if (cli_opts.remotehost == NULL) { | 349 if (host_arg == NULL) { |
345 printhelp(); | 350 printhelp(); |
346 exit(EXIT_FAILURE); | 351 exit(EXIT_FAILURE); |
347 } | 352 } |
348 | 353 |
349 if (cli_opts.remoteport == NULL) { | 354 if (cli_opts.remoteport == NULL) { |
375 if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) { | 380 if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) { |
376 dropbear_exit("Bad keepalive '%s'", keepalive_arg); | 381 dropbear_exit("Bad keepalive '%s'", keepalive_arg); |
377 } | 382 } |
378 } | 383 } |
379 | 384 |
385 if (idle_timeout_arg) { | |
386 if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) { | |
387 dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg); | |
388 } | |
389 } | |
390 | |
380 #ifdef ENABLE_CLI_NETCAT | 391 #ifdef ENABLE_CLI_NETCAT |
381 if (cli_opts.cmd && cli_opts.netcat_host) { | 392 if (cli_opts.cmd && cli_opts.netcat_host) { |
382 dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd); | 393 dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd); |
383 } | 394 } |
384 #endif | 395 #endif |
385 | 396 |
397 /* The hostname gets set up last, since | |
398 * in multi-hop mode it will require knowledge | |
399 * of other flags such as -i */ | |
400 #ifdef ENABLE_CLI_MULTIHOP | |
401 parse_multihop_hostname(host_arg, argv[0]); | |
402 #else | |
403 parse_hostname(host_arg); | |
404 #endif | |
386 } | 405 } |
387 | 406 |
388 #ifdef ENABLE_CLI_PUBKEY_AUTH | 407 #ifdef ENABLE_CLI_PUBKEY_AUTH |
389 static void loadidentityfile(const char* filename) { | 408 static void loadidentityfile(const char* filename) { |
390 | 409 |
393 int keytype; | 412 int keytype; |
394 | 413 |
395 key = new_sign_key(); | 414 key = new_sign_key(); |
396 keytype = DROPBEAR_SIGNKEY_ANY; | 415 keytype = DROPBEAR_SIGNKEY_ANY; |
397 if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) { | 416 if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) { |
398 | |
399 fprintf(stderr, "Failed loading keyfile '%s'\n", filename); | 417 fprintf(stderr, "Failed loading keyfile '%s'\n", filename); |
400 sign_key_free(key); | 418 sign_key_free(key); |
401 | |
402 } else { | 419 } else { |
403 | |
404 nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList)); | 420 nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList)); |
405 nextkey->key = key; | 421 nextkey->key = key; |
422 nextkey->filename = m_strdup(filename); | |
406 nextkey->next = cli_opts.privkeys; | 423 nextkey->next = cli_opts.privkeys; |
407 nextkey->type = keytype; | 424 nextkey->type = keytype; |
408 nextkey->source = SIGNKEY_SOURCE_RAW_FILE; | 425 nextkey->source = SIGNKEY_SOURCE_RAW_FILE; |
409 cli_opts.privkeys = nextkey; | 426 cli_opts.privkeys = nextkey; |
410 } | 427 } |
411 } | 428 } |
412 #endif | 429 #endif |
413 | 430 |
414 #ifdef ENABLE_CLI_MULTIHOP | 431 #ifdef ENABLE_CLI_MULTIHOP |
432 | |
433 static char* | |
434 multihop_passthrough_args() { | |
435 char *ret; | |
436 int total; | |
437 unsigned int len = 0; | |
438 struct SignKeyList *nextkey; | |
439 /* Fill out -i and -W options that make sense for all | |
440 * the intermediate processes */ | |
441 for (nextkey = cli_opts.privkeys; nextkey; nextkey = nextkey->next) | |
442 { | |
443 len += 3 + strlen(nextkey->filename); | |
444 } | |
445 len += 20; // space for -W <size>, terminator. | |
446 ret = m_malloc(len); | |
447 total = 0; | |
448 | |
449 if (opts.recv_window != DEFAULT_RECV_WINDOW) | |
450 { | |
451 int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window); | |
452 total += written; | |
453 } | |
454 | |
455 for (nextkey = cli_opts.privkeys; nextkey; nextkey = nextkey->next) | |
456 { | |
457 const size_t size = len - total; | |
458 int written = snprintf(ret+total, size, "-i %s", nextkey->filename); | |
459 dropbear_assert(written < size); | |
460 total += written; | |
461 } | |
462 | |
463 return ret; | |
464 } | |
415 | 465 |
416 /* Sets up 'onion-forwarding' connections. This will spawn | 466 /* Sets up 'onion-forwarding' connections. This will spawn |
417 * a separate dbclient process for each hop. | 467 * a separate dbclient process for each hop. |
418 * As an example, if the cmdline is | 468 * As an example, if the cmdline is |
419 * dbclient wrt,madako,canyons | 469 * dbclient wrt,madako,canyons |
425 * | 475 * |
426 * Ports for hosts can be specified as host/port. | 476 * Ports for hosts can be specified as host/port. |
427 */ | 477 */ |
428 static void parse_multihop_hostname(const char* orighostarg, const char* argv0) { | 478 static void parse_multihop_hostname(const char* orighostarg, const char* argv0) { |
429 char *userhostarg = NULL; | 479 char *userhostarg = NULL; |
480 char *hostbuf = NULL; | |
430 char *last_hop = NULL;; | 481 char *last_hop = NULL;; |
431 char *remainder = NULL; | 482 char *remainder = NULL; |
432 | 483 |
433 /* both scp and rsync parse a user@host argument | 484 /* both scp and rsync parse a user@host argument |
434 * and turn it into "-l user host". This breaks | 485 * and turn it into "-l user host". This breaks |
437 * though that should be fairly uncommon. */ | 488 * though that should be fairly uncommon. */ |
438 if (cli_opts.username | 489 if (cli_opts.username |
439 && strchr(cli_opts.username, ',') | 490 && strchr(cli_opts.username, ',') |
440 && strchr(cli_opts.username, '@')) { | 491 && strchr(cli_opts.username, '@')) { |
441 unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2; | 492 unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2; |
442 userhostarg = m_malloc(len); | 493 hostbuf = m_malloc(len); |
443 snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg); | 494 snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg); |
444 } else { | 495 } else { |
445 userhostarg = m_strdup(orighostarg); | 496 hostbuf = m_strdup(orighostarg); |
446 } | 497 } |
498 userhostarg = hostbuf; | |
447 | 499 |
448 last_hop = strrchr(userhostarg, ','); | 500 last_hop = strrchr(userhostarg, ','); |
449 if (last_hop) { | 501 if (last_hop) { |
450 if (last_hop == userhostarg) { | 502 if (last_hop == userhostarg) { |
451 dropbear_exit("Bad multi-hop hostnames"); | 503 dropbear_exit("Bad multi-hop hostnames"); |
459 parse_hostname(userhostarg); | 511 parse_hostname(userhostarg); |
460 | 512 |
461 if (last_hop) { | 513 if (last_hop) { |
462 /* Set up the proxycmd */ | 514 /* Set up the proxycmd */ |
463 unsigned int cmd_len = 0; | 515 unsigned int cmd_len = 0; |
516 char *passthrough_args = multihop_passthrough_args(); | |
464 if (cli_opts.proxycmd) { | 517 if (cli_opts.proxycmd) { |
465 dropbear_exit("-J can't be used with multihop mode"); | 518 dropbear_exit("-J can't be used with multihop mode"); |
466 } | 519 } |
467 if (cli_opts.remoteport == NULL) { | 520 if (cli_opts.remoteport == NULL) { |
468 cli_opts.remoteport = "22"; | 521 cli_opts.remoteport = "22"; |
469 } | 522 } |
470 cmd_len = strlen(remainder) | 523 cmd_len = strlen(argv0) + strlen(remainder) |
471 + strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport) | 524 + strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport) |
472 + strlen(argv0) + 30; | 525 + strlen(passthrough_args) |
526 + 30; | |
473 cli_opts.proxycmd = m_malloc(cmd_len); | 527 cli_opts.proxycmd = m_malloc(cmd_len); |
474 snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s", | 528 snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s", |
475 argv0, cli_opts.remotehost, cli_opts.remoteport, remainder); | 529 argv0, cli_opts.remotehost, cli_opts.remoteport, |
476 } | 530 passthrough_args, remainder); |
531 m_free(passthrough_args); | |
532 } | |
533 m_free(hostbuf); | |
477 } | 534 } |
478 #endif /* !ENABLE_CLI_MULTIHOP */ | 535 #endif /* !ENABLE_CLI_MULTIHOP */ |
479 | 536 |
480 /* Parses a [user@]hostname[/port] argument. */ | 537 /* Parses a [user@]hostname[/port] argument. */ |
481 static void parse_hostname(const char* orighostarg) { | 538 static void parse_hostname(const char* orighostarg) { |
620 if (newfwd->connectport > 65535) { | 677 if (newfwd->connectport > 65535) { |
621 TRACE(("connectport > 65535")) | 678 TRACE(("connectport > 65535")) |
622 goto badport; | 679 goto badport; |
623 } | 680 } |
624 | 681 |
682 newfwd->have_reply = 0; | |
625 newfwd->next = *fwdlist; | 683 newfwd->next = *fwdlist; |
626 *fwdlist = newfwd; | 684 *fwdlist = newfwd; |
627 | 685 |
628 TRACE(("leave addforward: done")) | 686 TRACE(("leave addforward: done")) |
629 return; | 687 return; |