1*8f892fcaSchristos /* $NetBSD: nchan.c,v 1.10 2019/04/20 17:16:40 christos Exp $ */ 2*8f892fcaSchristos /* $OpenBSD: nchan.c,v 1.69 2018/10/04 07:47:35 djm Exp $ */ 3ca32bd8dSchristos /* 4ca32bd8dSchristos * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 5ca32bd8dSchristos * 6ca32bd8dSchristos * Redistribution and use in source and binary forms, with or without 7ca32bd8dSchristos * modification, are permitted provided that the following conditions 8ca32bd8dSchristos * are met: 9ca32bd8dSchristos * 1. Redistributions of source code must retain the above copyright 10ca32bd8dSchristos * notice, this list of conditions and the following disclaimer. 11ca32bd8dSchristos * 2. Redistributions in binary form must reproduce the above copyright 12ca32bd8dSchristos * notice, this list of conditions and the following disclaimer in the 13ca32bd8dSchristos * documentation and/or other materials provided with the distribution. 14ca32bd8dSchristos * 15ca32bd8dSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16ca32bd8dSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17ca32bd8dSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18ca32bd8dSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19ca32bd8dSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20ca32bd8dSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21ca32bd8dSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22ca32bd8dSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23ca32bd8dSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24ca32bd8dSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25ca32bd8dSchristos */ 26ca32bd8dSchristos 27313c6c94Schristos #include "includes.h" 28*8f892fcaSchristos __RCSID("$NetBSD: nchan.c,v 1.10 2019/04/20 17:16:40 christos Exp $"); 29ca32bd8dSchristos #include <sys/types.h> 30ca32bd8dSchristos #include <sys/socket.h> 31ca32bd8dSchristos #include <sys/queue.h> 32ca32bd8dSchristos 33ca32bd8dSchristos #include <errno.h> 34ca32bd8dSchristos #include <string.h> 35ca32bd8dSchristos #include <stdarg.h> 36ca32bd8dSchristos 37ca32bd8dSchristos #include "ssh2.h" 3845a1cd19Schristos #include "sshbuf.h" 3945a1cd19Schristos #include "ssherr.h" 40ca32bd8dSchristos #include "packet.h" 41ca32bd8dSchristos #include "channels.h" 42ca32bd8dSchristos #include "compat.h" 43ca32bd8dSchristos #include "log.h" 44ca32bd8dSchristos 45ca32bd8dSchristos /* 46ca32bd8dSchristos * SSH Protocol 1.5 aka New Channel Protocol 47ca32bd8dSchristos * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. 48ca32bd8dSchristos * Written by Markus Friedl in October 1999 49ca32bd8dSchristos * 50ca32bd8dSchristos * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the 51ca32bd8dSchristos * tear down of channels: 52ca32bd8dSchristos * 53ca32bd8dSchristos * 1.3: strict request-ack-protocol: 54ca32bd8dSchristos * CLOSE -> 55ca32bd8dSchristos * <- CLOSE_CONFIRM 56ca32bd8dSchristos * 57ca32bd8dSchristos * 1.5: uses variations of: 58ca32bd8dSchristos * IEOF -> 59ca32bd8dSchristos * <- OCLOSE 60ca32bd8dSchristos * <- IEOF 61ca32bd8dSchristos * OCLOSE -> 62ca32bd8dSchristos * i.e. both sides have to close the channel 63ca32bd8dSchristos * 64ca32bd8dSchristos * 2.0: the EOF messages are optional 65ca32bd8dSchristos * 66ca32bd8dSchristos * See the debugging output from 'ssh -v' and 'sshd -d' of 67ca32bd8dSchristos * ssh-1.2.27 as an example. 68ca32bd8dSchristos * 69ca32bd8dSchristos */ 70ca32bd8dSchristos 71ca32bd8dSchristos /* functions manipulating channel states */ 72ca32bd8dSchristos /* 73ca32bd8dSchristos * EVENTS update channel input/output states execute ACTIONS 74ca32bd8dSchristos */ 75ca32bd8dSchristos /* 76ca32bd8dSchristos * ACTIONS: should never update the channel states 77ca32bd8dSchristos */ 7845a1cd19Schristos static void chan_send_eof2(struct ssh *, Channel *); 7945a1cd19Schristos static void chan_send_eow2(struct ssh *, Channel *); 80ca32bd8dSchristos 81ca32bd8dSchristos /* helper */ 8245a1cd19Schristos static void chan_shutdown_write(struct ssh *, Channel *); 8345a1cd19Schristos static void chan_shutdown_read(struct ssh *, Channel *); 84*8f892fcaSchristos static void chan_shutdown_extended_read(struct ssh *, Channel *); 85ca32bd8dSchristos 868983daf9Schristos static const char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; 878983daf9Schristos static const char *istates[] = { "open", "drain", "wait_oclose", "closed" }; 88ca32bd8dSchristos 89ca32bd8dSchristos static void 90ca32bd8dSchristos chan_set_istate(Channel *c, u_int next) 91ca32bd8dSchristos { 92ca32bd8dSchristos if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED) 93ca32bd8dSchristos fatal("chan_set_istate: bad state %d -> %d", c->istate, next); 94ca32bd8dSchristos debug2("channel %d: input %s -> %s", c->self, istates[c->istate], 95ca32bd8dSchristos istates[next]); 96ca32bd8dSchristos c->istate = next; 97ca32bd8dSchristos } 9845a1cd19Schristos 99ca32bd8dSchristos static void 100ca32bd8dSchristos chan_set_ostate(Channel *c, u_int next) 101ca32bd8dSchristos { 102ca32bd8dSchristos if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED) 103ca32bd8dSchristos fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next); 104ca32bd8dSchristos debug2("channel %d: output %s -> %s", c->self, ostates[c->ostate], 105ca32bd8dSchristos ostates[next]); 106ca32bd8dSchristos c->ostate = next; 107ca32bd8dSchristos } 108ca32bd8dSchristos 109ca32bd8dSchristos void 11045a1cd19Schristos chan_read_failed(struct ssh *ssh, Channel *c) 111ca32bd8dSchristos { 112ca32bd8dSchristos debug2("channel %d: read failed", c->self); 113ca32bd8dSchristos switch (c->istate) { 114ca32bd8dSchristos case CHAN_INPUT_OPEN: 11545a1cd19Schristos chan_shutdown_read(ssh, c); 116ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN); 117ca32bd8dSchristos break; 118ca32bd8dSchristos default: 119ca32bd8dSchristos error("channel %d: chan_read_failed for istate %d", 120ca32bd8dSchristos c->self, c->istate); 121ca32bd8dSchristos break; 122ca32bd8dSchristos } 123ca32bd8dSchristos } 12445a1cd19Schristos 125ca32bd8dSchristos void 12645a1cd19Schristos chan_ibuf_empty(struct ssh *ssh, Channel *c) 127ca32bd8dSchristos { 128ca32bd8dSchristos debug2("channel %d: ibuf empty", c->self); 12945a1cd19Schristos if (sshbuf_len(c->input)) { 130ca32bd8dSchristos error("channel %d: chan_ibuf_empty for non empty buffer", 131ca32bd8dSchristos c->self); 132ca32bd8dSchristos return; 133ca32bd8dSchristos } 134ca32bd8dSchristos switch (c->istate) { 135ca32bd8dSchristos case CHAN_INPUT_WAIT_DRAIN: 13634b27b53Sadam if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL))) 13745a1cd19Schristos chan_send_eof2(ssh, c); 138ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_CLOSED); 139ca32bd8dSchristos break; 140ca32bd8dSchristos default: 141ca32bd8dSchristos error("channel %d: chan_ibuf_empty for istate %d", 142ca32bd8dSchristos c->self, c->istate); 143ca32bd8dSchristos break; 144ca32bd8dSchristos } 145ca32bd8dSchristos } 14645a1cd19Schristos 147ca32bd8dSchristos void 14845a1cd19Schristos chan_obuf_empty(struct ssh *ssh, Channel *c) 149ca32bd8dSchristos { 150ca32bd8dSchristos debug2("channel %d: obuf empty", c->self); 15145a1cd19Schristos if (sshbuf_len(c->output)) { 152ca32bd8dSchristos error("channel %d: chan_obuf_empty for non empty buffer", 153ca32bd8dSchristos c->self); 154ca32bd8dSchristos return; 155ca32bd8dSchristos } 156ca32bd8dSchristos switch (c->ostate) { 157ca32bd8dSchristos case CHAN_OUTPUT_WAIT_DRAIN: 15845a1cd19Schristos chan_shutdown_write(ssh, c); 159ca32bd8dSchristos chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 160ca32bd8dSchristos break; 161ca32bd8dSchristos default: 162ca32bd8dSchristos error("channel %d: internal error: obuf_empty for ostate %d", 163ca32bd8dSchristos c->self, c->ostate); 164ca32bd8dSchristos break; 165ca32bd8dSchristos } 166ca32bd8dSchristos } 16745a1cd19Schristos 16845a1cd19Schristos void 16945a1cd19Schristos chan_rcvd_eow(struct ssh *ssh, Channel *c) 170ca32bd8dSchristos { 17145a1cd19Schristos debug2("channel %d: rcvd eow", c->self); 172ca32bd8dSchristos switch (c->istate) { 173ca32bd8dSchristos case CHAN_INPUT_OPEN: 17445a1cd19Schristos chan_shutdown_read(ssh, c); 17545a1cd19Schristos chan_set_istate(c, CHAN_INPUT_CLOSED); 176ca32bd8dSchristos break; 177ca32bd8dSchristos } 178ca32bd8dSchristos } 179ca32bd8dSchristos 180ca32bd8dSchristos static void 18145a1cd19Schristos chan_send_eof2(struct ssh *ssh, Channel *c) 18245a1cd19Schristos { 18345a1cd19Schristos int r; 18445a1cd19Schristos 18545a1cd19Schristos debug2("channel %d: send eof", c->self); 18645a1cd19Schristos switch (c->istate) { 18745a1cd19Schristos case CHAN_INPUT_WAIT_DRAIN: 18845a1cd19Schristos if (!c->have_remote_id) 18945a1cd19Schristos fatal("%s: channel %d: no remote_id", 19045a1cd19Schristos __func__, c->self); 19145a1cd19Schristos if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EOF)) != 0 || 19245a1cd19Schristos (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 19345a1cd19Schristos (r = sshpkt_send(ssh)) != 0) 19445a1cd19Schristos fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r)); 19545a1cd19Schristos c->flags |= CHAN_EOF_SENT; 19645a1cd19Schristos break; 19745a1cd19Schristos default: 19845a1cd19Schristos error("channel %d: cannot send eof for istate %d", 19945a1cd19Schristos c->self, c->istate); 20045a1cd19Schristos break; 20145a1cd19Schristos } 20245a1cd19Schristos } 20345a1cd19Schristos 20445a1cd19Schristos static void 20545a1cd19Schristos chan_send_close2(struct ssh *ssh, Channel *c) 20645a1cd19Schristos { 20745a1cd19Schristos int r; 20845a1cd19Schristos 20945a1cd19Schristos debug2("channel %d: send close", c->self); 21045a1cd19Schristos if (c->ostate != CHAN_OUTPUT_CLOSED || 21145a1cd19Schristos c->istate != CHAN_INPUT_CLOSED) { 21245a1cd19Schristos error("channel %d: cannot send close for istate/ostate %d/%d", 21345a1cd19Schristos c->self, c->istate, c->ostate); 21445a1cd19Schristos } else if (c->flags & CHAN_CLOSE_SENT) { 21545a1cd19Schristos error("channel %d: already sent close", c->self); 21645a1cd19Schristos } else { 21745a1cd19Schristos if (!c->have_remote_id) 21845a1cd19Schristos fatal("%s: channel %d: no remote_id", 21945a1cd19Schristos __func__, c->self); 22045a1cd19Schristos if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_CLOSE)) != 0 || 22145a1cd19Schristos (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 22245a1cd19Schristos (r = sshpkt_send(ssh)) != 0) 22345a1cd19Schristos fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r)); 22445a1cd19Schristos c->flags |= CHAN_CLOSE_SENT; 22545a1cd19Schristos } 22645a1cd19Schristos } 22745a1cd19Schristos 22845a1cd19Schristos static void 22945a1cd19Schristos chan_send_eow2(struct ssh *ssh, Channel *c) 23045a1cd19Schristos { 23145a1cd19Schristos int r; 23245a1cd19Schristos 23345a1cd19Schristos debug2("channel %d: send eow", c->self); 23445a1cd19Schristos if (c->ostate == CHAN_OUTPUT_CLOSED) { 23545a1cd19Schristos error("channel %d: must not sent eow on closed output", 23645a1cd19Schristos c->self); 23745a1cd19Schristos return; 23845a1cd19Schristos } 23945a1cd19Schristos if (!(datafellows & SSH_NEW_OPENSSH)) 24045a1cd19Schristos return; 24145a1cd19Schristos if (!c->have_remote_id) 24245a1cd19Schristos fatal("%s: channel %d: no remote_id", __func__, c->self); 24345a1cd19Schristos if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 || 24445a1cd19Schristos (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 24545a1cd19Schristos (r = sshpkt_put_cstring(ssh, "eow@openssh.com")) != 0 || 24645a1cd19Schristos (r = sshpkt_put_u8(ssh, 0)) != 0 || 24745a1cd19Schristos (r = sshpkt_send(ssh)) != 0) 24845a1cd19Schristos fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r)); 24945a1cd19Schristos } 25045a1cd19Schristos 25145a1cd19Schristos /* shared */ 25245a1cd19Schristos 25345a1cd19Schristos void 25445a1cd19Schristos chan_rcvd_ieof(struct ssh *ssh, Channel *c) 25545a1cd19Schristos { 25645a1cd19Schristos debug2("channel %d: rcvd eof", c->self); 25745a1cd19Schristos c->flags |= CHAN_EOF_RCVD; 25845a1cd19Schristos if (c->ostate == CHAN_OUTPUT_OPEN) 25945a1cd19Schristos chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 26045a1cd19Schristos if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && 26145a1cd19Schristos sshbuf_len(c->output) == 0 && 26245a1cd19Schristos !CHANNEL_EFD_OUTPUT_ACTIVE(c)) 26345a1cd19Schristos chan_obuf_empty(ssh, c); 26445a1cd19Schristos } 26545a1cd19Schristos 26645a1cd19Schristos void 26745a1cd19Schristos chan_rcvd_oclose(struct ssh *ssh, Channel *c) 268ca32bd8dSchristos { 269ca32bd8dSchristos debug2("channel %d: rcvd close", c->self); 27034b27b53Sadam if (!(c->flags & CHAN_LOCAL)) { 271ca32bd8dSchristos if (c->flags & CHAN_CLOSE_RCVD) 27234b27b53Sadam error("channel %d: protocol error: close rcvd twice", 27334b27b53Sadam c->self); 274ca32bd8dSchristos c->flags |= CHAN_CLOSE_RCVD; 27534b27b53Sadam } 276ca32bd8dSchristos if (c->type == SSH_CHANNEL_LARVAL) { 277ca32bd8dSchristos /* tear down larval channels immediately */ 278ca32bd8dSchristos chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 279ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_CLOSED); 280ca32bd8dSchristos return; 281ca32bd8dSchristos } 282ca32bd8dSchristos switch (c->ostate) { 283ca32bd8dSchristos case CHAN_OUTPUT_OPEN: 284ca32bd8dSchristos /* 285ca32bd8dSchristos * wait until a data from the channel is consumed if a CLOSE 286ca32bd8dSchristos * is received 287ca32bd8dSchristos */ 288ca32bd8dSchristos chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 289ca32bd8dSchristos break; 290ca32bd8dSchristos } 291ca32bd8dSchristos switch (c->istate) { 292ca32bd8dSchristos case CHAN_INPUT_OPEN: 29345a1cd19Schristos chan_shutdown_read(ssh, c); 294*8f892fcaSchristos chan_shutdown_extended_read(ssh, c); 295ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_CLOSED); 296ca32bd8dSchristos break; 297ca32bd8dSchristos case CHAN_INPUT_WAIT_DRAIN: 29834b27b53Sadam if (!(c->flags & CHAN_LOCAL)) 29945a1cd19Schristos chan_send_eof2(ssh, c); 300*8f892fcaSchristos chan_shutdown_extended_read(ssh, c); 301ca32bd8dSchristos chan_set_istate(c, CHAN_INPUT_CLOSED); 302ca32bd8dSchristos break; 303ca32bd8dSchristos } 304ca32bd8dSchristos } 30534b27b53Sadam 306ca32bd8dSchristos void 30745a1cd19Schristos chan_write_failed(struct ssh *ssh, Channel *c) 308ca32bd8dSchristos { 309ca32bd8dSchristos debug2("channel %d: write failed", c->self); 310ca32bd8dSchristos switch (c->ostate) { 311ca32bd8dSchristos case CHAN_OUTPUT_OPEN: 312ca32bd8dSchristos case CHAN_OUTPUT_WAIT_DRAIN: 31345a1cd19Schristos chan_shutdown_write(ssh, c); 314ca32bd8dSchristos if (strcmp(c->ctype, "session") == 0) 31545a1cd19Schristos chan_send_eow2(ssh, c); 316ca32bd8dSchristos chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 317ca32bd8dSchristos break; 318ca32bd8dSchristos default: 319ca32bd8dSchristos error("channel %d: chan_write_failed for ostate %d", 320ca32bd8dSchristos c->self, c->ostate); 321ca32bd8dSchristos break; 322ca32bd8dSchristos } 323ca32bd8dSchristos } 324ca32bd8dSchristos 325ca32bd8dSchristos void 32645a1cd19Schristos chan_mark_dead(struct ssh *ssh, Channel *c) 327ca32bd8dSchristos { 328ca32bd8dSchristos c->type = SSH_CHANNEL_ZOMBIE; 329ca32bd8dSchristos } 330ca32bd8dSchristos 331ca32bd8dSchristos int 33245a1cd19Schristos chan_is_dead(struct ssh *ssh, Channel *c, int do_send) 333ca32bd8dSchristos { 334ca32bd8dSchristos if (c->type == SSH_CHANNEL_ZOMBIE) { 335ca32bd8dSchristos debug2("channel %d: zombie", c->self); 336ca32bd8dSchristos return 1; 337ca32bd8dSchristos } 338ca32bd8dSchristos if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) 339ca32bd8dSchristos return 0; 340ca32bd8dSchristos if ((datafellows & SSH_BUG_EXTEOF) && 341ca32bd8dSchristos c->extended_usage == CHAN_EXTENDED_WRITE && 342ca32bd8dSchristos c->efd != -1 && 34345a1cd19Schristos sshbuf_len(c->extended) > 0) { 34445a1cd19Schristos debug2("channel %d: active efd: %d len %zu", 34545a1cd19Schristos c->self, c->efd, sshbuf_len(c->extended)); 346ca32bd8dSchristos return 0; 347ca32bd8dSchristos } 34834b27b53Sadam if (c->flags & CHAN_LOCAL) { 34934b27b53Sadam debug2("channel %d: is dead (local)", c->self); 35034b27b53Sadam return 1; 35134b27b53Sadam } 352ca32bd8dSchristos if (!(c->flags & CHAN_CLOSE_SENT)) { 353ca32bd8dSchristos if (do_send) { 35445a1cd19Schristos chan_send_close2(ssh, c); 355ca32bd8dSchristos } else { 356ca32bd8dSchristos /* channel would be dead if we sent a close */ 357ca32bd8dSchristos if (c->flags & CHAN_CLOSE_RCVD) { 358ca32bd8dSchristos debug2("channel %d: almost dead", 359ca32bd8dSchristos c->self); 360ca32bd8dSchristos return 1; 361ca32bd8dSchristos } 362ca32bd8dSchristos } 363ca32bd8dSchristos } 364ca32bd8dSchristos if ((c->flags & CHAN_CLOSE_SENT) && 365ca32bd8dSchristos (c->flags & CHAN_CLOSE_RCVD)) { 366ca32bd8dSchristos debug2("channel %d: is dead", c->self); 367ca32bd8dSchristos return 1; 368ca32bd8dSchristos } 369ca32bd8dSchristos return 0; 370ca32bd8dSchristos } 371ca32bd8dSchristos 372ca32bd8dSchristos /* helper */ 373ca32bd8dSchristos static void 37445a1cd19Schristos chan_shutdown_write(struct ssh *ssh, Channel *c) 375ca32bd8dSchristos { 37645a1cd19Schristos sshbuf_reset(c->output); 37745a1cd19Schristos if (c->type == SSH_CHANNEL_LARVAL) 378ca32bd8dSchristos return; 379ca32bd8dSchristos /* shutdown failure is allowed if write failed already */ 380*8f892fcaSchristos debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])", 381*8f892fcaSchristos c->self, __func__, c->istate, c->ostate, c->sock, c->wfd, c->efd, 382*8f892fcaSchristos channel_format_extended_usage(c)); 383ca32bd8dSchristos if (c->sock != -1) { 384*8f892fcaSchristos if (shutdown(c->sock, SHUT_WR) < 0) { 385*8f892fcaSchristos debug2("channel %d: %s: shutdown() failed for " 386*8f892fcaSchristos "fd %d [i%d o%d]: %.100s", c->self, __func__, 387*8f892fcaSchristos c->sock, c->istate, c->ostate, 388*8f892fcaSchristos strerror(errno)); 389*8f892fcaSchristos } 390ca32bd8dSchristos } else { 391*8f892fcaSchristos if (channel_close_fd(ssh, &c->wfd) < 0) { 392*8f892fcaSchristos logit("channel %d: %s: close() failed for " 393*8f892fcaSchristos "fd %d [i%d o%d]: %.100s", 394*8f892fcaSchristos c->self, __func__, c->wfd, c->istate, c->ostate, 395*8f892fcaSchristos strerror(errno)); 396*8f892fcaSchristos } 397ca32bd8dSchristos } 398ca32bd8dSchristos } 39945a1cd19Schristos 400ca32bd8dSchristos static void 40145a1cd19Schristos chan_shutdown_read(struct ssh *ssh, Channel *c) 402ca32bd8dSchristos { 40345a1cd19Schristos if (c->type == SSH_CHANNEL_LARVAL) 404ca32bd8dSchristos return; 405*8f892fcaSchristos debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])", 406*8f892fcaSchristos c->self, __func__, c->istate, c->ostate, c->sock, c->rfd, c->efd, 407*8f892fcaSchristos channel_format_extended_usage(c)); 408ca32bd8dSchristos if (c->sock != -1) { 409*8f892fcaSchristos if (shutdown(c->sock, SHUT_RD) < 0) { 410*8f892fcaSchristos error("channel %d: %s: shutdown() failed for " 411*8f892fcaSchristos "fd %d [i%d o%d]: %.100s", 412*8f892fcaSchristos c->self, __func__, c->sock, c->istate, c->ostate, 413ca32bd8dSchristos strerror(errno)); 414*8f892fcaSchristos } 415ca32bd8dSchristos } else { 416*8f892fcaSchristos if (channel_close_fd(ssh, &c->rfd) < 0) { 417*8f892fcaSchristos logit("channel %d: %s: close() failed for " 418*8f892fcaSchristos "fd %d [i%d o%d]: %.100s", 419*8f892fcaSchristos c->self, __func__, c->rfd, c->istate, c->ostate, 420*8f892fcaSchristos strerror(errno)); 421*8f892fcaSchristos } 422*8f892fcaSchristos } 423*8f892fcaSchristos } 424*8f892fcaSchristos 425*8f892fcaSchristos static void 426*8f892fcaSchristos chan_shutdown_extended_read(struct ssh *ssh, Channel *c) 427*8f892fcaSchristos { 428*8f892fcaSchristos if (c->type == SSH_CHANNEL_LARVAL || c->efd == -1) 429*8f892fcaSchristos return; 430*8f892fcaSchristos if (c->extended_usage != CHAN_EXTENDED_READ && 431*8f892fcaSchristos c->extended_usage != CHAN_EXTENDED_IGNORE) 432*8f892fcaSchristos return; 433*8f892fcaSchristos debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])", 434*8f892fcaSchristos c->self, __func__, c->istate, c->ostate, c->sock, c->rfd, c->efd, 435*8f892fcaSchristos channel_format_extended_usage(c)); 436*8f892fcaSchristos if (channel_close_fd(ssh, &c->efd) < 0) { 437*8f892fcaSchristos logit("channel %d: %s: close() failed for " 438*8f892fcaSchristos "extended fd %d [i%d o%d]: %.100s", 439*8f892fcaSchristos c->self, __func__, c->efd, c->istate, c->ostate, 440*8f892fcaSchristos strerror(errno)); 441ca32bd8dSchristos } 442ca32bd8dSchristos } 443