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