1 /* 2 * Copyright (c) 2002, Oracle and/or its affiliates. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 /* 24 * 25 Copyright 1990, 1998 The Open Group 26 27 Permission to use, copy, modify, distribute, and sell this software and its 28 documentation for any purpose is hereby granted without fee, provided that 29 the above copyright notice appear in all copies and that both that 30 copyright notice and this permission notice appear in supporting 31 documentation. 32 33 The above copyright notice and this permission notice shall be included in 34 all copies or substantial portions of the Software. 35 36 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 39 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 40 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 41 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 42 43 Except as contained in this notice, the name of a copyright holder shall not be 44 used in advertising or otherwise to promote the sale, use or other dealings 45 in this Software without prior written authorization from the copyright holder. 46 * 47 * Author: Keith Packard, MIT X Consortium 48 */ 49 50 51 /* 52 * Access control for XDMCP - keep a database of allowable display addresses 53 * and (potentially) a list of hosts to send ForwardQuery packets to 54 */ 55 56 #include "dm.h" 57 #include "dm_error.h" 58 59 #ifdef XDMCP 60 61 # include <X11/Xos.h> 62 # include <X11/Xdmcp.h> 63 # include <X11/X.h> 64 # include <stdio.h> 65 # include <ctype.h> 66 67 # include "dm_socket.h" 68 69 # include <netdb.h> 70 71 # ifdef IPv6 72 # include <arpa/inet.h> 73 # endif 74 75 # if defined(IPv6) && !defined(AF_INET6) 76 # error "Cannot build IPv6 support without AF_INET6" 77 # endif 78 79 # define ALIAS_CHARACTER '%' 80 # define NEGATE_CHARACTER '!' 81 # define CHOOSER_STRING "CHOOSER" 82 # define BROADCAST_STRING "BROADCAST" 83 # define NOBROADCAST_STRING "NOBROADCAST" 84 # define LISTEN_STRING "LISTEN" 85 # define WILDCARD_STRING "*" 86 87 # define HOST_ALIAS 0 88 # define HOST_ADDRESS 1 89 # define HOST_BROADCAST 2 90 # define HOST_CHOOSER 3 91 # define HOST_NOBROADCAST 4 92 # define HOST_ANYADDR 5 93 94 typedef struct _hostEntry { 95 struct _hostEntry *next; 96 int type; 97 union _hostOrAlias { 98 char *aliasName; 99 ARRAY8 hostAddress; 100 } entry; 101 int hopCount; 102 } HostEntry; 103 104 # define DISPLAY_ALIAS 0 105 # define DISPLAY_PATTERN 1 106 # define DISPLAY_ADDRESS 2 107 # define DISPLAY_LISTEN 3 108 109 typedef struct _displayEntry { 110 struct _displayEntry *next; 111 int type; 112 int notAllowed; 113 int notBroadcast; 114 int chooser; 115 union _displayType { 116 char *aliasName; 117 char *displayPattern; 118 struct _display { 119 ARRAY8 clientAddress; 120 CARD16 connectionType; 121 } displayAddress; 122 } entry; 123 HostEntry *hosts; 124 } DisplayEntry; 125 126 static DisplayEntry *database; 127 128 ARRAY8Ptr 129 getLocalAddress (void) 130 { 131 static ARRAY8 localAddress; 132 static int haveLocalAddress; 133 134 if (!haveLocalAddress) 135 { 136 # ifdef HAVE_GETADDRINFO 137 struct addrinfo *ai; 138 struct addrinfo hints = { 139 # ifdef IPv6 140 .ai_family = AF_UNSPEC 141 # else 142 .ai_family = AF_INET 143 # endif 144 }; 145 146 if (getaddrinfo(localHostname(), NULL, &hints, &ai) != 0) { 147 if (XdmcpAllocARRAY8 (&localAddress, 4)) { 148 localAddress.data[0] = 127; 149 localAddress.data[1] = 0; 150 localAddress.data[2] = 0; 151 localAddress.data[3] = 1; 152 haveLocalAddress = 1; 153 } 154 } else { 155 if (ai->ai_addr->sa_family == AF_INET) { 156 if (XdmcpAllocARRAY8 (&localAddress, sizeof(struct in_addr))) { 157 memcpy(localAddress.data, 158 &((struct sockaddr_in *)ai->ai_addr)->sin_addr, 159 sizeof(struct in_addr)); 160 haveLocalAddress = 1; 161 } 162 # ifdef IPv6 163 } else if (ai->ai_addr->sa_family == AF_INET6) { 164 if (XdmcpAllocARRAY8 (&localAddress, sizeof(struct in6_addr))) 165 { 166 memcpy(localAddress.data, 167 &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 168 sizeof(struct in6_addr)); 169 haveLocalAddress = 1; 170 } 171 # endif 172 } 173 freeaddrinfo(ai); 174 } 175 # else /* !HAVE_GETADDRINFO */ 176 struct hostent *hostent; 177 178 hostent = gethostbyname (localHostname()); 179 if (hostent != NULL) { 180 if (XdmcpAllocARRAY8 (&localAddress, hostent->h_length)) { 181 memcpy(localAddress.data, hostent->h_addr, hostent->h_length); 182 haveLocalAddress = 1; 183 } 184 } else { 185 /* Assume 127.0.0.1 */ 186 if (XdmcpAllocARRAY8 (&localAddress, 4)) { 187 localAddress.data[0] = 127; 188 localAddress.data[1] = 0; 189 localAddress.data[2] = 0; 190 localAddress.data[3] = 1; 191 haveLocalAddress = 1; 192 } 193 } 194 # endif 195 196 } 197 return &localAddress; 198 } 199 200 static void 201 FreeHostEntry (HostEntry *h) 202 { 203 switch (h->type) { 204 case HOST_ALIAS: 205 free (h->entry.aliasName); 206 break; 207 case HOST_ADDRESS: 208 XdmcpDisposeARRAY8 (&h->entry.hostAddress); 209 break; 210 case HOST_CHOOSER: 211 break; 212 } 213 free (h); 214 } 215 216 static void 217 FreeDisplayEntry (DisplayEntry *d) 218 { 219 HostEntry *h, *next; 220 switch (d->type) { 221 case DISPLAY_ALIAS: 222 free (d->entry.aliasName); 223 break; 224 case DISPLAY_PATTERN: 225 free (d->entry.displayPattern); 226 break; 227 case DISPLAY_ADDRESS: 228 XdmcpDisposeARRAY8 (&d->entry.displayAddress.clientAddress); 229 break; 230 case DISPLAY_LISTEN: 231 /* do nothing - this case doesn't use the d->entry union */ 232 break; 233 } 234 for (h = d->hosts; h; h = next) { 235 next = h->next; 236 FreeHostEntry (h); 237 } 238 free (d); 239 } 240 241 static void 242 FreeAccessDatabase (void) 243 { 244 DisplayEntry *d, *next; 245 246 for (d = database; d; d = next) 247 { 248 next = d->next; 249 FreeDisplayEntry (d); 250 } 251 database = NULL; 252 } 253 254 # define WORD_LEN 256 255 static char wordBuffer[WORD_LEN]; 256 static int nextIsEOF; 257 258 static char * 259 ReadWord (FILE *file, int EOFatEOL) 260 { 261 int c; 262 char *wordp; 263 int quoted; 264 265 wordp = wordBuffer; 266 if (nextIsEOF) 267 { 268 nextIsEOF = FALSE; 269 return NULL; 270 } 271 quoted = FALSE; 272 for (;wordp - wordBuffer < sizeof(wordBuffer)-2;) { 273 c = getc (file); 274 switch (c) { 275 case '#': 276 if (quoted) 277 { 278 *wordp++ = c; 279 break; 280 } 281 while ((c = getc (file)) != EOF && c != '\n') 282 ; 283 case '\n': 284 case EOF: 285 if (c == EOF || (EOFatEOL && !quoted)) 286 { 287 ungetc (c, file); 288 if (wordp == wordBuffer) 289 return NULL; 290 *wordp = '\0'; 291 nextIsEOF = TRUE; 292 return wordBuffer; 293 } 294 case ' ': 295 case '\t': 296 if (wordp != wordBuffer) 297 { 298 ungetc (c, file); 299 *wordp = '\0'; 300 return wordBuffer; 301 } 302 break; 303 case '\\': 304 if (!quoted) 305 { 306 quoted = TRUE; 307 continue; 308 } 309 default: 310 if (wordp < &(wordBuffer[WORD_LEN])) 311 *wordp++ = c; 312 break; 313 } 314 quoted = FALSE; 315 } 316 return NULL; 317 } 318 319 static HostEntry * 320 ReadHostEntry (FILE *file) 321 { 322 char *hostOrAlias; 323 HostEntry *h; 324 325 tryagain: 326 hostOrAlias = ReadWord (file, TRUE); 327 if (!hostOrAlias) 328 return NULL; 329 h = malloc (sizeof (DisplayEntry)); 330 if (!h) 331 { 332 LogOutOfMem ("ReadHostEntry: DisplayEntry\n"); 333 return NULL; 334 } 335 h->hopCount = 1; 336 if (*hostOrAlias == ALIAS_CHARACTER) 337 { 338 h->type = HOST_ALIAS; 339 h->entry.aliasName = strdup (hostOrAlias); 340 if (!h->entry.aliasName) { 341 free (h); 342 return NULL; 343 } 344 } 345 else if (!strcmp (hostOrAlias, CHOOSER_STRING)) 346 { 347 h->type = HOST_CHOOSER; 348 } 349 else if (!strcmp (hostOrAlias, BROADCAST_STRING)) 350 { 351 h->type = HOST_BROADCAST; 352 } 353 else if (!strcmp (hostOrAlias, NOBROADCAST_STRING)) 354 { 355 h->type = HOST_NOBROADCAST; 356 } 357 else if (!strcmp (hostOrAlias, WILDCARD_STRING)) 358 { 359 h->type = HOST_ANYADDR; 360 h->entry.hostAddress.length = 0; 361 } 362 else 363 { 364 void *addr=NULL; 365 size_t addr_length=0; 366 # ifdef HAVE_GETADDRINFO 367 struct addrinfo *ai = NULL; 368 struct addrinfo hints = { 369 # ifdef IPv6 370 .ai_family = AF_UNSPEC 371 # else 372 .ai_family = AF_INET 373 # endif 374 }; 375 # else 376 struct hostent *hostent; 377 # endif 378 char *hops = strrchr(hostOrAlias, '/'); 379 380 if (hops) { 381 *(hops++) = '\0'; 382 h->hopCount = strtol(hops, NULL, 10); 383 if (h->hopCount < 1) 384 h->hopCount = 1; 385 } 386 387 # ifdef HAVE_GETADDRINFO 388 if (getaddrinfo(hostOrAlias, NULL, &hints, &ai) == 0) { 389 if (ai->ai_addr->sa_family == AF_INET) { 390 addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr; 391 addr_length = sizeof(struct in_addr); 392 # ifdef IPv6 393 } else if (ai->ai_addr->sa_family == AF_INET6) { 394 addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; 395 addr_length = sizeof(struct in6_addr); 396 # endif 397 } 398 } 399 # else /* !HAVE_GETADDRINFO */ 400 hostent = gethostbyname (hostOrAlias); 401 if (hostent) { 402 addr = hostent->h_addr; 403 addr_length = hostent->h_length; 404 } 405 # endif 406 h->type = HOST_ADDRESS; 407 408 if (!addr) 409 { 410 Debug ("No such host %s\n", hostOrAlias); 411 LogError ("Access file \"%s\", host \"%s\" not found\n", accessFile, hostOrAlias); 412 free (h); 413 # ifdef HAVE_GETADDRINFO 414 if (ai) 415 freeaddrinfo(ai); 416 # endif 417 goto tryagain; 418 } 419 if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, addr_length)) 420 { 421 LogOutOfMem ("ReadHostEntry\n"); 422 free (h); 423 # ifdef HAVE_GETADDRINFO 424 if (ai) 425 freeaddrinfo(ai); 426 # endif 427 return NULL; 428 } 429 memcpy(h->entry.hostAddress.data, addr, addr_length); 430 # ifdef HAVE_GETADDRINFO 431 if (ai) 432 freeaddrinfo(ai); 433 # endif 434 } 435 return h; 436 } 437 438 static int 439 HasGlobCharacters (char *s) 440 { 441 for (;;) 442 switch (*s++) { 443 case '?': 444 case '*': 445 return 1; 446 case '\0': 447 return 0; 448 } 449 } 450 451 static DisplayEntry * 452 ReadDisplayEntry (FILE *file) 453 { 454 char *displayOrAlias; 455 DisplayEntry *d; 456 struct _display *display; 457 HostEntry *h, **prev; 458 459 tryagain: 460 displayOrAlias = ReadWord (file, FALSE); 461 if (!displayOrAlias) 462 return NULL; 463 d = malloc (sizeof (DisplayEntry)); 464 if (!d) 465 { 466 LogOutOfMem ("ReadDisplayEntry: DisplayEntry\n"); 467 return NULL; 468 } 469 d->notAllowed = 0; 470 d->notBroadcast = 0; 471 d->chooser = 0; 472 if (*displayOrAlias == ALIAS_CHARACTER) 473 { 474 d->type = DISPLAY_ALIAS; 475 d->entry.aliasName = strdup (displayOrAlias); 476 if (!d->entry.aliasName) 477 { 478 free (d); 479 return NULL; 480 } 481 } 482 else if (!strcmp(displayOrAlias, LISTEN_STRING)) 483 { 484 d->type = DISPLAY_LISTEN; 485 } 486 else 487 { 488 if (*displayOrAlias == NEGATE_CHARACTER) 489 { 490 d->notAllowed = 1; 491 ++displayOrAlias; 492 } 493 if (HasGlobCharacters (displayOrAlias)) 494 { 495 d->type = DISPLAY_PATTERN; 496 d->entry.displayPattern = strdup (displayOrAlias); 497 if (!d->entry.displayPattern) 498 { 499 free (d); 500 return NULL; 501 } 502 } 503 else 504 { 505 void *addr = NULL; 506 size_t addr_length = 0; 507 int addrtype = 0; 508 509 # ifdef HAVE_GETADDRINFO 510 struct addrinfo *ai = NULL; 511 struct addrinfo hints = { 512 # ifdef IPv6 513 .ai_family = AF_UNSPEC 514 # else 515 .ai_family = AF_INET 516 # endif 517 }; 518 519 if (getaddrinfo(displayOrAlias, NULL, &hints, &ai) == 0) { 520 addrtype = ai->ai_addr->sa_family; 521 if (addrtype == AF_INET) { 522 addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr; 523 addr_length = sizeof(struct in_addr); 524 # ifdef IPv6 525 } else if (addrtype == AF_INET6) { 526 addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; 527 addr_length = sizeof(struct in6_addr); 528 # endif 529 } 530 } 531 # else /* !HAVE_GETADDRINFO */ 532 struct hostent *hostent; 533 534 if ((hostent = gethostbyname (displayOrAlias)) != NULL) 535 { 536 Debug("ReadDisplayEntry: %s\n", displayOrAlias); 537 addr = hostent->h_addr; 538 addrtype = hostent->h_addrtype; 539 addr_length = hostent->h_length; 540 } 541 # endif 542 if (addr == NULL) 543 { 544 LogError ("Access file %s, display %s unknown\n", accessFile, displayOrAlias); 545 free (d); 546 # ifdef HAVE_GETADDRINFO 547 if (ai) 548 freeaddrinfo(ai); 549 # endif 550 goto tryagain; 551 } 552 d->type = DISPLAY_ADDRESS; 553 display = &d->entry.displayAddress; 554 if (!XdmcpAllocARRAY8 (&display->clientAddress, addr_length)) 555 { 556 free (d); 557 # ifdef HAVE_GETADDRINFO 558 if (ai) 559 freeaddrinfo(ai); 560 # endif 561 return NULL; 562 } 563 memcpy(display->clientAddress.data, addr, addr_length); 564 # ifdef HAVE_GETADDRINFO 565 if (ai) 566 freeaddrinfo(ai); 567 # endif 568 switch (addrtype) 569 { 570 # ifdef AF_UNIX 571 case AF_UNIX: 572 display->connectionType = FamilyLocal; 573 break; 574 # endif 575 # ifdef AF_INET 576 case AF_INET: 577 display->connectionType = FamilyInternet; 578 break; 579 # endif 580 # ifdef IPv6 581 case AF_INET6: 582 display->connectionType = FamilyInternet6; 583 break; 584 # endif 585 default: 586 display->connectionType = FamilyLocal; 587 break; 588 } 589 } 590 } 591 prev = &d->hosts; 592 while ((h = ReadHostEntry (file))) 593 { 594 if (h->type == HOST_CHOOSER) 595 { 596 FreeHostEntry (h); 597 d->chooser = 1; 598 } else if (h->type == HOST_NOBROADCAST) { 599 FreeHostEntry (h); 600 d->notBroadcast = 1; 601 } else if (h->type == HOST_ANYADDR) { 602 if (d->type == DISPLAY_LISTEN) { 603 *prev = h; 604 prev = &h->next; 605 } else { 606 Debug("Wildcard host specified in Xaccess for type other than LISTEN -- ignoring\n"); 607 FreeHostEntry (h); 608 } 609 } else { 610 *prev = h; 611 prev = &h->next; 612 } 613 } 614 *prev = NULL; 615 return d; 616 } 617 618 static void 619 ReadAccessDatabase (FILE *file) 620 { 621 DisplayEntry *d, **prev; 622 623 prev = &database; 624 while ((d = ReadDisplayEntry (file))) 625 { 626 *prev = d; 627 prev = &d->next; 628 } 629 *prev = NULL; 630 } 631 632 int 633 ScanAccessDatabase (void) 634 { 635 FILE *datafile; 636 637 FreeAccessDatabase (); 638 if (*accessFile) 639 { 640 datafile = fopen (accessFile, "r"); 641 if (!datafile) 642 { 643 LogError ("Cannot open access control file %s, no XDMCP requests will be granted\n", accessFile); 644 return 0; 645 } 646 ReadAccessDatabase (datafile); 647 fclose (datafile); 648 } 649 return 1; 650 } 651 652 /* 653 * calls the given function for each valid indirect entry. Returns TRUE if 654 * the local host exists on any of the lists, else FALSE 655 */ 656 657 # define MAX_DEPTH 32 658 659 static int indirectAlias ( 660 char *alias, 661 ARRAY8Ptr clientAddress, 662 CARD16 connectionType, 663 ChooserFunc function, 664 char *closure, 665 int depth, 666 int broadcast); 667 668 669 static int 670 scanHostlist ( 671 HostEntry *h, 672 ARRAY8Ptr clientAddress, 673 CARD16 connectionType, 674 ChooserFunc function, 675 char *closure, 676 int depth, 677 int broadcast) 678 { 679 int haveLocalhost = 0; 680 681 for (; h; h = h->next) 682 { 683 switch (h->type) { 684 case HOST_ALIAS: 685 if (indirectAlias (h->entry.aliasName, clientAddress, 686 connectionType, function, closure, depth, 687 broadcast)) 688 haveLocalhost = 1; 689 break; 690 case HOST_ADDRESS: 691 if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress)) 692 haveLocalhost = 1; 693 else if (function) 694 (*function) (connectionType, &h->entry.hostAddress, closure); 695 break; 696 case HOST_BROADCAST: 697 if (broadcast) 698 { 699 ARRAY8 temp; 700 701 if (function) 702 { 703 temp.data = (BYTE *) BROADCAST_STRING; 704 temp.length = strlen ((char *)temp.data); 705 (*function) (connectionType, &temp, closure); 706 } 707 } 708 break; 709 } 710 } 711 return haveLocalhost; 712 } 713 714 /* Returns non-0 iff string is matched by pattern. Does case folding. 715 */ 716 static int 717 patternMatch (const char *string, char *pattern) 718 { 719 int p, s; 720 721 if (!string) 722 string = ""; 723 724 for (;;) 725 { 726 s = *string++; 727 switch (p = *pattern++) { 728 case '*': 729 if (!*pattern) 730 return 1; 731 for (string--; *string; string++) 732 if (patternMatch (string, pattern)) 733 return 1; 734 return 0; 735 case '?': 736 if (s == '\0') 737 return 0; 738 break; 739 case '\0': 740 return s == '\0'; 741 case '\\': 742 p = *pattern++; 743 /* fall through */ 744 default: 745 if (isupper(p)) p = tolower(p); 746 if (isupper(s)) s = tolower(s); 747 if (p != s) 748 return 0; 749 } 750 } 751 } 752 753 static int 754 indirectAlias ( 755 char *alias, 756 ARRAY8Ptr clientAddress, 757 CARD16 connectionType, 758 ChooserFunc function, 759 char *closure, 760 int depth, 761 int broadcast) 762 { 763 DisplayEntry *d; 764 int haveLocalhost = 0; 765 766 if (depth == MAX_DEPTH) 767 return 0; 768 for (d = database; d; d = d->next) 769 { 770 if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName)) 771 continue; 772 if (scanHostlist (d->hosts, clientAddress, connectionType, 773 function, closure, depth + 1, broadcast)) 774 { 775 haveLocalhost = 1; 776 } 777 } 778 return haveLocalhost; 779 } 780 781 int ForEachMatchingIndirectHost ( 782 ARRAY8Ptr clientAddress, 783 CARD16 connectionType, 784 ChooserFunc function, 785 char *closure) 786 { 787 int haveLocalhost = 0; 788 DisplayEntry *d; 789 char *clientName = NULL; 790 791 for (d = database; d; d = d->next) 792 { 793 switch (d->type) { 794 case DISPLAY_ALIAS: 795 case DISPLAY_LISTEN: 796 continue; 797 case DISPLAY_PATTERN: 798 if (!clientName) 799 clientName = NetworkAddressToHostname (connectionType, 800 clientAddress); 801 if (!patternMatch (clientName, d->entry.displayPattern)) 802 continue; 803 break; 804 case DISPLAY_ADDRESS: 805 if (d->entry.displayAddress.connectionType != connectionType || 806 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, 807 clientAddress)) 808 { 809 continue; 810 } 811 break; 812 } 813 if (!d->hosts) 814 continue; 815 if (d->notAllowed) 816 break; 817 if (d->chooser) 818 { 819 ARRAY8Ptr choice; 820 821 choice = IndirectChoice (clientAddress, connectionType); 822 if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice)) 823 haveLocalhost = 1; 824 else 825 (*function) (connectionType, choice, closure); 826 } 827 else if (scanHostlist (d->hosts, clientAddress, connectionType, 828 function, closure, 0, FALSE)) 829 { 830 haveLocalhost = 1; 831 } 832 break; 833 } 834 free (clientName); 835 return haveLocalhost; 836 } 837 838 int UseChooser ( 839 ARRAY8Ptr clientAddress, 840 CARD16 connectionType) 841 { 842 DisplayEntry *d; 843 char *clientName = NULL; 844 845 for (d = database; d; d = d->next) 846 { 847 switch (d->type) { 848 case DISPLAY_ALIAS: 849 case DISPLAY_LISTEN: 850 continue; 851 case DISPLAY_PATTERN: 852 if (!clientName) 853 clientName = NetworkAddressToHostname (connectionType, 854 clientAddress); 855 if (!patternMatch (clientName, d->entry.displayPattern)) 856 continue; 857 break; 858 case DISPLAY_ADDRESS: 859 if (d->entry.displayAddress.connectionType != connectionType || 860 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, 861 clientAddress)) 862 { 863 continue; 864 } 865 break; 866 } 867 if (!d->hosts) 868 continue; 869 if (d->notAllowed) 870 break; 871 if (d->chooser && !IndirectChoice (clientAddress, connectionType)) { 872 free (clientName); 873 return 1; 874 } 875 break; 876 } 877 free (clientName); 878 return 0; 879 } 880 881 void ForEachChooserHost ( 882 ARRAY8Ptr clientAddress, 883 CARD16 connectionType, 884 ChooserFunc function, 885 char *closure) 886 { 887 int haveLocalhost = 0; 888 DisplayEntry *d; 889 char *clientName = NULL; 890 891 for (d = database; d; d = d->next) 892 { 893 switch (d->type) { 894 case DISPLAY_ALIAS: 895 case DISPLAY_LISTEN: 896 continue; 897 case DISPLAY_PATTERN: 898 if (!clientName) 899 clientName = NetworkAddressToHostname (connectionType, 900 clientAddress); 901 if (!patternMatch (clientName, d->entry.displayPattern)) 902 continue; 903 break; 904 case DISPLAY_ADDRESS: 905 if (d->entry.displayAddress.connectionType != connectionType || 906 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, 907 clientAddress)) 908 { 909 continue; 910 } 911 break; 912 } 913 if (!d->hosts) 914 continue; 915 if (d->notAllowed) 916 break; 917 if (!d->chooser) 918 break; 919 if (scanHostlist (d->hosts, clientAddress, connectionType, 920 function, closure, 0, TRUE)) 921 { 922 haveLocalhost = 1; 923 } 924 break; 925 } 926 free (clientName); 927 if (haveLocalhost) 928 (*function) (connectionType, getLocalAddress(), closure); 929 } 930 931 /* 932 * returns TRUE if the given client is acceptable to the local host. The 933 * given display client is acceptable if it occurs without a host list. 934 */ 935 936 int AcceptableDisplayAddress ( 937 ARRAY8Ptr clientAddress, 938 CARD16 connectionType, 939 xdmOpCode type) 940 { 941 DisplayEntry *d; 942 char *clientName = NULL; 943 944 if (!*accessFile) 945 return 1; 946 if (type == INDIRECT_QUERY) 947 return 1; 948 for (d = database; d; d = d->next) 949 { 950 if (d->hosts) 951 continue; 952 switch (d->type) { 953 case DISPLAY_ALIAS: 954 case DISPLAY_LISTEN: 955 continue; 956 case DISPLAY_PATTERN: 957 if (!clientName) 958 clientName = NetworkAddressToHostname (connectionType, 959 clientAddress); 960 if (!patternMatch (clientName, d->entry.displayPattern)) 961 continue; 962 break; 963 case DISPLAY_ADDRESS: 964 if (d->entry.displayAddress.connectionType != connectionType || 965 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, 966 clientAddress)) 967 { 968 continue; 969 } 970 break; 971 } 972 break; 973 } 974 free (clientName); 975 return (d != 0) && (d->notAllowed == 0) 976 && (type == BROADCAST_QUERY ? d->notBroadcast == 0 : 1); 977 } 978 979 void ForEachListenAddr ( 980 ListenFunc listenfunction, 981 ListenFunc mcastfunction, 982 void **closure) 983 { 984 DisplayEntry *d; 985 HostEntry *h; 986 int listenFound = 0; 987 988 for (d = database; d != NULL ; d = d->next) 989 { 990 if (d->type == DISPLAY_LISTEN) { 991 listenFound = 1; 992 h = d->hosts; 993 if (h != NULL) { 994 (*listenfunction) (&h->entry.hostAddress, closure); 995 for (h = h->next; h != NULL; h = h->next) { 996 (*mcastfunction) (&h->entry.hostAddress, closure); 997 } 998 } 999 } 1000 } 1001 if (!listenFound) { 1002 (*listenfunction) (NULL, closure); 1003 # if defined(IPv6) && defined(XDM_DEFAULT_MCAST_ADDR6) 1004 { /* Join default IPv6 Multicast Group */ 1005 1006 static ARRAY8 defaultMcastAddress; 1007 1008 if (defaultMcastAddress.length == 0) { 1009 struct in6_addr addr6; 1010 1011 if (inet_pton(AF_INET6,XDM_DEFAULT_MCAST_ADDR6,&addr6) == 1) { 1012 if (!XdmcpAllocARRAY8 (&defaultMcastAddress, 1013 sizeof(struct in6_addr))) { 1014 LogOutOfMem ("ReadHostEntry\n"); 1015 defaultMcastAddress.length = -1; 1016 } else { 1017 memcpy(defaultMcastAddress.data, &addr6, 1018 sizeof(struct in6_addr)); 1019 } 1020 } else { 1021 defaultMcastAddress.length = -1; 1022 } 1023 } 1024 if ( defaultMcastAddress.length == sizeof(struct in6_addr) ) { 1025 (*mcastfunction) (&defaultMcastAddress, closure); 1026 } 1027 } 1028 # endif 1029 } 1030 } 1031 1032 1033 #endif /* XDMCP */ 1034