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