comparison common-channel.c @ 1069:2fa71c3b2827 pam

merge pam branch up to date
author Matt Johnston <matt@ucc.asn.au>
date Mon, 16 Mar 2015 21:34:05 +0800
parents c71df09bc610
children 696205e3dc99
comparison
equal deleted inserted replaced
1068:9a6395ddb1b6 1069:2fa71c3b2827
33 #include "dbutil.h" 33 #include "dbutil.h"
34 #include "channel.h" 34 #include "channel.h"
35 #include "ssh.h" 35 #include "ssh.h"
36 #include "listener.h" 36 #include "listener.h"
37 #include "runopts.h" 37 #include "runopts.h"
38 #include "netio.h"
38 39
39 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,
40 const unsigned char *text, const unsigned char *lang); 41 const unsigned char *text, const unsigned char *lang);
41 static void send_msg_channel_open_confirmation(struct Channel* channel, 42 static void send_msg_channel_open_confirmation(struct Channel* channel,
42 unsigned int recvwindow, 43 unsigned int recvwindow,
43 unsigned int recvmaxpacket); 44 unsigned int recvmaxpacket);
44 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf); 45 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
46 const unsigned char *moredata, unsigned int *morelen);
45 static void send_msg_channel_window_adjust(struct Channel *channel, 47 static void send_msg_channel_window_adjust(struct Channel *channel,
46 unsigned int incr); 48 unsigned int incr);
47 static void send_msg_channel_data(struct Channel *channel, int isextended); 49 static void send_msg_channel_data(struct Channel *channel, int isextended);
48 static void send_msg_channel_eof(struct Channel *channel); 50 static void send_msg_channel_eof(struct Channel *channel);
49 static void send_msg_channel_close(struct Channel *channel); 51 static void send_msg_channel_close(struct Channel *channel);
50 static void remove_channel(struct Channel *channel); 52 static void remove_channel(struct Channel *channel);
51 static void check_in_progress(struct Channel *channel);
52 static unsigned int write_pending(struct Channel * channel); 53 static unsigned int write_pending(struct Channel * channel);
53 static void check_close(struct Channel *channel); 54 static void check_close(struct Channel *channel);
54 static void close_chan_fd(struct Channel *channel, int fd, int how); 55 static void close_chan_fd(struct Channel *channel, int fd, int how);
55 56
56 #define FD_UNINIT (-2) 57 #define FD_UNINIT (-2)
161 162
162 newchan->typedata = NULL; 163 newchan->typedata = NULL;
163 newchan->writefd = FD_UNINIT; 164 newchan->writefd = FD_UNINIT;
164 newchan->readfd = FD_UNINIT; 165 newchan->readfd = FD_UNINIT;
165 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ 166 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
166 newchan->initconn = 0;
167 newchan->await_open = 0; 167 newchan->await_open = 0;
168 newchan->flushing = 0; 168 newchan->flushing = 0;
169 169
170 newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */ 170 newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */
171 newchan->recvwindow = 0; 171 newchan->recvwindow = 0;
240 do_check_close = 1; 240 do_check_close = 1;
241 } 241 }
242 242
243 /* write to program/pipe stdin */ 243 /* write to program/pipe stdin */
244 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { 244 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
245 if (channel->initconn) { 245 writechannel(channel, channel->writefd, channel->writebuf, NULL, NULL);
246 /* XXX should this go somewhere cleaner? */
247 check_in_progress(channel);
248 continue; /* Important not to use the channel after
249 check_in_progress(), as it may be NULL */
250 }
251 writechannel(channel, channel->writefd, channel->writebuf);
252 do_check_close = 1; 246 do_check_close = 1;
253 } 247 }
254 248
255 /* stderr for client mode */ 249 /* stderr for client mode */
256 if (ERRFD_IS_WRITE(channel) 250 if (ERRFD_IS_WRITE(channel)
257 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { 251 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
258 writechannel(channel, channel->errfd, channel->extrabuf); 252 writechannel(channel, channel->errfd, channel->extrabuf, NULL, NULL);
259 do_check_close = 1; 253 do_check_close = 1;
260 } 254 }
261 255
262 if (ses.channel_signal_pending) { 256 if (ses.channel_signal_pending) {
263 /* SIGCHLD can change channel state for server sessions */ 257 /* SIGCHLD can change channel state for server sessions */
372 366
373 /* Check whether a deferred (EINPROGRESS) connect() was successful, and 367 /* Check whether a deferred (EINPROGRESS) connect() was successful, and
374 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so 368 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so
375 * it is important that the channel reference isn't used after a call to this 369 * it is important that the channel reference isn't used after a call to this
376 * function */ 370 * function */
377 static void check_in_progress(struct Channel *channel) { 371 void channel_connect_done(int result, int sock, void* user_data, const char* UNUSED(errstring)) {
378 372
379 int val; 373 struct Channel *channel = user_data;
380 socklen_t vallen = sizeof(val); 374
381 375 TRACE(("enter channel_connect_done"))
382 TRACE(("enter check_in_progress")) 376
383 377 if (result == DROPBEAR_SUCCESS)
384 if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen) 378 {
385 || val != 0) { 379 channel->readfd = channel->writefd = sock;
386 send_msg_channel_open_failure(channel->remotechan, 380 channel->conn_pending = NULL;
387 SSH_OPEN_CONNECT_FAILED, "", "");
388 close(channel->writefd);
389 remove_channel(channel);
390 TRACE(("leave check_in_progress: fail"))
391 } else {
392 chan_initwritebuf(channel); 381 chan_initwritebuf(channel);
393 send_msg_channel_open_confirmation(channel, channel->recvwindow, 382 send_msg_channel_open_confirmation(channel, channel->recvwindow,
394 channel->recvmaxpacket); 383 channel->recvmaxpacket);
395 channel->readfd = channel->writefd; 384 TRACE(("leave channel_connect_done: success"))
396 channel->initconn = 0; 385 }
397 TRACE(("leave check_in_progress: success")) 386 else
387 {
388 send_msg_channel_open_failure(channel->remotechan,
389 SSH_OPEN_CONNECT_FAILED, "", "");
390 remove_channel(channel);
391 TRACE(("leave check_in_progress: fail"))
398 } 392 }
399 } 393 }
400 394
401 395
402 /* Send the close message and set the channel as closed */ 396 /* Send the close message and set the channel as closed */
403 static void send_msg_channel_close(struct Channel *channel) { 397 static void send_msg_channel_close(struct Channel *channel) {
404 398
405 TRACE(("enter send_msg_channel_close %p", channel)) 399 TRACE(("enter send_msg_channel_close %p", (void*)channel))
406 if (channel->type->closehandler 400 if (channel->type->closehandler
407 && !channel->close_handler_done) { 401 && !channel->close_handler_done) {
408 channel->type->closehandler(channel); 402 channel->type->closehandler(channel);
409 channel->close_handler_done = 1; 403 channel->close_handler_done = 1;
410 } 404 }
439 433
440 TRACE(("leave send_msg_channel_eof")) 434 TRACE(("leave send_msg_channel_eof"))
441 } 435 }
442 436
443 /* Called to write data out to the local side of the channel. 437 /* Called to write data out to the local side of the channel.
444 * Only called when we know we can write to a channel, writes as much as 438 Writes the circular buffer contents and also the "moredata" buffer
445 * possible */ 439 if not null. Will ignore EAGAIN */
446 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) { 440 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
447 441 const unsigned char *moredata, unsigned int *morelen) {
448 int len, maxlen; 442
443 struct iovec iov[3];
444 unsigned char *circ_p1, *circ_p2;
445 unsigned int circ_len1, circ_len2;
446 int io_count = 0;
447
448 int written;
449 449
450 TRACE(("enter writechannel fd %d", fd)) 450 TRACE(("enter writechannel fd %d", fd))
451
452 cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
453
454 if (circ_len1 > 0) {
455 TRACE(("circ1 %d", circ_len1))
456 iov[io_count].iov_base = circ_p1;
457 iov[io_count].iov_len = circ_len1;
458 io_count++;
459 }
460
461 if (circ_len2 > 0) {
462 TRACE(("circ2 %d", circ_len2))
463 iov[io_count].iov_base = circ_p2;
464 iov[io_count].iov_len = circ_len2;
465 io_count++;
466 }
467
468 if (morelen) {
469 assert(moredata);
470 TRACE(("more %d", *morelen))
471 iov[io_count].iov_base = (void*)moredata;
472 iov[io_count].iov_len = *morelen;
473 io_count++;
474 }
475
476 if (morelen) {
477 /* Default return value, none consumed */
478 *morelen = 0;
479 }
480
481 written = writev(fd, iov, io_count);
482
483 if (written < 0) {
484 if (errno != EINTR && errno != EAGAIN) {
485 TRACE(("errno %d len %d", errno, len))
486 close_chan_fd(channel, fd, SHUT_WR);
487 }
488 } else {
489 int cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written);
490 cbuf_incrread(cbuf, cbuf_written);
491 if (morelen) {
492 *morelen = written - cbuf_written;
493 }
494 channel->recvdonelen += written;
495 }
496
497 #if 0
451 498
452 maxlen = cbuf_readlen(cbuf); 499 maxlen = cbuf_readlen(cbuf);
453 500
454 /* Write the data out */ 501 /* Write the data out */
455 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); 502 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
463 } 510 }
464 TRACE(("writechannel wrote %d", len)) 511 TRACE(("writechannel wrote %d", len))
465 512
466 cbuf_incrread(cbuf, len); 513 cbuf_incrread(cbuf, len);
467 channel->recvdonelen += len; 514 channel->recvdonelen += len;
515 #endif
468 516
469 /* Window adjust handling */ 517 /* Window adjust handling */
470 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { 518 if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
471 /* Set it back to max window */
472 send_msg_channel_window_adjust(channel, channel->recvdonelen); 519 send_msg_channel_window_adjust(channel, channel->recvdonelen);
473 channel->recvwindow += channel->recvdonelen; 520 channel->recvwindow += channel->recvdonelen;
474 channel->recvdonelen = 0; 521 channel->recvdonelen = 0;
475 } 522 }
476 523
512 FD_SET(channel->errfd, readfds); 559 FD_SET(channel->errfd, readfds);
513 } 560 }
514 } 561 }
515 562
516 /* Stuff from the wire */ 563 /* Stuff from the wire */
517 if (channel->initconn 564 if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
518 ||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
519 FD_SET(channel->writefd, writefds); 565 FD_SET(channel->writefd, writefds);
520 } 566 }
521 567
522 if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0 568 if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0
523 && cbuf_getused(channel->extrabuf) > 0) { 569 && cbuf_getused(channel->extrabuf) > 0) {
584 630
585 if (IS_DROPBEAR_SERVER || (channel->writefd != STDOUT_FILENO)) { 631 if (IS_DROPBEAR_SERVER || (channel->writefd != STDOUT_FILENO)) {
586 /* close the FDs in case they haven't been done 632 /* close the FDs in case they haven't been done
587 * yet (they might have been shutdown etc) */ 633 * yet (they might have been shutdown etc) */
588 TRACE(("CLOSE writefd %d", channel->writefd)) 634 TRACE(("CLOSE writefd %d", channel->writefd))
589 close(channel->writefd); 635 m_close(channel->writefd);
590 TRACE(("CLOSE readfd %d", channel->readfd)) 636 TRACE(("CLOSE readfd %d", channel->readfd))
591 close(channel->readfd); 637 m_close(channel->readfd);
592 TRACE(("CLOSE errfd %d", channel->errfd)) 638 TRACE(("CLOSE errfd %d", channel->errfd))
593 close(channel->errfd); 639 m_close(channel->errfd);
594 } 640 }
595 641
596 if (!channel->close_handler_done 642 if (!channel->close_handler_done
597 && channel->type->closehandler) { 643 && channel->type->closehandler) {
598 channel->type->closehandler(channel); 644 channel->type->closehandler(channel);
599 channel->close_handler_done = 1; 645 channel->close_handler_done = 1;
600 } 646 }
601 647
648 if (channel->conn_pending) {
649 cancel_connect(channel->conn_pending);
650 }
651
602 ses.channels[channel->index] = NULL; 652 ses.channels[channel->index] = NULL;
603 m_free(channel); 653 m_free(channel);
604 ses.chancount--; 654 ses.chancount--;
605 655
606 update_channel_prio(); 656 update_channel_prio();
614 664
615 struct Channel *channel; 665 struct Channel *channel;
616 666
617 channel = getchannel(); 667 channel = getchannel();
618 668
619 TRACE(("enter recv_msg_channel_request %p", channel)) 669 TRACE(("enter recv_msg_channel_request %p", (void*)channel))
620 670
621 if (channel->sent_close) { 671 if (channel->sent_close) {
622 TRACE(("leave recv_msg_channel_request: already closed channel")) 672 TRACE(("leave recv_msg_channel_request: already closed channel"))
623 return; 673 return;
624 } 674 }
747 797
748 unsigned int datalen; 798 unsigned int datalen;
749 unsigned int maxdata; 799 unsigned int maxdata;
750 unsigned int buflen; 800 unsigned int buflen;
751 unsigned int len; 801 unsigned int len;
802 unsigned int consumed;
752 803
753 TRACE(("enter recv_msg_channel_data")) 804 TRACE(("enter recv_msg_channel_data"))
754 805
755 if (channel->recv_eof) { 806 if (channel->recv_eof) {
756 dropbear_exit("Received data after eof"); 807 dropbear_exit("Received data after eof");
772 * lead to corrupted file transfers etc (chunks missed etc). It's better to 823 * lead to corrupted file transfers etc (chunks missed etc). It's better to
773 * just die horribly */ 824 * just die horribly */
774 if (datalen > maxdata) { 825 if (datalen > maxdata) {
775 dropbear_exit("Oversized packet"); 826 dropbear_exit("Oversized packet");
776 } 827 }
828
829 dropbear_assert(channel->recvwindow >= datalen);
830 channel->recvwindow -= datalen;
831 dropbear_assert(channel->recvwindow <= opts.recv_window);
832
833 consumed = datalen;
834 writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed);
835
836 datalen -= consumed;
837 buf_incrpos(ses.payload, consumed);
838
777 839
778 /* We may have to run throught twice, if the buffer wraps around. Can't 840 /* We may have to run throught twice, if the buffer wraps around. Can't
779 * just "leave it for next time" like with writechannel, since this 841 * just "leave it for next time" like with writechannel, since this
780 * is payload data */ 842 * is payload data */
781 len = datalen; 843 len = datalen;
787 buf_getptr(ses.payload, buflen), buflen); 849 buf_getptr(ses.payload, buflen), buflen);
788 cbuf_incrwrite(cbuf, buflen); 850 cbuf_incrwrite(cbuf, buflen);
789 buf_incrpos(ses.payload, buflen); 851 buf_incrpos(ses.payload, buflen);
790 len -= buflen; 852 len -= buflen;
791 } 853 }
792
793 dropbear_assert(channel->recvwindow >= datalen);
794 channel->recvwindow -= datalen;
795 dropbear_assert(channel->recvwindow <= opts.recv_window);
796 854
797 TRACE(("leave recv_msg_channel_data")) 855 TRACE(("leave recv_msg_channel_data"))
798 } 856 }
799 857
800 /* Increment the outgoing data window for a channel - the remote end limits 858 /* Increment the outgoing data window for a channel - the remote end limits
999 } else { 1057 } else {
1000 closein = 1; 1058 closein = 1;
1001 } 1059 }
1002 } else { 1060 } else {
1003 TRACE(("CLOSE some fd %d", fd)) 1061 TRACE(("CLOSE some fd %d", fd))
1004 close(fd); 1062 m_close(fd);
1005 closein = closeout = 1; 1063 closein = closeout = 1;
1006 } 1064 }
1007 1065
1008 if (closeout && (fd == channel->readfd)) { 1066 if (closeout && (fd == channel->readfd)) {
1009 channel->readfd = FD_CLOSED; 1067 channel->readfd = FD_CLOSED;
1022 /* if we called shutdown on it and all references are gone, then we 1080 /* if we called shutdown on it and all references are gone, then we
1023 * need to close() it to stop it lingering */ 1081 * need to close() it to stop it lingering */
1024 if (channel->type->sepfds && channel->readfd == FD_CLOSED 1082 if (channel->type->sepfds && channel->readfd == FD_CLOSED
1025 && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) { 1083 && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
1026 TRACE(("CLOSE (finally) of %d", fd)) 1084 TRACE(("CLOSE (finally) of %d", fd))
1027 close(fd); 1085 m_close(fd);
1028 } 1086 }
1029 } 1087 }
1030 1088
1031 1089
1032 #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT) 1090 #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
1139 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); 1197 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
1140 encrypt_packet(); 1198 encrypt_packet();
1141 } 1199 }
1142 1200
1143 struct Channel* get_any_ready_channel() { 1201 struct Channel* get_any_ready_channel() {
1202 size_t i;
1144 if (ses.chancount == 0) { 1203 if (ses.chancount == 0) {
1145 return NULL; 1204 return NULL;
1146 } 1205 }
1147 size_t i;
1148 for (i = 0; i < ses.chansize; i++) { 1206 for (i = 0; i < ses.chansize; i++) {
1149 struct Channel *chan = ses.channels[i]; 1207 struct Channel *chan = ses.channels[i];
1150 if (chan 1208 if (chan
1151 && !(chan->sent_eof || chan->recv_eof) 1209 && !(chan->sent_eof || chan->recv_eof)
1152 && !(chan->await_open || chan->initconn)) { 1210 && !(chan->await_open)) {
1153 return chan; 1211 return chan;
1154 } 1212 }
1155 } 1213 }
1156 return NULL; 1214 return NULL;
1157 } 1215 }