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