Mercurial > dropbear
comparison common-channel.c @ 1173:d734fe76b72f coverity
merge
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Mon, 23 Nov 2015 23:04:48 +0800 |
parents | 509cf5df51c6 |
children | b370b4b172d0 |
comparison
equal
deleted
inserted
replaced
1144:624fc24cfae5 | 1173:d734fe76b72f |
---|---|
40 static void send_msg_channel_open_failure(unsigned int remotechan, int reason, | 40 static void send_msg_channel_open_failure(unsigned int remotechan, int reason, |
41 const char *text, const char *lang); | 41 const char *text, const char *lang); |
42 static void send_msg_channel_open_confirmation(struct Channel* channel, | 42 static void send_msg_channel_open_confirmation(struct Channel* channel, |
43 unsigned int recvwindow, | 43 unsigned int recvwindow, |
44 unsigned int recvmaxpacket); | 44 unsigned int recvmaxpacket); |
45 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, | 45 static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf, |
46 const unsigned char *moredata, unsigned int *morelen); | 46 const unsigned char *moredata, unsigned int *morelen); |
47 static void send_msg_channel_window_adjust(struct Channel *channel, | 47 static void send_msg_channel_window_adjust(struct Channel *channel, |
48 unsigned int incr); | 48 unsigned int incr); |
49 static void send_msg_channel_data(struct Channel *channel, int isextended); | 49 static void send_msg_channel_data(struct Channel *channel, int isextended); |
50 static void send_msg_channel_eof(struct Channel *channel); | 50 static void send_msg_channel_eof(struct Channel *channel); |
98 } | 98 } |
99 m_free(ses.channels); | 99 m_free(ses.channels); |
100 TRACE(("leave chancleanup")) | 100 TRACE(("leave chancleanup")) |
101 } | 101 } |
102 | 102 |
103 static void | |
104 chan_initwritebuf(struct Channel *channel) | |
105 { | |
106 dropbear_assert(channel->writebuf->size == 0 && channel->recvwindow == 0); | |
107 cbuf_free(channel->writebuf); | |
108 channel->writebuf = cbuf_new(opts.recv_window); | |
109 channel->recvwindow = opts.recv_window; | |
110 } | |
111 | |
112 /* Create a new channel entry, send a reply confirm or failure */ | 103 /* Create a new channel entry, send a reply confirm or failure */ |
113 /* If remotechan, transwindow and transmaxpacket are not know (for a new | 104 /* If remotechan, transwindow and transmaxpacket are not know (for a new |
114 * outgoing connection, with them to be filled on confirmation), they should | 105 * outgoing connection, with them to be filled on confirmation), they should |
115 * all be set to 0 */ | 106 * all be set to 0 */ |
116 static struct Channel* newchannel(unsigned int remotechan, | 107 static struct Channel* newchannel(unsigned int remotechan, |
165 newchan->readfd = FD_UNINIT; | 156 newchan->readfd = FD_UNINIT; |
166 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ | 157 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ |
167 newchan->await_open = 0; | 158 newchan->await_open = 0; |
168 newchan->flushing = 0; | 159 newchan->flushing = 0; |
169 | 160 |
170 newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */ | 161 newchan->writebuf = cbuf_new(opts.recv_window); |
171 newchan->recvwindow = 0; | 162 newchan->recvwindow = opts.recv_window; |
172 | 163 |
173 newchan->extrabuf = NULL; /* The user code can set it up */ | 164 newchan->extrabuf = NULL; /* The user code can set it up */ |
174 newchan->recvdonelen = 0; | 165 newchan->recvdonelen = 0; |
175 newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN; | 166 newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN; |
176 | 167 |
254 } | 245 } |
255 | 246 |
256 if (ses.channel_signal_pending) { | 247 if (ses.channel_signal_pending) { |
257 /* SIGCHLD can change channel state for server sessions */ | 248 /* SIGCHLD can change channel state for server sessions */ |
258 do_check_close = 1; | 249 do_check_close = 1; |
259 ses.channel_signal_pending = 0; | |
260 } | 250 } |
261 | 251 |
262 /* handle any channel closing etc */ | 252 /* handle any channel closing etc */ |
263 if (do_check_close) { | 253 if (do_check_close) { |
264 check_close(channel); | 254 check_close(channel); |
265 } | 255 } |
266 } | 256 } |
257 | |
258 ses.channel_signal_pending = 0; | |
267 | 259 |
268 #ifdef USING_LISTENERS | 260 #ifdef USING_LISTENERS |
269 handle_listeners(readfds); | 261 handle_listeners(readfds); |
270 #endif | 262 #endif |
271 } | 263 } |
376 | 368 |
377 if (result == DROPBEAR_SUCCESS) | 369 if (result == DROPBEAR_SUCCESS) |
378 { | 370 { |
379 channel->readfd = channel->writefd = sock; | 371 channel->readfd = channel->writefd = sock; |
380 channel->conn_pending = NULL; | 372 channel->conn_pending = NULL; |
381 chan_initwritebuf(channel); | |
382 send_msg_channel_open_confirmation(channel, channel->recvwindow, | 373 send_msg_channel_open_confirmation(channel, channel->recvwindow, |
383 channel->recvmaxpacket); | 374 channel->recvmaxpacket); |
384 TRACE(("leave channel_connect_done: success")) | 375 TRACE(("leave channel_connect_done: success")) |
385 } | 376 } |
386 else | 377 else |
433 | 424 |
434 TRACE(("leave send_msg_channel_eof")) | 425 TRACE(("leave send_msg_channel_eof")) |
435 } | 426 } |
436 | 427 |
437 #ifndef HAVE_WRITEV | 428 #ifndef HAVE_WRITEV |
438 static void writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf, | 429 static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf, |
439 const unsigned char *UNUSED(moredata), unsigned int *morelen) { | 430 const unsigned char *UNUSED(moredata), unsigned int *morelen) { |
440 | 431 |
441 unsigned char *circ_p1, *circ_p2; | 432 unsigned char *circ_p1, *circ_p2; |
442 unsigned int circ_len1, circ_len2; | 433 unsigned int circ_len1, circ_len2; |
443 ssize_t written; | 434 ssize_t written; |
452 written = write(fd, circ_p1, circ_len1); | 443 written = write(fd, circ_p1, circ_len1); |
453 if (written < 0) { | 444 if (written < 0) { |
454 if (errno != EINTR && errno != EAGAIN) { | 445 if (errno != EINTR && errno != EAGAIN) { |
455 TRACE(("channel IO write error fd %d %s", fd, strerror(errno))) | 446 TRACE(("channel IO write error fd %d %s", fd, strerror(errno))) |
456 close_chan_fd(channel, fd, SHUT_WR); | 447 close_chan_fd(channel, fd, SHUT_WR); |
457 } | 448 return DROPBEAR_FAILURE; |
458 } else { | 449 } |
459 cbuf_incrread(cbuf, written); | 450 } |
460 channel->recvdonelen += written; | 451 cbuf_incrread(cbuf, written); |
461 } | 452 channel->recvdonelen += written; |
453 return DROPBEAR_SUCCESS; | |
462 } | 454 } |
463 #endif /* !HAVE_WRITEV */ | 455 #endif /* !HAVE_WRITEV */ |
464 | 456 |
465 #ifdef HAVE_WRITEV | 457 #ifdef HAVE_WRITEV |
466 static void writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf, | 458 static int writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf, |
467 const unsigned char *moredata, unsigned int *morelen) { | 459 const unsigned char *moredata, unsigned int *morelen) { |
468 | 460 |
469 struct iovec iov[3]; | 461 struct iovec iov[3]; |
470 unsigned char *circ_p1, *circ_p2; | 462 unsigned char *circ_p1, *circ_p2; |
471 unsigned int circ_len1, circ_len2; | 463 unsigned int circ_len1, circ_len2; |
472 int io_count = 0; | 464 int io_count = 0; |
473 | 465 int cbuf_written; |
474 ssize_t written; | 466 ssize_t written; |
475 | 467 |
476 cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2); | 468 cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2); |
477 | 469 |
478 if (circ_len1 > 0) { | 470 if (circ_len1 > 0) { |
500 if (io_count == 0) { | 492 if (io_count == 0) { |
501 /* writechannel may sometimes be called twice in a main loop iteration. | 493 /* writechannel may sometimes be called twice in a main loop iteration. |
502 From common_recv_msg_channel_data() then channelio(). | 494 From common_recv_msg_channel_data() then channelio(). |
503 The second call may not have any data to write, so we just return. */ | 495 The second call may not have any data to write, so we just return. */ |
504 TRACE(("leave writechannel, no data")) | 496 TRACE(("leave writechannel, no data")) |
505 return; | 497 return DROPBEAR_SUCCESS; |
506 } | 498 } |
507 | 499 |
508 if (morelen) { | 500 if (morelen) { |
509 /* Default return value, none consumed */ | 501 /* Default return value, none consumed */ |
510 *morelen = 0; | 502 *morelen = 0; |
514 | 506 |
515 if (written < 0) { | 507 if (written < 0) { |
516 if (errno != EINTR && errno != EAGAIN) { | 508 if (errno != EINTR && errno != EAGAIN) { |
517 TRACE(("channel IO write error fd %d %s", fd, strerror(errno))) | 509 TRACE(("channel IO write error fd %d %s", fd, strerror(errno))) |
518 close_chan_fd(channel, fd, SHUT_WR); | 510 close_chan_fd(channel, fd, SHUT_WR); |
519 } | 511 return DROPBEAR_FAILURE; |
520 } else { | 512 } |
521 int cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written); | 513 } |
522 cbuf_incrread(cbuf, cbuf_written); | 514 |
523 if (morelen) { | 515 cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written); |
524 *morelen = written - cbuf_written; | 516 cbuf_incrread(cbuf, cbuf_written); |
525 } | 517 if (morelen) { |
526 channel->recvdonelen += written; | 518 *morelen = written - cbuf_written; |
527 } | 519 } |
528 | 520 channel->recvdonelen += written; |
521 return DROPBEAR_SUCCESS; | |
529 } | 522 } |
530 #endif /* HAVE_WRITEV */ | 523 #endif /* HAVE_WRITEV */ |
531 | 524 |
532 /* Called to write data out to the local side of the channel. | 525 /* Called to write data out to the local side of the channel. |
533 Writes the circular buffer contents and also the "moredata" buffer | 526 Writes the circular buffer contents and also the "moredata" buffer |
534 if not null. Will ignore EAGAIN */ | 527 if not null. Will ignore EAGAIN. |
535 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, | 528 Returns DROPBEAR_FAILURE if writing to fd had an error and the channel is being closed, DROPBEAR_SUCCESS otherwise */ |
529 static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf, | |
536 const unsigned char *moredata, unsigned int *morelen) { | 530 const unsigned char *moredata, unsigned int *morelen) { |
531 int ret = DROPBEAR_SUCCESS; | |
537 TRACE(("enter writechannel fd %d", fd)) | 532 TRACE(("enter writechannel fd %d", fd)) |
538 #ifdef HAVE_WRITEV | 533 #ifdef HAVE_WRITEV |
539 writechannel_writev(channel, fd, cbuf, moredata, morelen); | 534 ret = writechannel_writev(channel, fd, cbuf, moredata, morelen); |
540 #else | 535 #else |
541 writechannel_fallback(channel, fd, cbuf, moredata, morelen); | 536 ret = writechannel_fallback(channel, fd, cbuf, moredata, morelen); |
542 #endif | 537 #endif |
543 | 538 |
544 /* Window adjust handling */ | 539 /* Window adjust handling */ |
545 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { | 540 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { |
546 send_msg_channel_window_adjust(channel, channel->recvdonelen); | 541 send_msg_channel_window_adjust(channel, channel->recvdonelen); |
552 dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf)); | 547 dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf)); |
553 dropbear_assert(channel->extrabuf == NULL || | 548 dropbear_assert(channel->extrabuf == NULL || |
554 channel->recvwindow <= cbuf_getavail(channel->extrabuf)); | 549 channel->recvwindow <= cbuf_getavail(channel->extrabuf)); |
555 | 550 |
556 TRACE(("leave writechannel")) | 551 TRACE(("leave writechannel")) |
552 return ret; | |
557 } | 553 } |
558 | 554 |
559 | 555 |
560 /* Set the file descriptors for the main select in session.c | 556 /* Set the file descriptors for the main select in session.c |
561 * This avoid channels which don't have any window available, are closed, etc*/ | 557 * This avoid channels which don't have any window available, are closed, etc*/ |
826 unsigned int datalen; | 822 unsigned int datalen; |
827 unsigned int maxdata; | 823 unsigned int maxdata; |
828 unsigned int buflen; | 824 unsigned int buflen; |
829 unsigned int len; | 825 unsigned int len; |
830 unsigned int consumed; | 826 unsigned int consumed; |
827 int res; | |
831 | 828 |
832 TRACE(("enter recv_msg_channel_data")) | 829 TRACE(("enter recv_msg_channel_data")) |
833 | 830 |
834 if (channel->recv_eof) { | 831 if (channel->recv_eof) { |
835 dropbear_exit("Received data after eof"); | 832 dropbear_exit("Received data after eof"); |
858 channel->recvwindow -= datalen; | 855 channel->recvwindow -= datalen; |
859 dropbear_assert(channel->recvwindow <= opts.recv_window); | 856 dropbear_assert(channel->recvwindow <= opts.recv_window); |
860 | 857 |
861 /* Attempt to write the data immediately without having to put it in the circular buffer */ | 858 /* Attempt to write the data immediately without having to put it in the circular buffer */ |
862 consumed = datalen; | 859 consumed = datalen; |
863 writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed); | 860 res = writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed); |
864 | 861 |
865 datalen -= consumed; | 862 datalen -= consumed; |
866 buf_incrpos(ses.payload, consumed); | 863 buf_incrpos(ses.payload, consumed); |
867 | 864 |
868 | 865 |
869 /* We may have to run throught twice, if the buffer wraps around. Can't | 866 /* We may have to run throught twice, if the buffer wraps around. Can't |
870 * just "leave it for next time" like with writechannel, since this | 867 * just "leave it for next time" like with writechannel, since this |
871 * is payload data */ | 868 * is payload data. |
872 len = datalen; | 869 * If the writechannel() failed then remaining data is discarded */ |
873 while (len > 0) { | 870 if (res == DROPBEAR_SUCCESS) { |
874 buflen = cbuf_writelen(cbuf); | 871 len = datalen; |
875 buflen = MIN(buflen, len); | 872 while (len > 0) { |
876 | 873 buflen = cbuf_writelen(cbuf); |
877 memcpy(cbuf_writeptr(cbuf, buflen), | 874 buflen = MIN(buflen, len); |
878 buf_getptr(ses.payload, buflen), buflen); | 875 |
879 cbuf_incrwrite(cbuf, buflen); | 876 memcpy(cbuf_writeptr(cbuf, buflen), |
880 buf_incrpos(ses.payload, buflen); | 877 buf_getptr(ses.payload, buflen), buflen); |
881 len -= buflen; | 878 cbuf_incrwrite(cbuf, buflen); |
879 buf_incrpos(ses.payload, buflen); | |
880 len -= buflen; | |
881 } | |
882 } | 882 } |
883 | 883 |
884 TRACE(("leave recv_msg_channel_data")) | 884 TRACE(("leave recv_msg_channel_data")) |
885 } | 885 } |
886 | 886 |
968 /* create the channel */ | 968 /* create the channel */ |
969 channel = newchannel(remotechan, chantype, transwindow, transmaxpacket); | 969 channel = newchannel(remotechan, chantype, transwindow, transmaxpacket); |
970 | 970 |
971 if (channel == NULL) { | 971 if (channel == NULL) { |
972 TRACE(("newchannel returned NULL")) | 972 TRACE(("newchannel returned NULL")) |
973 errtype = SSH_OPEN_RESOURCE_SHORTAGE; | |
973 goto failure; | 974 goto failure; |
974 } | 975 } |
975 | 976 |
976 if (channel->type->inithandler) { | 977 if (channel->type->inithandler) { |
977 ret = channel->type->inithandler(channel); | 978 ret = channel->type->inithandler(channel); |
988 } | 989 } |
989 | 990 |
990 if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) { | 991 if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) { |
991 channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; | 992 channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; |
992 } | 993 } |
993 | |
994 chan_initwritebuf(channel); | |
995 | 994 |
996 /* success */ | 995 /* success */ |
997 send_msg_channel_open_confirmation(channel, channel->recvwindow, | 996 send_msg_channel_open_confirmation(channel, channel->recvwindow, |
998 channel->recvmaxpacket); | 997 channel->recvmaxpacket); |
999 goto cleanup; | 998 goto cleanup; |
1133 return DROPBEAR_FAILURE; | 1132 return DROPBEAR_FAILURE; |
1134 } | 1133 } |
1135 | 1134 |
1136 /* Outbound opened channels don't make use of in-progress connections, | 1135 /* Outbound opened channels don't make use of in-progress connections, |
1137 * we can set it up straight away */ | 1136 * we can set it up straight away */ |
1138 chan_initwritebuf(chan); | |
1139 | 1137 |
1140 /* set fd non-blocking */ | 1138 /* set fd non-blocking */ |
1141 setnonblocking(fd); | 1139 setnonblocking(fd); |
1142 | 1140 |
1143 chan->writefd = chan->readfd = fd; | 1141 chan->writefd = chan->readfd = fd; |