nchan.c revision 181111
1181111Sdes/* $OpenBSD: nchan.c,v 1.60 2008/06/30 12:16:02 djm Exp $ */
257429Smarkm/*
392555Sdes * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl.  All rights reserved.
457429Smarkm *
557429Smarkm * Redistribution and use in source and binary forms, with or without
657429Smarkm * modification, are permitted provided that the following conditions
757429Smarkm * are met:
857429Smarkm * 1. Redistributions of source code must retain the above copyright
957429Smarkm *    notice, this list of conditions and the following disclaimer.
1057429Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1157429Smarkm *    notice, this list of conditions and the following disclaimer in the
1257429Smarkm *    documentation and/or other materials provided with the distribution.
1357429Smarkm *
1457429Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1557429Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1657429Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1757429Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1857429Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1957429Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2057429Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2157429Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2257429Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2357429Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2457429Smarkm */
2557429Smarkm
2657429Smarkm#include "includes.h"
2757429Smarkm
28162852Sdes#include <sys/types.h>
29162852Sdes#include <sys/socket.h>
30162852Sdes
31162852Sdes#include <errno.h>
32162852Sdes#include <string.h>
33162852Sdes#include <stdarg.h>
34162852Sdes
35181111Sdes#include "openbsd-compat/sys-queue.h"
3676259Sgreen#include "ssh1.h"
3776259Sgreen#include "ssh2.h"
3857429Smarkm#include "buffer.h"
3957429Smarkm#include "packet.h"
4057429Smarkm#include "channels.h"
4160573Skris#include "compat.h"
4276259Sgreen#include "log.h"
4357429Smarkm
4492555Sdes/*
4592555Sdes * SSH Protocol 1.5 aka New Channel Protocol
4692555Sdes * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
4792555Sdes * Written by Markus Friedl in October 1999
4892555Sdes *
4992555Sdes * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
5092555Sdes * tear down of channels:
5192555Sdes *
5292555Sdes * 1.3:	strict request-ack-protocol:
53137015Sdes *	CLOSE	->
54137015Sdes *		<-  CLOSE_CONFIRM
5592555Sdes *
5692555Sdes * 1.5:	uses variations of:
57137015Sdes *	IEOF	->
58137015Sdes *		<-  OCLOSE
59137015Sdes *		<-  IEOF
60137015Sdes *	OCLOSE	->
61137015Sdes *	i.e. both sides have to close the channel
6292555Sdes *
6392555Sdes * 2.0: the EOF messages are optional
6492555Sdes *
6592555Sdes * See the debugging output from 'ssh -v' and 'sshd -d' of
6692555Sdes * ssh-1.2.27 as an example.
6792555Sdes *
6892555Sdes */
6992555Sdes
7060573Skris/* functions manipulating channel states */
7157429Smarkm/*
7257429Smarkm * EVENTS update channel input/output states execute ACTIONS
7357429Smarkm */
7460573Skris/*
7560573Skris * ACTIONS: should never update the channel states
7660573Skris */
7792555Sdesstatic void	chan_send_ieof1(Channel *);
7892555Sdesstatic void	chan_send_oclose1(Channel *);
7992555Sdesstatic void	chan_send_close2(Channel *);
8092555Sdesstatic void	chan_send_eof2(Channel *);
81181111Sdesstatic void	chan_send_eow2(Channel *);
8257429Smarkm
8360573Skris/* helper */
8492555Sdesstatic void	chan_shutdown_write(Channel *);
8592555Sdesstatic void	chan_shutdown_read(Channel *);
8660573Skris
8792555Sdesstatic char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
8892555Sdesstatic char *istates[] = { "open", "drain", "wait_oclose", "closed" };
8992555Sdes
9092555Sdesstatic void
9192555Sdeschan_set_istate(Channel *c, u_int next)
9292555Sdes{
9392555Sdes	if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED)
9492555Sdes		fatal("chan_set_istate: bad state %d -> %d", c->istate, next);
95124208Sdes	debug2("channel %d: input %s -> %s", c->self, istates[c->istate],
9692555Sdes	    istates[next]);
9792555Sdes	c->istate = next;
9892555Sdes}
9992555Sdesstatic void
10092555Sdeschan_set_ostate(Channel *c, u_int next)
10192555Sdes{
10292555Sdes	if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED)
10392555Sdes		fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next);
104124208Sdes	debug2("channel %d: output %s -> %s", c->self, ostates[c->ostate],
10592555Sdes	    ostates[next]);
10692555Sdes	c->ostate = next;
10792555Sdes}
10892555Sdes
10960573Skris/*
11060573Skris * SSH1 specific implementation of event functions
11160573Skris */
11260573Skris
11360573Skrisstatic void
11460573Skrischan_rcvd_oclose1(Channel *c)
11557429Smarkm{
116124208Sdes	debug2("channel %d: rcvd oclose", c->self);
11757429Smarkm	switch (c->istate) {
11857429Smarkm	case CHAN_INPUT_WAIT_OCLOSE:
11992555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
12057429Smarkm		break;
12157429Smarkm	case CHAN_INPUT_OPEN:
12257429Smarkm		chan_shutdown_read(c);
12360573Skris		chan_send_ieof1(c);
12492555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
12557429Smarkm		break;
12657429Smarkm	case CHAN_INPUT_WAIT_DRAIN:
12757429Smarkm		/* both local read_failed and remote write_failed  */
12860573Skris		chan_send_ieof1(c);
12992555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
13057429Smarkm		break;
13157429Smarkm	default:
13292555Sdes		error("channel %d: protocol error: rcvd_oclose for istate %d",
13360573Skris		    c->self, c->istate);
13457429Smarkm		return;
13557429Smarkm	}
13657429Smarkm}
13792555Sdesvoid
13892555Sdeschan_read_failed(Channel *c)
13957429Smarkm{
140124208Sdes	debug2("channel %d: read failed", c->self);
14157429Smarkm	switch (c->istate) {
14257429Smarkm	case CHAN_INPUT_OPEN:
14357429Smarkm		chan_shutdown_read(c);
14492555Sdes		chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN);
14557429Smarkm		break;
14657429Smarkm	default:
14792555Sdes		error("channel %d: chan_read_failed for istate %d",
14860573Skris		    c->self, c->istate);
14957429Smarkm		break;
15057429Smarkm	}
15157429Smarkm}
15292555Sdesvoid
15392555Sdeschan_ibuf_empty(Channel *c)
15457429Smarkm{
155124208Sdes	debug2("channel %d: ibuf empty", c->self);
15657429Smarkm	if (buffer_len(&c->input)) {
15792555Sdes		error("channel %d: chan_ibuf_empty for non empty buffer",
15860573Skris		    c->self);
15957429Smarkm		return;
16057429Smarkm	}
16157429Smarkm	switch (c->istate) {
16257429Smarkm	case CHAN_INPUT_WAIT_DRAIN:
16392555Sdes		if (compat20) {
16492555Sdes			if (!(c->flags & CHAN_CLOSE_SENT))
16592555Sdes				chan_send_eof2(c);
16692555Sdes			chan_set_istate(c, CHAN_INPUT_CLOSED);
16792555Sdes		} else {
16892555Sdes			chan_send_ieof1(c);
16992555Sdes			chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE);
17092555Sdes		}
17157429Smarkm		break;
17257429Smarkm	default:
17392555Sdes		error("channel %d: chan_ibuf_empty for istate %d",
17460573Skris		    c->self, c->istate);
17557429Smarkm		break;
17657429Smarkm	}
17757429Smarkm}
17860573Skrisstatic void
17960573Skrischan_rcvd_ieof1(Channel *c)
18057429Smarkm{
181124208Sdes	debug2("channel %d: rcvd ieof", c->self);
18257429Smarkm	switch (c->ostate) {
18357429Smarkm	case CHAN_OUTPUT_OPEN:
18492555Sdes		chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
18557429Smarkm		break;
18657429Smarkm	case CHAN_OUTPUT_WAIT_IEOF:
18792555Sdes		chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
18857429Smarkm		break;
18957429Smarkm	default:
19092555Sdes		error("channel %d: protocol error: rcvd_ieof for ostate %d",
19160573Skris		    c->self, c->ostate);
19257429Smarkm		break;
19357429Smarkm	}
19457429Smarkm}
19560573Skrisstatic void
19660573Skrischan_write_failed1(Channel *c)
19757429Smarkm{
198124208Sdes	debug2("channel %d: write failed", c->self);
19957429Smarkm	switch (c->ostate) {
20057429Smarkm	case CHAN_OUTPUT_OPEN:
20192555Sdes		chan_shutdown_write(c);
20260573Skris		chan_send_oclose1(c);
20392555Sdes		chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF);
20457429Smarkm		break;
20557429Smarkm	case CHAN_OUTPUT_WAIT_DRAIN:
20692555Sdes		chan_shutdown_write(c);
20760573Skris		chan_send_oclose1(c);
20892555Sdes		chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
20957429Smarkm		break;
21057429Smarkm	default:
21192555Sdes		error("channel %d: chan_write_failed for ostate %d",
21260573Skris		    c->self, c->ostate);
21357429Smarkm		break;
21457429Smarkm	}
21557429Smarkm}
21692555Sdesvoid
21792555Sdeschan_obuf_empty(Channel *c)
21857429Smarkm{
219124208Sdes	debug2("channel %d: obuf empty", c->self);
22057429Smarkm	if (buffer_len(&c->output)) {
22192555Sdes		error("channel %d: chan_obuf_empty for non empty buffer",
22260573Skris		    c->self);
22357429Smarkm		return;
22457429Smarkm	}
22557429Smarkm	switch (c->ostate) {
22657429Smarkm	case CHAN_OUTPUT_WAIT_DRAIN:
22792555Sdes		chan_shutdown_write(c);
22892555Sdes		if (!compat20)
22992555Sdes			chan_send_oclose1(c);
23092555Sdes		chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
23157429Smarkm		break;
23257429Smarkm	default:
23392555Sdes		error("channel %d: internal error: obuf_empty for ostate %d",
23460573Skris		    c->self, c->ostate);
23557429Smarkm		break;
23657429Smarkm	}
23757429Smarkm}
23857429Smarkmstatic void
23960573Skrischan_send_ieof1(Channel *c)
24057429Smarkm{
241124208Sdes	debug2("channel %d: send ieof", c->self);
24257429Smarkm	switch (c->istate) {
24357429Smarkm	case CHAN_INPUT_OPEN:
24457429Smarkm	case CHAN_INPUT_WAIT_DRAIN:
24557429Smarkm		packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
24657429Smarkm		packet_put_int(c->remote_id);
24757429Smarkm		packet_send();
24857429Smarkm		break;
24957429Smarkm	default:
25092555Sdes		error("channel %d: cannot send ieof for istate %d",
25160573Skris		    c->self, c->istate);
25257429Smarkm		break;
25357429Smarkm	}
25457429Smarkm}
25557429Smarkmstatic void
25660573Skrischan_send_oclose1(Channel *c)
25757429Smarkm{
258124208Sdes	debug2("channel %d: send oclose", c->self);
25957429Smarkm	switch (c->ostate) {
26057429Smarkm	case CHAN_OUTPUT_OPEN:
26157429Smarkm	case CHAN_OUTPUT_WAIT_DRAIN:
26292555Sdes		buffer_clear(&c->output);
26357429Smarkm		packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
26457429Smarkm		packet_put_int(c->remote_id);
26557429Smarkm		packet_send();
26657429Smarkm		break;
26757429Smarkm	default:
26892555Sdes		error("channel %d: cannot send oclose for ostate %d",
26992555Sdes		    c->self, c->ostate);
27057429Smarkm		break;
27157429Smarkm	}
27257429Smarkm}
27357429Smarkm
27460573Skris/*
27560573Skris * the same for SSH2
27660573Skris */
27757429Smarkmstatic void
27892555Sdeschan_rcvd_close2(Channel *c)
27957429Smarkm{
280124208Sdes	debug2("channel %d: rcvd close", c->self);
28160573Skris	if (c->flags & CHAN_CLOSE_RCVD)
28260573Skris		error("channel %d: protocol error: close rcvd twice", c->self);
28360573Skris	c->flags |= CHAN_CLOSE_RCVD;
28460573Skris	if (c->type == SSH_CHANNEL_LARVAL) {
28560573Skris		/* tear down larval channels immediately */
28692555Sdes		chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
28792555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
28860573Skris		return;
28960573Skris	}
29060573Skris	switch (c->ostate) {
29160573Skris	case CHAN_OUTPUT_OPEN:
29292555Sdes		/*
29392555Sdes		 * wait until a data from the channel is consumed if a CLOSE
29492555Sdes		 * is received
29592555Sdes		 */
29692555Sdes		chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
29760573Skris		break;
29860573Skris	}
29960573Skris	switch (c->istate) {
30060573Skris	case CHAN_INPUT_OPEN:
30160573Skris		chan_shutdown_read(c);
30292555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
30360573Skris		break;
30460573Skris	case CHAN_INPUT_WAIT_DRAIN:
30560573Skris		chan_send_eof2(c);
30692555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
30760573Skris		break;
30860573Skris	}
30957429Smarkm}
310181111Sdesvoid
311181111Sdeschan_rcvd_eow(Channel *c)
312181111Sdes{
313181111Sdes	debug2("channel %d: rcvd eow", c->self);
314181111Sdes	switch (c->istate) {
315181111Sdes	case CHAN_INPUT_OPEN:
316181111Sdes		chan_shutdown_read(c);
317181111Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
318181111Sdes		break;
319181111Sdes	}
320181111Sdes}
32157429Smarkmstatic void
32292555Sdeschan_rcvd_eof2(Channel *c)
32357429Smarkm{
324124208Sdes	debug2("channel %d: rcvd eof", c->self);
32598675Sdes	c->flags |= CHAN_EOF_RCVD;
32692555Sdes	if (c->ostate == CHAN_OUTPUT_OPEN)
32792555Sdes		chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
32860573Skris}
32960573Skrisstatic void
33060573Skrischan_write_failed2(Channel *c)
33160573Skris{
332124208Sdes	debug2("channel %d: write failed", c->self);
33360573Skris	switch (c->ostate) {
33460573Skris	case CHAN_OUTPUT_OPEN:
33560573Skris	case CHAN_OUTPUT_WAIT_DRAIN:
33660573Skris		chan_shutdown_write(c);
337181111Sdes		if (strcmp(c->ctype, "session") == 0)
338181111Sdes			chan_send_eow2(c);
33992555Sdes		chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
34060573Skris		break;
34160573Skris	default:
34292555Sdes		error("channel %d: chan_write_failed for ostate %d",
34360573Skris		    c->self, c->ostate);
34460573Skris		break;
34560573Skris	}
34660573Skris}
34760573Skrisstatic void
34860573Skrischan_send_eof2(Channel *c)
34960573Skris{
350124208Sdes	debug2("channel %d: send eof", c->self);
35160573Skris	switch (c->istate) {
35260573Skris	case CHAN_INPUT_WAIT_DRAIN:
35360573Skris		packet_start(SSH2_MSG_CHANNEL_EOF);
35460573Skris		packet_put_int(c->remote_id);
35560573Skris		packet_send();
35698675Sdes		c->flags |= CHAN_EOF_SENT;
35760573Skris		break;
35860573Skris	default:
35992555Sdes		error("channel %d: cannot send eof for istate %d",
36060573Skris		    c->self, c->istate);
36160573Skris		break;
36260573Skris	}
36360573Skris}
36460573Skrisstatic void
36560573Skrischan_send_close2(Channel *c)
36660573Skris{
367124208Sdes	debug2("channel %d: send close", c->self);
36860573Skris	if (c->ostate != CHAN_OUTPUT_CLOSED ||
36960573Skris	    c->istate != CHAN_INPUT_CLOSED) {
37092555Sdes		error("channel %d: cannot send close for istate/ostate %d/%d",
37160573Skris		    c->self, c->istate, c->ostate);
37260573Skris	} else if (c->flags & CHAN_CLOSE_SENT) {
37392555Sdes		error("channel %d: already sent close", c->self);
37460573Skris	} else {
37560573Skris		packet_start(SSH2_MSG_CHANNEL_CLOSE);
37660573Skris		packet_put_int(c->remote_id);
37760573Skris		packet_send();
37860573Skris		c->flags |= CHAN_CLOSE_SENT;
37960573Skris	}
38060573Skris}
381181111Sdesstatic void
382181111Sdeschan_send_eow2(Channel *c)
383181111Sdes{
384181111Sdes	debug2("channel %d: send eow", c->self);
385181111Sdes	if (c->ostate == CHAN_OUTPUT_CLOSED) {
386181111Sdes		error("channel %d: must not sent eow on closed output",
387181111Sdes		    c->self);
388181111Sdes		return;
389181111Sdes	}
390181111Sdes	packet_start(SSH2_MSG_CHANNEL_REQUEST);
391181111Sdes	packet_put_int(c->remote_id);
392181111Sdes	packet_put_cstring("eow@openssh.com");
393181111Sdes	packet_put_char(0);
394181111Sdes	packet_send();
395181111Sdes}
39676259Sgreen
39776259Sgreen/* shared */
39876259Sgreen
39992555Sdesvoid
40092555Sdeschan_rcvd_ieof(Channel *c)
40192555Sdes{
40292555Sdes	if (compat20)
40392555Sdes		chan_rcvd_eof2(c);
40492555Sdes	else
40592555Sdes		chan_rcvd_ieof1(c);
40692555Sdes	if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
40798675Sdes	    buffer_len(&c->output) == 0 &&
40898675Sdes	    !CHANNEL_EFD_OUTPUT_ACTIVE(c))
40992555Sdes		chan_obuf_empty(c);
41092555Sdes}
41192555Sdesvoid
41292555Sdeschan_rcvd_oclose(Channel *c)
41392555Sdes{
41492555Sdes	if (compat20)
41592555Sdes		chan_rcvd_close2(c);
41692555Sdes	else
41792555Sdes		chan_rcvd_oclose1(c);
41892555Sdes}
41992555Sdesvoid
42092555Sdeschan_write_failed(Channel *c)
42192555Sdes{
42292555Sdes	if (compat20)
42392555Sdes		chan_write_failed2(c);
42492555Sdes	else
42592555Sdes		chan_write_failed1(c);
42692555Sdes}
42792555Sdes
42892555Sdesvoid
42992555Sdeschan_mark_dead(Channel *c)
43092555Sdes{
43192555Sdes	c->type = SSH_CHANNEL_ZOMBIE;
43292555Sdes}
43392555Sdes
43476259Sgreenint
435137015Sdeschan_is_dead(Channel *c, int do_send)
43660573Skris{
43792555Sdes	if (c->type == SSH_CHANNEL_ZOMBIE) {
438124208Sdes		debug2("channel %d: zombie", c->self);
43992555Sdes		return 1;
44092555Sdes	}
44176259Sgreen	if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
44276259Sgreen		return 0;
44376259Sgreen	if (!compat20) {
444124208Sdes		debug2("channel %d: is dead", c->self);
44576259Sgreen		return 1;
44676259Sgreen	}
44798675Sdes	if ((datafellows & SSH_BUG_EXTEOF) &&
44898675Sdes	    c->extended_usage == CHAN_EXTENDED_WRITE &&
44998675Sdes	    c->efd != -1 &&
45098675Sdes	    buffer_len(&c->extended) > 0) {
45198675Sdes		debug2("channel %d: active efd: %d len %d",
45298675Sdes		    c->self, c->efd, buffer_len(&c->extended));
45398675Sdes		return 0;
45498675Sdes	}
45598675Sdes	if (!(c->flags & CHAN_CLOSE_SENT)) {
456137015Sdes		if (do_send) {
45798675Sdes			chan_send_close2(c);
45898675Sdes		} else {
45998675Sdes			/* channel would be dead if we sent a close */
46098675Sdes			if (c->flags & CHAN_CLOSE_RCVD) {
461124208Sdes				debug2("channel %d: almost dead",
46298675Sdes				    c->self);
46398675Sdes				return 1;
46492555Sdes			}
46560573Skris		}
46657429Smarkm	}
46798675Sdes	if ((c->flags & CHAN_CLOSE_SENT) &&
46898675Sdes	    (c->flags & CHAN_CLOSE_RCVD)) {
469124208Sdes		debug2("channel %d: is dead", c->self);
47098675Sdes		return 1;
47198675Sdes	}
47276259Sgreen	return 0;
47357429Smarkm}
47460573Skris
47560573Skris/* helper */
47660573Skrisstatic void
47760573Skrischan_shutdown_write(Channel *c)
47860573Skris{
47992555Sdes	buffer_clear(&c->output);
48060573Skris	if (compat20 && c->type == SSH_CHANNEL_LARVAL)
48160573Skris		return;
48260573Skris	/* shutdown failure is allowed if write failed already */
483124208Sdes	debug2("channel %d: close_write", c->self);
48460573Skris	if (c->sock != -1) {
48560573Skris		if (shutdown(c->sock, SHUT_WR) < 0)
486124208Sdes			debug2("channel %d: chan_shutdown_write: "
48792555Sdes			    "shutdown() failed for fd%d: %.100s",
48860573Skris			    c->self, c->sock, strerror(errno));
48960573Skris	} else {
49092555Sdes		if (channel_close_fd(&c->wfd) < 0)
491124208Sdes			logit("channel %d: chan_shutdown_write: "
49292555Sdes			    "close() failed for fd%d: %.100s",
49360573Skris			    c->self, c->wfd, strerror(errno));
49460573Skris	}
49560573Skris}
49660573Skrisstatic void
49760573Skrischan_shutdown_read(Channel *c)
49860573Skris{
49960573Skris	if (compat20 && c->type == SSH_CHANNEL_LARVAL)
50060573Skris		return;
501124208Sdes	debug2("channel %d: close_read", c->self);
50260573Skris	if (c->sock != -1) {
50398937Sdes		/*
50498937Sdes		 * shutdown(sock, SHUT_READ) may return ENOTCONN if the
50598937Sdes		 * write side has been closed already. (bug on Linux)
50698937Sdes		 * HP-UX may return ENOTCONN also.
50798937Sdes		 */
50898937Sdes		if (shutdown(c->sock, SHUT_RD) < 0
50998937Sdes		    && errno != ENOTCONN)
51092555Sdes			error("channel %d: chan_shutdown_read: "
51192555Sdes			    "shutdown() failed for fd%d [i%d o%d]: %.100s",
51292555Sdes			    c->self, c->sock, c->istate, c->ostate,
51392555Sdes			    strerror(errno));
51460573Skris	} else {
51592555Sdes		if (channel_close_fd(&c->rfd) < 0)
516124208Sdes			logit("channel %d: chan_shutdown_read: "
51792555Sdes			    "close() failed for fd%d: %.100s",
51860573Skris			    c->self, c->rfd, strerror(errno));
51960573Skris	}
52060573Skris}
521