# HG changeset patch # User Matt Johnston # Date 1221487495 0 # Node ID 7ad49f34a122b0e09576ecea720dc40998680d8c # Parent 357a2e2e9bccf17caed1cbf0678bcf4660a2d3fa - Add run_shell_command() function to run a "sh -c" command, handling lots of the work that exechild did (and can be shared by client -J option) diff -r 357a2e2e9bcc -r 7ad49f34a122 common-session.c --- a/common-session.c Mon Sep 15 13:41:18 2008 +0000 +++ b/common-session.c Mon Sep 15 14:04:55 2008 +0000 @@ -414,3 +414,12 @@ 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; + } +} diff -r 357a2e2e9bcc -r 7ad49f34a122 dbutil.c --- a/dbutil.c Mon Sep 15 13:41:18 2008 +0000 +++ b/dbutil.c Mon Sep 15 14:04:55 2008 +0000 @@ -393,8 +393,7 @@ * 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. */ 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 *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) { int infds[2]; int outfds[2]; int errfds[2]; @@ -466,6 +465,48 @@ } } +/* 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) { diff -r 357a2e2e9bcc -r 7ad49f34a122 dbutil.h --- a/dbutil.h Mon Sep 15 13:41:18 2008 +0000 +++ b/dbutil.h Mon Sep 15 14:04:55 2008 +0000 @@ -51,6 +51,7 @@ 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); diff -r 357a2e2e9bcc -r 7ad49f34a122 session.h --- a/session.h Mon Sep 15 13:41:18 2008 +0000 +++ b/session.h Mon Sep 15 14:04:55 2008 +0000 @@ -47,6 +47,7 @@ void session_identification(); void send_msg_ignore(); +const char* get_user_shell(); /* Server */ void svr_session(int sock, int childpipe, char *remotehost, char *addrstring); diff -r 357a2e2e9bcc -r 7ad49f34a122 svr-chansession.c --- a/svr-chansession.c Mon Sep 15 13:41:18 2008 +0000 +++ b/svr-chansession.c Mon Sep 15 14:04:55 2008 +0000 @@ -809,12 +809,8 @@ /* Clean up, drop to user privileges, set up the environment and execute * the command/shell. This function does not return. */ static void execchild(void *user_data) { - - char *argv[4]; - char * usershell = NULL; - char * baseshell = NULL; - unsigned int i; 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 */ @@ -827,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. */ @@ -871,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); } @@ -901,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");