From 418e724c57fa27927e6400edae33a3490e23b163 Mon Sep 17 00:00:00 2001 From: djm Date: Fri, 12 Oct 2001 01:35:04 +0000 Subject: [PATCH] - (djm) OpenBSD CVS Sync - markus@cvs.openbsd.org 2001/10/10 22:18:47 [channels.c channels.h clientloop.c nchan.c serverloop.c] [session.c session.h] try to keep channels open until an exit-status message is sent. don't kill the login shells if the shells stdin/out/err is closed. this should now work: ssh -2n localhost 'exec > /dev/null 2>&1; sleep 10; exit 5'; echo ? --- ChangeLog | 10 +++++++++ channels.c | 49 ++++++++++++++++++++++---------------------- channels.h | 4 ++-- clientloop.c | 3 ++- nchan.c | 15 +++++++++++--- serverloop.c | 57 ++++++++++++++++++++++++++-------------------------- session.c | 29 ++++++++++---------------- session.h | 4 ++-- 8 files changed, 93 insertions(+), 78 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5de081ce..ed9b2baf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +20011012 + - (djm) OpenBSD CVS Sync + - markus@cvs.openbsd.org 2001/10/10 22:18:47 + [channels.c channels.h clientloop.c nchan.c serverloop.c] + [session.c session.h] + try to keep channels open until an exit-status message is sent. + don't kill the login shells if the shells stdin/out/err is closed. + this should now work: + ssh -2n localhost 'exec > /dev/null 2>&1; sleep 10; exit 5'; echo ? + 20011010 - (djm) OpenBSD CVS Sync - markus@cvs.openbsd.org 2001/10/04 14:34:16 diff --git a/channels.c b/channels.c index 04efd728..62fd73d7 100644 --- a/channels.c +++ b/channels.c @@ -39,7 +39,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.139 2001/10/09 21:59:41 markus Exp $"); +RCSID("$OpenBSD: channels.c,v 1.140 2001/10/10 22:18:47 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -331,10 +331,6 @@ channel_free(Channel *c) debug3("channel_free: status: %s", s); xfree(s); - if (c->detach_user != NULL) { - debug("channel_free: channel %d: detaching channel user", c->self); - c->detach_user(c->self, NULL); - } if (c->sock != -1) shutdown(c->sock, SHUT_RDWR); channel_close_fds(c); @@ -1520,6 +1516,28 @@ channel_handler_init(void) channel_handler_init_15(); } +/* gc dead channels */ +static void +channel_garbage_collect(Channel *c) +{ + if (c == NULL) + return; + if (c->detach_user != NULL) { + if (!chan_is_dead(c, 0)) + return; + debug("channel %d: gc: notify user", c->self); + c->detach_user(c->self, NULL); + /* if we still have a callback */ + if (c->detach_user != NULL) + return; + debug("channel %d: gc: user detached", c->self); + } + if (!chan_is_dead(c, 1)) + return; + debug("channel %d: garbage collecting", c->self); + channel_free(c); +} + static void channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) { @@ -1537,24 +1555,7 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) continue; if (ftab[c->type] != NULL) (*ftab[c->type])(c, readset, writeset); - if (chan_is_dead(c)) { - /* - * we have to remove the fd's from the select mask - * before the channels are free'd and the fd's are - * closed - */ - if (c->wfd != -1) - FD_CLR(c->wfd, writeset); - if (c->rfd != -1) - FD_CLR(c->rfd, readset); - if (c->efd != -1) { - if (c->extended_usage == CHAN_EXTENDED_READ) - FD_CLR(c->efd, readset); - if (c->extended_usage == CHAN_EXTENDED_WRITE) - FD_CLR(c->efd, writeset); - } - channel_free(c); - } + channel_garbage_collect(c); } } @@ -1625,7 +1626,7 @@ channel_output_poll() if (compat20 && (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { /* XXX is this true? */ - debug2("channel %d: no data after CLOSE", c->self); + debug3("channel %d: will not send data after close", c->self); continue; } diff --git a/channels.h b/channels.h index 090d2ca6..89e48009 100644 --- a/channels.h +++ b/channels.h @@ -32,7 +32,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("$OpenBSD: channels.h,v 1.49 2001/10/09 21:59:41 markus Exp $"); */ +/* RCSID("$OpenBSD: channels.h,v 1.50 2001/10/10 22:18:47 markus Exp $"); */ #ifndef CHANNEL_H #define CHANNEL_H @@ -214,7 +214,7 @@ void auth_input_open_request(int, int, void *); /* channel close */ -int chan_is_dead(Channel *); +int chan_is_dead(Channel *, int); void chan_mark_dead(Channel *); void chan_init_iostates(Channel *); void chan_init(void); diff --git a/clientloop.c b/clientloop.c index e6da67d5..43332d1f 100644 --- a/clientloop.c +++ b/clientloop.c @@ -59,7 +59,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: clientloop.c,v 1.82 2001/09/17 20:52:47 markus Exp $"); +RCSID("$OpenBSD: clientloop.c,v 1.83 2001/10/10 22:18:47 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -753,6 +753,7 @@ client_channel_closed(int id, void *arg) if (id != session_ident) error("client_channel_closed: id %d != session_ident %d", id, session_ident); + channel_cancel_cleanup(id); session_closed = 1; if (in_raw_mode()) leave_raw_mode(); diff --git a/nchan.c b/nchan.c index 91c34dec..2680f0a6 100644 --- a/nchan.c +++ b/nchan.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: nchan.c,v 1.31 2001/07/17 21:04:57 markus Exp $"); +RCSID("$OpenBSD: nchan.c,v 1.32 2001/10/10 22:18:47 markus Exp $"); #include "ssh1.h" #include "ssh2.h" @@ -432,7 +432,7 @@ chan_mark_dead(Channel *c) } int -chan_is_dead(Channel *c) +chan_is_dead(Channel *c, int send) { if (c->type == SSH_CHANNEL_ZOMBIE) { debug("channel %d: zombie", c->self); @@ -461,7 +461,16 @@ chan_is_dead(Channel *c) "read": "write"); } else { if (!(c->flags & CHAN_CLOSE_SENT)) { - chan_send_close2(c); + if (send) { + chan_send_close2(c); + } else { + /* channel would be dead if we sent a close */ + if (c->flags & CHAN_CLOSE_RCVD) { + debug("channel %d: almost dead", + c->self); + return 1; + } + } } if ((c->flags & CHAN_CLOSE_SENT) && (c->flags & CHAN_CLOSE_RCVD)) { diff --git a/serverloop.c b/serverloop.c index 8a82af55..983fe744 100644 --- a/serverloop.c +++ b/serverloop.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: serverloop.c,v 1.81 2001/10/09 21:59:41 markus Exp $"); +RCSID("$OpenBSD: serverloop.c,v 1.82 2001/10/10 22:18:47 markus Exp $"); #include "xmalloc.h" #include "packet.h" @@ -208,9 +208,6 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, max_time_milliseconds = options.client_alive_interval * 1000; } - /* When select fails we restart from here. */ -retry_select: - /* Allocate and update select() masks for channel descriptors. */ channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0); @@ -275,12 +272,11 @@ retry_select: ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); if (ret == -1) { + memset(*readsetp, 0, *maxfdp); + memset(*writesetp, 0, *maxfdp); if (errno != EINTR) error("select: %.100s", strerror(errno)); - else - goto retry_select; - } - if (ret == 0 && client_alive_scheduled) + } else if (ret == 0 && client_alive_scheduled) client_alive_check(); } @@ -668,13 +664,30 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) /* NOTREACHED */ } +static void +collect_children(void) +{ + pid_t pid; + sigset_t oset, nset; + int status; + + /* block SIGCHLD while we check for dead children */ + sigemptyset(&nset); + sigaddset(&nset, SIGCHLD); + sigprocmask(SIG_BLOCK, &nset, &oset); + if (child_terminated) { + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) + session_close_by_pid(pid, status); + child_terminated = 0; + } + sigprocmask(SIG_SETMASK, &oset, NULL); +} + void server_loop2(Authctxt *authctxt) { fd_set *readset = NULL, *writeset = NULL; - int rekeying = 0, max_fd, status, nalloc = 0; - pid_t pid; - sigset_t oset, nset; + int rekeying = 0, max_fd, nalloc = 0; debug("Entering interactive session for SSH2."); @@ -698,16 +711,7 @@ server_loop2(Authctxt *authctxt) wait_until_can_do_something(&readset, &writeset, &max_fd, &nalloc, 0); - /* block SIGCHLD while we check for dead children */ - sigemptyset(&nset); - sigaddset(&nset, SIGCHLD); - sigprocmask(SIG_BLOCK, &nset, &oset); - if (child_terminated) { - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) - session_close_by_pid(pid, status); - child_terminated = 0; - } - sigprocmask(SIG_SETMASK, &oset, NULL); + collect_children(); if (!rekeying) channel_after_select(readset, writeset); process_input(readset); @@ -715,6 +719,8 @@ server_loop2(Authctxt *authctxt) break; process_output(writeset); } + collect_children(); + if (readset) xfree(readset); if (writeset) @@ -723,13 +729,8 @@ server_loop2(Authctxt *authctxt) /* free all channels, no more reads and writes */ channel_free_all(); - /* collect remaining dead children, XXX not necessary? */ - mysignal(SIGCHLD, SIG_DFL); - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) - session_close_by_pid(pid, status); - - /* close remaining sessions, e.g remove wtmp entries */ - session_close_all(); + /* free remaining sessions, e.g. remove wtmp entries */ + session_destroy_all(); } static void diff --git a/session.c b/session.c index 0d6ebdae..6ba2e7c7 100644 --- a/session.c +++ b/session.c @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.106 2001/10/09 21:59:41 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.107 2001/10/10 22:18:47 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -1958,36 +1958,29 @@ session_close_by_channel(int id, void *arg) { Session *s = session_by_channel(id); if (s == NULL) { - debug("session_close_by_channel: no session for channel %d", id); + debug("session_close_by_channel: no session for id %d", id); return; } - /* disconnect channel */ - channel_cancel_cleanup(s->chanid); - s->chanid = -1; - - debug("session_close_by_channel: channel %d kill %d", id, s->pid); + debug("session_close_by_channel: channel %d child %d", id, s->pid); if (s->pid != 0) { - /* notify child */ - if (kill(s->pid, SIGHUP) < 0) - error("session_close_by_channel: kill %d: %s", - s->pid, strerror(errno)); + /* delay detach */ + debug("session_close_by_channel: channel %d: has child", id); + return; } + /* detach by removing callback */ + channel_cancel_cleanup(s->chanid); + s->chanid = -1; session_close(s); } void -session_close_all(void) +session_destroy_all(void) { int i; for(i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; - if (s->used) { - if (s->chanid != -1) { - channel_cancel_cleanup(s->chanid); - s->chanid = -1; - } + if (s->used) session_close(s); - } } } diff --git a/session.h b/session.h index d2b0d936..6d5b8e69 100644 --- a/session.h +++ b/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.12 2001/10/09 21:59:41 markus Exp $ */ +/* $OpenBSD: session.h,v 1.13 2001/10/10 22:18:47 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -32,6 +32,6 @@ int session_open(Authctxt*, int); void session_input_channel_req(int, void *); void session_close_by_pid(pid_t, int); void session_close_by_channel(int, void *); -void session_close_all(void); +void session_destroy_all(void); #endif -- 2.45.2