diff 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
line wrap: on
line diff
--- a/cli-runopts.c	Wed Feb 24 16:13:15 2010 +0000
+++ b/cli-runopts.c	Sat Feb 27 11:53:18 2010 +0000
@@ -29,6 +29,7 @@
 #include "dbutil.h"
 #include "algo.h"
 #include "tcpfwd.h"
+#include "list.h"
 
 cli_runopts cli_opts; /* GLOBAL */
 
@@ -40,7 +41,7 @@
 static void loadidentityfile(const char* filename);
 #endif
 #ifdef ENABLE_CLI_ANYTCPFWD
-static void addforward(const char* str, struct TCPFwdList** fwdlist);
+static void addforward(const char* str, m_list *fwdlist);
 #endif
 #ifdef ENABLE_CLI_NETCAT
 static void add_netcat(const char *str);
@@ -66,6 +67,9 @@
 #ifdef ENABLE_CLI_PUBKEY_AUTH
 					"-i <identityfile>   (multiple allowed)\n"
 #endif
+#ifdef ENABLE_CLI_AGENTFWD
+					"-A    Enable agent auth forwarding\n"
+#endif
 #ifdef ENABLE_CLI_LOCALTCPFWD
 					"-L <listenport:remotehost:remoteport> Local port forwarding\n"
 					"-g    Allow remote hosts to connect to forwarded ports\n"
@@ -91,7 +95,6 @@
 }
 
 void cli_getopts(int argc, char ** argv) {
-
 	unsigned int i, j;
 	char ** next = 0;
 	unsigned int cmdlen;
@@ -112,6 +115,7 @@
 	char* recv_window_arg = NULL;
 	char* keepalive_arg = NULL;
 	char* idle_timeout_arg = NULL;
+	char *host_arg = NULL;
 
 	/* see printhelp() for options */
 	cli_opts.progname = argv[0];
@@ -125,18 +129,25 @@
 	cli_opts.always_accept_key = 0;
 	cli_opts.is_subsystem = 0;
 #ifdef ENABLE_CLI_PUBKEY_AUTH
-	cli_opts.privkeys = NULL;
+	cli_opts.privkeys = list_new();
 #endif
 #ifdef ENABLE_CLI_LOCALTCPFWD
-	cli_opts.localfwds = NULL;
+	cli_opts.localfwds = list_new();
 	opts.listen_fwd_all = 0;
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
-	cli_opts.remotefwds = NULL;
+	cli_opts.remotefwds = list_new();
+#endif
+#ifdef ENABLE_CLI_AGENTFWD
+	cli_opts.agent_fwd = 0;
+	cli_opts.agent_keys_loaded = 0;
 #endif
 #ifdef ENABLE_CLI_PROXYCMD
 	cli_opts.proxycmd = NULL;
 #endif
+#ifndef DISABLE_ZLIB
+	opts.enable_compress = 1;
+#endif
 	/* not yet
 	opts.ipv4 = 1;
 	opts.ipv6 = 1;
@@ -158,7 +169,7 @@
 #ifdef ENABLE_CLI_REMOTETCPFWD
 		if (nextisremote) {
 			TRACE(("nextisremote true"))
-			addforward(argv[i], &cli_opts.remotefwds);
+			addforward(argv[i], cli_opts.remotefwds);
 			nextisremote = 0;
 			continue;
 		}
@@ -166,7 +177,7 @@
 #ifdef ENABLE_CLI_LOCALTCPFWD
 		if (nextislocal) {
 			TRACE(("nextislocal true"))
-			addforward(argv[i], &cli_opts.localfwds);
+			addforward(argv[i], cli_opts.localfwds);
 			nextislocal = 0;
 			continue;
 		}
@@ -266,6 +277,11 @@
 				case 'I':
 					next = &idle_timeout_arg;
 					break;
+#ifdef ENABLE_CLI_AGENTFWD
+				case 'A':
+					cli_opts.agent_fwd = 1;
+					break;
+#endif
 #ifdef DEBUG_TRACE
 				case 'v':
 					debug_trace = 1;
@@ -304,12 +320,8 @@
 
 			/* Either the hostname or commands */
 
-			if (cli_opts.remotehost == NULL) {
-#ifdef ENABLE_CLI_MULTIHOP
-				parse_multihop_hostname(argv[i], argv[0]);
-#else
-				parse_hostname(argv[i]);
-#endif
+			if (host_arg == NULL) {
+				host_arg = argv[i];
 			} else {
 
 				/* this is part of the commands to send - after this we
@@ -338,7 +350,7 @@
 
 	/* And now a few sanity checks and setup */
 
-	if (cli_opts.remotehost == NULL) {
+	if (host_arg == NULL) {
 		printhelp();
 		exit(EXIT_FAILURE);
 	}
@@ -369,15 +381,19 @@
 		}
 	}
 	if (keepalive_arg) {
-		if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
+		unsigned int val;
+		if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
 			dropbear_exit("Bad keepalive '%s'", keepalive_arg);
 		}
+		opts.keepalive_secs = val;
 	}
 
 	if (idle_timeout_arg) {
-		if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
+		unsigned int val;
+		if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
 			dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
 		}
+		opts.idle_timeout_secs = val;
 	}
 
 #ifdef ENABLE_CLI_NETCAT
@@ -385,36 +401,73 @@
 		dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
 	}
 #endif
