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