Add patch that contain Mali fixes.
[deb_xorg-server.git] / os / connection.c
CommitLineData
a09e091a
JB
1/***********************************************************
2
3Copyright 1987, 1989, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27 All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45******************************************************************/
46/*****************************************************************
47 * Stuff to create connections --- OS dependent
48 *
49 * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
50 * CloseDownConnection, CheckConnections, AddEnabledDevice,
51 * RemoveEnabledDevice, OnlyListToOneClient,
52 * ListenToAllClients,
53 *
54 * (WaitForSomething is in its own file)
55 *
56 * In this implementation, a client socket table is not kept.
57 * Instead, what would be the index into the table is just the
58 * file descriptor of the socket. This won't work for if the
59 * socket ids aren't small nums (0 - 2^8)
60 *
61 *****************************************************************/
62
63#ifdef HAVE_DIX_CONFIG_H
64#include <dix-config.h>
65#endif
66
67#ifdef WIN32
68#include <X11/Xwinsock.h>
69#endif
70#include <X11/X.h>
71#include <X11/Xproto.h>
72#define XSERV_t
73#define TRANS_SERVER
74#define TRANS_REOPEN
75#include <X11/Xtrans/Xtrans.h>
76#include <X11/Xtrans/Xtransint.h>
77#include <errno.h>
78#include <signal.h>
79#include <stdio.h>
80#include <stdlib.h>
81
82#ifndef WIN32
83#include <sys/socket.h>
84
85#if defined(TCPCONN) || defined(STREAMSCONN)
86#include <netinet/in.h>
87#include <arpa/inet.h>
88#ifdef apollo
89#ifndef NO_TCP_H
90#include <netinet/tcp.h>
91#endif
92#else
93#ifdef CSRG_BASED
94#include <sys/param.h>
95#endif
96#include <netinet/tcp.h>
97#endif
98#include <arpa/inet.h>
99#endif
100
101#include <sys/uio.h>
102
103#endif /* WIN32 */
104#include "misc.h" /* for typedef of pointer */
105#include "osdep.h"
106#include <X11/Xpoll.h>
107#include "opaque.h"
108#include "dixstruct.h"
109#include "xace.h"
110
111#define Pid_t pid_t
112
113#ifdef HAVE_GETPEERUCRED
114#include <ucred.h>
115#include <zone.h>
116#endif
117
118#ifdef XSERVER_DTRACE
119#include <sys/types.h>
120typedef const char *string;
121
122#ifndef HAVE_GETPEERUCRED
123#define zoneid_t int
124#endif
125#include "../dix/Xserver-dtrace.h"
126#endif
127
128static int lastfdesc; /* maximum file descriptor */
129
130fd_set WellKnownConnections; /* Listener mask */
131fd_set EnabledDevices; /* mask for input devices that are on */
132fd_set AllSockets; /* select on this */
133fd_set AllClients; /* available clients */
134fd_set LastSelectMask; /* mask returned from last select call */
135fd_set ClientsWithInput; /* clients with FULL requests in buffer */
136fd_set ClientsWriteBlocked; /* clients who cannot receive output */
137fd_set OutputPending; /* clients with reply/event data ready to go */
138int MaxClients = 0;
139Bool NewOutputPending; /* not yet attempted to write some new output */
140Bool AnyClientsWriteBlocked; /* true if some client blocked on write */
141
142static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
143Bool RunFromSigStopParent; /* send SIGSTOP to our own process; Upstart (or
144 equivalent) will send SIGCONT back. */
145static char dynamic_display[7]; /* display name */
146Bool PartialNetwork; /* continue even if unable to bind all addrs */
147static Pid_t ParentProcess;
148
149static Bool debug_conns = FALSE;
150
151fd_set IgnoredClientsWithInput;
152static fd_set GrabImperviousClients;
153static fd_set SavedAllClients;
154static fd_set SavedAllSockets;
155static fd_set SavedClientsWithInput;
156int GrabInProgress = 0;
157
158#if !defined(WIN32)
159int *ConnectionTranslation = NULL;
160#else
161/*
162 * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is
163 * not even a known maximum value, so use something quite arbitrary for now.
164 * Do storage is a hash table of size 256. Collisions are handled in a linked
165 * list.
166 */
167
168#undef MAXSOCKS
169#define MAXSOCKS 500
170#undef MAXSELECT
171#define MAXSELECT 500
172
173struct _ct_node {
174 struct _ct_node *next;
175 int key;
176 int value;
177};
178
179struct _ct_node *ct_head[256];
180
181void
182InitConnectionTranslation(void)
183{
184 memset(ct_head, 0, sizeof(ct_head));
185}
186
187int
188GetConnectionTranslation(int conn)
189{
190 struct _ct_node *node = ct_head[conn & 0xff];
191
192 while (node != NULL) {
193 if (node->key == conn)
194 return node->value;
195 node = node->next;
196 }
197 return 0;
198}
199
200void
201SetConnectionTranslation(int conn, int client)
202{
203 struct _ct_node **node = ct_head + (conn & 0xff);
204
205 if (client == 0) { /* remove entry */
206 while (*node != NULL) {
207 if ((*node)->key == conn) {
208 struct _ct_node *temp = *node;
209
210 *node = (*node)->next;
211 free(temp);
212 return;
213 }
214 node = &((*node)->next);
215 }
216 return;
217 }
218 else {
219 while (*node != NULL) {
220 if ((*node)->key == conn) {
221 (*node)->value = client;
222 return;
223 }
224 node = &((*node)->next);
225 }
226 *node = malloc(sizeof(struct _ct_node));
227 (*node)->next = NULL;
228 (*node)->key = conn;
229 (*node)->value = client;
230 return;
231 }
232}
233
234void
235ClearConnectionTranslation(void)
236{
237 unsigned i;
238
239 for (i = 0; i < 256; i++) {
240 struct _ct_node *node = ct_head[i];
241
242 while (node != NULL) {
243 struct _ct_node *temp = node;
244
245 node = node->next;
246 free(temp);
247 }
248 }
249}
250#endif
251
252static XtransConnInfo *ListenTransConns = NULL;
253static int *ListenTransFds = NULL;
254static int ListenTransCount;
255
256static void ErrorConnMax(XtransConnInfo /* trans_conn */ );
257
258static XtransConnInfo
259lookup_trans_conn(int fd)
260{
261 if (ListenTransFds) {
262 int i;
263
264 for (i = 0; i < ListenTransCount; i++)
265 if (ListenTransFds[i] == fd)
266 return ListenTransConns[i];
267 }
268
269 return NULL;
270}
271
272/* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */
273
274void
275InitConnectionLimits(void)
276{
277 lastfdesc = -1;
278
279#ifndef __CYGWIN__
280
281#if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX)
282 lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
283#endif
284
285#ifdef HAVE_GETDTABLESIZE
286 if (lastfdesc < 0)
287 lastfdesc = getdtablesize() - 1;
288#endif
289
290#ifdef _NFILE
291 if (lastfdesc < 0)
292 lastfdesc = _NFILE - 1;
293#endif
294
295#endif /* __CYGWIN__ */
296
297 /* This is the fallback */
298 if (lastfdesc < 0)
299 lastfdesc = MAXSOCKS;
300
301 if (lastfdesc > MAXSELECT)
302 lastfdesc = MAXSELECT;
303
304 if (lastfdesc > MAXCLIENTS) {
305 lastfdesc = MAXCLIENTS;
306 if (debug_conns)
307 ErrorF("REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS);
308 }
309 MaxClients = lastfdesc;
310
311#ifdef DEBUG
312 ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients);
313#endif
314
315#if !defined(WIN32)
316 if (!ConnectionTranslation)
317 ConnectionTranslation = (int *) xnfalloc(sizeof(int) * (lastfdesc + 1));
318#else
319 InitConnectionTranslation();
320#endif
321}
322
323/*
324 * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
325 *
326 * a- The parent process is ignoring SIGUSR1
327 *
328 * or
329 *
330 * b- The parent process is expecting a SIGUSR1
331 * when the server is ready to accept connections
332 *
333 * In the first case, the signal will be harmless, in the second case,
334 * the signal will be quite useful.
335 */
336static void
337InitParentProcess(void)
338{
339#if !defined(WIN32)
340 OsSigHandlerPtr handler;
341
342 handler = OsSignal(SIGUSR1, SIG_IGN);
343 if (handler == SIG_IGN)
344 RunFromSmartParent = TRUE;
345 OsSignal(SIGUSR1, handler);
346 ParentProcess = getppid();
347#endif
348}
349
350void
351NotifyParentProcess(void)
352{
353#if !defined(WIN32)
354 if (dynamic_display[0]) {
355 write(displayfd, dynamic_display, strlen(dynamic_display));
356 write(displayfd, "\n", 1);
357 close(displayfd);
358 }
359 if (RunFromSmartParent) {
360 if (ParentProcess > 1) {
361 kill(ParentProcess, SIGUSR1);
362 }
363 }
364 if (RunFromSigStopParent)
365 raise(SIGSTOP);
366#endif
367}
368
369static Bool
370TryCreateSocket(int num, int *partial)
371{
372 char port[20];
373
374 snprintf(port, sizeof(port), "%d", num);
375
376 return (_XSERVTransMakeAllCOTSServerListeners(port, partial,
377 &ListenTransCount,
378 &ListenTransConns) >= 0);
379}
380
381/*****************
382 * CreateWellKnownSockets
383 * At initialization, create the sockets to listen on for new clients.
384 *****************/
385
386void
387CreateWellKnownSockets(void)
388{
389 int i;
390 int partial;
391
392 FD_ZERO(&AllSockets);
393 FD_ZERO(&AllClients);
394 FD_ZERO(&LastSelectMask);
395 FD_ZERO(&ClientsWithInput);
396
397#if !defined(WIN32)
398 for (i = 0; i < MaxClients; i++)
399 ConnectionTranslation[i] = 0;
400#else
401 ClearConnectionTranslation();
402#endif
403
404 FD_ZERO(&WellKnownConnections);
405
406 /* display is initialized to "0" by main(). It is then set to the display
407 * number if specified on the command line, or to NULL when the -displayfd
408 * option is used. */
409 if (display) {
410 if (TryCreateSocket(atoi(display), &partial) &&
411 ListenTransCount >= 1)
412 if (!PartialNetwork && partial)
413 FatalError ("Failed to establish all listening sockets");
414 }
415 else { /* -displayfd */
416 Bool found = 0;
417 for (i = 0; i < 65535 - X_TCP_PORT; i++) {
418 if (TryCreateSocket(i, &partial) && !partial) {
419 found = 1;
420 break;
421 }
422 else
423 CloseWellKnownConnections();
424 }
425 if (!found)
426 FatalError("Failed to find a socket to listen on");
427 snprintf(dynamic_display, sizeof(dynamic_display), "%d", i);
428 display = dynamic_display;
429 }
430
431 ListenTransFds = malloc(ListenTransCount * sizeof (int));
432
433 for (i = 0; i < ListenTransCount; i++) {
434 int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
435
436 ListenTransFds[i] = fd;
437 FD_SET(fd, &WellKnownConnections);
438
439 if (!_XSERVTransIsLocal(ListenTransConns[i]))
440 DefineSelf (fd);
441 }
442
443 if (!XFD_ANYSET(&WellKnownConnections))
444 FatalError
445 ("Cannot establish any listening sockets - Make sure an X server isn't already running");
446#if !defined(WIN32)
447 OsSignal(SIGPIPE, SIG_IGN);
448 OsSignal(SIGHUP, AutoResetServer);
449#endif
450 OsSignal(SIGINT, GiveUp);
451 OsSignal(SIGTERM, GiveUp);
452 XFD_COPYSET(&WellKnownConnections, &AllSockets);
453 ResetHosts(display);
454
455 InitParentProcess();
456
457#ifdef XDMCP
458 XdmcpInit();
459#endif
460}
461
462void
463ResetWellKnownSockets(void)
464{
465 int i;
466
467 ResetOsBuffers();
468
469 for (i = 0; i < ListenTransCount; i++) {
470 int status = _XSERVTransResetListener(ListenTransConns[i]);
471
472 if (status != TRANS_RESET_NOOP) {
473 if (status == TRANS_RESET_FAILURE) {
474 /*
475 * ListenTransConns[i] freed by xtrans.
476 * Remove it from out list.
477 */
478
479 FD_CLR(ListenTransFds[i], &WellKnownConnections);
480 ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
481 ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
482 ListenTransCount -= 1;
483 i -= 1;
484 }
485 else if (status == TRANS_RESET_NEW_FD) {
486 /*
487 * A new file descriptor was allocated (the old one was closed)
488 */
489
490 int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
491
492 FD_CLR(ListenTransFds[i], &WellKnownConnections);
493 ListenTransFds[i] = newfd;
494 FD_SET(newfd, &WellKnownConnections);
495 }
496 }
497 }
498
499 ResetAuthorization();
500 ResetHosts(display);
501 /*
502 * restart XDMCP
503 */
504#ifdef XDMCP
505 XdmcpReset();
506#endif
507}
508
509void
510CloseWellKnownConnections(void)
511{
512 int i;
513
514 for (i = 0; i < ListenTransCount; i++)
515 _XSERVTransClose(ListenTransConns[i]);
516}
517
518static void
519AuthAudit(ClientPtr client, Bool letin,
520 struct sockaddr *saddr, int len,
521 unsigned int proto_n, char *auth_proto, int auth_id)
522{
523 char addr[128];
524 char client_uid_string[64];
525 LocalClientCredRec *lcc;
526
527#ifdef XSERVER_DTRACE
528 pid_t client_pid = -1;
529 zoneid_t client_zid = -1;
530#endif
531
532 if (!len)
533 strlcpy(addr, "local host", sizeof(addr));
534 else
535 switch (saddr->sa_family) {
536 case AF_UNSPEC:
537#if defined(UNIXCONN) || defined(LOCALCONN)
538 case AF_UNIX:
539#endif
540 strlcpy(addr, "local host", sizeof(addr));
541 break;
542#if defined(TCPCONN) || defined(STREAMSCONN)
543 case AF_INET:
544 snprintf(addr, sizeof(addr), "IP %s",
545 inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
546 break;
547#if defined(IPv6) && defined(AF_INET6)
548 case AF_INET6:{
549 char ipaddr[INET6_ADDRSTRLEN];
550
551 inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
552 ipaddr, sizeof(ipaddr));
553 snprintf(addr, sizeof(addr), "IP %s", ipaddr);
554 }
555 break;
556#endif
557#endif
558 default:
559 strlcpy(addr, "unknown address", sizeof(addr));
560 }
561
562 if (GetLocalClientCreds(client, &lcc) != -1) {
563 int slen; /* length written to client_uid_string */
564
565 strcpy(client_uid_string, " ( ");
566 slen = 3;
567
568 if (lcc->fieldsSet & LCC_UID_SET) {
569 snprintf(client_uid_string + slen,
570 sizeof(client_uid_string) - slen,
571 "uid=%ld ", (long) lcc->euid);
572 slen = strlen(client_uid_string);
573 }
574
575 if (lcc->fieldsSet & LCC_GID_SET) {
576 snprintf(client_uid_string + slen,
577 sizeof(client_uid_string) - slen,
578 "gid=%ld ", (long) lcc->egid);
579 slen = strlen(client_uid_string);
580 }
581
582 if (lcc->fieldsSet & LCC_PID_SET) {
583#ifdef XSERVER_DTRACE
584 client_pid = lcc->pid;
585#endif
586 snprintf(client_uid_string + slen,
587 sizeof(client_uid_string) - slen,
588 "pid=%ld ", (long) lcc->pid);
589 slen = strlen(client_uid_string);
590 }
591
592 if (lcc->fieldsSet & LCC_ZID_SET) {
593#ifdef XSERVER_DTRACE
594 client_zid = lcc->zoneid;
595#endif
596 snprintf(client_uid_string + slen,
597 sizeof(client_uid_string) - slen,
598 "zoneid=%ld ", (long) lcc->zoneid);
599 slen = strlen(client_uid_string);
600 }
601
602 snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
603 ")");
604 FreeLocalClientCreds(lcc);
605 }
606 else {
607 client_uid_string[0] = '\0';
608 }
609
610#ifdef XSERVER_DTRACE
611 XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
612#endif
613 if (auditTrailLevel > 1) {
614 if (proto_n)
615 AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n",
616 client->index, letin ? "connected" : "rejected", addr,
617 client_uid_string, (int) proto_n, auth_proto, auth_id);
618 else
619 AuditF("client %d %s from %s%s\n",
620 client->index, letin ? "connected" : "rejected", addr,
621 client_uid_string);
622
623 }
624}
625
626XID
627AuthorizationIDOfClient(ClientPtr client)
628{
629 if (client->osPrivate)
630 return ((OsCommPtr) client->osPrivate)->auth_id;
631 else
632 return None;
633}
634
635/*****************************************************************
636 * ClientAuthorized
637 *
638 * Sent by the client at connection setup:
639 * typedef struct _xConnClientPrefix {
640 * CARD8 byteOrder;
641 * BYTE pad;
642 * CARD16 majorVersion, minorVersion;
643 * CARD16 nbytesAuthProto;
644 * CARD16 nbytesAuthString;
645 * } xConnClientPrefix;
646 *
647 * It is hoped that eventually one protocol will be agreed upon. In the
648 * mean time, a server that implements a different protocol than the
649 * client expects, or a server that only implements the host-based
650 * mechanism, will simply ignore this information.
651 *
652 *****************************************************************/
653
654const char *
655ClientAuthorized(ClientPtr client,
656 unsigned int proto_n, char *auth_proto,
657 unsigned int string_n, char *auth_string)
658{
659 OsCommPtr priv;
660 Xtransaddr *from = NULL;
661 int family;
662 int fromlen;
663 XID auth_id;
664 const char *reason = NULL;
665 XtransConnInfo trans_conn;
666
667 priv = (OsCommPtr) client->osPrivate;
668 trans_conn = priv->trans_conn;
669
670 /* Allow any client to connect without authorization on a launchd socket,
671 because it is securely created -- this prevents a race condition on launch */
672 if (trans_conn->flags & TRANS_NOXAUTH) {
673 auth_id = (XID) 0L;
674 }
675 else {
676 auth_id =
677 CheckAuthorization(proto_n, auth_proto, string_n, auth_string,
678 client, &reason);
679 }
680
681 if (auth_id == (XID) ~0L) {
682 if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
683 if (InvalidHost((struct sockaddr *) from, fromlen, client))
684 AuthAudit(client, FALSE, (struct sockaddr *) from,
685 fromlen, proto_n, auth_proto, auth_id);
686 else {
687 auth_id = (XID) 0;
688#ifdef XSERVER_DTRACE
689 if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
690#else
691 if (auditTrailLevel > 1)
692#endif
693 AuthAudit(client, TRUE,
694 (struct sockaddr *) from, fromlen,
695 proto_n, auth_proto, auth_id);
696 }
697
698 free(from);
699 }
700
701 if (auth_id == (XID) ~0L) {
702 if (reason)
703 return reason;
704 else
705 return "Client is not authorized to connect to Server";
706 }
707 }
708#ifdef XSERVER_DTRACE
709 else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
710#else
711 else if (auditTrailLevel > 1)
712#endif
713 {
714 if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
715 AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
716 proto_n, auth_proto, auth_id);
717
718 free(from);
719 }
720 }
721 priv->auth_id = auth_id;
722 priv->conn_time = 0;
723
724#ifdef XDMCP
725 /* indicate to Xdmcp protocol that we've opened new client */
726 XdmcpOpenDisplay(priv->fd);
727#endif /* XDMCP */
728
729 XaceHook(XACE_AUTH_AVAIL, client, auth_id);
730
731 /* At this point, if the client is authorized to change the access control
732 * list, we should getpeername() information, and add the client to
733 * the selfhosts list. It's not really the host machine, but the
734 * true purpose of the selfhosts list is to see who may change the
735 * access control list.
736 */
737 return ((char *) NULL);
738}
739
740static ClientPtr
741AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
742{
743 OsCommPtr oc;
744 ClientPtr client;
745
746 if (
747#ifndef WIN32
748 fd >= lastfdesc
749#else
750 XFD_SETCOUNT(&AllClients) >= MaxClients
751#endif
752 )
753 return NullClient;
754 oc = malloc(sizeof(OsCommRec));
755 if (!oc)
756 return NullClient;
757 oc->trans_conn = trans_conn;
758 oc->fd = fd;
759 oc->input = (ConnectionInputPtr) NULL;
760 oc->output = (ConnectionOutputPtr) NULL;
761 oc->auth_id = None;
762 oc->conn_time = conn_time;
763 if (!(client = NextAvailableClient((pointer) oc))) {
764 free(oc);
765 return NullClient;
766 }
767 client->local = ComputeLocalClient(client);
768#if !defined(WIN32)
769 ConnectionTranslation[fd] = client->index;
770#else
771 SetConnectionTranslation(fd, client->index);
772#endif
773 if (GrabInProgress) {
774 FD_SET(fd, &SavedAllClients);
775 FD_SET(fd, &SavedAllSockets);
776 }
777 else {
778 FD_SET(fd, &AllClients);
779 FD_SET(fd, &AllSockets);
780 }
781
782#ifdef DEBUG
783 ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
784 client->index, fd);
785#endif
786#ifdef XSERVER_DTRACE
787 XSERVER_CLIENT_CONNECT(client->index, fd);
788#endif
789
790 return client;
791}
792
793/*****************
794 * EstablishNewConnections
795 * If anyone is waiting on listened sockets, accept them.
796 * Returns a mask with indices of new clients. Updates AllClients
797 * and AllSockets.
798 *****************/
799
800 /*ARGSUSED*/ Bool
801EstablishNewConnections(ClientPtr clientUnused, pointer closure)
802{
803 fd_set readyconnections; /* set of listeners that are ready */
804 int curconn; /* fd of listener that's ready */
805 register int newconn; /* fd of new client */
806 CARD32 connect_time;
807 register int i;
808 register ClientPtr client;
809 register OsCommPtr oc;
810 fd_set tmask;
811
812 XFD_ANDSET(&tmask, (fd_set *) closure, &WellKnownConnections);
813 XFD_COPYSET(&tmask, &readyconnections);
814 if (!XFD_ANYSET(&readyconnections))
815 return TRUE;
816 connect_time = GetTimeInMillis();
817 /* kill off stragglers */
818 for (i = 1; i < currentMaxClients; i++) {
819 if ((client = clients[i])) {
820 oc = (OsCommPtr) (client->osPrivate);
821 if ((oc && (oc->conn_time != 0) &&
822 (connect_time - oc->conn_time) >= TimeOutValue) ||
823 (client->noClientException != Success && !client->clientGone))
824 CloseDownClient(client);
825 }
826 }
827#ifndef WIN32
828 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
829 while (readyconnections.fds_bits[i])
830#else
831 for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++)
832#endif
833 {
834 XtransConnInfo trans_conn, new_trans_conn;
835 int status;
836
837#ifndef WIN32
838 curconn = mffs(readyconnections.fds_bits[i]) - 1;
839 readyconnections.fds_bits[i] &= ~((fd_mask) 1 << curconn);
840 curconn += (i * (sizeof(fd_mask) * 8));
841#else
842 curconn = XFD_FD(&readyconnections, i);
843#endif
844
845 if ((trans_conn = lookup_trans_conn(curconn)) == NULL)
846 continue;
847
848 if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL)
849 continue;
850
851 newconn = _XSERVTransGetConnectionNumber(new_trans_conn);
852
853 if (newconn < lastfdesc) {
854 int clientid;
855
856#if !defined(WIN32)
857 clientid = ConnectionTranslation[newconn];
858#else
859 clientid = GetConnectionTranslation(newconn);
860#endif
861 if (clientid && (client = clients[clientid]))
862 CloseDownClient(client);
863 }
864
865 _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
866
867 if (trans_conn->flags & TRANS_NOXAUTH)
868 new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
869
870 if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) {
871 ErrorConnMax(new_trans_conn);
872 _XSERVTransClose(new_trans_conn);
873 }
874 }
875#ifndef WIN32
876}
877#endif
878return TRUE;
879}
880
881#define NOROOM "Maximum number of clients reached"
882
883/************
884 * ErrorConnMax
885 * Fail a connection due to lack of client or file descriptor space
886 ************/
887
888#define BOTIMEOUT 200 /* in milliseconds */
889
890static void
891ErrorConnMax(XtransConnInfo trans_conn)
892{
893 int fd = _XSERVTransGetConnectionNumber(trans_conn);
894 xConnSetupPrefix csp;
895 char pad[3] = { 0, 0, 0 };
896 struct iovec iov[3];
897 char order = 0;
898 int whichbyte = 1;
899 struct timeval waittime;
900 fd_set mask;
901
902 /* if these seems like a lot of trouble to go to, it probably is */
903 waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND;
904 waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
905 (1000000 / MILLI_PER_SECOND);
906 FD_ZERO(&mask);
907 FD_SET(fd, &mask);
908 (void) Select(fd + 1, &mask, NULL, NULL, &waittime);
909 /* try to read the byte-order of the connection */
910 (void) _XSERVTransRead(trans_conn, &order, 1);
911 if (order == 'l' || order == 'B' || order == 'r' || order == 'R') {
912 csp.success = xFalse;
913 csp.lengthReason = sizeof(NOROOM) - 1;
914 csp.length = (sizeof(NOROOM) + 2) >> 2;
915 csp.majorVersion = X_PROTOCOL;
916 csp.minorVersion = X_PROTOCOL_REVISION;
917 if (((*(char *) &whichbyte) && (order == 'B' || order == 'R')) ||
918 (!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) {
919 swaps(&csp.majorVersion);
920 swaps(&csp.minorVersion);
921 swaps(&csp.length);
922 }
923 iov[0].iov_len = sz_xConnSetupPrefix;
924 iov[0].iov_base = (char *) &csp;
925 iov[1].iov_len = csp.lengthReason;
926 iov[1].iov_base = (void *) NOROOM;
927 iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
928 iov[2].iov_base = pad;
929 (void) _XSERVTransWritev(trans_conn, iov, 3);
930 }
931}
932
933/************
934 * CloseDownFileDescriptor:
935 * Remove this file descriptor and it's I/O buffers, etc.
936 ************/
937
938static void
939CloseDownFileDescriptor(OsCommPtr oc)
940{
941 int connection = oc->fd;
942
943 if (oc->trans_conn) {
944 _XSERVTransDisconnect(oc->trans_conn);
945 _XSERVTransClose(oc->trans_conn);
946 }
947#ifndef WIN32
948 ConnectionTranslation[connection] = 0;
949#else
950 SetConnectionTranslation(connection, 0);
951#endif
952 FD_CLR(connection, &AllSockets);
953 FD_CLR(connection, &AllClients);
954 FD_CLR(connection, &ClientsWithInput);
955 FD_CLR(connection, &GrabImperviousClients);
956 if (GrabInProgress) {
957 FD_CLR(connection, &SavedAllSockets);
958 FD_CLR(connection, &SavedAllClients);
959 FD_CLR(connection, &SavedClientsWithInput);
960 }
961 FD_CLR(connection, &ClientsWriteBlocked);
962 if (!XFD_ANYSET(&ClientsWriteBlocked))
963 AnyClientsWriteBlocked = FALSE;
964 FD_CLR(connection, &OutputPending);
965}
966
967/*****************
968 * CheckConnections
969 * Some connection has died, go find which one and shut it down
970 * The file descriptor has been closed, but is still in AllClients.
971 * If would truly be wonderful if select() would put the bogus
972 * file descriptors in the exception mask, but nooooo. So we have
973 * to check each and every socket individually.
974 *****************/
975
976void
977CheckConnections(void)
978{
979#ifndef WIN32
980 fd_mask mask;
981#endif
982 fd_set tmask;
983 int curclient, curoff;
984 int i;
985 struct timeval notime;
986 int r;
987
988#ifdef WIN32
989 fd_set savedAllClients;
990#endif
991
992 notime.tv_sec = 0;
993 notime.tv_usec = 0;
994
995#ifndef WIN32
996 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
997 mask = AllClients.fds_bits[i];
998 while (mask) {
999 curoff = mffs(mask) - 1;
1000 curclient = curoff + (i * (sizeof(fd_mask) * 8));
1001 FD_ZERO(&tmask);
1002 FD_SET(curclient, &tmask);
1003 do {
1004 r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
1005 } while (r < 0 && (errno == EINTR || errno == EAGAIN));
1006 if (r < 0)
1007 if (ConnectionTranslation[curclient] > 0)
1008 CloseDownClient(clients[ConnectionTranslation[curclient]]);
1009 mask &= ~((fd_mask) 1 << curoff);
1010 }
1011 }
1012#else
1013 XFD_COPYSET(&AllClients, &savedAllClients);
1014 for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) {
1015 curclient = XFD_FD(&savedAllClients, i);
1016 FD_ZERO(&tmask);
1017 FD_SET(curclient, &tmask);
1018 do {
1019 r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
1020 } while (r < 0 && (errno == EINTR || errno == EAGAIN));
1021 if (r < 0)
1022 if (GetConnectionTranslation(curclient) > 0)
1023 CloseDownClient(clients[GetConnectionTranslation(curclient)]);
1024 }
1025#endif
1026}
1027
1028/*****************
1029 * CloseDownConnection
1030 * Delete client from AllClients and free resources
1031 *****************/
1032
1033void
1034CloseDownConnection(ClientPtr client)
1035{
1036 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1037
1038 if (FlushCallback)
1039 CallCallbacks(&FlushCallback, NULL);
1040
1041 if (oc->output)
1042 FlushClient(client, oc, (char *) NULL, 0);
1043#ifdef XDMCP
1044 XdmcpCloseDisplay(oc->fd);
1045#endif
1046 CloseDownFileDescriptor(oc);
1047 FreeOsBuffers(oc);
1048 free(client->osPrivate);
1049 client->osPrivate = (pointer) NULL;
1050 if (auditTrailLevel > 1)
1051 AuditF("client %d disconnected\n", client->index);
1052}
1053
1054void
1055AddGeneralSocket(int fd)
1056{
1057 FD_SET(fd, &AllSockets);
1058 if (GrabInProgress)
1059 FD_SET(fd, &SavedAllSockets);
1060}
1061
1062void
1063AddEnabledDevice(int fd)
1064{
1065 FD_SET(fd, &EnabledDevices);
1066 AddGeneralSocket(fd);
1067}
1068
1069void
1070RemoveGeneralSocket(int fd)
1071{
1072 FD_CLR(fd, &AllSockets);
1073 if (GrabInProgress)
1074 FD_CLR(fd, &SavedAllSockets);
1075}
1076
1077void
1078RemoveEnabledDevice(int fd)
1079{
1080 FD_CLR(fd, &EnabledDevices);
1081 RemoveGeneralSocket(fd);
1082}
1083
1084/*****************
1085 * OnlyListenToOneClient:
1086 * Only accept requests from one client. Continue to handle new
1087 * connections, but don't take any protocol requests from the new
1088 * ones. Note that if GrabInProgress is set, EstablishNewConnections
1089 * needs to put new clients into SavedAllSockets and SavedAllClients.
1090 * Note also that there is no timeout for this in the protocol.
1091 * This routine is "undone" by ListenToAllClients()
1092 *****************/
1093
1094int
1095OnlyListenToOneClient(ClientPtr client)
1096{
1097 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1098 int rc, connection = oc->fd;
1099
1100 rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
1101 if (rc != Success)
1102 return rc;
1103
1104 if (!GrabInProgress) {
1105 XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
1106 XFD_ANDSET(&ClientsWithInput,
1107 &ClientsWithInput, &GrabImperviousClients);
1108 if (FD_ISSET(connection, &SavedClientsWithInput)) {
1109 FD_CLR(connection, &SavedClientsWithInput);
1110 FD_SET(connection, &ClientsWithInput);
1111 }
1112 XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
1113 XFD_COPYSET(&AllSockets, &SavedAllSockets);
1114 XFD_COPYSET(&AllClients, &SavedAllClients);
1115 XFD_UNSET(&AllSockets, &AllClients);
1116 XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
1117 FD_SET(connection, &AllClients);
1118 XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
1119 GrabInProgress = client->index;
1120 }
1121 return rc;
1122}
1123
1124/****************
1125 * ListenToAllClients:
1126 * Undoes OnlyListentToOneClient()
1127 ****************/
1128
1129void
1130ListenToAllClients(void)
1131{
1132 if (GrabInProgress) {
1133 XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
1134 XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
1135 XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
1136 GrabInProgress = 0;
1137 }
1138}
1139
1140/****************
1141 * IgnoreClient
1142 * Removes one client from input masks.
1143 * Must have cooresponding call to AttendClient.
1144 ****************/
1145
1146void
1147IgnoreClient(ClientPtr client)
1148{
1149 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1150 int connection = oc->fd;
1151
1152 client->ignoreCount++;
1153 if (client->ignoreCount > 1)
1154 return;
1155
1156 isItTimeToYield = TRUE;
1157 if (!GrabInProgress || FD_ISSET(connection, &AllClients)) {
1158 if (FD_ISSET(connection, &ClientsWithInput))
1159 FD_SET(connection, &IgnoredClientsWithInput);
1160 else
1161 FD_CLR(connection, &IgnoredClientsWithInput);
1162 FD_CLR(connection, &ClientsWithInput);
1163 FD_CLR(connection, &AllSockets);
1164 FD_CLR(connection, &AllClients);
1165 FD_CLR(connection, &LastSelectMask);
1166 }
1167 else {
1168 if (FD_ISSET(connection, &SavedClientsWithInput))
1169 FD_SET(connection, &IgnoredClientsWithInput);
1170 else
1171 FD_CLR(connection, &IgnoredClientsWithInput);
1172 FD_CLR(connection, &SavedClientsWithInput);
1173 FD_CLR(connection, &SavedAllSockets);
1174 FD_CLR(connection, &SavedAllClients);
1175 }
1176}
1177
1178/****************
1179 * AttendClient
1180 * Adds one client back into the input masks.
1181 ****************/
1182
1183void
1184AttendClient(ClientPtr client)
1185{
1186 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1187 int connection = oc->fd;
1188
1189 client->ignoreCount--;
1190 if (client->ignoreCount)
1191 return;
1192
1193 if (!GrabInProgress || GrabInProgress == client->index ||
1194 FD_ISSET(connection, &GrabImperviousClients)) {
1195 FD_SET(connection, &AllClients);
1196 FD_SET(connection, &AllSockets);
1197 FD_SET(connection, &LastSelectMask);
1198 if (FD_ISSET(connection, &IgnoredClientsWithInput))
1199 FD_SET(connection, &ClientsWithInput);
1200 }
1201 else {
1202 FD_SET(connection, &SavedAllClients);
1203 FD_SET(connection, &SavedAllSockets);
1204 if (FD_ISSET(connection, &IgnoredClientsWithInput))
1205 FD_SET(connection, &SavedClientsWithInput);
1206 }
1207}
1208
1209/* make client impervious to grabs; assume only executing client calls this */
1210
1211void
1212MakeClientGrabImpervious(ClientPtr client)
1213{
1214 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1215 int connection = oc->fd;
1216
1217 FD_SET(connection, &GrabImperviousClients);
1218
1219 if (ServerGrabCallback) {
1220 ServerGrabInfoRec grabinfo;
1221
1222 grabinfo.client = client;
1223 grabinfo.grabstate = CLIENT_IMPERVIOUS;
1224 CallCallbacks(&ServerGrabCallback, &grabinfo);
1225 }
1226}
1227
1228/* make client pervious to grabs; assume only executing client calls this */
1229
1230void
1231MakeClientGrabPervious(ClientPtr client)
1232{
1233 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1234 int connection = oc->fd;
1235
1236 FD_CLR(connection, &GrabImperviousClients);
1237 if (GrabInProgress && (GrabInProgress != client->index)) {
1238 if (FD_ISSET(connection, &ClientsWithInput)) {
1239 FD_SET(connection, &SavedClientsWithInput);
1240 FD_CLR(connection, &ClientsWithInput);
1241 }
1242 FD_CLR(connection, &AllSockets);
1243 FD_CLR(connection, &AllClients);
1244 isItTimeToYield = TRUE;
1245 }
1246
1247 if (ServerGrabCallback) {
1248 ServerGrabInfoRec grabinfo;
1249
1250 grabinfo.client = client;
1251 grabinfo.grabstate = CLIENT_PERVIOUS;
1252 CallCallbacks(&ServerGrabCallback, &grabinfo);
1253 }
1254}
1255
1256#ifdef XQUARTZ
1257/* Add a fd (from launchd) to our listeners */
1258void
1259ListenOnOpenFD(int fd, int noxauth)
1260{
1261 char port[256];
1262 XtransConnInfo ciptr;
1263 const char *display_env = getenv("DISPLAY");
1264
1265 if (display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) {
1266 /* Make the path the launchd socket if our DISPLAY is set right */
1267 strcpy(port, display_env);
1268 }
1269 else {
1270 /* Just some default so things don't break and die. */
1271 snprintf(port, sizeof(port), ":%d", atoi(display));
1272 }
1273
1274 /* Make our XtransConnInfo
1275 * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
1276 */
1277 ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1278 if (ciptr == NULL) {
1279 ErrorF("Got NULL while trying to Reopen launchd port.\n");
1280 return;
1281 }
1282
1283 if (noxauth)
1284 ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
1285
1286 /* Allocate space to store it */
1287 ListenTransFds =
1288 (int *) realloc(ListenTransFds, (ListenTransCount + 1) * sizeof(int));
1289 ListenTransConns =
1290 (XtransConnInfo *) realloc(ListenTransConns,
1291 (ListenTransCount +
1292 1) * sizeof(XtransConnInfo));
1293
1294 /* Store it */
1295 ListenTransConns[ListenTransCount] = ciptr;
1296 ListenTransFds[ListenTransCount] = fd;
1297
1298 FD_SET(fd, &WellKnownConnections);
1299 FD_SET(fd, &AllSockets);
1300
1301 /* Increment the count */
1302 ListenTransCount++;
1303
1304 /* This *might* not be needed... /shrug */
1305 ResetAuthorization();
1306 ResetHosts(display);
1307#ifdef XDMCP
1308 XdmcpReset();
1309#endif
1310}
1311
1312#endif