1*9469f4f1Schristos /* $NetBSD: nchan.c,v 1.16 2024/09/24 21:32:18 christos Exp $ */ 2*9469f4f1Schristos /* $OpenBSD: nchan.c,v 1.76 2024/07/25 22:40:08 djm Exp $ */ 3c5555919Schristos 4ca32bd8dSchristos /* 5ca32bd8dSchristos * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 6ca32bd8dSchristos * 7ca32bd8dSchristos * Redistribution and use in source and binary forms, with or without 8ca32bd8dSchristos * modification, are permitted provided that the following conditions 9ca32bd8dSchristos * are met: 10ca32bd8dSchristos * 1. Redistributions of source code must retain the above copyright 11ca32bd8dSchristos * notice, this list of conditions and the following disclaimer. 12ca32bd8dSchristos * 2. Redistributions in binary form must reproduce the above copyright 13ca32bd8dSchristos * notice, this list of conditions and the following disclaimer in the 14ca32bd8dSchristos * documentation and/or other materials provided with the distribution. 15ca32bd8dSchristos * 16ca32bd8dSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17ca32bd8dSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18ca32bd8dSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19ca32bd8dSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20ca32bd8dSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21ca32bd8dSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22ca32bd8dSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23ca32bd8dSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24ca32bd8dSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25ca32bd8dSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26ca32bd8dSchristos */ 27ca32bd8dSchristos 28313c6c94Schristos #include "includes.h" 29*9469f4f1Schristos __RCSID("$NetBSD: nchan.c,v 1.16 2024/09/24 21:32:18 christos Exp $"); 30ca32bd8dSchristos #include <sys/types.h> 31ca32bd8dSchristos #include <sys/socket.h> 32ca32bd8dSchristos #include <sys/queue.h> 33ca32bd8dSchristos 34ca32bd8dSchristos #include <errno.h> 35ca32bd8dSchristos #include <string.h> 36ca32bd8dSchristos #include <stdarg.h> 37ca32bd8dSchristos 38ca32bd8dSchristos #include "ssh2.h" 397a183406Schristos #include "sshbuf.h" 407a183406Schristos #include "ssherr.h" 41ca32bd8dSchristos #include "packet.h" 42ca32bd8dSchristos #include "channels.h" 43ca32bd8dSchristos #include "compat.h" 44ca32bd8dSchristos #include "log.h" 45ca32bd8dSchristos 46ca32bd8dSchristos /* 47ca32bd8dSchristos * SSH Protocol 1.5 aka New Channel Protocol 48ca32bd8dSchristos * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. 49ca32bd8dSchristos * Written by Markus Friedl in October 1999 50ca32bd8dSchristos * 51ca32bd8dSchristos * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the 52ca32bd8dSchristos * tear down of channels: 53ca32bd8dSchristos * 54ca32bd8dSchristos * 1.3: strict request-ack-protocol: 55ca32bd8dSchristos * CLOSE -> 56ca32bd8dSchristos * <- CLOSE_CONFIRM 57ca32bd8dSchristos * 58ca32bd8dSchristos * 1.5: uses variations of: 59ca32bd8dSchristos * IEOF -> 60ca32bd8dSchristos * <- OCLOSE 61ca32bd8dSchristos * <- IEOF 62ca32bd8dSchristos * OCLOSE -> 63ca32bd8dSchristos * i.e. both sides have to close the channel 64ca32bd8dSchristos * 65ca32bd8dSchristos * 2.0: the EOF messages are optional 66ca32bd8dSchristos * 67ca32bd8dSchristos * See the debugging output from 'ssh -v' and 'sshd -d' of 68ca32bd8dSchristos * ssh-1.2.27 as an example. 69ca32bd8dSchristos * 70ca32bd8dSchristos */ 71ca32bd8dSchristos 72ca32bd8dSchristos /* functions manipulating channel states */ 73ca32bd8dSchristos /* 74ca32bd8dSchristos * EVENTS update channel input/output states execute ACTIONS 75ca32bd8dSchristos */ 76ca32bd8dSchristos /* 77ca32bd8dSchristos * ACTIONS: should never update the channel states 78ca32bd8dSchristos */ 797a183406Schristos static void chan_send_eof2(struct ssh *, Channel *); 807a183406Schristos static void chan_send_eow2(struct ssh *, Channel *); 81ca32bd8dSchristos 82ca32bd8dSchristos /* helper */ 837a183406Schristos static void chan_shutdown_write(struct ssh *, Channel *); 847a183406Schristos static void chan_shutdown_read(struct ssh *, Channel *); 85aa36fcacSchristos static void chan_shutdown_extended_read(struct ssh *, Channel *); 86ca32bd8dSchristos 87a03ec00cSchristos static const char * const ostates[] = { 88a03ec00cSchristos "open", "drain", "wait_ieof", "closed", 89a03ec00cSchristos }; 90a03ec00cSchristos static const char * const istates[] = { 91a03ec00cSchristos "open", "drain", "wait_oclose", "closed", 92a03ec00cSchristos }; 93ca32bd8dSchristos 94ca32bd8dSchristos static void 95ca32bd8dSchristos chan_set_istate(Channel *c, u_int next) 96ca32bd8dSchristos { 97ca32bd8dSchristos if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED) 98ca32bd8dSchristos fatal("chan_set_istate: bad state %d -> %d", c->istate, next); 99ca32bd8dSchristos debug2("channel %d: input %s -> %s", c->self, istates[c->istate], 100ca32bd8dSchristos istates[next]); 101ca32bd8dSchristos c->istate = next; 102ca32bd8dSchristos } 1037a183406Schristos 104ca32bd8dSchristos static void 105ca32bd8dSchristos chan_set_ostate(Channel *c, u_int next) 106ca32bd8dSchristos { 107ca32bd8dSchristos if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED) 108ca32bd8dSchristos fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next); 109ca32bd8dSchristos debug2("channel %d: output %s -> %s", c->self, ostates[c->ostate], 110ca32bd8dSchristos ostates[next]); 111ca32bd8dSchristos c->ostate = next; 112ca32bd8dSchristos } 113ca32bd8dSchristos 114ca32bd8dSchristos void 1157a183406Schristos chan_read_failed(struct ssh *ssh, Channel *c) 116ca32bd8dSchristos { 117ca32bd8dSchristos debug2("channel %d: read failed", c->self); 118ca32bd8dSchristos switch (c->istate) { 119ca32bd8dSchristos case CHAN_INPUT_OPEN: 1207a183406Schristos chan_shutdown_read(ssh, c); 121ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN); 122ca32bd8dSchristos break; 123ca32bd8dSchristos default: 124ca32bd8dSchristos error("channel %d: chan_read_failed for istate %d", 125ca32bd8dSchristos c->self, c->istate); 126ca32bd8dSchristos break; 127ca32bd8dSchristos } 128ca32bd8dSchristos } 1297a183406Schristos 130ca32bd8dSchristos void 1317a183406Schristos chan_ibuf_empty(struct ssh *ssh, Channel *c) 132ca32bd8dSchristos { 133ca32bd8dSchristos debug2("channel %d: ibuf empty", c->self); 1347a183406Schristos if (sshbuf_len(c->input)) { 135ca32bd8dSchristos error("channel %d: chan_ibuf_empty for non empty buffer", 136ca32bd8dSchristos c->self); 137ca32bd8dSchristos return; 138ca32bd8dSchristos } 139ca32bd8dSchristos switch (c->istate) { 140ca32bd8dSchristos case CHAN_INPUT_WAIT_DRAIN: 14134b27b53Sadam if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL))) 1427a183406Schristos chan_send_eof2(ssh, c); 143ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_CLOSED); 144ca32bd8dSchristos break; 145ca32bd8dSchristos default: 146ca32bd8dSchristos error("channel %d: chan_ibuf_empty for istate %d", 147ca32bd8dSchristos c->self, c->istate); 148ca32bd8dSchristos break; 149ca32bd8dSchristos } 150ca32bd8dSchristos } 1517a183406Schristos 152ca32bd8dSchristos void 1537a183406Schristos chan_obuf_empty(struct ssh *ssh, Channel *c) 154ca32bd8dSchristos { 155ca32bd8dSchristos debug2("channel %d: obuf empty", c->self); 1567a183406Schristos if (sshbuf_len(c->output)) { 157ca32bd8dSchristos error("channel %d: chan_obuf_empty for non empty buffer", 158ca32bd8dSchristos c->self); 159ca32bd8dSchristos return; 160ca32bd8dSchristos } 161ca32bd8dSchristos switch (c->ostate) { 162ca32bd8dSchristos case CHAN_OUTPUT_WAIT_DRAIN: 1637a183406Schristos chan_shutdown_write(ssh, c); 164ca32bd8dSchristos chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 165ca32bd8dSchristos break; 166ca32bd8dSchristos default: 167ca32bd8dSchristos error("channel %d: internal error: obuf_empty for ostate %d", 168ca32bd8dSchristos c->self, c->ostate); 169ca32bd8dSchristos break; 170ca32bd8dSchristos } 171ca32bd8dSchristos } 1727a183406Schristos 1737a183406Schristos void 1747a183406Schristos chan_rcvd_eow(struct ssh *ssh, Channel *c) 175ca32bd8dSchristos { 1767a183406Schristos debug2("channel %d: rcvd eow", c->self); 177ca32bd8dSchristos switch (c->istate) { 178ca32bd8dSchristos case CHAN_INPUT_OPEN: 1797a183406Schristos chan_shutdown_read(ssh, c); 1807a183406Schristos chan_set_istate(c, CHAN_INPUT_CLOSED); 181ca32bd8dSchristos break; 182ca32bd8dSchristos } 183ca32bd8dSchristos } 184ca32bd8dSchristos 185ca32bd8dSchristos static void 1867a183406Schristos chan_send_eof2(struct ssh *ssh, Channel *c) 1877a183406Schristos { 1887a183406Schristos int r; 1897a183406Schristos 1907a183406Schristos debug2("channel %d: send eof", c->self); 1917a183406Schristos switch (c->istate) { 1927a183406Schristos case CHAN_INPUT_WAIT_DRAIN: 1937a183406Schristos if (!c->have_remote_id) 19417418e98Schristos fatal_f("channel %d: no remote_id", c->self); 1957a183406Schristos if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EOF)) != 0 || 1967a183406Schristos (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 1977a183406Schristos (r = sshpkt_send(ssh)) != 0) 19817418e98Schristos fatal_fr(r, "send CHANNEL_EOF"); 1997a183406Schristos c->flags |= CHAN_EOF_SENT; 2007a183406Schristos break; 2017a183406Schristos default: 2027a183406Schristos error("channel %d: cannot send eof for istate %d", 2037a183406Schristos c->self, c->istate); 2047a183406Schristos break; 2057a183406Schristos } 2067a183406Schristos } 2077a183406Schristos 2087a183406Schristos static void 2097a183406Schristos chan_send_close2(struct ssh *ssh, Channel *c) 2107a183406Schristos { 2117a183406Schristos int r; 2127a183406Schristos 213*9469f4f1Schristos debug2("channel %d: send_close2", c->self); 2147a183406Schristos if (c->ostate != CHAN_OUTPUT_CLOSED || 2157a183406Schristos c->istate != CHAN_INPUT_CLOSED) { 2167a183406Schristos error("channel %d: cannot send close for istate/ostate %d/%d", 2177a183406Schristos c->self, c->istate, c->ostate); 2187a183406Schristos } else if (c->flags & CHAN_CLOSE_SENT) { 2197a183406Schristos error("channel %d: already sent close", c->self); 2207a183406Schristos } else { 2217a183406Schristos if (!c->have_remote_id) 22217418e98Schristos fatal_f("channel %d: no remote_id", c->self); 223*9469f4f1Schristos debug2("channel %d: send close for remote id %u", c->self, 224*9469f4f1Schristos c->remote_id); 2257a183406Schristos if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_CLOSE)) != 0 || 2267a183406Schristos (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 2277a183406Schristos (r = sshpkt_send(ssh)) != 0) 22817418e98Schristos fatal_fr(r, "send CHANNEL_EOF"); 2297a183406Schristos c->flags |= CHAN_CLOSE_SENT; 2307a183406Schristos } 2317a183406Schristos } 2327a183406Schristos 2337a183406Schristos static void 2347a183406Schristos chan_send_eow2(struct ssh *ssh, Channel *c) 2357a183406Schristos { 2367a183406Schristos int r; 2377a183406Schristos 2387a183406Schristos debug2("channel %d: send eow", c->self); 2397a183406Schristos if (c->ostate == CHAN_OUTPUT_CLOSED) { 2407a183406Schristos error("channel %d: must not sent eow on closed output", 2417a183406Schristos c->self); 2427a183406Schristos return; 2437a183406Schristos } 24417418e98Schristos if (!(ssh->compat & SSH_NEW_OPENSSH)) 2457a183406Schristos return; 2467a183406Schristos if (!c->have_remote_id) 24717418e98Schristos fatal_f("channel %d: no remote_id", c->self); 2487a183406Schristos if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 || 2497a183406Schristos (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 2507a183406Schristos (r = sshpkt_put_cstring(ssh, "eow@openssh.com")) != 0 || 2517a183406Schristos (r = sshpkt_put_u8(ssh, 0)) != 0 || 2527a183406Schristos (r = sshpkt_send(ssh)) != 0) 25317418e98Schristos fatal_fr(r, "send CHANNEL_EOF"); 2547a183406Schristos } 2557a183406Schristos 2567a183406Schristos /* shared */ 2577a183406Schristos 2587a183406Schristos void 2597a183406Schristos chan_rcvd_ieof(struct ssh *ssh, Channel *c) 2607a183406Schristos { 2617a183406Schristos debug2("channel %d: rcvd eof", c->self); 2627a183406Schristos c->flags |= CHAN_EOF_RCVD; 2637a183406Schristos if (c->ostate == CHAN_OUTPUT_OPEN) 2647a183406Schristos chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 2657a183406Schristos if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && 2667a183406Schristos sshbuf_len(c->output) == 0 && 2677a183406Schristos !CHANNEL_EFD_OUTPUT_ACTIVE(c)) 2687a183406Schristos chan_obuf_empty(ssh, c); 2697a183406Schristos } 2707a183406Schristos 2717a183406Schristos void 2727a183406Schristos chan_rcvd_oclose(struct ssh *ssh, Channel *c) 273ca32bd8dSchristos { 274ca32bd8dSchristos debug2("channel %d: rcvd close", c->self); 27534b27b53Sadam if (!(c->flags & CHAN_LOCAL)) { 276ca32bd8dSchristos if (c->flags & CHAN_CLOSE_RCVD) 27734b27b53Sadam error("channel %d: protocol error: close rcvd twice", 27834b27b53Sadam c->self); 279ca32bd8dSchristos c->flags |= CHAN_CLOSE_RCVD; 28034b27b53Sadam } 281ca32bd8dSchristos if (c->type == SSH_CHANNEL_LARVAL) { 282ca32bd8dSchristos /* tear down larval channels immediately */ 283ca32bd8dSchristos chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 284ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_CLOSED); 285ca32bd8dSchristos return; 286ca32bd8dSchristos } 287ca32bd8dSchristos switch (c->ostate) { 288ca32bd8dSchristos case CHAN_OUTPUT_OPEN: 289ca32bd8dSchristos /* 290ca32bd8dSchristos * wait until a data from the channel is consumed if a CLOSE 291ca32bd8dSchristos * is received 292ca32bd8dSchristos */ 293ca32bd8dSchristos chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 294ca32bd8dSchristos break; 295ca32bd8dSchristos } 296ca32bd8dSchristos switch (c->istate) { 297ca32bd8dSchristos case CHAN_INPUT_OPEN: 2987a183406Schristos chan_shutdown_read(ssh, c); 299aa36fcacSchristos chan_shutdown_extended_read(ssh, c); 300ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_CLOSED); 301ca32bd8dSchristos break; 302ca32bd8dSchristos case CHAN_INPUT_WAIT_DRAIN: 30334b27b53Sadam if (!(c->flags & CHAN_LOCAL)) 3047a183406Schristos chan_send_eof2(ssh, c); 305aa36fcacSchristos chan_shutdown_extended_read(ssh, c); 306ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_CLOSED); 307ca32bd8dSchristos break; 308ca32bd8dSchristos } 309ca32bd8dSchristos } 31034b27b53Sadam 311ca32bd8dSchristos void 3127a183406Schristos chan_write_failed(struct ssh *ssh, Channel *c) 313ca32bd8dSchristos { 314ca32bd8dSchristos debug2("channel %d: write failed", c->self); 315ca32bd8dSchristos switch (c->ostate) { 316ca32bd8dSchristos case CHAN_OUTPUT_OPEN: 317ca32bd8dSchristos case CHAN_OUTPUT_WAIT_DRAIN: 3187a183406Schristos chan_shutdown_write(ssh, c); 319ca32bd8dSchristos if (strcmp(c->ctype, "session") == 0) 3207a183406Schristos chan_send_eow2(ssh, c); 321ca32bd8dSchristos chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 322ca32bd8dSchristos break; 323ca32bd8dSchristos default: 324ca32bd8dSchristos error("channel %d: chan_write_failed for ostate %d", 325ca32bd8dSchristos c->self, c->ostate); 326ca32bd8dSchristos break; 327ca32bd8dSchristos } 328ca32bd8dSchristos } 329ca32bd8dSchristos 330ca32bd8dSchristos void 3317a183406Schristos chan_mark_dead(struct ssh *ssh, Channel *c) 332ca32bd8dSchristos { 333ca32bd8dSchristos c->type = SSH_CHANNEL_ZOMBIE; 334ca32bd8dSchristos } 335ca32bd8dSchristos 336ca32bd8dSchristos int 3377a183406Schristos chan_is_dead(struct ssh *ssh, Channel *c, int do_send) 338ca32bd8dSchristos { 339ca32bd8dSchristos if (c->type == SSH_CHANNEL_ZOMBIE) { 340ca32bd8dSchristos debug2("channel %d: zombie", c->self); 341ca32bd8dSchristos return 1; 342ca32bd8dSchristos } 343ca32bd8dSchristos if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) 344ca32bd8dSchristos return 0; 34517418e98Schristos if ((ssh->compat & SSH_BUG_EXTEOF) && 346ca32bd8dSchristos c->extended_usage == CHAN_EXTENDED_WRITE && 347ca32bd8dSchristos c->efd != -1 && 3487a183406Schristos sshbuf_len(c->extended) > 0) { 3497a183406Schristos debug2("channel %d: active efd: %d len %zu", 3507a183406Schristos c->self, c->efd, sshbuf_len(c->extended)); 351ca32bd8dSchristos return 0; 352ca32bd8dSchristos } 35334b27b53Sadam if (c->flags & CHAN_LOCAL) { 35434b27b53Sadam debug2("channel %d: is dead (local)", c->self); 35534b27b53Sadam return 1; 35634b27b53Sadam } 357ca32bd8dSchristos if (!(c->flags & CHAN_CLOSE_SENT)) { 358ca32bd8dSchristos if (do_send) { 3597a183406Schristos chan_send_close2(ssh, c); 360ca32bd8dSchristos } else { 361ca32bd8dSchristos /* channel would be dead if we sent a close */ 362ca32bd8dSchristos if (c->flags & CHAN_CLOSE_RCVD) { 363ca32bd8dSchristos debug2("channel %d: almost dead", 364ca32bd8dSchristos c->self); 365ca32bd8dSchristos return 1; 366ca32bd8dSchristos } 367ca32bd8dSchristos } 368ca32bd8dSchristos } 369ca32bd8dSchristos if ((c->flags & CHAN_CLOSE_SENT) && 370ca32bd8dSchristos (c->flags & CHAN_CLOSE_RCVD)) { 371ca32bd8dSchristos debug2("channel %d: is dead", c->self); 372ca32bd8dSchristos return 1; 373ca32bd8dSchristos } 374ca32bd8dSchristos return 0; 375ca32bd8dSchristos } 376ca32bd8dSchristos 377ca32bd8dSchristos /* helper */ 378ca32bd8dSchristos static void 3797a183406Schristos chan_shutdown_write(struct ssh *ssh, Channel *c) 380ca32bd8dSchristos { 3817a183406Schristos sshbuf_reset(c->output); 3827a183406Schristos if (c->type == SSH_CHANNEL_LARVAL) 383ca32bd8dSchristos return; 384ca32bd8dSchristos /* shutdown failure is allowed if write failed already */ 38517418e98Schristos debug2_f("channel %d: (i%d o%d sock %d wfd %d efd %d [%s])", 38617418e98Schristos c->self, c->istate, c->ostate, c->sock, c->wfd, c->efd, 387aa36fcacSchristos channel_format_extended_usage(c)); 388ca32bd8dSchristos if (c->sock != -1) { 389cd4ada6aSchristos if (shutdown(c->sock, SHUT_WR) == -1) { 39017418e98Schristos debug2_f("channel %d: shutdown() failed for " 39117418e98Schristos "fd %d [i%d o%d]: %.100s", c->self, c->sock, 39217418e98Schristos c->istate, c->ostate, strerror(errno)); 393aa36fcacSchristos } 394ca32bd8dSchristos } else { 395b592f463Schristos if (channel_close_fd(ssh, c, &c->wfd) < 0) { 39617418e98Schristos logit_f("channel %d: close() failed for " 39717418e98Schristos "fd %d [i%d o%d]: %.100s", c->self, c->wfd, 39817418e98Schristos c->istate, c->ostate, strerror(errno)); 399aa36fcacSchristos } 400ca32bd8dSchristos } 401ca32bd8dSchristos } 4027a183406Schristos 403ca32bd8dSchristos static void 4047a183406Schristos chan_shutdown_read(struct ssh *ssh, Channel *c) 405ca32bd8dSchristos { 4067a183406Schristos if (c->type == SSH_CHANNEL_LARVAL) 407ca32bd8dSchristos return; 40817418e98Schristos debug2_f("channel %d: (i%d o%d sock %d wfd %d efd %d [%s])", 40917418e98Schristos c->self, c->istate, c->ostate, c->sock, c->rfd, c->efd, 410aa36fcacSchristos channel_format_extended_usage(c)); 411ca32bd8dSchristos if (c->sock != -1) { 412cd4ada6aSchristos if (shutdown(c->sock, SHUT_RD) == -1) { 41317418e98Schristos error_f("channel %d: shutdown() failed for " 41417418e98Schristos "fd %d [i%d o%d]: %.100s", c->self, c->sock, 41517418e98Schristos c->istate, c->ostate, strerror(errno)); 416aa36fcacSchristos } 417ca32bd8dSchristos } else { 418b592f463Schristos if (channel_close_fd(ssh, c, &c->rfd) < 0) { 41917418e98Schristos logit_f("channel %d: close() failed for " 42017418e98Schristos "fd %d [i%d o%d]: %.100s", c->self, c->rfd, 42117418e98Schristos c->istate, c->ostate, strerror(errno)); 422aa36fcacSchristos } 423aa36fcacSchristos } 424aa36fcacSchristos } 425aa36fcacSchristos 426aa36fcacSchristos static void 427aa36fcacSchristos chan_shutdown_extended_read(struct ssh *ssh, Channel *c) 428aa36fcacSchristos { 429aa36fcacSchristos if (c->type == SSH_CHANNEL_LARVAL || c->efd == -1) 430aa36fcacSchristos return; 431aa36fcacSchristos if (c->extended_usage != CHAN_EXTENDED_READ && 432aa36fcacSchristos c->extended_usage != CHAN_EXTENDED_IGNORE) 433aa36fcacSchristos return; 43417418e98Schristos debug_f("channel %d: (i%d o%d sock %d wfd %d efd %d [%s])", 43517418e98Schristos c->self, c->istate, c->ostate, c->sock, c->rfd, c->efd, 436aa36fcacSchristos channel_format_extended_usage(c)); 437b592f463Schristos if (channel_close_fd(ssh, c, &c->efd) < 0) { 43817418e98Schristos logit_f("channel %d: close() failed for " 43917418e98Schristos "extended fd %d [i%d o%d]: %.100s", c->self, c->efd, 44017418e98Schristos c->istate, c->ostate, strerror(errno)); 441ca32bd8dSchristos } 442ca32bd8dSchristos } 443