comparison common-channel.c @ 293:9d110777f345 contrib-blacklist

propagate from branch 'au.asn.ucc.matt.dropbear' (head 7ad1775ed65e75dbece27fe6b65bf1a234db386a) to branch 'au.asn.ucc.matt.dropbear.contrib.blacklist' (head 1d86a4f0a401cc68c2670d821a2f6366c37af143)
author Matt Johnston <matt@ucc.asn.au>
date Fri, 10 Mar 2006 06:31:29 +0000
parents e109fb08b8ee
children baea1d43e7eb
comparison
equal deleted inserted replaced
247:c07de41b53d7 293:9d110777f345
50 static void removechannel(struct Channel *channel); 50 static void removechannel(struct Channel *channel);
51 static void deletechannel(struct Channel *channel); 51 static void deletechannel(struct Channel *channel);
52 static void checkinitdone(struct Channel *channel); 52 static void checkinitdone(struct Channel *channel);
53 static void checkclose(struct Channel *channel); 53 static void checkclose(struct Channel *channel);
54 54
55 static void closeinfd(struct Channel * channel); 55 static void closewritefd(struct Channel * channel);
56 static void closeoutfd(struct Channel * channel, int fd); 56 static void closereadfd(struct Channel * channel, int fd);
57 static void closechanfd(struct Channel *channel, int fd, int how); 57 static void closechanfd(struct Channel *channel, int fd, int how);
58 58
59 #define FD_UNINIT (-2) 59 #define FD_UNINIT (-2)
60 #define FD_CLOSED (-1) 60 #define FD_CLOSED (-1)
61 61
141 newchan->remotechan = remotechan; 141 newchan->remotechan = remotechan;
142 newchan->transwindow = transwindow; 142 newchan->transwindow = transwindow;
143 newchan->transmaxpacket = transmaxpacket; 143 newchan->transmaxpacket = transmaxpacket;
144 144
145 newchan->typedata = NULL; 145 newchan->typedata = NULL;
146 newchan->infd = FD_UNINIT; 146 newchan->writefd = FD_UNINIT;
147 newchan->outfd = FD_UNINIT; 147 newchan->readfd = FD_UNINIT;
148 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 */
149 newchan->initconn = 0; 149 newchan->initconn = 0;
150 newchan->await_open = 0; 150 newchan->await_open = 0;
151 151
152 newchan->writebuf = cbuf_new(RECV_MAXWINDOW); 152 newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
175 } 175 }
176 return ses.channels[chan]; 176 return ses.channels[chan];
177 } 177 }
178 178
179 /* Iterate through the channels, performing IO if available */ 179 /* Iterate through the channels, performing IO if available */
180 void channelio(fd_set *readfd, fd_set *writefd) { 180 void channelio(fd_set *readfds, fd_set *writefds) {
181 181
182 struct Channel *channel; 182 struct Channel *channel;
183 unsigned int i; 183 unsigned int i;
184 int ret;
185 184
186 /* iterate through all the possible channels */ 185 /* iterate through all the possible channels */
187 for (i = 0; i < ses.chansize; i++) { 186 for (i = 0; i < ses.chansize; i++) {
188 187
189 channel = ses.channels[i]; 188 channel = ses.channels[i];
190 if (channel == NULL) { 189 if (channel == NULL) {
191 /* only process in-use channels */ 190 /* only process in-use channels */
192 continue; 191 continue;
193 } 192 }
194 193
195 /* read from program/pipe stdout */ 194 /* read data and send it over the wire */
196 if (channel->outfd >= 0 && FD_ISSET(channel->outfd, readfd)) { 195 if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
197 send_msg_channel_data(channel, 0, 0); 196 send_msg_channel_data(channel, 0, 0);
198 } 197 }
199 198
200 /* read from program/pipe stderr */ 199 /* read stderr data and send it over the wire */
201 if (channel->extrabuf == NULL && 200 if (channel->extrabuf == NULL &&
202 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) { 201 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) {
203 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR); 202 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
204 } 203 }
205 204
206 /* if we can read from the infd, it might be closed, so we try to
207 * see if it has errors */
208 if (channel->infd >= 0 && channel->infd != channel->outfd
209 && FD_ISSET(channel->infd, readfd)) {
210 if (channel->initconn) {
211 /* Handling for "in progress" connection - this is needed
212 * to avoid spinning 100% CPU when we connect to a server
213 * which doesn't send anything (tcpfwding) */
214 checkinitdone(channel);
215 continue; /* Important not to use the channel after
216 checkinitdone(), as it may be NULL */
217 }
218 ret = write(channel->infd, NULL, 0); /* Fake write */
219 if (ret < 0 && errno != EINTR && errno != EAGAIN) {
220 closeinfd(channel);
221 }
222 }
223
224 /* write to program/pipe stdin */ 205 /* write to program/pipe stdin */
225 if (channel->infd >= 0 && FD_ISSET(channel->infd, writefd)) { 206 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
226 if (channel->initconn) { 207 if (channel->initconn) {
227 checkinitdone(channel); 208 checkinitdone(channel);
228 continue; /* Important not to use the channel after 209 continue; /* Important not to use the channel after
229 checkinitdone(), as it may be NULL */ 210 checkinitdone(), as it may be NULL */
230 } 211 }
231 writechannel(channel, channel->infd, channel->writebuf); 212 writechannel(channel, channel->writefd, channel->writebuf);
232 } 213 }
233 214
234 /* stderr for client mode */ 215 /* stderr for client mode */
235 if (channel->extrabuf != NULL 216 if (channel->extrabuf != NULL
236 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) { 217 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
237 writechannel(channel, channel->errfd, channel->extrabuf); 218 writechannel(channel, channel->errfd, channel->extrabuf);
238 } 219 }
239 220
240 /* now handle any of the channel-closing type stuff */ 221 /* now handle any of the channel-closing type stuff */
241 checkclose(channel); 222 checkclose(channel);
242 223
243 } /* foreach channel */ 224 } /* foreach channel */
244 225
245 /* Listeners such as TCP, X11, agent-auth */ 226 /* Listeners such as TCP, X11, agent-auth */
246 #ifdef USING_LISTENERS 227 #ifdef USING_LISTENERS
247 handle_listeners(readfd); 228 handle_listeners(readfds);
248 #endif 229 #endif
249 } 230 }
250 231
251 232
252 /* do all the EOF/close type stuff checking for a channel */ 233 /* do all the EOF/close type stuff checking for a channel */
253 static void checkclose(struct Channel *channel) { 234 static void checkclose(struct Channel *channel) {
254 235
255 TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d", 236 TRACE(("checkclose: writefd %d, readfd %d, errfd %d, sentclosed %d, recvclosed %d",
256 channel->infd, channel->outfd, 237 channel->writefd, channel->readfd,
257 channel->errfd, channel->sentclosed, channel->recvclosed)) 238 channel->errfd, channel->sentclosed, channel->recvclosed))
258 TRACE(("writebuf %d extrabuf %s extrabuf %d", 239 TRACE(("writebuf %d extrabuf %s extrabuf %d",
259 cbuf_getused(channel->writebuf), 240 cbuf_getused(channel->writebuf),
260 channel->writebuf, 241 channel->writebuf,
261 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf))) 242 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)))
264 245
265 /* check for exited - currently only used for server sessions, 246 /* check for exited - currently only used for server sessions,
266 * if the shell has exited etc */ 247 * if the shell has exited etc */
267 if (channel->type->checkclose) { 248 if (channel->type->checkclose) {
268 if (channel->type->checkclose(channel)) { 249 if (channel->type->checkclose(channel)) {
269 closeinfd(channel); 250 closewritefd(channel);
270 } 251 }
271 } 252 }
272 253
273 if (!channel->senteof 254 if (!channel->senteof
274 && channel->outfd == FD_CLOSED 255 && channel->readfd == FD_CLOSED
275 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { 256 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
276 send_msg_channel_eof(channel); 257 send_msg_channel_eof(channel);
277 } 258 }
278 259
279 if (channel->infd == FD_CLOSED 260 if (channel->writefd == FD_CLOSED
280 && channel->outfd == FD_CLOSED 261 && channel->readfd == FD_CLOSED
281 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { 262 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
282 send_msg_channel_close(channel); 263 send_msg_channel_close(channel);
283 } 264 }
284 } 265 }
285 266
312 int val; 293 int val;
313 socklen_t vallen = sizeof(val); 294 socklen_t vallen = sizeof(val);
314 295
315 TRACE(("enter checkinitdone")) 296 TRACE(("enter checkinitdone"))
316 297
317 if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen) 298 if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
318 || val != 0) { 299 || val != 0) {
319 send_msg_channel_open_failure(channel->remotechan, 300 send_msg_channel_open_failure(channel->remotechan,
320 SSH_OPEN_CONNECT_FAILED, "", ""); 301 SSH_OPEN_CONNECT_FAILED, "", "");
321 close(channel->infd); 302 close(channel->writefd);
322 deletechannel(channel); 303 deletechannel(channel);
323 TRACE(("leave checkinitdone: fail")) 304 TRACE(("leave checkinitdone: fail"))
324 } else { 305 } else {
325 send_msg_channel_open_confirmation(channel, channel->recvwindow, 306 send_msg_channel_open_confirmation(channel, channel->recvwindow,
326 channel->recvmaxpacket); 307 channel->recvmaxpacket);
327 channel->outfd = channel->infd; 308 channel->readfd = channel->writefd;
328 channel->initconn = 0; 309 channel->initconn = 0;
329 TRACE(("leave checkinitdone: success")) 310 TRACE(("leave checkinitdone: success"))
330 } 311 }
331 } 312 }
332 313
384 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); 365 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
385 if (len <= 0) { 366 if (len <= 0) {
386 if (len < 0 && errno != EINTR) { 367 if (len < 0 && errno != EINTR) {
387 /* no more to write - we close it even if the fd was stderr, since 368 /* no more to write - we close it even if the fd was stderr, since
388 * that's a nasty failure too */ 369 * that's a nasty failure too */
389 closeinfd(channel); 370 closewritefd(channel);
390 } 371 }
391 TRACE(("leave writechannel: len <= 0")) 372 TRACE(("leave writechannel: len <= 0"))
392 return; 373 return;
393 } 374 }
394 375
395 cbuf_incrread(cbuf, len); 376 cbuf_incrread(cbuf, len);
396 channel->recvdonelen += len; 377 channel->recvdonelen += len;
397 378
398 if (fd == channel->infd && len == maxlen && channel->recveof) { 379 if (fd == channel->writefd && cbuf_getused(cbuf) == 0 && channel->recveof) {
399 /* Check if we're closing up */ 380 /* Check if we're closing up */
400 closeinfd(channel); 381 closewritefd(channel);
401 TRACE(("leave writechannel: recveof set")) 382 TRACE(("leave writechannel: recveof set"))
402 return; 383 return;
403 } 384 }
404 385
405 /* Window adjust handling */ 386 /* Window adjust handling */
419 TRACE(("leave writechannel")) 400 TRACE(("leave writechannel"))
420 } 401 }
421 402
422 /* Set the file descriptors for the main select in session.c 403 /* Set the file descriptors for the main select in session.c
423 * This avoid channels which don't have any window available, are closed, etc*/ 404 * This avoid channels which don't have any window available, are closed, etc*/
424 void setchannelfds(fd_set *readfd, fd_set *writefd) { 405 void setchannelfds(fd_set *readfds, fd_set *writefds) {
425 406
426 unsigned int i; 407 unsigned int i;
427 struct Channel * channel; 408 struct Channel * channel;
428 409
429 for (i = 0; i < ses.chansize; i++) { 410 for (i = 0; i < ses.chansize; i++) {
434 } 415 }
435 416
436 /* Stuff to put over the wire */ 417 /* Stuff to put over the wire */
437 if (channel->transwindow > 0) { 418 if (channel->transwindow > 0) {
438 419
439 if (channel->outfd >= 0) { 420 if (channel->readfd >= 0) {
440 FD_SET(channel->outfd, readfd); 421 FD_SET(channel->readfd, readfds);
441 } 422 }
442 423
443 if (channel->extrabuf == NULL && channel->errfd >= 0) { 424 if (channel->extrabuf == NULL && channel->errfd >= 0) {
444 FD_SET(channel->errfd, readfd); 425 FD_SET(channel->errfd, readfds);
445 } 426 }
446 } 427 }
447 428
448 /* For checking FD status (ie closure etc) - we don't actually 429 /* Stuff from the wire */
449 * read data from infd */ 430 if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
450 TRACE(("infd = %d, outfd %d, errfd %d, bufused %d",
451 channel->infd, channel->outfd,
452 channel->errfd,
453 cbuf_getused(channel->writebuf) ))
454 if (channel->infd >= 0 && channel->infd != channel->outfd) {
455 FD_SET(channel->infd, readfd);
456 }
457
458 /* Stuff from the wire, to local program/shell/user etc */
459 if ((channel->infd >= 0 && cbuf_getused(channel->writebuf) > 0 )
460 || channel->initconn) { 431 || channel->initconn) {
461 432
462 FD_SET(channel->infd, writefd); 433 FD_SET(channel->writefd, writefds);
463 } 434 }
464 435
465 if (channel->extrabuf != NULL && channel->errfd >= 0 436 if (channel->extrabuf != NULL && channel->errfd >= 0
466 && cbuf_getused(channel->extrabuf) > 0 ) { 437 && cbuf_getused(channel->extrabuf) > 0 ) {
467 FD_SET(channel->errfd, writefd); 438 FD_SET(channel->errfd, writefds);
468 } 439 }
469 440
470 } /* foreach channel */ 441 } /* foreach channel */
471 442
472 #ifdef USING_LISTENERS 443 #ifdef USING_LISTENERS
473 set_listener_fds(readfd); 444 set_listener_fds(readfds);
474 #endif 445 #endif
475 446
476 } 447 }
477 448
478 /* handle the channel EOF event, by closing the channel filedescriptor. The 449 /* handle the channel EOF event, by closing the channel filedescriptor. The
491 462
492 channel->recveof = 1; 463 channel->recveof = 1;
493 if (cbuf_getused(channel->writebuf) == 0 464 if (cbuf_getused(channel->writebuf) == 0
494 && (channel->extrabuf == NULL 465 && (channel->extrabuf == NULL
495 || cbuf_getused(channel->extrabuf) == 0)) { 466 || cbuf_getused(channel->extrabuf) == 0)) {
496 closeinfd(channel); 467 closewritefd(channel);
497 } 468 }
498 469
499 TRACE(("leave recv_msg_channel_eof")) 470 TRACE(("leave recv_msg_channel_eof"))
500 } 471 }
501 472
539 } 510 }
540 511
541 512
542 /* close the FDs in case they haven't been done 513 /* close the FDs in case they haven't been done
543 * yet (ie they were shutdown etc */ 514 * yet (ie they were shutdown etc */
544 close(channel->infd); 515 close(channel->writefd);
545 close(channel->outfd); 516 close(channel->readfd);
546 close(channel->errfd); 517 close(channel->errfd);
547 518
548 channel->typedata = NULL; 519 channel->typedata = NULL;
549 520
550 deletechannel(channel); 521 deletechannel(channel);
607 dropbear_assert(!channel->sentclosed); 578 dropbear_assert(!channel->sentclosed);
608 579
609 if (isextended) { 580 if (isextended) {
610 fd = channel->errfd; 581 fd = channel->errfd;
611 } else { 582 } else {
612 fd = channel->outfd; 583 fd = channel->readfd;
613 } 584 }
614 dropbear_assert(fd >= 0); 585 dropbear_assert(fd >= 0);
615 586
616 maxlen = MIN(channel->transwindow, channel->transmaxpacket); 587 maxlen = MIN(channel->transwindow, channel->transmaxpacket);
617 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and 588 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and
629 TRACE(("buf pos %d data %x", buf->pos, buf->data)) 600 TRACE(("buf pos %d data %x", buf->pos, buf->data))
630 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen); 601 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
631 if (len <= 0) { 602 if (len <= 0) {
632 /* on error/eof, send eof */ 603 /* on error/eof, send eof */
633 if (len == 0 || errno != EINTR) { 604 if (len == 0 || errno != EINTR) {
634 closeoutfd(channel, fd); 605 closereadfd(channel, fd);
635 } 606 }
636 buf_free(buf); 607 buf_free(buf);
637 buf = NULL; 608 buf = NULL;
638 TRACE(("leave send_msg_channel_data: read err or EOF for fd %d", 609 TRACE(("leave send_msg_channel_data: read err or EOF for fd %d",
639 channel->index)); 610 channel->index));
667 channel = getchannel(); 638 channel = getchannel();
668 if (channel == NULL) { 639 if (channel == NULL) {
669 dropbear_exit("Unknown channel"); 640 dropbear_exit("Unknown channel");
670 } 641 }
671 642
672 common_recv_msg_channel_data(channel, channel->infd, channel->writebuf); 643 common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf);
673 } 644 }
674 645
675 /* Shared for data and stderr data - when we receive data, put it in a buffer 646 /* Shared for data and stderr data - when we receive data, put it in a buffer
676 * for writing to the local file descriptor */ 647 * for writing to the local file descriptor */
677 void common_recv_msg_channel_data(struct Channel *channel, int fd, 648 void common_recv_msg_channel_data(struct Channel *channel, int fd,
687 if (channel->recveof) { 658 if (channel->recveof) {
688 dropbear_exit("received data after eof"); 659 dropbear_exit("received data after eof");
689 } 660 }
690 661
691 if (fd < 0) { 662 if (fd < 0) {
692 dropbear_exit("received data with bad infd"); 663 dropbear_exit("received data with bad writefd");
693 } 664 }
694 665
695 datalen = buf_getint(ses.payload); 666 datalen = buf_getint(ses.payload);
696 667
697 668
929 } 900 }
930 901
931 /* set fd non-blocking */ 902 /* set fd non-blocking */
932 setnonblocking(fd); 903 setnonblocking(fd);
933 904
934 chan->infd = chan->outfd = fd; 905 chan->writefd = chan->readfd = fd;
935 ses.maxfd = MAX(ses.maxfd, fd); 906 ses.maxfd = MAX(ses.maxfd, fd);
936 907
937 chan->await_open = 1; 908 chan->await_open = 1;
938 909
939 /* now open the channel connection */ 910 /* now open the channel connection */
1006 removechannel(channel); 977 removechannel(channel);
1007 } 978 }
1008 #endif /* USING_LISTENERS */ 979 #endif /* USING_LISTENERS */
1009 980
1010 /* close a stdout/stderr fd */ 981 /* close a stdout/stderr fd */
1011 static void closeoutfd(struct Channel * channel, int fd) { 982 static void closereadfd(struct Channel * channel, int fd) {
1012 983
1013 /* don't close it if it is the same as infd, 984 /* don't close it if it is the same as writefd,
1014 * unless infd is already set -1 */ 985 * unless writefd is already set -1 */
1015 TRACE(("enter closeoutfd")) 986 TRACE(("enter closereadfd"))
1016 closechanfd(channel, fd, 0); 987 closechanfd(channel, fd, 0);
1017 TRACE(("leave closeoutfd")) 988 TRACE(("leave closereadfd"))
1018 } 989 }
1019 990
1020 /* close a stdin fd */ 991 /* close a stdin fd */
1021 static void closeinfd(struct Channel * channel) { 992 static void closewritefd(struct Channel * channel) {
1022 993
1023 TRACE(("enter closeinfd")) 994 TRACE(("enter closewritefd"))
1024 closechanfd(channel, channel->infd, 1); 995 closechanfd(channel, channel->writefd, 1);
1025 TRACE(("leave closeinfd")) 996 TRACE(("leave closewritefd"))
1026 } 997 }
1027 998
1028 /* close a fd, how is 0 for stdout/stderr, 1 for stdin */ 999 /* close a fd, how is 0 for stdout/stderr, 1 for stdin */
1029 static void closechanfd(struct Channel *channel, int fd, int how) { 1000 static void closechanfd(struct Channel *channel, int fd, int how) {
1030 1001
1042 } else { 1013 } else {
1043 close(fd); 1014 close(fd);
1044 closein = closeout = 1; 1015 closein = closeout = 1;
1045 } 1016 }
1046 1017
1047 if (closeout && fd == channel->outfd) { 1018 if (closeout && fd == channel->readfd) {
1048 channel->outfd = FD_CLOSED; 1019 channel->readfd = FD_CLOSED;
1049 } 1020 }
1050 if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) { 1021 if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
1051 channel->errfd = FD_CLOSED; 1022 channel->errfd = FD_CLOSED;
1052 } 1023 }
1053 1024
1054 if (closein && fd == channel->infd) { 1025 if (closein && fd == channel->writefd) {
1055 channel->infd = FD_CLOSED; 1026 channel->writefd = FD_CLOSED;
1056 } 1027 }
1057 if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) { 1028 if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
1058 channel->errfd = FD_CLOSED; 1029 channel->errfd = FD_CLOSED;
1059 } 1030 }
1060 1031
1061 /* if we called shutdown on it and all references are gone, then we 1032 /* if we called shutdown on it and all references are gone, then we
1062 * need to close() it to stop it lingering */ 1033 * need to close() it to stop it lingering */
1063 if (channel->type->sepfds && channel->outfd == FD_CLOSED 1034 if (channel->type->sepfds && channel->readfd == FD_CLOSED
1064 && channel->infd == FD_CLOSED && channel->errfd == FD_CLOSED) { 1035 && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
1065 close(fd); 1036 close(fd);
1066 } 1037 }
1067 } 1038 }