Annotation of src/crypto/external/bsd/openssh/dist/nchan.c, Revision 1.1.1.2
1.1 christos 1: /* $NetBSD$ */
1.1.1.2 ! adam 2: /* $OpenBSD: nchan.c,v 1.63 2010/01/26 01:28:35 djm Exp $ */
1.1 christos 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) {
1.1.1.2 ! adam 163: if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
1.1 christos 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);
1.1.1.2 ! adam 280: if (!(c->flags & CHAN_LOCAL)) {
! 281: if (c->flags & CHAN_CLOSE_RCVD)
! 282: error("channel %d: protocol error: close rcvd twice",
! 283: c->self);
! 284: c->flags |= CHAN_CLOSE_RCVD;
! 285: }
1.1 christos 286: if (c->type == SSH_CHANNEL_LARVAL) {
287: /* tear down larval channels immediately */
288: chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
289: chan_set_istate(c, CHAN_INPUT_CLOSED);
290: return;
291: }
292: switch (c->ostate) {
293: case CHAN_OUTPUT_OPEN:
294: /*
295: * wait until a data from the channel is consumed if a CLOSE
296: * is received
297: */
298: chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
299: break;
300: }
301: switch (c->istate) {
302: case CHAN_INPUT_OPEN:
303: chan_shutdown_read(c);
304: chan_set_istate(c, CHAN_INPUT_CLOSED);
305: break;
306: case CHAN_INPUT_WAIT_DRAIN:
1.1.1.2 ! adam 307: if (!(c->flags & CHAN_LOCAL))
! 308: chan_send_eof2(c);
1.1 christos 309: chan_set_istate(c, CHAN_INPUT_CLOSED);
310: break;
311: }
312: }
1.1.1.2 ! adam 313:
1.1 christos 314: void
315: chan_rcvd_eow(Channel *c)
316: {
317: debug2("channel %d: rcvd eow", c->self);
318: switch (c->istate) {
319: case CHAN_INPUT_OPEN:
320: chan_shutdown_read(c);
321: chan_set_istate(c, CHAN_INPUT_CLOSED);
322: break;
323: }
324: }
325: static void
326: chan_rcvd_eof2(Channel *c)
327: {
328: debug2("channel %d: rcvd eof", c->self);
329: c->flags |= CHAN_EOF_RCVD;
330: if (c->ostate == CHAN_OUTPUT_OPEN)
331: chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
332: }
333: static void
334: chan_write_failed2(Channel *c)
335: {
336: debug2("channel %d: write failed", c->self);
337: switch (c->ostate) {
338: case CHAN_OUTPUT_OPEN:
339: case CHAN_OUTPUT_WAIT_DRAIN:
340: chan_shutdown_write(c);
341: if (strcmp(c->ctype, "session") == 0)
342: chan_send_eow2(c);
343: chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
344: break;
345: default:
346: error("channel %d: chan_write_failed for ostate %d",
347: c->self, c->ostate);
348: break;
349: }
350: }
351: static void
352: chan_send_eof2(Channel *c)
353: {
354: debug2("channel %d: send eof", c->self);
355: switch (c->istate) {
356: case CHAN_INPUT_WAIT_DRAIN:
357: packet_start(SSH2_MSG_CHANNEL_EOF);
358: packet_put_int(c->remote_id);
359: packet_send();
360: c->flags |= CHAN_EOF_SENT;
361: break;
362: default:
363: error("channel %d: cannot send eof for istate %d",
364: c->self, c->istate);
365: break;
366: }
367: }
368: static void
369: chan_send_close2(Channel *c)
370: {
371: debug2("channel %d: send close", c->self);
372: if (c->ostate != CHAN_OUTPUT_CLOSED ||
373: c->istate != CHAN_INPUT_CLOSED) {
374: error("channel %d: cannot send close for istate/ostate %d/%d",
375: c->self, c->istate, c->ostate);
376: } else if (c->flags & CHAN_CLOSE_SENT) {
377: error("channel %d: already sent close", c->self);
378: } else {
379: packet_start(SSH2_MSG_CHANNEL_CLOSE);
380: packet_put_int(c->remote_id);
381: packet_send();
382: c->flags |= CHAN_CLOSE_SENT;
383: }
384: }
385: static void
386: chan_send_eow2(Channel *c)
387: {
388: debug2("channel %d: send eow", c->self);
389: if (c->ostate == CHAN_OUTPUT_CLOSED) {
390: error("channel %d: must not sent eow on closed output",
391: c->self);
392: return;
393: }
394: if (!(datafellows & SSH_NEW_OPENSSH))
395: return;
396: packet_start(SSH2_MSG_CHANNEL_REQUEST);
397: packet_put_int(c->remote_id);
398: packet_put_cstring("eow@openssh.com");
399: packet_put_char(0);
400: packet_send();
401: }
402:
403: /* shared */
404:
405: void
406: chan_rcvd_ieof(Channel *c)
407: {
408: if (compat20)
409: chan_rcvd_eof2(c);
410: else
411: chan_rcvd_ieof1(c);
412: if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
413: buffer_len(&c->output) == 0 &&
414: !CHANNEL_EFD_OUTPUT_ACTIVE(c))
415: chan_obuf_empty(c);
416: }
417: void
418: chan_rcvd_oclose(Channel *c)
419: {
420: if (compat20)
421: chan_rcvd_close2(c);
422: else
423: chan_rcvd_oclose1(c);
424: }
425: void
426: chan_write_failed(Channel *c)
427: {
428: if (compat20)
429: chan_write_failed2(c);
430: else
431: chan_write_failed1(c);
432: }
433:
434: void
435: chan_mark_dead(Channel *c)
436: {
437: c->type = SSH_CHANNEL_ZOMBIE;
438: }
439:
440: int
441: chan_is_dead(Channel *c, int do_send)
442: {
443: if (c->type == SSH_CHANNEL_ZOMBIE) {
444: debug2("channel %d: zombie", c->self);
445: return 1;
446: }
447: if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
448: return 0;
449: if (!compat20) {
450: debug2("channel %d: is dead", c->self);
451: return 1;
452: }
453: if ((datafellows & SSH_BUG_EXTEOF) &&
454: c->extended_usage == CHAN_EXTENDED_WRITE &&
455: c->efd != -1 &&
456: buffer_len(&c->extended) > 0) {
457: debug2("channel %d: active efd: %d len %d",
458: c->self, c->efd, buffer_len(&c->extended));
459: return 0;
460: }
1.1.1.2 ! adam 461: if (c->flags & CHAN_LOCAL) {
! 462: debug2("channel %d: is dead (local)", c->self);
! 463: return 1;
! 464: }
1.1 christos 465: if (!(c->flags & CHAN_CLOSE_SENT)) {
466: if (do_send) {
467: chan_send_close2(c);
468: } else {
469: /* channel would be dead if we sent a close */
470: if (c->flags & CHAN_CLOSE_RCVD) {
471: debug2("channel %d: almost dead",
472: c->self);
473: return 1;
474: }
475: }
476: }
477: if ((c->flags & CHAN_CLOSE_SENT) &&
478: (c->flags & CHAN_CLOSE_RCVD)) {
479: debug2("channel %d: is dead", c->self);
480: return 1;
481: }
482: return 0;
483: }
484:
485: /* helper */
486: static void
487: chan_shutdown_write(Channel *c)
488: {
489: buffer_clear(&c->output);
490: if (compat20 && c->type == SSH_CHANNEL_LARVAL)
491: return;
492: /* shutdown failure is allowed if write failed already */
493: debug2("channel %d: close_write", c->self);
494: if (c->sock != -1) {
495: if (shutdown(c->sock, SHUT_WR) < 0)
496: debug2("channel %d: chan_shutdown_write: "
497: "shutdown() failed for fd %d: %.100s",
498: c->self, c->sock, strerror(errno));
499: } else {
500: if (channel_close_fd(&c->wfd) < 0)
501: logit("channel %d: chan_shutdown_write: "
502: "close() failed for fd %d: %.100s",
503: c->self, c->wfd, strerror(errno));
504: }
505: }
506: static void
507: chan_shutdown_read(Channel *c)
508: {
509: if (compat20 && c->type == SSH_CHANNEL_LARVAL)
510: return;
511: debug2("channel %d: close_read", c->self);
512: if (c->sock != -1) {
513: if (shutdown(c->sock, SHUT_RD) < 0)
514: error("channel %d: chan_shutdown_read: "
515: "shutdown() failed for fd %d [i%d o%d]: %.100s",
516: c->self, c->sock, c->istate, c->ostate,
517: strerror(errno));
518: } else {
519: if (channel_close_fd(&c->rfd) < 0)
520: logit("channel %d: chan_shutdown_read: "
521: "close() failed for fd %d: %.100s",
522: c->self, c->rfd, strerror(errno));
523: }
524: }
CVSweb <webmaster@jp.NetBSD.org>