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
8490bea6a0Smrg#include <sys/stat.h>
8590bea6a0Smrg
8605b261ecSmrg#ifndef WIN32
8705b261ecSmrg#include <sys/socket.h>
8805b261ecSmrg
897e31ba66Smrg#if defined(TCPCONN)
90f7df2e56Smrg#include <netinet/in.h>
91f7df2e56Smrg#include <arpa/inet.h>
92f7df2e56Smrg#ifdef apollo
93f7df2e56Smrg#ifndef NO_TCP_H
94f7df2e56Smrg#include <netinet/tcp.h>
95f7df2e56Smrg#endif
96f7df2e56Smrg#else
97f7df2e56Smrg#ifdef CSRG_BASED
98f7df2e56Smrg#include <sys/param.h>
99f7df2e56Smrg#endif
100f7df2e56Smrg#include <netinet/tcp.h>
101f7df2e56Smrg#endif
102f7df2e56Smrg#include <arpa/inet.h>
10305b261ecSmrg#endif
10405b261ecSmrg
10505b261ecSmrg#include <sys/uio.h>
1064642e01fSmrg
107f7df2e56Smrg#endif                          /* WIN32 */
108f7df2e56Smrg#include "misc.h"               /* for typedef of pointer */
10905b261ecSmrg#include "osdep.h"
11005b261ecSmrg#include "opaque.h"
11105b261ecSmrg#include "dixstruct.h"
11205b261ecSmrg#include "xace.h"
11305b261ecSmrg
11405b261ecSmrg#define Pid_t pid_t
11505b261ecSmrg
116f7df2e56Smrg#ifdef HAVE_GETPEERUCRED
117f7df2e56Smrg#include <ucred.h>
118f7df2e56Smrg#include <zone.h>
119f7df2e56Smrg#else
120f7df2e56Smrg#define zoneid_t int
12105b261ecSmrg#endif
12205b261ecSmrg
1235a112b11Smrg#ifdef HAVE_SYSTEMD_DAEMON
1245a112b11Smrg#include <systemd/sd-daemon.h>
1255a112b11Smrg#endif
1265a112b11Smrg
127f7df2e56Smrg#include "probes.h"
12805b261ecSmrg
1297e31ba66Smrgstruct ospoll   *server_poll;
13005b261ecSmrg
131f7df2e56SmrgBool NewOutputPending;          /* not yet attempted to write some new output */
132f7df2e56SmrgBool NoListenAll;               /* Don't establish any listening sockets */
133f7df2e56Smrg
134f7df2e56Smrgstatic Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
135f7df2e56SmrgBool RunFromSigStopParent;      /* send SIGSTOP to our own process; Upstart (or
136f7df2e56Smrg                                   equivalent) will send SIGCONT back. */
137f7df2e56Smrgstatic char dynamic_display[7]; /* display name */
138f7df2e56SmrgBool PartialNetwork;            /* continue even if unable to bind all addrs */
13905b261ecSmrgstatic Pid_t ParentProcess;
14005b261ecSmrg
1416747b715Smrgint GrabInProgress = 0;
14205b261ecSmrg
1437e31ba66Smrgstatic void
1445a112b11SmrgEstablishNewConnections(int curconn, int ready, void *data);
145f7df2e56Smrg
1467e31ba66Smrgstatic void
1477e31ba66Smrgset_poll_client(ClientPtr client);
148f7df2e56Smrg
1497e31ba66Smrgstatic void
1507e31ba66Smrgset_poll_clients(void);
15105b261ecSmrg
152f7df2e56Smrgstatic XtransConnInfo *ListenTransConns = NULL;
153f7df2e56Smrgstatic int *ListenTransFds = NULL;
154f7df2e56Smrgstatic int ListenTransCount;
15505b261ecSmrg
156f7df2e56Smrgstatic void ErrorConnMax(XtransConnInfo /* trans_conn */ );
15705b261ecSmrg
15805b261ecSmrgstatic XtransConnInfo
159f7df2e56Smrglookup_trans_conn(int fd)
16005b261ecSmrg{
161f7df2e56Smrg    if (ListenTransFds) {
162f7df2e56Smrg        int i;
163f7df2e56Smrg
164f7df2e56Smrg        for (i = 0; i < ListenTransCount; i++)
165f7df2e56Smrg            if (ListenTransFds[i] == fd)
166f7df2e56Smrg                return ListenTransConns[i];
16705b261ecSmrg    }
16805b261ecSmrg
1696747b715Smrg    return NULL;
17005b261ecSmrg}
17105b261ecSmrg
1724642e01fSmrg/*
1734642e01fSmrg * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
1744642e01fSmrg *
1754642e01fSmrg *  a- The parent process is ignoring SIGUSR1
1764642e01fSmrg *
1774642e01fSmrg * or
1784642e01fSmrg *
1794642e01fSmrg *  b- The parent process is expecting a SIGUSR1
1804642e01fSmrg *     when the server is ready to accept connections
1814642e01fSmrg *
1824642e01fSmrg * In the first case, the signal will be harmless, in the second case,
1834642e01fSmrg * the signal will be quite useful.
1844642e01fSmrg */
1854642e01fSmrgstatic void
1864642e01fSmrgInitParentProcess(void)
1874642e01fSmrg{
1884642e01fSmrg#if !defined(WIN32)
1894642e01fSmrg    OsSigHandlerPtr handler;
190f7df2e56Smrg
191f7df2e56Smrg    handler = OsSignal(SIGUSR1, SIG_IGN);
192f7df2e56Smrg    if (handler == SIG_IGN)
193f7df2e56Smrg        RunFromSmartParent = TRUE;
1944642e01fSmrg    OsSignal(SIGUSR1, handler);
195f7df2e56Smrg    ParentProcess = getppid();
1964642e01fSmrg#endif
1974642e01fSmrg}
1984642e01fSmrg
1994642e01fSmrgvoid
2004642e01fSmrgNotifyParentProcess(void)
2014642e01fSmrg{
2024642e01fSmrg#if !defined(WIN32)
203f7df2e56Smrg    if (displayfd >= 0) {
204f7df2e56Smrg        if (write(displayfd, display, strlen(display)) != strlen(display))
205f7df2e56Smrg            FatalError("Cannot write display number to fd %d\n", displayfd);
206f7df2e56Smrg        if (write(displayfd, "\n", 1) != 1)
207f7df2e56Smrg            FatalError("Cannot write display number to fd %d\n", displayfd);
208f7df2e56Smrg        close(displayfd);
209f7df2e56Smrg        displayfd = -1;
210f7df2e56Smrg    }
2114642e01fSmrg    if (RunFromSmartParent) {
212f7df2e56Smrg        if (ParentProcess > 1) {
213f7df2e56Smrg            kill(ParentProcess, SIGUSR1);
214f7df2e56Smrg        }
2154642e01fSmrg    }
2169ace9065Smrg    if (RunFromSigStopParent)
217f7df2e56Smrg        raise(SIGSTOP);
2185a112b11Smrg#ifdef HAVE_SYSTEMD_DAEMON
2195a112b11Smrg    /* If we have been started as a systemd service, tell systemd that
2205a112b11Smrg       we are ready. Otherwise sd_notify() won't do anything. */
2215a112b11Smrg    sd_notify(0, "READY=1");
2225a112b11Smrg#endif
2234642e01fSmrg#endif
2244642e01fSmrg}
22505b261ecSmrg
226f7df2e56Smrgstatic Bool
227f7df2e56SmrgTryCreateSocket(int num, int *partial)
228f7df2e56Smrg{
229f7df2e56Smrg    char port[20];
230f7df2e56Smrg
231f7df2e56Smrg    snprintf(port, sizeof(port), "%d", num);
232f7df2e56Smrg
233f7df2e56Smrg    return (_XSERVTransMakeAllCOTSServerListeners(port, partial,
234f7df2e56Smrg                                                  &ListenTransCount,
235f7df2e56Smrg                                                  &ListenTransConns) >= 0);
236f7df2e56Smrg}
237f7df2e56Smrg
23805b261ecSmrg/*****************
23905b261ecSmrg * CreateWellKnownSockets
24005b261ecSmrg *    At initialization, create the sockets to listen on for new clients.
24105b261ecSmrg *****************/
24205b261ecSmrg
24305b261ecSmrgvoid
24405b261ecSmrgCreateWellKnownSockets(void)
24505b261ecSmrg{
246f7df2e56Smrg    int i;
247d566a54bSmrg    int partial = 0;
24805b261ecSmrg
249f7df2e56Smrg    /* display is initialized to "0" by main(). It is then set to the display
250f7df2e56Smrg     * number if specified on the command line. */
25105b261ecSmrg
252f7df2e56Smrg    if (NoListenAll) {
253f7df2e56Smrg        ListenTransCount = 0;
254f7df2e56Smrg    }
255f7df2e56Smrg    else if ((displayfd < 0) || explicit_display) {
256f7df2e56Smrg        if (TryCreateSocket(atoi(display), &partial) &&
257f7df2e56Smrg            ListenTransCount >= 1)
258f7df2e56Smrg            if (!PartialNetwork && partial)
259f7df2e56Smrg                FatalError ("Failed to establish all listening sockets");
260f7df2e56Smrg    }
261f7df2e56Smrg    else { /* -displayfd and no explicit display number */
262f7df2e56Smrg        Bool found = 0;
263f7df2e56Smrg        for (i = 0; i < 65536 - X_TCP_PORT; i++) {
264f7df2e56Smrg            if (TryCreateSocket(i, &partial) && !partial) {
265f7df2e56Smrg                found = 1;
266f7df2e56Smrg                break;
267f7df2e56Smrg            }
268f7df2e56Smrg            else
269f7df2e56Smrg                CloseWellKnownConnections();
270f7df2e56Smrg        }
271f7df2e56Smrg        if (!found)
272f7df2e56Smrg            FatalError("Failed to find a socket to listen on");
273f7df2e56Smrg        snprintf(dynamic_display, sizeof(dynamic_display), "%d", i);
274f7df2e56Smrg        display = dynamic_display;
275f7df2e56Smrg        LogSetDisplay();
276f7df2e56Smrg    }
277f7df2e56Smrg
278f7df2e56Smrg    ListenTransFds = xallocarray(ListenTransCount, sizeof (int));
279f7df2e56Smrg    if (ListenTransFds == NULL)
280f7df2e56Smrg        FatalError ("Failed to create listening socket array");
281f7df2e56Smrg
282f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
283f7df2e56Smrg        int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
284f7df2e56Smrg
285f7df2e56Smrg        ListenTransFds[i] = fd;
2865a112b11Smrg        SetNotifyFd(fd, EstablishNewConnections, X_NOTIFY_READ, NULL);
287f7df2e56Smrg
288f7df2e56Smrg        if (!_XSERVTransIsLocal(ListenTransConns[i]))
289f7df2e56Smrg            DefineSelf (fd);
29005b261ecSmrg    }
29105b261ecSmrg
2927e31ba66Smrg    if (ListenTransCount == 0 && !NoListenAll)
293f7df2e56Smrg        FatalError
294f7df2e56Smrg            ("Cannot establish any listening sockets - Make sure an X server isn't already running");
295f7df2e56Smrg
29605b261ecSmrg#if !defined(WIN32)
297f7df2e56Smrg    OsSignal(SIGPIPE, SIG_IGN);
298f7df2e56Smrg    OsSignal(SIGHUP, AutoResetServer);
29905b261ecSmrg#endif
300f7df2e56Smrg    OsSignal(SIGINT, GiveUp);
301f7df2e56Smrg    OsSignal(SIGTERM, GiveUp);
30205b261ecSmrg    ResetHosts(display);
3034642e01fSmrg
3044642e01fSmrg    InitParentProcess();
3054642e01fSmrg
30605b261ecSmrg#ifdef XDMCP
307f7df2e56Smrg    XdmcpInit();
30805b261ecSmrg#endif
30905b261ecSmrg}
31005b261ecSmrg
31105b261ecSmrgvoid
312f7df2e56SmrgResetWellKnownSockets(void)
31305b261ecSmrg{
31405b261ecSmrg    int i;
31505b261ecSmrg
31605b261ecSmrg    ResetOsBuffers();
31705b261ecSmrg
318f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
319f7df2e56Smrg        int status = _XSERVTransResetListener(ListenTransConns[i]);
320f7df2e56Smrg
321f7df2e56Smrg        if (status != TRANS_RESET_NOOP) {
322f7df2e56Smrg            if (status == TRANS_RESET_FAILURE) {
323f7df2e56Smrg                /*
324f7df2e56Smrg                 * ListenTransConns[i] freed by xtrans.
325f7df2e56Smrg                 * Remove it from out list.
326f7df2e56Smrg                 */
327f7df2e56Smrg
3287e31ba66Smrg                RemoveNotifyFd(ListenTransFds[i]);
329f7df2e56Smrg                ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
330f7df2e56Smrg                ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
331f7df2e56Smrg                ListenTransCount -= 1;
332f7df2e56Smrg                i -= 1;
333f7df2e56Smrg            }
334f7df2e56Smrg            else if (status == TRANS_RESET_NEW_FD) {
335f7df2e56Smrg                /*
336f7df2e56Smrg                 * A new file descriptor was allocated (the old one was closed)
337f7df2e56Smrg                 */
338f7df2e56Smrg
339f7df2e56Smrg                int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
340f7df2e56Smrg
341f7df2e56Smrg                ListenTransFds[i] = newfd;
342f7df2e56Smrg            }
343f7df2e56Smrg        }
34405b261ecSmrg    }
3457e31ba66Smrg    for (i = 0; i < ListenTransCount; i++)
3465a112b11Smrg        SetNotifyFd(ListenTransFds[i], EstablishNewConnections, X_NOTIFY_READ,
3475a112b11Smrg                    NULL);
34805b261ecSmrg
349f7df2e56Smrg    ResetAuthorization();
35005b261ecSmrg    ResetHosts(display);
35105b261ecSmrg    /*
35205b261ecSmrg     * restart XDMCP
35305b261ecSmrg     */
35405b261ecSmrg#ifdef XDMCP
355f7df2e56Smrg    XdmcpReset();
35605b261ecSmrg#endif
35705b261ecSmrg}
35805b261ecSmrg
35905b261ecSmrgvoid
36005b261ecSmrgCloseWellKnownConnections(void)
36105b261ecSmrg{
36205b261ecSmrg    int i;
36305b261ecSmrg
364f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
365f7df2e56Smrg        if (ListenTransConns[i] != NULL) {
366f7df2e56Smrg            _XSERVTransClose(ListenTransConns[i]);
367f7df2e56Smrg            ListenTransConns[i] = NULL;
3687e31ba66Smrg            if (ListenTransFds != NULL)
3697e31ba66Smrg                RemoveNotifyFd(ListenTransFds[i]);
370f7df2e56Smrg        }
371f7df2e56Smrg    }
372f7df2e56Smrg    ListenTransCount = 0;
37305b261ecSmrg}
37405b261ecSmrg
37505b261ecSmrgstatic void
376f7df2e56SmrgAuthAudit(ClientPtr client, Bool letin,
377f7df2e56Smrg          struct sockaddr *saddr, int len,
378f7df2e56Smrg          unsigned int proto_n, char *auth_proto, int auth_id)
37905b261ecSmrg{
38005b261ecSmrg    char addr[128];
38105b261ecSmrg    char client_uid_string[64];
3824642e01fSmrg    LocalClientCredRec *lcc;
383f7df2e56Smrg
3844642e01fSmrg#ifdef XSERVER_DTRACE
38505b261ecSmrg    pid_t client_pid = -1;
38605b261ecSmrg    zoneid_t client_zid = -1;
38705b261ecSmrg#endif
38805b261ecSmrg
38905b261ecSmrg    if (!len)
390f7df2e56Smrg        strlcpy(addr, "local host", sizeof(addr));
39105b261ecSmrg    else
392f7df2e56Smrg        switch (saddr->sa_family) {
393f7df2e56Smrg        case AF_UNSPEC:
39405b261ecSmrg#if defined(UNIXCONN) || defined(LOCALCONN)
395f7df2e56Smrg        case AF_UNIX:
39605b261ecSmrg#endif
397f7df2e56Smrg            strlcpy(addr, "local host", sizeof(addr));
398f7df2e56Smrg            break;
3997e31ba66Smrg#if defined(TCPCONN)
400f7df2e56Smrg        case AF_INET:
401f7df2e56Smrg            snprintf(addr, sizeof(addr), "IP %s",
402f7df2e56Smrg                     inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
403f7df2e56Smrg            break;
40405b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
405f7df2e56Smrg        case AF_INET6:{
406f7df2e56Smrg            char ipaddr[INET6_ADDRSTRLEN];
407f7df2e56Smrg
408f7df2e56Smrg            inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
409f7df2e56Smrg                      ipaddr, sizeof(ipaddr));
410f7df2e56Smrg            snprintf(addr, sizeof(addr), "IP %s", ipaddr);
411f7df2e56Smrg        }
412f7df2e56Smrg            break;
41305b261ecSmrg#endif
41405b261ecSmrg#endif
415f7df2e56Smrg        default:
416f7df2e56Smrg            strlcpy(addr, "unknown address", sizeof(addr));
417f7df2e56Smrg        }
41805b261ecSmrg
4194642e01fSmrg    if (GetLocalClientCreds(client, &lcc) != -1) {
420f7df2e56Smrg        int slen;               /* length written to client_uid_string */
421f7df2e56Smrg
422f7df2e56Smrg        strcpy(client_uid_string, " ( ");
423f7df2e56Smrg        slen = 3;
424f7df2e56Smrg
425f7df2e56Smrg        if (lcc->fieldsSet & LCC_UID_SET) {
426f7df2e56Smrg            snprintf(client_uid_string + slen,
427f7df2e56Smrg                     sizeof(client_uid_string) - slen,
428f7df2e56Smrg                     "uid=%ld ", (long) lcc->euid);
429f7df2e56Smrg            slen = strlen(client_uid_string);
430f7df2e56Smrg        }
431f7df2e56Smrg
432f7df2e56Smrg        if (lcc->fieldsSet & LCC_GID_SET) {
433f7df2e56Smrg            snprintf(client_uid_string + slen,
434f7df2e56Smrg                     sizeof(client_uid_string) - slen,
435f7df2e56Smrg                     "gid=%ld ", (long) lcc->egid);
436f7df2e56Smrg            slen = strlen(client_uid_string);
437f7df2e56Smrg        }
438f7df2e56Smrg
439f7df2e56Smrg        if (lcc->fieldsSet & LCC_PID_SET) {
440f7df2e56Smrg#ifdef XSERVER_DTRACE
441f7df2e56Smrg            client_pid = lcc->pid;
44205b261ecSmrg#endif
443f7df2e56Smrg            snprintf(client_uid_string + slen,
444f7df2e56Smrg                     sizeof(client_uid_string) - slen,
445f7df2e56Smrg                     "pid=%ld ", (long) lcc->pid);
446f7df2e56Smrg            slen = strlen(client_uid_string);
447f7df2e56Smrg        }
448f7df2e56Smrg
449f7df2e56Smrg        if (lcc->fieldsSet & LCC_ZID_SET) {
4504642e01fSmrg#ifdef XSERVER_DTRACE
451f7df2e56Smrg            client_zid = lcc->zoneid;
452f7df2e56Smrg#endif
453f7df2e56Smrg            snprintf(client_uid_string + slen,
454f7df2e56Smrg                     sizeof(client_uid_string) - slen,
455f7df2e56Smrg                     "zoneid=%ld ", (long) lcc->zoneid);
456f7df2e56Smrg            slen = strlen(client_uid_string);
457f7df2e56Smrg        }
458f7df2e56Smrg
459f7df2e56Smrg        snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
460f7df2e56Smrg                 ")");
461f7df2e56Smrg        FreeLocalClientCreds(lcc);
4624642e01fSmrg    }
46305b261ecSmrg    else {
464f7df2e56Smrg        client_uid_string[0] = '\0';
46505b261ecSmrg    }
466f7df2e56Smrg
46705b261ecSmrg#ifdef XSERVER_DTRACE
46805b261ecSmrg    XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
46905b261ecSmrg#endif
4704642e01fSmrg    if (auditTrailLevel > 1) {
471f7df2e56Smrg        if (proto_n)
472f7df2e56Smrg            AuditF("client %d %s from %s%s\n  Auth name: %.*s ID: %d\n",
473f7df2e56Smrg                   client->index, letin ? "connected" : "rejected", addr,
474f7df2e56Smrg                   client_uid_string, (int) proto_n, auth_proto, auth_id);
475f7df2e56Smrg        else
476f7df2e56Smrg            AuditF("client %d %s from %s%s\n",
477f7df2e56Smrg                   client->index, letin ? "connected" : "rejected", addr,
478f7df2e56Smrg                   client_uid_string);
47905b261ecSmrg
48005b261ecSmrg    }
48105b261ecSmrg}
48205b261ecSmrg
48305b261ecSmrgXID
48405b261ecSmrgAuthorizationIDOfClient(ClientPtr client)
48505b261ecSmrg{
48605b261ecSmrg    if (client->osPrivate)
487f7df2e56Smrg        return ((OsCommPtr) client->osPrivate)->auth_id;
48805b261ecSmrg    else
489f7df2e56Smrg        return None;
49005b261ecSmrg}
49105b261ecSmrg
49205b261ecSmrg/*****************************************************************
49305b261ecSmrg * ClientAuthorized
49405b261ecSmrg *
49505b261ecSmrg *    Sent by the client at connection setup:
49605b261ecSmrg *                typedef struct _xConnClientPrefix {
49705b261ecSmrg *                   CARD8	byteOrder;
49805b261ecSmrg *                   BYTE	pad;
49905b261ecSmrg *                   CARD16	majorVersion, minorVersion;
500f7df2e56Smrg *                   CARD16	nbytesAuthProto;
501f7df2e56Smrg *                   CARD16	nbytesAuthString;
50205b261ecSmrg *                 } xConnClientPrefix;
50305b261ecSmrg *
50405b261ecSmrg *     	It is hoped that eventually one protocol will be agreed upon.  In the
50505b261ecSmrg *        mean time, a server that implements a different protocol than the
50605b261ecSmrg *        client expects, or a server that only implements the host-based
50705b261ecSmrg *        mechanism, will simply ignore this information.
50805b261ecSmrg *
50905b261ecSmrg *****************************************************************/
51005b261ecSmrg
511f7df2e56Smrgconst char *
512f7df2e56SmrgClientAuthorized(ClientPtr client,
513f7df2e56Smrg                 unsigned int proto_n, char *auth_proto,
514f7df2e56Smrg                 unsigned int string_n, char *auth_string)
51505b261ecSmrg{
516f7df2e56Smrg    OsCommPtr priv;
517f7df2e56Smrg    Xtransaddr *from = NULL;
518f7df2e56Smrg    int family;
519f7df2e56Smrg    int fromlen;
520f7df2e56Smrg    XID auth_id;
521f7df2e56Smrg    const char *reason = NULL;
522f7df2e56Smrg    XtransConnInfo trans_conn;
523f7df2e56Smrg
524f7df2e56Smrg    priv = (OsCommPtr) client->osPrivate;
52505b261ecSmrg    trans_conn = priv->trans_conn;
52605b261ecSmrg
5274642e01fSmrg    /* Allow any client to connect without authorization on a launchd socket,
5284642e01fSmrg       because it is securely created -- this prevents a race condition on launch */
529f7df2e56Smrg    if (trans_conn->flags & TRANS_NOXAUTH) {
5304642e01fSmrg        auth_id = (XID) 0L;
531f7df2e56Smrg    }
532f7df2e56Smrg    else {
533f7df2e56Smrg        auth_id =
534f7df2e56Smrg            CheckAuthorization(proto_n, auth_proto, string_n, auth_string,
535f7df2e56Smrg                               client, &reason);
5364642e01fSmrg    }
53705b261ecSmrg
538f7df2e56Smrg    if (auth_id == (XID) ~0L) {
539f7df2e56Smrg        if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
540f7df2e56Smrg            if (InvalidHost((struct sockaddr *) from, fromlen, client))
541f7df2e56Smrg                AuthAudit(client, FALSE, (struct sockaddr *) from,
542f7df2e56Smrg                          fromlen, proto_n, auth_proto, auth_id);
543f7df2e56Smrg            else {
544f7df2e56Smrg                auth_id = (XID) 0;
54505b261ecSmrg#ifdef XSERVER_DTRACE
546f7df2e56Smrg                if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
54705b261ecSmrg#else
548f7df2e56Smrg                if (auditTrailLevel > 1)
54905b261ecSmrg#endif
550f7df2e56Smrg                    AuthAudit(client, TRUE,
551f7df2e56Smrg                              (struct sockaddr *) from, fromlen,
552f7df2e56Smrg                              proto_n, auth_proto, auth_id);
553f7df2e56Smrg            }
554f7df2e56Smrg
555f7df2e56Smrg            free(from);
556f7df2e56Smrg        }
557f7df2e56Smrg
558f7df2e56Smrg        if (auth_id == (XID) ~0L) {
559f7df2e56Smrg            if (reason)
560f7df2e56Smrg                return reason;
561f7df2e56Smrg            else
562f7df2e56Smrg                return "Client is not authorized to connect to Server";
563f7df2e56Smrg        }
56405b261ecSmrg    }
56505b261ecSmrg#ifdef XSERVER_DTRACE
56605b261ecSmrg    else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
56705b261ecSmrg#else
56805b261ecSmrg    else if (auditTrailLevel > 1)
56905b261ecSmrg#endif
57005b261ecSmrg    {
571f7df2e56Smrg        if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
572f7df2e56Smrg            AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
573f7df2e56Smrg                      proto_n, auth_proto, auth_id);
574f7df2e56Smrg
575f7df2e56Smrg            free(from);
576f7df2e56Smrg        }
57705b261ecSmrg    }
57805b261ecSmrg    priv->auth_id = auth_id;
57905b261ecSmrg    priv->conn_time = 0;
58005b261ecSmrg
58105b261ecSmrg#ifdef XDMCP
58205b261ecSmrg    /* indicate to Xdmcp protocol that we've opened new client */
58305b261ecSmrg    XdmcpOpenDisplay(priv->fd);
584f7df2e56Smrg#endif                          /* XDMCP */
58505b261ecSmrg
58605b261ecSmrg    XaceHook(XACE_AUTH_AVAIL, client, auth_id);
58705b261ecSmrg
58805b261ecSmrg    /* At this point, if the client is authorized to change the access control
58905b261ecSmrg     * list, we should getpeername() information, and add the client to
59005b261ecSmrg     * the selfhosts list.  It's not really the host machine, but the
59105b261ecSmrg     * true purpose of the selfhosts list is to see who may change the
59205b261ecSmrg     * access control list.
59305b261ecSmrg     */
594f7df2e56Smrg    return ((char *) NULL);
59505b261ecSmrg}
59605b261ecSmrg
5977e31ba66Smrgstatic void
5987e31ba66SmrgClientReady(int fd, int xevents, void *data)
5997e31ba66Smrg{
6007e31ba66Smrg    ClientPtr client = data;
6017e31ba66Smrg
6027e31ba66Smrg    if (xevents & X_NOTIFY_ERROR) {
6037e31ba66Smrg        CloseDownClient(client);
6047e31ba66Smrg        return;
6057e31ba66Smrg    }
6067e31ba66Smrg    if (xevents & X_NOTIFY_READ)
6077e31ba66Smrg        mark_client_ready(client);
6087e31ba66Smrg    if (xevents & X_NOTIFY_WRITE) {
6097e31ba66Smrg        ospoll_mute(server_poll, fd, X_NOTIFY_WRITE);
6107e31ba66Smrg        NewOutputPending = TRUE;
6117e31ba66Smrg    }
6127e31ba66Smrg}
6137e31ba66Smrg
61405b261ecSmrgstatic ClientPtr
615f7df2e56SmrgAllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
61605b261ecSmrg{
617f7df2e56Smrg    OsCommPtr oc;
618f7df2e56Smrg    ClientPtr client;
619f7df2e56Smrg
6206747b715Smrg    oc = malloc(sizeof(OsCommRec));
62105b261ecSmrg    if (!oc)
622f7df2e56Smrg        return NullClient;
62305b261ecSmrg    oc->trans_conn = trans_conn;
62405b261ecSmrg    oc->fd = fd;
625f7df2e56Smrg    oc->input = (ConnectionInputPtr) NULL;
626f7df2e56Smrg    oc->output = (ConnectionOutputPtr) NULL;
62705b261ecSmrg    oc->auth_id = None;
62805b261ecSmrg    oc->conn_time = conn_time;
6297e31ba66Smrg    oc->flags = 0;
630f7df2e56Smrg    if (!(client = NextAvailableClient((void *) oc))) {
631f7df2e56Smrg        free(oc);
632f7df2e56Smrg        return NullClient;
63305b261ecSmrg    }
634f7df2e56Smrg    client->local = ComputeLocalClient(client);
6357e31ba66Smrg    ospoll_add(server_poll, fd,
6367e31ba66Smrg               ospoll_trigger_edge,
6377e31ba66Smrg               ClientReady,
6387e31ba66Smrg               client);
6397e31ba66Smrg    set_poll_client(client);
64005b261ecSmrg
64105b261ecSmrg#ifdef DEBUG
6423138c4c0Smrg    ErrorF("AllocNewConnection: client index = %d, socket fd = %d, local = %d\n",
6433138c4c0Smrg           client->index, fd, client->local);
64405b261ecSmrg#endif
64505b261ecSmrg#ifdef XSERVER_DTRACE
64605b261ecSmrg    XSERVER_CLIENT_CONNECT(client->index, fd);
647f7df2e56Smrg#endif
64805b261ecSmrg
64905b261ecSmrg    return client;
65005b261ecSmrg}
65105b261ecSmrg
65205b261ecSmrg/*****************
65305b261ecSmrg * EstablishNewConnections
6545a112b11Smrg *    If anyone is waiting on listened sockets, accept them. Drop pending
6555a112b11Smrg *    connections if they've stuck around for more than one minute.
65605b261ecSmrg *****************/
6575a112b11Smrg#define TimeOutValue 60 * MILLI_PER_SECOND
6585a112b11Smrgstatic void
6595a112b11SmrgEstablishNewConnections(int curconn, int ready, void *data)
66005b261ecSmrg{
6617e31ba66Smrg    int newconn;       /* fd of new client */
66205b261ecSmrg    CARD32 connect_time;
6637e31ba66Smrg    int i;
6647e31ba66Smrg    ClientPtr client;
6657e31ba66Smrg    OsCommPtr oc;
6667e31ba66Smrg    XtransConnInfo trans_conn, new_trans_conn;
6677e31ba66Smrg    int status;
6687e31ba66Smrg
66905b261ecSmrg    connect_time = GetTimeInMillis();
67005b261ecSmrg    /* kill off stragglers */
671f7df2e56Smrg    for (i = 1; i < currentMaxClients; i++) {
672f7df2e56Smrg        if ((client = clients[i])) {
673f7df2e56Smrg            oc = (OsCommPtr) (client->osPrivate);
674f7df2e56Smrg            if ((oc && (oc->conn_time != 0) &&
675f7df2e56Smrg                 (connect_time - oc->conn_time) >= TimeOutValue) ||
676f7df2e56Smrg                (client->noClientException != Success && !client->clientGone))
677f7df2e56Smrg                CloseDownClient(client);
678f7df2e56Smrg        }
67905b261ecSmrg    }
68005b261ecSmrg
6817e31ba66Smrg    if ((trans_conn = lookup_trans_conn(curconn)) == NULL)
6825a112b11Smrg        return;
683f7df2e56Smrg
6847e31ba66Smrg    if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL)
6855a112b11Smrg        return;
68605b261ecSmrg
6877e31ba66Smrg    newconn = _XSERVTransGetConnectionNumber(new_trans_conn);
68805b261ecSmrg
6897e31ba66Smrg    _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
6904642e01fSmrg
6917e31ba66Smrg    if (trans_conn->flags & TRANS_NOXAUTH)
6927e31ba66Smrg        new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
6934642e01fSmrg
6947e31ba66Smrg    if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) {
6957e31ba66Smrg        ErrorConnMax(new_trans_conn);
69605b261ecSmrg    }
6975a112b11Smrg    return;
69805b261ecSmrg}
69905b261ecSmrg
70005b261ecSmrg#define NOROOM "Maximum number of clients reached"
70105b261ecSmrg
70205b261ecSmrg/************
70305b261ecSmrg *   ErrorConnMax
70405b261ecSmrg *     Fail a connection due to lack of client or file descriptor space
70505b261ecSmrg ************/
70605b261ecSmrg
70705b261ecSmrgstatic void
7087e31ba66SmrgConnMaxNotify(int fd, int events, void *data)
70905b261ecSmrg{
7107e31ba66Smrg    XtransConnInfo trans_conn = data;
711f7df2e56Smrg    char order = 0;
7127e31ba66Smrg
71305b261ecSmrg    /* try to read the byte-order of the connection */
714f7df2e56Smrg    (void) _XSERVTransRead(trans_conn, &order, 1);
715f7df2e56Smrg    if (order == 'l' || order == 'B' || order == 'r' || order == 'R') {
7167e31ba66Smrg        xConnSetupPrefix csp;
7177e31ba66Smrg        char pad[3] = { 0, 0, 0 };
7187e31ba66Smrg        int whichbyte = 1;
7197e31ba66Smrg        struct iovec iov[3];
7207e31ba66Smrg
721f7df2e56Smrg        csp.success = xFalse;
722f7df2e56Smrg        csp.lengthReason = sizeof(NOROOM) - 1;
723f7df2e56Smrg        csp.length = (sizeof(NOROOM) + 2) >> 2;
724f7df2e56Smrg        csp.majorVersion = X_PROTOCOL;
725f7df2e56Smrg        csp.minorVersion = X_PROTOCOL_REVISION;
7267e31ba66Smrg        if (((*(char *) &whichbyte) && (order == 'B' || order == 'R')) ||
7277e31ba66Smrg            (!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) {
728f7df2e56Smrg            swaps(&csp.majorVersion);
729f7df2e56Smrg            swaps(&csp.minorVersion);
730f7df2e56Smrg            swaps(&csp.length);
731f7df2e56Smrg        }
732f7df2e56Smrg        iov[0].iov_len = sz_xConnSetupPrefix;
733f7df2e56Smrg        iov[0].iov_base = (char *) &csp;
734f7df2e56Smrg        iov[1].iov_len = csp.lengthReason;
735f7df2e56Smrg        iov[1].iov_base = (void *) NOROOM;
736f7df2e56Smrg        iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
737f7df2e56Smrg        iov[2].iov_base = pad;
738f7df2e56Smrg        (void) _XSERVTransWritev(trans_conn, iov, 3);
73905b261ecSmrg    }
7407e31ba66Smrg    RemoveNotifyFd(trans_conn->fd);
7417e31ba66Smrg    _XSERVTransClose(trans_conn);
7427e31ba66Smrg}
7437e31ba66Smrg
7447e31ba66Smrgstatic void
7457e31ba66SmrgErrorConnMax(XtransConnInfo trans_conn)
7467e31ba66Smrg{
7477e31ba66Smrg    if (!SetNotifyFd(trans_conn->fd, ConnMaxNotify, X_NOTIFY_READ, trans_conn))
7487e31ba66Smrg        _XSERVTransClose(trans_conn);
74905b261ecSmrg}
75005b261ecSmrg
75105b261ecSmrg/************
75205b261ecSmrg *   CloseDownFileDescriptor:
7537e31ba66Smrg *     Remove this file descriptor
75405b261ecSmrg ************/
75505b261ecSmrg
7567e31ba66Smrgvoid
75705b261ecSmrgCloseDownFileDescriptor(OsCommPtr oc)
75805b261ecSmrg{
75905b261ecSmrg    if (oc->trans_conn) {
7607e31ba66Smrg        int connection = oc->fd;
7617e31ba66Smrg#ifdef XDMCP
7627e31ba66Smrg        XdmcpCloseDisplay(connection);
7637e31ba66Smrg#endif
7647e31ba66Smrg        ospoll_remove(server_poll, connection);
765f7df2e56Smrg        _XSERVTransDisconnect(oc->trans_conn);
766f7df2e56Smrg        _XSERVTransClose(oc->trans_conn);
7677e31ba66Smrg        oc->trans_conn = NULL;
7687e31ba66Smrg        oc->fd = -1;
76905b261ecSmrg    }
77005b261ecSmrg}
77105b261ecSmrg
77205b261ecSmrg/*****************
77305b261ecSmrg * CloseDownConnection
774f7df2e56Smrg *    Delete client from AllClients and free resources
77505b261ecSmrg *****************/
77605b261ecSmrg
77705b261ecSmrgvoid
77805b261ecSmrgCloseDownConnection(ClientPtr client)
77905b261ecSmrg{
780f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
78105b261ecSmrg
7826747b715Smrg    if (FlushCallback)
7837e31ba66Smrg        CallCallbacks(&FlushCallback, client);
7846747b715Smrg
785f7df2e56Smrg    if (oc->output)
786f7df2e56Smrg	FlushClient(client, oc, (char *) NULL, 0);
78705b261ecSmrg    CloseDownFileDescriptor(oc);
78805b261ecSmrg    FreeOsBuffers(oc);
7896747b715Smrg    free(client->osPrivate);
790f7df2e56Smrg    client->osPrivate = (void *) NULL;
79105b261ecSmrg    if (auditTrailLevel > 1)
792f7df2e56Smrg        AuditF("client %d disconnected\n", client->index);
79305b261ecSmrg}
79405b261ecSmrg
7957e31ba66Smrgstruct notify_fd {
7967e31ba66Smrg    int mask;
7977e31ba66Smrg    NotifyFdProcPtr notify;
7987e31ba66Smrg    void *data;
7997e31ba66Smrg};
80005b261ecSmrg
8017e31ba66Smrg/*****************
8027e31ba66Smrg * HandleNotifyFd
8037e31ba66Smrg *    A poll callback to be called when the registered
8047e31ba66Smrg *    file descriptor is ready.
8057e31ba66Smrg *****************/
80605b261ecSmrg
8077e31ba66Smrgstatic void
8087e31ba66SmrgHandleNotifyFd(int fd, int xevents, void *data)
80905b261ecSmrg{
8107e31ba66Smrg    struct notify_fd *n = data;
8117e31ba66Smrg    n->notify(fd, xevents, n->data);
81205b261ecSmrg}
81305b261ecSmrg
8147e31ba66Smrg/*****************
8157e31ba66Smrg * SetNotifyFd
8167e31ba66Smrg *    Registers a callback to be invoked when the specified
8177e31ba66Smrg *    file descriptor becomes readable.
8187e31ba66Smrg *****************/
8197e31ba66Smrg
8207e31ba66SmrgBool
8217e31ba66SmrgSetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
82205b261ecSmrg{
8237e31ba66Smrg    struct notify_fd *n;
8247e31ba66Smrg
8257e31ba66Smrg    n = ospoll_data(server_poll, fd);
8267e31ba66Smrg    if (!n) {
8277e31ba66Smrg        if (mask == 0)
8287e31ba66Smrg            return TRUE;
8297e31ba66Smrg
8307e31ba66Smrg        n = calloc(1, sizeof (struct notify_fd));
8317e31ba66Smrg        if (!n)
8327e31ba66Smrg            return FALSE;
8337e31ba66Smrg        ospoll_add(server_poll, fd,
8347e31ba66Smrg                   ospoll_trigger_level,
8357e31ba66Smrg                   HandleNotifyFd,
8367e31ba66Smrg                   n);
8377e31ba66Smrg    }
8387e31ba66Smrg
8397e31ba66Smrg    if (mask == 0) {
8407e31ba66Smrg        ospoll_remove(server_poll, fd);
8417e31ba66Smrg        free(n);
8427e31ba66Smrg    } else {
8437e31ba66Smrg        int listen = mask & ~n->mask;
8447e31ba66Smrg        int mute = n->mask & ~mask;
8457e31ba66Smrg
8467e31ba66Smrg        if (listen)
8477e31ba66Smrg            ospoll_listen(server_poll, fd, listen);
8487e31ba66Smrg        if (mute)
8497e31ba66Smrg            ospoll_mute(server_poll, fd, mute);
8507e31ba66Smrg        n->mask = mask;
8517e31ba66Smrg        n->data = data;
8527e31ba66Smrg        n->notify = notify;
8537e31ba66Smrg    }
8547e31ba66Smrg
8557e31ba66Smrg    return TRUE;
85605b261ecSmrg}
85705b261ecSmrg
85805b261ecSmrg/*****************
85905b261ecSmrg * OnlyListenToOneClient:
86005b261ecSmrg *    Only accept requests from  one client.  Continue to handle new
86105b261ecSmrg *    connections, but don't take any protocol requests from the new
86205b261ecSmrg *    ones.  Note that if GrabInProgress is set, EstablishNewConnections
86305b261ecSmrg *    needs to put new clients into SavedAllSockets and SavedAllClients.
86405b261ecSmrg *    Note also that there is no timeout for this in the protocol.
86505b261ecSmrg *    This routine is "undone" by ListenToAllClients()
86605b261ecSmrg *****************/
86705b261ecSmrg
8684642e01fSmrgint
86905b261ecSmrgOnlyListenToOneClient(ClientPtr client)
87005b261ecSmrg{
8717e31ba66Smrg    int rc;
8724642e01fSmrg
8734642e01fSmrg    rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
8744642e01fSmrg    if (rc != Success)
875f7df2e56Smrg        return rc;
876f7df2e56Smrg
877f7df2e56Smrg    if (!GrabInProgress) {
878f7df2e56Smrg        GrabInProgress = client->index;
8797e31ba66Smrg        set_poll_clients();
88005b261ecSmrg    }
8817e31ba66Smrg
8824642e01fSmrg    return rc;
88305b261ecSmrg}
88405b261ecSmrg
88505b261ecSmrg/****************
88605b261ecSmrg * ListenToAllClients:
88705b261ecSmrg *    Undoes OnlyListentToOneClient()
88805b261ecSmrg ****************/
88905b261ecSmrg
89005b261ecSmrgvoid
89105b261ecSmrgListenToAllClients(void)
89205b261ecSmrg{
893f7df2e56Smrg    if (GrabInProgress) {
894f7df2e56Smrg        GrabInProgress = 0;
8957e31ba66Smrg        set_poll_clients();
896f7df2e56Smrg    }
89705b261ecSmrg}
89805b261ecSmrg
89905b261ecSmrg/****************
90005b261ecSmrg * IgnoreClient
90105b261ecSmrg *    Removes one client from input masks.
9025a112b11Smrg *    Must have corresponding call to AttendClient.
90305b261ecSmrg ****************/
90405b261ecSmrg
9056747b715Smrgvoid
906f7df2e56SmrgIgnoreClient(ClientPtr client)
90705b261ecSmrg{
908f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
90905b261ecSmrg
9106747b715Smrg    client->ignoreCount++;
9116747b715Smrg    if (client->ignoreCount > 1)
912f7df2e56Smrg        return;
9136747b715Smrg
91405b261ecSmrg    isItTimeToYield = TRUE;
9157e31ba66Smrg    mark_client_not_ready(client);
9167e31ba66Smrg
9177e31ba66Smrg    oc->flags |= OS_COMM_IGNORED;
9187e31ba66Smrg    set_poll_client(client);
91905b261ecSmrg}
92005b261ecSmrg
92105b261ecSmrg/****************
92205b261ecSmrg * AttendClient
92305b261ecSmrg *    Adds one client back into the input masks.
92405b261ecSmrg ****************/
92505b261ecSmrg
9266747b715Smrgvoid
927f7df2e56SmrgAttendClient(ClientPtr client)
92805b261ecSmrg{
929f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
9306747b715Smrg
9314e185dc0Smrg    if (client->clientGone) {
9324e185dc0Smrg        /*
9334e185dc0Smrg         * client is gone, so any pending requests will be dropped and its
9344e185dc0Smrg         * ignore count doesn't matter.
9354e185dc0Smrg         */
9364e185dc0Smrg        return;
9374e185dc0Smrg    }
9384e185dc0Smrg
9396747b715Smrg    client->ignoreCount--;
9406747b715Smrg    if (client->ignoreCount)
941f7df2e56Smrg        return;
9426747b715Smrg
9437e31ba66Smrg    oc->flags &= ~OS_COMM_IGNORED;
9447e31ba66Smrg    set_poll_client(client);
9457e31ba66Smrg    if (listen_to_client(client))
9467e31ba66Smrg        mark_client_ready(client);
947f7df2e56Smrg    else {
9487e31ba66Smrg        /* grab active, mark ready when grab goes away */
9497e31ba66Smrg        mark_client_saved_ready(client);
95005b261ecSmrg    }
95105b261ecSmrg}
95205b261ecSmrg
95305b261ecSmrg/* make client impervious to grabs; assume only executing client calls this */
95405b261ecSmrg
9554642e01fSmrgvoid
95605b261ecSmrgMakeClientGrabImpervious(ClientPtr client)
95705b261ecSmrg{
958f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
95905b261ecSmrg
9607e31ba66Smrg    oc->flags |= OS_COMM_GRAB_IMPERVIOUS;
9617e31ba66Smrg    set_poll_client(client);
96205b261ecSmrg
963f7df2e56Smrg    if (ServerGrabCallback) {
964f7df2e56Smrg        ServerGrabInfoRec grabinfo;
965f7df2e56Smrg
966f7df2e56Smrg        grabinfo.client = client;
967f7df2e56Smrg        grabinfo.grabstate = CLIENT_IMPERVIOUS;
968f7df2e56Smrg        CallCallbacks(&ServerGrabCallback, &grabinfo);
96905b261ecSmrg    }
97005b261ecSmrg}
97105b261ecSmrg
97205b261ecSmrg/* make client pervious to grabs; assume only executing client calls this */
97305b261ecSmrg
9744642e01fSmrgvoid
97505b261ecSmrgMakeClientGrabPervious(ClientPtr client)
97605b261ecSmrg{
977f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
97805b261ecSmrg
9797e31ba66Smrg    oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS;
9807e31ba66Smrg    set_poll_client(client);
9817e31ba66Smrg    isItTimeToYield = TRUE;
98205b261ecSmrg
983f7df2e56Smrg    if (ServerGrabCallback) {
984f7df2e56Smrg        ServerGrabInfoRec grabinfo;
985f7df2e56Smrg
986f7df2e56Smrg        grabinfo.client = client;
987f7df2e56Smrg        grabinfo.grabstate = CLIENT_PERVIOUS;
988f7df2e56Smrg        CallCallbacks(&ServerGrabCallback, &grabinfo);
98905b261ecSmrg    }
99005b261ecSmrg}
99105b261ecSmrg
992f7df2e56Smrg/* Add a fd (from launchd or similar) to our listeners */
993f7df2e56Smrgvoid
994f7df2e56SmrgListenOnOpenFD(int fd, int noxauth)
995f7df2e56Smrg{
99690bea6a0Smrg    char port[PATH_MAX];
9974642e01fSmrg    XtransConnInfo ciptr;
9986747b715Smrg    const char *display_env = getenv("DISPLAY");
9994642e01fSmrg
100090bea6a0Smrg    /* First check if display_env matches a <absolute path to unix socket>[.<screen number>] scheme (eg: launchd) */
100190bea6a0Smrg    if (display_env && display_env[0] == '/') {
100290bea6a0Smrg        struct stat sbuf;
100390bea6a0Smrg
100490bea6a0Smrg        strlcpy(port, display_env, sizeof(port));
100590bea6a0Smrg
100690bea6a0Smrg        /* If the path exists, we don't have do do anything else.
100790bea6a0Smrg         * If it doesn't, we need to check for a .<screen number> to strip off and recheck.
100890bea6a0Smrg         */
100990bea6a0Smrg        if (0 != stat(port, &sbuf)) {
101090bea6a0Smrg            char *dot = strrchr(port, '.');
101190bea6a0Smrg            if (dot) {
101290bea6a0Smrg                *dot = '\0';
101390bea6a0Smrg
101490bea6a0Smrg                if (0 != stat(port, &sbuf)) {
101590bea6a0Smrg                    display_env = NULL;
101690bea6a0Smrg                }
101790bea6a0Smrg            } else {
101890bea6a0Smrg                display_env = NULL;
101990bea6a0Smrg            }
102090bea6a0Smrg        }
1021f7df2e56Smrg    }
102290bea6a0Smrg
102390bea6a0Smrg    if (!display_env) {
10244642e01fSmrg        /* Just some default so things don't break and die. */
1025f7df2e56Smrg        snprintf(port, sizeof(port), ":%d", atoi(display));
10264642e01fSmrg    }
10274642e01fSmrg
10284642e01fSmrg    /* Make our XtransConnInfo
10294642e01fSmrg     * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
10304642e01fSmrg     */
10314642e01fSmrg    ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1032f7df2e56Smrg    if (ciptr == NULL) {
1033f7df2e56Smrg        ErrorF("Got NULL while trying to Reopen listen port.\n");
10344642e01fSmrg        return;
10354642e01fSmrg    }
1036f7df2e56Smrg
1037f7df2e56Smrg    if (noxauth)
10384642e01fSmrg        ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
10394642e01fSmrg
10404642e01fSmrg    /* Allocate space to store it */
1041f7df2e56Smrg    ListenTransFds =
1042f7df2e56Smrg        xnfreallocarray(ListenTransFds, ListenTransCount + 1, sizeof(int));
1043f7df2e56Smrg    ListenTransConns =
1044f7df2e56Smrg        xnfreallocarray(ListenTransConns, ListenTransCount + 1,
1045f7df2e56Smrg                        sizeof(XtransConnInfo));
1046f7df2e56Smrg
10474642e01fSmrg    /* Store it */
10484642e01fSmrg    ListenTransConns[ListenTransCount] = ciptr;
10494642e01fSmrg    ListenTransFds[ListenTransCount] = fd;
10504642e01fSmrg
10515a112b11Smrg    SetNotifyFd(fd, EstablishNewConnections, X_NOTIFY_READ, NULL);
1052f7df2e56Smrg
10534642e01fSmrg    /* Increment the count */
10544642e01fSmrg    ListenTransCount++;
10554642e01fSmrg}
10564642e01fSmrg
1057f7df2e56Smrg/* based on TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) */
1058f7df2e56SmrgBool
1059f7df2e56SmrgAddClientOnOpenFD(int fd)
1060f7df2e56Smrg{
1061f7df2e56Smrg    XtransConnInfo ciptr;
1062f7df2e56Smrg    CARD32 connect_time;
1063f7df2e56Smrg    char port[20];
1064f7df2e56Smrg
1065f7df2e56Smrg    snprintf(port, sizeof(port), ":%d", atoi(display));
1066f7df2e56Smrg    ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1067f7df2e56Smrg    if (ciptr == NULL)
1068f7df2e56Smrg        return FALSE;
1069f7df2e56Smrg
1070f7df2e56Smrg    _XSERVTransSetOption(ciptr, TRANS_NONBLOCKING, 1);
1071f7df2e56Smrg    ciptr->flags |= TRANS_NOXAUTH;
1072f7df2e56Smrg
1073f7df2e56Smrg    connect_time = GetTimeInMillis();
1074f7df2e56Smrg
1075f7df2e56Smrg    if (!AllocNewConnection(ciptr, fd, connect_time)) {
1076f7df2e56Smrg        ErrorConnMax(ciptr);
1077f7df2e56Smrg        return FALSE;
1078f7df2e56Smrg    }
1079f7df2e56Smrg
1080f7df2e56Smrg    return TRUE;
1081f7df2e56Smrg}
10827e31ba66Smrg
10837e31ba66SmrgBool
10847e31ba66Smrglisten_to_client(ClientPtr client)
10857e31ba66Smrg{
10867e31ba66Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
10877e31ba66Smrg
10887e31ba66Smrg    if (oc->flags & OS_COMM_IGNORED)
10897e31ba66Smrg        return FALSE;
10907e31ba66Smrg
10917e31ba66Smrg    if (!GrabInProgress)
10927e31ba66Smrg        return TRUE;
10937e31ba66Smrg
10947e31ba66Smrg    if (client->index == GrabInProgress)
10957e31ba66Smrg        return TRUE;
10967e31ba66Smrg
10977e31ba66Smrg    if (oc->flags & OS_COMM_GRAB_IMPERVIOUS)
10987e31ba66Smrg        return TRUE;
10997e31ba66Smrg
11007e31ba66Smrg    return FALSE;
11017e31ba66Smrg}
11027e31ba66Smrg
11037e31ba66Smrgstatic void
11047e31ba66Smrgset_poll_client(ClientPtr client)
11057e31ba66Smrg{
11067e31ba66Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
11077e31ba66Smrg
11087e31ba66Smrg    if (oc->trans_conn) {
11097e31ba66Smrg        if (listen_to_client(client))
11107e31ba66Smrg            ospoll_listen(server_poll, oc->trans_conn->fd, X_NOTIFY_READ);
11117e31ba66Smrg        else
11127e31ba66Smrg            ospoll_mute(server_poll, oc->trans_conn->fd, X_NOTIFY_READ);
11137e31ba66Smrg    }
11147e31ba66Smrg}
11157e31ba66Smrg
11167e31ba66Smrgstatic void
11177e31ba66Smrgset_poll_clients(void)
11187e31ba66Smrg{
11197e31ba66Smrg    int i;
11207e31ba66Smrg
11217e31ba66Smrg    for (i = 1; i < currentMaxClients; i++) {
11227e31ba66Smrg        ClientPtr client = clients[i];
11237e31ba66Smrg        if (client && !client->clientGone)
11247e31ba66Smrg            set_poll_client(client);
11257e31ba66Smrg    }
11267e31ba66Smrg}
1127