summaryrefslogtreecommitdiffhomepage
path: root/svr-chansession.c
diff options
context:
space:
mode:
Diffstat (limited to 'svr-chansession.c')
-rw-r--r--svr-chansession.c70
1 files changed, 54 insertions, 16 deletions
diff --git a/svr-chansession.c b/svr-chansession.c
index 0916e7e..619a451 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -59,7 +59,6 @@ static void send_msg_chansess_exitstatus(struct Channel * channel,
struct ChanSess * chansess);
static void send_msg_chansess_exitsignal(struct Channel * channel,
struct ChanSess * chansess);
-static int sesscheckclose(struct Channel *channel);
static void get_termmodes(struct ChanSess *chansess);
@@ -68,7 +67,8 @@ extern char** environ;
static int sesscheckclose(struct Channel *channel) {
struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
- return chansess->exit.exitpid >= 0;
+ TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid))
+ return chansess->exit.exitpid != -1;
}
/* Handler for childs exiting, store the state for return to the client */
@@ -89,10 +89,13 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
TRACE(("enter sigchld handler"))
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ TRACE(("sigchld handler: pid %d", pid))
+
+ exit = NULL;
/* find the corresponding chansess */
for (i = 0; i < svr_ses.childpidsize; i++) {
if (svr_ses.childpids[i].pid == pid) {
-
+ TRACE(("found match session"));
exit = &svr_ses.childpids[i].chansess->exit;
break;
}
@@ -100,7 +103,8 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
/* If the pid wasn't matched, then we might have hit the race mentioned
* above. So we just store the info for the parent to deal with */
- if (i == svr_ses.childpidsize) {
+ if (exit == NULL) {
+ TRACE(("using lastexit"));
exit = &svr_ses.lastexit;
}
@@ -119,10 +123,18 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
/* we use this to determine how pid exited */
exit->exitsignal = -1;
}
- exit = NULL;
+
+ /* Make sure that the main select() loop wakes up */
+ while (1) {
+ /* isserver is just a random byte to write. We can't do anything
+ about an error so should just ignore it */
+ if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1
+ || errno != EINTR) {
+ break;
+ }
+ }
}
-
sa_chld.sa_handler = sesssigchild_handler;
sa_chld.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &sa_chld, NULL);
@@ -130,7 +142,6 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
}
/* send the exit status or the signal causing termination for a session */
-/* XXX server */
static void send_exitsignalstatus(struct Channel *channel) {
struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
@@ -169,10 +180,11 @@ static void send_msg_chansess_exitsignal(struct Channel * channel,
int i;
char* signame = NULL;
-
dropbear_assert(chansess->exit.exitpid != -1);
dropbear_assert(chansess->exit.exitsignal > 0);
+ TRACE(("send_msg_chansess_exitsignal %d", chansess->exit.exitsignal))
+
CHECKCLEARTOWRITE();
/* we check that we can match a signal name, otherwise
@@ -244,16 +256,17 @@ static void closechansess(struct Channel *channel) {
unsigned int i;
struct logininfo *li;
- chansess = (struct ChanSess*)channel->typedata;
+ TRACE(("enter closechansess"))
- send_exitsignalstatus(channel);
+ chansess = (struct ChanSess*)channel->typedata;
- TRACE(("enter closechansess"))
if (chansess == NULL) {
TRACE(("leave closechansess: chansess == NULL"))
return;
}
+ send_exitsignalstatus(channel);
+
m_free(chansess->cmd);
m_free(chansess->term);
@@ -281,7 +294,7 @@ static void closechansess(struct Channel *channel) {
if (svr_ses.childpids[i].chansess == chansess) {
dropbear_assert(svr_ses.childpids[i].pid > 0);
TRACE(("closing pid %d", svr_ses.childpids[i].pid))
- TRACE(("exitpid = %d", chansess->exit.exitpid))
+ TRACE(("exitpid is %d", chansess->exit.exitpid))
svr_ses.childpids[i].pid = -1;
svr_ses.childpids[i].chansess = NULL;
}
@@ -410,7 +423,7 @@ static int sessionwinchange(struct ChanSess *chansess) {
pty_change_window_size(chansess->master, termr, termc, termw, termh);
- return DROPBEAR_FAILURE;
+ return DROPBEAR_SUCCESS;
}
static void get_termmodes(struct ChanSess *chansess) {
@@ -588,6 +601,16 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
}
}
+#ifdef LOG_COMMANDS
+ if (chansess->cmd) {
+ dropbear_log(LOG_INFO, "user %s executing '%s'",
+ ses.authstate.printableuser, chansess->cmd);
+ } else {
+ dropbear_log(LOG_INFO, "user %s executing login shell",
+ ses.authstate.printableuser);
+ }
+#endif
+
if (chansess->term == NULL) {
/* no pty */
ret = noptycommand(channel, chansess);
@@ -635,6 +658,12 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
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 */
#define FDIN 0
#define FDOUT 1
@@ -659,22 +688,24 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
/* 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 it's data manually */
+ * out its data manually */
for (i = 0; i < svr_ses.childpidsize; i++) {
- if (svr_ses.childpids[i].pid == pid) {
+ 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]);
@@ -730,6 +761,12 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
if (pid == 0) {
/* 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/stderr */
close(chansess->master);
@@ -997,6 +1034,7 @@ void addnewvar(const char* param, const char* var) {
newvar[plen] = '=';
memcpy(&newvar[plen+1], var, vlen);
newvar[plen+vlen+1] = '\0';
+ /* newvar is leaked here, but that's part of putenv()'s semantics */
if (putenv(newvar) < 0) {
dropbear_exit("environ error");
}