diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 355 |
1 files changed, 193 insertions, 162 deletions
diff --git a/channels.c b/channels.c index 503a81450..2bb0e9851 100644 --- a/channels.c +++ b/channels.c | |||
@@ -40,7 +40,7 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | RCSID("$OpenBSD: channels.c,v 1.112 2001/05/04 14:34:34 markus Exp $"); | 43 | RCSID("$OpenBSD: channels.c,v 1.113 2001/05/04 23:47:33 markus Exp $"); |
44 | 44 | ||
45 | #include <openssl/rsa.h> | 45 | #include <openssl/rsa.h> |
46 | #include <openssl/dsa.h> | 46 | #include <openssl/dsa.h> |
@@ -72,18 +72,17 @@ RCSID("$OpenBSD: channels.c,v 1.112 2001/05/04 14:34:34 markus Exp $"); | |||
72 | * Pointer to an array containing all allocated channels. The array is | 72 | * Pointer to an array containing all allocated channels. The array is |
73 | * dynamically extended as needed. | 73 | * dynamically extended as needed. |
74 | */ | 74 | */ |
75 | static Channel *channels = NULL; | 75 | static Channel **channels = NULL; |
76 | 76 | ||
77 | /* | 77 | /* |
78 | * Size of the channel array. All slots of the array must always be | 78 | * Size of the channel array. All slots of the array must always be |
79 | * initialized (at least the type field); unused slots are marked with type | 79 | * initialized (at least the type field); unused slots set to NULL |
80 | * SSH_CHANNEL_FREE. | ||
81 | */ | 80 | */ |
82 | static int channels_alloc = 0; | 81 | static int channels_alloc = 0; |
83 | 82 | ||
84 | /* | 83 | /* |
85 | * Maximum file descriptor value used in any of the channels. This is | 84 | * Maximum file descriptor value used in any of the channels. This is |
86 | * updated in channel_allocate. | 85 | * updated in channel_new. |
87 | */ | 86 | */ |
88 | static int channel_max_fd = 0; | 87 | static int channel_max_fd = 0; |
89 | 88 | ||
@@ -150,12 +149,13 @@ Channel * | |||
150 | channel_lookup(int id) | 149 | channel_lookup(int id) |
151 | { | 150 | { |
152 | Channel *c; | 151 | Channel *c; |
152 | |||
153 | if (id < 0 || id > channels_alloc) { | 153 | if (id < 0 || id > channels_alloc) { |
154 | log("channel_lookup: %d: bad id", id); | 154 | log("channel_lookup: %d: bad id", id); |
155 | return NULL; | 155 | return NULL; |
156 | } | 156 | } |
157 | c = &channels[id]; | 157 | c = channels[id]; |
158 | if (c->type == SSH_CHANNEL_FREE) { | 158 | if (c == NULL) { |
159 | log("channel_lookup: %d: bad id: channel free", id); | 159 | log("channel_lookup: %d: bad id: channel free", id); |
160 | return NULL; | 160 | return NULL; |
161 | } | 161 | } |
@@ -212,7 +212,7 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, | |||
212 | * remote_name to be freed. | 212 | * remote_name to be freed. |
213 | */ | 213 | */ |
214 | 214 | ||
215 | int | 215 | Channel * |
216 | channel_new(char *ctype, int type, int rfd, int wfd, int efd, | 216 | channel_new(char *ctype, int type, int rfd, int wfd, int efd, |
217 | int window, int maxpack, int extusage, char *remote_name, int nonblock) | 217 | int window, int maxpack, int extusage, char *remote_name, int nonblock) |
218 | { | 218 | { |
@@ -223,9 +223,9 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
223 | if (channels_alloc == 0) { | 223 | if (channels_alloc == 0) { |
224 | chan_init(); | 224 | chan_init(); |
225 | channels_alloc = 10; | 225 | channels_alloc = 10; |
226 | channels = xmalloc(channels_alloc * sizeof(Channel)); | 226 | channels = xmalloc(channels_alloc * sizeof(Channel *)); |
227 | for (i = 0; i < channels_alloc; i++) | 227 | for (i = 0; i < channels_alloc; i++) |
228 | channels[i].type = SSH_CHANNEL_FREE; | 228 | channels[i] = NULL; |
229 | /* | 229 | /* |
230 | * Kludge: arrange a call to channel_stop_listening if we | 230 | * Kludge: arrange a call to channel_stop_listening if we |
231 | * terminate with fatal(). | 231 | * terminate with fatal(). |
@@ -234,7 +234,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
234 | } | 234 | } |
235 | /* Try to find a free slot where to put the new channel. */ | 235 | /* Try to find a free slot where to put the new channel. */ |
236 | for (found = -1, i = 0; i < channels_alloc; i++) | 236 | for (found = -1, i = 0; i < channels_alloc; i++) |
237 | if (channels[i].type == SSH_CHANNEL_FREE) { | 237 | if (channels[i] == NULL) { |
238 | /* Found a free slot. */ | 238 | /* Found a free slot. */ |
239 | found = i; | 239 | found = i; |
240 | break; | 240 | break; |
@@ -244,12 +244,12 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
244 | found = channels_alloc; | 244 | found = channels_alloc; |
245 | channels_alloc += 10; | 245 | channels_alloc += 10; |
246 | debug2("channel: expanding %d", channels_alloc); | 246 | debug2("channel: expanding %d", channels_alloc); |
247 | channels = xrealloc(channels, channels_alloc * sizeof(Channel)); | 247 | channels = xrealloc(channels, channels_alloc * sizeof(Channel *)); |
248 | for (i = found; i < channels_alloc; i++) | 248 | for (i = found; i < channels_alloc; i++) |
249 | channels[i].type = SSH_CHANNEL_FREE; | 249 | channels[i] = NULL; |
250 | } | 250 | } |
251 | /* Initialize and return new channel number. */ | 251 | /* Initialize and return new channel. */ |
252 | c = &channels[found]; | 252 | c = channels[found] = xmalloc(sizeof(Channel)); |
253 | buffer_init(&c->input); | 253 | buffer_init(&c->input); |
254 | buffer_init(&c->output); | 254 | buffer_init(&c->output); |
255 | buffer_init(&c->extended); | 255 | buffer_init(&c->extended); |
@@ -272,16 +272,9 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
272 | c->dettach_user = NULL; | 272 | c->dettach_user = NULL; |
273 | c->input_filter = NULL; | 273 | c->input_filter = NULL; |
274 | debug("channel %d: new [%s]", found, remote_name); | 274 | debug("channel %d: new [%s]", found, remote_name); |
275 | return found; | 275 | return c; |
276 | } | ||
277 | /* old interface XXX */ | ||
278 | int | ||
279 | channel_allocate(int type, int sock, char *remote_name) | ||
280 | { | ||
281 | return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name, 1); | ||
282 | } | 276 | } |
283 | 277 | ||
284 | |||
285 | /* Close all channel fd/socket. */ | 278 | /* Close all channel fd/socket. */ |
286 | 279 | ||
287 | void | 280 | void |
@@ -308,18 +301,16 @@ channel_close_fds(Channel *c) | |||
308 | /* Free the channel and close its fd/socket. */ | 301 | /* Free the channel and close its fd/socket. */ |
309 | 302 | ||
310 | void | 303 | void |
311 | channel_free(int id) | 304 | channel_free(Channel *c) |
312 | { | 305 | { |
313 | Channel *c = channel_lookup(id); | 306 | char *s; |
314 | char *s = channel_open_message(); | ||
315 | 307 | ||
316 | if (c == NULL) | 308 | s = channel_open_message(); |
317 | packet_disconnect("channel free: bad local channel %d", id); | 309 | debug("channel_free: channel %d: status: %s", c->self, s); |
318 | debug("channel_free: channel %d: status: %s", id, s); | ||
319 | xfree(s); | 310 | xfree(s); |
320 | 311 | ||
321 | if (c->dettach_user != NULL) { | 312 | if (c->dettach_user != NULL) { |
322 | debug("channel_free: channel %d: dettaching channel user", id); | 313 | debug("channel_free: channel %d: dettaching channel user", c->self); |
323 | c->dettach_user(c->self, NULL); | 314 | c->dettach_user(c->self, NULL); |
324 | } | 315 | } |
325 | if (c->sock != -1) | 316 | if (c->sock != -1) |
@@ -328,11 +319,12 @@ channel_free(int id) | |||
328 | buffer_free(&c->input); | 319 | buffer_free(&c->input); |
329 | buffer_free(&c->output); | 320 | buffer_free(&c->output); |
330 | buffer_free(&c->extended); | 321 | buffer_free(&c->extended); |
331 | c->type = SSH_CHANNEL_FREE; | ||
332 | if (c->remote_name) { | 322 | if (c->remote_name) { |
333 | xfree(c->remote_name); | 323 | xfree(c->remote_name); |
334 | c->remote_name = NULL; | 324 | c->remote_name = NULL; |
335 | } | 325 | } |
326 | channels[c->self] = NULL; | ||
327 | xfree(c); | ||
336 | } | 328 | } |
337 | 329 | ||
338 | /* | 330 | /* |
@@ -428,7 +420,7 @@ void | |||
428 | channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) | 420 | channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) |
429 | { | 421 | { |
430 | if (buffer_len(&c->output) == 0) | 422 | if (buffer_len(&c->output) == 0) |
431 | channel_free(c->self); | 423 | chan_mark_dead(c); |
432 | else | 424 | else |
433 | FD_SET(c->sock, writeset); | 425 | FD_SET(c->sock, writeset); |
434 | } | 426 | } |
@@ -640,7 +632,7 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | |||
640 | break; | 632 | break; |
641 | } | 633 | } |
642 | if (ret < 0) { | 634 | if (ret < 0) { |
643 | channel_free(c->self); | 635 | chan_mark_dead(c); |
644 | } else if (ret == 0) { | 636 | } else if (ret == 0) { |
645 | debug2("channel %d: pre_dynamic: need more", c->self); | 637 | debug2("channel %d: pre_dynamic: need more", c->self); |
646 | /* need more */ | 638 | /* need more */ |
@@ -656,8 +648,9 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | |||
656 | void | 648 | void |
657 | channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) | 649 | channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) |
658 | { | 650 | { |
651 | Channel *nc; | ||
659 | struct sockaddr addr; | 652 | struct sockaddr addr; |
660 | int newsock, newch, oldch; | 653 | int newsock; |
661 | socklen_t addrlen; | 654 | socklen_t addrlen; |
662 | char buf[16384], *remote_ipaddr; | 655 | char buf[16384], *remote_ipaddr; |
663 | int remote_port; | 656 | int remote_port; |
@@ -675,16 +668,19 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
675 | snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", | 668 | snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", |
676 | remote_ipaddr, remote_port); | 669 | remote_ipaddr, remote_port); |
677 | 670 | ||
678 | oldch = c->self; | 671 | nc = channel_new("accepted x11 socket", |
679 | newch = channel_new("x11", | ||
680 | SSH_CHANNEL_OPENING, newsock, newsock, -1, | 672 | SSH_CHANNEL_OPENING, newsock, newsock, -1, |
681 | c->local_window_max, c->local_maxpacket, | 673 | c->local_window_max, c->local_maxpacket, |
682 | 0, xstrdup(buf), 1); | 674 | 0, xstrdup(buf), 1); |
683 | c = channel_lookup(oldch); | 675 | if (nc == NULL) { |
676 | close(newsock); | ||
677 | xfree(remote_ipaddr); | ||
678 | return; | ||
679 | } | ||
684 | if (compat20) { | 680 | if (compat20) { |
685 | packet_start(SSH2_MSG_CHANNEL_OPEN); | 681 | packet_start(SSH2_MSG_CHANNEL_OPEN); |
686 | packet_put_cstring("x11"); | 682 | packet_put_cstring("x11"); |
687 | packet_put_int(newch); | 683 | packet_put_int(nc->self); |
688 | packet_put_int(c->local_window_max); | 684 | packet_put_int(c->local_window_max); |
689 | packet_put_int(c->local_maxpacket); | 685 | packet_put_int(c->local_maxpacket); |
690 | /* originator ipaddr and port */ | 686 | /* originator ipaddr and port */ |
@@ -697,7 +693,7 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
697 | packet_send(); | 693 | packet_send(); |
698 | } else { | 694 | } else { |
699 | packet_start(SSH_SMSG_X11_OPEN); | 695 | packet_start(SSH_SMSG_X11_OPEN); |
700 | packet_put_int(newch); | 696 | packet_put_int(nc->self); |
701 | if (have_hostname_in_open) | 697 | if (have_hostname_in_open) |
702 | packet_put_string(buf, strlen(buf)); | 698 | packet_put_string(buf, strlen(buf)); |
703 | packet_send(); | 699 | packet_send(); |
@@ -764,7 +760,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
764 | { | 760 | { |
765 | Channel *nc; | 761 | Channel *nc; |
766 | struct sockaddr addr; | 762 | struct sockaddr addr; |
767 | int newsock, newch, nextstate, oldch; | 763 | int newsock, nextstate; |
768 | socklen_t addrlen; | 764 | socklen_t addrlen; |
769 | char *rtype; | 765 | char *rtype; |
770 | 766 | ||
@@ -784,16 +780,13 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
784 | error("accept: %.100s", strerror(errno)); | 780 | error("accept: %.100s", strerror(errno)); |
785 | return; | 781 | return; |
786 | } | 782 | } |
787 | oldch = c->self; | 783 | nc = channel_new(rtype, |
788 | newch = channel_new(rtype, | ||
789 | nextstate, newsock, newsock, -1, | 784 | nextstate, newsock, newsock, -1, |
790 | c->local_window_max, c->local_maxpacket, | 785 | c->local_window_max, c->local_maxpacket, |
791 | 0, xstrdup(rtype), 1); | 786 | 0, xstrdup(rtype), 1); |
792 | |||
793 | c = channel_lookup(oldch); | ||
794 | nc = channel_lookup(newch); | ||
795 | if (nc == NULL) { | 787 | if (nc == NULL) { |
796 | error("xxx: no new channel:"); | 788 | error("channel_post_port_listener: no new channel:"); |
789 | close(newsock); | ||
797 | return; | 790 | return; |
798 | } | 791 | } |
799 | nc->listening_port = c->listening_port; | 792 | nc->listening_port = c->listening_port; |
@@ -812,8 +805,9 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
812 | void | 805 | void |
813 | channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) | 806 | channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) |
814 | { | 807 | { |
808 | Channel *nc; | ||
809 | int newsock; | ||
815 | struct sockaddr addr; | 810 | struct sockaddr addr; |
816 | int newsock, newch, oldch; | ||
817 | socklen_t addrlen; | 811 | socklen_t addrlen; |
818 | 812 | ||
819 | if (FD_ISSET(c->sock, readset)) { | 813 | if (FD_ISSET(c->sock, readset)) { |
@@ -823,21 +817,23 @@ channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
823 | error("accept from auth socket: %.100s", strerror(errno)); | 817 | error("accept from auth socket: %.100s", strerror(errno)); |
824 | return; | 818 | return; |
825 | } | 819 | } |
826 | oldch = c->self; | 820 | nc = channel_new("accepted auth socket", |
827 | newch = channel_new("accepted auth socket", | ||
828 | SSH_CHANNEL_OPENING, newsock, newsock, -1, | 821 | SSH_CHANNEL_OPENING, newsock, newsock, -1, |
829 | c->local_window_max, c->local_maxpacket, | 822 | c->local_window_max, c->local_maxpacket, |
830 | 0, xstrdup("accepted auth socket"), 1); | 823 | 0, xstrdup("accepted auth socket"), 1); |
831 | c = channel_lookup(oldch); | 824 | if (nc == NULL) { |
825 | error("channel_post_auth_listener: channel_new failed"); | ||
826 | close(newsock); | ||
827 | } | ||
832 | if (compat20) { | 828 | if (compat20) { |
833 | packet_start(SSH2_MSG_CHANNEL_OPEN); | 829 | packet_start(SSH2_MSG_CHANNEL_OPEN); |
834 | packet_put_cstring("auth-agent@openssh.com"); | 830 | packet_put_cstring("auth-agent@openssh.com"); |
835 | packet_put_int(newch); | 831 | packet_put_int(nc->self); |
836 | packet_put_int(c->local_window_max); | 832 | packet_put_int(c->local_window_max); |
837 | packet_put_int(c->local_maxpacket); | 833 | packet_put_int(c->local_maxpacket); |
838 | } else { | 834 | } else { |
839 | packet_start(SSH_SMSG_AGENT_OPEN); | 835 | packet_start(SSH_SMSG_AGENT_OPEN); |
840 | packet_put_int(newch); | 836 | packet_put_int(nc->self); |
841 | } | 837 | } |
842 | packet_send(); | 838 | packet_send(); |
843 | } | 839 | } |
@@ -881,7 +877,7 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) | |||
881 | c->self, c->rfd, len); | 877 | c->self, c->rfd, len); |
882 | if (c->type != SSH_CHANNEL_OPEN) { | 878 | if (c->type != SSH_CHANNEL_OPEN) { |
883 | debug("channel %d: not open", c->self); | 879 | debug("channel %d: not open", c->self); |
884 | channel_free(c->self); | 880 | chan_mark_dead(c); |
885 | return -1; | 881 | return -1; |
886 | } else if (compat13) { | 882 | } else if (compat13) { |
887 | buffer_consume(&c->output, buffer_len(&c->output)); | 883 | buffer_consume(&c->output, buffer_len(&c->output)); |
@@ -920,7 +916,7 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) | |||
920 | if (len <= 0) { | 916 | if (len <= 0) { |
921 | if (c->type != SSH_CHANNEL_OPEN) { | 917 | if (c->type != SSH_CHANNEL_OPEN) { |
922 | debug("channel %d: not open", c->self); | 918 | debug("channel %d: not open", c->self); |
923 | channel_free(c->self); | 919 | chan_mark_dead(c); |
924 | return -1; | 920 | return -1; |
925 | } else if (compat13) { | 921 | } else if (compat13) { |
926 | buffer_consume(&c->output, buffer_len(&c->output)); | 922 | buffer_consume(&c->output, buffer_len(&c->output)); |
@@ -1138,13 +1134,12 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) | |||
1138 | did_init = 1; | 1134 | did_init = 1; |
1139 | } | 1135 | } |
1140 | for (i = 0; i < channels_alloc; i++) { | 1136 | for (i = 0; i < channels_alloc; i++) { |
1141 | c = &channels[i]; | 1137 | c = channels[i]; |
1142 | if (c->type == SSH_CHANNEL_FREE) | 1138 | if (c == NULL) |
1143 | continue; | 1139 | continue; |
1144 | if (ftab[c->type] == NULL) | 1140 | if (ftab[c->type] == NULL) |
1145 | continue; | 1141 | continue; |
1146 | (*ftab[c->type])(c, readset, writeset); | 1142 | (*ftab[c->type])(c, readset, writeset); |
1147 | c = &channels[i]; /* XXX realloc */ | ||
1148 | if (chan_is_dead(c)) { | 1143 | if (chan_is_dead(c)) { |
1149 | /* | 1144 | /* |
1150 | * we have to remove the fd's from the select mask | 1145 | * we have to remove the fd's from the select mask |
@@ -1161,7 +1156,7 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) | |||
1161 | if (c->extended_usage == CHAN_EXTENDED_WRITE) | 1156 | if (c->extended_usage == CHAN_EXTENDED_WRITE) |
1162 | FD_CLR(c->efd, writeset); | 1157 | FD_CLR(c->efd, writeset); |
1163 | } | 1158 | } |
1164 | channel_free(c->self); | 1159 | channel_free(c); |
1165 | } | 1160 | } |
1166 | } | 1161 | } |
1167 | } | 1162 | } |
@@ -1207,7 +1202,10 @@ channel_output_poll() | |||
1207 | Channel *c; | 1202 | Channel *c; |
1208 | 1203 | ||
1209 | for (i = 0; i < channels_alloc; i++) { | 1204 | for (i = 0; i < channels_alloc; i++) { |
1210 | c = &channels[i]; | 1205 | |
1206 | c = channels[i]; | ||
1207 | if (c == NULL) | ||
1208 | continue; | ||
1211 | 1209 | ||
1212 | /* We are only interested in channels that can have buffered incoming data. */ | 1210 | /* We are only interested in channels that can have buffered incoming data. */ |
1213 | if (compat13) { | 1211 | if (compat13) { |
@@ -1391,8 +1389,8 @@ channel_not_very_much_buffered_data() | |||
1391 | Channel *c; | 1389 | Channel *c; |
1392 | 1390 | ||
1393 | for (i = 0; i < channels_alloc; i++) { | 1391 | for (i = 0; i < channels_alloc; i++) { |
1394 | c = &channels[i]; | 1392 | c = channels[i]; |
1395 | if (c->type == SSH_CHANNEL_OPEN) { | 1393 | if (c != NULL && c->type == SSH_CHANNEL_OPEN) { |
1396 | if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) { | 1394 | if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) { |
1397 | debug("channel %d: big input buffer %d", | 1395 | debug("channel %d: big input buffer %d", |
1398 | c->self, buffer_len(&c->input)); | 1396 | c->self, buffer_len(&c->input)); |
@@ -1486,7 +1484,7 @@ channel_input_close_confirmation(int type, int plen, void *ctxt) | |||
1486 | if (c->type != SSH_CHANNEL_CLOSED) | 1484 | if (c->type != SSH_CHANNEL_CLOSED) |
1487 | packet_disconnect("Received close confirmation for " | 1485 | packet_disconnect("Received close confirmation for " |
1488 | "non-closed channel %d (type %d).", id, c->type); | 1486 | "non-closed channel %d (type %d).", id, c->type); |
1489 | channel_free(c->self); | 1487 | channel_free(c); |
1490 | } | 1488 | } |
1491 | 1489 | ||
1492 | void | 1490 | void |
@@ -1554,7 +1552,7 @@ channel_input_open_failure(int type, int plen, void *ctxt) | |||
1554 | xfree(lang); | 1552 | xfree(lang); |
1555 | } | 1553 | } |
1556 | /* Free the channel. This will also close the socket. */ | 1554 | /* Free the channel. This will also close the socket. */ |
1557 | channel_free(id); | 1555 | channel_free(c); |
1558 | } | 1556 | } |
1559 | 1557 | ||
1560 | void | 1558 | void |
@@ -1615,21 +1613,26 @@ void | |||
1615 | channel_stop_listening() | 1613 | channel_stop_listening() |
1616 | { | 1614 | { |
1617 | int i; | 1615 | int i; |
1616 | Channel *c; | ||
1617 | |||
1618 | for (i = 0; i < channels_alloc; i++) { | 1618 | for (i = 0; i < channels_alloc; i++) { |
1619 | switch (channels[i].type) { | 1619 | c = channels[i]; |
1620 | case SSH_CHANNEL_AUTH_SOCKET: | 1620 | if (c != NULL) { |
1621 | close(channels[i].sock); | 1621 | switch (c->type) { |
1622 | unlink(channels[i].path); | 1622 | case SSH_CHANNEL_AUTH_SOCKET: |
1623 | channel_free(i); | 1623 | close(c->sock); |
1624 | break; | 1624 | unlink(c->path); |
1625 | case SSH_CHANNEL_PORT_LISTENER: | 1625 | channel_free(c); |
1626 | case SSH_CHANNEL_RPORT_LISTENER: | 1626 | break; |
1627 | case SSH_CHANNEL_X11_LISTENER: | 1627 | case SSH_CHANNEL_PORT_LISTENER: |
1628 | close(channels[i].sock); | 1628 | case SSH_CHANNEL_RPORT_LISTENER: |
1629 | channel_free(i); | 1629 | case SSH_CHANNEL_X11_LISTENER: |
1630 | break; | 1630 | close(c->sock); |
1631 | default: | 1631 | channel_free(c); |
1632 | break; | 1632 | break; |
1633 | default: | ||
1634 | break; | ||
1635 | } | ||
1633 | } | 1636 | } |
1634 | } | 1637 | } |
1635 | } | 1638 | } |
@@ -1643,9 +1646,10 @@ void | |||
1643 | channel_close_all() | 1646 | channel_close_all() |
1644 | { | 1647 | { |
1645 | int i; | 1648 | int i; |
1649 | |||
1646 | for (i = 0; i < channels_alloc; i++) | 1650 | for (i = 0; i < channels_alloc; i++) |
1647 | if (channels[i].type != SSH_CHANNEL_FREE) | 1651 | if (channels[i] != NULL) |
1648 | channel_close_fds(&channels[i]); | 1652 | channel_close_fds(channels[i]); |
1649 | } | 1653 | } |
1650 | 1654 | ||
1651 | /* Returns true if any channel is still open. */ | 1655 | /* Returns true if any channel is still open. */ |
@@ -1653,10 +1657,14 @@ channel_close_all() | |||
1653 | int | 1657 | int |
1654 | channel_still_open() | 1658 | channel_still_open() |
1655 | { | 1659 | { |
1656 | u_int i; | 1660 | int i; |
1657 | for (i = 0; i < channels_alloc; i++) | 1661 | Channel *c; |
1658 | switch (channels[i].type) { | 1662 | |
1659 | case SSH_CHANNEL_FREE: | 1663 | for (i = 0; i < channels_alloc; i++) { |
1664 | c = channels[i]; | ||
1665 | if (c == NULL) | ||
1666 | continue; | ||
1667 | switch (c->type) { | ||
1660 | case SSH_CHANNEL_X11_LISTENER: | 1668 | case SSH_CHANNEL_X11_LISTENER: |
1661 | case SSH_CHANNEL_PORT_LISTENER: | 1669 | case SSH_CHANNEL_PORT_LISTENER: |
1662 | case SSH_CHANNEL_RPORT_LISTENER: | 1670 | case SSH_CHANNEL_RPORT_LISTENER: |
@@ -1679,9 +1687,10 @@ channel_still_open() | |||
1679 | fatal("cannot happen: OUT_DRAIN"); | 1687 | fatal("cannot happen: OUT_DRAIN"); |
1680 | return 1; | 1688 | return 1; |
1681 | default: | 1689 | default: |
1682 | fatal("channel_still_open: bad channel type %d", channels[i].type); | 1690 | fatal("channel_still_open: bad channel type %d", c->type); |
1683 | /* NOTREACHED */ | 1691 | /* NOTREACHED */ |
1684 | } | 1692 | } |
1693 | } | ||
1685 | return 0; | 1694 | return 0; |
1686 | } | 1695 | } |
1687 | 1696 | ||
@@ -1690,12 +1699,16 @@ channel_still_open() | |||
1690 | int | 1699 | int |
1691 | channel_find_open() | 1700 | channel_find_open() |
1692 | { | 1701 | { |
1693 | u_int i; | 1702 | int i; |
1694 | for (i = 0; i < channels_alloc; i++) | 1703 | Channel *c; |
1695 | switch (channels[i].type) { | 1704 | |
1705 | for (i = 0; i < channels_alloc; i++) { | ||
1706 | c = channels[i]; | ||
1707 | if (c == NULL) | ||
1708 | continue; | ||
1709 | switch (c->type) { | ||
1696 | case SSH_CHANNEL_CLOSED: | 1710 | case SSH_CHANNEL_CLOSED: |
1697 | case SSH_CHANNEL_DYNAMIC: | 1711 | case SSH_CHANNEL_DYNAMIC: |
1698 | case SSH_CHANNEL_FREE: | ||
1699 | case SSH_CHANNEL_X11_LISTENER: | 1712 | case SSH_CHANNEL_X11_LISTENER: |
1700 | case SSH_CHANNEL_PORT_LISTENER: | 1713 | case SSH_CHANNEL_PORT_LISTENER: |
1701 | case SSH_CHANNEL_RPORT_LISTENER: | 1714 | case SSH_CHANNEL_RPORT_LISTENER: |
@@ -1713,9 +1726,10 @@ channel_find_open() | |||
1713 | fatal("cannot happen: OUT_DRAIN"); | 1726 | fatal("cannot happen: OUT_DRAIN"); |
1714 | return i; | 1727 | return i; |
1715 | default: | 1728 | default: |
1716 | fatal("channel_find_open: bad channel type %d", channels[i].type); | 1729 | fatal("channel_find_open: bad channel type %d", c->type); |
1717 | /* NOTREACHED */ | 1730 | /* NOTREACHED */ |
1718 | } | 1731 | } |
1732 | } | ||
1719 | return -1; | 1733 | return -1; |
1720 | } | 1734 | } |
1721 | 1735 | ||
@@ -1730,16 +1744,18 @@ char * | |||
1730 | channel_open_message() | 1744 | channel_open_message() |
1731 | { | 1745 | { |
1732 | Buffer buffer; | 1746 | Buffer buffer; |
1747 | Channel *c; | ||
1748 | char buf[1024], *cp; | ||
1733 | int i; | 1749 | int i; |
1734 | char buf[512], *cp; | ||
1735 | 1750 | ||
1736 | buffer_init(&buffer); | 1751 | buffer_init(&buffer); |
1737 | snprintf(buf, sizeof buf, "The following connections are open:\r\n"); | 1752 | snprintf(buf, sizeof buf, "The following connections are open:\r\n"); |
1738 | buffer_append(&buffer, buf, strlen(buf)); | 1753 | buffer_append(&buffer, buf, strlen(buf)); |
1739 | for (i = 0; i < channels_alloc; i++) { | 1754 | for (i = 0; i < channels_alloc; i++) { |
1740 | Channel *c = &channels[i]; | 1755 | c = channels[i]; |
1756 | if (c == NULL) | ||
1757 | continue; | ||
1741 | switch (c->type) { | 1758 | switch (c->type) { |
1742 | case SSH_CHANNEL_FREE: | ||
1743 | case SSH_CHANNEL_X11_LISTENER: | 1759 | case SSH_CHANNEL_X11_LISTENER: |
1744 | case SSH_CHANNEL_PORT_LISTENER: | 1760 | case SSH_CHANNEL_PORT_LISTENER: |
1745 | case SSH_CHANNEL_RPORT_LISTENER: | 1761 | case SSH_CHANNEL_RPORT_LISTENER: |
@@ -1797,7 +1813,8 @@ channel_request_forwarding( | |||
1797 | const char *host_to_connect, u_short port_to_connect, | 1813 | const char *host_to_connect, u_short port_to_connect, |
1798 | int gateway_ports, int remote_fwd) | 1814 | int gateway_ports, int remote_fwd) |
1799 | { | 1815 | { |
1800 | int success, ch, sock, on = 1, ctype; | 1816 | Channel *c; |
1817 | int success, sock, on = 1, ctype; | ||
1801 | struct addrinfo hints, *ai, *aitop; | 1818 | struct addrinfo hints, *ai, *aitop; |
1802 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | 1819 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
1803 | const char *host; | 1820 | const char *host; |
@@ -1813,7 +1830,7 @@ channel_request_forwarding( | |||
1813 | ctype =SSH_CHANNEL_PORT_LISTENER; | 1830 | ctype =SSH_CHANNEL_PORT_LISTENER; |
1814 | } | 1831 | } |
1815 | 1832 | ||
1816 | if (strlen(host) > sizeof(channels[0].path) - 1) { | 1833 | if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { |
1817 | error("Forward host name too long."); | 1834 | error("Forward host name too long."); |
1818 | return success; | 1835 | return success; |
1819 | } | 1836 | } |
@@ -1874,12 +1891,17 @@ channel_request_forwarding( | |||
1874 | continue; | 1891 | continue; |
1875 | } | 1892 | } |
1876 | /* Allocate a channel number for the socket. */ | 1893 | /* Allocate a channel number for the socket. */ |
1877 | ch = channel_new("port listener", ctype, sock, sock, -1, | 1894 | c = channel_new("port listener", ctype, sock, sock, -1, |
1878 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, | 1895 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
1879 | 0, xstrdup("port listener"), 1); | 1896 | 0, xstrdup("port listener"), 1); |
1880 | strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); | 1897 | if (c == NULL) { |
1881 | channels[ch].host_port = port_to_connect; | 1898 | error("channel_request_forwarding: channel_new failed"); |
1882 | channels[ch].listening_port = listen_port; | 1899 | close(sock); |
1900 | continue; | ||
1901 | } | ||
1902 | strlcpy(c->path, host, sizeof(c->path)); | ||
1903 | c->host_port = port_to_connect; | ||
1904 | c->listening_port = listen_port; | ||
1883 | success = 1; | 1905 | success = 1; |
1884 | } | 1906 | } |
1885 | if (success == 0) | 1907 | if (success == 0) |
@@ -2116,11 +2138,12 @@ channel_connect_to(const char *host, u_short port) | |||
2116 | void | 2138 | void |
2117 | channel_input_port_open(int type, int plen, void *ctxt) | 2139 | channel_input_port_open(int type, int plen, void *ctxt) |
2118 | { | 2140 | { |
2141 | Channel *c = NULL; | ||
2119 | u_short host_port; | 2142 | u_short host_port; |
2120 | char *host, *originator_string; | 2143 | char *host, *originator_string; |
2121 | int remote_channel, sock = -1, newch; | 2144 | int remote_id, sock = -1; |
2122 | 2145 | ||
2123 | remote_channel = packet_get_int(); | 2146 | remote_id = packet_get_int(); |
2124 | host = packet_get_string(NULL); | 2147 | host = packet_get_string(NULL); |
2125 | host_port = packet_get_int(); | 2148 | host_port = packet_get_int(); |
2126 | 2149 | ||
@@ -2132,20 +2155,26 @@ channel_input_port_open(int type, int plen, void *ctxt) | |||
2132 | packet_done(); | 2155 | packet_done(); |
2133 | sock = channel_connect_to(host, host_port); | 2156 | sock = channel_connect_to(host, host_port); |
2134 | if (sock != -1) { | 2157 | if (sock != -1) { |
2135 | newch = channel_allocate(SSH_CHANNEL_CONNECTING, | 2158 | c = channel_new("connected socket", |
2136 | sock, originator_string); | 2159 | SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, |
2137 | channels[newch].remote_id = remote_channel; | 2160 | originator_string, 1); |
2138 | 2161 | if (c == NULL) { | |
2162 | error("channel_input_port_open: channel_new failed"); | ||
2163 | close(sock); | ||
2164 | } else { | ||
2165 | c->remote_id = remote_id; | ||
2166 | } | ||
2167 | } | ||
2168 | if (c == NULL) { | ||
2169 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
2170 | packet_put_int(remote_id); | ||
2171 | } else { | ||
2139 | /*XXX delay answer? */ | 2172 | /*XXX delay answer? */ |
2140 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | 2173 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
2141 | packet_put_int(remote_channel); | 2174 | packet_put_int(remote_id); |
2142 | packet_put_int(newch); | 2175 | packet_put_int(c->self); |
2143 | packet_send(); | ||
2144 | } else { | ||
2145 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
2146 | packet_put_int(remote_channel); | ||
2147 | packet_send(); | ||
2148 | } | 2176 | } |
2177 | packet_send(); | ||
2149 | xfree(host); | 2178 | xfree(host); |
2150 | } | 2179 | } |
2151 | 2180 | ||
@@ -2430,46 +2459,45 @@ x11_connect_display(void) | |||
2430 | void | 2459 | void |
2431 | x11_input_open(int type, int plen, void *ctxt) | 2460 | x11_input_open(int type, int plen, void *ctxt) |
2432 | { | 2461 | { |
2433 | int remote_channel, sock = 0, newch; | 2462 | Channel *c = NULL; |
2463 | int remote_id, sock = 0; | ||
2434 | char *remote_host; | 2464 | char *remote_host; |
2435 | u_int remote_len; | ||
2436 | 2465 | ||
2437 | /* Get remote channel number. */ | 2466 | debug("Received X11 open request."); |
2438 | remote_channel = packet_get_int(); | ||
2439 | 2467 | ||
2440 | /* Get remote originator name. */ | 2468 | remote_id = packet_get_int(); |
2441 | if (have_hostname_in_open) { | 2469 | if (have_hostname_in_open) { |
2442 | remote_host = packet_get_string(&remote_len); | 2470 | remote_host = packet_get_string(NULL); |
2443 | remote_len += 4; | ||
2444 | } else { | 2471 | } else { |
2445 | remote_host = xstrdup("unknown (remote did not supply name)"); | 2472 | remote_host = xstrdup("unknown (remote did not supply name)"); |
2446 | remote_len = 0; | ||
2447 | } | 2473 | } |
2448 | 2474 | packet_done(); | |
2449 | debug("Received X11 open request."); | ||
2450 | packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN); | ||
2451 | 2475 | ||
2452 | /* Obtain a connection to the real X display. */ | 2476 | /* Obtain a connection to the real X display. */ |
2453 | sock = x11_connect_display(); | 2477 | sock = x11_connect_display(); |
2454 | if (sock == -1) { | 2478 | if (sock != -1) { |
2479 | /* Allocate a channel for this connection. */ | ||
2480 | c = channel_new("connected x11 socket", | ||
2481 | SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0, | ||
2482 | remote_host, 1); | ||
2483 | if (c == NULL) { | ||
2484 | error("x11_input_open: channel_new failed"); | ||
2485 | close(sock); | ||
2486 | } else { | ||
2487 | c->remote_id = remote_id; | ||
2488 | } | ||
2489 | } | ||
2490 | if (c == NULL) { | ||
2455 | /* Send refusal to the remote host. */ | 2491 | /* Send refusal to the remote host. */ |
2456 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | 2492 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
2457 | packet_put_int(remote_channel); | 2493 | packet_put_int(remote_id); |
2458 | packet_send(); | ||
2459 | } else { | 2494 | } else { |
2460 | /* Allocate a channel for this connection. */ | ||
2461 | newch = channel_allocate( | ||
2462 | (x11_saved_proto == NULL) ? | ||
2463 | SSH_CHANNEL_OPEN : SSH_CHANNEL_X11_OPEN, | ||
2464 | sock, remote_host); | ||
2465 | channels[newch].remote_id = remote_channel; | ||
2466 | |||
2467 | /* Send a confirmation to the remote host. */ | 2495 | /* Send a confirmation to the remote host. */ |
2468 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | 2496 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
2469 | packet_put_int(remote_channel); | 2497 | packet_put_int(remote_id); |
2470 | packet_put_int(newch); | 2498 | packet_put_int(c->self); |
2471 | packet_send(); | ||
2472 | } | 2499 | } |
2500 | packet_send(); | ||
2473 | } | 2501 | } |
2474 | 2502 | ||
2475 | /* dummy protocol handler that denies SSH-1 requests (agent/x11) */ | 2503 | /* dummy protocol handler that denies SSH-1 requests (agent/x11) */ |
@@ -2602,7 +2630,8 @@ cleanup_socket(void) | |||
2602 | int | 2630 | int |
2603 | auth_input_request_forwarding(struct passwd * pw) | 2631 | auth_input_request_forwarding(struct passwd * pw) |
2604 | { | 2632 | { |
2605 | int sock, newch; | 2633 | Channel *nc; |
2634 | int sock; | ||
2606 | struct sockaddr_un sunaddr; | 2635 | struct sockaddr_un sunaddr; |
2607 | 2636 | ||
2608 | if (auth_get_socket_name() != NULL) | 2637 | if (auth_get_socket_name() != NULL) |
@@ -2657,13 +2686,16 @@ auth_input_request_forwarding(struct passwd * pw) | |||
2657 | packet_disconnect("listen: %.100s", strerror(errno)); | 2686 | packet_disconnect("listen: %.100s", strerror(errno)); |
2658 | 2687 | ||
2659 | /* Allocate a channel for the authentication agent socket. */ | 2688 | /* Allocate a channel for the authentication agent socket. */ |
2660 | newch = channel_new("auth socket", | 2689 | nc = channel_new("auth socket", |
2661 | SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, | 2690 | SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, |
2662 | CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, | 2691 | CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, |
2663 | 0, xstrdup("auth socket"), 1); | 2692 | 0, xstrdup("auth socket"), 1); |
2664 | 2693 | if (nc == NULL) { | |
2665 | strlcpy(channels[newch].path, channel_forwarded_auth_socket_name, | 2694 | error("auth_input_request_forwarding: channel_new failed"); |
2666 | sizeof(channels[newch].path)); | 2695 | close(sock); |
2696 | return 0; | ||
2697 | } | ||
2698 | strlcpy(nc->path, channel_forwarded_auth_socket_name, sizeof(nc->path)); | ||
2667 | return 1; | 2699 | return 1; |
2668 | } | 2700 | } |
2669 | 2701 | ||
@@ -2672,13 +2704,14 @@ auth_input_request_forwarding(struct passwd * pw) | |||
2672 | void | 2704 | void |
2673 | auth_input_open_request(int type, int plen, void *ctxt) | 2705 | auth_input_open_request(int type, int plen, void *ctxt) |
2674 | { | 2706 | { |
2675 | int remch, sock, newch; | 2707 | Channel *c = NULL; |
2708 | int remote_id, sock; | ||
2676 | char *dummyname; | 2709 | char *dummyname; |
2677 | 2710 | ||
2678 | packet_integrity_check(plen, 4, type); | 2711 | packet_integrity_check(plen, 4, type); |
2679 | 2712 | ||
2680 | /* Read the remote channel number from the message. */ | 2713 | /* Read the remote channel number from the message. */ |
2681 | remch = packet_get_int(); | 2714 | remote_id = packet_get_int(); |
2682 | 2715 | ||
2683 | /* | 2716 | /* |
2684 | * Get a connection to the local authentication agent (this may again | 2717 | * Get a connection to the local authentication agent (this may again |
@@ -2692,28 +2725,26 @@ auth_input_open_request(int type, int plen, void *ctxt) | |||
2692 | * because authentication forwarding is only enabled if we have an | 2725 | * because authentication forwarding is only enabled if we have an |
2693 | * agent. | 2726 | * agent. |
2694 | */ | 2727 | */ |
2695 | if (sock < 0) { | 2728 | if (sock >= 0) { |
2729 | dummyname = xstrdup("authentication agent connection"); | ||
2730 | c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, -1, 0, 0, 0, dummyname, 1); | ||
2731 | if (c == NULL) { | ||
2732 | error("auth_input_open_request: channel_new failed"); | ||
2733 | close(sock); | ||
2734 | } else { | ||
2735 | c->remote_id = remote_id; | ||
2736 | } | ||
2737 | } | ||
2738 | if (c == NULL) { | ||
2696 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | 2739 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
2697 | packet_put_int(remch); | 2740 | packet_put_int(remote_id); |
2698 | packet_send(); | 2741 | } else { |
2699 | return; | 2742 | /* Send a confirmation to the remote host. */ |
2743 | debug("Forwarding authentication connection."); | ||
2744 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | ||
2745 | packet_put_int(remote_id); | ||
2746 | packet_put_int(c->self); | ||
2700 | } | 2747 | } |
2701 | debug("Forwarding authentication connection."); | ||
2702 | |||
2703 | /* | ||
2704 | * Dummy host name. This will be freed when the channel is freed; it | ||
2705 | * will still be valid in the packet_put_string below since the | ||
2706 | * channel cannot yet be freed at that point. | ||
2707 | */ | ||
2708 | dummyname = xstrdup("authentication agent connection"); | ||
2709 | |||
2710 | newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname); | ||
2711 | channels[newch].remote_id = remch; | ||
2712 | |||
2713 | /* Send a confirmation to the remote host. */ | ||
2714 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | ||
2715 | packet_put_int(remch); | ||
2716 | packet_put_int(newch); | ||
2717 | packet_send(); | 2748 | packet_send(); |
2718 | } | 2749 | } |
2719 | 2750 | ||