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