xref: /freebsd/crypto/openssh/nchan.c (revision 2f513db72b034fd5ef7f080b11be5c711c15186a)
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