connection.c revision 5a112b11
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
1215a112b11Smrg#ifdef HAVE_SYSTEMD_DAEMON
1225a112b11Smrg#include <systemd/sd-daemon.h>
1235a112b11Smrg#endif
1245a112b11Smrg
125f7df2e56Smrg#include "probes.h"
12605b261ecSmrg
1277e31ba66Smrgstruct ospoll   *server_poll;
12805b261ecSmrg
129f7df2e56SmrgBool NewOutputPending;          /* not yet attempted to write some new output */
130f7df2e56SmrgBool NoListenAll;               /* Don't establish any listening sockets */
131f7df2e56Smrg
132f7df2e56Smrgstatic Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
133f7df2e56SmrgBool RunFromSigStopParent;      /* send SIGSTOP to our own process; Upstart (or
134f7df2e56Smrg                                   equivalent) will send SIGCONT back. */
135f7df2e56Smrgstatic char dynamic_display[7]; /* display name */
136f7df2e56SmrgBool PartialNetwork;            /* continue even if unable to bind all addrs */
13705b261ecSmrgstatic Pid_t ParentProcess;
13805b261ecSmrg
1396747b715Smrgint GrabInProgress = 0;
14005b261ecSmrg
1417e31ba66Smrgstatic void
1425a112b11SmrgEstablishNewConnections(int curconn, int ready, void *data);
143f7df2e56Smrg
1447e31ba66Smrgstatic void
1457e31ba66Smrgset_poll_client(ClientPtr client);
146f7df2e56Smrg
1477e31ba66Smrgstatic void
1487e31ba66Smrgset_poll_clients(void);
14905b261ecSmrg
150f7df2e56Smrgstatic XtransConnInfo *ListenTransConns = NULL;
151f7df2e56Smrgstatic int *ListenTransFds = NULL;
152f7df2e56Smrgstatic int ListenTransCount;
15305b261ecSmrg
154f7df2e56Smrgstatic void ErrorConnMax(XtransConnInfo /* trans_conn */ );
15505b261ecSmrg
15605b261ecSmrgstatic XtransConnInfo
157f7df2e56Smrglookup_trans_conn(int fd)
15805b261ecSmrg{
159f7df2e56Smrg    if (ListenTransFds) {
160f7df2e56Smrg        int i;
161f7df2e56Smrg
162f7df2e56Smrg        for (i = 0; i < ListenTransCount; i++)
163f7df2e56Smrg            if (ListenTransFds[i] == fd)
164f7df2e56Smrg                return ListenTransConns[i];
16505b261ecSmrg    }
16605b261ecSmrg
1676747b715Smrg    return NULL;
16805b261ecSmrg}
16905b261ecSmrg
1704642e01fSmrg/*
1714642e01fSmrg * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
1724642e01fSmrg *
1734642e01fSmrg *  a- The parent process is ignoring SIGUSR1
1744642e01fSmrg *
1754642e01fSmrg * or
1764642e01fSmrg *
1774642e01fSmrg *  b- The parent process is expecting a SIGUSR1
1784642e01fSmrg *     when the server is ready to accept connections
1794642e01fSmrg *
1804642e01fSmrg * In the first case, the signal will be harmless, in the second case,
1814642e01fSmrg * the signal will be quite useful.
1824642e01fSmrg */
1834642e01fSmrgstatic void
1844642e01fSmrgInitParentProcess(void)
1854642e01fSmrg{
1864642e01fSmrg#if !defined(WIN32)
1874642e01fSmrg    OsSigHandlerPtr handler;
188f7df2e56Smrg
189f7df2e56Smrg    handler = OsSignal(SIGUSR1, SIG_IGN);
190f7df2e56Smrg    if (handler == SIG_IGN)
191f7df2e56Smrg        RunFromSmartParent = TRUE;
1924642e01fSmrg    OsSignal(SIGUSR1, handler);
193f7df2e56Smrg    ParentProcess = getppid();
1944642e01fSmrg#endif
1954642e01fSmrg}
1964642e01fSmrg
1974642e01fSmrgvoid
1984642e01fSmrgNotifyParentProcess(void)
1994642e01fSmrg{
2004642e01fSmrg#if !defined(WIN32)
201f7df2e56Smrg    if (displayfd >= 0) {
202f7df2e56Smrg        if (write(displayfd, display, strlen(display)) != strlen(display))
203f7df2e56Smrg            FatalError("Cannot write display number to fd %d\n", displayfd);
204f7df2e56Smrg        if (write(displayfd, "\n", 1) != 1)
205f7df2e56Smrg            FatalError("Cannot write display number to fd %d\n", displayfd);
206f7df2e56Smrg        close(displayfd);
207f7df2e56Smrg        displayfd = -1;
208f7df2e56Smrg    }
2094642e01fSmrg    if (RunFromSmartParent) {
210f7df2e56Smrg        if (ParentProcess > 1) {
211f7df2e56Smrg            kill(ParentProcess, SIGUSR1);
212f7df2e56Smrg        }
2134642e01fSmrg    }
2149ace9065Smrg    if (RunFromSigStopParent)
215f7df2e56Smrg        raise(SIGSTOP);
2165a112b11Smrg#ifdef HAVE_SYSTEMD_DAEMON
2175a112b11Smrg    /* If we have been started as a systemd service, tell systemd that
2185a112b11Smrg       we are ready. Otherwise sd_notify() won't do anything. */
2195a112b11Smrg    sd_notify(0, "READY=1");
2205a112b11Smrg#endif
2214642e01fSmrg#endif
2224642e01fSmrg}
22305b261ecSmrg
224f7df2e56Smrgstatic Bool
225f7df2e56SmrgTryCreateSocket(int num, int *partial)
226f7df2e56Smrg{
227f7df2e56Smrg    char port[20];
228f7df2e56Smrg
229f7df2e56Smrg    snprintf(port, sizeof(port), "%d", num);
230f7df2e56Smrg
231f7df2e56Smrg    return (_XSERVTransMakeAllCOTSServerListeners(port, partial,
232f7df2e56Smrg                                                  &ListenTransCount,
233f7df2e56Smrg                                                  &ListenTransConns) >= 0);
234f7df2e56Smrg}
235f7df2e56Smrg
23605b261ecSmrg/*****************
23705b261ecSmrg * CreateWellKnownSockets
23805b261ecSmrg *    At initialization, create the sockets to listen on for new clients.
23905b261ecSmrg *****************/
24005b261ecSmrg
24105b261ecSmrgvoid
24205b261ecSmrgCreateWellKnownSockets(void)
24305b261ecSmrg{
244f7df2e56Smrg    int i;
245f7df2e56Smrg    int partial;
24605b261ecSmrg
247f7df2e56Smrg    /* display is initialized to "0" by main(). It is then set to the display
248f7df2e56Smrg     * number if specified on the command line. */
24905b261ecSmrg
250f7df2e56Smrg    if (NoListenAll) {
251f7df2e56Smrg        ListenTransCount = 0;
252f7df2e56Smrg    }
253f7df2e56Smrg    else if ((displayfd < 0) || explicit_display) {
254f7df2e56Smrg        if (TryCreateSocket(atoi(display), &partial) &&
255f7df2e56Smrg            ListenTransCount >= 1)
256f7df2e56Smrg            if (!PartialNetwork && partial)
257f7df2e56Smrg                FatalError ("Failed to establish all listening sockets");
258f7df2e56Smrg    }
259f7df2e56Smrg    else { /* -displayfd and no explicit display number */
260f7df2e56Smrg        Bool found = 0;
261f7df2e56Smrg        for (i = 0; i < 65536 - X_TCP_PORT; i++) {
262f7df2e56Smrg            if (TryCreateSocket(i, &partial) && !partial) {
263f7df2e56Smrg                found = 1;
264f7df2e56Smrg                break;
265f7df2e56Smrg            }
266f7df2e56Smrg            else
267f7df2e56Smrg                CloseWellKnownConnections();
268f7df2e56Smrg        }
269f7df2e56Smrg        if (!found)
270f7df2e56Smrg            FatalError("Failed to find a socket to listen on");
271f7df2e56Smrg        snprintf(dynamic_display, sizeof(dynamic_display), "%d", i);
272f7df2e56Smrg        display = dynamic_display;
273f7df2e56Smrg        LogSetDisplay();
274f7df2e56Smrg    }
275f7df2e56Smrg
276f7df2e56Smrg    ListenTransFds = xallocarray(ListenTransCount, sizeof (int));
277f7df2e56Smrg    if (ListenTransFds == NULL)
278f7df2e56Smrg        FatalError ("Failed to create listening socket array");
279f7df2e56Smrg
280f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
281f7df2e56Smrg        int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
282f7df2e56Smrg
283f7df2e56Smrg        ListenTransFds[i] = fd;
2845a112b11Smrg        SetNotifyFd(fd, EstablishNewConnections, X_NOTIFY_READ, NULL);
285f7df2e56Smrg
286f7df2e56Smrg        if (!_XSERVTransIsLocal(ListenTransConns[i]))
287f7df2e56Smrg            DefineSelf (fd);
28805b261ecSmrg    }
28905b261ecSmrg
2907e31ba66Smrg    if (ListenTransCount == 0 && !NoListenAll)
291f7df2e56Smrg        FatalError
292f7df2e56Smrg            ("Cannot establish any listening sockets - Make sure an X server isn't already running");
293f7df2e56Smrg
29405b261ecSmrg#if !defined(WIN32)
295f7df2e56Smrg    OsSignal(SIGPIPE, SIG_IGN);
296f7df2e56Smrg    OsSignal(SIGHUP, AutoResetServer);
29705b261ecSmrg#endif
298f7df2e56Smrg    OsSignal(SIGINT, GiveUp);
299f7df2e56Smrg    OsSignal(SIGTERM, GiveUp);
30005b261ecSmrg    ResetHosts(display);
3014642e01fSmrg
3024642e01fSmrg    InitParentProcess();
3034642e01fSmrg
30405b261ecSmrg#ifdef XDMCP
305f7df2e56Smrg    XdmcpInit();
30605b261ecSmrg#endif
30705b261ecSmrg}
30805b261ecSmrg
30905b261ecSmrgvoid
310f7df2e56SmrgResetWellKnownSockets(void)
31105b261ecSmrg{
31205b261ecSmrg    int i;
31305b261ecSmrg
31405b261ecSmrg    ResetOsBuffers();
31505b261ecSmrg
316f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
317f7df2e56Smrg        int status = _XSERVTransResetListener(ListenTransConns[i]);
318f7df2e56Smrg
319f7df2e56Smrg        if (status != TRANS_RESET_NOOP) {
320f7df2e56Smrg            if (status == TRANS_RESET_FAILURE) {
321f7df2e56Smrg                /*
322f7df2e56Smrg                 * ListenTransConns[i] freed by xtrans.
323f7df2e56Smrg                 * Remove it from out list.
324f7df2e56Smrg                 */
325f7df2e56Smrg
3267e31ba66Smrg                RemoveNotifyFd(ListenTransFds[i]);
327f7df2e56Smrg                ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
328f7df2e56Smrg                ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
329f7df2e56Smrg                ListenTransCount -= 1;
330f7df2e56Smrg                i -= 1;
331f7df2e56Smrg            }
332f7df2e56Smrg            else if (status == TRANS_RESET_NEW_FD) {
333f7df2e56Smrg                /*
334f7df2e56Smrg                 * A new file descriptor was allocated (the old one was closed)
335f7df2e56Smrg                 */
336f7df2e56Smrg
337f7df2e56Smrg                int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
338f7df2e56Smrg
339f7df2e56Smrg                ListenTransFds[i] = newfd;
340f7df2e56Smrg            }
341f7df2e56Smrg        }
34205b261ecSmrg    }
3437e31ba66Smrg    for (i = 0; i < ListenTransCount; i++)
3445a112b11Smrg        SetNotifyFd(ListenTransFds[i], EstablishNewConnections, X_NOTIFY_READ,
3455a112b11Smrg                    NULL);
34605b261ecSmrg
347f7df2e56Smrg    ResetAuthorization();
34805b261ecSmrg    ResetHosts(display);
34905b261ecSmrg    /*
35005b261ecSmrg     * restart XDMCP
35105b261ecSmrg     */
35205b261ecSmrg#ifdef XDMCP
353f7df2e56Smrg    XdmcpReset();
35405b261ecSmrg#endif
35505b261ecSmrg}
35605b261ecSmrg
35705b261ecSmrgvoid
35805b261ecSmrgCloseWellKnownConnections(void)
35905b261ecSmrg{
36005b261ecSmrg    int i;
36105b261ecSmrg
362f7df2e56Smrg    for (i = 0; i < ListenTransCount; i++) {
363f7df2e56Smrg        if (ListenTransConns[i] != NULL) {
364f7df2e56Smrg            _XSERVTransClose(ListenTransConns[i]);
365f7df2e56Smrg            ListenTransConns[i] = NULL;
3667e31ba66Smrg            if (ListenTransFds != NULL)
3677e31ba66Smrg                RemoveNotifyFd(ListenTransFds[i]);
368f7df2e56Smrg        }
369f7df2e56Smrg    }
370f7df2e56Smrg    ListenTransCount = 0;
37105b261ecSmrg}
37205b261ecSmrg
37305b261ecSmrgstatic void
374f7df2e56SmrgAuthAudit(ClientPtr client, Bool letin,
375f7df2e56Smrg          struct sockaddr *saddr, int len,
376f7df2e56Smrg          unsigned int proto_n, char *auth_proto, int auth_id)
37705b261ecSmrg{
37805b261ecSmrg    char addr[128];
37905b261ecSmrg    char client_uid_string[64];
3804642e01fSmrg    LocalClientCredRec *lcc;
381f7df2e56Smrg
3824642e01fSmrg#ifdef XSERVER_DTRACE
38305b261ecSmrg    pid_t client_pid = -1;
38405b261ecSmrg    zoneid_t client_zid = -1;
38505b261ecSmrg#endif
38605b261ecSmrg
38705b261ecSmrg    if (!len)
388f7df2e56Smrg        strlcpy(addr, "local host", sizeof(addr));
38905b261ecSmrg    else
390f7df2e56Smrg        switch (saddr->sa_family) {
391f7df2e56Smrg        case AF_UNSPEC:
39205b261ecSmrg#if defined(UNIXCONN) || defined(LOCALCONN)
393f7df2e56Smrg        case AF_UNIX:
39405b261ecSmrg#endif
395f7df2e56Smrg            strlcpy(addr, "local host", sizeof(addr));
396f7df2e56Smrg            break;
3977e31ba66Smrg#if defined(TCPCONN)
398f7df2e56Smrg        case AF_INET:
399f7df2e56Smrg            snprintf(addr, sizeof(addr), "IP %s",
400f7df2e56Smrg                     inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
401f7df2e56Smrg            break;
40205b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
403f7df2e56Smrg        case AF_INET6:{
404f7df2e56Smrg            char ipaddr[INET6_ADDRSTRLEN];
405f7df2e56Smrg
406f7df2e56Smrg            inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
407f7df2e56Smrg                      ipaddr, sizeof(ipaddr));
408f7df2e56Smrg            snprintf(addr, sizeof(addr), "IP %s", ipaddr);
409f7df2e56Smrg        }
410f7df2e56Smrg            break;
41105b261ecSmrg#endif
41205b261ecSmrg#endif
413f7df2e56Smrg        default:
414f7df2e56Smrg            strlcpy(addr, "unknown address", sizeof(addr));
415f7df2e56Smrg        }
41605b261ecSmrg
4174642e01fSmrg    if (GetLocalClientCreds(client, &lcc) != -1) {
418f7df2e56Smrg        int slen;               /* length written to client_uid_string */
419f7df2e56Smrg
420f7df2e56Smrg        strcpy(client_uid_string, " ( ");
421f7df2e56Smrg        slen = 3;
422f7df2e56Smrg
423f7df2e56Smrg        if (lcc->fieldsSet & LCC_UID_SET) {
424f7df2e56Smrg            snprintf(client_uid_string + slen,
425f7df2e56Smrg                     sizeof(client_uid_string) - slen,
426f7df2e56Smrg                     "uid=%ld ", (long) lcc->euid);
427f7df2e56Smrg            slen = strlen(client_uid_string);
428f7df2e56Smrg        }
429f7df2e56Smrg
430f7df2e56Smrg        if (lcc->fieldsSet & LCC_GID_SET) {
431f7df2e56Smrg            snprintf(client_uid_string + slen,
432f7df2e56Smrg                     sizeof(client_uid_string) - slen,
433f7df2e56Smrg                     "gid=%ld ", (long) lcc->egid);
434f7df2e56Smrg            slen = strlen(client_uid_string);
435f7df2e56Smrg        }
436f7df2e56Smrg
437f7df2e56Smrg        if (lcc->fieldsSet & LCC_PID_SET) {
438f7df2e56Smrg#ifdef XSERVER_DTRACE
439f7df2e56Smrg            client_pid = lcc->pid;
44005b261ecSmrg#endif
441f7df2e56Smrg            snprintf(client_uid_string + slen,
442f7df2e56Smrg                     sizeof(client_uid_string) - slen,
443f7df2e56Smrg                     "pid=%ld ", (long) lcc->pid);
444f7df2e56Smrg            slen = strlen(client_uid_string);
445f7df2e56Smrg        }
446f7df2e56Smrg
447f7df2e56Smrg        if (lcc->fieldsSet & LCC_ZID_SET) {
4484642e01fSmrg#ifdef XSERVER_DTRACE
449f7df2e56Smrg            client_zid = lcc->zoneid;
450f7df2e56Smrg#endif
451f7df2e56Smrg            snprintf(client_uid_string + slen,
452f7df2e56Smrg                     sizeof(client_uid_string) - slen,
453f7df2e56Smrg                     "zoneid=%ld ", (long) lcc->zoneid);
454f7df2e56Smrg            slen = strlen(client_uid_string);
455f7df2e56Smrg        }
456f7df2e56Smrg
457f7df2e56Smrg        snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
458f7df2e56Smrg                 ")");
459f7df2e56Smrg        FreeLocalClientCreds(lcc);
4604642e01fSmrg    }
46105b261ecSmrg    else {
462f7df2e56Smrg        client_uid_string[0] = '\0';
46305b261ecSmrg    }
464f7df2e56Smrg
46505b261ecSmrg#ifdef XSERVER_DTRACE
46605b261ecSmrg    XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
46705b261ecSmrg#endif
4684642e01fSmrg    if (auditTrailLevel > 1) {
469f7df2e56Smrg        if (proto_n)
470f7df2e56Smrg            AuditF("client %d %s from %s%s\n  Auth name: %.*s ID: %d\n",
471f7df2e56Smrg                   client->index, letin ? "connected" : "rejected", addr,
472f7df2e56Smrg                   client_uid_string, (int) proto_n, auth_proto, auth_id);
473f7df2e56Smrg        else
474f7df2e56Smrg            AuditF("client %d %s from %s%s\n",
475f7df2e56Smrg                   client->index, letin ? "connected" : "rejected", addr,
476f7df2e56Smrg                   client_uid_string);
47705b261ecSmrg
47805b261ecSmrg    }
47905b261ecSmrg}
48005b261ecSmrg
48105b261ecSmrgXID
48205b261ecSmrgAuthorizationIDOfClient(ClientPtr client)
48305b261ecSmrg{
48405b261ecSmrg    if (client->osPrivate)
485f7df2e56Smrg        return ((OsCommPtr) client->osPrivate)->auth_id;
48605b261ecSmrg    else
487f7df2e56Smrg        return None;
48805b261ecSmrg}
48905b261ecSmrg
49005b261ecSmrg/*****************************************************************
49105b261ecSmrg * ClientAuthorized
49205b261ecSmrg *
49305b261ecSmrg *    Sent by the client at connection setup:
49405b261ecSmrg *                typedef struct _xConnClientPrefix {
49505b261ecSmrg *                   CARD8	byteOrder;
49605b261ecSmrg *                   BYTE	pad;
49705b261ecSmrg *                   CARD16	majorVersion, minorVersion;
498f7df2e56Smrg *                   CARD16	nbytesAuthProto;
499f7df2e56Smrg *                   CARD16	nbytesAuthString;
50005b261ecSmrg *                 } xConnClientPrefix;
50105b261ecSmrg *
50205b261ecSmrg *     	It is hoped that eventually one protocol will be agreed upon.  In the
50305b261ecSmrg *        mean time, a server that implements a different protocol than the
50405b261ecSmrg *        client expects, or a server that only implements the host-based
50505b261ecSmrg *        mechanism, will simply ignore this information.
50605b261ecSmrg *
50705b261ecSmrg *****************************************************************/
50805b261ecSmrg
509f7df2e56Smrgconst char *
510f7df2e56SmrgClientAuthorized(ClientPtr client,
511f7df2e56Smrg                 unsigned int proto_n, char *auth_proto,
512f7df2e56Smrg                 unsigned int string_n, char *auth_string)
51305b261ecSmrg{
514f7df2e56Smrg    OsCommPtr priv;
515f7df2e56Smrg    Xtransaddr *from = NULL;
516f7df2e56Smrg    int family;
517f7df2e56Smrg    int fromlen;
518f7df2e56Smrg    XID auth_id;
519f7df2e56Smrg    const char *reason = NULL;
520f7df2e56Smrg    XtransConnInfo trans_conn;
521f7df2e56Smrg
522f7df2e56Smrg    priv = (OsCommPtr) client->osPrivate;
52305b261ecSmrg    trans_conn = priv->trans_conn;
52405b261ecSmrg
5254642e01fSmrg    /* Allow any client to connect without authorization on a launchd socket,
5264642e01fSmrg       because it is securely created -- this prevents a race condition on launch */
527f7df2e56Smrg    if (trans_conn->flags & TRANS_NOXAUTH) {
5284642e01fSmrg        auth_id = (XID) 0L;
529f7df2e56Smrg    }
530f7df2e56Smrg    else {
531f7df2e56Smrg        auth_id =
532f7df2e56Smrg            CheckAuthorization(proto_n, auth_proto, string_n, auth_string,
533f7df2e56Smrg                               client, &reason);
5344642e01fSmrg    }
53505b261ecSmrg
536f7df2e56Smrg    if (auth_id == (XID) ~0L) {
537f7df2e56Smrg        if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
538f7df2e56Smrg            if (InvalidHost((struct sockaddr *) from, fromlen, client))
539f7df2e56Smrg                AuthAudit(client, FALSE, (struct sockaddr *) from,
540f7df2e56Smrg                          fromlen, proto_n, auth_proto, auth_id);
541f7df2e56Smrg            else {
542f7df2e56Smrg                auth_id = (XID) 0;
54305b261ecSmrg#ifdef XSERVER_DTRACE
544f7df2e56Smrg                if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
54505b261ecSmrg#else
546f7df2e56Smrg                if (auditTrailLevel > 1)
54705b261ecSmrg#endif
548f7df2e56Smrg                    AuthAudit(client, TRUE,
549f7df2e56Smrg                              (struct sockaddr *) from, fromlen,
550f7df2e56Smrg                              proto_n, auth_proto, auth_id);
551f7df2e56Smrg            }
552f7df2e56Smrg
553f7df2e56Smrg            free(from);
554f7df2e56Smrg        }
555f7df2e56Smrg
556f7df2e56Smrg        if (auth_id == (XID) ~0L) {
557f7df2e56Smrg            if (reason)
558f7df2e56Smrg                return reason;
559f7df2e56Smrg            else
560f7df2e56Smrg                return "Client is not authorized to connect to Server";
561f7df2e56Smrg        }
56205b261ecSmrg    }
56305b261ecSmrg#ifdef XSERVER_DTRACE
56405b261ecSmrg    else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
56505b261ecSmrg#else
56605b261ecSmrg    else if (auditTrailLevel > 1)
56705b261ecSmrg#endif
56805b261ecSmrg    {
569f7df2e56Smrg        if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
570f7df2e56Smrg            AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
571f7df2e56Smrg                      proto_n, auth_proto, auth_id);
572f7df2e56Smrg
573f7df2e56Smrg            free(from);
574f7df2e56Smrg        }
57505b261ecSmrg    }
57605b261ecSmrg    priv->auth_id = auth_id;
57705b261ecSmrg    priv->conn_time = 0;
57805b261ecSmrg
57905b261ecSmrg#ifdef XDMCP
58005b261ecSmrg    /* indicate to Xdmcp protocol that we've opened new client */
58105b261ecSmrg    XdmcpOpenDisplay(priv->fd);
582f7df2e56Smrg#endif                          /* XDMCP */
58305b261ecSmrg
58405b261ecSmrg    XaceHook(XACE_AUTH_AVAIL, client, auth_id);
58505b261ecSmrg
58605b261ecSmrg    /* At this point, if the client is authorized to change the access control
58705b261ecSmrg     * list, we should getpeername() information, and add the client to
58805b261ecSmrg     * the selfhosts list.  It's not really the host machine, but the
58905b261ecSmrg     * true purpose of the selfhosts list is to see who may change the
59005b261ecSmrg     * access control list.
59105b261ecSmrg     */
592f7df2e56Smrg    return ((char *) NULL);
59305b261ecSmrg}
59405b261ecSmrg
5957e31ba66Smrgstatic void
5967e31ba66SmrgClientReady(int fd, int xevents, void *data)
5977e31ba66Smrg{
5987e31ba66Smrg    ClientPtr client = data;
5997e31ba66Smrg
6007e31ba66Smrg    if (xevents & X_NOTIFY_ERROR) {
6017e31ba66Smrg        CloseDownClient(client);
6027e31ba66Smrg        return;
6037e31ba66Smrg    }
6047e31ba66Smrg    if (xevents & X_NOTIFY_READ)
6057e31ba66Smrg        mark_client_ready(client);
6067e31ba66Smrg    if (xevents & X_NOTIFY_WRITE) {
6077e31ba66Smrg        ospoll_mute(server_poll, fd, X_NOTIFY_WRITE);
6087e31ba66Smrg        NewOutputPending = TRUE;
6097e31ba66Smrg    }
6107e31ba66Smrg}
6117e31ba66Smrg
61205b261ecSmrgstatic ClientPtr
613f7df2e56SmrgAllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
61405b261ecSmrg{
615f7df2e56Smrg    OsCommPtr oc;
616f7df2e56Smrg    ClientPtr client;
617f7df2e56Smrg
6186747b715Smrg    oc = malloc(sizeof(OsCommRec));
61905b261ecSmrg    if (!oc)
620f7df2e56Smrg        return NullClient;
62105b261ecSmrg    oc->trans_conn = trans_conn;
62205b261ecSmrg    oc->fd = fd;
623f7df2e56Smrg    oc->input = (ConnectionInputPtr) NULL;
624f7df2e56Smrg    oc->output = (ConnectionOutputPtr) NULL;
62505b261ecSmrg    oc->auth_id = None;
62605b261ecSmrg    oc->conn_time = conn_time;
6277e31ba66Smrg    oc->flags = 0;
628f7df2e56Smrg    if (!(client = NextAvailableClient((void *) oc))) {
629f7df2e56Smrg        free(oc);
630f7df2e56Smrg        return NullClient;
63105b261ecSmrg    }
632f7df2e56Smrg    client->local = ComputeLocalClient(client);
6337e31ba66Smrg    ospoll_add(server_poll, fd,
6347e31ba66Smrg               ospoll_trigger_edge,
6357e31ba66Smrg               ClientReady,
6367e31ba66Smrg               client);
6377e31ba66Smrg    set_poll_client(client);
63805b261ecSmrg
63905b261ecSmrg#ifdef DEBUG
64005b261ecSmrg    ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
641f7df2e56Smrg           client->index, fd);
64205b261ecSmrg#endif
64305b261ecSmrg#ifdef XSERVER_DTRACE
64405b261ecSmrg    XSERVER_CLIENT_CONNECT(client->index, fd);
645f7df2e56Smrg#endif
64605b261ecSmrg
64705b261ecSmrg    return client;
64805b261ecSmrg}
64905b261ecSmrg
65005b261ecSmrg/*****************
65105b261ecSmrg * EstablishNewConnections
6525a112b11Smrg *    If anyone is waiting on listened sockets, accept them. Drop pending
6535a112b11Smrg *    connections if they've stuck around for more than one minute.
65405b261ecSmrg *****************/
6555a112b11Smrg#define TimeOutValue 60 * MILLI_PER_SECOND
6565a112b11Smrgstatic void
6575a112b11SmrgEstablishNewConnections(int curconn, int ready, void *data)
65805b261ecSmrg{
6597e31ba66Smrg    int newconn;       /* fd of new client */
66005b261ecSmrg    CARD32 connect_time;
6617e31ba66Smrg    int i;
6627e31ba66Smrg    ClientPtr client;
6637e31ba66Smrg    OsCommPtr oc;
6647e31ba66Smrg    XtransConnInfo trans_conn, new_trans_conn;
6657e31ba66Smrg    int status;
6667e31ba66Smrg
66705b261ecSmrg    connect_time = GetTimeInMillis();
66805b261ecSmrg    /* kill off stragglers */
669f7df2e56Smrg    for (i = 1; i < currentMaxClients; i++) {
670f7df2e56Smrg        if ((client = clients[i])) {
671f7df2e56Smrg            oc = (OsCommPtr) (client->osPrivate);
672f7df2e56Smrg            if ((oc && (oc->conn_time != 0) &&
673f7df2e56Smrg                 (connect_time - oc->conn_time) >= TimeOutValue) ||
674f7df2e56Smrg                (client->noClientException != Success && !client->clientGone))
675f7df2e56Smrg                CloseDownClient(client);
676f7df2e56Smrg        }
67705b261ecSmrg    }
67805b261ecSmrg
6797e31ba66Smrg    if ((trans_conn = lookup_trans_conn(curconn)) == NULL)
6805a112b11Smrg        return;
681f7df2e56Smrg
6827e31ba66Smrg    if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL)
6835a112b11Smrg        return;
68405b261ecSmrg
6857e31ba66Smrg    newconn = _XSERVTransGetConnectionNumber(new_trans_conn);
68605b261ecSmrg
6877e31ba66Smrg    _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
6884642e01fSmrg
6897e31ba66Smrg    if (trans_conn->flags & TRANS_NOXAUTH)
6907e31ba66Smrg        new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
6914642e01fSmrg
6927e31ba66Smrg    if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) {
6937e31ba66Smrg        ErrorConnMax(new_trans_conn);
69405b261ecSmrg    }
6955a112b11Smrg    return;
69605b261ecSmrg}
69705b261ecSmrg
69805b261ecSmrg#define NOROOM "Maximum number of clients reached"
69905b261ecSmrg
70005b261ecSmrg/************
70105b261ecSmrg *   ErrorConnMax
70205b261ecSmrg *     Fail a connection due to lack of client or file descriptor space
70305b261ecSmrg ************/
70405b261ecSmrg
70505b261ecSmrgstatic void
7067e31ba66SmrgConnMaxNotify(int fd, int events, void *data)
70705b261ecSmrg{
7087e31ba66Smrg    XtransConnInfo trans_conn = data;
709f7df2e56Smrg    char order = 0;
7107e31ba66Smrg
71105b261ecSmrg    /* try to read the byte-order of the connection */
712f7df2e56Smrg    (void) _XSERVTransRead(trans_conn, &order, 1);
713f7df2e56Smrg    if (order == 'l' || order == 'B' || order == 'r' || order == 'R') {
7147e31ba66Smrg        xConnSetupPrefix csp;
7157e31ba66Smrg        char pad[3] = { 0, 0, 0 };
7167e31ba66Smrg        int whichbyte = 1;
7177e31ba66Smrg        struct iovec iov[3];
7187e31ba66Smrg
719f7df2e56Smrg        csp.success = xFalse;
720f7df2e56Smrg        csp.lengthReason = sizeof(NOROOM) - 1;
721f7df2e56Smrg        csp.length = (sizeof(NOROOM) + 2) >> 2;
722f7df2e56Smrg        csp.majorVersion = X_PROTOCOL;
723f7df2e56Smrg        csp.minorVersion = X_PROTOCOL_REVISION;
7247e31ba66Smrg        if (((*(char *) &whichbyte) && (order == 'B' || order == 'R')) ||
7257e31ba66Smrg            (!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) {
726f7df2e56Smrg            swaps(&csp.majorVersion);
727f7df2e56Smrg            swaps(&csp.minorVersion);
728f7df2e56Smrg            swaps(&csp.length);
729f7df2e56Smrg        }
730f7df2e56Smrg        iov[0].iov_len = sz_xConnSetupPrefix;
731f7df2e56Smrg        iov[0].iov_base = (char *) &csp;
732f7df2e56Smrg        iov[1].iov_len = csp.lengthReason;
733f7df2e56Smrg        iov[1].iov_base = (void *) NOROOM;
734f7df2e56Smrg        iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
735f7df2e56Smrg        iov[2].iov_base = pad;
736f7df2e56Smrg        (void) _XSERVTransWritev(trans_conn, iov, 3);
73705b261ecSmrg    }
7387e31ba66Smrg    RemoveNotifyFd(trans_conn->fd);
7397e31ba66Smrg    _XSERVTransClose(trans_conn);
7407e31ba66Smrg}
7417e31ba66Smrg
7427e31ba66Smrgstatic void
7437e31ba66SmrgErrorConnMax(XtransConnInfo trans_conn)
7447e31ba66Smrg{
7457e31ba66Smrg    if (!SetNotifyFd(trans_conn->fd, ConnMaxNotify, X_NOTIFY_READ, trans_conn))
7467e31ba66Smrg        _XSERVTransClose(trans_conn);
74705b261ecSmrg}
74805b261ecSmrg
74905b261ecSmrg/************
75005b261ecSmrg *   CloseDownFileDescriptor:
7517e31ba66Smrg *     Remove this file descriptor
75205b261ecSmrg ************/
75305b261ecSmrg
7547e31ba66Smrgvoid
75505b261ecSmrgCloseDownFileDescriptor(OsCommPtr oc)
75605b261ecSmrg{
75705b261ecSmrg    if (oc->trans_conn) {
7587e31ba66Smrg        int connection = oc->fd;
7597e31ba66Smrg#ifdef XDMCP
7607e31ba66Smrg        XdmcpCloseDisplay(connection);
7617e31ba66Smrg#endif
7627e31ba66Smrg        ospoll_remove(server_poll, connection);
763f7df2e56Smrg        _XSERVTransDisconnect(oc->trans_conn);
764f7df2e56Smrg        _XSERVTransClose(oc->trans_conn);
7657e31ba66Smrg        oc->trans_conn = NULL;
7667e31ba66Smrg        oc->fd = -1;
76705b261ecSmrg    }
76805b261ecSmrg}
76905b261ecSmrg
77005b261ecSmrg/*****************
77105b261ecSmrg * CloseDownConnection
772f7df2e56Smrg *    Delete client from AllClients and free resources
77305b261ecSmrg *****************/
77405b261ecSmrg
77505b261ecSmrgvoid
77605b261ecSmrgCloseDownConnection(ClientPtr client)
77705b261ecSmrg{
778f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
77905b261ecSmrg
7806747b715Smrg    if (FlushCallback)
7817e31ba66Smrg        CallCallbacks(&FlushCallback, client);
7826747b715Smrg
783f7df2e56Smrg    if (oc->output)
784f7df2e56Smrg	FlushClient(client, oc, (char *) NULL, 0);
78505b261ecSmrg    CloseDownFileDescriptor(oc);
78605b261ecSmrg    FreeOsBuffers(oc);
7876747b715Smrg    free(client->osPrivate);
788f7df2e56Smrg    client->osPrivate = (void *) NULL;
78905b261ecSmrg    if (auditTrailLevel > 1)
790f7df2e56Smrg        AuditF("client %d disconnected\n", client->index);
79105b261ecSmrg}
79205b261ecSmrg
7937e31ba66Smrgstruct notify_fd {
7947e31ba66Smrg    int mask;
7957e31ba66Smrg    NotifyFdProcPtr notify;
7967e31ba66Smrg    void *data;
7977e31ba66Smrg};
79805b261ecSmrg
7997e31ba66Smrg/*****************
8007e31ba66Smrg * HandleNotifyFd
8017e31ba66Smrg *    A poll callback to be called when the registered
8027e31ba66Smrg *    file descriptor is ready.
8037e31ba66Smrg *****************/
80405b261ecSmrg
8057e31ba66Smrgstatic void
8067e31ba66SmrgHandleNotifyFd(int fd, int xevents, void *data)
80705b261ecSmrg{
8087e31ba66Smrg    struct notify_fd *n = data;
8097e31ba66Smrg    n->notify(fd, xevents, n->data);
81005b261ecSmrg}
81105b261ecSmrg
8127e31ba66Smrg/*****************
8137e31ba66Smrg * SetNotifyFd
8147e31ba66Smrg *    Registers a callback to be invoked when the specified
8157e31ba66Smrg *    file descriptor becomes readable.
8167e31ba66Smrg *****************/
8177e31ba66Smrg
8187e31ba66SmrgBool
8197e31ba66SmrgSetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
82005b261ecSmrg{
8217e31ba66Smrg    struct notify_fd *n;
8227e31ba66Smrg
8237e31ba66Smrg    n = ospoll_data(server_poll, fd);
8247e31ba66Smrg    if (!n) {
8257e31ba66Smrg        if (mask == 0)
8267e31ba66Smrg            return TRUE;
8277e31ba66Smrg
8287e31ba66Smrg        n = calloc(1, sizeof (struct notify_fd));
8297e31ba66Smrg        if (!n)
8307e31ba66Smrg            return FALSE;
8317e31ba66Smrg        ospoll_add(server_poll, fd,
8327e31ba66Smrg                   ospoll_trigger_level,
8337e31ba66Smrg                   HandleNotifyFd,
8347e31ba66Smrg                   n);
8357e31ba66Smrg    }
8367e31ba66Smrg
8377e31ba66Smrg    if (mask == 0) {
8387e31ba66Smrg        ospoll_remove(server_poll, fd);
8397e31ba66Smrg        free(n);
8407e31ba66Smrg    } else {
8417e31ba66Smrg        int listen = mask & ~n->mask;
8427e31ba66Smrg        int mute = n->mask & ~mask;
8437e31ba66Smrg
8447e31ba66Smrg        if (listen)
8457e31ba66Smrg            ospoll_listen(server_poll, fd, listen);
8467e31ba66Smrg        if (mute)
8477e31ba66Smrg            ospoll_mute(server_poll, fd, mute);
8487e31ba66Smrg        n->mask = mask;
8497e31ba66Smrg        n->data = data;
8507e31ba66Smrg        n->notify = notify;
8517e31ba66Smrg    }
8527e31ba66Smrg
8537e31ba66Smrg    return TRUE;
85405b261ecSmrg}
85505b261ecSmrg
85605b261ecSmrg/*****************
85705b261ecSmrg * OnlyListenToOneClient:
85805b261ecSmrg *    Only accept requests from  one client.  Continue to handle new
85905b261ecSmrg *    connections, but don't take any protocol requests from the new
86005b261ecSmrg *    ones.  Note that if GrabInProgress is set, EstablishNewConnections
86105b261ecSmrg *    needs to put new clients into SavedAllSockets and SavedAllClients.
86205b261ecSmrg *    Note also that there is no timeout for this in the protocol.
86305b261ecSmrg *    This routine is "undone" by ListenToAllClients()
86405b261ecSmrg *****************/
86505b261ecSmrg
8664642e01fSmrgint
86705b261ecSmrgOnlyListenToOneClient(ClientPtr client)
86805b261ecSmrg{
8697e31ba66Smrg    int rc;
8704642e01fSmrg
8714642e01fSmrg    rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
8724642e01fSmrg    if (rc != Success)
873f7df2e56Smrg        return rc;
874f7df2e56Smrg
875f7df2e56Smrg    if (!GrabInProgress) {
876f7df2e56Smrg        GrabInProgress = client->index;
8777e31ba66Smrg        set_poll_clients();
87805b261ecSmrg    }
8797e31ba66Smrg
8804642e01fSmrg    return rc;
88105b261ecSmrg}
88205b261ecSmrg
88305b261ecSmrg/****************
88405b261ecSmrg * ListenToAllClients:
88505b261ecSmrg *    Undoes OnlyListentToOneClient()
88605b261ecSmrg ****************/
88705b261ecSmrg
88805b261ecSmrgvoid
88905b261ecSmrgListenToAllClients(void)
89005b261ecSmrg{
891f7df2e56Smrg    if (GrabInProgress) {
892f7df2e56Smrg        GrabInProgress = 0;
8937e31ba66Smrg        set_poll_clients();
894f7df2e56Smrg    }
89505b261ecSmrg}
89605b261ecSmrg
89705b261ecSmrg/****************
89805b261ecSmrg * IgnoreClient
89905b261ecSmrg *    Removes one client from input masks.
9005a112b11Smrg *    Must have corresponding call to AttendClient.
90105b261ecSmrg ****************/
90205b261ecSmrg
9036747b715Smrgvoid
904f7df2e56SmrgIgnoreClient(ClientPtr client)
90505b261ecSmrg{
906f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
90705b261ecSmrg
9086747b715Smrg    client->ignoreCount++;
9096747b715Smrg    if (client->ignoreCount > 1)
910f7df2e56Smrg        return;
9116747b715Smrg
91205b261ecSmrg    isItTimeToYield = TRUE;
9137e31ba66Smrg    mark_client_not_ready(client);
9147e31ba66Smrg
9157e31ba66Smrg    oc->flags |= OS_COMM_IGNORED;
9167e31ba66Smrg    set_poll_client(client);
91705b261ecSmrg}
91805b261ecSmrg
91905b261ecSmrg/****************
92005b261ecSmrg * AttendClient
92105b261ecSmrg *    Adds one client back into the input masks.
92205b261ecSmrg ****************/
92305b261ecSmrg
9246747b715Smrgvoid
925f7df2e56SmrgAttendClient(ClientPtr client)
92605b261ecSmrg{
927f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
9286747b715Smrg
9294e185dc0Smrg    if (client->clientGone) {
9304e185dc0Smrg        /*
9314e185dc0Smrg         * client is gone, so any pending requests will be dropped and its
9324e185dc0Smrg         * ignore count doesn't matter.
9334e185dc0Smrg         */
9344e185dc0Smrg        return;
9354e185dc0Smrg    }
9364e185dc0Smrg
9376747b715Smrg    client->ignoreCount--;
9386747b715Smrg    if (client->ignoreCount)
939f7df2e56Smrg        return;
9406747b715Smrg
9417e31ba66Smrg    oc->flags &= ~OS_COMM_IGNORED;
9427e31ba66Smrg    set_poll_client(client);
9437e31ba66Smrg    if (listen_to_client(client))
9447e31ba66Smrg        mark_client_ready(client);
945f7df2e56Smrg    else {
9467e31ba66Smrg        /* grab active, mark ready when grab goes away */
9477e31ba66Smrg        mark_client_saved_ready(client);
94805b261ecSmrg    }
94905b261ecSmrg}
95005b261ecSmrg
95105b261ecSmrg/* make client impervious to grabs; assume only executing client calls this */
95205b261ecSmrg
9534642e01fSmrgvoid
95405b261ecSmrgMakeClientGrabImpervious(ClientPtr client)
95505b261ecSmrg{
956f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
95705b261ecSmrg
9587e31ba66Smrg    oc->flags |= OS_COMM_GRAB_IMPERVIOUS;
9597e31ba66Smrg    set_poll_client(client);
96005b261ecSmrg
961f7df2e56Smrg    if (ServerGrabCallback) {
962f7df2e56Smrg        ServerGrabInfoRec grabinfo;
963f7df2e56Smrg
964f7df2e56Smrg        grabinfo.client = client;
965f7df2e56Smrg        grabinfo.grabstate = CLIENT_IMPERVIOUS;
966f7df2e56Smrg        CallCallbacks(&ServerGrabCallback, &grabinfo);
96705b261ecSmrg    }
96805b261ecSmrg}
96905b261ecSmrg
97005b261ecSmrg/* make client pervious to grabs; assume only executing client calls this */
97105b261ecSmrg
9724642e01fSmrgvoid
97305b261ecSmrgMakeClientGrabPervious(ClientPtr client)
97405b261ecSmrg{
975f7df2e56Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
97605b261ecSmrg
9777e31ba66Smrg    oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS;
9787e31ba66Smrg    set_poll_client(client);
9797e31ba66Smrg    isItTimeToYield = TRUE;
98005b261ecSmrg
981f7df2e56Smrg    if (ServerGrabCallback) {
982f7df2e56Smrg        ServerGrabInfoRec grabinfo;
983f7df2e56Smrg
984f7df2e56Smrg        grabinfo.client = client;
985f7df2e56Smrg        grabinfo.grabstate = CLIENT_PERVIOUS;
986f7df2e56Smrg        CallCallbacks(&ServerGrabCallback, &grabinfo);
98705b261ecSmrg    }
98805b261ecSmrg}
98905b261ecSmrg
990f7df2e56Smrg/* Add a fd (from launchd or similar) to our listeners */
991f7df2e56Smrgvoid
992f7df2e56SmrgListenOnOpenFD(int fd, int noxauth)
993f7df2e56Smrg{
9944642e01fSmrg    char port[256];
9954642e01fSmrg    XtransConnInfo ciptr;
9966747b715Smrg    const char *display_env = getenv("DISPLAY");
9974642e01fSmrg
998f7df2e56Smrg    if (display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) {
9994642e01fSmrg        /* Make the path the launchd socket if our DISPLAY is set right */
10006747b715Smrg        strcpy(port, display_env);
1001f7df2e56Smrg    }
1002f7df2e56Smrg    else {
10034642e01fSmrg        /* Just some default so things don't break and die. */
1004f7df2e56Smrg        snprintf(port, sizeof(port), ":%d", atoi(display));
10054642e01fSmrg    }
10064642e01fSmrg
10074642e01fSmrg    /* Make our XtransConnInfo
10084642e01fSmrg     * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
10094642e01fSmrg     */
10104642e01fSmrg    ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1011f7df2e56Smrg    if (ciptr == NULL) {
1012f7df2e56Smrg        ErrorF("Got NULL while trying to Reopen listen port.\n");
10134642e01fSmrg        return;
10144642e01fSmrg    }
1015f7df2e56Smrg
1016f7df2e56Smrg    if (noxauth)
10174642e01fSmrg        ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
10184642e01fSmrg
10194642e01fSmrg    /* Allocate space to store it */
1020f7df2e56Smrg    ListenTransFds =
1021f7df2e56Smrg        xnfreallocarray(ListenTransFds, ListenTransCount + 1, sizeof(int));
1022f7df2e56Smrg    ListenTransConns =
1023f7df2e56Smrg        xnfreallocarray(ListenTransConns, ListenTransCount + 1,
1024f7df2e56Smrg                        sizeof(XtransConnInfo));
1025f7df2e56Smrg
10264642e01fSmrg    /* Store it */
10274642e01fSmrg    ListenTransConns[ListenTransCount] = ciptr;
10284642e01fSmrg    ListenTransFds[ListenTransCount] = fd;
10294642e01fSmrg
10305a112b11Smrg    SetNotifyFd(fd, EstablishNewConnections, X_NOTIFY_READ, NULL);
1031f7df2e56Smrg
10324642e01fSmrg    /* Increment the count */
10334642e01fSmrg    ListenTransCount++;
10344642e01fSmrg}
10354642e01fSmrg
1036f7df2e56Smrg/* based on TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) */
1037f7df2e56SmrgBool
1038f7df2e56SmrgAddClientOnOpenFD(int fd)
1039f7df2e56Smrg{
1040f7df2e56Smrg    XtransConnInfo ciptr;
1041f7df2e56Smrg    CARD32 connect_time;
1042f7df2e56Smrg    char port[20];
1043f7df2e56Smrg
1044f7df2e56Smrg    snprintf(port, sizeof(port), ":%d", atoi(display));
1045f7df2e56Smrg    ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1046f7df2e56Smrg    if (ciptr == NULL)
1047f7df2e56Smrg        return FALSE;
1048f7df2e56Smrg
1049f7df2e56Smrg    _XSERVTransSetOption(ciptr, TRANS_NONBLOCKING, 1);
1050f7df2e56Smrg    ciptr->flags |= TRANS_NOXAUTH;
1051f7df2e56Smrg
1052f7df2e56Smrg    connect_time = GetTimeInMillis();
1053f7df2e56Smrg
1054f7df2e56Smrg    if (!AllocNewConnection(ciptr, fd, connect_time)) {
1055f7df2e56Smrg        ErrorConnMax(ciptr);
1056f7df2e56Smrg        return FALSE;
1057f7df2e56Smrg    }
1058f7df2e56Smrg
1059f7df2e56Smrg    return TRUE;
1060f7df2e56Smrg}
10617e31ba66Smrg
10627e31ba66SmrgBool
10637e31ba66Smrglisten_to_client(ClientPtr client)
10647e31ba66Smrg{
10657e31ba66Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
10667e31ba66Smrg
10677e31ba66Smrg    if (oc->flags & OS_COMM_IGNORED)
10687e31ba66Smrg        return FALSE;
10697e31ba66Smrg
10707e31ba66Smrg    if (!GrabInProgress)
10717e31ba66Smrg        return TRUE;
10727e31ba66Smrg
10737e31ba66Smrg    if (client->index == GrabInProgress)
10747e31ba66Smrg        return TRUE;
10757e31ba66Smrg
10767e31ba66Smrg    if (oc->flags & OS_COMM_GRAB_IMPERVIOUS)
10777e31ba66Smrg        return TRUE;
10787e31ba66Smrg
10797e31ba66Smrg    return FALSE;
10807e31ba66Smrg}
10817e31ba66Smrg
10827e31ba66Smrgstatic void
10837e31ba66Smrgset_poll_client(ClientPtr client)
10847e31ba66Smrg{
10857e31ba66Smrg    OsCommPtr oc = (OsCommPtr) client->osPrivate;
10867e31ba66Smrg
10877e31ba66Smrg    if (oc->trans_conn) {
10887e31ba66Smrg        if (listen_to_client(client))
10897e31ba66Smrg            ospoll_listen(server_poll, oc->trans_conn->fd, X_NOTIFY_READ);
10907e31ba66Smrg        else
10917e31ba66Smrg            ospoll_mute(server_poll, oc->trans_conn->fd, X_NOTIFY_READ);
10927e31ba66Smrg    }
10937e31ba66Smrg}
10947e31ba66Smrg
10957e31ba66Smrgstatic void
10967e31ba66Smrgset_poll_clients(void)
10977e31ba66Smrg{
10987e31ba66Smrg    int i;
10997e31ba66Smrg
11007e31ba66Smrg    for (i = 1; i < currentMaxClients; i++) {
11017e31ba66Smrg        ClientPtr client = clients[i];
11027e31ba66Smrg        if (client && !client->clientGone)
11037e31ba66Smrg            set_poll_client(client);
11047e31ba66Smrg    }
11057e31ba66Smrg}
1106