diff options
author | Colin Watson <cjwatson@debian.org> | 2010-01-01 23:53:30 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2010-01-01 23:53:30 +0000 |
commit | df03186a4f9e0c2ece398b5c0571cb6263d7a752 (patch) | |
tree | 1aab079441dff9615274769b19f2d734ddf508dd /channels.c | |
parent | 6ad6994c288662fca6949f42bf91fec2aff00bca (diff) | |
parent | 99b402ea4c8457b0a3cafff37f5b3410a8dc6476 (diff) |
* New upstream release (closes: #536182). Yes, I know 5.3p1 has been out
for a while, but there's no GSSAPI patch available for it yet.
- Change the default cipher order to prefer the AES CTR modes and the
revised "arcfour256" mode to CBC mode ciphers that are susceptible to
CPNI-957037 "Plaintext Recovery Attack Against SSH".
- Add countermeasures to mitigate CPNI-957037-style attacks against the
SSH protocol's use of CBC-mode ciphers. Upon detection of an invalid
packet length or Message Authentication Code, ssh/sshd will continue
reading up to the maximum supported packet length rather than
immediately terminating the connection. This eliminates most of the
known differences in behaviour that leaked information about the
plaintext of injected data which formed the basis of this attack
(closes: #506115, LP: #379329).
- ForceCommand directive now accepts commandline arguments for the
internal-sftp server (closes: #524423, LP: #362511).
- Add AllowAgentForwarding to available Match keywords list (closes:
#540623).
- Make ssh(1) send the correct channel number for
SSH2_MSG_CHANNEL_SUCCESS and SSH2_MSG_CHANNEL_FAILURE messages to
avoid triggering 'Non-public channel' error messages on sshd(8) in
openssh-5.1.
- Avoid printing 'Non-public channel' warnings in sshd(8), since the
ssh(1) has sent incorrect channel numbers since ~2004 (this reverts a
behaviour introduced in openssh-5.1; closes: #496017).
* Update to GSSAPI patch from
http://www.sxw.org.uk/computing/patches/openssh-5.2p1-gsskex-all-20090726.patch,
including cascading credentials support (LP: #416958).
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 187 |
1 files changed, 149 insertions, 38 deletions
diff --git a/channels.c b/channels.c index c293eadf1..f0b8aa7d0 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.286 2008/07/16 11:52:19 djm Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.295 2009/02/12 03:00:56 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -296,6 +296,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
296 | buffer_init(&c->input); | 296 | buffer_init(&c->input); |
297 | buffer_init(&c->output); | 297 | buffer_init(&c->output); |
298 | buffer_init(&c->extended); | 298 | buffer_init(&c->extended); |
299 | c->path = NULL; | ||
299 | c->ostate = CHAN_OUTPUT_OPEN; | 300 | c->ostate = CHAN_OUTPUT_OPEN; |
300 | c->istate = CHAN_INPUT_OPEN; | 301 | c->istate = CHAN_INPUT_OPEN; |
301 | c->flags = 0; | 302 | c->flags = 0; |
@@ -402,6 +403,10 @@ channel_free(Channel *c) | |||
402 | xfree(c->remote_name); | 403 | xfree(c->remote_name); |
403 | c->remote_name = NULL; | 404 | c->remote_name = NULL; |
404 | } | 405 | } |
406 | if (c->path) { | ||
407 | xfree(c->path); | ||
408 | c->path = NULL; | ||
409 | } | ||
405 | while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { | 410 | while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { |
406 | if (cc->abandon_cb != NULL) | 411 | if (cc->abandon_cb != NULL) |
407 | cc->abandon_cb(c, cc->ctx); | 412 | cc->abandon_cb(c, cc->ctx); |
@@ -691,7 +696,7 @@ channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx) | |||
691 | Channel *c = channel_lookup(id); | 696 | Channel *c = channel_lookup(id); |
692 | 697 | ||
693 | if (c == NULL) { | 698 | if (c == NULL) { |
694 | logit("channel_register_open_comfirm: %d: bad id", id); | 699 | logit("channel_register_open_confirm: %d: bad id", id); |
695 | return; | 700 | return; |
696 | } | 701 | } |
697 | c->open_confirm = fn; | 702 | c->open_confirm = fn; |
@@ -980,7 +985,7 @@ static int | |||
980 | channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | 985 | channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) |
981 | { | 986 | { |
982 | char *p, *host; | 987 | char *p, *host; |
983 | u_int len, have, i, found; | 988 | u_int len, have, i, found, need; |
984 | char username[256]; | 989 | char username[256]; |
985 | struct { | 990 | struct { |
986 | u_int8_t version; | 991 | u_int8_t version; |
@@ -996,10 +1001,20 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
996 | if (have < len) | 1001 | if (have < len) |
997 | return 0; | 1002 | return 0; |
998 | p = buffer_ptr(&c->input); | 1003 | p = buffer_ptr(&c->input); |
1004 | |||
1005 | need = 1; | ||
1006 | /* SOCKS4A uses an invalid IP address 0.0.0.x */ | ||
1007 | if (p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] != 0) { | ||
1008 | debug2("channel %d: socks4a request", c->self); | ||
1009 | /* ... and needs an extra string (the hostname) */ | ||
1010 | need = 2; | ||
1011 | } | ||
1012 | /* Check for terminating NUL on the string(s) */ | ||
999 | for (found = 0, i = len; i < have; i++) { | 1013 | for (found = 0, i = len; i < have; i++) { |
1000 | if (p[i] == '\0') { | 1014 | if (p[i] == '\0') { |
1001 | found = 1; | 1015 | found++; |
1002 | break; | 1016 | if (found == need) |
1017 | break; | ||
1003 | } | 1018 | } |
1004 | if (i > 1024) { | 1019 | if (i > 1024) { |
1005 | /* the peer is probably sending garbage */ | 1020 | /* the peer is probably sending garbage */ |
@@ -1008,7 +1023,7 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
1008 | return -1; | 1023 | return -1; |
1009 | } | 1024 | } |
1010 | } | 1025 | } |
1011 | if (!found) | 1026 | if (found < need) |
1012 | return 0; | 1027 | return 0; |
1013 | buffer_get(&c->input, (char *)&s4_req.version, 1); | 1028 | buffer_get(&c->input, (char *)&s4_req.version, 1); |
1014 | buffer_get(&c->input, (char *)&s4_req.command, 1); | 1029 | buffer_get(&c->input, (char *)&s4_req.command, 1); |
@@ -1018,23 +1033,46 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
1018 | p = buffer_ptr(&c->input); | 1033 | p = buffer_ptr(&c->input); |
1019 | len = strlen(p); | 1034 | len = strlen(p); |
1020 | debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); | 1035 | debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); |
1036 | len++; /* trailing '\0' */ | ||
1021 | if (len > have) | 1037 | if (len > have) |
1022 | fatal("channel %d: decode socks4: len %d > have %d", | 1038 | fatal("channel %d: decode socks4: len %d > have %d", |
1023 | c->self, len, have); | 1039 | c->self, len, have); |
1024 | strlcpy(username, p, sizeof(username)); | 1040 | strlcpy(username, p, sizeof(username)); |
1025 | buffer_consume(&c->input, len); | 1041 | buffer_consume(&c->input, len); |
1026 | buffer_consume(&c->input, 1); /* trailing '\0' */ | ||
1027 | 1042 | ||
1028 | host = inet_ntoa(s4_req.dest_addr); | 1043 | if (c->path != NULL) { |
1029 | strlcpy(c->path, host, sizeof(c->path)); | 1044 | xfree(c->path); |
1045 | c->path = NULL; | ||
1046 | } | ||
1047 | if (need == 1) { /* SOCKS4: one string */ | ||
1048 | host = inet_ntoa(s4_req.dest_addr); | ||
1049 | c->path = xstrdup(host); | ||
1050 | } else { /* SOCKS4A: two strings */ | ||
1051 | have = buffer_len(&c->input); | ||
1052 | p = buffer_ptr(&c->input); | ||
1053 | len = strlen(p); | ||
1054 | debug2("channel %d: decode socks4a: host %s/%d", | ||
1055 | c->self, p, len); | ||
1056 | len++; /* trailing '\0' */ | ||
1057 | if (len > have) | ||
1058 | fatal("channel %d: decode socks4a: len %d > have %d", | ||
1059 | c->self, len, have); | ||
1060 | if (len > NI_MAXHOST) { | ||
1061 | error("channel %d: hostname \"%.100s\" too long", | ||
1062 | c->self, p); | ||
1063 | return -1; | ||
1064 | } | ||
1065 | c->path = xstrdup(p); | ||
1066 | buffer_consume(&c->input, len); | ||
1067 | } | ||
1030 | c->host_port = ntohs(s4_req.dest_port); | 1068 | c->host_port = ntohs(s4_req.dest_port); |
1031 | 1069 | ||
1032 | debug2("channel %d: dynamic request: socks4 host %s port %u command %u", | 1070 | debug2("channel %d: dynamic request: socks4 host %s port %u command %u", |
1033 | c->self, host, c->host_port, s4_req.command); | 1071 | c->self, c->path, c->host_port, s4_req.command); |
1034 | 1072 | ||
1035 | if (s4_req.command != 1) { | 1073 | if (s4_req.command != 1) { |
1036 | debug("channel %d: cannot handle: socks4 cn %d", | 1074 | debug("channel %d: cannot handle: %s cn %d", |
1037 | c->self, s4_req.command); | 1075 | c->self, need == 1 ? "SOCKS4" : "SOCKS4A", s4_req.command); |
1038 | return -1; | 1076 | return -1; |
1039 | } | 1077 | } |
1040 | s4_rsp.version = 0; /* vn: 0 for reply */ | 1078 | s4_rsp.version = 0; /* vn: 0 for reply */ |
@@ -1065,7 +1103,7 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) | |||
1065 | u_int8_t atyp; | 1103 | u_int8_t atyp; |
1066 | } s5_req, s5_rsp; | 1104 | } s5_req, s5_rsp; |
1067 | u_int16_t dest_port; | 1105 | u_int16_t dest_port; |
1068 | u_char *p, dest_addr[255+1]; | 1106 | u_char *p, dest_addr[255+1], ntop[INET6_ADDRSTRLEN]; |
1069 | u_int have, need, i, found, nmethods, addrlen, af; | 1107 | u_int have, need, i, found, nmethods, addrlen, af; |
1070 | 1108 | ||
1071 | debug2("channel %d: decode socks5", c->self); | 1109 | debug2("channel %d: decode socks5", c->self); |
@@ -1138,10 +1176,22 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) | |||
1138 | buffer_get(&c->input, (char *)&dest_addr, addrlen); | 1176 | buffer_get(&c->input, (char *)&dest_addr, addrlen); |
1139 | buffer_get(&c->input, (char *)&dest_port, 2); | 1177 | buffer_get(&c->input, (char *)&dest_port, 2); |
1140 | dest_addr[addrlen] = '\0'; | 1178 | dest_addr[addrlen] = '\0'; |
1141 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) | 1179 | if (c->path != NULL) { |
1142 | strlcpy(c->path, (char *)dest_addr, sizeof(c->path)); | 1180 | xfree(c->path); |
1143 | else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL) | 1181 | c->path = NULL; |
1144 | return -1; | 1182 | } |
1183 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) { | ||
1184 | if (addrlen >= NI_MAXHOST) { | ||
1185 | error("channel %d: dynamic request: socks5 hostname " | ||
1186 | "\"%.100s\" too long", c->self, dest_addr); | ||
1187 | return -1; | ||
1188 | } | ||
1189 | c->path = xstrdup(dest_addr); | ||
1190 | } else { | ||
1191 | if (inet_ntop(af, dest_addr, ntop, sizeof(ntop)) == NULL) | ||
1192 | return -1; | ||
1193 | c->path = xstrdup(ntop); | ||
1194 | } | ||
1145 | c->host_port = ntohs(dest_port); | 1195 | c->host_port = ntohs(dest_port); |
1146 | 1196 | ||
1147 | debug2("channel %d: dynamic request: socks5 host %s port %u command %u", | 1197 | debug2("channel %d: dynamic request: socks5 host %s port %u command %u", |
@@ -1370,7 +1420,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1370 | c->local_window_max, c->local_maxpacket, 0, rtype, 1); | 1420 | c->local_window_max, c->local_maxpacket, 0, rtype, 1); |
1371 | nc->listening_port = c->listening_port; | 1421 | nc->listening_port = c->listening_port; |
1372 | nc->host_port = c->host_port; | 1422 | nc->host_port = c->host_port; |
1373 | strlcpy(nc->path, c->path, sizeof(nc->path)); | 1423 | if (c->path != NULL) |
1424 | nc->path = xstrdup(c->path); | ||
1374 | 1425 | ||
1375 | if (nextstate == SSH_CHANNEL_DYNAMIC) { | 1426 | if (nextstate == SSH_CHANNEL_DYNAMIC) { |
1376 | /* | 1427 | /* |
@@ -2311,8 +2362,8 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt) | |||
2311 | xfree(lang); | 2362 | xfree(lang); |
2312 | } | 2363 | } |
2313 | packet_check_eom(); | 2364 | packet_check_eom(); |
2314 | /* Free the channel. This will also close the socket. */ | 2365 | /* Schedule the channel for cleanup/deletion. */ |
2315 | channel_free(c); | 2366 | chan_mark_dead(c); |
2316 | } | 2367 | } |
2317 | 2368 | ||
2318 | /* ARGSUSED */ | 2369 | /* ARGSUSED */ |
@@ -2377,18 +2428,18 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt) | |||
2377 | { | 2428 | { |
2378 | Channel *c; | 2429 | Channel *c; |
2379 | struct channel_confirm *cc; | 2430 | struct channel_confirm *cc; |
2380 | int remote_id; | 2431 | int id; |
2381 | 2432 | ||
2382 | /* Reset keepalive timeout */ | 2433 | /* Reset keepalive timeout */ |
2383 | keep_alive_timeouts = 0; | 2434 | keep_alive_timeouts = 0; |
2384 | 2435 | ||
2385 | remote_id = packet_get_int(); | 2436 | id = packet_get_int(); |
2386 | packet_check_eom(); | 2437 | packet_check_eom(); |
2387 | 2438 | ||
2388 | debug2("channel_input_confirm: type %d id %d", type, remote_id); | 2439 | debug2("channel_input_status_confirm: type %d id %d", type, id); |
2389 | 2440 | ||
2390 | if ((c = channel_lookup(remote_id)) == NULL) { | 2441 | if ((c = channel_lookup(id)) == NULL) { |
2391 | logit("channel_input_success_failure: %d: unknown", remote_id); | 2442 | logit("channel_input_status_confirm: %d: unknown", id); |
2392 | return; | 2443 | return; |
2393 | } | 2444 | } |
2394 | ; | 2445 | ; |
@@ -2409,7 +2460,8 @@ channel_set_af(int af) | |||
2409 | } | 2460 | } |
2410 | 2461 | ||
2411 | static int | 2462 | static int |
2412 | channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, | 2463 | channel_setup_fwd_listener(int type, const char *listen_addr, |
2464 | u_short listen_port, int *allocated_listen_port, | ||
2413 | const char *host_to_connect, u_short port_to_connect, int gateway_ports) | 2465 | const char *host_to_connect, u_short port_to_connect, int gateway_ports) |
2414 | { | 2466 | { |
2415 | Channel *c; | 2467 | Channel *c; |
@@ -2417,6 +2469,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por | |||
2417 | struct addrinfo hints, *ai, *aitop; | 2469 | struct addrinfo hints, *ai, *aitop; |
2418 | const char *host, *addr; | 2470 | const char *host, *addr; |
2419 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | 2471 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
2472 | in_port_t *lport_p; | ||
2420 | 2473 | ||
2421 | host = (type == SSH_CHANNEL_RPORT_LISTENER) ? | 2474 | host = (type == SSH_CHANNEL_RPORT_LISTENER) ? |
2422 | listen_addr : host_to_connect; | 2475 | listen_addr : host_to_connect; |
@@ -2426,7 +2479,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por | |||
2426 | error("No forward host name."); | 2479 | error("No forward host name."); |
2427 | return 0; | 2480 | return 0; |
2428 | } | 2481 | } |
2429 | if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { | 2482 | if (strlen(host) >= NI_MAXHOST) { |
2430 | error("Forward host name too long."); | 2483 | error("Forward host name too long."); |
2431 | return 0; | 2484 | return 0; |
2432 | } | 2485 | } |
@@ -2485,10 +2538,29 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por | |||
2485 | } | 2538 | } |
2486 | return 0; | 2539 | return 0; |
2487 | } | 2540 | } |
2488 | 2541 | if (allocated_listen_port != NULL) | |
2542 | *allocated_listen_port = 0; | ||
2489 | for (ai = aitop; ai; ai = ai->ai_next) { | 2543 | for (ai = aitop; ai; ai = ai->ai_next) { |
2490 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | 2544 | switch (ai->ai_family) { |
2545 | case AF_INET: | ||
2546 | lport_p = &((struct sockaddr_in *)ai->ai_addr)-> | ||
2547 | sin_port; | ||
2548 | break; | ||
2549 | case AF_INET6: | ||
2550 | lport_p = &((struct sockaddr_in6 *)ai->ai_addr)-> | ||
2551 | sin6_port; | ||
2552 | break; | ||
2553 | default: | ||
2491 | continue; | 2554 | continue; |
2555 | } | ||
2556 | /* | ||
2557 | * If allocating a port for -R forwards, then use the | ||
2558 | * same port for all address families. | ||
2559 | */ | ||
2560 | if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && | ||
2561 | allocated_listen_port != NULL && *allocated_listen_port > 0) | ||
2562 | *lport_p = htons(*allocated_listen_port); | ||
2563 | |||
2492 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), | 2564 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
2493 | strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { | 2565 | strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
2494 | error("channel_setup_fwd_listener: getnameinfo failed"); | 2566 | error("channel_setup_fwd_listener: getnameinfo failed"); |
@@ -2504,7 +2576,8 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por | |||
2504 | 2576 | ||
2505 | channel_set_reuseaddr(sock); | 2577 | channel_set_reuseaddr(sock); |
2506 | 2578 | ||
2507 | debug("Local forwarding listening on %s port %s.", ntop, strport); | 2579 | debug("Local forwarding listening on %s port %s.", |
2580 | ntop, strport); | ||
2508 | 2581 | ||
2509 | /* Bind the socket to the address. */ | 2582 | /* Bind the socket to the address. */ |
2510 | if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | 2583 | if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
@@ -2523,11 +2596,24 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por | |||
2523 | close(sock); | 2596 | close(sock); |
2524 | continue; | 2597 | continue; |
2525 | } | 2598 | } |
2599 | |||
2600 | /* | ||
2601 | * listen_port == 0 requests a dynamically allocated port - | ||
2602 | * record what we got. | ||
2603 | */ | ||
2604 | if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && | ||
2605 | allocated_listen_port != NULL && | ||
2606 | *allocated_listen_port == 0) { | ||
2607 | *allocated_listen_port = get_sock_port(sock, 1); | ||
2608 | debug("Allocated listen port %d", | ||
2609 | *allocated_listen_port); | ||
2610 | } | ||
2611 | |||
2526 | /* Allocate a channel number for the socket. */ | 2612 | /* Allocate a channel number for the socket. */ |
2527 | c = channel_new("port listener", type, sock, sock, -1, | 2613 | c = channel_new("port listener", type, sock, sock, -1, |
2528 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, | 2614 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
2529 | 0, "port listener", 1); | 2615 | 0, "port listener", 1); |
2530 | strlcpy(c->path, host, sizeof(c->path)); | 2616 | c->path = xstrdup(host); |
2531 | c->host_port = port_to_connect; | 2617 | c->host_port = port_to_connect; |
2532 | c->listening_port = listen_port; | 2618 | c->listening_port = listen_port; |
2533 | success = 1; | 2619 | success = 1; |
@@ -2549,8 +2635,7 @@ channel_cancel_rport_listener(const char *host, u_short port) | |||
2549 | Channel *c = channels[i]; | 2635 | Channel *c = channels[i]; |
2550 | 2636 | ||
2551 | if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && | 2637 | if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && |
2552 | strncmp(c->path, host, sizeof(c->path)) == 0 && | 2638 | strcmp(c->path, host) == 0 && c->listening_port == port) { |
2553 | c->listening_port == port) { | ||
2554 | debug2("%s: close channel %d", __func__, i); | 2639 | debug2("%s: close channel %d", __func__, i); |
2555 | channel_free(c); | 2640 | channel_free(c); |
2556 | found = 1; | 2641 | found = 1; |
@@ -2566,17 +2651,18 @@ channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, | |||
2566 | const char *host_to_connect, u_short port_to_connect, int gateway_ports) | 2651 | const char *host_to_connect, u_short port_to_connect, int gateway_ports) |
2567 | { | 2652 | { |
2568 | return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, | 2653 | return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, |
2569 | listen_host, listen_port, host_to_connect, port_to_connect, | 2654 | listen_host, listen_port, NULL, host_to_connect, port_to_connect, |
2570 | gateway_ports); | 2655 | gateway_ports); |
2571 | } | 2656 | } |
2572 | 2657 | ||
2573 | /* protocol v2 remote port fwd, used by sshd */ | 2658 | /* protocol v2 remote port fwd, used by sshd */ |
2574 | int | 2659 | int |
2575 | channel_setup_remote_fwd_listener(const char *listen_address, | 2660 | channel_setup_remote_fwd_listener(const char *listen_address, |
2576 | u_short listen_port, int gateway_ports) | 2661 | u_short listen_port, int *allocated_listen_port, int gateway_ports) |
2577 | { | 2662 | { |
2578 | return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, | 2663 | return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, |
2579 | listen_address, listen_port, NULL, 0, gateway_ports); | 2664 | listen_address, listen_port, allocated_listen_port, |
2665 | NULL, 0, gateway_ports); | ||
2580 | } | 2666 | } |
2581 | 2667 | ||
2582 | /* | 2668 | /* |
@@ -2791,10 +2877,16 @@ channel_print_adm_permitted_opens(void) | |||
2791 | { | 2877 | { |
2792 | int i; | 2878 | int i; |
2793 | 2879 | ||
2880 | printf("permitopen"); | ||
2881 | if (num_adm_permitted_opens == 0) { | ||
2882 | printf(" any\n"); | ||
2883 | return; | ||
2884 | } | ||
2794 | for (i = 0; i < num_adm_permitted_opens; i++) | 2885 | for (i = 0; i < num_adm_permitted_opens; i++) |
2795 | if (permitted_adm_opens[i].host_to_connect != NULL) | 2886 | if (permitted_adm_opens[i].host_to_connect != NULL) |
2796 | printf(" %s:%d", permitted_adm_opens[i].host_to_connect, | 2887 | printf(" %s:%d", permitted_adm_opens[i].host_to_connect, |
2797 | permitted_adm_opens[i].port_to_connect); | 2888 | permitted_adm_opens[i].port_to_connect); |
2889 | printf("\n"); | ||
2798 | } | 2890 | } |
2799 | 2891 | ||
2800 | /* Try to start non-blocking connect to next host in cctx list */ | 2892 | /* Try to start non-blocking connect to next host in cctx list */ |
@@ -3078,7 +3170,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, | |||
3078 | } | 3170 | } |
3079 | 3171 | ||
3080 | static int | 3172 | static int |
3081 | connect_local_xsocket(u_int dnr) | 3173 | connect_local_xsocket_path(const char *pathname) |
3082 | { | 3174 | { |
3083 | int sock; | 3175 | int sock; |
3084 | struct sockaddr_un addr; | 3176 | struct sockaddr_un addr; |
@@ -3088,7 +3180,7 @@ connect_local_xsocket(u_int dnr) | |||
3088 | error("socket: %.100s", strerror(errno)); | 3180 | error("socket: %.100s", strerror(errno)); |
3089 | memset(&addr, 0, sizeof(addr)); | 3181 | memset(&addr, 0, sizeof(addr)); |
3090 | addr.sun_family = AF_UNIX; | 3182 | addr.sun_family = AF_UNIX; |
3091 | snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr); | 3183 | strlcpy(addr.sun_path, pathname, sizeof addr.sun_path); |
3092 | if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) | 3184 | if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) |
3093 | return sock; | 3185 | return sock; |
3094 | close(sock); | 3186 | close(sock); |
@@ -3096,6 +3188,14 @@ connect_local_xsocket(u_int dnr) | |||
3096 | return -1; | 3188 | return -1; |
3097 | } | 3189 | } |
3098 | 3190 | ||
3191 | static int | ||
3192 | connect_local_xsocket(u_int dnr) | ||
3193 | { | ||
3194 | char buf[1024]; | ||
3195 | snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr); | ||
3196 | return connect_local_xsocket_path(buf); | ||
3197 | } | ||
3198 | |||
3099 | int | 3199 | int |
3100 | x11_connect_display(void) | 3200 | x11_connect_display(void) |
3101 | { | 3201 | { |
@@ -3117,6 +3217,17 @@ x11_connect_display(void) | |||
3117 | * connection to the real X server. | 3217 | * connection to the real X server. |
3118 | */ | 3218 | */ |
3119 | 3219 | ||
3220 | /* Check if the display is from launchd. */ | ||
3221 | #ifdef __APPLE__ | ||
3222 | if (strncmp(display, "/tmp/launch", 11) == 0) { | ||
3223 | sock = connect_local_xsocket_path(display); | ||
3224 | if (sock < 0) | ||
3225 | return -1; | ||
3226 | |||
3227 | /* OK, we now have a connection to the display. */ | ||
3228 | return sock; | ||
3229 | } | ||
3230 | #endif | ||
3120 | /* | 3231 | /* |
3121 | * Check if it is a unix domain socket. Unix domain displays are in | 3232 | * Check if it is a unix domain socket. Unix domain displays are in |
3122 | * one of the following formats: unix:d[.s], :d[.s], ::d[.s] | 3233 | * one of the following formats: unix:d[.s], :d[.s], ::d[.s] |