
cookies. This will not work when we start talking tcp to the local X-server but `connect_local_xsocket' and the rest of the code doesn't handle it anyway and the old code could (and did) pick up the wrong cookie sometimes. If we have to match FamilyInternet cookies, the search order has to be changed anyway git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@7058 ec53bebd-3082-4978-b11e-865c3cabbd6b
786 lines
18 KiB
C
786 lines
18 KiB
C
/*
|
|
* Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
|
|
* (Royal Institute of Technology, Stockholm, Sweden).
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the Kungliga Tekniska
|
|
* Högskolan and its contributors.
|
|
*
|
|
* 4. Neither the name of the Institute nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "kx.h"
|
|
|
|
RCSID("$Id$");
|
|
|
|
char x_socket[MaxPathLen];
|
|
|
|
u_int32_t display_num;
|
|
char display[MaxPathLen];
|
|
int display_size = sizeof(display);
|
|
char xauthfile[MaxPathLen];
|
|
int xauthfile_size = sizeof(xauthfile);
|
|
u_char cookie[16];
|
|
size_t cookie_len = sizeof(cookie);
|
|
|
|
#ifndef X_UNIX_PATH
|
|
#define X_UNIX_PATH "/tmp/.X11-unix/X"
|
|
#endif
|
|
|
|
#ifndef X_PIPE_PATH
|
|
#define X_PIPE_PATH "/tmp/.X11-pipe/X"
|
|
#endif
|
|
|
|
#ifndef INADDR_LOOPBACK
|
|
#define INADDR_LOOPBACK 0x7f000001
|
|
#endif
|
|
|
|
/*
|
|
* Allocate a unix domain socket in `s' for display `dpy' and with
|
|
* filename `pattern'
|
|
*
|
|
* 0 if all is OK
|
|
* -1 if bind failed badly
|
|
* 1 if dpy is already used */
|
|
|
|
static int
|
|
try_socket (struct x_socket *s, int dpy, const char *pattern)
|
|
{
|
|
struct sockaddr_un addr;
|
|
int fd;
|
|
|
|
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
|
if (fd < 0)
|
|
err (1, "socket AF_UNIX");
|
|
memset (&addr, 0, sizeof(addr));
|
|
addr.sun_family = AF_UNIX;
|
|
snprintf (addr.sun_path, sizeof(addr.sun_path), pattern, dpy);
|
|
if(bind(fd,
|
|
(struct sockaddr *)&addr,
|
|
sizeof(addr)) < 0) {
|
|
close (fd);
|
|
if (errno == EADDRINUSE ||
|
|
errno == EACCES /* Cray return EACCESS */
|
|
#ifdef ENOTUNIQ
|
|
|| errno == ENOTUNIQ /* bug in Solaris 2.4 */
|
|
#endif
|
|
)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
s->fd = fd;
|
|
s->pathname = strdup (addr.sun_path);
|
|
if (s->pathname == NULL)
|
|
errx (1, "strdup: out of memory");
|
|
s->flags = UNIX_SOCKET;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef MAY_HAVE_X11_PIPES
|
|
/*
|
|
* Allocate a stream (masqueraded as a named pipe)
|
|
*
|
|
* 0 if all is OK
|
|
* -1 if bind failed badly
|
|
* 1 if dpy is already used
|
|
*/
|
|
|
|
static int
|
|
try_pipe (struct x_socket *s, int dpy, const char *pattern)
|
|
{
|
|
char path[MAXPATHLEN];
|
|
int ret;
|
|
int fd;
|
|
int pipefd[2];
|
|
|
|
snprintf (path, sizeof(path), pattern, dpy);
|
|
fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
|
if (fd < 0) {
|
|
if (errno == EEXIST)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
close (fd);
|
|
|
|
ret = pipe (pipefd);
|
|
if (ret < 0)
|
|
err (1, "pipe");
|
|
|
|
ret = ioctl (pipefd[1], I_PUSH, "connld");
|
|
if (ret < 0) {
|
|
if(errno == ENOSYS)
|
|
return -1;
|
|
err (1, "ioctl I_PUSH");
|
|
}
|
|
|
|
ret = fattach (pipefd[1], path);
|
|
if (ret < 0)
|
|
err (1, "fattach %s", path);
|
|
|
|
s->fd = pipefd[0];
|
|
close (pipefd[1]);
|
|
s->pathname = strdup (path);
|
|
if (s->pathname == NULL)
|
|
errx (1, "strdup: out of memory");
|
|
s->flags = STREAM_PIPE;
|
|
return 0;
|
|
}
|
|
#endif /* MAY_HAVE_X11_PIPES */
|
|
|
|
/*
|
|
* Try to create a TCP socket in `s' corresponding to display `dpy'.
|
|
*
|
|
* 0 if all is OK
|
|
* -1 if bind failed badly
|
|
* 1 if dpy is already used
|
|
*/
|
|
|
|
static int
|
|
try_tcp (struct x_socket *s, int dpy)
|
|
{
|
|
struct sockaddr_in tcpaddr;
|
|
struct in_addr local;
|
|
int one = 1;
|
|
int fd;
|
|
|
|
memset(&local, 0, sizeof(local));
|
|
local.s_addr = htonl(INADDR_LOOPBACK);
|
|
|
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
|
if (fd < 0)
|
|
err (1, "socket AF_INET");
|
|
#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
|
|
setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&one,
|
|
sizeof(one));
|
|
#endif
|
|
memset (&tcpaddr, 0, sizeof(tcpaddr));
|
|
tcpaddr.sin_family = AF_INET;
|
|
tcpaddr.sin_addr = local;
|
|
tcpaddr.sin_port = htons(6000 + dpy);
|
|
if (bind (fd, (struct sockaddr *)&tcpaddr,
|
|
sizeof(tcpaddr)) < 0) {
|
|
close (fd);
|
|
if (errno == EADDRINUSE)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
s->fd = fd;
|
|
s->pathname = NULL;
|
|
s->flags = TCP;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* The potential places to create unix sockets.
|
|
*/
|
|
|
|
static char *x_sockets[] = {
|
|
X_UNIX_PATH "%u",
|
|
"/var/X/.X11-unix/X" "%u",
|
|
"/usr/spool/sockets/X11/" "%u",
|
|
NULL
|
|
};
|
|
|
|
/*
|
|
* Dito for stream pipes.
|
|
*/
|
|
|
|
#ifdef MAY_HAVE_X11_PIPES
|
|
static char *x_pipes[] = {
|
|
X_PIPE_PATH "%u",
|
|
"/var/X/.X11-pipe/X" "%u",
|
|
NULL
|
|
};
|
|
#endif
|
|
|
|
/*
|
|
* Create the directory corresponding to dirname of `path' or fail.
|
|
*/
|
|
|
|
static void
|
|
try_mkdir (const char *path)
|
|
{
|
|
char *dir;
|
|
char *p;
|
|
int oldmask;
|
|
|
|
if((dir = strdup (path)) == NULL)
|
|
errx (1, "strdup: out of memory");
|
|
p = strrchr (dir, '/');
|
|
if (p)
|
|
*p = '\0';
|
|
|
|
oldmask = umask(0);
|
|
mkdir (dir, 01777);
|
|
umask (oldmask);
|
|
free (dir);
|
|
}
|
|
|
|
/*
|
|
* Allocate a display, returning the number of sockets in `number' and
|
|
* all the corresponding sockets in `sockets'. If `tcp_socket' is
|
|
* true, also allcoaet a TCP socket.
|
|
*
|
|
* The return value is the display allocated or -1 if an error occurred.
|
|
*/
|
|
|
|
int
|
|
get_xsockets (int *number, struct x_socket **sockets, int tcp_socket)
|
|
{
|
|
int dpy;
|
|
struct x_socket *s;
|
|
int n;
|
|
int i;
|
|
|
|
s = malloc (sizeof(*s) * 5);
|
|
if (s == NULL)
|
|
errx (1, "malloc: out of memory");
|
|
|
|
try_mkdir (X_UNIX_PATH);
|
|
try_mkdir (X_PIPE_PATH);
|
|
|
|
for(dpy = 4; dpy < 256; ++dpy) {
|
|
char **path;
|
|
int tmp = 0;
|
|
|
|
n = 0;
|
|
for (path = x_sockets; *path; ++path) {
|
|
tmp = try_socket (&s[n], dpy, *path);
|
|
if (tmp == -1) {
|
|
if (errno != ENOTDIR && errno != ENOENT)
|
|
return -1;
|
|
} else if (tmp == 1) {
|
|
while(--n >= 0) {
|
|
close (s[n].fd);
|
|
free (s[n].pathname);
|
|
}
|
|
break;
|
|
} else if (tmp == 0)
|
|
++n;
|
|
}
|
|
if (tmp == 1)
|
|
continue;
|
|
|
|
#ifdef MAY_HAVE_X11_PIPES
|
|
for (path = x_pipes; *path; ++path) {
|
|
tmp = try_pipe (&s[n], dpy, *path);
|
|
if (tmp == -1) {
|
|
if (errno != ENOTDIR && errno != ENOENT && errno != ENOSYS)
|
|
return -1;
|
|
} else if (tmp == 1) {
|
|
while (--n >= 0) {
|
|
close (s[n].fd);
|
|
free (s[n].pathname);
|
|
}
|
|
break;
|
|
} else if (tmp == 0)
|
|
++n;
|
|
}
|
|
|
|
if (tmp == 1)
|
|
continue;
|
|
#endif
|
|
|
|
if (tcp_socket) {
|
|
tmp = try_tcp (&s[n], dpy);
|
|
if (tmp == -1)
|
|
return -1;
|
|
else if (tmp == 1) {
|
|
while (--n >= 0) {
|
|
close (s[n].fd);
|
|
free (s[n].pathname);
|
|
}
|
|
break;
|
|
} else if (tmp == 0)
|
|
++n;
|
|
}
|
|
break;
|
|
}
|
|
if (dpy == 256)
|
|
errx (1, "no free x-servers");
|
|
for (i = 0; i < n; ++i)
|
|
if (s[i].flags & LISTENP
|
|
&& listen (s[i].fd, SOMAXCONN) < 0)
|
|
err (1, "listen %s", s[i].pathname ? s[i].pathname : "tcp");
|
|
*number = n;
|
|
*sockets = s;
|
|
return dpy;
|
|
}
|
|
|
|
/*
|
|
* Change owner on the `n' sockets in `sockets' to `uid', `gid'.
|
|
* Return 0 is succesful or -1 if an error occurred.
|
|
*/
|
|
|
|
int
|
|
chown_xsockets (int n, struct x_socket *sockets, uid_t uid, gid_t gid)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; ++i)
|
|
if (sockets[i].pathname != NULL)
|
|
if (chown (sockets[i].pathname, uid, gid) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Connect to local display `dnr' with local transport.
|
|
* Return a file descriptor.
|
|
*/
|
|
|
|
int
|
|
connect_local_xsocket (unsigned dnr)
|
|
{
|
|
int fd;
|
|
struct sockaddr_un addr;
|
|
char **path;
|
|
|
|
for (path = x_sockets; *path; ++path) {
|
|
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
|
if (fd < 0)
|
|
err (1, "socket AF_UNIX");
|
|
memset (&addr, 0, sizeof(addr));
|
|
addr.sun_family = AF_UNIX;
|
|
snprintf (addr.sun_path, sizeof(addr.sun_path), *path, dnr);
|
|
if (connect (fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
|
|
return fd;
|
|
}
|
|
err (1, "connecting to local display %u", dnr);
|
|
}
|
|
|
|
/*
|
|
* Create a cookie file with a random cookie for the localhost. The
|
|
* file name will be stored in `xauthfile' (but not larger than
|
|
* `xauthfile_size'), and the cookie returned in `cookie', `cookie_sz'.
|
|
* Return 0 if succesful, or errno.
|
|
*/
|
|
|
|
int
|
|
create_and_write_cookie (char *xauthfile,
|
|
size_t xauthfile_size,
|
|
u_char *cookie,
|
|
size_t cookie_sz)
|
|
{
|
|
Xauth auth;
|
|
char tmp[64];
|
|
int fd;
|
|
FILE *f;
|
|
char hostname[MaxHostNameLen];
|
|
struct in_addr loopback;
|
|
int saved_errno;
|
|
|
|
gethostname (hostname, sizeof(hostname));
|
|
loopback.s_addr = htonl(INADDR_LOOPBACK);
|
|
|
|
auth.family = FamilyLocal;
|
|
auth.address = hostname;
|
|
auth.address_length = strlen(auth.address);
|
|
snprintf (tmp, sizeof(tmp), "%d", display_num);
|
|
auth.number_length = strlen(tmp);
|
|
auth.number = tmp;
|
|
auth.name = COOKIE_TYPE;
|
|
auth.name_length = strlen(auth.name);
|
|
auth.data_length = cookie_sz;
|
|
auth.data = (char*)cookie;
|
|
des_rand_data (cookie, cookie_sz);
|
|
|
|
strlcpy(xauthfile, "/tmp/AXXXXXX", xauthfile_size);
|
|
fd = mkstemp(xauthfile);
|
|
if(fd < 0) {
|
|
saved_errno = errno;
|
|
syslog(LOG_ERR, "create_and_write_cookie: mkstemp: %m");
|
|
return saved_errno;
|
|
}
|
|
f = fdopen(fd, "r+");
|
|
if(f == NULL){
|
|
saved_errno = errno;
|
|
close(fd);
|
|
return errno;
|
|
}
|
|
if(XauWriteAuth(f, &auth) == 0) {
|
|
saved_errno = errno;
|
|
fclose(f);
|
|
return saved_errno;
|
|
}
|
|
|
|
/*
|
|
* I would like to write a cookie for localhost:n here, but some
|
|
* stupid code in libX11 will not look for cookies of that type,
|
|
* so we are forced to use FamilyWild instead.
|
|
*/
|
|
|
|
auth.family = FamilyWild;
|
|
auth.address_length = 0;
|
|
|
|
#if 0 /* XXX */
|
|
auth.address = (char *)&loopback;
|
|
auth.address_length = sizeof(loopback);
|
|
#endif
|
|
|
|
if (XauWriteAuth(f, &auth) == 0) {
|
|
saved_errno = errno;
|
|
fclose (f);
|
|
return saved_errno;
|
|
}
|
|
|
|
if(fclose(f))
|
|
return errno;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Verify and remove cookies. Read and parse a X-connection from
|
|
* `fd'. Check the cookie used is the same as in `cookie'. Remove the
|
|
* cookie and copy the rest of it to `sock'.
|
|
* Expect cookies iff cookiesp.
|
|
* Return 0 iff ok.
|
|
*
|
|
* The protocol is as follows:
|
|
*
|
|
* C->S: [Bl] 1
|
|
* unused 1
|
|
* protocol major version 2
|
|
* protocol minor version 2
|
|
* length of auth protocol name(n) 2
|
|
* length of auth protocol data 2
|
|
* unused 2
|
|
* authorization protocol name n
|
|
* pad pad(n)
|
|
* authorization protocol data d
|
|
* pad pad(d)
|
|
*
|
|
* S->C: Failed
|
|
* 0 1
|
|
* length of reason 1
|
|
* protocol major version 2
|
|
* protocol minor version 2
|
|
* length in 4 bytes unit of
|
|
* additional data (n+p)/4 2
|
|
* reason n
|
|
* unused p = pad(n)
|
|
*/
|
|
|
|
int
|
|
verify_and_remove_cookies (int fd, int sock, int cookiesp)
|
|
{
|
|
u_char beg[12];
|
|
int bigendianp;
|
|
unsigned n, d, npad, dpad;
|
|
char *protocol_name, *protocol_data;
|
|
u_char zeros[6] = {0, 0, 0, 0, 0, 0};
|
|
u_char refused[20] = {0, 10,
|
|
0, 0, /* protocol major version */
|
|
0, 0, /* protocol minor version */
|
|
0, 0, /* length of additional data / 4 */
|
|
'b', 'a', 'd', ' ', 'c', 'o', 'o', 'k', 'i', 'e',
|
|
0, 0};
|
|
|
|
if (net_read (fd, beg, sizeof(beg)) != sizeof(beg))
|
|
return 1;
|
|
if (net_write (sock, beg, 6) != 6)
|
|
return 1;
|
|
bigendianp = beg[0] == 'B';
|
|
if (bigendianp) {
|
|
n = (beg[6] << 8) | beg[7];
|
|
d = (beg[8] << 8) | beg[9];
|
|
} else {
|
|
n = (beg[7] << 8) | beg[6];
|
|
d = (beg[9] << 8) | beg[8];
|
|
}
|
|
npad = (4 - (n % 4)) % 4;
|
|
dpad = (4 - (d % 4)) % 4;
|
|
protocol_name = malloc(n + npad);
|
|
if (n + npad != 0 && protocol_name == NULL)
|
|
return 1;
|
|
protocol_data = malloc(d + dpad);
|
|
if (d + dpad != 0 && protocol_data == NULL) {
|
|
free (protocol_name);
|
|
return 1;
|
|
}
|
|
if (net_read (fd, protocol_name, n + npad) != n + npad)
|
|
goto fail;
|
|
if (net_read (fd, protocol_data, d + dpad) != d + dpad)
|
|
goto fail;
|
|
if (cookiesp) {
|
|
if (strncmp (protocol_name, COOKIE_TYPE, strlen(COOKIE_TYPE)) != 0)
|
|
goto refused;
|
|
if (d != cookie_len ||
|
|
memcmp (protocol_data, cookie, cookie_len) != 0)
|
|
goto refused;
|
|
}
|
|
free (protocol_name);
|
|
free (protocol_data);
|
|
if (net_write (sock, zeros, 6) != 6)
|
|
return 1;
|
|
return 0;
|
|
refused:
|
|
refused[2] = beg[2];
|
|
refused[3] = beg[3];
|
|
refused[4] = beg[4];
|
|
refused[5] = beg[5];
|
|
if (bigendianp)
|
|
refused[7] = 3;
|
|
else
|
|
refused[6] = 3;
|
|
|
|
net_write (fd, refused, sizeof(refused));
|
|
fail:
|
|
free (protocol_name);
|
|
free (protocol_data);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Return 0 iff `cookie' is compatible with the cookie for the
|
|
* localhost with name given in `disp_he' and display number in
|
|
* `disp_nr'.
|
|
*/
|
|
|
|
static int
|
|
match_local_auth (Xauth* auth, struct hostent *disp_he, int disp_nr)
|
|
{
|
|
int auth_disp;
|
|
char *tmp_disp;
|
|
|
|
tmp_disp = strndup (auth->number, auth->number_length);
|
|
if (tmp_disp == NULL)
|
|
return -1;
|
|
auth_disp = atoi(tmp_disp);
|
|
free (tmp_disp);
|
|
if (auth_disp != disp_nr)
|
|
return 1;
|
|
if (auth->family == FamilyLocal
|
|
|| auth->family == FamilyWild) {
|
|
int i;
|
|
|
|
if (strncmp (auth->address,
|
|
disp_he->h_name,
|
|
auth->address_length) == 0)
|
|
return 0;
|
|
|
|
for (i = 0; disp_he->h_aliases[i] != NULL; ++i)
|
|
if (strncmp (auth->address,
|
|
disp_he->h_aliases[i],
|
|
auth->address_length) == 0)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Find `our' cookie from the cookie file `f' and return it or NULL.
|
|
*/
|
|
|
|
static Xauth*
|
|
find_auth_cookie (FILE *f)
|
|
{
|
|
Xauth *ret = NULL;
|
|
char local_hostname[MaxHostNameLen];
|
|
char *display = getenv("DISPLAY");
|
|
char *colon;
|
|
struct hostent *display_he;
|
|
int disp;
|
|
|
|
if (display == NULL)
|
|
display = ":0";
|
|
colon = strchr (display, ':');
|
|
if (colon == NULL)
|
|
disp = 0;
|
|
else {
|
|
*colon = '\0';
|
|
disp = atoi (colon + 1);
|
|
}
|
|
if (strcmp (display, "") == 0
|
|
|| strncmp (display, "unix", 4) == 0
|
|
|| strncmp (display, "localhost", 9) == 0) {
|
|
gethostname (local_hostname, sizeof(local_hostname));
|
|
display = local_hostname;
|
|
}
|
|
display_he = gethostbyname (display);
|
|
if (display_he == NULL) {
|
|
warnx ("gethostbyname %s: %s", display, hstrerror(h_errno));
|
|
return NULL;
|
|
}
|
|
|
|
for (; (ret = XauReadAuth (f)) != NULL; XauDisposeAuth(ret)) {
|
|
if (match_local_auth (ret, display_he, disp) == 0)
|
|
return ret;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Get rid of the cookie that we were sent and get the correct one
|
|
* from our own cookie file instead.
|
|
*/
|
|
|
|
int
|
|
replace_cookie(int xserver, int fd, char *filename, int cookiesp) /* XXX */
|
|
{
|
|
u_char beg[12];
|
|
int bigendianp;
|
|
unsigned n, d, npad, dpad;
|
|
FILE *f;
|
|
u_char zeros[6] = {0, 0, 0, 0, 0, 0};
|
|
|
|
if (net_read (fd, beg, sizeof(beg)) != sizeof(beg))
|
|
return 1;
|
|
if (net_write (xserver, beg, 6) != 6)
|
|
return 1;
|
|
bigendianp = beg[0] == 'B';
|
|
if (bigendianp) {
|
|
n = (beg[6] << 8) | beg[7];
|
|
d = (beg[8] << 8) | beg[9];
|
|
} else {
|
|
n = (beg[7] << 8) | beg[6];
|
|
d = (beg[9] << 8) | beg[8];
|
|
}
|
|
if (n != 0 || d != 0)
|
|
return 1;
|
|
f = fopen(filename, "r");
|
|
if (f != NULL) {
|
|
Xauth *auth = find_auth_cookie (f);
|
|
u_char len[6] = {0, 0, 0, 0, 0, 0};
|
|
|
|
fclose (f);
|
|
|
|
if (auth != NULL) {
|
|
n = auth->name_length;
|
|
d = auth->data_length;
|
|
} else {
|
|
n = 0;
|
|
d = 0;
|
|
}
|
|
if (bigendianp) {
|
|
len[0] = n >> 8;
|
|
len[1] = n & 0xFF;
|
|
len[2] = d >> 8;
|
|
len[3] = d & 0xFF;
|
|
} else {
|
|
len[0] = n & 0xFF;
|
|
len[1] = n >> 8;
|
|
len[2] = d & 0xFF;
|
|
len[3] = d >> 8;
|
|
}
|
|
if (net_write (xserver, len, 6) != 6) {
|
|
XauDisposeAuth(auth);
|
|
return 1;
|
|
}
|
|
if(n != 0 && net_write (xserver, auth->name, n) != n) {
|
|
XauDisposeAuth(auth);
|
|
return 1;
|
|
}
|
|
npad = (4 - (n % 4)) % 4;
|
|
if (npad && net_write (xserver, zeros, npad) != npad) {
|
|
XauDisposeAuth(auth);
|
|
return 1;
|
|
}
|
|
if (d != 0 && net_write (xserver, auth->data, d) != d) {
|
|
XauDisposeAuth(auth);
|
|
return 1;
|
|
}
|
|
XauDisposeAuth(auth);
|
|
dpad = (4 - (d % 4)) % 4;
|
|
if (dpad && net_write (xserver, zeros, dpad) != dpad)
|
|
return 1;
|
|
} else {
|
|
if(net_write(xserver, zeros, 6) != 6)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Some simple controls on the address and corresponding socket
|
|
*/
|
|
|
|
int
|
|
suspicious_address (int sock, struct sockaddr_in addr)
|
|
{
|
|
char data[40];
|
|
int len = sizeof(data);
|
|
|
|
return addr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
|
|
#if defined(IP_OPTIONS) && defined(HAVE_GETSOCKOPT)
|
|
|| getsockopt (sock, IPPROTO_IP, IP_OPTIONS, data, &len) < 0
|
|
|| len != 0
|
|
#endif
|
|
;
|
|
}
|
|
|
|
/*
|
|
* This really sucks, but these functions are used and if we're not
|
|
* linking against libkrb they don't exist. Using the heimdal storage
|
|
* functions will not work either cause we do not always link with
|
|
* libkrb5 either.
|
|
*/
|
|
|
|
#ifndef KRB4
|
|
|
|
int
|
|
krb_get_int(void *f, u_int32_t *to, int size, int lsb)
|
|
{
|
|
int i;
|
|
unsigned char *from = (unsigned char *)f;
|
|
|
|
*to = 0;
|
|
if(lsb){
|
|
for(i = size-1; i >= 0; i--)
|
|
*to = (*to << 8) | from[i];
|
|
}else{
|
|
for(i = 0; i < size; i++)
|
|
*to = (*to << 8) | from[i];
|
|
}
|
|
return size;
|
|
}
|
|
|
|
int
|
|
krb_put_int(u_int32_t from, void *to, size_t rem, int size)
|
|
{
|
|
int i;
|
|
unsigned char *p = (unsigned char *)to;
|
|
|
|
if (rem < size)
|
|
return -1;
|
|
|
|
for(i = size - 1; i >= 0; i--){
|
|
p[i] = from & 0xff;
|
|
from >>= 8;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
#endif /* !KRB4 */
|