Xtransutil.c revision 73143b9a
1/* 2 3Copyright 1993, 1994, 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 * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA 28 * 29 * All Rights Reserved 30 * 31 * Permission to use, copy, modify, and distribute this software and its 32 * documentation for any purpose and without fee is hereby granted, provided 33 * that the above copyright notice appear in all copies and that both that 34 * copyright notice and this permission notice appear in supporting 35 * documentation, and that the name NCR not be used in advertising 36 * or publicity pertaining to distribution of the software without specific, 37 * written prior permission. NCR makes no representations about the 38 * suitability of this software for any purpose. It is provided "as is" 39 * without express or implied warranty. 40 * 41 * NCRS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 42 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 43 * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR 44 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 45 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 46 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 47 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 48 */ 49 50/* 51 * These are some utility functions created for convenience or to provide 52 * an interface that is similar to an existing interface. These are built 53 * only using the Transport Independant API, and have no knowledge of 54 * the internal implementation. 55 */ 56 57#ifdef XTHREADS 58#include <X11/Xthreads.h> 59#endif 60#ifdef WIN32 61#include <X11/Xlibint.h> 62#include <X11/Xwinsock.h> 63#endif 64 65#ifdef X11_t 66 67/* 68 * These values come from X.h and Xauth.h, and MUST match them. Some 69 * of these values are also defined by the ChangeHost protocol message. 70 */ 71 72#define FamilyInternet 0 /* IPv4 */ 73#define FamilyDECnet 1 74#define FamilyChaos 2 75#define FamilyInternet6 6 76#define FamilyAmoeba 33 77#define FamilyLocalHost 252 78#define FamilyKrb5Principal 253 79#define FamilyNetname 254 80#define FamilyLocal 256 81#define FamilyWild 65535 82 83/* 84 * TRANS(ConvertAddress) converts a sockaddr based address to an 85 * X authorization based address. Some of this is defined as part of 86 * the ChangeHost protocol. The rest is just done in a consistent manner. 87 */ 88 89int 90TRANS(ConvertAddress)(int *familyp, int *addrlenp, Xtransaddr **addrp) 91 92{ 93 94 PRMSG(2,"ConvertAddress(%d,%d,%x)\n",*familyp,*addrlenp,*addrp); 95 96 switch( *familyp ) 97 { 98#if defined(TCPCONN) || defined(STREAMSCONN) 99 case AF_INET: 100 { 101 /* 102 * Check for the BSD hack localhost address 127.0.0.1. 103 * In this case, we are really FamilyLocal. 104 */ 105 106 struct sockaddr_in saddr; 107#ifdef CRAY 108#ifdef OLDTCP 109 int len = sizeof(saddr.sin_addr); 110#else 111 int len = SIZEOF_in_addr; 112#endif /* OLDTCP */ 113 char *cp = (char *) &saddr.sin_addr; 114#else /* else not CRAY */ 115 int len = sizeof(saddr.sin_addr.s_addr); 116 char *cp = (char *) &saddr.sin_addr.s_addr; 117#endif /* CRAY */ 118 119 memcpy (&saddr, *addrp, sizeof (struct sockaddr_in)); 120 121 if ((len == 4) && (cp[0] == 127) && (cp[1] == 0) && 122 (cp[2] == 0) && (cp[3] == 1)) 123 { 124 *familyp=FamilyLocal; 125 } 126 else 127 { 128 *familyp=FamilyInternet; 129 *addrlenp=len; 130 memcpy(*addrp,&saddr.sin_addr,len); 131 } 132 break; 133 } 134 135#if defined(IPv6) && defined(AF_INET6) 136 case AF_INET6: 137 { 138 struct sockaddr_in6 saddr6; 139 140 memcpy (&saddr6, *addrp, sizeof (struct sockaddr_in6)); 141 142 if (IN6_IS_ADDR_LOOPBACK(&saddr6.sin6_addr)) 143 { 144 *familyp=FamilyLocal; 145 } 146 else if (IN6_IS_ADDR_V4MAPPED(&(saddr6.sin6_addr))) { 147 char *cp = (char *) &saddr6.sin6_addr.s6_addr[12]; 148 149 if ((cp[0] == 127) && (cp[1] == 0) && 150 (cp[2] == 0) && (cp[3] == 1)) 151 { 152 *familyp=FamilyLocal; 153 } 154 else 155 { 156 *familyp=FamilyInternet; 157 *addrlenp = sizeof (struct in_addr); 158 memcpy(*addrp,cp,*addrlenp); 159 } 160 } 161 else 162 { 163 *familyp=FamilyInternet6; 164 *addrlenp=sizeof(saddr6.sin6_addr); 165 memcpy(*addrp,&saddr6.sin6_addr,sizeof(saddr6.sin6_addr)); 166 } 167 break; 168 } 169#endif /* IPv6 */ 170#endif /* defined(TCPCONN) || defined(STREAMSCONN) */ 171 172#if defined(DNETCONN) 173 case AF_DECnet: 174 { 175 struct sockaddr_dn saddr; 176 177 memcpy (&saddr, *addrp, sizeof (struct sockaddr_dn)); 178 179 *familyp=FamilyDECnet; 180 *addrlenp=sizeof(struct dn_naddr); 181 memcpy(*addrp,&saddr.sdn_add,*addrlenp); 182 183 break; 184 } 185#endif /* defined(DNETCONN) */ 186 187#if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) 188 case AF_UNIX: 189 { 190 *familyp=FamilyLocal; 191 break; 192 } 193#endif /* defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN)*/ 194 195#if (defined(__SCO__) || defined(__UNIXWARE__)) && defined(LOCALCONN) 196 case 0: 197 { 198 *familyp=FamilyLocal; 199 break; 200 } 201#endif 202 203 default: 204 PRMSG(1,"ConvertAddress: Unknown family type %d\n", 205 *familyp, 0,0 ); 206 return -1; 207 } 208 209 210 if (*familyp == FamilyLocal) 211 { 212 /* 213 * In the case of a local connection, we need to get the 214 * host name for authentication. 215 */ 216 217 char hostnamebuf[256]; 218 int len = TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf); 219 220 if (len > 0) { 221 if (*addrp && *addrlenp < (len + 1)) 222 { 223 xfree ((char *) *addrp); 224 *addrp = NULL; 225 } 226 if (!*addrp) 227 *addrp = (Xtransaddr *) xalloc (len + 1); 228 if (*addrp) { 229 strcpy ((char *) *addrp, hostnamebuf); 230 *addrlenp = len; 231 } else { 232 *addrlenp = 0; 233 } 234 } 235 else 236 { 237 if (*addrp) 238 xfree ((char *) *addrp); 239 *addrp = NULL; 240 *addrlenp = 0; 241 } 242 } 243 244 return 0; 245} 246 247#endif /* X11_t */ 248 249#ifdef ICE_t 250 251#include <signal.h> 252 253char * 254TRANS(GetMyNetworkId) (XtransConnInfo ciptr) 255 256{ 257 int family = ciptr->family; 258 char *addr = ciptr->addr; 259 char hostnamebuf[256]; 260 char *networkId = NULL; 261 char *transName = ciptr->transptr->TransName; 262 263 if (gethostname (hostnamebuf, sizeof (hostnamebuf)) < 0) 264 { 265 return (NULL); 266 } 267 268 switch (family) 269 { 270#if defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) 271 case AF_UNIX: 272 { 273 struct sockaddr_un *saddr = (struct sockaddr_un *) addr; 274 networkId = (char *) xalloc (3 + strlen (transName) + 275 strlen (hostnamebuf) + strlen (saddr->sun_path)); 276 sprintf (networkId, "%s/%s:%s", transName, 277 hostnamebuf, saddr->sun_path); 278 break; 279 } 280#endif /* defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) */ 281 282#if defined(TCPCONN) || defined(STREAMSCONN) 283 case AF_INET: 284#if defined(IPv6) && defined(AF_INET6) 285 case AF_INET6: 286#endif 287 { 288 struct sockaddr_in *saddr = (struct sockaddr_in *) addr; 289#if defined(IPv6) && defined(AF_INET6) 290 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) addr; 291#endif 292 int portnum; 293 char portnumbuf[10]; 294 295 296#if defined(IPv6) && defined(AF_INET6) 297 if (family == AF_INET6) 298 portnum = ntohs (saddr6->sin6_port); 299 else 300#endif 301 portnum = ntohs (saddr->sin_port); 302 303 snprintf (portnumbuf, sizeof(portnumbuf), "%d", portnum); 304 networkId = (char *) xalloc (3 + strlen (transName) + 305 strlen (hostnamebuf) + strlen (portnumbuf)); 306 sprintf (networkId, "%s/%s:%s", transName, hostnamebuf, portnumbuf); 307 break; 308 } 309#endif /* defined(TCPCONN) || defined(STREAMSCONN) */ 310 311#if defined(DNETCONN) 312 case AF_DECnet: 313 { 314 struct sockaddr_dn *saddr = (struct sockaddr_dn *) addr; 315 316 networkId = (char *) xalloc ( 317 13 + strlen (hostnamebuf) + saddr->sdn_objnamel); 318 sprintf (networkId, "dnet/%s::%s", 319 hostnamebuf, saddr->sdn_objname); 320 break; 321 } 322#endif /* defined(DNETCONN) */ 323 324 default: 325 break; 326 } 327 328 return (networkId); 329} 330 331#include <setjmp.h> 332static jmp_buf env; 333 334#ifdef SIGALRM 335static volatile int nameserver_timedout = 0; 336 337static 338#ifdef RETSIGTYPE /* set by autoconf AC_TYPE_SIGNAL */ 339RETSIGTYPE 340#else /* Imake */ 341#ifdef SIGNALRETURNSINT 342int 343#else 344void 345#endif 346#endif 347nameserver_lost(int sig) 348{ 349 nameserver_timedout = 1; 350 longjmp (env, -1); 351 /* NOTREACHED */ 352#ifdef SIGNALRETURNSINT 353 return -1; /* for picky compilers */ 354#endif 355} 356#endif /* SIGALARM */ 357 358 359char * 360TRANS(GetPeerNetworkId) (XtransConnInfo ciptr) 361 362{ 363 int family = ciptr->family; 364 char *peer_addr = ciptr->peeraddr; 365 char *hostname; 366 char addrbuf[256]; 367 const char *addr = NULL; 368 369 switch (family) 370 { 371 case AF_UNSPEC: 372#if defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) 373 case AF_UNIX: 374 { 375 if (gethostname (addrbuf, sizeof (addrbuf)) == 0) 376 addr = addrbuf; 377 break; 378 } 379#endif /* defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) */ 380 381#if defined(TCPCONN) || defined(STREAMSCONN) 382 case AF_INET: 383#if defined(IPv6) && defined(AF_INET6) 384 case AF_INET6: 385#endif 386 { 387 struct sockaddr_in *saddr = (struct sockaddr_in *) peer_addr; 388#if defined(IPv6) && defined(AF_INET6) 389 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) peer_addr; 390#endif 391 char *address; 392 int addresslen; 393#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 394 _Xgethostbynameparams hparams; 395#endif 396 struct hostent * volatile hostp = NULL; 397 398#if defined(IPv6) && defined(AF_INET6) 399 if (family == AF_INET6) 400 { 401 address = (char *) &saddr6->sin6_addr; 402 addresslen = sizeof (saddr6->sin6_addr); 403 } 404 else 405#endif 406 { 407 address = (char *) &saddr->sin_addr; 408 addresslen = sizeof (saddr->sin_addr); 409 } 410 411#ifdef SIGALRM 412 /* 413 * gethostbyaddr can take a LONG time if the host does not exist. 414 * Assume that if it does not respond in NAMESERVER_TIMEOUT seconds 415 * that something is wrong and do not make the user wait. 416 * gethostbyaddr will continue after a signal, so we have to 417 * jump out of it. 418 */ 419 420 nameserver_timedout = 0; 421 signal (SIGALRM, nameserver_lost); 422 alarm (4); 423 if (setjmp(env) == 0) { 424#endif 425 hostp = _XGethostbyaddr (address, addresslen, family, hparams); 426#ifdef SIGALRM 427 } 428 alarm (0); 429#endif 430 if (hostp != NULL) 431 addr = hostp->h_name; 432 else 433#if defined(IPv6) && defined(AF_INET6) 434 addr = inet_ntop (family, address, addrbuf, sizeof (addrbuf)); 435#else 436 addr = inet_ntoa (saddr->sin_addr); 437#endif 438 break; 439 } 440 441#endif /* defined(TCPCONN) || defined(STREAMSCONN) */ 442 443#if defined(DNETCONN) 444 case AF_DECnet: 445 { 446 struct sockaddr_dn *saddr = (struct sockaddr_dn *) peer_addr; 447 struct nodeent *np; 448 449 if (np = getnodebyaddr(saddr->sdn_add.a_addr, 450 saddr->sdn_add.a_len, AF_DECnet)) { 451 sprintf(addrbuf, "%s:", np->n_name); 452 } else { 453 sprintf(addrbuf, "%s:", dnet_htoa(&saddr->sdn_add)); 454 } 455 addr = addrbuf; 456 break; 457 } 458#endif /* defined(DNETCONN) */ 459 460 default: 461 return (NULL); 462 } 463 464 465 hostname = (char *) xalloc ( 466 strlen (ciptr->transptr->TransName) + strlen (addr) + 2); 467 strcpy (hostname, ciptr->transptr->TransName); 468 strcat (hostname, "/"); 469 if (addr) 470 strcat (hostname, addr); 471 472 return (hostname); 473} 474 475#endif /* ICE_t */ 476 477 478#if defined(WIN32) && (defined(TCPCONN) || defined(DNETCONN)) 479int 480TRANS(WSAStartup) (void) 481{ 482 static WSADATA wsadata; 483 484 PRMSG (2,"WSAStartup()\n", 0, 0, 0); 485 486 if (!wsadata.wVersion && WSAStartup(MAKEWORD(2,2), &wsadata)) 487 return 1; 488 return 0; 489} 490#endif 491 492 493static int 494is_numeric (char *str) 495 496{ 497 int i; 498 499 for (i = 0; i < (int) strlen (str); i++) 500 if (!isdigit (str[i])) 501 return (0); 502 503 return (1); 504} 505 506#ifdef TRANS_SERVER 507#include <sys/types.h> 508#include <sys/stat.h> 509#include <errno.h> 510 511#if !defined(S_IFLNK) && !defined(S_ISLNK) 512#undef lstat 513#define lstat(a,b) stat(a,b) 514#endif 515 516#define FAIL_IF_NOMODE 1 517#define FAIL_IF_NOT_ROOT 2 518#define WARN_NO_ACCESS 4 519 520/* 521 * We make the assumption that when the 'sticky' (t) bit is requested 522 * it's not save if the directory has non-root ownership or the sticky 523 * bit cannot be set and fail. 524 */ 525static int 526trans_mkdir(char *path, int mode) 527{ 528 struct stat buf; 529 530 if (lstat(path, &buf) != 0) { 531 if (errno != ENOENT) { 532 PRMSG(1, "mkdir: ERROR: (l)stat failed for %s (%d)\n", 533 path, errno, 0); 534 return -1; 535 } 536 /* Dir doesn't exist. Try to create it */ 537 538#ifndef WIN32 539 /* 540 * 'sticky' bit requested: assume application makes 541 * certain security implications. If effective user ID 542 * is != 0: fail as we may not be able to meet them. 543 */ 544 if (geteuid() != 0) { 545 if (mode & 01000) { 546 PRMSG(1, "mkdir: ERROR: euid != 0," 547 "directory %s will not be created.\n", 548 path, 0, 0); 549#ifdef FAIL_HARD 550 return -1; 551#endif 552 } else { 553 PRMSG(1, "mkdir: Cannot create %s with root ownership\n", 554 path, 0, 0); 555 } 556 } 557#endif 558 559#ifndef WIN32 560 if (mkdir(path, mode) == 0) { 561 if (chmod(path, mode)) { 562 PRMSG(1, "mkdir: ERROR: Mode of %s should be set to %04o\n", 563 path, mode, 0); 564#ifdef FAIL_HARD 565 return -1; 566#endif 567 } 568#else 569 if (mkdir(path) == 0) { 570#endif 571 } else { 572 PRMSG(1, "mkdir: ERROR: Cannot create %s\n", 573 path, 0, 0); 574 return -1; 575 } 576 577 return 0; 578 579 } else { 580 if (S_ISDIR(buf.st_mode)) { 581 int updateOwner = 0; 582 int updateMode = 0; 583 int updatedOwner = 0; 584 int updatedMode = 0; 585 int status = 0; 586 /* Check if the directory's ownership is OK. */ 587 if (buf.st_uid != 0) 588 updateOwner = 1; 589 590 /* 591 * Check if the directory's mode is OK. An exact match isn't 592 * required, just a mode that isn't more permissive than the 593 * one requested. 594 */ 595 if ((~mode) & 0077 & buf.st_mode) 596 updateMode = 1; 597 598 /* 599 * If the directory is not writeable not everybody may 600 * be able to create sockets. Therefore warn if mode 601 * cannot be fixed. 602 */ 603 if ((~buf.st_mode) & 0022 & mode) { 604 updateMode = 1; 605 status |= WARN_NO_ACCESS; 606 } 607 608 /* 609 * If 'sticky' bit is requested fail if owner isn't root 610 * as we assume the caller makes certain security implications 611 */ 612 if (mode & 01000) { 613 status |= FAIL_IF_NOT_ROOT; 614 if (!(buf.st_mode & 01000)) { 615 status |= FAIL_IF_NOMODE; 616 updateMode = 1; 617 } 618 } 619 620#ifdef HAS_FCHOWN 621 /* 622 * If fchown(2) and fchmod(2) are available, try to correct the 623 * directory's owner and mode. Otherwise it isn't safe to attempt 624 * to do this. 625 */ 626 if (updateMode || updateOwner) { 627 int fd = -1; 628 struct stat fbuf; 629 if ((fd = open(path, O_RDONLY)) != -1) { 630 if (fstat(fd, &fbuf) == -1) { 631 PRMSG(1, "mkdir: ERROR: fstat failed for %s (%d)\n", 632 path, errno, 0); 633 return -1; 634 } 635 /* 636 * Verify that we've opened the same directory as was 637 * checked above. 638 */ 639 if (!S_ISDIR(fbuf.st_mode) || 640 buf.st_dev != fbuf.st_dev || 641 buf.st_ino != fbuf.st_ino) { 642 PRMSG(1, "mkdir: ERROR: inode for %s changed\n", 643 path, 0, 0); 644 return -1; 645 } 646 if (updateOwner && fchown(fd, 0, 0) == 0) 647 updatedOwner = 1; 648 if (updateMode && fchmod(fd, mode) == 0) 649 updatedMode = 1; 650 close(fd); 651 } 652 } 653#endif 654 655 if (updateOwner && !updatedOwner) { 656#ifdef FAIL_HARD 657 if (status & FAIL_IF_NOT_ROOT) { 658 PRMSG(1, "mkdir: ERROR: Owner of %s must be set to root\n", 659 path, 0, 0); 660 return -1; 661 } 662#endif 663#ifndef __APPLE_CC__ 664 PRMSG(1, "mkdir: Owner of %s should be set to root\n", 665 path, 0, 0); 666#endif 667 } 668 669 if (updateMode && !updatedMode) { 670#ifdef FAIL_HARD 671 if (status & FAIL_IF_NOMODE) { 672 PRMSG(1, "mkdir: ERROR: Mode of %s must be set to %04o\n", 673 path, mode, 0); 674 return -1; 675 } 676#endif 677 PRMSG(1, "mkdir: Mode of %s should be set to %04o\n", 678 path, mode, 0); 679 if (status & WARN_NO_ACCESS) { 680 PRMSG(1, "mkdir: this may cause subsequent errors\n", 681 0, 0, 0); 682 } 683 } 684 return 0; 685 } 686 return -1; 687 } 688 689 /* In all other cases, fail */ 690 return -1; 691} 692 693#endif /* TRANS_SERVER */ 694