git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@5167 ec53bebd-3082-4978-b11e-865c3cabbd6b
		
			
				
	
	
		
			650 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			650 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 1995, 1996, 1997, 1998 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);
 | 
						|
 | 
						|
static int
 | 
						|
do_enccopy (int fd1, int fd2, int mode, des_cblock *iv,
 | 
						|
	    des_key_schedule schedule, int *num)
 | 
						|
{
 | 
						|
     int ret;
 | 
						|
     u_char buf[BUFSIZ];
 | 
						|
 | 
						|
     ret = read (fd1, buf, sizeof(buf));
 | 
						|
     if (ret == 0)
 | 
						|
	  return 0;
 | 
						|
     if (ret < 0) {
 | 
						|
	 warn ("read");
 | 
						|
	 return ret;
 | 
						|
     }
 | 
						|
#ifndef NOENCRYPTION
 | 
						|
     des_cfb64_encrypt (buf, buf, ret, schedule, iv,
 | 
						|
			num, mode);
 | 
						|
#endif
 | 
						|
     ret = krb_net_write (fd2, buf, ret);
 | 
						|
     if (ret < 0) {
 | 
						|
	 warn ("write");
 | 
						|
	 return ret;
 | 
						|
     }
 | 
						|
     return 1;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Copy data from `fd1' to `fd2', encrypting it.  Data in the other
 | 
						|
 * direction is of course, decrypted.
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
copy_encrypted (int fd1, int fd2, des_cblock *iv,
 | 
						|
		des_key_schedule schedule)
 | 
						|
{
 | 
						|
     des_cblock iv1, iv2;
 | 
						|
     int num1 = 0, num2 = 0;
 | 
						|
 | 
						|
     memcpy (iv1, *iv, sizeof(iv1));
 | 
						|
     memcpy (iv2, *iv, sizeof(iv2));
 | 
						|
     for (;;) {
 | 
						|
	  fd_set fdset;
 | 
						|
	  int ret;
 | 
						|
 | 
						|
	  FD_ZERO(&fdset);
 | 
						|
	  FD_SET(fd1, &fdset);
 | 
						|
	  FD_SET(fd2, &fdset);
 | 
						|
 | 
						|
	  ret = select (max(fd1, fd2)+1, &fdset, NULL, NULL, NULL);
 | 
						|
	  if (ret < 0 && errno != EINTR) {
 | 
						|
	      warn ("select");
 | 
						|
	      return 1;
 | 
						|
	  }
 | 
						|
	  if (FD_ISSET(fd1, &fdset)) {
 | 
						|
	       ret = do_enccopy (fd1, fd2, DES_ENCRYPT, &iv1, schedule, &num1);
 | 
						|
	       if (ret <= 0)
 | 
						|
		    return ret;
 | 
						|
	  }
 | 
						|
	  if (FD_ISSET(fd2, &fdset)) {
 | 
						|
	       ret = do_enccopy (fd2, fd1, DES_DECRYPT, &iv2, schedule, &num2);
 | 
						|
	       if (ret <= 0)
 | 
						|
		    return ret;
 | 
						|
	  }
 | 
						|
     }
 | 
						|
}
 | 
						|
 | 
						|
#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.
 | 
						|
 *
 | 
						|
 * 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 */
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Allocate and listen on a number of local X server sockets, pipes,
 | 
						|
 * and a TCP socket.  Return the display number.
 | 
						|
 */
 | 
						|
 | 
						|
static char *x_sockets[] = {
 | 
						|
X_UNIX_PATH "%u",
 | 
						|
"/var/X/.X11-unix/X" "%u",
 | 
						|
"/usr/spool/sockets/X11/" "%u",
 | 
						|
NULL
 | 
						|
};
 | 
						|
 | 
						|
static char *x_pipes[] = {
 | 
						|
X_PIPE_PATH "%u",
 | 
						|
"/var/X/.X11-pipe/X" "%u",
 | 
						|
NULL
 | 
						|
};
 | 
						|
 | 
						|
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);
 | 
						|
}
 | 
						|
 | 
						|
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) {
 | 
						|
	 int tcpfd;
 | 
						|
	 char **path;
 | 
						|
	 int tmp;
 | 
						|
 | 
						|
	 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;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
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);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
create_and_write_cookie (char *xauthfile,
 | 
						|
			 size_t size,
 | 
						|
			 u_char *cookie,
 | 
						|
			 size_t sz)
 | 
						|
{
 | 
						|
     Xauth auth;
 | 
						|
     char tmp[64];
 | 
						|
     int fd;
 | 
						|
     FILE *f;
 | 
						|
     char hostname[MaxHostNameLen];
 | 
						|
     struct in_addr loopback;
 | 
						|
     struct hostent *h;
 | 
						|
 | 
						|
     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 = sz;
 | 
						|
     auth.data = (char*)cookie;
 | 
						|
     des_rand_data (cookie, sz);
 | 
						|
 | 
						|
     strcpy_truncate(xauthfile, "/tmp/AXXXXXX", size);
 | 
						|
     fd = mkstemp(xauthfile);
 | 
						|
     if(fd < 0) {
 | 
						|
	 syslog(LOG_ERR, "create_and_write_cookie: mkstemp: %m");
 | 
						|
         return 1;
 | 
						|
     }
 | 
						|
     f = fdopen(fd, "r+");
 | 
						|
     if(f == NULL){
 | 
						|
	 close(fd);
 | 
						|
	 return 1;
 | 
						|
     }
 | 
						|
     if(XauWriteAuth(f, &auth) == 0) {
 | 
						|
	  fclose(f);
 | 
						|
	  return 1;
 | 
						|
     }
 | 
						|
 | 
						|
     h = gethostbyname (hostname);
 | 
						|
     if (h == NULL) {
 | 
						|
	  fclose (f);
 | 
						|
	  return 1;
 | 
						|
     }
 | 
						|
 | 
						|
     /*
 | 
						|
      * 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) {
 | 
						|
	  fclose (f);
 | 
						|
	  return 1;
 | 
						|
     }
 | 
						|
 | 
						|
     if(fclose(f))
 | 
						|
	  return 1;
 | 
						|
     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.
 | 
						|
 */
 | 
						|
 | 
						|
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};
 | 
						|
 | 
						|
     if (krb_net_read (fd, beg, sizeof(beg)) != sizeof(beg))
 | 
						|
	  return 1;
 | 
						|
     if (krb_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);
 | 
						|
	 goto fail;
 | 
						|
     }
 | 
						|
     if (krb_net_read (fd, protocol_name, n + npad) != n + npad)
 | 
						|
	 goto fail;
 | 
						|
     if (krb_net_read (fd, protocol_data, d + dpad) != d + dpad)
 | 
						|
	 goto fail;
 | 
						|
     if (cookiesp) {
 | 
						|
	 if (strncmp (protocol_name, COOKIE_TYPE, strlen(COOKIE_TYPE)) != 0)
 | 
						|
	     goto fail;
 | 
						|
	 if (d != cookie_len ||
 | 
						|
	     memcmp (protocol_data, cookie, cookie_len) != 0)
 | 
						|
	     goto fail;
 | 
						|
     }
 | 
						|
     free (protocol_name);
 | 
						|
     free (protocol_data);
 | 
						|
     if (krb_net_write (sock, zeros, 6) != 6)
 | 
						|
	  return 1;
 | 
						|
     return 0;
 | 
						|
