1706f2543Smrg/***********************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgAll rights reserved.
6706f2543Smrg
7706f2543SmrgPermission is hereby granted, free of charge, to any person obtaining a
8706f2543Smrgcopy of this software and associated documentation files (the
9706f2543Smrg"Software"), to deal in the Software without restriction, including
10706f2543Smrgwithout limitation the rights to use, copy, modify, merge, publish,
11706f2543Smrgdistribute, and/or sell copies of the Software, and to permit persons
12706f2543Smrgto whom the Software is furnished to do so, provided that the above
13706f2543Smrgcopyright notice(s) and this permission notice appear in all copies of
14706f2543Smrgthe Software and that both the above copyright notice(s) and this
15706f2543Smrgpermission notice appear in supporting documentation.
16706f2543Smrg
17706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18706f2543SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19706f2543SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
20706f2543SmrgOF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21706f2543SmrgHOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
22706f2543SmrgINDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
23706f2543SmrgFROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
24706f2543SmrgNEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25706f2543SmrgWITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26706f2543Smrg
27706f2543SmrgExcept as contained in this notice, the name of a copyright holder
28706f2543Smrgshall not be used in advertising or otherwise to promote the sale, use
29706f2543Smrgor other dealings in this Software without prior written authorization
30706f2543Smrgof the copyright holder.
31706f2543Smrg
32706f2543SmrgX Window System is a trademark of The Open Group.
33706f2543Smrg
34706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
35706f2543Smrg
36706f2543Smrg                        All Rights Reserved
37706f2543Smrg
38706f2543SmrgPermission to use, copy, modify, and distribute this software and its
39706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
40706f2543Smrgprovided that the above copyright notice appear in all copies and that
41706f2543Smrgboth that copyright notice and this permission notice appear in
42706f2543Smrgsupporting documentation, and that the name of Digital not be
43706f2543Smrgused in advertising or publicity pertaining to distribution of the
44706f2543Smrgsoftware without specific, written prior permission.
45706f2543Smrg
46706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
52706f2543SmrgSOFTWARE.
53706f2543Smrg
54706f2543Smrg******************************************************************/
55706f2543Smrg
56706f2543Smrg/*
57706f2543Smrg * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
58706f2543Smrg *
59706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
60706f2543Smrg * copy of this software and associated documentation files (the "Software"),
61706f2543Smrg * to deal in the Software without restriction, including without limitation
62706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
63706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
64706f2543Smrg * Software is furnished to do so, subject to the following conditions:
65706f2543Smrg *
66706f2543Smrg * The above copyright notice and this permission notice (including the next
67706f2543Smrg * paragraph) shall be included in all copies or substantial portions of the
68706f2543Smrg * Software.
69706f2543Smrg *
70706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
73706f2543Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74706f2543Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
75706f2543Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
76706f2543Smrg * DEALINGS IN THE SOFTWARE.
77706f2543Smrg */
78706f2543Smrg
79706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
80706f2543Smrg#include <dix-config.h>
81706f2543Smrg#endif
82706f2543Smrg
83706f2543Smrg#ifdef WIN32
84706f2543Smrg#include <X11/Xwinsock.h>
85706f2543Smrg#endif
86706f2543Smrg
87706f2543Smrg#include <stdio.h>
88706f2543Smrg#include <stdlib.h>
89706f2543Smrg#define XSERV_t
90706f2543Smrg#define TRANS_SERVER
91706f2543Smrg#define TRANS_REOPEN
92706f2543Smrg#include <X11/Xtrans/Xtrans.h>
93706f2543Smrg#include <X11/Xauth.h>
94706f2543Smrg#include <X11/X.h>
95706f2543Smrg#include <X11/Xproto.h>
96706f2543Smrg#include "misc.h"
97706f2543Smrg#include "site.h"
98706f2543Smrg#include <errno.h>
99706f2543Smrg#include <sys/types.h>
100706f2543Smrg#ifndef WIN32
101706f2543Smrg#include <sys/socket.h>
102706f2543Smrg#include <sys/ioctl.h>
103706f2543Smrg#include <ctype.h>
104706f2543Smrg
105706f2543Smrg#if defined(TCPCONN) || defined(STREAMSCONN)
106706f2543Smrg#include <netinet/in.h>
107706f2543Smrg#endif /* TCPCONN || STREAMSCONN */
108706f2543Smrg
109706f2543Smrg#ifdef HAS_GETPEERUCRED
110706f2543Smrg# include <ucred.h>
111706f2543Smrg# ifdef sun
112706f2543Smrg#  include <zone.h>
113706f2543Smrg# endif
114706f2543Smrg#endif
115706f2543Smrg
116706f2543Smrg#if defined(SVR4) ||  (defined(SYSV) && defined(__i386__)) || defined(__GNU__)
117706f2543Smrg# include <sys/utsname.h>
118706f2543Smrg#endif
119706f2543Smrg#if defined(SYSV) &&  defined(__i386__)
120706f2543Smrg# include <sys/stream.h>
121706f2543Smrg#endif
122706f2543Smrg#ifdef __GNU__
123706f2543Smrg#undef SIOCGIFCONF
124706f2543Smrg#include <netdb.h>
125706f2543Smrg#else /*!__GNU__*/
126706f2543Smrg# include <net/if.h>
127706f2543Smrg#endif /*__GNU__ */
128706f2543Smrg
129706f2543Smrg#ifdef SVR4
130706f2543Smrg#include <sys/sockio.h>
131706f2543Smrg#include <sys/stropts.h>
132706f2543Smrg#endif
133706f2543Smrg
134706f2543Smrg#include <netdb.h>
135706f2543Smrg
136706f2543Smrg#ifdef CSRG_BASED
137706f2543Smrg#include <sys/param.h>
138706f2543Smrg#if (BSD >= 199103)
139706f2543Smrg#define VARIABLE_IFREQ
140706f2543Smrg#endif
141706f2543Smrg#endif
142706f2543Smrg
143706f2543Smrg#ifdef BSD44SOCKETS
144706f2543Smrg#ifndef VARIABLE_IFREQ
145706f2543Smrg#define VARIABLE_IFREQ
146706f2543Smrg#endif
147706f2543Smrg#endif
148706f2543Smrg
149706f2543Smrg#ifdef HAS_GETIFADDRS
150706f2543Smrg#include <ifaddrs.h>
151706f2543Smrg#endif
152706f2543Smrg
153706f2543Smrg/* Solaris provides an extended interface SIOCGLIFCONF.  Other systems
154706f2543Smrg * may have this as well, but the code has only been tested on Solaris
155706f2543Smrg * so far, so we only enable it there.  Other platforms may be added as
156706f2543Smrg * needed.
157706f2543Smrg *
158706f2543Smrg * Test for Solaris commented out  --  TSI @ UQV  2003.06.13
159706f2543Smrg */
160706f2543Smrg#ifdef SIOCGLIFCONF
161706f2543Smrg/* #if defined(sun) */
162706f2543Smrg#define USE_SIOCGLIFCONF
163706f2543Smrg/* #endif */
164706f2543Smrg#endif
165706f2543Smrg
166706f2543Smrg#endif /* WIN32 */
167706f2543Smrg
168706f2543Smrg#ifndef PATH_MAX
169706f2543Smrg#include <sys/param.h>
170706f2543Smrg#ifndef PATH_MAX
171706f2543Smrg#ifdef MAXPATHLEN
172706f2543Smrg#define PATH_MAX MAXPATHLEN
173706f2543Smrg#else
174706f2543Smrg#define PATH_MAX 1024
175706f2543Smrg#endif
176706f2543Smrg#endif
177706f2543Smrg#endif
178706f2543Smrg
179706f2543Smrg
180706f2543Smrg#define X_INCLUDE_NETDB_H
181706f2543Smrg#include <X11/Xos_r.h>
182706f2543Smrg
183706f2543Smrg#include "dixstruct.h"
184706f2543Smrg#include "osdep.h"
185706f2543Smrg
186706f2543Smrg#include "xace.h"
187706f2543Smrg
188706f2543Smrg#ifndef PATH_MAX
189706f2543Smrg#ifdef MAXPATHLEN
190706f2543Smrg#define PATH_MAX MAXPATHLEN
191706f2543Smrg#else
192706f2543Smrg#define PATH_MAX 1024
193706f2543Smrg#endif
194706f2543Smrg#endif
195706f2543Smrg
196706f2543SmrgBool defeatAccessControl = FALSE;
197706f2543Smrg
198706f2543Smrg#define acmp(a1, a2, len) memcmp((char *)(a1), (char *)(a2), len)
199706f2543Smrg#define acopy(a1, a2, len) memmove((char *)(a2), (char *)(a1), len)
200706f2543Smrg#define addrEqual(fam, address, length, host) \
201706f2543Smrg			 ((fam) == (host)->family &&\
202706f2543Smrg			  (length) == (host)->len &&\
203706f2543Smrg			  !acmp (address, (host)->addr, length))
204706f2543Smrg
205706f2543Smrgstatic int ConvertAddr(struct sockaddr * /*saddr*/,
206706f2543Smrg		       int * /*len*/,
207706f2543Smrg		       pointer * /*addr*/);
208706f2543Smrg
209706f2543Smrgstatic int CheckAddr(int /*family*/,
210706f2543Smrg		     const void * /*pAddr*/,
211706f2543Smrg		     unsigned /*length*/);
212706f2543Smrg
213706f2543Smrgstatic Bool NewHost(int /*family*/,
214706f2543Smrg		    const void  * /*addr*/,
215706f2543Smrg		    int /*len*/,
216706f2543Smrg		    int /* addingLocalHosts */);
217706f2543Smrg
218706f2543Smrg/* XFree86 bug #156: To keep track of which hosts were explicitly requested in
219706f2543Smrg   /etc/X<display>.hosts, we've added a requested field to the HOST struct,
220706f2543Smrg   and a LocalHostRequested variable.  These default to FALSE, but are set
221706f2543Smrg   to TRUE in ResetHosts when reading in /etc/X<display>.hosts.  They are
222706f2543Smrg   checked in DisableLocalHost(), which is called to disable the default
223706f2543Smrg   local host entries when stronger authentication is turned on. */
224706f2543Smrg
225706f2543Smrgtypedef struct _host {
226706f2543Smrg	short		family;
227706f2543Smrg	short		len;
228706f2543Smrg	unsigned char	*addr;
229706f2543Smrg	struct _host *next;
230706f2543Smrg	int		requested;
231706f2543Smrg} HOST;
232706f2543Smrg
233706f2543Smrg#define MakeHost(h,l)	(h)=malloc(sizeof *(h)+(l));\
234706f2543Smrg			if (h) { \
235706f2543Smrg			   (h)->addr=(unsigned char *) ((h) + 1);\
236706f2543Smrg			   (h)->requested = FALSE; \
237706f2543Smrg			}
238706f2543Smrg#define FreeHost(h)	free(h)
239706f2543Smrgstatic HOST *selfhosts = NULL;
240706f2543Smrgstatic HOST *validhosts = NULL;
241706f2543Smrgstatic int AccessEnabled = DEFAULT_ACCESS_CONTROL;
242706f2543Smrgstatic int LocalHostEnabled = FALSE;
243706f2543Smrgstatic int LocalHostRequested = FALSE;
244706f2543Smrgstatic int UsingXdmcp = FALSE;
245706f2543Smrg
246706f2543Smrg/* FamilyServerInterpreted implementation */
247706f2543Smrgstatic Bool siAddrMatch(int family, pointer addr, int len, HOST *host,
248706f2543Smrg	ClientPtr client);
249706f2543Smrgstatic int  siCheckAddr(const char *addrString, int length);
250706f2543Smrgstatic void siTypesInitialize(void);
251706f2543Smrg
252706f2543Smrg/*
253706f2543Smrg * called when authorization is not enabled to add the
254706f2543Smrg * local host to the access list
255706f2543Smrg */
256706f2543Smrg
257706f2543Smrgvoid
258706f2543SmrgEnableLocalHost (void)
259706f2543Smrg{
260706f2543Smrg    if (!UsingXdmcp)
261706f2543Smrg    {
262706f2543Smrg	LocalHostEnabled = TRUE;
263706f2543Smrg	AddLocalHosts ();
264706f2543Smrg    }
265706f2543Smrg}
266706f2543Smrg
267706f2543Smrg/*
268706f2543Smrg * called when authorization is enabled to keep us secure
269706f2543Smrg */
270706f2543Smrgvoid
271706f2543SmrgDisableLocalHost (void)
272706f2543Smrg{
273706f2543Smrg    HOST *self;
274706f2543Smrg
275706f2543Smrg    if (!LocalHostRequested)		/* Fix for XFree86 bug #156 */
276706f2543Smrg	LocalHostEnabled = FALSE;
277706f2543Smrg    for (self = selfhosts; self; self = self->next) {
278706f2543Smrg      if (!self->requested)		/* Fix for XFree86 bug #156 */
279706f2543Smrg	(void) RemoveHost ((ClientPtr)NULL, self->family, self->len, (pointer)self->addr);
280706f2543Smrg    }
281706f2543Smrg}
282706f2543Smrg
283706f2543Smrg/*
284706f2543Smrg * called at init time when XDMCP will be used; xdmcp always
285706f2543Smrg * adds local hosts manually when needed
286706f2543Smrg */
287706f2543Smrg
288706f2543Smrgvoid
289706f2543SmrgAccessUsingXdmcp (void)
290706f2543Smrg{
291706f2543Smrg    UsingXdmcp = TRUE;
292706f2543Smrg    LocalHostEnabled = FALSE;
293706f2543Smrg}
294706f2543Smrg
295706f2543Smrg
296706f2543Smrg#if  defined(SVR4) && !defined(sun)  && defined(SIOCGIFCONF) && !defined(USE_SIOCGLIFCONF)
297706f2543Smrg
298706f2543Smrg/* Deal with different SIOCGIFCONF ioctl semantics on these OSs */
299706f2543Smrg
300706f2543Smrgstatic int
301706f2543Smrgifioctl (int fd, int cmd, char *arg)
302706f2543Smrg{
303706f2543Smrg    struct strioctl ioc;
304706f2543Smrg    int ret;
305706f2543Smrg
306706f2543Smrg    memset((char *) &ioc, 0, sizeof(ioc));
307706f2543Smrg    ioc.ic_cmd = cmd;
308706f2543Smrg    ioc.ic_timout = 0;
309706f2543Smrg    if (cmd == SIOCGIFCONF)
310706f2543Smrg    {
311706f2543Smrg	ioc.ic_len = ((struct ifconf *) arg)->ifc_len;
312706f2543Smrg	ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf;
313706f2543Smrg    }
314706f2543Smrg    else
315706f2543Smrg    {
316706f2543Smrg	ioc.ic_len = sizeof(struct ifreq);
317706f2543Smrg	ioc.ic_dp = arg;
318706f2543Smrg    }
319706f2543Smrg    ret = ioctl(fd, I_STR, (char *) &ioc);
320706f2543Smrg    if (ret >= 0 && cmd == SIOCGIFCONF)
321706f2543Smrg#ifdef SVR4
322706f2543Smrg	((struct ifconf *) arg)->ifc_len = ioc.ic_len;
323706f2543Smrg#endif
324706f2543Smrg    return ret;
325706f2543Smrg}
326706f2543Smrg#else
327706f2543Smrg#define ifioctl ioctl
328706f2543Smrg#endif
329706f2543Smrg
330706f2543Smrg/*
331706f2543Smrg * DefineSelf (fd):
332706f2543Smrg *
333706f2543Smrg * Define this host for access control.  Find all the hosts the OS knows about
334706f2543Smrg * for this fd and add them to the selfhosts list.
335706f2543Smrg */
336706f2543Smrg
337706f2543Smrg#if !defined(SIOCGIFCONF)
338706f2543Smrgvoid
339706f2543SmrgDefineSelf (int fd)
340706f2543Smrg{
341706f2543Smrg#if !defined(TCPCONN) && !defined(STREAMSCONN) && !defined(UNIXCONN)
342706f2543Smrg    return;
343706f2543Smrg#else
344706f2543Smrg    register int n;
345706f2543Smrg    int	len;
346706f2543Smrg    caddr_t	addr;
347706f2543Smrg    int		family;
348706f2543Smrg    register HOST	*host;
349706f2543Smrg
350706f2543Smrg#ifndef WIN32
351706f2543Smrg    struct utsname name;
352706f2543Smrg#else
353706f2543Smrg    struct {
354706f2543Smrg        char  nodename[512];
355706f2543Smrg    } name;
356706f2543Smrg#endif
357706f2543Smrg
358706f2543Smrg    register struct hostent  *hp;
359706f2543Smrg
360706f2543Smrg    union {
361706f2543Smrg	struct  sockaddr   sa;
362706f2543Smrg	struct  sockaddr_in  in;
363706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
364706f2543Smrg	struct  sockaddr_in6  in6;
365706f2543Smrg#endif
366706f2543Smrg    } saddr;
367706f2543Smrg
368706f2543Smrg    struct	sockaddr_in	*inetaddr;
369706f2543Smrg    struct	sockaddr_in6	*inet6addr;
370706f2543Smrg    struct sockaddr_in broad_addr;
371706f2543Smrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
372706f2543Smrg    _Xgethostbynameparams hparams;
373706f2543Smrg#endif
374706f2543Smrg
375706f2543Smrg    /* Why not use gethostname()?  Well, at least on my system, I've had to
376706f2543Smrg     * make an ugly kernel patch to get a name longer than 8 characters, and
377706f2543Smrg     * uname() lets me access to the whole string (it smashes release, you
378706f2543Smrg     * see), whereas gethostname() kindly truncates it for me.
379706f2543Smrg     */
380706f2543Smrg#ifndef WIN32
381706f2543Smrg    uname(&name);
382706f2543Smrg#else
383706f2543Smrg    gethostname(name.nodename, sizeof(name.nodename));
384706f2543Smrg#endif
385706f2543Smrg
386706f2543Smrg    hp = _XGethostbyname(name.nodename, hparams);
387706f2543Smrg    if (hp != NULL)
388706f2543Smrg    {
389706f2543Smrg	saddr.sa.sa_family = hp->h_addrtype;
390706f2543Smrg	switch (hp->h_addrtype) {
391706f2543Smrg	case AF_INET:
392706f2543Smrg	    inetaddr = (struct sockaddr_in *) (&(saddr.sa));
393706f2543Smrg	    acopy ( hp->h_addr, &(inetaddr->sin_addr), hp->h_length);
394706f2543Smrg	    len = sizeof(saddr.sa);
395706f2543Smrg	    break;
396706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
397706f2543Smrg	case AF_INET6:
398706f2543Smrg	    inet6addr = (struct sockaddr_in6 *) (&(saddr.sa));
399706f2543Smrg	    acopy ( hp->h_addr, &(inet6addr->sin6_addr), hp->h_length);
400706f2543Smrg	    len = sizeof(saddr.in6);
401706f2543Smrg	    break;
402706f2543Smrg#endif
403706f2543Smrg	default:
404706f2543Smrg	    goto DefineLocalHost;
405706f2543Smrg	}
406706f2543Smrg	family = ConvertAddr ( &(saddr.sa), &len, (pointer *)&addr);
407706f2543Smrg	if ( family != -1 && family != FamilyLocal )
408706f2543Smrg	{
409706f2543Smrg	    for (host = selfhosts;
410706f2543Smrg		 host && !addrEqual (family, addr, len, host);
411706f2543Smrg		 host = host->next) ;
412706f2543Smrg	    if (!host)
413706f2543Smrg	    {
414706f2543Smrg		/* add this host to the host list.	*/
415706f2543Smrg		MakeHost(host,len)
416706f2543Smrg		if (host)
417706f2543Smrg		{
418706f2543Smrg		    host->family = family;
419706f2543Smrg		    host->len = len;
420706f2543Smrg		    acopy ( addr, host->addr, len);
421706f2543Smrg		    host->next = selfhosts;
422706f2543Smrg		    selfhosts = host;
423706f2543Smrg		}
424706f2543Smrg#ifdef XDMCP
425706f2543Smrg		/*
426706f2543Smrg		 *  If this is an Internet Address, but not the localhost
427706f2543Smrg		 *  address (127.0.0.1), nor the bogus address (0.0.0.0),
428706f2543Smrg		 *  register it.
429706f2543Smrg		 */
430706f2543Smrg		if (family == FamilyInternet &&
431706f2543Smrg		    !(len == 4 &&
432706f2543Smrg		      ((addr[0] == 127) ||
433706f2543Smrg		       (addr[0] == 0 && addr[1] == 0 &&
434706f2543Smrg			addr[2] == 0 && addr[3] == 0)))
435706f2543Smrg		      )
436706f2543Smrg		{
437706f2543Smrg		    XdmcpRegisterConnection (family, (char *)addr, len);
438706f2543Smrg		    broad_addr = *inetaddr;
439706f2543Smrg		    ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
440706f2543Smrg			htonl (INADDR_BROADCAST);
441706f2543Smrg		    XdmcpRegisterBroadcastAddress ((struct sockaddr_in *)
442706f2543Smrg						   &broad_addr);
443706f2543Smrg		}
444706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
445706f2543Smrg		else if (family == FamilyInternet6 &&
446706f2543Smrg		  !(IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr)))
447706f2543Smrg		{
448706f2543Smrg		    XdmcpRegisterConnection (family, (char *)addr, len);
449706f2543Smrg		}
450706f2543Smrg#endif
451706f2543Smrg
452706f2543Smrg#endif /* XDMCP */
453706f2543Smrg	    }
454706f2543Smrg	}
455706f2543Smrg    }
456706f2543Smrg    /*
457706f2543Smrg     * now add a host of family FamilyLocalHost...
458706f2543Smrg     */
459706f2543SmrgDefineLocalHost:
460706f2543Smrg    for (host = selfhosts;
461706f2543Smrg	 host && !addrEqual(FamilyLocalHost, "", 0, host);
462706f2543Smrg	 host = host->next);
463706f2543Smrg    if (!host)
464706f2543Smrg    {
465706f2543Smrg	MakeHost(host, 0);
466706f2543Smrg	if (host)
467706f2543Smrg	{
468706f2543Smrg	    host->family = FamilyLocalHost;
469706f2543Smrg	    host->len = 0;
470706f2543Smrg	    acopy("", host->addr, 0);
471706f2543Smrg	    host->next = selfhosts;
472706f2543Smrg	    selfhosts = host;
473706f2543Smrg	}
474706f2543Smrg    }
475706f2543Smrg#endif /* !TCPCONN && !STREAMSCONN && !UNIXCONN */
476706f2543Smrg}
477706f2543Smrg
478706f2543Smrg#else
479706f2543Smrg
480706f2543Smrg#ifdef USE_SIOCGLIFCONF
481706f2543Smrg#define ifr_type    struct lifreq
482706f2543Smrg#else
483706f2543Smrg#define ifr_type    struct ifreq
484706f2543Smrg#endif
485706f2543Smrg
486706f2543Smrg#ifdef VARIABLE_IFREQ
487706f2543Smrg#define ifr_size(p) (sizeof (struct ifreq) + \
488706f2543Smrg		     (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
489706f2543Smrg		      p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
490706f2543Smrg#define ifraddr_size(a) (a.sa_len)
491706f2543Smrg#else
492706f2543Smrg#define ifr_size(p) (sizeof (ifr_type))
493706f2543Smrg#define ifraddr_size(a) (sizeof (a))
494706f2543Smrg#endif
495706f2543Smrg
496706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
497706f2543Smrg#include <arpa/inet.h>
498706f2543Smrg#endif
499706f2543Smrg
500706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
501706f2543Smrgstatic void
502706f2543Smrgin6_fillscopeid(struct sockaddr_in6 *sin6)
503706f2543Smrg{
504706f2543Smrg#if defined(__KAME__)
505706f2543Smrg	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
506706f2543Smrg		sin6->sin6_scope_id =
507706f2543Smrg			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
508706f2543Smrg		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
509706f2543Smrg	}
510706f2543Smrg#endif
511706f2543Smrg}
512706f2543Smrg#endif
513706f2543Smrg
514706f2543Smrgvoid
515706f2543SmrgDefineSelf (int fd)
516706f2543Smrg{
517706f2543Smrg#ifndef HAS_GETIFADDRS
518706f2543Smrg    char 		*cp, *cplim;
519706f2543Smrg# ifdef USE_SIOCGLIFCONF
520706f2543Smrg    struct sockaddr_storage buf[16];
521706f2543Smrg    struct lifconf	ifc;
522706f2543Smrg    register struct lifreq *ifr;
523706f2543Smrg#  ifdef SIOCGLIFNUM
524706f2543Smrg    struct lifnum	ifn;
525706f2543Smrg#  endif
526706f2543Smrg# else /* !USE_SIOCGLIFCONF */
527706f2543Smrg    char		buf[2048];
528706f2543Smrg    struct ifconf	ifc;
529706f2543Smrg    register struct ifreq *ifr;
530706f2543Smrg# endif
531706f2543Smrg    void *		bufptr = buf;
532706f2543Smrg#else /* HAS_GETIFADDRS */
533706f2543Smrg    struct ifaddrs *	ifap, *ifr;
534706f2543Smrg#endif
535706f2543Smrg    int 		len;
536706f2543Smrg    unsigned char *	addr;
537706f2543Smrg    int 		family;
538706f2543Smrg    register HOST 	*host;
539706f2543Smrg
540706f2543Smrg#ifndef HAS_GETIFADDRS
541706f2543Smrg
542706f2543Smrg    len = sizeof(buf);
543706f2543Smrg
544706f2543Smrg#ifdef USE_SIOCGLIFCONF
545706f2543Smrg
546706f2543Smrg#ifdef SIOCGLIFNUM
547706f2543Smrg    ifn.lifn_family = AF_UNSPEC;
548706f2543Smrg    ifn.lifn_flags = 0;
549706f2543Smrg    if (ioctl (fd, SIOCGLIFNUM, (char *) &ifn) < 0)
550706f2543Smrg        Error ("Getting interface count");
551706f2543Smrg    if (len < (ifn.lifn_count * sizeof(struct lifreq))) {
552706f2543Smrg	len = ifn.lifn_count * sizeof(struct lifreq);
553706f2543Smrg	bufptr = malloc(len);
554706f2543Smrg    }
555706f2543Smrg#endif
556706f2543Smrg
557706f2543Smrg    ifc.lifc_family = AF_UNSPEC;
558706f2543Smrg    ifc.lifc_flags = 0;
559706f2543Smrg    ifc.lifc_len = len;
560706f2543Smrg    ifc.lifc_buf = bufptr;
561706f2543Smrg
562706f2543Smrg#define IFC_IOCTL_REQ SIOCGLIFCONF
563706f2543Smrg#define IFC_IFC_REQ ifc.lifc_req
564706f2543Smrg#define IFC_IFC_LEN ifc.lifc_len
565706f2543Smrg#define IFR_IFR_ADDR ifr->lifr_addr
566706f2543Smrg#define IFR_IFR_NAME ifr->lifr_name
567706f2543Smrg
568706f2543Smrg#else /* Use SIOCGIFCONF */
569706f2543Smrg    ifc.ifc_len = len;
570706f2543Smrg    ifc.ifc_buf = bufptr;
571706f2543Smrg
572706f2543Smrg#define IFC_IOCTL_REQ SIOCGIFCONF
573706f2543Smrg#define IFC_IFC_REQ ifc.ifc_req
574706f2543Smrg#define IFC_IFC_LEN ifc.ifc_len
575706f2543Smrg#define IFR_IFR_ADDR ifr->ifr_addr
576706f2543Smrg#define IFR_IFR_NAME ifr->ifr_name
577706f2543Smrg#endif
578706f2543Smrg
579706f2543Smrg    if (ifioctl (fd, IFC_IOCTL_REQ, (pointer) &ifc) < 0)
580706f2543Smrg        Error ("Getting interface configuration (4)");
581706f2543Smrg
582706f2543Smrg    cplim = (char *) IFC_IFC_REQ + IFC_IFC_LEN;
583706f2543Smrg
584706f2543Smrg    for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size (ifr))
585706f2543Smrg    {
586706f2543Smrg	ifr = (ifr_type *) cp;
587706f2543Smrg	len = ifraddr_size (IFR_IFR_ADDR);
588706f2543Smrg	family = ConvertAddr ((struct sockaddr *) &IFR_IFR_ADDR,
589706f2543Smrg	  			&len, (pointer *)&addr);
590706f2543Smrg        if (family == -1 || family == FamilyLocal)
591706f2543Smrg	    continue;
592706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
593706f2543Smrg	if (family == FamilyInternet6)
594706f2543Smrg	    in6_fillscopeid((struct sockaddr_in6 *)&IFR_IFR_ADDR);
595706f2543Smrg#endif
596706f2543Smrg        for (host = selfhosts;
597706f2543Smrg 	     host && !addrEqual (family, addr, len, host);
598706f2543Smrg	     host = host->next)
599706f2543Smrg	    ;
600706f2543Smrg        if (host)
601706f2543Smrg	    continue;
602706f2543Smrg	MakeHost(host,len)
603706f2543Smrg	if (host)
604706f2543Smrg	{
605706f2543Smrg	    host->family = family;
606706f2543Smrg	    host->len = len;
607706f2543Smrg	    acopy(addr, host->addr, len);
608706f2543Smrg	    host->next = selfhosts;
609706f2543Smrg	    selfhosts = host;
610706f2543Smrg	}
611706f2543Smrg#ifdef XDMCP
612706f2543Smrg	{
613706f2543Smrg#ifdef USE_SIOCGLIFCONF
614706f2543Smrg	    struct sockaddr_storage broad_addr;
615706f2543Smrg#else
616706f2543Smrg	    struct sockaddr broad_addr;
617706f2543Smrg#endif
618706f2543Smrg
619706f2543Smrg	    /*
620706f2543Smrg	     * If this isn't an Internet Address, don't register it.
621706f2543Smrg	     */
622706f2543Smrg	    if (family != FamilyInternet
623706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
624706f2543Smrg	      && family != FamilyInternet6
625706f2543Smrg#endif
626706f2543Smrg		)
627706f2543Smrg		continue;
628706f2543Smrg
629706f2543Smrg	    /*
630706f2543Smrg 	     * ignore 'localhost' entries as they're not useful
631706f2543Smrg	     * on the other end of the wire
632706f2543Smrg	     */
633706f2543Smrg	    if (family == FamilyInternet &&
634706f2543Smrg		addr[0] == 127 && addr[1] == 0 &&
635706f2543Smrg		addr[2] == 0 && addr[3] == 1)
636706f2543Smrg		continue;
637706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
638706f2543Smrg	    else if (family == FamilyInternet6 &&
639706f2543Smrg	      IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr))
640706f2543Smrg		continue;
641706f2543Smrg#endif
642706f2543Smrg
643706f2543Smrg	    /*
644706f2543Smrg	     * Ignore '0.0.0.0' entries as they are
645706f2543Smrg	     * returned by some OSes for unconfigured NICs but they are
646706f2543Smrg	     * not useful on the other end of the wire.
647706f2543Smrg	     */
648706f2543Smrg	    if (len == 4 &&
649706f2543Smrg		addr[0] == 0 && addr[1] == 0 &&
650706f2543Smrg		addr[2] == 0 && addr[3] == 0)
651706f2543Smrg		continue;
652706f2543Smrg
653706f2543Smrg	    XdmcpRegisterConnection (family, (char *)addr, len);
654706f2543Smrg
655706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
656706f2543Smrg	    /* IPv6 doesn't support broadcasting, so we drop out here */
657706f2543Smrg	    if (family == FamilyInternet6)
658706f2543Smrg		continue;
659706f2543Smrg#endif
660706f2543Smrg
661706f2543Smrg	    broad_addr = IFR_IFR_ADDR;
662706f2543Smrg
663706f2543Smrg	    ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
664706f2543Smrg		htonl (INADDR_BROADCAST);
665706f2543Smrg#if defined(USE_SIOCGLIFCONF) && defined(SIOCGLIFBRDADDR)
666706f2543Smrg	    {
667706f2543Smrg	    	struct lifreq    broad_req;
668706f2543Smrg
669706f2543Smrg	    	broad_req = *ifr;
670706f2543Smrg		if (ioctl (fd, SIOCGLIFFLAGS, (char *) &broad_req) != -1 &&
671706f2543Smrg		    (broad_req.lifr_flags & IFF_BROADCAST) &&
672706f2543Smrg		    (broad_req.lifr_flags & IFF_UP)
673706f2543Smrg		    )
674706f2543Smrg		{
675706f2543Smrg		    broad_req = *ifr;
676706f2543Smrg		    if (ioctl (fd, SIOCGLIFBRDADDR, &broad_req) != -1)
677706f2543Smrg			broad_addr = broad_req.lifr_broadaddr;
678706f2543Smrg		    else
679706f2543Smrg			continue;
680706f2543Smrg		}
681706f2543Smrg		else
682706f2543Smrg		    continue;
683706f2543Smrg	    }
684706f2543Smrg
685706f2543Smrg#elif defined(SIOCGIFBRDADDR)
686706f2543Smrg	    {
687706f2543Smrg	    	struct ifreq    broad_req;
688706f2543Smrg
689706f2543Smrg	    	broad_req = *ifr;
690706f2543Smrg		if (ifioctl (fd, SIOCGIFFLAGS, (pointer) &broad_req) != -1 &&
691706f2543Smrg		    (broad_req.ifr_flags & IFF_BROADCAST) &&
692706f2543Smrg		    (broad_req.ifr_flags & IFF_UP)
693706f2543Smrg		    )
694706f2543Smrg		{
695706f2543Smrg		    broad_req = *ifr;
696706f2543Smrg		    if (ifioctl (fd, SIOCGIFBRDADDR, (pointer) &broad_req) != -1)
697706f2543Smrg			broad_addr = broad_req.ifr_addr;
698706f2543Smrg		    else
699706f2543Smrg			continue;
700706f2543Smrg		}
701706f2543Smrg		else
702706f2543Smrg		    continue;
703706f2543Smrg	    }
704706f2543Smrg#endif /* SIOCGIFBRDADDR */
705706f2543Smrg	    XdmcpRegisterBroadcastAddress ((struct sockaddr_in *) &broad_addr);
706706f2543Smrg	}
707706f2543Smrg#endif /* XDMCP */
708706f2543Smrg    }
709706f2543Smrg    if (bufptr != buf)
710706f2543Smrg        free(bufptr);
711706f2543Smrg#else /* HAS_GETIFADDRS */
712706f2543Smrg    if (getifaddrs(&ifap) < 0) {
713706f2543Smrg	ErrorF("Warning: getifaddrs returns %s\n", strerror(errno));
714706f2543Smrg	return;
715706f2543Smrg    }
716706f2543Smrg    for (ifr = ifap; ifr != NULL; ifr = ifr->ifa_next) {
717706f2543Smrg        if (!ifr->ifa_addr)
718706f2543Smrg            continue;
719706f2543Smrg	len = sizeof(*(ifr->ifa_addr));
720706f2543Smrg	family = ConvertAddr((struct sockaddr *) ifr->ifa_addr, &len,
721706f2543Smrg			     (pointer *)&addr);
722706f2543Smrg	if (family == -1 || family == FamilyLocal)
723706f2543Smrg	    continue;
724706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
725706f2543Smrg	if (family == FamilyInternet6)
726706f2543Smrg	    in6_fillscopeid((struct sockaddr_in6 *)ifr->ifa_addr);
727706f2543Smrg#endif
728706f2543Smrg
729706f2543Smrg	for (host = selfhosts;
730706f2543Smrg	     host != NULL && !addrEqual(family, addr, len, host);
731706f2543Smrg	     host = host->next)
732706f2543Smrg	    ;
733706f2543Smrg	if (host != NULL)
734706f2543Smrg	    continue;
735706f2543Smrg	MakeHost(host, len);
736706f2543Smrg	if (host != NULL) {
737706f2543Smrg	    host->family = family;
738706f2543Smrg	    host->len = len;
739706f2543Smrg	    acopy(addr, host->addr, len);
740706f2543Smrg	    host->next = selfhosts;
741706f2543Smrg	    selfhosts = host;
742706f2543Smrg	}
743706f2543Smrg#ifdef XDMCP
744706f2543Smrg	{
745706f2543Smrg	    /*
746706f2543Smrg	     * If this isn't an Internet Address, don't register it.
747706f2543Smrg	     */
748706f2543Smrg	    if (family != FamilyInternet
749706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
750706f2543Smrg		&& family != FamilyInternet6
751706f2543Smrg#endif
752706f2543Smrg	    )
753706f2543Smrg		continue;
754706f2543Smrg
755706f2543Smrg	    /*
756706f2543Smrg	     * ignore 'localhost' entries as they're not useful
757706f2543Smrg	     * on the other end of the wire
758706f2543Smrg	     */
759706f2543Smrg	    if (ifr->ifa_flags & IFF_LOOPBACK)
760706f2543Smrg		    continue;
761706f2543Smrg
762706f2543Smrg	    if (family == FamilyInternet &&
763706f2543Smrg		addr[0] == 127 && addr[1] == 0 &&
764706f2543Smrg		addr[2] == 0 && addr[3] == 1)
765706f2543Smrg		continue;
766706f2543Smrg
767706f2543Smrg	    /*
768706f2543Smrg	     * Ignore '0.0.0.0' entries as they are
769706f2543Smrg	     * returned by some OSes for unconfigured NICs but they are
770706f2543Smrg	     * not useful on the other end of the wire.
771706f2543Smrg	     */
772706f2543Smrg	    if (len == 4 &&
773706f2543Smrg		addr[0] == 0 && addr[1] == 0 &&
774706f2543Smrg		addr[2] == 0 && addr[3] == 0)
775706f2543Smrg		continue;
776706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
777706f2543Smrg	    else if (family == FamilyInternet6 &&
778706f2543Smrg	      IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr))
779706f2543Smrg		continue;
780706f2543Smrg#endif
781706f2543Smrg	    XdmcpRegisterConnection(family, (char *)addr, len);
782706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
783706f2543Smrg	    if (family == FamilyInternet6)
784706f2543Smrg		/* IPv6 doesn't support broadcasting, so we drop out here */
785706f2543Smrg		continue;
786706f2543Smrg#endif
787706f2543Smrg	    if ((ifr->ifa_flags & IFF_BROADCAST) &&
788706f2543Smrg		(ifr->ifa_flags & IFF_UP) &&
789706f2543Smrg                ifr->ifa_broadaddr)
790706f2543Smrg		XdmcpRegisterBroadcastAddress(
791706f2543Smrg		    (struct sockaddr_in *) ifr->ifa_broadaddr);
792706f2543Smrg	    else
793706f2543Smrg		continue;
794706f2543Smrg	}
795706f2543Smrg#endif /* XDMCP */
796706f2543Smrg
797706f2543Smrg    } /* for */
798706f2543Smrg    freeifaddrs(ifap);
799706f2543Smrg#endif /* HAS_GETIFADDRS */
800706f2543Smrg
801706f2543Smrg    /*
802706f2543Smrg     * add something of FamilyLocalHost
803706f2543Smrg     */
804706f2543Smrg    for (host = selfhosts;
805706f2543Smrg	 host && !addrEqual(FamilyLocalHost, "", 0, host);
806706f2543Smrg	 host = host->next);
807706f2543Smrg    if (!host)
808706f2543Smrg    {
809706f2543Smrg	MakeHost(host, 0);
810706f2543Smrg	if (host)
811706f2543Smrg	{
812706f2543Smrg	    host->family = FamilyLocalHost;
813706f2543Smrg	    host->len = 0;
814706f2543Smrg	    acopy("", host->addr, 0);
815706f2543Smrg	    host->next = selfhosts;
816706f2543Smrg	    selfhosts = host;
817706f2543Smrg	}
818706f2543Smrg    }
819706f2543Smrg}
820706f2543Smrg#endif /* hpux && !HAS_IFREQ */
821706f2543Smrg
822706f2543Smrg#ifdef XDMCP
823706f2543Smrgvoid
824706f2543SmrgAugmentSelf(pointer from, int len)
825706f2543Smrg{
826706f2543Smrg    int family;
827706f2543Smrg    pointer addr;
828706f2543Smrg    register HOST *host;
829706f2543Smrg
830706f2543Smrg    family = ConvertAddr(from, &len, (pointer *)&addr);
831706f2543Smrg    if (family == -1 || family == FamilyLocal)
832706f2543Smrg	return;
833706f2543Smrg    for (host = selfhosts; host; host = host->next)
834706f2543Smrg    {
835706f2543Smrg	if (addrEqual(family, addr, len, host))
836706f2543Smrg	    return;
837706f2543Smrg    }
838706f2543Smrg    MakeHost(host,len)
839706f2543Smrg    if (!host)
840706f2543Smrg	return;
841706f2543Smrg    host->family = family;
842706f2543Smrg    host->len = len;
843706f2543Smrg    acopy(addr, host->addr, len);
844706f2543Smrg    host->next = selfhosts;
845706f2543Smrg    selfhosts = host;
846706f2543Smrg}
847706f2543Smrg#endif
848706f2543Smrg
849706f2543Smrgvoid
850706f2543SmrgAddLocalHosts (void)
851706f2543Smrg{
852706f2543Smrg    HOST    *self;
853706f2543Smrg
854706f2543Smrg    for (self = selfhosts; self; self = self->next)
855706f2543Smrg	    /* Fix for XFree86 bug #156: pass addingLocal = TRUE to
856706f2543Smrg	     * NewHost to tell that we are adding the default local
857706f2543Smrg	     * host entries and not to flag the entries as being
858706f2543Smrg	     * explicitely requested */
859706f2543Smrg	(void) NewHost (self->family, self->addr, self->len, TRUE);
860706f2543Smrg}
861706f2543Smrg
862706f2543Smrg/* Reset access control list to initial hosts */
863706f2543Smrgvoid
864706f2543SmrgResetHosts (char *display)
865706f2543Smrg{
866706f2543Smrg    register HOST	*host;
867706f2543Smrg    char                lhostname[120], ohostname[120];
868706f2543Smrg    char 		*hostname = ohostname;
869706f2543Smrg    char		fname[PATH_MAX + 1];
870706f2543Smrg    int			fnamelen;
871706f2543Smrg    FILE		*fd;
872706f2543Smrg    char		*ptr;
873706f2543Smrg    int                 i, hostlen;
874706f2543Smrg#if (defined(TCPCONN) || defined(STREAMSCONN) ) && \
875706f2543Smrg     (!defined(IPv6) || !defined(AF_INET6))
876706f2543Smrg    union {
877706f2543Smrg        struct sockaddr	sa;
878706f2543Smrg#if defined(TCPCONN) || defined(STREAMSCONN)
879706f2543Smrg	struct sockaddr_in in;
880706f2543Smrg#endif /* TCPCONN || STREAMSCONN */
881706f2543Smrg    }			saddr;
882706f2543Smrg#endif
883706f2543Smrg    int			family = 0;
884706f2543Smrg    pointer		addr;
885706f2543Smrg    int 		len;
886706f2543Smrg
887706f2543Smrg    siTypesInitialize();
888706f2543Smrg    AccessEnabled = defeatAccessControl ? FALSE : DEFAULT_ACCESS_CONTROL;
889706f2543Smrg    LocalHostEnabled = FALSE;
890706f2543Smrg    while ((host = validhosts) != 0)
891706f2543Smrg    {
892706f2543Smrg        validhosts = host->next;
893706f2543Smrg        FreeHost (host);
894706f2543Smrg    }
895706f2543Smrg
896706f2543Smrg#if defined WIN32 && defined __MINGW32__
897706f2543Smrg#define ETC_HOST_PREFIX "X"
898706f2543Smrg#else
899706f2543Smrg#define ETC_HOST_PREFIX "/etc/X"
900706f2543Smrg#endif
901706f2543Smrg#define ETC_HOST_SUFFIX ".hosts"
902706f2543Smrg    fnamelen = strlen(ETC_HOST_PREFIX) + strlen(ETC_HOST_SUFFIX) +
903706f2543Smrg		strlen(display) + 1;
904706f2543Smrg    if (fnamelen > sizeof(fname))
905706f2543Smrg	FatalError("Display name `%s' is too long\n", display);
906706f2543Smrg    snprintf(fname, sizeof(fname), ETC_HOST_PREFIX "%s" ETC_HOST_SUFFIX,
907706f2543Smrg	     display);
908706f2543Smrg
909706f2543Smrg    if ((fd = fopen (fname, "r")) != 0)
910706f2543Smrg    {
911706f2543Smrg        while (fgets (ohostname, sizeof (ohostname), fd))
912706f2543Smrg	{
913706f2543Smrg	family = FamilyWild;
914706f2543Smrg	if (*ohostname == '#')
915706f2543Smrg	    continue;
916706f2543Smrg    	if ((ptr = strchr(ohostname, '\n')) != 0)
917706f2543Smrg    	    *ptr = 0;
918706f2543Smrg        hostlen = strlen(ohostname) + 1;
919706f2543Smrg        for (i = 0; i < hostlen; i++)
920706f2543Smrg	    lhostname[i] = tolower(ohostname[i]);
921706f2543Smrg	hostname = ohostname;
922706f2543Smrg	if (!strncmp("local:", lhostname, 6))
923706f2543Smrg	{
924706f2543Smrg	    family = FamilyLocalHost;
925706f2543Smrg	    NewHost(family, "", 0, FALSE);
926706f2543Smrg	    LocalHostRequested = TRUE;	/* Fix for XFree86 bug #156 */
927706f2543Smrg	}
928706f2543Smrg#if defined(TCPCONN) || defined(STREAMSCONN)
929706f2543Smrg	else if (!strncmp("inet:", lhostname, 5))
930706f2543Smrg	{
931706f2543Smrg	    family = FamilyInternet;
932706f2543Smrg	    hostname = ohostname + 5;
933706f2543Smrg	}
934706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
935706f2543Smrg	else if (!strncmp("inet6:", lhostname, 6))
936706f2543Smrg	{
937706f2543Smrg	    family = FamilyInternet6;
938706f2543Smrg	    hostname = ohostname + 6;
939706f2543Smrg	}
940706f2543Smrg#endif
941706f2543Smrg#endif
942706f2543Smrg#ifdef SECURE_RPC
943706f2543Smrg	else if (!strncmp("nis:", lhostname, 4))
944706f2543Smrg	{
945706f2543Smrg	    family = FamilyNetname;
946706f2543Smrg	    hostname = ohostname + 4;
947706f2543Smrg	}
948706f2543Smrg#endif
949706f2543Smrg	else if (!strncmp("si:", lhostname, 3))
950706f2543Smrg	{
951706f2543Smrg	    family = FamilyServerInterpreted;
952706f2543Smrg	    hostname = ohostname + 3;
953706f2543Smrg	    hostlen -= 3;
954706f2543Smrg	}
955706f2543Smrg
956706f2543Smrg
957706f2543Smrg	if (family == FamilyServerInterpreted)
958706f2543Smrg	{
959706f2543Smrg	    len = siCheckAddr(hostname, hostlen);
960706f2543Smrg	    if (len >= 0) {
961706f2543Smrg		NewHost(family, hostname, len, FALSE);
962706f2543Smrg	    }
963706f2543Smrg	}
964706f2543Smrg	else
965706f2543Smrg#ifdef SECURE_RPC
966706f2543Smrg	if ((family == FamilyNetname) || (strchr(hostname, '@')))
967706f2543Smrg	{
968706f2543Smrg	    SecureRPCInit ();
969706f2543Smrg	    (void) NewHost (FamilyNetname, hostname, strlen (hostname), FALSE);
970706f2543Smrg	}
971706f2543Smrg	else
972706f2543Smrg#endif /* SECURE_RPC */
973706f2543Smrg#if defined(TCPCONN) || defined(STREAMSCONN)
974706f2543Smrg	{
975706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
976706f2543Smrg	    if ( (family == FamilyInternet) || (family == FamilyInternet6) ||
977706f2543Smrg		 (family == FamilyWild) )
978706f2543Smrg            {
979706f2543Smrg		struct addrinfo *addresses;
980706f2543Smrg		struct addrinfo *a;
981706f2543Smrg		int f;
982706f2543Smrg
983706f2543Smrg		if (getaddrinfo(hostname, NULL, NULL, &addresses) == 0) {
984706f2543Smrg		    for (a = addresses ; a != NULL ; a = a->ai_next) {
985706f2543Smrg			len = a->ai_addrlen;
986706f2543Smrg			f = ConvertAddr(a->ai_addr,&len,(pointer *)&addr);
987706f2543Smrg			if ( (family == f) ||
988706f2543Smrg			     ((family == FamilyWild) && (f != -1)) ) {
989706f2543Smrg			    NewHost(f, addr, len, FALSE);
990706f2543Smrg			}
991706f2543Smrg		    }
992706f2543Smrg		    freeaddrinfo(addresses);
993706f2543Smrg		}
994706f2543Smrg	    }
995706f2543Smrg#else
996706f2543Smrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
997706f2543Smrg	    _Xgethostbynameparams hparams;
998706f2543Smrg#endif
999706f2543Smrg	    register struct hostent *hp;
1000706f2543Smrg
1001706f2543Smrg    	    /* host name */
1002706f2543Smrg    	    if ((family == FamilyInternet &&
1003706f2543Smrg		 ((hp = _XGethostbyname(hostname, hparams)) != 0)) ||
1004706f2543Smrg		((hp = _XGethostbyname(hostname, hparams)) != 0))
1005706f2543Smrg	    {
1006706f2543Smrg    		saddr.sa.sa_family = hp->h_addrtype;
1007706f2543Smrg		len = sizeof(saddr.sa);
1008706f2543Smrg    		if ((family = ConvertAddr (&saddr.sa, &len, (pointer *)&addr)) != -1)
1009706f2543Smrg		{
1010706f2543Smrg#ifdef h_addr				/* new 4.3bsd version of gethostent */
1011706f2543Smrg		    char **list;
1012706f2543Smrg
1013706f2543Smrg		    /* iterate over the addresses */
1014706f2543Smrg		    for (list = hp->h_addr_list; *list; list++)
1015706f2543Smrg			(void) NewHost (family, (pointer)*list, len, FALSE);
1016706f2543Smrg#else
1017706f2543Smrg    		    (void) NewHost (family, (pointer)hp->h_addr, len, FALSE);
1018706f2543Smrg#endif
1019706f2543Smrg		}
1020706f2543Smrg    	    }
1021706f2543Smrg#endif /* IPv6 */
1022706f2543Smrg        }
1023706f2543Smrg#endif /* TCPCONN || STREAMSCONN */
1024706f2543Smrg	family = FamilyWild;
1025706f2543Smrg        }
1026706f2543Smrg        fclose (fd);
1027706f2543Smrg    }
1028706f2543Smrg}
1029706f2543Smrg
1030706f2543Smrg/* Is client on the local host */
1031706f2543SmrgBool
1032706f2543SmrgComputeLocalClient(ClientPtr client)
1033706f2543Smrg{
1034706f2543Smrg    int    		alen, family, notused;
1035706f2543Smrg    Xtransaddr		*from = NULL;
1036706f2543Smrg    pointer		addr;
1037706f2543Smrg    register HOST	*host;
1038706f2543Smrg    OsCommPtr           oc = (OsCommPtr) client->osPrivate;
1039706f2543Smrg
1040706f2543Smrg    if (!oc->trans_conn)
1041706f2543Smrg        return FALSE;
1042706f2543Smrg
1043706f2543Smrg    if (!_XSERVTransGetPeerAddr (oc->trans_conn, &notused, &alen, &from))
1044706f2543Smrg    {
1045706f2543Smrg	family = ConvertAddr ((struct sockaddr *) from,
1046706f2543Smrg	    &alen, (pointer *)&addr);
1047706f2543Smrg	if (family == -1)
1048706f2543Smrg	{
1049706f2543Smrg	    free(from);
1050706f2543Smrg	    return FALSE;
1051706f2543Smrg	}
1052706f2543Smrg	if (family == FamilyLocal)
1053706f2543Smrg	{
1054706f2543Smrg	    free(from);
1055706f2543Smrg	    return TRUE;
1056706f2543Smrg	}
1057706f2543Smrg	for (host = selfhosts; host; host = host->next)
1058706f2543Smrg	{
1059706f2543Smrg	    if (addrEqual (family, addr, alen, host)) {
1060706f2543Smrg		free(from);
1061706f2543Smrg		return TRUE;
1062706f2543Smrg	    }
1063706f2543Smrg	}
1064706f2543Smrg	free(from);
1065706f2543Smrg    }
1066706f2543Smrg    return FALSE;
1067706f2543Smrg}
1068706f2543Smrg
1069706f2543SmrgBool LocalClient(ClientPtr client)
1070706f2543Smrg{
1071706f2543Smrg    if (!client->osPrivate)
1072706f2543Smrg        return FALSE;
1073706f2543Smrg    return ((OsCommPtr)client->osPrivate)->local_client;
1074706f2543Smrg}
1075706f2543Smrg
1076706f2543Smrg/*
1077706f2543Smrg * Return the uid and gid of a connected local client
1078706f2543Smrg *
1079706f2543Smrg * Used by XShm to test access rights to shared memory segments
1080706f2543Smrg */
1081706f2543Smrgint
1082706f2543SmrgLocalClientCred(ClientPtr client, int *pUid, int *pGid)
1083706f2543Smrg{
1084706f2543Smrg    LocalClientCredRec *lcc;
1085706f2543Smrg    int ret = GetLocalClientCreds(client, &lcc);
1086706f2543Smrg
1087706f2543Smrg    if (ret == 0) {
1088706f2543Smrg#ifdef HAVE_GETZONEID /* only local if in the same zone */
1089706f2543Smrg	if ((lcc->fieldsSet & LCC_ZID_SET) && (lcc->zoneid != getzoneid())) {
1090706f2543Smrg	    FreeLocalClientCreds(lcc);
1091706f2543Smrg	    return -1;
1092706f2543Smrg	}
1093706f2543Smrg#endif
1094706f2543Smrg	if ((lcc->fieldsSet & LCC_UID_SET) && (pUid != NULL))
1095706f2543Smrg	    *pUid = lcc->euid;
1096706f2543Smrg	if ((lcc->fieldsSet & LCC_GID_SET) && (pGid != NULL))
1097706f2543Smrg	    *pGid = lcc->egid;
1098706f2543Smrg	FreeLocalClientCreds(lcc);
1099706f2543Smrg    }
1100706f2543Smrg    return ret;
1101706f2543Smrg}
1102706f2543Smrg
1103706f2543Smrg/*
1104706f2543Smrg * Return the uid and all gids of a connected local client
1105706f2543Smrg * Allocates a LocalClientCredRec - caller must call FreeLocalClientCreds
1106706f2543Smrg *
1107706f2543Smrg * Used by localuser & localgroup ServerInterpreted access control forms below
1108706f2543Smrg * Used by AuthAudit to log who local connections came from
1109706f2543Smrg */
1110706f2543Smrgint
1111706f2543SmrgGetLocalClientCreds(ClientPtr client, LocalClientCredRec **lccp)
1112706f2543Smrg{
1113706f2543Smrg#if defined(HAS_GETPEEREID) || defined(HAS_GETPEERUCRED) || defined(SO_PEERCRED)
1114706f2543Smrg    int fd;
1115706f2543Smrg    XtransConnInfo ci;
1116706f2543Smrg    LocalClientCredRec *lcc;
1117706f2543Smrg#ifdef HAS_GETPEEREID
1118706f2543Smrg    uid_t uid;
1119706f2543Smrg    gid_t gid;
1120706f2543Smrg#elif defined(HAS_GETPEERUCRED)
1121706f2543Smrg    ucred_t *peercred = NULL;
1122706f2543Smrg    const gid_t *gids;
1123706f2543Smrg#elif defined(SO_PEERCRED)
1124706f2543Smrg    struct ucred peercred;
1125706f2543Smrg    socklen_t so_len = sizeof(peercred);
1126706f2543Smrg#endif
1127706f2543Smrg
1128706f2543Smrg    if (client == NULL)
1129706f2543Smrg	return -1;
1130706f2543Smrg    ci = ((OsCommPtr)client->osPrivate)->trans_conn;
1131706f2543Smrg#if !(defined(sun) && defined(HAS_GETPEERUCRED))
1132706f2543Smrg    /* Most implementations can only determine peer credentials for Unix
1133706f2543Smrg     * domain sockets - Solaris getpeerucred can work with a bit more, so
1134706f2543Smrg     * we just let it tell us if the connection type is supported or not
1135706f2543Smrg     */
1136706f2543Smrg    if (!_XSERVTransIsLocal(ci)) {
1137706f2543Smrg	return -1;
1138706f2543Smrg    }
1139706f2543Smrg#endif
1140706f2543Smrg
1141706f2543Smrg    *lccp = calloc(1, sizeof(LocalClientCredRec));
1142706f2543Smrg    if (*lccp == NULL)
1143706f2543Smrg	return -1;
1144706f2543Smrg    lcc = *lccp;
1145706f2543Smrg
1146706f2543Smrg    fd = _XSERVTransGetConnectionNumber(ci);
1147706f2543Smrg#ifdef HAS_GETPEEREID
1148706f2543Smrg    if (getpeereid(fd, &uid, &gid) == -1) {
1149706f2543Smrg	FreeLocalClientCreds(lcc);
1150706f2543Smrg	return -1;
1151706f2543Smrg    }
1152706f2543Smrg    lcc->euid = uid;
1153706f2543Smrg    lcc->egid = gid;
1154706f2543Smrg    lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET;
1155706f2543Smrg    return 0;
1156706f2543Smrg#elif defined(HAS_GETPEERUCRED)
1157706f2543Smrg    if (getpeerucred(fd, &peercred) < 0) {
1158706f2543Smrg	FreeLocalClientCreds(lcc);
1159706f2543Smrg    	return -1;
1160706f2543Smrg    }
1161706f2543Smrg    lcc->euid = ucred_geteuid(peercred);
1162706f2543Smrg    if (lcc->euid != -1)
1163706f2543Smrg	lcc->fieldsSet |= LCC_UID_SET;
1164706f2543Smrg    lcc->egid = ucred_getegid(peercred);
1165706f2543Smrg    if (lcc->egid != -1)
1166706f2543Smrg	lcc->fieldsSet |= LCC_GID_SET;
1167706f2543Smrg    lcc->pid = ucred_getpid(peercred);
1168706f2543Smrg    if (lcc->pid != -1)
1169706f2543Smrg	lcc->fieldsSet |= LCC_PID_SET;
1170706f2543Smrg#ifdef HAVE_GETZONEID
1171706f2543Smrg    lcc->zoneid = ucred_getzoneid(peercred);
1172706f2543Smrg    if (lcc->zoneid != -1)
1173706f2543Smrg	lcc->fieldsSet |= LCC_ZID_SET;
1174706f2543Smrg#endif
1175706f2543Smrg    lcc->nSuppGids = ucred_getgroups(peercred, &gids);
1176706f2543Smrg    if (lcc->nSuppGids > 0) {
1177706f2543Smrg	lcc->pSuppGids = calloc(lcc->nSuppGids, sizeof(int));
1178706f2543Smrg	if (lcc->pSuppGids == NULL) {
1179706f2543Smrg	    lcc->nSuppGids = 0;
1180706f2543Smrg	} else {
1181706f2543Smrg	    int i;
1182706f2543Smrg	    for (i = 0 ; i < lcc->nSuppGids; i++) {
1183706f2543Smrg		(lcc->pSuppGids)[i] = (int) gids[i];
1184706f2543Smrg	    }
1185706f2543Smrg	}
1186706f2543Smrg    } else {
1187706f2543Smrg	lcc->nSuppGids = 0;
1188706f2543Smrg    }
1189706f2543Smrg    ucred_free(peercred);
1190706f2543Smrg    return 0;
1191706f2543Smrg#elif defined(SO_PEERCRED)
1192706f2543Smrg    if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) {
1193706f2543Smrg	FreeLocalClientCreds(lcc);
1194706f2543Smrg	return -1;
1195706f2543Smrg    }
1196706f2543Smrg    lcc->euid = peercred.uid;
1197706f2543Smrg    lcc->egid = peercred.gid;
1198706f2543Smrg    lcc->pid = peercred.pid;
1199706f2543Smrg    lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET | LCC_PID_SET;
1200706f2543Smrg    return 0;
1201706f2543Smrg#endif
1202706f2543Smrg#else
1203706f2543Smrg    /* No system call available to get the credentials of the peer */
1204706f2543Smrg#define NO_LOCAL_CLIENT_CRED
1205706f2543Smrg    return -1;
1206706f2543Smrg#endif
1207706f2543Smrg}
1208706f2543Smrg
1209706f2543Smrgvoid
1210706f2543SmrgFreeLocalClientCreds(LocalClientCredRec *lcc)
1211706f2543Smrg{
1212706f2543Smrg    if (lcc != NULL) {
1213706f2543Smrg	if (lcc->nSuppGids > 0) {
1214706f2543Smrg	    free(lcc->pSuppGids);
1215706f2543Smrg	}
1216706f2543Smrg	free(lcc);
1217706f2543Smrg    }
1218706f2543Smrg}
1219706f2543Smrg
1220706f2543Smrgstatic int
1221706f2543SmrgAuthorizedClient(ClientPtr client)
1222706f2543Smrg{
1223706f2543Smrg    int rc;
1224706f2543Smrg
1225706f2543Smrg    if (!client || defeatAccessControl)
1226706f2543Smrg	return Success;
1227706f2543Smrg
1228706f2543Smrg    /* untrusted clients can't change host access */
1229706f2543Smrg    rc = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess);
1230706f2543Smrg    if (rc != Success)
1231706f2543Smrg	return rc;
1232706f2543Smrg
1233706f2543Smrg    return LocalClient(client) ? Success : BadAccess;
1234706f2543Smrg}
1235706f2543Smrg
1236706f2543Smrg/* Add a host to the access control list.  This is the external interface
1237706f2543Smrg * called from the dispatcher */
1238706f2543Smrg
1239706f2543Smrgint
1240706f2543SmrgAddHost (ClientPtr	client,
1241706f2543Smrg	 int            family,
1242706f2543Smrg	 unsigned       length,        /* of bytes in pAddr */
1243706f2543Smrg	 const void *   pAddr)
1244706f2543Smrg{
1245706f2543Smrg    int rc, len;
1246706f2543Smrg
1247706f2543Smrg    rc = AuthorizedClient(client);
1248706f2543Smrg    if (rc != Success)
1249706f2543Smrg	return rc;
1250706f2543Smrg    switch (family) {
1251706f2543Smrg    case FamilyLocalHost:
1252706f2543Smrg	len = length;
1253706f2543Smrg	LocalHostEnabled = TRUE;
1254706f2543Smrg	break;
1255706f2543Smrg#ifdef SECURE_RPC
1256706f2543Smrg    case FamilyNetname:
1257706f2543Smrg	len = length;
1258706f2543Smrg	SecureRPCInit ();
1259706f2543Smrg	break;
1260706f2543Smrg#endif
1261706f2543Smrg    case FamilyInternet:
1262706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
1263706f2543Smrg    case FamilyInternet6:
1264706f2543Smrg#endif
1265706f2543Smrg    case FamilyDECnet:
1266706f2543Smrg    case FamilyChaos:
1267706f2543Smrg    case FamilyServerInterpreted:
1268706f2543Smrg	if ((len = CheckAddr (family, pAddr, length)) < 0)
1269706f2543Smrg	{
1270706f2543Smrg	    client->errorValue = length;
1271706f2543Smrg	    return BadValue;
1272706f2543Smrg	}
1273706f2543Smrg	break;
1274706f2543Smrg    case FamilyLocal:
1275706f2543Smrg    default:
1276706f2543Smrg	client->errorValue = family;
1277706f2543Smrg	return BadValue;
1278706f2543Smrg    }
1279706f2543Smrg    if (NewHost (family, pAddr, len, FALSE))
1280706f2543Smrg	return Success;
1281706f2543Smrg    return BadAlloc;
1282706f2543Smrg}
1283706f2543Smrg
1284706f2543SmrgBool
1285706f2543SmrgForEachHostInFamily (int	    family,
1286706f2543Smrg		     Bool    (*func)(
1287706f2543Smrg			 unsigned char * /* addr */,
1288706f2543Smrg			 short           /* len */,
1289706f2543Smrg			 pointer         /* closure */),
1290706f2543Smrg		     pointer closure)
1291706f2543Smrg{
1292706f2543Smrg    HOST    *host;
1293706f2543Smrg
1294706f2543Smrg    for (host = validhosts; host; host = host->next)
1295706f2543Smrg	if (family == host->family && func (host->addr, host->len, closure))
1296706f2543Smrg	    return TRUE;
1297706f2543Smrg    return FALSE;
1298706f2543Smrg}
1299706f2543Smrg
1300706f2543Smrg/* Add a host to the access control list. This is the internal interface
1301706f2543Smrg * called when starting or resetting the server */
1302706f2543Smrgstatic Bool
1303706f2543SmrgNewHost (int		family,
1304706f2543Smrg	 const void *	addr,
1305706f2543Smrg	 int		len,
1306706f2543Smrg	 int		addingLocalHosts)
1307706f2543Smrg{
1308706f2543Smrg    register HOST *host;
1309706f2543Smrg
1310706f2543Smrg    for (host = validhosts; host; host = host->next)
1311706f2543Smrg    {
1312706f2543Smrg        if (addrEqual (family, addr, len, host))
1313706f2543Smrg	    return TRUE;
1314706f2543Smrg    }
1315706f2543Smrg    if (!addingLocalHosts) {			/* Fix for XFree86 bug #156 */
1316706f2543Smrg	for (host = selfhosts; host; host = host->next) {
1317706f2543Smrg	    if (addrEqual (family, addr, len, host)) {
1318706f2543Smrg		host->requested = TRUE;
1319706f2543Smrg		break;
1320706f2543Smrg	    }
1321706f2543Smrg	}
1322706f2543Smrg    }
1323706f2543Smrg    MakeHost(host,len)
1324706f2543Smrg    if (!host)
1325706f2543Smrg	return FALSE;
1326706f2543Smrg    host->family = family;
1327706f2543Smrg    host->len = len;
1328706f2543Smrg    acopy(addr, host->addr, len);
1329706f2543Smrg    host->next = validhosts;
1330706f2543Smrg    validhosts = host;
1331706f2543Smrg    return TRUE;
1332706f2543Smrg}
1333706f2543Smrg
1334706f2543Smrg/* Remove a host from the access control list */
1335706f2543Smrg
1336706f2543Smrgint
1337706f2543SmrgRemoveHost (
1338706f2543Smrg    ClientPtr		client,
1339706f2543Smrg    int                 family,
1340706f2543Smrg    unsigned            length,        /* of bytes in pAddr */
1341706f2543Smrg    pointer             pAddr)
1342706f2543Smrg{
1343706f2543Smrg    int rc, len;
1344706f2543Smrg    register HOST	*host, **prev;
1345706f2543Smrg
1346706f2543Smrg    rc = AuthorizedClient(client);
1347706f2543Smrg    if (rc != Success)
1348706f2543Smrg	return rc;
1349706f2543Smrg    switch (family) {
1350706f2543Smrg    case FamilyLocalHost:
1351706f2543Smrg	len = length;
1352706f2543Smrg	LocalHostEnabled = FALSE;
1353706f2543Smrg	break;
1354706f2543Smrg#ifdef SECURE_RPC
1355706f2543Smrg    case FamilyNetname:
1356706f2543Smrg	len = length;
1357706f2543Smrg	break;
1358706f2543Smrg#endif
1359706f2543Smrg    case FamilyInternet:
1360706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
1361706f2543Smrg    case FamilyInternet6:
1362706f2543Smrg#endif
1363706f2543Smrg    case FamilyDECnet:
1364706f2543Smrg    case FamilyChaos:
1365706f2543Smrg    case FamilyServerInterpreted:
1366706f2543Smrg    	if ((len = CheckAddr (family, pAddr, length)) < 0)
1367706f2543Smrg    	{
1368706f2543Smrg	    client->errorValue = length;
1369706f2543Smrg            return BadValue;
1370706f2543Smrg    	}
1371706f2543Smrg	break;
1372706f2543Smrg    case FamilyLocal:
1373706f2543Smrg    default:
1374706f2543Smrg	client->errorValue = family;
1375706f2543Smrg        return BadValue;
1376706f2543Smrg    }
1377706f2543Smrg    for (prev = &validhosts;
1378706f2543Smrg         (host = *prev) && (!addrEqual (family, pAddr, len, host));
1379706f2543Smrg         prev = &host->next)
1380706f2543Smrg        ;
1381706f2543Smrg    if (host)
1382706f2543Smrg    {
1383706f2543Smrg        *prev = host->next;
1384706f2543Smrg        FreeHost (host);
1385706f2543Smrg    }
1386706f2543Smrg    return Success;
1387706f2543Smrg}
1388706f2543Smrg
1389706f2543Smrg/* Get all hosts in the access control list */
1390706f2543Smrgint
1391706f2543SmrgGetHosts (
1392706f2543Smrg    pointer		*data,
1393706f2543Smrg    int			*pnHosts,
1394706f2543Smrg    int			*pLen,
1395706f2543Smrg    BOOL		*pEnabled)
1396706f2543Smrg{
1397706f2543Smrg    int			len;
1398706f2543Smrg    register int 	n = 0;
1399706f2543Smrg    register unsigned char *ptr;
1400706f2543Smrg    register HOST	*host;
1401706f2543Smrg    int			nHosts = 0;
1402706f2543Smrg
1403706f2543Smrg    *pEnabled = AccessEnabled ? EnableAccess : DisableAccess;
1404706f2543Smrg    for (host = validhosts; host; host = host->next)
1405706f2543Smrg    {
1406706f2543Smrg	nHosts++;
1407706f2543Smrg	n += pad_to_int32(host->len) + sizeof(xHostEntry);
1408706f2543Smrg        /* Could check for INT_MAX, but in reality having more than 1mb of
1409706f2543Smrg           hostnames in the access list is ridiculous */
1410706f2543Smrg        if (n >= 1048576)
1411706f2543Smrg            break;
1412706f2543Smrg    }
1413706f2543Smrg    if (n)
1414706f2543Smrg    {
1415706f2543Smrg        *data = ptr = malloc(n);
1416706f2543Smrg	if (!ptr)
1417706f2543Smrg	{
1418706f2543Smrg	    return BadAlloc;
1419706f2543Smrg	}
1420706f2543Smrg        for (host = validhosts; host; host = host->next)
1421706f2543Smrg	{
1422706f2543Smrg	    len = host->len;
1423706f2543Smrg            if ((ptr + sizeof(xHostEntry) + len) > ((unsigned char *) *data + n))
1424706f2543Smrg                break;
1425706f2543Smrg	    ((xHostEntry *)ptr)->family = host->family;
1426706f2543Smrg	    ((xHostEntry *)ptr)->length = len;
1427706f2543Smrg	    ptr += sizeof(xHostEntry);
1428706f2543Smrg	    acopy (host->addr, ptr, len);
1429706f2543Smrg	    ptr += pad_to_int32(len);
1430706f2543Smrg        }
1431706f2543Smrg    } else {
1432706f2543Smrg	*data = NULL;
1433706f2543Smrg    }
1434706f2543Smrg    *pnHosts = nHosts;
1435706f2543Smrg    *pLen = n;
1436706f2543Smrg    return Success;
1437706f2543Smrg}
1438706f2543Smrg
1439706f2543Smrg/* Check for valid address family and length, and return address length. */
1440706f2543Smrg
1441706f2543Smrg/*ARGSUSED*/
1442706f2543Smrgstatic int
1443706f2543SmrgCheckAddr (
1444706f2543Smrg    int			family,
1445706f2543Smrg    const void *	pAddr,
1446706f2543Smrg    unsigned		length)
1447706f2543Smrg{
1448706f2543Smrg    int	len;
1449706f2543Smrg
1450706f2543Smrg    switch (family)
1451706f2543Smrg    {
1452706f2543Smrg#if defined(TCPCONN) || defined(STREAMSCONN)
1453706f2543Smrg      case FamilyInternet:
1454706f2543Smrg	if (length == sizeof (struct in_addr))
1455706f2543Smrg	    len = length;
1456706f2543Smrg	else
1457706f2543Smrg	    len = -1;
1458706f2543Smrg        break;
1459706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
1460706f2543Smrg      case FamilyInternet6:
1461706f2543Smrg	if (length == sizeof (struct in6_addr))
1462706f2543Smrg	    len = length;
1463706f2543Smrg	else
1464706f2543Smrg	    len = -1;
1465706f2543Smrg        break;
1466706f2543Smrg#endif
1467706f2543Smrg#endif
1468706f2543Smrg      case FamilyServerInterpreted:
1469706f2543Smrg	len = siCheckAddr(pAddr, length);
1470706f2543Smrg	break;
1471706f2543Smrg      default:
1472706f2543Smrg        len = -1;
1473706f2543Smrg    }
1474706f2543Smrg    return len;
1475706f2543Smrg}
1476706f2543Smrg
1477706f2543Smrg/* Check if a host is not in the access control list.
1478706f2543Smrg * Returns 1 if host is invalid, 0 if we've found it. */
1479706f2543Smrg
1480706f2543Smrgint
1481706f2543SmrgInvalidHost (
1482706f2543Smrg    register struct sockaddr	*saddr,
1483706f2543Smrg    int				len,
1484706f2543Smrg    ClientPtr			client)
1485706f2543Smrg{
1486706f2543Smrg    int 			family;
1487706f2543Smrg    pointer			addr;
1488706f2543Smrg    register HOST 		*selfhost, *host;
1489706f2543Smrg
1490706f2543Smrg    if (!AccessEnabled)   /* just let them in */
1491706f2543Smrg        return 0;
1492706f2543Smrg    family = ConvertAddr (saddr, &len, (pointer *)&addr);
1493706f2543Smrg    if (family == -1)
1494706f2543Smrg        return 1;
1495706f2543Smrg    if (family == FamilyLocal)
1496706f2543Smrg    {
1497706f2543Smrg	if (!LocalHostEnabled)
1498706f2543Smrg 	{
1499706f2543Smrg	    /*
1500706f2543Smrg	     * check to see if any local address is enabled.  This
1501706f2543Smrg	     * implicitly enables local connections.
1502706f2543Smrg	     */
1503706f2543Smrg	    for (selfhost = selfhosts; selfhost; selfhost=selfhost->next)
1504706f2543Smrg 	    {
1505706f2543Smrg		for (host = validhosts; host; host=host->next)
1506706f2543Smrg		{
1507706f2543Smrg		    if (addrEqual (selfhost->family, selfhost->addr,
1508706f2543Smrg				   selfhost->len, host))
1509706f2543Smrg			return 0;
1510706f2543Smrg		}
1511706f2543Smrg	    }
1512706f2543Smrg	} else
1513706f2543Smrg	    return 0;
1514706f2543Smrg    }
1515706f2543Smrg    for (host = validhosts; host; host = host->next)
1516706f2543Smrg    {
1517706f2543Smrg	if (host->family == FamilyServerInterpreted) {
1518706f2543Smrg	    if (siAddrMatch (family, addr, len, host, client)) {
1519706f2543Smrg		return 0;
1520706f2543Smrg	    }
1521706f2543Smrg	} else {
1522706f2543Smrg	    if (addrEqual (family, addr, len, host))
1523706f2543Smrg		return 0;
1524706f2543Smrg	}
1525706f2543Smrg
1526706f2543Smrg    }
1527706f2543Smrg    return 1;
1528706f2543Smrg}
1529706f2543Smrg
1530706f2543Smrgstatic int
1531706f2543SmrgConvertAddr (
1532706f2543Smrg    register struct sockaddr	*saddr,
1533706f2543Smrg    int				*len,
1534706f2543Smrg    pointer			*addr)
1535706f2543Smrg{
1536706f2543Smrg    if (*len == 0)
1537706f2543Smrg        return FamilyLocal;
1538706f2543Smrg    switch (saddr->sa_family)
1539706f2543Smrg    {
1540706f2543Smrg    case AF_UNSPEC:
1541706f2543Smrg#if defined(UNIXCONN) || defined(LOCALCONN)
1542706f2543Smrg    case AF_UNIX:
1543706f2543Smrg#endif
1544706f2543Smrg        return FamilyLocal;
1545706f2543Smrg#if defined(TCPCONN) || defined(STREAMSCONN)
1546706f2543Smrg    case AF_INET:
1547706f2543Smrg#ifdef WIN32
1548706f2543Smrg        if (16777343 == *(long*)&((struct sockaddr_in *) saddr)->sin_addr)
1549706f2543Smrg            return FamilyLocal;
1550706f2543Smrg#endif
1551706f2543Smrg        *len = sizeof (struct in_addr);
1552706f2543Smrg        *addr = (pointer) &(((struct sockaddr_in *) saddr)->sin_addr);
1553706f2543Smrg        return FamilyInternet;
1554706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
1555706f2543Smrg    case AF_INET6:
1556706f2543Smrg    {
1557706f2543Smrg	struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) saddr;
1558706f2543Smrg	if (IN6_IS_ADDR_V4MAPPED(&(saddr6->sin6_addr))) {
1559706f2543Smrg	    *len = sizeof (struct in_addr);
1560706f2543Smrg	    *addr = (pointer) &(saddr6->sin6_addr.s6_addr[12]);
1561706f2543Smrg	    return FamilyInternet;
1562706f2543Smrg	} else {
1563706f2543Smrg	    *len = sizeof (struct in6_addr);
1564706f2543Smrg	    *addr = (pointer) &(saddr6->sin6_addr);
1565706f2543Smrg	    return FamilyInternet6;
1566706f2543Smrg	}
1567706f2543Smrg    }
1568706f2543Smrg#endif
1569706f2543Smrg#endif
1570706f2543Smrg    default:
1571706f2543Smrg        return -1;
1572706f2543Smrg    }
1573706f2543Smrg}
1574706f2543Smrg
1575706f2543Smrgint
1576706f2543SmrgChangeAccessControl(
1577706f2543Smrg    ClientPtr client,
1578706f2543Smrg    int fEnabled)
1579706f2543Smrg{
1580706f2543Smrg    int rc = AuthorizedClient(client);
1581706f2543Smrg    if (rc != Success)
1582706f2543Smrg	return rc;
1583706f2543Smrg    AccessEnabled = fEnabled;
1584706f2543Smrg    return Success;
1585706f2543Smrg}
1586706f2543Smrg
1587706f2543Smrg/* returns FALSE if xhost + in effect, else TRUE */
1588706f2543Smrgint
1589706f2543SmrgGetAccessControl(void)
1590706f2543Smrg{
1591706f2543Smrg    return AccessEnabled;
1592706f2543Smrg}
1593706f2543Smrg
1594706f2543Smrg/*****************************************************************************
1595706f2543Smrg * FamilyServerInterpreted host entry implementation
1596706f2543Smrg *
1597706f2543Smrg * Supports an extensible system of host types which the server can interpret
1598706f2543Smrg * See the IPv6 extensions to the X11 protocol spec for the definition.
1599706f2543Smrg *
1600706f2543Smrg * Currently supported schemes:
1601706f2543Smrg *
1602706f2543Smrg * hostname	- hostname as defined in IETF RFC 2396
1603706f2543Smrg * ipv6		- IPv6 literal address as defined in IETF RFC's 3513 and <TBD>
1604706f2543Smrg *
1605706f2543Smrg * See xc/doc/specs/SIAddresses for formal definitions of each type.
1606706f2543Smrg */
1607706f2543Smrg
1608706f2543Smrg/* These definitions and the siTypeAdd function could be exported in the
1609706f2543Smrg * future to enable loading additional host types, but that was not done for
1610706f2543Smrg * the initial implementation.
1611706f2543Smrg */
1612706f2543Smrgtypedef Bool (*siAddrMatchFunc)(int family, pointer addr, int len,
1613706f2543Smrg  const char *siAddr, int siAddrlen, ClientPtr client, void *siTypePriv);
1614706f2543Smrgtypedef int  (*siCheckAddrFunc)(const char *addrString, int length,
1615706f2543Smrg  void *siTypePriv);
1616706f2543Smrg
1617706f2543Smrgstruct siType {
1618706f2543Smrg    struct siType *	next;
1619706f2543Smrg    const char *	typeName;
1620706f2543Smrg    siAddrMatchFunc	addrMatch;
1621706f2543Smrg    siCheckAddrFunc	checkAddr;
1622706f2543Smrg    void *		typePriv;	/* Private data for type routines */
1623706f2543Smrg};
1624706f2543Smrg
1625706f2543Smrgstatic struct siType *siTypeList;
1626706f2543Smrg
1627706f2543Smrgstatic int
1628706f2543SmrgsiTypeAdd(const char *typeName, siAddrMatchFunc addrMatch,
1629706f2543Smrg  siCheckAddrFunc checkAddr, void *typePriv)
1630706f2543Smrg{
1631706f2543Smrg    struct siType *s, *p;
1632706f2543Smrg
1633706f2543Smrg    if ((typeName == NULL) || (addrMatch == NULL) || (checkAddr == NULL))
1634706f2543Smrg	return BadValue;
1635706f2543Smrg
1636706f2543Smrg    for (s = siTypeList, p = NULL; s != NULL ; p = s, s = s->next) {
1637706f2543Smrg	if (strcmp(typeName, s->typeName) == 0) {
1638706f2543Smrg	    s->addrMatch = addrMatch;
1639706f2543Smrg	    s->checkAddr = checkAddr;
1640706f2543Smrg	    s->typePriv = typePriv;
1641706f2543Smrg	    return Success;
1642706f2543Smrg	}
1643706f2543Smrg    }
1644706f2543Smrg
1645706f2543Smrg    s = malloc(sizeof(struct siType));
1646706f2543Smrg    if (s == NULL)
1647706f2543Smrg	return BadAlloc;
1648706f2543Smrg
1649706f2543Smrg    if (p == NULL)
1650706f2543Smrg	siTypeList = s;
1651706f2543Smrg    else
1652706f2543Smrg	p->next = s;
1653706f2543Smrg
1654706f2543Smrg    s->next = NULL;
1655706f2543Smrg    s->typeName = typeName;
1656706f2543Smrg    s->addrMatch = addrMatch;
1657706f2543Smrg    s->checkAddr = checkAddr;
1658706f2543Smrg    s->typePriv = typePriv;
1659706f2543Smrg    return Success;
1660706f2543Smrg}
1661706f2543Smrg
1662706f2543Smrg/* Checks to see if a host matches a server-interpreted host entry */
1663706f2543Smrgstatic Bool
1664706f2543SmrgsiAddrMatch(int family, pointer addr, int len, HOST *host, ClientPtr client)
1665706f2543Smrg{
1666706f2543Smrg    Bool matches = FALSE;
1667706f2543Smrg    struct siType *s;
1668706f2543Smrg    const char *valueString;
1669706f2543Smrg    int addrlen;
1670706f2543Smrg
1671706f2543Smrg    valueString = (const char *) memchr(host->addr, '\0', host->len);
1672706f2543Smrg    if (valueString != NULL) {
1673706f2543Smrg	for (s = siTypeList; s != NULL ; s = s->next) {
1674706f2543Smrg	    if (strcmp((char *) host->addr, s->typeName) == 0) {
1675706f2543Smrg		addrlen = host->len - (strlen((char *)host->addr) + 1);
1676706f2543Smrg		matches = s->addrMatch(family, addr, len,
1677706f2543Smrg		  valueString + 1, addrlen, client, s->typePriv);
1678706f2543Smrg		break;
1679706f2543Smrg	    }
1680706f2543Smrg	}
1681706f2543Smrg#ifdef FAMILY_SI_DEBUG
1682706f2543Smrg	ErrorF(
1683706f2543Smrg	    "Xserver: siAddrMatch(): type = %s, value = %*.*s -- %s\n",
1684706f2543Smrg	      host->addr, addrlen, addrlen, valueString + 1,
1685706f2543Smrg	      (matches) ? "accepted" : "rejected");
1686706f2543Smrg#endif
1687706f2543Smrg    }
1688706f2543Smrg    return matches;
1689706f2543Smrg}
1690706f2543Smrg
1691706f2543Smrgstatic int
1692706f2543SmrgsiCheckAddr(const char *addrString, int length)
1693706f2543Smrg{
1694706f2543Smrg    const char *valueString;
1695706f2543Smrg    int addrlen, typelen;
1696706f2543Smrg    int len = -1;
1697706f2543Smrg    struct siType *s;
1698706f2543Smrg
1699706f2543Smrg    /* Make sure there is a \0 byte inside the specified length
1700706f2543Smrg       to separate the address type from the address value. */
1701706f2543Smrg    valueString = (const char *) memchr(addrString, '\0', length);
1702706f2543Smrg    if (valueString != NULL) {
1703706f2543Smrg	/* Make sure the first string is a recognized address type,
1704706f2543Smrg	 * and the second string is a valid address of that type.
1705706f2543Smrg	 */
1706706f2543Smrg	typelen = strlen(addrString) + 1;
1707706f2543Smrg	addrlen = length - typelen;
1708706f2543Smrg
1709706f2543Smrg	for (s = siTypeList; s != NULL ; s = s->next) {
1710706f2543Smrg	    if (strcmp(addrString, s->typeName) == 0) {
1711706f2543Smrg		len = s->checkAddr(valueString + 1, addrlen, s->typePriv);
1712706f2543Smrg		if (len >= 0) {
1713706f2543Smrg		    len += typelen;
1714706f2543Smrg		}
1715706f2543Smrg		break;
1716706f2543Smrg	    }
1717706f2543Smrg	}
1718706f2543Smrg#ifdef FAMILY_SI_DEBUG
1719706f2543Smrg	{
1720706f2543Smrg	    const char *resultMsg;
1721706f2543Smrg
1722706f2543Smrg	    if (s == NULL) {
1723706f2543Smrg		resultMsg = "type not registered";
1724706f2543Smrg	    } else {
1725706f2543Smrg		if (len == -1)
1726706f2543Smrg		    resultMsg = "rejected";
1727706f2543Smrg		else
1728706f2543Smrg		    resultMsg = "accepted";
1729706f2543Smrg	    }
1730706f2543Smrg
1731706f2543Smrg	    ErrorF("Xserver: siCheckAddr(): type = %s, value = %*.*s, len = %d -- %s\n",
1732706f2543Smrg	      addrString, addrlen, addrlen, valueString + 1, len, resultMsg);
1733706f2543Smrg	}
1734706f2543Smrg#endif
1735706f2543Smrg    }
1736706f2543Smrg    return len;
1737706f2543Smrg}
1738706f2543Smrg
1739706f2543Smrg
1740706f2543Smrg/***
1741706f2543Smrg * Hostname server-interpreted host type
1742706f2543Smrg *
1743706f2543Smrg * Stored as hostname string, explicitly defined to be resolved ONLY
1744706f2543Smrg * at access check time, to allow for hosts with dynamic addresses
1745706f2543Smrg * but static hostnames, such as found in some DHCP & mobile setups.
1746706f2543Smrg *
1747706f2543Smrg * Hostname must conform to IETF RFC 2396 sec. 3.2.2, which defines it as:
1748706f2543Smrg * 	hostname     = *( domainlabel "." ) toplabel [ "." ]
1749706f2543Smrg *	domainlabel  = alphanum | alphanum *( alphanum | "-" ) alphanum
1750706f2543Smrg *	toplabel     = alpha | alpha *( alphanum | "-" ) alphanum
1751706f2543Smrg */
1752706f2543Smrg
1753706f2543Smrg#ifdef NI_MAXHOST
1754706f2543Smrg# define SI_HOSTNAME_MAXLEN NI_MAXHOST
1755706f2543Smrg#else
1756706f2543Smrg# ifdef MAXHOSTNAMELEN
1757706f2543Smrg#  define SI_HOSTNAME_MAXLEN MAXHOSTNAMELEN
1758706f2543Smrg# else
1759706f2543Smrg#  define SI_HOSTNAME_MAXLEN 256
1760706f2543Smrg# endif
1761706f2543Smrg#endif
1762706f2543Smrg
1763706f2543Smrgstatic Bool
1764706f2543SmrgsiHostnameAddrMatch(int family, pointer addr, int len,
1765706f2543Smrg  const char *siAddr, int siAddrLen, ClientPtr client, void *typePriv)
1766706f2543Smrg{
1767706f2543Smrg    Bool res = FALSE;
1768706f2543Smrg
1769706f2543Smrg/* Currently only supports checking against IPv4 & IPv6 connections, but
1770706f2543Smrg * support for other address families, such as DECnet, could be added if
1771706f2543Smrg * desired.
1772706f2543Smrg */
1773706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
1774706f2543Smrg    if ((family == FamilyInternet) || (family == FamilyInternet6)) {
1775706f2543Smrg	char hostname[SI_HOSTNAME_MAXLEN];
1776706f2543Smrg	struct addrinfo *addresses;
1777706f2543Smrg	struct addrinfo *a;
1778706f2543Smrg	int f, hostaddrlen;
1779706f2543Smrg	pointer hostaddr;
1780706f2543Smrg
1781706f2543Smrg	if (siAddrLen >= sizeof(hostname))
1782706f2543Smrg	    return FALSE;
1783706f2543Smrg
1784706f2543Smrg	strncpy(hostname, siAddr, siAddrLen);
1785706f2543Smrg	hostname[siAddrLen] = '\0';
1786706f2543Smrg
1787706f2543Smrg	if (getaddrinfo(hostname, NULL, NULL, &addresses) == 0) {
1788706f2543Smrg	    for (a = addresses ; a != NULL ; a = a->ai_next) {
1789706f2543Smrg		hostaddrlen = a->ai_addrlen;
1790706f2543Smrg		f = ConvertAddr(a->ai_addr,&hostaddrlen,&hostaddr);
1791706f2543Smrg		if ((f == family) && (len == hostaddrlen) &&
1792706f2543Smrg		  (acmp (addr, hostaddr, len) == 0) ) {
1793706f2543Smrg		    res = TRUE;
1794706f2543Smrg		    break;
1795706f2543Smrg		}
1796706f2543Smrg	    }
1797706f2543Smrg	    freeaddrinfo(addresses);
1798706f2543Smrg	}
1799706f2543Smrg    }
1800706f2543Smrg#else /* IPv6 not supported, use gethostbyname instead for IPv4 */
1801706f2543Smrg    if (family == FamilyInternet) {
1802706f2543Smrg	register struct hostent *hp;
1803706f2543Smrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1804706f2543Smrg	_Xgethostbynameparams hparams;
1805706f2543Smrg#endif
1806706f2543Smrg	char hostname[SI_HOSTNAME_MAXLEN];
1807706f2543Smrg	int f, hostaddrlen;
1808706f2543Smrg	pointer hostaddr;
1809706f2543Smrg	const char **addrlist;
1810706f2543Smrg
1811706f2543Smrg	if (siAddrLen >= sizeof(hostname))
1812706f2543Smrg	    return FALSE;
1813706f2543Smrg
1814706f2543Smrg	strncpy(hostname, siAddr, siAddrLen);
1815706f2543Smrg	hostname[siAddrLen] = '\0';
1816706f2543Smrg
1817706f2543Smrg	if ((hp = _XGethostbyname(hostname, hparams)) != NULL) {
1818706f2543Smrg#ifdef h_addr				/* new 4.3bsd version of gethostent */
1819706f2543Smrg	    /* iterate over the addresses */
1820706f2543Smrg	    for (addrlist = hp->h_addr_list; *addrlist; addrlist++)
1821706f2543Smrg#else
1822706f2543Smrg	    addrlist = &hp->h_addr;
1823706f2543Smrg#endif
1824706f2543Smrg	    {
1825706f2543Smrg		struct  sockaddr_in  sin;
1826706f2543Smrg
1827706f2543Smrg    		sin.sin_family = hp->h_addrtype;
1828706f2543Smrg		acopy ( *addrlist, &(sin.sin_addr), hp->h_length);
1829706f2543Smrg		hostaddrlen = sizeof(sin);
1830706f2543Smrg    		f = ConvertAddr ((struct sockaddr *)&sin,
1831706f2543Smrg		  &hostaddrlen, &hostaddr);
1832706f2543Smrg		if ((f == family) && (len == hostaddrlen) &&
1833706f2543Smrg		  (acmp (addr, hostaddr, len) == 0) ) {
1834706f2543Smrg		    res = TRUE;
1835706f2543Smrg		    break;
1836706f2543Smrg		}
1837706f2543Smrg    	    }
1838706f2543Smrg        }
1839706f2543Smrg    }
1840706f2543Smrg#endif
1841706f2543Smrg    return res;
1842706f2543Smrg}
1843706f2543Smrg
1844706f2543Smrg
1845706f2543Smrgstatic int
1846706f2543SmrgsiHostnameCheckAddr(const char *valueString, int length, void *typePriv)
1847706f2543Smrg{
1848706f2543Smrg    /* Check conformance of hostname to RFC 2396 sec. 3.2.2 definition.
1849706f2543Smrg     * We do not use ctype functions here to avoid locale-specific
1850706f2543Smrg     * character sets.  Hostnames must be pure ASCII.
1851706f2543Smrg     */
1852706f2543Smrg    int len = length;
1853706f2543Smrg    int i;
1854706f2543Smrg    Bool dotAllowed = FALSE;
1855706f2543Smrg    Bool dashAllowed = FALSE;
1856706f2543Smrg
1857706f2543Smrg    if ((length <= 0) || (length >= SI_HOSTNAME_MAXLEN)) {
1858706f2543Smrg	len = -1;
1859706f2543Smrg    } else {
1860706f2543Smrg	for (i = 0; i < length; i++) {
1861706f2543Smrg	    char c = valueString[i];
1862706f2543Smrg
1863706f2543Smrg	    if (c == 0x2E) { /* '.' */
1864706f2543Smrg		if (dotAllowed == FALSE) {
1865706f2543Smrg		    len = -1;
1866706f2543Smrg		    break;
1867706f2543Smrg		} else {
1868706f2543Smrg		    dotAllowed = FALSE;
1869706f2543Smrg		    dashAllowed = FALSE;
1870706f2543Smrg		}
1871706f2543Smrg	    } else if (c == 0x2D) { /* '-' */
1872706f2543Smrg		if (dashAllowed == FALSE) {
1873706f2543Smrg		    len = -1;
1874706f2543Smrg		    break;
1875706f2543Smrg		} else {
1876706f2543Smrg		    dotAllowed = FALSE;
1877706f2543Smrg		}
1878706f2543Smrg	    } else if (((c >= 0x30) && (c <= 0x3A)) /* 0-9 */ ||
1879706f2543Smrg		       ((c >= 0x61) && (c <= 0x7A)) /* a-z */ ||
1880706f2543Smrg		       ((c >= 0x41) && (c <= 0x5A)) /* A-Z */) {
1881706f2543Smrg		dotAllowed = TRUE;
1882706f2543Smrg		dashAllowed = TRUE;
1883706f2543Smrg	    } else { /* Invalid character */
1884706f2543Smrg		len = -1;
1885706f2543Smrg		break;
1886706f2543Smrg	    }
1887706f2543Smrg	}
1888706f2543Smrg    }
1889706f2543Smrg    return len;
1890706f2543Smrg}
1891706f2543Smrg
1892706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
1893706f2543Smrg/***
1894706f2543Smrg * "ipv6" server interpreted type
1895706f2543Smrg *
1896706f2543Smrg * Currently supports only IPv6 literal address as specified in IETF RFC 3513
1897706f2543Smrg *
1898706f2543Smrg * Once draft-ietf-ipv6-scoping-arch-00.txt becomes an RFC, support will be
1899706f2543Smrg * added for the scoped address format it specifies.
1900706f2543Smrg */
1901706f2543Smrg
1902706f2543Smrg/* Maximum length of an IPv6 address string - increase when adding support
1903706f2543Smrg * for scoped address qualifiers.  Includes room for trailing NUL byte.
1904706f2543Smrg */
1905706f2543Smrg#define SI_IPv6_MAXLEN INET6_ADDRSTRLEN
1906706f2543Smrg
1907706f2543Smrgstatic Bool
1908706f2543SmrgsiIPv6AddrMatch(int family, pointer addr, int len,
1909706f2543Smrg  const char *siAddr, int siAddrlen, ClientPtr client, void *typePriv)
1910706f2543Smrg{
1911706f2543Smrg    struct in6_addr addr6;
1912706f2543Smrg    char addrbuf[SI_IPv6_MAXLEN];
1913706f2543Smrg
1914706f2543Smrg    if ((family != FamilyInternet6) || (len != sizeof(addr6)))
1915706f2543Smrg	return FALSE;
1916706f2543Smrg
1917706f2543Smrg    memcpy(addrbuf, siAddr, siAddrlen);
1918706f2543Smrg    addrbuf[siAddrlen] = '\0';
1919706f2543Smrg
1920706f2543Smrg    if (inet_pton(AF_INET6, addrbuf, &addr6) != 1) {
1921706f2543Smrg	perror("inet_pton");
1922706f2543Smrg	return FALSE;
1923706f2543Smrg    }
1924706f2543Smrg
1925706f2543Smrg    if (memcmp(addr, &addr6, len) == 0) {
1926706f2543Smrg	return TRUE;
1927706f2543Smrg    } else {
1928706f2543Smrg	return FALSE;
1929706f2543Smrg    }
1930706f2543Smrg}
1931706f2543Smrg
1932706f2543Smrgstatic int
1933706f2543SmrgsiIPv6CheckAddr(const char *addrString, int length, void *typePriv)
1934706f2543Smrg{
1935706f2543Smrg    int len;
1936706f2543Smrg
1937706f2543Smrg    /* Minimum length is 3 (smallest legal address is "::1") */
1938706f2543Smrg    if (length < 3) {
1939706f2543Smrg	/* Address is too short! */
1940706f2543Smrg	len = -1;
1941706f2543Smrg    } else if (length >= SI_IPv6_MAXLEN) {
1942706f2543Smrg	/* Address is too long! */
1943706f2543Smrg	len = -1;
1944706f2543Smrg    } else {
1945706f2543Smrg	/* Assume inet_pton is sufficient validation */
1946706f2543Smrg	struct in6_addr addr6;
1947706f2543Smrg	char addrbuf[SI_IPv6_MAXLEN];
1948706f2543Smrg
1949706f2543Smrg	memcpy(addrbuf, addrString, length);
1950706f2543Smrg	addrbuf[length] = '\0';
1951706f2543Smrg
1952706f2543Smrg	if (inet_pton(AF_INET6, addrbuf, &addr6) != 1) {
1953706f2543Smrg	    perror("inet_pton");
1954706f2543Smrg	    len = -1;
1955706f2543Smrg	} else {
1956706f2543Smrg	    len = length;
1957706f2543Smrg	}
1958706f2543Smrg    }
1959706f2543Smrg    return len;
1960706f2543Smrg}
1961706f2543Smrg#endif /* IPv6 */
1962706f2543Smrg
1963706f2543Smrg#if !defined(NO_LOCAL_CLIENT_CRED)
1964706f2543Smrg/***
1965706f2543Smrg * "localuser" & "localgroup" server interpreted types
1966706f2543Smrg *
1967706f2543Smrg * Allows local connections from a given local user or group
1968706f2543Smrg */
1969706f2543Smrg
1970706f2543Smrg#include <pwd.h>
1971706f2543Smrg#include <grp.h>
1972706f2543Smrg
1973706f2543Smrg#define LOCAL_USER 1
1974706f2543Smrg#define LOCAL_GROUP 2
1975706f2543Smrg
1976706f2543Smrgtypedef struct {
1977706f2543Smrg    int credType;
1978706f2543Smrg} siLocalCredPrivRec, *siLocalCredPrivPtr;
1979706f2543Smrg
1980706f2543Smrgstatic siLocalCredPrivRec siLocalUserPriv = { LOCAL_USER };
1981706f2543Smrgstatic siLocalCredPrivRec siLocalGroupPriv = { LOCAL_GROUP };
1982706f2543Smrg
1983706f2543Smrgstatic Bool
1984706f2543SmrgsiLocalCredGetId(const char *addr, int len, siLocalCredPrivPtr lcPriv, int *id)
1985706f2543Smrg{
1986706f2543Smrg    Bool parsedOK = FALSE;
1987706f2543Smrg    char *addrbuf = malloc(len + 1);
1988706f2543Smrg
1989706f2543Smrg    if (addrbuf == NULL) {
1990706f2543Smrg	return FALSE;
1991706f2543Smrg    }
1992706f2543Smrg
1993706f2543Smrg    memcpy(addrbuf, addr, len);
1994706f2543Smrg    addrbuf[len] = '\0';
1995706f2543Smrg
1996706f2543Smrg    if (addr[0] == '#') { /* numeric id */
1997706f2543Smrg	char *cp;
1998706f2543Smrg	errno = 0;
1999706f2543Smrg	*id = strtol(addrbuf + 1, &cp, 0);
2000706f2543Smrg	if ((errno == 0) && (cp != (addrbuf+1))) {
2001706f2543Smrg	    parsedOK = TRUE;
2002706f2543Smrg	}
2003706f2543Smrg    } else { /* non-numeric name */
2004706f2543Smrg	if (lcPriv->credType == LOCAL_USER) {
2005706f2543Smrg	    struct passwd *pw = getpwnam(addrbuf);
2006706f2543Smrg
2007706f2543Smrg	    if (pw != NULL) {
2008706f2543Smrg		*id = (int) pw->pw_uid;
2009706f2543Smrg		parsedOK = TRUE;
2010706f2543Smrg	    }
2011706f2543Smrg	} else { /* group */
2012706f2543Smrg	    struct group *gr = getgrnam(addrbuf);
2013706f2543Smrg
2014706f2543Smrg	    if (gr != NULL) {
2015706f2543Smrg		*id = (int) gr->gr_gid;
2016706f2543Smrg		parsedOK = TRUE;
2017706f2543Smrg	    }
2018706f2543Smrg	}
2019706f2543Smrg    }
2020706f2543Smrg
2021706f2543Smrg    free(addrbuf);
2022706f2543Smrg    return parsedOK;
2023706f2543Smrg}
2024706f2543Smrg
2025706f2543Smrgstatic Bool
2026706f2543SmrgsiLocalCredAddrMatch(int family, pointer addr, int len,
2027706f2543Smrg  const char *siAddr, int siAddrlen, ClientPtr client, void *typePriv)
2028706f2543Smrg{
2029706f2543Smrg    int siAddrId;
2030706f2543Smrg    LocalClientCredRec *lcc;
2031706f2543Smrg    siLocalCredPrivPtr lcPriv = (siLocalCredPrivPtr) typePriv;
2032706f2543Smrg
2033706f2543Smrg    if (GetLocalClientCreds(client, &lcc) == -1) {
2034706f2543Smrg	return FALSE;
2035706f2543Smrg    }
2036706f2543Smrg
2037706f2543Smrg#ifdef HAVE_GETZONEID /* Ensure process is in the same zone */
2038706f2543Smrg    if ((lcc->fieldsSet & LCC_ZID_SET) && (lcc->zoneid != getzoneid())) {
2039706f2543Smrg	FreeLocalClientCreds(lcc);
2040706f2543Smrg	return FALSE;
2041706f2543Smrg    }
2042706f2543Smrg#endif
2043706f2543Smrg
2044706f2543Smrg    if (siLocalCredGetId(siAddr, siAddrlen, lcPriv, &siAddrId) == FALSE) {
2045706f2543Smrg	FreeLocalClientCreds(lcc);
2046706f2543Smrg	return FALSE;
2047706f2543Smrg    }
2048706f2543Smrg
2049706f2543Smrg    if (lcPriv->credType == LOCAL_USER) {
2050706f2543Smrg	if ((lcc->fieldsSet & LCC_UID_SET) && (lcc->euid == siAddrId)) {
2051706f2543Smrg	    FreeLocalClientCreds(lcc);
2052706f2543Smrg	    return TRUE;
2053706f2543Smrg	}
2054706f2543Smrg    } else {
2055706f2543Smrg	if ((lcc->fieldsSet & LCC_GID_SET) && (lcc->egid == siAddrId)) {
2056706f2543Smrg	    FreeLocalClientCreds(lcc);
2057706f2543Smrg	    return TRUE;
2058706f2543Smrg	}
2059706f2543Smrg	if (lcc->pSuppGids != NULL) {
2060706f2543Smrg	    int i;
2061706f2543Smrg
2062706f2543Smrg	    for (i = 0 ; i < lcc->nSuppGids; i++) {
2063706f2543Smrg		if (lcc->pSuppGids[i] == siAddrId) {
2064706f2543Smrg		    FreeLocalClientCreds(lcc);
2065706f2543Smrg		    return TRUE;
2066706f2543Smrg		}
2067706f2543Smrg	    }
2068706f2543Smrg	}
2069706f2543Smrg    }
2070706f2543Smrg    FreeLocalClientCreds(lcc);
2071706f2543Smrg    return FALSE;
2072706f2543Smrg}
2073706f2543Smrg
2074706f2543Smrgstatic int
2075706f2543SmrgsiLocalCredCheckAddr(const char *addrString, int length, void *typePriv)
2076706f2543Smrg{
2077706f2543Smrg    int len = length;
2078706f2543Smrg    int id;
2079706f2543Smrg
2080706f2543Smrg    if (siLocalCredGetId(addrString, length,
2081706f2543Smrg	(siLocalCredPrivPtr)typePriv, &id) == FALSE) {
2082706f2543Smrg	len = -1;
2083706f2543Smrg    }
2084706f2543Smrg    return len;
2085706f2543Smrg}
2086706f2543Smrg#endif /* localuser */
2087706f2543Smrg
2088706f2543Smrgstatic void
2089706f2543SmrgsiTypesInitialize(void)
2090706f2543Smrg{
2091706f2543Smrg    siTypeAdd("hostname", siHostnameAddrMatch, siHostnameCheckAddr, NULL);
2092706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
2093706f2543Smrg    siTypeAdd("ipv6", siIPv6AddrMatch, siIPv6CheckAddr, NULL);
2094706f2543Smrg#endif
2095706f2543Smrg#if !defined(NO_LOCAL_CLIENT_CRED)
2096706f2543Smrg    siTypeAdd("localuser", siLocalCredAddrMatch, siLocalCredCheckAddr,
2097706f2543Smrg      &siLocalUserPriv);
2098706f2543Smrg    siTypeAdd("localgroup", siLocalCredAddrMatch, siLocalCredCheckAddr,
2099706f2543Smrg      &siLocalGroupPriv);
2100706f2543Smrg#endif
2101706f2543Smrg}
2102