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