Xtransutil.c revision b53e5eea
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 int len = sizeof(saddr.sin_addr.s_addr); 108 char *cp = (char *) &saddr.sin_addr.s_addr; 109 110 memcpy (&saddr, *addrp, sizeof (struct sockaddr_in)); 111 112 if ((len == 4) && (cp[0] == 127) && (cp[1] == 0) && 113 (cp[2] == 0) && (cp[3] == 1)) 114 { 115 *familyp=FamilyLocal; 116 } 117 else 118 { 119 *familyp=FamilyInternet; 120 *addrlenp=len; 121 memcpy(*addrp,&saddr.sin_addr,len); 122 } 123 break; 124 } 125 126#if defined(IPv6) && defined(AF_INET6) 127 case AF_INET6: 128 { 129 struct sockaddr_in6 saddr6; 130 131 memcpy (&saddr6, *addrp, sizeof (struct sockaddr_in6)); 132 133 if (IN6_IS_ADDR_LOOPBACK(&saddr6.sin6_addr)) 134 { 135 *familyp=FamilyLocal; 136 } 137 else if (IN6_IS_ADDR_V4MAPPED(&(saddr6.sin6_addr))) { 138 char *cp = (char *) &saddr6.sin6_addr.s6_addr[12]; 139 140 if ((cp[0] == 127) && (cp[1] == 0) && 141 (cp[2] == 0) && (cp[3] == 1)) 142 { 143 *familyp=FamilyLocal; 144 } 145 else 146 { 147 *familyp=FamilyInternet; 148 *addrlenp = sizeof (struct in_addr); 149 memcpy(*addrp,cp,*addrlenp); 150 } 151 } 152 else 153 { 154 *familyp=FamilyInternet6; 155 *addrlenp=sizeof(saddr6.sin6_addr); 156 memcpy(*addrp,&saddr6.sin6_addr,sizeof(saddr6.sin6_addr)); 157 } 158 break; 159 } 160#endif /* IPv6 */ 161#endif /* defined(TCPCONN) || defined(STREAMSCONN) */ 162 163 164#if defined(UNIXCONN) || defined(LOCALCONN) 165 case AF_UNIX: 166 { 167 *familyp=FamilyLocal; 168 break; 169 } 170#endif /* defined(UNIXCONN) || defined(LOCALCONN) */ 171 172#if (defined(__SCO__) || defined(__UNIXWARE__)) && defined(LOCALCONN) 173 case 0: 174 { 175 *familyp=FamilyLocal; 176 break; 177 } 178#endif 179 180 default: 181 PRMSG(1,"ConvertAddress: Unknown family type %d\n", 182 *familyp, 0,0 ); 183 return -1; 184 } 185 186 187 if (*familyp == FamilyLocal) 188 { 189 /* 190 * In the case of a local connection, we need to get the 191 * host name for authentication. 192 */ 193 194 char hostnamebuf[256]; 195 int len = TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf); 196 197 if (len > 0) { 198 if (*addrp && *addrlenp < (len + 1)) 199 { 200 xfree ((char *) *addrp); 201 *addrp = NULL; 202 } 203 if (!*addrp) 204 *addrp = (Xtransaddr *) xalloc (len + 1); 205 if (*addrp) { 206 strcpy ((char *) *addrp, hostnamebuf); 207 *addrlenp = len; 208 } else { 209 *addrlenp = 0; 210 } 211 } 212 else 213 { 214 if (*addrp) 215 xfree ((char *) *addrp); 216 *addrp = NULL; 217 *addrlenp = 0; 218 } 219 } 220 221 return 0; 222} 223 224#endif /* X11_t */ 225 226#ifdef ICE_t 227 228/* Needed for _XGethostbyaddr usage in TRANS(GetPeerNetworkId) */ 229# if defined(TCPCONN) || defined(UNIXCONN) 230# define X_INCLUDE_NETDB_H 231# define XOS_USE_NO_LOCKING 232# include <X11/Xos_r.h> 233# endif 234 235#include <signal.h> 236 237char * 238TRANS(GetMyNetworkId) (XtransConnInfo ciptr) 239 240{ 241 int family = ciptr->family; 242 char *addr = ciptr->addr; 243 char hostnamebuf[256]; 244 char *networkId = NULL; 245 char *transName = ciptr->transptr->TransName; 246 247 if (gethostname (hostnamebuf, sizeof (hostnamebuf)) < 0) 248 { 249 return (NULL); 250 } 251 252 switch (family) 253 { 254#if defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) 255 case AF_UNIX: 256 { 257 struct sockaddr_un *saddr = (struct sockaddr_un *) addr; 258 networkId = (char *) xalloc (3 + strlen (transName) + 259 strlen (hostnamebuf) + strlen (saddr->sun_path)); 260 sprintf (networkId, "%s/%s:%s", transName, 261 hostnamebuf, saddr->sun_path); 262 break; 263 } 264#endif /* defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) */ 265 266#if defined(TCPCONN) || defined(STREAMSCONN) 267 case AF_INET: 268#if defined(IPv6) && defined(AF_INET6) 269 case AF_INET6: 270#endif 271 { 272 struct sockaddr_in *saddr = (struct sockaddr_in *) addr; 273#if defined(IPv6) && defined(AF_INET6) 274 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) addr; 275#endif 276 int portnum; 277 char portnumbuf[10]; 278 279 280#if defined(IPv6) && defined(AF_INET6) 281 if (family == AF_INET6) 282 portnum = ntohs (saddr6->sin6_port); 283 else 284#endif 285 portnum = ntohs (saddr->sin_port); 286 287 snprintf (portnumbuf, sizeof(portnumbuf), "%d", portnum); 288 networkId = (char *) xalloc (3 + strlen (transName) + 289 strlen (hostnamebuf) + strlen (portnumbuf)); 290 sprintf (networkId, "%s/%s:%s", transName, hostnamebuf, portnumbuf); 291 break; 292 } 293#endif /* defined(TCPCONN) || defined(STREAMSCONN) */ 294 295 296 default: 297 break; 298 } 299 300 return (networkId); 301} 302 303#include <setjmp.h> 304static jmp_buf env; 305 306#ifdef SIGALRM 307static volatile int nameserver_timedout = 0; 308 309static 310#ifdef RETSIGTYPE /* set by autoconf AC_TYPE_SIGNAL */ 311RETSIGTYPE 312#else /* Imake */ 313#ifdef SIGNALRETURNSINT 314int 315#else 316void 317#endif 318#endif 319nameserver_lost(int sig) 320{ 321 nameserver_timedout = 1; 322 longjmp (env, -1); 323 /* NOTREACHED */ 324#ifdef SIGNALRETURNSINT 325 return -1; /* for picky compilers */ 326#endif 327} 328#endif /* SIGALARM */ 329 330 331char * 332TRANS(GetPeerNetworkId) (XtransConnInfo ciptr) 333 334{ 335 int family = ciptr->family; 336 char *peer_addr = ciptr->peeraddr; 337 char *hostname; 338 char addrbuf[256]; 339 const char *addr = NULL; 340 341 switch (family) 342 { 343 case AF_UNSPEC: 344#if defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) 345 case AF_UNIX: 346 { 347 if (gethostname (addrbuf, sizeof (addrbuf)) == 0) 348 addr = addrbuf; 349 break; 350 } 351#endif /* defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) */ 352 353#if defined(TCPCONN) || defined(STREAMSCONN) 354 case AF_INET: 355#if defined(IPv6) && defined(AF_INET6) 356 case AF_INET6: 357#endif 358 { 359 struct sockaddr_in *saddr = (struct sockaddr_in *) peer_addr; 360#if defined(IPv6) && defined(AF_INET6) 361 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) peer_addr; 362#endif 363 char *address; 364 int addresslen; 365#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 366 _Xgethostbynameparams hparams; 367#endif 368 struct hostent * volatile hostp = NULL; 369 370#if defined(IPv6) && defined(AF_INET6) 371 if (family == AF_INET6) 372 { 373 address = (char *) &saddr6->sin6_addr; 374 addresslen = sizeof (saddr6->sin6_addr); 375 } 376 else 377#endif 378 { 379 address = (char *) &saddr->sin_addr; 380 addresslen = sizeof (saddr->sin_addr); 381 } 382 383#ifdef SIGALRM 384 /* 385 * gethostbyaddr can take a LONG time if the host does not exist. 386 * Assume that if it does not respond in NAMESERVER_TIMEOUT seconds 387 * that something is wrong and do not make the user wait. 388 * gethostbyaddr will continue after a signal, so we have to 389 * jump out of it. 390 */ 391 392 nameserver_timedout = 0; 393 signal (SIGALRM, nameserver_lost); 394 alarm (4); 395 if (setjmp(env) == 0) { 396#endif 397 hostp = _XGethostbyaddr (address, addresslen, family, hparams); 398#ifdef SIGALRM 399 } 400 alarm (0); 401#endif 402 if (hostp != NULL) 403 addr = hostp->h_name; 404 else 405#if defined(IPv6) && defined(AF_INET6) 406 addr = inet_ntop (family, address, addrbuf, sizeof (addrbuf)); 407#else 408 addr = inet_ntoa (saddr->sin_addr); 409#endif 410 break; 411 } 412 413#endif /* defined(TCPCONN) || defined(STREAMSCONN) */ 414 415 416 default: 417 return (NULL); 418 } 419 420 421 hostname = (char *) xalloc ( 422 strlen (ciptr->transptr->TransName) + strlen (addr) + 2); 423 strcpy (hostname, ciptr->transptr->TransName); 424 strcat (hostname, "/"); 425 if (addr) 426 strcat (hostname, addr); 427 428 return (hostname); 429} 430 431#endif /* ICE_t */ 432 433 434#if defined(WIN32) && defined(TCPCONN) 435int 436TRANS(WSAStartup) (void) 437{ 438 static WSADATA wsadata; 439 440 PRMSG (2,"WSAStartup()\n", 0, 0, 0); 441 442 if (!wsadata.wVersion && WSAStartup(MAKEWORD(2,2), &wsadata)) 443 return 1; 444 return 0; 445} 446#endif 447 448#include <ctype.h> 449 450static int 451is_numeric (const char *str) 452{ 453 int i; 454 455 for (i = 0; i < (int) strlen (str); i++) 456 if (!isdigit (str[i])) 457 return (0); 458 459 return (1); 460} 461 462#ifdef TRANS_SERVER 463#include <sys/types.h> 464#include <sys/stat.h> 465#include <errno.h> 466 467#if !defined(S_IFLNK) && !defined(S_ISLNK) 468#undef lstat 469#define lstat(a,b) stat(a,b) 470#endif 471 472#define FAIL_IF_NOMODE 1 473#define FAIL_IF_NOT_ROOT 2 474#define WARN_NO_ACCESS 4 475 476/* 477 * We make the assumption that when the 'sticky' (t) bit is requested 478 * it's not save if the directory has non-root ownership or the sticky 479 * bit cannot be set and fail. 480 */ 481static int 482trans_mkdir(const char *path, int mode) 483{ 484 struct stat buf; 485 486 if (lstat(path, &buf) != 0) { 487 if (errno != ENOENT) { 488 PRMSG(1, "mkdir: ERROR: (l)stat failed for %s (%d)\n", 489 path, errno, 0); 490 return -1; 491 } 492 /* Dir doesn't exist. Try to create it */ 493 494#if !defined(WIN32) && !defined(__CYGWIN__) 495 /* 496 * 'sticky' bit requested: assume application makes 497 * certain security implications. If effective user ID 498 * is != 0: fail as we may not be able to meet them. 499 */ 500 if (geteuid() != 0) { 501 if (mode & 01000) { 502 PRMSG(1, "mkdir: ERROR: euid != 0," 503 "directory %s will not be created.\n", 504 path, 0, 0); 505#ifdef FAIL_HARD 506 return -1; 507#endif 508 } else { 509 PRMSG(1, "mkdir: Cannot create %s with root ownership\n", 510 path, 0, 0); 511 } 512 } 513#endif 514 515#ifndef WIN32 516 if (mkdir(path, mode) == 0) { 517 if (chmod(path, mode)) { 518 PRMSG(1, "mkdir: ERROR: Mode of %s should be set to %04o\n", 519 path, mode, 0); 520#ifdef FAIL_HARD 521 return -1; 522#endif 523 } 524#else 525 if (mkdir(path) == 0) { 526#endif 527 } else { 528 PRMSG(1, "mkdir: ERROR: Cannot create %s\n", 529 path, 0, 0); 530 return -1; 531 } 532 533 return 0; 534 535 } else { 536 if (S_ISDIR(buf.st_mode)) { 537 int updateOwner = 0; 538 int updateMode = 0; 539 int updatedOwner = 0; 540 int updatedMode = 0; 541 int status = 0; 542 /* Check if the directory's ownership is OK. */ 543 if (buf.st_uid != 0) 544 updateOwner = 1; 545 546 /* 547 * Check if the directory's mode is OK. An exact match isn't 548 * required, just a mode that isn't more permissive than the 549 * one requested. 550 */ 551 if ((~mode) & 0077 & buf.st_mode) 552 updateMode = 1; 553 554 /* 555 * If the directory is not writeable not everybody may 556 * be able to create sockets. Therefore warn if mode 557 * cannot be fixed. 558 */ 559 if ((~buf.st_mode) & 0022 & mode) { 560 updateMode = 1; 561 status |= WARN_NO_ACCESS; 562 } 563 564 /* 565 * If 'sticky' bit is requested fail if owner isn't root 566 * as we assume the caller makes certain security implications 567 */ 568 if (mode & 01000) { 569 status |= FAIL_IF_NOT_ROOT; 570 if (!(buf.st_mode & 01000)) { 571 status |= FAIL_IF_NOMODE; 572 updateMode = 1; 573 } 574 } 575 576#ifdef HAS_FCHOWN 577 /* 578 * If fchown(2) and fchmod(2) are available, try to correct the 579 * directory's owner and mode. Otherwise it isn't safe to attempt 580 * to do this. 581 */ 582 if (updateMode || updateOwner) { 583 int fd = -1; 584 struct stat fbuf; 585 if ((fd = open(path, O_RDONLY)) != -1) { 586 if (fstat(fd, &fbuf) == -1) { 587 PRMSG(1, "mkdir: ERROR: fstat failed for %s (%d)\n", 588 path, errno, 0); 589 return -1; 590 } 591 /* 592 * Verify that we've opened the same directory as was 593 * checked above. 594 */ 595 if (!S_ISDIR(fbuf.st_mode) || 596 buf.st_dev != fbuf.st_dev || 597 buf.st_ino != fbuf.st_ino) { 598 PRMSG(1, "mkdir: ERROR: inode for %s changed\n", 599 path, 0, 0); 600 return -1; 601 } 602 if (updateOwner && fchown(fd, 0, 0) == 0) 603 updatedOwner = 1; 604 if (updateMode && fchmod(fd, mode) == 0) 605 updatedMode = 1; 606 close(fd); 607 } 608 } 609#endif 610 611 if (updateOwner && !updatedOwner) { 612#ifdef FAIL_HARD 613 if (status & FAIL_IF_NOT_ROOT) { 614 PRMSG(1, "mkdir: ERROR: Owner of %s must be set to root\n", 615 path, 0, 0); 616 return -1; 617 } 618#endif 619#if !defined(__APPLE_CC__) && !defined(__CYGWIN__) 620 PRMSG(1, "mkdir: Owner of %s should be set to root\n", 621 path, 0, 0); 622#endif 623 } 624 625 if (updateMode && !updatedMode) { 626#ifdef FAIL_HARD 627 if (status & FAIL_IF_NOMODE) { 628 PRMSG(1, "mkdir: ERROR: Mode of %s must be set to %04o\n", 629 path, mode, 0); 630 return -1; 631 } 632#endif 633 PRMSG(1, "mkdir: Mode of %s should be set to %04o\n", 634 path, mode, 0); 635 if (status & WARN_NO_ACCESS) { 636 PRMSG(1, "mkdir: this may cause subsequent errors\n", 637 0, 0, 0); 638 } 639 } 640 return 0; 641 } 642 return -1; 643 } 644 645 /* In all other cases, fail */ 646 return -1; 647} 648 649#endif /* TRANS_SERVER */ 650