Mercurial > dropbear
changeset 486:d59f628e7baa
propagate from branch 'au.asn.ucc.matt.dropbear.dbclient-netcat-alike' (head b02ba6628cf2095017c60d202ac630f231e6b553)
to branch 'au.asn.ucc.matt.dropbear' (head 636506b73e973b004cc058b07e6f36a25ff902f8)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 17 Sep 2008 14:49:12 +0000 |
parents | effb4a25b1ae (diff) 12d845ab7b5f (current diff) |
children | 2e17f82a7330 |
files | cli-runopts.c cli-session.c dbutil.c debug.h options.h runopts.h |
diffstat | 14 files changed, 314 insertions(+), 202 deletions(-) [+] |
line wrap: on
line diff
--- a/cli-main.c Wed Sep 17 14:36:49 2008 +0000 +++ b/cli-main.c Wed Sep 17 14:49:12 2008 +0000 @@ -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) { @@ -39,7 +41,7 @@ int main(int argc, char ** argv) { #endif - int sock; + int sock_in, sock_out; char* error = NULL; char* hostandport; int len; @@ -58,10 +60,18 @@ dropbear_exit("signal() error"); } - sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport, - 0, &error); +#ifdef ENABLE_CLI_PROXYCMD + if (cli_opts.proxycmd) { + cli_proxy_cmd(&sock_in, &sock_out); + } else +#endif + { + int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport, + 0, &error); + sock_in = sock_out = sock; + } - if (sock < 0) { + if (sock_in < 0) { dropbear_exit("%s", error); } @@ -72,7 +82,7 @@ snprintf(hostandport, len, "%s:%s", cli_opts.remotehost, cli_opts.remoteport); - cli_session(sock, hostandport); + cli_session(sock_in, sock_out, hostandport); /* not reached */ return -1; @@ -112,3 +122,25 @@ 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; + + fill_passwd(cli_opts.own_user); + + ret = spawn_command(exec_proxy_cmd, cli_opts.proxycmd, + sock_out, sock_in, NULL, NULL); + if (ret == DROPBEAR_FAILURE) { + dropbear_exit("Failed running proxy command"); + *sock_in = *sock_out = -1; + } +}
--- a/cli-runopts.c Wed Sep 17 14:36:49 2008 +0000 +++ b/cli-runopts.c Wed Sep 17 14:49:12 2008 +0000 @@ -34,6 +34,7 @@ static void printhelp(); static void parsehostname(const char* orighostarg); +static void fill_own_user(); #ifdef ENABLE_CLI_PUBKEY_AUTH static void loadidentityfile(const char* filename); #endif @@ -71,6 +72,9 @@ #ifdef ENABLE_CLI_NETCAT "-B <endhost:endport> Netcat-alike bouncing\n" #endif +#ifdef ENABLE_CLI_PROXYCMD + "-J <proxy_program> Use program rather than tcp connection\n" +#endif #ifdef DEBUG_TRACE "-v verbose\n" #endif @@ -121,12 +125,17 @@ #ifdef ENABLE_CLI_REMOTETCPFWD cli_opts.remotefwds = NULL; #endif +#ifdef ENABLE_CLI_PROXYCMD + cli_opts.proxycmd = NULL; +#endif /* not yet opts.ipv4 = 1; opts.ipv6 = 1; */ 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 @@ -221,6 +230,11 @@ nextisnetcat = 1; break; #endif +#ifdef ENABLE_CLI_PROXYCMD + case 'J': + next = &cli_opts.proxycmd; + break; +#endif case 'l': next = &cli_opts.username; break; @@ -329,18 +343,15 @@ 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); } } @@ -394,14 +405,7 @@ } 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') { @@ -447,6 +451,20 @@ } #endif +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 */
--- a/cli-session.c Wed Sep 17 14:36:49 2008 +0000 +++ b/cli-session.c Wed Sep 17 14:49:12 2008 +0000 @@ -74,13 +74,13 @@ NULL /* Null termination */ }; -void cli_session(int sock, char* remotehost) { +void cli_session(int sock_in, int sock_out, char* remotehost) { seedrandom(); crypto_init(); - common_session_init(sock, remotehost); + common_session_init(sock_in, sock_out, remotehost); chaninitialise(cli_chantypes); @@ -286,8 +286,10 @@ /* XXX TODO perhaps print a friendlier message if we get this but have * already sent/received disconnect message(s) ??? */ - close(ses.sock); - ses.sock = -1; + m_close(ses.sock_in); + m_close(ses.sock_out); + ses.sock_in = -1; + ses.sock_out = -1; dropbear_exit("remote closed the connection"); }
--- a/common-session.c Wed Sep 17 14:36:49 2008 +0000 +++ b/common-session.c Wed Sep 17 14:49:12 2008 +0000 @@ -52,14 +52,15 @@ /* called only at the start of a session, set up initial state */ -void common_session_init(int sock, char* remotehost) { +void common_session_init(int sock_in, int sock_out, char* remotehost) { TRACE(("enter session_init")) ses.remotehost = remotehost; - ses.sock = sock; - ses.maxfd = sock; + ses.sock_in = sock_in; + ses.sock_out = sock_out; + ses.maxfd = MAX(sock_in, sock_out); ses.connect_time = 0; ses.last_packet_time = 0; @@ -137,11 +138,11 @@ FD_ZERO(&writefd); FD_ZERO(&readfd); dropbear_assert(ses.payload == NULL); - if (ses.sock != -1) { - FD_SET(ses.sock, &readfd); - if (!isempty(&ses.writequeue)) { - FD_SET(ses.sock, &writefd); - } + if (ses.sock_in != -1) { + FD_SET(ses.sock_in, &readfd); + } + if (ses.sock_out != -1 && !isempty(&ses.writequeue)) { + FD_SET(ses.sock_out, &writefd); } /* We get woken up when signal handlers write to this pipe. @@ -183,12 +184,14 @@ checktimeouts(); /* process session socket's incoming/outgoing data */ - if (ses.sock != -1) { - if (FD_ISSET(ses.sock, &writefd) && !isempty(&ses.writequeue)) { + if (ses.sock_out != -1) { + if (FD_ISSET(ses.sock_out, &writefd) && !isempty(&ses.writequeue)) { write_packet(); } + } - if (FD_ISSET(ses.sock, &readfd)) { + if (ses.sock_in != -1) { + if (FD_ISSET(ses.sock_in, &readfd)) { read_packet(); } @@ -248,14 +251,14 @@ int i; /* write our version string, this blocks */ - if (atomicio(write, ses.sock, LOCAL_IDENT "\r\n", + if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) { ses.remoteclosed(); } /* If they send more than 50 lines, something is wrong */ for (i = 0; i < 50; i++) { - len = ident_readln(ses.sock, linebuf, sizeof(linebuf)); + len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf)); if (len < 0 && errno != EINTR) { /* It failed */ @@ -411,3 +414,35 @@ ret = MIN(opts.keepalive_secs, ret); return ret; } + +const char* get_user_shell() { + /* an empty shell should be interpreted as "/bin/sh" */ + if (ses.authstate.pw_shell[0] == '\0') { + return "/bin/sh"; + } else { + 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); +} +
--- a/dbutil.c Wed Sep 17 14:36:49 2008 +0000 +++ b/dbutil.c Wed Sep 17 14:49:12 2008 +0000 @@ -389,6 +389,141 @@ return sock; } +/* Sets up a pipe for a, returning three non-blocking file descriptors + * and the pid. exec_fn is the function that will actually execute the child process, + * it will be run after the child has fork()ed, and is passed exec_data. + * If ret_errfd == NULL then stderr will not be captured. + * ret_pid can be passed as NULL to discard the pid. */ +int spawn_command(void(*exec_fn)(void *user_data), void *exec_data, + int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) { + int infds[2]; + int outfds[2]; + int errfds[2]; + pid_t pid; + + const int FDIN = 0; + const int FDOUT = 1; + + /* redirect stdin/stdout/stderr */ + if (pipe(infds) != 0) { + return DROPBEAR_FAILURE; + } + if (pipe(outfds) != 0) { + return DROPBEAR_FAILURE; + } + if (ret_errfd && pipe(errfds) != 0) { + return DROPBEAR_FAILURE; + } + +#ifdef __uClinux__ + pid = vfork(); +#else + pid = fork(); +#endif + + if (pid < 0) { + return DROPBEAR_FAILURE; + } + + if (!pid) { + /* child */ + + TRACE(("back to normal sigchld")) + /* Revert to normal sigchld handling */ + if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) { + dropbear_exit("signal() error"); + } + + /* redirect stdin/stdout */ + + if ((dup2(infds[FDIN], STDIN_FILENO) < 0) || + (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) || + (ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) { + TRACE(("leave noptycommand: error redirecting FDs")) + dropbear_exit("child dup2() failure"); + } + + close(infds[FDOUT]); + close(infds[FDIN]); + close(outfds[FDIN]); + close(outfds[FDOUT]); + if (ret_errfd) + { + close(errfds[FDIN]); + close(errfds[FDOUT]); + } + + exec_fn(exec_data); + /* not reached */ + return DROPBEAR_FAILURE; + } else { + /* parent */ + close(infds[FDIN]); + close(outfds[FDOUT]); + + setnonblocking(outfds[FDIN]); + setnonblocking(infds[FDOUT]); + + if (ret_errfd) { + close(errfds[FDOUT]); + setnonblocking(errfds[FDIN]); + } + + if (ret_pid) { + *ret_pid = pid; + } + + *ret_writefd = infds[FDOUT]; + *ret_readfd = outfds[FDIN]; + if (ret_errfd) { + *ret_errfd = errfds[FDIN]; + } + return DROPBEAR_SUCCESS; + } +} + +/* Runs a command with "sh -c". Will close FDs (except stdin/stdout/stderr) and + * re-enabled SIGPIPE. If cmd is NULL, will run a login shell. + */ +void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) { + char * argv[4]; + char * baseshell = NULL; + unsigned int i; + + baseshell = basename(usershell); + + if (cmd != NULL) { + argv[0] = baseshell; + } else { + /* a login shell should be "-bash" for "/bin/bash" etc */ + int len = strlen(baseshell) + 2; /* 2 for "-" */ + argv[0] = (char*)m_malloc(len); + snprintf(argv[0], len, "-%s", baseshell); + } + + if (cmd != NULL) { + argv[1] = "-c"; + argv[2] = cmd; + argv[3] = NULL; + } else { + /* construct a shell of the form "-bash" etc */ + argv[1] = NULL; + } + + /* Re-enable SIGPIPE for the executed process */ + if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) { + dropbear_exit("signal() error"); + } + + /* close file descriptors except stdin/stdout/stderr + * Need to be sure FDs are closed here to avoid reading files as root */ + for (i = 3; i <= maxfd; i++) { + m_close(i); + } + + execv(usershell, argv); +} + /* Return a string representation of the socket address passed. The return * value is allocated with malloc() */ unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
--- a/dbutil.h Wed Sep 17 14:36:49 2008 +0000 +++ b/dbutil.h Wed Sep 17 14:49:12 2008 +0000 @@ -49,6 +49,9 @@ unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport); int dropbear_listen(const char* address, const char* port, int *socks, unsigned int sockcount, char **errstring, int *maxfd); +int spawn_command(void(*exec_fn)(void *user_data), void *exec_data, + int *writefd, int *readfd, int *errfd, pid_t *pid); +void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell); int connect_remote(const char* remotehost, const char* remoteport, int nonblocking, char ** errstring); char* getaddrhostname(struct sockaddr_storage * addr);
--- a/debug.h Wed Sep 17 14:36:49 2008 +0000 +++ b/debug.h Wed Sep 17 14:49:12 2008 +0000 @@ -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
--- a/options.h Wed Sep 17 14:36:49 2008 +0000 +++ b/options.h Wed Sep 17 14:49:12 2008 +0000 @@ -60,6 +60,10 @@ #define ENABLE_CLI_LOCALTCPFWD #define ENABLE_CLI_REMOTETCPFWD +/* 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_SVR_LOCALTCPFWD #define ENABLE_SVR_REMOTETCPFWD
--- a/packet.c Wed Sep 17 14:36:49 2008 +0000 +++ b/packet.c Wed Sep 17 14:49:12 2008 +0000 @@ -61,7 +61,7 @@ len = writebuf->len - writebuf->pos; dropbear_assert(len > 0); /* Try to write as much as possible */ - written = write(ses.sock, buf_getptr(writebuf, len), len); + written = write(ses.sock_out, buf_getptr(writebuf, len), len); if (written < 0) { if (errno == EINTR) { @@ -122,7 +122,7 @@ * mightn't be any available (EAGAIN) */ dropbear_assert(ses.readbuf != NULL); maxlen = ses.readbuf->len - ses.readbuf->pos; - len = read(ses.sock, buf_getptr(ses.readbuf, maxlen), maxlen); + len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen); if (len == 0) { ses.remoteclosed(); @@ -171,7 +171,7 @@ maxlen = blocksize - ses.readbuf->pos; /* read the rest of the packet if possible */ - len = read(ses.sock, buf_getwriteptr(ses.readbuf, maxlen), + len = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen), maxlen); if (len == 0) { ses.remoteclosed();
--- a/runopts.h Wed Sep 17 14:36:49 2008 +0000 +++ b/runopts.h Wed Sep 17 14:49:12 2008 +0000 @@ -101,6 +101,7 @@ char *remotehost; char *remoteport; + char *own_user; char *username; char *cmd; @@ -122,6 +123,9 @@ char *netcat_host; unsigned int netcat_port; #endif +#ifdef ENABLE_CLI_PROXYCMD + char *proxycmd; +#endif } cli_runopts;
--- a/session.h Wed Sep 17 14:36:49 2008 +0000 +++ b/session.h Wed Sep 17 14:49:12 2008 +0000 @@ -41,12 +41,14 @@ extern int sessinitdone; /* Is set to 0 somewhere */ extern int exitflag; -void common_session_init(int sock, char* remotehost); +void common_session_init(int sock_in, int sock_out, char* remotehost); void session_loop(void(*loophandler)()); void common_session_cleanup(); 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); @@ -54,7 +56,7 @@ void svr_dropbear_log(int priority, const char* format, va_list param); /* Client */ -void cli_session(int sock, char *remotehost); +void cli_session(int sock_in, int sock_out, char *remotehost); void cli_session_cleanup(); void cleantext(unsigned char* dirtytext); @@ -97,7 +99,8 @@ (cleared after auth once we're not respecting AUTH_TIMEOUT any more) */ - int sock; + int sock_in; + int sock_out; unsigned char *remotehost; /* the peer hostname */
--- a/svr-auth.c Wed Sep 17 14:36:49 2008 +0000 +++ b/svr-auth.c Wed Sep 17 14:49:12 2008 +0000 @@ -203,29 +203,6 @@ 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.
--- a/svr-chansession.c Wed Sep 17 14:36:49 2008 +0000 +++ b/svr-chansession.c Wed Sep 17 14:49:12 2008 +0000 @@ -47,7 +47,7 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess); static int ptycommand(struct Channel *channel, struct ChanSess *chansess); static int sessionwinchange(struct ChanSess *chansess); -static void execchild(struct ChanSess *chansess); +static void execchild(void *user_data_chansess); static void addchildpid(struct ChanSess *chansess, pid_t pid); static void sesssigchild_handler(int val); static void closechansess(struct Channel *channel); @@ -633,100 +633,37 @@ * pty. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) { - - int infds[2]; - int outfds[2]; - int errfds[2]; - pid_t pid; - unsigned int i; + int ret; TRACE(("enter noptycommand")) - - /* redirect stdin/stdout/stderr */ - if (pipe(infds) != 0) - return DROPBEAR_FAILURE; - if (pipe(outfds) != 0) - return DROPBEAR_FAILURE; - if (pipe(errfds) != 0) - return DROPBEAR_FAILURE; + ret = spawn_command(execchild, chansess, + &channel->writefd, &channel->readfd, &channel->errfd, + &chansess->pid); -#ifdef __uClinux__ - pid = vfork(); -#else - pid = fork(); -#endif - - if (pid < 0) - return DROPBEAR_FAILURE; + if (ret == DROPBEAR_FAILURE) { + return ret; + } - if (!pid) { - /* child */ - - TRACE(("back to normal sigchld")) - /* Revert to normal sigchld handling */ - if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) { - dropbear_exit("signal() error"); - } + ses.maxfd = MAX(ses.maxfd, channel->writefd); + ses.maxfd = MAX(ses.maxfd, channel->readfd); + ses.maxfd = MAX(ses.maxfd, channel->errfd); - /* redirect stdin/stdout */ -#define FDIN 0 -#define FDOUT 1 - if ((dup2(infds[FDIN], STDIN_FILENO) < 0) || - (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) || - (dup2(errfds[FDOUT], STDERR_FILENO) < 0)) { - TRACE(("leave noptycommand: error redirecting FDs")) - return DROPBEAR_FAILURE; - } - - close(infds[FDOUT]); - close(infds[FDIN]); - close(outfds[FDIN]); - close(outfds[FDOUT]); - close(errfds[FDIN]); - close(errfds[FDOUT]); - - execchild(chansess); - /* not reached */ + addchildpid(chansess, chansess->pid); - } else { - /* parent */ - TRACE(("continue noptycommand: parent")) - chansess->pid = pid; - TRACE(("child pid is %d", pid)) - - addchildpid(chansess, pid); - - if (svr_ses.lastexit.exitpid != -1) { - TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid)) - /* The child probably exited and the signal handler triggered - * possibly before we got around to adding the childpid. So we fill - * out its data manually */ - for (i = 0; i < svr_ses.childpidsize; i++) { - if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) { - TRACE(("found match for lastexitpid")) - svr_ses.childpids[i].chansess->exit = svr_ses.lastexit; - svr_ses.lastexit.exitpid = -1; - } + if (svr_ses.lastexit.exitpid != -1) { + TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid)) + /* The child probably exited and the signal handler triggered + * possibly before we got around to adding the childpid. So we fill + * out its data manually */ + int i; + for (i = 0; i < svr_ses.childpidsize; i++) { + if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) { + TRACE(("found match for lastexitpid")) + svr_ses.childpids[i].chansess->exit = svr_ses.lastexit; + svr_ses.lastexit.exitpid = -1; } } - - close(infds[FDIN]); - close(outfds[FDOUT]); - close(errfds[FDOUT]); - channel->writefd = infds[FDOUT]; - channel->readfd = outfds[FDIN]; - channel->errfd = errfds[FDIN]; - ses.maxfd = MAX(ses.maxfd, channel->writefd); - ses.maxfd = MAX(ses.maxfd, channel->readfd); - ses.maxfd = MAX(ses.maxfd, channel->errfd); - - setnonblocking(channel->readfd); - setnonblocking(channel->writefd); - setnonblocking(channel->errfd); - } -#undef FDIN -#undef FDOUT TRACE(("leave noptycommand")) return DROPBEAR_SUCCESS; @@ -871,12 +808,9 @@ /* Clean up, drop to user privileges, set up the environment and execute * the command/shell. This function does not return. */ -static void execchild(struct ChanSess *chansess) { - - char *argv[4]; - char * usershell = NULL; - char * baseshell = NULL; - unsigned int i; +static void execchild(void *user_data) { + struct ChanSess *chansess = user_data; + char *usershell = NULL; /* with uClinux we'll have vfork()ed, so don't want to overwrite the * hostkey. can't think of a workaround to clear it */ @@ -889,12 +823,6 @@ reseedrandom(); #endif - /* close file descriptors except stdin/stdout/stderr - * Need to be sure FDs are closed here to avoid reading files as root */ - for (i = 3; i <= (unsigned int)ses.maxfd; i++) { - m_close(i); - } - /* clear environment */ /* if we're debugging using valgrind etc, we need to keep the LD_PRELOAD * etc. This is hazardous, so should only be used for debugging. */ @@ -933,18 +861,11 @@ } } - /* an empty shell should be interpreted as "/bin/sh" */ - if (ses.authstate.pw_shell[0] == '\0') { - usershell = "/bin/sh"; - } else { - usershell = ses.authstate.pw_shell; - } - /* set env vars */ addnewvar("USER", ses.authstate.pw_name); addnewvar("LOGNAME", ses.authstate.pw_name); addnewvar("HOME", ses.authstate.pw_dir); - addnewvar("SHELL", usershell); + addnewvar("SHELL", get_user_shell()); if (chansess->term != NULL) { addnewvar("TERM", chansess->term); } @@ -963,32 +884,8 @@ agentset(chansess); #endif - /* Re-enable SIGPIPE for the executed process */ - if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) { - dropbear_exit("signal() error"); - } - - baseshell = basename(usershell); - - if (chansess->cmd != NULL) { - argv[0] = baseshell; - } else { - /* a login shell should be "-bash" for "/bin/bash" etc */ - int len = strlen(baseshell) + 2; /* 2 for "-" */ - argv[0] = (char*)m_malloc(len); - snprintf(argv[0], len, "-%s", baseshell); - } - - if (chansess->cmd != NULL) { - argv[1] = "-c"; - argv[2] = chansess->cmd; - argv[3] = NULL; - } else { - /* construct a shell of the form "-bash" etc */ - argv[1] = NULL; - } - - execv(usershell, argv); + usershell = m_strdup(get_user_shell()); + run_shell_command(chansess->cmd, ses.maxfd, usershell); /* only reached on error */ dropbear_exit("child failed");
--- a/svr-session.c Wed Sep 17 14:36:49 2008 +0000 +++ b/svr-session.c Wed Sep 17 14:49:12 2008 +0000 @@ -80,7 +80,7 @@ reseedrandom(); crypto_init(); - common_session_init(sock, remotehost); + common_session_init(sock, sock, remotehost); /* Initialise server specific parts of the session */ svr_ses.childpipe = childpipe; @@ -183,7 +183,7 @@ localtime(×ec)) == 0) { /* upon failure, just print the epoch-seconds time. */ - snprintf(datestr, sizeof(datestr), "%d", timesec); + snprintf(datestr, sizeof(datestr), "%d", (int)timesec); } fprintf(stderr, "[%d] %s %s\n", getpid(), datestr, printbuf); } @@ -192,8 +192,10 @@ /* called when the remote side closes the connection */ static void svr_remoteclosed() { - close(ses.sock); - ses.sock = -1; + m_close(ses.sock_in); + m_close(ses.sock_out); + ses.sock_in = -1; + ses.sock_out = -1; dropbear_close("Exited normally"); }