mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00: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:
parent
f4db9196da
commit
61976b417e
3
ssh.h
3
ssh.h
@ -1002,6 +1002,9 @@ char *platform_get_x_display(void);
|
||||
*/
|
||||
void x11_get_auth_from_authfile(struct X11Display *display,
|
||||
const char *authfilename);
|
||||
void x11_format_auth_for_authfile(
|
||||
BinarySink *bs, SockAddr *addr, int display_no,
|
||||
ptrlen authproto, ptrlen authdata);
|
||||
int x11_identify_auth_proto(ptrlen protoname);
|
||||
void *x11_dehexify(ptrlen hex, int *outlen);
|
||||
|
||||
|
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;
|
||||
}
|
||||
|
42
x11fwd.c
42
x11fwd.c
@ -449,6 +449,15 @@ ptrlen BinarySource_get_string_xauth(BinarySource *src)
|
||||
#define get_string_xauth(src) \
|
||||
BinarySource_get_string_xauth(BinarySource_UPCAST(src))
|
||||
|
||||
void BinarySink_put_stringpl_xauth(BinarySink *bs, ptrlen pl)
|
||||
{
|
||||
assert((pl.len >> 16) == 0);
|
||||
put_uint16(bs, pl.len);
|
||||
put_data(bs, pl.ptr, pl.len);
|
||||
}
|
||||
#define put_stringpl_xauth(bs, ptrlen) \
|
||||
BinarySink_put_stringpl_xauth(BinarySink_UPCAST(bs),ptrlen)
|
||||
|
||||
void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
const char *authfilename)
|
||||
{
|
||||
@ -631,6 +640,39 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
sfree(ourhostname);
|
||||
}
|
||||
|
||||
void x11_format_auth_for_authfile(
|
||||
BinarySink *bs, SockAddr *addr, int display_no,
|
||||
ptrlen authproto, ptrlen authdata)
|
||||
{
|
||||
if (sk_address_is_special_local(addr)) {
|
||||
char *ourhostname = get_hostname();
|
||||
put_uint16(bs, 256); /* indicates Unix-domain socket */
|
||||
put_stringpl_xauth(bs, ptrlen_from_asciz(ourhostname));
|
||||
sfree(ourhostname);
|
||||
} else if (sk_addrtype(addr) == ADDRTYPE_IPV4) {
|
||||
char ipv4buf[4];
|
||||
sk_addrcopy(addr, ipv4buf);
|
||||
put_uint16(bs, 0); /* indicates IPv4 */
|
||||
put_stringpl_xauth(bs, make_ptrlen(ipv4buf, 4));
|
||||
} else if (sk_addrtype(addr) == ADDRTYPE_IPV6) {
|
||||
char ipv6buf[16];
|
||||
sk_addrcopy(addr, ipv6buf);
|
||||
put_uint16(bs, 6); /* indicates IPv6 */
|
||||
put_stringpl_xauth(bs, make_ptrlen(ipv6buf, 16));
|
||||
} else {
|
||||
assert(FALSE && "Bad address type in x11_format_auth_for_authfile");
|
||||
}
|
||||
|
||||
{
|
||||
char *numberbuf = dupprintf("%d", display_no);
|
||||
put_stringpl_xauth(bs, ptrlen_from_asciz(numberbuf));
|
||||
sfree(numberbuf);
|
||||
}
|
||||
|
||||
put_stringpl_xauth(bs, authproto);
|
||||
put_stringpl_xauth(bs, authdata);
|
||||
}
|
||||
|
||||
static void x11_log(Plug *p, int type, SockAddr *addr, int port,
|
||||
const char *error_msg, int error_code)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user