connection.c revision 6747b715
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#ifdef HAVE_DIX_CONFIG_H
65#include <dix-config.h>
66#endif
67
68#ifdef WIN32
69#include <X11/Xwinsock.h>
70#endif
71#include <X11/X.h>
72#include <X11/Xproto.h>
73#define XSERV_t
74#define TRANS_SERVER
75#define TRANS_REOPEN
76#include <X11/Xtrans/Xtrans.h>
77#include <X11/Xtrans/Xtransint.h>
78#include <errno.h>
79#include <signal.h>
80#include <stdio.h>
81#include <stdlib.h>
82
83#ifndef WIN32
84#include <sys/socket.h>
85
86
87
88#if defined(TCPCONN) || defined(STREAMSCONN)
89# include <netinet/in.h>
90# include <arpa/inet.h>
91#  ifdef apollo
92#   ifndef NO_TCP_H
93#    include <netinet/tcp.h>
94#   endif
95#  else
96#   ifdef CSRG_BASED
97#    include <sys/param.h>
98#   endif
99#   include <netinet/tcp.h>
100#  endif
101# include <arpa/inet.h>
102#endif
103
104#include <sys/uio.h>
105
106#endif /* WIN32 */
107#include "misc.h"		/* for typedef of pointer */
108#include "osdep.h"
109#include <X11/Xpoll.h>
110#include "opaque.h"
111#include "dixstruct.h"
112#include "xace.h"
113
114#define Pid_t pid_t
115
116#ifdef DNETCONN
117#include <netdnet/dn.h>
118#endif /* DNETCONN */
119
120#ifdef HAS_GETPEERUCRED
121# include <ucred.h>
122# include <zone.h>
123#endif
124
125#ifdef XSERVER_DTRACE
126# include <sys/types.h>
127typedef const char *string;
128# ifndef HAS_GETPEERUCRED
129#  define zoneid_t int
130# endif
131# include "../dix/Xserver-dtrace.h"
132#endif
133
134static int lastfdesc;		/* maximum file descriptor */
135
136fd_set WellKnownConnections;	/* Listener mask */
137fd_set EnabledDevices;		/* mask for input devices that are on */
138fd_set AllSockets;		/* select on this */
139fd_set AllClients;		/* available clients */
140fd_set LastSelectMask;		/* mask returned from last select call */
141fd_set ClientsWithInput;	/* clients with FULL requests in buffer */
142fd_set ClientsWriteBlocked;	/* clients who cannot receive output */
143fd_set OutputPending;		/* clients with reply/event data ready to go */
144int MaxClients = 0;
145Bool NewOutputPending;		/* not yet attempted to write some new output */
146Bool AnyClientsWriteBlocked;	/* true if some client blocked on write */
147
148static Bool RunFromSmartParent;	/* send SIGUSR1 to parent process */
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#endif
361}
362
363/*****************
364 * CreateWellKnownSockets
365 *    At initialization, create the sockets to listen on for new clients.
366 *****************/
367
368void
369CreateWellKnownSockets(void)
370{
371    int		i;
372    int		partial;
373    char 	port[20];
374
375    FD_ZERO(&AllSockets);
376    FD_ZERO(&AllClients);
377    FD_ZERO(&LastSelectMask);
378    FD_ZERO(&ClientsWithInput);
379
380#if !defined(WIN32)
381    for (i=0; i<MaxClients; i++) ConnectionTranslation[i] = 0;
382#else
383    ClearConnectionTranslation();
384#endif
385
386    FD_ZERO (&WellKnownConnections);
387
388    sprintf (port, "%d", atoi (display));
389
390    if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial,
391	&ListenTransCount, &ListenTransConns) >= 0) &&
392	(ListenTransCount >= 1))
393    {
394	if (!PartialNetwork && partial)
395	{
396	    FatalError ("Failed to establish all listening sockets");
397	}
398	else
399	{
400	    ListenTransFds = malloc(ListenTransCount * sizeof (int));
401
402	    for (i = 0; i < ListenTransCount; i++)
403	    {
404		int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
405
406		ListenTransFds[i] = fd;
407		FD_SET (fd, &WellKnownConnections);
408
409		if (!_XSERVTransIsLocal (ListenTransConns[i]))
410		{
411		    DefineSelf (fd);
412		}
413	    }
414	}
415    }
416
417    if (!XFD_ANYSET (&WellKnownConnections))
418        FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running");
419#if !defined(WIN32)
420    OsSignal (SIGPIPE, SIG_IGN);
421    OsSignal (SIGHUP, AutoResetServer);
422#endif
423    OsSignal (SIGINT, GiveUp);
424    OsSignal (SIGTERM, GiveUp);
425    XFD_COPYSET (&WellKnownConnections, &AllSockets);
426    ResetHosts(display);
427
428    InitParentProcess();
429
430#ifdef XDMCP
431    XdmcpInit ();
432#endif
433}
434
435void
436ResetWellKnownSockets (void)
437{
438    int i;
439
440    ResetOsBuffers();
441
442    for (i = 0; i < ListenTransCount; i++)
443    {
444	int status = _XSERVTransResetListener (ListenTransConns[i]);
445
446	if (status != TRANS_RESET_NOOP)
447	{
448	    if (status == TRANS_RESET_FAILURE)
449	    {
450		/*
451		 * ListenTransConns[i] freed by xtrans.
452		 * Remove it from out list.
453		 */
454
455		FD_CLR (ListenTransFds[i], &WellKnownConnections);
456		ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
457		ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
458		ListenTransCount -= 1;
459		i -= 1;
460	    }
461	    else if (status == TRANS_RESET_NEW_FD)
462	    {
463		/*
464		 * A new file descriptor was allocated (the old one was closed)
465		 */
466
467		int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
468
469		FD_CLR (ListenTransFds[i], &WellKnownConnections);
470		ListenTransFds[i] = newfd;
471		FD_SET(newfd, &WellKnownConnections);
472	    }
473	}
474    }
475
476    ResetAuthorization ();
477    ResetHosts(display);
478    /*
479     * restart XDMCP
480     */
481#ifdef XDMCP
482    XdmcpReset ();
483#endif
484}
485
486void
487CloseWellKnownConnections(void)
488{
489    int i;
490
491    for (i = 0; i < ListenTransCount; i++)
492	_XSERVTransClose (ListenTransConns[i]);
493}
494
495static void
496AuthAudit (ClientPtr client, Bool letin,
497    struct sockaddr *saddr, int len,
498    unsigned int proto_n, char *auth_proto, int auth_id)
499{
500    char addr[128];
501    char *out = addr;
502    char client_uid_string[64];
503    LocalClientCredRec *lcc;
504#ifdef XSERVER_DTRACE
505    pid_t client_pid = -1;
506    zoneid_t client_zid = -1;
507#endif
508
509    if (!len)
510        strcpy(out, "local host");
511    else
512	switch (saddr->sa_family)
513	{
514	case AF_UNSPEC:
515#if defined(UNIXCONN) || defined(LOCALCONN)
516	case AF_UNIX:
517#endif
518	    strcpy(out, "local host");
519	    break;
520#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN)
521	case AF_INET:
522	    sprintf(out, "IP %s",
523		inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
524	    break;
525#if defined(IPv6) && defined(AF_INET6)
526	case AF_INET6: {
527	    char ipaddr[INET6_ADDRSTRLEN];
528	    inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
529	      ipaddr, sizeof(ipaddr));
530	    sprintf(out, "IP %s", ipaddr);
531	}
532	    break;
533#endif
534#endif
535#ifdef DNETCONN
536	case AF_DECnet:
537	    sprintf(out, "DN %s",
538		    dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add));
539	    break;
540#endif
541	default:
542	    strcpy(out, "unknown address");
543	}
544
545    if (GetLocalClientCreds(client, &lcc) != -1) {
546	int slen; /* length written to client_uid_string */
547
548	strcpy(client_uid_string, " ( ");
549	slen = 3;
550
551	if (lcc->fieldsSet & LCC_UID_SET) {
552	    snprintf(client_uid_string + slen,
553		     sizeof(client_uid_string) - slen,
554		     "uid=%ld ", (long) lcc->euid);
555	    slen = strlen(client_uid_string);
556	}
557
558	if (lcc->fieldsSet & LCC_GID_SET) {
559	    snprintf(client_uid_string + slen,
560		     sizeof(client_uid_string) - slen,
561		     "gid=%ld ", (long) lcc->egid);
562	    slen = strlen(client_uid_string);
563	}
564
565	if (lcc->fieldsSet & LCC_PID_SET) {
566#ifdef XSERVER_DTRACE
567	    client_pid = lcc->pid;
568#endif
569	    snprintf(client_uid_string + slen,
570		     sizeof(client_uid_string) - slen,
571		     "pid=%ld ", (long) lcc->pid);
572	    slen = strlen(client_uid_string);
573	}
574
575	if (lcc->fieldsSet & LCC_ZID_SET) {
576#ifdef XSERVER_DTRACE
577	    client_zid = lcc->zoneid;
578#endif
579	    snprintf(client_uid_string + slen,
580		     sizeof(client_uid_string) - slen,
581		     "zoneid=%ld ", (long) lcc->zoneid);
582	    slen = strlen(client_uid_string);
583	}
584
585	snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
586		 ")");
587	FreeLocalClientCreds(lcc);
588    }
589    else {
590	client_uid_string[0] = '\0';
591    }
592
593#ifdef XSERVER_DTRACE
594    XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
595#endif
596    if (auditTrailLevel > 1) {
597      if (proto_n)
598	AuditF("client %d %s from %s%s\n  Auth name: %.*s ID: %d\n",
599	       client->index, letin ? "connected" : "rejected", addr,
600	       client_uid_string, (int)proto_n, auth_proto, auth_id);
601      else
602	AuditF("client %d %s from %s%s\n",
603	       client->index, letin ? "connected" : "rejected", addr,
604	       client_uid_string);
605
606    }
607}
608
609XID
610AuthorizationIDOfClient(ClientPtr client)
611{
612    if (client->osPrivate)
613	return ((OsCommPtr)client->osPrivate)->auth_id;
614    else
615	return None;
616}
617
618
619/*****************************************************************
620 * ClientAuthorized
621 *
622 *    Sent by the client at connection setup:
623 *                typedef struct _xConnClientPrefix {
624 *                   CARD8	byteOrder;
625 *                   BYTE	pad;
626 *                   CARD16	majorVersion, minorVersion;
627 *                   CARD16	nbytesAuthProto;
628 *                   CARD16	nbytesAuthString;
629 *                 } xConnClientPrefix;
630 *
631 *     	It is hoped that eventually one protocol will be agreed upon.  In the
632 *        mean time, a server that implements a different protocol than the
633 *        client expects, or a server that only implements the host-based
634 *        mechanism, will simply ignore this information.
635 *
636 *****************************************************************/
637
638char *
639ClientAuthorized(ClientPtr client,
640    unsigned int proto_n, char *auth_proto,
641    unsigned int string_n, char *auth_string)
642{
643    OsCommPtr 		priv;
644    Xtransaddr		*from = NULL;
645    int 		family;
646    int			fromlen;
647    XID	 		auth_id;
648    char	 	*reason = NULL;
649    XtransConnInfo	trans_conn;
650
651    priv = (OsCommPtr)client->osPrivate;
652    trans_conn = priv->trans_conn;
653
654    /* Allow any client to connect without authorization on a launchd socket,
655       because it is securely created -- this prevents a race condition on launch */
656    if(trans_conn->flags & TRANS_NOXAUTH) {
657        auth_id = (XID) 0L;
658    } else {
659        auth_id = CheckAuthorization (proto_n, auth_proto, string_n, auth_string, client, &reason);
660    }
661
662    if (auth_id == (XID) ~0L)
663    {
664	if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1)
665	{
666	    if (InvalidHost ((struct sockaddr *) from, fromlen, client))
667		AuthAudit(client, FALSE, (struct sockaddr *) from,
668			  fromlen, proto_n, auth_proto, auth_id);
669	    else
670	    {
671		auth_id = (XID) 0;
672#ifdef XSERVER_DTRACE
673		if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
674#else
675		if (auditTrailLevel > 1)
676#endif
677		    AuthAudit(client, TRUE,
678			(struct sockaddr *) from, fromlen,
679			proto_n, auth_proto, auth_id);
680	    }
681
682	    free(from);
683	}
684
685	if (auth_id == (XID) ~0L) {
686	    if (reason)
687		return reason;
688	    else
689		return "Client is not authorized to connect to Server";
690	}
691    }
692#ifdef XSERVER_DTRACE
693    else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
694#else
695    else if (auditTrailLevel > 1)
696#endif
697    {
698	if (_XSERVTransGetPeerAddr (trans_conn,
699	    &family, &fromlen, &from) != -1)
700	{
701	    AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
702		      proto_n, auth_proto, auth_id);
703
704	    free(from);
705	}
706    }
707    priv->auth_id = auth_id;
708    priv->conn_time = 0;
709
710#ifdef XDMCP
711    /* indicate to Xdmcp protocol that we've opened new client */
712    XdmcpOpenDisplay(priv->fd);
713#endif /* XDMCP */
714
715    XaceHook(XACE_AUTH_AVAIL, client, auth_id);
716
717    /* At this point, if the client is authorized to change the access control
718     * list, we should getpeername() information, and add the client to
719     * the selfhosts list.  It's not really the host machine, but the
720     * true purpose of the selfhosts list is to see who may change the
721     * access control list.
722     */
723    return((char *)NULL);
724}
725
726static ClientPtr
727AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time)
728{
729    OsCommPtr	oc;
730    ClientPtr	client;
731
732    if (
733#ifndef WIN32
734	fd >= lastfdesc
735#else
736	XFD_SETCOUNT(&AllClients) >= MaxClients
737#endif
738	)
739	return NullClient;
740    oc = malloc(sizeof(OsCommRec));
741    if (!oc)
742	return NullClient;
743    oc->trans_conn = trans_conn;
744    oc->fd = fd;
745    oc->input = (ConnectionInputPtr)NULL;
746    oc->output = (ConnectionOutputPtr)NULL;
747    oc->auth_id = None;
748    oc->conn_time = conn_time;
749    if (!(client = NextAvailableClient((pointer)oc)))
750    {
751	free(oc);
752	return NullClient;
753    }
754#if !defined(WIN32)
755    ConnectionTranslation[fd] = client->index;
756#else
757    SetConnectionTranslation(fd, client->index);
758#endif
759    if (GrabInProgress)
760    {
761        FD_SET(fd, &SavedAllClients);
762        FD_SET(fd, &SavedAllSockets);
763    }
764    else
765    {
766        FD_SET(fd, &AllClients);
767        FD_SET(fd, &AllSockets);
768    }
769
770#ifdef DEBUG
771    ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
772	   client->index, fd);
773#endif
774#ifdef XSERVER_DTRACE
775    XSERVER_CLIENT_CONNECT(client->index, fd);
776#endif
777
778    return client;
779}
780
781/*****************
782 * EstablishNewConnections
783 *    If anyone is waiting on listened sockets, accept them.
784 *    Returns a mask with indices of new clients.  Updates AllClients
785 *    and AllSockets.
786 *****************/
787
788/*ARGSUSED*/
789Bool
790EstablishNewConnections(ClientPtr clientUnused, pointer closure)
791{
792    fd_set  readyconnections;     /* set of listeners that are ready */
793    int curconn;                  /* fd of listener that's ready */
794    register int newconn;         /* fd of new client */
795    CARD32 connect_time;
796    register int i;
797    register ClientPtr client;
798    register OsCommPtr oc;
799    fd_set tmask;
800
801    XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections);
802    XFD_COPYSET(&tmask, &readyconnections);
803    if (!XFD_ANYSET(&readyconnections))
804	return TRUE;
805    connect_time = GetTimeInMillis();
806    /* kill off stragglers */
807    for (i=1; i<currentMaxClients; i++)
808    {
809	if ((client = clients[i]))
810	{
811	    oc = (OsCommPtr)(client->osPrivate);
812	    if ((oc && (oc->conn_time != 0) &&
813		(connect_time - oc->conn_time) >= TimeOutValue) ||
814		(client->noClientException != Success && !client->clientGone))
815		CloseDownClient(client);
816	}
817    }
818#ifndef WIN32
819    for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++)
820    {
821      while (readyconnections.fds_bits[i])
822#else
823      for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++)
824#endif
825      {
826	XtransConnInfo trans_conn, new_trans_conn;
827	int status;
828
829#ifndef WIN32
830	curconn = mffs (readyconnections.fds_bits[i]) - 1;
831	readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn);
832	curconn += (i * (sizeof(fd_mask)*8));
833#else
834	curconn = XFD_FD(&readyconnections, i);
835#endif
836
837	if ((trans_conn = lookup_trans_conn (curconn)) == NULL)
838	    continue;
839
840	if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL)
841	    continue;
842
843	newconn = _XSERVTransGetConnectionNumber (new_trans_conn);
844
845	if (newconn < lastfdesc)
846	{
847		int clientid;
848#if !defined(WIN32)
849  		clientid = ConnectionTranslation[newconn];
850#else
851  		clientid = GetConnectionTranslation(newconn);
852#endif
853		if(clientid && (client = clients[clientid]))
854 			CloseDownClient(client);
855	}
856
857	_XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
858
859	if (!AllocNewConnection (new_trans_conn, newconn, connect_time))
860	{
861	    ErrorConnMax(new_trans_conn);
862	    _XSERVTransClose(new_trans_conn);
863	}
864
865	if(trans_conn->flags & TRANS_NOXAUTH)
866	    new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
867
868      }
869#ifndef WIN32
870    }
871#endif
872    return TRUE;
873}
874
875#define NOROOM "Maximum number of clients reached"
876
877/************
878 *   ErrorConnMax
879 *     Fail a connection due to lack of client or file descriptor space
880 ************/
881
882static void
883ErrorConnMax(XtransConnInfo trans_conn)
884{
885    int fd = _XSERVTransGetConnectionNumber (trans_conn);
886    xConnSetupPrefix csp;
887    char pad[3];
888    struct iovec iov[3];
889    char byteOrder = 0;
890    int whichbyte = 1;
891    struct timeval waittime;
892    fd_set mask;
893
894    /* if these seems like a lot of trouble to go to, it probably is */
895    waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND;
896    waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
897		       (1000000 / MILLI_PER_SECOND);
898    FD_ZERO(&mask);
899    FD_SET(fd, &mask);
900    (void)Select(fd + 1, &mask, NULL, NULL, &waittime);
901    /* try to read the byte-order of the connection */
902    (void)_XSERVTransRead(trans_conn, &byteOrder, 1);
903    if ((byteOrder == 'l') || (byteOrder == 'B'))
904    {
905	csp.success = xFalse;
906	csp.lengthReason = sizeof(NOROOM) - 1;
907	csp.length = (sizeof(NOROOM) + 2) >> 2;
908	csp.majorVersion = X_PROTOCOL;
909	csp.minorVersion = X_PROTOCOL_REVISION;
910	if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
911	    (!(*(char *) &whichbyte) && (byteOrder == 'l')))
912	{
913	    swaps(&csp.majorVersion, whichbyte);
914	    swaps(&csp.minorVersion, whichbyte);
915	    swaps(&csp.length, whichbyte);
916	}
917	iov[0].iov_len = sz_xConnSetupPrefix;
918	iov[0].iov_base = (char *) &csp;
919	iov[1].iov_len = csp.lengthReason;
920	iov[1].iov_base = NOROOM;
921	iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
922	iov[2].iov_base = pad;
923	(void)_XSERVTransWritev(trans_conn, iov, 3);
924    }
925}
926
927/************
928 *   CloseDownFileDescriptor:
929 *     Remove this file descriptor and it's I/O buffers, etc.
930 ************/
931
932static void
933CloseDownFileDescriptor(OsCommPtr oc)
934{
935    int connection = oc->fd;
936
937    if (oc->trans_conn) {
938	_XSERVTransDisconnect(oc->trans_conn);
939	_XSERVTransClose(oc->trans_conn);
940    }
941#ifndef WIN32
942    ConnectionTranslation[connection] = 0;
943#else
944    SetConnectionTranslation(connection, 0);
945#endif
946    FD_CLR(connection, &AllSockets);
947    FD_CLR(connection, &AllClients);
948    FD_CLR(connection, &ClientsWithInput);
949    FD_CLR(connection, &GrabImperviousClients);
950    if (GrabInProgress)
951    {
952	FD_CLR(connection, &SavedAllSockets);
953	FD_CLR(connection, &SavedAllClients);
954	FD_CLR(connection, &SavedClientsWithInput);
955    }
956    FD_CLR(connection, &ClientsWriteBlocked);
957    if (!XFD_ANYSET(&ClientsWriteBlocked))
958    	AnyClientsWriteBlocked = FALSE;
959    FD_CLR(connection, &OutputPending);
960}
961
962/*****************
963 * CheckConnections
964 *    Some connection has died, go find which one and shut it down
965 *    The file descriptor has been closed, but is still in AllClients.
966 *    If would truly be wonderful if select() would put the bogus
967 *    file descriptors in the exception mask, but nooooo.  So we have
968 *    to check each and every socket individually.
969 *****************/
970
971void
972CheckConnections(void)
973{
974#ifndef WIN32
975    fd_mask		mask;
976#endif
977    fd_set		tmask;
978    int			curclient, curoff;
979    int			i;
980    struct timeval	notime;
981    int r;
982#ifdef WIN32
983    fd_set savedAllClients;
984#endif
985
986    notime.tv_sec = 0;
987    notime.tv_usec = 0;
988
989#ifndef WIN32
990    for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
991    {
992	mask = AllClients.fds_bits[i];
993        while (mask)
994    	{
995	    curoff = mffs (mask) - 1;
996	    curclient = curoff + (i * (sizeof(fd_mask)*8));
997            FD_ZERO(&tmask);
998            FD_SET(curclient, &tmask);
999            do {
1000                r = Select (curclient + 1, &tmask, NULL, NULL, &notime);
1001            } while (r < 0 && (errno == EINTR || errno == EAGAIN));
1002            if (r < 0)
1003                if (ConnectionTranslation[curclient] > 0)
1004                    CloseDownClient(clients[ConnectionTranslation[curclient]]);
1005	    mask &= ~((fd_mask)1 << curoff);
1006	}
1007    }
1008#else
1009    XFD_COPYSET(&AllClients, &savedAllClients);
1010    for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++)
1011    {
1012	curclient = XFD_FD(&savedAllClients, i);
1013	FD_ZERO(&tmask);
1014	FD_SET(curclient, &tmask);
1015        do {
1016            r = Select (curclient + 1, &tmask, NULL, NULL, &notime);
1017        } while (r < 0 && (errno == EINTR || errno == EAGAIN));
1018	if (r < 0)
1019            if (GetConnectionTranslation(curclient) > 0)
1020                CloseDownClient(clients[GetConnectionTranslation(curclient)]);
1021    }
1022#endif
1023}
1024
1025
1026/*****************
1027 * CloseDownConnection
1028 *    Delete client from AllClients and free resources
1029 *****************/
1030
1031void
1032CloseDownConnection(ClientPtr client)
1033{
1034    OsCommPtr oc = (OsCommPtr)client->osPrivate;
1035
1036    if (FlushCallback)
1037	CallCallbacks(&FlushCallback, NULL);
1038
1039    if (oc->output && oc->output->count)
1040	FlushClient(client, oc, (char *)NULL, 0);
1041#ifdef XDMCP
1042    XdmcpCloseDisplay(oc->fd);
1043#endif
1044    CloseDownFileDescriptor(oc);
1045    FreeOsBuffers(oc);
1046    free(client->osPrivate);
1047    client->osPrivate = (pointer)NULL;
1048    if (auditTrailLevel > 1)
1049	AuditF("client %d disconnected\n", client->index);
1050}
1051
1052void
1053AddGeneralSocket(int fd)
1054{
1055    FD_SET(fd, &AllSockets);
1056    if (GrabInProgress)
1057	FD_SET(fd, &SavedAllSockets);
1058}
1059
1060void
1061AddEnabledDevice(int fd)
1062{
1063    FD_SET(fd, &EnabledDevices);
1064    AddGeneralSocket(fd);
1065}
1066
1067void
1068RemoveGeneralSocket(int fd)
1069{
1070    FD_CLR(fd, &AllSockets);
1071    if (GrabInProgress)
1072	FD_CLR(fd, &SavedAllSockets);
1073}
1074
1075void
1076RemoveEnabledDevice(int fd)
1077{
1078    FD_CLR(fd, &EnabledDevices);
1079    RemoveGeneralSocket(fd);
1080}
1081
1082/*****************
1083 * OnlyListenToOneClient:
1084 *    Only accept requests from  one client.  Continue to handle new
1085 *    connections, but don't take any protocol requests from the new
1086 *    ones.  Note that if GrabInProgress is set, EstablishNewConnections
1087 *    needs to put new clients into SavedAllSockets and SavedAllClients.
1088 *    Note also that there is no timeout for this in the protocol.
1089 *    This routine is "undone" by ListenToAllClients()
1090 *****************/
1091
1092int
1093OnlyListenToOneClient(ClientPtr client)
1094{
1095    OsCommPtr oc = (OsCommPtr)client->osPrivate;
1096    int rc, connection = oc->fd;
1097
1098    rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
1099    if (rc != Success)
1100	return rc;
1101
1102    if (! GrabInProgress)
1103    {
1104	XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
1105	XFD_ANDSET(&ClientsWithInput,
1106		       &ClientsWithInput, &GrabImperviousClients);
1107	if (FD_ISSET(connection, &SavedClientsWithInput))
1108	{
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    {
1134	XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
1135	XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
1136	XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
1137	GrabInProgress = 0;
1138    }
1139}
1140
1141/****************
1142 * IgnoreClient
1143 *    Removes one client from input masks.
1144 *    Must have cooresponding call to AttendClient.
1145 ****************/
1146
1147void
1148IgnoreClient (ClientPtr client)
1149{
1150    OsCommPtr oc = (OsCommPtr)client->osPrivate;
1151    int connection = oc->fd;
1152
1153    client->ignoreCount++;
1154    if (client->ignoreCount > 1)
1155	return;
1156
1157    isItTimeToYield = TRUE;
1158    if (!GrabInProgress || FD_ISSET(connection, &AllClients))
1159    {
1160    	if (FD_ISSET (connection, &ClientsWithInput))
1161	    FD_SET(connection, &IgnoredClientsWithInput);
1162    	else
1163	    FD_CLR(connection, &IgnoredClientsWithInput);
1164    	FD_CLR(connection, &ClientsWithInput);
1165    	FD_CLR(connection, &AllSockets);
1166    	FD_CLR(connection, &AllClients);
1167	FD_CLR(connection, &LastSelectMask);
1168    }
1169    else
1170    {
1171    	if (FD_ISSET (connection, &SavedClientsWithInput))
1172	    FD_SET(connection, &IgnoredClientsWithInput);
1173    	else
1174	    FD_CLR(connection, &IgnoredClientsWithInput);
1175	FD_CLR(connection, &SavedClientsWithInput);
1176	FD_CLR(connection, &SavedAllSockets);
1177	FD_CLR(connection, &SavedAllClients);
1178    }
1179}
1180
1181/****************
1182 * AttendClient
1183 *    Adds one client back into the input masks.
1184 ****************/
1185
1186void
1187AttendClient (ClientPtr client)
1188{
1189    OsCommPtr oc = (OsCommPtr)client->osPrivate;
1190    int connection = oc->fd;
1191
1192    client->ignoreCount--;
1193    if (client->ignoreCount)
1194	return;
1195
1196    if (!GrabInProgress || GrabInProgress == client->index ||
1197	FD_ISSET(connection, &GrabImperviousClients))
1198    {
1199    	FD_SET(connection, &AllClients);
1200    	FD_SET(connection, &AllSockets);
1201	FD_SET(connection, &LastSelectMask);
1202    	if (FD_ISSET (connection, &IgnoredClientsWithInput))
1203	    FD_SET(connection, &ClientsWithInput);
1204    }
1205    else
1206    {
1207	FD_SET(connection, &SavedAllClients);
1208	FD_SET(connection, &SavedAllSockets);
1209	if (FD_ISSET(connection, &IgnoredClientsWithInput))
1210	    FD_SET(connection, &SavedClientsWithInput);
1211    }
1212}
1213
1214/* make client impervious to grabs; assume only executing client calls this */
1215
1216void
1217MakeClientGrabImpervious(ClientPtr client)
1218{
1219    OsCommPtr oc = (OsCommPtr)client->osPrivate;
1220    int connection = oc->fd;
1221
1222    FD_SET(connection, &GrabImperviousClients);
1223
1224    if (ServerGrabCallback)
1225    {
1226	ServerGrabInfoRec grabinfo;
1227	grabinfo.client = client;
1228	grabinfo.grabstate  = CLIENT_IMPERVIOUS;
1229	CallCallbacks(&ServerGrabCallback, &grabinfo);
1230    }
1231}
1232
1233/* make client pervious to grabs; assume only executing client calls this */
1234
1235void
1236MakeClientGrabPervious(ClientPtr client)
1237{
1238    OsCommPtr oc = (OsCommPtr)client->osPrivate;
1239    int connection = oc->fd;
1240
1241    FD_CLR(connection, &GrabImperviousClients);
1242    if (GrabInProgress && (GrabInProgress != client->index))
1243    {
1244	if (FD_ISSET(connection, &ClientsWithInput))
1245	{
1246	    FD_SET(connection, &SavedClientsWithInput);
1247	    FD_CLR(connection, &ClientsWithInput);
1248	}
1249	FD_CLR(connection, &AllSockets);
1250	FD_CLR(connection, &AllClients);
1251	isItTimeToYield = TRUE;
1252    }
1253
1254    if (ServerGrabCallback)
1255    {
1256	ServerGrabInfoRec grabinfo;
1257	grabinfo.client = client;
1258	grabinfo.grabstate  = CLIENT_PERVIOUS;
1259	CallCallbacks(&ServerGrabCallback, &grabinfo);
1260    }
1261}
1262
1263#ifdef XQUARTZ
1264/* Add a fd (from launchd) to our listeners */
1265void ListenOnOpenFD(int fd, int noxauth) {
1266    char port[256];
1267    XtransConnInfo ciptr;
1268    const char *display_env = getenv("DISPLAY");
1269
1270    if(display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) {
1271        /* Make the path the launchd socket if our DISPLAY is set right */
1272        strcpy(port, display_env);
1273    } else {
1274        /* Just some default so things don't break and die. */
1275        sprintf(port, ":%d", atoi(display));
1276    }
1277
1278    /* Make our XtransConnInfo
1279     * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
1280     */
1281    ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1282    if(ciptr == NULL) {
1283        ErrorF("Got NULL while trying to Reopen launchd port.\n");
1284        return;
1285    }
1286
1287    if(noxauth)
1288        ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
1289
1290    /* Allocate space to store it */
1291    ListenTransFds = (int *) realloc(ListenTransFds, (ListenTransCount + 1) * sizeof (int));
1292    ListenTransConns = (XtransConnInfo *) realloc(ListenTransConns, (ListenTransCount + 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
1313