1/***********************************************************
2
3Copyright 1987, 1998  The Open Group
4
5All rights reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, and/or sell copies of the Software, and to permit persons
12to whom the Software is furnished to do so, provided that the above
13copyright notice(s) and this permission notice appear in all copies of
14the Software and that both the above copyright notice(s) and this
15permission notice appear in supporting documentation.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
20OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
22INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
23FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
24NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26
27Except as contained in this notice, the name of a copyright holder
28shall not be used in advertising or otherwise to promote the sale, use
29or other dealings in this Software without prior written authorization
30of the copyright holder.
31
32X Window System is a trademark of The Open Group.
33
34Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
35
36                        All Rights Reserved
37
38Permission to use, copy, modify, and distribute this software and its
39documentation for any purpose and without fee is hereby granted,
40provided that the above copyright notice appear in all copies and that
41both that copyright notice and this permission notice appear in
42supporting documentation, and that the name of Digital not be
43used in advertising or publicity pertaining to distribution of the
44software without specific, written prior permission.
45
46DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
52SOFTWARE.
53
54******************************************************************/
55
56/*
57 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
58 *
59 * Permission is hereby granted, free of charge, to any person obtaining a
60 * copy of this software and associated documentation files (the "Software"),
61 * to deal in the Software without restriction, including without limitation
62 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
63 * and/or sell copies of the Software, and to permit persons to whom the
64 * Software is furnished to do so, subject to the following conditions:
65 *
66 * The above copyright notice and this permission notice (including the next
67 * paragraph) shall be included in all copies or substantial portions of the
68 * Software.
69 *
70 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
73 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
75 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
76 * DEALINGS IN THE SOFTWARE.
77 */
78
79#ifdef HAVE_DIX_CONFIG_H
80#include <dix-config.h>
81#endif
82
83#ifdef WIN32
84#include <X11/Xwinsock.h>
85#endif
86
87#include <stdio.h>
88#include <stdlib.h>
89#define XSERV_t
90#define TRANS_SERVER
91#define TRANS_REOPEN
92#include <X11/Xtrans/Xtrans.h>
93#include <X11/Xauth.h>
94#include <X11/X.h>
95#include <X11/Xproto.h>
96#include "misc.h"
97#include "site.h"
98#include <errno.h>
99#include <sys/types.h>
100#ifndef WIN32
101#include <sys/socket.h>
102#include <sys/ioctl.h>
103#include <ctype.h>
104
105#if defined(TCPCONN) || defined(STREAMSCONN)
106#include <netinet/in.h>
107#endif /* TCPCONN || STREAMSCONN */
108
109#ifdef HAS_GETPEERUCRED
110# include <ucred.h>
111# ifdef sun
112#  include <zone.h>
113# endif
114#endif
115
116#if defined(SVR4) ||  (defined(SYSV) && defined(__i386__)) || defined(__GNU__)
117# include <sys/utsname.h>
118#endif
119#if defined(SYSV) &&  defined(__i386__)
120# include <sys/stream.h>
121#endif
122#ifdef __GNU__
123#undef SIOCGIFCONF
124#include <netdb.h>
125#else /*!__GNU__*/
126# include <net/if.h>
127#endif /*__GNU__ */
128
129#ifdef SVR4
130#include <sys/sockio.h>
131#include <sys/stropts.h>
132#endif
133
134#include <netdb.h>
135
136#ifdef CSRG_BASED
137#include <sys/param.h>
138#if (BSD >= 199103)
139#define VARIABLE_IFREQ
140#endif
141#endif
142
143#ifdef BSD44SOCKETS
144#ifndef VARIABLE_IFREQ
145#define VARIABLE_IFREQ
146#endif
147#endif
148
149#ifdef HAS_GETIFADDRS
150#include <ifaddrs.h>
151#endif
152
153/* Solaris provides an extended interface SIOCGLIFCONF.  Other systems
154 * may have this as well, but the code has only been tested on Solaris
155 * so far, so we only enable it there.  Other platforms may be added as
156 * needed.
157 *
158 * Test for Solaris commented out  --  TSI @ UQV  2003.06.13
159 */
160#ifdef SIOCGLIFCONF
161/* #if defined(sun) */
162#define USE_SIOCGLIFCONF
163/* #endif */
164#endif
165
166#endif /* WIN32 */
167
168#ifndef PATH_MAX
169#include <sys/param.h>
170#ifndef PATH_MAX
171#ifdef MAXPATHLEN
172#define PATH_MAX MAXPATHLEN
173#else
174#define PATH_MAX 1024
175#endif
176#endif
177#endif
178
179
180#define X_INCLUDE_NETDB_H
181#include <X11/Xos_r.h>
182
183#include "dixstruct.h"
184#include "osdep.h"
185
186#include "xace.h"
187
188#ifndef PATH_MAX
189#ifdef MAXPATHLEN
190#define PATH_MAX MAXPATHLEN
191#else
192#define PATH_MAX 1024
193#endif
194#endif
195
196Bool defeatAccessControl = FALSE;
197
198#define acmp(a1, a2, len) memcmp((char *)(a1), (char *)(a2), len)
199#define acopy(a1, a2, len) memmove((char *)(a2), (char *)(a1), len)
200#define addrEqual(fam, address, length, host) \
201			 ((fam) == (host)->family &&\
202			  (length) == (host)->len &&\
203			  !acmp (address, (host)->addr, length))
204
205static int ConvertAddr(struct sockaddr * /*saddr*/,
206		       int * /*len*/,
207		       pointer * /*addr*/);
208
209static int CheckAddr(int /*family*/,
210		     const void * /*pAddr*/,
211		     unsigned /*length*/);
212
213static Bool NewHost(int /*family*/,
214		    const void  * /*addr*/,
215		    int /*len*/,
216		    int /* addingLocalHosts */);
217
218/* XFree86 bug #156: To keep track of which hosts were explicitly requested in
219   /etc/X<display>.hosts, we've added a requested field to the HOST struct,
220   and a LocalHostRequested variable.  These default to FALSE, but are set
221   to TRUE in ResetHosts when reading in /etc/X<display>.hosts.  They are
222   checked in DisableLocalHost(), which is called to disable the default
223   local host entries when stronger authentication is turned on. */
224
225typedef struct _host {
226	short		family;
227	short		len;
228	unsigned char	*addr;
229	struct _host *next;
230	int		requested;
231} HOST;
232
233#define MakeHost(h,l)	(h)=malloc(sizeof *(h)+(l));\
234			if (h) { \
235			   (h)->addr=(unsigned char *) ((h) + 1);\
236			   (h)->requested = FALSE; \
237			}
238#define FreeHost(h)	free(h)
239static HOST *selfhosts = NULL;
240static HOST *validhosts = NULL;
241static int AccessEnabled = DEFAULT_ACCESS_CONTROL;
242static int LocalHostEnabled = FALSE;
243static int LocalHostRequested = FALSE;
244static int UsingXdmcp = FALSE;
245
246/* FamilyServerInterpreted implementation */
247static Bool siAddrMatch(int family, pointer addr, int len, HOST *host,
248	ClientPtr client);
249static int  siCheckAddr(const char *addrString, int length);
250static void siTypesInitialize(void);
251
252/*
253 * called when authorization is not enabled to add the
254 * local host to the access list
255 */
256
257void
258EnableLocalHost (void)
259{
260    if (!UsingXdmcp)
261    {
262	LocalHostEnabled = TRUE;
263	AddLocalHosts ();
264    }
265}
266
267/*
268 * called when authorization is enabled to keep us secure
269 */
270void
271DisableLocalHost (void)
272{
273    HOST *self;
274
275    if (!LocalHostRequested)		/* Fix for XFree86 bug #156 */
276	LocalHostEnabled = FALSE;
277    for (self = selfhosts; self; self = self->next) {
278      if (!self->requested)		/* Fix for XFree86 bug #156 */
279	(void) RemoveHost ((ClientPtr)NULL, self->family, self->len, (pointer)self->addr);
280    }
281}
282
283/*
284 * called at init time when XDMCP will be used; xdmcp always
285 * adds local hosts manually when needed
286 */
287
288void
289AccessUsingXdmcp (void)
290{
291    UsingXdmcp = TRUE;
292    LocalHostEnabled = FALSE;
293}
294
295
296#if  defined(SVR4) && !defined(sun)  && defined(SIOCGIFCONF) && !defined(USE_SIOCGLIFCONF)
297
298/* Deal with different SIOCGIFCONF ioctl semantics on these OSs */
299
300static int
301ifioctl (int fd, int cmd, char *arg)
302{
303    struct strioctl ioc;
304    int ret;
305
306    memset((char *) &ioc, 0, sizeof(ioc));
307    ioc.ic_cmd = cmd;
308    ioc.ic_timout = 0;
309    if (cmd == SIOCGIFCONF)
310    {
311	ioc.ic_len = ((struct ifconf *) arg)->ifc_len;
312	ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf;
313    }
314    else
315    {
316	ioc.ic_len = sizeof(struct ifreq);
317	ioc.ic_dp = arg;
318    }
319    ret = ioctl(fd, I_STR, (char *) &ioc);
320    if (ret >= 0 && cmd == SIOCGIFCONF)
321#ifdef SVR4
322	((struct ifconf *) arg)->ifc_len = ioc.ic_len;
323#endif
324    return ret;
325}
326#else
327#define ifioctl ioctl
328#endif
329
330/*
331 * DefineSelf (fd):
332 *
333 * Define this host for access control.  Find all the hosts the OS knows about
334 * for this fd and add them to the selfhosts list.
335 */
336
337#if !defined(SIOCGIFCONF)
338void
339DefineSelf (int fd)
340{
341#if !defined(TCPCONN) && !defined(STREAMSCONN) && !defined(UNIXCONN)
342    return;
343#else
344    register int n;
345    int	len;
346    caddr_t	addr;
347    int		family;
348    register HOST	*host;
349
350#ifndef WIN32
351    struct utsname name;
352#else
353    struct {
354        char  nodename[512];
355    } name;
356#endif
357
358    register struct hostent  *hp;
359
360    union {
361	struct  sockaddr   sa;
362	struct  sockaddr_in  in;
363#if defined(IPv6) && defined(AF_INET6)
364	struct  sockaddr_in6  in6;
365#endif
366    } saddr;
367
368    struct	sockaddr_in	*inetaddr;
369    struct	sockaddr_in6	*inet6addr;
370    struct sockaddr_in broad_addr;
371#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
372    _Xgethostbynameparams hparams;
373#endif
374
375    /* Why not use gethostname()?  Well, at least on my system, I've had to
376     * make an ugly kernel patch to get a name longer than 8 characters, and
377     * uname() lets me access to the whole string (it smashes release, you
378     * see), whereas gethostname() kindly truncates it for me.
379     */
380#ifndef WIN32
381    uname(&name);
382#else
383    gethostname(name.nodename, sizeof(name.nodename));
384#endif
385
386    hp = _XGethostbyname(name.nodename, hparams);
387    if (hp != NULL)
388    {
389	saddr.sa.sa_family = hp->h_addrtype;
390	switch (hp->h_addrtype) {
391	case AF_INET:
392	    inetaddr = (struct sockaddr_in *) (&(saddr.sa));
393	    acopy ( hp->h_addr, &(inetaddr->sin_addr), hp->h_length);
394	    len = sizeof(saddr.sa);
395	    break;
396#if defined(IPv6) && defined(AF_INET6)
397	case AF_INET6:
398	    inet6addr = (struct sockaddr_in6 *) (&(saddr.sa));
399	    acopy ( hp->h_addr, &(inet6addr->sin6_addr), hp->h_length);
400	    len = sizeof(saddr.in6);
401	    break;
402#endif
403	default:
404	    goto DefineLocalHost;
405	}
406	family = ConvertAddr ( &(saddr.sa), &len, (pointer *)&addr);
407	if ( family != -1 && family != FamilyLocal )
408	{
409	    for (host = selfhosts;
410		 host && !addrEqual (family, addr, len, host);
411		 host = host->next) ;
412	    if (!host)
413	    {
414		/* add this host to the host list.	*/
415		MakeHost(host,len)
416		if (host)
417		{
418		    host->family = family;
419		    host->len = len;
420		    acopy ( addr, host->addr, len);
421		    host->next = selfhosts;
422		    selfhosts = host;
423		}
424#ifdef XDMCP
425		/*
426		 *  If this is an Internet Address, but not the localhost
427		 *  address (127.0.0.1), nor the bogus address (0.0.0.0),
428		 *  register it.
429		 */
430		if (family == FamilyInternet &&
431		    !(len == 4 &&
432		      ((addr[0] == 127) ||
433		       (addr[0] == 0 && addr[1] == 0 &&
434			addr[2] == 0 && addr[3] == 0)))
435		      )
436		{
437		    XdmcpRegisterConnection (family, (char *)addr, len);
438		    broad_addr = *inetaddr;
439		    ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
440			htonl (INADDR_BROADCAST);
441		    XdmcpRegisterBroadcastAddress ((struct sockaddr_in *)
442						   &broad_addr);
443		}
444#if defined(IPv6) && defined(AF_INET6)
445		else if (family == FamilyInternet6 &&
446		  !(IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr)))
447		{
448		    XdmcpRegisterConnection (family, (char *)addr, len);
449		}
450#endif
451
452#endif /* XDMCP */
453	    }
454	}
455    }
456    /*
457     * now add a host of family FamilyLocalHost...
458     */
459DefineLocalHost:
460    for (host = selfhosts;
461	 host && !addrEqual(FamilyLocalHost, "", 0, host);
462	 host = host->next);
463    if (!host)
464    {
465	MakeHost(host, 0);
466	if (host)
467	{
468	    host->family = FamilyLocalHost;
469	    host->len = 0;
470	    acopy("", host->addr, 0);
471	    host->next = selfhosts;
472	    selfhosts = host;
473	}
474    }
475#endif /* !TCPCONN && !STREAMSCONN && !UNIXCONN */
476}
477
478#else
479
480#ifdef USE_SIOCGLIFCONF
481#define ifr_type    struct lifreq
482#else
483#define ifr_type    struct ifreq
484#endif
485
486#ifdef VARIABLE_IFREQ
487#define ifr_size(p) (sizeof (struct ifreq) + \
488		     (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
489		      p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
490#define ifraddr_size(a) (a.sa_len)
491#else
492#define ifr_size(p) (sizeof (ifr_type))
493#define ifraddr_size(a) (sizeof (a))
494#endif
495
496#if defined(IPv6) && defined(AF_INET6)
497#include <arpa/inet.h>
498#endif
499
500#if defined(IPv6) && defined(AF_INET6)
501static void
502in6_fillscopeid(struct sockaddr_in6 *sin6)
503{
504#if defined(__KAME__)
505	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
506		sin6->sin6_scope_id =
507			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
508		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
509	}
510#endif
511}
512#endif
513
514void
515DefineSelf (int fd)
516{
517#ifndef HAS_GETIFADDRS
518    char 		*cp, *cplim;
519# ifdef USE_SIOCGLIFCONF
520    struct sockaddr_storage buf[16];
521    struct lifconf	ifc;
522    register struct lifreq *ifr;
523#  ifdef SIOCGLIFNUM
524    struct lifnum	ifn;
525#  endif
526# else /* !USE_SIOCGLIFCONF */
527    char		buf[2048];
528    struct ifconf	ifc;
529    register struct ifreq *ifr;
530# endif
531    void *		bufptr = buf;
532#else /* HAS_GETIFADDRS */
533    struct ifaddrs *	ifap, *ifr;
534#endif
535    int 		len;
536    unsigned char *	addr;
537    int 		family;
538    register HOST 	*host;
539
540#ifndef HAS_GETIFADDRS
541
542    len = sizeof(buf);
543
544#ifdef USE_SIOCGLIFCONF
545
546#ifdef SIOCGLIFNUM
547    ifn.lifn_family = AF_UNSPEC;
548    ifn.lifn_flags = 0;
549    if (ioctl (fd, SIOCGLIFNUM, (char *) &ifn) < 0)
550        Error ("Getting interface count");
551    if (len < (ifn.lifn_count * sizeof(struct lifreq))) {
552	len = ifn.lifn_count * sizeof(struct lifreq);
553	bufptr = malloc(len);
554    }
555#endif
556
557    ifc.lifc_family = AF_UNSPEC;
558    ifc.lifc_flags = 0;
559    ifc.lifc_len = len;
560    ifc.lifc_buf = bufptr;
561
562#define IFC_IOCTL_REQ SIOCGLIFCONF
563#define IFC_IFC_REQ ifc.lifc_req
564#define IFC_IFC_LEN ifc.lifc_len
565#define IFR_IFR_ADDR ifr->lifr_addr
566#define IFR_IFR_NAME ifr->lifr_name
567
568#else /* Use SIOCGIFCONF */
569    ifc.ifc_len = len;
570    ifc.ifc_buf = bufptr;
571
572#define IFC_IOCTL_REQ SIOCGIFCONF
573#define IFC_IFC_REQ ifc.ifc_req
574#define IFC_IFC_LEN ifc.ifc_len
575#define IFR_IFR_ADDR ifr->ifr_addr
576#define IFR_IFR_NAME ifr->ifr_name
577#endif
578
579    if (ifioctl (fd, IFC_IOCTL_REQ, (pointer) &ifc) < 0)
580        Error ("Getting interface configuration (4)");
581
582    cplim = (char *) IFC_IFC_REQ + IFC_IFC_LEN;
583
584    for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size (ifr))
585    {
586	ifr = (ifr_type *) cp;
587	len = ifraddr_size (IFR_IFR_ADDR);
588	family = ConvertAddr ((struct sockaddr *) &IFR_IFR_ADDR,
589	  			&len, (pointer *)&addr);
590        if (family == -1 || family == FamilyLocal)
591	    continue;
592#if defined(IPv6) && defined(AF_INET6)
593	if (family == FamilyInternet6)
594	    in6_fillscopeid((struct sockaddr_in6 *)&IFR_IFR_ADDR);
595#endif
596        for (host = selfhosts;
597 	     host && !addrEqual (family, addr, len, host);
598	     host = host->next)
599	    ;
600        if (host)
601	    continue;
602	MakeHost(host,len)
603	if (host)
604	{
605	    host->family = family;
606	    host->len = len;
607	    acopy(addr, host->addr, len);
608	    host->next = selfhosts;
609	    selfhosts = host;
610	}
611#ifdef XDMCP
612	{
613#ifdef USE_SIOCGLIFCONF
614	    struct sockaddr_storage broad_addr;
615#else
616	    struct sockaddr broad_addr;
617#endif
618
619	    /*
620	     * If this isn't an Internet Address, don't register it.
621	     */
622	    if (family != FamilyInternet
623#if defined(IPv6) && defined(AF_INET6)
624	      && family != FamilyInternet6
625#endif
626		)
627		continue;
628
629	    /*
630 	     * ignore 'localhost' entries as they're not useful
631	     * on the other end of the wire
632	     */
633	    if (family == FamilyInternet &&
634		addr[0] == 127 && addr[1] == 0 &&
635		addr[2] == 0 && addr[3] == 1)
636		continue;
637#if defined(IPv6) && defined(AF_INET6)
638	    else if (family == FamilyInternet6 &&
639	      IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr))
640		continue;
641#endif
642
643	    /*
644	     * Ignore '0.0.0.0' entries as they are
645	     * returned by some OSes for unconfigured NICs but they are
646	     * not useful on the other end of the wire.
647	     */
648	    if (len == 4 &&
649		addr[0] == 0 && addr[1] == 0 &&
650		addr[2] == 0 && addr[3] == 0)
651		continue;
652
653	    XdmcpRegisterConnection (family, (char *)addr, len);
654
655#if defined(IPv6) && defined(AF_INET6)
656	    /* IPv6 doesn't support broadcasting, so we drop out here */
657	    if (family == FamilyInternet6)
658		continue;
659#endif
660
661	    broad_addr = IFR_IFR_ADDR;
662
663	    ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
664		htonl (INADDR_BROADCAST);
665#if defined(USE_SIOCGLIFCONF) && defined(SIOCGLIFBRDADDR)
666	    {
667	    	struct lifreq    broad_req;
668
669	    	broad_req = *ifr;
670		if (ioctl (fd, SIOCGLIFFLAGS, (char *) &broad_req) != -1 &&
671		    (broad_req.lifr_flags & IFF_BROADCAST) &&
672		    (broad_req.lifr_flags & IFF_UP)
673		    )
674		{
675		    broad_req = *ifr;
676		    if (ioctl (fd, SIOCGLIFBRDADDR, &broad_req) != -1)
677			broad_addr = broad_req.lifr_broadaddr;
678		    else
679			continue;
680		}
681		else
682		    continue;
683	    }
684
685#elif defined(SIOCGIFBRDADDR)
686	    {
687	    	struct ifreq    broad_req;
688
689	    	broad_req = *ifr;
690		if (ifioctl (fd, SIOCGIFFLAGS, (pointer) &broad_req) != -1 &&
691		    (broad_req.ifr_flags & IFF_BROADCAST) &&
692		    (broad_req.ifr_flags & IFF_UP)
693		    )
694		{
695		    broad_req = *ifr;
696		    if (ifioctl (fd, SIOCGIFBRDADDR, (pointer) &broad_req) != -1)
697			broad_addr = broad_req.ifr_addr;
698		    else
699			continue;
700		}
701		else
702		    continue;
703	    }
704#endif /* SIOCGIFBRDADDR */
705	    XdmcpRegisterBroadcastAddress ((struct sockaddr_in *) &broad_addr);
706	}
707#endif /* XDMCP */
708    }
709    if (bufptr != buf)
710        free(bufptr);
711#else /* HAS_GETIFADDRS */
712    if (getifaddrs(&ifap) < 0) {
713	ErrorF("Warning: getifaddrs returns %s\n", strerror(errno));
714	return;
715    }
716    for (ifr = ifap; ifr != NULL; ifr = ifr->ifa_next) {
717        if (!ifr->ifa_addr)
718            continue;
719	len = sizeof(*(ifr->ifa_addr));
720	family = ConvertAddr((struct sockaddr *) ifr->ifa_addr, &len,
721			     (pointer *)&addr);
722	if (family == -1 || family == FamilyLocal)
723	    continue;
724#if defined(IPv6) && defined(AF_INET6)
725	if (family == FamilyInternet6)
726	    in6_fillscopeid((struct sockaddr_in6 *)ifr->ifa_addr);
727#endif
728
729	for (host = selfhosts;
730	     host != NULL && !addrEqual(family, addr, len, host);
731	     host = host->next)
732	    ;
733	if (host != NULL)
734	    continue;
735	MakeHost(host, len);
736	if (host != NULL) {
737	    host->family = family;
738	    host->len = len;
739	    acopy(addr, host->addr, len);
740	    host->next = selfhosts;
741	    selfhosts = host;
742	}
743#ifdef XDMCP
744	{
745	    /*
746	     * If this isn't an Internet Address, don't register it.
747	     */
748	    if (family != FamilyInternet
749#if defined(IPv6) && defined(AF_INET6)
750		&& family != FamilyInternet6
751#endif
752	    )
753		continue;
754
755	    /*
756	     * ignore 'localhost' entries as they're not useful
757	     * on the other end of the wire
758	     */
759	    if (ifr->ifa_flags & IFF_LOOPBACK)
760		    continue;
761
762	    if (family == FamilyInternet &&
763		addr[0] == 127 && addr[1] == 0 &&
764		addr[2] == 0 && addr[3] == 1)
765		continue;
766
767	    /*
768	     * Ignore '0.0.0.0' entries as they are
769	     * returned by some OSes for unconfigured NICs but they are
770	     * not useful on the other end of the wire.
771	     */
772	    if (len == 4 &&
773		addr[0] == 0 && addr[1] == 0 &&
774		addr[2] == 0 && addr[3] == 0)
775		continue;
776#if defined(IPv6) && defined(AF_INET6)
777	    else if (family == FamilyInternet6 &&
778	      IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr))
779		continue;
780#endif
781	    XdmcpRegisterConnection(family, (char *)addr, len);
782#if defined(IPv6) && defined(AF_INET6)
783	    if (family == FamilyInternet6)
784		/* IPv6 doesn't support broadcasting, so we drop out here */
785		continue;
786#endif
787	    if ((ifr->ifa_flags & IFF_BROADCAST) &&
788		(ifr->ifa_flags & IFF_UP) &&
789                ifr->ifa_broadaddr)
790		XdmcpRegisterBroadcastAddress(
791		    (struct sockaddr_in *) ifr->ifa_broadaddr);
792	    else
793		continue;
794	}
795#endif /* XDMCP */
796
797    } /* for */
798    freeifaddrs(ifap);
799#endif /* HAS_GETIFADDRS */
800
801    /*
802     * add something of FamilyLocalHost
803     */
804    for (host = selfhosts;
805	 host && !addrEqual(FamilyLocalHost, "", 0, host);
806	 host = host->next);
807    if (!host)
808    {
809	MakeHost(host, 0);
810	if (host)
811	{
812	    host->family = FamilyLocalHost;
813	    host->len = 0;
814	    acopy("", host->addr, 0);
815	    host->next = selfhosts;
816	    selfhosts = host;
817	}
818    }
819}
820#endif /* hpux && !HAS_IFREQ */
821
822#ifdef XDMCP
823void
824AugmentSelf(pointer from, int len)
825{
826    int family;
827    pointer addr;
828    register HOST *host;
829
830    family = ConvertAddr(from, &len, (pointer *)&addr);
831    if (family == -1 || family == FamilyLocal)
832	return;
833    for (host = selfhosts; host; host = host->next)
834    {
835	if (addrEqual(family, addr, len, host))
836	    return;
837    }
838    MakeHost(host,len)
839    if (!host)
840	return;
841    host->family = family;
842    host->len = len;
843    acopy(addr, host->addr, len);
844    host->next = selfhosts;
845    selfhosts = host;
846}
847#endif
848
849void
850AddLocalHosts (void)
851{
852    HOST    *self;
853
854    for (self = selfhosts; self; self = self->next)
855	    /* Fix for XFree86 bug #156: pass addingLocal = TRUE to
856	     * NewHost to tell that we are adding the default local
857	     * host entries and not to flag the entries as being
858	     * explicitely requested */
859	(void) NewHost (self->family, self->addr, self->len, TRUE);
860}
861
862/* Reset access control list to initial hosts */
863void
864ResetHosts (char *display)
865{
866    register HOST	*host;
867    char                lhostname[120], ohostname[120];
868    char 		*hostname = ohostname;
869    char		fname[PATH_MAX + 1];
870    int			fnamelen;
871    FILE		*fd;
872    char		*ptr;
873    int                 i, hostlen;
874#if (defined(TCPCONN) || defined(STREAMSCONN) ) && \
875     (!defined(IPv6) || !defined(AF_INET6))
876    union {
877        struct sockaddr	sa;
878#if defined(TCPCONN) || defined(STREAMSCONN)
879	struct sockaddr_in in;
880#endif /* TCPCONN || STREAMSCONN */
881    }			saddr;
882#endif
883    int			family = 0;
884    pointer		addr;
885    int 		len;
886
887    siTypesInitialize();
888    AccessEnabled = defeatAccessControl ? FALSE : DEFAULT_ACCESS_CONTROL;
889    LocalHostEnabled = FALSE;
890    while ((host = validhosts) != 0)
891    {
892        validhosts = host->next;
893        FreeHost (host);
894    }
895
896#if defined WIN32 && defined __MINGW32__
897#define ETC_HOST_PREFIX "X"
898#else
899#define ETC_HOST_PREFIX "/etc/X"
900#endif
901#define ETC_HOST_SUFFIX ".hosts"
902    fnamelen = strlen(ETC_HOST_PREFIX) + strlen(ETC_HOST_SUFFIX) +
903		strlen(display) + 1;
904    if (fnamelen > sizeof(fname))
905	FatalError("Display name `%s' is too long\n", display);
906    snprintf(fname, sizeof(fname), ETC_HOST_PREFIX "%s" ETC_HOST_SUFFIX,
907	     display);
908
909    if ((fd = fopen (fname, "r")) != 0)
910    {
911        while (fgets (ohostname, sizeof (ohostname), fd))
912	{
913	family = FamilyWild;
914	if (*ohostname == '#')
915	    continue;
916    	if ((ptr = strchr(ohostname, '\n')) != 0)
917    	    *ptr = 0;
918        hostlen = strlen(ohostname) + 1;
919        for (i = 0; i < hostlen; i++)
920	    lhostname[i] = tolower(ohostname[i]);
921	hostname = ohostname;
922	if (!strncmp("local:", lhostname, 6))
923	{
924	    family = FamilyLocalHost;
925	    NewHost(family, "", 0, FALSE);
926	    LocalHostRequested = TRUE;	/* Fix for XFree86 bug #156 */
927	}
928#if defined(TCPCONN) || defined(STREAMSCONN)
929	else if (!strncmp("inet:", lhostname, 5))
930	{
931	    family = FamilyInternet;
932	    hostname = ohostname + 5;
933	}
934#if defined(IPv6) && defined(AF_INET6)
935	else if (!strncmp("inet6:", lhostname, 6))
936	{
937	    family = FamilyInternet6;
938	    hostname = ohostname + 6;
939	}
940#endif
941#endif
942#ifdef SECURE_RPC
943	else if (!strncmp("nis:", lhostname, 4))
944	{
945	    family = FamilyNetname;
946	    hostname = ohostname + 4;
947	}
948#endif
949	else if (!strncmp("si:", lhostname, 3))
950	{
951	    family = FamilyServerInterpreted;
952	    hostname = ohostname + 3;
953	    hostlen -= 3;
954	}
955
956
957	if (family == FamilyServerInterpreted)
958	{
959	    len = siCheckAddr(hostname, hostlen);
960	    if (len >= 0) {
961		NewHost(family, hostname, len, FALSE);
962	    }
963	}
964	else
965#ifdef SECURE_RPC
966	if ((family == FamilyNetname) || (strchr(hostname, '@')))
967	{
968	    SecureRPCInit ();
969	    (void) NewHost (FamilyNetname, hostname, strlen (hostname), FALSE);
970	}
971	else
972#endif /* SECURE_RPC */
973#if defined(TCPCONN) || defined(STREAMSCONN)
974	{
975#if defined(IPv6) && defined(AF_INET6)
976	    if ( (family == FamilyInternet) || (family == FamilyInternet6) ||
977		 (family == FamilyWild) )
978            {
979		struct addrinfo *addresses;
980		struct addrinfo *a;
981		int f;
982
983		if (getaddrinfo(hostname, NULL, NULL, &addresses) == 0) {
984		    for (a = addresses ; a != NULL ; a = a->ai_next) {
985			len = a->ai_addrlen;
986			f = ConvertAddr(a->ai_addr,&len,(pointer *)&addr);
987			if ( (family == f) ||
988			     ((family == FamilyWild) && (f != -1)) ) {
989			    NewHost(f, addr, len, FALSE);
990			}
991		    }
992		    freeaddrinfo(addresses);
993		}
994	    }
995#else
996#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
997	    _Xgethostbynameparams hparams;
998#endif
999	    register struct hostent *hp;
1000
1001    	    /* host name */
1002    	    if ((family == FamilyInternet &&
1003		 ((hp = _XGethostbyname(hostname, hparams)) != 0)) ||
1004		((hp = _XGethostbyname(hostname, hparams)) != 0))
1005	    {
1006    		saddr.sa.sa_family = hp->h_addrtype;
1007		len = sizeof(saddr.sa);
1008    		if ((family = ConvertAddr (&saddr.sa, &len, (pointer *)&addr)) != -1)
1009		{
1010#ifdef h_addr				/* new 4.3bsd version of gethostent */
1011		    char **list;
1012
1013		    /* iterate over the addresses */
1014		    for (list = hp->h_addr_list; *list; list++)
1015			(void) NewHost (family, (pointer)*list, len, FALSE);
1016#else
1017    		    (void) NewHost (family, (pointer)hp->h_addr, len, FALSE);
1018#endif
1019		}
1020    	    }
1021#endif /* IPv6 */
1022        }
1023#endif /* TCPCONN || STREAMSCONN */
1024	family = FamilyWild;
1025        }
1026        fclose (fd);
1027    }
1028}
1029
1030/* Is client on the local host */
1031Bool
1032ComputeLocalClient(ClientPtr client)
1033{
1034    int    		alen, family, notused;
1035    Xtransaddr		*from = NULL;
1036    pointer		addr;
1037    register HOST	*host;
1038    OsCommPtr           oc = (OsCommPtr) client->osPrivate;
1039
1040    if (!oc->trans_conn)
1041        return FALSE;
1042
1043    if (!_XSERVTransGetPeerAddr (oc->trans_conn, &notused, &alen, &from))
1044    {
1045	family = ConvertAddr ((struct sockaddr *) from,
1046	    &alen, (pointer *)&addr);
1047	if (family == -1)
1048	{
1049	    free(from);
1050	    return FALSE;
1051	}
1052	if (family == FamilyLocal)
1053	{
1054	    free(from);
1055	    return TRUE;
1056	}
1057	for (host = selfhosts; host; host = host->next)
1058	{
1059	    if (addrEqual (family, addr, alen, host)) {
1060		free(from);
1061		return TRUE;
1062	    }
1063	}
1064	free(from);
1065    }
1066    return FALSE;
1067}
1068
1069Bool LocalClient(ClientPtr client)
1070{
1071    if (!client->osPrivate)
1072        return FALSE;
1073    return ((OsCommPtr)client->osPrivate)->local_client;
1074}
1075
1076/*
1077 * Return the uid and gid of a connected local client
1078 *
1079 * Used by XShm to test access rights to shared memory segments
1080 */
1081int
1082LocalClientCred(ClientPtr client, int *pUid, int *pGid)
1083{
1084    LocalClientCredRec *lcc;
1085    int ret = GetLocalClientCreds(client, &lcc);
1086
1087    if (ret == 0) {
1088#ifdef HAVE_GETZONEID /* only local if in the same zone */
1089	if ((lcc->fieldsSet & LCC_ZID_SET) && (lcc->zoneid != getzoneid())) {
1090	    FreeLocalClientCreds(lcc);
1091	    return -1;
1092	}
1093#endif
1094	if ((lcc->fieldsSet & LCC_UID_SET) && (pUid != NULL))
1095	    *pUid = lcc->euid;
1096	if ((lcc->fieldsSet & LCC_GID_SET) && (pGid != NULL))
1097	    *pGid = lcc->egid;
1098	FreeLocalClientCreds(lcc);
1099    }
1100    return ret;
1101}
1102
1103/*
1104 * Return the uid and all gids of a connected local client
1105 * Allocates a LocalClientCredRec - caller must call FreeLocalClientCreds
1106 *
1107 * Used by localuser & localgroup ServerInterpreted access control forms below
1108 * Used by AuthAudit to log who local connections came from
1109 */
1110int
1111GetLocalClientCreds(ClientPtr client, LocalClientCredRec **lccp)
1112{
1113#if defined(HAS_GETPEEREID) || defined(HAS_GETPEERUCRED) || defined(SO_PEERCRED)
1114    int fd;
1115    XtransConnInfo ci;
1116    LocalClientCredRec *lcc;
1117#ifdef HAS_GETPEEREID
1118    uid_t uid;
1119    gid_t gid;
1120#elif defined(HAS_GETPEERUCRED)
1121    ucred_t *peercred = NULL;
1122    const gid_t *gids;
1123#elif defined(SO_PEERCRED)
1124    struct ucred peercred;
1125    socklen_t so_len = sizeof(peercred);
1126#endif
1127
1128    if (client == NULL)
1129	return -1;
1130    ci = ((OsCommPtr)client->osPrivate)->trans_conn;
1131#if !(defined(sun) && defined(HAS_GETPEERUCRED))
1132    /* Most implementations can only determine peer credentials for Unix
1133     * domain sockets - Solaris getpeerucred can work with a bit more, so
1134     * we just let it tell us if the connection type is supported or not
1135     */
1136    if (!_XSERVTransIsLocal(ci)) {
1137	return -1;
1138    }
1139#endif
1140
1141    *lccp = calloc(1, sizeof(LocalClientCredRec));
1142    if (*lccp == NULL)
1143	return -1;
1144    lcc = *lccp;
1145
1146    fd = _XSERVTransGetConnectionNumber(ci);
1147#ifdef HAS_GETPEEREID
1148    if (getpeereid(fd, &uid, &gid) == -1) {
1149	FreeLocalClientCreds(lcc);
1150	return -1;
1151    }
1152    lcc->euid = uid;
1153    lcc->egid = gid;
1154    lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET;
1155    return 0;
1156#elif defined(HAS_GETPEERUCRED)
1157    if (getpeerucred(fd, &peercred) < 0) {
1158	FreeLocalClientCreds(lcc);
1159    	return -1;
1160    }
1161    lcc->euid = ucred_geteuid(peercred);
1162    if (lcc->euid != -1)
1163	lcc->fieldsSet |= LCC_UID_SET;
1164    lcc->egid = ucred_getegid(peercred);
1165    if (lcc->egid != -1)
1166	lcc->fieldsSet |= LCC_GID_SET;
1167    lcc->pid = ucred_getpid(peercred);
1168    if (lcc->pid != -1)
1169	lcc->fieldsSet |= LCC_PID_SET;
1170#ifdef HAVE_GETZONEID
1171    lcc->zoneid = ucred_getzoneid(peercred);
1172    if (lcc->zoneid != -1)
1173	lcc->fieldsSet |= LCC_ZID_SET;
1174#endif
1175    lcc->nSuppGids = ucred_getgroups(peercred, &gids);
1176    if (lcc->nSuppGids > 0) {
1177	lcc->pSuppGids = calloc(lcc->nSuppGids, sizeof(int));
1178	if (lcc->pSuppGids == NULL) {
1179	    lcc->nSuppGids = 0;
1180	} else {
1181	    int i;
1182	    for (i = 0 ; i < lcc->nSuppGids; i++) {
1183		(lcc->pSuppGids)[i] = (int) gids[i];
1184	    }
1185	}
1186    } else {
1187	lcc->nSuppGids = 0;
1188    }
1189    ucred_free(peercred);
1190    return 0;
1191#elif defined(SO_PEERCRED)
1192    if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) {
1193	FreeLocalClientCreds(lcc);
1194	return -1;
1195    }
1196    lcc->euid = peercred.uid;
1197    lcc->egid = peercred.gid;
1198    lcc->pid = peercred.pid;
1199    lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET | LCC_PID_SET;
1200    return 0;
1201#endif
1202#else
1203    /* No system call available to get the credentials of the peer */
1204#define NO_LOCAL_CLIENT_CRED
1205    return -1;
1206#endif
1207}
1208
1209void
1210FreeLocalClientCreds(LocalClientCredRec *lcc)
1211{
1212    if (lcc != NULL) {
1213	if (lcc->nSuppGids > 0) {
1214	    free(lcc->pSuppGids);
1215	}
1216	free(lcc);
1217    }
1218}
1219
1220static int
1221AuthorizedClient(ClientPtr client)
1222{
1223    int rc;
1224
1225    if (!client || defeatAccessControl)
1226	return Success;
1227
1228    /* untrusted clients can't change host access */
1229    rc = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess);
1230    if (rc != Success)
1231	return rc;
1232
1233    return LocalClient(client) ? Success : BadAccess;
1234}
1235
1236/* Add a host to the access control list.  This is the external interface
1237 * called from the dispatcher */
1238
1239int
1240AddHost (ClientPtr	client,
1241	 int            family,
1242	 unsigned       length,        /* of bytes in pAddr */
1243	 const void *   pAddr)
1244{
1245    int rc, len;
1246
1247    rc = AuthorizedClient(client);
1248    if (rc != Success)
1249	return rc;
1250    switch (family) {
1251    case FamilyLocalHost:
1252	len = length;
1253	LocalHostEnabled = TRUE;
1254	break;
1255#ifdef SECURE_RPC
1256    case FamilyNetname:
1257	len = length;
1258	SecureRPCInit ();
1259	break;
1260#endif
1261    case FamilyInternet:
1262#if defined(IPv6) && defined(AF_INET6)
1263    case FamilyInternet6:
1264#endif
1265    case FamilyDECnet:
1266    case FamilyChaos:
1267    case FamilyServerInterpreted:
1268	if ((len = CheckAddr (family, pAddr, length)) < 0)
1269	{
1270	    client->errorValue = length;
1271	    return BadValue;
1272	}
1273	break;
1274    case FamilyLocal:
1275    default:
1276	client->errorValue = family;
1277	return BadValue;
1278    }
1279    if (NewHost (family, pAddr, len, FALSE))
1280	return Success;
1281    return BadAlloc;
1282}
1283
1284Bool
1285ForEachHostInFamily (int	    family,
1286		     Bool    (*func)(
1287			 unsigned char * /* addr */,
1288			 short           /* len */,
1289			 pointer         /* closure */),
1290		     pointer closure)
1291{
1292    HOST    *host;
1293
1294    for (host = validhosts; host; host = host->next)
1295	if (family == host->family && func (host->addr, host->len, closure))
1296	    return TRUE;
1297    return FALSE;
1298}
1299
1300/* Add a host to the access control list. This is the internal interface
1301 * called when starting or resetting the server */
1302static Bool
1303NewHost (int		family,
1304	 const void *	addr,
1305	 int		len,
1306	 int		addingLocalHosts)
1307{
1308    register HOST *host;
1309
1310    for (host = validhosts; host; host = host->next)
1311    {
1312        if (addrEqual (family, addr, len, host))
1313	    return TRUE;
1314    }
1315    if (!addingLocalHosts) {			/* Fix for XFree86 bug #156 */
1316	for (host = selfhosts; host; host = host->next) {
1317	    if (addrEqual (family, addr, len, host)) {
1318		host->requested = TRUE;
1319		break;
1320	    }
1321	}
1322    }
1323    MakeHost(host,len)
1324    if (!host)
1325	return FALSE;
1326    host->family = family;
1327    host->len = len;
1328    acopy(addr, host->addr, len);
1329    host->next = validhosts;
1330    validhosts = host;
1331    return TRUE;
1332}
1333
1334/* Remove a host from the access control list */
1335
1336int
1337RemoveHost (
1338    ClientPtr		client,
1339    int                 family,
1340    unsigned            length,        /* of bytes in pAddr */
1341    pointer             pAddr)
1342{
1343    int rc, len;
1344    register HOST	*host, **prev;
1345
1346    rc = AuthorizedClient(client);
1347    if (rc != Success)
1348	return rc;
1349    switch (family) {
1350    case FamilyLocalHost:
1351	len = length;
1352	LocalHostEnabled = FALSE;
1353	break;
1354#ifdef SECURE_RPC
1355    case FamilyNetname:
1356	len = length;
1357	break;
1358#endif
1359    case FamilyInternet:
1360#if defined(IPv6) && defined(AF_INET6)
1361    case FamilyInternet6:
1362#endif
1363    case FamilyDECnet:
1364    case FamilyChaos:
1365    case FamilyServerInterpreted:
1366    	if ((len = CheckAddr (family, pAddr, length)) < 0)
1367    	{
1368	    client->errorValue = length;
1369            return BadValue;
1370    	}
1371	break;
1372    case FamilyLocal:
1373    default:
1374	client->errorValue = family;
1375        return BadValue;
1376    }
1377    for (prev = &validhosts;
1378         (host = *prev) && (!addrEqual (family, pAddr, len, host));
1379         prev = &host->next)
1380        ;
1381    if (host)
1382    {
1383        *prev = host->next;
1384        FreeHost (host);
1385    }
1386    return Success;
1387}
1388
1389/* Get all hosts in the access control list */
1390int
1391GetHosts (
1392    pointer		*data,
1393    int			*pnHosts,
1394    int			*pLen,
1395    BOOL		*pEnabled)
1396{
1397    int			len;
1398    register int 	n = 0;
1399    register unsigned char *ptr;
1400    register HOST	*host;
1401    int			nHosts = 0;
1402
1403    *pEnabled = AccessEnabled ? EnableAccess : DisableAccess;
1404    for (host = validhosts; host; host = host->next)
1405    {
1406	nHosts++;
1407	n += pad_to_int32(host->len) + sizeof(xHostEntry);
1408        /* Could check for INT_MAX, but in reality having more than 1mb of
1409           hostnames in the access list is ridiculous */
1410        if (n >= 1048576)
1411            break;
1412    }
1413    if (n)
1414    {
1415        *data = ptr = malloc(n);
1416	if (!ptr)
1417	{
1418	    return BadAlloc;
1419	}
1420        for (host = validhosts; host; host = host->next)
1421	{
1422	    len = host->len;
1423            if ((ptr + sizeof(xHostEntry) + len) > ((unsigned char *) *data + n))
1424                break;
1425	    ((xHostEntry *)ptr)->family = host->family;
1426	    ((xHostEntry *)ptr)->length = len;
1427	    ptr += sizeof(xHostEntry);
1428	    acopy (host->addr, ptr, len);
1429	    ptr += pad_to_int32(len);
1430        }
1431    } else {
1432	*data = NULL;
1433    }
1434    *pnHosts = nHosts;
1435    *pLen = n;
1436    return Success;
1437}
1438
1439/* Check for valid address family and length, and return address length. */
1440
1441/*ARGSUSED*/
1442static int
1443CheckAddr (
1444    int			family,
1445    const void *	pAddr,
1446    unsigned		length)
1447{
1448    int	len;
1449
1450    switch (family)
1451    {
1452#if defined(TCPCONN) || defined(STREAMSCONN)
1453      case FamilyInternet:
1454	if (length == sizeof (struct in_addr))
1455	    len = length;
1456	else
1457	    len = -1;
1458        break;
1459#if defined(IPv6) && defined(AF_INET6)
1460      case FamilyInternet6:
1461	if (length == sizeof (struct in6_addr))
1462	    len = length;
1463	else
1464	    len = -1;
1465        break;
1466#endif
1467#endif
1468      case FamilyServerInterpreted:
1469	len = siCheckAddr(pAddr, length);
1470	break;
1471      default:
1472        len = -1;
1473    }
1474    return len;
1475}
1476
1477/* Check if a host is not in the access control list.
1478 * Returns 1 if host is invalid, 0 if we've found it. */
1479
1480int
1481InvalidHost (
1482    register struct sockaddr	*saddr,
1483    int				len,
1484    ClientPtr			client)
1485{
1486    int 			family;
1487    pointer			addr;
1488    register HOST 		*selfhost, *host;
1489
1490    if (!AccessEnabled)   /* just let them in */
1491        return 0;
1492    family = ConvertAddr (saddr, &len, (pointer *)&addr);
1493    if (family == -1)
1494        return 1;
1495    if (family == FamilyLocal)
1496    {
1497	if (!LocalHostEnabled)
1498 	{
1499	    /*
1500	     * check to see if any local address is enabled.  This
1501	     * implicitly enables local connections.
1502	     */
1503	    for (selfhost = selfhosts; selfhost; selfhost=selfhost->next)
1504 	    {
1505		for (host = validhosts; host; host=host->next)
1506		{
1507		    if (addrEqual (selfhost->family, selfhost->addr,
1508				   selfhost->len, host))
1509			return 0;
1510		}
1511	    }
1512	} else
1513	    return 0;
1514    }
1515    for (host = validhosts; host; host = host->next)
1516    {
1517	if (host->family == FamilyServerInterpreted) {
1518	    if (siAddrMatch (family, addr, len, host, client)) {
1519		return 0;
1520	    }
1521	} else {
1522	    if (addrEqual (family, addr, len, host))
1523		return 0;
1524	}
1525
1526    }
1527    return 1;
1528}
1529
1530static int
1531ConvertAddr (
1532    register struct sockaddr	*saddr,
1533    int				*len,
1534    pointer			*addr)
1535{
1536    if (*len == 0)
1537        return FamilyLocal;
1538    switch (saddr->sa_family)
1539    {
1540    case AF_UNSPEC:
1541#if defined(UNIXCONN) || defined(LOCALCONN)
1542    case AF_UNIX:
1543#endif
1544        return FamilyLocal;
1545#if defined(TCPCONN) || defined(STREAMSCONN)
1546    case AF_INET:
1547#ifdef WIN32
1548        if (16777343 == *(long*)&((struct sockaddr_in *) saddr)->sin_addr)
1549            return FamilyLocal;
1550#endif
1551        *len = sizeof (struct in_addr);
1552        *addr = (pointer) &(((struct sockaddr_in *) saddr)->sin_addr);
1553        return FamilyInternet;
1554#if defined(IPv6) && defined(AF_INET6)
1555    case AF_INET6:
1556    {
1557	struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) saddr;
1558	if (IN6_IS_ADDR_V4MAPPED(&(saddr6->sin6_addr))) {
1559	    *len = sizeof (struct in_addr);
1560	    *addr = (pointer) &(saddr6->sin6_addr.s6_addr[12]);
1561	    return FamilyInternet;
1562	} else {
1563	    *len = sizeof (struct in6_addr);
1564	    *addr = (pointer) &(saddr6->sin6_addr);
1565	    return FamilyInternet6;
1566	}
1567    }
1568#endif
1569#endif
1570    default:
1571        return -1;
1572    }
1573}
1574
1575int
1576ChangeAccessControl(
1577    ClientPtr client,
1578    int fEnabled)
1579{
1580    int rc = AuthorizedClient(client);
1581    if (rc != Success)
1582	return rc;
1583    AccessEnabled = fEnabled;
1584    return Success;
1585}
1586
1587/* returns FALSE if xhost + in effect, else TRUE */
1588int
1589GetAccessControl(void)
1590{
1591    return AccessEnabled;
1592}
1593
1594/*****************************************************************************
1595 * FamilyServerInterpreted host entry implementation
1596 *
1597 * Supports an extensible system of host types which the server can interpret
1598 * See the IPv6 extensions to the X11 protocol spec for the definition.
1599 *
1600 * Currently supported schemes:
1601 *
1602 * hostname	- hostname as defined in IETF RFC 2396
1603 * ipv6		- IPv6 literal address as defined in IETF RFC's 3513 and <TBD>
1604 *
1605 * See xc/doc/specs/SIAddresses for formal definitions of each type.
1606 */
1607
1608/* These definitions and the siTypeAdd function could be exported in the
1609 * future to enable loading additional host types, but that was not done for
1610 * the initial implementation.
1611 */
1612typedef Bool (*siAddrMatchFunc)(int family, pointer addr, int len,
1613  const char *siAddr, int siAddrlen, ClientPtr client, void *siTypePriv);
1614typedef int  (*siCheckAddrFunc)(const char *addrString, int length,
1615  void *siTypePriv);
1616
1617struct siType {
1618    struct siType *	next;
1619    const char *	typeName;
1620    siAddrMatchFunc	addrMatch;
1621    siCheckAddrFunc	checkAddr;
1622    void *		typePriv;	/* Private data for type routines */
1623};
1624
1625static struct siType *siTypeList;
1626
1627static int
1628siTypeAdd(const char *typeName, siAddrMatchFunc addrMatch,
1629  siCheckAddrFunc checkAddr, void *typePriv)
1630{
1631    struct siType *s, *p;
1632
1633    if ((typeName == NULL) || (addrMatch == NULL) || (checkAddr == NULL))
1634	return BadValue;
1635
1636    for (s = siTypeList, p = NULL; s != NULL ; p = s, s = s->next) {
1637	if (strcmp(typeName, s->typeName) == 0) {
1638	    s->addrMatch = addrMatch;
1639	    s->checkAddr = checkAddr;
1640	    s->typePriv = typePriv;
1641	    return Success;
1642	}
1643    }
1644
1645    s = malloc(sizeof(struct siType));
1646    if (s == NULL)
1647	return BadAlloc;
1648
1649    if (p == NULL)
1650	siTypeList = s;
1651    else
1652	p->next = s;
1653
1654    s->next = NULL;
1655    s->typeName = typeName;
1656    s->addrMatch = addrMatch;
1657    s->checkAddr = checkAddr;
1658    s->typePriv = typePriv;
1659    return Success;
1660}
1661
1662/* Checks to see if a host matches a server-interpreted host entry */
1663static Bool
1664siAddrMatch(int family, pointer addr, int len, HOST *host, ClientPtr client)
1665{
1666    Bool matches = FALSE;
1667    struct siType *s;
1668    const char *valueString;
1669    int addrlen;
1670
1671    valueString = (const char *) memchr(host->addr, '\0', host->len);
1672    if (valueString != NULL) {
1673	for (s = siTypeList; s != NULL ; s = s->next) {
1674	    if (strcmp((char *) host->addr, s->typeName) == 0) {
1675		addrlen = host->len - (strlen((char *)host->addr) + 1);
1676		matches = s->addrMatch(family, addr, len,
1677		  valueString + 1, addrlen, client, s->typePriv);
1678		break;
1679	    }
1680	}
1681#ifdef FAMILY_SI_DEBUG
1682	ErrorF(
1683	    "Xserver: siAddrMatch(): type = %s, value = %*.*s -- %s\n",
1684	      host->addr, addrlen, addrlen, valueString + 1,
1685	      (matches) ? "accepted" : "rejected");
1686#endif
1687    }
1688    return matches;
1689}
1690
1691static int
1692siCheckAddr(const char *addrString, int length)
1693{
1694    const char *valueString;
1695    int addrlen, typelen;
1696    int len = -1;
1697    struct siType *s;
1698
1699    /* Make sure there is a \0 byte inside the specified length
1700       to separate the address type from the address value. */
1701    valueString = (const char *) memchr(addrString, '\0', length);
1702    if (valueString != NULL) {
1703	/* Make sure the first string is a recognized address type,
1704	 * and the second string is a valid address of that type.
1705	 */
1706	typelen = strlen(addrString) + 1;
1707	addrlen = length - typelen;
1708
1709	for (s = siTypeList; s != NULL ; s = s->next) {
1710	    if (strcmp(addrString, s->typeName) == 0) {
1711		len = s->checkAddr(valueString + 1, addrlen, s->typePriv);
1712		if (len >= 0) {
1713		    len += typelen;
1714		}
1715		break;
1716	    }
1717	}
1718#ifdef FAMILY_SI_DEBUG
1719	{
1720	    const char *resultMsg;
1721
1722	    if (s == NULL) {
1723		resultMsg = "type not registered";
1724	    } else {
1725		if (len == -1)
1726		    resultMsg = "rejected";
1727		else
1728		    resultMsg = "accepted";
1729	    }
1730
1731	    ErrorF("Xserver: siCheckAddr(): type = %s, value = %*.*s, len = %d -- %s\n",
1732	      addrString, addrlen, addrlen, valueString + 1, len, resultMsg);
1733	}
1734#endif
1735    }
1736    return len;
1737}
1738
1739
1740/***
1741 * Hostname server-interpreted host type
1742 *
1743 * Stored as hostname string, explicitly defined to be resolved ONLY
1744 * at access check time, to allow for hosts with dynamic addresses
1745 * but static hostnames, such as found in some DHCP & mobile setups.
1746 *
1747 * Hostname must conform to IETF RFC 2396 sec. 3.2.2, which defines it as:
1748 * 	hostname     = *( domainlabel "." ) toplabel [ "." ]
1749 *	domainlabel  = alphanum | alphanum *( alphanum | "-" ) alphanum
1750 *	toplabel     = alpha | alpha *( alphanum | "-" ) alphanum
1751 */
1752
1753#ifdef NI_MAXHOST
1754# define SI_HOSTNAME_MAXLEN NI_MAXHOST
1755#else
1756# ifdef MAXHOSTNAMELEN
1757#  define SI_HOSTNAME_MAXLEN MAXHOSTNAMELEN
1758# else
1759#  define SI_HOSTNAME_MAXLEN 256
1760# endif
1761#endif
1762
1763static Bool
1764siHostnameAddrMatch(int family, pointer addr, int len,
1765  const char *siAddr, int siAddrLen, ClientPtr client, void *typePriv)
1766{
1767    Bool res = FALSE;
1768
1769/* Currently only supports checking against IPv4 & IPv6 connections, but
1770 * support for other address families, such as DECnet, could be added if
1771 * desired.
1772 */
1773#if defined(IPv6) && defined(AF_INET6)
1774    if ((family == FamilyInternet) || (family == FamilyInternet6)) {
1775	char hostname[SI_HOSTNAME_MAXLEN];
1776	struct addrinfo *addresses;
1777	struct addrinfo *a;
1778	int f, hostaddrlen;
1779	pointer hostaddr;
1780
1781	if (siAddrLen >= sizeof(hostname))
1782	    return FALSE;
1783
1784	strncpy(hostname, siAddr, siAddrLen);
1785	hostname[siAddrLen] = '\0';
1786
1787	if (getaddrinfo(hostname, NULL, NULL, &addresses) == 0) {
1788	    for (a = addresses ; a != NULL ; a = a->ai_next) {
1789		hostaddrlen = a->ai_addrlen;
1790		f = ConvertAddr(a->ai_addr,&hostaddrlen,&hostaddr);
1791		if ((f == family) && (len == hostaddrlen) &&
1792		  (acmp (addr, hostaddr, len) == 0) ) {
1793		    res = TRUE;
1794		    break;
1795		}
1796	    }
1797	    freeaddrinfo(addresses);
1798	}
1799    }
1800#else /* IPv6 not supported, use gethostbyname instead for IPv4 */
1801    if (family == FamilyInternet) {
1802	register struct hostent *hp;
1803#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1804	_Xgethostbynameparams hparams;
1805#endif
1806	char hostname[SI_HOSTNAME_MAXLEN];
1807	int f, hostaddrlen;
1808	pointer hostaddr;
1809	const char **addrlist;
1810
1811	if (siAddrLen >= sizeof(hostname))
1812	    return FALSE;
1813
1814	strncpy(hostname, siAddr, siAddrLen);
1815	hostname[siAddrLen] = '\0';
1816
1817	if ((hp = _XGethostbyname(hostname, hparams)) != NULL) {
1818#ifdef h_addr				/* new 4.3bsd version of gethostent */
1819	    /* iterate over the addresses */
1820	    for (addrlist = hp->h_addr_list; *addrlist; addrlist++)
1821#else
1822	    addrlist = &hp->h_addr;
1823#endif
1824	    {
1825		struct  sockaddr_in  sin;
1826
1827    		sin.sin_family = hp->h_addrtype;
1828		acopy ( *addrlist, &(sin.sin_addr), hp->h_length);
1829		hostaddrlen = sizeof(sin);
1830    		f = ConvertAddr ((struct sockaddr *)&sin,
1831		  &hostaddrlen, &hostaddr);
1832		if ((f == family) && (len == hostaddrlen) &&
1833		  (acmp (addr, hostaddr, len) == 0) ) {
1834		    res = TRUE;
1835		    break;
1836		}
1837    	    }
1838        }
1839    }
1840#endif
1841    return res;
1842}
1843
1844
1845static int
1846siHostnameCheckAddr(const char *valueString, int length, void *typePriv)
1847{
1848    /* Check conformance of hostname to RFC 2396 sec. 3.2.2 definition.
1849     * We do not use ctype functions here to avoid locale-specific
1850     * character sets.  Hostnames must be pure ASCII.
1851     */
1852    int len = length;
1853    int i;
1854    Bool dotAllowed = FALSE;
1855    Bool dashAllowed = FALSE;
1856
1857    if ((length <= 0) || (length >= SI_HOSTNAME_MAXLEN)) {
1858	len = -1;
1859    } else {
1860	for (i = 0; i < length; i++) {
1861	    char c = valueString[i];
1862
1863	    if (c == 0x2E) { /* '.' */
1864		if (dotAllowed == FALSE) {
1865		    len = -1;
1866		    break;
1867		} else {
1868		    dotAllowed = FALSE;
1869		    dashAllowed = FALSE;
1870		}
1871	    } else if (c == 0x2D) { /* '-' */
1872		if (dashAllowed == FALSE) {
1873		    len = -1;
1874		    break;
1875		} else {
1876		    dotAllowed = FALSE;
1877		}
1878	    } else if (((c >= 0x30) && (c <= 0x3A)) /* 0-9 */ ||
1879		       ((c >= 0x61) && (c <= 0x7A)) /* a-z */ ||
1880		       ((c >= 0x41) && (c <= 0x5A)) /* A-Z */) {
1881		dotAllowed = TRUE;
1882		dashAllowed = TRUE;
1883	    } else { /* Invalid character */
1884		len = -1;
1885		break;
1886	    }
1887	}
1888    }
1889    return len;
1890}
1891
1892#if defined(IPv6) && defined(AF_INET6)
1893/***
1894 * "ipv6" server interpreted type
1895 *
1896 * Currently supports only IPv6 literal address as specified in IETF RFC 3513
1897 *
1898 * Once draft-ietf-ipv6-scoping-arch-00.txt becomes an RFC, support will be
1899 * added for the scoped address format it specifies.
1900 */
1901
1902/* Maximum length of an IPv6 address string - increase when adding support
1903 * for scoped address qualifiers.  Includes room for trailing NUL byte.
1904 */
1905#define SI_IPv6_MAXLEN INET6_ADDRSTRLEN
1906
1907static Bool
1908siIPv6AddrMatch(int family, pointer addr, int len,
1909  const char *siAddr, int siAddrlen, ClientPtr client, void *typePriv)
1910{
1911    struct in6_addr addr6;
1912    char addrbuf[SI_IPv6_MAXLEN];
1913
1914    if ((family != FamilyInternet6) || (len != sizeof(addr6)))
1915	return FALSE;
1916
1917    memcpy(addrbuf, siAddr, siAddrlen);
1918    addrbuf[siAddrlen] = '\0';
1919
1920    if (inet_pton(AF_INET6, addrbuf, &addr6) != 1) {
1921	perror("inet_pton");
1922	return FALSE;
1923    }
1924
1925    if (memcmp(addr, &addr6, len) == 0) {
1926	return TRUE;
1927    } else {
1928	return FALSE;
1929    }
1930}
1931
1932static int
1933siIPv6CheckAddr(const char *addrString, int length, void *typePriv)
1934{
1935    int len;
1936
1937    /* Minimum length is 3 (smallest legal address is "::1") */
1938    if (length < 3) {
1939	/* Address is too short! */
1940	len = -1;
1941    } else if (length >= SI_IPv6_MAXLEN) {
1942	/* Address is too long! */
1943	len = -1;
1944    } else {
1945	/* Assume inet_pton is sufficient validation */
1946	struct in6_addr addr6;
1947	char addrbuf[SI_IPv6_MAXLEN];
1948
1949	memcpy(addrbuf, addrString, length);
1950	addrbuf[length] = '\0';
1951
1952	if (inet_pton(AF_INET6, addrbuf, &addr6) != 1) {
1953	    perror("inet_pton");
1954	    len = -1;
1955	} else {
1956	    len = length;
1957	}
1958    }
1959    return len;
1960}
1961#endif /* IPv6 */
1962
1963#if !defined(NO_LOCAL_CLIENT_CRED)
1964/***
1965 * "localuser" & "localgroup" server interpreted types
1966 *
1967 * Allows local connections from a given local user or group
1968 */
1969
1970#include <pwd.h>
1971#include <grp.h>
1972
1973#define LOCAL_USER 1
1974#define LOCAL_GROUP 2
1975
1976typedef struct {
1977    int credType;
1978} siLocalCredPrivRec, *siLocalCredPrivPtr;
1979
1980static siLocalCredPrivRec siLocalUserPriv = { LOCAL_USER };
1981static siLocalCredPrivRec siLocalGroupPriv = { LOCAL_GROUP };
1982
1983static Bool
1984siLocalCredGetId(const char *addr, int len, siLocalCredPrivPtr lcPriv, int *id)
1985{
1986    Bool parsedOK = FALSE;
1987    char *addrbuf = malloc(len + 1);
1988
1989    if (addrbuf == NULL) {
1990	return FALSE;
1991    }
1992
1993    memcpy(addrbuf, addr, len);
1994    addrbuf[len] = '\0';
1995
1996    if (addr[0] == '#') { /* numeric id */
1997	char *cp;
1998	errno = 0;
1999	*id = strtol(addrbuf + 1, &cp, 0);
2000	if ((errno == 0) && (cp != (addrbuf+1))) {
2001	    parsedOK = TRUE;
2002	}
2003    } else { /* non-numeric name */
2004	if (lcPriv->credType == LOCAL_USER) {
2005	    struct passwd *pw = getpwnam(addrbuf);
2006
2007	    if (pw != NULL) {
2008		*id = (int) pw->pw_uid;
2009		parsedOK = TRUE;
2010	    }
2011	} else { /* group */
2012	    struct group *gr = getgrnam(addrbuf);
2013
2014	    if (gr != NULL) {
2015		*id = (int) gr->gr_gid;
2016		parsedOK = TRUE;
2017	    }
2018	}
2019    }
2020
2021    free(addrbuf);
2022    return parsedOK;
2023}
2024
2025static Bool
2026siLocalCredAddrMatch(int family, pointer addr, int len,
2027  const char *siAddr, int siAddrlen, ClientPtr client, void *typePriv)
2028{
2029    int siAddrId;
2030    LocalClientCredRec *lcc;
2031    siLocalCredPrivPtr lcPriv = (siLocalCredPrivPtr) typePriv;
2032
2033    if (GetLocalClientCreds(client, &lcc) == -1) {
2034	return FALSE;
2035    }
2036
2037#ifdef HAVE_GETZONEID /* Ensure process is in the same zone */
2038    if ((lcc->fieldsSet & LCC_ZID_SET) && (lcc->zoneid != getzoneid())) {
2039	FreeLocalClientCreds(lcc);
2040	return FALSE;
2041    }
2042#endif
2043
2044    if (siLocalCredGetId(siAddr, siAddrlen, lcPriv, &siAddrId) == FALSE) {
2045	FreeLocalClientCreds(lcc);
2046	return FALSE;
2047    }
2048
2049    if (lcPriv->credType == LOCAL_USER) {
2050	if ((lcc->fieldsSet & LCC_UID_SET) && (lcc->euid == siAddrId)) {
2051	    FreeLocalClientCreds(lcc);
2052	    return TRUE;
2053	}
2054    } else {
2055	if ((lcc->fieldsSet & LCC_GID_SET) && (lcc->egid == siAddrId)) {
2056	    FreeLocalClientCreds(lcc);
2057	    return TRUE;
2058	}
2059	if (lcc->pSuppGids != NULL) {
2060	    int i;
2061
2062	    for (i = 0 ; i < lcc->nSuppGids; i++) {
2063		if (lcc->pSuppGids[i] == siAddrId) {
2064		    FreeLocalClientCreds(lcc);
2065		    return TRUE;
2066		}
2067	    }
2068	}
2069    }
2070    FreeLocalClientCreds(lcc);
2071    return FALSE;
2072}
2073
2074static int
2075siLocalCredCheckAddr(const char *addrString, int length, void *typePriv)
2076{
2077    int len = length;
2078    int id;
2079
2080    if (siLocalCredGetId(addrString, length,
2081	(siLocalCredPrivPtr)typePriv, &id) == FALSE) {
2082	len = -1;
2083    }
2084    return len;
2085}
2086#endif /* localuser */
2087
2088static void
2089siTypesInitialize(void)
2090{
2091    siTypeAdd("hostname", siHostnameAddrMatch, siHostnameCheckAddr, NULL);
2092#if defined(IPv6) && defined(AF_INET6)
2093    siTypeAdd("ipv6", siIPv6AddrMatch, siIPv6CheckAddr, NULL);
2094#endif
2095#if !defined(NO_LOCAL_CLIENT_CRED)
2096    siTypeAdd("localuser", siLocalCredAddrMatch, siLocalCredCheckAddr,
2097      &siLocalUserPriv);
2098    siTypeAdd("localgroup", siLocalCredAddrMatch, siLocalCredCheckAddr,
2099      &siLocalGroupPriv);
2100#endif
2101}
2102