xhost.c revision 3544ea2e
1/* 2 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. 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 25Copyright 1985, 1986, 1987, 1998 The Open Group 26 27All rights reserved. 28 29Permission is hereby granted, free of charge, to any person obtaining a 30copy of this software and associated documentation files (the 31"Software"), to deal in the Software without restriction, including 32without limitation the rights to use, copy, modify, merge, publish, 33distribute, and/or sell copies of the Software, and to permit persons 34to whom the Software is furnished to do so, provided that the above 35copyright notice(s) and this permission notice appear in all copies of 36the Software and that both the above copyright notice(s) and this 37permission notice appear in supporting documentation. 38 39THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 40OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 41MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 42OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 43HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 44INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 45FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 46NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 47WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 48 49Except as contained in this notice, the name of a copyright holder 50shall not be used in advertising or otherwise to promote the sale, use 51or other dealings in this Software without prior written authorization 52of the copyright holder. 53 54X Window System is a trademark of The Open Group. 55 56*/ 57 58#ifdef HAVE_CONFIG_H 59#include "config.h" 60#endif 61 62#if defined(TCPCONN) || defined(STREAMSCONN) 63#define NEEDSOCKETS 64#endif 65#ifdef UNIXCONN 66#define NEEDSOCKETS 67#endif 68#ifdef DNETCONN 69#define NEEDSOCKETS 70#endif 71 72#include <X11/Xlib.h> 73#include <X11/Xos.h> 74#include <X11/Xproto.h> 75#include <X11/Xfuncs.h> 76#include <stdio.h> 77#include <stdlib.h> 78#include <signal.h> 79#ifdef X_NOT_POSIX 80#include <setjmp.h> 81#endif 82#include <ctype.h> 83#include <X11/Xauth.h> 84#include <X11/Xmu/Error.h> 85#include <stdlib.h> 86 87#ifdef NEEDSOCKETS 88#ifdef att 89typedef unsigned short unsign16; 90typedef unsigned long unsign32; 91typedef short sign16; 92typedef long sign32; 93#include <interlan/socket.h> 94#include <interlan/netdb.h> 95#include <interlan/in.h> 96#else 97#ifndef Lynx 98#include <sys/socket.h> 99#else 100#include <socket.h> 101#endif 102#include <netdb.h> 103#include <netinet/in.h> 104#endif 105#endif /* NEEDSOCKETS */ 106 107#ifndef BAD_ARPAINET 108#include <arpa/inet.h> 109#else 110/* bogus definition of inet_makeaddr() in BSD 4.2 and Ultrix */ 111extern unsigned long inet_makeaddr(); 112#endif 113 114#ifdef DNETCONN 115#include <netdnet/dn.h> 116#include <netdnet/dnetdb.h> 117#endif 118 119#ifdef SECURE_RPC 120#include <pwd.h> 121#include <rpc/rpc.h> 122#ifdef X_POSIX_C_SOURCE 123#define _POSIX_C_SOURCE X_POSIX_C_SOURCE 124#include <limits.h> 125#undef _POSIX_C_SOURCE 126#else 127#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) 128#include <limits.h> 129#else 130#define _POSIX_SOURCE 131#include <limits.h> 132#undef _POSIX_SOURCE 133#endif 134#endif 135#ifndef NGROUPS_MAX 136#include <sys/param.h> 137#define NGROUPS_MAX NGROUPS 138#endif 139#ifdef sun 140/* Go figure, there's no getdomainname() prototype available */ 141extern int getdomainname(char *name, size_t len); 142#endif 143#endif 144 145static int change_host(Display *dpy, char *name, Bool add); 146static const char *get_hostname(XHostAddress *ha); 147static int local_xerror(Display *dpy, XErrorEvent *rep); 148 149#ifdef RETSIGTYPE /* autoconf AC_TYPE_SIGNAL */ 150# define signal_t RETSIGTYPE 151#else /* Imake */ 152#ifdef SIGNALRETURNSINT 153#define signal_t int 154#else 155#define signal_t void 156#endif 157#endif /* RETSIGTYPE */ 158static signal_t nameserver_lost(int sig); 159 160#define NAMESERVER_TIMEOUT 5 /* time to wait for nameserver */ 161 162static volatile int nameserver_timedout; 163 164static char *ProgramName; 165 166#ifdef NEEDSOCKETS 167static int 168XFamily(int af) 169{ 170 int i; 171 static struct _familyMap { 172 int af, xf; 173 } familyMap[] = { 174#ifdef AF_DECnet 175 { AF_DECnet, FamilyDECnet }, 176#endif 177#ifdef AF_CHAOS 178 { AF_CHAOS, FamilyChaos }, 179#endif 180#ifdef AF_INET 181 { AF_INET, FamilyInternet }, 182#if defined(IPv6) && defined(AF_INET6) 183 { AF_INET6, FamilyInternet6 }, 184#endif 185#endif 186}; 187 188#define FAMILIES ((sizeof familyMap)/(sizeof familyMap[0])) 189 190 for (i = 0; i < FAMILIES; i++) 191 if (familyMap[i].af == af) return familyMap[i].xf; 192 return -1; 193} 194#endif /* NEEDSOCKETS */ 195 196static Display *dpy; 197 198int 199main(int argc, char *argv[]) 200{ 201 register char *arg; 202 int i, nhosts = 0; 203 const char *hostname; 204 int nfailed = 0; 205 XHostAddress *list; 206 Bool enabled = False; 207#ifdef DNETCONN 208 char *dnet_htoa(); 209 struct nodeent *np; 210 struct dn_naddr *nlist, dnaddr, *dnaddrp, *dnet_addr(); 211 char *cp; 212#endif 213 214 ProgramName = argv[0]; 215 216 if (argc == 2 && !strcmp(argv[1], "-help")) { 217 fprintf(stderr, "usage: %s [[+-]hostname ...]\n", argv[0]); 218 exit(1); 219 } 220 221 if ((dpy = XOpenDisplay(NULL)) == NULL) { 222 fprintf(stderr, "%s: unable to open display \"%s\"\n", 223 ProgramName, XDisplayName (NULL)); 224 exit(1); 225 } 226 227 XSetErrorHandler(local_xerror); 228 229 230 if (argc == 1) { 231#ifdef DNETCONN 232 setnodeent(1); /* keep the database accessed */ 233#endif 234 sethostent(1); /* don't close the data base each time */ 235 list = XListHosts(dpy, &nhosts, &enabled); 236 if (enabled) 237 printf ("access control enabled, only authorized clients can connect\n"); 238 else 239 printf ("access control disabled, clients can connect from any host\n"); 240 241 if (nhosts != 0) { 242 for (i = 0; i < nhosts; i++ ) { 243 hostname = get_hostname(&list[i]); 244 if (hostname) { 245 switch (list[i].family) { 246 case FamilyInternet: 247 printf("INET:"); 248 break; 249 case FamilyInternet6: 250 printf("INET6:"); 251 break; 252 case FamilyDECnet: 253 printf("DNET:"); 254 break; 255 case FamilyNetname: 256 printf("NIS:"); 257 break; 258 case FamilyKrb5Principal: 259 printf("KRB:"); 260 break; 261 case FamilyLocalHost: 262 printf("LOCAL:"); 263 break; 264 case FamilyServerInterpreted: 265 printf("SI:"); 266 break; 267 default: 268 printf("<unknown family type %d>:", list[i].family); 269 break; 270 } 271 printf ("%s", hostname); 272 } else { 273 printf ("<unknown address in family %d>", 274 list[i].family); 275 } 276 if (nameserver_timedout) { 277 printf("\t(no nameserver response within %d seconds)\n", 278 NAMESERVER_TIMEOUT); 279 nameserver_timedout = 0; 280 } else 281 printf("\n"); 282 } 283 free(list); 284 endhostent(); 285 } 286 exit(0); 287 } 288 289 for (i = 1; i < argc; i++) { 290 arg = argv[i]; 291 if (*arg == '-') { 292 293 if (!argv[i][1] && ((i+1) == argc)) { 294 printf ("access control enabled, only authorized clients can connect\n"); 295 XEnableAccessControl(dpy); 296 } else { 297 arg = argv[i][1]? &argv[i][1] : argv[++i]; 298 if (!change_host (dpy, arg, False)) { 299 fprintf (stderr, "%s: bad hostname \"%s\"\n", 300 ProgramName, arg); 301 nfailed++; 302 } 303 } 304 } else { 305 if (*arg == '+' && !argv[i][1] && ((i+1) == argc)) { 306 printf ("access control disabled, clients can connect from any host\n"); 307 XDisableAccessControl(dpy); 308 } else { 309 if (*arg == '+') { 310 arg = argv[i][1]? &argv[i][1] : argv[++i]; 311 } 312 if (!change_host (dpy, arg, True)) { 313 fprintf (stderr, "%s: bad hostname \"%s\"\n", 314 ProgramName, arg); 315 nfailed++; 316 } 317 } 318 } 319 } 320 XCloseDisplay (dpy); /* does an XSync first */ 321 exit(nfailed); 322} 323 324 325 326/* 327 * change_host - edit the list of hosts that may connect to the server; 328 * it parses DECnet names (expo::), Internet addresses (18.30.0.212), or 329 * Internet names (expo.lcs.mit.edu); if 4.3bsd macro h_addr is defined 330 * (from <netdb.h>), it will add or remove all addresses with the given 331 * address. 332 */ 333 334static int 335change_host(Display *dpy, char *name, Bool add) 336{ 337 XHostAddress ha; 338 char *lname; 339 int namelen, i, family = FamilyWild; 340#ifdef K5AUTH 341 krb5_principal princ; 342 krb5_data kbuf; 343#endif 344#ifdef NEEDSOCKETS 345 static struct in_addr addr; /* so we can point at it */ 346#if defined(IPv6) && defined(AF_INET6) 347 static struct in6_addr addr6; /* so we can point at it */ 348#else 349 struct hostent *hp; 350#endif 351#endif 352 char *cp; 353#ifdef DNETCONN 354 struct dn_naddr *dnaddrp; 355 struct nodeent *np; 356 static struct dn_naddr dnaddr; 357#endif /* DNETCONN */ 358 static const char *add_msg = "being added to access control list"; 359 static const char *remove_msg = "being removed from access control list"; 360 361 namelen = strlen(name); 362 if ((lname = (char *)malloc(namelen+1)) == NULL) { 363 fprintf (stderr, "%s: malloc bombed in change_host\n", ProgramName); 364 exit (1); 365 } 366 for (i = 0; i < namelen; i++) { 367 lname[i] = tolower(name[i]); 368 } 369 lname[namelen] = '\0'; 370 if (!strncmp("inet:", lname, 5)) { 371#if defined(TCPCONN) || defined(STREAMSCONN) 372 family = FamilyInternet; 373 name += 5; 374#else 375 fprintf (stderr, "%s: not compiled for TCP/IP\n", ProgramName); 376 free(lname); 377 return 0; 378#endif 379 } 380 else if (!strncmp("inet6:", lname, 6)) { 381#if (defined(TCPCONN) || defined(STREAMSCONN)) && \ 382 defined(IPv6) && defined(AF_INET6) 383 family = FamilyInternet6; 384 name += 6; 385#else 386 fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName); 387 free(lname); 388 return 0; 389#endif 390 } 391#ifdef ACCEPT_INETV6 /* Allow inetv6 as an alias for inet6 for compatibility 392 with original X11 over IPv6 draft. */ 393 else if (!strncmp("inetv6:", lname, 7)) { 394#if (defined(TCPCONN) || defined(STREAMSCONN)) && \ 395 defined(IPv6) && defined(AF_INET6) 396 family = FamilyInternet6; 397 name += 7; 398#else 399 fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName); 400 free(lname); 401 return 0; 402#endif 403 } 404#endif /* ACCEPT_INETV6 */ 405 else if (!strncmp("dnet:", lname, 5)) { 406#ifdef DNETCONN 407 family = FamilyDECnet; 408 name += 5; 409#else 410 fprintf (stderr, "%s: not compiled for DECnet\n", ProgramName); 411 free(lname); 412 return 0; 413#endif 414 } 415 else if (!strncmp("nis:", lname, 4)) { 416#ifdef SECURE_RPC 417 family = FamilyNetname; 418 name += 4; 419#else 420 fprintf (stderr, "%s: not compiled for Secure RPC\n", ProgramName); 421 free(lname); 422 return 0; 423#endif 424 } 425 else if (!strncmp("krb:", lname, 4)) { 426#ifdef K5AUTH 427 family = FamilyKrb5Principal; 428 name +=4; 429#else 430 fprintf (stderr, "%s: not compiled for Kerberos 5\n", ProgramName); 431 free(lname); 432 return 0; 433#endif 434 } 435 else if (!strncmp("local:", lname, 6)) { 436 family = FamilyLocalHost; 437 } 438 else if (!strncmp("si:", lname, 3)) { 439 family = FamilyServerInterpreted; 440 name += 3; 441 } 442 if (family == FamilyWild && (cp = strchr(lname, ':'))) { 443 *cp = '\0'; 444 fprintf (stderr, "%s: unknown address family \"%s\"\n", 445 ProgramName, lname); 446 free(lname); 447 return 0; 448 } 449 free(lname); 450 451 if (family == FamilyServerInterpreted) { 452 XServerInterpretedAddress siaddr; 453 int rc; 454 455 cp = strchr(name, ':'); 456 if (cp == NULL || cp == name) { 457 fprintf(stderr, 458 "%s: type must be specified for server interpreted family \"%s\"\n", 459 ProgramName, name); 460 return 0; 461 } 462 siaddr.type = name; 463 siaddr.typelength = cp - name; 464 siaddr.value = ++cp; 465 siaddr.valuelength = strlen(cp); 466 ha.family = FamilyServerInterpreted; 467 ha.address = (char *) &siaddr; 468 if (add) 469 rc = XAddHost(dpy, &ha); 470 else 471 rc = XRemoveHost(dpy, &ha); 472 printf( "%s %s%s\n", name, rc == 1 ? "" : "failed when ", 473 add ? add_msg : remove_msg); 474 if (rc != 1) 475 return 0; 476 return 1; 477 } 478 479#ifdef DNETCONN 480 if (family == FamilyDECnet || ((family == FamilyWild) && 481 (cp = strchr(name, ':')) && (*(cp + 1) == ':') && 482 !(*cp = '\0'))) { 483 ha.family = FamilyDECnet; 484 if (dnaddrp = dnet_addr(name)) { 485 dnaddr = *dnaddrp; 486 } else { 487 if ((np = getnodebyname (name)) == NULL) { 488 fprintf (stderr, "%s: unable to get node name for \"%s::\"\n", 489 ProgramName, name); 490 return 0; 491 } 492 dnaddr.a_len = np->n_length; 493 memmove( dnaddr.a_addr, np->n_addr, np->n_length); 494 } 495 ha.length = sizeof(struct dn_naddr); 496 ha.address = (char *)&dnaddr; 497 if (add) { 498 XAddHost (dpy, &ha); 499 printf ("%s:: %s\n", name, add_msg); 500 } else { 501 XRemoveHost (dpy, &ha); 502 printf ("%s:: %s\n", name, remove_msg); 503 } 504 return 1; 505 } 506#endif /* DNETCONN */ 507#ifdef K5AUTH 508 if (family == FamilyKrb5Principal) { 509 krb5_error_code retval; 510 511 retval = krb5_parse_name(name, &princ); 512 if (retval) { 513 krb5_init_ets(); /* init krb errs for error_message() */ 514 fprintf(stderr, "%s: cannot parse Kerberos name: %s\n", 515 ProgramName, error_message(retval)); 516 return 0; 517 } 518 XauKrb5Encode(princ, &kbuf); 519 ha.length = kbuf.length; 520 ha.address = kbuf.data; 521 ha.family = family; 522 if (add) 523 XAddHost(dpy, &ha); 524 else 525 XRemoveHost(dpy, &ha); 526 krb5_free_principal(princ); 527 free(kbuf.data); 528 printf( "%s %s\n", name, add ? add_msg : remove_msg); 529 return 1; 530 } 531#endif 532 if (family == FamilyLocalHost) { 533 ha.length = 0; 534 ha.address = ""; 535 ha.family = family; 536 if (add) 537 XAddHost(dpy, &ha); 538 else 539 XRemoveHost(dpy, &ha); 540 printf( "non-network local connections %s\n", add ? add_msg : remove_msg); 541 return 1; 542 } 543 /* 544 * If it has an '@', it's a netname 545 */ 546 if ((family == FamilyNetname && (cp = strchr(name, '@'))) || 547 (cp = strchr(name, '@'))) { 548 char *netname = name; 549#ifdef SECURE_RPC 550 static char username[MAXNETNAMELEN]; 551 552 if (!cp[1]) { 553 struct passwd *pwd; 554 static char domainname[128]; 555 556 *cp = '\0'; 557 pwd = getpwnam(name); 558 if (!pwd) { 559 fprintf(stderr, "no such user \"%s\"\n", name); 560 return 0; 561 } 562 getdomainname(domainname, sizeof(domainname)); 563 if (!user2netname(username, pwd->pw_uid, domainname)) { 564 fprintf(stderr, "failed to get netname for \"%s\"\n", name); 565 return 0; 566 } 567 netname = username; 568 } 569#endif 570 ha.family = FamilyNetname; 571 ha.length = strlen(netname); 572 ha.address = netname; 573 if (add) 574 XAddHost (dpy, &ha); 575 else 576 XRemoveHost (dpy, &ha); 577 if (netname != name) 578 printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg); 579 else 580 printf ("%s %s\n", netname, add ? add_msg : remove_msg); 581 return 1; 582 } 583#ifdef NEEDSOCKETS 584 /* 585 * First see if inet_addr() can grok the name; if so, then use it. 586 */ 587 if (((family == FamilyWild) || (family == FamilyInternet)) && 588 ((addr.s_addr = inet_addr(name)) != -1)) { 589 ha.family = FamilyInternet; 590 ha.length = 4; /* but for Cray would be sizeof(addr.s_addr) */ 591 ha.address = (char *)&addr; /* but for Cray would be &addr.s_addr */ 592 if (add) { 593 XAddHost (dpy, &ha); 594 printf ("%s %s\n", name, add_msg); 595 } else { 596 XRemoveHost (dpy, &ha); 597 printf ("%s %s\n", name, remove_msg); 598 } 599 return 1; 600 } 601#if defined(IPv6) && defined(AF_INET6) 602 /* 603 * Check to see if inet_pton() can grok it as an IPv6 address 604 */ 605 else if (((family == FamilyWild) || (family == FamilyInternet6)) && 606 (inet_pton(AF_INET6, name, &addr6.s6_addr) == 1)) { 607 ha.family = FamilyInternet6; 608 ha.length = sizeof(addr6.s6_addr); 609 ha.address = (char *) &addr6.s6_addr; 610 if (add) { 611 XAddHost (dpy, &ha); 612 printf ("%s %s\n", name, add_msg); 613 } else { 614 XRemoveHost (dpy, &ha); 615 printf ("%s %s\n", name, remove_msg); 616 } 617 return 1; 618 } else { 619 /* 620 * Is it in the namespace? 621 * 622 * If no family was specified, use both Internet v4 & v6 addresses. 623 * Otherwise, use only addresses matching specified family. 624 */ 625 struct addrinfo *addresses; 626 struct addrinfo *a; 627 Bool didit = False; 628 629 if (getaddrinfo(name, NULL, NULL, &addresses) != 0) 630 return 0; 631 632 for (a = addresses; a != NULL; a = a->ai_next) { 633 if ( ((a->ai_family == AF_INET) && (family != FamilyInternet6)) 634 || ((a->ai_family == AF_INET6) && (family != FamilyInternet)) ) { 635 char ad[INET6_ADDRSTRLEN]; 636 ha.family = XFamily(a->ai_family); 637 if (a->ai_family == AF_INET6) { 638 ha.address = (char *) 639 &((struct sockaddr_in6 *) a->ai_addr)->sin6_addr; 640 ha.length = 641 sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr); 642 } else { 643 ha.address = (char *) 644 &((struct sockaddr_in *) a->ai_addr)->sin_addr; 645 ha.length = 646 sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr); 647 } 648 inet_ntop(a->ai_family, ha.address, ad, sizeof(ad)); 649 /* printf("Family: %d\nLength: %d\n", a->ai_family, ha.length); */ 650 /* printf("Address: %s\n", ad); */ 651 652 if (add) { 653 XAddHost (dpy, &ha); 654 } else { 655 XRemoveHost (dpy, &ha); 656 } 657 didit = True; 658 } 659 } 660 if (didit == True) { 661 printf ("%s %s\n", name, add ? add_msg : remove_msg); 662 } else { 663 const char *familyMsg = ""; 664 665 if (family == FamilyInternet6) { 666 familyMsg = "inet6 "; 667 } else if (family == FamilyInternet) { 668 familyMsg = "inet "; 669 } 670 671 fprintf(stderr, "%s: unable to get %saddress for \"%s\"\n", 672 ProgramName, familyMsg, name); 673 } 674 freeaddrinfo(addresses); 675 return 1; 676 } 677#else /* !IPv6 */ 678 /* 679 * Is it in the namespace? 680 */ 681 else if (((hp = gethostbyname(name)) == (struct hostent *)NULL) 682 || hp->h_addrtype != AF_INET) { 683 return 0; 684 } else { 685 ha.family = XFamily(hp->h_addrtype); 686 ha.length = hp->h_length; 687#ifdef h_addr /* new 4.3bsd version of gethostent */ 688 { 689 char **list; 690 691 /* iterate over the hosts */ 692 for (list = hp->h_addr_list; *list; list++) { 693 ha.address = *list; 694 if (add) { 695 XAddHost (dpy, &ha); 696 } else { 697 XRemoveHost (dpy, &ha); 698 } 699 } 700 } 701#else 702 ha.address = hp->h_addr; 703 if (add) { 704 XAddHost (dpy, &ha); 705 } else { 706 XRemoveHost (dpy, &ha); 707 } 708#endif 709 printf ("%s %s\n", name, add ? add_msg : remove_msg); 710 return 1; 711 } 712#endif /* IPv6 */ 713#else /* NEEDSOCKETS */ 714 return 0; 715#endif /* NEEDSOCKETS */ 716} 717 718 719/* 720 * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU) 721 * or a string representing the address (18.58.0.13) if the name cannot 722 * be found. 723 */ 724 725#ifdef X_NOT_POSIX 726jmp_buf env; 727#endif 728 729static const char * 730get_hostname(XHostAddress *ha) 731{ 732#if (defined(TCPCONN) || defined(STREAMSCONN)) && \ 733 (!defined(IPv6) || !defined(AF_INET6)) 734 static struct hostent *hp = NULL; 735#endif 736#ifdef DNETCONN 737 struct nodeent *np; 738 static char nodeaddr[5 + 2 * DN_MAXADDL]; 739#endif /* DNETCONN */ 740#ifdef K5AUTH 741 krb5_principal princ; 742 krb5_data kbuf; 743 char *kname; 744 static char kname_out[255]; 745#endif 746#ifndef X_NOT_POSIX 747 struct sigaction sa; 748#endif 749 750#if defined(TCPCONN) || defined(STREAMSCONN) 751#if defined(IPv6) && defined(AF_INET6) 752 if ((ha->family == FamilyInternet) || (ha->family == FamilyInternet6)) { 753 struct sockaddr_storage saddr; 754 static char inetname[NI_MAXHOST]; 755 int saddrlen; 756 757 inetname[0] = '\0'; 758 memset(&saddr, 0, sizeof saddr); 759 if (ha->family == FamilyInternet) { 760 struct sockaddr_in *sin = (struct sockaddr_in *) &saddr; 761#ifdef BSD44SOCKETS 762 sin->sin_len = sizeof(struct sockaddr_in); 763#endif 764 sin->sin_family = AF_INET; 765 sin->sin_port = 0; 766 memcpy(&sin->sin_addr, ha->address, sizeof(sin->sin_addr)); 767 saddrlen = sizeof(struct sockaddr_in); 768 } else { 769 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &saddr; 770#ifdef SIN6_LEN 771 sin6->sin6_len = sizeof(struct sockaddr_in6); 772#endif 773 sin6->sin6_family = AF_INET6; 774 sin6->sin6_port = 0; 775 memcpy(&sin6->sin6_addr, ha->address, sizeof(sin6->sin6_addr)); 776 saddrlen = sizeof(struct sockaddr_in6); 777 } 778 779 /* gethostbyaddr can take a LONG time if the host does not exist. 780 Assume that if it does not respond in NAMESERVER_TIMEOUT seconds 781 that something is wrong and do not make the user wait. 782 gethostbyaddr will continue after a signal, so we have to 783 jump out of it. 784 */ 785#ifndef X_NOT_POSIX 786 memset(&sa, 0, sizeof sa); 787 sa.sa_handler = nameserver_lost; 788 sa.sa_flags = 0; /* don't restart syscalls */ 789 sigaction(SIGALRM, &sa, NULL); 790#else 791 signal(SIGALRM, nameserver_lost); 792#endif 793 alarm(NAMESERVER_TIMEOUT); 794#ifdef X_NOT_POSIX 795 if (setjmp(env) == 0) 796#endif 797 { 798 getnameinfo((struct sockaddr *) &saddr, saddrlen, inetname, 799 sizeof(inetname), NULL, 0, 0); 800 } 801 alarm(0); 802 if (nameserver_timedout || inetname[0] == '\0') 803 inet_ntop(((struct sockaddr *)&saddr)->sa_family, ha->address, 804 inetname, sizeof(inetname)); 805 return inetname; 806 } 807#else 808 if (ha->family == FamilyInternet) { 809#ifdef CRAY 810 struct in_addr t_addr; 811 bzero((char *)&t_addr, sizeof(t_addr)); 812 bcopy(ha->address, (char *)&t_addr, 4); 813 ha->address = (char *)&t_addr; 814#endif 815 /* gethostbyaddr can take a LONG time if the host does not exist. 816 Assume that if it does not respond in NAMESERVER_TIMEOUT seconds 817 that something is wrong and do not make the user wait. 818 gethostbyaddr will continue after a signal, so we have to 819 jump out of it. 820 */ 821#ifndef X_NOT_POSIX 822 memset(&sa, 0, sizeof sa); 823 sa.sa_handler = nameserver_lost; 824 sa.sa_flags = 0; /* don't restart syscalls */ 825 sigaction(SIGALRM, &sa, NULL); 826#else 827 signal(SIGALRM, nameserver_lost); 828#endif 829 alarm(4); 830#ifdef X_NOT_POSIX 831 if (setjmp(env) == 0) { 832#endif 833 hp = gethostbyaddr (ha->address, ha->length, AF_INET); 834#ifdef X_NOT_POSIX 835 } 836#endif 837 alarm(0); 838 if (hp) 839 return (hp->h_name); 840 else return (inet_ntoa(*((struct in_addr *)(ha->address)))); 841 } 842#endif /* IPv6 */ 843#endif 844 if (ha->family == FamilyNetname) { 845 static char netname[512]; 846 int len; 847#ifdef SECURE_RPC 848 int gidlen; 849 uid_t uid; 850 gid_t gid, gidlist[NGROUPS_MAX]; 851#endif 852 853 if (ha->length < sizeof(netname) - 1) 854 len = ha->length; 855 else 856 len = sizeof(netname) - 1; 857 memmove( netname, ha->address, len); 858 netname[len] = '\0'; 859#ifdef SECURE_RPC 860 if (netname2user(netname, &uid, &gid, &gidlen, gidlist)) { 861 struct passwd *pwd; 862 863 pwd = getpwuid(uid); 864 if (pwd) 865 sprintf(netname, "%s@ (%*.*s)", pwd->pw_name, 866 ha->length, ha->length, ha->address); 867 } 868#endif 869 return (netname); 870 } 871#ifdef DNETCONN 872 if (ha->family == FamilyDECnet) { 873 struct dn_naddr *addr_ptr = (struct dn_naddr *) ha->address; 874 875 if (np = getnodebyaddr(addr_ptr->a_addr, addr_ptr->a_len, AF_DECnet)) { 876 sprintf(nodeaddr, "%s", np->n_name); 877 } else { 878 sprintf(nodeaddr, "%s", dnet_htoa(ha->address)); 879 } 880 return(nodeaddr); 881 } 882#endif 883#ifdef K5AUTH 884 if (ha->family == FamilyKrb5Principal) { 885 kbuf.data = ha->address; 886 kbuf.length = ha->length; 887 XauKrb5Decode(kbuf, &princ); 888 krb5_unparse_name(princ, &kname); 889 krb5_free_principal(princ); 890 strncpy(kname_out, kname, sizeof (kname_out)); 891 free(kname); 892 return kname_out; 893 } 894#endif 895 if (ha->family == FamilyLocalHost) { 896 return ""; 897 } 898 if (ha->family == FamilyServerInterpreted) { 899 XServerInterpretedAddress *sip; 900 static char *addressString; 901 static size_t addressStringSize; 902 size_t neededSize; 903 904 sip = (XServerInterpretedAddress *) ha->address; 905 neededSize = sip->typelength + sip->valuelength + 2; 906 907 if (addressStringSize < neededSize) { 908 if (addressString != NULL) { 909 free(addressString); 910 } 911 addressStringSize = neededSize; 912 addressString = malloc(addressStringSize); 913 } 914 if (addressString != NULL) { 915 char *cp = addressString; 916 917 memcpy(cp, sip->type, sip->typelength); 918 cp += sip->typelength; 919 *cp++ = ':'; 920 memcpy(cp, sip->value, sip->valuelength); 921 cp += sip->valuelength; 922 *cp = '\0'; 923 } 924 return addressString; 925 } 926 return (NULL); 927} 928 929/*ARGUSED*/ 930static signal_t 931nameserver_lost(int sig) 932{ 933 nameserver_timedout = 1; 934#ifdef X_NOT_POSIX 935 /* not needed with POSIX signals - stuck syscalls will not 936 be restarted after signal delivery */ 937 longjmp(env, -1); 938#endif 939} 940 941/* 942 * local_xerror - local non-fatal error handling routine. If the error was 943 * that an X_GetHosts request for an unknown address format was received, just 944 * return, otherwise print the normal error message and continue. 945 */ 946static int 947local_xerror(Display *dpy, XErrorEvent *rep) 948{ 949 if ((rep->error_code == BadAccess) && (rep->request_code == X_ChangeHosts)) { 950 fprintf (stderr, 951 "%s: must be on local machine to add or remove hosts.\n", 952 ProgramName); 953 return 1; 954 } else if ((rep->error_code == BadAccess) && 955 (rep->request_code == X_SetAccessControl)) { 956 fprintf (stderr, 957 "%s: must be on local machine to enable or disable access control.\n", 958 ProgramName); 959 return 1; 960 } else if ((rep->error_code == BadValue) && 961 (rep->request_code == X_ListHosts)) { 962 return 1; 963 } 964 965 XmuPrintDefaultErrorMessage (dpy, rep, stderr); 966 return 0; 967} 968 969#ifdef __CYGWIN__ 970void sethostent(int x) 971{} 972 973void endhostent() 974{} 975#endif 976 977