1 /*
2 * ux_x11.c: fetch local auth data for X forwarding.
3 */
4
5 #include <ctype.h>
6 #include <unistd.h>
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12
13 #include "putty.h"
14 #include "ssh.h"
15 #include "network.h"
16
platform_get_x11_auth(struct X11Display * disp,Conf * conf)17 void platform_get_x11_auth(struct X11Display *disp, Conf *conf)
18 {
19 char *xauthfile;
20 bool needs_free;
21
22 /*
23 * Find the .Xauthority file.
24 */
25 needs_free = false;
26 xauthfile = getenv("XAUTHORITY");
27 if (!xauthfile) {
28 xauthfile = getenv("HOME");
29 if (xauthfile) {
30 xauthfile = dupcat(xauthfile, "/.Xauthority");
31 needs_free = true;
32 }
33 }
34
35 if (xauthfile) {
36 x11_get_auth_from_authfile(disp, xauthfile);
37 if (needs_free)
38 sfree(xauthfile);
39 }
40 }
41
42 const bool platform_uses_x11_unix_by_default = true;
43
platform_make_x11_server(Plug * plug,const char * progname,int mindisp,const char * screen_number_suffix,ptrlen authproto,ptrlen authdata,Socket ** sockets,Conf * conf)44 int platform_make_x11_server(Plug *plug, const char *progname, int mindisp,
45 const char *screen_number_suffix,
46 ptrlen authproto, ptrlen authdata,
47 Socket **sockets, Conf *conf)
48 {
49 char *tmpdir;
50 char *authfilename = NULL;
51 strbuf *authfiledata = NULL;
52 char *unix_path = NULL;
53
54 SockAddr *a_tcp = NULL, *a_unix = NULL;
55
56 int authfd;
57 FILE *authfp;
58
59 int displayno;
60
61 authfiledata = strbuf_new_nm();
62
63 int nsockets = 0;
64
65 /*
66 * Look for a free TCP port to run our server on.
67 */
68 for (displayno = mindisp;; displayno++) {
69 const char *err;
70 int tcp_port = displayno + 6000;
71 int addrtype = ADDRTYPE_IPV4;
72
73 sockets[nsockets] = new_listener(
74 NULL, tcp_port, plug, false, conf, addrtype);
75
76 err = sk_socket_error(sockets[nsockets]);
77 if (!err) {
78 char *hostname = get_hostname();
79 if (hostname) {
80 char *canonicalname = NULL;
81 a_tcp = sk_namelookup(hostname, &canonicalname, addrtype);
82 sfree(canonicalname);
83 }
84 sfree(hostname);
85 nsockets++;
86 break; /* success! */
87 } else {
88 sk_close(sockets[nsockets]);
89 }
90
91 if (!strcmp(err, strerror(EADDRINUSE))) /* yuck! */
92 goto out;
93 }
94
95 if (a_tcp) {
96 x11_format_auth_for_authfile(
97 BinarySink_UPCAST(authfiledata),
98 a_tcp, displayno, authproto, authdata);
99 }
100
101 /*
102 * Try to establish the Unix-domain analogue. That may or may not
103 * work - file permissions in /tmp may prevent it, for example -
104 * but it's worth a try, and we don't consider it a fatal error if
105 * it doesn't work.
106 */
107 unix_path = dupprintf("/tmp/.X11-unix/X%d", displayno);
108 a_unix = unix_sock_addr(unix_path);
109
110 sockets[nsockets] = new_unix_listener(a_unix, plug);
111 if (!sk_socket_error(sockets[nsockets])) {
112 x11_format_auth_for_authfile(
113 BinarySink_UPCAST(authfiledata),
114 a_unix, displayno, authproto, authdata);
115 nsockets++;
116 } else {
117 sk_close(sockets[nsockets]);
118 sfree(unix_path);
119 unix_path = NULL;
120 }
121
122 /*
123 * Decide where the authority data will be written.
124 */
125
126 tmpdir = getenv("TMPDIR");
127 if (!tmpdir || !*tmpdir)
128 tmpdir = "/tmp";
129
130 authfilename = dupcat(tmpdir, "/", progname, "-Xauthority-XXXXXX");
131
132 {
133 int oldumask = umask(077);
134 authfd = mkstemp(authfilename);
135 umask(oldumask);
136 }
137 if (authfd < 0) {
138 while (nsockets-- > 0)
139 sk_close(sockets[nsockets]);
140 goto out;
141 }
142
143 /*
144 * Spawn a subprocess which will try to reliably delete our
145 * auth file when we terminate, in case we die unexpectedly.
146 */
147 {
148 int cleanup_pipe[2];
149 pid_t pid;
150
151 /* Don't worry if pipe or fork fails; it's not _that_ critical. */
152 if (!pipe(cleanup_pipe)) {
153 if ((pid = fork()) == 0) {
154 int buf[1024];
155 /*
156 * Our parent process holds the writing end of
157 * this pipe, and writes nothing to it. Hence,
158 * we expect read() to return EOF as soon as
159 * that process terminates.
160 */
161
162 close(0);
163 close(1);
164 close(2);
165
166 setpgid(0, 0);
167 close(cleanup_pipe[1]);
168 close(authfd);
169 while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0);
170 unlink(authfilename);
171 if (unix_path)
172 unlink(unix_path);
173 _exit(0);
174 } else if (pid < 0) {
175 close(cleanup_pipe[0]);
176 close(cleanup_pipe[1]);
177 } else {
178 close(cleanup_pipe[0]);
179 cloexec(cleanup_pipe[1]);
180 }
181 }
182 }
183
184 authfp = fdopen(authfd, "wb");
185 fwrite(authfiledata->u, 1, authfiledata->len, authfp);
186 fclose(authfp);
187
188 {
189 char *display = dupprintf(":%d%s", displayno, screen_number_suffix);
190 conf_set_str_str(conf, CONF_environmt, "DISPLAY", display);
191 sfree(display);
192 }
193 conf_set_str_str(conf, CONF_environmt, "XAUTHORITY", authfilename);
194
195 /*
196 * FIXME: return at least the DISPLAY and XAUTHORITY env settings,
197 * and perhaps also the display number
198 */
199
200 out:
201 if (a_tcp)
202 sk_addr_free(a_tcp);
203 /* a_unix doesn't need freeing, because new_unix_listener took it over */
204 sfree(authfilename);
205 strbuf_free(authfiledata);
206 sfree(unix_path);
207 return nsockets;
208 }
209