1204917Sdes/* $OpenBSD: nchan.c,v 1.63 2010/01/26 01:28:35 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) {
164204917Sdes			if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
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);
281204917Sdes	if (!(c->flags & CHAN_LOCAL)) {
282204917Sdes		if (c->flags & CHAN_CLOSE_RCVD)
283204917Sdes			error("channel %d: protocol error: close rcvd twice",
284204917Sdes			    c->self);
285204917Sdes		c->flags |= CHAN_CLOSE_RCVD;
286204917Sdes	}
28760573Skris	if (c->type == SSH_CHANNEL_LARVAL) {
28860573Skris		/* tear down larval channels immediately */
28992555Sdes		chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
29092555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
29160573Skris		return;
29260573Skris	}
29360573Skris	switch (c->ostate) {
29460573Skris	case CHAN_OUTPUT_OPEN:
29592555Sdes		/*
29692555Sdes		 * wait until a data from the channel is consumed if a CLOSE
29792555Sdes		 * is received
29892555Sdes		 */
29992555Sdes		chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
30060573Skris		break;
30160573Skris	}
30260573Skris	switch (c->istate) {
30360573Skris	case CHAN_INPUT_OPEN:
30460573Skris		chan_shutdown_read(c);
30592555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
30660573Skris		break;
30760573Skris	case CHAN_INPUT_WAIT_DRAIN:
308204917Sdes		if (!(c->flags & CHAN_LOCAL))
309204917Sdes			chan_send_eof2(c);
31092555Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
31160573Skris		break;
31260573Skris	}
31357429Smarkm}
314204917Sdes
315181111Sdesvoid
316181111Sdeschan_rcvd_eow(Channel *c)
317181111Sdes{
318181111Sdes	debug2("channel %d: rcvd eow", c->self);
319181111Sdes	switch (c->istate) {
320181111Sdes	case CHAN_INPUT_OPEN:
321181111Sdes		chan_shutdown_read(c);
322181111Sdes		chan_set_istate(c, CHAN_INPUT_CLOSED);
323181111Sdes		break;
324181111Sdes	}
325181111Sdes}
32657429Smarkmstatic void
32792555Sdeschan_rcvd_eof2(Channel *c)
32857429Smarkm{
329124208Sdes	debug2("channel %d: rcvd eof", c->self);
33098675Sdes	c->flags |= CHAN_EOF_RCVD;
33192555Sdes	if (c->ostate == CHAN_OUTPUT_OPEN)
33292555Sdes		chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
33360573Skris}
33460573Skrisstatic void
33560573Skrischan_write_failed2(Channel *c)
33660573Skris{
337124208Sdes	debug2("channel %d: write failed", c->self);
33860573Skris	switch (c->ostate) {
33960573Skris	case CHAN_OUTPUT_OPEN:
34060573Skris	case CHAN_OUTPUT_WAIT_DRAIN:
34160573Skris		chan_shutdown_write(c);
342181111Sdes		if (strcmp(c->ctype, "session") == 0)
343181111Sdes			chan_send_eow2(c);
34492555Sdes		chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
34560573Skris		break;
34660573Skris	default:
34792555Sdes		error("channel %d: chan_write_failed for ostate %d",
34860573Skris		    c->self, c->ostate);
34960573Skris		break;
35060573Skris	}
35160573Skris}
35260573Skrisstatic void
35360573Skrischan_send_eof2(Channel *c)
35460573Skris{
355124208Sdes	debug2("channel %d: send eof", c->self);
35660573Skris	switch (c->istate) {
35760573Skris	case CHAN_INPUT_WAIT_DRAIN:
35860573Skris		packet_start(SSH2_MSG_CHANNEL_EOF);
35960573Skris		packet_put_int(c->remote_id);
36060573Skris		packet_send();
36198675Sdes		c->flags |= CHAN_EOF_SENT;
36260573Skris		break;
36360573Skris	default:
36492555Sdes		error("channel %d: cannot send eof for istate %d",
36560573Skris		    c->self, c->istate);
36660573Skris		break;
36760573Skris	}
36860573Skris}
36960573Skrisstatic void
37060573Skrischan_send_close2(Channel *c)
37160573Skris{
372124208Sdes	debug2("channel %d: send close", c->self);
37360573Skris	if (c->ostate != CHAN_OUTPUT_CLOSED ||
37460573Skris	    c->istate != CHAN_INPUT_CLOSED) {
37592555Sdes		error("channel %d: cannot send close for istate/ostate %d/%d",
37660573Skris		    c->self, c->istate, c->ostate);
37760573Skris	} else if (c->flags & CHAN_CLOSE_SENT) {
37892555Sdes		error("channel %d: already sent close", c->self);
37960573Skris	} else {
38060573Skris		packet_start(SSH2_MSG_CHANNEL_CLOSE);
38160573Skris		packet_put_int(c->remote_id);
38260573Skris		packet_send();
38360573Skris		c->flags |= CHAN_CLOSE_SENT;
38460573Skris	}
38560573Skris}
386181111Sdesstatic void
387181111Sdeschan_send_eow2(Channel *c)
388181111Sdes{
389181111Sdes	debug2("channel %d: send eow", c->self);
390181111Sdes	if (c->ostate == CHAN_OUTPUT_CLOSED) {
391181111Sdes		error("channel %d: must not sent eow on closed output",
392181111Sdes		    c->self);
393181111Sdes		return;
394181111Sdes	}
395192595Sdes	if (!(datafellows & SSH_NEW_OPENSSH))
396192595Sdes		return;
397181111Sdes	packet_start(SSH2_MSG_CHANNEL_REQUEST);
398181111Sdes	packet_put_int(c->remote_id);
399181111Sdes	packet_put_cstring("eow@openssh.com");
400181111Sdes	packet_put_char(0);
401181111Sdes	packet_send();
402181111Sdes}
40376259Sgreen
40476259Sgreen/* shared */
40576259Sgreen
40692555Sdesvoid
40792555Sdeschan_rcvd_ieof(Channel *c)
40892555Sdes{
40992555Sdes	if (compat20)
41092555Sdes		chan_rcvd_eof2(c);
41192555Sdes	else
41292555Sdes		chan_rcvd_ieof1(c);
41392555Sdes	if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
41498675Sdes	    buffer_len(&c->output) == 0 &&
41598675Sdes	    !CHANNEL_EFD_OUTPUT_ACTIVE(c))
41692555Sdes		chan_obuf_empty(c);
41792555Sdes}
41892555Sdesvoid
41992555Sdeschan_rcvd_oclose(Channel *c)
42092555Sdes{
42192555Sdes	if (compat20)
42292555Sdes		chan_rcvd_close2(c);
42392555Sdes	else
42492555Sdes		chan_rcvd_oclose1(c);
42592555Sdes}
42692555Sdesvoid
42792555Sdeschan_write_failed(Channel *c)
42892555Sdes{
42992555Sdes	if (compat20)
43092555Sdes		chan_write_failed2(c);
43192555Sdes	else
43292555Sdes		chan_write_failed1(c);
43392555Sdes}
43492555Sdes
43592555Sdesvoid
43692555Sdeschan_mark_dead(Channel *c)
43792555Sdes{
43892555Sdes	c->type = SSH_CHANNEL_ZOMBIE;
43992555Sdes}
44092555Sdes
44176259Sgreenint
442137015Sdeschan_is_dead(Channel *c, int do_send)
44360573Skris{
44492555Sdes	if (c->type == SSH_CHANNEL_ZOMBIE) {
445124208Sdes		debug2("channel %d: zombie", c->self);
44692555Sdes		return 1;
44792555Sdes	}
44876259Sgreen	if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
44976259Sgreen		return 0;
45076259Sgreen	if (!compat20) {
451124208Sdes		debug2("channel %d: is dead", c->self);
45276259Sgreen		return 1;
45376259Sgreen	}
45498675Sdes	if ((datafellows & SSH_BUG_EXTEOF) &&
45598675Sdes	    c->extended_usage == CHAN_EXTENDED_WRITE &&
45698675Sdes	    c->efd != -1 &&
45798675Sdes	    buffer_len(&c->extended) > 0) {
45898675Sdes		debug2("channel %d: active efd: %d len %d",
45998675Sdes		    c->self, c->efd, buffer_len(&c->extended));
46098675Sdes		return 0;
46198675Sdes	}
462204917Sdes	if (c->flags & CHAN_LOCAL) {
463204917Sdes		debug2("channel %d: is dead (local)", c->self);
464204917Sdes		return 1;
465204917Sdes	}
46698675Sdes	if (!(c->flags & CHAN_CLOSE_SENT)) {
467137015Sdes		if (do_send) {
46898675Sdes			chan_send_close2(c);
46998675Sdes		} else {
47098675Sdes			/* channel would be dead if we sent a close */
47198675Sdes			if (c->flags & CHAN_CLOSE_RCVD) {
472124208Sdes				debug2("channel %d: almost dead",
47398675Sdes				    c->self);
47498675Sdes				return 1;
47592555Sdes			}
47660573Skris		}
47757429Smarkm	}
47898675Sdes	if ((c->flags & CHAN_CLOSE_SENT) &&
47998675Sdes	    (c->flags & CHAN_CLOSE_RCVD)) {
480124208Sdes		debug2("channel %d: is dead", c->self);
48198675Sdes		return 1;
48298675Sdes	}
48376259Sgreen	return 0;
48457429Smarkm}
48560573Skris
48660573Skris/* helper */
48760573Skrisstatic void
48860573Skrischan_shutdown_write(Channel *c)
48960573Skris{
49092555Sdes	buffer_clear(&c->output);
49160573Skris	if (compat20 && c->type == SSH_CHANNEL_LARVAL)
49260573Skris		return;
49360573Skris	/* shutdown failure is allowed if write failed already */
494124208Sdes	debug2("channel %d: close_write", c->self);
49560573Skris	if (c->sock != -1) {
49660573Skris		if (shutdown(c->sock, SHUT_WR) < 0)
497124208Sdes			debug2("channel %d: chan_shutdown_write: "
498192595Sdes			    "shutdown() failed for fd %d: %.100s",
49960573Skris			    c->self, c->sock, strerror(errno));
50060573Skris	} else {
50192555Sdes		if (channel_close_fd(&c->wfd) < 0)
502124208Sdes			logit("channel %d: chan_shutdown_write: "
503192595Sdes			    "close() failed for fd %d: %.100s",
50460573Skris			    c->self, c->wfd, strerror(errno));
50560573Skris	}
50660573Skris}
50760573Skrisstatic void
50860573Skrischan_shutdown_read(Channel *c)
50960573Skris{
51060573Skris	if (compat20 && c->type == SSH_CHANNEL_LARVAL)
51160573Skris		return;
512124208Sdes	debug2("channel %d: close_read", c->self);
51360573Skris	if (c->sock != -1) {
51498937Sdes		/*
51598937Sdes		 * shutdown(sock, SHUT_READ) may return ENOTCONN if the
51698937Sdes		 * write side has been closed already. (bug on Linux)
51798937Sdes		 * HP-UX may return ENOTCONN also.
51898937Sdes		 */
51998937Sdes		if (shutdown(c->sock, SHUT_RD) < 0
52098937Sdes		    && errno != ENOTCONN)
52192555Sdes			error("channel %d: chan_shutdown_read: "
522192595Sdes			    "shutdown() failed for fd %d [i%d o%d]: %.100s",
52392555Sdes			    c->self, c->sock, c->istate, c->ostate,
52492555Sdes			    strerror(errno));
52560573Skris	} else {
52692555Sdes		if (channel_close_fd(&c->rfd) < 0)
527124208Sdes			logit("channel %d: chan_shutdown_read: "
528192595Sdes			    "close() failed for fd %d: %.100s",
52960573Skris			    c->self, c->rfd, strerror(errno));
53060573Skris	}
53160573Skris}
532