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