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