os: if inet_ntop() is available, use it for IPv4 addresses as well
[xserver.git] / os / access.c
blob44d6c24308810f9f5de89893fe75aaf72b1b66fa
1 /***********************************************************
3 Copyright 1987, 1998 The Open Group
5 All rights reserved.
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, and/or sell copies of the Software, and to permit persons
12 to whom the Software is furnished to do so, provided that the above
13 copyright notice(s) and this permission notice appear in all copies of
14 the Software and that both the above copyright notice(s) and this
15 permission notice appear in supporting documentation.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
20 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
22 INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
23 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
24 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 Except as contained in this notice, the name of a copyright holder
28 shall not be used in advertising or otherwise to promote the sale, use
29 or other dealings in this Software without prior written authorization
30 of the copyright holder.
32 X Window System is a trademark of The Open Group.
34 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
36 All Rights Reserved
38 Permission to use, copy, modify, and distribute this software and its
39 documentation for any purpose and without fee is hereby granted,
40 provided that the above copyright notice appear in all copies and that
41 both that copyright notice and this permission notice appear in
42 supporting documentation, and that the name of Digital not be
43 used in advertising or publicity pertaining to distribution of the
44 software without specific, written prior permission.
46 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
52 SOFTWARE.
54 ******************************************************************/
57 * Copyright (c) 2004, Oracle and/or its affiliates.
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:
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.
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.
79 #include <dix-config.h>
81 #ifdef WIN32
82 #include <X11/Xwinsock.h>
83 #endif
85 #include <stdio.h>
86 #include <stdlib.h>
87 #define XSERV_t
88 #define TRANS_SERVER
89 #define TRANS_REOPEN
90 #include <X11/Xtrans/Xtrans.h>
91 #include <X11/Xauth.h>
92 #include <X11/X.h>
93 #include <X11/Xproto.h>
94 #include "misc.h"
95 #include <errno.h>
96 #include <sys/types.h>
97 #ifndef WIN32
98 #include <sys/socket.h>
99 #include <sys/ioctl.h>
100 #include <ctype.h>
102 #ifndef NO_LOCAL_CLIENT_CRED
103 #include <pwd.h>
104 #endif
106 #if defined(TCPCONN)
107 #include <netinet/in.h>
108 #endif /* TCPCONN */
110 #ifdef HAVE_GETPEERUCRED
111 #include <ucred.h>
112 #ifdef __sun
113 #include <zone.h>
114 #endif
115 #endif
117 #ifdef HAVE_SYS_UCRED_H
118 #include <sys/ucred.h>
119 #endif
121 #ifdef HAVE_SYS_UN_H
122 #include <sys/un.h>
123 #endif
125 #if defined(SVR4) || defined(__GNU__)
126 #include <sys/utsname.h>
127 #endif
128 #ifdef __GNU__
129 #undef SIOCGIFCONF
130 #include <netdb.h>
131 #else /*!__GNU__ */
132 #include <net/if.h>
133 #endif /*__GNU__ */
135 #ifdef SVR4
136 #include <sys/sockio.h>
137 #include <sys/stropts.h>
138 #endif
140 #include <netdb.h>
142 #ifdef CSRG_BASED
143 #include <sys/param.h>
144 #if (BSD >= 199103)
145 #define VARIABLE_IFREQ
146 #endif
147 #endif
149 #ifdef BSD44SOCKETS
150 #ifndef VARIABLE_IFREQ
151 #define VARIABLE_IFREQ
152 #endif
153 #endif
155 #ifdef HAVE_GETIFADDRS
156 #include <ifaddrs.h>
157 #else
159 /* Solaris provides an extended interface SIOCGLIFCONF. */
160 #ifdef SIOCGLIFCONF
161 #define USE_SIOCGLIFCONF
162 #endif
163 #endif /* HAVE_GETIFADDRS */
165 #include <arpa/inet.h>
167 #endif /* WIN32 */
169 #if !defined(WIN32) || defined(__CYGWIN__)
170 #include <libgen.h>
171 #endif
173 #define X_INCLUDE_NETDB_H
174 #include <X11/Xos_r.h>
176 #include "os/auth.h"
177 #include "os/client_priv.h"
179 #include "dixstruct.h"
180 #include "osdep.h"
182 #include "xace.h"
183 #include "xdmcp.h"
185 Bool defeatAccessControl = FALSE;
187 #define addrEqual(fam, address, length, host) \
188 ((fam) == (host)->family &&\
189 (length) == (host)->len &&\
190 !memcmp (address, (host)->addr, length))
192 static int ConvertAddr(struct sockaddr * /*saddr */ ,
193 int * /*len */ ,
194 void ** /*addr */ );
196 static int CheckAddr(int /*family */ ,
197 const void * /*pAddr */ ,
198 unsigned /*length */ );
200 static Bool NewHost(int /*family */ ,
201 const void * /*addr */ ,
202 int /*len */ ,
203 int /* addingLocalHosts */ );
205 /* XFree86 bug #156: To keep track of which hosts were explicitly requested in
206 /etc/X<display>.hosts, we've added a requested field to the HOST struct,
207 and a LocalHostRequested variable. These default to FALSE, but are set
208 to TRUE in ResetHosts when reading in /etc/X<display>.hosts. They are
209 checked in DisableLocalHost(), which is called to disable the default
210 local host entries when stronger authentication is turned on. */
212 typedef struct _host {
213 short family;
214 short len;
215 unsigned char *addr;
216 struct _host *next;
217 int requested;
218 } HOST;
220 #define MakeHost(h,l) (h)=malloc(sizeof *(h)+(l));\
221 if (h) { \
222 (h)->addr=(unsigned char *) ((h) + 1);\
223 (h)->requested = FALSE; \
225 #define FreeHost(h) free(h)
226 static HOST *selfhosts = NULL;
227 static HOST *validhosts = NULL;
228 static int AccessEnabled = TRUE;
229 static int LocalHostEnabled = FALSE;
230 static int LocalHostRequested = FALSE;
231 static int UsingXdmcp = FALSE;
233 static enum {
234 LOCAL_ACCESS_SCOPE_HOST = 0,
235 #ifndef NO_LOCAL_CLIENT_CRED
236 LOCAL_ACCESS_SCOPE_USER,
237 #endif
238 } LocalAccessScope;
240 /* FamilyServerInterpreted implementation */
241 static Bool siAddrMatch(int family, void *addr, int len, HOST * host,
242 ClientPtr client);
243 static int siCheckAddr(const char *addrString, int length);
244 static void siTypesInitialize(void);
246 static void EnableLocalHost(void);
247 static void DisableLocalHost(void);
249 #ifndef NO_LOCAL_CLIENT_CRED
250 static void EnableLocalUser(void);
251 static void DisableLocalUser(void);
252 #endif
255 * called when authorization is not enabled to add the
256 * local host to the access list
259 void
260 EnableLocalAccess(void)
262 switch (LocalAccessScope) {
263 case LOCAL_ACCESS_SCOPE_HOST:
264 EnableLocalHost();
265 break;
266 #ifndef NO_LOCAL_CLIENT_CRED
267 case LOCAL_ACCESS_SCOPE_USER:
268 EnableLocalUser();
269 break;
270 #endif
274 static void EnableLocalHost(void)
276 if (!UsingXdmcp) {
277 LocalHostEnabled = TRUE;
278 AddLocalHosts();
283 * called when authorization is enabled to keep us secure
285 void
286 DisableLocalAccess(void)
288 switch (LocalAccessScope) {
289 case LOCAL_ACCESS_SCOPE_HOST:
290 DisableLocalHost();
291 break;
292 #ifndef NO_LOCAL_CLIENT_CRED
293 case LOCAL_ACCESS_SCOPE_USER:
294 DisableLocalUser();
295 break;
296 #endif
300 static void DisableLocalHost(void)
302 HOST *self;
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);
313 #ifndef NO_LOCAL_CLIENT_CRED
314 static int GetLocalUserAddr(char **addr)
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;
322 pw = getpwuid(getuid());
324 if (pw == NULL || pw->pw_name == NULL)
325 goto out;
327 value = pw->pw_name;
329 length = asprintf(addr, "%s%c%s", type, delimiter, value);
331 if (length == -1) {
332 goto out;
335 /* Trailing NUL */
336 length++;
338 out:
339 return length;
342 static void EnableLocalUser(void)
344 char *addr = NULL;
345 int length = -1;
347 length = GetLocalUserAddr(&addr);
349 if (length == -1)
350 return;
352 NewHost(FamilyServerInterpreted, addr, length, TRUE);
354 free(addr);
357 static void DisableLocalUser(void)
359 char *addr = NULL;
360 int length = -1;
362 length = GetLocalUserAddr(&addr);
364 if (length == -1)
365 return;
367 RemoveHost(NULL, FamilyServerInterpreted, length, addr);
369 free(addr);
372 void
373 LocalAccessScopeUser(void)
375 LocalAccessScope = LOCAL_ACCESS_SCOPE_USER;
377 #endif
380 * called at init time when XDMCP will be used; xdmcp always
381 * adds local hosts manually when needed
384 void
385 AccessUsingXdmcp(void)
387 UsingXdmcp = TRUE;
388 LocalHostEnabled = FALSE;
392 * DefineSelf (fd):
394 * Define this host for access control. Find all the hosts the OS knows about
395 * for this fd and add them to the selfhosts list.
398 #if !defined(SIOCGIFCONF)
399 void
400 DefineSelf(int fd)
402 #if !defined(TCPCONN) && !defined(UNIXCONN)
403 return;
404 #else
405 int len;
406 caddr_t addr;
407 int family;
408 register HOST *host;
409 struct utsname name;
410 register struct hostent *hp;
412 union {
413 struct sockaddr sa;
414 struct sockaddr_in in;
415 #if defined(IPv6)
416 struct sockaddr_in6 in6;
417 #endif
418 } saddr;
420 struct sockaddr_in *inetaddr;
421 #if defined(IPv6)
422 struct sockaddr_in6 *inet6addr;
423 #endif
424 struct sockaddr_in broad_addr;
426 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
427 _Xgethostbynameparams hparams;
428 #endif
430 /* Why not use gethostname()? Well, at least on my system, I've had to
431 * make an ugly kernel patch to get a name longer than 8 characters, and
432 * uname() lets me access to the whole string (it smashes release, you
433 * see), whereas gethostname() kindly truncates it for me.
435 uname(&name);
437 hp = _XGethostbyname(name.nodename, hparams);
438 if (hp != NULL) {
439 saddr.sa.sa_family = hp->h_addrtype;
440 switch (hp->h_addrtype) {
441 case AF_INET:
442 inetaddr = (struct sockaddr_in *) (&(saddr.sa));
443 memcpy(&(inetaddr->sin_addr), hp->h_addr, hp->h_length);
444 len = sizeof(saddr.sa);
445 break;
446 #if defined(IPv6)
447 case AF_INET6:
448 inet6addr = (struct sockaddr_in6 *) (&(saddr.sa));
449 memcpy(&(inet6addr->sin6_addr), hp->h_addr, hp->h_length);
450 len = sizeof(saddr.in6);
451 break;
452 #endif
453 default:
454 goto DefineLocalHost;
456 family = ConvertAddr(&(saddr.sa), &len, (void **) &addr);
457 if (family != -1 && family != FamilyLocal) {
458 for (host = selfhosts;
459 host && !addrEqual(family, addr, len, host);
460 host = host->next);
461 if (!host) {
462 /* add this host to the host list. */
463 MakeHost(host, len)
464 if (host) {
465 host->family = family;
466 host->len = len;
467 memcpy(host->addr, addr, len);
468 host->next = selfhosts;
469 selfhosts = host;
471 #ifdef XDMCP
473 * If this is an Internet Address, but not the localhost
474 * address (127.0.0.1), nor the bogus address (0.0.0.0),
475 * register it.
477 if (family == FamilyInternet &&
478 !(len == 4 &&
479 ((addr[0] == 127) ||
480 (addr[0] == 0 && addr[1] == 0 &&
481 addr[2] == 0 && addr[3] == 0)))
483 XdmcpRegisterConnection(family, (char *) addr, len);
484 broad_addr = *inetaddr;
485 ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
486 htonl(INADDR_BROADCAST);
487 XdmcpRegisterBroadcastAddress((struct sockaddr_in *)
488 &broad_addr);
490 #if defined(IPv6)
491 else if (family == FamilyInternet6 &&
492 !(IN6_IS_ADDR_LOOPBACK((struct in6_addr *) addr))) {
493 XdmcpRegisterConnection(family, (char *) addr, len);
495 #endif
497 #endif /* XDMCP */
502 * now add a host of family FamilyLocalHost...
504 DefineLocalHost:
505 for (host = selfhosts;
506 host && !addrEqual(FamilyLocalHost, "", 0, host); host = host->next);
507 if (!host) {
508 MakeHost(host, 0);
509 if (host) {
510 host->family = FamilyLocalHost;
511 host->len = 0;
512 /* Nothing to store in host->addr */
513 host->next = selfhosts;
514 selfhosts = host;
517 #endif /* !TCPCONN && !UNIXCONN */
520 #else
522 #ifdef USE_SIOCGLIFCONF
523 #define ifr_type struct lifreq
524 #else
525 #define ifr_type struct ifreq
526 #endif
528 #ifdef VARIABLE_IFREQ
529 #define ifr_size(p) (sizeof (struct ifreq) + \
530 (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
531 p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
532 #define ifraddr_size(a) (a.sa_len)
533 #else
534 #define ifr_size(p) (sizeof (ifr_type))
535 #define ifraddr_size(a) (sizeof (a))
536 #endif
538 #if defined(IPv6)
539 static void
540 in6_fillscopeid(struct sockaddr_in6 *sin6)
542 #if defined(__KAME__)
543 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id == 0) {
544 sin6->sin6_scope_id =
545 ntohs(*(u_int16_t *) &sin6->sin6_addr.s6_addr[2]);
546 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
548 #endif
550 #endif
552 void
553 DefineSelf(int fd)
555 #ifndef HAVE_GETIFADDRS
556 char *cp, *cplim;
558 #ifdef USE_SIOCGLIFCONF
559 struct sockaddr_storage buf[16];
560 struct lifconf ifc;
561 register struct lifreq *ifr;
563 #ifdef SIOCGLIFNUM
564 struct lifnum ifn;
565 #endif
566 #else /* !USE_SIOCGLIFCONF */
567 char buf[2048];
568 struct ifconf ifc;
569 register struct ifreq *ifr;
570 #endif
571 void *bufptr = buf;
572 #else /* HAVE_GETIFADDRS */
573 struct ifaddrs *ifap, *ifr;
574 #endif
575 int len;
576 unsigned char *addr;
577 int family;
578 register HOST *host;
580 #ifndef HAVE_GETIFADDRS
582 len = sizeof(buf);
584 #ifdef USE_SIOCGLIFCONF
586 #ifdef SIOCGLIFNUM
587 ifn.lifn_family = AF_UNSPEC;
588 ifn.lifn_flags = 0;
589 if (ioctl(fd, SIOCGLIFNUM, (char *) &ifn) < 0)
590 ErrorF("Getting interface count: %s\n", strerror(errno));
591 if (len < (ifn.lifn_count * sizeof(struct lifreq))) {
592 len = ifn.lifn_count * sizeof(struct lifreq);
593 bufptr = malloc(len);
595 #endif
597 ifc.lifc_family = AF_UNSPEC;
598 ifc.lifc_flags = 0;
599 ifc.lifc_len = len;
600 ifc.lifc_buf = bufptr;
602 #define IFC_IOCTL_REQ SIOCGLIFCONF
603 #define IFC_IFC_REQ ifc.lifc_req
604 #define IFC_IFC_LEN ifc.lifc_len
605 #define IFR_IFR_ADDR ifr->lifr_addr
606 #define IFR_IFR_NAME ifr->lifr_name
608 #else /* Use SIOCGIFCONF */
609 ifc.ifc_len = len;
610 ifc.ifc_buf = bufptr;
612 #define IFC_IOCTL_REQ SIOCGIFCONF
613 #define IFC_IFC_REQ ifc.ifc_req
614 #define IFC_IFC_LEN ifc.ifc_len
615 #define IFR_IFR_ADDR ifr->ifr_addr
616 #define IFR_IFR_NAME ifr->ifr_name
617 #endif
619 if (ioctl(fd, IFC_IOCTL_REQ, (void *) &ifc) < 0)
620 ErrorF("Getting interface configuration (4): %s\n", strerror(errno));
622 cplim = (char *) IFC_IFC_REQ + IFC_IFC_LEN;
624 for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size(ifr)) {
625 ifr = (ifr_type *) cp;
626 len = ifraddr_size(IFR_IFR_ADDR);
627 family = ConvertAddr((struct sockaddr *) &IFR_IFR_ADDR,
628 &len, (void **) &addr);
629 if (family == -1 || family == FamilyLocal)
630 continue;
631 #if defined(IPv6)
632 if (family == FamilyInternet6)
633 in6_fillscopeid((struct sockaddr_in6 *) &IFR_IFR_ADDR);
634 #endif
635 for (host = selfhosts;
636 host && !addrEqual(family, addr, len, host); host = host->next);
637 if (host)
638 continue;
639 MakeHost(host, len)
640 if (host) {
641 host->family = family;
642 host->len = len;
643 memcpy(host->addr, addr, len);
644 host->next = selfhosts;
645 selfhosts = host;
647 #ifdef XDMCP
649 #ifdef USE_SIOCGLIFCONF
650 struct sockaddr_storage broad_addr;
651 #else
652 struct sockaddr broad_addr;
653 #endif
656 * If this isn't an Internet Address, don't register it.
658 if (family != FamilyInternet
659 #if defined(IPv6)
660 && family != FamilyInternet6
661 #endif
663 continue;
666 * ignore 'localhost' entries as they're not useful
667 * on the other end of the wire
669 if (family == FamilyInternet &&
670 addr[0] == 127 && addr[1] == 0 && addr[2] == 0 && addr[3] == 1)
671 continue;
672 #if defined(IPv6)
673 else if (family == FamilyInternet6 &&
674 IN6_IS_ADDR_LOOPBACK((struct in6_addr *) addr))
675 continue;
676 #endif
679 * Ignore '0.0.0.0' entries as they are
680 * returned by some OSes for unconfigured NICs but they are
681 * not useful on the other end of the wire.
683 if (len == 4 &&
684 addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0)
685 continue;
687 XdmcpRegisterConnection(family, (char *) addr, len);
689 #if defined(IPv6)
690 /* IPv6 doesn't support broadcasting, so we drop out here */
691 if (family == FamilyInternet6)
692 continue;
693 #endif
695 broad_addr = IFR_IFR_ADDR;
697 ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
698 htonl(INADDR_BROADCAST);
699 #if defined(USE_SIOCGLIFCONF) && defined(SIOCGLIFBRDADDR)
701 struct lifreq broad_req;
703 broad_req = *ifr;
704 if (ioctl(fd, SIOCGLIFFLAGS, (char *) &broad_req) != -1 &&
705 (broad_req.lifr_flags & IFF_BROADCAST) &&
706 (broad_req.lifr_flags & IFF_UP)
708 broad_req = *ifr;
709 if (ioctl(fd, SIOCGLIFBRDADDR, &broad_req) != -1)
710 broad_addr = broad_req.lifr_broadaddr;
711 else
712 continue;
714 else
715 continue;
718 #elif defined(SIOCGIFBRDADDR)
720 struct ifreq broad_req;
722 broad_req = *ifr;
723 if (ioctl(fd, SIOCGIFFLAGS, (void *) &broad_req) != -1 &&
724 (broad_req.ifr_flags & IFF_BROADCAST) &&
725 (broad_req.ifr_flags & IFF_UP)
727 broad_req = *ifr;
728 if (ioctl(fd, SIOCGIFBRDADDR, (void *) &broad_req) != -1)
729 broad_addr = broad_req.ifr_addr;
730 else
731 continue;
733 else
734 continue;
736 #endif /* SIOCGIFBRDADDR */
737 XdmcpRegisterBroadcastAddress((struct sockaddr_in *) &broad_addr);
739 #endif /* XDMCP */
741 if (bufptr != buf)
742 free(bufptr);
743 #else /* HAVE_GETIFADDRS */
744 if (getifaddrs(&ifap) < 0) {
745 ErrorF("Warning: getifaddrs returns %s\n", strerror(errno));
746 return;
748 for (ifr = ifap; ifr != NULL; ifr = ifr->ifa_next) {
749 if (!ifr->ifa_addr)
750 continue;
751 len = sizeof(*(ifr->ifa_addr));
752 family = ConvertAddr((struct sockaddr *) ifr->ifa_addr, &len,
753 (void **) &addr);
754 if (family == -1 || family == FamilyLocal)
755 continue;
756 #if defined(IPv6)
757 if (family == FamilyInternet6)
758 in6_fillscopeid((struct sockaddr_in6 *) ifr->ifa_addr);
759 #endif
761 for (host = selfhosts;
762 host != NULL && !addrEqual(family, addr, len, host);
763 host = host->next);
764 if (host != NULL)
765 continue;
766 MakeHost(host, len);
767 if (host != NULL) {
768 host->family = family;
769 host->len = len;
770 memcpy(host->addr, addr, len);
771 host->next = selfhosts;
772 selfhosts = host;
774 #ifdef XDMCP
777 * If this isn't an Internet Address, don't register it.
779 if (family != FamilyInternet
780 #if defined(IPv6)
781 && family != FamilyInternet6
782 #endif
784 continue;
787 * ignore 'localhost' entries as they're not useful
788 * on the other end of the wire
790 if (ifr->ifa_flags & IFF_LOOPBACK)
791 continue;
793 if (family == FamilyInternet &&
794 addr[0] == 127 && addr[1] == 0 && addr[2] == 0 && addr[3] == 1)
795 continue;
798 * Ignore '0.0.0.0' entries as they are
799 * returned by some OSes for unconfigured NICs but they are
800 * not useful on the other end of the wire.
802 if (len == 4 &&
803 addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0)
804 continue;
805 #if defined(IPv6)
806 else if (family == FamilyInternet6 &&
807 IN6_IS_ADDR_LOOPBACK((struct in6_addr *) addr))
808 continue;
809 #endif
810 XdmcpRegisterConnection(family, (char *) addr, len);
811 #if defined(IPv6)
812 if (family == FamilyInternet6)
813 /* IPv6 doesn't support broadcasting, so we drop out here */
814 continue;
815 #endif
816 if ((ifr->ifa_flags & IFF_BROADCAST) &&
817 (ifr->ifa_flags & IFF_UP) && ifr->ifa_broadaddr)
818 XdmcpRegisterBroadcastAddress((struct sockaddr_in *) ifr->
819 ifa_broadaddr);
820 else
821 continue;
823 #endif /* XDMCP */
825 } /* for */
826 freeifaddrs(ifap);
827 #endif /* HAVE_GETIFADDRS */
830 * add something of FamilyLocalHost
832 for (host = selfhosts;
833 host && !addrEqual(FamilyLocalHost, "", 0, host); host = host->next);
834 if (!host) {
835 MakeHost(host, 0);
836 if (host) {
837 host->family = FamilyLocalHost;
838 host->len = 0;
839 /* Nothing to store in host->addr */
840 host->next = selfhosts;
841 selfhosts = host;
845 #endif /* hpux && !HAVE_IFREQ */
847 #ifdef XDMCP
848 void
849 AugmentSelf(void *from, int len)
851 int family;
852 void *addr;
853 register HOST *host;
855 family = ConvertAddr(from, &len, (void **) &addr);
856 if (family == -1 || family == FamilyLocal)
857 return;
858 for (host = selfhosts; host; host = host->next) {
859 if (addrEqual(family, addr, len, host))
860 return;
862 MakeHost(host, len)
863 if (!host)
864 return;
865 host->family = family;
866 host->len = len;
867 memcpy(host->addr, addr, len);
868 host->next = selfhosts;
869 selfhosts = host;
871 #endif
873 void
874 AddLocalHosts(void)
876 HOST *self;
878 for (self = selfhosts; self; self = self->next)
879 /* Fix for XFree86 bug #156: pass addingLocal = TRUE to
880 * NewHost to tell that we are adding the default local
881 * host entries and not to flag the entries as being
882 * explicitly requested */
883 (void) NewHost(self->family, self->addr, self->len, TRUE);
886 /* Reset access control list to initial hosts */
887 void
888 ResetHosts(const char *display)
890 register HOST *host;
891 char lhostname[120], ohostname[120];
892 char *hostname = ohostname;
893 char fname[PATH_MAX + 1];
894 int fnamelen;
895 FILE *fd;
896 char *ptr;
897 int i, hostlen;
899 #if defined(TCPCONN) && (!defined(IPv6))
900 union {
901 struct sockaddr sa;
902 struct sockaddr_in in;
903 } saddr;
904 #endif
905 int family = 0;
906 void *addr = NULL;
907 int len;
909 siTypesInitialize();
910 AccessEnabled = !defeatAccessControl;
911 LocalHostEnabled = FALSE;
912 while ((host = validhosts) != 0) {
913 validhosts = host->next;
914 FreeHost(host);
917 #if defined WIN32 && defined __MINGW32__
918 #define ETC_HOST_PREFIX "X"
919 #else
920 #define ETC_HOST_PREFIX "/etc/X"
921 #endif
922 #define ETC_HOST_SUFFIX ".hosts"
923 fnamelen = strlen(ETC_HOST_PREFIX) + strlen(ETC_HOST_SUFFIX) +
924 strlen(display) + 1;
925 if (fnamelen > sizeof(fname))
926 FatalError("Display name `%s' is too long\n", display);
927 snprintf(fname, sizeof(fname), ETC_HOST_PREFIX "%s" ETC_HOST_SUFFIX,
928 display);
930 if ((fd = fopen(fname, "r")) != 0) {
931 while (fgets(ohostname, sizeof(ohostname), fd)) {
932 family = FamilyWild;
933 if (*ohostname == '#')
934 continue;
935 if ((ptr = strchr(ohostname, '\n')) != 0)
936 *ptr = 0;
937 hostlen = strlen(ohostname) + 1;
938 for (i = 0; i < hostlen; i++)
939 lhostname[i] = tolower((unsigned char)ohostname[i]);
940 hostname = ohostname;
941 if (!strncmp("local:", lhostname, 6)) {
942 family = FamilyLocalHost;
943 NewHost(family, "", 0, FALSE);
944 LocalHostRequested = TRUE; /* Fix for XFree86 bug #156 */
946 #if defined(TCPCONN)
947 else if (!strncmp("inet:", lhostname, 5)) {
948 family = FamilyInternet;
949 hostname = ohostname + 5;
951 #if defined(IPv6)
952 else if (!strncmp("inet6:", lhostname, 6)) {
953 family = FamilyInternet6;
954 hostname = ohostname + 6;
956 #endif
957 #endif
958 else if (!strncmp("si:", lhostname, 3)) {
959 family = FamilyServerInterpreted;
960 hostname = ohostname + 3;
961 hostlen -= 3;
964 if (family == FamilyServerInterpreted) {
965 len = siCheckAddr(hostname, hostlen);
966 if (len >= 0) {
967 NewHost(family, hostname, len, FALSE);
970 else
971 #if defined(TCPCONN)
973 #if defined(HAVE_GETADDRINFO)
974 if ((family == FamilyInternet) ||
975 #if defined(IPv6)
976 (family == FamilyInternet6) ||
977 #endif
978 (family == FamilyWild)) {
979 struct addrinfo *addresses;
980 struct addrinfo *a;
981 int f;
983 if (getaddrinfo(hostname, NULL, NULL, &addresses) == 0) {
984 for (a = addresses; a != NULL; a = a->ai_next) {
985 len = a->ai_addrlen;
986 f = ConvertAddr(a->ai_addr, &len,
987 (void **) &addr);
988 if (addr && ((family == f) ||
989 ((family == FamilyWild) && (f != -1)))) {
990 NewHost(f, addr, len, FALSE);
993 freeaddrinfo(addresses);
996 #else /* HAVE_GETADDRINFO */
997 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
998 _Xgethostbynameparams hparams;
999 #endif
1000 register struct hostent *hp;
1002 /* host name */
1003 if ((family == FamilyInternet &&
1004 ((hp = _XGethostbyname(hostname, hparams)) != 0)) ||
1005 ((hp = _XGethostbyname(hostname, hparams)) != 0)) {
1006 saddr.sa.sa_family = hp->h_addrtype;
1007 len = sizeof(saddr.sa);
1008 if ((family =
1009 ConvertAddr(&saddr.sa, &len,
1010 (void **) &addr)) != -1) {
1011 #ifdef h_addr /* new 4.3bsd version of gethostent */
1012 char **list;
1014 /* iterate over the addresses */
1015 for (list = hp->h_addr_list; *list; list++)
1016 (void) NewHost(family, (void *) *list, len, FALSE);
1017 #else
1018 (void) NewHost(family, (void *) hp->h_addr, len,
1019 FALSE);
1020 #endif
1023 #endif /* HAVE_GETADDRINFO */
1025 #endif /* TCPCONN */
1026 family = FamilyWild;
1028 fclose(fd);
1032 static Bool
1033 xtransLocalClient(ClientPtr client)
1035 int alen, family, notused;
1036 Xtransaddr *from = NULL;
1037 void *addr;
1038 register HOST *host;
1039 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1041 if (!oc->trans_conn)
1042 return FALSE;
1044 if (!_XSERVTransGetPeerAddr(oc->trans_conn, &notused, &alen, &from)) {
1045 family = ConvertAddr((struct sockaddr *) from,
1046 &alen, (void **) &addr);
1047 if (family == -1) {
1048 free(from);
1049 return FALSE;
1051 if (family == FamilyLocal) {
1052 free(from);
1053 return TRUE;
1055 for (host = selfhosts; host; host = host->next) {
1056 if (addrEqual(family, addr, alen, host)) {
1057 free(from);
1058 return TRUE;
1061 free(from);
1063 return FALSE;
1066 /* Is client on the local host */
1067 Bool
1068 ComputeLocalClient(ClientPtr client)
1070 const char *cmdname = GetClientCmdName(client);
1072 if (!xtransLocalClient(client))
1073 return FALSE;
1075 /* If the executable name is "ssh", assume that this client connection
1076 * is forwarded from another host via SSH
1078 if (cmdname) {
1079 char *cmd = strdup(cmdname);
1080 Bool ret;
1082 /* Cut off any colon and whatever comes after it, see
1083 * https://lists.freedesktop.org/archives/xorg-devel/2015-December/048164.html
1085 char *tok = strtok(cmd, ":");
1087 #if !defined(WIN32) || defined(__CYGWIN__)
1088 ret = strcmp(basename(tok), "ssh") != 0;
1089 #else
1090 ret = strcmp(tok, "ssh") != 0;
1091 #endif
1093 free(cmd);
1095 return ret;
1098 return TRUE;
1102 * Return the uid and all gids of a connected local client
1103 * Allocates a LocalClientCredRec - caller must call FreeLocalClientCreds
1105 * Used by localuser & localgroup ServerInterpreted access control forms below
1106 * Used by AuthAudit to log who local connections came from
1109 GetLocalClientCreds(ClientPtr client, LocalClientCredRec ** lccp)
1111 #if defined(HAVE_GETPEEREID) || defined(HAVE_GETPEERUCRED) || defined(SO_PEERCRED) || defined(LOCAL_PEERCRED)
1112 int fd;
1113 XtransConnInfo ci;
1114 LocalClientCredRec *lcc;
1116 #if defined(HAVE_GETPEERUCRED)
1117 ucred_t *peercred = NULL;
1118 const gid_t *gids;
1119 #elif defined(SO_PEERCRED)
1120 #ifndef __OpenBSD__
1121 struct ucred peercred;
1122 #else
1123 struct sockpeercred peercred;
1124 #endif
1125 socklen_t so_len = sizeof(peercred);
1126 #elif defined(LOCAL_PEERCRED) && defined(HAVE_XUCRED_CR_PID)
1127 struct xucred peercred;
1128 socklen_t so_len = sizeof(peercred);
1129 #elif defined(HAVE_GETPEEREID)
1130 uid_t uid;
1131 gid_t gid;
1132 #if defined(LOCAL_PEERPID)
1133 pid_t pid;
1134 socklen_t so_len = sizeof(pid);
1135 #endif
1136 #endif
1138 if (client == NULL)
1139 return -1;
1140 ci = ((OsCommPtr) client->osPrivate)->trans_conn;
1141 #if !(defined(__sun) && defined(HAVE_GETPEERUCRED))
1142 /* Most implementations can only determine peer credentials for Unix
1143 * domain sockets - Solaris getpeerucred can work with a bit more, so
1144 * we just let it tell us if the connection type is supported or not
1146 if (!_XSERVTransIsLocal(ci)) {
1147 return -1;
1149 #endif
1151 *lccp = calloc(1, sizeof(LocalClientCredRec));
1152 if (*lccp == NULL)
1153 return -1;
1154 lcc = *lccp;
1156 fd = _XSERVTransGetConnectionNumber(ci);
1157 #if defined(HAVE_GETPEERUCRED)
1158 if (getpeerucred(fd, &peercred) < 0) {
1159 FreeLocalClientCreds(lcc);
1160 return -1;
1162 lcc->euid = ucred_geteuid(peercred);
1163 if (lcc->euid != -1)
1164 lcc->fieldsSet |= LCC_UID_SET;
1165 lcc->egid = ucred_getegid(peercred);
1166 if (lcc->egid != -1)
1167 lcc->fieldsSet |= LCC_GID_SET;
1168 lcc->pid = ucred_getpid(peercred);
1169 if (lcc->pid != -1)
1170 lcc->fieldsSet |= LCC_PID_SET;
1171 #ifdef HAVE_GETZONEID
1172 lcc->zoneid = ucred_getzoneid(peercred);
1173 if (lcc->zoneid != -1)
1174 lcc->fieldsSet |= LCC_ZID_SET;
1175 #endif
1176 lcc->nSuppGids = ucred_getgroups(peercred, &gids);
1177 if (lcc->nSuppGids > 0) {
1178 lcc->pSuppGids = calloc(lcc->nSuppGids, sizeof(int));
1179 if (lcc->pSuppGids == NULL) {
1180 lcc->nSuppGids = 0;
1182 else {
1183 int i;
1185 for (i = 0; i < lcc->nSuppGids; i++) {
1186 (lcc->pSuppGids)[i] = (int) gids[i];
1190 else {
1191 lcc->nSuppGids = 0;
1193 ucred_free(peercred);
1194 return 0;
1195 #elif defined(SO_PEERCRED)
1196 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) {
1197 FreeLocalClientCreds(lcc);
1198 return -1;
1200 lcc->euid = peercred.uid;
1201 lcc->egid = peercred.gid;
1202 lcc->pid = peercred.pid;
1203 lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET | LCC_PID_SET;
1204 return 0;
1205 #elif defined(LOCAL_PEERCRED) && defined(HAVE_XUCRED_CR_PID)
1206 if (getsockopt(fd, SOL_LOCAL, LOCAL_PEERCRED, &peercred, &so_len) != 0 ||
1207 peercred.cr_version != XUCRED_VERSION) {
1208 FreeLocalClientCreds(lcc);
1209 return -1;
1211 lcc->euid = peercred.cr_uid;
1212 lcc->egid = peercred.cr_gid;
1213 lcc->pid = peercred.cr_pid;
1214 lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET | LCC_PID_SET;
1215 return 0;
1216 #elif defined(HAVE_GETPEEREID)
1217 if (getpeereid(fd, &uid, &gid) == -1) {
1218 FreeLocalClientCreds(lcc);
1219 return -1;
1221 lcc->euid = uid;
1222 lcc->egid = gid;
1223 lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET;
1225 #if defined(LOCAL_PEERPID)
1226 if (getsockopt(fd, SOL_LOCAL, LOCAL_PEERPID, &pid, &so_len) != 0) {
1227 ErrorF("getsockopt failed to determine pid of socket %d: %s\n", fd, strerror(errno));
1228 } else {
1229 lcc->pid = pid;
1230 lcc->fieldsSet |= LCC_PID_SET;
1232 #endif
1234 return 0;
1235 #endif
1236 #else
1237 /* No system call available to get the credentials of the peer */
1238 return -1;
1239 #endif
1242 void
1243 FreeLocalClientCreds(LocalClientCredRec * lcc)
1245 if (lcc != NULL) {
1246 if (lcc->nSuppGids > 0) {
1247 free(lcc->pSuppGids);
1249 free(lcc);
1253 static int
1254 AuthorizedClient(ClientPtr client)
1256 int rc;
1258 if (!client || defeatAccessControl)
1259 return Success;
1261 /* untrusted clients can't change host access */
1262 rc = XaceHookServerAccess(client, DixManageAccess);
1263 if (rc != Success)
1264 return rc;
1266 return client->local ? Success : BadAccess;
1269 /* Add a host to the access control list. This is the external interface
1270 * called from the dispatcher */
1273 AddHost(ClientPtr client, int family, unsigned length, /* of bytes in pAddr */
1274 const void *pAddr)
1276 int rc, len;
1278 rc = AuthorizedClient(client);
1279 if (rc != Success)
1280 return rc;
1281 switch (family) {
1282 case FamilyLocalHost:
1283 len = length;
1284 LocalHostEnabled = TRUE;
1285 break;
1286 case FamilyInternet:
1287 #if defined(IPv6)
1288 case FamilyInternet6:
1289 #endif
1290 case FamilyDECnet:
1291 case FamilyChaos:
1292 case FamilyServerInterpreted:
1293 if ((len = CheckAddr(family, pAddr, length)) < 0) {
1294 client->errorValue = length;
1295 return BadValue;
1297 break;
1298 case FamilyLocal:
1299 default:
1300 client->errorValue = family;
1301 return BadValue;
1303 if (NewHost(family, pAddr, len, FALSE))
1304 return Success;
1305 return BadAlloc;
1308 Bool
1309 ForEachHostInFamily(int family, Bool (*func) (unsigned char *addr,
1310 short len,
1311 void *closure),
1312 void *closure)
1314 HOST *host;
1316 for (host = validhosts; host; host = host->next)
1317 if (family == host->family && func(host->addr, host->len, closure))
1318 return TRUE;
1319 return FALSE;
1322 /* Add a host to the access control list. This is the internal interface
1323 * called when starting or resetting the server */
1324 static Bool
1325 NewHost(int family, const void *addr, int len, int addingLocalHosts)
1327 register HOST *host;
1329 for (host = validhosts; host; host = host->next) {
1330 if (addrEqual(family, addr, len, host))
1331 return TRUE;
1333 if (!addingLocalHosts) { /* Fix for XFree86 bug #156 */
1334 for (host = selfhosts; host; host = host->next) {
1335 if (addrEqual(family, addr, len, host)) {
1336 host->requested = TRUE;
1337 break;
1341 MakeHost(host, len)
1342 if (!host)
1343 return FALSE;
1344 host->family = family;
1345 host->len = len;
1346 memcpy(host->addr, addr, len);
1347 host->next = validhosts;
1348 validhosts = host;
1349 return TRUE;
1352 /* Remove a host from the access control list */
1355 RemoveHost(ClientPtr client, int family, unsigned length, /* of bytes in pAddr */
1356 void *pAddr)
1358 int rc, len;
1359 register HOST *host, **prev;
1361 rc = AuthorizedClient(client);
1362 if (rc != Success)
1363 return rc;
1364 switch (family) {
1365 case FamilyLocalHost:
1366 len = length;
1367 LocalHostEnabled = FALSE;
1368 break;
1369 case FamilyInternet:
1370 #if defined(IPv6)
1371 case FamilyInternet6:
1372 #endif
1373 case FamilyDECnet:
1374 case FamilyChaos:
1375 case FamilyServerInterpreted:
1376 if ((len = CheckAddr(family, pAddr, length)) < 0) {
1377 if (client)
1378 client->errorValue = length;
1379 return BadValue;
1381 break;
1382 case FamilyLocal:
1383 default:
1384 if (client)
1385 client->errorValue = family;
1386 return BadValue;
1388 for (prev = &validhosts;
1389 (host = *prev) && (!addrEqual(family, pAddr, len, host));
1390 prev = &host->next);
1391 if (host) {
1392 *prev = host->next;
1393 FreeHost(host);
1395 return Success;
1398 /* Get all hosts in the access control list */
1400 GetHosts(void **data, int *pnHosts, int *pLen, BOOL * pEnabled)
1402 int len;
1403 register int n = 0;
1404 register unsigned char *ptr;
1405 register HOST *host;
1406 int nHosts = 0;
1408 *pEnabled = AccessEnabled ? EnableAccess : DisableAccess;
1409 for (host = validhosts; host; host = host->next) {
1410 nHosts++;
1411 n += pad_to_int32(host->len) + sizeof(xHostEntry);
1412 /* Could check for INT_MAX, but in reality having more than 1mb of
1413 hostnames in the access list is ridiculous */
1414 if (n >= 1048576)
1415 break;
1417 if (n) {
1418 *data = ptr = malloc(n);
1419 if (!ptr) {
1420 return BadAlloc;
1422 for (host = validhosts; host; host = host->next) {
1423 len = host->len;
1424 if ((ptr + sizeof(xHostEntry) + len) > ((unsigned char *) *data + n))
1425 break;
1426 ((xHostEntry *) ptr)->family = host->family;
1427 ((xHostEntry *) ptr)->length = len;
1428 ptr += sizeof(xHostEntry);
1429 memcpy(ptr, host->addr, len);
1430 ptr += pad_to_int32(len);
1433 else {
1434 *data = NULL;
1436 *pnHosts = nHosts;
1437 *pLen = n;
1438 return Success;
1441 /* Check for valid address family and length, and return address length. */
1443 /*ARGSUSED*/ static int
1444 CheckAddr(int family, const void *pAddr, unsigned length)
1446 int len;
1448 switch (family) {
1449 #if defined(TCPCONN)
1450 case FamilyInternet:
1451 if (length == sizeof(struct in_addr))
1452 len = length;
1453 else
1454 len = -1;
1455 break;
1456 #if defined(IPv6)
1457 case FamilyInternet6:
1458 if (length == sizeof(struct in6_addr))
1459 len = length;
1460 else
1461 len = -1;
1462 break;
1463 #endif
1464 #endif
1465 case FamilyServerInterpreted:
1466 len = siCheckAddr(pAddr, length);
1467 break;
1468 default:
1469 len = -1;
1471 return len;
1474 /* Check if a host is not in the access control list.
1475 * Returns 1 if host is invalid, 0 if we've found it. */
1478 InvalidHost(register struct sockaddr *saddr, int len, ClientPtr client)
1480 int family;
1481 void *addr = NULL;
1482 register HOST *selfhost, *host;
1484 if (!AccessEnabled) /* just let them in */
1485 return 0;
1486 family = ConvertAddr(saddr, &len, (void **) &addr);
1487 if (family == -1)
1488 return 1;
1489 if (family == FamilyLocal) {
1490 if (!LocalHostEnabled) {
1492 * check to see if any local address is enabled. This
1493 * implicitly enables local connections.
1495 for (selfhost = selfhosts; selfhost; selfhost = selfhost->next) {
1496 for (host = validhosts; host; host = host->next) {
1497 if (addrEqual(selfhost->family, selfhost->addr,
1498 selfhost->len, host))
1499 return 0;
1503 else
1504 return 0;
1506 for (host = validhosts; host; host = host->next) {
1507 if (host->family == FamilyServerInterpreted) {
1508 if (siAddrMatch(family, addr, len, host, client)) {
1509 return 0;
1512 else {
1513 if (addr && addrEqual(family, addr, len, host))
1514 return 0;
1518 return 1;
1521 static int
1522 ConvertAddr(register struct sockaddr *saddr, int *len, void **addr)
1524 if (*len == 0)
1525 return FamilyLocal;
1526 switch (saddr->sa_family) {
1527 case AF_UNSPEC:
1528 #if defined(UNIXCONN) || defined(LOCALCONN)
1529 case AF_UNIX:
1530 #endif
1531 return FamilyLocal;
1532 #if defined(TCPCONN)
1533 case AF_INET:
1534 #ifdef WIN32
1535 if (16777343 == *(long *) &((struct sockaddr_in *) saddr)->sin_addr)
1536 return FamilyLocal;
1537 #endif
1538 *len = sizeof(struct in_addr);
1539 *addr = (void *) &(((struct sockaddr_in *) saddr)->sin_addr);
1540 return FamilyInternet;
1541 #if defined(IPv6)
1542 case AF_INET6:
1544 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) saddr;
1546 if (IN6_IS_ADDR_V4MAPPED(&(saddr6->sin6_addr))) {
1547 *len = sizeof(struct in_addr);
1548 *addr = (void *) &(saddr6->sin6_addr.s6_addr[12]);
1549 return FamilyInternet;
1551 else {
1552 *len = sizeof(struct in6_addr);
1553 *addr = (void *) &(saddr6->sin6_addr);
1554 return FamilyInternet6;
1557 #endif
1558 #endif
1559 default:
1560 return -1;
1565 ChangeAccessControl(ClientPtr client, int fEnabled)
1567 int rc = AuthorizedClient(client);
1569 if (rc != Success)
1570 return rc;
1571 AccessEnabled = fEnabled;
1572 return Success;
1576 GetClientFd(ClientPtr client)
1578 return ((OsCommPtr) client->osPrivate)->fd;
1581 Bool
1582 ClientIsLocal(ClientPtr client)
1584 XtransConnInfo ci = ((OsCommPtr) client->osPrivate)->trans_conn;
1586 return _XSERVTransIsLocal(ci);
1589 /*****************************************************************************
1590 * FamilyServerInterpreted host entry implementation
1592 * Supports an extensible system of host types which the server can interpret
1593 * See the IPv6 extensions to the X11 protocol spec for the definition.
1595 * Currently supported schemes:
1597 * hostname - hostname as defined in IETF RFC 2396
1598 * ipv6 - IPv6 literal address as defined in IETF RFC's 3513 and <TBD>
1600 * See xc/doc/specs/SIAddresses for formal definitions of each type.
1603 /* These definitions and the siTypeAdd function could be exported in the
1604 * future to enable loading additional host types, but that was not done for
1605 * the initial implementation.
1607 typedef Bool (*siAddrMatchFunc) (int family, void *addr, int len,
1608 const char *siAddr, int siAddrlen,
1609 ClientPtr client, void *siTypePriv);
1610 typedef int (*siCheckAddrFunc) (const char *addrString, int length,
1611 void *siTypePriv);
1613 struct siType {
1614 struct siType *next;
1615 const char *typeName;
1616 siAddrMatchFunc addrMatch;
1617 siCheckAddrFunc checkAddr;
1618 void *typePriv; /* Private data for type routines */
1621 static struct siType *siTypeList;
1623 static int
1624 siTypeAdd(const char *typeName, siAddrMatchFunc addrMatch,
1625 siCheckAddrFunc checkAddr, void *typePriv)
1627 struct siType *s, *p;
1629 if ((typeName == NULL) || (addrMatch == NULL) || (checkAddr == NULL))
1630 return BadValue;
1632 for (s = siTypeList, p = NULL; s != NULL; p = s, s = s->next) {
1633 if (strcmp(typeName, s->typeName) == 0) {
1634 s->addrMatch = addrMatch;
1635 s->checkAddr = checkAddr;
1636 s->typePriv = typePriv;
1637 return Success;
1641 s = malloc(sizeof(struct siType));
1642 if (s == NULL)
1643 return BadAlloc;
1645 if (p == NULL)
1646 siTypeList = s;
1647 else
1648 p->next = s;
1650 s->next = NULL;
1651 s->typeName = typeName;
1652 s->addrMatch = addrMatch;
1653 s->checkAddr = checkAddr;
1654 s->typePriv = typePriv;
1655 return Success;
1658 /* Checks to see if a host matches a server-interpreted host entry */
1659 static Bool
1660 siAddrMatch(int family, void *addr, int len, HOST * host, ClientPtr client)
1662 Bool matches = FALSE;
1663 struct siType *s;
1664 const char *valueString;
1665 int addrlen;
1667 valueString = (const char *) memchr(host->addr, '\0', host->len);
1668 if (valueString != NULL) {
1669 for (s = siTypeList; s != NULL; s = s->next) {
1670 if (strcmp((char *) host->addr, s->typeName) == 0) {
1671 addrlen = host->len - (strlen((char *) host->addr) + 1);
1672 matches = s->addrMatch(family, addr, len,
1673 valueString + 1, addrlen, client,
1674 s->typePriv);
1675 break;
1678 #ifdef FAMILY_SI_DEBUG
1679 ErrorF("Xserver: siAddrMatch(): type = %s, value = %*.*s -- %s\n",
1680 host->addr, addrlen, addrlen, valueString + 1,
1681 (matches) ? "accepted" : "rejected");
1682 #endif
1684 return matches;
1687 static int
1688 siCheckAddr(const char *addrString, int length)
1690 const char *valueString;
1691 int addrlen, typelen;
1692 int len = -1;
1693 struct siType *s;
1695 /* Make sure there is a \0 byte inside the specified length
1696 to separate the address type from the address value. */
1697 valueString = (const char *) memchr(addrString, '\0', length);
1698 if (valueString != NULL) {
1699 /* Make sure the first string is a recognized address type,
1700 * and the second string is a valid address of that type.
1702 typelen = strlen(addrString) + 1;
1703 addrlen = length - typelen;
1705 for (s = siTypeList; s != NULL; s = s->next) {
1706 if (strcmp(addrString, s->typeName) == 0) {
1707 len = s->checkAddr(valueString + 1, addrlen, s->typePriv);
1708 if (len >= 0) {
1709 len += typelen;
1711 break;
1714 #ifdef FAMILY_SI_DEBUG
1716 const char *resultMsg;
1718 if (s == NULL) {
1719 resultMsg = "type not registered";
1721 else {
1722 if (len == -1)
1723 resultMsg = "rejected";
1724 else
1725 resultMsg = "accepted";
1728 ErrorF
1729 ("Xserver: siCheckAddr(): type = %s, value = %*.*s, len = %d -- %s\n",
1730 addrString, addrlen, addrlen, valueString + 1, len, resultMsg);
1732 #endif
1734 return len;
1737 /***
1738 * Hostname server-interpreted host type
1740 * Stored as hostname string, explicitly defined to be resolved ONLY
1741 * at access check time, to allow for hosts with dynamic addresses
1742 * but static hostnames, such as found in some DHCP & mobile setups.
1744 * Hostname must conform to IETF RFC 2396 sec. 3.2.2, which defines it as:
1745 * hostname = *( domainlabel "." ) toplabel [ "." ]
1746 * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
1747 * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
1750 #ifdef NI_MAXHOST
1751 #define SI_HOSTNAME_MAXLEN NI_MAXHOST
1752 #else
1753 #ifdef MAXHOSTNAMELEN
1754 #define SI_HOSTNAME_MAXLEN MAXHOSTNAMELEN
1755 #else
1756 #define SI_HOSTNAME_MAXLEN 256
1757 #endif
1758 #endif
1760 static Bool
1761 siHostnameAddrMatch(int family, void *addr, int len,
1762 const char *siAddr, int siAddrLen, ClientPtr client,
1763 void *typePriv)
1765 Bool res = FALSE;
1767 /* Currently only supports checking against IPv4 & IPv6 connections, but
1768 * support for other address families, such as DECnet, could be added if
1769 * desired.
1771 #if defined(HAVE_GETADDRINFO)
1772 if ((family == FamilyInternet)
1773 #if defined(IPv6)
1774 || (family == FamilyInternet6)
1775 #endif
1777 char hostname[SI_HOSTNAME_MAXLEN];
1778 struct addrinfo *addresses;
1779 struct addrinfo *a;
1780 int f, hostaddrlen;
1781 void *hostaddr = NULL;
1783 if (siAddrLen >= sizeof(hostname))
1784 return FALSE;
1786 strlcpy(hostname, siAddr, siAddrLen + 1);
1788 if (getaddrinfo(hostname, NULL, NULL, &addresses) == 0) {
1789 for (a = addresses; a != NULL; a = a->ai_next) {
1790 hostaddrlen = a->ai_addrlen;
1791 f = ConvertAddr(a->ai_addr, &hostaddrlen, &hostaddr);
1792 if ((f == family) && (len == hostaddrlen) && hostaddr &&
1793 (memcmp(addr, hostaddr, len) == 0)) {
1794 res = TRUE;
1795 break;
1798 freeaddrinfo(addresses);
1801 #else /* getaddrinfo not supported, use gethostbyname instead for IPv4 */
1802 if (family == FamilyInternet) {
1803 register struct hostent *hp;
1805 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1806 _Xgethostbynameparams hparams;
1807 #endif
1808 char hostname[SI_HOSTNAME_MAXLEN];
1809 int f, hostaddrlen;
1810 void *hostaddr;
1811 char **addrlist;
1813 if (siAddrLen >= sizeof(hostname))
1814 return FALSE;
1816 strlcpy(hostname, siAddr, siAddrLen + 1);
1818 if ((hp = _XGethostbyname(hostname, hparams)) != NULL) {
1819 #ifdef h_addr /* new 4.3bsd version of gethostent */
1820 /* iterate over the addresses */
1821 for (addrlist = hp->h_addr_list; *addrlist; addrlist++)
1822 #else
1823 addrlist = &hp->h_addr;
1824 #endif
1826 struct sockaddr_in sin;
1828 sin.sin_family = hp->h_addrtype;
1829 memcpy(&(sin.sin_addr), *addrlist, hp->h_length);
1830 hostaddrlen = sizeof(sin);
1831 f = ConvertAddr((struct sockaddr *) &sin,
1832 &hostaddrlen, &hostaddr);
1833 if ((f == family) && (len == hostaddrlen) &&
1834 (memcmp(addr, hostaddr, len) == 0)) {
1835 res = TRUE;
1836 #ifdef h_addr
1837 break;
1838 #endif
1843 #endif
1844 return res;
1847 static int
1848 siHostnameCheckAddr(const char *valueString, int length, void *typePriv)
1850 /* Check conformance of hostname to RFC 2396 sec. 3.2.2 definition.
1851 * We do not use ctype functions here to avoid locale-specific
1852 * character sets. Hostnames must be pure ASCII.
1854 int len = length;
1855 int i;
1856 Bool dotAllowed = FALSE;
1857 Bool dashAllowed = FALSE;
1859 if ((length <= 0) || (length >= SI_HOSTNAME_MAXLEN)) {
1860 len = -1;
1862 else {
1863 for (i = 0; i < length; i++) {
1864 char c = valueString[i];
1866 if (c == 0x2E) { /* '.' */
1867 if (dotAllowed == FALSE) {
1868 len = -1;
1869 break;
1871 else {
1872 dotAllowed = FALSE;
1873 dashAllowed = FALSE;
1876 else if (c == 0x2D) { /* '-' */
1877 if (dashAllowed == FALSE) {
1878 len = -1;
1879 break;
1881 else {
1882 dotAllowed = FALSE;
1885 else if (((c >= 0x30) && (c <= 0x3A)) /* 0-9 */ ||
1886 ((c >= 0x61) && (c <= 0x7A)) /* a-z */ ||
1887 ((c >= 0x41) && (c <= 0x5A)) /* A-Z */ ) {
1888 dotAllowed = TRUE;
1889 dashAllowed = TRUE;
1891 else { /* Invalid character */
1892 len = -1;
1893 break;
1897 return len;
1900 #if defined(IPv6)
1901 /***
1902 * "ipv6" server interpreted type
1904 * Currently supports only IPv6 literal address as specified in IETF RFC 3513
1906 * Once draft-ietf-ipv6-scoping-arch-00.txt becomes an RFC, support will be
1907 * added for the scoped address format it specifies.
1910 /* Maximum length of an IPv6 address string - increase when adding support
1911 * for scoped address qualifiers. Includes room for trailing NUL byte.
1913 #define SI_IPv6_MAXLEN INET6_ADDRSTRLEN
1915 static Bool
1916 siIPv6AddrMatch(int family, void *addr, int len,
1917 const char *siAddr, int siAddrlen, ClientPtr client,
1918 void *typePriv)
1920 struct in6_addr addr6;
1921 char addrbuf[SI_IPv6_MAXLEN];
1923 if ((family != FamilyInternet6) || (len != sizeof(addr6)))
1924 return FALSE;
1926 memcpy(addrbuf, siAddr, siAddrlen);
1927 addrbuf[siAddrlen] = '\0';
1929 if (inet_pton(AF_INET6, addrbuf, &addr6) != 1) {
1930 perror("inet_pton");
1931 return FALSE;
1934 if (memcmp(addr, &addr6, len) == 0) {
1935 return TRUE;
1937 else {
1938 return FALSE;
1942 static int
1943 siIPv6CheckAddr(const char *addrString, int length, void *typePriv)
1945 int len;
1947 /* Minimum length is 3 (smallest legal address is "::1") */
1948 if (length < 3) {
1949 /* Address is too short! */
1950 len = -1;
1952 else if (length >= SI_IPv6_MAXLEN) {
1953 /* Address is too long! */
1954 len = -1;
1956 else {
1957 /* Assume inet_pton is sufficient validation */
1958 struct in6_addr addr6;
1959 char addrbuf[SI_IPv6_MAXLEN];
1961 memcpy(addrbuf, addrString, length);
1962 addrbuf[length] = '\0';
1964 if (inet_pton(AF_INET6, addrbuf, &addr6) != 1) {
1965 perror("inet_pton");
1966 len = -1;
1968 else {
1969 len = length;
1972 return len;
1974 #endif /* IPv6 */
1976 #if !defined(NO_LOCAL_CLIENT_CRED)
1977 /***
1978 * "localuser" & "localgroup" server interpreted types
1980 * Allows local connections from a given local user or group
1983 #include <pwd.h>
1984 #include <grp.h>
1986 #define LOCAL_USER 1
1987 #define LOCAL_GROUP 2
1989 typedef struct {
1990 int credType;
1991 } siLocalCredPrivRec, *siLocalCredPrivPtr;
1993 static siLocalCredPrivRec siLocalUserPriv = { LOCAL_USER };
1994 static siLocalCredPrivRec siLocalGroupPriv = { LOCAL_GROUP };
1996 static Bool
1997 siLocalCredGetId(const char *addr, int len, siLocalCredPrivPtr lcPriv, int *id)
1999 Bool parsedOK = FALSE;
2000 char *addrbuf = malloc(len + 1);
2002 if (addrbuf == NULL) {
2003 return FALSE;
2006 memcpy(addrbuf, addr, len);
2007 addrbuf[len] = '\0';
2009 if (addr[0] == '#') { /* numeric id */
2010 char *cp;
2012 errno = 0;
2013 *id = strtol(addrbuf + 1, &cp, 0);
2014 if ((errno == 0) && (cp != (addrbuf + 1))) {
2015 parsedOK = TRUE;
2018 else { /* non-numeric name */
2019 if (lcPriv->credType == LOCAL_USER) {
2020 struct passwd *pw = getpwnam(addrbuf);
2022 if (pw != NULL) {
2023 *id = (int) pw->pw_uid;
2024 parsedOK = TRUE;
2027 else { /* group */
2028 struct group *gr = getgrnam(addrbuf);
2030 if (gr != NULL) {
2031 *id = (int) gr->gr_gid;
2032 parsedOK = TRUE;
2037 free(addrbuf);
2038 return parsedOK;
2041 static Bool
2042 siLocalCredAddrMatch(int family, void *addr, int len,
2043 const char *siAddr, int siAddrlen, ClientPtr client,
2044 void *typePriv)
2046 int siAddrId;
2047 LocalClientCredRec *lcc;
2048 siLocalCredPrivPtr lcPriv = (siLocalCredPrivPtr) typePriv;
2050 if (GetLocalClientCreds(client, &lcc) == -1) {
2051 return FALSE;
2054 #ifdef HAVE_GETZONEID /* Ensure process is in the same zone */
2055 if ((lcc->fieldsSet & LCC_ZID_SET) && (lcc->zoneid != getzoneid())) {
2056 FreeLocalClientCreds(lcc);
2057 return FALSE;
2059 #endif
2061 if (siLocalCredGetId(siAddr, siAddrlen, lcPriv, &siAddrId) == FALSE) {
2062 FreeLocalClientCreds(lcc);
2063 return FALSE;
2066 if (lcPriv->credType == LOCAL_USER) {
2067 if ((lcc->fieldsSet & LCC_UID_SET) && (lcc->euid == siAddrId)) {
2068 FreeLocalClientCreds(lcc);
2069 return TRUE;
2072 else {
2073 if ((lcc->fieldsSet & LCC_GID_SET) && (lcc->egid == siAddrId)) {
2074 FreeLocalClientCreds(lcc);
2075 return TRUE;
2077 if (lcc->pSuppGids != NULL) {
2078 int i;
2080 for (i = 0; i < lcc->nSuppGids; i++) {
2081 if (lcc->pSuppGids[i] == siAddrId) {
2082 FreeLocalClientCreds(lcc);
2083 return TRUE;
2088 FreeLocalClientCreds(lcc);
2089 return FALSE;
2092 static int
2093 siLocalCredCheckAddr(const char *addrString, int length, void *typePriv)
2095 int len = length;
2096 int id;
2098 if (siLocalCredGetId(addrString, length,
2099 (siLocalCredPrivPtr) typePriv, &id) == FALSE) {
2100 len = -1;
2102 return len;
2104 #endif /* localuser */
2106 static void
2107 siTypesInitialize(void)
2109 siTypeAdd("hostname", siHostnameAddrMatch, siHostnameCheckAddr, NULL);
2110 #if defined(IPv6)
2111 siTypeAdd("ipv6", siIPv6AddrMatch, siIPv6CheckAddr, NULL);
2112 #endif
2113 #if !defined(NO_LOCAL_CLIENT_CRED)
2114 siTypeAdd("localuser", siLocalCredAddrMatch, siLocalCredCheckAddr,
2115 &siLocalUserPriv);
2116 siTypeAdd("localgroup", siLocalCredAddrMatch, siLocalCredCheckAddr,
2117 &siLocalGroupPriv);
2118 #endif