]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: Add channel_force_close()
authordjm@openbsd.org <djm@openbsd.org>
Fri, 6 Jan 2023 02:39:59 +0000 (02:39 +0000)
committerDamien Miller <djm@mindrot.org>
Fri, 6 Jan 2023 05:21:39 +0000 (16:21 +1100)
This will forcibly close an open channel by simulating read/write errors,
draining the IO buffers and calling the detach function.

Previously the detach function was only ever called during channel garbage
collection, but there was no way to signal the user of a channel (e.g.
session.c) that its channel was being closed deliberately (vs. by the
usual state-machine logic). So this adds an extra "force" argument to the
channel cleanup callback to indicate this condition.

ok markus dtucker

OpenBSD-Commit-ID: 23052707a42bdc62fda2508636e624afd466324b

channels.c
channels.h
clientloop.c
mux.c
session.c
session.h
ssh.c

index 5541e904c925d07b73a7dbec3f492a5df32cd144..84d902bdb69bb7725d4ee538d524b5c540f53bd2 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.422 2023/01/06 02:38:23 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.423 2023/01/06 02:39:59 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1222,6 +1222,29 @@ x11_open_helper(struct ssh *ssh, struct sshbuf *b)
        return 1;
 }
 
+void
+channel_force_close(struct ssh *ssh, Channel *c, int abandon)
+{
+       debug3_f("channel %d: forcibly closing", c->self);
+       if (c->istate == CHAN_INPUT_OPEN)
+               chan_read_failed(ssh, c);
+       if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
+               sshbuf_reset(c->input);
+               chan_ibuf_empty(ssh, c);
+       }
+       if (c->ostate == CHAN_OUTPUT_OPEN ||
+           c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+               sshbuf_reset(c->output);
+               chan_write_failed(ssh, c);
+       }
+       if (c->detach_user)
+               c->detach_user(ssh, c->self, 1, NULL);
+       if (c->efd != -1)
+               channel_close_fd(ssh, c, &c->efd);
+       if (abandon)
+               c->type = SSH_CHANNEL_ABANDONED;
+}
+
 static void
 channel_pre_x11_open(struct ssh *ssh, Channel *c)
 {
@@ -1233,15 +1256,11 @@ channel_pre_x11_open(struct ssh *ssh, Channel *c)
                c->type = SSH_CHANNEL_OPEN;
                channel_pre_open(ssh, c);
        } else if (ret == -1) {
-               logit("X11 connection rejected because of wrong authentication.");
+               logit("X11 connection rejected because of wrong "
+                   "authentication.");
                debug2("X11 rejected %d i%d/o%d",
                    c->self, c->istate, c->ostate);
-               chan_read_failed(ssh, c);
-               sshbuf_reset(c->input);
-               chan_ibuf_empty(ssh, c);
-               sshbuf_reset(c->output);
-               chan_write_failed(ssh, c);
-               debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
+               channel_force_close(ssh, c, 0);
        }
 }
 
@@ -1591,11 +1610,7 @@ static void
 rdynamic_close(struct ssh *ssh, Channel *c)
 {
        c->type = SSH_CHANNEL_OPEN;
-       chan_read_failed(ssh, c);
-       sshbuf_reset(c->input);
-       chan_ibuf_empty(ssh, c);
-       sshbuf_reset(c->output);
-       chan_write_failed(ssh, c);
+       channel_force_close(ssh, c, 0);
 }
 
 /* reverse dynamic port forwarding */
@@ -2395,7 +2410,7 @@ channel_garbage_collect(struct ssh *ssh, Channel *c)
                        return;
 
                debug2("channel %d: gc: notify user", c->self);
-               c->detach_user(ssh, c->self, NULL);
+               c->detach_user(ssh, c->self, 0, NULL);
                /* if we still have a callback */
                if (c->detach_user != NULL)
                        return;
