comparison cli-runopts.c @ 579:8c737cd7c1af

merge of '48fdaa8706d1acda35e9d564adc9a1fbc96c18c8' and '658fd03abd21e0da7c4c89b9fff9dc693c72daae'
author Matt Johnston <matt@ucc.asn.au>
date Sat, 27 Feb 2010 11:53:18 +0000
parents 69e98c45db7c 44f486b72427
children dd9947170fc8
comparison
equal deleted inserted replaced
577:69e98c45db7c 579:8c737cd7c1af
27 #include "signkey.h" 27 #include "signkey.h"
28 #include "buffer.h" 28 #include "buffer.h"
29 #include "dbutil.h" 29 #include "dbutil.h"
30 #include "algo.h" 30 #include "algo.h"
31 #include "tcpfwd.h" 31 #include "tcpfwd.h"
32 #include "list.h"
32 33
33 cli_runopts cli_opts; /* GLOBAL */ 34 cli_runopts cli_opts; /* GLOBAL */
34 35
35 static void printhelp(); 36 static void printhelp();
36 static void parse_hostname(const char* orighostarg); 37 static void parse_hostname(const char* orighostarg);
38 static void fill_own_user(); 39 static void fill_own_user();
39 #ifdef ENABLE_CLI_PUBKEY_AUTH 40 #ifdef ENABLE_CLI_PUBKEY_AUTH
40 static void loadidentityfile(const char* filename); 41 static void loadidentityfile(const char* filename);
41 #endif 42 #endif
42 #ifdef ENABLE_CLI_ANYTCPFWD 43 #ifdef ENABLE_CLI_ANYTCPFWD
43 static void addforward(const char* str, struct TCPFwdList** fwdlist); 44 static void addforward(const char* str, m_list *fwdlist);
44 #endif 45 #endif
45 #ifdef ENABLE_CLI_NETCAT 46 #ifdef ENABLE_CLI_NETCAT
46 static void add_netcat(const char *str); 47 static void add_netcat(const char *str);
47 #endif 48 #endif
48 49
64 "-y Always accept remote host key if unknown\n" 65 "-y Always accept remote host key if unknown\n"
65 "-s Request a subsystem (use for sftp)\n" 66 "-s Request a subsystem (use for sftp)\n"
66 #ifdef ENABLE_CLI_PUBKEY_AUTH 67 #ifdef ENABLE_CLI_PUBKEY_AUTH
67 "-i <identityfile> (multiple allowed)\n" 68 "-i <identityfile> (multiple allowed)\n"
68 #endif 69 #endif
70 #ifdef ENABLE_CLI_AGENTFWD
71 "-A Enable agent auth forwarding\n"
72 #endif
69 #ifdef ENABLE_CLI_LOCALTCPFWD 73 #ifdef ENABLE_CLI_LOCALTCPFWD
70 "-L <listenport:remotehost:remoteport> Local port forwarding\n" 74 "-L <listenport:remotehost:remoteport> Local port forwarding\n"
71 "-g Allow remote hosts to connect to forwarded ports\n" 75 "-g Allow remote hosts to connect to forwarded ports\n"
72 #endif 76 #endif
73 #ifdef ENABLE_CLI_REMOTETCPFWD 77 #ifdef ENABLE_CLI_REMOTETCPFWD
89 DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT); 93 DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
90 94
91 } 95 }
92 96
93 void cli_getopts(int argc, char ** argv) { 97 void cli_getopts(int argc, char ** argv) {
94
95 unsigned int i, j; 98 unsigned int i, j;
96 char ** next = 0; 99 char ** next = 0;
97 unsigned int cmdlen; 100 unsigned int cmdlen;
98 #ifdef ENABLE_CLI_PUBKEY_AUTH 101 #ifdef ENABLE_CLI_PUBKEY_AUTH
99 int nextiskey = 0; /* A flag if the next argument is a keyfile */ 102 int nextiskey = 0; /* A flag if the next argument is a keyfile */
110 char* dummy = NULL; /* Not used for anything real */ 113 char* dummy = NULL; /* Not used for anything real */
111 114
112 char* recv_window_arg = NULL; 115 char* recv_window_arg = NULL;
113 char* keepalive_arg = NULL; 116 char* keepalive_arg = NULL;
114 char* idle_timeout_arg = NULL; 117 char* idle_timeout_arg = NULL;
118 char *host_arg = NULL;
115 119
116 /* see printhelp() for options */ 120 /* see printhelp() for options */
117 cli_opts.progname = argv[0]; 121 cli_opts.progname = argv[0];
118 cli_opts.remotehost = NULL; 122 cli_opts.remotehost = NULL;
119 cli_opts.remoteport = NULL; 123 cli_opts.remoteport = NULL;
123 cli_opts.backgrounded = 0; 127 cli_opts.backgrounded = 0;
124 cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ 128 cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
125 cli_opts.always_accept_key = 0; 129 cli_opts.always_accept_key = 0;
126 cli_opts.is_subsystem = 0; 130 cli_opts.is_subsystem = 0;
127 #ifdef ENABLE_CLI_PUBKEY_AUTH 131 #ifdef ENABLE_CLI_PUBKEY_AUTH
128 cli_opts.privkeys = NULL; 132 cli_opts.privkeys = list_new();
129 #endif 133 #endif
130 #ifdef ENABLE_CLI_LOCALTCPFWD 134 #ifdef ENABLE_CLI_LOCALTCPFWD
131 cli_opts.localfwds = NULL; 135 cli_opts.localfwds = list_new();
132 opts.listen_fwd_all = 0; 136 opts.listen_fwd_all = 0;
133 #endif 137 #endif
134 #ifdef ENABLE_CLI_REMOTETCPFWD 138 #ifdef ENABLE_CLI_REMOTETCPFWD
135 cli_opts.remotefwds = NULL; 139 cli_opts.remotefwds = list_new();
140 #endif
141 #ifdef ENABLE_CLI_AGENTFWD
142 cli_opts.agent_fwd = 0;
143 cli_opts.agent_keys_loaded = 0;
136 #endif 144 #endif
137 #ifdef ENABLE_CLI_PROXYCMD 145 #ifdef ENABLE_CLI_PROXYCMD
138 cli_opts.proxycmd = NULL; 146 cli_opts.proxycmd = NULL;
147 #endif
148 #ifndef DISABLE_ZLIB
149 opts.enable_compress = 1;
139 #endif 150 #endif
140 /* not yet 151 /* not yet
141 opts.ipv4 = 1; 152 opts.ipv4 = 1;
142 opts.ipv6 = 1; 153 opts.ipv6 = 1;
143 */ 154 */
156 } 167 }
157 #endif 168 #endif
158 #ifdef ENABLE_CLI_REMOTETCPFWD 169 #ifdef ENABLE_CLI_REMOTETCPFWD
159 if (nextisremote) { 170 if (nextisremote) {
160 TRACE(("nextisremote true")) 171 TRACE(("nextisremote true"))
161 addforward(argv[i], &cli_opts.remotefwds); 172 addforward(argv[i], cli_opts.remotefwds);
162 nextisremote = 0; 173 nextisremote = 0;
163 continue; 174 continue;
164 } 175 }
165 #endif 176 #endif
166 #ifdef ENABLE_CLI_LOCALTCPFWD 177 #ifdef ENABLE_CLI_LOCALTCPFWD
167 if (nextislocal) { 178 if (nextislocal) {
168 TRACE(("nextislocal true")) 179 TRACE(("nextislocal true"))
169 addforward(argv[i], &cli_opts.localfwds); 180 addforward(argv[i], cli_opts.localfwds);
170 nextislocal = 0; 181 nextislocal = 0;
171 continue; 182 continue;
172 } 183 }
173 #endif 184 #endif
174 #ifdef ENABLE_CLI_NETCAT 185 #ifdef ENABLE_CLI_NETCAT
264 next = &keepalive_arg; 275 next = &keepalive_arg;
265 break; 276 break;
266 case 'I': 277 case 'I':
267 next = &idle_timeout_arg; 278 next = &idle_timeout_arg;
268 break; 279 break;
280 #ifdef ENABLE_CLI_AGENTFWD
281 case 'A':
282 cli_opts.agent_fwd = 1;
283 break;
284 #endif
269 #ifdef DEBUG_TRACE 285 #ifdef DEBUG_TRACE
270 case 'v': 286 case 'v':
271 debug_trace = 1; 287 debug_trace = 1;
272 break; 288 break;
273 #endif 289 #endif
302 } else { 318 } else {
303 TRACE(("non-flag arg: '%s'", argv[i])) 319 TRACE(("non-flag arg: '%s'", argv[i]))
304 320
305 /* Either the hostname or commands */ 321 /* Either the hostname or commands */
306 322
307 if (cli_opts.remotehost == NULL) { 323 if (host_arg == NULL) {
308 #ifdef ENABLE_CLI_MULTIHOP 324 host_arg = argv[i];
309 parse_multihop_hostname(argv[i], argv[0]);
310 #else
311 parse_hostname(argv[i]);
312 #endif
313 } else { 325 } else {
314 326
315 /* this is part of the commands to send - after this we 327 /* this is part of the commands to send - after this we
316 * don't parse any more options, and flags are sent as the 328 * don't parse any more options, and flags are sent as the
317 * command */ 329 * command */
336 } 348 }
337 } 349 }
338 350
339 /* And now a few sanity checks and setup */ 351 /* And now a few sanity checks and setup */
340 352
341 if (cli_opts.remotehost == NULL) { 353 if (host_arg == NULL) {
342 printhelp(); 354 printhelp();
343 exit(EXIT_FAILURE); 355 exit(EXIT_FAILURE);
344 } 356 }
345 357
346 if (cli_opts.remoteport == NULL) { 358 if (cli_opts.remoteport == NULL) {
367 if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) { 379 if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
368 dropbear_exit("Bad recv window '%s'", recv_window_arg); 380 dropbear_exit("Bad recv window '%s'", recv_window_arg);
369 } 381 }
370 } 382 }
371 if (keepalive_arg) { 383 if (keepalive_arg) {
372 if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) { 384 unsigned int val;
385 if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
373 dropbear_exit("Bad keepalive '%s'", keepalive_arg); 386 dropbear_exit("Bad keepalive '%s'", keepalive_arg);
374 } 387 }
388 opts.keepalive_secs = val;
375 } 389 }
376 390
377 if (idle_timeout_arg) { 391 if (idle_timeout_arg) {
378 if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) { 392 unsigned int val;
393 if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
379 dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg); 394 dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
380 } 395 }
396 opts.idle_timeout_secs = val;
381 } 397 }
382 398
383 #ifdef ENABLE_CLI_NETCAT 399 #ifdef ENABLE_CLI_NETCAT
384 if (cli_opts.cmd && cli_opts.netcat_host) { 400 if (cli_opts.cmd && cli_opts.netcat_host) {
385 dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd); 401 dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
386 } 402 }
387 #endif 403 #endif
388 404
405 /* The hostname gets set up last, since
406 * in multi-hop mode it will require knowledge
407 * of other flags such as -i */
408 #ifdef ENABLE_CLI_MULTIHOP
409 parse_multihop_hostname(host_arg, argv[0]);
410 #else
411 parse_hostname(host_arg);
412 #endif
389 } 413 }
390 414
391 #ifdef ENABLE_CLI_PUBKEY_AUTH 415 #ifdef ENABLE_CLI_PUBKEY_AUTH
392 static void loadidentityfile(const char* filename) { 416 static void loadidentityfile(const char* filename) {
393
394 struct SignKeyList * nextkey;
395 sign_key *key; 417 sign_key *key;
396 int keytype; 418 int keytype;
397 419
398 key = new_sign_key(); 420 key = new_sign_key();
399 keytype = DROPBEAR_SIGNKEY_ANY; 421 keytype = DROPBEAR_SIGNKEY_ANY;
400 if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) { 422 if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
401
402 fprintf(stderr, "Failed loading keyfile '%s'\n", filename); 423 fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
403 sign_key_free(key); 424 sign_key_free(key);
404
405 } else { 425 } else {
406 426 key->type = keytype;
407 nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList)); 427 key->source = SIGNKEY_SOURCE_RAW_FILE;
408 nextkey->key = key; 428 key->filename = m_strdup(filename);
409 nextkey->next = cli_opts.privkeys; 429 list_append(cli_opts.privkeys, key);
410 nextkey->type = keytype;
411 cli_opts.privkeys = nextkey;
412 } 430 }
413 } 431 }
414 #endif 432 #endif
415 433
416 #ifdef ENABLE_CLI_MULTIHOP 434 #ifdef ENABLE_CLI_MULTIHOP
435
436 static char*
437 multihop_passthrough_args() {
438 char *ret;
439 int total;
440 unsigned int len = 0;
441 m_list_elem *iter;
442 /* Fill out -i and -W options that make sense for all
443 * the intermediate processes */
444 for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
445 {
446 sign_key * key = (sign_key*)iter->item;
447 len += 3 + strlen(key->filename);
448 }
449 len += 20; // space for -W <size>, terminator.
450 ret = m_malloc(len);
451 total = 0;
452
453 if (opts.recv_window != DEFAULT_RECV_WINDOW)
454 {
455 int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
456 total += written;
457 }
458
459 for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
460 {
461 sign_key * key = (sign_key*)iter->item;
462 const size_t size = len - total;
463 int written = snprintf(ret+total, size, "-i %s", key->filename);
464 dropbear_assert((unsigned int)written < size);
465 total += written;
466 }
467
468 return ret;
469 }
417 470
418 /* Sets up 'onion-forwarding' connections. This will spawn 471 /* Sets up 'onion-forwarding' connections. This will spawn
419 * a separate dbclient process for each hop. 472 * a separate dbclient process for each hop.
420 * As an example, if the cmdline is 473 * As an example, if the cmdline is
421 * dbclient wrt,madako,canyons 474 * dbclient wrt,madako,canyons
427 * 480 *
428 * Ports for hosts can be specified as host/port. 481 * Ports for hosts can be specified as host/port.
429 */ 482 */
430 static void parse_multihop_hostname(const char* orighostarg, const char* argv0) { 483 static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
431 char *userhostarg = NULL; 484 char *userhostarg = NULL;
432 char *last_hop = NULL;; 485 char *hostbuf = NULL;
486 char *last_hop = NULL;
433 char *remainder = NULL; 487 char *remainder = NULL;
434 488
435 /* both scp and rsync parse a user@host argument 489 /* both scp and rsync parse a user@host argument
436 * and turn it into "-l user host". This breaks 490 * and turn it into "-l user host". This breaks
437 * for our multihop syntax, so we suture it back together. 491 * for our multihop syntax, so we suture it back together.
439 * though that should be fairly uncommon. */ 493 * though that should be fairly uncommon. */
440 if (cli_opts.username 494 if (cli_opts.username
441 && strchr(cli_opts.username, ',') 495 && strchr(cli_opts.username, ',')
442 && strchr(cli_opts.username, '@')) { 496 && strchr(cli_opts.username, '@')) {
443 unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2; 497 unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
444 userhostarg = m_malloc(len); 498 hostbuf = m_malloc(len);
445 snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg); 499 snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
446 } else { 500 } else {
447 userhostarg = m_strdup(orighostarg); 501 hostbuf = m_strdup(orighostarg);
448 } 502 }
503 userhostarg = hostbuf;
449 504
450 last_hop = strrchr(userhostarg, ','); 505 last_hop = strrchr(userhostarg, ',');
451 if (last_hop) { 506 if (last_hop) {
452 if (last_hop == userhostarg) { 507 if (last_hop == userhostarg) {
453 dropbear_exit("Bad multi-hop hostnames"); 508 dropbear_exit("Bad multi-hop hostnames");
461 parse_hostname(userhostarg); 516 parse_hostname(userhostarg);
462 517
463 if (last_hop) { 518 if (last_hop) {
464 /* Set up the proxycmd */ 519 /* Set up the proxycmd */
465 unsigned int cmd_len = 0; 520 unsigned int cmd_len = 0;
521 char *passthrough_args = multihop_passthrough_args();
466 if (cli_opts.proxycmd) { 522 if (cli_opts.proxycmd) {
467 dropbear_exit("-J can't be used with multihop mode"); 523 dropbear_exit("-J can't be used with multihop mode");
468 } 524 }
469 if (cli_opts.remoteport == NULL) { 525 if (cli_opts.remoteport == NULL) {
470 cli_opts.remoteport = "22"; 526 cli_opts.remoteport = "22";
471 } 527 }
472 cmd_len = strlen(remainder) 528 cmd_len = strlen(argv0) + strlen(remainder)
473 + strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport) 529 + strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
474 + strlen(argv0) + 30; 530 + strlen(passthrough_args)
531 + 30;
475 cli_opts.proxycmd = m_malloc(cmd_len); 532 cli_opts.proxycmd = m_malloc(cmd_len);
476 snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s", 533 snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
477 argv0, cli_opts.remotehost, cli_opts.remoteport, remainder); 534 argv0, cli_opts.remotehost, cli_opts.remoteport,
478 } 535 passthrough_args, remainder);
536 #ifndef DISABLE_ZLIB
537 /* The stream will be incompressible since it's encrypted. */
538 opts.enable_compress = 0;
539 #endif
540 m_free(passthrough_args);
541 }
542 m_free(hostbuf);
479 } 543 }
480 #endif /* !ENABLE_CLI_MULTIHOP */ 544 #endif /* !ENABLE_CLI_MULTIHOP */
481 545
482 /* Parses a [user@]hostname[/port] argument. */ 546 /* Parses a [user@]hostname[/port] argument. */
483 static void parse_hostname(const char* orighostarg) { 547 static void parse_hostname(const char* orighostarg) {
564 } 628 }
565 629
566 #ifdef ENABLE_CLI_ANYTCPFWD 630 #ifdef ENABLE_CLI_ANYTCPFWD
567 /* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding 631 /* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
568 * set, and add it to the forwarding list */ 632 * set, and add it to the forwarding list */
569 static void addforward(const char* origstr, struct TCPFwdList** fwdlist) { 633 static void addforward(const char* origstr, m_list *fwdlist) {
570 634
571 char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL; 635 char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
572 char * listenaddr = NULL; 636 char * listenaddr = NULL;
573 char * listenport = NULL; 637 char * listenport = NULL;
574 char * connectaddr = NULL; 638 char * connectaddr = NULL;
575 char * connectport = NULL; 639 char * connectport = NULL;
576 struct TCPFwdList* newfwd = NULL; 640 struct TCPFwdEntry* newfwd = NULL;
577 char * str = NULL; 641 char * str = NULL;
578 642
579 TRACE(("enter addforward")) 643 TRACE(("enter addforward"))
580 644
581 /* We need to split the original argument up. This var 645 /* We need to split the original argument up. This var
616 listenport = part1; 680 listenport = part1;
617 connectaddr = part2; 681 connectaddr = part2;
618 connectport = part3; 682 connectport = part3;
619 } 683 }
620 684
621 newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList)); 685 }
686
687 newfwd = m_malloc(sizeof(struct TCPFwdEntry));
622 688
623 /* Now we check the ports - note that the port ints are unsigned, 689 /* Now we check the ports - note that the port ints are unsigned,
624 * the check later only checks for >= MAX_PORT */ 690 * the check later only checks for >= MAX_PORT */
625 if (m_str_to_uint(listenport, &newfwd->listenport) == DROPBEAR_FAILURE) { 691 if (m_str_to_uint(listenport, &newfwd->listenport) == DROPBEAR_FAILURE) {
626 TRACE(("bad listenport strtoul")) 692 TRACE(("bad listenport strtoul"))
644 TRACE(("connectport > 65535")) 710 TRACE(("connectport > 65535"))
645 goto badport; 711 goto badport;
646 } 712 }
647 713
648 newfwd->have_reply = 0; 714 newfwd->have_reply = 0;
649 newfwd->next = *fwdlist; 715 list_append(fwdlist, newfwd);
650 *fwdlist = newfwd;
651 716
652 TRACE(("leave addforward: done")) 717 TRACE(("leave addforward: done"))
653 return; 718 return;
654 719
655 fail: 720 fail: