diff options
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] |