Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2 
      3 Copyright 1993, 1994, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from 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 #if defined(IPv6) && !defined(AF_INET6)
     66 #error "Cannot build IPv6 support without AF_INET6"
     67 #endif
     68 
     69 /* Temporary workaround for consumers whose configure scripts were
     70    generated with pre-1.6 versions of xtrans.m4 */
     71 #if defined(IPv6) && !defined(HAVE_INET_NTOP)
     72 #define HAVE_INET_NTOP
     73 #endif
     74 
     75 #ifdef X11_t
     76 
     77 /*
     78  * These values come from X.h and Xauth.h, and MUST match them. Some
     79  * of these values are also defined by the ChangeHost protocol message.
     80  */
     81 
     82 #define FamilyInternet		0	/* IPv4 */
     83 #define FamilyDECnet		1
     84 #define FamilyChaos		2
     85 #define FamilyInternet6		6
     86 #define FamilyAmoeba		33
     87 #define FamilyLocalHost		252
     88 #define FamilyKrb5Principal	253
     89 #define FamilyNetname		254
     90 #define FamilyLocal		256
     91 #define FamilyWild		65535
     92 
     93 /*
     94  * TRANS(ConvertAddress) converts a sockaddr based address to an
     95  * X authorization based address. Some of this is defined as part of
     96  * the ChangeHost protocol. The rest is just done in a consistent manner.
     97  */
     98 
     99 int
    100 TRANS(ConvertAddress)(int *familyp, int *addrlenp, Xtransaddr **addrp)
    101 
    102 {
    103 
    104     prmsg(2,"ConvertAddress(%d,%d,%p)\n",*familyp,*addrlenp,*addrp);
    105 
    106     switch( *familyp )
    107     {
    108 #if defined(TCPCONN)
    109     case AF_INET:
    110     {
    111 	/*
    112 	 * Check for the BSD hack localhost address 127.0.0.1.
    113 	 * In this case, we are really FamilyLocal.
    114 	 */
    115 
    116 	struct sockaddr_in saddr;
    117 	int len = sizeof(saddr.sin_addr.s_addr);
    118 	char *cp = (char *) &saddr.sin_addr.s_addr;
    119 
    120 	memcpy (&saddr, *addrp, sizeof (struct sockaddr_in));
    121 
    122 	if ((len == 4) && (cp[0] == 127) && (cp[1] == 0) &&
    123 	    (cp[2] == 0) && (cp[3] == 1))
    124 	{
    125 	    *familyp=FamilyLocal;
    126 	}
    127 	else
    128 	{
    129 	    *familyp=FamilyInternet;
    130 	    *addrlenp=len;
    131 	    memcpy(*addrp,&saddr.sin_addr,len);
    132 	}
    133 	break;
    134     }
    135 
    136 #ifdef IPv6
    137     case AF_INET6:
    138     {
    139 	struct sockaddr_in6 saddr6;
    140 
    141 	memcpy (&saddr6, *addrp, sizeof (struct sockaddr_in6));
    142 
    143 	if (IN6_IS_ADDR_LOOPBACK(&saddr6.sin6_addr))
    144 	{
    145 	    *familyp=FamilyLocal;
    146 	}
    147 	else if (IN6_IS_ADDR_V4MAPPED(&(saddr6.sin6_addr))) {
    148 	    char *cp = (char *) &saddr6.sin6_addr.s6_addr[12];
    149 
    150 	    if ((cp[0] == 127) && (cp[1] == 0) &&
    151 	      (cp[2] == 0) && (cp[3] == 1))
    152 	    {
    153 		*familyp=FamilyLocal;
    154 	    }
    155 	    else
    156 	    {
    157 		*familyp=FamilyInternet;
    158 		*addrlenp = sizeof (struct in_addr);
    159 		memcpy(*addrp,cp,*addrlenp);
    160 	    }
    161 	}
    162 	else
    163 	{
    164 	    *familyp=FamilyInternet6;
    165 	    *addrlenp=sizeof(saddr6.sin6_addr);
    166 	    memcpy(*addrp,&saddr6.sin6_addr,sizeof(saddr6.sin6_addr));
    167 	}
    168 	break;
    169     }
    170 #endif /* IPv6 */
    171 #endif /* defined(TCPCONN) */
    172 
    173 
    174 #if defined(UNIXCONN) || defined(LOCALCONN)
    175     case AF_UNIX:
    176     {
    177 	*familyp=FamilyLocal;
    178 	break;
    179     }
    180 #endif /* defined(UNIXCONN) || defined(LOCALCONN) */
    181 
    182 
    183     default:
    184 	prmsg(1,"ConvertAddress: Unknown family type %d\n",
    185 	      *familyp);
    186 	return -1;
    187     }
    188 
    189 
    190     if (*familyp == FamilyLocal)
    191     {
    192 	/*
    193 	 * In the case of a local connection, we need to get the
    194 	 * host name for authentication.
    195 	 */
    196 
    197 	char hostnamebuf[256];
    198 	int len = TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
    199 
    200 	if (len > 0) {
    201 	    if (*addrp && *addrlenp < (len + 1))
    202 	    {
    203 		free (*addrp);
    204 		*addrp = NULL;
    205 	    }
    206 	    if (!*addrp)
    207 		*addrp = malloc (len + 1);
    208 	    if (*addrp) {
    209 		strcpy ((char *) *addrp, hostnamebuf);
    210 		*addrlenp = len;
    211 	    } else {
    212 		*addrlenp = 0;
    213 	    }
    214 	}
    215 	else
    216 	{
    217 	    if (*addrp)
    218 		free (*addrp);
    219 	    *addrp = NULL;
    220 	    *addrlenp = 0;
    221 	}
    222     }
    223 
    224     return 0;
    225 }
    226 
    227 #endif /* X11_t */
    228 
    229 #ifdef ICE_t
    230 
    231 /* Needed for _XGethostbyaddr usage in TRANS(GetPeerNetworkId) */
    232 # if defined(TCPCONN) || defined(UNIXCONN)
    233 #  define X_INCLUDE_NETDB_H
    234 #  define XOS_USE_NO_LOCKING
    235 #  include <X11/Xos_r.h>
    236 # endif
    237 
    238 #include <signal.h>
    239 
    240 char *
    241 TRANS(GetMyNetworkId) (XtransConnInfo ciptr)
    242 
    243 {
    244     int		family = ciptr->family;
    245     char 	*addr = ciptr->addr;
    246     char	hostnamebuf[256];
    247     char 	*networkId = NULL;
    248     const char	*transName = ciptr->transptr->TransName;
    249 
    250     if (gethostname (hostnamebuf, sizeof (hostnamebuf)) < 0)
    251     {
    252 	return (NULL);
    253     }
    254 
    255     switch (family)
    256     {
    257 #if defined(UNIXCONN) || defined(LOCALCONN)
    258     case AF_UNIX:
    259     {
    260 	struct sockaddr_un *saddr = (struct sockaddr_un *) addr;
    261 	networkId = malloc (3 + strlen (transName) +
    262 	    strlen (hostnamebuf) + strlen (saddr->sun_path));
    263 	if (networkId != NULL)
    264 	    sprintf (networkId, "%s/%s:%s", transName,
    265 		     hostnamebuf, saddr->sun_path);
    266 	break;
    267     }
    268 #endif /* defined(UNIXCONN) || defined(LOCALCONN) */
    269 
    270 #if defined(TCPCONN)
    271     case AF_INET:
    272 #ifdef IPv6
    273     case AF_INET6:
    274 #endif
    275     {
    276 	struct sockaddr_in *saddr = (struct sockaddr_in *) addr;
    277 #ifdef IPv6
    278 	struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) addr;
    279 #endif
    280 	int portnum;
    281 	char portnumbuf[10];
    282 
    283 
    284 #ifdef IPv6
    285 	if (family == AF_INET6)
    286 	    portnum = ntohs (saddr6->sin6_port);
    287 	else
    288 #endif
    289 	    portnum = ntohs (saddr->sin_port);
    290 
    291 	snprintf (portnumbuf, sizeof(portnumbuf), "%d", portnum);
    292 	networkId = malloc (3 + strlen (transName) +
    293 	    strlen (hostnamebuf) + strlen (portnumbuf));
    294 	if (networkId != NULL)
    295 	    sprintf (networkId, "%s/%s:%s", transName, hostnamebuf, portnumbuf);
    296 	break;
    297     }
    298 #endif /* defined(TCPCONN) */
    299 
    300 
    301     default:
    302 	break;
    303     }
    304 
    305     return (networkId);
    306 }
    307 
    308 #include <setjmp.h>
    309 static jmp_buf env;
    310 
    311 #ifdef SIGALRM
    312 static volatile int nameserver_timedout = 0;
    313 
    314 static void
    315 nameserver_lost(int sig _X_UNUSED)
    316 {
    317   nameserver_timedout = 1;
    318   longjmp (env, -1);
    319   /* NOTREACHED */
    320 }
    321 #endif /* SIGALARM */
    322 
    323 
    324 char *
    325 TRANS(GetPeerNetworkId) (XtransConnInfo ciptr)
    326 
    327 {
    328     int		family = ciptr->family;
    329     char	*peer_addr = ciptr->peeraddr;
    330     char	*hostname;
    331     char	addrbuf[256];
    332     const char	*addr = NULL;
    333 
    334     switch (family)
    335     {
    336     case AF_UNSPEC:
    337 #if defined(UNIXCONN) || defined(LOCALCONN)
    338     case AF_UNIX:
    339     {
    340 	if (gethostname (addrbuf, sizeof (addrbuf)) == 0)
    341 	    addr = addrbuf;
    342 	break;
    343     }
    344 #endif /* defined(UNIXCONN) || defined(LOCALCONN) */
    345 
    346 #if defined(TCPCONN)
    347     case AF_INET:
    348 #ifdef IPv6
    349     case AF_INET6:
    350 #endif
    351     {
    352 	struct sockaddr_in *saddr = (struct sockaddr_in *) peer_addr;
    353 #ifdef IPv6
    354 	struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) peer_addr;
    355 #endif
    356 	char *address;
    357 	int addresslen;
    358 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
    359 	_Xgethostbynameparams hparams;
    360 #endif
    361 	struct hostent * volatile hostp = NULL;
    362 
    363 #ifdef IPv6
    364 	if (family == AF_INET6)
    365 	{
    366 	    address = (char *) &saddr6->sin6_addr;
    367 	    addresslen = sizeof (saddr6->sin6_addr);
    368 	}
    369 	else
    370 #endif
    371 	{
    372 	    address = (char *) &saddr->sin_addr;
    373 	    addresslen = sizeof (saddr->sin_addr);
    374 	}
    375 
    376 #ifdef SIGALRM
    377 	/*
    378 	 * gethostbyaddr can take a LONG time if the host does not exist.
    379 	 * Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
    380 	 * that something is wrong and do not make the user wait.
    381 	 * gethostbyaddr will continue after a signal, so we have to
    382 	 * jump out of it.
    383 	 */
    384 
    385 	nameserver_timedout = 0;
    386 	signal (SIGALRM, nameserver_lost);
    387 	alarm (4);
    388 	if (setjmp(env) == 0) {
    389 #endif
    390 	    hostp = _XGethostbyaddr (address, addresslen, family, hparams);
    391 #ifdef SIGALRM
    392 	}
    393 	alarm (0);
    394 #endif
    395 	if (hostp != NULL)
    396 	  addr = hostp->h_name;
    397 	else
    398 #ifdef HAVE_INET_NTOP
    399 	  addr = inet_ntop (family, address, addrbuf, sizeof (addrbuf));
    400 #else
    401 	  addr = inet_ntoa (saddr->sin_addr);
    402 #endif
    403 	break;
    404     }
    405 
    406 #endif /* defined(TCPCONN) */
    407 
    408 
    409     default:
    410 	return (NULL);
    411     }
    412 
    413 
    414     hostname = malloc (strlen (ciptr->transptr->TransName) +
    415                        (addr ? strlen (addr) : 0) + 2);
    416     if (hostname)
    417     {
    418 	strcpy (hostname, ciptr->transptr->TransName);
    419 	strcat (hostname, "/");
    420 	if (addr)
    421 	    strcat (hostname, addr);
    422     }
    423     return (hostname);
    424 }
    425 
    426 #endif /* ICE_t */
    427 
    428 
    429 #if defined(WIN32) && defined(TCPCONN)
    430 int
    431 TRANS(WSAStartup) (void)
    432 {
    433     static WSADATA wsadata;
    434 
    435     prmsg (2,"WSAStartup()\n");
    436 
    437     if (!wsadata.wVersion && WSAStartup(MAKEWORD(2,2), &wsadata))
    438         return 1;
    439     return 0;
    440 }
    441 #endif
    442 
    443 #ifdef TRANS_SERVER
    444 #include <sys/types.h>
    445 #include <sys/stat.h>
    446 #include <errno.h>
    447 
    448 #if !defined(S_IFLNK) && !defined(S_ISLNK)
    449 #undef lstat
    450 #define lstat(a,b) stat(a,b)
    451 #endif
    452 
    453 #define FAIL_IF_NOMODE  1
    454 #define FAIL_IF_NOT_ROOT 2
    455 #define WARN_NO_ACCESS 4
    456 
    457 /*
    458  * We make the assumption that when the 'sticky' (t) bit is requested
    459  * it's not save if the directory has non-root ownership or the sticky
    460  * bit cannot be set and fail.
    461  */
    462 static int
    463 trans_mkdir(const char *path, int mode)
    464 {
    465     struct stat buf;
    466 
    467     if (lstat(path, &buf) != 0) {
    468 	if (errno != ENOENT) {
    469 	    prmsg(1, "mkdir: ERROR: (l)stat failed for %s (%d)\n",
    470 		  path, errno);
    471 	    return -1;
    472 	}
    473 	/* Dir doesn't exist. Try to create it */
    474 
    475 #if !defined(WIN32) && !defined(__CYGWIN__)
    476 	/*
    477 	 * 'sticky' bit requested: assume application makes
    478 	 * certain security implications. If effective user ID
    479 	 * is != 0: fail as we may not be able to meet them.
    480 	 */
    481 	if (geteuid() != 0) {
    482 	    if (mode & 01000) {
    483 		prmsg(1, "mkdir: ERROR: euid != 0,"
    484 		      "directory %s will not be created.\n",
    485 		      path);
    486 #ifdef FAIL_HARD
    487 		return -1;
    488 #endif
    489 	    } else {
    490 		prmsg(1, "mkdir: Cannot create %s with root ownership\n",
    491 		      path);
    492 	    }
    493 	}
    494 #endif
    495 
    496 #ifndef WIN32
    497 	if (mkdir(path, mode) == 0) {
    498 	    if (chmod(path, mode)) {
    499 		prmsg(1, "mkdir: ERROR: Mode of %s should be set to %04o\n",
    500 		      path, mode);
    501 #ifdef FAIL_HARD
    502 		return -1;
    503 #endif
    504 	    }
    505 #else
    506 	if (mkdir(path) == 0) {
    507 #endif
    508 	} else {
    509 	    prmsg(1, "mkdir: ERROR: Cannot create %s\n",
    510 		  path);
    511 	    return -1;
    512 	}
    513 
    514 	return 0;
    515 
    516     } else {
    517 	if (S_ISDIR(buf.st_mode)) {
    518 	    int updateOwner = 0;
    519 	    int updateMode = 0;
    520 	    int updatedOwner = 0;
    521 	    int updatedMode = 0;
    522 	    int status = 0;
    523 	    /* Check if the directory's ownership is OK. */
    524 	    if (buf.st_uid != 0)
    525 		updateOwner = 1;
    526 
    527 	    /*
    528 	     * Check if the directory's mode is OK.  An exact match isn't
    529 	     * required, just a mode that isn't more permissive than the
    530 	     * one requested.
    531 	     */
    532 	    if ((~mode) & 0077 & buf.st_mode)
    533 		updateMode = 1;
    534 
    535 	    /*
    536 	     * If the directory is not writeable not everybody may
    537 	     * be able to create sockets. Therefore warn if mode
    538 	     * cannot be fixed.
    539 	     */
    540 	    if ((~buf.st_mode) & 0022 & mode) {
    541 		updateMode = 1;
    542 		status |= WARN_NO_ACCESS;
    543 	    }
    544 
    545 	    /*
    546 	     * If 'sticky' bit is requested fail if owner isn't root
    547 	     * as we assume the caller makes certain security implications
    548 	     */
    549 	    if (mode & 01000) {
    550 		status |= FAIL_IF_NOT_ROOT;
    551 		if (!(buf.st_mode & 01000)) {
    552 		    status |= FAIL_IF_NOMODE;
    553 		    updateMode = 1;
    554 		}
    555 	    }
    556 
    557 #ifdef HAS_FCHOWN
    558 	    /*
    559 	     * If fchown(2) and fchmod(2) are available, try to correct the
    560 	     * directory's owner and mode.  Otherwise it isn't safe to attempt
    561 	     * to do this.
    562 	     */
    563 	    if (updateMode || updateOwner) {
    564 		int fd = -1;
    565 		struct stat fbuf;
    566 		if ((fd = open(path, O_RDONLY)) != -1) {
    567 		    if (fstat(fd, &fbuf) == -1) {
    568 			prmsg(1, "mkdir: ERROR: fstat failed for %s (%d)\n",
    569 			      path, errno);
    570 			close(fd);
    571 			return -1;
    572 		    }
    573 		    /*
    574 		     * Verify that we've opened the same directory as was
    575 		     * checked above.
    576 		     */
    577 		    if (!S_ISDIR(fbuf.st_mode) ||
    578 			buf.st_dev != fbuf.st_dev ||
    579 			buf.st_ino != fbuf.st_ino) {
    580 			prmsg(1, "mkdir: ERROR: inode for %s changed\n",
    581 			      path);
    582 			close(fd);
    583 			return -1;
    584 		    }
    585 		    if (updateOwner && fchown(fd, 0, 0) == 0)
    586 			updatedOwner = 1;
    587 		    if (updateMode && fchmod(fd, mode) == 0)
    588 			updatedMode = 1;
    589 		    close(fd);
    590 		}
    591 	    }
    592 #endif
    593 
    594 	    if (updateOwner && !updatedOwner) {
    595 #ifdef FAIL_HARD
    596 		if (status & FAIL_IF_NOT_ROOT) {
    597 		    prmsg(1, "mkdir: ERROR: Owner of %s must be set to root\n",
    598 			  path);
    599 		    return -1;
    600 		}
    601 #endif
    602 #if !defined(__APPLE_CC__) && !defined(__CYGWIN__)
    603 		prmsg(1, "mkdir: Owner of %s should be set to root\n",
    604 		      path);
    605 #endif
    606 	    }
    607 
    608 	    if (updateMode && !updatedMode) {
    609 #ifdef FAIL_HARD
    610 		if (status & FAIL_IF_NOMODE) {
    611 		    prmsg(1, "mkdir: ERROR: Mode of %s must be set to %04o\n",
    612 			  path, mode);
    613 		    return -1;
    614 		}
    615 #endif
    616 		prmsg(1, "mkdir: Mode of %s should be set to %04o\n",
    617 		      path, mode);
    618 		if (status & WARN_NO_ACCESS) {
    619 		    prmsg(1, "mkdir: this may cause subsequent errors\n");
    620 		}
    621 	    }
    622 	    return 0;
    623 	}
    624 	return -1;
    625     }
    626 
    627     /* In all other cases, fail */
    628     return -1;
    629 }
    630 
    631 #endif /* TRANS_SERVER */
    632