diff options
author | Colin Watson <cjwatson@debian.org> | 2007-06-12 16:16:35 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2007-06-12 16:16:35 +0000 |
commit | b7e40fa9da0b5491534a429dadb321eab5a77558 (patch) | |
tree | bed1da11e9f829925797aa093e379fc0b5868ecd /channels.c | |
parent | 4f84beedf1005e44ff33c854abd6b711ffc0adb7 (diff) | |
parent | 086ea76990b1e6287c24b6db74adffd4605eb3b0 (diff) |
* New upstream release (closes: #395507, #397961, #420035). Important
changes not previously backported to 4.3p2:
- 4.4/4.4p1 (http://www.openssh.org/txt/release-4.4):
+ On portable OpenSSH, fix a GSSAPI authentication abort that could be
used to determine the validity of usernames on some platforms.
+ Implemented conditional configuration in sshd_config(5) using the
"Match" directive. This allows some configuration options to be
selectively overridden if specific criteria (based on user, group,
hostname and/or address) are met. So far a useful subset of
post-authentication options are supported and more are expected to
be added in future releases.
+ Add support for Diffie-Hellman group exchange key agreement with a
final hash of SHA256.
+ Added a "ForceCommand" directive to sshd_config(5). Similar to the
command="..." option accepted in ~/.ssh/authorized_keys, this forces
the execution of the specified command regardless of what the user
requested. This is very useful in conjunction with the new "Match"
option.
+ Add a "PermitOpen" directive to sshd_config(5). This mirrors the
permitopen="..." authorized_keys option, allowing fine-grained
control over the port-forwardings that a user is allowed to
establish.
+ Add optional logging of transactions to sftp-server(8).
+ ssh(1) will now record port numbers for hosts stored in
~/.ssh/known_hosts when a non-standard port has been requested
(closes: #50612).
+ Add an "ExitOnForwardFailure" option to cause ssh(1) to exit (with a
non-zero exit code) when requested port forwardings could not be
established.
+ Extend sshd_config(5) "SubSystem" declarations to allow the
specification of command-line arguments.
+ Replacement of all integer overflow susceptible invocations of
malloc(3) and realloc(3) with overflow-checking equivalents.
+ Many manpage fixes and improvements.
+ Add optional support for OpenSSL hardware accelerators (engines),
enabled using the --with-ssl-engine configure option.
+ Tokens in configuration files may be double-quoted in order to
contain spaces (closes: #319639).
+ Move a debug() call out of a SIGCHLD handler, fixing a hang when the
session exits very quickly (closes: #307890).
+ Fix some incorrect buffer allocation calculations (closes: #410599).
+ ssh-add doesn't ask for a passphrase if key file permissions are too
liberal (closes: #103677).
+ Likewise, ssh doesn't ask either (closes: #99675).
- 4.6/4.6p1 (http://www.openssh.org/txt/release-4.6):
+ sshd now allows the enabling and disabling of authentication methods
on a per user, group, host and network basis via the Match directive
in sshd_config.
+ Fixed an inconsistent check for a terminal when displaying scp
progress meter (closes: #257524).
+ Fix "hang on exit" when background processes are running at the time
of exit on a ttyful/login session (closes: #88337).
* Update to current GSSAPI patch from
http://www.sxw.org.uk/computing/patches/openssh-4.6p1-gsskex-20070312.patch;
install ChangeLog.gssapi.
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 303 |
1 files changed, 202 insertions, 101 deletions
diff --git a/channels.c b/channels.c index 92448da77..530c0d460 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,3 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.268 2007/01/03 03:01:40 stevesk Exp $ */ | ||
1 | /* | 2 | /* |
2 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -39,22 +40,41 @@ | |||
39 | */ | 40 | */ |
40 | 41 | ||
41 | #include "includes.h" | 42 | #include "includes.h" |
42 | RCSID("$OpenBSD: channels.c,v 1.232 2006/01/30 12:22:22 reyk Exp $"); | ||
43 | 43 | ||
44 | #include <sys/types.h> | ||
45 | #include <sys/ioctl.h> | ||
46 | #include <sys/un.h> | ||
47 | #include <sys/socket.h> | ||
48 | #ifdef HAVE_SYS_TIME_H | ||
49 | # include <sys/time.h> | ||
50 | #endif | ||
51 | |||
52 | #include <netinet/in.h> | ||
53 | #include <arpa/inet.h> | ||
54 | |||
55 | #include <errno.h> | ||
56 | #include <netdb.h> | ||
57 | #include <stdio.h> | ||
58 | #include <stdlib.h> | ||
59 | #include <string.h> | ||
60 | #include <termios.h> | ||
61 | #include <unistd.h> | ||
62 | #include <stdarg.h> | ||
63 | |||
64 | #include "xmalloc.h" | ||
44 | #include "ssh.h" | 65 | #include "ssh.h" |
45 | #include "ssh1.h" | 66 | #include "ssh1.h" |
46 | #include "ssh2.h" | 67 | #include "ssh2.h" |
47 | #include "packet.h" | 68 | #include "packet.h" |
48 | #include "xmalloc.h" | ||
49 | #include "log.h" | 69 | #include "log.h" |
50 | #include "misc.h" | 70 | #include "misc.h" |
71 | #include "buffer.h" | ||
51 | #include "channels.h" | 72 | #include "channels.h" |
52 | #include "compat.h" | 73 | #include "compat.h" |
53 | #include "canohost.h" | 74 | #include "canohost.h" |
54 | #include "key.h" | 75 | #include "key.h" |
55 | #include "authfd.h" | 76 | #include "authfd.h" |
56 | #include "pathnames.h" | 77 | #include "pathnames.h" |
57 | #include "bufaux.h" | ||
58 | 78 | ||
59 | /* -- channel core */ | 79 | /* -- channel core */ |
60 | 80 | ||
@@ -91,11 +111,18 @@ typedef struct { | |||
91 | u_short listen_port; /* Remote side should listen port number. */ | 111 | u_short listen_port; /* Remote side should listen port number. */ |
92 | } ForwardPermission; | 112 | } ForwardPermission; |
93 | 113 | ||
94 | /* List of all permitted host/port pairs to connect. */ | 114 | /* List of all permitted host/port pairs to connect by the user. */ |
95 | static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; | 115 | static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; |
96 | 116 | ||
97 | /* Number of permitted host/port pairs in the array. */ | 117 | /* List of all permitted host/port pairs to connect by the admin. */ |
118 | static ForwardPermission permitted_adm_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; | ||
119 | |||
120 | /* Number of permitted host/port pairs in the array permitted by the user. */ | ||
98 | static int num_permitted_opens = 0; | 121 | static int num_permitted_opens = 0; |
122 | |||
123 | /* Number of permitted host/port pair in the array permitted by the admin. */ | ||
124 | static int num_adm_permitted_opens = 0; | ||
125 | |||
99 | /* | 126 | /* |
100 | * If this is true, all opens are permitted. This is the case on the server | 127 | * If this is true, all opens are permitted. This is the case on the server |
101 | * on which we have to trust the client anyway, and the user could do | 128 | * on which we have to trust the client anyway, and the user could do |
@@ -123,7 +150,7 @@ static u_int x11_saved_data_len = 0; | |||
123 | * Fake X11 authentication data. This is what the server will be sending us; | 150 | * Fake X11 authentication data. This is what the server will be sending us; |
124 | * we should replace any occurrences of this by the real data. | 151 | * we should replace any occurrences of this by the real data. |
125 | */ | 152 | */ |
126 | static char *x11_fake_data = NULL; | 153 | static u_char *x11_fake_data = NULL; |
127 | static u_int x11_fake_data_len; | 154 | static u_int x11_fake_data_len; |
128 | 155 | ||
129 | 156 | ||
@@ -168,7 +195,7 @@ channel_lookup(int id) | |||
168 | if ((c = channel_by_id(id)) == NULL) | 195 | if ((c = channel_by_id(id)) == NULL) |
169 | return (NULL); | 196 | return (NULL); |
170 | 197 | ||
171 | switch(c->type) { | 198 | switch (c->type) { |
172 | case SSH_CHANNEL_X11_OPEN: | 199 | case SSH_CHANNEL_X11_OPEN: |
173 | case SSH_CHANNEL_LARVAL: | 200 | case SSH_CHANNEL_LARVAL: |
174 | case SSH_CHANNEL_CONNECTING: | 201 | case SSH_CHANNEL_CONNECTING: |
@@ -178,7 +205,6 @@ channel_lookup(int id) | |||
178 | case SSH_CHANNEL_INPUT_DRAINING: | 205 | case SSH_CHANNEL_INPUT_DRAINING: |
179 | case SSH_CHANNEL_OUTPUT_DRAINING: | 206 | case SSH_CHANNEL_OUTPUT_DRAINING: |
180 | return (c); | 207 | return (c); |
181 | break; | ||
182 | } | 208 | } |
183 | logit("Non-public channel %d, type %d.", id, c->type); | 209 | logit("Non-public channel %d, type %d.", id, c->type); |
184 | return (NULL); | 210 | return (NULL); |
@@ -188,7 +214,6 @@ channel_lookup(int id) | |||
188 | * Register filedescriptors for a channel, used when allocating a channel or | 214 | * Register filedescriptors for a channel, used when allocating a channel or |
189 | * when the channel consumer/producer is ready, e.g. shell exec'd | 215 | * when the channel consumer/producer is ready, e.g. shell exec'd |
190 | */ | 216 | */ |
191 | |||
192 | static void | 217 | static void |
193 | channel_register_fds(Channel *c, int rfd, int wfd, int efd, | 218 | channel_register_fds(Channel *c, int rfd, int wfd, int efd, |
194 | int extusage, int nonblock) | 219 | int extusage, int nonblock) |
@@ -235,7 +260,6 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, | |||
235 | * Allocate a new channel object and set its type and socket. This will cause | 260 | * Allocate a new channel object and set its type and socket. This will cause |
236 | * remote_name to be freed. | 261 | * remote_name to be freed. |
237 | */ | 262 | */ |
238 | |||
239 | Channel * | 263 | Channel * |
240 | channel_new(char *ctype, int type, int rfd, int wfd, int efd, | 264 | channel_new(char *ctype, int type, int rfd, int wfd, int efd, |
241 | u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) | 265 | u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) |
@@ -247,7 +271,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
247 | /* Do initial allocation if this is the first call. */ | 271 | /* Do initial allocation if this is the first call. */ |
248 | if (channels_alloc == 0) { | 272 | if (channels_alloc == 0) { |
249 | channels_alloc = 10; | 273 | channels_alloc = 10; |
250 | channels = xmalloc(channels_alloc * sizeof(Channel *)); | 274 | channels = xcalloc(channels_alloc, sizeof(Channel *)); |
251 | for (i = 0; i < channels_alloc; i++) | 275 | for (i = 0; i < channels_alloc; i++) |
252 | channels[i] = NULL; | 276 | channels[i] = NULL; |
253 | } | 277 | } |
@@ -264,16 +288,15 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
264 | if (channels_alloc > 10000) | 288 | if (channels_alloc > 10000) |
265 | fatal("channel_new: internal error: channels_alloc %d " | 289 | fatal("channel_new: internal error: channels_alloc %d " |
266 | "too big.", channels_alloc); | 290 | "too big.", channels_alloc); |
267 | channels = xrealloc(channels, | 291 | channels = xrealloc(channels, channels_alloc + 10, |
268 | (channels_alloc + 10) * sizeof(Channel *)); | 292 | sizeof(Channel *)); |
269 | channels_alloc += 10; | 293 | channels_alloc += 10; |
270 | debug2("channel: expanding %d", channels_alloc); | 294 | debug2("channel: expanding %d", channels_alloc); |
271 | for (i = found; i < channels_alloc; i++) | 295 | for (i = found; i < channels_alloc; i++) |
272 | channels[i] = NULL; | 296 | channels[i] = NULL; |
273 | } | 297 | } |
274 | /* Initialize and return new channel. */ | 298 | /* Initialize and return new channel. */ |
275 | c = channels[found] = xmalloc(sizeof(Channel)); | 299 | c = channels[found] = xcalloc(1, sizeof(Channel)); |
276 | memset(c, 0, sizeof(Channel)); | ||
277 | buffer_init(&c->input); | 300 | buffer_init(&c->input); |
278 | buffer_init(&c->output); | 301 | buffer_init(&c->output); |
279 | buffer_init(&c->extended); | 302 | buffer_init(&c->extended); |
@@ -337,7 +360,6 @@ channel_close_fd(int *fdp) | |||
337 | } | 360 | } |
338 | 361 | ||
339 | /* Close all channel fd/socket. */ | 362 | /* Close all channel fd/socket. */ |
340 | |||
341 | static void | 363 | static void |
342 | channel_close_fds(Channel *c) | 364 | channel_close_fds(Channel *c) |
343 | { | 365 | { |
@@ -352,7 +374,6 @@ channel_close_fds(Channel *c) | |||
352 | } | 374 | } |
353 | 375 | ||
354 | /* Free the channel and close its fd/socket. */ | 376 | /* Free the channel and close its fd/socket. */ |
355 | |||
356 | void | 377 | void |
357 | channel_free(Channel *c) | 378 | channel_free(Channel *c) |
358 | { | 379 | { |
@@ -399,7 +420,6 @@ channel_free_all(void) | |||
399 | * Closes the sockets/fds of all channels. This is used to close extra file | 420 | * Closes the sockets/fds of all channels. This is used to close extra file |
400 | * descriptors after a fork. | 421 | * descriptors after a fork. |
401 | */ | 422 | */ |
402 | |||
403 | void | 423 | void |
404 | channel_close_all(void) | 424 | channel_close_all(void) |
405 | { | 425 | { |
@@ -413,7 +433,6 @@ channel_close_all(void) | |||
413 | /* | 433 | /* |
414 | * Stop listening to channels. | 434 | * Stop listening to channels. |
415 | */ | 435 | */ |
416 | |||
417 | void | 436 | void |
418 | channel_stop_listening(void) | 437 | channel_stop_listening(void) |
419 | { | 438 | { |
@@ -440,7 +459,6 @@ channel_stop_listening(void) | |||
440 | * Returns true if no channel has too much buffered data, and false if one or | 459 | * Returns true if no channel has too much buffered data, and false if one or |
441 | * more channel is overfull. | 460 | * more channel is overfull. |
442 | */ | 461 | */ |
443 | |||
444 | int | 462 | int |
445 | channel_not_very_much_buffered_data(void) | 463 | channel_not_very_much_buffered_data(void) |
446 | { | 464 | { |
@@ -470,7 +488,6 @@ channel_not_very_much_buffered_data(void) | |||
470 | } | 488 | } |
471 | 489 | ||
472 | /* Returns true if any channel is still open. */ | 490 | /* Returns true if any channel is still open. */ |
473 | |||
474 | int | 491 | int |
475 | channel_still_open(void) | 492 | channel_still_open(void) |
476 | { | 493 | { |
@@ -513,7 +530,6 @@ channel_still_open(void) | |||
513 | } | 530 | } |
514 | 531 | ||
515 | /* Returns the id of an open channel suitable for keepaliving */ | 532 | /* Returns the id of an open channel suitable for keepaliving */ |
516 | |||
517 | int | 533 | int |
518 | channel_find_open(void) | 534 | channel_find_open(void) |
519 | { | 535 | { |
@@ -558,7 +574,6 @@ channel_find_open(void) | |||
558 | * suitable for sending to the client. The message contains crlf pairs for | 574 | * suitable for sending to the client. The message contains crlf pairs for |
559 | * newlines. | 575 | * newlines. |
560 | */ | 576 | */ |
561 | |||
562 | char * | 577 | char * |
563 | channel_open_message(void) | 578 | channel_open_message(void) |
564 | { | 579 | { |
@@ -643,6 +658,7 @@ channel_request_start(int id, char *service, int wantconfirm) | |||
643 | packet_put_cstring(service); | 658 | packet_put_cstring(service); |
644 | packet_put_char(wantconfirm); | 659 | packet_put_char(wantconfirm); |
645 | } | 660 | } |
661 | |||
646 | void | 662 | void |
647 | channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) | 663 | channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) |
648 | { | 664 | { |
@@ -655,6 +671,7 @@ channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) | |||
655 | c->confirm = fn; | 671 | c->confirm = fn; |
656 | c->confirm_ctx = ctx; | 672 | c->confirm_ctx = ctx; |
657 | } | 673 | } |
674 | |||
658 | void | 675 | void |
659 | channel_register_cleanup(int id, channel_callback_fn *fn, int do_close) | 676 | channel_register_cleanup(int id, channel_callback_fn *fn, int do_close) |
660 | { | 677 | { |
@@ -667,6 +684,7 @@ channel_register_cleanup(int id, channel_callback_fn *fn, int do_close) | |||
667 | c->detach_user = fn; | 684 | c->detach_user = fn; |
668 | c->detach_close = do_close; | 685 | c->detach_close = do_close; |
669 | } | 686 | } |
687 | |||
670 | void | 688 | void |
671 | channel_cancel_cleanup(int id) | 689 | channel_cancel_cleanup(int id) |
672 | { | 690 | { |
@@ -679,6 +697,7 @@ channel_cancel_cleanup(int id) | |||
679 | c->detach_user = NULL; | 697 | c->detach_user = NULL; |
680 | c->detach_close = 0; | 698 | c->detach_close = 0; |
681 | } | 699 | } |
700 | |||
682 | void | 701 | void |
683 | channel_register_filter(int id, channel_infilter_fn *ifn, | 702 | channel_register_filter(int id, channel_infilter_fn *ifn, |
684 | channel_outfilter_fn *ofn) | 703 | channel_outfilter_fn *ofn) |
@@ -718,25 +737,27 @@ channel_set_fds(int id, int rfd, int wfd, int efd, | |||
718 | * 'channel_post*': perform any appropriate operations for channels which | 737 | * 'channel_post*': perform any appropriate operations for channels which |
719 | * have events pending. | 738 | * have events pending. |
720 | */ | 739 | */ |
721 | typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset); | 740 | typedef void chan_fn(Channel *c, fd_set *readset, fd_set *writeset); |
722 | chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; | 741 | chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; |
723 | chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; | 742 | chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; |
724 | 743 | ||
744 | /* ARGSUSED */ | ||
725 | static void | 745 | static void |
726 | channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset) | 746 | channel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset) |
727 | { | 747 | { |
728 | FD_SET(c->sock, readset); | 748 | FD_SET(c->sock, readset); |
729 | } | 749 | } |
730 | 750 | ||
751 | /* ARGSUSED */ | ||
731 | static void | 752 | static void |
732 | channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset) | 753 | channel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset) |
733 | { | 754 | { |
734 | debug3("channel %d: waiting for connection", c->self); | 755 | debug3("channel %d: waiting for connection", c->self); |
735 | FD_SET(c->sock, writeset); | 756 | FD_SET(c->sock, writeset); |
736 | } | 757 | } |
737 | 758 | ||
738 | static void | 759 | static void |
739 | channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) | 760 | channel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset) |
740 | { | 761 | { |
741 | if (buffer_len(&c->input) < packet_get_maxsize()) | 762 | if (buffer_len(&c->input) < packet_get_maxsize()) |
742 | FD_SET(c->sock, readset); | 763 | FD_SET(c->sock, readset); |
@@ -745,16 +766,14 @@ channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) | |||
745 | } | 766 | } |
746 | 767 | ||
747 | static void | 768 | static void |
748 | channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset) | 769 | channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) |
749 | { | 770 | { |
750 | u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); | 771 | u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); |
751 | 772 | ||
752 | /* check buffer limits */ | ||
753 | limit = MIN(limit, (BUFFER_MAX_LEN - BUFFER_MAX_CHUNK - CHAN_RBUF)); | ||
754 | |||
755 | if (c->istate == CHAN_INPUT_OPEN && | 773 | if (c->istate == CHAN_INPUT_OPEN && |
756 | limit > 0 && | 774 | limit > 0 && |
757 | buffer_len(&c->input) < limit) | 775 | buffer_len(&c->input) < limit && |
776 | buffer_check_alloc(&c->input, CHAN_RBUF)) | ||
758 | FD_SET(c->rfd, readset); | 777 | FD_SET(c->rfd, readset); |
759 | if (c->ostate == CHAN_OUTPUT_OPEN || | 778 | if (c->ostate == CHAN_OUTPUT_OPEN || |
760 | c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { | 779 | c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { |
@@ -784,8 +803,9 @@ channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset) | |||
784 | FD_SET(c->ctl_fd, readset); | 803 | FD_SET(c->ctl_fd, readset); |
785 | } | 804 | } |
786 | 805 | ||
806 | /* ARGSUSED */ | ||
787 | static void | 807 | static void |
788 | channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) | 808 | channel_pre_input_draining(Channel *c, fd_set *readset, fd_set *writeset) |
789 | { | 809 | { |
790 | if (buffer_len(&c->input) == 0) { | 810 | if (buffer_len(&c->input) == 0) { |
791 | packet_start(SSH_MSG_CHANNEL_CLOSE); | 811 | packet_start(SSH_MSG_CHANNEL_CLOSE); |
@@ -796,8 +816,9 @@ channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) | |||
796 | } | 816 | } |
797 | } | 817 | } |
798 | 818 | ||
819 | /* ARGSUSED */ | ||
799 | static void | 820 | static void |
800 | channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) | 821 | channel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset) |
801 | { | 822 | { |
802 | if (buffer_len(&c->output) == 0) | 823 | if (buffer_len(&c->output) == 0) |
803 | chan_mark_dead(c); | 824 | chan_mark_dead(c); |
@@ -873,7 +894,7 @@ x11_open_helper(Buffer *b) | |||
873 | } | 894 | } |
874 | 895 | ||
875 | static void | 896 | static void |
876 | channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) | 897 | channel_pre_x11_open_13(Channel *c, fd_set *readset, fd_set *writeset) |
877 | { | 898 | { |
878 | int ret = x11_open_helper(&c->output); | 899 | int ret = x11_open_helper(&c->output); |
879 | 900 | ||
@@ -899,7 +920,7 @@ channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) | |||
899 | } | 920 | } |
900 | 921 | ||
901 | static void | 922 | static void |
902 | channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) | 923 | channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset) |
903 | { | 924 | { |
904 | int ret = x11_open_helper(&c->output); | 925 | int ret = x11_open_helper(&c->output); |
905 | 926 | ||
@@ -925,8 +946,9 @@ channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) | |||
925 | } | 946 | } |
926 | 947 | ||
927 | /* try to decode a socks4 header */ | 948 | /* try to decode a socks4 header */ |
949 | /* ARGSUSED */ | ||
928 | static int | 950 | static int |
929 | channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) | 951 | channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) |
930 | { | 952 | { |
931 | char *p, *host; | 953 | char *p, *host; |
932 | u_int len, have, i, found; | 954 | u_int len, have, i, found; |
@@ -990,7 +1012,7 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) | |||
990 | s4_rsp.command = 90; /* cd: req granted */ | 1012 | s4_rsp.command = 90; /* cd: req granted */ |
991 | s4_rsp.dest_port = 0; /* ignored */ | 1013 | s4_rsp.dest_port = 0; /* ignored */ |
992 | s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ | 1014 | s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ |
993 | buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); | 1015 | buffer_append(&c->output, &s4_rsp, sizeof(s4_rsp)); |
994 | return 1; | 1016 | return 1; |
995 | } | 1017 | } |
996 | 1018 | ||
@@ -1003,8 +1025,9 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) | |||
1003 | #define SSH_SOCKS5_CONNECT 0x01 | 1025 | #define SSH_SOCKS5_CONNECT 0x01 |
1004 | #define SSH_SOCKS5_SUCCESS 0x00 | 1026 | #define SSH_SOCKS5_SUCCESS 0x00 |
1005 | 1027 | ||
1028 | /* ARGSUSED */ | ||
1006 | static int | 1029 | static int |
1007 | channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset) | 1030 | channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) |
1008 | { | 1031 | { |
1009 | struct { | 1032 | struct { |
1010 | u_int8_t version; | 1033 | u_int8_t version; |
@@ -1014,7 +1037,7 @@ channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset) | |||
1014 | } s5_req, s5_rsp; | 1037 | } s5_req, s5_rsp; |
1015 | u_int16_t dest_port; | 1038 | u_int16_t dest_port; |
1016 | u_char *p, dest_addr[255+1]; | 1039 | u_char *p, dest_addr[255+1]; |
1017 | u_int have, i, found, nmethods, addrlen, af; | 1040 | u_int have, need, i, found, nmethods, addrlen, af; |
1018 | 1041 | ||
1019 | debug2("channel %d: decode socks5", c->self); | 1042 | debug2("channel %d: decode socks5", c->self); |
1020 | p = buffer_ptr(&c->input); | 1043 | p = buffer_ptr(&c->input); |
@@ -1029,8 +1052,8 @@ channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset) | |||
1029 | if (have < nmethods + 2) | 1052 | if (have < nmethods + 2) |
1030 | return 0; | 1053 | return 0; |
1031 | /* look for method: "NO AUTHENTICATION REQUIRED" */ | 1054 | /* look for method: "NO AUTHENTICATION REQUIRED" */ |
1032 | for (found = 0, i = 2 ; i < nmethods + 2; i++) { | 1055 | for (found = 0, i = 2; i < nmethods + 2; i++) { |
1033 | if (p[i] == SSH_SOCKS5_NOAUTH ) { | 1056 | if (p[i] == SSH_SOCKS5_NOAUTH) { |
1034 | found = 1; | 1057 | found = 1; |
1035 | break; | 1058 | break; |
1036 | } | 1059 | } |
@@ -1051,7 +1074,7 @@ channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset) | |||
1051 | debug2("channel %d: socks5 post auth", c->self); | 1074 | debug2("channel %d: socks5 post auth", c->self); |
1052 | if (have < sizeof(s5_req)+1) | 1075 | if (have < sizeof(s5_req)+1) |
1053 | return 0; /* need more */ | 1076 | return 0; /* need more */ |
1054 | memcpy((char *)&s5_req, p, sizeof(s5_req)); | 1077 | memcpy(&s5_req, p, sizeof(s5_req)); |
1055 | if (s5_req.version != 0x05 || | 1078 | if (s5_req.version != 0x05 || |
1056 | s5_req.command != SSH_SOCKS5_CONNECT || | 1079 | s5_req.command != SSH_SOCKS5_CONNECT || |
1057 | s5_req.reserved != 0x00) { | 1080 | s5_req.reserved != 0x00) { |
@@ -1075,7 +1098,10 @@ channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset) | |||
1075 | debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp); | 1098 | debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp); |
1076 | return -1; | 1099 | return -1; |
1077 | } | 1100 | } |
1078 | if (have < 4 + addrlen + 2) | 1101 | need = sizeof(s5_req) + addrlen + 2; |
1102 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) | ||
1103 | need++; | ||
1104 | if (have < need) | ||
1079 | return 0; | 1105 | return 0; |
1080 | buffer_consume(&c->input, sizeof(s5_req)); | 1106 | buffer_consume(&c->input, sizeof(s5_req)); |
1081 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) | 1107 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) |
@@ -1099,15 +1125,15 @@ channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset) | |||
1099 | ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY; | 1125 | ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY; |
1100 | dest_port = 0; /* ignored */ | 1126 | dest_port = 0; /* ignored */ |
1101 | 1127 | ||
1102 | buffer_append(&c->output, (char *)&s5_rsp, sizeof(s5_rsp)); | 1128 | buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp)); |
1103 | buffer_append(&c->output, (char *)&dest_addr, sizeof(struct in_addr)); | 1129 | buffer_append(&c->output, &dest_addr, sizeof(struct in_addr)); |
1104 | buffer_append(&c->output, (char *)&dest_port, sizeof(dest_port)); | 1130 | buffer_append(&c->output, &dest_port, sizeof(dest_port)); |
1105 | return 1; | 1131 | return 1; |
1106 | } | 1132 | } |
1107 | 1133 | ||
1108 | /* dynamic port forwarding */ | 1134 | /* dynamic port forwarding */ |
1109 | static void | 1135 | static void |
1110 | channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | 1136 | channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) |
1111 | { | 1137 | { |
1112 | u_char *p; | 1138 | u_char *p; |
1113 | u_int have; | 1139 | u_int have; |
@@ -1150,8 +1176,9 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | |||
1150 | } | 1176 | } |
1151 | 1177 | ||
1152 | /* This is our fake X11 server socket. */ | 1178 | /* This is our fake X11 server socket. */ |
1179 | /* ARGSUSED */ | ||
1153 | static void | 1180 | static void |
1154 | channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) | 1181 | channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset) |
1155 | { | 1182 | { |
1156 | Channel *nc; | 1183 | Channel *nc; |
1157 | struct sockaddr addr; | 1184 | struct sockaddr addr; |
@@ -1275,8 +1302,9 @@ channel_set_reuseaddr(int fd) | |||
1275 | /* | 1302 | /* |
1276 | * This socket is listening for connections to a forwarded TCP/IP port. | 1303 | * This socket is listening for connections to a forwarded TCP/IP port. |
1277 | */ | 1304 | */ |
1305 | /* ARGSUSED */ | ||
1278 | static void | 1306 | static void |
1279 | channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) | 1307 | channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) |
1280 | { | 1308 | { |
1281 | Channel *nc; | 1309 | Channel *nc; |
1282 | struct sockaddr addr; | 1310 | struct sockaddr addr; |
@@ -1332,8 +1360,9 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
1332 | * This is the authentication agent socket listening for connections from | 1360 | * This is the authentication agent socket listening for connections from |
1333 | * clients. | 1361 | * clients. |
1334 | */ | 1362 | */ |
1363 | /* ARGSUSED */ | ||
1335 | static void | 1364 | static void |
1336 | channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) | 1365 | channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset) |
1337 | { | 1366 | { |
1338 | Channel *nc; | 1367 | Channel *nc; |
1339 | int newsock; | 1368 | int newsock; |
@@ -1365,8 +1394,9 @@ channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
1365 | } | 1394 | } |
1366 | } | 1395 | } |
1367 | 1396 | ||
1397 | /* ARGSUSED */ | ||
1368 | static void | 1398 | static void |
1369 | channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) | 1399 | channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) |
1370 | { | 1400 | { |
1371 | int err = 0; | 1401 | int err = 0; |
1372 | socklen_t sz = sizeof(err); | 1402 | socklen_t sz = sizeof(err); |
@@ -1411,18 +1441,26 @@ channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) | |||
1411 | } | 1441 | } |
1412 | } | 1442 | } |
1413 | 1443 | ||
1444 | /* ARGSUSED */ | ||
1414 | static int | 1445 | static int |
1415 | channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) | 1446 | channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset) |
1416 | { | 1447 | { |
1417 | char buf[CHAN_RBUF]; | 1448 | char buf[CHAN_RBUF]; |
1418 | int len; | 1449 | int len; |
1419 | 1450 | ||
1420 | if (c->rfd != -1 && | 1451 | if (c->rfd != -1 && |
1421 | FD_ISSET(c->rfd, readset)) { | 1452 | (c->detach_close || FD_ISSET(c->rfd, readset))) { |
1453 | errno = 0; | ||
1422 | len = read(c->rfd, buf, sizeof(buf)); | 1454 | len = read(c->rfd, buf, sizeof(buf)); |
1423 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | 1455 | if (len < 0 && (errno == EINTR || |
1456 | (errno == EAGAIN && !(c->isatty && c->detach_close)))) | ||
1424 | return 1; | 1457 | return 1; |
1458 | #ifndef PTY_ZEROREAD | ||
1425 | if (len <= 0) { | 1459 | if (len <= 0) { |
1460 | #else | ||
1461 | if ((!c->isatty && len <= 0) || | ||
1462 | (c->isatty && (len < 0 || (len == 0 && errno != 0)))) { | ||
1463 | #endif | ||
1426 | debug2("channel %d: read<=0 rfd %d len %d", | 1464 | debug2("channel %d: read<=0 rfd %d len %d", |
1427 | c->self, c->rfd, len); | 1465 | c->self, c->rfd, len); |
1428 | if (c->type != SSH_CHANNEL_OPEN) { | 1466 | if (c->type != SSH_CHANNEL_OPEN) { |
@@ -1451,8 +1489,10 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) | |||
1451 | } | 1489 | } |
1452 | return 1; | 1490 | return 1; |
1453 | } | 1491 | } |
1492 | |||
1493 | /* ARGSUSED */ | ||
1454 | static int | 1494 | static int |
1455 | channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) | 1495 | channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset) |
1456 | { | 1496 | { |
1457 | struct termios tio; | 1497 | struct termios tio; |
1458 | u_char *data = NULL, *buf; | 1498 | u_char *data = NULL, *buf; |
@@ -1538,8 +1578,9 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) | |||
1538 | } | 1578 | } |
1539 | return 1; | 1579 | return 1; |
1540 | } | 1580 | } |
1581 | |||
1541 | static int | 1582 | static int |
1542 | channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) | 1583 | channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset) |
1543 | { | 1584 | { |
1544 | char buf[CHAN_RBUF]; | 1585 | char buf[CHAN_RBUF]; |
1545 | int len; | 1586 | int len; |
@@ -1564,11 +1605,12 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) | |||
1564 | c->local_consumed += len; | 1605 | c->local_consumed += len; |
1565 | } | 1606 | } |
1566 | } else if (c->extended_usage == CHAN_EXTENDED_READ && | 1607 | } else if (c->extended_usage == CHAN_EXTENDED_READ && |
1567 | FD_ISSET(c->efd, readset)) { | 1608 | (c->detach_close || FD_ISSET(c->efd, readset))) { |
1568 | len = read(c->efd, buf, sizeof(buf)); | 1609 | len = read(c->efd, buf, sizeof(buf)); |
1569 | debug2("channel %d: read %d from efd %d", | 1610 | debug2("channel %d: read %d from efd %d", |
1570 | c->self, len, c->efd); | 1611 | c->self, len, c->efd); |
1571 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | 1612 | if (len < 0 && (errno == EINTR || |
1613 | (errno == EAGAIN && !c->detach_close))) | ||
1572 | return 1; | 1614 | return 1; |
1573 | if (len <= 0) { | 1615 | if (len <= 0) { |
1574 | debug2("channel %d: closing read-efd %d", | 1616 | debug2("channel %d: closing read-efd %d", |
@@ -1581,8 +1623,10 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) | |||
1581 | } | 1623 | } |
1582 | return 1; | 1624 | return 1; |
1583 | } | 1625 | } |
1626 | |||
1627 | /* ARGSUSED */ | ||
1584 | static int | 1628 | static int |
1585 | channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset) | 1629 | channel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset) |
1586 | { | 1630 | { |
1587 | char buf[16]; | 1631 | char buf[16]; |
1588 | int len; | 1632 | int len; |
@@ -1608,6 +1652,7 @@ channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset) | |||
1608 | } | 1652 | } |
1609 | return 1; | 1653 | return 1; |
1610 | } | 1654 | } |
1655 | |||
1611 | static int | 1656 | static int |
1612 | channel_check_window(Channel *c) | 1657 | channel_check_window(Channel *c) |
1613 | { | 1658 | { |
@@ -1629,7 +1674,7 @@ channel_check_window(Channel *c) | |||
1629 | } | 1674 | } |
1630 | 1675 | ||
1631 | static void | 1676 | static void |
1632 | channel_post_open(Channel *c, fd_set * readset, fd_set * writeset) | 1677 | channel_post_open(Channel *c, fd_set *readset, fd_set *writeset) |
1633 | { | 1678 | { |
1634 | if (c->delayed) | 1679 | if (c->delayed) |
1635 | return; | 1680 | return; |
@@ -1642,8 +1687,9 @@ channel_post_open(Channel *c, fd_set * readset, fd_set * writeset) | |||
1642 | channel_check_window(c); | 1687 | channel_check_window(c); |
1643 | } | 1688 | } |
1644 | 1689 | ||
1690 | /* ARGSUSED */ | ||
1645 | static void | 1691 | static void |
1646 | channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) | 1692 | channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset) |
1647 | { | 1693 | { |
1648 | int len; | 1694 | int len; |
1649 | 1695 | ||
@@ -1760,7 +1806,7 @@ channel_garbage_collect(Channel *c) | |||
1760 | } | 1806 | } |
1761 | 1807 | ||
1762 | static void | 1808 | static void |
1763 | channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) | 1809 | channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) |
1764 | { | 1810 | { |
1765 | static int did_init = 0; | 1811 | static int did_init = 0; |
1766 | u_int i; | 1812 | u_int i; |
@@ -1788,15 +1834,20 @@ void | |||
1788 | channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | 1834 | channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, |
1789 | u_int *nallocp, int rekeying) | 1835 | u_int *nallocp, int rekeying) |
1790 | { | 1836 | { |
1791 | u_int n, sz; | 1837 | u_int n, sz, nfdset; |
1792 | 1838 | ||
1793 | n = MAX(*maxfdp, channel_max_fd); | 1839 | n = MAX(*maxfdp, channel_max_fd); |
1794 | 1840 | ||
1795 | sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); | 1841 | nfdset = howmany(n+1, NFDBITS); |
1842 | /* Explicitly test here, because xrealloc isn't always called */ | ||
1843 | if (nfdset && SIZE_T_MAX / nfdset < sizeof(fd_mask)) | ||
1844 | fatal("channel_prepare_select: max_fd (%d) is too large", n); | ||
1845 | sz = nfdset * sizeof(fd_mask); | ||
1846 | |||
1796 | /* perhaps check sz < nalloc/2 and shrink? */ | 1847 | /* perhaps check sz < nalloc/2 and shrink? */ |
1797 | if (*readsetp == NULL || sz > *nallocp) { | 1848 | if (*readsetp == NULL || sz > *nallocp) { |
1798 | *readsetp = xrealloc(*readsetp, sz); | 1849 | *readsetp = xrealloc(*readsetp, nfdset, sizeof(fd_mask)); |
1799 | *writesetp = xrealloc(*writesetp, sz); | 1850 | *writesetp = xrealloc(*writesetp, nfdset, sizeof(fd_mask)); |
1800 | *nallocp = sz; | 1851 | *nallocp = sz; |
1801 | } | 1852 | } |
1802 | *maxfdp = n; | 1853 | *maxfdp = n; |
@@ -1812,14 +1863,13 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
1812 | * events pending. | 1863 | * events pending. |
1813 | */ | 1864 | */ |
1814 | void | 1865 | void |
1815 | channel_after_select(fd_set * readset, fd_set * writeset) | 1866 | channel_after_select(fd_set *readset, fd_set *writeset) |
1816 | { | 1867 | { |
1817 | channel_handler(channel_post, readset, writeset); | 1868 | channel_handler(channel_post, readset, writeset); |
1818 | } | 1869 | } |
1819 | 1870 | ||
1820 | 1871 | ||
1821 | /* If there is data to send to the connection, enqueue some of it now. */ | 1872 | /* If there is data to send to the connection, enqueue some of it now. */ |
1822 | |||
1823 | void | 1873 | void |
1824 | channel_output_poll(void) | 1874 | channel_output_poll(void) |
1825 | { | 1875 | { |
@@ -1940,6 +1990,7 @@ channel_output_poll(void) | |||
1940 | 1990 | ||
1941 | /* -- protocol input */ | 1991 | /* -- protocol input */ |
1942 | 1992 | ||
1993 | /* ARGSUSED */ | ||
1943 | void | 1994 | void |
1944 | channel_input_data(int type, u_int32_t seq, void *ctxt) | 1995 | channel_input_data(int type, u_int32_t seq, void *ctxt) |
1945 | { | 1996 | { |
@@ -1999,6 +2050,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt) | |||
1999 | xfree(data); | 2050 | xfree(data); |
2000 | } | 2051 | } |
2001 | 2052 | ||
2053 | /* ARGSUSED */ | ||
2002 | void | 2054 | void |
2003 | channel_input_extended_data(int type, u_int32_t seq, void *ctxt) | 2055 | channel_input_extended_data(int type, u_int32_t seq, void *ctxt) |
2004 | { | 2056 | { |
@@ -2045,6 +2097,7 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt) | |||
2045 | xfree(data); | 2097 | xfree(data); |
2046 | } | 2098 | } |
2047 | 2099 | ||
2100 | /* ARGSUSED */ | ||
2048 | void | 2101 | void |
2049 | channel_input_ieof(int type, u_int32_t seq, void *ctxt) | 2102 | channel_input_ieof(int type, u_int32_t seq, void *ctxt) |
2050 | { | 2103 | { |
@@ -2068,6 +2121,7 @@ channel_input_ieof(int type, u_int32_t seq, void *ctxt) | |||
2068 | 2121 | ||
2069 | } | 2122 | } |
2070 | 2123 | ||
2124 | /* ARGSUSED */ | ||
2071 | void | 2125 | void |
2072 | channel_input_close(int type, u_int32_t seq, void *ctxt) | 2126 | channel_input_close(int type, u_int32_t seq, void *ctxt) |
2073 | { | 2127 | { |
@@ -2106,6 +2160,7 @@ channel_input_close(int type, u_int32_t seq, void *ctxt) | |||
2106 | } | 2160 | } |
2107 | 2161 | ||
2108 | /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ | 2162 | /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ |
2163 | /* ARGSUSED */ | ||
2109 | void | 2164 | void |
2110 | channel_input_oclose(int type, u_int32_t seq, void *ctxt) | 2165 | channel_input_oclose(int type, u_int32_t seq, void *ctxt) |
2111 | { | 2166 | { |
@@ -2118,6 +2173,7 @@ channel_input_oclose(int type, u_int32_t seq, void *ctxt) | |||
2118 | chan_rcvd_oclose(c); | 2173 | chan_rcvd_oclose(c); |
2119 | } | 2174 | } |
2120 | 2175 | ||
2176 | /* ARGSUSED */ | ||
2121 | void | 2177 | void |
2122 | channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) | 2178 | channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) |
2123 | { | 2179 | { |
@@ -2134,6 +2190,7 @@ channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) | |||
2134 | channel_free(c); | 2190 | channel_free(c); |
2135 | } | 2191 | } |
2136 | 2192 | ||
2193 | /* ARGSUSED */ | ||
2137 | void | 2194 | void |
2138 | channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) | 2195 | channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) |
2139 | { | 2196 | { |
@@ -2181,6 +2238,7 @@ reason2txt(int reason) | |||
2181 | return "unknown reason"; | 2238 | return "unknown reason"; |
2182 | } | 2239 | } |
2183 | 2240 | ||
2241 | /* ARGSUSED */ | ||
2184 | void | 2242 | void |
2185 | channel_input_open_failure(int type, u_int32_t seq, void *ctxt) | 2243 | channel_input_open_failure(int type, u_int32_t seq, void *ctxt) |
2186 | { | 2244 | { |
@@ -2212,6 +2270,7 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt) | |||
2212 | channel_free(c); | 2270 | channel_free(c); |
2213 | } | 2271 | } |
2214 | 2272 | ||
2273 | /* ARGSUSED */ | ||
2215 | void | 2274 | void |
2216 | channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) | 2275 | channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) |
2217 | { | 2276 | { |
@@ -2236,6 +2295,7 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) | |||
2236 | c->remote_window += adjust; | 2295 | c->remote_window += adjust; |
2237 | } | 2296 | } |
2238 | 2297 | ||
2298 | /* ARGSUSED */ | ||
2239 | void | 2299 | void |
2240 | channel_input_port_open(int type, u_int32_t seq, void *ctxt) | 2300 | channel_input_port_open(int type, u_int32_t seq, void *ctxt) |
2241 | { | 2301 | { |
@@ -2454,7 +2514,7 @@ channel_setup_remote_fwd_listener(const char *listen_address, | |||
2454 | * the secure channel to host:port from local side. | 2514 | * the secure channel to host:port from local side. |
2455 | */ | 2515 | */ |
2456 | 2516 | ||
2457 | void | 2517 | int |
2458 | channel_request_remote_forwarding(const char *listen_host, u_short listen_port, | 2518 | channel_request_remote_forwarding(const char *listen_host, u_short listen_port, |
2459 | const char *host_to_connect, u_short port_to_connect) | 2519 | const char *host_to_connect, u_short port_to_connect) |
2460 | { | 2520 | { |
@@ -2467,11 +2527,18 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port, | |||
2467 | /* Send the forward request to the remote side. */ | 2527 | /* Send the forward request to the remote side. */ |
2468 | if (compat20) { | 2528 | if (compat20) { |
2469 | const char *address_to_bind; | 2529 | const char *address_to_bind; |
2470 | if (listen_host == NULL) | 2530 | if (listen_host == NULL) { |
2471 | address_to_bind = "localhost"; | 2531 | if (datafellows & SSH_BUG_RFWD_ADDR) |
2472 | else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) | 2532 | address_to_bind = "127.0.0.1"; |
2473 | address_to_bind = ""; | 2533 | else |
2474 | else | 2534 | address_to_bind = "localhost"; |
2535 | } else if (*listen_host == '\0' || | ||
2536 | strcmp(listen_host, "*") == 0) { | ||
2537 | if (datafellows & SSH_BUG_RFWD_ADDR) | ||
2538 | address_to_bind = "0.0.0.0"; | ||
2539 | else | ||
2540 | address_to_bind = ""; | ||
2541 | } else | ||
2475 | address_to_bind = listen_host; | 2542 | address_to_bind = listen_host; |
2476 | 2543 | ||
2477 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | 2544 | packet_start(SSH2_MSG_GLOBAL_REQUEST); |
@@ -2498,7 +2565,6 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port, | |||
2498 | success = 1; | 2565 | success = 1; |
2499 | break; | 2566 | break; |
2500 | case SSH_SMSG_FAILURE: | 2567 | case SSH_SMSG_FAILURE: |
2501 | logit("Warning: Server denied remote port forwarding."); | ||
2502 | break; | 2568 | break; |
2503 | default: | 2569 | default: |
2504 | /* Unknown packet */ | 2570 | /* Unknown packet */ |
@@ -2512,6 +2578,7 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port, | |||
2512 | permitted_opens[num_permitted_opens].listen_port = listen_port; | 2578 | permitted_opens[num_permitted_opens].listen_port = listen_port; |
2513 | num_permitted_opens++; | 2579 | num_permitted_opens++; |
2514 | } | 2580 | } |
2581 | return (success ? 0 : -1); | ||
2515 | } | 2582 | } |
2516 | 2583 | ||
2517 | /* | 2584 | /* |
@@ -2551,13 +2618,13 @@ channel_request_rforward_cancel(const char *host, u_short port) | |||
2551 | /* | 2618 | /* |
2552 | * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates | 2619 | * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates |
2553 | * listening for the port, and sends back a success reply (or disconnect | 2620 | * listening for the port, and sends back a success reply (or disconnect |
2554 | * message if there was an error). This never returns if there was an error. | 2621 | * message if there was an error). |
2555 | */ | 2622 | */ |
2556 | 2623 | int | |
2557 | void | ||
2558 | channel_input_port_forward_request(int is_root, int gateway_ports) | 2624 | channel_input_port_forward_request(int is_root, int gateway_ports) |
2559 | { | 2625 | { |
2560 | u_short port, host_port; | 2626 | u_short port, host_port; |
2627 | int success = 0; | ||
2561 | char *hostname; | 2628 | char *hostname; |
2562 | 2629 | ||
2563 | /* Get arguments from the packet. */ | 2630 | /* Get arguments from the packet. */ |
@@ -2579,11 +2646,13 @@ channel_input_port_forward_request(int is_root, int gateway_ports) | |||
2579 | #endif | 2646 | #endif |
2580 | 2647 | ||
2581 | /* Initiate forwarding */ | 2648 | /* Initiate forwarding */ |
2582 | channel_setup_local_fwd_listener(NULL, port, hostname, | 2649 | success = channel_setup_local_fwd_listener(NULL, port, hostname, |
2583 | host_port, gateway_ports); | 2650 | host_port, gateway_ports); |
2584 | 2651 | ||
2585 | /* Free the argument string. */ | 2652 | /* Free the argument string. */ |
2586 | xfree(hostname); | 2653 | xfree(hostname); |
2654 | |||
2655 | return (success ? 0 : -1); | ||
2587 | } | 2656 | } |
2588 | 2657 | ||
2589 | /* | 2658 | /* |
@@ -2602,7 +2671,7 @@ void | |||
2602 | channel_add_permitted_opens(char *host, int port) | 2671 | channel_add_permitted_opens(char *host, int port) |
2603 | { | 2672 | { |
2604 | if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) | 2673 | if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) |
2605 | fatal("channel_request_remote_forwarding: too many forwards"); | 2674 | fatal("channel_add_permitted_opens: too many forwards"); |
2606 | debug("allow port forwarding to host %s port %d", host, port); | 2675 | debug("allow port forwarding to host %s port %d", host, port); |
2607 | 2676 | ||
2608 | permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); | 2677 | permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); |
@@ -2612,6 +2681,19 @@ channel_add_permitted_opens(char *host, int port) | |||
2612 | all_opens_permitted = 0; | 2681 | all_opens_permitted = 0; |
2613 | } | 2682 | } |
2614 | 2683 | ||
2684 | int | ||
2685 | channel_add_adm_permitted_opens(char *host, int port) | ||
2686 | { | ||
2687 | if (num_adm_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) | ||
2688 | fatal("channel_add_adm_permitted_opens: too many forwards"); | ||
2689 | debug("config allows port forwarding to host %s port %d", host, port); | ||
2690 | |||
2691 | permitted_adm_opens[num_adm_permitted_opens].host_to_connect | ||
2692 | = xstrdup(host); | ||
2693 | permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; | ||
2694 | return ++num_adm_permitted_opens; | ||
2695 | } | ||
2696 | |||
2615 | void | 2697 | void |
2616 | channel_clear_permitted_opens(void) | 2698 | channel_clear_permitted_opens(void) |
2617 | { | 2699 | { |
@@ -2621,9 +2703,18 @@ channel_clear_permitted_opens(void) | |||
2621 | if (permitted_opens[i].host_to_connect != NULL) | 2703 | if (permitted_opens[i].host_to_connect != NULL) |
2622 | xfree(permitted_opens[i].host_to_connect); | 2704 | xfree(permitted_opens[i].host_to_connect); |
2623 | num_permitted_opens = 0; | 2705 | num_permitted_opens = 0; |
2624 | |||
2625 | } | 2706 | } |
2626 | 2707 | ||
2708 | void | ||
2709 | channel_clear_adm_permitted_opens(void) | ||
2710 | { | ||
2711 | int i; | ||
2712 | |||
2713 | for (i = 0; i < num_adm_permitted_opens; i++) | ||
2714 | if (permitted_adm_opens[i].host_to_connect != NULL) | ||
2715 | xfree(permitted_adm_opens[i].host_to_connect); | ||
2716 | num_adm_permitted_opens = 0; | ||
2717 | } | ||
2627 | 2718 | ||
2628 | /* return socket to remote host, port */ | 2719 | /* return socket to remote host, port */ |
2629 | static int | 2720 | static int |
@@ -2701,7 +2792,7 @@ channel_connect_by_listen_address(u_short listen_port) | |||
2701 | int | 2792 | int |
2702 | channel_connect_to(const char *host, u_short port) | 2793 | channel_connect_to(const char *host, u_short port) |
2703 | { | 2794 | { |
2704 | int i, permit; | 2795 | int i, permit, permit_adm = 1; |
2705 | 2796 | ||
2706 | permit = all_opens_permitted; | 2797 | permit = all_opens_permitted; |
2707 | if (!permit) { | 2798 | if (!permit) { |
@@ -2710,9 +2801,19 @@ channel_connect_to(const char *host, u_short port) | |||
2710 | permitted_opens[i].port_to_connect == port && | 2801 | permitted_opens[i].port_to_connect == port && |
2711 | strcmp(permitted_opens[i].host_to_connect, host) == 0) | 2802 | strcmp(permitted_opens[i].host_to_connect, host) == 0) |
2712 | permit = 1; | 2803 | permit = 1; |
2804 | } | ||
2713 | 2805 | ||
2806 | if (num_adm_permitted_opens > 0) { | ||
2807 | permit_adm = 0; | ||
2808 | for (i = 0; i < num_adm_permitted_opens; i++) | ||
2809 | if (permitted_adm_opens[i].host_to_connect != NULL && | ||
2810 | permitted_adm_opens[i].port_to_connect == port && | ||
2811 | strcmp(permitted_adm_opens[i].host_to_connect, host) | ||
2812 | == 0) | ||
2813 | permit_adm = 1; | ||
2714 | } | 2814 | } |
2715 | if (!permit) { | 2815 | |
2816 | if (!permit || !permit_adm) { | ||
2716 | logit("Received request to connect to host %.100s port %d, " | 2817 | logit("Received request to connect to host %.100s port %d, " |
2717 | "but the request was denied.", host, port); | 2818 | "but the request was denied.", host, port); |
2718 | return -1; | 2819 | return -1; |
@@ -2733,10 +2834,10 @@ channel_send_window_changes(void) | |||
2733 | if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0) | 2834 | if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0) |
2734 | continue; | 2835 | continue; |
2735 | channel_request_start(i, "window-change", 0); | 2836 | channel_request_start(i, "window-change", 0); |
2736 | packet_put_int(ws.ws_col); | 2837 | packet_put_int((u_int)ws.ws_col); |
2737 | packet_put_int(ws.ws_row); | 2838 | packet_put_int((u_int)ws.ws_row); |
2738 | packet_put_int(ws.ws_xpixel); | 2839 | packet_put_int((u_int)ws.ws_xpixel); |
2739 | packet_put_int(ws.ws_ypixel); | 2840 | packet_put_int((u_int)ws.ws_ypixel); |
2740 | packet_send(); | 2841 | packet_send(); |
2741 | } | 2842 | } |
2742 | } | 2843 | } |
@@ -2848,7 +2949,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, | |||
2848 | } | 2949 | } |
2849 | 2950 | ||
2850 | /* Allocate a channel for each socket. */ | 2951 | /* Allocate a channel for each socket. */ |
2851 | *chanids = xmalloc(sizeof(**chanids) * (num_socks + 1)); | 2952 | *chanids = xcalloc(num_socks + 1, sizeof(**chanids)); |
2852 | for (n = 0; n < num_socks; n++) { | 2953 | for (n = 0; n < num_socks; n++) { |
2853 | sock = socks[n]; | 2954 | sock = socks[n]; |
2854 | nc = channel_new("x11 listener", | 2955 | nc = channel_new("x11 listener", |
@@ -2877,7 +2978,7 @@ connect_local_xsocket(u_int dnr) | |||
2877 | memset(&addr, 0, sizeof(addr)); | 2978 | memset(&addr, 0, sizeof(addr)); |
2878 | addr.sun_family = AF_UNIX; | 2979 | addr.sun_family = AF_UNIX; |
2879 | snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr); | 2980 | snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr); |
2880 | if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0) | 2981 | if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) |
2881 | return sock; | 2982 | return sock; |
2882 | close(sock); | 2983 | close(sock); |
2883 | error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); | 2984 | error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); |
@@ -2887,12 +2988,12 @@ connect_local_xsocket(u_int dnr) | |||
2887 | int | 2988 | int |
2888 | x11_connect_display(void) | 2989 | x11_connect_display(void) |
2889 | { | 2990 | { |
2890 | int display_number, sock = 0; | 2991 | u_int display_number; |
2891 | const char *display; | 2992 | const char *display; |
2892 | char buf[1024], *cp; | 2993 | char buf[1024], *cp; |
2893 | struct addrinfo hints, *ai, *aitop; | 2994 | struct addrinfo hints, *ai, *aitop; |
2894 | char strport[NI_MAXSERV]; | 2995 | char strport[NI_MAXSERV]; |
2895 | int gaierr; | 2996 | int gaierr, sock = 0; |
2896 | 2997 | ||
2897 | /* Try to open a socket for the local X server. */ | 2998 | /* Try to open a socket for the local X server. */ |
2898 | display = getenv("DISPLAY"); | 2999 | display = getenv("DISPLAY"); |
@@ -2912,7 +3013,7 @@ x11_connect_display(void) | |||
2912 | if (strncmp(display, "unix:", 5) == 0 || | 3013 | if (strncmp(display, "unix:", 5) == 0 || |
2913 | display[0] == ':') { | 3014 | display[0] == ':') { |
2914 | /* Connect to the unix domain socket. */ | 3015 | /* Connect to the unix domain socket. */ |
2915 | if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) { | 3016 | if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) { |
2916 | error("Could not parse display number from DISPLAY: %.100s", | 3017 | error("Could not parse display number from DISPLAY: %.100s", |
2917 | display); | 3018 | display); |
2918 | return -1; | 3019 | return -1; |
@@ -2937,7 +3038,7 @@ x11_connect_display(void) | |||
2937 | } | 3038 | } |
2938 | *cp = 0; | 3039 | *cp = 0; |
2939 | /* buf now contains the host name. But first we parse the display number. */ | 3040 | /* buf now contains the host name. But first we parse the display number. */ |
2940 | if (sscanf(cp + 1, "%d", &display_number) != 1) { | 3041 | if (sscanf(cp + 1, "%u", &display_number) != 1) { |
2941 | error("Could not parse display number from DISPLAY: %.100s", | 3042 | error("Could not parse display number from DISPLAY: %.100s", |
2942 | display); | 3043 | display); |
2943 | return -1; | 3044 | return -1; |
@@ -2947,7 +3048,7 @@ x11_connect_display(void) | |||
2947 | memset(&hints, 0, sizeof(hints)); | 3048 | memset(&hints, 0, sizeof(hints)); |
2948 | hints.ai_family = IPv4or6; | 3049 | hints.ai_family = IPv4or6; |
2949 | hints.ai_socktype = SOCK_STREAM; | 3050 | hints.ai_socktype = SOCK_STREAM; |
2950 | snprintf(strport, sizeof strport, "%d", 6000 + display_number); | 3051 | snprintf(strport, sizeof strport, "%u", 6000 + display_number); |
2951 | if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { | 3052 | if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { |
2952 | error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); | 3053 | error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); |
2953 | return -1; | 3054 | return -1; |
@@ -2961,7 +3062,7 @@ x11_connect_display(void) | |||
2961 | } | 3062 | } |
2962 | /* Connect it to the display. */ | 3063 | /* Connect it to the display. */ |
2963 | if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | 3064 | if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
2964 | debug2("connect %.100s port %d: %.100s", buf, | 3065 | debug2("connect %.100s port %u: %.100s", buf, |
2965 | 6000 + display_number, strerror(errno)); | 3066 | 6000 + display_number, strerror(errno)); |
2966 | close(sock); | 3067 | close(sock); |
2967 | continue; | 3068 | continue; |
@@ -2971,7 +3072,7 @@ x11_connect_display(void) | |||
2971 | } | 3072 | } |
2972 | freeaddrinfo(aitop); | 3073 | freeaddrinfo(aitop); |
2973 | if (!ai) { | 3074 | if (!ai) { |
2974 | error("connect %.100s port %d: %.100s", buf, 6000 + display_number, | 3075 | error("connect %.100s port %u: %.100s", buf, 6000 + display_number, |
2975 | strerror(errno)); | 3076 | strerror(errno)); |
2976 | return -1; | 3077 | return -1; |
2977 | } | 3078 | } |
@@ -2985,6 +3086,7 @@ x11_connect_display(void) | |||
2985 | * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. | 3086 | * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. |
2986 | */ | 3087 | */ |
2987 | 3088 | ||
3089 | /* ARGSUSED */ | ||
2988 | void | 3090 | void |
2989 | x11_input_open(int type, u_int32_t seq, void *ctxt) | 3091 | x11_input_open(int type, u_int32_t seq, void *ctxt) |
2990 | { | 3092 | { |
@@ -3028,6 +3130,7 @@ x11_input_open(int type, u_int32_t seq, void *ctxt) | |||
3028 | } | 3130 | } |
3029 | 3131 | ||
3030 | /* dummy protocol handler that denies SSH-1 requests (agent/x11) */ | 3132 | /* dummy protocol handler that denies SSH-1 requests (agent/x11) */ |
3133 | /* ARGSUSED */ | ||
3031 | void | 3134 | void |
3032 | deny_input_open(int type, u_int32_t seq, void *ctxt) | 3135 | deny_input_open(int type, u_int32_t seq, void *ctxt) |
3033 | { | 3136 | { |
@@ -3074,13 +3177,11 @@ x11_request_forwarding_with_spoofing(int client_session_id, const char *disp, | |||
3074 | return; | 3177 | return; |
3075 | } | 3178 | } |
3076 | 3179 | ||
3077 | cp = disp; | 3180 | cp = strchr(disp, ':'); |
3078 | if (disp) | ||
3079 | cp = strchr(disp, ':'); | ||
3080 | if (cp) | 3181 | if (cp) |
3081 | cp = strchr(cp, '.'); | 3182 | cp = strchr(cp, '.'); |
3082 | if (cp) | 3183 | if (cp) |
3083 | screen_number = atoi(cp + 1); | 3184 | screen_number = (u_int)strtonum(cp + 1, 0, 400, NULL); |
3084 | else | 3185 | else |
3085 | screen_number = 0; | 3186 | screen_number = 0; |
3086 | 3187 | ||