connection.c revision 4e185dc0
105b261ecSmrg/***********************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1989, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrgCopyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrg                        All Rights Reserved
2805b261ecSmrg
29f7df2e56SmrgPermission to use, copy, modify, and distribute this software and its
30f7df2e56Smrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
32f7df2e56Smrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Digital not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
35f7df2e56Smrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4305b261ecSmrgSOFTWARE.
4405b261ecSmrg
4505b261ecSmrg******************************************************************/
4605b261ecSmrg/*****************************************************************
4705b261ecSmrg *  Stuff to create connections --- OS dependent
4805b261ecSmrg *
4905b261ecSmrg *      EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
507e31ba66Smrg *      CloseDownConnection,
517e31ba66Smrg *	OnlyListToOneClient,
5205b261ecSmrg *      ListenToAllClients,
5305b261ecSmrg *
5405b261ecSmrg *      (WaitForSomething is in its own file)
5505b261ecSmrg *
5605b261ecSmrg *      In this implementation, a client socket table is not kept.
5705b261ecSmrg *      Instead, what would be the index into the table is just the
5805b261ecSmrg *      file descriptor of the socket.  This won't work for if the
5905b261ecSmrg *      socket ids aren't small nums (0 - 2^8)
6005b261ecSmrg *
6105b261ecSmrg *****************************************************************/
6205b261ecSmrg
635bd42952Smrg#include <X11/Xpoll.h>
645bd42952Smrg
6505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
6605b261ecSmrg#include <dix-config.h>
6705b261ecSmrg#endif
6805b261ecSmrg
6905b261ecSmrg#ifdef WIN32
7005b261ecSmrg#include <X11/Xwinsock.h>
7105b261ecSmrg#endif
7205b261ecSmrg#include <X11/X.h>
7305b261ecSmrg#include <X11/Xproto.h>
7405b261ecSmrg#define XSERV_t
7505b261ecSmrg#define TRANS_SERVER
7605b261ecSmrg#define TRANS_REOPEN
7705b261ecSmrg#include <X11/Xtrans/Xtrans.h>
784642e01fSmrg#include <X11/Xtrans/Xtransint.h>
7905b261ecSmrg#include <errno.h>
8005b261ecSmrg#include <signal.h>
8105b261ecSmrg#include <stdio.h>
8205b261ecSmrg#include <stdlib.h>
8305b261ecSmrg
8405b261ecSmrg#ifndef WIN32
8505b261ecSmrg#include <sys/socket.h>
8605b261ecSmrg
877e31ba66Smrg#if defined(TCPCONN)
88f7df2e56Smrg#include <netinet/in.h>
89f7df2e56Smrg#include <arpa/inet.h>
90f7df2e56Smrg#ifdef apollo
91f7df2e56Smrg#ifndef NO_TCP_H
92f7df2e56Smrg#include <netinet/tcp.h>
93f7df2e56Smrg#endif
94f7df2e56Smrg#else
95f7df2e56Smrg#ifdef CSRG_BASED
96f7df2e56Smrg#include <sys/param.h>
97f7df2e56Smrg#endif
98f7df2e56Smrg#include <netinet/tcp.h>
99f7df2e56Smrg#endif
100f7df2e56Smrg#include <arpa/inet.h>
10105b261ecSmrg#endif
10205b261ecSmrg
10305b261ecSmrg#include <sys/uio.h>
1044642e01fSmrg
105f7df2e56Smrg#endif                          /* WIN32 */
106f7df2e56Smrg#include "misc.h"               /* for typedef of pointer */
10705b261ecSmrg#include "osdep.h"
10805b261ecSmrg#include "opaque.h"
10905b261ecSmrg#include "dixstruct.h"
11005b261ecSmrg#include "xace.h"
11105b261ecSmrg
11205b261ecSmrg#define Pid_t pid_t
11305b261ecSmrg
114f7df2e56Smrg#ifdef HAVE_GETPEERUCRED
115f7df2e56Smrg#include <ucred.h>
116f7df2e56Smrg#include <zone.h>
117f7df2e56Smrg#else
118f7df2e56Smrg#define zoneid_t int
11905b261ecSmrg#endif
12005b261ecSmrg
121f7df2e56Smrg#include "probes.h"
12205b261ecSmrg
1237e31ba66Smrgstruct ospoll   *server_poll;
12405b261ecSmrg
12505b261ecSmrgint MaxClients = 0;
126f7df2e56SmrgBool NewOutputPending;          /* not yet attempted to write some new output */
127f7df2e56SmrgBool NoListenAll;               /* Don't establish any listening sockets */
128f7df2e56Smrg
129f7df2e56Smrgstatic Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
130f7df2e56SmrgBool RunFromSigStopParent;      /* send SIGSTOP to our own process; Upstart (or
131f7df2e56Smrg                                   equivalent) will send SIGCONT back. */
132f7df2e56Smrgstatic char dynamic_display[7]; /* display name */
133f7df2e56SmrgBool PartialNetwork;            /* continue even if unable to bind all addrs */
13405b261ecSmrgstatic Pid_t ParentProcess;
13505b261ecSmrg
1366747b715Smrgint GrabInProgress = 0;
13705b261ecSmrg
1387e31ba66Smrgstatic void
1397e31ba66SmrgQueueNewConnections(int curconn, int ready, void *data);
140f7df2e56Smrg
1417e31ba66Smrgstatic void
1427e31ba66Smrgset_poll_client(ClientPtr client);
143f7df2e56Smrg
1447e31ba66Smrgstatic void
1457e31ba66Smrgset_poll_clients(void);
14605b261ecSmrg
147f7df2e56Smrgstatic XtransConnInfo *ListenTransConns = NULL;
148f7df2e56Smrgstatic int *ListenTransFds = NULL;
149f7df2e56Smrgstatic int ListenTransCount;
15005b261ecSmrg
151f7df2e56Smrgstatic void ErrorConnMax(XtransConnInfo /* trans_conn */ );
15205b261ecSmrg
15305b261ecSmrgstatic XtransConnInfo
154f7df2e56Smrglookup_trans_conn(int fd)
15505b261ecSmrg{
156f7df2e56Smrg    if (ListenTransFds) {
157f7df2e56Smrg        int i;
158f7df2e56Smrg
159f7df2e56Smrg        for (i = 0; i < ListenTransCount; i++)
160f7df2e56Smrg            if (ListenTransFds[i] == fd)
161f7df2e56Smrg                return ListenTransConns[i];
16205b261ecSmrg    }
16305b261ecSmrg
1646747b715Smrg    return NULL;
16505b261ecSmrg}
16605b261ecSmrg
1677e31ba66Smrg/* Set MaxClients */
16805b261ecSmrg
16905b261ecSmrgvoid
17005b261ecSmrgInitConnectionLimits(void)
17105b261ecSmrg{
1727e31ba66Smrg    MaxClients = MAXCLIENTS;
17305b261ecSmrg
17405b261ecSmrg#ifdef DEBUG
17505b261ecSmrg    ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients);
17605b261ecSmrg#endif
17705b261ecSmrg}
17805b261ecSmrg
1794642e01fSmrg/*
1804642e01fSmrg * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
1814642e01fSmrg *
1824642e01fSmrg *  a- The parent process is ignoring SIGUSR1
1834642e01fSmrg *
1844642e01fSmrg * or
1854642e01fSmrg *
1864642e01fSmrg *  b- The parent process is expecting a SIGUSR1
1874642e01fSmrg *     when the server is ready to accept connections
1884642e01fSmrg *
1894642e01fSmrg * In the first case, the signal will be harmless, in the second case,
1904642e01fSmrg * the signal will be quite useful.
1914642e01fSmrg */
1924642e01fSmrgstatic void
1934642e01fSmrgInitParentProcess(void)
1944642e01fSmrg{
1954642e01fSmrg#if !defined(WIN32)
1964642e01fSmrg    OsSigHandlerPtr handler;
197f7df2e56Smrg
198f7df2e56Smrg    handler = OsSignal(SIGUSR1, SIG_IGN);
199f7df2e56Smrg    if (handler == SIG_IGN)
200f7df2e56Smrg        RunFromSmartParent = TRUE;
2014642e01fSmrg    OsSignal(SIGUSR1, handler);
202f7df2e56Smrg    ParentProcess = getppid();
2034642e01fSmrg#endif
2044642e01fSmrg}
2054642e01fSmrg
2064642e01fSmrgvoid
2074642e01fSmrgNotifyParentProcess(void)
2084642e01fSmrg{
2094642e01fSmrg#if !defined(WIN32)
210f7df2e56Smrg    if (displayfd >= 0) {
211f7df2e56Smrg        if (write(displayfd, display, strlen(display)) != strlen(display))
212f7df2e56Smrg            FatalError("Cannot write display number to fd %d\n", displayfd);
213f7df2e56Smrg        if (write(displayfd, "\n", 1) != 1)
214f7df2e56Smrg            FatalError("Cannot write display number to fd %d\n", displayfd);
215f7df2e56Smrg        close(displayfd);
216f7df2e56Smrg        displayfd = -1;
217f7df2e56Smrg    }
2184642e01fSmrg    if (RunFromSmartParent) {
219f7df2e56Smrg        if (ParentProcess > 1) {
220f7df2e56Smrg            kill(ParentProcess, SIGUSR1);
221f7df2e56Smrg        }
2224642e01fSmrg    }
2239ace9065Smrg    if (RunFromSigStopParent)
224f7df2e56Smrg        raise(SIGSTOP);
2254642e01fSmrg#endif
2264642e01fSmrg}
22705b261ecSmrg
228f7df2e56Smrgstatic Bool
229f7df2e56SmrgTryCreateSocket(int num, int *partial)
230f7df2e56Smrg{
231f7df2e56Smrg    char port[20];
232f7df2e56Smrg
233f7df2e56Smrg    snprintf(port, sizeof(port), "%d", num);
234f7df2e56Smrg
235f7df2e56Smrg    return (_XSERVTransMakeAllCOTSServerListeners(port, partial,
236f7df2e56Smrg                                                  &ListenTransCount,
237f7df2e56Smrg                                                  &ListenTransConns) >= 0);
238f7df2e56Smrg}
239f7df2e56Smrg
24005b261ecSmrg/*****************
24105b261ecSmrg * CreateWellKnownSockets
24205b261ecSmrg *    At initialization, create the sockets to listen on for new clients.
24305b261ecSmrg *****************/
24405b261ecSmrg
24505b261ecSmrgvoid
24605b261ecSmrgCreateWellKnownSockets(void)
24705b261ecSmrg{
248f7df2e56Smrg    int i;
249f7df2e56Smrg    int partial;
25005b261ecSmrg
251f7df2e56Smrg    /* display is initialized to "0" by main(). It is then set to the display
252f7df2e56Smrg     * number if specified on the command line. */
25305b261ecSmrg
254f7df2e56Smrg    if (NoListenAll) {
255f7df2e56Smrg        ListenTransCount = 0;
256f7df2e56Smrg    }
257f7df2e56Smrg    else if ((displayfd < 0) || explicit_display) {
258f7df2e56Smrg        if (TryCreateSocket(atoi(display), &partial) &&
259f7df2e56Smrg            ListenTransCount >= 1)
260f7df2e56Smrg            if (!PartialNetwork && partial)
261f7df2e56Smrg                FatalError ("Failed to establish all listening sockets");
262f7df2e56Smrg    }
263f7df2e56Smrg    else { /* -displayfd and no explicit display number */
264f7df2e56Smrg        Bool found = 0;
265f7df2e56Smrg        for (i = 0; i < 65536 - X_TCP_PORT; i++) {
266f7df2e56Smrg            if (TryCreateSocket(i, &partial) && !partial) {
267f7df2e56Smrg                found = 1;
268f7df2e56Smrg                break;
269f7df2e56Smrg            }
270f7df2e56Smrg            else
271f7df2e56Smrg                CloseWellKnownConnections();
272f7df2e56Smrg        }
273f7df2e56Smrg        if (!found)
274f7df2e56Smrg            FatalError("Failed to find a socket to listen on");
275f7df2e56Smrg        snprintf(dynamic_display, sizeof(dynamic_display), "%d", i);
276f7df2e56Smrg        display = dynamic_display;
277f7df2e56Smrg        LogSetDisplay();
278f7df2e56Smrg    }
279f7df2e56Smrg
280f7df2e56Smrg    ListenTransFds = xallocarray(ListenTransCount, sizeof (int));
281f7df2e56Smrg    if (ListenTransFds == NULL)
282f7df2e56Smrg        FatalError ("Failed to create listening socket array");
283f7df2e56Smrg
284f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
285f7df2e56Smrg        int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
286f7df2e56Smrg
287f7df2e56Smrg        ListenTransFds[i] = fd;
2887e31ba66Smrg        SetNotifyFd(fd, QueueNewConnections, X_NOTIFY_READ, NULL);
289f7df2e56Smrg
290f7df2e56Smrg        if (!_XSERVTransIsLocal(ListenTransConns[i]))
291f7df2e56Smrg            DefineSelf (fd);
29205b261ecSmrg    }
29305b261ecSmrg
2947e31ba66Smrg    if (ListenTransCount == 0 && !NoListenAll)
295f7df2e56Smrg        FatalError
296f7df2e56Smrg            ("Cannot establish any listening sockets - Make sure an X server isn't already running");
297f7df2e56Smrg
29805b261ecSmrg#if !defined(WIN32)
299f7df2e56Smrg    OsSignal(SIGPIPE, SIG_IGN);
300f7df2e56Smrg    OsSignal(SIGHUP, AutoResetServer);
30105b261ecSmrg#endif
302f7df2e56Smrg    OsSignal(SIGINT, GiveUp);
303f7df2e56Smrg    OsSignal(SIGTERM, GiveUp);
30405b261ecSmrg    ResetHosts(display);
3054642e01fSmrg
3064642e01fSmrg    InitParentProcess();
3074642e01fSmrg
30805b261ecSmrg#ifdef XDMCP
309f7df2e56Smrg    XdmcpInit();
31005b261ecSmrg#endif
31105b261ecSmrg}
31205b261ecSmrg
31305b261ecSmrgvoid
314f7df2e56SmrgResetWellKnownSockets(void)
31505b261ecSmrg{
31605b261ecSmrg    int i;
31705b261ecSmrg
31805b261ecSmrg    ResetOsBuffers();
31905b261ecSmrg
320f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
321f7df2e56Smrg        int status = _XSERVTransResetListener(ListenTransConns[i]);
322f7df2e56Smrg
323f7df2e56Smrg        if (status != TRANS_RESET_NOOP) {
324f7df2e56Smrg            if (status == TRANS_RESET_FAILURE) {
325f7df2e56Smrg                /*
326f7df2e56Smrg                 * ListenTransConns[i] freed by xtrans.
327f7df2e56Smrg                 * Remove it from out list.
328f7df2e56Smrg                 */
329f7df2e56Smrg
3307e31ba66Smrg                RemoveNotifyFd(ListenTransFds[i]);
331f7df2e56Smrg                ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
332f7df2e56Smrg                ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
333f7df2e56Smrg                ListenTransCount -= 1;
334f7df2e56Smrg                i -= 1;
335f7df2e56Smrg            }
336f7df2e56Smrg            else if (status == TRANS_RESET_NEW_FD) {
337f7df2e56Smrg                /*
338f7df2e56Smrg                 * A new file descriptor was allocated (the old one was closed)
339f7df2e56Smrg                 */
340f7df2e56Smrg
341f7df2e56Smrg                int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
342f7df2e56Smrg
343f7df2e56Smrg                ListenTransFds[i] = newfd;
344f7df2e56Smrg            }
345f7df2e56Smrg        }
34605b261ecSmrg    }
3477e31ba66Smrg    for (i = 0; i < ListenTransCount; i++)
3487e31ba66Smrg        SetNotifyFd(ListenTransFds[i], QueueNewConnections, X_NOTIFY_READ, NULL);
34905b261ecSmrg
350f7df2e56Smrg    ResetAuthorization();
35105b261ecSmrg    ResetHosts(display);
35205b261ecSmrg    /*
35305b261ecSmrg     * restart XDMCP
35405b261ecSmrg     */
35505b261ecSmrg#ifdef XDMCP
356f7df2e56Smrg    XdmcpReset();
35705b261ecSmrg#endif
35805b261ecSmrg}
35905b261ecSmrg
36005b261ecSmrgvoid
36105b261ecSmrgCloseWellKnownConnections(void)
36205b261ecSmrg{
36305b261ecSmrg    int i;
36405b261ecSmrg
365f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
366f7df2e56Smrg        if (ListenTransConns[i] != NULL) {
367f7df2e56Smrg            _XSERVTransClose(ListenTransConns[i]);
368f7df2e56Smrg            ListenTransConns[i] = NULL;
3697e31ba66Smrg            if (ListenTransFds != NULL)
3707e31ba66Smrg                RemoveNotifyFd(ListenTransFds[i]);
371f7df2e56Smrg        }
372f7df2e56Smrg    }
373f7df2e56Smrg    ListenTransCount = 0;
37405b261ecSmrg}
37505b261ecSmrg
37605b261ecSmrgstatic void
377f7df2e56SmrgAuthAudit(ClientPtr client, Bool letin,
378f7df2e56Smrg          struct sockaddr *saddr, int len,
379f7df2e56Smrg          unsigned int proto_n, char *auth_proto, int auth_id)
38005b261ecSmrg{
38105b261ecSmrg    char addr[128];
38205b261ecSmrg    char client_uid_string[64];
3834642e01fSmrg    LocalClientCredRec *lcc;
384f7df2e56Smrg
3854642e01fSmrg#ifdef XSERVER_DTRACE
38605b261ecSmrg    pid_t client_pid = -1;
38705b261ecSmrg    zoneid_t client_zid = -1;
38805b261ecSmrg#endif
38905b261ecSmrg
39005b261ecSmrg    if (!len)
391f7df2e56Smrg        strlcpy(addr, "local host", sizeof(addr));
39205b261ecSmrg    else
393f7df2e56Smrg        switch (saddr->sa_family) {
394f7df2e56Smrg        case AF_UNSPEC:
39505b261ecSmrg#if defined(UNIXCONN) || defined(LOCALCONN)
396f7df2e56Smrg        case AF_UNIX:
39705b261ecSmrg#endif
398f7df2e56Smrg            strlcpy(addr, "local host", sizeof(addr));
399f7df2e56Smrg            break;
4007e31ba66Smrg#if defined(TCPCONN)
401f7df2e56Smrg        case AF_INET:
402f7df2e56Smrg            snprintf(addr, sizeof(addr), "IP %s",
403f7df2e56Smrg                     inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
404f7df2e56Smrg            break;
40505b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
406f7df2e56Smrg        case AF_INET6:{
407f7df2e56Smrg            char ipaddr[INET6_ADDRSTRLEN];
408f7df2e56Smrg
409f7df2e56Smrg            inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
410f7df2e56Smrg                      ipaddr, sizeof(ipaddr));
411f7df2e56Smrg            snprintf(addr, sizeof(addr), "IP %s", ipaddr);
412f7df2e56Smrg        }
413f7df2e56Smrg            break;
41405b261ecSmrg#endif
41505b261ecSmrg#endif
416f7df2e56Smrg        default:
417f7df2e56Smrg            strlcpy(addr, "unknown address", sizeof(addr));
418f7df2e56Smrg        }
41905b261ecSmrg
4204642e01fSmrg    if (GetLocalClientCreds(client, &lcc) != -1) {
421f7df2e56Smrg        int slen;               /* length written to client_uid_string */
422f7df2e56Smrg
423f7df2e56Smrg        strcpy(client_uid_string, " ( ");
424f7df2e56Smrg        slen = 3;
425f7df2e56Smrg
426f7df2e56Smrg        if (lcc->fieldsSet & LCC_UID_SET) {
427f7df2e56Smrg            snprintf(client_uid_string + slen,
428f7df2e56Smrg                     sizeof(client_uid_string) - slen,
429f7df2e56Smrg                     "uid=%ld ", (long) lcc->euid);
430f7df2e56Smrg            slen = strlen(client_uid_string);
431f7df2e56Smrg        }
432f7df2e56Smrg
433f7df2e56Smrg        if (lcc->fieldsSet & LCC_GID_SET) {
434f7df2e56Smrg            snprintf(client_uid_string + slen,
435f7df2e56Smrg                     sizeof(client_uid_string) - slen,
436f7df2e56Smrg                     "gid=%ld ", (long) lcc->egid);
437f7df2e56Smrg            slen = strlen(client_uid_string);
438f7df2e56Smrg        }
439f7df2e56Smrg
440f7df2e56Smrg        if (lcc->fieldsSet & LCC_PID_SET) {
441f7df2e56Smrg#ifdef XSERVER_DTRACE
442f7df2e56Smrg            client_pid = lcc->pid;
44305b261ecSmrg#endif
444f7df2e56Smrg            snprintf(client_uid_string + slen,
445f7df2e56Smrg                     sizeof(client_uid_string) - slen,
446f7df2e56Smrg                     "pid=%ld ", (long) lcc->pid);
447f7df2e56Smrg            slen = strlen(client_uid_string);
448f7df2e56Smrg        }
449f7df2e56Smrg
450f7df2e56Smrg        if (lcc->fieldsSet & LCC_ZID_SET) {
4514642e01fSmrg#ifdef XSERVER_DTRACE
452f7df2e56Smrg            client_zid = lcc->zoneid;
453f7df2e56Smrg#endif
454f7df2e56Smrg            snprintf(client_uid_string + slen,
455f7df2e56Smrg                     sizeof(client_uid_string) - slen,
456f7df2e56Smrg                     "zoneid=%ld ", (long) lcc->zoneid);
457f7df2e56Smrg            slen = strlen(client_uid_string);
458f7df2e56Smrg        }
459f7df2e56Smrg
460f7df2e56Smrg        snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
461f7df2e56Smrg                 ")");
462f7df2e56Smrg        FreeLocalClientCreds(lcc);
4634642e01fSmrg    }
46405b261ecSmrg    else {
465f7df2e56Smrg        client_uid_string[0] = '\0';
46605b261ecSmrg    }
467f7df2e56Smrg
46805b261ecSmrg#ifdef XSERVER_DTRACE
46905b261ecSmrg    XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
47005b261ecSmrg#endif
4714642e01fSmrg    if (auditTrailLevel > 1) {
472f7df2e56Smrg        if (proto_n)
473f7df2e56Smrg            AuditF("client %d %s from %s%s\n  Auth name: %.*s ID: %d\n",
474f7df2e56Smrg                   client->index, letin ? "connected" : "rejected", addr,
475f7df2e56Smrg                   client_uid_string, (int) proto_n, auth_proto, auth_id);
476f7df2e56Smrg        else
477f7df2e56Smrg            AuditF("client %d %s from %s%s\n",
478f7df2e56Smrg                   client->index, letin ? "connected" : "rejected", addr,
479f7df2e56Smrg                   client_uid_string);
48005b261ecSmrg
48105b261ecSmrg    }
48205b261ecSmrg}
48305b261ecSmrg
48405b261ecSmrgXID
48505b261ecSmrgAuthorizationIDOfClient(ClientPtr client)
48605b261ecSmrg{
48705b261ecSmrg    if (client->osPrivate)
488f7df2e56Smrg        return ((OsCommPtr) client->osPrivate)->auth_id;
48905b261ecSmrg    else
490f7df2e56Smrg        return None;
49105b261ecSmrg}
49205b261ecSmrg
49305b261ecSmrg/*****************************************************************
49405b261ecSmrg * ClientAuthorized
49505b261ecSmrg *
49605b261ecSmrg *    Sent by the client at connection setup:
49705b261ecSmrg *                typedef struct _xConnClientPrefix {
49805b261ecSmrg *                   CARD8	byteOrder;
49905b261ecSmrg *                   BYTE	pad;
50005b261ecSmrg *                   CARD16	majorVersion, minorVersion;
501f7df2e56Smrg *                   CARD16	nbytesAuthProto;
502f7df2e56Smrg *                   CARD16	nbytesAuthString;
50305b261ecSmrg *                 } xConnClientPrefix;
50405b261ecSmrg *
50505b261ecSmrg *     	It is hoped that eventually one protocol will be agreed upon.  In the
50605b261ecSmrg *        mean time, a server that implements a different protocol than the
50705b261ecSmrg *        client expects, or a server that only implements the host-based
50805b261ecSmrg *        mechanism, will simply ignore this information.
50905b261ecSmrg *
51005b261ecSmrg *****************************************************************/
51105b261ecSmrg
512f7df2e56Smrgconst char *
513f7df2e56SmrgClientAuthorized(ClientPtr client,
514f7df2e56Smrg                 unsigned int proto_n, char *auth_proto,
515f7df2e56Smrg                 unsigned int string_n, char *auth_string)
51605b261ecSmrg{
517f7df2e56Smrg    OsCommPtr priv;
518f7df2e56Smrg    Xtransaddr *from = NULL;
519f7df2e56Smrg    int family;
520f7df2e56Smrg    int fromlen;
521f7df2e56Smrg    XID auth_id;
522f7df2e56Smrg    const char *reason = NULL;
523f7df2e56Smrg    XtransConnInfo trans_conn;
524f7df2e56Smrg
525f7df2e56Smrg    priv = (OsCommPtr) client->osPrivate;
52605b261ecSmrg    trans_conn = priv->trans_conn;
52705b261ecSmrg
5284642e01fSmrg    /* Allow any client to connect without authorization on a launchd socket,
5294642e01fSmrg       because it is securely created -- this prevents a race condition on launch */
530f7df2e56Smrg    if (trans_conn->flags & TRANS_NOXAUTH) {
5314642e01fSmrg        auth_id = (XID) 0L;
532f7df2e56Smrg    }
533f7df2e56Smrg    else {
534f7df2e56Smrg        auth_id =
535f7df2e56Smrg            CheckAuthorization(proto_n, auth_proto, string_n, auth_string,
536f7df2e56Smrg                               client, &reason);
5374642e01fSmrg    }
53805b261ecSmrg
539f7df2e56Smrg    if (auth_id == (XID) ~0L) {
540f7df2e56Smrg        if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
541f7df2e56Smrg            if (InvalidHost((struct sockaddr *) from, fromlen, client))
542f7df2e56Smrg                AuthAudit(client, FALSE, (struct sockaddr *) from,
543f7df2e56Smrg                          fromlen, proto_n, auth_proto, auth_id);
544f7df2e56Smrg            else {
545f7df2e56Smrg                auth_id = (XID) 0;
54605b261ecSmrg#ifdef XSERVER_DTRACE
547f7df2e56Smrg                if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
54805b261ecSmrg#else
549f7df2e56Smrg                if (auditTrailLevel > 1)
55005b261ecSmrg#endif
551f7df2e56Smrg                    AuthAudit(client, TRUE,
552f7df2e56Smrg                              (struct sockaddr *) from, fromlen,
553f7df2e56Smrg                              proto_n, auth_proto, auth_id);
554f7df2e56Smrg            }
555f7df2e56Smrg
556f7df2e56Smrg            free(from);
557f7df2e56Smrg        }
558f7df2e56Smrg
559f7df2e56Smrg        if (auth_id == (XID) ~0L) {
560f7df2e56Smrg            if (reason)
561f7df2e56Smrg                return reason;
562f7df2e56Smrg            else
563f7df2e56Smrg                return "Client is not authorized to connect to Server";
564f7df2e56Smrg        }
56505b261ecSmrg    }
56605b261ecSmrg#ifdef XSERVER_DTRACE
56705b261ecSmrg    else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
56805b261ecSmrg#else
56905b261ecSmrg    else if (auditTrailLevel > 1)
57005b261ecSmrg#endif
57105b261ecSmrg    {
572f7df2e56Smrg        if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
573f7df2e56Smrg            AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
574f7df2e56Smrg                      proto_n, auth_proto, auth_id);
575f7df2e56Smrg
576f7df2e56Smrg            free(from);
577f7df2e56Smrg        }
57805b261ecSmrg    }
57905b261ecSmrg    priv->auth_id = auth_id;
58005b261ecSmrg    priv->conn_time = 0;
58105b261ecSmrg
58205b261ecSmrg#ifdef XDMCP
58305b261ecSmrg    /* indicate to Xdmcp protocol that we've opened new client */
58405b261ecSmrg    XdmcpOpenDisplay(priv->fd);
585f7df2e56Smrg#endif                          /* XDMCP */
58605b261ecSmrg
58705b261ecSmrg    XaceHook(XACE_AUTH_AVAIL, client, auth_id);
58805b261ecSmrg
58905b261ecSmrg    /* At this point, if the client is authorized to change the access control
59005b261ecSmrg     * list, we should getpeername() information, and add the client to
59105b261ecSmrg     * the selfhosts list.  It's not really the host machine, but the
59205b261ecSmrg     * true purpose of the selfhosts list is to see who may change the
59305b261ecSmrg     * access control list.
59405b261ecSmrg     */
595f7df2e56Smrg    return ((char *) NULL);
59605b261ecSmrg}
59705b261ecSmrg
5987e31ba66Smrgstatic void
5997e31ba66SmrgClientReady(int fd, int xevents, void *data)
6007e31ba66Smrg{
6017e31ba66Smrg    ClientPtr client = data;
6027e31ba66Smrg
6037e31ba66Smrg    if (xevents & X_NOTIFY_ERROR) {
6047e31ba66Smrg        CloseDownClient(client);
6057e31ba66Smrg        return;
6067e31ba66Smrg    }
6077e31ba66Smrg    if (xevents & X_NOTIFY_READ)
6087e31ba66Smrg        mark_client_ready(client);
6097e31ba66Smrg    if (xevents & X_NOTIFY_WRITE) {
6107e31ba66Smrg        ospoll_mute(server_poll, fd, X_NOTIFY_WRITE);
6117e31ba66Smrg        NewOutputPending = TRUE;
6127e31ba66Smrg    }
6137e31ba66Smrg}
6147e31ba66Smrg
61505b261ecSmrgstatic ClientPtr
616f7df2e56SmrgAllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
61705b261ecSmrg{
618f7df2e56Smrg    OsCommPtr oc;
619f7df2e56Smrg    ClientPtr client;
620f7df2e56Smrg
6216747b715Smrg    oc = malloc(sizeof(OsCommRec));
62205b261ecSmrg    if (!oc)
623f7df2e56Smrg        return NullClient;
62405b261ecSmrg    oc->trans_conn = trans_conn;
62505b261ecSmrg    oc->fd = fd;
626f7df2e56Smrg    oc->input = (ConnectionInputPtr) NULL;
627f7df2e56Smrg    oc->output = (ConnectionOutputPtr) NULL;
62805b261ecSmrg    oc->auth_id = None;
62905b261ecSmrg    oc->conn_time = conn_time;
6307e31ba66Smrg    oc->flags = 0;
631f7df2e56Smrg    if (!(client = NextAvailableClient((void *) oc))) {
632f7df2e56Smrg        free(oc);
633f7df2e56Smrg        return NullClient;
63405b261ecSmrg    }
635f7df2e56Smrg    client->local = ComputeLocalClient(client);
6367e31ba66Smrg    ospoll_add(server_poll, fd,
6377e31ba66Smrg               ospoll_trigger_edge,
6387e31ba66Smrg               ClientReady,
6397e31ba66Smrg               client);
6407e31ba66Smrg    set_poll_client(client);
64105b261ecSmrg
64205b261ecSmrg#ifdef DEBUG
64305b261ecSmrg    ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
644f7df2e56Smrg           client->index, fd);
64505b261ecSmrg#endif
64605b261ecSmrg#ifdef XSERVER_DTRACE
64705b261ecSmrg    XSERVER_CLIENT_CONNECT(client->index, fd);
648f7df2e56Smrg#endif
64905b261ecSmrg
65005b261ecSmrg    return client;
65105b261ecSmrg}
65205b261ecSmrg
65305b261ecSmrg/*****************
65405b261ecSmrg * EstablishNewConnections
65505b261ecSmrg *    If anyone is waiting on listened sockets, accept them.
65605b261ecSmrg *    Returns a mask with indices of new clients.  Updates AllClients
65705b261ecSmrg *    and AllSockets.
65805b261ecSmrg *****************/
65905b261ecSmrg
6607e31ba66Smrgstatic Bool
661f7df2e56SmrgEstablishNewConnections(ClientPtr clientUnused, void *closure)
66205b261ecSmrg{
6637e31ba66Smrg    int curconn = (int) (intptr_t) closure;
6647e31ba66Smrg    int newconn;       /* fd of new client */
66505b261ecSmrg    CARD32 connect_time;
6667e31ba66Smrg    int i;
6677e31ba66Smrg    ClientPtr client;
6687e31ba66Smrg    OsCommPtr oc;
6697e31ba66Smrg    XtransConnInfo trans_conn, new_trans_conn;
6707e31ba66Smrg    int status;
6717e31ba66Smrg
67205b261ecSmrg    connect_time = GetTimeInMillis();
67305b261ecSmrg    /* kill off stragglers */
674f7df2e56Smrg    for (i = 1; i < currentMaxClients; i++) {
675f7df2e56Smrg        if ((client = clients[i])) {
676f7df2e56Smrg            oc = (OsCommPtr) (client->osPrivate);
677f7df2e56Smrg            if ((oc && (oc->conn_time != 0) &&
678f7df2e56Smrg                 (connect_time - oc->conn_time) >= TimeOutValue) ||
679f7df2e56Smrg                (client->noClientException != Success && !client->clientGone))
680f7df2e56Smrg                CloseDownClient(client);
681f7df2e56Smrg        }
68205b261ecSmrg    }
68305b261ecSmrg
6847e31ba66Smrg    if ((trans_conn = lookup_trans_conn(curconn)) == NULL)
6857e31ba66Smrg        return TRUE;
686f7df2e56Smrg
6877e31ba66Smrg    if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL)
6887e31ba66Smrg        return TRUE;
68905b261ecSmrg
6907e31ba66Smrg    newconn = _XSERVTransGetConnectionNumber(new_trans_conn);
69105b261ecSmrg
6927e31ba66Smrg    _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
6934642e01fSmrg
6947e31ba66Smrg    if (trans_conn->flags & TRANS_NOXAUTH)
6957e31ba66Smrg        new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
6964642e01fSmrg
6977e31ba66Smrg    if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) {
6987e31ba66Smrg        ErrorConnMax(new_trans_conn);
69905b261ecSmrg    }
7007e31ba66Smrg    return TRUE;
701f7df2e56Smrg}
7027e31ba66Smrg
7037e31ba66Smrgstatic void
7047e31ba66SmrgQueueNewConnections(int fd, int ready, void *data)
7057e31ba66Smrg{
7067e31ba66Smrg    QueueWorkProc(EstablishNewConnections, NULL, (void *) (intptr_t) fd);
70705b261ecSmrg}
70805b261ecSmrg
70905b261ecSmrg#define NOROOM "Maximum number of clients reached"
71005b261ecSmrg
71105b261ecSmrg/************
71205b261ecSmrg *   ErrorConnMax
71305b261ecSmrg *     Fail a connection due to lack of client or file descriptor space
71405b261ecSmrg ************/
71505b261ecSmrg
71605b261ecSmrgstatic void
7177e31ba66SmrgConnMaxNotify(int fd, int events, void *data)
71805b261ecSmrg{
7197e31ba66Smrg    XtransConnInfo trans_conn = data;
720f7df2e56Smrg    char order = 0;
7217e31ba66Smrg
72205b261ecSmrg    /* try to read the byte-order of the connection */
723f7df2e56Smrg    (void) _XSERVTransRead(trans_conn, &order, 1);
724f7df2e56Smrg    if (order == 'l' || order == 'B' || order == 'r' || order == 'R') {
7257e31ba66Smrg        xConnSetupPrefix csp;
7267e31ba66Smrg        char pad[3] = { 0, 0, 0 };
7277e31ba66Smrg        int whichbyte = 1;
7287e31ba66Smrg        struct iovec iov[3];
7297e31ba66Smrg
730f7df2e56Smrg        csp.success = xFalse;
731f7df2e56Smrg        csp.lengthReason = sizeof(NOROOM) - 1;
732f7df2e56Smrg        csp.length = (sizeof(NOROOM) + 2) >> 2;
733f7df2e56Smrg        csp.majorVersion = X_PROTOCOL;
734f7df2e56Smrg        csp.minorVersion = X_PROTOCOL_REVISION;
7357e31ba66Smrg        if (((*(char *) &whichbyte) && (order == 'B' || order == 'R')) ||
7367e31ba66Smrg            (!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) {
737f7df2e56Smrg            swaps(&csp.majorVersion);
738f7df2e56Smrg            swaps(&csp.minorVersion);
739f7df2e56Smrg            swaps(&csp.length);
740f7df2e56Smrg        }
741f7df2e56Smrg        iov[0].iov_len = sz_xConnSetupPrefix;
742f7df2e56Smrg        iov[0].iov_base = (char *) &csp;
743f7df2e56Smrg        iov[1].iov_len = csp.lengthReason;
744f7df2e56Smrg        iov[1].iov_base = (void *) NOROOM;
745f7df2e56Smrg        iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
746f7df2e56Smrg        iov[2].iov_base = pad;
747f7df2e56Smrg        (void) _XSERVTransWritev(trans_conn, iov, 3);
74805b261ecSmrg    }
7497e31ba66Smrg    RemoveNotifyFd(trans_conn->fd);
7507e31ba66Smrg    _XSERVTransClose(trans_conn);
7517e31ba66Smrg}
7527e31ba66Smrg
7537e31ba66Smrgstatic void
7547e31ba66SmrgErrorConnMax(XtransConnInfo trans_conn)
7557e31ba66Smrg{
7567e31ba66Smrg    if (!SetNotifyFd(trans_conn->fd, ConnMaxNotify, X_NOTIFY_READ, trans_conn))
7577e31ba66Smrg        _XSERVTransClose(trans_conn);
75805b261ecSmrg}
75905b261ecSmrg
76005b261ecSmrg/************
76105b261ecSmrg *   CloseDownFileDescriptor:
7627e31ba66Smrg *     Remove this file descriptor
76305b261ecSmrg ************/
76405b261ecSmrg
7657e31ba66Smrgvoid
76605b261ecSmrgCloseDownFileDescriptor(OsCommPtr oc)
76705b261ecSmrg{
76805b261ecSmrg    if (oc->trans_conn) {
7697e31ba66Smrg        int connection = oc->fd;
7707e31ba66Smrg#ifdef XDMCP
7717e31ba66Smrg        XdmcpCloseDisplay(connection);
7727e31ba66Smrg#endif
7737e31ba66Smrg        ospoll_remove(server_poll, connection);
774f7df2e56Smrg        _XSERVTransDisconnect(oc->trans_conn);
775f7df2e56Smrg        _XSERVTransClose(oc->trans_conn);
7767e31ba66Smrg        oc->trans_conn = NULL;
7777e31ba66Smrg        oc->fd = -1;
77805b261ecSmrg    }
77905b261ecSmrg}
78005b261ecSmrg
78105b261ecSmrg/*****************
78205b261ecSmrg * CloseDownConnection
783f7df2e56Smrg *    Delete client from AllClients and free resources
78405b261ecSmrg *****************/
78505b261ecSmrg
78605b261ecSmrgvoid
78705b261ecSmrgCloseDownConnection(ClientPtr client)
78805b261ecSmrg{
789f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
79005b261ecSmrg
7916747b715Smrg    if (FlushCallback)
7927e31ba66Smrg        CallCallbacks(&FlushCallback, client);
7936747b715Smrg
794f7df2e56Smrg    if (oc->output)
795f7df2e56Smrg	FlushClient(client, oc, (char *) NULL, 0);
79605b261ecSmrg    CloseDownFileDescriptor(oc);
79705b261ecSmrg    FreeOsBuffers(oc);
7986747b715Smrg    free(client->osPrivate);
799f7df2e56Smrg    client->osPrivate = (void *) NULL;
80005b261ecSmrg    if (auditTrailLevel > 1)
801f7df2e56Smrg        AuditF("client %d disconnected\n", client->index);
80205b261ecSmrg}
80305b261ecSmrg
8047e31ba66Smrgstruct notify_fd {
8057e31ba66Smrg    int mask;
8067e31ba66Smrg    NotifyFdProcPtr notify;
8077e31ba66Smrg    void *data;
8087e31ba66Smrg};
80905b261ecSmrg
8107e31ba66Smrg/*****************
8117e31ba66Smrg * HandleNotifyFd
8127e31ba66Smrg *    A poll callback to be called when the registered
8137e31ba66Smrg *    file descriptor is ready.
8147e31ba66Smrg *****************/
81505b261ecSmrg
8167e31ba66Smrgstatic void
8177e31ba66SmrgHandleNotifyFd(int fd, int xevents, void *data)
81805b261ecSmrg{
8197e31ba66Smrg    struct notify_fd *n = data;
8207e31ba66Smrg    n->notify(fd, xevents, n->data);
82105b261ecSmrg}
82205b261ecSmrg
8237e31ba66Smrg/*****************
8247e31ba66Smrg * SetNotifyFd
8257e31ba66Smrg *    Registers a callback to be invoked when the specified
8267e31ba66Smrg *    file descriptor becomes readable.
8277e31ba66Smrg *****************/
8287e31ba66Smrg
8297e31ba66SmrgBool
8307e31ba66SmrgSetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
83105b261ecSmrg{
8327e31ba66Smrg    struct notify_fd *n;
8337e31ba66Smrg
8347e31ba66Smrg    n = ospoll_data(server_poll, fd);
8357e31ba66Smrg    if (!n) {
8367e31ba66Smrg        if (mask == 0)
8377e31ba66Smrg            return TRUE;
8387e31ba66Smrg
8397e31ba66Smrg        n = calloc(1, sizeof (struct notify_fd));
8407e31ba66Smrg        if (!n)
8417e31ba66Smrg            return FALSE;
8427e31ba66Smrg        ospoll_add(server_poll, fd,
8437e31ba66Smrg                   ospoll_trigger_level,
8447e31ba66Smrg                   HandleNotifyFd,
8457e31ba66Smrg                   n);
8467e31ba66Smrg    }
8477e31ba66Smrg
8487e31ba66Smrg    if (mask == 0) {
8497e31ba66Smrg        ospoll_remove(server_poll, fd);
8507e31ba66Smrg        free(n);
8517e31ba66Smrg    } else {
8527e31ba66Smrg        int listen = mask & ~n->mask;
8537e31ba66Smrg        int mute = n->mask & ~mask;
8547e31ba66Smrg
8557e31ba66Smrg        if (listen)
8567e31ba66Smrg            ospoll_listen(server_poll, fd, listen);
8577e31ba66Smrg        if (mute)
8587e31ba66Smrg            ospoll_mute(server_poll, fd, mute);
8597e31ba66Smrg        n->mask = mask;
8607e31ba66Smrg        n->data = data;
8617e31ba66Smrg        n->notify = notify;
8627e31ba66Smrg    }
8637e31ba66Smrg
8647e31ba66Smrg    return TRUE;
86505b261ecSmrg}
86605b261ecSmrg
86705b261ecSmrg/*****************
86805b261ecSmrg * OnlyListenToOneClient:
86905b261ecSmrg *    Only accept requests from  one client.  Continue to handle new
87005b261ecSmrg *    connections, but don't take any protocol requests from the new
87105b261ecSmrg *    ones.  Note that if GrabInProgress is set, EstablishNewConnections
87205b261ecSmrg *    needs to put new clients into SavedAllSockets and SavedAllClients.
87305b261ecSmrg *    Note also that there is no timeout for this in the protocol.
87405b261ecSmrg *    This routine is "undone" by ListenToAllClients()
87505b261ecSmrg *****************/
87605b261ecSmrg
8774642e01fSmrgint
87805b261ecSmrgOnlyListenToOneClient(ClientPtr client)
87905b261ecSmrg{
8807e31ba66Smrg    int rc;
8814642e01fSmrg
8824642e01fSmrg    rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
8834642e01fSmrg    if (rc != Success)
884f7df2e56Smrg        return rc;
885f7df2e56Smrg
886f7df2e56Smrg    if (!GrabInProgress) {
887f7df2e56Smrg        GrabInProgress = client->index;
8887e31ba66Smrg        set_poll_clients();
88905b261ecSmrg    }
8907e31ba66Smrg
8914642e01fSmrg    return rc;
89205b261ecSmrg}
89305b261ecSmrg
89405b261ecSmrg/****************
89505b261ecSmrg * ListenToAllClients:
89605b261ecSmrg *    Undoes OnlyListentToOneClient()
89705b261ecSmrg ****************/
89805b261ecSmrg
89905b261ecSmrgvoid
90005b261ecSmrgListenToAllClients(void)
90105b261ecSmrg{
902f7df2e56Smrg    if (GrabInProgress) {
903f7df2e56Smrg        GrabInProgress = 0;
9047e31ba66Smrg        set_poll_clients();
905f7df2e56Smrg    }
90605b261ecSmrg}
90705b261ecSmrg
90805b261ecSmrg/****************
90905b261ecSmrg * IgnoreClient
91005b261ecSmrg *    Removes one client from input masks.
91105b261ecSmrg *    Must have cooresponding call to AttendClient.
91205b261ecSmrg ****************/
91305b261ecSmrg
9146747b715Smrgvoid
915f7df2e56SmrgIgnoreClient(ClientPtr client)
91605b261ecSmrg{
917f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
91805b261ecSmrg
9196747b715Smrg    client->ignoreCount++;
9206747b715Smrg    if (client->ignoreCount > 1)
921f7df2e56Smrg        return;
9226747b715Smrg
92305b261ecSmrg    isItTimeToYield = TRUE;
9247e31ba66Smrg    mark_client_not_ready(client);
9257e31ba66Smrg
9267e31ba66Smrg    oc->flags |= OS_COMM_IGNORED;
9277e31ba66Smrg    set_poll_client(client);
92805b261ecSmrg}
92905b261ecSmrg
93005b261ecSmrg/****************
93105b261ecSmrg * AttendClient
93205b261ecSmrg *    Adds one client back into the input masks.
93305b261ecSmrg ****************/
93405b261ecSmrg
9356747b715Smrgvoid
936f7df2e56SmrgAttendClient(ClientPtr client)
93705b261ecSmrg{
938f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
9396747b715Smrg
9404e185dc0Smrg    if (client->clientGone) {
9414e185dc0Smrg        /*
9424e185dc0Smrg         * client is gone, so any pending requests will be dropped and its
9434e185dc0Smrg         * ignore count doesn't matter.
9444e185dc0Smrg         */
9454e185dc0Smrg        return;
9464e185dc0Smrg    }
9474e185dc0Smrg
9486747b715Smrg    client->ignoreCount--;
9496747b715Smrg    if (client->ignoreCount)
950f7df2e56Smrg        return;
9516747b715Smrg
9527e31ba66Smrg    oc->flags &= ~OS_COMM_IGNORED;
9537e31ba66Smrg    set_poll_client(client);
9547e31ba66Smrg    if (listen_to_client(client))
9557e31ba66Smrg        mark_client_ready(client);
956f7df2e56Smrg    else {
9577e31ba66Smrg        /* grab active, mark ready when grab goes away */
9587e31ba66Smrg        mark_client_saved_ready(client);
95905b261ecSmrg    }
96005b261ecSmrg}
96105b261ecSmrg
96205b261ecSmrg/* make client impervious to grabs; assume only executing client calls this */
96305b261ecSmrg
9644642e01fSmrgvoid
96505b261ecSmrgMakeClientGrabImpervious(ClientPtr client)
96605b261ecSmrg{
967f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
96805b261ecSmrg
9697e31ba66Smrg    oc->flags |= OS_COMM_GRAB_IMPERVIOUS;
9707e31ba66Smrg    set_poll_client(client);
97105b261ecSmrg
972f7df2e56Smrg    if (ServerGrabCallback) {
973f7df2e56Smrg        ServerGrabInfoRec grabinfo;
974f7df2e56Smrg
975f7df2e56Smrg        grabinfo.client = client;
976f7df2e56Smrg        grabinfo.grabstate = CLIENT_IMPERVIOUS;
977f7df2e56Smrg        CallCallbacks(&ServerGrabCallback, &grabinfo);
97805b261ecSmrg    }
97905b261ecSmrg}
98005b261ecSmrg
98105b261ecSmrg/* make client pervious to grabs; assume only executing client calls this */
98205b261ecSmrg
9834642e01fSmrgvoid
98405b261ecSmrgMakeClientGrabPervious(ClientPtr client)
98505b261ecSmrg{
986f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
98705b261ecSmrg
9887e31ba66Smrg    oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS;
9897e31ba66Smrg    set_poll_client(client);
9907e31ba66Smrg    isItTimeToYield = TRUE;
99105b261ecSmrg
992f7df2e56Smrg    if (ServerGrabCallback) {
993f7df2e56Smrg        ServerGrabInfoRec grabinfo;
994f7df2e56Smrg
995f7df2e56Smrg        grabinfo.client = client;
996f7df2e56Smrg        grabinfo.grabstate = CLIENT_PERVIOUS;
997f7df2e56Smrg        CallCallbacks(&ServerGrabCallback, &grabinfo);
99805b261ecSmrg    }
99905b261ecSmrg}
100005b261ecSmrg
1001f7df2e56Smrg/* Add a fd (from launchd or similar) to our listeners */
1002f7df2e56Smrgvoid
1003f7df2e56SmrgListenOnOpenFD(int fd, int noxauth)
1004f7df2e56Smrg{
10054642e01fSmrg    char port[256];
10064642e01fSmrg    XtransConnInfo ciptr;
10076747b715Smrg    const char *display_env = getenv("DISPLAY");
10084642e01fSmrg
1009f7df2e56Smrg    if (display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) {
10104642e01fSmrg        /* Make the path the launchd socket if our DISPLAY is set right */
10116747b715Smrg        strcpy(port, display_env);
1012f7df2e56Smrg    }
1013f7df2e56Smrg    else {
10144642e01fSmrg        /* Just some default so things don't break and die. */
1015f7df2e56Smrg        snprintf(port, sizeof(port), ":%d", atoi(display));
10164642e01fSmrg    }
10174642e01fSmrg
10184642e01fSmrg    /* Make our XtransConnInfo
10194642e01fSmrg     * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
10204642e01fSmrg     */
10214642e01fSmrg    ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1022f7df2e56Smrg    if (ciptr == NULL) {
1023f7df2e56Smrg        ErrorF("Got NULL while trying to Reopen listen port.\n");
10244642e01fSmrg        return;
10254642e01fSmrg    }
1026f7df2e56Smrg
1027f7df2e56Smrg    if (noxauth)
10284642e01fSmrg        ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
10294642e01fSmrg
10304642e01fSmrg    /* Allocate space to store it */
1031f7df2e56Smrg    ListenTransFds =
1032f7df2e56Smrg        xnfreallocarray(ListenTransFds, ListenTransCount + 1, sizeof(int));
1033f7df2e56Smrg    ListenTransConns =
1034f7df2e56Smrg        xnfreallocarray(ListenTransConns, ListenTransCount + 1,
1035f7df2e56Smrg                        sizeof(XtransConnInfo));
1036f7df2e56Smrg
10374642e01fSmrg    /* Store it */
10384642e01fSmrg    ListenTransConns[ListenTransCount] = ciptr;
10394642e01fSmrg    ListenTransFds[ListenTransCount] = fd;
10404642e01fSmrg
10417e31ba66Smrg    SetNotifyFd(fd, QueueNewConnections, X_NOTIFY_READ, NULL);
1042f7df2e56Smrg
10434642e01fSmrg    /* Increment the count */
10444642e01fSmrg    ListenTransCount++;
10454642e01fSmrg}
10464642e01fSmrg
1047f7df2e56Smrg/* based on TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) */
1048f7df2e56SmrgBool
1049f7df2e56SmrgAddClientOnOpenFD(int fd)
1050f7df2e56Smrg{
1051f7df2e56Smrg    XtransConnInfo ciptr;
1052f7df2e56Smrg    CARD32 connect_time;
1053f7df2e56Smrg    char port[20];
1054f7df2e56Smrg
1055f7df2e56Smrg    snprintf(port, sizeof(port), ":%d", atoi(display));
1056f7df2e56Smrg    ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1057f7df2e56Smrg    if (ciptr == NULL)
1058f7df2e56Smrg        return FALSE;
1059f7df2e56Smrg
1060f7df2e56Smrg    _XSERVTransSetOption(ciptr, TRANS_NONBLOCKING, 1);
1061f7df2e56Smrg    ciptr->flags |= TRANS_NOXAUTH;
1062f7df2e56Smrg
1063f7df2e56Smrg    connect_time = GetTimeInMillis();
1064f7df2e56Smrg
1065f7df2e56Smrg    if (!AllocNewConnection(ciptr, fd, connect_time)) {
1066f7df2e56Smrg        ErrorConnMax(ciptr);
1067f7df2e56Smrg        return FALSE;
1068f7df2e56Smrg    }
1069f7df2e56Smrg
1070f7df2e56Smrg    return TRUE;
1071f7df2e56Smrg}
10727e31ba66Smrg
10737e31ba66SmrgBool
10747e31ba66Smrglisten_to_client(ClientPtr client)
10757e31ba66Smrg{
10767e31ba66Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
10777e31ba66Smrg
10787e31ba66Smrg    if (oc->flags & OS_COMM_IGNORED)
10797e31ba66Smrg        return FALSE;
10807e31ba66Smrg
10817e31ba66Smrg    if (!GrabInProgress)
10827e31ba66Smrg        return TRUE;
10837e31ba66Smrg
10847e31ba66Smrg    if (client->index == GrabInProgress)
10857e31ba66Smrg        return TRUE;
10867e31ba66Smrg
10877e31ba66Smrg    if (oc->flags & OS_COMM_GRAB_IMPERVIOUS)
10887e31ba66Smrg        return TRUE;
10897e31ba66Smrg
10907e31ba66Smrg    return FALSE;
10917e31ba66Smrg}
10927e31ba66Smrg
10937e31ba66Smrgstatic void
10947e31ba66Smrgset_poll_client(ClientPtr client)
10957e31ba66Smrg{
10967e31ba66Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
10977e31ba66Smrg
10987e31ba66Smrg    if (oc->trans_conn) {
10997e31ba66Smrg        if (listen_to_client(client))
11007e31ba66Smrg            ospoll_listen(server_poll, oc->trans_conn->fd, X_NOTIFY_READ);
11017e31ba66Smrg        else
11027e31ba66Smrg            ospoll_mute(server_poll, oc->trans_conn->fd, X_NOTIFY_READ);
11037e31ba66Smrg    }
11047e31ba66Smrg}
11057e31ba66Smrg
11067e31ba66Smrgstatic void
11077e31ba66Smrgset_poll_clients(void)
11087e31ba66Smrg{
11097e31ba66Smrg    int i;
11107e31ba66Smrg
11117e31ba66Smrg    for (i = 1; i < currentMaxClients; i++) {
11127e31ba66Smrg        ClientPtr client = clients[i];
11137e31ba66Smrg        if (client && !client->clientGone)
11147e31ba66Smrg            set_poll_client(client);
11157e31ba66Smrg    }
11167e31ba66Smrg}
1117