1*2f513db7SEd Maste /* $OpenBSD: nchan.c,v 1.69 2018/10/04 07:47:35 djm Exp $ */ 2511b41d2SMark Murray /* 3ae1f160dSDag-Erling Smørgrav * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 4511b41d2SMark Murray * 5511b41d2SMark Murray * Redistribution and use in source and binary forms, with or without 6511b41d2SMark Murray * modification, are permitted provided that the following conditions 7511b41d2SMark Murray * are met: 8511b41d2SMark Murray * 1. Redistributions of source code must retain the above copyright 9511b41d2SMark Murray * notice, this list of conditions and the following disclaimer. 10511b41d2SMark Murray * 2. Redistributions in binary form must reproduce the above copyright 11511b41d2SMark Murray * notice, this list of conditions and the following disclaimer in the 12511b41d2SMark Murray * documentation and/or other materials provided with the distribution. 13511b41d2SMark Murray * 14511b41d2SMark Murray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15511b41d2SMark Murray * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16511b41d2SMark Murray * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17511b41d2SMark Murray * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18511b41d2SMark Murray * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19511b41d2SMark Murray * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20511b41d2SMark Murray * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21511b41d2SMark Murray * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22511b41d2SMark Murray * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23511b41d2SMark Murray * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24511b41d2SMark Murray */ 25511b41d2SMark Murray 26511b41d2SMark Murray #include "includes.h" 27761efaa7SDag-Erling Smørgrav 28761efaa7SDag-Erling Smørgrav #include <sys/types.h> 29761efaa7SDag-Erling Smørgrav #include <sys/socket.h> 30761efaa7SDag-Erling Smørgrav 31761efaa7SDag-Erling Smørgrav #include <errno.h> 32761efaa7SDag-Erling Smørgrav #include <string.h> 33761efaa7SDag-Erling Smørgrav #include <stdarg.h> 34511b41d2SMark Murray 35d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h" 361e8db6e2SBrian Feldman #include "ssh2.h" 374f52dfbbSDag-Erling Smørgrav #include "sshbuf.h" 384f52dfbbSDag-Erling Smørgrav #include "ssherr.h" 39511b41d2SMark Murray #include "packet.h" 40511b41d2SMark Murray #include "channels.h" 41a04a10f8SKris Kennaway #include "compat.h" 421e8db6e2SBrian Feldman #include "log.h" 43511b41d2SMark Murray 44ae1f160dSDag-Erling Smørgrav /* 45ae1f160dSDag-Erling Smørgrav * SSH Protocol 1.5 aka New Channel Protocol 46ae1f160dSDag-Erling Smørgrav * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. 47ae1f160dSDag-Erling Smørgrav * Written by Markus Friedl in October 1999 48ae1f160dSDag-Erling Smørgrav * 49ae1f160dSDag-Erling Smørgrav * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the 50ae1f160dSDag-Erling Smørgrav * tear down of channels: 51ae1f160dSDag-Erling Smørgrav * 52ae1f160dSDag-Erling Smørgrav * 1.3: strict request-ack-protocol: 53ae1f160dSDag-Erling Smørgrav * CLOSE -> 54ae1f160dSDag-Erling Smørgrav * <- CLOSE_CONFIRM 55ae1f160dSDag-Erling Smørgrav * 56ae1f160dSDag-Erling Smørgrav * 1.5: uses variations of: 57ae1f160dSDag-Erling Smørgrav * IEOF -> 58ae1f160dSDag-Erling Smørgrav * <- OCLOSE 59ae1f160dSDag-Erling Smørgrav * <- IEOF 60ae1f160dSDag-Erling Smørgrav * OCLOSE -> 61ae1f160dSDag-Erling Smørgrav * i.e. both sides have to close the channel 62ae1f160dSDag-Erling Smørgrav * 63ae1f160dSDag-Erling Smørgrav * 2.0: the EOF messages are optional 64ae1f160dSDag-Erling Smørgrav * 65ae1f160dSDag-Erling Smørgrav * See the debugging output from 'ssh -v' and 'sshd -d' of 66ae1f160dSDag-Erling Smørgrav * ssh-1.2.27 as an example. 67ae1f160dSDag-Erling Smørgrav * 68ae1f160dSDag-Erling Smørgrav */ 69ae1f160dSDag-Erling Smørgrav 70a04a10f8SKris Kennaway /* functions manipulating channel states */ 71511b41d2SMark Murray /* 72511b41d2SMark Murray * EVENTS update channel input/output states execute ACTIONS 73511b41d2SMark Murray */ 74a04a10f8SKris Kennaway /* 75a04a10f8SKris Kennaway * ACTIONS: should never update the channel states 76a04a10f8SKris Kennaway */ 774f52dfbbSDag-Erling Smørgrav static void chan_send_eof2(struct ssh *, Channel *); 784f52dfbbSDag-Erling Smørgrav static void chan_send_eow2(struct ssh *, Channel *); 79a04a10f8SKris Kennaway 80a04a10f8SKris Kennaway /* helper */ 814f52dfbbSDag-Erling Smørgrav static void chan_shutdown_write(struct ssh *, Channel *); 824f52dfbbSDag-Erling Smørgrav static void chan_shutdown_read(struct ssh *, Channel *); 83*2f513db7SEd Maste static void chan_shutdown_extended_read(struct ssh *, Channel *); 84ae1f160dSDag-Erling Smørgrav 854f52dfbbSDag-Erling Smørgrav static const char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; 864f52dfbbSDag-Erling Smørgrav static const char *istates[] = { "open", "drain", "wait_oclose", "closed" }; 87ae1f160dSDag-Erling Smørgrav 88ae1f160dSDag-Erling Smørgrav static void 89ae1f160dSDag-Erling Smørgrav chan_set_istate(Channel *c, u_int next) 90ae1f160dSDag-Erling Smørgrav { 91ae1f160dSDag-Erling Smørgrav if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED) 92ae1f160dSDag-Erling Smørgrav fatal("chan_set_istate: bad state %d -> %d", c->istate, next); 93d95e11bfSDag-Erling Smørgrav debug2("channel %d: input %s -> %s", c->self, istates[c->istate], 94ae1f160dSDag-Erling Smørgrav istates[next]); 95ae1f160dSDag-Erling Smørgrav c->istate = next; 96ae1f160dSDag-Erling Smørgrav } 974f52dfbbSDag-Erling Smørgrav 98ae1f160dSDag-Erling Smørgrav static void 99ae1f160dSDag-Erling Smørgrav chan_set_ostate(Channel *c, u_int next) 100ae1f160dSDag-Erling Smørgrav { 101ae1f160dSDag-Erling Smørgrav if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED) 102ae1f160dSDag-Erling Smørgrav fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next); 103d95e11bfSDag-Erling Smørgrav debug2("channel %d: output %s -> %s", c->self, ostates[c->ostate], 104ae1f160dSDag-Erling Smørgrav ostates[next]); 105ae1f160dSDag-Erling Smørgrav c->ostate = next; 106ae1f160dSDag-Erling Smørgrav } 107a04a10f8SKris Kennaway 108ae1f160dSDag-Erling Smørgrav void 1094f52dfbbSDag-Erling Smørgrav chan_read_failed(struct ssh *ssh, Channel *c) 110511b41d2SMark Murray { 111d95e11bfSDag-Erling Smørgrav debug2("channel %d: read failed", c->self); 112511b41d2SMark Murray switch (c->istate) { 113511b41d2SMark Murray case CHAN_INPUT_OPEN: 1144f52dfbbSDag-Erling Smørgrav chan_shutdown_read(ssh, c); 115ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN); 116511b41d2SMark Murray break; 117511b41d2SMark Murray default: 118ae1f160dSDag-Erling Smørgrav error("channel %d: chan_read_failed for istate %d", 119511b41d2SMark Murray c->self, c->istate); 120511b41d2SMark Murray break; 121511b41d2SMark Murray } 122511b41d2SMark Murray } 1234f52dfbbSDag-Erling Smørgrav 124ae1f160dSDag-Erling Smørgrav void 1254f52dfbbSDag-Erling Smørgrav chan_ibuf_empty(struct ssh *ssh, Channel *c) 126511b41d2SMark Murray { 127d95e11bfSDag-Erling Smørgrav debug2("channel %d: ibuf empty", c->self); 1284f52dfbbSDag-Erling Smørgrav if (sshbuf_len(c->input)) { 129ae1f160dSDag-Erling Smørgrav error("channel %d: chan_ibuf_empty for non empty buffer", 130a04a10f8SKris Kennaway c->self); 131511b41d2SMark Murray return; 132511b41d2SMark Murray } 133511b41d2SMark Murray switch (c->istate) { 134511b41d2SMark Murray case CHAN_INPUT_WAIT_DRAIN: 135b15c8340SDag-Erling Smørgrav if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL))) 1364f52dfbbSDag-Erling Smørgrav chan_send_eof2(ssh, c); 137ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 138511b41d2SMark Murray break; 139511b41d2SMark Murray default: 140ae1f160dSDag-Erling Smørgrav error("channel %d: chan_ibuf_empty for istate %d", 141a04a10f8SKris Kennaway c->self, c->istate); 142511b41d2SMark Murray break; 143511b41d2SMark Murray } 144511b41d2SMark Murray } 1454f52dfbbSDag-Erling Smørgrav 146ae1f160dSDag-Erling Smørgrav void 1474f52dfbbSDag-Erling Smørgrav chan_obuf_empty(struct ssh *ssh, Channel *c) 148511b41d2SMark Murray { 149d95e11bfSDag-Erling Smørgrav debug2("channel %d: obuf empty", c->self); 1504f52dfbbSDag-Erling Smørgrav if (sshbuf_len(c->output)) { 151ae1f160dSDag-Erling Smørgrav error("channel %d: chan_obuf_empty for non empty buffer", 152a04a10f8SKris Kennaway c->self); 153511b41d2SMark Murray return; 154511b41d2SMark Murray } 155511b41d2SMark Murray switch (c->ostate) { 156511b41d2SMark Murray case CHAN_OUTPUT_WAIT_DRAIN: 1574f52dfbbSDag-Erling Smørgrav chan_shutdown_write(ssh, c); 158ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 159511b41d2SMark Murray break; 160511b41d2SMark Murray default: 161ae1f160dSDag-Erling Smørgrav error("channel %d: internal error: obuf_empty for ostate %d", 162a04a10f8SKris Kennaway c->self, c->ostate); 163511b41d2SMark Murray break; 164511b41d2SMark Murray } 165511b41d2SMark Murray } 1664f52dfbbSDag-Erling Smørgrav 1674f52dfbbSDag-Erling Smørgrav void 1684f52dfbbSDag-Erling Smørgrav chan_rcvd_eow(struct ssh *ssh, Channel *c) 169511b41d2SMark Murray { 1704f52dfbbSDag-Erling Smørgrav debug2("channel %d: rcvd eow", c->self); 171511b41d2SMark Murray switch (c->istate) { 172511b41d2SMark Murray case CHAN_INPUT_OPEN: 1734f52dfbbSDag-Erling Smørgrav chan_shutdown_read(ssh, c); 1744f52dfbbSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 175511b41d2SMark Murray break; 176511b41d2SMark Murray } 177511b41d2SMark Murray } 178a04a10f8SKris Kennaway 179a04a10f8SKris Kennaway static void 1804f52dfbbSDag-Erling Smørgrav chan_send_eof2(struct ssh *ssh, Channel *c) 1814f52dfbbSDag-Erling Smørgrav { 1824f52dfbbSDag-Erling Smørgrav int r; 1834f52dfbbSDag-Erling Smørgrav 1844f52dfbbSDag-Erling Smørgrav debug2("channel %d: send eof", c->self); 1854f52dfbbSDag-Erling Smørgrav switch (c->istate) { 1864f52dfbbSDag-Erling Smørgrav case CHAN_INPUT_WAIT_DRAIN: 1874f52dfbbSDag-Erling Smørgrav if (!c->have_remote_id) 1884f52dfbbSDag-Erling Smørgrav fatal("%s: channel %d: no remote_id", 1894f52dfbbSDag-Erling Smørgrav __func__, c->self); 1904f52dfbbSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EOF)) != 0 || 1914f52dfbbSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 1924f52dfbbSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 1934f52dfbbSDag-Erling Smørgrav fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r)); 1944f52dfbbSDag-Erling Smørgrav c->flags |= CHAN_EOF_SENT; 1954f52dfbbSDag-Erling Smørgrav break; 1964f52dfbbSDag-Erling Smørgrav default: 1974f52dfbbSDag-Erling Smørgrav error("channel %d: cannot send eof for istate %d", 1984f52dfbbSDag-Erling Smørgrav c->self, c->istate); 1994f52dfbbSDag-Erling Smørgrav break; 2004f52dfbbSDag-Erling Smørgrav } 2014f52dfbbSDag-Erling Smørgrav } 2024f52dfbbSDag-Erling Smørgrav 2034f52dfbbSDag-Erling Smørgrav static void 2044f52dfbbSDag-Erling Smørgrav chan_send_close2(struct ssh *ssh, Channel *c) 2054f52dfbbSDag-Erling Smørgrav { 2064f52dfbbSDag-Erling Smørgrav int r; 2074f52dfbbSDag-Erling Smørgrav 2084f52dfbbSDag-Erling Smørgrav debug2("channel %d: send close", c->self); 2094f52dfbbSDag-Erling Smørgrav if (c->ostate != CHAN_OUTPUT_CLOSED || 2104f52dfbbSDag-Erling Smørgrav c->istate != CHAN_INPUT_CLOSED) { 2114f52dfbbSDag-Erling Smørgrav error("channel %d: cannot send close for istate/ostate %d/%d", 2124f52dfbbSDag-Erling Smørgrav c->self, c->istate, c->ostate); 2134f52dfbbSDag-Erling Smørgrav } else if (c->flags & CHAN_CLOSE_SENT) { 2144f52dfbbSDag-Erling Smørgrav error("channel %d: already sent close", c->self); 2154f52dfbbSDag-Erling Smørgrav } else { 2164f52dfbbSDag-Erling Smørgrav if (!c->have_remote_id) 2174f52dfbbSDag-Erling Smørgrav fatal("%s: channel %d: no remote_id", 2184f52dfbbSDag-Erling Smørgrav __func__, c->self); 2194f52dfbbSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_CLOSE)) != 0 || 2204f52dfbbSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 2214f52dfbbSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 2224f52dfbbSDag-Erling Smørgrav fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r)); 2234f52dfbbSDag-Erling Smørgrav c->flags |= CHAN_CLOSE_SENT; 2244f52dfbbSDag-Erling Smørgrav } 2254f52dfbbSDag-Erling Smørgrav } 2264f52dfbbSDag-Erling Smørgrav 2274f52dfbbSDag-Erling Smørgrav static void 2284f52dfbbSDag-Erling Smørgrav chan_send_eow2(struct ssh *ssh, Channel *c) 2294f52dfbbSDag-Erling Smørgrav { 2304f52dfbbSDag-Erling Smørgrav int r; 2314f52dfbbSDag-Erling Smørgrav 2324f52dfbbSDag-Erling Smørgrav debug2("channel %d: send eow", c->self); 2334f52dfbbSDag-Erling Smørgrav if (c->ostate == CHAN_OUTPUT_CLOSED) { 2344f52dfbbSDag-Erling Smørgrav error("channel %d: must not sent eow on closed output", 2354f52dfbbSDag-Erling Smørgrav c->self); 2364f52dfbbSDag-Erling Smørgrav return; 2374f52dfbbSDag-Erling Smørgrav } 2384f52dfbbSDag-Erling Smørgrav if (!(datafellows & SSH_NEW_OPENSSH)) 2394f52dfbbSDag-Erling Smørgrav return; 2404f52dfbbSDag-Erling Smørgrav if (!c->have_remote_id) 2414f52dfbbSDag-Erling Smørgrav fatal("%s: channel %d: no remote_id", __func__, c->self); 2424f52dfbbSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 || 2434f52dfbbSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || 2444f52dfbbSDag-Erling Smørgrav (r = sshpkt_put_cstring(ssh, "eow@openssh.com")) != 0 || 2454f52dfbbSDag-Erling Smørgrav (r = sshpkt_put_u8(ssh, 0)) != 0 || 2464f52dfbbSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 2474f52dfbbSDag-Erling Smørgrav fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r)); 2484f52dfbbSDag-Erling Smørgrav } 2494f52dfbbSDag-Erling Smørgrav 2504f52dfbbSDag-Erling Smørgrav /* shared */ 2514f52dfbbSDag-Erling Smørgrav 2524f52dfbbSDag-Erling Smørgrav void 2534f52dfbbSDag-Erling Smørgrav chan_rcvd_ieof(struct ssh *ssh, Channel *c) 2544f52dfbbSDag-Erling Smørgrav { 2554f52dfbbSDag-Erling Smørgrav debug2("channel %d: rcvd eof", c->self); 2564f52dfbbSDag-Erling Smørgrav c->flags |= CHAN_EOF_RCVD; 2574f52dfbbSDag-Erling Smørgrav if (c->ostate == CHAN_OUTPUT_OPEN) 2584f52dfbbSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 2594f52dfbbSDag-Erling Smørgrav if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && 2604f52dfbbSDag-Erling Smørgrav sshbuf_len(c->output) == 0 && 2614f52dfbbSDag-Erling Smørgrav !CHANNEL_EFD_OUTPUT_ACTIVE(c)) 2624f52dfbbSDag-Erling Smørgrav chan_obuf_empty(ssh, c); 2634f52dfbbSDag-Erling Smørgrav } 2644f52dfbbSDag-Erling Smørgrav 2654f52dfbbSDag-Erling Smørgrav void 2664f52dfbbSDag-Erling Smørgrav chan_rcvd_oclose(struct ssh *ssh, Channel *c) 267a04a10f8SKris Kennaway { 268d95e11bfSDag-Erling Smørgrav debug2("channel %d: rcvd close", c->self); 269b15c8340SDag-Erling Smørgrav if (!(c->flags & CHAN_LOCAL)) { 270a04a10f8SKris Kennaway if (c->flags & CHAN_CLOSE_RCVD) 271b15c8340SDag-Erling Smørgrav error("channel %d: protocol error: close rcvd twice", 272b15c8340SDag-Erling Smørgrav c->self); 273a04a10f8SKris Kennaway c->flags |= CHAN_CLOSE_RCVD; 274b15c8340SDag-Erling Smørgrav } 275a04a10f8SKris Kennaway if (c->type == SSH_CHANNEL_LARVAL) { 276a04a10f8SKris Kennaway /* tear down larval channels immediately */ 277ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 278ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 279a04a10f8SKris Kennaway return; 280a04a10f8SKris Kennaway } 281a04a10f8SKris Kennaway switch (c->ostate) { 282a04a10f8SKris Kennaway case CHAN_OUTPUT_OPEN: 283ae1f160dSDag-Erling Smørgrav /* 284ae1f160dSDag-Erling Smørgrav * wait until a data from the channel is consumed if a CLOSE 285ae1f160dSDag-Erling Smørgrav * is received 286ae1f160dSDag-Erling Smørgrav */ 287ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 288a04a10f8SKris Kennaway break; 289a04a10f8SKris Kennaway } 290a04a10f8SKris Kennaway switch (c->istate) { 291a04a10f8SKris Kennaway case CHAN_INPUT_OPEN: 2924f52dfbbSDag-Erling Smørgrav chan_shutdown_read(ssh, c); 293*2f513db7SEd Maste chan_shutdown_extended_read(ssh, c); 294ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 295a04a10f8SKris Kennaway break; 296a04a10f8SKris Kennaway case CHAN_INPUT_WAIT_DRAIN: 297b15c8340SDag-Erling Smørgrav if (!(c->flags & CHAN_LOCAL)) 2984f52dfbbSDag-Erling Smørgrav chan_send_eof2(ssh, c); 299*2f513db7SEd Maste chan_shutdown_extended_read(ssh, c); 300ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 301a04a10f8SKris Kennaway break; 302a04a10f8SKris Kennaway } 303a04a10f8SKris Kennaway } 304b15c8340SDag-Erling Smørgrav 305d4af9e69SDag-Erling Smørgrav void 3064f52dfbbSDag-Erling Smørgrav chan_write_failed(struct ssh *ssh, Channel *c) 307a04a10f8SKris Kennaway { 308d95e11bfSDag-Erling Smørgrav debug2("channel %d: write failed", c->self); 309a04a10f8SKris Kennaway switch (c->ostate) { 310a04a10f8SKris Kennaway case CHAN_OUTPUT_OPEN: 311a04a10f8SKris Kennaway case CHAN_OUTPUT_WAIT_DRAIN: 3124f52dfbbSDag-Erling Smørgrav chan_shutdown_write(ssh, c); 313d4af9e69SDag-Erling Smørgrav if (strcmp(c->ctype, "session") == 0) 3144f52dfbbSDag-Erling Smørgrav chan_send_eow2(ssh, c); 315ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 316a04a10f8SKris Kennaway break; 317a04a10f8SKris Kennaway default: 318ae1f160dSDag-Erling Smørgrav error("channel %d: chan_write_failed for ostate %d", 319a04a10f8SKris Kennaway c->self, c->ostate); 320a04a10f8SKris Kennaway break; 321a04a10f8SKris Kennaway } 322a04a10f8SKris Kennaway } 3231e8db6e2SBrian Feldman 324ae1f160dSDag-Erling Smørgrav void 3254f52dfbbSDag-Erling Smørgrav chan_mark_dead(struct ssh *ssh, Channel *c) 326ae1f160dSDag-Erling Smørgrav { 327ae1f160dSDag-Erling Smørgrav c->type = SSH_CHANNEL_ZOMBIE; 328ae1f160dSDag-Erling Smørgrav } 329ae1f160dSDag-Erling Smørgrav 330ae1f160dSDag-Erling Smørgrav int 3314f52dfbbSDag-Erling Smørgrav chan_is_dead(struct ssh *ssh, Channel *c, int do_send) 332ae1f160dSDag-Erling Smørgrav { 333ae1f160dSDag-Erling Smørgrav if (c->type == SSH_CHANNEL_ZOMBIE) { 334d95e11bfSDag-Erling Smørgrav debug2("channel %d: zombie", c->self); 335ae1f160dSDag-Erling Smørgrav return 1; 336ae1f160dSDag-Erling Smørgrav } 3371e8db6e2SBrian Feldman if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) 3381e8db6e2SBrian Feldman return 0; 339545d5ecaSDag-Erling Smørgrav if ((datafellows & SSH_BUG_EXTEOF) && 340545d5ecaSDag-Erling Smørgrav c->extended_usage == CHAN_EXTENDED_WRITE && 341545d5ecaSDag-Erling Smørgrav c->efd != -1 && 3424f52dfbbSDag-Erling Smørgrav sshbuf_len(c->extended) > 0) { 3434f52dfbbSDag-Erling Smørgrav debug2("channel %d: active efd: %d len %zu", 3444f52dfbbSDag-Erling Smørgrav c->self, c->efd, sshbuf_len(c->extended)); 345545d5ecaSDag-Erling Smørgrav return 0; 346545d5ecaSDag-Erling Smørgrav } 347b15c8340SDag-Erling Smørgrav if (c->flags & CHAN_LOCAL) { 348b15c8340SDag-Erling Smørgrav debug2("channel %d: is dead (local)", c->self); 349b15c8340SDag-Erling Smørgrav return 1; 350b15c8340SDag-Erling Smørgrav } 351a04a10f8SKris Kennaway if (!(c->flags & CHAN_CLOSE_SENT)) { 352d74d50a8SDag-Erling Smørgrav if (do_send) { 3534f52dfbbSDag-Erling Smørgrav chan_send_close2(ssh, c); 354ae1f160dSDag-Erling Smørgrav } else { 355ae1f160dSDag-Erling Smørgrav /* channel would be dead if we sent a close */ 356ae1f160dSDag-Erling Smørgrav if (c->flags & CHAN_CLOSE_RCVD) { 357d95e11bfSDag-Erling Smørgrav debug2("channel %d: almost dead", 358ae1f160dSDag-Erling Smørgrav c->self); 359ae1f160dSDag-Erling Smørgrav return 1; 360ae1f160dSDag-Erling Smørgrav } 361ae1f160dSDag-Erling Smørgrav } 362a04a10f8SKris Kennaway } 363a04a10f8SKris Kennaway if ((c->flags & CHAN_CLOSE_SENT) && 364a04a10f8SKris Kennaway (c->flags & CHAN_CLOSE_RCVD)) { 365d95e11bfSDag-Erling Smørgrav debug2("channel %d: is dead", c->self); 3661e8db6e2SBrian Feldman return 1; 367a04a10f8SKris Kennaway } 3681e8db6e2SBrian Feldman return 0; 369a04a10f8SKris Kennaway } 370a04a10f8SKris Kennaway 371511b41d2SMark Murray /* helper */ 372511b41d2SMark Murray static void 3734f52dfbbSDag-Erling Smørgrav chan_shutdown_write(struct ssh *ssh, Channel *c) 374511b41d2SMark Murray { 3754f52dfbbSDag-Erling Smørgrav sshbuf_reset(c->output); 3764f52dfbbSDag-Erling Smørgrav if (c->type == SSH_CHANNEL_LARVAL) 377a04a10f8SKris Kennaway return; 378511b41d2SMark Murray /* shutdown failure is allowed if write failed already */ 379*2f513db7SEd Maste debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])", 380*2f513db7SEd Maste c->self, __func__, c->istate, c->ostate, c->sock, c->wfd, c->efd, 381*2f513db7SEd Maste channel_format_extended_usage(c)); 382a04a10f8SKris Kennaway if (c->sock != -1) { 383*2f513db7SEd Maste if (shutdown(c->sock, SHUT_WR) < 0) { 384*2f513db7SEd Maste debug2("channel %d: %s: shutdown() failed for " 385*2f513db7SEd Maste "fd %d [i%d o%d]: %.100s", c->self, __func__, 386*2f513db7SEd Maste c->sock, c->istate, c->ostate, 387*2f513db7SEd Maste strerror(errno)); 388*2f513db7SEd Maste } 389a04a10f8SKris Kennaway } else { 390*2f513db7SEd Maste if (channel_close_fd(ssh, &c->wfd) < 0) { 391*2f513db7SEd Maste logit("channel %d: %s: close() failed for " 392*2f513db7SEd Maste "fd %d [i%d o%d]: %.100s", 393*2f513db7SEd Maste c->self, __func__, c->wfd, c->istate, c->ostate, 394*2f513db7SEd Maste strerror(errno)); 395*2f513db7SEd Maste } 396a04a10f8SKris Kennaway } 397511b41d2SMark Murray } 3984f52dfbbSDag-Erling Smørgrav 399511b41d2SMark Murray static void 4004f52dfbbSDag-Erling Smørgrav chan_shutdown_read(struct ssh *ssh, Channel *c) 401511b41d2SMark Murray { 4024f52dfbbSDag-Erling Smørgrav if (c->type == SSH_CHANNEL_LARVAL) 403a04a10f8SKris Kennaway return; 404*2f513db7SEd Maste debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])", 405*2f513db7SEd Maste c->self, __func__, c->istate, c->ostate, c->sock, c->rfd, c->efd, 406*2f513db7SEd Maste channel_format_extended_usage(c)); 407a04a10f8SKris Kennaway if (c->sock != -1) { 40883d2307dSDag-Erling Smørgrav /* 40983d2307dSDag-Erling Smørgrav * shutdown(sock, SHUT_READ) may return ENOTCONN if the 41083d2307dSDag-Erling Smørgrav * write side has been closed already. (bug on Linux) 41183d2307dSDag-Erling Smørgrav * HP-UX may return ENOTCONN also. 41283d2307dSDag-Erling Smørgrav */ 413*2f513db7SEd Maste if (shutdown(c->sock, SHUT_RD) < 0 && errno != ENOTCONN) { 414*2f513db7SEd Maste error("channel %d: %s: shutdown() failed for " 415*2f513db7SEd Maste "fd %d [i%d o%d]: %.100s", 416*2f513db7SEd Maste c->self, __func__, c->sock, c->istate, c->ostate, 417ae1f160dSDag-Erling Smørgrav strerror(errno)); 418*2f513db7SEd Maste } 419a04a10f8SKris Kennaway } else { 420*2f513db7SEd Maste if (channel_close_fd(ssh, &c->rfd) < 0) { 421*2f513db7SEd Maste logit("channel %d: %s: close() failed for " 422*2f513db7SEd Maste "fd %d [i%d o%d]: %.100s", 423*2f513db7SEd Maste c->self, __func__, c->rfd, c->istate, c->ostate, 424*2f513db7SEd Maste strerror(errno)); 425*2f513db7SEd Maste } 426*2f513db7SEd Maste } 427*2f513db7SEd Maste } 428*2f513db7SEd Maste 429*2f513db7SEd Maste static void 430*2f513db7SEd Maste chan_shutdown_extended_read(struct ssh *ssh, Channel *c) 431*2f513db7SEd Maste { 432*2f513db7SEd Maste if (c->type == SSH_CHANNEL_LARVAL || c->efd == -1) 433*2f513db7SEd Maste return; 434*2f513db7SEd Maste if (c->extended_usage != CHAN_EXTENDED_READ && 435*2f513db7SEd Maste c->extended_usage != CHAN_EXTENDED_IGNORE) 436*2f513db7SEd Maste return; 437*2f513db7SEd Maste debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])", 438*2f513db7SEd Maste c->self, __func__, c->istate, c->ostate, c->sock, c->rfd, c->efd, 439*2f513db7SEd Maste channel_format_extended_usage(c)); 440*2f513db7SEd Maste if (channel_close_fd(ssh, &c->efd) < 0) { 441*2f513db7SEd Maste logit("channel %d: %s: close() failed for " 442*2f513db7SEd Maste "extended fd %d [i%d o%d]: %.100s", 443*2f513db7SEd Maste c->self, __func__, c->efd, c->istate, c->ostate, 444*2f513db7SEd Maste strerror(errno)); 445511b41d2SMark Murray } 446511b41d2SMark Murray } 447