auth.c revision 1d778f8e
1/* 2 3Copyright 1988, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28 29/* 30 * xdm - display manager daemon 31 * Author: Keith Packard, MIT X Consortium 32 * 33 * auth.c 34 * 35 * maintain the authorization generation daemon 36 */ 37 38#include <X11/X.h> 39#include <X11/Xlibint.h> 40#include <sys/types.h> 41#include <sys/stat.h> 42 43#include "dm.h" 44#include "dm_auth.h" 45#include "dm_error.h" 46 47#include <errno.h> 48 49#include <sys/ioctl.h> 50 51#ifdef TCPCONN 52# include "dm_socket.h" 53#endif 54 55 56 57#ifdef SVR4 58# include <netdb.h> 59# include <sys/sockio.h> 60# include <sys/stropts.h> 61#endif 62#ifdef __GNU__ 63# include <netdb.h> 64# undef SIOCGIFCONF 65#else /* __GNU__ */ 66# include <net/if.h> 67#endif /* __GNU__ */ 68 69#if defined(TCPCONN) && !defined(WIN32) 70# include <netinet/in.h> 71#endif 72 73/* Solaris provides an extended interface SIOCGLIFCONF for IPv6 support. 74 */ 75#ifdef SIOCGLIFCONF 76# define USE_SIOCGLIFCONF 77#endif 78 79#ifdef HAVE_SYS_PARAM_H 80# include <sys/param.h> 81# ifdef BSD 82# if (BSD >= 199103) 83# define VARIABLE_IFREQ 84# endif 85# endif 86#endif 87 88 89struct AuthProtocol { 90 unsigned short name_length; 91 const char *name; 92 void (*InitAuth)(unsigned short len, char *name); 93 Xauth *(*GetAuth)(unsigned short len, char *name); 94 void (*GetXdmcpAuth)( 95 struct protoDisplay *pdpy, 96 unsigned short authorizationNameLen, 97 char *authorizationName); 98 int inited; 99}; 100 101static struct AuthProtocol AuthProtocols[] = { 102{ (unsigned short) 18, "MIT-MAGIC-COOKIE-1", 103 MitInitAuth, MitGetAuth, NULL 104}, 105#ifdef HASXDMAUTH 106{ (unsigned short) 19, "XDM-AUTHORIZATION-1", 107 XdmInitAuth, XdmGetAuth, XdmGetXdmcpAuth, 108}, 109#endif 110#ifdef SECURE_RPC 111{ (unsigned short) 9, "SUN-DES-1", 112 SecureRPCInitAuth, SecureRPCGetAuth, NULL, 113}, 114#endif 115#ifdef K5AUTH 116{ (unsigned short) 14, "MIT-KERBEROS-5", 117 Krb5InitAuth, Krb5GetAuth, NULL, 118}, 119#endif 120}; 121 122#define NUM_AUTHORIZATION (sizeof (AuthProtocols) / sizeof (AuthProtocols[0])) 123 124static struct AuthProtocol * 125findProtocol (unsigned short name_length, char *name) 126{ 127 int i; 128 129 for (i = 0; i < NUM_AUTHORIZATION; i++) 130 if (AuthProtocols[i].name_length == name_length && 131 memcmp(AuthProtocols[i].name, name, name_length) == 0) 132 { 133 return &AuthProtocols[i]; 134 } 135 return (struct AuthProtocol *) 0; 136} 137 138int 139ValidAuthorization (unsigned short name_length, char *name) 140{ 141 if (findProtocol (name_length, name)) 142 return TRUE; 143 return FALSE; 144} 145 146static Xauth * 147GenerateAuthorization (unsigned short name_length, char *name) 148{ 149 struct AuthProtocol *a; 150 Xauth *auth = NULL; 151 int i; 152 153 Debug ("GenerateAuthorization %*.*s\n", 154 name_length, name_length, name); 155 a = findProtocol (name_length, name); 156 if (a) 157 { 158 if (!a->inited) 159 { 160 (*a->InitAuth) (name_length, name); 161 a->inited = TRUE; 162 } 163 auth = (*a->GetAuth) (name_length, name); 164 if (auth) 165 { 166 Debug ("Got %p (%d %*.*s) ", auth, 167 auth->name_length, auth->name_length, 168 auth->name_length, auth->name); 169 for (i = 0; i < (int)auth->data_length; i++) 170 Debug (" %02x", auth->data[i] & 0xff); 171 Debug ("\n"); 172 } 173 else 174 Debug ("Got (null)\n"); 175 } 176 else 177 { 178 Debug ("Unknown authorization %*.*s\n", name_length, name_length, name); 179 } 180 return auth; 181} 182 183#ifdef XDMCP 184 185void 186SetProtoDisplayAuthorization ( 187 struct protoDisplay *pdpy, 188 unsigned short authorizationNameLen, 189 char *authorizationName) 190{ 191 struct AuthProtocol *a; 192 Xauth *auth; 193 194 a = findProtocol (authorizationNameLen, authorizationName); 195 pdpy->xdmcpAuthorization = pdpy->fileAuthorization = NULL; 196 if (a) 197 { 198 if (!a->inited) 199 { 200 (*a->InitAuth) (authorizationNameLen, authorizationName); 201 a->inited = TRUE; 202 } 203 if (a->GetXdmcpAuth) 204 { 205 (*a->GetXdmcpAuth) (pdpy, authorizationNameLen, authorizationName); 206 auth = pdpy->xdmcpAuthorization; 207 } 208 else 209 { 210 auth = (*a->GetAuth) (authorizationNameLen, authorizationName); 211 pdpy->fileAuthorization = auth; 212 pdpy->xdmcpAuthorization = NULL; 213 } 214 if (auth) 215 Debug ("Got %p (%d %*.*s)\n", auth, 216 auth->name_length, auth->name_length, 217 auth->name_length, auth->name); 218 else 219 Debug ("Got (null)\n"); 220 } 221} 222 223#endif /* XDMCP */ 224 225void 226CleanUpFileName (char *src, char *dst, int len) 227{ 228 while (*src) { 229 if (--len <= 0) 230 break; 231 switch (*src & 0x7f) 232 { 233 case '/': 234 *dst++ = '_'; 235 break; 236 case '-': 237 *dst++ = '.'; 238 break; 239 default: 240 *dst++ = (*src & 0x7f); 241 } 242 ++src; 243 } 244 *dst = '\0'; 245} 246 247/* Checks to see if specified directory exists, makes it if not 248 * Returns: 0 if already exists, 1 if created, < 0 if error occurred 249 */ 250static int 251CheckServerAuthDir (const char *path, struct stat *statb, int mode) 252{ 253 int r = stat(path, statb); 254 255 if (r != 0) { 256 if (errno == ENOENT) { 257 r = mkdir(path, mode); 258 if (r < 0) { 259 LogError ("cannot make authentication directory %s: %s\n", 260 path, _SysErrorMsg (errno)); 261 } else { 262 r = 1; 263 } 264 } else { 265 LogError ("cannot access authentication directory %s: %s\n", 266 path, _SysErrorMsg (errno)); 267 } 268 } else { /* Directory already exists */ 269 if (!S_ISDIR(statb->st_mode)) { 270 LogError ("cannot make authentication directory %s: %s\n", 271 path, "file with that name already exists"); 272 return -1; 273 } 274 } 275 276 return r; 277} 278 279static char authdir1[] = "authdir"; 280static char authdir2[] = "authfiles"; 281 282static int 283MakeServerAuthFile (struct display *d, FILE ** file) 284{ 285 int len; 286#ifdef MAXNAMELEN 287# define NAMELEN MAXNAMELEN 288#else 289# define NAMELEN 255 290#endif 291 char cleanname[NAMELEN]; 292 int r; 293#ifdef HAVE_MKSTEMP 294 int fd; 295#endif 296 struct stat statb; 297 298 *file = NULL; 299 300 if (!d->authFile) { 301 if (d->clientAuthFile && *d->clientAuthFile) { 302 d->authFile = strdup(d->clientAuthFile); 303 if (!d->authFile) 304 return FALSE; 305 } else { 306 CleanUpFileName (d->name, cleanname, NAMELEN - 8); 307 308 /* Make authDir if it doesn't already exist */ 309 r = CheckServerAuthDir(authDir, &statb, 0755); 310 if (r < 0) { 311 return FALSE; 312 } 313 314 len = strlen (authDir) + strlen (authdir1) + strlen (authdir2) 315 + strlen (cleanname) + 14; 316 d->authFile = malloc (len); 317 if (!d->authFile) 318 return FALSE; 319 320 snprintf (d->authFile, len, "%s/%s", authDir, authdir1); 321 r = CheckServerAuthDir(d->authFile, &statb, 0700); 322 if (r == 0) { 323 if (statb.st_uid != 0) 324 (void) chown(d->authFile, 0, statb.st_gid); 325 if ((statb.st_mode & 0077) != 0) 326 (void) chmod(d->authFile, statb.st_mode & 0700); 327 } else if (r < 0) { 328 free (d->authFile); 329 d->authFile = NULL; 330 return FALSE; 331 } 332 333 snprintf (d->authFile, len, "%s/%s/%s", 334 authDir, authdir1, authdir2); 335 r = CheckServerAuthDir(d->authFile, &statb, 0700); 336 if (r < 0) { 337 free (d->authFile); 338 d->authFile = NULL; 339 return FALSE; 340 } 341 snprintf (d->authFile, len, "%s/%s/%s/A%s-XXXXXX", 342 authDir, authdir1, authdir2, cleanname); 343#ifdef HAVE_MKSTEMP 344 fd = mkstemp (d->authFile); 345 if (fd < 0) { 346 LogError ("cannot make authentication file %s: %s\n", 347 d->authFile, _SysErrorMsg (errno)); 348 free (d->authFile); 349 d->authFile = NULL; 350 return FALSE; 351 } 352 353 *file = fdopen(fd, "w"); 354 if (!*file) 355 (void) close (fd); 356 return TRUE; 357#else 358 (void) mktemp (d->authFile); 359#endif 360 } 361 } 362 363 (void) unlink (d->authFile); 364 *file = fopen (d->authFile, "w"); 365 return TRUE; 366} 367 368int 369SaveServerAuthorizations ( 370 struct display *d, 371 Xauth **auths, 372 int count) 373{ 374 FILE *auth_file; 375 mode_t mask; 376 int ret; 377 int i; 378 const char dummy_auth[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 379 "XXXXXXXXXXXXXXXXX"; /* 64 "X"s */ 380 int err = 0; 381 382 mask = umask (0077); 383 ret = MakeServerAuthFile(d, &auth_file); 384 umask (mask); 385 if (!ret) 386 return FALSE; 387 if (!auth_file) { 388 LogError ("cannot open server authorization file %s: %s\n", 389 d->authFile, _SysErrorMsg (errno)); 390 ret = FALSE; 391 } 392 else 393 { 394 Debug ("File: %s auth: %p\n", d->authFile, auths); 395 ret = TRUE; 396 if (count == 0) 397 { 398 /* 399 * This is a crude hack to determine whether we really can 400 * write to the auth file even if we don't have real data 401 * to write right now. 402 */ 403 404 /* 405 * Write garbage data to file to provoke ENOSPC and other 406 * errors. 407 */ 408 (void) fprintf (auth_file, "%s", dummy_auth); 409 (void) fflush (auth_file); 410 if (ferror (auth_file)) 411 { 412 err = errno; 413 ret = FALSE; 414 } 415 /* 416 * Rewind so that the garbage data is overwritten later. 417 */ 418 rewind(auth_file); 419 } 420 for (i = 0; i < count; i++) 421 { 422 /* 423 * User-based auths may not have data until 424 * a user logs in. In which case don't write 425 * to the auth file so xrdb and setup programs don't fail. 426 */ 427 if (auths[i]->data_length > 0) { 428 if (!XauWriteAuth (auth_file, auths[i])) 429 { 430 Debug ("XauWriteAuth() failed\n"); 431 } 432 (void) fflush (auth_file); 433 if (ferror (auth_file)) 434 { 435 err = errno; 436 ret = FALSE; 437 } 438 } 439 } 440 /* 441 * XXX: This is not elegant, but stdio has no truncation function. 442 */ 443 if (ftruncate(fileno(auth_file), ftell(auth_file))) 444 { 445 Debug ("ftruncate() failed\n"); 446 } 447 fclose (auth_file); 448 449 } 450 if (ret == FALSE) 451 { 452 LogError ("Cannot write to server authorization file %s%s%s\n", 453 d->authFile, 454 err ? ": " : "", 455 err ? _SysErrorMsg (errno) : ""); 456 free (d->authFile); 457 d->authFile = NULL; 458 } 459 return ret; 460} 461 462void 463SetLocalAuthorization (struct display *d) 464{ 465 Xauth *auth, **auths; 466 int i, j; 467 468 if (d->authorizations) 469 { 470 for (i = 0; i < d->authNum; i++) 471 XauDisposeAuth (d->authorizations[i]); 472 free (d->authorizations); 473 d->authorizations = (Xauth **) NULL; 474 d->authNum = 0; 475 } 476 if (!d->authNames) 477 return; 478 for (i = 0; d->authNames[i]; i++) 479 ; 480 d->authNameNum = i; 481 free (d->authNameLens); 482 d->authNameLens = malloc (d->authNameNum * sizeof (unsigned short)); 483 if (!d->authNameLens) 484 return; 485 for (i = 0; i < d->authNameNum; i++) 486 d->authNameLens[i] = strlen (d->authNames[i]); 487 auths = malloc (d->authNameNum * sizeof (Xauth *)); 488 if (!auths) 489 return; 490 j = 0; 491 for (i = 0; i < d->authNameNum; i++) 492 { 493 auth = GenerateAuthorization (d->authNameLens[i], d->authNames[i]); 494 if (auth) 495 auths[j++] = auth; 496 } 497 if (SaveServerAuthorizations (d, auths, j)) 498 { 499 d->authorizations = auths; 500 d->authNum = j; 501 } 502 else 503 { 504 for (i = 0; i < j; i++) 505 XauDisposeAuth (auths[i]); 506 free (auths); 507 } 508} 509 510/* 511 * Set the authorization to use for xdm's initial connection 512 * to the X server. Cannot use user-based authorizations 513 * because no one has logged in yet, so we don't have any 514 * user credentials. 515 * Well, actually we could use SUN-DES-1 because we tell the server 516 * to allow root in. This is bogus and should be fixed. 517 */ 518void 519SetAuthorization (struct display *d) 520{ 521 register Xauth **auth = d->authorizations; 522 int i; 523 524 for (i = 0; i < d->authNum; i++) 525 { 526 if (auth[i]->name_length == 9 && 527 memcmp(auth[i]->name, "SUN-DES-1", 9) == 0) 528 continue; 529 if (auth[i]->name_length == 14 && 530 memcmp(auth[i]->name, "MIT-KERBEROS-5", 14) == 0) 531 continue; 532 XSetAuthorization (auth[i]->name, (int) auth[i]->name_length, 533 auth[i]->data, (int) auth[i]->data_length); 534 } 535} 536 537static int 538openFiles (char *name, char *new_name, FILE **oldp, FILE **newp) 539{ 540 mode_t mask; 541 int newfd; 542 543 strcpy (new_name, name); 544 strcat (new_name, "-n"); 545 /* 546 * Set safe umask for file creation operations. 547 */ 548 mask = umask (0077); 549 /* 550 * Unlink the authorization file we intend to create, and then open 551 * it with O_CREAT | O_EXCL to avoid race-based symlink attacks. 552 */ 553 (void) unlink (new_name); 554 newfd = open (new_name, O_WRONLY | O_CREAT | O_EXCL, 0600); 555 if (newfd >= 0) { 556 *newp = fdopen (newfd, "w"); 557 if (*newp == NULL) 558 close(newfd); 559 } 560 else 561 { 562 LogError ("Cannot create file %s: %s\n", new_name, 563 _SysErrorMsg (errno)); 564 *newp = NULL; 565 } 566 /* 567 * There are no more attempts to create files after this point; 568 * restore the original umask. 569 */ 570 (void) umask (mask); 571 if (!*newp) { 572 Debug ("can't open new file %s\n", new_name); 573 return 0; 574 } 575 if (!*oldp) 576 *oldp = fopen (name, "r"); 577 Debug ("opens succeeded %s %s\n", name, new_name); 578 return 1; 579} 580 581static int 582binaryEqual (char *a, char *b, unsigned short len) 583{ 584 while (len-- > 0) 585 if (*a++ != *b++) 586 return FALSE; 587 return TRUE; 588} 589 590static void 591dumpBytes (unsigned short len, char *data) 592{ 593 unsigned short i; 594 595 Debug ("%d: ", len); 596 for (i = 0; i < len; i++) 597 Debug ("%02x ", data[i] & 0377); 598 Debug ("\n"); 599} 600 601static void 602dumpAuth (Xauth *auth) 603{ 604 Debug ("family: %d\n", auth->family); 605 Debug ("addr: "); 606 dumpBytes (auth->address_length, auth->address); 607 Debug ("number: "); 608 dumpBytes (auth->number_length, auth->number); 609 Debug ("name: "); 610 dumpBytes (auth->name_length, auth->name); 611 Debug ("data: "); 612 dumpBytes (auth->data_length, auth->data); 613} 614 615struct addrList { 616 unsigned short family; 617 unsigned short address_length; 618 char *address; 619 unsigned short number_length; 620 char *number; 621 unsigned short name_length; 622 char *name; 623 struct addrList *next; 624}; 625 626static struct addrList *addrs; 627 628static void 629initAddrs (void) 630{ 631 addrs = NULL; 632} 633 634static void 635doneAddrs (void) 636{ 637 struct addrList *a, *n; 638 for (a = addrs; a; a = n) { 639 n = a->next; 640 free (a->address); 641 free (a->number); 642 free (a); 643 } 644 addrs = NULL; 645} 646 647static int checkEntry (Xauth *auth); 648 649static void 650saveEntry (Xauth *auth) 651{ 652 struct addrList *new; 653 654 new = malloc (sizeof (struct addrList)); 655 if (!new) { 656 LogOutOfMem ("saveEntry"); 657 return; 658 } 659 if ((new->address_length = auth->address_length) > 0) { 660 new->address = malloc (auth->address_length); 661 if (!new->address) { 662 LogOutOfMem ("saveEntry"); 663 free (new); 664 return; 665 } 666 memcpy(new->address, auth->address, (int) auth->address_length); 667 } else 668 new->address = NULL; 669 if ((new->number_length = auth->number_length) > 0) { 670 new->number = malloc (auth->number_length); 671 if (!new->number) { 672 LogOutOfMem ("saveEntry"); 673 free (new->address); 674 free (new); 675 return; 676 } 677 memcpy(new->number, auth->number, (int) auth->number_length); 678 } else 679 new->number = NULL; 680 if ((new->name_length = auth->name_length) > 0) { 681 new->name = malloc (auth->name_length); 682 if (!new->name) { 683 LogOutOfMem ("saveEntry"); 684 free (new->number); 685 free (new->address); 686 free (new); 687 return; 688 } 689 memcpy(new->name, auth->name, (int) auth->name_length); 690 } else 691 new->name = NULL; 692 new->family = auth->family; 693 new->next = addrs; 694 addrs = new; 695} 696 697static int 698checkEntry (Xauth *auth) 699{ 700 struct addrList *a; 701 702 for (a = addrs; a; a = a->next) { 703 if (a->family == auth->family && 704 a->address_length == auth->address_length && 705 binaryEqual (a->address, auth->address, auth->address_length) && 706 a->number_length == auth->number_length && 707 binaryEqual (a->number, auth->number, auth->number_length) && 708 a->name_length == auth->name_length && 709 binaryEqual (a->name, auth->name, auth->name_length)) 710 { 711 return 1; 712 } 713 } 714 return 0; 715} 716 717static int doWrite; 718 719static void 720writeAuth (FILE *file, Xauth *auth) 721{ 722 if (debugLevel >= 15) { /* normally too verbose */ 723 Debug ("writeAuth: doWrite = %d\n", doWrite); 724 dumpAuth (auth); /* does Debug only */ 725 } 726 if (doWrite) 727 XauWriteAuth (file, auth); 728} 729 730static void 731writeAddr ( 732 int family, 733 int addr_length, 734 char *addr, 735 FILE *file, 736 Xauth *auth) 737{ 738 auth->family = (unsigned short) family; 739 auth->address_length = addr_length; 740 auth->address = addr; 741 Debug ("writeAddr: writing and saving an entry\n"); 742 writeAuth (file, auth); 743 saveEntry (auth); 744} 745 746static void 747DefineLocal (FILE *file, Xauth *auth) 748{ 749 char displayname[100]; 750 int len = _XGetHostname (displayname, sizeof(displayname)); 751 752/* Make sure this produces the same string as _XGetHostname in lib/X/XlibInt.c. 753 * Otherwise, Xau will not be able to find your cookies in the Xauthority file. 754 * 755 * Note: POSIX says that the ``nodename'' member of utsname does _not_ have 756 * to have sufficient information for interfacing to the network, 757 * and so, you may be better off using gethostname (if it exists). 758 */ 759 760 761 writeAddr (FamilyLocal, len, displayname, file, auth); 762} 763 764#ifdef HAVE_GETIFADDRS 765# include <ifaddrs.h> 766 767static void 768DefineSelf(int fd, FILE *file, Xauth *auth) 769{ 770 struct ifaddrs *ifap, *ifr; 771 char *addr; 772 int family, len; 773 774 Debug("DefineSelf\n"); 775 if (getifaddrs(&ifap) < 0) 776 return; 777 for (ifr = ifap; ifr != NULL; ifr = ifr->ifa_next) { 778 len = sizeof(*(ifr->ifa_addr)); 779 family = ConvertAddr((XdmcpNetaddr)(ifr->ifa_addr), &len, &addr); 780 if (family == -1 || family == FamilyLocal) 781 continue; 782 /* 783 * don't write out 'localhost' entries, as 784 * they may conflict with other local entries. 785 * DefineLocal will always be called to add 786 * the local entry anyway, so this one can 787 * be tossed. 788 */ 789 if (family == FamilyInternet && len == 4 && addr[0] == 127) 790 { 791 Debug ("Skipping localhost address\n"); 792 continue; 793 } 794# ifdef IPv6 795 if(family == FamilyInternet6) { 796 if (IN6_IS_ADDR_LOOPBACK(((struct in6_addr *)addr))) { 797 Debug ("Skipping IPv6 localhost address\n"); 798 continue; 799 } 800 /* Also skip XDM-AUTHORIZATION-1 */ 801 if (auth->name_length == 19 && 802 strcmp(auth->name, "XDM-AUTHORIZATION-1") == 0) { 803 Debug ("Skipping IPv6 XDM-AUTHORIZATION-1\n"); 804 continue; 805 } 806 } 807# endif 808 writeAddr(family, len, addr, file, auth); 809 } 810 freeifaddrs(ifap); 811 Debug("DefineSelf done\n"); 812} 813#else /* GETIFADDRS */ 814 815# if defined(SIOCGIFCONF) || defined (USE_SIOCGLIFCONF) 816 817# ifdef USE_SIOCGLIFCONF 818# define ifr_type struct lifreq 819# else 820# define ifr_type struct ifreq 821# endif 822 823/* Handle variable length ifreq in BNR2 and later */ 824# ifdef VARIABLE_IFREQ 825# define ifr_size(p) (sizeof (struct ifreq) + \ 826 (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \ 827 p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0)) 828# else 829# define ifr_size(p) (sizeof (ifr_type)) 830# endif 831 832/* Define this host for access control. Find all the hosts the OS knows about 833 * for this fd and add them to the selfhosts list. 834 */ 835static void 836DefineSelf (int fd, FILE *file, Xauth *auth) 837{ 838 char buf[2048], *cp, *cplim; 839 int len; 840 char *addr; 841 int family; 842 register ifr_type *ifr; 843# ifdef USE_SIOCGLIFCONF 844 void * bufptr = buf; 845 size_t buflen = sizeof(buf); 846 struct lifconf ifc; 847# ifdef SIOCGLIFNUM 848 struct lifnum ifn; 849# endif 850# else 851 struct ifconf ifc; 852# endif 853 854# if defined(SIOCGLIFNUM) && defined(SIOCGLIFCONF) 855 ifn.lifn_family = AF_UNSPEC; 856 ifn.lifn_flags = 0; 857 if (ioctl (fd, (int) SIOCGLIFNUM, (char *) &ifn) < 0) 858 LogError ("Failed getting interface count"); 859 if (buflen < (ifn.lifn_count * sizeof(struct lifreq))) { 860 buflen = ifn.lifn_count * sizeof(struct lifreq); 861 bufptr = malloc(buflen); 862 } 863# endif 864 865# ifdef USE_SIOCGLIFCONF 866 ifc.lifc_family = AF_UNSPEC; 867 ifc.lifc_flags = 0; 868 ifc.lifc_len = buflen; 869 ifc.lifc_buf = bufptr; 870 871# define IFC_IOCTL_REQ SIOCGLIFCONF 872# define IFC_IFC_REQ ifc.lifc_req 873# define IFC_IFC_LEN ifc.lifc_len 874# define IFR_IFR_ADDR ifr->lifr_addr 875# define IFR_IFR_NAME ifr->lifr_name 876 877# else 878 ifc.ifc_len = sizeof (buf); 879 ifc.ifc_buf = buf; 880 881# define IFC_IOCTL_REQ SIOCGIFCONF 882# define IFC_IFC_REQ ifc.ifc_req 883# define IFC_IFC_LEN ifc.ifc_len 884# define IFR_IFR_ADDR ifr->ifr_addr 885# define IFR_IFR_NAME ifr->ifr_name 886# endif 887 888 if (ioctl (fd, IFC_IOCTL_REQ, (char *) &ifc) < 0) { 889 LogError ("Trouble getting network interface configuration"); 890 891# ifdef USE_SIOCGLIFCONF 892 if (bufptr != buf) { 893 free(bufptr); 894 } 895# endif 896 return; 897 } 898 899 cplim = (char *) IFC_IFC_REQ + IFC_IFC_LEN; 900 901 for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size (ifr)) 902 { 903 ifr = (ifr_type *) cp; 904 family = ConvertAddr ((XdmcpNetaddr) &IFR_IFR_ADDR, &len, &addr); 905 if (family < 0) 906 continue; 907 908 if (len == 0) 909 { 910 Debug ("Skipping zero length address\n"); 911 continue; 912 } 913 /* 914 * don't write out 'localhost' entries, as 915 * they may conflict with other local entries. 916 * DefineLocal will always be called to add 917 * the local entry anyway, so this one can 918 * be tossed. 919 */ 920 if (family == FamilyInternet && len == 4 && 921 addr[0] == 127 && addr[1] == 0 && 922 addr[2] == 0 && addr[3] == 1) 923 { 924 Debug ("Skipping localhost address\n"); 925 continue; 926 } 927# ifdef IPv6 928 if (family == FamilyInternet6) { 929 if (IN6_IS_ADDR_LOOPBACK(((struct in6_addr *)addr))) { 930 Debug ("Skipping IPv6 localhost address\n"); 931 continue; 932 } 933 /* Also skip XDM-AUTHORIZATION-1 */ 934 if (auth->name_length == 19 && 935 strcmp(auth->name, "XDM-AUTHORIZATION-1") == 0) { 936 Debug ("Skipping IPv6 XDM-AUTHORIZATION-1\n"); 937 continue; 938 } 939 } 940# endif 941 Debug ("DefineSelf: write network address, length %d\n", len); 942 writeAddr (family, len, addr, file, auth); 943 } 944} 945 946# else /* SIOCGIFCONF */ 947 948/* Define this host for access control. Find all the hosts the OS knows about 949 * for this fd and add them to the selfhosts list. 950 */ 951static void 952DefineSelf (int fd, int file, int auth) 953{ 954 register int n; 955 int len; 956 caddr_t addr; 957 int family; 958 959 struct utsname name; 960 register struct hostent *hp; 961 962 union { 963 struct sockaddr sa; 964 struct sockaddr_in in; 965 } saddr; 966 967 struct sockaddr_in *inetaddr; 968 969 /* hpux: 970 * Why not use gethostname()? Well, at least on my system, I've had to 971 * make an ugly kernel patch to get a name longer than 8 characters, and 972 * uname() lets me access to the whole string (it smashes release, you 973 * see), whereas gethostname() kindly truncates it for me. 974 */ 975 uname(&name); 976 hp = gethostbyname (name.nodename); 977 if (hp != NULL) { 978 saddr.sa.sa_family = hp->h_addrtype; 979 inetaddr = (struct sockaddr_in *) (&(saddr.sa)); 980 memcpy(&(inetaddr->sin_addr), hp->h_addr, hp->h_length); 981 family = ConvertAddr ( &(saddr.sa), &len, &addr); 982 if ( family >= 0) { 983 writeAddr (FamilyInternet, sizeof (inetaddr->sin_addr), 984 (char *) (&inetaddr->sin_addr), file, auth); 985 } 986 } 987} 988 989 990# endif /* SIOCGIFCONF else */ 991#endif /* HAVE_GETIFADDRS */ 992 993static void 994setAuthNumber (Xauth *auth, char *name) 995{ 996 char *colon; 997 char *dot, *number; 998 999 Debug ("setAuthNumber %s\n", name); 1000 colon = strrchr(name, ':'); 1001 if (colon) { 1002 ++colon; 1003 dot = strchr(colon, '.'); 1004 if (dot) 1005 auth->number_length = dot - colon; 1006 else 1007 auth->number_length = strlen (colon); 1008 number = malloc (auth->number_length + 1); 1009 if (number) { 1010 strncpy (number, colon, auth->number_length); 1011 number[auth->number_length] = '\0'; 1012 } else { 1013 LogOutOfMem ("setAuthNumber"); 1014 auth->number_length = 0; 1015 } 1016 auth->number = number; 1017 Debug ("setAuthNumber: %s\n", number); 1018 } 1019} 1020 1021static void 1022writeLocalAuth (FILE *file, Xauth *auth, char *name) 1023{ 1024 int fd; 1025 1026 Debug ("writeLocalAuth: %s %.*s\n", name, auth->name_length, auth->name); 1027 setAuthNumber (auth, name); 1028#ifdef TCPCONN 1029# ifdef IPv6 1030 fd = socket (AF_INET6, SOCK_STREAM, 0); 1031 if (fd < 0) 1032# endif 1033 fd = socket (AF_INET, SOCK_STREAM, 0); 1034 DefineSelf (fd, file, auth); 1035 close (fd); 1036#endif 1037 DefineLocal (file, auth); 1038} 1039 1040#ifdef XDMCP 1041 1042static void 1043writeRemoteAuth (FILE *file, Xauth *auth, XdmcpNetaddr peer, int peerlen, char *name) 1044{ 1045 int family = FamilyLocal; 1046 char *addr; 1047 1048 Debug ("writeRemoteAuth: %s %.*s\n", name, auth->name_length, auth->name); 1049 if (!peer || peerlen < 2) 1050 return; 1051 setAuthNumber (auth, name); 1052 family = ConvertAddr (peer, &peerlen, &addr); 1053 Debug ("writeRemoteAuth: family %d\n", family); 1054 if (family != FamilyLocal) 1055 { 1056 Debug ("writeRemoteAuth: %d, %d, %x\n", 1057 family, peerlen, *(int *)addr); 1058 writeAddr (family, peerlen, addr, file, auth); 1059 } 1060 else 1061 { 1062 writeLocalAuth (file, auth, name); 1063 } 1064} 1065 1066#endif /* XDMCP */ 1067 1068void 1069SetUserAuthorization (struct display *d, struct verify_info *verify) 1070{ 1071 FILE *old = NULL, *new; 1072 char home_name[1024], backup_name[1024], new_name[1024]; 1073 char *name = NULL; 1074 char *home; 1075 char *envname = NULL; 1076 int lockStatus; 1077 Xauth *entry, **auths; 1078 int setenv = 0; 1079 struct stat statb; 1080 int i; 1081 int magicCookie; 1082 int data_len; 1083#ifdef HAVE_MKSTEMP 1084 int fd; 1085#endif 1086 1087 Debug ("SetUserAuthorization\n"); 1088 auths = d->authorizations; 1089 if (auths) { 1090 home = getEnv (verify->userEnviron, "HOME"); 1091 lockStatus = LOCK_ERROR; 1092 if (home) { 1093 snprintf (home_name, sizeof(home_name), "%s/.Xauthority", home); 1094 Debug ("XauLockAuth %s\n", home_name); 1095 lockStatus = XauLockAuth (home_name, 1, 2, 10); 1096 Debug ("Lock is %d\n", lockStatus); 1097 if (lockStatus == LOCK_SUCCESS) { 1098 if (openFiles (home_name, new_name, &old, &new) 1099 && (old != NULL) && (new != NULL)) { 1100 name = home_name; 1101 setenv = 0; 1102 } else { 1103 Debug ("openFiles failed\n"); 1104 XauUnlockAuth (home_name); 1105 lockStatus = LOCK_ERROR; 1106 if (old != NULL) { 1107 (void) fclose (old); 1108 old = NULL; 1109 } 1110 if (new != NULL) 1111 (void) fclose (new); 1112 } 1113 } 1114 } 1115 if (lockStatus != LOCK_SUCCESS) { 1116 snprintf (backup_name, sizeof(backup_name), 1117 "%s/.XauthXXXXXX", d->userAuthDir); 1118#ifdef HAVE_MKSTEMP 1119 fd = mkstemp (backup_name); 1120 if (fd >= 0) { 1121 old = fdopen (fd, "r"); 1122 if (old == NULL) 1123 (void) close(fd); 1124 } 1125 1126 if (old != NULL) 1127#else 1128 (void) mktemp (backup_name); 1129#endif 1130 { 1131 lockStatus = XauLockAuth (backup_name, 1, 2, 10); 1132 Debug ("backup lock is %d\n", lockStatus); 1133 if (lockStatus == LOCK_SUCCESS) { 1134 if (openFiles (backup_name, new_name, &old, &new) 1135 && (old != NULL) && (new != NULL)) { 1136 name = backup_name; 1137 setenv = 1; 1138 } else { 1139 XauUnlockAuth (backup_name); 1140 lockStatus = LOCK_ERROR; 1141 if (old != NULL) { 1142 (void) fclose (old); 1143 old = NULL; 1144 } 1145 if (new != NULL) 1146 (void) fclose (new); 1147 } 1148#ifdef HAVE_MKSTEMP 1149 } else { 1150 (void) fclose (old); 1151#endif 1152 } 1153 } 1154 } 1155 if (lockStatus != LOCK_SUCCESS) { 1156 Debug ("can't lock auth file %s or backup %s\n", 1157 home_name, backup_name); 1158 LogError ("can't lock authorization file %s or backup %s\n", 1159 home_name, backup_name); 1160 return; 1161 } 1162 initAddrs (); 1163 doWrite = 1; 1164 Debug ("%d authorization protocols for %s\n", d->authNum, d->name); 1165 /* 1166 * Write MIT-MAGIC-COOKIE-1 authorization first, so that 1167 * R4 clients which only knew that, and used the first 1168 * matching entry will continue to function 1169 */ 1170 magicCookie = -1; 1171 for (i = 0; i < d->authNum; i++) 1172 { 1173 if (auths[i]->name_length == 18 && 1174 !strncmp (auths[i]->name, "MIT-MAGIC-COOKIE-1", 18)) 1175 { 1176 magicCookie = i; 1177 if (d->displayType.location == Local) 1178 writeLocalAuth (new, auths[i], d->name); 1179#ifdef XDMCP 1180 else 1181 writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name); 1182#endif 1183 break; 1184 } 1185 } 1186 /* now write other authorizations */ 1187 for (i = 0; i < d->authNum; i++) 1188 { 1189 if (i != magicCookie) 1190 { 1191 data_len = auths[i]->data_length; 1192 /* client will just use default Kerberos cache, so don't 1193 * even write cache info into the authority file. 1194 */ 1195 if (auths[i]->name_length == 14 && 1196 !strncmp (auths[i]->name, "MIT-KERBEROS-5", 14)) 1197 auths[i]->data_length = 0; 1198 if (d->displayType.location == Local) 1199 writeLocalAuth (new, auths[i], d->name); 1200#ifdef XDMCP 1201 else 1202 writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name); 1203#endif 1204 auths[i]->data_length = data_len; 1205 } 1206 } 1207 if (old) { 1208 if (fstat (fileno (old), &statb) != -1) 1209 chmod (new_name, (int) (statb.st_mode & 0777)); 1210 /*SUPPRESS 560*/ 1211 while ((entry = XauReadAuth (old))) { 1212 if (!checkEntry (entry)) 1213 { 1214 Debug ("Writing an entry\n"); 1215 writeAuth (new, entry); 1216 } 1217 XauDisposeAuth (entry); 1218 } 1219 fclose (old); 1220 } 1221 doneAddrs (); 1222 fclose (new); 1223 if (unlink (name) == -1) 1224 if (errno != ENOENT) 1225 LogError ("cannot remove old authorization file %s: %s\n", 1226 name, _SysErrorMsg (errno)); 1227 envname = name; 1228 if (link (new_name, name) == -1) { 1229 LogError ("cannot link temporary authorization file %s to old " 1230 "location %s: %s\n", new_name, name, 1231 _SysErrorMsg (errno)); 1232 setenv = 1; 1233 envname = new_name; 1234 } else { 1235 Debug ("authorization file %s successfully updated\n", name); 1236 if (unlink (new_name)) 1237 if (errno != ENOENT) 1238 LogError ("cannot remove new authorization file %s:" 1239 " %s\n", new_name, _SysErrorMsg (errno)); 1240 } 1241 if (setenv) { 1242 verify->userEnviron = setEnv (verify->userEnviron, 1243 "XAUTHORITY", envname); 1244 verify->systemEnviron = setEnv (verify->systemEnviron, 1245 "XAUTHORITY", envname); 1246 } 1247 XauUnlockAuth (name); 1248 if (envname) 1249 chown (envname, verify->uid, verify->gid); 1250 } 1251 Debug ("done SetUserAuthorization\n"); 1252} 1253 1254void 1255RemoveUserAuthorization (struct display *d, struct verify_info *verify) 1256{ 1257 char *home; 1258 Xauth **auths, *entry; 1259 char name[1024], new_name[1024]; 1260 int lockStatus; 1261 FILE *old, *new; 1262 struct stat statb; 1263 int i; 1264 1265 if (!(auths = d->authorizations)) 1266 return; 1267 home = getEnv (verify->userEnviron, "HOME"); 1268 if (!home) 1269 return; 1270 Debug ("RemoveUserAuthorization\n"); 1271 snprintf(name, sizeof(name), "%s/.Xauthority", home); 1272 Debug ("XauLockAuth %s\n", name); 1273 lockStatus = XauLockAuth (name, 1, 2, 10); 1274 Debug ("Lock is %d\n", lockStatus); 1275 if (lockStatus != LOCK_SUCCESS) 1276 return; 1277 old = NULL; 1278 if (openFiles (name, new_name, &old, &new)) 1279 { 1280 initAddrs (); 1281 doWrite = 0; 1282 for (i = 0; i < d->authNum; i++) 1283 { 1284 if (d->displayType.location == Local) 1285 writeLocalAuth (new, auths[i], d->name); 1286#ifdef XDMCP 1287 else 1288 writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name); 1289#endif 1290 } 1291 doWrite = 1; 1292 if (old) { 1293 if (fstat (fileno (old), &statb) != -1) 1294 chmod (new_name, (int) (statb.st_mode & 0777)); 1295 /*SUPPRESS 560*/ 1296 while ((entry = XauReadAuth (old))) { 1297 if (!checkEntry (entry)) 1298 { 1299 Debug ("Writing an entry\n"); 1300 writeAuth (new, entry); 1301 } 1302 XauDisposeAuth (entry); 1303 } 1304 fclose (old); 1305 } 1306 doneAddrs (); 1307 fclose (new); 1308 if (unlink (name) == -1) 1309 if (errno != ENOENT) 1310 LogError ("cannot remove new authorization file %s: %s\n", 1311 name, _SysErrorMsg (errno)); 1312 if (link (new_name, name) == -1) { 1313 LogError ("cannot link temporary authorization file %s to old " 1314 "location %s: %s\n", new_name, name, 1315 _SysErrorMsg (errno)); 1316 } else { 1317 Debug ("authorization file %s successfully updated\n", name); 1318 if (unlink (new_name)) 1319 if (errno != ENOENT) 1320 LogError ("cannot remove new authorization file %s:" 1321 " %s\n", new_name, _SysErrorMsg (errno)); 1322 } 1323 } 1324 XauUnlockAuth (name); 1325} 1326