diff --git a/cli-main.c b/cli-main.c index 1f1cf916a65138fda642037e5502e84b34ed94bf..2d9f1c8af4378377b67df807c32ecfceafc6f60b 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 a1be06a633204e3ef140141ad65569984a82f3d4..d0c9f3ff763eada7de8d3203a7358acb7d1a4117 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 ea8b3f7f4e43a01e39a0610680e7c5f02e6466ed..3d759b5768fa12f2d5a1176443824a0ab0766555 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 175f3fc46032ec8f9f2e94d6ae15e7a73165e24f..ecc9d4ac8d032c1ad8814336ab9f0b479fdd9b7a 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 6a90163eb2d62ddc0d181b2e51aed7cfecbda157..54cfc65ba5fe6364890f1b1a95608662822b7c6e 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 6b34f923008fc90bfec90f7c5a0e1a3fd3a5925f..4ec75343aec3422039d588df7052d0bd0733026b 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 60c342209b325c9ed587f89f90f0f4f7544c9589..b63a258c009d1f44663a6c258fb5315b6eb1a232 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 88909f3f2426adab6b24958eb0da50738cdcebe4..4adf80989bb163a6ea457505163a9de4eea390dd 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.