From: mikeg@Ingres.COM (Mike Glendinning)
Newsgroups: fj.mail-lists.x-window
Subject: Re: How do I generate valid XDM-AUTHORIZATION-1 ?
Date: 9 Jan 93 19:35:30 GMT
Distribution: fj
Organization: Ingres Corporation

Date: 9 Jan 93 17:36:03 GMT
Message-Id: <1993Jan9.173603.24271@pony.Ingres.COM>
Newsgroups: comp.windows.x

It is possible to add hexkeys for XDM-AUTHORIZATION-1 using the
standard 'xauth' command.  The trick is to leave the 8 most
significant bits of the DES key as zero.

As you pointed out, the 128-bit hexkey for XDM-AUTHORIZATION-1
is composed of two parts: 64 bits of random data and a 56-bit
DES key.  The 56-bit key is stored in the lower end of a 64-bit
field.  You specify the full 128 bits to 'xauth' with the
random data first.

For example, the following 'xauth' command generates a valid
hexkey for XDM-AUTHORIZATION-1:

   xauth add :0 XDM-AUTHORIZATION-1 aabbccddeeffaabb00aabbccddeeffaa

                                                    ^^ zeros!!

Note that the only "win" with XDM-AUTHORIZATION-1 as opposed to
MIT-MAGIC-COOKIE-1 is that the key is not transmitted
in the X connection information by each client and thus you
are not prone to networking snooping (people with PC's on
your Ethernet!).  If you have a secure way of transmitting the
128-bit hexkey from the server machine to the client machine,
then great!  Otherwise, there is no real benefit.  Unfortunately,
since the key is stored in the Unix filesystem, you're limited by
the security provided there.  And if you are using NFS, then you might
as well forget it anyway, as NFS provides almost No File Security!

Also, beware of trying to use *only* XDM-AUTHORIZATION-1.  If you
do this, then R4 based clients will not be able to connect as
they don't know about XDM-AUTHORIZATION-1.  Always add a key for
MIT-MAGIC-COOKIE-1 as well.  You will also potentially get the same
problem with clients from other sources that contain their own Xlib
that doesn't know about XDM-AUTHORIZATION-1.

Personally, I have modified 'xauth' to add a "create" command
which will generate random hexkeys automatically.  This is
much easier than getting "ksh" or "perl" to generate a random
cookie for use by the 'xauth' "add" command.  With my changes
(included below), you can just say:

   xauth create :0 && xauth create `hostname`:0

in order to generate a full set of authorization information for
display number 0 on the local host.  The technique used is exactly
the same as the one used by 'xdm' (in fact, I borrowed the code from
there).  If you just want to generate a random key for a particular
protocol, you can say something like:

   xauth create :0 MIT-MAGIC-COOKIE-1

The abbreviation "." for "MIT-MAGIC-COOKIE-1" is supported.

I would appreciate some comments on these patches, as I am
rather surprised that nobody has done it before.  Of course,
the 'xauth' "add" command is required, but isn't "create"
more useful?

By the way, these patches are for the X11R5pl21 version
of 'xauth'.

-Mike Glendinning, Ingres UK (mikeg@ingres.com).


*** Imakefile.orig	Thu Jan  7 16:46:53 1993
--- Imakefile	Fri Jan  8 10:26:25 1993
***************
*** 1,9 ****
  XCOMM $XConsortium: Imakefile,v 1.14 91/07/16 23:06:17 gildea Exp $
  DEPLIBS = $(DEPXAUTHLIB) $(DEPXMULIB)
  LOCAL_LIBRARIES = $(XAUTHLIB) $(XMULIB)
             SRCS = xauth.c gethost.c process.c parsedpy.c
             OBJS = xauth.o gethost.o process.o parsedpy.o
!         DEFINES = ConnectionFlags $(SIGNAL_DEFINES)
  
  ComplexProgramTarget(xauth)
  
--- 1,14 ----
  XCOMM $XConsortium: Imakefile,v 1.14 91/07/16 23:06:17 gildea Exp $
+ 
+ #ifdef HasXdmAuth
+ XDMAUTH_DEFINES = -DHASXDMAUTH
+ #endif
+ 
  DEPLIBS = $(DEPXAUTHLIB) $(DEPXMULIB)
  LOCAL_LIBRARIES = $(XAUTHLIB) $(XMULIB)
             SRCS = xauth.c gethost.c process.c parsedpy.c
             OBJS = xauth.o gethost.o process.o parsedpy.o
!         DEFINES = ConnectionFlags $(SIGNAL_DEFINES) $(XDMAUTH_DEFINES)
  
  ComplexProgramTarget(xauth)
  
*** process.c.orig	Thu Jan  7 16:46:53 1993
--- process.c	Fri Jan  8 11:52:46 1993
***************
*** 40,47 ****
  #define DEFAULT_PROTOCOL "MIT-MAGIC-COOKIE-1"
  #endif
  
! #define SECURERPC "SUN-DES-1"
  
  #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 */