index 51a02b224a305743b590940931981b38f6e08ea2..bcffa6cf62974e7c3430d0f18e597e7edc6ad821 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.144 2023/01/06 02:38:23 djm Exp $ */
+/* $OpenBSD: channels.h,v 1.145 2023/01/06 02:39:59 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -88,7 +88,7 @@ typedef struct Channel Channel;
 struct fwd_perm_list;
 
 typedef void channel_open_fn(struct ssh *, int, int, void *);
-typedef void channel_callback_fn(struct ssh *, int, void *);
+typedef void channel_callback_fn(struct ssh *, int, int, void *);
 typedef int channel_infilter_fn(struct ssh *, struct Channel *, char *, int);
 typedef void channel_filter_cleanup_fn(struct ssh *, int, void *);
 typedef u_char *channel_outfilter_fn(struct ssh *, struct Channel *,
@@ -281,6 +281,7 @@ void         channel_set_fds(struct ssh *, int, int, int, int, int,
 void    channel_free(struct ssh *, Channel *);
 void    channel_free_all(struct ssh *);
 void    channel_stop_listening(struct ssh *);
+void    channel_force_close(struct ssh *, Channel *, int);
 
 void    channel_send_open(struct ssh *, int);
 void    channel_request_start(struct ssh *, int, char *, int);
index d087b05b8bb6ca6bc6ad155ba8b9d3786492e15f..fef9efc6cc3ae1761a42cd61953a709d3d90cf67 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.386 2023/01/06 02:38:23 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.387 2023/01/06 02:39:59 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1033,15 +1033,7 @@ process_escapes(struct ssh *ssh, Channel *c,
                                    efc->escape_char)) != 0)
                                        fatal_fr(r, "sshbuf_putf");
                                if (c && c->ctl_chan != -1) {
-                                       chan_read_failed(ssh, c);
-                                       chan_write_failed(ssh, c);
-                                       if (c->detach_user) {
-                                               c->detach_user(ssh,
-                                                   c->self, NULL);
-                                       }
-                                       c->type = SSH_CHANNEL_ABANDONED;
-                                       sshbuf_reset(c->input);
-                                       chan_ibuf_empty(ssh, c);
+                                       channel_force_close(ssh, c, 1);
                                        return 0;
                                } else
                                        quit_pending = 1;
@@ -1267,7 +1259,7 @@ client_simple_escape_filter(struct ssh *ssh, Channel *c, char *buf, int len)
 }
 
 static void
-client_channel_closed(struct ssh *ssh, int id, void *arg)
+client_channel_closed(struct ssh *ssh, int id, int force, void *arg)
 {
        channel_cancel_cleanup(ssh, id);
        session_closed = 1;
diff --git a/mux.c b/mux.c
index 3cb3876148aa14978270897bdbd7298bb3e2bc00..e7580ac742ab9538889c992fabcc5b757b94f5aa 100644 (file)
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.94 2022/06/03 04:30:47 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.95 2023/01/06 02:39:59 djm Exp $ */
 /*
  * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
  *
@@ -188,7 +188,7 @@ static const struct {
 /* Cleanup callback fired on closure of mux client _session_ channel */
 /* ARGSUSED */
 static void
-mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused)
+mux_master_session_cleanup_cb(struct ssh *ssh, int cid, int force, void *unused)
 {
        Channel *cc, *c = channel_by_id(ssh, cid);
 
@@ -210,7 +210,7 @@ mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused)
 /* Cleanup callback fired on closure of mux client _control_ channel */
 /* ARGSUSED */
 static void
-mux_master_control_cleanup_cb(struct ssh *ssh, int cid, void *unused)
+mux_master_control_cleanup_cb(struct ssh *ssh, int cid, int force, void *unused)
 {
        Channel *sc, *c = channel_by_id(ssh, cid);
 
index e67d24d23c9995a2f37302e5df426b254bee4533..a40ee2c0f2423e1863b3575fed272efd55b8c391 100644 (file)
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.330 2022/02/08 08:59:12 dtucker Exp $ */
+/* $OpenBSD: session.c,v 1.331 2023/01/06 02:39:59 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -2335,7 +2335,7 @@ session_close_x11(struct ssh *ssh, int id)
 }
 
 static void
-session_close_single_x11(struct ssh *ssh, int id, void *arg)
+session_close_single_x11(struct ssh *ssh, int id, int force, void *arg)
 {
        Session *s;
        u_int i;
@@ -2469,7 +2469,7 @@ session_close_by_pid(struct ssh *ssh, pid_t pid, int status)
  * the session 'child' itself dies
  */
 void
-session_close_by_channel(struct ssh *ssh, int id, void *arg)
+session_close_by_channel(struct ssh *ssh, int id, int force, void *arg)
 {
        Session *s = session_by_channel(id);
        u_int i;
@@ -2482,12 +2482,14 @@ session_close_by_channel(struct ssh *ssh, int id, void *arg)
        if (s->pid != 0) {
                debug_f("channel %d: has child, ttyfd %d", id, s->ttyfd);
                /*
-                * delay detach of session, but release pty, since
-                * the fd's to the child are already closed
+                * delay detach of session (unless this is a forced close),
+                * but release pty, since the fd's to the child are already
+                * closed
                 */
                if (s->ttyfd != -1)
                        session_pty_cleanup(s);
-               return;
+               if (!force)
+                       return;
        }
        /* detach by removing callback */
        channel_cancel_cleanup(ssh, s->chanid);
index ce59dabd906de32cf2c423d62bfd3e3d9f2a8ba8..344a1ddf9d540bbc8a55fe62eba28675e4807754 100644 (file)
--- a/session.h
+++ b/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.36 2018/10/02 12:40:07 djm Exp $ */
+/* $OpenBSD: session.h,v 1.37 2023/01/06 02:39:59 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -70,7 +70,7 @@ int    session_open(Authctxt *, int);
 void    session_unused(int);
 int     session_input_channel_req(struct ssh *, Channel *, const char *);
 void    session_close_by_pid(struct ssh *ssh, pid_t, int);
-void    session_close_by_channel(struct ssh *, int, void *);
+void    session_close_by_channel(struct ssh *, int, int, void *);
 void    session_destroy_all(struct ssh *, void (*)(Session *));
 void    session_pty_cleanup2(Session *);
 
diff --git a/ssh.c b/ssh.c
index ba27674fcfe926abfe0c727e4bee402c6836f10f..f20848e6bcb54b39a26a541f7e4f4f4852176995 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.581 2022/12/09 00:22:29 dtucker Exp $ */
+/* $OpenBSD: ssh.c,v 1.582 2023/01/06 02:39:59 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1855,7 +1855,7 @@ ssh_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
 }
 
 static void
-client_cleanup_stdio_fwd(struct ssh *ssh, int id, void *arg)
+client_cleanup_stdio_fwd(struct ssh *ssh, int id, int force, void *arg)
 {
        debug("stdio forwarding: done");
        cleanup_exit(0);