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