--- 40,56 ----
  #define DEFAULT_PROTOCOL "MIT-MAGIC-COOKIE-1"
  #endif
  
! #define MITMAGICCOOKIE		"MIT-MAGIC-COOKIE-1"
! #define XDMAUTHORIZATION	"XDM-AUTHORIZATION-1"
! #define SECURERPC		"SUN-DES-1"
  
+ #ifndef DEFAULT_RANDOM_FILE
+ #define DEFAULT_RANDOM_FILE "/dev/mem"
+ #endif
+ 
+ #define FILE_LIMIT 1024			/* no more than this many buffers */
+ #define AUTH_DATA_LEN 16		/* bytes of authorization data */
+ 
  #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 */
***************
*** 86,96 ****
  
  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();
  
  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,
--- 95,107 ----
  
  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_create();
  
  static CommandTable command_table[] = {	/* table of known commands */
      { "add",      2, 3, do_add,
  	"add dpyname protoname hexkey   add entry" },
+     { "create",   2, 6, do_create,
+ 	"create dpyname [protoname]     create random entry" },
      { "exit",     3, 4, do_exit,
  	"exit                           save changes and exit program" },
      { "extract",  3, 7, do_extract,
***************
*** 1091,1096 ****
--- 1102,1235 ----
      return errors;
  }
  
+ #ifdef HASXDMAUTH
+ static longtochars (l, c)
+     long l;
+     unsigned char *c;
+ {
+     c[0] = (l >> 24) & 0xff;
+     c[1] = (l >> 16) & 0xff;
+     c[2] = (l >> 8) & 0xff;
+     c[3] = l & 0xff;
+ }
+ 
+ static int sumfile (name, sum)
+     char *name;
+     long sum[2];
+ {
+     long buf[1024*2];
+     int cnt;
+     int fd;
+     int loops;
+     int reads;
+     int i;
+ 
+     fd = open (name, 0);
+     if (fd < 0)
+ 	return 0;
+     reads = FILE_LIMIT;
+     while ((cnt = read (fd, buf, sizeof (buf))) > 0 && --reads > 0) {
+ 	loops = cnt / (2 * sizeof (long));
+ 	for (i = 0; i < loops; i += 2) {
+ 	    sum[0] += buf[i];
+ 	    sum[1] += buf[i+1];
+ 	}
+     }
+     close (fd);
+     return 1;
+ }
+ #endif
+ 
+ static genauth(authstr, len)
+     char *authstr;
+     int len;
+ {
+     long ldata[2];
+ 
+ #ifdef ITIMER_REAL
+     {
+ 	struct timeval  now;
+ 	struct timezone zone;
+ 	gettimeofday (&now, &zone);
+ 	ldata[0] = now.tv_sec;
+ 	ldata[1] = now.tv_usec;
+     }
+ #else
+     {
+ 	long time ();
+ 
+ 	ldata[0] = time ((long *) 0);
+ 	ldata[1] = getpid ();
+     }
+ #endif
+ 
+ #ifdef HASXDMAUTH
+     {
+ 	typedef unsigned char auth_cblock[8];   /* block size */
+ 	typedef struct auth_ks_struct { auth_cblock _; }
+ 	                  auth_wrapper_schedule[16];
+ 
+ 	int i, bit, authi;
+ 	char *authc;
+ 	auth_wrapper_schedule schedule;
+ 	unsigned char data[8];
+ 	static unsigned char key[8];
+ 	static int xdmcpauthinited = 0;
+ 
+ 	longtochars (ldata[0], data+0);
+ 	longtochars (ldata[1], data+4);
+ 	if (!xdmcpauthinited) {
+ 	    char *name, *getenv();
+ 	    long sum[2];
+ 	    unsigned char tmpkey[8];
+ 
+ 	    name = getenv ("RANDOM_FILE");
+ 	    if (name == NULL)
+ 	        name = DEFAULT_RANDOM_FILE;
+ 	    if (!sumfile (name, sum)) {
+ 	        sum[0] = time ((long *) 0);
+ 	        sum[1] = time ((long *) 0);
+ 	    }
+ 	    longtochars (sum[0], tmpkey+0);
+ 	    longtochars (sum[1], tmpkey+4);
+ 	    tmpkey[0] = 0;
+ 	    _XdmcpWrapperToOddParity (tmpkey, key);
+ 
+ 	    xdmcpauthinited = 1;
+ 	}
+ 	_XdmcpAuthSetup (key, schedule);
+ 	for (i = 0; i < len; i++) {
+ 	    authi = 0;
+ 	    for (bit = 1; bit < 256; bit <<= 1) {
+ 	        _XdmcpAuthDoIt (data, data, schedule, 1);
+ 	        if (data[0] + data[1] & 0x4)
+ 	            authi |= bit;
+ 	    }
+ 	    authc = hex_table[authi & 0xff];
+ 	    authstr[i*2] = authc[0];
+ 	    authstr[i*2+1] = authc[1];
+ 	}
+ 	authstr[len*2] = '\0';
+     }
+ #else
+     {
+ 	int i, seed, value;
+ 	char *authc;
+ 
+ 	seed = (ldata[0]) + (ldata[1] << 16);
+ 	srand (seed);
+ 	for (i = 0; i < len; i++)
+ 	{
+ 	    value = rand ();
+ 	    authc = hex_table[value & 0xff];
+ 	    authstr[i*2] = authc[0];
+ 	    authstr[i*2+1] = authc[1];
+ 	}
+ 	authstr[len*2] = '\0';
+     }
+ #endif
+ }
+ 
  /* ARGSUSED */
  static int remove_entry (inputfilename, lineno, auth, data)
      char *inputfilename;
***************
*** 1466,1471 ****
--- 1605,1691 ----
  
      xauth_modified = True;
      return 0;
+ }
+ 
+ /*
+  * create displayname protocolname
+  */
+ static int do_create (inputfilename, lineno, argc, argv)
+     char *inputfilename;
+     int lineno;
+     int argc;
+     char **argv;
+ { 
+     int p1, p2;
+     char *dpyname;
+     char *protoname;
+     char authstr[AUTH_DATA_LEN*2+1];
+     char *addcmds[5];
+     int errors;
+ 
+     if (argc < 2 || argc > 3 || !argv[1]) {
+ 	prefix (inputfilename, lineno);
+ 	badcommandline (argv[0]);
+ 	return 1;
+     }
+ 
+     dpyname = argv[1];
+ 
+     addcmds[0] = "create"; /* OK since do_add won't check! */
+     addcmds[1] = dpyname;
+     addcmds[2] = ""; /* protocol filled-in later on */
+     addcmds[3] = authstr;
+     addcmds[4] = NULL;
+ 
+     if (argc == 3 && argv[2]) {
+ 	protoname = argv[2];
+ 	if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) {
+ 	    protoname = DEFAULT_PROTOCOL;
+ 	}
+ 	p1 = (strcmp (protoname, MITMAGICCOOKIE) == 0);
+ #ifdef HASXDMAUTH
+ 	p2 = (strcmp (protoname, XDMAUTHORIZATION) == 0);
+ #else
+ 	p2 = 0;
+ #endif
+ 	if (p1 || p2) {
+ 	    genauth(authstr, AUTH_DATA_LEN);
+ 	    if (p2) {
+ 	        authstr[16] = '0';
+ 	        authstr[17] = '0';
+ 	    }
+ 	    addcmds[2] = protoname;
+ 	    errors = do_add (inputfilename, lineno, 4, addcmds);
+ 	}
+ 	else {
+ 	    prefix (inputfilename, lineno);
+ 	    fprintf (stderr,
+ 	             "don't know how to create protocol %s\n", protoname);
+ 	    return 1;
+ 	}
+     }
+     else {
+ 
+ 	/*
+ 	 * by default, generate both MIT-MAGIC-COOKIE-1 and XDM-AUTHORIZATION-1
+ 	 */
+ 	genauth(authstr, AUTH_DATA_LEN);
+ 	addcmds[2] = MITMAGICCOOKIE;
+ 	errors = do_add (inputfilename, lineno, 4, addcmds);
+ #ifdef HASXDMAUTH
+ 	if (errors)
+ 	    return errors;
+ 
+ 	genauth(authstr, AUTH_DATA_LEN);
+ 	authstr[16] = '0';
+ 	authstr[17] = '0';
+ 	addcmds[2] = XDMAUTHORIZATION;
+ 	errors = do_add (inputfilename, lineno, 4, addcmds);
+ #endif
+ 
+     }
+ 
+     return errors;
  }
  
  /*
*** xauth.man.orig	Thu Jan  7 16:46:54 1993
--- xauth.man	Fri Jan  8 09:35:28 1993
***************
*** 57,62 ****
--- 57,70 ----
  A protocol name consisting of just a 
  single period is treated as an abbreviation for \fIMIT-MAGIC-COOKIE-1\fP.
  .TP 8
+ .B "create \fIdisplayname \fR[\fIprotocolname\fP]"
+ An authorization entry for the indicated display using the given protocol
+ is created using a random number generator and 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 protocol name is not specified, then authorization entries are
+ created for all supported protocols.
+ .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
***************
*** 111,117 ****
  .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)
--- 119,125 ----
  .B "?"
  A short list of the valid commands is printed on the standard output.
  .SH "DISPLAY NAMES"
! Display names for the \fIadd\fP, \fIcreate\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)
***************
*** 153,157 ****
  Copyright 1989, Massachusetts Institute of Technology.
  .br
  See \fIX(1)\fP for a full statement of rights and permissions.
! .SH AUTHOR
  Jim Fulton, MIT X Consortium
--- 161,167 ----
  Copyright 1989, Massachusetts Institute of Technology.
  .br
  See \fIX(1)\fP for a full statement of rights and permissions.
! .SH AUTHORS
  Jim Fulton, MIT X Consortium
+ .br
+ Mike Glendinning, Ingres Corporation