summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
commit2f9dac1bee2aa9d396899f42c10e84a432ac31ff (patch)
tree360d9e05d43da78c7c67d137972e07ca47682e16
downloadxorg-app-xauth-2f9dac1bee2aa9d396899f42c10e84a432ac31ff.tar.gz
R6.6 is the Xorg base-lineXORG-MAINXORG-STABLE
-rw-r--r--gethost.c283
-rw-r--r--parsedpy.c225
-rw-r--r--process.c1857
-rw-r--r--xauth.c166
-rw-r--r--xauth.h54
-rw-r--r--xauth.man233
6 files changed, 2818 insertions, 0 deletions
diff --git a/gethost.c b/gethost.c
new file mode 100644
index 0000000..bd71bc1
--- /dev/null
+++ b/gethost.c
@@ -0,0 +1,283 @@
+/*
+ * $Xorg: gethost.c,v 1.5 2001/02/09 02:05:38 xorgcvs Exp $
+ *
+ *
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+/* sorry, streams support does not really work yet */
+#if defined(STREAMSCONN) && defined(SVR4)
+#undef STREAMSCONN
+#define TCPCONN
+#endif
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#define EPROTOTYPE WSAEPROTOTYPE
+#endif
+#include "xauth.h"
+#include <X11/X.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+#ifndef __TYPES__
+#include <sys/types.h>
+#define __TYPES__
+#endif
+#ifndef WIN32
+#ifndef STREAMSCONN
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#ifdef SYSV
+#ifdef i386
+#ifndef sco
+#include <net/errno.h>
+#endif /* !sco */
+#endif /* i386 */
+#endif /* SYSV */
+#endif /* !STREAMSCONN */
+#endif /* !WIN32 */
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#ifdef DNETCONN
+#include <netdnet/dn.h>
+#include <netdnet/dnetdb.h>
+#endif
+
+#ifdef SIGALRM
+Bool nameserver_timedout = False;
+
+
+/*
+ * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU)
+ * or a string representing the address (18.58.0.13) if the name cannot
+ * be found. Stolen from xhost.
+ */
+
+static jmp_buf env;
+static
+#ifdef SIGNALRETURNSINT
+int
+#else
+void
+#endif
+nameserver_lost(sig)
+{
+ nameserver_timedout = True;
+ longjmp (env, -1);
+ /* NOTREACHED */
+#ifdef SIGNALRETURNSINT
+ return -1; /* for picky compilers */
+#endif
+}
+#endif
+
+char *get_hostname (auth)
+ Xauth *auth;
+{
+ struct hostent *hp = NULL;
+#ifndef WIN32
+ char *inet_ntoa();
+#endif
+#ifdef DNETCONN
+ struct nodeent *np;
+ static char nodeaddr[4 + 2 * DN_MAXADDL];
+#endif /* DNETCONN */
+
+ if (auth->address_length == 0)
+ return "Illegal Address";
+#ifdef TCPCONN
+ if (auth->family == FamilyInternet) {
+#ifdef SIGALRM
+ /* gethostbyaddr can take a LONG time if the host does not exist.
+ Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
+ that something is wrong and do not make the user wait.
+ gethostbyaddr will continue after a signal, so we have to
+ jump out of it.
+ */
+ nameserver_timedout = False;
+ signal (SIGALRM, nameserver_lost);
+ alarm (4);
+ if (setjmp(env) == 0) {
+#endif
+ hp = gethostbyaddr (auth->address, auth->address_length, AF_INET);
+#ifdef SIGALRM
+ }
+ alarm (0);
+#endif
+ if (hp)
+ return (hp->h_name);
+ else
+ return (inet_ntoa(*((struct in_addr *)(auth->address))));
+ }
+#endif
+#ifdef DNETCONN
+ if (auth->family == FamilyDECnet) {
+ struct dn_naddr *addr_ptr = (struct dn_naddr *) auth->address;
+
+ if (np = getnodebyaddr(addr_ptr->a_addr, addr_ptr->a_len, AF_DECnet)) {
+ sprintf(nodeaddr, "%s:", np->n_name);
+ } else {
+ sprintf(nodeaddr, "%s:", dnet_htoa(auth->address));
+ }
+ return(nodeaddr);
+ }
+#endif
+
+ return (NULL);
+}
+
+#ifdef TCPCONN
+/*
+ * cribbed from lib/X/XConnDis.c
+ */
+static Bool get_inet_address (name, resultp)
+ char *name;
+ unsigned long *resultp; /* return */
+{
+ unsigned long hostinetaddr = inet_addr (name);
+ struct hostent *host_ptr;
+ struct sockaddr_in inaddr; /* dummy variable for size calcs */
+
+ if (hostinetaddr == -1) { /* oh, gross.... */
+ if ((host_ptr = gethostbyname (name)) == NULL) {
+ /* No such host! */
+ errno = EINVAL;
+ return False;
+ }
+ /* Check the address type for an internet host. */
+ if (host_ptr->h_addrtype != AF_INET) {
+ /* Not an Internet host! */
+ errno = EPROTOTYPE;
+ return False;
+ }
+
+ memmove( (char *)&hostinetaddr, (char *)host_ptr->h_addr,
+ sizeof(inaddr.sin_addr));
+ }
+ *resultp = hostinetaddr;
+ return True;
+}
+#endif
+
+#ifdef DNETCONN
+static Bool get_dnet_address (name, resultp)
+ char *name;
+ struct dn_naddr *resultp;
+{
+ struct dn_naddr *dnaddrp, dnaddr;
+ struct nodeent *np;
+
+ if (dnaddrp = dnet_addr (name)) { /* stolen from xhost */
+ dnaddr = *dnaddrp;
+ } else {
+ if ((np = getnodebyname (name)) == NULL) return False;
+ dnaddr.a_len = np->n_length;
+ memmove( dnaddr.a_addr, np->n_addr, np->n_length);
+ }
+ *resultp = dnaddr;
+ return True;
+}
+#endif
+
+char *get_address_info (family, fulldpyname, prefix, host, lenp)
+ int family;
+ char *fulldpyname;
+ int prefix;
+ char *host;
+ int *lenp;
+{
+ char *retval = NULL;
+ int len = 0;
+ char *src = NULL;
+#ifdef TCPCONN
+ unsigned long hostinetaddr;
+#endif
+#ifdef DNETCONN
+ struct dn_naddr dnaddr;
+#endif
+ char buf[255];
+
+ /*
+ * based on the family, set the pointer src to the start of the address
+ * information to be copied and set len to the number of bytes.
+ */
+ switch (family) {
+ case FamilyLocal: /* hostname/unix:0 */
+ /* handle unix:0 and :0 specially */
+ if (prefix == 0 && (strncmp (fulldpyname, "unix:", 5) == 0 ||
+ fulldpyname[0] == ':')) {
+ extern char *get_local_hostname();
+
+ if (!get_local_hostname (buf, sizeof buf)) {
+ len = 0;
+ } else {
+ src = buf;
+ len = strlen (buf);
+ }
+ } else {
+ src = fulldpyname;
+ len = prefix;
+ }
+ break;
+ case FamilyInternet: /* host:0 */
+#ifdef TCPCONN
+ if (!get_inet_address (host, &hostinetaddr)) return NULL;
+ src = (char *) &hostinetaddr;
+ len = 4; /* sizeof inaddr.sin_addr, would fail on Cray */
+ break;
+#else
+ return NULL;
+#endif
+ case FamilyDECnet: /* host::0 */
+#ifdef DNETCONN
+ if (!get_dnet_address (host, &dnaddr)) return NULL;
+ src = (char *) &dnaddr;
+ len = (sizeof dnaddr);
+ break;
+#else
+ /* fall through since we don't have code for it */
+#endif
+ default:
+ src = NULL;
+ len = 0;
+ }
+
+ /*
+ * if source was provided, allocate space and copy it
+ */
+ if (len == 0 || !src) return NULL;
+
+ retval = malloc (len);
+ if (retval) {
+ memmove( retval, src, len);
+ *lenp = len;
+ }
+ return retval;
+}
diff --git a/parsedpy.c b/parsedpy.c
new file mode 100644
index 0000000..ebfd49e
--- /dev/null
+++ b/parsedpy.c
@@ -0,0 +1,225 @@
+/*
+ * $Xorg: parsedpy.c,v 1.4 2001/02/09 02:05:38 xorgcvs Exp $
+ *
+ * parse_displayname - utility routine for splitting up display name strings
+ *
+ *
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#include <stdio.h> /* for NULL */
+#include <ctype.h> /* for isascii() and isdigit() */
+#include <X11/Xos.h> /* for strchr() and string routines */
+#include <X11/Xlib.h> /* for Family contants */
+#ifdef hpux
+#include <sys/utsname.h> /* for struct utsname */
+#endif
+#include <X11/Xauth.h> /* for FamilyLocal */
+#include <X11/Xmu/SysUtil.h>
+
+#ifdef UNIXCONN
+#define UNIX_CONNECTION "unix"
+#define UNIX_CONNECTION_LENGTH 4
+#endif
+
+extern char *malloc();
+
+
+/*
+ * private utility routines
+ */
+
+/*static*/ char *copystring (src, len)
+ char *src;
+ int len;
+{
+ char *cp;
+
+ if (!src && len != 0) return NULL;
+ cp = malloc (len + 1);
+ if (cp) {
+ if (src) strncpy (cp, src, len);
+ cp[len] = '\0';
+ }
+ return cp;
+}
+
+
+char *get_local_hostname (buf, maxlen)
+ char *buf;
+ int maxlen;
+{
+ buf[0] = '\0';
+ (void) XmuGetHostname (buf, maxlen);
+ return (buf[0] ? buf : NULL);
+}
+
+#ifndef UNIXCONN
+static char *copyhostname ()
+{
+ char buf[256];
+
+ return (get_local_hostname (buf, sizeof buf) ?
+ copystring (buf, strlen (buf)) : NULL);
+}
+#endif
+
+/*
+ * parse_displayname - display a display string up into its component parts
+ */
+Bool parse_displayname (displayname, familyp, hostp, dpynump, scrnump, restp)
+ char *displayname;
+ int *familyp; /* return */
+ char **hostp; /* return */
+ int *dpynump, *scrnump; /* return */
+ char **restp; /* return */
+{
+ char *ptr; /* work variables */
+ int len; /* work variable */
+ int family = -1; /* value to be returned */
+ char *host = NULL; /* must free if set and error return */
+ int dpynum = -1; /* value to be returned */
+ int scrnum = 0; /* value to be returned */
+ char *rest = NULL; /* must free if set and error return */
+ Bool dnet = False; /* if true then using DECnet */
+
+ /* check the name */
+ if (!displayname || !displayname[0]) return False;
+
+ /* must have at least :number */
+ ptr = strchr(displayname, ':');
+ if (!ptr || !ptr[1]) return False;
+ if (ptr[1] == ':') {
+ if (ptr[2] == '\0') return False;
+ dnet = True;
+ }
+
+
+ /*
+ * get the host string; if none is given, use the most effiecient path
+ */
+
+ len = (ptr - displayname); /* length of host name */
+ if (len == 0) { /* choose most efficient path */
+#ifdef UNIXCONN
+ host = copystring (UNIX_CONNECTION, UNIX_CONNECTION_LENGTH);
+ family = FamilyLocal;
+#else
+ if (dnet) {
+ host = copystring ("0", 1);
+ family = FamilyDECnet;
+ } else {
+ host = copyhostname ();
+ family = FamilyInternet;
+ }
+#endif
+ } else {
+ host = copystring (displayname, len);
+ if (dnet) {
+ family = dnet;
+ } else {
+#ifdef UNIXCONN
+ if (host && strcmp (host, UNIX_CONNECTION) == 0)
+ family = FamilyLocal;
+ else
+#endif
+ family = FamilyInternet;
+ }
+ }
+
+ if (!host) return False;
+
+
+ /*
+ * get the display number; we know that there is something after the
+ * colon (or colons) from above. note that host is now set and must
+ * be freed if there is an error.
+ */
+
+ if (dnet) ptr++; /* skip the extra DECnet colon */
+ ptr++; /* move to start of display num */
+ {
+ register char *cp;
+
+ for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ;
+ len = (cp - ptr);
+ /* check present and valid follow */
+ if (len == 0 || (*cp && *cp != '.')) {
+ free (host);
+ return False;
+ }
+
+ dpynum = atoi (ptr); /* it will handle num. as well */
+ ptr = cp;
+ }
+
+ /*
+ * now get screen number if given; ptr may point to nul at this point
+ */
+ if (ptr[0] == '.') {
+ register char *cp;
+
+ ptr++;
+ for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ;
+ len = (cp - ptr);
+ if (len == 0 || (*cp && *cp != '.')) { /* all prop name */
+ free (host);
+ return False;
+ }
+
+ scrnum = atoi (ptr); /* it will handle num. as well */
+ ptr = cp;
+ }
+
+ /*
+ * and finally, get any additional stuff that might be following the
+ * the screen number; ptr must point to a period if there is anything
+ */
+
+ if (ptr[0] == '.') {
+ ptr++;
+ len = strlen (ptr);
+ if (len > 0) {
+ rest = copystring (ptr, len);
+ if (!rest) {
+ free (host);
+ return False;
+ }
+ }
+ }
+
+ /*
+ * and we are done!
+ */
+
+ *familyp = family;
+ *hostp = host;
+ *dpynump = dpynum;
+ *scrnump = scrnum;
+ *restp = rest;
+ return True;
+}
+
+
diff --git a/process.c b/process.c
new file mode 100644
index 0000000..788c49e
--- /dev/null
+++ b/process.c
@@ -0,0 +1,1857 @@
+/* $Xorg: process.c,v 1.6 2001/02/09 02:05:38 xorgcvs Exp $ */
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+/*
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#include "xauth.h"
+#include <ctype.h>
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#include <signal.h>
+#include <X11/X.h> /* for Family constants */
+
+#include <X11/Xlib.h>
+#include <X11/extensions/security.h>
+
+extern char *get_hostname();
+extern Bool nameserver_timedout;
+
+#ifndef DEFAULT_PROTOCOL_ABBREV /* to make add command easier */
+#define DEFAULT_PROTOCOL_ABBREV "."
+#endif
+#ifndef DEFAULT_PROTOCOL /* for protocol abbreviation */
+#define DEFAULT_PROTOCOL "MIT-MAGIC-COOKIE-1"
+#endif
+
+#define SECURERPC "SUN-DES-1"
+#define K5AUTH "MIT-KERBEROS-5"
+
+#define XAUTH_DEFAULT_RETRIES 10 /* number of competitors we expect */
+#define XAUTH_DEFAULT_TIMEOUT 2 /* in seconds, be quick */
+#define XAUTH_DEFAULT_DEADTIME 600L /* 10 minutes in seconds */
+
+typedef struct _AuthList { /* linked list of entries */
+ struct _AuthList *next;
+ Xauth *auth;
+} AuthList;
+
+#define add_to_list(h,t,e) {if (t) (t)->next = (e); else (h) = (e); (t) = (e);}
+
+typedef struct _CommandTable { /* commands that are understood */
+ char *name; /* full name */
+ int minlen; /* unique prefix */
+ int maxlen; /* strlen(name) */
+ int (*processfunc)(); /* handler */
+ char *helptext; /* what to print for help */
+} CommandTable;
+
+struct _extract_data { /* for iterating */
+ FILE *fp; /* input source */
+ char *filename; /* name of input */
+ Bool used_stdout; /* whether or not need to close */
+ Bool numeric; /* format in which to write */
+ int nwritten; /* number of entries written */
+ char *cmd; /* for error messages */
+};
+
+struct _list_data { /* for iterating */
+ FILE *fp; /* output file */
+ Bool numeric; /* format in which to write */
+};
+
+
+/*
+ * private data
+ */
+static char *stdin_filename = "(stdin)"; /* for messages */
+static char *stdout_filename = "(stdout)"; /* for messages */
+static char *Yes = "yes"; /* for messages */
+static char *No = "no"; /* for messages */
+
+static int do_list(), do_merge(), do_extract(), do_add(), do_remove();
+static int do_help(), do_source(), do_info(), do_exit();
+static int do_quit(), do_questionmark(), do_generate();
+
+static CommandTable command_table[] = { /* table of known commands */
+ { "add", 2, 3, do_add,
+ "add dpyname protoname hexkey add entry" },
+ { "exit", 3, 4, do_exit,
+ "exit save changes and exit program" },
+ { "extract", 3, 7, do_extract,
+ "extract filename dpyname... extract entries into file" },
+ { "help", 1, 4, do_help,
+ "help [topic] print help" },
+ { "info", 1, 4, do_info,
+ "info print information about entries" },
+ { "list", 1, 4, do_list,
+ "list [dpyname...] list entries" },
+ { "merge", 1, 5, do_merge,
+ "merge filename... merge entries from files" },
+ { "nextract", 2, 8, do_extract,
+ "nextract filename dpyname... numerically extract entries" },
+ { "nlist", 2, 5, do_list,
+ "nlist [dpyname...] numerically list entries" },
+ { "nmerge", 2, 6, do_merge,
+ "nmerge filename... numerically merge entries" },
+ { "quit", 1, 4, do_quit,
+ "quit abort changes and exit program" },
+ { "remove", 1, 6, do_remove,
+ "remove dpyname... remove entries" },
+ { "source", 1, 6, do_source,
+ "source filename read commands from file" },
+ { "?", 1, 1, do_questionmark,
+ "? list available commands" },
+ { "generate", 1, 8, do_generate,
+ "generate dpyname protoname [options] use server to generate entry\n"
+ " options are:\n"
+ " timeout n authorization expiration time in seconds\n"
+ " trusted clients using this entry are trusted\n"
+ " untrusted clients using this entry are untrusted\n"
+ " group n clients using this entry belong to application group n\n"
+ " data hexkey auth protocol specific data needed to generate the entry\n"
+ },
+ { NULL, 0, 0, NULL, NULL },
+};
+
+#define COMMAND_NAMES_PADDED_WIDTH 10 /* wider than anything above */
+
+
+static Bool okay_to_use_stdin = True; /* set to false after using */
+
+static char *hex_table[] = { /* for printing hex digits */
+ "00", "01", "02", "03", "04", "05", "06", "07",
+ "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
+ "10", "11", "12", "13", "14", "15", "16", "17",
+ "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
+ "20", "21", "22", "23", "24", "25", "26", "27",
+ "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
+ "30", "31", "32", "33", "34", "35", "36", "37",
+ "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
+ "40", "41", "42", "43", "44", "45", "46", "47",
+ "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
+ "50", "51", "52", "53", "54", "55", "56", "57",
+ "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
+ "60", "61", "62", "63", "64", "65", "66", "67",
+ "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
+ "70", "71", "72", "73", "74", "75", "76", "77",
+ "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
+ "80", "81", "82", "83", "84", "85", "86", "87",
+ "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
+ "90", "91", "92", "93", "94", "95", "96", "97",
+ "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
+ "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
+ "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
+ "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
+ "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
+ "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7",
+ "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "d8", "d9", "da", "db", "dc", "dd", "de", "df",
+ "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7",
+ "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
+};
+
+static unsigned int hexvalues[256]; /* for parsing hex input */
+
+static int original_umask = 0; /* for restoring */
+
+
+/*
+ * private utility procedures
+ */
+
+static void prefix (fn, n)
+ char *fn;
+ int n;
+{
+ fprintf (stderr, "%s: %s:%d: ", ProgramName, fn, n);
+}
+
+static void baddisplayname (dpy, cmd)
+ char *dpy, *cmd;
+{
+ fprintf (stderr, "bad display name \"%s\" in \"%s\" command\n",
+ dpy, cmd);
+}
+
+static void badcommandline (cmd)
+ char *cmd;
+{
+ fprintf (stderr, "bad \"%s\" command line\n", cmd);
+}
+
+static char *skip_space (s)
+ register char *s;
+{
+ if (!s) return NULL;
+
+ for ( ; *s && isascii(*s) && isspace(*s); s++)
+ ;
+ return s;
+}
+
+
+static char *skip_nonspace (s)
+ register char *s;
+{
+ if (!s) return NULL;
+
+ /* put quoting into loop if need be */
+ for ( ; *s && isascii(*s) && !isspace(*s); s++)
+ ;
+ return s;
+}
+
+static char **split_into_words (src, argcp) /* argvify string */
+ char *src;
+ int *argcp;
+{
+ char *jword;
+ char savec;
+ char **argv;
+ int cur, total;
+
+ *argcp = 0;
+#define WORDSTOALLOC 4 /* most lines are short */
+ argv = (char **) malloc (WORDSTOALLOC * sizeof (char *));
+ if (!argv) return NULL;
+ cur = 0;
+ total = WORDSTOALLOC;
+
+ /*
+ * split the line up into separate, nul-terminated tokens; the last
+ * "token" will point to the empty string so that it can be bashed into
+ * a null pointer.
+ */
+
+ do {
+ jword = skip_space (src);
+ src = skip_nonspace (jword);
+ savec = *src;
+ *src = '\0';
+ if (cur == total) {
+ total += WORDSTOALLOC;
+ argv = (char **) realloc (argv, total * sizeof (char *));
+ if (!argv) return NULL;
+ }
+ argv[cur++] = jword;
+ if (savec) src++; /* if not last on line advance */
+ } while (jword != src);
+
+ argv[--cur] = NULL; /* smash empty token to end list */
+ *argcp = cur;
+ return argv;
+}
+
+
+static FILE *open_file (filenamep, mode, usedstdp, srcfn, srcln, cmd)
+ char **filenamep;
+ char *mode;
+ Bool *usedstdp;
+ char *srcfn;
+ int srcln;
+ char *cmd;
+{
+ FILE *fp;
+
+ if (strcmp (*filenamep, "-") == 0) {
+ *usedstdp = True;
+ /* select std descriptor to use */
+ if (mode[0] == 'r') {
+ if (okay_to_use_stdin) {
+ okay_to_use_stdin = False;
+ *filenamep = stdin_filename;
+ return stdin;
+ } else {
+ prefix (srcfn, srcln);
+ fprintf (stderr, "%s: stdin already in use\n", cmd);
+ return NULL;
+ }
+ } else {
+ *filenamep = stdout_filename;
+ return stdout; /* always okay to use stdout */
+ }
+ }
+
+ fp = fopen (*filenamep, mode);
+ if (!fp) {
+ prefix (srcfn, srcln);
+ fprintf (stderr, "%s: unable to open file %s\n", cmd, *filenamep);
+ }
+ return fp;
+}
+
+static int getinput (fp)
+ FILE *fp;
+{
+ register int c;
+
+ while ((c = getc (fp)) != EOF && isascii(c) && c != '\n' && isspace(c)) ;
+ return c;
+}
+
+static int get_short (fp, sp) /* for reading numeric input */
+ FILE *fp;
+ unsigned short *sp;
+{
+ int c;
+ int i;
+ unsigned short us = 0;
+
+ /*
+ * read family: written with %04x
+ */
+ for (i = 0; i < 4; i++) {
+ switch (c = getinput (fp)) {
+ case EOF:
+ case '\n':
+ return 0;
+ }
+ if (c < 0 || c > 255) return 0;
+ us = (us * 16) + hexvalues[c]; /* since msb */
+ }
+ *sp = us;
+ return 1;
+}
+
+static int get_bytes (fp, n, ptr) /* for reading numeric input */
+ FILE *fp;
+ unsigned int n;
+ char **ptr;
+{
+ char *s;
+ register char *cp;
+ int c1, c2;
+
+ cp = s = malloc (n);
+ if (!cp) return 0;
+
+ while (n > 0) {
+ if ((c1 = getinput (fp)) == EOF || c1 == '\n' ||
+ (c2 = getinput (fp)) == EOF || c2 == '\n') {
+ free (s);
+ return 0;
+ }
+ *cp = (char) ((hexvalues[c1] * 16) + hexvalues[c2]);
+ cp++;
+ n--;
+ }
+
+ *ptr = s;
+ return 1;
+}
+
+
+static Xauth *read_numeric (fp)
+ FILE *fp;
+{
+ Xauth *auth;
+
+ auth = (Xauth *) malloc (sizeof (Xauth));
+ if (!auth) goto bad;
+ auth->family = 0;
+ auth->address = NULL;
+ auth->address_length = 0;
+ auth->number = NULL;
+ auth->number_length = 0;
+ auth->name = NULL;
+ auth->name_length = 0;
+ auth->data = NULL;
+ auth->data_length = 0;
+
+ if (!get_short (fp, (unsigned short *) &auth->family))
+ goto bad;
+ if (!get_short (fp, (unsigned short *) &auth->address_length))
+ goto bad;
+ if (!get_bytes (fp, (unsigned int) auth->address_length, &auth->address))
+ goto bad;
+ if (!get_short (fp, (unsigned short *) &auth->number_length))
+ goto bad;
+ if (!get_bytes (fp, (unsigned int) auth->number_length, &auth->number))
+ goto bad;
+ if (!get_short (fp, (unsigned short *) &auth->name_length))
+ goto bad;
+ if (!get_bytes (fp, (unsigned int) auth->name_length, &auth->name))
+ goto bad;
+ if (!get_short (fp, (unsigned short *) &auth->data_length))
+ goto bad;
+ if (!get_bytes (fp, (unsigned int) auth->data_length, &auth->data))
+ goto bad;
+
+ switch (getinput (fp)) { /* get end of line */
+ case EOF:
+ case '\n':
+ return auth;
+ }
+
+ bad:
+ if (auth) XauDisposeAuth (auth); /* won't free null pointers */
+ return NULL;
+}
+
+static int read_auth_entries (fp, numeric, headp, tailp)
+ FILE *fp;
+ Bool numeric;
+ AuthList **headp, **tailp;
+{
+ Xauth *((*readfunc)()) = (numeric ? read_numeric : XauReadAuth);
+ Xauth *auth;
+ AuthList *head, *tail;
+ int n;
+
+ head = tail = NULL;
+ n = 0;
+ /* put all records into linked list */
+ while ((auth = ((*readfunc) (fp))) != NULL) {
+ AuthList *l = (AuthList *) malloc (sizeof (AuthList));
+ if (!l) {
+ fprintf (stderr,
+ "%s: unable to alloc entry reading auth file\n",
+ ProgramName);
+ exit (1);
+ }
+ l->next = NULL;
+ l->auth = auth;
+ if (tail) /* if not first time through append */
+ tail->next = l;
+ else
+ head = l; /* first time through, so assign */
+ tail = l;
+ n++;
+ }
+ *headp = head;
+ *tailp = tail;
+ return n;
+}
+
+static Bool get_displayname_auth (displayname, auth)
+ char *displayname;
+ Xauth *auth; /* fill in */
+{
+ int family;
+ char *host = NULL, *rest = NULL;
+ int dpynum, scrnum;
+ char *cp;
+ int len;
+ extern char *get_address_info();
+ Xauth proto;
+ int prelen = 0;
+
+ /*
+ * check to see if the display name is of the form "host/unix:"
+ * which is how the list routine prints out local connections
+ */
+ cp = strchr(displayname, '/');
+ if (cp && strncmp (cp, "/unix:", 6) == 0)
+ prelen = (cp - displayname);
+
+ if (!parse_displayname (displayname + ((prelen > 0) ? prelen + 1 : 0),
+ &family, &host, &dpynum, &scrnum, &rest)) {
+ return False;
+ }
+
+ proto.family = family;
+ proto.address = get_address_info (family, displayname, prelen, host, &len);
+ if (proto.address) {
+ char buf[40]; /* want to hold largest display num */
+
+ proto.address_length = len;
+ buf[0] = '\0';
+ sprintf (buf, "%d", dpynum);
+ proto.number_length = strlen (buf);
+ if (proto.number_length <= 0) {
+ free (proto.address);
+ proto.address = NULL;
+ } else {
+ proto.number = copystring (buf, proto.number_length);
+ }
+ }
+
+ if (host) free (host);
+ if (rest) free (rest);
+
+ if (proto.address) {
+ auth->family = proto.family;
+ auth->address = proto.address;
+ auth->address_length = proto.address_length;
+ auth->number = proto.number;
+ auth->number_length = proto.number_length;
+ auth->name = NULL;
+ auth->name_length = 0;
+ auth->data = NULL;
+ auth->data_length = 0;
+ return True;
+ } else {
+ return False;
+ }
+}
+
+static int cvthexkey (hexstr, ptrp) /* turn hex key string into octets */
+ char *hexstr;
+ char **ptrp;
+{
+ int i;
+ int len = 0;
+ char *retval, *s;
+ unsigned char *us;
+ char c;
+ char savec = '\0';
+
+ /* count */
+ for (s = hexstr; *s; s++) {
+ if (!isascii(*s)) return -1;
+ if (isspace(*s)) continue;
+ if (!isxdigit(*s)) return -1;
+ len++;
+ }
+
+ /* if odd then there was an error */
+ if ((len & 1) == 1) return -1;
+
+
+ /* now we know that the input is good */
+ len >>= 1;
+ retval = malloc (len);
+ if (!retval) {
+ fprintf (stderr, "%s: unable to allocate %d bytes for hexkey\n",
+ ProgramName, len);
+ return -1;
+ }
+
+ for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) {
+ c = *hexstr;
+ if (isspace(c)) continue; /* already know it is ascii */
+ if (isupper(c))
+ c = tolower(c);
+ if (savec) {
+#define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10)))
+ *us = (unsigned char)((atoh(savec) << 4) + atoh(c));
+#undef atoh
+ savec = 0; /* ready for next character */
+ us++;
+ i--;
+ } else {
+ savec = c;
+ }
+ }
+ *ptrp = retval;
+ return len;
+}
+
+static int dispatch_command (inputfilename, lineno, argc, argv, tab, statusp)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+ CommandTable *tab;
+ int *statusp;
+{
+ CommandTable *ct;
+ char *cmd;
+ int n;
+ /* scan table for command */
+ cmd = argv[0];
+ n = strlen (cmd);
+ for (ct = tab; ct->name; ct++) {
+ /* look for unique prefix */
+ if (n >= ct->minlen && n <= ct->maxlen &&
+ strncmp (cmd, ct->name, n) == 0) {
+ *statusp = (*(ct->processfunc))(inputfilename, lineno, argc, argv);
+ return 1;
+ }
+ }
+
+ *statusp = 1;
+ return 0;
+}
+
+
+static AuthList *xauth_head = NULL; /* list of auth entries */
+static Bool xauth_existed = False; /* if was present at initialize */
+static Bool xauth_modified = False; /* if added, removed, or merged */
+static Bool xauth_allowed = True; /* if allowed to write auth file */
+static char *xauth_filename = NULL;
+static Bool dieing = False;
+
+#ifdef SIGNALRETURNSINT
+#define _signal_t int
+#else
+#define _signal_t void
+#endif
+
+/* poor man's puts(), for under signal handlers */
+#define WRITES(fd, S) (void)write((fd), (S), strlen((S)))
+
+/* ARGSUSED */
+static _signal_t die (sig)
+ int sig;
+{
+ dieing = True;
+ exit (auth_finalize ());
+ /* NOTREACHED */
+#ifdef SIGNALRETURNSINT
+ return -1; /* for picky compilers */
+#endif
+}
+
+static _signal_t catchsig (sig)
+ int sig;
+{
+#ifdef SYSV
+ if (sig > 0) signal (sig, die); /* re-establish signal handler */
+#endif
+ if (verbose && xauth_modified) WRITES(fileno(stdout), "\r\n");
+ die (sig);
+ /* NOTREACHED */
+#ifdef SIGNALRETURNSINT
+ return -1; /* for picky compilers */
+#endif
+}
+
+static void register_signals ()
+{
+ signal (SIGINT, catchsig);
+ signal (SIGTERM, catchsig);
+#ifdef SIGHUP
+ signal (SIGHUP, catchsig);
+#endif
+ return;
+}
+
+
+/*
+ * public procedures for parsing lines of input
+ */
+
+int auth_initialize (authfilename)
+ char *authfilename;
+{
+ int n;
+ AuthList *head, *tail;
+ FILE *authfp;
+ Bool exists;
+
+ xauth_filename = authfilename; /* used in cleanup, prevent race with
+ signals */
+ register_signals ();
+
+ bzero ((char *) hexvalues, sizeof hexvalues);
+ hexvalues['0'] = 0;
+ hexvalues['1'] = 1;
+ hexvalues['2'] = 2;
+ hexvalues['3'] = 3;
+ hexvalues['4'] = 4;
+ hexvalues['5'] = 5;
+ hexvalues['6'] = 6;
+ hexvalues['7'] = 7;
+ hexvalues['8'] = 8;
+ hexvalues['9'] = 9;
+ hexvalues['a'] = hexvalues['A'] = 0xa;
+ hexvalues['b'] = hexvalues['B'] = 0xb;
+ hexvalues['c'] = hexvalues['C'] = 0xc;
+ hexvalues['d'] = hexvalues['D'] = 0xd;
+ hexvalues['e'] = hexvalues['E'] = 0xe;
+ hexvalues['f'] = hexvalues['F'] = 0xf;
+
+ if (break_locks && verbose) {
+ printf ("Attempting to break locks on authority file %s\n",
+ authfilename);
+ }
+
+ if (ignore_locks) {
+ if (break_locks) XauUnlockAuth (authfilename);
+ } else {
+ n = XauLockAuth (authfilename, XAUTH_DEFAULT_RETRIES,
+ XAUTH_DEFAULT_TIMEOUT,
+ (break_locks ? 0L : XAUTH_DEFAULT_DEADTIME));
+ if (n != LOCK_SUCCESS) {
+ char *reason = "unknown error";
+ switch (n) {
+ case LOCK_ERROR:
+ reason = "error";
+ break;
+ case LOCK_TIMEOUT:
+ reason = "timeout";
+ break;
+ }
+ fprintf (stderr, "%s: %s in locking authority file %s\n",
+ ProgramName, reason, authfilename);
+ return -1;
+ }
+ }
+
+ /* these checks can only be done reliably after the file is locked */
+ exists = (access (authfilename, F_OK) == 0);
+ if (exists && access (authfilename, W_OK) != 0) {
+ fprintf (stderr,
+ "%s: %s not writable, changes will be ignored\n",
+ ProgramName, authfilename);
+ xauth_allowed = False;
+ }
+
+ original_umask = umask (0077); /* disallow non-owner access */
+
+ authfp = fopen (authfilename, "rb");
+ if (!authfp) {
+ int olderrno = errno;
+
+ /* if file there then error */
+ if (access (authfilename, F_OK) == 0) { /* then file does exist! */
+ errno = olderrno;
+ return -1;
+ } /* else ignore it */
+ fprintf (stderr,
+ "%s: creating new authority file %s\n",
+ ProgramName, authfilename);
+ } else {
+ xauth_existed = True;
+ n = read_auth_entries (authfp, False, &head, &tail);
+ (void) fclose (authfp);
+ if (n < 0) {
+ fprintf (stderr,
+ "%s: unable to read auth entries from file \"%s\"\n",
+ ProgramName, authfilename);
+ return -1;
+ }
+ xauth_head = head;
+ }
+
+ n = strlen (authfilename);
+ xauth_filename = malloc (n + 1);
+ if (xauth_filename) strcpy (xauth_filename, authfilename);
+ xauth_modified = False;
+
+ if (verbose) {
+ printf ("%s authority file %s\n",
+ ignore_locks ? "Ignoring locks on" : "Using", authfilename);
+ }
+ return 0;
+}
+
+static int write_auth_file (tmp_nam)
+ char *tmp_nam;
+{
+ FILE *fp;
+ AuthList *list;
+
+ /*
+ * xdm and auth spec assumes auth file is 12 or fewer characters
+ */
+ strcpy (tmp_nam, xauth_filename);
+ strcat (tmp_nam, "-n"); /* for new */
+ (void) unlink (tmp_nam);
+ fp = fopen (tmp_nam, "wb"); /* umask is still set to 0077 */
+ if (!fp) {
+ fprintf (stderr, "%s: unable to open tmp file \"%s\"\n",
+ ProgramName, tmp_nam);
+ return -1;
+ }
+
+ /*
+ * Write MIT-MAGIC-COOKIE-1 first, because R4 Xlib knows
+ * only that and uses the first authorization it finds.
+ */
+ for (list = xauth_head; list; list = list->next) {
+ if (list->auth->name_length == 18
+ && strncmp(list->auth->name, "MIT-MAGIC-COOKIE-1", 18) == 0)
+ {
+ XauWriteAuth (fp, list->auth);
+ }
+ }
+ for (list = xauth_head; list; list = list->next) {
+ if (list->auth->name_length != 18
+ || strncmp(list->auth->name, "MIT-MAGIC-COOKIE-1", 18) != 0)
+ {
+ XauWriteAuth (fp, list->auth);
+ }
+ }
+
+ (void) fclose (fp);
+ return 0;
+}
+
+int auth_finalize ()
+{
+ char temp_name[1024]; /* large filename size */
+
+ if (xauth_modified) {
+ if (dieing) {
+ if (verbose) {
+ /* called from a signal handler -- printf is *not* reentrant */
+ WRITES(fileno(stdout), "\nAborting changes to authority file ");
+ WRITES(fileno(stdout), xauth_filename);
+ WRITES(fileno(stdout), "\n");
+ }
+ } else if (!xauth_allowed) {
+ fprintf (stderr,
+ "%s: %s not writable, changes ignored\n",
+ ProgramName, xauth_filename);
+ } else {
+ if (verbose) {
+ printf ("%s authority file %s\n",
+ ignore_locks ? "Ignoring locks and writing" :
+ "Writing", xauth_filename);
+ }
+ temp_name[0] = '\0';
+ if (write_auth_file (temp_name) == -1) {
+ fprintf (stderr,
+ "%s: unable to write authority file %s\n",
+ ProgramName, temp_name);
+ } else {
+ (void) unlink (xauth_filename);
+#ifdef WIN32
+ if (rename(temp_name, xauth_filename) == -1)
+#else
+ if (link (temp_name, xauth_filename) == -1)
+#endif
+ {
+ fprintf (stderr,
+ "%s: unable to link authority file %s, use %s\n",
+ ProgramName, xauth_filename, temp_name);
+ } else {
+ (void) unlink (temp_name);
+ }
+ }
+ }
+ }
+
+ if (!ignore_locks) {
+ XauUnlockAuth (xauth_filename);
+ }
+ (void) umask (original_umask);
+ return 0;
+}
+
+int process_command (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ int status;
+
+ if (argc < 1 || !argv || !argv[0]) return 1;
+
+ if (dispatch_command (inputfilename, lineno, argc, argv,
+ command_table, &status))
+ return status;
+
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "unknown command \"%s\"\n", argv[0]);
+ return 1;
+}
+
+
+/*
+ * utility routines
+ */
+
+static char * bintohex(len, bindata)
+ unsigned int len;
+ unsigned char *bindata;
+{
+ char *hexdata, *starthex;
+
+ /* two chars per byte, plus null termination */
+ starthex = hexdata = (char *)malloc(2*len + 1);
+ if (!hexdata)
+ return NULL;
+
+ for (; len > 0; len--, bindata++) {
+ register char *s = hex_table[*bindata];
+ *hexdata++ = s[0];
+ *hexdata++ = s[1];
+ }
+ *hexdata = '\0';
+ return starthex;
+}
+
+static void fprintfhex (fp, len, cp)
+ register FILE *fp;
+ unsigned int len;
+ char *cp;
+{
+ char *hex;
+
+ hex = bintohex(len, cp);
+ fprintf(fp, hex);
+ free(hex);
+}
+
+dump_numeric (fp, auth)
+ register FILE *fp;
+ register Xauth *auth;
+{
+ fprintf (fp, "%04x", auth->family); /* unsigned short */
+ fprintf (fp, " %04x ", auth->address_length); /* short */
+ fprintfhex (fp, auth->address_length, auth->address);
+ fprintf (fp, " %04x ", auth->number_length); /* short */
+ fprintfhex (fp, auth->number_length, auth->number);
+ fprintf (fp, " %04x ", auth->name_length); /* short */
+ fprintfhex (fp, auth->name_length, auth->name);
+ fprintf (fp, " %04x ", auth->data_length); /* short */
+ fprintfhex (fp, auth->data_length, auth->data);
+ putc ('\n', fp);
+ return 1;
+}
+
+/* ARGSUSED */
+static int dump_entry (inputfilename, lineno, auth, data)
+ char *inputfilename;
+ int lineno;
+ Xauth *auth;
+ char *data;
+{
+ struct _list_data *ld = (struct _list_data *) data;
+ FILE *fp = ld->fp;
+
+ if (ld->numeric) {
+ dump_numeric (fp, auth);
+ } else {
+ char *dpyname = NULL;
+
+ switch (auth->family) {
+ case FamilyLocal:
+ fwrite (auth->address, sizeof (char), auth->address_length, fp);
+ fprintf (fp, "/unix");
+ break;
+ case FamilyInternet:
+ case FamilyDECnet:
+ dpyname = get_hostname (auth);
+ if (dpyname) {
+ fprintf (fp, "%s", dpyname);
+ break;
+ }
+ /* else fall through to default */
+ default:
+ fprintf (fp, "#%04x#", auth->family);
+ fprintfhex (fp, auth->address_length, auth->address);
+ putc ('#', fp);
+ }
+ putc (':', fp);
+ fwrite (auth->number, sizeof (char), auth->number_length, fp);
+ putc (' ', fp);
+ putc (' ', fp);
+ fwrite (auth->name, sizeof (char), auth->name_length, fp);
+ putc (' ', fp);
+ putc (' ', fp);
+ if (!strncmp(auth->name, SECURERPC, auth->name_length) ||
+ !strncmp(auth->name, K5AUTH, auth->name_length))
+ fwrite (auth->data, sizeof (char), auth->data_length, fp);
+ else
+ fprintfhex (fp, auth->data_length, auth->data);
+ putc ('\n', fp);
+ }
+ return 0;
+}
+
+static int extract_entry (inputfilename, lineno, auth, data)
+ char *inputfilename;
+ int lineno;
+ Xauth *auth;
+ char *data;
+{
+ struct _extract_data *ed = (struct _extract_data *) data;
+
+ if (!ed->fp) {
+ ed->fp = open_file (&ed->filename,
+ ed->numeric ? "w" : "wb",
+ &ed->used_stdout,
+ inputfilename, lineno, ed->cmd);
+ if (!ed->fp) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr,
+ "unable to open extraction file \"%s\"\n",
+ ed->filename);
+ return -1;
+ }
+ }
+ (*(ed->numeric ? dump_numeric : XauWriteAuth)) (ed->fp, auth);
+ ed->nwritten++;
+
+ return 0;
+}
+
+
+static int match_auth_dpy (a, b)
+ register Xauth *a, *b;
+{
+ return ((a->family == b->family &&
+ a->address_length == b->address_length &&
+ a->number_length == b->number_length &&
+ memcmp(a->address, b->address, a->address_length) == 0 &&
+ memcmp(a->number, b->number, a->number_length) == 0) ? 1 : 0);
+}
+
+/* return non-zero iff display and authorization type are the same */
+
+static int match_auth (a, b)
+ register Xauth *a, *b;
+{
+ return ((match_auth_dpy(a, b)
+ && a->name_length == b->name_length
+ && memcmp(a->name, b->name, a->name_length) == 0) ? 1 : 0);
+}
+
+
+static int merge_entries (firstp, second, nnewp, nreplp)
+ AuthList **firstp, *second;
+ int *nnewp, *nreplp;
+{
+ AuthList *a, *b, *first, *tail;
+ int n = 0, nnew = 0, nrepl = 0;
+
+ if (!second) return 0;
+
+ if (!*firstp) { /* if nothing to merge into */
+ *firstp = second;
+ for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ;
+ *nnewp = n;
+ *nreplp = 0;
+ return n;
+ }
+
+ first = *firstp;
+ /*
+ * find end of first list and stick second list on it
+ */
+ for (tail = first; tail->next; tail = tail->next) ;
+ tail->next = second;
+
+ /*
+ * run down list freeing duplicate entries; if an entry is okay, then
+ * bump the tail up to include it, otherwise, cut the entry out of
+ * the chain.
+ */
+ for (b = second; b; ) {
+ AuthList *next = b->next; /* in case we free it */
+
+ a = first;
+ for (;;) {
+ if (match_auth (a->auth, b->auth)) { /* found a duplicate */
+ AuthList tmp; /* swap it in for old one */
+ tmp = *a;
+ *a = *b;
+ *b = tmp;
+ a->next = b->next;
+ XauDisposeAuth (b->auth);
+ free ((char *) b);
+ b = NULL;
+ tail->next = next;
+ nrepl++;
+ nnew--;
+ break;
+ }
+ if (a == tail) break; /* if have looked at left side */
+ a = a->next;
+ }
+ if (b) { /* if we didn't remove it */
+ tail = b; /* bump end of first list */
+ }
+ b = next;
+ n++;
+ nnew++;
+ }
+
+ *nnewp = nnew;
+ *nreplp = nrepl;
+ return n;
+
+}
+
+
+static int iterdpy (inputfilename, lineno, start,
+ argc, argv, yfunc, nfunc, data)
+ char *inputfilename;
+ int lineno;
+ int start;
+ int argc;
+ char *argv[];
+ int (*yfunc)(), (*nfunc)();
+ char *data;
+{
+ int i;
+ int status;
+ int errors = 0;
+ Xauth proto;
+ AuthList *l, *next;
+
+ /*
+ * iterate
+ */
+ for (i = start; i < argc; i++) {
+ char *displayname = argv[i];
+ proto.address = proto.number = NULL;
+ if (!get_displayname_auth (displayname, &proto)) {
+ prefix (inputfilename, lineno);
+ baddisplayname (displayname, argv[0]);
+ errors++;
+ continue;
+ }
+ status = 0;
+ for (l = xauth_head; l; l = next) {
+ next = l->next;
+ if (match_auth_dpy (&proto, l->auth)) {
+ if (yfunc) {
+ status = (*yfunc) (inputfilename, lineno,
+ l->auth, data);
+ if (status < 0) break;
+ }
+ } else {
+ if (nfunc) {
+ status = (*nfunc) (inputfilename, lineno,
+ l->auth, data);
+ if (status < 0) break;
+ }
+ }
+ }
+ if (proto.address) free (proto.address);
+ if (proto.number) free (proto.number);
+ if (status < 0) {
+ errors -= status; /* since status is negative */
+ break;
+ }
+ }
+
+ return errors;
+}
+
+/* ARGSUSED */
+static int remove_entry (inputfilename, lineno, auth, data)
+ char *inputfilename;
+ int lineno;
+ Xauth *auth;
+ char *data;
+{
+ int *nremovedp = (int *) data;
+ AuthList **listp = &xauth_head;
+ AuthList *list;
+
+ /*
+ * unlink the auth we were asked to
+ */
+ while ((list = *listp)->auth != auth)
+ listp = &list->next;
+ *listp = list->next;
+ XauDisposeAuth (list->auth); /* free the auth */
+ free (list); /* free the link */
+ xauth_modified = True;
+ (*nremovedp)++;
+ return 1;
+}
+
+/*
+ * action routines
+ */
+
+/*
+ * help
+ */
+int print_help (fp, cmd, prefix)
+ FILE *fp;
+ char *cmd;
+ char *prefix;
+{
+ CommandTable *ct;
+ int n = 0;
+
+ if (!prefix) prefix = "";
+
+ if (!cmd) { /* if no cmd, print all help */
+ for (ct = command_table; ct->name; ct++) {
+ fprintf (fp, "%s%s\n", prefix, ct->helptext);
+ n++;
+ }
+ } else {
+ int len = strlen (cmd);
+ for (ct = command_table; ct->name; ct++) {
+ if (strncmp (cmd, ct->name, len) == 0) {
+ fprintf (fp, "%s%s\n", prefix, ct->helptext);
+ n++;
+ }
+ }
+ }
+
+ return n;
+}
+
+static int do_help (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ char *cmd = (argc > 1 ? argv[1] : NULL);
+ int n;
+
+ n = print_help (stdout, cmd, " "); /* a nice amount */
+
+ if (n < 0 || (n == 0 && !cmd)) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "internal error with help");
+ if (cmd) {
+ fprintf (stderr, " on command \"%s\"", cmd);
+ }
+ fprintf (stderr, "\n");
+ return 1;
+ }
+
+ if (n == 0) {
+ prefix (inputfilename, lineno);
+ /* already know that cmd is set in this case */
+ fprintf (stderr, "no help for noexistent command \"%s\"\n", cmd);
+ }
+
+ return 0;
+}
+
+/*
+ * questionmark
+ */
+/* ARGSUSED */
+static int do_questionmark (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ CommandTable *ct;
+ int i;
+#define WIDEST_COLUMN 72
+ int col = WIDEST_COLUMN;
+
+ printf ("Commands:\n");
+ for (ct = command_table; ct->name; ct++) {
+ if ((col + ct->maxlen) > WIDEST_COLUMN) {
+ if (ct != command_table) {
+ putc ('\n', stdout);
+ }
+ fputs (" ", stdout);
+ col = 8; /* length of string above */
+ }
+ fputs (ct->name, stdout);
+ col += ct->maxlen;
+ for (i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) {
+ putc (' ', stdout);
+ col++;
+ }
+ }
+ if (col != 0) {
+ putc ('\n', stdout);
+ }
+
+ /* allow bad lines since this is help */
+ return 0;
+}
+
+/*
+ * list [displayname ...]
+ */
+static int do_list (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ struct _list_data ld;
+
+ ld.fp = stdout;
+ ld.numeric = (argv[0][0] == 'n');
+
+ if (argc == 1) {
+ register AuthList *l;
+
+ if (xauth_head) {
+ for (l = xauth_head; l; l = l->next) {
+ dump_entry (inputfilename, lineno, l->auth, (char *) &ld);
+ }
+ }
+ return 0;
+ }
+
+ return iterdpy (inputfilename, lineno, 1, argc, argv,
+ dump_entry, NULL, (char *) &ld);
+}
+
+/*
+ * merge filename [filename ...]
+ */
+static int do_merge (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ int i;
+ int errors = 0;
+ AuthList *head, *tail, *listhead, *listtail;
+ int nentries, nnew, nrepl;
+ Bool numeric = False;
+
+ if (argc < 2) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[0]);
+ return 1;
+ }
+
+ if (argv[0][0] == 'n') numeric = True;
+ listhead = listtail = NULL;
+
+ for (i = 1; i < argc; i++) {
+ char *filename = argv[i];
+ FILE *fp;
+ Bool used_stdin = False;
+
+ fp = open_file (&filename,
+ numeric ? "r" : "rb",
+ &used_stdin, inputfilename, lineno,
+ argv[0]);
+ if (!fp) {
+ errors++;
+ continue;
+ }
+
+ head = tail = NULL;
+ nentries = read_auth_entries (fp, numeric, &head, &tail);
+ if (nentries == 0) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "unable to read any entries from file \"%s\"\n",
+ filename);
+ errors++;
+ } else { /* link it in */
+ add_to_list (listhead, listtail, head);
+ }
+
+ if (!used_stdin) (void) fclose (fp);
+ }
+
+ /*
+ * if we have new entries, merge them in (freeing any duplicates)
+ */
+ if (listhead) {
+ nentries = merge_entries (&xauth_head, listhead, &nnew, &nrepl);
+ if (verbose)
+ printf ("%d entries read in: %d new, %d replacement%s\n",
+ nentries, nnew, nrepl, nrepl != 1 ? "s" : "");
+ if (nentries > 0) xauth_modified = True;
+ }
+
+ return 0;
+}
+
+/*
+ * extract filename displayname [displayname ...]
+ */
+static int do_extract (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ int errors;
+ struct _extract_data ed;
+
+ if (argc < 3) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[0]);
+ return 1;
+ }
+
+ ed.fp = NULL;
+ ed.filename = argv[1];
+ ed.numeric = (argv[0][0] == 'n');
+ ed.nwritten = 0;
+ ed.cmd = argv[0];
+
+ errors = iterdpy (inputfilename, lineno, 2, argc, argv,
+ extract_entry, NULL, (char *) &ed);
+
+ if (!ed.fp) {
+ fprintf (stderr,
+ "No matches found, authority file \"%s\" not written\n",
+ ed.filename);
+ } else {
+ if (verbose) {
+ printf ("%d entries written to \"%s\"\n",
+ ed.nwritten, ed.filename);
+ }
+ if (!ed.used_stdout) {
+ (void) fclose (ed.fp);
+ }
+ }
+
+ return errors;
+}
+
+
+/*
+ * add displayname protocolname hexkey
+ */
+static int do_add (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ int n, nnew, nrepl;
+ int len;
+ char *dpyname;
+ char *protoname;
+ char *hexkey;
+ char *key;
+ Xauth *auth;
+ AuthList *list;
+
+ if (argc != 4 || !argv[1] || !argv[2] || !argv[3]) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[0]);
+ return 1;
+ }
+
+ dpyname = argv[1];
+ protoname = argv[2];
+ hexkey = argv[3];
+
+ len = strlen(hexkey);
+ if (hexkey[0] == '"' && hexkey[len-1] == '"') {
+ key = malloc(len-1);
+ strncpy(key, hexkey+1, len-2);
+ len -= 2;
+ } else if (!strcmp(protoname, SECURERPC) ||
+ !strcmp(protoname, K5AUTH)) {
+ key = malloc(len+1);
+ strcpy(key, hexkey);
+ } else {
+ len = cvthexkey (hexkey, &key);
+ if (len < 0) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr,
+ "key contains odd number of or non-hex characters\n");
+ return 1;
+ }
+ }
+
+ auth = (Xauth *) malloc (sizeof (Xauth));
+ if (!auth) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "unable to allocate %d bytes for Xauth structure\n",
+ sizeof (Xauth));
+ free (key);
+ return 1;
+ }
+
+ if (!get_displayname_auth (dpyname, auth)) {
+ prefix (inputfilename, lineno);
+ baddisplayname (dpyname, argv[0]);
+ free (auth);
+ free (key);
+ return 1;
+ }
+
+ /*
+ * allow an abbreviation for common protocol names
+ */
+ if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) {
+ protoname = DEFAULT_PROTOCOL;
+ }
+
+ auth->name_length = strlen (protoname);
+ auth->name = copystring (protoname, auth->name_length);
+ if (!auth->name) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "unable to allocate %d character protocol name\n",
+ auth->name_length);
+ free (auth);
+ free (key);
+ return 1;
+ }
+ auth->data_length = len;
+ auth->data = key;
+
+ list = (AuthList *) malloc (sizeof (AuthList));
+ if (!list) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "unable to allocate %d bytes for auth list\n",
+ sizeof (AuthList));
+ free (auth);
+ free (key);
+ free (auth->name);
+ return 1;
+ }
+
+ list->next = NULL;
+ list->auth = auth;
+
+ /*
+ * merge it in; note that merge will deal with allocation
+ */
+ n = merge_entries (&xauth_head, list, &nnew, &nrepl);
+ if (n <= 0) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "unable to merge in added record\n");
+ return 1;
+ }
+
+ xauth_modified = True;
+ return 0;
+}
+
+/*
+ * remove displayname
+ */
+static int do_remove (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ int nremoved = 0;
+ int errors;
+
+ if (argc < 2) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[0]);
+ return 1;
+ }
+
+ errors = iterdpy (inputfilename, lineno, 1, argc, argv,
+ remove_entry, NULL, (char *) &nremoved);
+ if (verbose) printf ("%d entries removed\n", nremoved);
+ return errors;
+}
+
+/*
+ * info
+ */
+static int do_info (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ int n;
+ AuthList *l;
+
+ if (argc != 1) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[0]);
+ return 1;
+ }
+
+ for (l = xauth_head, n = 0; l; l = l->next, n++) ;
+
+ printf ("Authority file: %s\n",
+ xauth_filename ? xauth_filename : "(none)");
+ printf ("File new: %s\n", xauth_existed ? No : Yes);
+ printf ("File locked: %s\n", ignore_locks ? No : Yes);
+ printf ("Number of entries: %d\n", n);
+ printf ("Changes honored: %s\n", xauth_allowed ? Yes : No);
+ printf ("Changes made: %s\n", xauth_modified ? Yes : No);
+ printf ("Current input: %s:%d\n", inputfilename, lineno);
+ return 0;
+}
+
+
+/*
+ * exit
+ */
+static Bool alldone = False;
+
+/* ARGSUSED */
+static int do_exit (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ /* allow bogus stuff */
+ alldone = True;
+ return 0;
+}
+
+/*
+ * quit
+ */
+/* ARGSUSED */
+static int do_quit (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ /* allow bogus stuff */
+ die (0);
+ /* NOTREACHED */
+ return -1; /* for picky compilers */
+}
+
+
+/*
+ * source filename
+ */
+static int do_source (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ char *script;
+ char buf[BUFSIZ];
+ FILE *fp;
+ Bool used_stdin = False;
+ int len;
+ int errors = 0, status;
+ int sublineno = 0;
+ char **subargv;
+ int subargc;
+ Bool prompt = False; /* only true if reading from tty */
+
+ if (argc != 2 || !argv[1]) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[0]);
+ return 1;
+ }
+
+ script = argv[1];
+
+ fp = open_file (&script, "r", &used_stdin, inputfilename, lineno, argv[0]);
+ if (!fp) {
+ return 1;
+ }
+
+ if (verbose && used_stdin && isatty (fileno (fp))) prompt = True;
+
+ while (!alldone) {
+ buf[0] = '\0';
+ if (prompt) {
+ printf ("xauth> ");
+ fflush (stdout);
+ }
+ if (fgets (buf, sizeof buf, fp) == NULL) break;
+ sublineno++;
+ len = strlen (buf);
+ if (len == 0 || buf[0] == '#') continue;
+ if (buf[len-1] != '\n') {
+ prefix (script, sublineno);
+ fprintf (stderr, "line too long\n");
+ errors++;
+ break;
+ }
+ buf[--len] = '\0'; /* remove new line */
+ subargv = split_into_words (buf, &subargc);
+ if (subargv) {
+ status = process_command (script, sublineno, subargc, subargv);
+ free ((char *) subargv);
+ errors += status;
+ } else {
+ prefix (script, sublineno);
+ fprintf (stderr, "unable to break line into words\n");
+ errors++;
+ }
+ }
+
+ if (!used_stdin) {
+ (void) fclose (fp);
+ }
+ return errors;
+}
+
+static int x_protocol_error;
+static int
+catch_x_protocol_error(dpy, errevent)
+Display *dpy;
+XErrorEvent *errevent;
+{
+ char buf[80];
+ XGetErrorText(dpy, errevent->error_code, buf, sizeof (buf));
+ fprintf(stderr, "%s\n", buf);
+ x_protocol_error = errevent->error_code;
+ return 1;
+}
+
+/*
+ * generate
+ */
+static int do_generate (inputfilename, lineno, argc, argv)
+ char *inputfilename;
+ int lineno;
+ int argc;
+ char **argv;
+{
+ char *displayname;
+ int major_version, minor_version;
+ XSecurityAuthorization id_return;
+ Xauth *auth_in, *auth_return;
+ XSecurityAuthorizationAttributes attributes;
+ unsigned long attrmask = 0;
+ Display *dpy;
+ int status;
+ char *args[4];
+ char *protoname = ".";
+ int i;
+ int authdatalen = 0;
+ char *hexdata;
+ char *authdata = NULL;
+
+ if (argc < 2 || !argv[1]) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[0]);
+ return 1;
+ }
+
+ displayname = argv[1];
+
+ if (argc > 2) {
+ protoname = argv[2];
+ }
+
+ for (i = 3; i < argc; i++) {
+ if (0 == strcmp(argv[i], "timeout")) {
+ if (++i == argc) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[i-1]);
+ return 1;
+ }
+ attributes.timeout = atoi(argv[i]);
+ attrmask |= XSecurityTimeout;
+
+ } else if (0 == strcmp(argv[i], "trusted")) {
+ attributes.trust_level = XSecurityClientTrusted;
+ attrmask |= XSecurityTrustLevel;
+
+ } else if (0 == strcmp(argv[i], "untrusted")) {
+ attributes.trust_level = XSecurityClientUntrusted;
+ attrmask |= XSecurityTrustLevel;
+
+ } else if (0 == strcmp(argv[i], "group")) {
+ if (++i == argc) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[i-1]);
+ return 1;
+ }
+ attributes.group = atoi(argv[i]);
+ attrmask |= XSecurityGroup;
+
+ } else if (0 == strcmp(argv[i], "data")) {
+ if (++i == argc) {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[i-1]);
+ return 1;
+ }
+ hexdata = argv[i];
+ authdatalen = strlen(hexdata);
+ if (hexdata[0] == '"' && hexdata[authdatalen-1] == '"') {
+ authdata = malloc(authdatalen-1);
+ strncpy(authdata, hexdata+1, authdatalen-2);
+ authdatalen -= 2;
+ } else {
+ authdatalen = cvthexkey (hexdata, &authdata);
+ if (authdatalen < 0) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr,
+ "data contains odd number of or non-hex characters\n");
+ return 1;
+ }
+ }
+ } else {
+ prefix (inputfilename, lineno);
+ badcommandline (argv[i]);
+ return 1;
+ }
+ }
+
+ /* generate authorization using the Security extension */
+
+ dpy = XOpenDisplay (displayname);
+ if (!dpy) {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "unable to open display \"%s\".\n", displayname);
+ return 1;
+ }
+
+ status = XSecurityQueryExtension(dpy, &major_version, &minor_version);
+ if (!status)
+ {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "couldn't query Security extension on display \"%s\"\n",
+ displayname);
+ return 1;
+ }
+
+ /* fill in input Xauth struct */
+
+ auth_in = XSecurityAllocXauth();
+ if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) {
+ auth_in->name = DEFAULT_PROTOCOL;
+ }
+ else
+ auth_in->name = protoname;
+ auth_in->name_length = strlen(auth_in->name);
+ auth_in->data = authdata;
+ auth_in->data_length = authdatalen;
+
+ x_protocol_error = 0;
+ XSetErrorHandler(catch_x_protocol_error);
+ auth_return = XSecurityGenerateAuthorization(dpy, auth_in, attrmask,
+ &attributes, &id_return);
+ XSync(dpy, False);
+
+ if (!auth_return || x_protocol_error)
+ {
+ prefix (inputfilename, lineno);
+ fprintf (stderr, "couldn't generate authorization\n");
+ return 1;
+ }
+
+ if (verbose)
+ printf("authorization id is %d\n", id_return);
+
+ /* create a fake input line to give to do_add */
+
+ args[0] = "add";
+ args[1] = displayname;
+ args[2] = auth_in->name;
+ args[3] = bintohex(auth_return->data_length, auth_return->data);
+
+ status = do_add(inputfilename, lineno, 4, args);
+
+ if (authdata) free(authdata);
+ XSecurityFreeXauth(auth_in);
+ XSecurityFreeXauth(auth_return);
+ free(args[3]); /* hex data */
+ XCloseDisplay(dpy);
+ return status;
+}
diff --git a/xauth.c b/xauth.c
new file mode 100644
index 0000000..6327dea
--- /dev/null
+++ b/xauth.c
@@ -0,0 +1,166 @@
+/*
+ * $Xorg: xauth.c,v 1.4 2001/02/09 02:05:38 xorgcvs Exp $
+ *
+ * xauth - manipulate authorization file
+ *
+ *
+Copyright 1989,1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#include "xauth.h"
+
+
+/*
+ * global data
+ */
+char *ProgramName; /* argv[0], set at top of main() */
+int verbose = -1; /* print certain messages */
+Bool ignore_locks = False; /* for error recovery */
+Bool break_locks = False; /* for error recovery */
+
+/*
+ * local data
+ */
+
+static char *authfilename = NULL; /* filename of cookie file */
+static char *defcmds[] = { "source", "-", NULL }; /* default command */
+static int ndefcmds = 2;
+static char *defsource = "(stdin)";
+
+/*
+ * utility routines
+ */
+static void usage ()
+{
+ static char *prefixmsg[] = {
+"",
+"where options include:",
+" -f authfilename name of authority file to use",
+" -v turn on extra messages",
+" -q turn off extra messages",
+" -i ignore locks on authority file",
+" -b break locks on authority file",
+"",
+"and commands have the following syntax:",
+"",
+NULL };
+ static char *suffixmsg[] = {
+"A dash may be used with the \"merge\" and \"source\" to read from the",
+"standard input. Commands beginning with \"n\" use numeric format.",
+"",
+NULL };
+ char **msg;
+
+ fprintf (stderr, "usage: %s [-options ...] [command arg ...]\n",
+ ProgramName);
+ for (msg = prefixmsg; *msg; msg++) {
+ fprintf (stderr, "%s\n", *msg);
+ }
+ print_help (stderr, NULL, " "); /* match prefix indentation */
+ fprintf (stderr, "\n");
+ for (msg = suffixmsg; *msg; msg++) {
+ fprintf (stderr, "%s\n", *msg);
+ }
+ exit (1);
+}
+
+
+/*
+ * The main routine - parses command line and calls action procedures
+ */
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ char *sourcename = defsource;
+ char **arglist = defcmds;
+ int nargs = ndefcmds;
+ int status;
+
+ ProgramName = argv[0];
+
+ for (i = 1; i < argc; i++) {
+ char *arg = argv[i];
+
+ if (arg[0] == '-') {
+ char *flag;
+
+ for (flag = (arg + 1); *flag; flag++) {
+ switch (*flag) {
+ case 'f': /* -f authfilename */
+ if (++i >= argc) usage ();
+ authfilename = argv[i];
+ continue;
+ case 'v': /* -v */
+ verbose = 1;
+ continue;
+ case 'q': /* -q */
+ verbose = 0;
+ continue;
+ case 'b': /* -b */
+ break_locks = True;
+ continue;
+ case 'i': /* -i */
+ ignore_locks = True;
+ continue;
+ default:
+ usage ();
+ }
+ }
+ } else {
+ sourcename = "(argv)";
+ nargs = argc - i;
+ arglist = argv + i;
+ if (verbose == -1) verbose = 0;
+ break;
+ }
+ }
+
+ if (verbose == -1) { /* set default, don't junk stdout */
+ verbose = (isatty(fileno(stdout)) != 0);
+ }
+
+ if (!authfilename) {
+ authfilename = XauFileName (); /* static name, do not free */
+ if (!authfilename) {
+ fprintf (stderr,
+ "%s: unable to generate an authority file name\n",
+ ProgramName);
+ exit (1);
+ }
+ }
+ if (auth_initialize (authfilename) != 0) {
+ /* error message printed in auth_initialize */
+ exit (1);
+ }
+
+ status = process_command (sourcename, 1, nargs, arglist);
+
+ (void) auth_finalize ();
+ exit ((status != 0) ? 1 : 0);
+}
+
+
diff --git a/xauth.h b/xauth.h
new file mode 100644
index 0000000..d43cc56
--- /dev/null
+++ b/xauth.h
@@ -0,0 +1,54 @@
+/*
+ * $Xorg: xauth.h,v 1.4 2001/02/09 02:05:38 xorgcvs Exp $
+ *
+ *
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#include <stdio.h>
+#include <X11/Xos.h>
+#include <X11/Xauth.h>
+#include <X11/Xfuncs.h>
+
+#ifndef True
+typedef int Bool;
+#define False 0
+#define True 1
+#endif
+
+extern char *ProgramName;
+
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h>
+#else
+extern char *malloc(), *realloc();
+#endif
+
+extern char *copystring();
+int process_command(), auth_initialize(), auth_finalize();
+extern int print_help();
+extern int verbose;
+extern Bool ignore_locks;
+extern Bool break_locks;
diff --git a/xauth.man b/xauth.man
new file mode 100644
index 0000000..94af090
--- /dev/null
+++ b/xauth.man
@@ -0,0 +1,233 @@
+.\" $Xorg: xauth.man,v 1.4 2001/02/09 02:05:38 xorgcvs Exp $
+.\" Copyright 1993, 1998 The Open Group
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation.
+.\"
+.\" The above copyright notice and this permission notice shall be included
+.\" in all copies or substantial portions of the Software.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+.\" OTHER DEALINGS IN THE SOFTWARE.
+.\"
+.\" Except as contained in this notice, the name of The Open Group shall
+.\" not be used in advertising or otherwise to promote the sale, use or
+.\" other dealings in this Software without prior written authorization
+.\" from The Open Group.
+.TH XAUTH 1 "Release 6.4" "X Version 11"
+.SH NAME
+xauth \- X authority file utility
+.SH SYNOPSIS
+.B xauth
+[ \fB\-f\fP \fIauthfile\fP ] [ \fB\-vqib\fP ] [ \fIcommand arg ...\fP ]
+.SH DESCRIPTION
+.PP
+The \fIxauth\fP program is used to edit and display the authorization
+information used in connecting to the X server. This program is usually
+used to extract authorization records from one machine and merge them in on
+another (as is the case when using remote logins or granting access to
+other users). Commands (described below) may be entered interactively,
+on the \fIxauth\fP command line, or in scripts. Note that this program
+does \fBnot\fP contact the X server except when the generate command is used.
+Normally \fIxauth\fP is not used to create the authority file entry in
+the first place; \fIxdm\fP does that.
+.SH OPTIONS
+The following options may be used with \fIxauth\fP. They may be given
+individually (e.g., \fI\-q \-i\|\fP) or may combined (e.g., \fI\-qi\|\fP).
+.TP 8
+.B "\-f \fIauthfile\fP"
+This option specifies the name of the authority file to use. By default,
+\fIxauth\fP will use the file specified by the XAUTHORITY environment variable
+or \fI\.Xauthority\fP in the user's home directory.
+.TP 8
+.B \-q
+This option indicates that \fIxauth\fP should operate quietly and not print
+unsolicited status messages. This is the default if an \fIxauth\fP command is
+is given on the command line or if the standard output is not directed to a
+terminal.
+.TP 8
+.B \-v
+This option indicates that \fIxauth\fP should operate verbosely and print
+status messages indicating the results of various operations (e.g., how many
+records have been read in or written out). This is the default if \fIxauth\fP
+is reading commands from its standard input and its standard output is
+directed to a terminal.
+.TP 8
+.B \-i
+This option indicates that \fIxauth\fP should ignore any authority file
+locks. Normally, \fIxauth\fP will refuse to read or edit any authority files
+that have been locked by other programs (usually \fIxdm\fP or another
+\fIxauth\fP).
+.TP 8
+.B \-b
+This option indicates that \fIxauth\fP should attempt to break any authority
+file locks before proceeding. Use this option only to clean up stale locks.
+.SH COMMANDS
+The following commands may be used to manipulate authority files:
+.TP 8
+.B "add \fIdisplayname protocolname hexkey"
+An authorization entry for the indicated display using the given protocol
+and key data is added to the authorization file. The data is specified as
+an even-lengthed string of hexadecimal digits, each pair representing
+one octet. The first digit of each pair gives the most significant 4 bits
+of the octet, and the second digit of the pair gives the least significant 4
+bits. For example, a 32 character hexkey would represent a 128-bit value.
+A protocol name consisting of just a
+single period is treated as an abbreviation for \fIMIT-MAGIC-COOKIE-1\fP.
+
+.TP 8
+.B "generate \fIdisplayname protocolname\fP \fR[\fPtrusted|untrusted\fR]\fP"
+.B \fR[\fPtimeout \fIseconds\fP\fR]\fP \fR[\fPgroup \fIgroup-id\fP\fR]\fP \fR[\fBdata \fIhexdata\fR]
+
+This command is similar to add. The main difference is that instead
+of requiring the user to supply the key data, it connects to the
+server specified in \fIdisplayname\fP and uses the SECURITY extension
+in order to get the key data to store in the authorization file. If
+the server cannot be contacted or if it does not support the SECURITY
+extension, the command fails. Otherwise, an authorization entry for
+the indicated display using the given protocol is added to the
+authorization file. A protocol name consisting of just a single
+period is treated as an abbreviation for \fIMIT-MAGIC-COOKIE-1\fP.
+
+If the \fBtrusted\fP option is used, clients that connect using this
+authorization will have full run of the display, as usual. If
+\fBuntrusted\fP is used, clients that connect using this authorization
+will be considered untrusted and prevented from stealing or tampering
+with data belonging to trusted clients. See the SECURITY extension
+specification for full details on the restrictions imposed on
+untrusted clients. The default is \fBuntrusted\fP.
+
+The \fBtimeout\fP option specifies how long in seconds this
+authorization will be valid. If the authorization remains unused (no
+clients are connected with it) for longer than this time period, the
+server purges the authorization, and future attempts to connect using
+it will fail. Note that the purging done by the server does \fBnot\fP
+delete the authorization entry from the authorization file. The
+default timeout is 60 seconds.
+
+The \fBgroup\fP option specifies the application group that clients
+connecting with this authorization should belong to. See the
+application group extension specification for more details. The
+default is to not belong to an application group.
+
+The \fBdata\fP option specifies data that the server should use to
+generate the authorization. Note that this is \fBnot\fP the same data
+that gets written to the authorization file. The interpretation of
+this data depends on the authorization protocol. The \fIhexdata\fP is
+in the same format as the \fIhexkey\fP described in the add command.
+The default is to send no data.
+
+.TP 8
+.B "[n]extract \fIfilename displayname..."
+Authorization entries for each of the specified displays are written to the
+indicated file. If the \fInextract\fP command is used, the entries are written
+in a numeric format suitable for non-binary transmission (such as secure
+electronic mail). The extracted entries can be read back in using the
+\fImerge\fP and \fInmerge\fP commands. If the filename consists of
+just a single dash, the entries will be written to the standard output.
+.TP 8
+.B "[n]list \fR[\fIdisplayname\fP...]"
+Authorization entries for each of the specified displays (or all if no
+displays are named) are printed on the standard output. If the \fInlist\fP
+command is used, entries will be shown in the numeric format used by
+the \fInextract\fP command; otherwise, they are shown in a textual format.
+Key data is always displayed in the hexadecimal format given in the
+description of the \fIadd\fP command.
+.TP 8
+.B "[n]merge \fR[\fIfilename\fP...]"
+Authorization entries are read from the specified files and are merged into
+the authorization database, superceding any matching existing entries. If
+the \fInmerge\fP command is used, the numeric format given in the description
+of the \fIextract\fP command is used. If a filename consists of just a single
+dash, the standard input will be read if it hasn't been read before.
+.TP 8
+.B "remove \fIdisplayname\fR..."
+Authorization entries matching the specified displays are removed from the
+authority file.
+.TP 8
+.B "source \fIfilename"
+The specified file is treated as a script containing \fIxauth\fP commands
+to execute. Blank lines and lines beginning with a sharp sign (#) are
+ignored. A single dash may be used to indicate the standard input, if it
+hasn't already been read.
+.TP 8
+.B "info"
+Information describing the authorization file, whether or not any changes
+have been made, and from where \fIxauth\fP commands are being read
+is printed on the standard output.
+.TP 8
+.B "exit"
+If any modifications have been made, the authority file is written out (if
+allowed), and the program exits. An end of file is treated as an implicit
+\fIexit\fP command.
+.TP 8
+.B "quit"
+The program exits, ignoring any modifications. This may also be accomplished
+by pressing the interrupt character.
+.TP 8
+.B "help [\fIstring\fP]"
+A description of all commands that begin with the given string (or all
+commands if no string is given) is printed on the standard output.
+.TP 8
+.B "?"
+A short list of the valid commands is printed on the standard output.
+.SH "DISPLAY NAMES"
+Display names for the \fIadd\fP, \fI[n]extract\fP, \fI[n]list\fP,
+\fI[n]merge\fP, and \fIremove\fP commands use the same format as the
+DISPLAY environment variable and the common \fI\-display\fP command line
+argument. Display-specific information (such as the screen number)
+is unnecessary and will be ignored.
+Same-machine connections (such as local-host sockets,
+shared memory, and the Internet Protocol hostname \fIlocalhost\fP) are
+referred to as \fIhostname\fP/unix:\fIdisplaynumber\fP so that
+local entries for different machines may be stored in one authority file.
+.SH EXAMPLE
+.PP
+The most common use for \fIxauth\fP is to extract the entry for the
+current display, copy it to another machine, and merge it into the
+user's authority file on the remote machine:
+.sp
+.nf
+ % xauth extract \- $DISPLAY | rsh otherhost xauth merge \-
+.fi
+.PP
+.sp
+The following command contacts the server :0 to create an
+authorization using the MIT-MAGIC-COOKIE-1 protocol. Clients that
+connect with this authorization will be untrusted.
+.nf
+ % xauth generate :0 .
+.fi
+.SH ENVIRONMENT
+This \fIxauth\fP program uses the following environment variables:
+.TP 8
+.B XAUTHORITY
+to get the name of the authority file to use if the \fI\-f\fP option isn't
+used.
+.TP 8
+.B HOME
+to get the user's home directory if XAUTHORITY isn't defined.
+.SH FILES
+.TP 8
+.I $HOME/.Xauthority
+default authority file if XAUTHORITY isn't defined.
+.SH BUGS
+.PP
+Users that have unsecure networks should take care to use encrypted
+file transfer mechanisms to copy authorization entries between machines.
+Similarly, the \fIMIT-MAGIC-COOKIE-1\fP protocol is not very useful in
+unsecure environments. Sites that are interested in additional security
+may need to use encrypted authorization mechanisms such as Kerberos.
+.PP
+Spaces are currently not allowed in the protocol name. Quoting could be
+added for the truly perverse.
+.SH AUTHOR
+Jim Fulton, MIT X Consortium