]> andersk Git - openssh.git/blob - nchan.c
- markus@cvs.openbsd.org 2001/06/25 08:25:41
[openssh.git] / nchan.c
1 /*
2  * Copyright (c) 1999, 2000, 2001 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  *
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
25 #include "includes.h"
26 RCSID("$OpenBSD: nchan.c,v 1.30 2001/06/25 08:25:38 markus Exp $");
27
28 #include "ssh1.h"
29 #include "ssh2.h"
30 #include "buffer.h"
31 #include "packet.h"
32 #include "channels.h"
33 #include "compat.h"
34 #include "log.h"
35
36 /*
37  * SSH Protocol 1.5 aka New Channel Protocol
38  * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
39  * Written by Markus Friedl in October 1999
40  *
41  * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
42  * tear down of channels:
43  *
44  * 1.3: strict request-ack-protocol:
45  *      CLOSE   ->
46  *              <-  CLOSE_CONFIRM
47  *
48  * 1.5: uses variations of:
49  *      IEOF    ->
50  *              <-  OCLOSE
51  *              <-  IEOF
52  *      OCLOSE  ->
53  *      i.e. both sides have to close the channel
54  *
55  * 2.0: the EOF messages are optional
56  *
57  * See the debugging output from 'ssh -v' and 'sshd -d' of
58  * ssh-1.2.27 as an example.
59  *
60  */
61  
62 /* functions manipulating channel states */
63 /*
64  * EVENTS update channel input/output states execute ACTIONS
65  */
66 /* events concerning the INPUT from socket for channel (istate) */
67 chan_event_fn *chan_rcvd_oclose                 = NULL;
68 chan_event_fn *chan_read_failed                 = NULL;
69 chan_event_fn *chan_ibuf_empty                  = NULL;
70 /* events concerning the OUTPUT from channel for socket (ostate) */
71 chan_event_fn *chan_rcvd_ieof                   = NULL;
72 chan_event_fn *chan_write_failed                = NULL;
73 chan_event_fn *chan_obuf_empty                  = NULL;
74 /*
75  * ACTIONS: should never update the channel states
76  */
77 static void     chan_send_ieof1(Channel *);
78 static void     chan_send_oclose1(Channel *);
79 static void     chan_send_close2(Channel *);
80 static void     chan_send_eof2(Channel *);
81
82 /* helper */
83 static void     chan_shutdown_write(Channel *);
84 static void     chan_shutdown_read(Channel *);
85
86 /*
87  * SSH1 specific implementation of event functions
88  */
89
90 static void
91 chan_rcvd_oclose1(Channel *c)
92 {
93         debug("channel %d: rcvd oclose", c->self);
94         switch (c->istate) {
95         case CHAN_INPUT_WAIT_OCLOSE:
96                 debug("channel %d: input wait_oclose -> closed", c->self);
97                 c->istate = CHAN_INPUT_CLOSED;
98                 break;
99         case CHAN_INPUT_OPEN:
100                 debug("channel %d: input open -> closed", c->self);
101                 chan_shutdown_read(c);
102                 chan_send_ieof1(c);
103                 c->istate = CHAN_INPUT_CLOSED;
104                 break;
105         case CHAN_INPUT_WAIT_DRAIN:
106                 /* both local read_failed and remote write_failed  */
107                 log("channel %d: input drain -> closed", c->self);
108                 chan_send_ieof1(c);
109                 c->istate = CHAN_INPUT_CLOSED;
110                 break;
111         default:
112                 error("channel %d: protocol error: rcvd_oclose for istate %d",
113                     c->self, c->istate);
114                 return;
115         }
116 }
117 static void
118 chan_read_failed_12(Channel *c)
119 {
120         debug("channel %d: read failed", c->self);
121         switch (c->istate) {
122         case CHAN_INPUT_OPEN:
123                 debug("channel %d: input open -> drain", c->self);
124                 chan_shutdown_read(c);
125                 c->istate = CHAN_INPUT_WAIT_DRAIN;
126 #if 0
127                 if (buffer_len(&c->input) == 0) {
128                         debug("channel %d: input: no drain shortcut", c->self);
129                         chan_ibuf_empty(c);
130                 }
131 #endif
132                 break;
133         default:
134                 error("channel %d: chan_read_failed for istate %d",
135                     c->self, c->istate);
136                 break;
137         }
138 }
139 static void
140 chan_ibuf_empty1(Channel *c)
141 {
142         debug("channel %d: ibuf empty", c->self);
143         if (buffer_len(&c->input)) {
144                 error("channel %d: chan_ibuf_empty for non empty buffer",
145                     c->self);
146                 return;
147         }
148         switch (c->istate) {
149         case CHAN_INPUT_WAIT_DRAIN:
150                 debug("channel %d: input drain -> wait_oclose", c->self);
151                 chan_send_ieof1(c);
152                 c->istate = CHAN_INPUT_WAIT_OCLOSE;
153                 break;
154         default:
155                 error("channel %d: chan_ibuf_empty for istate %d",
156                     c->self, c->istate);
157                 break;
158         }
159 }
160 static void
161 chan_rcvd_ieof1(Channel *c)
162 {
163         debug("channel %d: rcvd ieof", c->self);
164         if (c->type != SSH_CHANNEL_OPEN) {
165                 debug("channel %d: non-open", c->self);
166                 if (c->istate == CHAN_INPUT_OPEN) {
167                         debug("channel %d: non-open: input open -> wait_oclose",
168                             c->self);
169                         chan_shutdown_read(c);
170                         chan_send_ieof1(c);
171                         c->istate = CHAN_INPUT_WAIT_OCLOSE;
172                 } else {
173                         error("channel %d: non-open: istate %d != open",
174                             c->self, c->istate);
175                 }
176                 if (c->ostate == CHAN_OUTPUT_OPEN) {
177                         debug("channel %d: non-open: output open -> closed",
178                             c->self);
179                         chan_send_oclose1(c);
180                         c->ostate = CHAN_OUTPUT_CLOSED;
181                 } else {
182                         error("channel %d: non-open: ostate %d != open",
183                             c->self, c->ostate);
184                 }
185                 return;
186         }
187         switch (c->ostate) {
188         case CHAN_OUTPUT_OPEN:
189                 debug("channel %d: output open -> drain", c->self);
190                 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
191                 break;
192         case CHAN_OUTPUT_WAIT_IEOF:
193                 debug("channel %d: output wait_ieof -> closed", c->self);
194                 c->ostate = CHAN_OUTPUT_CLOSED;
195                 break;
196         default:
197                 error("channel %d: protocol error: rcvd_ieof for ostate %d",
198                     c->self, c->ostate);
199                 break;
200         }
201 }
202 static void
203 chan_write_failed1(Channel *c)
204 {
205         debug("channel %d: write failed", c->self);
206         switch (c->ostate) {
207         case CHAN_OUTPUT_OPEN:
208                 debug("channel %d: output open -> wait_ieof", c->self);
209                 chan_send_oclose1(c);
210                 c->ostate = CHAN_OUTPUT_WAIT_IEOF;
211                 break;
212         case CHAN_OUTPUT_WAIT_DRAIN:
213                 debug("channel %d: output wait_drain -> closed", c->self);
214                 chan_send_oclose1(c);
215                 c->ostate = CHAN_OUTPUT_CLOSED;
216                 break;
217         default:
218                 error("channel %d: chan_write_failed for ostate %d",
219                     c->self, c->ostate);
220                 break;
221         }
222 }
223 static void
224 chan_obuf_empty1(Channel *c)
225 {
226         debug("channel %d: obuf empty", c->self);
227         if (buffer_len(&c->output)) {
228                 error("channel %d: chan_obuf_empty for non empty buffer",
229                     c->self);
230                 return;
231         }
232         switch (c->ostate) {
233         case CHAN_OUTPUT_WAIT_DRAIN:
234                 debug("channel %d: output drain -> closed", c->self);
235                 chan_send_oclose1(c);
236                 c->ostate = CHAN_OUTPUT_CLOSED;
237                 break;
238         default:
239                 error("channel %d: internal error: obuf_empty for ostate %d",
240                     c->self, c->ostate);
241                 break;
242         }
243 }
244 static void
245 chan_send_ieof1(Channel *c)
246 {
247         debug("channel %d: send ieof", c->self);
248         switch (c->istate) {
249         case CHAN_INPUT_OPEN:
250         case CHAN_INPUT_WAIT_DRAIN:
251                 packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
252                 packet_put_int(c->remote_id);
253                 packet_send();
254                 break;
255         default:
256                 error("channel %d: cannot send ieof for istate %d",
257                     c->self, c->istate);
258                 break;
259         }
260 }
261 static void
262 chan_send_oclose1(Channel *c)
263 {
264         debug("channel %d: send oclose", c->self);
265         switch (c->ostate) {
266         case CHAN_OUTPUT_OPEN:
267         case CHAN_OUTPUT_WAIT_DRAIN:
268                 chan_shutdown_write(c);
269                 buffer_consume(&c->output, buffer_len(&c->output));
270                 packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
271                 packet_put_int(c->remote_id);
272                 packet_send();
273                 break;
274         default:
275                 error("channel %d: cannot send oclose for ostate %d",
276                      c->self, c->ostate);
277                 break;
278         }
279 }
280
281 /*
282  * the same for SSH2
283  */
284 static void
285 chan_rcvd_oclose2(Channel *c)
286 {
287         debug("channel %d: rcvd close", c->self);
288         if (c->flags & CHAN_CLOSE_RCVD)
289                 error("channel %d: protocol error: close rcvd twice", c->self);
290         c->flags |= CHAN_CLOSE_RCVD;
291         if (c->type == SSH_CHANNEL_LARVAL) {
292                 /* tear down larval channels immediately */
293                 c->ostate = CHAN_OUTPUT_CLOSED;
294                 c->istate = CHAN_INPUT_CLOSED;
295                 return;
296         }
297         switch (c->ostate) {
298         case CHAN_OUTPUT_OPEN:
299                 /*
300                  * wait until a data from the channel is consumed if a CLOSE
301                  * is received
302                  */
303                 debug("channel %d: output open -> drain", c->self);
304                 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
305                 break;
306         }
307         switch (c->istate) {
308         case CHAN_INPUT_OPEN:
309                 debug("channel %d: input open -> closed", c->self);
310                 chan_shutdown_read(c);
311                 break;
312         case CHAN_INPUT_WAIT_DRAIN:
313                 debug("channel %d: input drain -> closed", c->self);
314                 chan_send_eof2(c);
315                 break;
316         }
317         c->istate = CHAN_INPUT_CLOSED;
318 }
319 static void
320 chan_ibuf_empty2(Channel *c)
321 {
322         debug("channel %d: ibuf empty", c->self);
323         if (buffer_len(&c->input)) {
324                 error("channel %d: chan_ibuf_empty for non empty buffer",
325                      c->self);
326                 return;
327         }
328         switch (c->istate) {
329         case CHAN_INPUT_WAIT_DRAIN:
330                 debug("channel %d: input drain -> closed", c->self);
331                 if (!(c->flags & CHAN_CLOSE_SENT))
332                         chan_send_eof2(c);
333                 c->istate = CHAN_INPUT_CLOSED;
334                 break;
335         default:
336                 error("channel %d: chan_ibuf_empty for istate %d",
337                      c->self, c->istate);
338                 break;
339         }
340 }
341 static void
342 chan_rcvd_ieof2(Channel *c)
343 {
344         debug("channel %d: rcvd eof", c->self);
345         if (c->ostate == CHAN_OUTPUT_OPEN) {
346                 debug("channel %d: output open -> drain", c->self);
347                 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
348         }
349 }
350 static void
351 chan_write_failed2(Channel *c)
352 {
353         debug("channel %d: write failed", c->self);
354         switch (c->ostate) {
355         case CHAN_OUTPUT_OPEN:
356                 debug("channel %d: output open -> closed", c->self);
357                 chan_shutdown_write(c); /* ?? */
358                 c->ostate = CHAN_OUTPUT_CLOSED;
359                 break;
360         case CHAN_OUTPUT_WAIT_DRAIN:
361                 debug("channel %d: output drain -> closed", c->self);
362                 chan_shutdown_write(c);
363                 c->ostate = CHAN_OUTPUT_CLOSED;
364                 break;
365         default:
366                 error("channel %d: chan_write_failed for ostate %d",
367                     c->self, c->ostate);
368                 break;
369         }
370 }
371 static void
372 chan_obuf_empty2(Channel *c)
373 {
374         debug("channel %d: obuf empty", c->self);
375         if (buffer_len(&c->output)) {
376                 error("channel %d: chan_obuf_empty for non empty buffer",
377                     c->self);
378                 return;
379         }
380         switch (c->ostate) {
381         case CHAN_OUTPUT_WAIT_DRAIN:
382                 debug("channel %d: output drain -> closed", c->self);
383                 chan_shutdown_write(c);
384                 c->ostate = CHAN_OUTPUT_CLOSED;
385                 break;
386         default:
387                 error("channel %d: chan_obuf_empty for ostate %d",
388                     c->self, c->ostate);
389                 break;
390         }
391 }
392 static void
393 chan_send_eof2(Channel *c)
394 {
395         debug("channel %d: send eof", c->self);
396         switch (c->istate) {
397         case CHAN_INPUT_WAIT_DRAIN:
398                 packet_start(SSH2_MSG_CHANNEL_EOF);
399                 packet_put_int(c->remote_id);
400                 packet_send();
401                 break;
402         default:
403                 error("channel %d: cannot send eof for istate %d",
404                     c->self, c->istate);
405                 break;
406         }
407 }
408 static void
409 chan_send_close2(Channel *c)
410 {
411         debug("channel %d: send close", c->self);
412         if (c->ostate != CHAN_OUTPUT_CLOSED ||
413             c->istate != CHAN_INPUT_CLOSED) {
414                 error("channel %d: cannot send close for istate/ostate %d/%d",
415                     c->self, c->istate, c->ostate);
416         } else if (c->flags & CHAN_CLOSE_SENT) {
417                 error("channel %d: already sent close", c->self);
418         } else {
419                 packet_start(SSH2_MSG_CHANNEL_CLOSE);
420                 packet_put_int(c->remote_id);
421                 packet_send();
422                 c->flags |= CHAN_CLOSE_SENT;
423         }
424 }
425
426 /* shared */
427
428 void
429 chan_mark_dead(Channel *c)
430 {
431         c->type = SSH_CHANNEL_ZOMBIE;
432 }
433
434 int
435 chan_is_dead(Channel *c)
436 {
437         if (c->type == SSH_CHANNEL_ZOMBIE) {
438                 debug("channel %d: zombie", c->self);
439                 return 1;
440         }
441         if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
442                 return 0;
443         if (!compat20) {
444                 debug("channel %d: is dead", c->self);
445                 return 1;
446         }
447         /*
448          * we have to delay the close message if the efd (for stderr) is
449          * still active
450          */
451         if (((c->extended_usage != CHAN_EXTENDED_IGNORE) &&
452             buffer_len(&c->extended) > 0)
453 #if 0
454             || ((c->extended_usage == CHAN_EXTENDED_READ) &&
455             c->efd != -1)
456 #endif
457             ) {
458                 debug2("channel %d: active efd: %d len %d type %s",
459                     c->self, c->efd, buffer_len(&c->extended),
460                     c->extended_usage==CHAN_EXTENDED_READ ?
461                        "read": "write");
462         } else {
463                 if (!(c->flags & CHAN_CLOSE_SENT)) {
464                         chan_send_close2(c);
465                 }
466                 if ((c->flags & CHAN_CLOSE_SENT) &&
467                     (c->flags & CHAN_CLOSE_RCVD)) {
468                         debug("channel %d: is dead", c->self);
469                         return 1;
470                 }
471         }
472         return 0;
473 }
474
475 void
476 chan_init_iostates(Channel *c)
477 {
478         c->ostate = CHAN_OUTPUT_OPEN;
479         c->istate = CHAN_INPUT_OPEN;
480         c->flags = 0;
481 }
482
483 /* init */
484 void
485 chan_init(void)
486 {
487         if (compat20) {
488                 chan_rcvd_oclose                = chan_rcvd_oclose2;
489                 chan_read_failed                = chan_read_failed_12;
490                 chan_ibuf_empty                 = chan_ibuf_empty2;
491
492                 chan_rcvd_ieof                  = chan_rcvd_ieof2;
493                 chan_write_failed               = chan_write_failed2;
494                 chan_obuf_empty                 = chan_obuf_empty2;
495         } else {
496                 chan_rcvd_oclose                = chan_rcvd_oclose1;
497                 chan_read_failed                = chan_read_failed_12;
498                 chan_ibuf_empty                 = chan_ibuf_empty1;
499
500                 chan_rcvd_ieof                  = chan_rcvd_ieof1;
501                 chan_write_failed               = chan_write_failed1;
502                 chan_obuf_empty                 = chan_obuf_empty1;
503         }
504 }
505
506 /* helper */
507 static void
508 chan_shutdown_write(Channel *c)
509 {
510         buffer_consume(&c->output, buffer_len(&c->output));
511         if (compat20 && c->type == SSH_CHANNEL_LARVAL)
512                 return;
513         /* shutdown failure is allowed if write failed already */
514         debug("channel %d: close_write", c->self);
515         if (c->sock != -1) {
516                 if (shutdown(c->sock, SHUT_WR) < 0)
517                         debug("channel %d: chan_shutdown_write: "
518                             "shutdown() failed for fd%d: %.100s",
519                             c->self, c->sock, strerror(errno));
520         } else {
521                 if (close(c->wfd) < 0)
522                         log("channel %d: chan_shutdown_write: "
523                             "close() failed for fd%d: %.100s",
524                             c->self, c->wfd, strerror(errno));
525                 c->wfd = -1;
526         }
527 }
528 static void
529 chan_shutdown_read(Channel *c)
530 {
531         if (compat20 && c->type == SSH_CHANNEL_LARVAL)
532                 return;
533         debug("channel %d: close_read", c->self);
534         if (c->sock != -1) {
535                 /*
536                  * shutdown(sock, SHUT_READ) may return ENOTCONN if the
537                  * write side has been closed already. (bug on Linux)
538                  * HP-UX will return EINVAL.
539                  */
540                 if (shutdown(c->sock, SHUT_RD) < 0
541                     && (errno != ENOTCONN && errno != EINVAL))
542                         error("channel %d: chan_shutdown_read: "
543                             "shutdown() failed for fd%d [i%d o%d]: %.100s",
544                             c->self, c->sock, c->istate, c->ostate,
545                             strerror(errno));
546         } else {
547                 if (close(c->rfd) < 0)
548                         log("channel %d: chan_shutdown_read: "
549                             "close() failed for fd%d: %.100s",
550                             c->self, c->rfd, strerror(errno));
551                 c->rfd = -1;
552         }
553 }
This page took 0.241584 seconds and 5 git commands to generate.