From e44aa503f0b816adb1611f118c1c09877e7bb3d3 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 15 Sep 2008 14:40:30 +0000
Subject: [PATCH] - "-J 'nc localhost 22'" kind of works, needs fixing
 hostkeys, ptys etc.

--HG--
extra : convert_revision : 45069dd007ebf414330e0a7abf4fb7e0727049c3
---
 cli-main.c       | 32 ++++++++++++++++++++++++++---
 cli-runopts.c    | 52 +++++++++++++++++++++++++++++-------------------
 common-session.c | 23 +++++++++++++++++++++
 debug.h          |  2 +-
 options.h        |  2 +-
 runopts.h        |  1 +
 session.h        |  1 +
 svr-auth.c       | 23 ---------------------
 8 files changed, 88 insertions(+), 48 deletions(-)

diff --git a/cli-main.c b/cli-main.c
index 1f1cf916..2d9f1c8a 100644
--- a/cli-main.c
+++ b/cli-main.c
@@ -32,6 +32,8 @@
 static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
 static void cli_dropbear_log(int priority, const char* format, va_list param);
 
+static void cli_proxy_cmd(int *sock_in, int *sock_out);
+
 #if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
 #if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
 int cli_main(int argc, char ** argv) {
@@ -58,9 +60,9 @@ int main(int argc, char ** argv) {
 		dropbear_exit("signal() error");
 	}
 
-#ifdef CLI_ENABLE_PROXYCMD
-	if (cli_runopts.proxycmd) {
-
+#ifdef ENABLE_CLI_PROXYCMD
+	if (cli_opts.proxycmd) {
+		cli_proxy_cmd(&sock_in, &sock_out);
 	} else
 #endif
 	{
@@ -120,3 +122,27 @@ static void cli_dropbear_log(int UNUSED(priority),
 	fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
 
 }
+
+static void exec_proxy_cmd(void *user_data_cmd) {
+	const char *cmd = user_data_cmd;
+	char *usershell;
+
+	usershell = m_strdup(get_user_shell());
+	run_shell_command(cmd, ses.maxfd, usershell);
+	dropbear_exit("Failed to run '%s'\n", cmd);
+}
+
+static void cli_proxy_cmd(int *sock_in, int *sock_out) {
+	int ret;
+	int errfd;
+	pid_t pid;
+
+	fill_passwd(cli_opts.own_user);
+
+	ret = spawn_command(exec_proxy_cmd, cli_opts.proxycmd,
+			sock_out, sock_in, &errfd, &pid);
+	if (ret == DROPBEAR_FAILURE) {
+		dropbear_exit("Failed running proxy command");
+		*sock_in = *sock_out = -1;
+	}
+}
diff --git a/cli-runopts.c b/cli-runopts.c
index a1be06a6..d0c9f3ff 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -34,6 +34,7 @@ cli_runopts cli_opts; /* GLOBAL */
 
 static void printhelp();
 static void parsehostname(char* userhostarg);
+static void fill_own_user();
 #ifdef ENABLE_CLI_PUBKEY_AUTH
 static void loadidentityfile(const char* filename);
 #endif
@@ -89,9 +90,6 @@ void cli_getopts(int argc, char ** argv) {
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
 	int nextisremote = 0;
-#endif
-#ifdef ENABLE_CLI_PROXYCMD
-	int nextisproxycmd = 0;
 #endif
 	char* dummy = NULL; /* Not used for anything real */
 
@@ -117,6 +115,9 @@ void cli_getopts(int argc, char ** argv) {
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
 	cli_opts.remotefwds = NULL;
+#endif
+#ifdef ENABLE_CLI_PROXYCMD
+	cli_opts.proxycmd = NULL;
 #endif
 	/* not yet
 	opts.ipv4 = 1;
@@ -124,6 +125,8 @@ void cli_getopts(int argc, char ** argv) {
 	*/
 	opts.recv_window = DEFAULT_RECV_WINDOW;
 
+	fill_own_user();
+
 	/* Iterate all the arguments */
 	for (i = 1; i < (unsigned int)argc; i++) {
 #ifdef ENABLE_CLI_PUBKEY_AUTH
@@ -294,6 +297,14 @@ void cli_getopts(int argc, char ** argv) {
 		}
 	}
 
+#ifdef ENABLE_CLI_PROXYCMD
+	if (cli_opts.proxycmd != NULL) {
+		/* XXX something more useful */
+		cli_opts.remotehost = cli_opts.proxycmd;
+		cli_opts.remoteport = "";
+	}
+#endif
+
 	if (cli_opts.remotehost == NULL) {
 		printhelp();
 		exit(EXIT_FAILURE);
@@ -318,18 +329,15 @@ void cli_getopts(int argc, char ** argv) {
 		dropbear_exit("command required for -f");
 	}
 	
-	if (recv_window_arg)
-	{
+	if (recv_window_arg) {
 		opts.recv_window = atol(recv_window_arg);
-		if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW)
-		{
+		if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
 			dropbear_exit("Bad recv window '%s'", recv_window_arg);
 		}
 	}
 	if (keepalive_arg) {
 		opts.keepalive_secs = strtoul(keepalive_arg, NULL, 10);
-		if (opts.keepalive_secs == 0 && errno == EINVAL)
-		{
+		if (opts.keepalive_secs == 0 && errno == EINVAL) {
 			dropbear_exit("Bad keepalive '%s'", keepalive_arg);
 		}
 	}
@@ -365,9 +373,6 @@ static void loadidentityfile(const char* filename) {
 /* Parses a [user@]hostname argument. userhostarg is the argv[i] corresponding
  * - note that it will be modified */
 static void parsehostname(char* orighostarg) {
-
-	uid_t uid;
-	struct passwd *pw = NULL; 
 	char *userhostarg = NULL;
 
 	/* We probably don't want to be editing argvs */
@@ -385,14 +390,7 @@ static void parsehostname(char* orighostarg) {
 	}
 
 	if (cli_opts.username == NULL) {
-		uid = getuid();
-		
-		pw = getpwuid(uid);
-		if (pw == NULL || pw->pw_name == NULL) {
-			dropbear_exit("Unknown own user");
-		}
-
-		cli_opts.username = m_strdup(pw->pw_name);
+		cli_opts.username = m_strdup(cli_opts.own_user);
 	}
 
 	if (cli_opts.remotehost[0] == '\0') {
@@ -400,6 +398,20 @@ static void parsehostname(char* orighostarg) {
 	}
 }
 
+static void fill_own_user() {
+	uid_t uid;
+	struct passwd *pw = NULL; 
+
+	uid = getuid();
+
+	pw = getpwuid(uid);
+	if (pw == NULL || pw->pw_name == NULL) {
+		dropbear_exit("Unknown own user");
+	}
+
+	cli_opts.own_user = m_strdup(pw->pw_name);
+}
+
 #ifdef ENABLE_CLI_ANYTCPFWD
 /* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding
  * set, and add it to the forwarding list */
diff --git a/common-session.c b/common-session.c
index ea8b3f7f..3d759b57 100644
--- a/common-session.c
+++ b/common-session.c
@@ -423,3 +423,26 @@ const char* get_user_shell() {
 		return ses.authstate.pw_shell;
 	}
 }
+void fill_passwd(const char* username) {
+	struct passwd *pw = NULL;
+	if (ses.authstate.pw_name)
+		m_free(ses.authstate.pw_name);
+	if (ses.authstate.pw_dir)
+		m_free(ses.authstate.pw_dir);
+	if (ses.authstate.pw_shell)
+		m_free(ses.authstate.pw_shell);
+	if (ses.authstate.pw_passwd)
+		m_free(ses.authstate.pw_passwd);
+
+	pw = getpwnam(username);
+	if (!pw) {
+		return;
+	}
+	ses.authstate.pw_uid = pw->pw_uid;
+	ses.authstate.pw_gid = pw->pw_gid;
+	ses.authstate.pw_name = m_strdup(pw->pw_name);
+	ses.authstate.pw_dir = m_strdup(pw->pw_dir);
+	ses.authstate.pw_shell = m_strdup(pw->pw_shell);
+	ses.authstate.pw_passwd = m_strdup(pw->pw_passwd);
+}
+
diff --git a/debug.h b/debug.h
index 175f3fc4..ecc9d4ac 100644
--- a/debug.h
+++ b/debug.h
@@ -39,7 +39,7 @@
  * Caution: Don't use this in an unfriendly environment (ie unfirewalled),
  * since the printing may not sanitise strings etc. This will add a reasonable
  * amount to your executable size. */
-/*#define DEBUG_TRACE*/
+#define DEBUG_TRACE
 
 /* All functions writing to the cleartext payload buffer call
  * CHECKCLEARTOWRITE() before writing. This is only really useful if you're
diff --git a/options.h b/options.h
index 6a90163e..54cfc65b 100644
--- a/options.h
+++ b/options.h
@@ -62,7 +62,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
 
 /* Allow using -J <proxycommand> to run the connection through a 
    pipe to a program, rather the normal TCP connection */
-/*#define ENABLE_CLI_PROXYCMD*/
+#define ENABLE_CLI_PROXYCMD
 
 #define ENABLE_SVR_LOCALTCPFWD
 #define ENABLE_SVR_REMOTETCPFWD
diff --git a/runopts.h b/runopts.h
index 6b34f923..4ec75343 100644
--- a/runopts.h
+++ b/runopts.h
@@ -101,6 +101,7 @@ typedef struct cli_runopts {
 	char *remotehost;
 	char *remoteport;
 
+	char *own_user;
 	char *username;
 
 	char *cmd;
diff --git a/session.h b/session.h
index 60c34220..b63a258c 100644
--- a/session.h
+++ b/session.h
@@ -48,6 +48,7 @@ void session_identification();
 void send_msg_ignore();
 
 const char* get_user_shell();
+void fill_passwd(const char* username);
 
 /* Server */
 void svr_session(int sock, int childpipe, char *remotehost, char *addrstring);
diff --git a/svr-auth.c b/svr-auth.c
index 88909f3f..4adf8098 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -203,29 +203,6 @@ out:
 	m_free(methodname);
 }
 
-static void fill_passwd(const char* username) {
-	struct passwd *pw = NULL;
-	if (ses.authstate.pw_name)
-		m_free(ses.authstate.pw_name);
-	if (ses.authstate.pw_dir)
-		m_free(ses.authstate.pw_dir);
-	if (ses.authstate.pw_shell)
-		m_free(ses.authstate.pw_shell);
-	if (ses.authstate.pw_passwd)
-		m_free(ses.authstate.pw_passwd);
-
-	pw = getpwnam(username);
-	if (!pw) {
-		return;
-	}
-	ses.authstate.pw_uid = pw->pw_uid;
-	ses.authstate.pw_gid = pw->pw_gid;
-	ses.authstate.pw_name = m_strdup(pw->pw_name);
-	ses.authstate.pw_dir = m_strdup(pw->pw_dir);
-	ses.authstate.pw_shell = m_strdup(pw->pw_shell);
-	ses.authstate.pw_passwd = m_strdup(pw->pw_passwd);
-}
-
 
 /* Check that the username exists, has a non-empty password, and has a valid
  * shell.
-- 
GitLab