fail:
 | 
						|
     free (protocol_name);
 | 
						|
     free (protocol_data);
 | 
						|
     return 1;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * 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;
 | 
						|
     Xauth *auth;
 | 
						|
     FILE *f;
 | 
						|
     u_char zeros[6] = {0, 0, 0, 0, 0, 0};
 | 
						|
 | 
						|
     if (krb_net_read (fd, beg, sizeof(beg)) != sizeof(beg))
 | 
						|
	  return 1;
 | 
						|
     if (krb_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) {
 | 
						|
	  u_char len[6] = {0, 0, 0, 0, 0, 0};
 | 
						|
 | 
						|
	  auth = XauReadAuth(f);
 | 
						|
	  fclose(f);
 | 
						|
	  n = auth->name_length;
 | 
						|
	  d = auth->data_length;
 | 
						|
	  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 (krb_net_write (xserver, len, 6) != 6)
 | 
						|
	       return 1;
 | 
						|
	  if(krb_net_write (xserver, auth->name, n) != n)
 | 
						|
	       return 1;
 | 
						|
	  npad = (4 - (n % 4)) % 4;
 | 
						|
	  if (npad) { 
 | 
						|
	       if (krb_net_write (xserver, zeros, npad) != npad)
 | 
						|
		    return 1;
 | 
						|
	  }
 | 
						|
	  if (krb_net_write (xserver, auth->data, d) != d)
 | 
						|
	       return 1;
 | 
						|
	  dpad = (4 - (d % 4)) % 4;
 | 
						|
	  if (dpad) { 
 | 
						|
	       if (krb_net_write (xserver, zeros, dpad) != dpad)
 | 
						|
		    return 1;
 | 
						|
	  }
 | 
						|
	  XauDisposeAuth(auth);
 | 
						|
     } else {
 | 
						|
	  if(krb_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
 | 
						|
    ;
 | 
						|
}
 |