summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2010-01-01 23:53:30 +0000
committerColin Watson <cjwatson@debian.org>2010-01-01 23:53:30 +0000
commitdf03186a4f9e0c2ece398b5c0571cb6263d7a752 (patch)
tree1aab079441dff9615274769b19f2d734ddf508dd /channels.c
parent6ad6994c288662fca6949f42bf91fec2aff00bca (diff)
parent99b402ea4c8457b0a3cafff37f5b3410a8dc6476 (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.c187
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
980channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) 985channel_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
2411static int 2462static int
2412channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, 2463channel_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 */
2574int 2659int
2575channel_setup_remote_fwd_listener(const char *listen_address, 2660channel_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
3080static int 3172static int
3081connect_local_xsocket(u_int dnr) 3173connect_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
3191static int
3192connect_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
3099int 3199int
3100x11_connect_display(void) 3200x11_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]