Home | History | Annotate | Line # | Download | only in xdm
      1 /*
      2 
      3 Copyright 1988, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from The Open Group.
     26 
     27 */
     28 
     29 /*
     30  * xdm - display manager daemon
     31  * Author:  Keith Packard, MIT X Consortium
     32  */
     33 
     34 #include   <X11/Xauth.h>
     35 #include   <X11/Xos.h>
     36 
     37 #include   "dm.h"
     38 #include   "dm_auth.h"
     39 #include   "dm_error.h"
     40 
     41 #include <errno.h>
     42 
     43 #ifdef HAVE_ARC4RANDOM
     44 # include <stdlib.h>
     45 #endif
     46 
     47 #include <time.h>
     48 #define Time_t time_t
     49 
     50 #ifdef HASXDMAUTH
     51 static unsigned char	key[8];
     52 #endif
     53 
     54 #ifdef DEV_RANDOM
     55 extern char	*randomDevice;
     56 #endif
     57 
     58 #ifdef HASXDMAUTH
     59 
     60 typedef unsigned char auth_cblock[8];	/* block size */
     61 
     62 typedef struct auth_ks_struct { auth_cblock _; } auth_wrapper_schedule[16];
     63 
     64 extern int _XdmcpAuthSetup(unsigned char *, auth_wrapper_schedule);
     65 extern int _XdmcpAuthDoIt(unsigned char *, unsigned char *,
     66     auth_wrapper_schedule, int);
     67 extern void _XdmcpWrapperToOddParity(unsigned char *, unsigned char *);
     68 
     69 static void
     70 longtochars (long l, unsigned char *c)
     71 {
     72     c[0] = (l >> 24) & 0xff;
     73     c[1] = (l >> 16) & 0xff;
     74     c[2] = (l >> 8) & 0xff;
     75     c[3] = l & 0xff;
     76 }
     77 
     78 #endif
     79 
     80 #ifdef POLL_DEV_RANDOM
     81 # include <poll.h>
     82 static int
     83 pollRandomDevice (int fd)
     84 {
     85     struct pollfd fds;
     86 
     87     fds.fd = fd;
     88     fds.events = POLLIN | POLLRDNORM;
     89     /* Wait up to 5 seconds for entropy to accumulate */
     90     return poll(&fds, 1, 5000);
     91 }
     92 #else
     93 # define pollRandomDevice(fd) 1
     94 #endif
     95 
     96 #if !defined(HAVE_ARC4RANDOM)
     97 
     98 /* ####################################################################### */
     99 
    100 /*
    101  * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999.  All
    102  * rights reserved.
    103  *
    104  * Redistribution and use in source and binary forms, with or without
    105  * modification, are permitted provided that the following conditions
    106  * are met:
    107  * 1. Redistributions of source code must retain the above copyright
    108  *    notice, and the entire permission notice in its entirety,
    109  *    including the disclaimer of warranties.
    110  * 2. Redistributions in binary form must reproduce the above copyright
    111  *    notice, this list of conditions and the following disclaimer in the
    112  *    documentation and/or other materials provided with the distribution.
    113  * 3. The name of the author may not be used to endorse or promote
    114  *    products derived from this software without specific prior
    115  *    written permission.
    116  *
    117  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
    118  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    119  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
    120  * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
    121  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    122  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    123  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    124  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    125  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    126  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
    127  * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
    128  * DAMAGE.
    129  */
    130 
    131 static CARD32 epool[32], erotate, eadd_ptr;
    132 
    133 static void
    134 add_entropy (const CARD32 *in, int nwords)
    135 {
    136 	static const CARD32 twist_table[8] = {
    137 		         0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
    138 		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
    139 	CARD32 i, w;
    140 	int new_rotate;
    141 
    142 	while (nwords--) {
    143 		w = *in++;
    144 		w = (w<<erotate | w>>(32-erotate)) & 0xffffffff;
    145 		i = eadd_ptr = (eadd_ptr - 1) & 31;
    146 		new_rotate = erotate + 14;
    147 		if (i)
    148 			new_rotate = erotate + 7;
    149 		erotate = new_rotate & 31;
    150 		w ^= epool[(i + 26) & 31];
    151 		w ^= epool[(i + 20) & 31];
    152 		w ^= epool[(i + 14) & 31];
    153 		w ^= epool[(i + 7) & 31];
    154 		w ^= epool[(i + 1) & 31];
    155 		w ^= epool[i];
    156 		epool[i] = (w >> 3) ^ twist_table[w & 7];
    157 	}
    158 }
    159 
    160 /* ####################################################################### */
    161 
    162 /*
    163  * This code implements something close to the MD5 message-digest
    164  * algorithm. This code is based on code written by Colin Plumb
    165  * in 1993, no copyright is claimed.
    166  * This code is in the public domain; do with it what you wish.
    167  */
    168 
    169 /* The four core functions - F1 is optimized somewhat */
    170 # define F1(x, y, z) (z ^ (x & (y ^ z)))
    171 # define F2(x, y, z) F1 (z, x, y)
    172 # define F3(x, y, z) (x ^ y ^ z)
    173 # define F4(x, y, z) (y ^ (x | ~z))
    174 
    175 /* This is the central step in the MD5 algorithm. */
    176 # define pmd5_step(f, w, x, y, z, data, s) \
    177 	( w += (f(x, y, z) + data) & 0xffffffff,  w = w<<s | w>>(32-s),  w += x )
    178 
    179 /*
    180  * The core of the MD5 algorithm, this alters an existing MD5 hash to
    181  * reflect the addition of 16 longwords of new data.
    182  */
    183 static void
    184 pmd5_hash (CARD32 *out, const CARD32 in[16])
    185 {
    186     CARD32 a, b, c, d;
    187 
    188     a = out[0];
    189     b = out[1];
    190     c = out[2];
    191     d = out[3];
    192 
    193     pmd5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    194     pmd5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    195     pmd5_step(F1, c, d, a, b, in[2] + 0x242070db, 17);
    196     pmd5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    197     pmd5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    198     pmd5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    199     pmd5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    200     pmd5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    201     pmd5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    202     pmd5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    203     pmd5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    204     pmd5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    205     pmd5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    206     pmd5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    207     pmd5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    208     pmd5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22);
    209 
    210     pmd5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    211     pmd5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    212     pmd5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
    213     pmd5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
    214     pmd5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
    215     pmd5_step(F2, d, a, b, c, in[10] + 0x02441453, 9);
    216     pmd5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
    217     pmd5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
    218     pmd5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
    219     pmd5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
    220     pmd5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
    221     pmd5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
    222     pmd5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
    223     pmd5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
    224     pmd5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
    225     pmd5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
    226 
    227     pmd5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
    228     pmd5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11);
    229     pmd5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
    230     pmd5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
    231     pmd5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
    232     pmd5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
    233     pmd5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
    234     pmd5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
    235     pmd5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
    236     pmd5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
    237     pmd5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
    238     pmd5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23);
    239     pmd5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
    240     pmd5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
    241     pmd5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
    242     pmd5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
    243 
    244     pmd5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6);
    245     pmd5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10);
    246     pmd5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
    247     pmd5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
    248     pmd5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
    249     pmd5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
    250     pmd5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
    251     pmd5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
    252     pmd5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
    253     pmd5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
    254     pmd5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15);
    255     pmd5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
    256     pmd5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
    257     pmd5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
    258     pmd5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
    259     pmd5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
    260 
    261     out[0] += a;
    262     out[1] += b;
    263     out[2] += c;
    264     out[3] += d;
    265 }
    266 
    267 /* ####################################################################### */
    268 
    269 
    270 static int
    271 sumFile (const char *name, int len, int whence, off_t offset)
    272 {
    273     int fd, cnt, readlen = 0;
    274     unsigned char buf[0x1000];
    275 
    276     if ((fd = open (name, O_RDONLY)) < 0) {
    277 	Debug("cannot open entropy source \"%s\", errno=%d\n", name, errno);
    278 	return -1;
    279     }
    280     lseek (fd, offset, whence);
    281     while (readlen < len) {
    282 	if (!(cnt = read (fd, buf, sizeof (buf))))
    283 	    break;
    284 	if (cnt < 0) {
    285 	    close (fd);
    286 	    Debug("cannot read entropy source \"%s\", errno=%d\n",
    287 		  name, errno);
    288 	    return -1;
    289 	}
    290 	readlen += cnt;
    291 	add_entropy((CARD32 *)buf, (cnt + 3) / 4);
    292     }
    293     close (fd);
    294     Debug("read %d bytes from entropy source \"%s\"\n", readlen, name);
    295     return readlen;
    296 }
    297 
    298 void
    299 AddTimerEntropy (void)
    300 {
    301     struct timeval now;
    302     X_GETTIMEOFDAY (&now);
    303     add_entropy((CARD32 *)&now, sizeof(now)/sizeof(CARD32));
    304 }
    305 
    306 # define BSIZ 0x10000
    307 
    308 void
    309 AddOtherEntropy (void)
    310 {
    311     AddTimerEntropy();
    312     /* XXX -- setup-specific ... use some common ones */
    313     sumFile ("/var/log/messages", 0x1000, SEEK_END, -0x1000);
    314     sumFile ("/var/log/syslog", 0x1000, SEEK_END, -0x1000);
    315     sumFile ("/var/log/debug", 0x1000, SEEK_END, -0x1000);
    316     sumFile ("/var/log/kern.log", 0x1000, SEEK_END, -0x1000);
    317     sumFile ("/var/log/daemon.log", 0x1000, SEEK_END, -0x1000);
    318 }
    319 
    320 void
    321 AddPreGetEntropy (void)
    322 {
    323     static off_t offset;
    324     off_t readlen;
    325 
    326     AddTimerEntropy();
    327     if ((readlen = sumFile (randomFile, BSIZ, SEEK_SET, offset)) == BSIZ) {
    328 	offset += readlen;
    329 	return;
    330     } else if (readlen >= 0 && offset) {
    331 	if ((offset = sumFile (randomFile, BSIZ, SEEK_SET, 0)) == BSIZ)
    332 	    return;
    333     }
    334     LogError("Cannot read randomFile \"%s\"; X cookies may be easily guessable\n", randomFile);
    335 }
    336 #endif /* !HAVE_ARC4RANDOM && !DEV_RANDOM */
    337 
    338 
    339 #ifdef HASXDMAUTH
    340 static void
    341 InitXdmcpWrapper (void)
    342 {
    343     CARD32 sum[4];
    344 
    345 # ifdef	HAVE_ARC4RANDOM
    346     sum[0] = arc4random();
    347     sum[1] = arc4random();
    348     *(u_char *)sum = 0;
    349 
    350     _XdmcpWrapperToOddParity((unsigned char *)sum, key);
    351 # else
    352     unsigned char   tmpkey[8];
    353 
    354 #  ifdef DEV_RANDOM
    355     int fd;
    356 
    357     if ((fd = open(randomDevice, O_RDONLY)) >= 0) {
    358 	if (pollRandomDevice(fd) && read(fd, tmpkey, 8) == 8) {
    359 	    tmpkey[0] = 0;
    360 	    _XdmcpWrapperToOddParity(tmpkey, key);
    361 	    close(fd);
    362 	    return;
    363 	} else {
    364 	    close(fd);
    365 	}
    366     } else {
    367 	LogError("Cannot open randomDevice \"%s\", errno = %d\n",
    368 	  randomDevice, errno);
    369     }
    370 #  endif
    371     /*  Try some pseudo-random number generator daemon next */
    372     if (prngdSocket != NULL || prngdPort != 0) {
    373 	    if (get_prngd_bytes((char *)tmpkey, sizeof(tmpkey), prngdPort,
    374 		    prngdSocket) == 0) {
    375 		    tmpkey[0] = 0;
    376 		    _XdmcpWrapperToOddParity(tmpkey, key);
    377 		    return;
    378 	    }
    379     }
    380     /* Fall back if no other source of random number was found */
    381     AddPreGetEntropy();
    382     pmd5_hash (sum, epool);
    383     add_entropy (sum, 1);
    384     pmd5_hash (sum, epool + 16);
    385     add_entropy (sum + 2, 1);
    386 
    387     longtochars (sum[0], tmpkey+0);
    388     longtochars (sum[1], tmpkey+4);
    389     tmpkey[0] = 0;
    390     _XdmcpWrapperToOddParity (tmpkey, key);
    391 # endif
    392 }
    393 
    394 #endif
    395 
    396 
    397 int
    398 GenerateAuthData (char *auth, int len)
    399 {
    400 #ifdef HASXDMAUTH
    401     int		    i, bit;
    402     auth_wrapper_schedule    schedule;
    403     unsigned char	    data[8];
    404     static int	    xdmcpAuthInited;
    405     long	    ldata[2];
    406 
    407 # ifndef HAVE_ARC4RANDOM
    408 #  ifdef ITIMER_REAL
    409     struct timeval  now;
    410 
    411     X_GETTIMEOFDAY (&now);
    412     ldata[0] = now.tv_usec;
    413     ldata[1] = now.tv_sec;
    414 #  else
    415     ldata[0] = time ((long *) 0);
    416     ldata[1] = getpid ();
    417 #  endif
    418 # else
    419     ldata[0] = arc4random();
    420     ldata[1] = arc4random();
    421 # endif
    422 
    423     longtochars (ldata[0], data+0);
    424     longtochars (ldata[1], data+4);
    425     if (!xdmcpAuthInited)
    426     {
    427 	InitXdmcpWrapper ();
    428 	xdmcpAuthInited = 1;
    429     }
    430     _XdmcpAuthSetup (key, schedule);
    431     for (i = 0; i < len; i++) {
    432 	auth[i] = 0;
    433 	for (bit = 1; bit < 256; bit <<= 1) {
    434 	    _XdmcpAuthDoIt (data, data, schedule, 1);
    435 	    if ((data[0] + data[1]) & 0x4)
    436 		auth[i] |= bit;
    437 	}
    438     }
    439     return 1;
    440 #else /* !XDMAUTH */
    441 # ifdef HAVE_ARC4RANDOM
    442     CARD32 *rnd = (CARD32 *)auth;
    443     int i;
    444 
    445     for (i = 0; i < len; i += 4)
    446 	rnd[i / 4] = arc4random();
    447     return 1;
    448 # else /* !HAVE_ARC4RANDOM */
    449     CARD32 tmp[4] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 };
    450 #  ifdef DEV_RANDOM
    451     int fd;
    452 
    453     if ((fd = open(randomDevice, O_RDONLY)) >= 0) {
    454 	if (pollRandomDevice(fd) &&
    455 	    read(fd, auth, len) == len) {
    456 	    close(fd);
    457 	    return 1;
    458 	}
    459 	close(fd);
    460 	LogError("Cannot read randomDevice \"%s\", errno=%d\n",
    461 		 randomDevice, errno);
    462     } else
    463 	LogError("Cannot open randomDevice \"%s\", errno = %d\n",
    464 		 randomDevice, errno);
    465 #  endif /* DEV_RANDOM */
    466     /*  Try some pseudo-random number generator daemon next */
    467     if (prngdSocket != NULL || prngdPort != 0) {
    468 	    if (get_prngd_bytes(auth, len, prngdPort, prngdSocket) == 0) {
    469 		    return 1;
    470 	    }
    471     }
    472     /* Fallback if not able to get from /dev/random */
    473     AddPreGetEntropy();
    474     pmd5_hash (tmp, epool);
    475     add_entropy (tmp, 1);
    476     pmd5_hash (tmp, epool + 16);
    477     add_entropy (tmp + 2, 1);
    478     memcpy (auth, tmp, len);
    479     return 1;
    480 # endif /* !HAVE_ARC4RANDOM */
    481 #endif /* !HASXDMAUTH */
    482 }
    483