comparison common-channel.c @ 118:5312ca05ed48 private-rez

propagate of 717950f4061f1123659ee87c7c168805af920ab7 and 839f98f136788cc1466e4641bf796f96040a085d from branch 'matt.dbclient.authpam' to 'matt.dbclient.rez'
author Matt Johnston <matt@ucc.asn.au>
date Sun, 12 Sep 2004 04:56:50 +0000
parents 2e9d1f29c50f
children 8c2b3506f112
comparison
equal deleted inserted replaced
57:3b2a5a1c4347 118:5312ca05ed48
1 /* 1 /*
2 * Dropbear - a SSH2 server 2 * Dropbear SSH
3 * 3 *
4 * Copyright (c) 2002,2003 Matt Johnston 4 * Copyright (c) 2002-2004 Matt Johnston
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy 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 8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights 9 * in the Software without restriction, including without limitation the rights
27 #include "includes.h" 27 #include "includes.h"
28 #include "session.h" 28 #include "session.h"
29 #include "packet.h" 29 #include "packet.h"
30 #include "ssh.h" 30 #include "ssh.h"
31 #include "buffer.h" 31 #include "buffer.h"
32 #include "circbuffer.h"
32 #include "dbutil.h" 33 #include "dbutil.h"
33 #include "channel.h" 34 #include "channel.h"
34 #include "ssh.h" 35 #include "ssh.h"
35 #include "tcpfwd-direct.h"
36 #include "tcpfwd-remote.h"
37 #include "listener.h" 36 #include "listener.h"
38 37
39 static void send_msg_channel_open_failure(unsigned int remotechan, int reason, 38 static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
40 const unsigned char *text, const unsigned char *lang); 39 const unsigned char *text, const unsigned char *lang);
41 static void send_msg_channel_open_confirmation(struct Channel* channel, 40 static void send_msg_channel_open_confirmation(struct Channel* channel,
42 unsigned int recvwindow, 41 unsigned int recvwindow,
43 unsigned int recvmaxpacket); 42 unsigned int recvmaxpacket);
44 static void writechannel(struct Channel *channel); 43 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
45 static void send_msg_channel_window_adjust(struct Channel *channel, 44 static void send_msg_channel_window_adjust(struct Channel *channel,
46 unsigned int incr); 45 unsigned int incr);
47 static void send_msg_channel_data(struct Channel *channel, int isextended, 46 static void send_msg_channel_data(struct Channel *channel, int isextended,
48 unsigned int exttype); 47 unsigned int exttype);
49 static void send_msg_channel_eof(struct Channel *channel); 48 static void send_msg_channel_eof(struct Channel *channel);
147 newchan->infd = FD_UNINIT; 146 newchan->infd = FD_UNINIT;
148 newchan->outfd = FD_UNINIT; 147 newchan->outfd = FD_UNINIT;
149 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ 148 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
150 newchan->initconn = 0; 149 newchan->initconn = 0;
151 150
152 newchan->writebuf = buf_new(RECV_MAXWINDOW); 151 newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
152 newchan->extrabuf = NULL; /* The user code can set it up */
153 newchan->recvwindow = RECV_MAXWINDOW; 153 newchan->recvwindow = RECV_MAXWINDOW;
154 newchan->recvdonelen = 0;
154 newchan->recvmaxpacket = RECV_MAXPACKET; 155 newchan->recvmaxpacket = RECV_MAXPACKET;
155 156
156 ses.channels[i] = newchan; 157 ses.channels[i] = newchan;
157 ses.chancount++; 158 ses.chancount++;
158 159
160 161
161 return newchan; 162 return newchan;
162 } 163 }
163 164
164 /* Get the channel structure corresponding to a channel number */ 165 /* Get the channel structure corresponding to a channel number */
165 static struct Channel* getchannel(unsigned int chan) { 166 struct Channel* getchannel(unsigned int chan) {
166 if (chan >= ses.chansize || ses.channels[chan] == NULL) { 167 if (chan >= ses.chansize || ses.channels[chan] == NULL) {
167 return NULL; 168 return NULL;
168 } 169 }
169 return ses.channels[chan]; 170 return ses.channels[chan];
170 } 171 }
172 /* Iterate through the channels, performing IO if available */ 173 /* Iterate through the channels, performing IO if available */
173 void channelio(fd_set *readfd, fd_set *writefd) { 174 void channelio(fd_set *readfd, fd_set *writefd) {
174 175
175 struct Channel *channel; 176 struct Channel *channel;
176 unsigned int i; 177 unsigned int i;
178 int ret;
177 179
178 /* iterate through all the possible channels */ 180 /* iterate through all the possible channels */
179 for (i = 0; i < ses.chansize; i++) { 181 for (i = 0; i < ses.chansize; i++) {
180 182
181 channel = ses.channels[i]; 183 channel = ses.channels[i];
188 if (channel->outfd >= 0 && FD_ISSET(channel->outfd, readfd)) { 190 if (channel->outfd >= 0 && FD_ISSET(channel->outfd, readfd)) {
189 send_msg_channel_data(channel, 0, 0); 191 send_msg_channel_data(channel, 0, 0);
190 } 192 }
191 193
192 /* read from program/pipe stderr */ 194 /* read from program/pipe stderr */
193 if (channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) { 195 if (channel->extrabuf == NULL &&
196 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) {
194 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR); 197 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
195 } 198 }
196 199
197 /* if we can read from the infd, it might be closed, so we try to 200 /* if we can read from the infd, it might be closed, so we try to
198 * see if it has errors */ 201 * see if it has errors */
199 if (channel->infd >= 0 && channel->infd != channel->outfd 202 if (channel->infd >= 0 && channel->infd != channel->outfd
200 && FD_ISSET(channel->infd, readfd)) { 203 && FD_ISSET(channel->infd, readfd)) {
201 int ret; 204 if (channel->initconn) {
202 ret = write(channel->infd, NULL, 0); 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 */
211 }
212 ret = write(channel->infd, NULL, 0); /* Fake write */
203 if (ret < 0 && errno != EINTR && errno != EAGAIN) { 213 if (ret < 0 && errno != EINTR && errno != EAGAIN) {
204 closeinfd(channel); 214 closeinfd(channel);
205 } 215 }
206 } 216 }
207 217
209 if (channel->infd >= 0 && FD_ISSET(channel->infd, writefd)) { 219 if (channel->infd >= 0 && FD_ISSET(channel->infd, writefd)) {
210 if (channel->initconn) { 220 if (channel->initconn) {
211 checkinitdone(channel); 221 checkinitdone(channel);
212 continue; /* Important not to use the channel after 222 continue; /* Important not to use the channel after
213 checkinitdone(), as it may be NULL */ 223 checkinitdone(), as it may be NULL */
214 } else {
215 writechannel(channel);
216 } 224 }
225 writechannel(channel, channel->infd, channel->writebuf);
226 }
227
228 /* stderr for client mode */
229 if (channel->extrabuf != NULL
230 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) {
231 writechannel(channel, channel->errfd, channel->extrabuf);
217 } 232 }
218 233
219 /* now handle any of the channel-closing type stuff */ 234 /* now handle any of the channel-closing type stuff */
220 checkclose(channel); 235 checkclose(channel);
221 236
228 } 243 }
229 244
230 245
231 /* do all the EOF/close type stuff checking for a channel */ 246 /* do all the EOF/close type stuff checking for a channel */
232 static void checkclose(struct Channel *channel) { 247 static void checkclose(struct Channel *channel) {
248
249 TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d",
250 channel->infd, channel->outfd,
251 channel->errfd, channel->sentclosed, channel->recvclosed));
252 TRACE(("writebuf %d extrabuf %s extrabuf %d",
253 cbuf_getused(channel->writebuf),
254 channel->writebuf,
255 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)));
233 256
234 if (!channel->sentclosed) { 257 if (!channel->sentclosed) {
235 258
236 /* check for exited - currently only used for server sessions, 259 /* check for exited - currently only used for server sessions,
237 * if the shell has exited etc */ 260 * if the shell has exited etc */
241 } 264 }
242 } 265 }
243 266
244 if (!channel->senteof 267 if (!channel->senteof
245 && channel->outfd == FD_CLOSED 268 && channel->outfd == FD_CLOSED
246 && channel->errfd == FD_CLOSED) { 269 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
247 send_msg_channel_eof(channel); 270 send_msg_channel_eof(channel);
248 } 271 }
249 272
250 if (channel->infd == FD_CLOSED 273 if (channel->infd == FD_CLOSED
251 && channel->outfd == FD_CLOSED 274 && channel->outfd == FD_CLOSED
252 && channel->errfd == FD_CLOSED) { 275 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
253 send_msg_channel_close(channel); 276 send_msg_channel_close(channel);
254 } 277 }
255 } 278 }
256 279
257 /* When either party wishes to terminate the channel, it sends 280 /* When either party wishes to terminate the channel, it sends
285 308
286 TRACE(("enter checkinitdone")); 309 TRACE(("enter checkinitdone"));
287 310
288 if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen) 311 if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen)
289 || val != 0) { 312 || val != 0) {
313 send_msg_channel_open_failure(channel->remotechan,
314 SSH_OPEN_CONNECT_FAILED, "", "");
290 close(channel->infd); 315 close(channel->infd);
291 deletechannel(channel); 316 deletechannel(channel);
292 TRACE(("leave checkinitdone: fail")); 317 TRACE(("leave checkinitdone: fail"));
293 } else { 318 } else {
319 send_msg_channel_open_confirmation(channel, channel->recvwindow,
320 channel->recvmaxpacket);
294 channel->outfd = channel->infd; 321 channel->outfd = channel->infd;
295 channel->initconn = 0; 322 channel->initconn = 0;
296 TRACE(("leave checkinitdone: success")); 323 TRACE(("leave checkinitdone: success"));
297 } 324 }
298 } 325 }
305 TRACE(("enter send_msg_channel_close")); 332 TRACE(("enter send_msg_channel_close"));
306 /* XXX server */ 333 /* XXX server */
307 if (channel->type->closehandler) { 334 if (channel->type->closehandler) {
308 channel->type->closehandler(channel); 335 channel->type->closehandler(channel);
309 } 336 }
310 #if 0
311 if (channel->type == CHANNEL_ID_SESSION) {
312 send_exitsignalstatus(channel);
313
314 closechansess(channel);
315 }
316 #endif
317 337
318 CHECKCLEARTOWRITE(); 338 CHECKCLEARTOWRITE();
319 339
320 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_CLOSE); 340 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_CLOSE);
321 buf_putint(ses.writepayload, channel->remotechan); 341 buf_putint(ses.writepayload, channel->remotechan);
341 channel->senteof = 1; 361 channel->senteof = 1;
342 362
343 TRACE(("leave send_msg_channel_eof")); 363 TRACE(("leave send_msg_channel_eof"));
344 } 364 }
345 365
346 /* Called to write data out to the server side of a channel (eg a shell or a 366 /* Called to write data out to the local side of the channel.
347 * program.
348 * Only called when we know we can write to a channel, writes as much as 367 * Only called when we know we can write to a channel, writes as much as
349 * possible */ 368 * possible */
350 static void writechannel(struct Channel* channel) { 369 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
351 370
352 int len, maxlen; 371 int len, maxlen;
353 buffer *buf;
354 372
355 TRACE(("enter writechannel")); 373 TRACE(("enter writechannel"));
356 374
357 buf = channel->writebuf; 375 maxlen = cbuf_readlen(cbuf);
358 maxlen = buf->len - buf->pos; 376
359 377 /* Write the data out */
360 len = write(channel->infd, buf_getptr(buf, maxlen), maxlen); 378 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
361 if (len <= 0) { 379 if (len <= 0) {
362 if (len < 0 && errno != EINTR) { 380 if (len < 0 && errno != EINTR) {
363 /* no more to write */ 381 /* no more to write - we close it even if the fd was stderr, since
382 * that's a nasty failure too */
364 closeinfd(channel); 383 closeinfd(channel);
365 } 384 }
366 TRACE(("leave writechannel: len <= 0")); 385 TRACE(("leave writechannel: len <= 0"));
367 return; 386 return;
368 } 387 }
369 388
370 if (len == maxlen) { 389 cbuf_incrread(cbuf, len);
371 buf_setpos(buf, 0); 390 channel->recvdonelen += len;
372 buf_setlen(buf, 0); 391
373 392 if (fd == channel->infd && len == maxlen && channel->recveof) {
374 if (channel->recveof) { 393 /* Check if we're closing up */
375 /* we're closing up */ 394 closeinfd(channel);
376 closeinfd(channel); 395 TRACE(("leave writechannel: recveof set"));
377 return; 396 return;
378 TRACE(("leave writechannel: recveof set")); 397 }
379 } 398
380 399 /* Window adjust handling */
381 /* extend the window if we're at the end*/ 400 if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
382 /* TODO - this is inefficient */ 401 /* Set it back to max window */
383 send_msg_channel_window_adjust(channel, buf->size 402 send_msg_channel_window_adjust(channel, channel->recvdonelen);
384 - channel->recvwindow); 403 channel->recvwindow += channel->recvdonelen;
385 channel->recvwindow = buf->size; 404 channel->recvdonelen = 0;
386 } else { 405 }
387 buf_incrpos(buf, len); 406
388 } 407 assert(channel->recvwindow <= RECV_MAXWINDOW);
408 assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
409 assert(channel->extrabuf == NULL ||
410 channel->recvwindow <= cbuf_getavail(channel->extrabuf));
411
412
389 TRACE(("leave writechannel")); 413 TRACE(("leave writechannel"));
390 } 414 }
391 415
392 /* Set the file descriptors for the main select in session.c 416 /* Set the file descriptors for the main select in session.c
393 * This avoid channels which don't have any window available, are closed, etc*/ 417 * This avoid channels which don't have any window available, are closed, etc*/
401 channel = ses.channels[i]; 425 channel = ses.channels[i];
402 if (channel == NULL) { 426 if (channel == NULL) {
403 continue; 427 continue;
404 } 428 }
405 429
406 /* stdout and stderr */ 430 /* Stuff to put over the wire */
407 if (channel->transwindow > 0) { 431 if (channel->transwindow > 0) {
408 432
409 /* stdout */
410 if (channel->outfd >= 0) { 433 if (channel->outfd >= 0) {
411 /* there's space to read more from the program */
412 FD_SET(channel->outfd, readfd); 434 FD_SET(channel->outfd, readfd);
413 } 435 }
414 /* stderr */ 436
415 if (channel->errfd >= 0) { 437 if (channel->extrabuf == NULL && channel->errfd >= 0) {
416 FD_SET(channel->errfd, readfd); 438 FD_SET(channel->errfd, readfd);
417 } 439 }
418 } 440 }
419 441
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,
446 channel->errfd,
447 cbuf_getused(channel->writebuf) ));
420 if (channel->infd >= 0 && channel->infd != channel->outfd) { 448 if (channel->infd >= 0 && channel->infd != channel->outfd) {
421 FD_SET(channel->infd, readfd); 449 FD_SET(channel->infd, readfd);
422 } 450 }
423 451
424 /* stdin */ 452 /* Stuff from the wire, to local program/shell/user etc */
425 if (channel->infd >= 0 && 453 if ((channel->infd >= 0 && cbuf_getused(channel->writebuf) > 0 )
426 (channel->writebuf->pos < channel->writebuf->len || 454 || channel->initconn) {
427 channel->initconn)) { 455
428 /* there's space to write more to the program */ 456 FD_SET(channel->infd, writefd);
429 FD_SET(channel->infd, writefd); 457 }
458
459 if (channel->extrabuf != NULL && channel->errfd >= 0
460 && cbuf_getused(channel->extrabuf) > 0 ) {
461 FD_SET(channel->errfd, writefd);
430 } 462 }
431 463
432 } /* foreach channel */ 464 } /* foreach channel */
433 465
434 #ifdef USING_LISTENERS 466 #ifdef USING_LISTENERS
453 if (channel == NULL) { 485 if (channel == NULL) {
454 dropbear_exit("EOF for unknown channel"); 486 dropbear_exit("EOF for unknown channel");
455 } 487 }
456 488
457 channel->recveof = 1; 489 channel->recveof = 1;
458 if (channel->writebuf->len == 0) { 490 if (cbuf_getused(channel->writebuf) == 0
491 && (channel->extrabuf == NULL
492 || cbuf_getused(channel->extrabuf) == 0)) {
459 closeinfd(channel); 493 closeinfd(channel);
460 } 494 }
461 495
462 TRACE(("leave recv_msg_channel_eof")); 496 TRACE(("leave recv_msg_channel_eof"));
463 } 497 }
495 static void removechannel(struct Channel * channel) { 529 static void removechannel(struct Channel * channel) {
496 530
497 TRACE(("enter removechannel")); 531 TRACE(("enter removechannel"));
498 TRACE(("channel index is %d", channel->index)); 532 TRACE(("channel index is %d", channel->index));
499 533
500 buf_free(channel->writebuf); 534 cbuf_free(channel->writebuf);
535 channel->writebuf = NULL;
536
537 if (channel->extrabuf) {
538 cbuf_free(channel->extrabuf);
539 channel->extrabuf = NULL;
540 }
541
501 542
502 /* close the FDs in case they haven't been done 543 /* close the FDs in case they haven't been done
503 * yet (ie they were shutdown etc */ 544 * yet (ie they were shutdown etc */
504 close(channel->infd); 545 close(channel->infd);
505 close(channel->outfd); 546 close(channel->outfd);
506 if (channel->errfd >= 0) { 547 close(channel->errfd);
507 close(channel->errfd); 548
508 } 549 channel->typedata = NULL;
509 550
510 deletechannel(channel); 551 deletechannel(channel);
511 552
512 TRACE(("leave removechannel")); 553 TRACE(("leave removechannel"));
513 } 554 }
542 if (channel->type->reqhandler) { 583 if (channel->type->reqhandler) {
543 channel->type->reqhandler(channel); 584 channel->type->reqhandler(channel);
544 } else { 585 } else {
545 send_msg_channel_failure(channel); 586 send_msg_channel_failure(channel);
546 } 587 }
547
548 #if 0
549 /* handle according to channel type */
550 switch (channel->type) {
551
552 case CHANNEL_ID_SESSION:
553 TRACE(("continue recv_msg_channel_request: session request"));
554 /* XXX server */
555 /* Here we need to do things channel-specific style. Function
556 * pointer callbacks perhaps */
557 chansessionrequest(channel);
558 break;
559
560 default:
561 send_msg_channel_failure(channel);
562 }
563 #endif
564 588
565 TRACE(("leave recv_msg_channel_request")); 589 TRACE(("leave recv_msg_channel_request"));
566 590
567 } 591 }
568 592
602 TRACE(("leave send_msg_channel_data: no window")); 626 TRACE(("leave send_msg_channel_data: no window"));
603 return; /* the data will get written later */ 627 return; /* the data will get written later */
604 } 628 }
605 629
606 /* read the data */ 630 /* read the data */
631 TRACE(("maxlen %d", maxlen));
607 buf = buf_new(maxlen); 632 buf = buf_new(maxlen);
633 TRACE(("buf pos %d data %x", buf->pos, buf->data));
608 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen); 634 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
609 if (len <= 0) { 635 if (len <= 0) {
610 /* on error/eof, send eof */ 636 /* on error/eof, send eof */
611 if (len == 0 || errno != EINTR) { 637 if (len == 0 || errno != EINTR) {
612 closeoutfd(channel, fd); 638 closeoutfd(channel, fd);
613 TRACE(("leave send_msg_channel_data: read err %d", channel->index));
614 } 639 }
615 buf_free(buf); 640 buf_free(buf);
641 buf = NULL;
642 TRACE(("leave send_msg_channel_data: read err or EOF for fd %d",
643 channel->index));
616 return; 644 return;
617 } 645 }
618 buf_incrlen(buf, len); 646 buf_incrlen(buf, len);
619 647
620 buf_putbyte(ses.writepayload, 648 buf_putbyte(ses.writepayload,
625 buf_putint(ses.writepayload, exttype); 653 buf_putint(ses.writepayload, exttype);
626 } 654 }
627 655
628 buf_putstring(ses.writepayload, buf_getptr(buf, len), len); 656 buf_putstring(ses.writepayload, buf_getptr(buf, len), len);
629 buf_free(buf); 657 buf_free(buf);
658 buf = NULL;
630 659
631 channel->transwindow -= len; 660 channel->transwindow -= len;
632 661
633 encrypt_packet(); 662 encrypt_packet();
634 TRACE(("leave send_msg_channel_data")); 663 TRACE(("leave send_msg_channel_data"));
635 } 664 }
636 665
637 666 /* We receive channel data */
638 /* when we receive channel data, put it in a buffer for writing to the program/
639 * shell etc */
640 void recv_msg_channel_data() { 667 void recv_msg_channel_data() {
641 668
642 unsigned int chan; 669 unsigned int chan;
643 struct Channel * channel; 670 struct Channel *channel;
644 unsigned int datalen; 671
645 unsigned int pos;
646 unsigned int maxdata;
647
648 TRACE(("enter recv_msg_channel_data"));
649
650 chan = buf_getint(ses.payload); 672 chan = buf_getint(ses.payload);
651 channel = getchannel(chan); 673 channel = getchannel(chan);
674
652 if (channel == NULL) { 675 if (channel == NULL) {
653 dropbear_exit("Unknown channel"); 676 dropbear_exit("Unknown channel");
654 } 677 }
655 678
679 common_recv_msg_channel_data(channel, channel->infd, channel->writebuf);
680 }
681
682 /* Shared for data and stderr data - when we receive data, put it in a buffer
683 * for writing to the local file descriptor */
684 void common_recv_msg_channel_data(struct Channel *channel, int fd,
685 circbuffer * cbuf) {
686
687 unsigned int datalen;
688 unsigned int maxdata;
689 unsigned int buflen;
690 unsigned int len;
691
692 TRACE(("enter recv_msg_channel_data"));
693
656 if (channel->recveof) { 694 if (channel->recveof) {
657 dropbear_exit("received data after eof"); 695 dropbear_exit("received data after eof");
658 } 696 }
659 697
660 if (channel->infd < 0) { 698 if (fd < 0) {
661 dropbear_exit("received data with bad infd"); 699 dropbear_exit("received data with bad infd");
662 } 700 }
663 701
664 datalen = buf_getint(ses.payload); 702 datalen = buf_getint(ses.payload);
665 703
666 /* if the client is going to send us more data than we've allocated, then 704
667 * it has ignored the windowsize, so we "MAY ignore all extra data" */ 705 maxdata = cbuf_getavail(cbuf);
668 maxdata = channel->writebuf->size - channel->writebuf->pos; 706
707 /* Whilst the spec says we "MAY ignore data past the end" this could
708 * lead to corrupted file transfers etc (chunks missed etc). It's better to
709 * just die horribly */
669 if (datalen > maxdata) { 710 if (datalen > maxdata) {
670 TRACE(("Warning: recv_msg_channel_data: extra data past window")); 711 dropbear_exit("Oversized packet");
671 datalen = maxdata; 712 }
672 } 713
673 714 /* We may have to run throught twice, if the buffer wraps around. Can't
674 /* write to the buffer - we always append to the end of the buffer */ 715 * just "leave it for next time" like with writechannel, since this
675 pos = channel->writebuf->pos; 716 * is payload data */
676 buf_setpos(channel->writebuf, channel->writebuf->len); 717 len = datalen;
677 memcpy(buf_getwriteptr(channel->writebuf, datalen), 718 while (len > 0) {
678 buf_getptr(ses.payload, datalen), datalen); 719 buflen = cbuf_writelen(cbuf);
679 buf_incrwritepos(channel->writebuf, datalen); 720 buflen = MIN(buflen, len);
680 buf_setpos(channel->writebuf, pos); /* revert pos */ 721
681 722 memcpy(cbuf_writeptr(cbuf, buflen),
723 buf_getptr(ses.payload, buflen), buflen);
724 cbuf_incrwrite(cbuf, buflen);
725 buf_incrpos(ses.payload, buflen);
726 len -= buflen;
727 }
728
729 assert(channel->recvwindow >= datalen);
682 channel->recvwindow -= datalen; 730 channel->recvwindow -= datalen;
683 731 assert(channel->recvwindow <= RECV_MAXWINDOW);
684 /* matt - this might be for later */
685 /* if (channel->recvwindow < RECV_MINWINDOW) {
686 send_msg_channel_window_adjust(channel,
687 RECV_MAXWINDOW - channel->recvwindow);
688 channel->recvwindow = RECV_MAXWINDOW;
689 }*/
690 732
691 TRACE(("leave recv_msg_channel_data")); 733 TRACE(("leave recv_msg_channel_data"));
692 } 734 }
693 735
694 /* Increment the outgoing data window for a channel - the remote end limits 736 /* Increment the outgoing data window for a channel - the remote end limits
788 } 830 }
789 831
790 if (channel->type->inithandler) { 832 if (channel->type->inithandler) {
791 ret = channel->type->inithandler(channel); 833 ret = channel->type->inithandler(channel);
792 if (ret > 0) { 834 if (ret > 0) {
835 if (ret == SSH_OPEN_IN_PROGRESS) {
836 /* We'll send the confirmation later */
837 goto cleanup;
838 }
793 errtype = ret; 839 errtype = ret;
794 deletechannel(channel); 840 deletechannel(channel);
795 TRACE(("inithandler returned failure %d", ret)); 841 TRACE(("inithandler returned failure %d", ret));
796 goto failure; 842 goto failure;
797 } 843 }
798 } 844 }
799
800 #if 0
801 /* type specific initialisation */
802 if (typeval == CHANNEL_ID_SESSION) {
803 newchansess(channel);
804 #ifndef DISABLE_LOCALTCPFWD
805 } else if (typeval == CHANNEL_ID_TCPDIRECT) {
806 if (ses.opts->nolocaltcp) {
807 errtype = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
808 } else if (newtcpdirect(channel) == DROPBEAR_FAILURE) {
809 errtype = SSH_OPEN_CONNECT_FAILED;
810 deletechannel(channel);
811 goto failure;
812 }
813 #endif
814 }
815 #endif
816 845
817 /* success */ 846 /* success */
818 send_msg_channel_open_confirmation(channel, channel->recvwindow, 847 send_msg_channel_open_confirmation(channel, channel->recvwindow,
819 channel->recvmaxpacket); 848 channel->recvmaxpacket);
820 goto cleanup; 849 goto cleanup;
908 TRACE(("leave send_msg_channel_open_init() - FAILED in newchannel()")); 937 TRACE(("leave send_msg_channel_open_init() - FAILED in newchannel()"));
909 return DROPBEAR_FAILURE; 938 return DROPBEAR_FAILURE;
910 } 939 }
911 940
912 /* set fd non-blocking */ 941 /* set fd non-blocking */
913 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 942 setnonblocking(fd);
914 TRACE(("leave send_msg_channel_open_init() - FAILED in fcntl()"));
915 return DROPBEAR_FAILURE;
916 }
917 943
918 chan->infd = chan->outfd = fd; 944 chan->infd = chan->outfd = fd;
919 ses.maxfd = MAX(ses.maxfd, fd); 945 ses.maxfd = MAX(ses.maxfd, fd);
920 946
921 /* now open the channel connection */ 947 /* now open the channel connection */
1015 } else { 1041 } else {
1016 close(fd); 1042 close(fd);
1017 closein = closeout = 1; 1043 closein = closeout = 1;
1018 } 1044 }
1019 1045
1020 if (closeout && fd == channel->errfd) {
1021 channel->errfd = FD_CLOSED;
1022 }
1023 if (closeout && fd == channel->outfd) { 1046 if (closeout && fd == channel->outfd) {
1024 channel->outfd = FD_CLOSED; 1047 channel->outfd = FD_CLOSED;
1025 } 1048 }
1049 if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
1050 channel->errfd = FD_CLOSED;
1051 }
1052
1026 if (closein && fd == channel->infd) { 1053 if (closein && fd == channel->infd) {
1027 channel->infd = FD_CLOSED; 1054 channel->infd = FD_CLOSED;
1028 } 1055 }
1056 if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
1057 channel->errfd = FD_CLOSED;
1058 }
1029 } 1059 }
1030 1060
1031 #endif /* USING_LISTENERS */ 1061 #endif /* USING_LISTENERS */