1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 5*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 6*0Sstevel@tonic-gate * are met: 7*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 8*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 9*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 10*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 11*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16*0Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17*0Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19*0Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20*0Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21*0Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22*0Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23*0Sstevel@tonic-gate */ 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate #include "includes.h" 26*0Sstevel@tonic-gate RCSID("$OpenBSD: nchan.c,v 1.47 2002/06/19 00:27:55 deraadt Exp $"); 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include "ssh1.h" 31*0Sstevel@tonic-gate #include "ssh2.h" 32*0Sstevel@tonic-gate #include "buffer.h" 33*0Sstevel@tonic-gate #include "packet.h" 34*0Sstevel@tonic-gate #include "channels.h" 35*0Sstevel@tonic-gate #include "compat.h" 36*0Sstevel@tonic-gate #include "log.h" 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate /* 39*0Sstevel@tonic-gate * SSH Protocol 1.5 aka New Channel Protocol 40*0Sstevel@tonic-gate * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. 41*0Sstevel@tonic-gate * Written by Markus Friedl in October 1999 42*0Sstevel@tonic-gate * 43*0Sstevel@tonic-gate * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the 44*0Sstevel@tonic-gate * tear down of channels: 45*0Sstevel@tonic-gate * 46*0Sstevel@tonic-gate * 1.3: strict request-ack-protocol: 47*0Sstevel@tonic-gate * CLOSE -> 48*0Sstevel@tonic-gate * <- CLOSE_CONFIRM 49*0Sstevel@tonic-gate * 50*0Sstevel@tonic-gate * 1.5: uses variations of: 51*0Sstevel@tonic-gate * IEOF -> 52*0Sstevel@tonic-gate * <- OCLOSE 53*0Sstevel@tonic-gate * <- IEOF 54*0Sstevel@tonic-gate * OCLOSE -> 55*0Sstevel@tonic-gate * i.e. both sides have to close the channel 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * 2.0: the EOF messages are optional 58*0Sstevel@tonic-gate * 59*0Sstevel@tonic-gate * See the debugging output from 'ssh -v' and 'sshd -d' of 60*0Sstevel@tonic-gate * ssh-1.2.27 as an example. 61*0Sstevel@tonic-gate * 62*0Sstevel@tonic-gate */ 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate /* functions manipulating channel states */ 65*0Sstevel@tonic-gate /* 66*0Sstevel@tonic-gate * EVENTS update channel input/output states execute ACTIONS 67*0Sstevel@tonic-gate */ 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * ACTIONS: should never update the channel states 70*0Sstevel@tonic-gate */ 71*0Sstevel@tonic-gate static void chan_send_ieof1(Channel *); 72*0Sstevel@tonic-gate static void chan_send_oclose1(Channel *); 73*0Sstevel@tonic-gate static void chan_send_close2(Channel *); 74*0Sstevel@tonic-gate static void chan_send_eof2(Channel *); 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* helper */ 77*0Sstevel@tonic-gate static void chan_shutdown_write(Channel *); 78*0Sstevel@tonic-gate static void chan_shutdown_read(Channel *); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate static char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; 81*0Sstevel@tonic-gate static char *istates[] = { "open", "drain", "wait_oclose", "closed" }; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static void 84*0Sstevel@tonic-gate chan_set_istate(Channel *c, u_int next) 85*0Sstevel@tonic-gate { 86*0Sstevel@tonic-gate if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED) 87*0Sstevel@tonic-gate fatal("chan_set_istate: bad state %d -> %d", c->istate, next); 88*0Sstevel@tonic-gate debug("channel %d: input %s -> %s", c->self, istates[c->istate], 89*0Sstevel@tonic-gate istates[next]); 90*0Sstevel@tonic-gate c->istate = next; 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate static void 93*0Sstevel@tonic-gate chan_set_ostate(Channel *c, u_int next) 94*0Sstevel@tonic-gate { 95*0Sstevel@tonic-gate if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED) 96*0Sstevel@tonic-gate fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next); 97*0Sstevel@tonic-gate debug("channel %d: output %s -> %s", c->self, ostates[c->ostate], 98*0Sstevel@tonic-gate ostates[next]); 99*0Sstevel@tonic-gate c->ostate = next; 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate /* 103*0Sstevel@tonic-gate * SSH1 specific implementation of event functions 104*0Sstevel@tonic-gate */ 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate static void 107*0Sstevel@tonic-gate chan_rcvd_oclose1(Channel *c) 108*0Sstevel@tonic-gate { 109*0Sstevel@tonic-gate debug("channel %d: rcvd oclose", c->self); 110*0Sstevel@tonic-gate switch (c->istate) { 111*0Sstevel@tonic-gate case CHAN_INPUT_WAIT_OCLOSE: 112*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED); 113*0Sstevel@tonic-gate break; 114*0Sstevel@tonic-gate case CHAN_INPUT_OPEN: 115*0Sstevel@tonic-gate chan_shutdown_read(c); 116*0Sstevel@tonic-gate chan_send_ieof1(c); 117*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED); 118*0Sstevel@tonic-gate break; 119*0Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN: 120*0Sstevel@tonic-gate /* both local read_failed and remote write_failed */ 121*0Sstevel@tonic-gate chan_send_ieof1(c); 122*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED); 123*0Sstevel@tonic-gate break; 124*0Sstevel@tonic-gate default: 125*0Sstevel@tonic-gate error("channel %d: protocol error: rcvd_oclose for istate %d", 126*0Sstevel@tonic-gate c->self, c->istate); 127*0Sstevel@tonic-gate return; 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate void 131*0Sstevel@tonic-gate chan_read_failed(Channel *c) 132*0Sstevel@tonic-gate { 133*0Sstevel@tonic-gate debug("channel %d: read failed", c->self); 134*0Sstevel@tonic-gate switch (c->istate) { 135*0Sstevel@tonic-gate case CHAN_INPUT_OPEN: 136*0Sstevel@tonic-gate chan_shutdown_read(c); 137*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN); 138*0Sstevel@tonic-gate break; 139*0Sstevel@tonic-gate default: 140*0Sstevel@tonic-gate error("channel %d: chan_read_failed for istate %d", 141*0Sstevel@tonic-gate c->self, c->istate); 142*0Sstevel@tonic-gate break; 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate void 146*0Sstevel@tonic-gate chan_ibuf_empty(Channel *c) 147*0Sstevel@tonic-gate { 148*0Sstevel@tonic-gate debug("channel %d: ibuf empty", c->self); 149*0Sstevel@tonic-gate if (buffer_len(&c->input)) { 150*0Sstevel@tonic-gate error("channel %d: chan_ibuf_empty for non empty buffer", 151*0Sstevel@tonic-gate c->self); 152*0Sstevel@tonic-gate return; 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate switch (c->istate) { 155*0Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN: 156*0Sstevel@tonic-gate if (compat20) { 157*0Sstevel@tonic-gate if (!(c->flags & CHAN_CLOSE_SENT)) 158*0Sstevel@tonic-gate chan_send_eof2(c); 159*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED); 160*0Sstevel@tonic-gate } else { 161*0Sstevel@tonic-gate chan_send_ieof1(c); 162*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate break; 165*0Sstevel@tonic-gate default: 166*0Sstevel@tonic-gate error("channel %d: chan_ibuf_empty for istate %d", 167*0Sstevel@tonic-gate c->self, c->istate); 168*0Sstevel@tonic-gate break; 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate static void 172*0Sstevel@tonic-gate chan_rcvd_ieof1(Channel *c) 173*0Sstevel@tonic-gate { 174*0Sstevel@tonic-gate debug("channel %d: rcvd ieof", c->self); 175*0Sstevel@tonic-gate switch (c->ostate) { 176*0Sstevel@tonic-gate case CHAN_OUTPUT_OPEN: 177*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 178*0Sstevel@tonic-gate break; 179*0Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_IEOF: 180*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 181*0Sstevel@tonic-gate break; 182*0Sstevel@tonic-gate default: 183*0Sstevel@tonic-gate error("channel %d: protocol error: rcvd_ieof for ostate %d", 184*0Sstevel@tonic-gate c->self, c->ostate); 185*0Sstevel@tonic-gate break; 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate static void 189*0Sstevel@tonic-gate chan_write_failed1(Channel *c) 190*0Sstevel@tonic-gate { 191*0Sstevel@tonic-gate debug("channel %d: write failed", c->self); 192*0Sstevel@tonic-gate switch (c->ostate) { 193*0Sstevel@tonic-gate case CHAN_OUTPUT_OPEN: 194*0Sstevel@tonic-gate chan_shutdown_write(c); 195*0Sstevel@tonic-gate chan_send_oclose1(c); 196*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF); 197*0Sstevel@tonic-gate break; 198*0Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_DRAIN: 199*0Sstevel@tonic-gate chan_shutdown_write(c); 200*0Sstevel@tonic-gate chan_send_oclose1(c); 201*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 202*0Sstevel@tonic-gate break; 203*0Sstevel@tonic-gate default: 204*0Sstevel@tonic-gate error("channel %d: chan_write_failed for ostate %d", 205*0Sstevel@tonic-gate c->self, c->ostate); 206*0Sstevel@tonic-gate break; 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate void 210*0Sstevel@tonic-gate chan_obuf_empty(Channel *c) 211*0Sstevel@tonic-gate { 212*0Sstevel@tonic-gate debug("channel %d: obuf empty", c->self); 213*0Sstevel@tonic-gate if (buffer_len(&c->output)) { 214*0Sstevel@tonic-gate error("channel %d: chan_obuf_empty for non empty buffer", 215*0Sstevel@tonic-gate c->self); 216*0Sstevel@tonic-gate return; 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate switch (c->ostate) { 219*0Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_DRAIN: 220*0Sstevel@tonic-gate chan_shutdown_write(c); 221*0Sstevel@tonic-gate if (!compat20) 222*0Sstevel@tonic-gate chan_send_oclose1(c); 223*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 224*0Sstevel@tonic-gate break; 225*0Sstevel@tonic-gate default: 226*0Sstevel@tonic-gate error("channel %d: internal error: obuf_empty for ostate %d", 227*0Sstevel@tonic-gate c->self, c->ostate); 228*0Sstevel@tonic-gate break; 229*0Sstevel@tonic-gate } 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate static void 232*0Sstevel@tonic-gate chan_send_ieof1(Channel *c) 233*0Sstevel@tonic-gate { 234*0Sstevel@tonic-gate debug("channel %d: send ieof", c->self); 235*0Sstevel@tonic-gate switch (c->istate) { 236*0Sstevel@tonic-gate case CHAN_INPUT_OPEN: 237*0Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN: 238*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_INPUT_EOF); 239*0Sstevel@tonic-gate packet_put_int(c->remote_id); 240*0Sstevel@tonic-gate packet_send(); 241*0Sstevel@tonic-gate break; 242*0Sstevel@tonic-gate default: 243*0Sstevel@tonic-gate error("channel %d: cannot send ieof for istate %d", 244*0Sstevel@tonic-gate c->self, c->istate); 245*0Sstevel@tonic-gate break; 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate static void 249*0Sstevel@tonic-gate chan_send_oclose1(Channel *c) 250*0Sstevel@tonic-gate { 251*0Sstevel@tonic-gate debug("channel %d: send oclose", c->self); 252*0Sstevel@tonic-gate switch (c->ostate) { 253*0Sstevel@tonic-gate case CHAN_OUTPUT_OPEN: 254*0Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_DRAIN: 255*0Sstevel@tonic-gate buffer_clear(&c->output); 256*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE); 257*0Sstevel@tonic-gate packet_put_int(c->remote_id); 258*0Sstevel@tonic-gate packet_send(); 259*0Sstevel@tonic-gate break; 260*0Sstevel@tonic-gate default: 261*0Sstevel@tonic-gate error("channel %d: cannot send oclose for ostate %d", 262*0Sstevel@tonic-gate c->self, c->ostate); 263*0Sstevel@tonic-gate break; 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate /* 268*0Sstevel@tonic-gate * the same for SSH2 269*0Sstevel@tonic-gate */ 270*0Sstevel@tonic-gate static void 271*0Sstevel@tonic-gate chan_rcvd_close2(Channel *c) 272*0Sstevel@tonic-gate { 273*0Sstevel@tonic-gate debug("channel %d: rcvd close", c->self); 274*0Sstevel@tonic-gate if (c->flags & CHAN_CLOSE_RCVD) 275*0Sstevel@tonic-gate error("channel %d: protocol error: close rcvd twice", c->self); 276*0Sstevel@tonic-gate c->flags |= CHAN_CLOSE_RCVD; 277*0Sstevel@tonic-gate if (c->type == SSH_CHANNEL_LARVAL) { 278*0Sstevel@tonic-gate /* tear down larval channels immediately */ 279*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 280*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED); 281*0Sstevel@tonic-gate return; 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate switch (c->ostate) { 284*0Sstevel@tonic-gate case CHAN_OUTPUT_OPEN: 285*0Sstevel@tonic-gate /* 286*0Sstevel@tonic-gate * wait until a data from the channel is consumed if a CLOSE 287*0Sstevel@tonic-gate * is received 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 290*0Sstevel@tonic-gate break; 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate switch (c->istate) { 293*0Sstevel@tonic-gate case CHAN_INPUT_OPEN: 294*0Sstevel@tonic-gate chan_shutdown_read(c); 295*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED); 296*0Sstevel@tonic-gate break; 297*0Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN: 298*0Sstevel@tonic-gate chan_send_eof2(c); 299*0Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED); 300*0Sstevel@tonic-gate break; 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate static void 304*0Sstevel@tonic-gate chan_rcvd_eof2(Channel *c) 305*0Sstevel@tonic-gate { 306*0Sstevel@tonic-gate debug("channel %d: rcvd eof", c->self); 307*0Sstevel@tonic-gate c->flags |= CHAN_EOF_RCVD; 308*0Sstevel@tonic-gate if (c->ostate == CHAN_OUTPUT_OPEN) 309*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate static void 312*0Sstevel@tonic-gate chan_write_failed2(Channel *c) 313*0Sstevel@tonic-gate { 314*0Sstevel@tonic-gate debug("channel %d: write failed", c->self); 315*0Sstevel@tonic-gate switch (c->ostate) { 316*0Sstevel@tonic-gate case CHAN_OUTPUT_OPEN: 317*0Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_DRAIN: 318*0Sstevel@tonic-gate chan_shutdown_write(c); 319*0Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 320*0Sstevel@tonic-gate break; 321*0Sstevel@tonic-gate default: 322*0Sstevel@tonic-gate error("channel %d: chan_write_failed for ostate %d", 323*0Sstevel@tonic-gate c->self, c->ostate); 324*0Sstevel@tonic-gate break; 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate static void 328*0Sstevel@tonic-gate chan_send_eof2(Channel *c) 329*0Sstevel@tonic-gate { 330*0Sstevel@tonic-gate debug("channel %d: send eof", c->self); 331*0Sstevel@tonic-gate switch (c->istate) { 332*0Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN: 333*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_EOF); 334*0Sstevel@tonic-gate packet_put_int(c->remote_id); 335*0Sstevel@tonic-gate packet_send(); 336*0Sstevel@tonic-gate c->flags |= CHAN_EOF_SENT; 337*0Sstevel@tonic-gate break; 338*0Sstevel@tonic-gate default: 339*0Sstevel@tonic-gate error("channel %d: cannot send eof for istate %d", 340*0Sstevel@tonic-gate c->self, c->istate); 341*0Sstevel@tonic-gate break; 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate static void 345*0Sstevel@tonic-gate chan_send_close2(Channel *c) 346*0Sstevel@tonic-gate { 347*0Sstevel@tonic-gate debug("channel %d: send close", c->self); 348*0Sstevel@tonic-gate if (c->ostate != CHAN_OUTPUT_CLOSED || 349*0Sstevel@tonic-gate c->istate != CHAN_INPUT_CLOSED) { 350*0Sstevel@tonic-gate error("channel %d: cannot send close for istate/ostate %d/%d", 351*0Sstevel@tonic-gate c->self, c->istate, c->ostate); 352*0Sstevel@tonic-gate } else if (c->flags & CHAN_CLOSE_SENT) { 353*0Sstevel@tonic-gate error("channel %d: already sent close", c->self); 354*0Sstevel@tonic-gate } else { 355*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_CLOSE); 356*0Sstevel@tonic-gate packet_put_int(c->remote_id); 357*0Sstevel@tonic-gate packet_send(); 358*0Sstevel@tonic-gate c->flags |= CHAN_CLOSE_SENT; 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* shared */ 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate void 365*0Sstevel@tonic-gate chan_rcvd_ieof(Channel *c) 366*0Sstevel@tonic-gate { 367*0Sstevel@tonic-gate if (compat20) 368*0Sstevel@tonic-gate chan_rcvd_eof2(c); 369*0Sstevel@tonic-gate else 370*0Sstevel@tonic-gate chan_rcvd_ieof1(c); 371*0Sstevel@tonic-gate if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && 372*0Sstevel@tonic-gate buffer_len(&c->output) == 0 && 373*0Sstevel@tonic-gate !CHANNEL_EFD_OUTPUT_ACTIVE(c)) 374*0Sstevel@tonic-gate chan_obuf_empty(c); 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate void 377*0Sstevel@tonic-gate chan_rcvd_oclose(Channel *c) 378*0Sstevel@tonic-gate { 379*0Sstevel@tonic-gate if (compat20) 380*0Sstevel@tonic-gate chan_rcvd_close2(c); 381*0Sstevel@tonic-gate else 382*0Sstevel@tonic-gate chan_rcvd_oclose1(c); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate void 385*0Sstevel@tonic-gate chan_write_failed(Channel *c) 386*0Sstevel@tonic-gate { 387*0Sstevel@tonic-gate if (compat20) 388*0Sstevel@tonic-gate chan_write_failed2(c); 389*0Sstevel@tonic-gate else 390*0Sstevel@tonic-gate chan_write_failed1(c); 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate void 394*0Sstevel@tonic-gate chan_mark_dead(Channel *c) 395*0Sstevel@tonic-gate { 396*0Sstevel@tonic-gate c->type = SSH_CHANNEL_ZOMBIE; 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate int 400*0Sstevel@tonic-gate chan_is_dead(Channel *c, int send) 401*0Sstevel@tonic-gate { 402*0Sstevel@tonic-gate if (c->type == SSH_CHANNEL_ZOMBIE) { 403*0Sstevel@tonic-gate debug("channel %d: zombie", c->self); 404*0Sstevel@tonic-gate return 1; 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) 407*0Sstevel@tonic-gate return 0; 408*0Sstevel@tonic-gate if (!compat20) { 409*0Sstevel@tonic-gate debug("channel %d: is dead", c->self); 410*0Sstevel@tonic-gate return 1; 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate if ((datafellows & SSH_BUG_EXTEOF) && 413*0Sstevel@tonic-gate c->extended_usage == CHAN_EXTENDED_WRITE && 414*0Sstevel@tonic-gate c->efd != -1 && 415*0Sstevel@tonic-gate buffer_len(&c->extended) > 0) { 416*0Sstevel@tonic-gate debug2("channel %d: active efd: %d len %d", 417*0Sstevel@tonic-gate c->self, c->efd, buffer_len(&c->extended)); 418*0Sstevel@tonic-gate return 0; 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate if (!(c->flags & CHAN_CLOSE_SENT)) { 421*0Sstevel@tonic-gate if (send) { 422*0Sstevel@tonic-gate chan_send_close2(c); 423*0Sstevel@tonic-gate } else { 424*0Sstevel@tonic-gate /* channel would be dead if we sent a close */ 425*0Sstevel@tonic-gate if (c->flags & CHAN_CLOSE_RCVD) { 426*0Sstevel@tonic-gate debug("channel %d: almost dead", 427*0Sstevel@tonic-gate c->self); 428*0Sstevel@tonic-gate return 1; 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate if ((c->flags & CHAN_CLOSE_SENT) && 433*0Sstevel@tonic-gate (c->flags & CHAN_CLOSE_RCVD)) { 434*0Sstevel@tonic-gate debug("channel %d: is dead", c->self); 435*0Sstevel@tonic-gate return 1; 436*0Sstevel@tonic-gate } 437*0Sstevel@tonic-gate return 0; 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate /* helper */ 441*0Sstevel@tonic-gate static void 442*0Sstevel@tonic-gate chan_shutdown_write(Channel *c) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate buffer_clear(&c->output); 445*0Sstevel@tonic-gate if (compat20 && c->type == SSH_CHANNEL_LARVAL) 446*0Sstevel@tonic-gate return; 447*0Sstevel@tonic-gate /* shutdown failure is allowed if write failed already */ 448*0Sstevel@tonic-gate debug("channel %d: close_write", c->self); 449*0Sstevel@tonic-gate if (c->sock != -1) { 450*0Sstevel@tonic-gate if (shutdown(c->sock, SHUT_WR) < 0) 451*0Sstevel@tonic-gate debug("channel %d: chan_shutdown_write: " 452*0Sstevel@tonic-gate "shutdown() failed for fd%d: %.100s", 453*0Sstevel@tonic-gate c->self, c->sock, strerror(errno)); 454*0Sstevel@tonic-gate } else { 455*0Sstevel@tonic-gate if (channel_close_fd(&c->wfd) < 0) 456*0Sstevel@tonic-gate log("channel %d: chan_shutdown_write: " 457*0Sstevel@tonic-gate "close() failed for fd%d: %.100s", 458*0Sstevel@tonic-gate c->self, c->wfd, strerror(errno)); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate static void 462*0Sstevel@tonic-gate chan_shutdown_read(Channel *c) 463*0Sstevel@tonic-gate { 464*0Sstevel@tonic-gate if (compat20 && c->type == SSH_CHANNEL_LARVAL) 465*0Sstevel@tonic-gate return; 466*0Sstevel@tonic-gate debug("channel %d: close_read", c->self); 467*0Sstevel@tonic-gate if (c->sock != -1) { 468*0Sstevel@tonic-gate /* 469*0Sstevel@tonic-gate * shutdown(sock, SHUT_READ) may return ENOTCONN if the 470*0Sstevel@tonic-gate * write side has been closed already. (bug on Linux) 471*0Sstevel@tonic-gate * HP-UX may return ENOTCONN also. 472*0Sstevel@tonic-gate */ 473*0Sstevel@tonic-gate if (shutdown(c->sock, SHUT_RD) < 0 474*0Sstevel@tonic-gate && errno != ENOTCONN) 475*0Sstevel@tonic-gate error("channel %d: chan_shutdown_read: " 476*0Sstevel@tonic-gate "shutdown() failed for fd%d [i%d o%d]: %.100s", 477*0Sstevel@tonic-gate c->self, c->sock, c->istate, c->ostate, 478*0Sstevel@tonic-gate strerror(errno)); 479*0Sstevel@tonic-gate } else { 480*0Sstevel@tonic-gate if (channel_close_fd(&c->rfd) < 0) 481*0Sstevel@tonic-gate log("channel %d: chan_shutdown_read: " 482*0Sstevel@tonic-gate "close() failed for fd%d: %.100s", 483*0Sstevel@tonic-gate c->self, c->rfd, strerror(errno)); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate } 486