4 * Copyright (c) 2002-2004 Matt Johnston
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 /* Handle the multiplexed channels, such as sessions, x11, agent connections */
32 #include "circbuffer.h"
39 static void send_msg_channel_open_failure(unsigned int remotechan
, int reason
,
40 const unsigned char *text
, const unsigned char *lang
);
41 static void send_msg_channel_open_confirmation(struct Channel
* channel
,
42 unsigned int recvwindow
,
43 unsigned int recvmaxpacket
);
44 static void writechannel(struct Channel
* channel
, int fd
, circbuffer
*cbuf
);
45 static void send_msg_channel_window_adjust(struct Channel
*channel
,
47 static void send_msg_channel_data(struct Channel
*channel
, int isextended
);
48 static void send_msg_channel_eof(struct Channel
*channel
);
49 static void send_msg_channel_close(struct Channel
*channel
);
50 static void remove_channel(struct Channel
*channel
);
51 static void delete_channel(struct Channel
*channel
);
52 static void check_in_progress(struct Channel
*channel
);
53 static unsigned int write_pending(struct Channel
* channel
);
54 static void check_close(struct Channel
*channel
);
55 static void close_chan_fd(struct Channel
*channel
, int fd
, int how
);
57 #define FD_UNINIT (-2)
58 #define FD_CLOSED (-1)
60 #define ERRFD_IS_READ(channel) ((channel)->extrabuf == NULL)
61 #define ERRFD_IS_WRITE(channel) (!ERRFD_IS_READ(channel))
63 /* Initialise all the channels */
64 void chaninitialise(const struct ChanType
*chantypes
[]) {
66 /* may as well create space for a single channel */
67 ses
.channels
= (struct Channel
**)m_malloc(sizeof(struct Channel
*));
69 ses
.channels
[0] = NULL
;
72 ses
.chantypes
= chantypes
;
74 #ifdef USING_LISTENERS
75 listeners_initialise();
80 /* Clean up channels, freeing allocated memory */
85 TRACE(("enter chancleanup"))
86 for (i
= 0; i
< ses
.chansize
; i
++) {
87 if (ses
.channels
[i
] != NULL
) {
88 TRACE(("channel %d closing", i
))
89 remove_channel(ses
.channels
[i
]);
93 TRACE(("leave chancleanup"))
96 /* Create a new channel entry, send a reply confirm or failure */
97 /* If remotechan, transwindow and transmaxpacket are not know (for a new
98 * outgoing connection, with them to be filled on confirmation), they should
100 struct Channel
* newchannel(unsigned int remotechan
,
101 const struct ChanType
*type
,
102 unsigned int transwindow
, unsigned int transmaxpacket
) {
104 struct Channel
* newchan
;
107 TRACE(("enter newchannel"))
109 /* first see if we can use existing channels */
110 for (i
= 0; i
< ses
.chansize
; i
++) {
111 if (ses
.channels
[i
] == NULL
) {
116 /* otherwise extend the list */
117 if (i
== ses
.chansize
) {
118 if (ses
.chansize
>= MAX_CHANNELS
) {
119 TRACE(("leave newchannel: max chans reached"))
123 /* extend the channels */
124 ses
.channels
= (struct Channel
**)m_realloc(ses
.channels
,
125 (ses
.chansize
+CHAN_EXTEND_SIZE
)*sizeof(struct Channel
*));
127 ses
.chansize
+= CHAN_EXTEND_SIZE
;
129 /* set the new channels to null */
130 for (j
= i
; j
< ses
.chansize
; j
++) {
131 ses
.channels
[j
] = NULL
;
136 newchan
= (struct Channel
*)m_malloc(sizeof(struct Channel
));
137 newchan
->type
= type
;
139 newchan
->sent_close
= newchan
->recv_close
= 0;
140 newchan
->sent_eof
= newchan
->recv_eof
= 0;
142 newchan
->remotechan
= remotechan
;
143 newchan
->transwindow
= transwindow
;
144 newchan
->transmaxpacket
= transmaxpacket
;
146 newchan
->typedata
= NULL
;
147 newchan
->writefd
= FD_UNINIT
;
148 newchan
->readfd
= FD_UNINIT
;
149 newchan
->errfd
= FD_CLOSED
; /* this isn't always set to start with */
150 newchan
->initconn
= 0;
151 newchan
->await_open
= 0;
152 newchan
->flushing
= 0;
154 newchan
->writebuf
= cbuf_new(opts
.recv_window
);
155 newchan
->extrabuf
= NULL
; /* The user code can set it up */
156 newchan
->recvwindow
= opts
.recv_window
;
157 newchan
->recvdonelen
= 0;
158 newchan
->recvmaxpacket
= RECV_MAX_PAYLOAD_LEN
;
160 ses
.channels
[i
] = newchan
;
163 TRACE(("leave newchannel"))
168 /* Returns the channel structure corresponding to the channel in the current
169 * data packet (ses.payload must be positioned appropriately).
170 * A valid channel is always returns, it will fail fatally with an unknown
172 static struct Channel
* getchannel_msg(const char* kind
) {
176 chan
= buf_getint(ses
.payload
);
177 if (chan
>= ses
.chansize
|| ses
.channels
[chan
] == NULL
) {
179 dropbear_exit("%s for unknown channel %d", kind
, chan
);
181 dropbear_exit("Unknown channel %d", chan
);
184 return ses
.channels
[chan
];
187 struct Channel
* getchannel() {
188 return getchannel_msg(NULL
);
191 /* Iterate through the channels, performing IO if available */
192 void channelio(fd_set
*readfds
, fd_set
*writefds
) {
194 struct Channel
*channel
;
197 /* foreach channel */
198 for (i
= 0; i
< ses
.chansize
; i
++) {
200 channel
= ses
.channels
[i
];
201 if (channel
== NULL
) {
202 /* only process in-use channels */
206 /* read data and send it over the wire */
207 if (channel
->readfd
>= 0 && FD_ISSET(channel
->readfd
, readfds
)) {
208 TRACE(("send normal readfd"))
209 send_msg_channel_data(channel
, 0);
212 /* read stderr data and send it over the wire */
213 if (ERRFD_IS_READ(channel
) && channel
->errfd
>= 0
214 && FD_ISSET(channel
->errfd
, readfds
)) {
215 TRACE(("send normal errfd"))
216 send_msg_channel_data(channel
, 1);
219 /* write to program/pipe stdin */
220 if (channel
->writefd
>= 0 && FD_ISSET(channel
->writefd
, writefds
)) {
221 if (channel
->initconn
) {
222 /* XXX should this go somewhere cleaner? */
223 check_in_progress(channel
);
224 continue; /* Important not to use the channel after
225 check_in_progress(), as it may be NULL */
227 writechannel(channel
, channel
->writefd
, channel
->writebuf
);
230 /* stderr for client mode */
231 if (ERRFD_IS_WRITE(channel
)
232 && channel
->errfd
>= 0 && FD_ISSET(channel
->errfd
, writefds
)) {
233 writechannel(channel
, channel
->errfd
, channel
->extrabuf
);
236 /* handle any channel closing etc */
237 check_close(channel
);
241 /* Listeners such as TCP, X11, agent-auth */
242 #ifdef USING_LISTENERS
243 handle_listeners(readfds
);
248 /* Returns true if there is data remaining to be written to stdin or
249 * stderr of a channel's endpoint. */
250 static unsigned int write_pending(struct Channel
* channel
) {
252 if (channel
->writefd
>= 0 && cbuf_getused(channel
->writebuf
) > 0) {
254 } else if (channel
->errfd
>= 0 && channel
->extrabuf
&&
255 cbuf_getused(channel
->extrabuf
) > 0) {
262 /* EOF/close handling */
263 static void check_close(struct Channel
*channel
) {
264 int close_allowed
= 0;
266 TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
267 channel
->writefd
, channel
->readfd
,
268 channel
->errfd
, channel
->sent_close
, channel
->recv_close
))
269 TRACE(("writebuf size %d extrabuf size %d",
270 cbuf_getused(channel
->writebuf
),
271 channel
->extrabuf
? cbuf_getused(channel
->extrabuf
) : 0))
273 if (!channel
->flushing
&& channel
->type
->check_close
274 && channel
->type
->check_close(channel
))
276 channel
->flushing
= 1;
279 /* if a type-specific check_close is defined we will only exit
280 once that has been triggered. this is only used for a server "session"
281 channel, to ensure that the shell has exited (and the exit status
282 retrieved) before we close things up. */
283 if (!channel
->type
->check_close
284 || channel
->type
->check_close(channel
)) {
288 if (channel
->recv_close
&& !write_pending(channel
) && close_allowed
) {
289 if (!channel
->sent_close
) {
290 TRACE(("Sending MSG_CHANNEL_CLOSE in response to same."))
291 send_msg_channel_close(channel
);
293 remove_channel(channel
);
297 if (channel
->recv_eof
&& !write_pending(channel
)) {
298 close_chan_fd(channel
, channel
->writefd
, SHUT_WR
);
301 /* Special handling for flushing read data after an exit. We
302 read regardless of whether the select FD was set,
303 and if there isn't data available, the channel will get closed. */
304 if (channel
->flushing
) {
305 TRACE(("might send data, flushing"))
306 if (channel
->readfd
>= 0 && channel
->transwindow
> 0) {
307 TRACE(("send data readfd"))
308 send_msg_channel_data(channel
, 0);
310 if (ERRFD_IS_READ(channel
) && channel
->errfd
>= 0
311 && channel
->transwindow
> 0) {
312 TRACE(("send data errfd"))
313 send_msg_channel_data(channel
, 1);
317 /* If we're not going to send any more data, send EOF */
318 if (!channel
->sent_eof
319 && channel
->readfd
== FD_CLOSED
320 && (ERRFD_IS_WRITE(channel
) || channel
->errfd
== FD_CLOSED
)) {
321 send_msg_channel_eof(channel
);
324 /* And if we can't receive any more data from them either, close up */
325 if (channel
->readfd
== FD_CLOSED
326 && (ERRFD_IS_WRITE(channel
) || channel
->errfd
== FD_CLOSED
)
327 && !channel
->sent_close
329 && !write_pending(channel
)) {
330 TRACE(("sending close, readfd is closed"))
331 send_msg_channel_close(channel
);
335 /* Check whether a deferred (EINPROGRESS) connect() was successful, and
336 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so
337 * it is important that the channel reference isn't used after a call to this
339 static void check_in_progress(struct Channel
*channel
) {
342 socklen_t vallen
= sizeof(val
);
344 TRACE(("enter check_in_progress"))
346 if (getsockopt(channel
->writefd
, SOL_SOCKET
, SO_ERROR
, &val
, &vallen
)
348 send_msg_channel_open_failure(channel
->remotechan
,
349 SSH_OPEN_CONNECT_FAILED
, "", "");
350 close(channel
->writefd
);
351 delete_channel(channel
);
352 TRACE(("leave check_in_progress: fail"))
354 send_msg_channel_open_confirmation(channel
, channel
->recvwindow
,
355 channel
->recvmaxpacket
);
356 channel
->readfd
= channel
->writefd
;
357 channel
->initconn
= 0;
358 TRACE(("leave check_in_progress: success"))
363 /* Send the close message and set the channel as closed */
364 static void send_msg_channel_close(struct Channel
*channel
) {
366 TRACE(("enter send_msg_channel_close"))
367 if (channel
->type
->closehandler
) {
368 channel
->type
->closehandler(channel
);
373 buf_putbyte(ses
.writepayload
, SSH_MSG_CHANNEL_CLOSE
);
374 buf_putint(ses
.writepayload
, channel
->remotechan
);
378 channel
->sent_eof
= 1;
379 channel
->sent_close
= 1;
380 close_chan_fd(channel
, channel
->readfd
, SHUT_RD
);
381 close_chan_fd(channel
, channel
->errfd
, SHUT_RDWR
);
382 close_chan_fd(channel
, channel
->writefd
, SHUT_WR
);
383 TRACE(("leave send_msg_channel_close"))
386 /* call this when trans/eof channels are closed */
387 static void send_msg_channel_eof(struct Channel
*channel
) {
389 TRACE(("enter send_msg_channel_eof"))
392 buf_putbyte(ses
.writepayload
, SSH_MSG_CHANNEL_EOF
);
393 buf_putint(ses
.writepayload
, channel
->remotechan
);
397 channel
->sent_eof
= 1;
399 TRACE(("leave send_msg_channel_eof"))
402 /* Called to write data out to the local side of the channel.
403 * Only called when we know we can write to a channel, writes as much as
405 static void writechannel(struct Channel
* channel
, int fd
, circbuffer
*cbuf
) {
409 TRACE(("enter writechannel fd %d", fd
))
411 maxlen
= cbuf_readlen(cbuf
);
413 /* Write the data out */
414 len
= write(fd
, cbuf_readptr(cbuf
, maxlen
), maxlen
);
416 TRACE(("errno %d len %d", errno
, len
))
417 if (len
< 0 && errno
!= EINTR
) {
418 close_chan_fd(channel
, fd
, SHUT_WR
);
420 TRACE(("leave writechannel: len <= 0"))
423 TRACE(("writechannel wrote %d", len
))
425 cbuf_incrread(cbuf
, len
);
426 channel
->recvdonelen
+= len
;
428 /* Window adjust handling */
429 if (channel
->recvdonelen
>= RECV_WINDOWEXTEND
) {
430 /* Set it back to max window */
431 send_msg_channel_window_adjust(channel
, channel
->recvdonelen
);
432 channel
->recvwindow
+= channel
->recvdonelen
;
433 channel
->recvdonelen
= 0;
436 dropbear_assert(channel
->recvwindow
<= opts
.recv_window
);
437 dropbear_assert(channel
->recvwindow
<= cbuf_getavail(channel
->writebuf
));
438 dropbear_assert(channel
->extrabuf
== NULL
||
439 channel
->recvwindow
<= cbuf_getavail(channel
->extrabuf
));
441 TRACE(("leave writechannel"))
444 /* Set the file descriptors for the main select in session.c
445 * This avoid channels which don't have any window available, are closed, etc*/
446 void setchannelfds(fd_set
*readfds
, fd_set
*writefds
) {
449 struct Channel
* channel
;
451 for (i
= 0; i
< ses
.chansize
; i
++) {
453 channel
= ses
.channels
[i
];
454 if (channel
== NULL
) {
458 /* Stuff to put over the wire */
459 if (channel
->transwindow
> 0) {
461 if (channel
->readfd
>= 0) {
462 FD_SET(channel
->readfd
, readfds
);
465 if (ERRFD_IS_READ(channel
) && channel
->errfd
>= 0) {
466 FD_SET(channel
->errfd
, readfds
);
470 /* Stuff from the wire */
471 if ((channel
->writefd
>= 0 && cbuf_getused(channel
->writebuf
) > 0 )
472 || channel
->initconn
) {
473 FD_SET(channel
->writefd
, writefds
);
476 if (ERRFD_IS_WRITE(channel
) && channel
->errfd
>= 0
477 && cbuf_getused(channel
->extrabuf
) > 0 ) {
478 FD_SET(channel
->errfd
, writefds
);
481 } /* foreach channel */
483 #ifdef USING_LISTENERS
484 set_listener_fds(readfds
);
489 /* handle the channel EOF event, by closing the channel filedescriptor. The
490 * channel isn't closed yet, it is left until the incoming (from the program
491 * etc) FD is also EOF */
492 void recv_msg_channel_eof() {
494 struct Channel
* channel
;
496 TRACE(("enter recv_msg_channel_eof"))
498 channel
= getchannel_msg("EOF");
500 channel
->recv_eof
= 1;
502 check_close(channel
);
503 TRACE(("leave recv_msg_channel_eof"))
507 /* Handle channel closure(), respond in kind and close the channels */
508 void recv_msg_channel_close() {
510 struct Channel
* channel
;
512 TRACE(("enter recv_msg_channel_close"))
514 channel
= getchannel_msg("Close");
516 channel
->recv_eof
= 1;
517 channel
->recv_close
= 1;
519 check_close(channel
);
520 TRACE(("leave recv_msg_channel_close"))
523 /* Remove a channel entry, this is only executed after both sides have sent
525 static void remove_channel(struct Channel
* channel
) {
527 TRACE(("enter remove_channel"))
528 TRACE(("channel index is %d", channel
->index
))
530 cbuf_free(channel
->writebuf
);
531 channel
->writebuf
= NULL
;
533 if (channel
->extrabuf
) {
534 cbuf_free(channel
->extrabuf
);
535 channel
->extrabuf
= NULL
;
539 /* close the FDs in case they haven't been done
540 * yet (they might have been shutdown etc) */
541 TRACE(("CLOSE writefd %d", channel
->writefd
))
542 close(channel
->writefd
);
543 TRACE(("CLOSE readfd %d", channel
->readfd
))
544 close(channel
->readfd
);
545 TRACE(("CLOSE errfd %d", channel
->errfd
))
546 close(channel
->errfd
);
548 channel
->typedata
= NULL
;
550 delete_channel(channel
);
552 TRACE(("leave remove_channel"))
555 /* Remove a channel entry */
556 static void delete_channel(struct Channel
*channel
) {
558 ses
.channels
[channel
->index
] = NULL
;
565 /* Handle channel specific requests, passing off to corresponding handlers
566 * such as chansession or x11fwd */
567 void recv_msg_channel_request() {
569 struct Channel
*channel
;
571 TRACE(("enter recv_msg_channel_request"))
573 channel
= getchannel();
575 if (channel
->sent_close
) {
576 TRACE(("leave recv_msg_channel_request: already closed channel"))
580 if (channel
->type
->reqhandler
) {
581 channel
->type
->reqhandler(channel
);
583 send_msg_channel_failure(channel
);
586 TRACE(("leave recv_msg_channel_request"))
590 /* Reads data from the server's program/shell/etc, and puts it in a
591 * channel_data packet to send.
592 * chan is the remote channel, isextended is 0 if it is normal data, 1
593 * if it is extended data. if it is extended, then the type is in
595 static void send_msg_channel_data(struct Channel
*channel
, int isextended
) {
598 size_t maxlen
, size_pos
;
603 TRACE(("enter send_msg_channel_data"))
604 dropbear_assert(!channel
->sent_close
);
609 fd
= channel
->readfd
;
611 TRACE(("enter send_msg_channel_data isextended %d fd %d", isextended
, fd
))
612 dropbear_assert(fd
>= 0);
614 maxlen
= MIN(channel
->transwindow
, channel
->transmaxpacket
);
615 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and
616 * exttype if is extended */
618 ses
.writepayload
->size
- 1 - 4 - 4 - (isextended
? 4 : 0));
619 TRACE(("maxlen %d", maxlen
))
621 TRACE(("leave send_msg_channel_data: no window"))
625 buf_putbyte(ses
.writepayload
,
626 isextended
? SSH_MSG_CHANNEL_EXTENDED_DATA
: SSH_MSG_CHANNEL_DATA
);
627 buf_putint(ses
.writepayload
, channel
->remotechan
);
629 buf_putint(ses
.writepayload
, SSH_EXTENDED_DATA_STDERR
);
631 /* a dummy size first ...*/
632 size_pos
= ses
.writepayload
->pos
;
633 buf_putint(ses
.writepayload
, 0);
636 len
= read(fd
, buf_getwriteptr(ses
.writepayload
, maxlen
), maxlen
);
638 if (len
== 0 || errno
!= EINTR
) {
639 /* This will also get hit in the case of EAGAIN. The only
640 time we expect to receive EAGAIN is when we're flushing a FD,
641 in which case it can be treated the same as EOF */
642 close_chan_fd(channel
, fd
, SHUT_RD
);
644 ses
.writepayload
->len
= ses
.writepayload
->pos
= 0;
645 TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d",
649 buf_incrwritepos(ses
.writepayload
, len
);
650 /* ... real size here */
651 buf_setpos(ses
.writepayload
, size_pos
);
652 buf_putint(ses
.writepayload
, len
);
654 channel
->transwindow
-= len
;
658 /* If we receive less data than we requested when flushing, we've
659 reached the equivalent of EOF */
660 if (channel
->flushing
&& len
< (ssize_t
)maxlen
)
662 TRACE(("closing from channel, flushing out."))
663 close_chan_fd(channel
, fd
, SHUT_RD
);
665 TRACE(("leave send_msg_channel_data"))
668 /* We receive channel data */
669 void recv_msg_channel_data() {
671 struct Channel
*channel
;
673 channel
= getchannel();
675 common_recv_msg_channel_data(channel
, channel
->writefd
, channel
->writebuf
);
678 /* Shared for data and stderr data - when we receive data, put it in a buffer
679 * for writing to the local file descriptor */
680 void common_recv_msg_channel_data(struct Channel
*channel
, int fd
,
683 unsigned int datalen
;
684 unsigned int maxdata
;
688 TRACE(("enter recv_msg_channel_data"))
690 if (channel
->recv_eof
) {
691 dropbear_exit("received data after eof");
695 /* If we have encountered failed write, the far side might still
696 * be sending data without having yet received our close notification.
697 * We just drop the data. */
701 datalen
= buf_getint(ses
.payload
);
702 TRACE(("length %d", datalen
))
704 maxdata
= cbuf_getavail(cbuf
);
706 /* Whilst the spec says we "MAY ignore data past the end" this could
707 * lead to corrupted file transfers etc (chunks missed etc). It's better to
708 * just die horribly */
709 if (datalen
> maxdata
) {
710 dropbear_exit("Oversized packet");
713 /* We may have to run throught twice, if the buffer wraps around. Can't
714 * just "leave it for next time" like with writechannel, since this
718 buflen
= cbuf_writelen(cbuf
);
719 buflen
= MIN(buflen
, len
);
721 memcpy(cbuf_writeptr(cbuf
, buflen
),
722 buf_getptr(ses
.payload
, buflen
), buflen
);
723 cbuf_incrwrite(cbuf
, buflen
);
724 buf_incrpos(ses
.payload
, buflen
);
728 dropbear_assert(channel
->recvwindow
>= datalen
);
729 channel
->recvwindow
-= datalen
;
730 dropbear_assert(channel
->recvwindow
<= opts
.recv_window
);
732 TRACE(("leave recv_msg_channel_data"))
735 /* Increment the outgoing data window for a channel - the remote end limits
736 * the amount of data which may be transmitted, this window is decremented
737 * as data is sent, and incremented upon receiving window-adjust messages */
738 void recv_msg_channel_window_adjust() {
740 struct Channel
* channel
;
743 channel
= getchannel();
745 incr
= buf_getint(ses
.payload
);
746 TRACE(("received window increment %d", incr
))
747 incr
= MIN(incr
, TRANS_MAX_WIN_INCR
);
749 channel
->transwindow
+= incr
;
750 channel
->transwindow
= MIN(channel
->transwindow
, TRANS_MAX_WINDOW
);
754 /* Increment the incoming data window for a channel, and let the remote
756 static void send_msg_channel_window_adjust(struct Channel
* channel
,
759 TRACE(("sending window adjust %d", incr
))
762 buf_putbyte(ses
.writepayload
, SSH_MSG_CHANNEL_WINDOW_ADJUST
);
763 buf_putint(ses
.writepayload
, channel
->remotechan
);
764 buf_putint(ses
.writepayload
, incr
);
769 /* Handle a new channel request, performing any channel-type-specific setup */
770 void recv_msg_channel_open() {
773 unsigned int typelen
;
774 unsigned int remotechan
, transwindow
, transmaxpacket
;
775 struct Channel
*channel
;
776 const struct ChanType
**cp
;
777 const struct ChanType
*chantype
;
778 unsigned int errtype
= SSH_OPEN_UNKNOWN_CHANNEL_TYPE
;
782 TRACE(("enter recv_msg_channel_open"))
784 /* get the packet contents */
785 type
= buf_getstring(ses
.payload
, &typelen
);
787 remotechan
= buf_getint(ses
.payload
);
788 transwindow
= buf_getint(ses
.payload
);
789 transwindow
= MIN(transwindow
, TRANS_MAX_WINDOW
);
790 transmaxpacket
= buf_getint(ses
.payload
);
791 transmaxpacket
= MIN(transmaxpacket
, TRANS_MAX_PAYLOAD_LEN
);
793 /* figure what type of packet it is */
794 if (typelen
> MAX_NAME_LEN
) {
798 /* Get the channel type. Client and server style invokation will set up a
799 * different list for ses.chantypes at startup. We just iterate through
800 * this list and find the matching name */
801 for (cp
= &ses
.chantypes
[0], chantype
= (*cp
);
803 cp
++, chantype
= (*cp
)) {
804 if (strcmp(type
, chantype
->name
) == 0) {
809 if (chantype
== NULL
) {
810 TRACE(("No matching type for '%s'", type
))
814 TRACE(("matched type '%s'", type
))
816 /* create the channel */
817 channel
= newchannel(remotechan
, chantype
, transwindow
, transmaxpacket
);
819 if (channel
== NULL
) {
820 TRACE(("newchannel returned NULL"))
824 if (channel
->type
->inithandler
) {
825 ret
= channel
->type
->inithandler(channel
);
826 if (ret
== SSH_OPEN_IN_PROGRESS
) {
827 /* We'll send the confirmation later */
832 delete_channel(channel
);
833 TRACE(("inithandler returned failure %d", ret
))
839 send_msg_channel_open_confirmation(channel
, channel
->recvwindow
,
840 channel
->recvmaxpacket
);
844 TRACE(("recv_msg_channel_open failure"))
845 send_msg_channel_open_failure(remotechan
, errtype
, "", "");
850 TRACE(("leave recv_msg_channel_open"))
853 /* Send a failure message */
854 void send_msg_channel_failure(struct Channel
*channel
) {
856 TRACE(("enter send_msg_channel_failure"))
859 buf_putbyte(ses
.writepayload
, SSH_MSG_CHANNEL_FAILURE
);
860 buf_putint(ses
.writepayload
, channel
->remotechan
);
863 TRACE(("leave send_msg_channel_failure"))
866 /* Send a success message */
867 void send_msg_channel_success(struct Channel
*channel
) {
869 TRACE(("enter send_msg_channel_success"))
872 buf_putbyte(ses
.writepayload
, SSH_MSG_CHANNEL_SUCCESS
);
873 buf_putint(ses
.writepayload
, channel
->remotechan
);
876 TRACE(("leave send_msg_channel_success"))
879 /* Send a channel open failure message, with a corresponding reason
880 * code (usually resource shortage or unknown chan type) */
881 static void send_msg_channel_open_failure(unsigned int remotechan
,
882 int reason
, const unsigned char *text
, const unsigned char *lang
) {
884 TRACE(("enter send_msg_channel_open_failure"))
887 buf_putbyte(ses
.writepayload
, SSH_MSG_CHANNEL_OPEN_FAILURE
);
888 buf_putint(ses
.writepayload
, remotechan
);
889 buf_putint(ses
.writepayload
, reason
);
890 buf_putstring(ses
.writepayload
, text
, strlen((char*)text
));
891 buf_putstring(ses
.writepayload
, lang
, strlen((char*)lang
));
894 TRACE(("leave send_msg_channel_open_failure"))
897 /* Confirm a channel open, and let the remote end know what number we've
898 * allocated and the receive parameters */
899 static void send_msg_channel_open_confirmation(struct Channel
* channel
,
900 unsigned int recvwindow
,
901 unsigned int recvmaxpacket
) {
903 TRACE(("enter send_msg_channel_open_confirmation"))
906 buf_putbyte(ses
.writepayload
, SSH_MSG_CHANNEL_OPEN_CONFIRMATION
);
907 buf_putint(ses
.writepayload
, channel
->remotechan
);
908 buf_putint(ses
.writepayload
, channel
->index
);
909 buf_putint(ses
.writepayload
, recvwindow
);
910 buf_putint(ses
.writepayload
, recvmaxpacket
);
913 TRACE(("leave send_msg_channel_open_confirmation"))
916 /* close a fd, how is SHUT_RD or SHUT_WR */
917 static void close_chan_fd(struct Channel
*channel
, int fd
, int how
) {
919 int closein
= 0, closeout
= 0;
921 if (channel
->type
->sepfds
) {
922 TRACE(("SHUTDOWN(%d, %d)", fd
, how
))
930 TRACE(("CLOSE some fd %d", fd
))
932 closein
= closeout
= 1;
935 if (closeout
&& (fd
== channel
->readfd
)) {
936 channel
->readfd
= FD_CLOSED
;
938 if (closeout
&& ERRFD_IS_READ(channel
) && (fd
== channel
->errfd
)) {
939 channel
->errfd
= FD_CLOSED
;
942 if (closein
&& fd
== channel
->writefd
) {
943 channel
->writefd
= FD_CLOSED
;
945 if (closein
&& ERRFD_IS_WRITE(channel
) && (fd
== channel
->errfd
)) {
946 channel
->errfd
= FD_CLOSED
;
949 /* if we called shutdown on it and all references are gone, then we
950 * need to close() it to stop it lingering */
951 if (channel
->type
->sepfds
&& channel
->readfd
== FD_CLOSED
952 && channel
->writefd
== FD_CLOSED
&& channel
->errfd
== FD_CLOSED
) {
953 TRACE(("CLOSE (finally) of %d", fd
))
959 #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
960 /* Create a new channel, and start the open request. This is intended
961 * for X11, agent, tcp forwarding, and should be filled with channel-specific
962 * options, with the calling function calling encrypt_packet() after
963 * completion. It is mandatory for the caller to encrypt_packet() if
964 * DROPBEAR_SUCCESS is returned */
965 int send_msg_channel_open_init(int fd
, const struct ChanType
*type
) {
967 struct Channel
* chan
;
969 TRACE(("enter send_msg_channel_open_init()"))
970 chan
= newchannel(0, type
, 0, 0);
972 TRACE(("leave send_msg_channel_open_init() - FAILED in newchannel()"))
973 return DROPBEAR_FAILURE
;
976 /* set fd non-blocking */
979 chan
->writefd
= chan
->readfd
= fd
;
980 ses
.maxfd
= MAX(ses
.maxfd
, fd
);
982 chan
->await_open
= 1;
984 /* now open the channel connection */
987 buf_putbyte(ses
.writepayload
, SSH_MSG_CHANNEL_OPEN
);
988 buf_putstring(ses
.writepayload
, type
->name
, strlen(type
->name
));
989 buf_putint(ses
.writepayload
, chan
->index
);
990 buf_putint(ses
.writepayload
, opts
.recv_window
);
991 buf_putint(ses
.writepayload
, RECV_MAX_PAYLOAD_LEN
);
993 TRACE(("leave send_msg_channel_open_init()"))
994 return DROPBEAR_SUCCESS
;
997 /* Confirmation that our channel open request (for forwardings) was
999 void recv_msg_channel_open_confirmation() {
1001 struct Channel
* channel
;
1004 TRACE(("enter recv_msg_channel_open_confirmation"))
1006 channel
= getchannel();
1008 if (!channel
->await_open
) {
1009 dropbear_exit("unexpected channel reply");
1011 channel
->await_open
= 0;
1013 channel
->remotechan
= buf_getint(ses
.payload
);
1014 channel
->transwindow
= buf_getint(ses
.payload
);
1015 channel
->transmaxpacket
= buf_getint(ses
.payload
);
1017 TRACE(("new chan remote %d local %d",
1018 channel
->remotechan
, channel
->index
))
1020 /* Run the inithandler callback */
1021 if (channel
->type
->inithandler
) {
1022 ret
= channel
->type
->inithandler(channel
);
1024 remove_channel(channel
);
1025 TRACE(("inithandler returned failure %d", ret
))
1030 TRACE(("leave recv_msg_channel_open_confirmation"))
1033 /* Notification that our channel open request failed */
1034 void recv_msg_channel_open_failure() {
1036 struct Channel
* channel
;
1038 channel
= getchannel();
1040 if (!channel
->await_open
) {
1041 dropbear_exit("unexpected channel reply");
1043 channel
->await_open
= 0;
1045 remove_channel(channel
);
1047 #endif /* USING_LISTENERS */