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