xref: /freebsd/crypto/openssh/nchan.c (revision a79b71281cd63ad7a6cc43a6d5673a2510b51630)
1 /*
2  * Copyright (c) 1999 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by Markus Friedl.
15  * 4. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "includes.h"
31 RCSID("$Id: nchan.c,v 1.17 2000/05/08 17:44:54 markus Exp $");
32 
33 #include "ssh.h"
34 
35 #include "buffer.h"
36 #include "packet.h"
37 #include "channels.h"
38 #include "nchan.h"
39 
40 #include "ssh2.h"
41 #include "compat.h"
42 
43 /* functions manipulating channel states */
44 /*
45  * EVENTS update channel input/output states execute ACTIONS
46  */
47 /* events concerning the INPUT from socket for channel (istate) */
48 chan_event_fn *chan_rcvd_oclose			= NULL;
49 chan_event_fn *chan_read_failed			= NULL;
50 chan_event_fn *chan_ibuf_empty			= NULL;
51 /* events concerning the OUTPUT from channel for socket (ostate) */
52 chan_event_fn *chan_rcvd_ieof			= NULL;
53 chan_event_fn *chan_write_failed		= NULL;
54 chan_event_fn *chan_obuf_empty			= NULL;
55 /*
56  * ACTIONS: should never update the channel states
57  */
58 static void	chan_send_ieof1(Channel *c);
59 static void	chan_send_oclose1(Channel *c);
60 static void	chan_send_close2(Channel *c);
61 static void	chan_send_eof2(Channel *c);
62 
63 /* channel cleanup */
64 chan_event_fn *chan_delete_if_full_closed	= NULL;
65 
66 /* helper */
67 static void	chan_shutdown_write(Channel *c);
68 static void	chan_shutdown_read(Channel *c);
69 
70 /*
71  * SSH1 specific implementation of event functions
72  */
73 
74 static void
75 chan_rcvd_oclose1(Channel *c)
76 {
77 	debug("channel %d: rcvd oclose", c->self);
78 	switch (c->istate) {
79 	case CHAN_INPUT_WAIT_OCLOSE:
80 		debug("channel %d: input wait_oclose -> closed", c->self);
81 		c->istate = CHAN_INPUT_CLOSED;
82 		break;
83 	case CHAN_INPUT_OPEN:
84 		debug("channel %d: input open -> closed", c->self);
85 		chan_shutdown_read(c);
86 		chan_send_ieof1(c);
87 		c->istate = CHAN_INPUT_CLOSED;
88 		break;
89 	case CHAN_INPUT_WAIT_DRAIN:
90 		/* both local read_failed and remote write_failed  */
91 		log("channel %d: input drain -> closed", c->self);
92 		chan_send_ieof1(c);
93 		c->istate = CHAN_INPUT_CLOSED;
94 		break;
95 	default:
96 		error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
97 		    c->self, c->istate);
98 		return;
99 	}
100 }
101 static void
102 chan_read_failed_12(Channel *c)
103 {
104 	debug("channel %d: read failed", c->self);
105 	switch (c->istate) {
106 	case CHAN_INPUT_OPEN:
107 		debug("channel %d: input open -> drain", c->self);
108 		chan_shutdown_read(c);
109 		c->istate = CHAN_INPUT_WAIT_DRAIN;
110 		if (buffer_len(&c->input) == 0) {
111 			debug("channel %d: input: no drain shortcut", c->self);
112 			chan_ibuf_empty(c);
113 		}
114 		break;
115 	default:
116 		error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
117 		    c->self, c->istate);
118 		break;
119 	}
120 }
121 static void
122 chan_ibuf_empty1(Channel *c)
123 {
124 	debug("channel %d: ibuf empty", c->self);
125 	if (buffer_len(&c->input)) {
126 		error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
127 		    c->self);
128 		return;
129 	}
130 	switch (c->istate) {
131 	case CHAN_INPUT_WAIT_DRAIN:
132 		debug("channel %d: input drain -> wait_oclose", c->self);
133 		chan_send_ieof1(c);
134 		c->istate = CHAN_INPUT_WAIT_OCLOSE;
135 		break;
136 	default:
137 		error("channel %d: internal error: chan_ibuf_empty for istate %d",
138 		    c->self, c->istate);
139 		break;
140 	}
141 }
142 static void
143 chan_rcvd_ieof1(Channel *c)
144 {
145 	debug("channel %d: rcvd ieof", c->self);
146 	if (c->type != SSH_CHANNEL_OPEN) {
147 		debug("channel %d: non-open", c->self);
148 		if (c->istate == CHAN_INPUT_OPEN) {
149 			debug("channel %d: non-open: input open -> wait_oclose", c->self);
150 			chan_shutdown_read(c);
151 			chan_send_ieof1(c);
152 			c->istate = CHAN_INPUT_WAIT_OCLOSE;
153 		} else {
154 			error("channel %d: istate %d != open", c->self, c->istate);
155 		}
156 		if (c->ostate == CHAN_OUTPUT_OPEN) {
157 			debug("channel %d: non-open: output open -> closed", c->self);
158 			chan_send_oclose1(c);
159 			c->ostate = CHAN_OUTPUT_CLOSED;
160 		} else {
161 			error("channel %d: ostate %d != open", c->self, c->ostate);
162 		}
163 		return;
164 	}
165 	switch (c->ostate) {
166 	case CHAN_OUTPUT_OPEN:
167 		debug("channel %d: output open -> drain", c->self);
168 		c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
169 		break;
170 	case CHAN_OUTPUT_WAIT_IEOF:
171 		debug("channel %d: output wait_ieof -> closed", c->self);
172 		c->ostate = CHAN_OUTPUT_CLOSED;
173 		break;
174 	default:
175 		error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
176 		    c->self, c->ostate);
177 		break;
178 	}
179 }
180 static void
181 chan_write_failed1(Channel *c)
182 {
183 	debug("channel %d: write failed", c->self);
184 	switch (c->ostate) {
185 	case CHAN_OUTPUT_OPEN:
186 		debug("channel %d: output open -> wait_ieof", c->self);
187 		chan_send_oclose1(c);
188 		c->ostate = CHAN_OUTPUT_WAIT_IEOF;
189 		break;
190 	case CHAN_OUTPUT_WAIT_DRAIN:
191 		debug("channel %d: output wait_drain -> closed", c->self);
192 		chan_send_oclose1(c);
193 		c->ostate = CHAN_OUTPUT_CLOSED;
194 		break;
195 	default:
196 		error("channel %d: internal error: chan_write_failed for ostate %d",
197 		    c->self, c->ostate);
198 		break;
199 	}
200 }
201 static void
202 chan_obuf_empty1(Channel *c)
203 {
204 	debug("channel %d: obuf empty", c->self);
205 	if (buffer_len(&c->output)) {
206 		error("channel %d: internal error: chan_obuf_empty for non empty buffer",
207 		    c->self);
208 		return;
209 	}
210 	switch (c->ostate) {
211 	case CHAN_OUTPUT_WAIT_DRAIN:
212 		debug("channel %d: output drain -> closed", c->self);
213 		chan_send_oclose1(c);
214 		c->ostate = CHAN_OUTPUT_CLOSED;
215 		break;
216 	default:
217 		error("channel %d: internal error: chan_obuf_empty for ostate %d",
218 		    c->self, c->ostate);
219 		break;
220 	}
221 }
222 static void
223 chan_send_ieof1(Channel *c)
224 {
225 	debug("channel %d: send ieof", c->self);
226 	switch (c->istate) {
227 	case CHAN_INPUT_OPEN:
228 	case CHAN_INPUT_WAIT_DRAIN:
229 		packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
230 		packet_put_int(c->remote_id);
231 		packet_send();
232 		break;
233 	default:
234 		error("channel %d: internal error: cannot send ieof for istate %d",
235 		    c->self, c->istate);
236 		break;
237 	}
238 }
239 static void
240 chan_send_oclose1(Channel *c)
241 {
242 	debug("channel %d: send oclose", c->self);
243 	switch (c->ostate) {
244 	case CHAN_OUTPUT_OPEN:
245 	case CHAN_OUTPUT_WAIT_DRAIN:
246 		chan_shutdown_write(c);
247 		buffer_consume(&c->output, buffer_len(&c->output));
248 		packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
249 		packet_put_int(c->remote_id);
250 		packet_send();
251 		break;
252 	default:
253 		error("channel %d: internal error: cannot send oclose for ostate %d",
254 		     c->self, c->ostate);
255 		break;
256 	}
257 }
258 static void
259 chan_delete_if_full_closed1(Channel *c)
260 {
261 	if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
262 		debug("channel %d: full closed", c->self);
263 		channel_free(c->self);
264 	}
265 }
266 
267 /*
268  * the same for SSH2
269  */
270 static void
271 chan_rcvd_oclose2(Channel *c)
272 {
273 	debug("channel %d: rcvd close", c->self);
274 	if (c->flags & CHAN_CLOSE_RCVD)
275 		error("channel %d: protocol error: close rcvd twice", c->self);
276 	c->flags |= CHAN_CLOSE_RCVD;
277 	if (c->type == SSH_CHANNEL_LARVAL) {
278 		/* tear down larval channels immediately */
279 		c->ostate = CHAN_OUTPUT_CLOSED;
280 		c->istate = CHAN_INPUT_CLOSED;
281 		return;
282 	}
283 	switch (c->ostate) {
284 	case CHAN_OUTPUT_OPEN:
285 		/* wait until a data from the channel is consumed if a CLOSE is received */
286 		debug("channel %d: output open -> drain", c->self);
287 		c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
288 		break;
289 	}
290 	switch (c->istate) {
291 	case CHAN_INPUT_OPEN:
292 		debug("channel %d: input open -> closed", c->self);
293 		chan_shutdown_read(c);
294 		break;
295 	case CHAN_INPUT_WAIT_DRAIN:
296 		debug("channel %d: input drain -> closed", c->self);
297 		chan_send_eof2(c);
298 		break;
299 	}
300 	c->istate = CHAN_INPUT_CLOSED;
301 }
302 static void
303 chan_ibuf_empty2(Channel *c)
304 {
305 	debug("channel %d: ibuf empty", c->self);
306 	if (buffer_len(&c->input)) {
307 		error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
308 		     c->self);
309 		return;
310 	}
311 	switch (c->istate) {
312 	case CHAN_INPUT_WAIT_DRAIN:
313 		debug("channel %d: input drain -> closed", c->self);
314 		if (!(c->flags & CHAN_CLOSE_SENT))
315 			chan_send_eof2(c);
316 		c->istate = CHAN_INPUT_CLOSED;
317 		break;
318 	default:
319 		error("channel %d: internal error: chan_ibuf_empty for istate %d",
320 		     c->self, c->istate);
321 		break;
322 	}
323 }
324 static void
325 chan_rcvd_ieof2(Channel *c)
326 {
327 	debug("channel %d: rcvd eof", c->self);
328 	if (c->ostate == CHAN_OUTPUT_OPEN) {
329 		debug("channel %d: output open -> drain", c->self);
330 		c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
331 	}
332 }
333 static void
334 chan_write_failed2(Channel *c)
335 {
336 	debug("channel %d: write failed", c->self);
337 	switch (c->ostate) {
338 	case CHAN_OUTPUT_OPEN:
339 		debug("channel %d: output open -> closed", c->self);
340 		chan_shutdown_write(c); /* ?? */
341 		c->ostate = CHAN_OUTPUT_CLOSED;
342 		break;
343 	case CHAN_OUTPUT_WAIT_DRAIN:
344 		debug("channel %d: output drain -> closed", c->self);
345 		chan_shutdown_write(c);
346 		c->ostate = CHAN_OUTPUT_CLOSED;
347 		break;
348 	default:
349 		error("channel %d: internal error: chan_write_failed for ostate %d",
350 		    c->self, c->ostate);
351 		break;
352 	}
353 }
354 static void
355 chan_obuf_empty2(Channel *c)
356 {
357 	debug("channel %d: obuf empty", c->self);
358 	if (buffer_len(&c->output)) {
359 		error("internal error: chan_obuf_empty %d for non empty buffer",
360 		    c->self);
361 		return;
362 	}
363 	switch (c->ostate) {
364 	case CHAN_OUTPUT_WAIT_DRAIN:
365 		debug("channel %d: output drain -> closed", c->self);
366 		chan_shutdown_write(c);
367 		c->ostate = CHAN_OUTPUT_CLOSED;
368 		break;
369 	default:
370 		error("channel %d: internal error: chan_obuf_empty for ostate %d",
371 		    c->self, c->ostate);
372 		break;
373 	}
374 }
375 static void
376 chan_send_eof2(Channel *c)
377 {
378 	debug("channel %d: send eof", c->self);
379 	switch (c->istate) {
380 	case CHAN_INPUT_WAIT_DRAIN:
381 		packet_start(SSH2_MSG_CHANNEL_EOF);
382 		packet_put_int(c->remote_id);
383 		packet_send();
384 		break;
385 	default:
386 		error("channel %d: internal error: cannot send eof for istate %d",
387 		    c->self, c->istate);
388 		break;
389 	}
390 }
391 static void
392 chan_send_close2(Channel *c)
393 {
394 	debug("channel %d: send close", c->self);
395 	if (c->ostate != CHAN_OUTPUT_CLOSED ||
396 	    c->istate != CHAN_INPUT_CLOSED) {
397 		error("channel %d: internal error: cannot send close for istate/ostate %d/%d",
398 		    c->self, c->istate, c->ostate);
399 	} else if (c->flags & CHAN_CLOSE_SENT) {
400 		error("channel %d: internal error: already sent close", c->self);
401 	} else {
402 		packet_start(SSH2_MSG_CHANNEL_CLOSE);
403 		packet_put_int(c->remote_id);
404 		packet_send();
405 		c->flags |= CHAN_CLOSE_SENT;
406 	}
407 }
408 static void
409 chan_delete_if_full_closed2(Channel *c)
410 {
411 	if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
412 		if (!(c->flags & CHAN_CLOSE_SENT)) {
413 			chan_send_close2(c);
414 		}
415 		if ((c->flags & CHAN_CLOSE_SENT) &&
416 		    (c->flags & CHAN_CLOSE_RCVD)) {
417 			debug("channel %d: full closed2", c->self);
418 			channel_free(c->self);
419 		}
420 	}
421 }
422 
423 /* shared */
424 void
425 chan_init_iostates(Channel *c)
426 {
427 	c->ostate = CHAN_OUTPUT_OPEN;
428 	c->istate = CHAN_INPUT_OPEN;
429 	c->flags = 0;
430 }
431 
432 /* init */
433 void
434 chan_init(void)
435 {
436 	if (compat20) {
437 		chan_rcvd_oclose		= chan_rcvd_oclose2;
438 		chan_read_failed		= chan_read_failed_12;
439 		chan_ibuf_empty			= chan_ibuf_empty2;
440 
441 		chan_rcvd_ieof			= chan_rcvd_ieof2;
442 		chan_write_failed		= chan_write_failed2;
443 		chan_obuf_empty			= chan_obuf_empty2;
444 
445 		chan_delete_if_full_closed	= chan_delete_if_full_closed2;
446 	} else {
447 		chan_rcvd_oclose		= chan_rcvd_oclose1;
448 		chan_read_failed		= chan_read_failed_12;
449 		chan_ibuf_empty			= chan_ibuf_empty1;
450 
451 		chan_rcvd_ieof			= chan_rcvd_ieof1;
452 		chan_write_failed		= chan_write_failed1;
453 		chan_obuf_empty			= chan_obuf_empty1;
454 
455 		chan_delete_if_full_closed	= chan_delete_if_full_closed1;
456 	}
457 }
458 
459 /* helper */
460 static void
461 chan_shutdown_write(Channel *c)
462 {
463 	buffer_consume(&c->output, buffer_len(&c->output));
464 	if (compat20 && c->type == SSH_CHANNEL_LARVAL)
465 		return;
466 	/* shutdown failure is allowed if write failed already */
467 	debug("channel %d: close_write", c->self);
468 	if (c->sock != -1) {
469 		if (shutdown(c->sock, SHUT_WR) < 0)
470 			debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
471 			    c->self, c->sock, strerror(errno));
472 	} else {
473 		if (close(c->wfd) < 0)
474 			log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
475 			    c->self, c->wfd, strerror(errno));
476 		c->wfd = -1;
477 	}
478 }
479 static void
480 chan_shutdown_read(Channel *c)
481 {
482 	if (compat20 && c->type == SSH_CHANNEL_LARVAL)
483 		return;
484 	debug("channel %d: close_read", c->self);
485 	if (c->sock != -1) {
486 		if (shutdown(c->sock, SHUT_RD) < 0)
487 			error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
488 			    c->self, c->sock, c->istate, c->ostate, strerror(errno));
489 	} else {
490 		if (close(c->rfd) < 0)
491 			log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
492 			    c->self, c->rfd, strerror(errno));
493 		c->rfd = -1;
494 	}
495 }
496