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