1511b41d2SMark Murray /* 2ae1f160dSDag-Erling Smørgrav * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 3511b41d2SMark Murray * 4511b41d2SMark Murray * Redistribution and use in source and binary forms, with or without 5511b41d2SMark Murray * modification, are permitted provided that the following conditions 6511b41d2SMark Murray * are met: 7511b41d2SMark Murray * 1. Redistributions of source code must retain the above copyright 8511b41d2SMark Murray * notice, this list of conditions and the following disclaimer. 9511b41d2SMark Murray * 2. Redistributions in binary form must reproduce the above copyright 10511b41d2SMark Murray * notice, this list of conditions and the following disclaimer in the 11511b41d2SMark Murray * documentation and/or other materials provided with the distribution. 12511b41d2SMark Murray * 13511b41d2SMark Murray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14511b41d2SMark Murray * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15511b41d2SMark Murray * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16511b41d2SMark Murray * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17511b41d2SMark Murray * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18511b41d2SMark Murray * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19511b41d2SMark Murray * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20511b41d2SMark Murray * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21511b41d2SMark Murray * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22511b41d2SMark Murray * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23511b41d2SMark Murray */ 24511b41d2SMark Murray 25511b41d2SMark Murray #include "includes.h" 26545d5ecaSDag-Erling Smørgrav RCSID("$OpenBSD: nchan.c,v 1.47 2002/06/19 00:27:55 deraadt Exp $"); 27511b41d2SMark Murray 281e8db6e2SBrian Feldman #include "ssh1.h" 291e8db6e2SBrian Feldman #include "ssh2.h" 30511b41d2SMark Murray #include "buffer.h" 31511b41d2SMark Murray #include "packet.h" 32511b41d2SMark Murray #include "channels.h" 33a04a10f8SKris Kennaway #include "compat.h" 341e8db6e2SBrian Feldman #include "log.h" 35511b41d2SMark Murray 36ae1f160dSDag-Erling Smørgrav /* 37ae1f160dSDag-Erling Smørgrav * SSH Protocol 1.5 aka New Channel Protocol 38ae1f160dSDag-Erling Smørgrav * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. 39ae1f160dSDag-Erling Smørgrav * Written by Markus Friedl in October 1999 40ae1f160dSDag-Erling Smørgrav * 41ae1f160dSDag-Erling Smørgrav * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the 42ae1f160dSDag-Erling Smørgrav * tear down of channels: 43ae1f160dSDag-Erling Smørgrav * 44ae1f160dSDag-Erling Smørgrav * 1.3: strict request-ack-protocol: 45ae1f160dSDag-Erling Smørgrav * CLOSE -> 46ae1f160dSDag-Erling Smørgrav * <- CLOSE_CONFIRM 47ae1f160dSDag-Erling Smørgrav * 48ae1f160dSDag-Erling Smørgrav * 1.5: uses variations of: 49ae1f160dSDag-Erling Smørgrav * IEOF -> 50ae1f160dSDag-Erling Smørgrav * <- OCLOSE 51ae1f160dSDag-Erling Smørgrav * <- IEOF 52ae1f160dSDag-Erling Smørgrav * OCLOSE -> 53ae1f160dSDag-Erling Smørgrav * i.e. both sides have to close the channel 54ae1f160dSDag-Erling Smørgrav * 55ae1f160dSDag-Erling Smørgrav * 2.0: the EOF messages are optional 56ae1f160dSDag-Erling Smørgrav * 57ae1f160dSDag-Erling Smørgrav * See the debugging output from 'ssh -v' and 'sshd -d' of 58ae1f160dSDag-Erling Smørgrav * ssh-1.2.27 as an example. 59ae1f160dSDag-Erling Smørgrav * 60ae1f160dSDag-Erling Smørgrav */ 61ae1f160dSDag-Erling Smørgrav 62a04a10f8SKris Kennaway /* functions manipulating channel states */ 63511b41d2SMark Murray /* 64511b41d2SMark Murray * EVENTS update channel input/output states execute ACTIONS 65511b41d2SMark Murray */ 66a04a10f8SKris Kennaway /* 67a04a10f8SKris Kennaway * ACTIONS: should never update the channel states 68a04a10f8SKris Kennaway */ 69ae1f160dSDag-Erling Smørgrav static void chan_send_ieof1(Channel *); 70ae1f160dSDag-Erling Smørgrav static void chan_send_oclose1(Channel *); 71ae1f160dSDag-Erling Smørgrav static void chan_send_close2(Channel *); 72ae1f160dSDag-Erling Smørgrav static void chan_send_eof2(Channel *); 73a04a10f8SKris Kennaway 74a04a10f8SKris Kennaway /* helper */ 75ae1f160dSDag-Erling Smørgrav static void chan_shutdown_write(Channel *); 76ae1f160dSDag-Erling Smørgrav static void chan_shutdown_read(Channel *); 77ae1f160dSDag-Erling Smørgrav 78ae1f160dSDag-Erling Smørgrav static char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; 79ae1f160dSDag-Erling Smørgrav static char *istates[] = { "open", "drain", "wait_oclose", "closed" }; 80ae1f160dSDag-Erling Smørgrav 81ae1f160dSDag-Erling Smørgrav static void 82ae1f160dSDag-Erling Smørgrav chan_set_istate(Channel *c, u_int next) 83ae1f160dSDag-Erling Smørgrav { 84ae1f160dSDag-Erling Smørgrav if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED) 85ae1f160dSDag-Erling Smørgrav fatal("chan_set_istate: bad state %d -> %d", c->istate, next); 86ae1f160dSDag-Erling Smørgrav debug("channel %d: input %s -> %s", c->self, istates[c->istate], 87ae1f160dSDag-Erling Smørgrav istates[next]); 88ae1f160dSDag-Erling Smørgrav c->istate = next; 89ae1f160dSDag-Erling Smørgrav } 90ae1f160dSDag-Erling Smørgrav static void 91ae1f160dSDag-Erling Smørgrav chan_set_ostate(Channel *c, u_int next) 92ae1f160dSDag-Erling Smørgrav { 93ae1f160dSDag-Erling Smørgrav if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED) 94ae1f160dSDag-Erling Smørgrav fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next); 95ae1f160dSDag-Erling Smørgrav debug("channel %d: output %s -> %s", c->self, ostates[c->ostate], 96ae1f160dSDag-Erling Smørgrav ostates[next]); 97ae1f160dSDag-Erling Smørgrav c->ostate = next; 98ae1f160dSDag-Erling Smørgrav } 99a04a10f8SKris Kennaway 100a04a10f8SKris Kennaway /* 101a04a10f8SKris Kennaway * SSH1 specific implementation of event functions 102a04a10f8SKris Kennaway */ 103a04a10f8SKris Kennaway 104a04a10f8SKris Kennaway static void 105a04a10f8SKris Kennaway chan_rcvd_oclose1(Channel *c) 106511b41d2SMark Murray { 107a04a10f8SKris Kennaway debug("channel %d: rcvd oclose", c->self); 108511b41d2SMark Murray switch (c->istate) { 109511b41d2SMark Murray case CHAN_INPUT_WAIT_OCLOSE: 110ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 111511b41d2SMark Murray break; 112511b41d2SMark Murray case CHAN_INPUT_OPEN: 113511b41d2SMark Murray chan_shutdown_read(c); 114a04a10f8SKris Kennaway chan_send_ieof1(c); 115ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 116511b41d2SMark Murray break; 117511b41d2SMark Murray case CHAN_INPUT_WAIT_DRAIN: 118511b41d2SMark Murray /* both local read_failed and remote write_failed */ 119a04a10f8SKris Kennaway chan_send_ieof1(c); 120ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 121511b41d2SMark Murray break; 122511b41d2SMark Murray default: 123ae1f160dSDag-Erling Smørgrav error("channel %d: protocol error: rcvd_oclose for istate %d", 124a04a10f8SKris Kennaway c->self, c->istate); 125511b41d2SMark Murray return; 126511b41d2SMark Murray } 127511b41d2SMark Murray } 128ae1f160dSDag-Erling Smørgrav void 129ae1f160dSDag-Erling Smørgrav chan_read_failed(Channel *c) 130511b41d2SMark Murray { 131a04a10f8SKris Kennaway debug("channel %d: read failed", c->self); 132511b41d2SMark Murray switch (c->istate) { 133511b41d2SMark Murray case CHAN_INPUT_OPEN: 134511b41d2SMark Murray chan_shutdown_read(c); 135ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN); 136511b41d2SMark Murray break; 137511b41d2SMark Murray default: 138ae1f160dSDag-Erling Smørgrav error("channel %d: chan_read_failed for istate %d", 139511b41d2SMark Murray c->self, c->istate); 140511b41d2SMark Murray break; 141511b41d2SMark Murray } 142511b41d2SMark Murray } 143ae1f160dSDag-Erling Smørgrav void 144ae1f160dSDag-Erling Smørgrav chan_ibuf_empty(Channel *c) 145511b41d2SMark Murray { 146a04a10f8SKris Kennaway debug("channel %d: ibuf empty", c->self); 147511b41d2SMark Murray if (buffer_len(&c->input)) { 148ae1f160dSDag-Erling Smørgrav error("channel %d: chan_ibuf_empty for non empty buffer", 149a04a10f8SKris Kennaway c->self); 150511b41d2SMark Murray return; 151511b41d2SMark Murray } 152511b41d2SMark Murray switch (c->istate) { 153511b41d2SMark Murray case CHAN_INPUT_WAIT_DRAIN: 154ae1f160dSDag-Erling Smørgrav if (compat20) { 155ae1f160dSDag-Erling Smørgrav if (!(c->flags & CHAN_CLOSE_SENT)) 156ae1f160dSDag-Erling Smørgrav chan_send_eof2(c); 157ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 158ae1f160dSDag-Erling Smørgrav } else { 159a04a10f8SKris Kennaway chan_send_ieof1(c); 160ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE); 161ae1f160dSDag-Erling Smørgrav } 162511b41d2SMark Murray break; 163511b41d2SMark Murray default: 164ae1f160dSDag-Erling Smørgrav error("channel %d: chan_ibuf_empty for istate %d", 165a04a10f8SKris Kennaway c->self, c->istate); 166511b41d2SMark Murray break; 167511b41d2SMark Murray } 168511b41d2SMark Murray } 169a04a10f8SKris Kennaway static void 170a04a10f8SKris Kennaway chan_rcvd_ieof1(Channel *c) 171511b41d2SMark Murray { 172a04a10f8SKris Kennaway debug("channel %d: rcvd ieof", c->self); 173511b41d2SMark Murray switch (c->ostate) { 174511b41d2SMark Murray case CHAN_OUTPUT_OPEN: 175ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 176511b41d2SMark Murray break; 177511b41d2SMark Murray case CHAN_OUTPUT_WAIT_IEOF: 178ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 179511b41d2SMark Murray break; 180511b41d2SMark Murray default: 181ae1f160dSDag-Erling Smørgrav error("channel %d: protocol error: rcvd_ieof for ostate %d", 182a04a10f8SKris Kennaway c->self, c->ostate); 183511b41d2SMark Murray break; 184511b41d2SMark Murray } 185511b41d2SMark Murray } 186a04a10f8SKris Kennaway static void 187a04a10f8SKris Kennaway chan_write_failed1(Channel *c) 188511b41d2SMark Murray { 189a04a10f8SKris Kennaway debug("channel %d: write failed", c->self); 190511b41d2SMark Murray switch (c->ostate) { 191511b41d2SMark Murray case CHAN_OUTPUT_OPEN: 192ae1f160dSDag-Erling Smørgrav chan_shutdown_write(c); 193a04a10f8SKris Kennaway chan_send_oclose1(c); 194ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF); 195511b41d2SMark Murray break; 196511b41d2SMark Murray case CHAN_OUTPUT_WAIT_DRAIN: 197ae1f160dSDag-Erling Smørgrav chan_shutdown_write(c); 198a04a10f8SKris Kennaway chan_send_oclose1(c); 199ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 200511b41d2SMark Murray break; 201511b41d2SMark Murray default: 202ae1f160dSDag-Erling Smørgrav error("channel %d: chan_write_failed for ostate %d", 203a04a10f8SKris Kennaway c->self, c->ostate); 204511b41d2SMark Murray break; 205511b41d2SMark Murray } 206511b41d2SMark Murray } 207ae1f160dSDag-Erling Smørgrav void 208ae1f160dSDag-Erling Smørgrav chan_obuf_empty(Channel *c) 209511b41d2SMark Murray { 210a04a10f8SKris Kennaway debug("channel %d: obuf empty", c->self); 211511b41d2SMark Murray if (buffer_len(&c->output)) { 212ae1f160dSDag-Erling Smørgrav error("channel %d: chan_obuf_empty for non empty buffer", 213a04a10f8SKris Kennaway c->self); 214511b41d2SMark Murray return; 215511b41d2SMark Murray } 216511b41d2SMark Murray switch (c->ostate) { 217511b41d2SMark Murray case CHAN_OUTPUT_WAIT_DRAIN: 218ae1f160dSDag-Erling Smørgrav chan_shutdown_write(c); 219ae1f160dSDag-Erling Smørgrav if (!compat20) 220a04a10f8SKris Kennaway chan_send_oclose1(c); 221ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 222511b41d2SMark Murray break; 223511b41d2SMark Murray default: 224ae1f160dSDag-Erling Smørgrav error("channel %d: internal error: obuf_empty for ostate %d", 225a04a10f8SKris Kennaway c->self, c->ostate); 226511b41d2SMark Murray break; 227511b41d2SMark Murray } 228511b41d2SMark Murray } 229511b41d2SMark Murray static void 230a04a10f8SKris Kennaway chan_send_ieof1(Channel *c) 231511b41d2SMark Murray { 232a04a10f8SKris Kennaway debug("channel %d: send ieof", c->self); 233511b41d2SMark Murray switch (c->istate) { 234511b41d2SMark Murray case CHAN_INPUT_OPEN: 235511b41d2SMark Murray case CHAN_INPUT_WAIT_DRAIN: 236511b41d2SMark Murray packet_start(SSH_MSG_CHANNEL_INPUT_EOF); 237511b41d2SMark Murray packet_put_int(c->remote_id); 238511b41d2SMark Murray packet_send(); 239511b41d2SMark Murray break; 240511b41d2SMark Murray default: 241ae1f160dSDag-Erling Smørgrav error("channel %d: cannot send ieof for istate %d", 242a04a10f8SKris Kennaway c->self, c->istate); 243511b41d2SMark Murray break; 244511b41d2SMark Murray } 245511b41d2SMark Murray } 246511b41d2SMark Murray static void 247a04a10f8SKris Kennaway chan_send_oclose1(Channel *c) 248511b41d2SMark Murray { 249a04a10f8SKris Kennaway debug("channel %d: send oclose", c->self); 250511b41d2SMark Murray switch (c->ostate) { 251511b41d2SMark Murray case CHAN_OUTPUT_OPEN: 252511b41d2SMark Murray case CHAN_OUTPUT_WAIT_DRAIN: 253ae1f160dSDag-Erling Smørgrav buffer_clear(&c->output); 254511b41d2SMark Murray packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE); 255511b41d2SMark Murray packet_put_int(c->remote_id); 256511b41d2SMark Murray packet_send(); 257511b41d2SMark Murray break; 258511b41d2SMark Murray default: 259ae1f160dSDag-Erling Smørgrav error("channel %d: cannot send oclose for ostate %d", 260a04a10f8SKris Kennaway c->self, c->ostate); 261511b41d2SMark Murray break; 262511b41d2SMark Murray } 263511b41d2SMark Murray } 264a04a10f8SKris Kennaway 265a04a10f8SKris Kennaway /* 266a04a10f8SKris Kennaway * the same for SSH2 267a04a10f8SKris Kennaway */ 268a04a10f8SKris Kennaway static void 269ae1f160dSDag-Erling Smørgrav chan_rcvd_close2(Channel *c) 270a04a10f8SKris Kennaway { 271a04a10f8SKris Kennaway debug("channel %d: rcvd close", c->self); 272a04a10f8SKris Kennaway if (c->flags & CHAN_CLOSE_RCVD) 273a04a10f8SKris Kennaway error("channel %d: protocol error: close rcvd twice", c->self); 274a04a10f8SKris Kennaway c->flags |= CHAN_CLOSE_RCVD; 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: 292a04a10f8SKris Kennaway chan_shutdown_read(c); 293ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 294a04a10f8SKris Kennaway break; 295a04a10f8SKris Kennaway case CHAN_INPUT_WAIT_DRAIN: 296a04a10f8SKris Kennaway chan_send_eof2(c); 297ae1f160dSDag-Erling Smørgrav chan_set_istate(c, CHAN_INPUT_CLOSED); 298a04a10f8SKris Kennaway break; 299a04a10f8SKris Kennaway } 300a04a10f8SKris Kennaway } 301a04a10f8SKris Kennaway static void 302ae1f160dSDag-Erling Smørgrav chan_rcvd_eof2(Channel *c) 303a04a10f8SKris Kennaway { 304a04a10f8SKris Kennaway debug("channel %d: rcvd eof", c->self); 305545d5ecaSDag-Erling Smørgrav c->flags |= CHAN_EOF_RCVD; 306ae1f160dSDag-Erling Smørgrav if (c->ostate == CHAN_OUTPUT_OPEN) 307ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 308a04a10f8SKris Kennaway } 309a04a10f8SKris Kennaway static void 310a04a10f8SKris Kennaway chan_write_failed2(Channel *c) 311a04a10f8SKris Kennaway { 312a04a10f8SKris Kennaway debug("channel %d: write failed", c->self); 313a04a10f8SKris Kennaway switch (c->ostate) { 314a04a10f8SKris Kennaway case CHAN_OUTPUT_OPEN: 315a04a10f8SKris Kennaway case CHAN_OUTPUT_WAIT_DRAIN: 316a04a10f8SKris Kennaway chan_shutdown_write(c); 317ae1f160dSDag-Erling Smørgrav chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 318a04a10f8SKris Kennaway break; 319a04a10f8SKris Kennaway default: 320ae1f160dSDag-Erling Smørgrav error("channel %d: chan_write_failed for ostate %d", 321a04a10f8SKris Kennaway c->self, c->ostate); 322a04a10f8SKris Kennaway break; 323a04a10f8SKris Kennaway } 324a04a10f8SKris Kennaway } 325a04a10f8SKris Kennaway static void 326a04a10f8SKris Kennaway chan_send_eof2(Channel *c) 327a04a10f8SKris Kennaway { 328a04a10f8SKris Kennaway debug("channel %d: send eof", c->self); 329a04a10f8SKris Kennaway switch (c->istate) { 330a04a10f8SKris Kennaway case CHAN_INPUT_WAIT_DRAIN: 331a04a10f8SKris Kennaway packet_start(SSH2_MSG_CHANNEL_EOF); 332a04a10f8SKris Kennaway packet_put_int(c->remote_id); 333a04a10f8SKris Kennaway packet_send(); 334545d5ecaSDag-Erling Smørgrav c->flags |= CHAN_EOF_SENT; 335a04a10f8SKris Kennaway break; 336a04a10f8SKris Kennaway default: 337ae1f160dSDag-Erling Smørgrav error("channel %d: cannot send eof for istate %d", 338a04a10f8SKris Kennaway c->self, c->istate); 339a04a10f8SKris Kennaway break; 340a04a10f8SKris Kennaway } 341a04a10f8SKris Kennaway } 342a04a10f8SKris Kennaway static void 343a04a10f8SKris Kennaway chan_send_close2(Channel *c) 344a04a10f8SKris Kennaway { 345a04a10f8SKris Kennaway debug("channel %d: send close", c->self); 346a04a10f8SKris Kennaway if (c->ostate != CHAN_OUTPUT_CLOSED || 347a04a10f8SKris Kennaway c->istate != CHAN_INPUT_CLOSED) { 348ae1f160dSDag-Erling Smørgrav error("channel %d: cannot send close for istate/ostate %d/%d", 349a04a10f8SKris Kennaway c->self, c->istate, c->ostate); 350a04a10f8SKris Kennaway } else if (c->flags & CHAN_CLOSE_SENT) { 351ae1f160dSDag-Erling Smørgrav error("channel %d: already sent close", c->self); 352a04a10f8SKris Kennaway } else { 353a04a10f8SKris Kennaway packet_start(SSH2_MSG_CHANNEL_CLOSE); 354a04a10f8SKris Kennaway packet_put_int(c->remote_id); 355a04a10f8SKris Kennaway packet_send(); 356a04a10f8SKris Kennaway c->flags |= CHAN_CLOSE_SENT; 357a04a10f8SKris Kennaway } 358a04a10f8SKris Kennaway } 3591e8db6e2SBrian Feldman 3601e8db6e2SBrian Feldman /* shared */ 3611e8db6e2SBrian Feldman 362ae1f160dSDag-Erling Smørgrav void 363ae1f160dSDag-Erling Smørgrav chan_rcvd_ieof(Channel *c) 364a04a10f8SKris Kennaway { 365ae1f160dSDag-Erling Smørgrav if (compat20) 366ae1f160dSDag-Erling Smørgrav chan_rcvd_eof2(c); 367ae1f160dSDag-Erling Smørgrav else 368ae1f160dSDag-Erling Smørgrav chan_rcvd_ieof1(c); 369ae1f160dSDag-Erling Smørgrav if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && 370545d5ecaSDag-Erling Smørgrav buffer_len(&c->output) == 0 && 371545d5ecaSDag-Erling Smørgrav !CHANNEL_EFD_OUTPUT_ACTIVE(c)) 372ae1f160dSDag-Erling Smørgrav chan_obuf_empty(c); 373ae1f160dSDag-Erling Smørgrav } 374ae1f160dSDag-Erling Smørgrav void 375ae1f160dSDag-Erling Smørgrav chan_rcvd_oclose(Channel *c) 376ae1f160dSDag-Erling Smørgrav { 377ae1f160dSDag-Erling Smørgrav if (compat20) 378ae1f160dSDag-Erling Smørgrav chan_rcvd_close2(c); 379ae1f160dSDag-Erling Smørgrav else 380ae1f160dSDag-Erling Smørgrav chan_rcvd_oclose1(c); 381ae1f160dSDag-Erling Smørgrav } 382ae1f160dSDag-Erling Smørgrav void 383ae1f160dSDag-Erling Smørgrav chan_write_failed(Channel *c) 384ae1f160dSDag-Erling Smørgrav { 385ae1f160dSDag-Erling Smørgrav if (compat20) 386ae1f160dSDag-Erling Smørgrav chan_write_failed2(c); 387ae1f160dSDag-Erling Smørgrav else 388ae1f160dSDag-Erling Smørgrav chan_write_failed1(c); 389ae1f160dSDag-Erling Smørgrav } 390ae1f160dSDag-Erling Smørgrav 391ae1f160dSDag-Erling Smørgrav void 392ae1f160dSDag-Erling Smørgrav chan_mark_dead(Channel *c) 393ae1f160dSDag-Erling Smørgrav { 394ae1f160dSDag-Erling Smørgrav c->type = SSH_CHANNEL_ZOMBIE; 395ae1f160dSDag-Erling Smørgrav } 396ae1f160dSDag-Erling Smørgrav 397ae1f160dSDag-Erling Smørgrav int 398ae1f160dSDag-Erling Smørgrav chan_is_dead(Channel *c, int send) 399ae1f160dSDag-Erling Smørgrav { 400ae1f160dSDag-Erling Smørgrav if (c->type == SSH_CHANNEL_ZOMBIE) { 401ae1f160dSDag-Erling Smørgrav debug("channel %d: zombie", c->self); 402ae1f160dSDag-Erling Smørgrav return 1; 403ae1f160dSDag-Erling Smørgrav } 4041e8db6e2SBrian Feldman if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) 4051e8db6e2SBrian Feldman return 0; 4061e8db6e2SBrian Feldman if (!compat20) { 4071e8db6e2SBrian Feldman debug("channel %d: is dead", c->self); 4081e8db6e2SBrian Feldman return 1; 4091e8db6e2SBrian Feldman } 410545d5ecaSDag-Erling Smørgrav if ((datafellows & SSH_BUG_EXTEOF) && 411545d5ecaSDag-Erling Smørgrav c->extended_usage == CHAN_EXTENDED_WRITE && 412545d5ecaSDag-Erling Smørgrav c->efd != -1 && 413545d5ecaSDag-Erling Smørgrav buffer_len(&c->extended) > 0) { 414545d5ecaSDag-Erling Smørgrav debug2("channel %d: active efd: %d len %d", 415545d5ecaSDag-Erling Smørgrav c->self, c->efd, buffer_len(&c->extended)); 416545d5ecaSDag-Erling Smørgrav return 0; 417545d5ecaSDag-Erling Smørgrav } 418a04a10f8SKris Kennaway if (!(c->flags & CHAN_CLOSE_SENT)) { 419ae1f160dSDag-Erling Smørgrav if (send) { 420a04a10f8SKris Kennaway chan_send_close2(c); 421ae1f160dSDag-Erling Smørgrav } else { 422ae1f160dSDag-Erling Smørgrav /* channel would be dead if we sent a close */ 423ae1f160dSDag-Erling Smørgrav if (c->flags & CHAN_CLOSE_RCVD) { 424ae1f160dSDag-Erling Smørgrav debug("channel %d: almost dead", 425ae1f160dSDag-Erling Smørgrav c->self); 426ae1f160dSDag-Erling Smørgrav return 1; 427ae1f160dSDag-Erling Smørgrav } 428ae1f160dSDag-Erling Smørgrav } 429a04a10f8SKris Kennaway } 430a04a10f8SKris Kennaway if ((c->flags & CHAN_CLOSE_SENT) && 431a04a10f8SKris Kennaway (c->flags & CHAN_CLOSE_RCVD)) { 4321e8db6e2SBrian Feldman debug("channel %d: is dead", c->self); 4331e8db6e2SBrian Feldman return 1; 434a04a10f8SKris Kennaway } 4351e8db6e2SBrian Feldman return 0; 436a04a10f8SKris Kennaway } 437a04a10f8SKris Kennaway 438511b41d2SMark Murray /* helper */ 439511b41d2SMark Murray static void 440511b41d2SMark Murray chan_shutdown_write(Channel *c) 441511b41d2SMark Murray { 442ae1f160dSDag-Erling Smørgrav buffer_clear(&c->output); 443a04a10f8SKris Kennaway if (compat20 && c->type == SSH_CHANNEL_LARVAL) 444a04a10f8SKris Kennaway return; 445511b41d2SMark Murray /* shutdown failure is allowed if write failed already */ 446a04a10f8SKris Kennaway debug("channel %d: close_write", c->self); 447a04a10f8SKris Kennaway if (c->sock != -1) { 448511b41d2SMark Murray if (shutdown(c->sock, SHUT_WR) < 0) 449ae1f160dSDag-Erling Smørgrav debug("channel %d: chan_shutdown_write: " 450ae1f160dSDag-Erling Smørgrav "shutdown() failed for fd%d: %.100s", 451511b41d2SMark Murray c->self, c->sock, strerror(errno)); 452a04a10f8SKris Kennaway } else { 453ae1f160dSDag-Erling Smørgrav if (channel_close_fd(&c->wfd) < 0) 454ae1f160dSDag-Erling Smørgrav log("channel %d: chan_shutdown_write: " 455ae1f160dSDag-Erling Smørgrav "close() failed for fd%d: %.100s", 456a04a10f8SKris Kennaway c->self, c->wfd, strerror(errno)); 457a04a10f8SKris Kennaway } 458511b41d2SMark Murray } 459511b41d2SMark Murray static void 460511b41d2SMark Murray chan_shutdown_read(Channel *c) 461511b41d2SMark Murray { 462a04a10f8SKris Kennaway if (compat20 && c->type == SSH_CHANNEL_LARVAL) 463a04a10f8SKris Kennaway return; 464a04a10f8SKris Kennaway debug("channel %d: close_read", c->self); 465a04a10f8SKris Kennaway if (c->sock != -1) { 466511b41d2SMark Murray if (shutdown(c->sock, SHUT_RD) < 0) 467ae1f160dSDag-Erling Smørgrav error("channel %d: chan_shutdown_read: " 468ae1f160dSDag-Erling Smørgrav "shutdown() failed for fd%d [i%d o%d]: %.100s", 469ae1f160dSDag-Erling Smørgrav c->self, c->sock, c->istate, c->ostate, 470ae1f160dSDag-Erling Smørgrav strerror(errno)); 471a04a10f8SKris Kennaway } else { 472ae1f160dSDag-Erling Smørgrav if (channel_close_fd(&c->rfd) < 0) 473ae1f160dSDag-Erling Smørgrav log("channel %d: chan_shutdown_read: " 474ae1f160dSDag-Erling Smørgrav "close() failed for fd%d: %.100s", 475a04a10f8SKris Kennaway c->self, c->rfd, strerror(errno)); 476511b41d2SMark Murray } 477511b41d2SMark Murray } 478