17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
57c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions
67c478bd9Sstevel@tonic-gate * are met:
77c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
87c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
97c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
107c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
117c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
147c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
157c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
167c478bd9Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
177c478bd9Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
187c478bd9Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
197c478bd9Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
207c478bd9Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
217c478bd9Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
227c478bd9Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate #include "includes.h"
267c478bd9Sstevel@tonic-gate RCSID("$OpenBSD: nchan.c,v 1.47 2002/06/19 00:27:55 deraadt Exp $");
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include "ssh1.h"
297c478bd9Sstevel@tonic-gate #include "ssh2.h"
307c478bd9Sstevel@tonic-gate #include "buffer.h"
317c478bd9Sstevel@tonic-gate #include "packet.h"
327c478bd9Sstevel@tonic-gate #include "channels.h"
337c478bd9Sstevel@tonic-gate #include "compat.h"
347c478bd9Sstevel@tonic-gate #include "log.h"
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate * SSH Protocol 1.5 aka New Channel Protocol
387c478bd9Sstevel@tonic-gate * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
397c478bd9Sstevel@tonic-gate * Written by Markus Friedl in October 1999
407c478bd9Sstevel@tonic-gate *
417c478bd9Sstevel@tonic-gate * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
427c478bd9Sstevel@tonic-gate * tear down of channels:
437c478bd9Sstevel@tonic-gate *
447c478bd9Sstevel@tonic-gate * 1.3: strict request-ack-protocol:
457c478bd9Sstevel@tonic-gate * CLOSE ->
467c478bd9Sstevel@tonic-gate * <- CLOSE_CONFIRM
477c478bd9Sstevel@tonic-gate *
487c478bd9Sstevel@tonic-gate * 1.5: uses variations of:
497c478bd9Sstevel@tonic-gate * IEOF ->
507c478bd9Sstevel@tonic-gate * <- OCLOSE
517c478bd9Sstevel@tonic-gate * <- IEOF
527c478bd9Sstevel@tonic-gate * OCLOSE ->
537c478bd9Sstevel@tonic-gate * i.e. both sides have to close the channel
547c478bd9Sstevel@tonic-gate *
557c478bd9Sstevel@tonic-gate * 2.0: the EOF messages are optional
567c478bd9Sstevel@tonic-gate *
577c478bd9Sstevel@tonic-gate * See the debugging output from 'ssh -v' and 'sshd -d' of
587c478bd9Sstevel@tonic-gate * ssh-1.2.27 as an example.
597c478bd9Sstevel@tonic-gate *
607c478bd9Sstevel@tonic-gate */
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate /* functions manipulating channel states */
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate * EVENTS update channel input/output states execute ACTIONS
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate * ACTIONS: should never update the channel states
687c478bd9Sstevel@tonic-gate */
697c478bd9Sstevel@tonic-gate static void chan_send_ieof1(Channel *);
707c478bd9Sstevel@tonic-gate static void chan_send_oclose1(Channel *);
717c478bd9Sstevel@tonic-gate static void chan_send_close2(Channel *);
727c478bd9Sstevel@tonic-gate static void chan_send_eof2(Channel *);
73*371387faSAdam Stevko static void chan_send_eow2(Channel *);
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /* helper */
767c478bd9Sstevel@tonic-gate static void chan_shutdown_write(Channel *);
777c478bd9Sstevel@tonic-gate static void chan_shutdown_read(Channel *);
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate static char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
807c478bd9Sstevel@tonic-gate static char *istates[] = { "open", "drain", "wait_oclose", "closed" };
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate static void
chan_set_istate(Channel * c,u_int next)837c478bd9Sstevel@tonic-gate chan_set_istate(Channel *c, u_int next)
847c478bd9Sstevel@tonic-gate {
857c478bd9Sstevel@tonic-gate if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED)
867c478bd9Sstevel@tonic-gate fatal("chan_set_istate: bad state %d -> %d", c->istate, next);
877c478bd9Sstevel@tonic-gate debug("channel %d: input %s -> %s", c->self, istates[c->istate],
887c478bd9Sstevel@tonic-gate istates[next]);
897c478bd9Sstevel@tonic-gate c->istate = next;
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate static void
chan_set_ostate(Channel * c,u_int next)927c478bd9Sstevel@tonic-gate chan_set_ostate(Channel *c, u_int next)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED)
957c478bd9Sstevel@tonic-gate fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next);
967c478bd9Sstevel@tonic-gate debug("channel %d: output %s -> %s", c->self, ostates[c->ostate],
977c478bd9Sstevel@tonic-gate ostates[next]);
987c478bd9Sstevel@tonic-gate c->ostate = next;
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate * SSH1 specific implementation of event functions
1037c478bd9Sstevel@tonic-gate */
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate static void
chan_rcvd_oclose1(Channel * c)1067c478bd9Sstevel@tonic-gate chan_rcvd_oclose1(Channel *c)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate debug("channel %d: rcvd oclose", c->self);
1097c478bd9Sstevel@tonic-gate switch (c->istate) {
1107c478bd9Sstevel@tonic-gate case CHAN_INPUT_WAIT_OCLOSE:
1117c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED);
1127c478bd9Sstevel@tonic-gate break;
1137c478bd9Sstevel@tonic-gate case CHAN_INPUT_OPEN:
1147c478bd9Sstevel@tonic-gate chan_shutdown_read(c);
1157c478bd9Sstevel@tonic-gate chan_send_ieof1(c);
1167c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED);
1177c478bd9Sstevel@tonic-gate break;
1187c478bd9Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN:
1197c478bd9Sstevel@tonic-gate /* both local read_failed and remote write_failed */
1207c478bd9Sstevel@tonic-gate chan_send_ieof1(c);
1217c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED);
1227c478bd9Sstevel@tonic-gate break;
1237c478bd9Sstevel@tonic-gate default:
1247c478bd9Sstevel@tonic-gate error("channel %d: protocol error: rcvd_oclose for istate %d",
1257c478bd9Sstevel@tonic-gate c->self, c->istate);
1267c478bd9Sstevel@tonic-gate return;
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate void
chan_read_failed(Channel * c)1307c478bd9Sstevel@tonic-gate chan_read_failed(Channel *c)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate debug("channel %d: read failed", c->self);
1337c478bd9Sstevel@tonic-gate switch (c->istate) {
1347c478bd9Sstevel@tonic-gate case CHAN_INPUT_OPEN:
1357c478bd9Sstevel@tonic-gate chan_shutdown_read(c);
1367c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN);
1377c478bd9Sstevel@tonic-gate break;
1387c478bd9Sstevel@tonic-gate default:
1397c478bd9Sstevel@tonic-gate error("channel %d: chan_read_failed for istate %d",
1407c478bd9Sstevel@tonic-gate c->self, c->istate);
1417c478bd9Sstevel@tonic-gate break;
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate void
chan_ibuf_empty(Channel * c)1457c478bd9Sstevel@tonic-gate chan_ibuf_empty(Channel *c)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate debug("channel %d: ibuf empty", c->self);
1487c478bd9Sstevel@tonic-gate if (buffer_len(&c->input)) {
1497c478bd9Sstevel@tonic-gate error("channel %d: chan_ibuf_empty for non empty buffer",
1507c478bd9Sstevel@tonic-gate c->self);
1517c478bd9Sstevel@tonic-gate return;
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate switch (c->istate) {
1547c478bd9Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN:
1557c478bd9Sstevel@tonic-gate if (compat20) {
1567c478bd9Sstevel@tonic-gate if (!(c->flags & CHAN_CLOSE_SENT))
1577c478bd9Sstevel@tonic-gate chan_send_eof2(c);
1587c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED);
1597c478bd9Sstevel@tonic-gate } else {
1607c478bd9Sstevel@tonic-gate chan_send_ieof1(c);
1617c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate break;
1647c478bd9Sstevel@tonic-gate default:
1657c478bd9Sstevel@tonic-gate error("channel %d: chan_ibuf_empty for istate %d",
1667c478bd9Sstevel@tonic-gate c->self, c->istate);
1677c478bd9Sstevel@tonic-gate break;
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate static void
chan_rcvd_ieof1(Channel * c)1717c478bd9Sstevel@tonic-gate chan_rcvd_ieof1(Channel *c)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate debug("channel %d: rcvd ieof", c->self);
1747c478bd9Sstevel@tonic-gate switch (c->ostate) {
1757c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_OPEN:
1767c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
1777c478bd9Sstevel@tonic-gate break;
1787c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_IEOF:
1797c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
1807c478bd9Sstevel@tonic-gate break;
1817c478bd9Sstevel@tonic-gate default:
1827c478bd9Sstevel@tonic-gate error("channel %d: protocol error: rcvd_ieof for ostate %d",
1837c478bd9Sstevel@tonic-gate c->self, c->ostate);
1847c478bd9Sstevel@tonic-gate break;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate static void
chan_write_failed1(Channel * c)1887c478bd9Sstevel@tonic-gate chan_write_failed1(Channel *c)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate debug("channel %d: write failed", c->self);
1917c478bd9Sstevel@tonic-gate switch (c->ostate) {
1927c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_OPEN:
1937c478bd9Sstevel@tonic-gate chan_shutdown_write(c);
1947c478bd9Sstevel@tonic-gate chan_send_oclose1(c);
1957c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF);
1967c478bd9Sstevel@tonic-gate break;
1977c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_DRAIN:
1987c478bd9Sstevel@tonic-gate chan_shutdown_write(c);
1997c478bd9Sstevel@tonic-gate chan_send_oclose1(c);
2007c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
2017c478bd9Sstevel@tonic-gate break;
2027c478bd9Sstevel@tonic-gate default:
2037c478bd9Sstevel@tonic-gate error("channel %d: chan_write_failed for ostate %d",
2047c478bd9Sstevel@tonic-gate c->self, c->ostate);
2057c478bd9Sstevel@tonic-gate break;
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate void
chan_obuf_empty(Channel * c)2097c478bd9Sstevel@tonic-gate chan_obuf_empty(Channel *c)
2107c478bd9Sstevel@tonic-gate {
2117c478bd9Sstevel@tonic-gate debug("channel %d: obuf empty", c->self);
2127c478bd9Sstevel@tonic-gate if (buffer_len(&c->output)) {
2137c478bd9Sstevel@tonic-gate error("channel %d: chan_obuf_empty for non empty buffer",
2147c478bd9Sstevel@tonic-gate c->self);
2157c478bd9Sstevel@tonic-gate return;
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate switch (c->ostate) {
2187c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_DRAIN:
2197c478bd9Sstevel@tonic-gate chan_shutdown_write(c);
2207c478bd9Sstevel@tonic-gate if (!compat20)
2217c478bd9Sstevel@tonic-gate chan_send_oclose1(c);
2227c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
2237c478bd9Sstevel@tonic-gate break;
2247c478bd9Sstevel@tonic-gate default:
2257c478bd9Sstevel@tonic-gate error("channel %d: internal error: obuf_empty for ostate %d",
2267c478bd9Sstevel@tonic-gate c->self, c->ostate);
2277c478bd9Sstevel@tonic-gate break;
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate static void
chan_send_ieof1(Channel * c)2317c478bd9Sstevel@tonic-gate chan_send_ieof1(Channel *c)
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate debug("channel %d: send ieof", c->self);
2347c478bd9Sstevel@tonic-gate switch (c->istate) {
2357c478bd9Sstevel@tonic-gate case CHAN_INPUT_OPEN:
2367c478bd9Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN:
2377c478bd9Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
2387c478bd9Sstevel@tonic-gate packet_put_int(c->remote_id);
2397c478bd9Sstevel@tonic-gate packet_send();
2407c478bd9Sstevel@tonic-gate break;
2417c478bd9Sstevel@tonic-gate default:
2427c478bd9Sstevel@tonic-gate error("channel %d: cannot send ieof for istate %d",
2437c478bd9Sstevel@tonic-gate c->self, c->istate);
2447c478bd9Sstevel@tonic-gate break;
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate static void
chan_send_oclose1(Channel * c)2487c478bd9Sstevel@tonic-gate chan_send_oclose1(Channel *c)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate debug("channel %d: send oclose", c->self);
2517c478bd9Sstevel@tonic-gate switch (c->ostate) {
2527c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_OPEN:
2537c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_DRAIN:
2547c478bd9Sstevel@tonic-gate buffer_clear(&c->output);
2557c478bd9Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
2567c478bd9Sstevel@tonic-gate packet_put_int(c->remote_id);
2577c478bd9Sstevel@tonic-gate packet_send();
2587c478bd9Sstevel@tonic-gate break;
2597c478bd9Sstevel@tonic-gate default:
2607c478bd9Sstevel@tonic-gate error("channel %d: cannot send oclose for ostate %d",
2617c478bd9Sstevel@tonic-gate c->self, c->ostate);
2627c478bd9Sstevel@tonic-gate break;
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate * the same for SSH2
2687c478bd9Sstevel@tonic-gate */
2697c478bd9Sstevel@tonic-gate static void
chan_rcvd_close2(Channel * c)2707c478bd9Sstevel@tonic-gate chan_rcvd_close2(Channel *c)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate debug("channel %d: rcvd close", c->self);
2737c478bd9Sstevel@tonic-gate if (c->flags & CHAN_CLOSE_RCVD)
2747c478bd9Sstevel@tonic-gate error("channel %d: protocol error: close rcvd twice", c->self);
2757c478bd9Sstevel@tonic-gate c->flags |= CHAN_CLOSE_RCVD;
2767c478bd9Sstevel@tonic-gate if (c->type == SSH_CHANNEL_LARVAL) {
2777c478bd9Sstevel@tonic-gate /* tear down larval channels immediately */
2787c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
2797c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED);
2807c478bd9Sstevel@tonic-gate return;
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate switch (c->ostate) {
2837c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_OPEN:
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate * wait until a data from the channel is consumed if a CLOSE
2867c478bd9Sstevel@tonic-gate * is received
2877c478bd9Sstevel@tonic-gate */
2887c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
2897c478bd9Sstevel@tonic-gate break;
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate switch (c->istate) {
2927c478bd9Sstevel@tonic-gate case CHAN_INPUT_OPEN:
2937c478bd9Sstevel@tonic-gate chan_shutdown_read(c);
2947c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED);
2957c478bd9Sstevel@tonic-gate break;
2967c478bd9Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN:
2977c478bd9Sstevel@tonic-gate chan_send_eof2(c);
2987c478bd9Sstevel@tonic-gate chan_set_istate(c, CHAN_INPUT_CLOSED);
2997c478bd9Sstevel@tonic-gate break;
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate }
302*371387faSAdam Stevko void
chan_rcvd_eow(Channel * c)303*371387faSAdam Stevko chan_rcvd_eow(Channel *c)
304*371387faSAdam Stevko {
305*371387faSAdam Stevko debug2("channel %d: rcvd eow", c->self);
306*371387faSAdam Stevko switch (c->istate) {
307*371387faSAdam Stevko case CHAN_INPUT_OPEN:
308*371387faSAdam Stevko chan_shutdown_read(c);
309*371387faSAdam Stevko chan_set_istate(c, CHAN_INPUT_CLOSED);
310*371387faSAdam Stevko break;
311*371387faSAdam Stevko }
312*371387faSAdam Stevko }
3137c478bd9Sstevel@tonic-gate static void
chan_rcvd_eof2(Channel * c)3147c478bd9Sstevel@tonic-gate chan_rcvd_eof2(Channel *c)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate debug("channel %d: rcvd eof", c->self);
3177c478bd9Sstevel@tonic-gate c->flags |= CHAN_EOF_RCVD;
3187c478bd9Sstevel@tonic-gate if (c->ostate == CHAN_OUTPUT_OPEN)
3197c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate static void
chan_write_failed2(Channel * c)3227c478bd9Sstevel@tonic-gate chan_write_failed2(Channel *c)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate debug("channel %d: write failed", c->self);
3257c478bd9Sstevel@tonic-gate switch (c->ostate) {
3267c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_OPEN:
3277c478bd9Sstevel@tonic-gate case CHAN_OUTPUT_WAIT_DRAIN:
3287c478bd9Sstevel@tonic-gate chan_shutdown_write(c);
329*371387faSAdam Stevko if (strcmp(c->ctype, "session") == 0)
330*371387faSAdam Stevko chan_send_eow2(c);
3317c478bd9Sstevel@tonic-gate chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
3327c478bd9Sstevel@tonic-gate break;
3337c478bd9Sstevel@tonic-gate default:
3347c478bd9Sstevel@tonic-gate error("channel %d: chan_write_failed for ostate %d",
3357c478bd9Sstevel@tonic-gate c->self, c->ostate);
3367c478bd9Sstevel@tonic-gate break;
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate static void
chan_send_eof2(Channel * c)3407c478bd9Sstevel@tonic-gate chan_send_eof2(Channel *c)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate debug("channel %d: send eof", c->self);
3437c478bd9Sstevel@tonic-gate switch (c->istate) {
3447c478bd9Sstevel@tonic-gate case CHAN_INPUT_WAIT_DRAIN:
3457c478bd9Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_EOF);
3467c478bd9Sstevel@tonic-gate packet_put_int(c->remote_id);
3477c478bd9Sstevel@tonic-gate packet_send();
3487c478bd9Sstevel@tonic-gate c->flags |= CHAN_EOF_SENT;
3497c478bd9Sstevel@tonic-gate break;
3507c478bd9Sstevel@tonic-gate default:
3517c478bd9Sstevel@tonic-gate error("channel %d: cannot send eof for istate %d",
3527c478bd9Sstevel@tonic-gate c->self, c->istate);
3537c478bd9Sstevel@tonic-gate break;
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate static void
chan_send_close2(Channel * c)3577c478bd9Sstevel@tonic-gate chan_send_close2(Channel *c)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate debug("channel %d: send close", c->self);
3607c478bd9Sstevel@tonic-gate if (c->ostate != CHAN_OUTPUT_CLOSED ||
3617c478bd9Sstevel@tonic-gate c->istate != CHAN_INPUT_CLOSED) {
3627c478bd9Sstevel@tonic-gate error("channel %d: cannot send close for istate/ostate %d/%d",
3637c478bd9Sstevel@tonic-gate c->self, c->istate, c->ostate);
3647c478bd9Sstevel@tonic-gate } else if (c->flags & CHAN_CLOSE_SENT) {
3657c478bd9Sstevel@tonic-gate error("channel %d: already sent close", c->self);
3667c478bd9Sstevel@tonic-gate } else {
3677c478bd9Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_CLOSE);
3687c478bd9Sstevel@tonic-gate packet_put_int(c->remote_id);
3697c478bd9Sstevel@tonic-gate packet_send();
3707c478bd9Sstevel@tonic-gate c->flags |= CHAN_CLOSE_SENT;
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate }
373*371387faSAdam Stevko static void
chan_send_eow2(Channel * c)374*371387faSAdam Stevko chan_send_eow2(Channel *c)
375*371387faSAdam Stevko {
376*371387faSAdam Stevko debug2("channel %d: send eow", c->self);
377*371387faSAdam Stevko if (c->ostate == CHAN_OUTPUT_CLOSED) {
378*371387faSAdam Stevko error("channel %d: must not sent eow on closed output",
379*371387faSAdam Stevko c->self);
380*371387faSAdam Stevko return;
381*371387faSAdam Stevko }
382*371387faSAdam Stevko packet_start(SSH2_MSG_CHANNEL_REQUEST);
383*371387faSAdam Stevko packet_put_int(c->remote_id);
384*371387faSAdam Stevko packet_put_cstring("eow@openssh.com");
385*371387faSAdam Stevko packet_put_char(0);
386*371387faSAdam Stevko packet_send();
387*371387faSAdam Stevko }
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /* shared */
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate void
chan_rcvd_ieof(Channel * c)3927c478bd9Sstevel@tonic-gate chan_rcvd_ieof(Channel *c)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate if (compat20)
3957c478bd9Sstevel@tonic-gate chan_rcvd_eof2(c);
3967c478bd9Sstevel@tonic-gate else
3977c478bd9Sstevel@tonic-gate chan_rcvd_ieof1(c);
3987c478bd9Sstevel@tonic-gate if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
3997c478bd9Sstevel@tonic-gate buffer_len(&c->output) == 0 &&
4007c478bd9Sstevel@tonic-gate !CHANNEL_EFD_OUTPUT_ACTIVE(c))
4017c478bd9Sstevel@tonic-gate chan_obuf_empty(c);
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate void
chan_rcvd_oclose(Channel * c)4047c478bd9Sstevel@tonic-gate chan_rcvd_oclose(Channel *c)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate if (compat20)
4077c478bd9Sstevel@tonic-gate chan_rcvd_close2(c);
4087c478bd9Sstevel@tonic-gate else
4097c478bd9Sstevel@tonic-gate chan_rcvd_oclose1(c);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate void
chan_write_failed(Channel * c)4127c478bd9Sstevel@tonic-gate chan_write_failed(Channel *c)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate if (compat20)
4157c478bd9Sstevel@tonic-gate chan_write_failed2(c);
4167c478bd9Sstevel@tonic-gate else
4177c478bd9Sstevel@tonic-gate chan_write_failed1(c);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate void
chan_mark_dead(Channel * c)4217c478bd9Sstevel@tonic-gate chan_mark_dead(Channel *c)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate c->type = SSH_CHANNEL_ZOMBIE;
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate int
chan_is_dead(Channel * c,int send)4277c478bd9Sstevel@tonic-gate chan_is_dead(Channel *c, int send)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate if (c->type == SSH_CHANNEL_ZOMBIE) {
4307c478bd9Sstevel@tonic-gate debug("channel %d: zombie", c->self);
4317c478bd9Sstevel@tonic-gate return 1;
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
4347c478bd9Sstevel@tonic-gate return 0;
4357c478bd9Sstevel@tonic-gate if (!compat20) {
4367c478bd9Sstevel@tonic-gate debug("channel %d: is dead", c->self);
4377c478bd9Sstevel@tonic-gate return 1;
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate if ((datafellows & SSH_BUG_EXTEOF) &&
4407c478bd9Sstevel@tonic-gate c->extended_usage == CHAN_EXTENDED_WRITE &&
4417c478bd9Sstevel@tonic-gate c->efd != -1 &&
4427c478bd9Sstevel@tonic-gate buffer_len(&c->extended) > 0) {
4437c478bd9Sstevel@tonic-gate debug2("channel %d: active efd: %d len %d",
4447c478bd9Sstevel@tonic-gate c->self, c->efd, buffer_len(&c->extended));
4457c478bd9Sstevel@tonic-gate return 0;
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate if (!(c->flags & CHAN_CLOSE_SENT)) {
4487c478bd9Sstevel@tonic-gate if (send) {
4497c478bd9Sstevel@tonic-gate chan_send_close2(c);
4507c478bd9Sstevel@tonic-gate } else {
4517c478bd9Sstevel@tonic-gate /* channel would be dead if we sent a close */
4527c478bd9Sstevel@tonic-gate if (c->flags & CHAN_CLOSE_RCVD) {
4537c478bd9Sstevel@tonic-gate debug("channel %d: almost dead",
4547c478bd9Sstevel@tonic-gate c->self);
4557c478bd9Sstevel@tonic-gate return 1;
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate if ((c->flags & CHAN_CLOSE_SENT) &&
4607c478bd9Sstevel@tonic-gate (c->flags & CHAN_CLOSE_RCVD)) {
4617c478bd9Sstevel@tonic-gate debug("channel %d: is dead", c->self);
4627c478bd9Sstevel@tonic-gate return 1;
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate return 0;
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate /* helper */
4687c478bd9Sstevel@tonic-gate static void
chan_shutdown_write(Channel * c)4697c478bd9Sstevel@tonic-gate chan_shutdown_write(Channel *c)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate buffer_clear(&c->output);
4727c478bd9Sstevel@tonic-gate if (compat20 && c->type == SSH_CHANNEL_LARVAL)
4737c478bd9Sstevel@tonic-gate return;
4747c478bd9Sstevel@tonic-gate /* shutdown failure is allowed if write failed already */
4757c478bd9Sstevel@tonic-gate debug("channel %d: close_write", c->self);
4767c478bd9Sstevel@tonic-gate if (c->sock != -1) {
4777c478bd9Sstevel@tonic-gate if (shutdown(c->sock, SHUT_WR) < 0)
4787c478bd9Sstevel@tonic-gate debug("channel %d: chan_shutdown_write: "
4797c478bd9Sstevel@tonic-gate "shutdown() failed for fd%d: %.100s",
4807c478bd9Sstevel@tonic-gate c->self, c->sock, strerror(errno));
4817c478bd9Sstevel@tonic-gate } else {
4827c478bd9Sstevel@tonic-gate if (channel_close_fd(&c->wfd) < 0)
4837c478bd9Sstevel@tonic-gate log("channel %d: chan_shutdown_write: "
4847c478bd9Sstevel@tonic-gate "close() failed for fd%d: %.100s",
4857c478bd9Sstevel@tonic-gate c->self, c->wfd, strerror(errno));
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate static void
chan_shutdown_read(Channel * c)4897c478bd9Sstevel@tonic-gate chan_shutdown_read(Channel *c)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate if (compat20 && c->type == SSH_CHANNEL_LARVAL)
4927c478bd9Sstevel@tonic-gate return;
4937c478bd9Sstevel@tonic-gate debug("channel %d: close_read", c->self);
4947c478bd9Sstevel@tonic-gate if (c->sock != -1) {
4957c478bd9Sstevel@tonic-gate /*
4967c478bd9Sstevel@tonic-gate * shutdown(sock, SHUT_READ) may return ENOTCONN if the
4977c478bd9Sstevel@tonic-gate * write side has been closed already. (bug on Linux)
4987c478bd9Sstevel@tonic-gate * HP-UX may return ENOTCONN also.
4997c478bd9Sstevel@tonic-gate */
5007c478bd9Sstevel@tonic-gate if (shutdown(c->sock, SHUT_RD) < 0
5017c478bd9Sstevel@tonic-gate && errno != ENOTCONN)
5027c478bd9Sstevel@tonic-gate error("channel %d: chan_shutdown_read: "
5037c478bd9Sstevel@tonic-gate "shutdown() failed for fd%d [i%d o%d]: %.100s",
5047c478bd9Sstevel@tonic-gate c->self, c->sock, c->istate, c->ostate,
5057c478bd9Sstevel@tonic-gate strerror(errno));
5067c478bd9Sstevel@tonic-gate } else {
5077c478bd9Sstevel@tonic-gate if (channel_close_fd(&c->rfd) < 0)
5087c478bd9Sstevel@tonic-gate log("channel %d: chan_shutdown_read: "
5097c478bd9Sstevel@tonic-gate "close() failed for fd%d: %.100s",
5107c478bd9Sstevel@tonic-gate c->self, c->rfd, strerror(errno));
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate }
513