52
52
static void checkinitdone(struct Channel *channel);
53
53
static void checkclose(struct Channel *channel);
55
static void closeinfd(struct Channel * channel);
56
static void closeoutfd(struct Channel * channel, int fd);
55
static void closewritefd(struct Channel * channel);
56
static void closereadfd(struct Channel * channel, int fd);
57
57
static void closechanfd(struct Channel *channel, int fd, int how);
59
59
#define FD_UNINIT (-2)
143
143
newchan->transmaxpacket = transmaxpacket;
145
145
newchan->typedata = NULL;
146
newchan->infd = FD_UNINIT;
147
newchan->outfd = FD_UNINIT;
146
newchan->writefd = FD_UNINIT;
147
newchan->readfd = FD_UNINIT;
148
148
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
149
149
newchan->initconn = 0;
150
newchan->await_open = 0;
151
152
newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
152
153
newchan->extrabuf = NULL; /* The user code can set it up */
165
/* Get the channel structure corresponding to a channel number */
166
struct Channel* getchannel(unsigned int chan) {
166
/* Returns the channel structure corresponding to the channel in the current
167
* data packet (ses.payload must be positioned appropriately) */
168
struct Channel* getchannel() {
172
chan = buf_getint(ses.payload);
167
173
if (chan >= ses.chansize || ses.channels[chan] == NULL) {
189
/* read from program/pipe stdout */
190
if (channel->outfd >= 0 && FD_ISSET(channel->outfd, readfd)) {
195
/* read data and send it over the wire */
196
if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
191
197
send_msg_channel_data(channel, 0, 0);
194
/* read from program/pipe stderr */
200
/* read stderr data and send it over the wire */
195
201
if (channel->extrabuf == NULL &&
196
channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) {
202
channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) {
197
203
send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
200
/* if we can read from the infd, it might be closed, so we try to
201
* see if it has errors */
202
if (channel->infd >= 0 && channel->infd != channel->outfd
203
&& FD_ISSET(channel->infd, readfd)) {
204
if (channel->initconn) {
205
/* Handling for "in progress" connection - this is needed
206
* to avoid spinning 100% CPU when we connect to a server
207
* which doesn't send anything (tcpfwding) */
208
checkinitdone(channel);
209
continue; /* Important not to use the channel after
210
checkinitdone(), as it may be NULL */
212
ret = write(channel->infd, NULL, 0); /* Fake write */
213
if (ret < 0 && errno != EINTR && errno != EAGAIN) {
218
206
/* write to program/pipe stdin */
219
if (channel->infd >= 0 && FD_ISSET(channel->infd, writefd)) {
207
if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
220
208
if (channel->initconn) {
221
209
checkinitdone(channel);
222
210
continue; /* Important not to use the channel after
223
211
checkinitdone(), as it may be NULL */
225
writechannel(channel, channel->infd, channel->writebuf);
213
writechannel(channel, channel->writefd, channel->writebuf);
228
216
/* stderr for client mode */
229
217
if (channel->extrabuf != NULL
230
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) {
218
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
231
219
writechannel(channel, channel->errfd, channel->extrabuf);
246
234
/* do all the EOF/close type stuff checking for a channel */
247
235
static void checkclose(struct Channel *channel) {
249
TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d",
250
channel->infd, channel->outfd,
237
TRACE(("checkclose: writefd %d, readfd %d, errfd %d, sentclosed %d, recvclosed %d",
238
channel->writefd, channel->readfd,
251
239
channel->errfd, channel->sentclosed, channel->recvclosed))
252
240
TRACE(("writebuf %d extrabuf %s extrabuf %d",
253
241
cbuf_getused(channel->writebuf),
260
248
* if the shell has exited etc */
261
249
if (channel->type->checkclose) {
262
250
if (channel->type->checkclose(channel)) {
251
closewritefd(channel);
267
255
if (!channel->senteof
268
&& channel->outfd == FD_CLOSED
256
&& channel->readfd == FD_CLOSED
269
257
&& (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
270
258
send_msg_channel_eof(channel);
273
if (channel->infd == FD_CLOSED
274
&& channel->outfd == FD_CLOSED
261
if (channel->writefd == FD_CLOSED
262
&& channel->readfd == FD_CLOSED
275
263
&& (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
276
264
send_msg_channel_close(channel);
309
297
TRACE(("enter checkinitdone"))
311
if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen)
299
if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
313
301
send_msg_channel_open_failure(channel->remotechan,
314
302
SSH_OPEN_CONNECT_FAILED, "", "");
315
close(channel->infd);
303
close(channel->writefd);
316
304
deletechannel(channel);
317
305
TRACE(("leave checkinitdone: fail"))
319
307
send_msg_channel_open_confirmation(channel, channel->recvwindow,
320
308
channel->recvmaxpacket);
321
channel->outfd = channel->infd;
309
channel->readfd = channel->writefd;
322
310
channel->initconn = 0;
323
311
TRACE(("leave checkinitdone: success"))
389
377
cbuf_incrread(cbuf, len);
390
378
channel->recvdonelen += len;
392
if (fd == channel->infd && len == maxlen && channel->recveof) {
380
if (fd == channel->writefd && len == maxlen && channel->recveof) {
393
381
/* Check if we're closing up */
382
closewritefd(channel);
395
383
TRACE(("leave writechannel: recveof set"))
404
392
channel->recvdonelen = 0;
407
assert(channel->recvwindow <= RECV_MAXWINDOW);
408
assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
409
assert(channel->extrabuf == NULL ||
395
dropbear_assert(channel->recvwindow <= RECV_MAXWINDOW);
396
dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
397
dropbear_assert(channel->extrabuf == NULL ||
410
398
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
416
404
/* Set the file descriptors for the main select in session.c
417
405
* This avoid channels which don't have any window available, are closed, etc*/
418
void setchannelfds(fd_set *readfd, fd_set *writefd) {
406
void setchannelfds(fd_set *readfds, fd_set *writefds) {
421
409
struct Channel * channel;
430
418
/* Stuff to put over the wire */
431
419
if (channel->transwindow > 0) {
433
if (channel->outfd >= 0) {
434
FD_SET(channel->outfd, readfd);
421
if (channel->readfd >= 0) {
422
FD_SET(channel->readfd, readfds);
437
425
if (channel->extrabuf == NULL && channel->errfd >= 0) {
438
FD_SET(channel->errfd, readfd);
426
FD_SET(channel->errfd, readfds);
442
/* For checking FD status (ie closure etc) - we don't actually
443
* read data from infd */
444
TRACE(("infd = %d, outfd %d, errfd %d, bufused %d",
445
channel->infd, channel->outfd,
447
cbuf_getused(channel->writebuf) ))
448
if (channel->infd >= 0 && channel->infd != channel->outfd) {
449
FD_SET(channel->infd, readfd);
452
/* Stuff from the wire, to local program/shell/user etc */
453
if ((channel->infd >= 0 && cbuf_getused(channel->writebuf) > 0 )
430
/* Stuff from the wire */
431
if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
454
432
|| channel->initconn) {
456
FD_SET(channel->infd, writefd);
434
FD_SET(channel->writefd, writefds);
459
437
if (channel->extrabuf != NULL && channel->errfd >= 0
460
438
&& cbuf_getused(channel->extrabuf) > 0 ) {
461
FD_SET(channel->errfd, writefd);
439
FD_SET(channel->errfd, writefds);
464
442
} /* foreach channel */
466
444
#ifdef USING_LISTENERS
467
set_listener_fds(readfd);
445
set_listener_fds(readfds);
500
475
/* Handle channel closure(), respond in kind and close the channels */
501
476
void recv_msg_channel_close() {
504
478
struct Channel * channel;
506
480
TRACE(("enter recv_msg_channel_close"))
508
chan = buf_getint(ses.payload);
509
TRACE(("close channel = %d", chan))
510
channel = getchannel(chan);
482
channel = getchannel();
512
483
if (channel == NULL) {
513
484
/* disconnect ? */
514
485
dropbear_exit("Close for unknown channel");
567
538
* such as chansession or x11fwd */
568
539
void recv_msg_channel_request() {
571
541
struct Channel *channel;
573
543
TRACE(("enter recv_msg_channel_request"))
575
chan = buf_getint(ses.payload);
576
channel = getchannel(chan);
545
channel = getchannel();
578
546
if (channel == NULL) {
579
547
/* disconnect ? */
580
548
dropbear_exit("Unknown channel");
609
577
CHECKCLEARTOWRITE();
611
assert(!channel->sentclosed);
579
dropbear_assert(!channel->sentclosed);
613
581
if (isextended) {
614
582
fd = channel->errfd;
584
fd = channel->readfd;
586
dropbear_assert(fd >= 0);
620
588
maxlen = MIN(channel->transwindow, channel->transmaxpacket);
621
589
/* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and
666
634
/* We receive channel data */
667
635
void recv_msg_channel_data() {
670
637
struct Channel *channel;
672
chan = buf_getint(ses.payload);
673
channel = getchannel(chan);
639
channel = getchannel();
675
640
if (channel == NULL) {
676
641
dropbear_exit("Unknown channel");
679
common_recv_msg_channel_data(channel, channel->infd, channel->writebuf);
644
common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf);
682
647
/* Shared for data and stderr data - when we receive data, put it in a buffer
729
assert(channel->recvwindow >= datalen);
694
dropbear_assert(channel->recvwindow >= datalen);
730
695
channel->recvwindow -= datalen;
731
assert(channel->recvwindow <= RECV_MAXWINDOW);
696
dropbear_assert(channel->recvwindow <= RECV_MAXWINDOW);
733
698
TRACE(("leave recv_msg_channel_data"))
738
703
* as data is sent, and incremented upon receiving window-adjust messages */
739
704
void recv_msg_channel_window_adjust() {
742
706
struct Channel * channel;
743
707
unsigned int incr;
745
chan = buf_getint(ses.payload);
746
channel = getchannel(chan);
709
channel = getchannel();
748
710
if (channel == NULL) {
749
711
dropbear_exit("Unknown channel");
962
926
void recv_msg_channel_open_confirmation() {
965
928
struct Channel * channel;
968
931
TRACE(("enter recv_msg_channel_open_confirmation"))
969
chan = buf_getint(ses.payload);
971
channel = getchannel(chan);
933
channel = getchannel();
972
934
if (channel == NULL) {
973
935
dropbear_exit("Unknown channel");
938
if (!channel->await_open) {
939
dropbear_exit("unexpected channel reply");
941
channel->await_open = 0;
976
943
channel->remotechan = buf_getint(ses.payload);
977
944
channel->transwindow = buf_getint(ses.payload);
978
945
channel->transmaxpacket = buf_getint(ses.payload);
980
TRACE(("new chan remote %d localho %d", channel->remotechan, chan))
947
TRACE(("new chan remote %d local %d",
948
channel->remotechan, channel->index))
982
950
/* Run the inithandler callback */
983
951
if (channel->type->inithandler) {
995
963
/* Notification that our channel open request failed */
996
964
void recv_msg_channel_open_failure() {
999
966
struct Channel * channel;
1000
chan = buf_getbyte(ses.payload);
1002
channel = getchannel(chan);
968
channel = getchannel();
1003
969
if (channel == NULL) {
1004
970
dropbear_exit("Unknown channel");
973
if (!channel->await_open) {
974
dropbear_exit("unexpected channel reply");
976
channel->await_open = 0;
1007
978
removechannel(channel);
1009
980
#endif /* USING_LISTENERS */
1011
982
/* close a stdout/stderr fd */
1012
static void closeoutfd(struct Channel * channel, int fd) {
983
static void closereadfd(struct Channel * channel, int fd) {
1014
/* don't close it if it is the same as infd,
1015
* unless infd is already set -1 */
1016
TRACE(("enter closeoutfd"))
985
/* don't close it if it is the same as writefd,
986
* unless writefd is already set -1 */
987
TRACE(("enter closereadfd"))
1017
988
closechanfd(channel, fd, 0);
1018
TRACE(("leave closeoutfd"))
989
TRACE(("leave closereadfd"))
1021
992
/* close a stdin fd */
1022
static void closeinfd(struct Channel * channel) {
993
static void closewritefd(struct Channel * channel) {
1024
TRACE(("enter closeinfd"))
1025
closechanfd(channel, channel->infd, 1);
1026
TRACE(("leave closeinfd"))
995
TRACE(("enter closewritefd"))
996
closechanfd(channel, channel->writefd, 1);
997
TRACE(("leave closewritefd"))
1029
1000
/* close a fd, how is 0 for stdout/stderr, 1 for stdin */
1044
1016
closein = closeout = 1;
1047
if (closeout && fd == channel->outfd) {
1048
channel->outfd = FD_CLOSED;
1019
if (closeout && fd == channel->readfd) {
1020
channel->readfd = FD_CLOSED;
1050
1022
if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
1051
1023
channel->errfd = FD_CLOSED;
1054
if (closein && fd == channel->infd) {
1055
channel->infd = FD_CLOSED;
1026
if (closein && fd == channel->writefd) {
1027
channel->writefd = FD_CLOSED;
1057
1029
if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
1058
1030
channel->errfd = FD_CLOSED;
1033
/* if we called shutdown on it and all references are gone, then we
1034
* need to close() it to stop it lingering */
1035
if (channel->type->sepfds && channel->readfd == FD_CLOSED
1036
&& channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {