2 * Functions to manage an X11Display structure, by creating one from
3 * an ordinary display name string, and freeing one.
13 #include "ssh/channel.h"
16 struct X11Display
*x11_setup_display(const char *display
, Conf
*conf
,
19 struct X11Display
*disp
= snew(struct X11Display
);
24 if (!display
|| !*display
) {
25 localcopy
= platform_get_x_display();
26 if (!localcopy
|| !*localcopy
) {
28 localcopy
= dupstr(":0"); /* plausible default for any platform */
31 localcopy
= dupstr(display
);
34 * Parse the display name.
36 * We expect this to have one of the following forms:
38 * - the standard X format which looks like
39 * [ [ protocol '/' ] host ] ':' displaynumber [ '.' screennumber ]
40 * (X11 also permits a double colon to indicate DECnet, but
41 * that's not our problem, thankfully!)
43 * - only seen in the wild on MacOS (so far): a pathname to a
44 * Unix-domain socket, which will typically and confusingly
45 * end in ":0", and which I'm currently distinguishing from
46 * the standard scheme by noting that it starts with '/'.
48 if (localcopy
[0] == '/') {
49 disp
->unixsocketpath
= localcopy
;
50 disp
->unixdomain
= true;
51 disp
->hostname
= NULL
;
52 disp
->displaynum
= -1;
56 char *colon
, *dot
, *slash
;
57 char *protocol
, *hostname
;
59 colon
= host_strrchr(localcopy
, ':');
61 *error_msg
= dupprintf("display name '%s' has no ':number'"
62 " suffix", localcopy
);
70 dot
= strchr(colon
, '.');
74 disp
->displaynum
= atoi(colon
);
76 disp
->screennum
= atoi(dot
);
82 if (colon
> localcopy
) {
83 slash
= strchr(localcopy
, '/');
91 disp
->hostname
= *hostname
? dupstr(hostname
) : NULL
;
94 disp
->unixdomain
= (!strcmp(protocol
, "local") ||
95 !strcmp(protocol
, "unix"));
96 else if (!*hostname
|| !strcmp(hostname
, "unix"))
97 disp
->unixdomain
= platform_uses_x11_unix_by_default
;
99 disp
->unixdomain
= false;
101 if (!disp
->hostname
&& !disp
->unixdomain
)
102 disp
->hostname
= dupstr("localhost");
104 disp
->unixsocketpath
= NULL
;
111 * Look up the display hostname, if we need to.
113 if (!disp
->unixdomain
) {
116 disp
->port
= 6000 + disp
->displaynum
;
117 disp
->addr
= name_lookup(disp
->hostname
, disp
->port
,
118 &disp
->realhost
, conf
, ADDRTYPE_UNSPEC
,
121 if ((err
= sk_addr_error(disp
->addr
)) != NULL
) {
122 *error_msg
= dupprintf("unable to resolve host name '%s' in "
123 "display name", disp
->hostname
);
125 sk_addr_free(disp
->addr
);
126 sfree(disp
->hostname
);
127 sfree(disp
->unixsocketpath
);
134 * Try upgrading an IP-style localhost display to a Unix-socket
135 * display (as the standard X connection libraries do).
137 if (!disp
->unixdomain
&& sk_address_is_local(disp
->addr
)) {
138 SockAddr
*ux
= platform_get_x11_unix_address(NULL
, disp
->displaynum
);
139 const char *err
= sk_addr_error(ux
);
141 /* Create trial connection to see if there is a useful Unix-domain
143 Socket
*s
= sk_new(sk_addr_dup(ux
), 0, false, false,
144 false, false, nullplug
);
145 err
= sk_socket_error(s
);
151 sk_addr_free(disp
->addr
);
152 disp
->unixdomain
= true;
154 /* Fill in the rest in a moment */
158 if (disp
->unixdomain
) {
160 disp
->addr
= platform_get_x11_unix_address(disp
->unixsocketpath
,
162 if (disp
->unixsocketpath
)
163 disp
->realhost
= dupstr(disp
->unixsocketpath
);
165 disp
->realhost
= dupprintf("unix:%d", disp
->displaynum
);
170 * Fetch the local authorisation details.
172 disp
->localauthproto
= X11_NO_AUTH
;
173 disp
->localauthdata
= NULL
;
174 disp
->localauthdatalen
= 0;
175 platform_get_x11_auth(disp
, conf
);
180 void x11_free_display(struct X11Display
*disp
)
182 sfree(disp
->hostname
);
183 sfree(disp
->unixsocketpath
);
184 if (disp
->localauthdata
)
185 smemclr(disp
->localauthdata
, disp
->localauthdatalen
);
186 sfree(disp
->localauthdata
);
187 sk_addr_free(disp
->addr
);