mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-25 01:02:24 +00:00
5d718ef64b
The number of people has been steadily increasing who read our source code with an editor that thinks tab stops are 4 spaces apart, as opposed to the traditional tty-derived 8 that the PuTTY code expects. So I've been wondering for ages about just fixing it, and switching to a spaces-only policy throughout the code. And I recently found out about 'git blame -w', which should make this change not too disruptive for the purposes of source-control archaeology; so perhaps now is the time. While I'm at it, I've also taken the opportunity to remove all the trailing spaces from source lines (on the basis that git dislikes them, and is the only thing that seems to have a strong opinion one way or the other). Apologies to anyone downstream of this code who has complicated patch sets to rebase past this change. I don't intend it to be needed again.
209 lines
5.5 KiB
C
209 lines
5.5 KiB
C
/*
|
|
* ux_x11.c: fetch local auth data for X forwarding.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "putty.h"
|
|
#include "ssh.h"
|
|
#include "network.h"
|
|
|
|
void platform_get_x11_auth(struct X11Display *disp, Conf *conf)
|
|
{
|
|
char *xauthfile;
|
|
bool needs_free;
|
|
|
|
/*
|
|
* Find the .Xauthority file.
|
|
*/
|
|
needs_free = false;
|
|
xauthfile = getenv("XAUTHORITY");
|
|
if (!xauthfile) {
|
|
xauthfile = getenv("HOME");
|
|
if (xauthfile) {
|
|
xauthfile = dupcat(xauthfile, "/.Xauthority", NULL);
|
|
needs_free = true;
|
|
}
|
|
}
|
|
|
|
if (xauthfile) {
|
|
x11_get_auth_from_authfile(disp, xauthfile);
|
|
if (needs_free)
|
|
sfree(xauthfile);
|
|
}
|
|
}
|
|
|
|
const bool 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_nm();
|
|
|
|
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 = sk_namelookup(hostname, &canonicalname, addrtype);
|
|
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", NULL);
|
|
|
|
{
|
|
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.
|
|
*/
|
|
|
|
close(0);
|
|
close(1);
|
|
close(2);
|
|
|
|
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);
|
|
/* a_unix doesn't need freeing, because new_unix_listener took it over */
|
|
sfree(authfilename);
|
|
strbuf_free(authfiledata);
|
|
sfree(unix_path);
|
|
return nsockets;
|
|
}
|