mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-30 19:12:48 -05:00
Server prep: routine to create a local X display.
This will be used for the server side of X forwarding. It wraps up the mechanics of listening on the right TCP port and (if possible) the associated AF_UNIX socket, and also creates an appropriate X authority file containing authorisation data provided by its caller. Like the new platform_create_agent_socket, this function spawns a watchdog subprocess to clean up the mess afterwards, in the hope of at least _most_ of the time not leaving old sockets and authority files lying around /tmp,
This commit is contained in:
165
unix/ux_x11.c
165
unix/ux_x11.c
@ -7,6 +7,8 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
@ -38,3 +40,166 @@ void platform_get_x11_auth(struct X11Display *disp, Conf *conf)
|
||||
}
|
||||
|
||||
const int platform_uses_x11_unix_by_default = TRUE;
|
||||
|
||||
int platform_make_x11_server(Plug *plug, const char *progname, int mindisp,
|
||||
const char *screen_number_suffix,
|
||||
ptrlen authproto, ptrlen authdata,
|
||||
Socket **sockets, Conf *conf)
|
||||
{
|
||||
char *tmpdir;
|
||||
char *authfilename = NULL;
|
||||
strbuf *authfiledata = NULL;
|
||||
char *unix_path = NULL;
|
||||
|
||||
SockAddr *a_tcp = NULL, *a_unix = NULL;
|
||||
|
||||
int authfd;
|
||||
FILE *authfp;
|
||||
|
||||
int displayno;
|
||||
|
||||
authfiledata = strbuf_new();
|
||||
|
||||
int nsockets = 0;
|
||||
|
||||
/*
|
||||
* Look for a free TCP port to run our server on.
|
||||
*/
|
||||
for (displayno = mindisp;; displayno++) {
|
||||
const char *err;
|
||||
int tcp_port = displayno + 6000;
|
||||
int addrtype = ADDRTYPE_IPV4;
|
||||
|
||||
sockets[nsockets] = new_listener(
|
||||
NULL, tcp_port, plug, FALSE, conf, addrtype);
|
||||
|
||||
err = sk_socket_error(sockets[nsockets]);
|
||||
if (!err) {
|
||||
char *hostname = get_hostname();
|
||||
if (hostname) {
|
||||
char *canonicalname = NULL;
|
||||
a_tcp = name_lookup(hostname, tcp_port, &canonicalname,
|
||||
conf, addrtype, NULL, "");
|
||||
sfree(canonicalname);
|
||||
}
|
||||
sfree(hostname);
|
||||
nsockets++;
|
||||
break; /* success! */
|
||||
} else {
|
||||
sk_close(sockets[nsockets]);
|
||||
}
|
||||
|
||||
if (!strcmp(err, strerror(EADDRINUSE))) /* yuck! */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (a_tcp) {
|
||||
x11_format_auth_for_authfile(
|
||||
BinarySink_UPCAST(authfiledata),
|
||||
a_tcp, displayno, authproto, authdata);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to establish the Unix-domain analogue. That may or may not
|
||||
* work - file permissions in /tmp may prevent it, for example -
|
||||
* but it's worth a try, and we don't consider it a fatal error if
|
||||
* it doesn't work.
|
||||
*/
|
||||
unix_path = dupprintf("/tmp/.X11-unix/X%d", displayno);
|
||||
a_unix = unix_sock_addr(unix_path);
|
||||
|
||||
sockets[nsockets] = new_unix_listener(a_unix, plug);
|
||||
if (!sk_socket_error(sockets[nsockets])) {
|
||||
x11_format_auth_for_authfile(
|
||||
BinarySink_UPCAST(authfiledata),
|
||||
a_unix, displayno, authproto, authdata);
|
||||
nsockets++;
|
||||
} else {
|
||||
sk_close(sockets[nsockets]);
|
||||
sfree(unix_path);
|
||||
unix_path = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decide where the authority data will be written.
|
||||
*/
|
||||
|
||||
tmpdir = getenv("TMPDIR");
|
||||
if (!tmpdir || !*tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
|
||||
authfilename = dupcat(tmpdir, "/", progname, "-Xauthority-XXXXXX");
|
||||
|
||||
{
|
||||
int oldumask = umask(077);
|
||||
authfd = mkstemp(authfilename);
|
||||
umask(oldumask);
|
||||
}
|
||||
if (authfd < 0) {
|
||||
while (nsockets-- > 0)
|
||||
sk_close(sockets[nsockets]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Spawn a subprocess which will try to reliably delete our
|
||||
* auth file when we terminate, in case we die unexpectedly.
|
||||
*/
|
||||
{
|
||||
int cleanup_pipe[2];
|
||||
pid_t pid;
|
||||
|
||||
/* Don't worry if pipe or fork fails; it's not _that_ critical. */
|
||||
if (!pipe(cleanup_pipe)) {
|
||||
if ((pid = fork()) == 0) {
|
||||
int buf[1024];
|
||||
/*
|
||||
* Our parent process holds the writing end of
|
||||
* this pipe, and writes nothing to it. Hence,
|
||||
* we expect read() to return EOF as soon as
|
||||
* that process terminates.
|
||||
*/
|
||||
setpgid(0, 0);
|
||||
close(cleanup_pipe[1]);
|
||||
close(authfd);
|
||||
while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0);
|
||||
unlink(authfilename);
|
||||
if (unix_path)
|
||||
unlink(unix_path);
|
||||
_exit(0);
|
||||
} else if (pid < 0) {
|
||||
close(cleanup_pipe[0]);
|
||||
close(cleanup_pipe[1]);
|
||||
} else {
|
||||
close(cleanup_pipe[0]);
|
||||
cloexec(cleanup_pipe[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
authfp = fdopen(authfd, "wb");
|
||||
fwrite(authfiledata->u, 1, authfiledata->len, authfp);
|
||||
fclose(authfp);
|
||||
|
||||
{
|
||||
char *display = dupprintf(":%d%s", displayno, screen_number_suffix);
|
||||
conf_set_str_str(conf, CONF_environmt, "DISPLAY", display);
|
||||
sfree(display);
|
||||
}
|
||||
conf_set_str_str(conf, CONF_environmt, "XAUTHORITY", authfilename);
|
||||
|
||||
/*
|
||||
* FIXME: return at least the DISPLAY and XAUTHORITY env settings,
|
||||
* and perhaps also the display number
|
||||
*/
|
||||
|
||||
out:
|
||||
if (a_tcp)
|
||||
sk_addr_free(a_tcp);
|
||||
if (a_unix)
|
||||
sk_addr_free(a_unix);
|
||||
sfree(authfilename);
|
||||
strbuf_free(authfiledata);
|
||||
sfree(unix_path);
|
||||
return nsockets;
|
||||
}
|
||||
|
Reference in New Issue
Block a user