-	
+
+	/* The hostname gets set up last, since
+	 * in multi-hop mode it will require knowledge
+	 * of other flags such as -i */
+#ifdef ENABLE_CLI_MULTIHOP
+	parse_multihop_hostname(host_arg, argv[0]);
+#else
+	parse_hostname(host_arg);
+#endif
 }
 
 #ifdef ENABLE_CLI_PUBKEY_AUTH
 static void loadidentityfile(const char* filename) {
-
-	struct SignKeyList * nextkey;
 	sign_key *key;
 	int keytype;
 
 	key = new_sign_key();
 	keytype = DROPBEAR_SIGNKEY_ANY;
 	if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
-
 		fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
 		sign_key_free(key);
-
 	} else {
-
-		nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
-		nextkey->key = key;
-		nextkey->next = cli_opts.privkeys;
-		nextkey->type = keytype;
-		cli_opts.privkeys = nextkey;
+		key->type = keytype;
+		key->source = SIGNKEY_SOURCE_RAW_FILE;
+		key->filename = m_strdup(filename);
+		list_append(cli_opts.privkeys, key);
 	}
 }
 #endif
 
 #ifdef ENABLE_CLI_MULTIHOP
 
+static char*
+multihop_passthrough_args() {
+	char *ret;
+	int total;
+	unsigned int len = 0;
+	m_list_elem *iter;
+	/* Fill out -i and -W options that make sense for all
+	 * the intermediate processes */
+	for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
+	{
+		sign_key * key = (sign_key*)iter->item;
+		len += 3 + strlen(key->filename);
+	}
+	len += 20; // space for -W <size>, terminator.
+	ret = m_malloc(len);
+	total = 0;
+
+	if (opts.recv_window != DEFAULT_RECV_WINDOW)
+	{
+		int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
+		total += written;
+	}
+
+	for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
+	{
+		sign_key * key = (sign_key*)iter->item;
+		const size_t size = len - total;
+		int written = snprintf(ret+total, size, "-i %s", key->filename);
+		dropbear_assert((unsigned int)written < size);
+		total += written;
+	}
+
+	return ret;
+}
+
 /* Sets up 'onion-forwarding' connections. This will spawn
  * a separate dbclient process for each hop.
  * As an example, if the cmdline is
@@ -429,7 +482,8 @@
  */
 static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
 	char *userhostarg = NULL;
-	char *last_hop = NULL;;
+	char *hostbuf = NULL;
+	char *last_hop = NULL;
 	char *remainder = NULL;
 
 	/* both scp and rsync parse a user@host argument
@@ -441,11 +495,12 @@
 			&& strchr(cli_opts.username, ',') 
 			&& strchr(cli_opts.username, '@')) {
 		unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
-		userhostarg = m_malloc(len);
-		snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg);
+		hostbuf = m_malloc(len);
+		snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
 	} else {
-		userhostarg = m_strdup(orighostarg);
+		hostbuf = m_strdup(orighostarg);
 	}
+	userhostarg = hostbuf;
 
 	last_hop = strrchr(userhostarg, ',');
 	if (last_hop) {
@@ -463,19 +518,28 @@
 	if (last_hop) {
 		/* Set up the proxycmd */
 		unsigned int cmd_len = 0;
+		char *passthrough_args = multihop_passthrough_args();
 		if (cli_opts.proxycmd) {
 			dropbear_exit("-J can't be used with multihop mode");
 		}
 		if (cli_opts.remoteport == NULL) {
 			cli_opts.remoteport = "22";
 		}
-		cmd_len = strlen(remainder) 
+		cmd_len = strlen(argv0) + strlen(remainder) 
 			+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
-			+ strlen(argv0) + 30;
+			+ strlen(passthrough_args)
+			+ 30;
 		cli_opts.proxycmd = m_malloc(cmd_len);
-		snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s", 
-				argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
+		snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s", 
+				argv0, cli_opts.remotehost, cli_opts.remoteport, 
+				passthrough_args, remainder);
+#ifndef DISABLE_ZLIB
+		/* The stream will be incompressible since it's encrypted. */
+		opts.enable_compress = 0;
+#endif
+		m_free(passthrough_args);
 	}
+	m_free(hostbuf);
 }
 #endif /* !ENABLE_CLI_MULTIHOP */
 
@@ -566,14 +630,14 @@
 #ifdef ENABLE_CLI_ANYTCPFWD
 /* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
  * set, and add it to the forwarding list */
-static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
+static void addforward(const char* origstr, m_list *fwdlist) {
 
 	char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
 	char * listenaddr = NULL;
 	char * listenport = NULL;
 	char * connectaddr = NULL;
 	char * connectport = NULL;
-	struct TCPFwdList* newfwd = NULL;
+	struct TCPFwdEntry* newfwd = NULL;
 	char * str = NULL;
 
 	TRACE(("enter addforward"))
@@ -618,7 +682,9 @@
 		connectport = part3;
 	}
 
-	newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList));
+	}
+
+	newfwd = m_malloc(sizeof(struct TCPFwdEntry));
 
 	/* Now we check the ports - note that the port ints are unsigned,
 	 * the check later only checks for >= MAX_PORT */
@@ -646,8 +712,7 @@
 	}
 
 	newfwd->have_reply = 0;
-	newfwd->next = *fwdlist;
-	*fwdlist = newfwd;
+	list_append(fwdlist, newfwd);
 
 	TRACE(("leave addforward: done"))
 	return;