xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

connection.c (30530B)


      1 /***********************************************************
      2 
      3 Copyright 1987, 1989, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from The Open Group.
     24 
     25 Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
     26 
     27                         All Rights Reserved
     28 
     29 Permission to use, copy, modify, and distribute this software and its
     30 documentation for any purpose and without fee is hereby granted,
     31 provided that the above copyright notice appear in all copies and that
     32 both that copyright notice and this permission notice appear in
     33 supporting documentation, and that the name of Digital not be
     34 used in advertising or publicity pertaining to distribution of the
     35 software without specific, written prior permission.
     36 
     37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     43 SOFTWARE.
     44 
     45 ******************************************************************/
     46 /*****************************************************************
     47  *  Stuff to create connections --- OS dependent
     48  *
     49  *      EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
     50  *      CloseDownConnection,
     51  *	OnlyListToOneClient,
     52  *      ListenToAllClients,
     53  *
     54  *      (WaitForSomething is in its own file)
     55  *
     56  *      In this implementation, a client socket table is not kept.
     57  *      Instead, what would be the index into the table is just the
     58  *      file descriptor of the socket.  This won't work for if the
     59  *      socket ids aren't small nums (0 - 2^8)
     60  *
     61  *****************************************************************/
     62 
     63 #ifdef HAVE_DIX_CONFIG_H
     64 #include <dix-config.h>
     65 #endif
     66 
     67 #ifdef WIN32
     68 #include <X11/Xwinsock.h>
     69 #endif
     70 #include <X11/X.h>
     71 #include <X11/Xproto.h>
     72 #define XSERV_t
     73 #define TRANS_SERVER
     74 #define TRANS_REOPEN
     75 #include <X11/Xtrans/Xtrans.h>
     76 #include <X11/Xtrans/Xtransint.h>
     77 #include <errno.h>
     78 #include <signal.h>
     79 #include <stdio.h>
     80 #include <stdlib.h>
     81 
     82 #ifndef WIN32
     83 #include <sys/socket.h>
     84 
     85 #if defined(TCPCONN)
     86 #include <netinet/in.h>
     87 #include <arpa/inet.h>
     88 #ifdef apollo
     89 #ifndef NO_TCP_H
     90 #include <netinet/tcp.h>
     91 #endif
     92 #else
     93 #ifdef CSRG_BASED
     94 #include <sys/param.h>
     95 #endif
     96 #include <netinet/tcp.h>
     97 #endif
     98 #include <arpa/inet.h>
     99 #endif
    100 
    101 #include <sys/uio.h>
    102 
    103 #endif                          /* WIN32 */
    104 #include "misc.h"               /* for typedef of pointer */
    105 #include "osdep.h"
    106 #include "opaque.h"
    107 #include "dixstruct.h"
    108 #include "xace.h"
    109 
    110 #define Pid_t pid_t
    111 
    112 #ifdef HAVE_GETPEERUCRED
    113 #include <ucred.h>
    114 #include <zone.h>
    115 #else
    116 #define zoneid_t int
    117 #endif
    118 
    119 #ifdef HAVE_SYSTEMD_DAEMON
    120 #include <systemd/sd-daemon.h>
    121 #endif
    122 
    123 #include "probes.h"
    124 
    125 struct ospoll   *server_poll;
    126 
    127 Bool NewOutputPending;          /* not yet attempted to write some new output */
    128 Bool NoListenAll;               /* Don't establish any listening sockets */
    129 
    130 static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
    131 Bool RunFromSigStopParent;      /* send SIGSTOP to our own process; Upstart (or
    132                                    equivalent) will send SIGCONT back. */
    133 static char dynamic_display[7]; /* display name */
    134 Bool PartialNetwork;            /* continue even if unable to bind all addrs */
    135 static Pid_t ParentProcess;
    136 
    137 int GrabInProgress = 0;
    138 
    139 static void
    140 EstablishNewConnections(int curconn, int ready, void *data);
    141 
    142 static void
    143 set_poll_client(ClientPtr client);
    144 
    145 static void
    146 set_poll_clients(void);
    147 
    148 static XtransConnInfo *ListenTransConns = NULL;
    149 static int *ListenTransFds = NULL;
    150 static int ListenTransCount;
    151 
    152 static void ErrorConnMax(XtransConnInfo /* trans_conn */ );
    153 
    154 static XtransConnInfo
    155 lookup_trans_conn(int fd)
    156 {
    157     if (ListenTransFds) {
    158         int i;
    159 
    160         for (i = 0; i < ListenTransCount; i++)
    161             if (ListenTransFds[i] == fd)
    162                 return ListenTransConns[i];
    163     }
    164 
    165     return NULL;
    166 }
    167 
    168 /*
    169  * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
    170  *
    171  *  a- The parent process is ignoring SIGUSR1
    172  *
    173  * or
    174  *
    175  *  b- The parent process is expecting a SIGUSR1
    176  *     when the server is ready to accept connections
    177  *
    178  * In the first case, the signal will be harmless, in the second case,
    179  * the signal will be quite useful.
    180  */
    181 static void
    182 InitParentProcess(void)
    183 {
    184 #if !defined(WIN32)
    185     OsSigHandlerPtr handler;
    186 
    187     handler = OsSignal(SIGUSR1, SIG_IGN);
    188     if (handler == SIG_IGN)
    189         RunFromSmartParent = TRUE;
    190     OsSignal(SIGUSR1, handler);
    191     ParentProcess = getppid();
    192 #endif
    193 }
    194 
    195 void
    196 NotifyParentProcess(void)
    197 {
    198 #if !defined(WIN32)
    199     if (displayfd >= 0) {
    200         if (write(displayfd, display, strlen(display)) != strlen(display))
    201             FatalError("Cannot write display number to fd %d\n", displayfd);
    202         if (write(displayfd, "\n", 1) != 1)
    203             FatalError("Cannot write display number to fd %d\n", displayfd);
    204         close(displayfd);
    205         displayfd = -1;
    206     }
    207     if (RunFromSmartParent) {
    208         if (ParentProcess > 1) {
    209             kill(ParentProcess, SIGUSR1);
    210         }
    211     }
    212     if (RunFromSigStopParent)
    213         raise(SIGSTOP);
    214 #ifdef HAVE_SYSTEMD_DAEMON
    215     /* If we have been started as a systemd service, tell systemd that
    216        we are ready. Otherwise sd_notify() won't do anything. */
    217     sd_notify(0, "READY=1");
    218 #endif
    219 #endif
    220 }
    221 
    222 static Bool
    223 TryCreateSocket(int num, int *partial)
    224 {
    225     char port[20];
    226 
    227     snprintf(port, sizeof(port), "%d", num);
    228 
    229     return (_XSERVTransMakeAllCOTSServerListeners(port, partial,
    230                                                   &ListenTransCount,
    231                                                   &ListenTransConns) >= 0);
    232 }
    233 
    234 /*****************
    235  * CreateWellKnownSockets
    236  *    At initialization, create the sockets to listen on for new clients.
    237  *****************/
    238 
    239 void
    240 CreateWellKnownSockets(void)
    241 {
    242     int i;
    243     int partial;
    244 
    245     /* display is initialized to "0" by main(). It is then set to the display
    246      * number if specified on the command line. */
    247 
    248     if (NoListenAll) {
    249         ListenTransCount = 0;
    250     }
    251     else if ((displayfd < 0) || explicit_display) {
    252         if (TryCreateSocket(atoi(display), &partial) &&
    253             ListenTransCount >= 1)
    254             if (!PartialNetwork && partial)
    255                 FatalError ("Failed to establish all listening sockets");
    256     }
    257     else { /* -displayfd and no explicit display number */
    258         Bool found = 0;
    259         for (i = 0; i < 65536 - X_TCP_PORT; i++) {
    260             if (TryCreateSocket(i, &partial) && !partial) {
    261                 found = 1;
    262                 break;
    263             }
    264             else
    265                 CloseWellKnownConnections();
    266         }
    267         if (!found)
    268             FatalError("Failed to find a socket to listen on");
    269         snprintf(dynamic_display, sizeof(dynamic_display), "%d", i);
    270         display = dynamic_display;
    271         LogSetDisplay();
    272     }
    273 
    274     ListenTransFds = xallocarray(ListenTransCount, sizeof (int));
    275     if (ListenTransFds == NULL)
    276         FatalError ("Failed to create listening socket array");
    277 
    278     for (i = 0; i < ListenTransCount; i++) {
    279         int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
    280 
    281         ListenTransFds[i] = fd;
    282         SetNotifyFd(fd, EstablishNewConnections, X_NOTIFY_READ, NULL);
    283 
    284         if (!_XSERVTransIsLocal(ListenTransConns[i]))
    285             DefineSelf (fd);
    286     }
    287 
    288     if (ListenTransCount == 0 && !NoListenAll)
    289         FatalError
    290             ("Cannot establish any listening sockets - Make sure an X server isn't already running");
    291 
    292 #if !defined(WIN32)
    293     OsSignal(SIGPIPE, SIG_IGN);
    294     OsSignal(SIGHUP, AutoResetServer);
    295 #endif
    296     OsSignal(SIGINT, GiveUp);
    297     OsSignal(SIGTERM, GiveUp);
    298     ResetHosts(display);
    299 
    300     InitParentProcess();
    301 
    302 #ifdef XDMCP
    303     XdmcpInit();
    304 #endif
    305 }
    306 
    307 void
    308 ResetWellKnownSockets(void)
    309 {
    310     int i;
    311 
    312     ResetOsBuffers();
    313 
    314     for (i = 0; i < ListenTransCount; i++) {
    315         int status = _XSERVTransResetListener(ListenTransConns[i]);
    316 
    317         if (status != TRANS_RESET_NOOP) {
    318             if (status == TRANS_RESET_FAILURE) {
    319                 /*
    320                  * ListenTransConns[i] freed by xtrans.
    321                  * Remove it from out list.
    322                  */
    323 
    324                 RemoveNotifyFd(ListenTransFds[i]);
    325                 ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
    326                 ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
    327                 ListenTransCount -= 1;
    328                 i -= 1;
    329             }
    330             else if (status == TRANS_RESET_NEW_FD) {
    331                 /*
    332                  * A new file descriptor was allocated (the old one was closed)
    333                  */
    334 
    335                 int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
    336 
    337                 ListenTransFds[i] = newfd;
    338             }
    339         }
    340     }
    341     for (i = 0; i < ListenTransCount; i++)
    342         SetNotifyFd(ListenTransFds[i], EstablishNewConnections, X_NOTIFY_READ,
    343                     NULL);
    344 
    345     ResetAuthorization();
    346     ResetHosts(display);
    347     /*
    348      * restart XDMCP
    349      */
    350 #ifdef XDMCP
    351     XdmcpReset();
    352 #endif
    353 }
    354 
    355 void
    356 CloseWellKnownConnections(void)
    357 {
    358     int i;
    359 
    360     for (i = 0; i < ListenTransCount; i++) {
    361         if (ListenTransConns[i] != NULL) {
    362             _XSERVTransClose(ListenTransConns[i]);
    363             ListenTransConns[i] = NULL;
    364             if (ListenTransFds != NULL)
    365                 RemoveNotifyFd(ListenTransFds[i]);
    366         }
    367     }
    368     ListenTransCount = 0;
    369 }
    370 
    371 static void
    372 AuthAudit(ClientPtr client, Bool letin,
    373           struct sockaddr *saddr, int len,
    374           unsigned int proto_n, char *auth_proto, int auth_id)
    375 {
    376     char addr[128];
    377     char client_uid_string[64];
    378     LocalClientCredRec *lcc;
    379 
    380 #ifdef XSERVER_DTRACE
    381     pid_t client_pid = -1;
    382     zoneid_t client_zid = -1;
    383 #endif
    384 
    385     if (!len)
    386         strlcpy(addr, "local host", sizeof(addr));
    387     else
    388         switch (saddr->sa_family) {
    389         case AF_UNSPEC:
    390 #if defined(UNIXCONN) || defined(LOCALCONN)
    391         case AF_UNIX:
    392 #endif
    393             strlcpy(addr, "local host", sizeof(addr));
    394             break;
    395 #if defined(TCPCONN)
    396         case AF_INET:
    397             snprintf(addr, sizeof(addr), "IP %s",
    398                      inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
    399             break;
    400 #if defined(IPv6) && defined(AF_INET6)
    401         case AF_INET6:{
    402             char ipaddr[INET6_ADDRSTRLEN];
    403 
    404             inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
    405                       ipaddr, sizeof(ipaddr));
    406             snprintf(addr, sizeof(addr), "IP %s", ipaddr);
    407         }
    408             break;
    409 #endif
    410 #endif
    411         default:
    412             strlcpy(addr, "unknown address", sizeof(addr));
    413         }
    414 
    415     if (GetLocalClientCreds(client, &lcc) != -1) {
    416         int slen;               /* length written to client_uid_string */
    417 
    418         strcpy(client_uid_string, " ( ");
    419         slen = 3;
    420 
    421         if (lcc->fieldsSet & LCC_UID_SET) {
    422             snprintf(client_uid_string + slen,
    423                      sizeof(client_uid_string) - slen,
    424                      "uid=%ld ", (long) lcc->euid);
    425             slen = strlen(client_uid_string);
    426         }
    427 
    428         if (lcc->fieldsSet & LCC_GID_SET) {
    429             snprintf(client_uid_string + slen,
    430                      sizeof(client_uid_string) - slen,
    431                      "gid=%ld ", (long) lcc->egid);
    432             slen = strlen(client_uid_string);
    433         }
    434 
    435         if (lcc->fieldsSet & LCC_PID_SET) {
    436 #ifdef XSERVER_DTRACE
    437             client_pid = lcc->pid;
    438 #endif
    439             snprintf(client_uid_string + slen,
    440                      sizeof(client_uid_string) - slen,
    441                      "pid=%ld ", (long) lcc->pid);
    442             slen = strlen(client_uid_string);
    443         }
    444 
    445         if (lcc->fieldsSet & LCC_ZID_SET) {
    446 #ifdef XSERVER_DTRACE
    447             client_zid = lcc->zoneid;
    448 #endif
    449             snprintf(client_uid_string + slen,
    450                      sizeof(client_uid_string) - slen,
    451                      "zoneid=%ld ", (long) lcc->zoneid);
    452             slen = strlen(client_uid_string);
    453         }
    454 
    455         snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
    456                  ")");
    457         FreeLocalClientCreds(lcc);
    458     }
    459     else {
    460         client_uid_string[0] = '\0';
    461     }
    462 
    463 #ifdef XSERVER_DTRACE
    464     XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
    465 #endif
    466     if (auditTrailLevel > 1) {
    467         if (proto_n)
    468             AuditF("client %d %s from %s%s\n  Auth name: %.*s ID: %d\n",
    469                    client->index, letin ? "connected" : "rejected", addr,
    470                    client_uid_string, (int) proto_n, auth_proto, auth_id);
    471         else
    472             AuditF("client %d %s from %s%s\n",
    473                    client->index, letin ? "connected" : "rejected", addr,
    474                    client_uid_string);
    475 
    476     }
    477 }
    478 
    479 XID
    480 AuthorizationIDOfClient(ClientPtr client)
    481 {
    482     if (client->osPrivate)
    483         return ((OsCommPtr) client->osPrivate)->auth_id;
    484     else
    485         return None;
    486 }
    487 
    488 /*****************************************************************
    489  * ClientAuthorized
    490  *
    491  *    Sent by the client at connection setup:
    492  *                typedef struct _xConnClientPrefix {
    493  *                   CARD8	byteOrder;
    494  *                   BYTE	pad;
    495  *                   CARD16	majorVersion, minorVersion;
    496  *                   CARD16	nbytesAuthProto;
    497  *                   CARD16	nbytesAuthString;
    498  *                 } xConnClientPrefix;
    499  *
    500  *     	It is hoped that eventually one protocol will be agreed upon.  In the
    501  *        mean time, a server that implements a different protocol than the
    502  *        client expects, or a server that only implements the host-based
    503  *        mechanism, will simply ignore this information.
    504  *
    505  *****************************************************************/
    506 
    507 const char *
    508 ClientAuthorized(ClientPtr client,
    509                  unsigned int proto_n, char *auth_proto,
    510                  unsigned int string_n, char *auth_string)
    511 {
    512     OsCommPtr priv;
    513     Xtransaddr *from = NULL;
    514     int family;
    515     int fromlen;
    516     XID auth_id;
    517     const char *reason = NULL;
    518     XtransConnInfo trans_conn;
    519 
    520     priv = (OsCommPtr) client->osPrivate;
    521     trans_conn = priv->trans_conn;
    522 
    523     /* Allow any client to connect without authorization on a launchd socket,
    524        because it is securely created -- this prevents a race condition on launch */
    525     if (trans_conn->flags & TRANS_NOXAUTH) {
    526         auth_id = (XID) 0L;
    527     }
    528     else {
    529         auth_id =
    530             CheckAuthorization(proto_n, auth_proto, string_n, auth_string,
    531                                client, &reason);
    532     }
    533 
    534     if (auth_id == (XID) ~0L) {
    535         if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
    536             if (InvalidHost((struct sockaddr *) from, fromlen, client))
    537                 AuthAudit(client, FALSE, (struct sockaddr *) from,
    538                           fromlen, proto_n, auth_proto, auth_id);
    539             else {
    540                 auth_id = (XID) 0;
    541 #ifdef XSERVER_DTRACE
    542                 if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
    543 #else
    544                 if (auditTrailLevel > 1)
    545 #endif
    546                     AuthAudit(client, TRUE,
    547                               (struct sockaddr *) from, fromlen,
    548                               proto_n, auth_proto, auth_id);
    549             }
    550 
    551             free(from);
    552         }
    553 
    554         if (auth_id == (XID) ~0L) {
    555             if (reason)
    556                 return reason;
    557             else
    558                 return "Client is not authorized to connect to Server";
    559         }
    560     }
    561 #ifdef XSERVER_DTRACE
    562     else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
    563 #else
    564     else if (auditTrailLevel > 1)
    565 #endif
    566     {
    567         if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
    568             AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
    569                       proto_n, auth_proto, auth_id);
    570 
    571             free(from);
    572         }
    573     }
    574     priv->auth_id = auth_id;
    575     priv->conn_time = 0;
    576 
    577 #ifdef XDMCP
    578     /* indicate to Xdmcp protocol that we've opened new client */
    579     XdmcpOpenDisplay(priv->fd);
    580 #endif                          /* XDMCP */
    581 
    582     XaceHook(XACE_AUTH_AVAIL, client, auth_id);
    583 
    584     /* At this point, if the client is authorized to change the access control
    585      * list, we should getpeername() information, and add the client to
    586      * the selfhosts list.  It's not really the host machine, but the
    587      * true purpose of the selfhosts list is to see who may change the
    588      * access control list.
    589      */
    590     return ((char *) NULL);
    591 }
    592 
    593 static void
    594 ClientReady(int fd, int xevents, void *data)
    595 {
    596     ClientPtr client = data;
    597 
    598     if (xevents & X_NOTIFY_ERROR) {
    599         CloseDownClient(client);
    600         return;
    601     }
    602     if (xevents & X_NOTIFY_READ)
    603         mark_client_ready(client);
    604     if (xevents & X_NOTIFY_WRITE) {
    605         ospoll_mute(server_poll, fd, X_NOTIFY_WRITE);
    606         NewOutputPending = TRUE;
    607     }
    608 }
    609 
    610 static ClientPtr
    611 AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
    612 {
    613     OsCommPtr oc;
    614     ClientPtr client;
    615 
    616     oc = malloc(sizeof(OsCommRec));
    617     if (!oc)
    618         return NullClient;
    619     oc->trans_conn = trans_conn;
    620     oc->fd = fd;
    621     oc->input = (ConnectionInputPtr) NULL;
    622     oc->output = (ConnectionOutputPtr) NULL;
    623     oc->auth_id = None;
    624     oc->conn_time = conn_time;
    625     oc->flags = 0;
    626     if (!(client = NextAvailableClient((void *) oc))) {
    627         free(oc);
    628         return NullClient;
    629     }
    630     client->local = ComputeLocalClient(client);
    631     ospoll_add(server_poll, fd,
    632                ospoll_trigger_edge,
    633                ClientReady,
    634                client);
    635     set_poll_client(client);
    636 
    637 #ifdef DEBUG
    638     ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
    639            client->index, fd);
    640 #endif
    641 #ifdef XSERVER_DTRACE
    642     XSERVER_CLIENT_CONNECT(client->index, fd);
    643 #endif
    644 
    645     return client;
    646 }
    647 
    648 /*****************
    649  * EstablishNewConnections
    650  *    If anyone is waiting on listened sockets, accept them. Drop pending
    651  *    connections if they've stuck around for more than one minute.
    652  *****************/
    653 #define TimeOutValue 60 * MILLI_PER_SECOND
    654 static void
    655 EstablishNewConnections(int curconn, int ready, void *data)
    656 {
    657     int newconn;       /* fd of new client */
    658     CARD32 connect_time;
    659     int i;
    660     ClientPtr client;
    661     OsCommPtr oc;
    662     XtransConnInfo trans_conn, new_trans_conn;
    663     int status;
    664 
    665     connect_time = GetTimeInMillis();
    666     /* kill off stragglers */
    667     for (i = 1; i < currentMaxClients; i++) {
    668         if ((client = clients[i])) {
    669             oc = (OsCommPtr) (client->osPrivate);
    670             if ((oc && (oc->conn_time != 0) &&
    671                  (connect_time - oc->conn_time) >= TimeOutValue) ||
    672                 (client->noClientException != Success && !client->clientGone))
    673                 CloseDownClient(client);
    674         }
    675     }
    676 
    677     if ((trans_conn = lookup_trans_conn(curconn)) == NULL)
    678         return;
    679 
    680     if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL)
    681         return;
    682 
    683     newconn = _XSERVTransGetConnectionNumber(new_trans_conn);
    684 
    685     _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
    686 
    687     if (trans_conn->flags & TRANS_NOXAUTH)
    688         new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
    689 
    690     if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) {
    691         ErrorConnMax(new_trans_conn);
    692     }
    693     return;
    694 }
    695 
    696 #define NOROOM "Maximum number of clients reached"
    697 
    698 /************
    699  *   ErrorConnMax
    700  *     Fail a connection due to lack of client or file descriptor space
    701  ************/
    702 
    703 static void
    704 ConnMaxNotify(int fd, int events, void *data)
    705 {
    706     XtransConnInfo trans_conn = data;
    707     char order = 0;
    708 
    709     /* try to read the byte-order of the connection */
    710     (void) _XSERVTransRead(trans_conn, &order, 1);
    711     if (order == 'l' || order == 'B' || order == 'r' || order == 'R') {
    712         xConnSetupPrefix csp;
    713         char pad[3] = { 0, 0, 0 };
    714         int whichbyte = 1;
    715         struct iovec iov[3];
    716 
    717         csp.success = xFalse;
    718         csp.lengthReason = sizeof(NOROOM) - 1;
    719         csp.length = (sizeof(NOROOM) + 2) >> 2;
    720         csp.majorVersion = X_PROTOCOL;
    721         csp.minorVersion = X_PROTOCOL_REVISION;
    722         if (((*(char *) &whichbyte) && (order == 'B' || order == 'R')) ||
    723             (!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) {
    724             swaps(&csp.majorVersion);
    725             swaps(&csp.minorVersion);
    726             swaps(&csp.length);
    727         }
    728         iov[0].iov_len = sz_xConnSetupPrefix;
    729         iov[0].iov_base = (char *) &csp;
    730         iov[1].iov_len = csp.lengthReason;
    731         iov[1].iov_base = (void *) NOROOM;
    732         iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
    733         iov[2].iov_base = pad;
    734         (void) _XSERVTransWritev(trans_conn, iov, 3);
    735     }
    736     RemoveNotifyFd(trans_conn->fd);
    737     _XSERVTransClose(trans_conn);
    738 }
    739 
    740 static void
    741 ErrorConnMax(XtransConnInfo trans_conn)
    742 {
    743     if (!SetNotifyFd(trans_conn->fd, ConnMaxNotify, X_NOTIFY_READ, trans_conn))
    744         _XSERVTransClose(trans_conn);
    745 }
    746 
    747 /************
    748  *   CloseDownFileDescriptor:
    749  *     Remove this file descriptor
    750  ************/
    751 
    752 void
    753 CloseDownFileDescriptor(OsCommPtr oc)
    754 {
    755     if (oc->trans_conn) {
    756         int connection = oc->fd;
    757 #ifdef XDMCP
    758         XdmcpCloseDisplay(connection);
    759 #endif
    760         ospoll_remove(server_poll, connection);
    761         _XSERVTransDisconnect(oc->trans_conn);
    762         _XSERVTransClose(oc->trans_conn);
    763         oc->trans_conn = NULL;
    764         oc->fd = -1;
    765     }
    766 }
    767 
    768 /*****************
    769  * CloseDownConnection
    770  *    Delete client from AllClients and free resources
    771  *****************/
    772 
    773 void
    774 CloseDownConnection(ClientPtr client)
    775 {
    776     OsCommPtr oc = (OsCommPtr) client->osPrivate;
    777 
    778     if (FlushCallback)
    779         CallCallbacks(&FlushCallback, client);
    780 
    781     if (oc->output)
    782 	FlushClient(client, oc, (char *) NULL, 0);
    783     CloseDownFileDescriptor(oc);
    784     FreeOsBuffers(oc);
    785     free(client->osPrivate);
    786     client->osPrivate = (void *) NULL;
    787     if (auditTrailLevel > 1)
    788         AuditF("client %d disconnected\n", client->index);
    789 }
    790 
    791 struct notify_fd {
    792     int mask;
    793     NotifyFdProcPtr notify;
    794     void *data;
    795 };
    796 
    797 /*****************
    798  * HandleNotifyFd
    799  *    A poll callback to be called when the registered
    800  *    file descriptor is ready.
    801  *****************/
    802 
    803 static void
    804 HandleNotifyFd(int fd, int xevents, void *data)
    805 {
    806     struct notify_fd *n = data;
    807     n->notify(fd, xevents, n->data);
    808 }
    809 
    810 /*****************
    811  * SetNotifyFd
    812  *    Registers a callback to be invoked when the specified
    813  *    file descriptor becomes readable.
    814  *****************/
    815 
    816 Bool
    817 SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
    818 {
    819     struct notify_fd *n;
    820 
    821     n = ospoll_data(server_poll, fd);
    822     if (!n) {
    823         if (mask == 0)
    824             return TRUE;
    825 
    826         n = calloc(1, sizeof (struct notify_fd));
    827         if (!n)
    828             return FALSE;
    829         ospoll_add(server_poll, fd,
    830                    ospoll_trigger_level,
    831                    HandleNotifyFd,
    832                    n);
    833     }
    834 
    835     if (mask == 0) {
    836         ospoll_remove(server_poll, fd);
    837         free(n);
    838     } else {
    839         int listen = mask & ~n->mask;
    840         int mute = n->mask & ~mask;
    841 
    842         if (listen)
    843             ospoll_listen(server_poll, fd, listen);
    844         if (mute)
    845             ospoll_mute(server_poll, fd, mute);
    846         n->mask = mask;
    847         n->data = data;
    848         n->notify = notify;
    849     }
    850 
    851     return TRUE;
    852 }
    853 
    854 /*****************
    855  * OnlyListenToOneClient:
    856  *    Only accept requests from  one client.  Continue to handle new
    857  *    connections, but don't take any protocol requests from the new
    858  *    ones.  Note that if GrabInProgress is set, EstablishNewConnections
    859  *    needs to put new clients into SavedAllSockets and SavedAllClients.
    860  *    Note also that there is no timeout for this in the protocol.
    861  *    This routine is "undone" by ListenToAllClients()
    862  *****************/
    863 
    864 int
    865 OnlyListenToOneClient(ClientPtr client)
    866 {
    867     int rc;
    868 
    869     rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
    870     if (rc != Success)
    871         return rc;
    872 
    873     if (!GrabInProgress) {
    874         GrabInProgress = client->index;
    875         set_poll_clients();
    876     }
    877 
    878     return rc;
    879 }
    880 
    881 /****************
    882  * ListenToAllClients:
    883  *    Undoes OnlyListentToOneClient()
    884  ****************/
    885 
    886 void
    887 ListenToAllClients(void)
    888 {
    889     if (GrabInProgress) {
    890         GrabInProgress = 0;
    891         set_poll_clients();
    892     }
    893 }
    894 
    895 /****************
    896  * IgnoreClient
    897  *    Removes one client from input masks.
    898  *    Must have corresponding call to AttendClient.
    899  ****************/
    900 
    901 void
    902 IgnoreClient(ClientPtr client)
    903 {
    904     OsCommPtr oc = (OsCommPtr) client->osPrivate;
    905 
    906     client->ignoreCount++;
    907     if (client->ignoreCount > 1)
    908         return;
    909 
    910     isItTimeToYield = TRUE;
    911     mark_client_not_ready(client);
    912 
    913     oc->flags |= OS_COMM_IGNORED;
    914     set_poll_client(client);
    915 }
    916 
    917 /****************
    918  * AttendClient
    919  *    Adds one client back into the input masks.
    920  ****************/
    921 
    922 void
    923 AttendClient(ClientPtr client)
    924 {
    925     OsCommPtr oc = (OsCommPtr) client->osPrivate;
    926 
    927     if (client->clientGone) {
    928         /*
    929          * client is gone, so any pending requests will be dropped and its
    930          * ignore count doesn't matter.
    931          */
    932         return;
    933     }
    934 
    935     client->ignoreCount--;
    936     if (client->ignoreCount)
    937         return;
    938 
    939     oc->flags &= ~OS_COMM_IGNORED;
    940     set_poll_client(client);
    941     if (listen_to_client(client))
    942         mark_client_ready(client);
    943     else {
    944         /* grab active, mark ready when grab goes away */
    945         mark_client_saved_ready(client);
    946     }
    947 }
    948 
    949 /* make client impervious to grabs; assume only executing client calls this */
    950 
    951 void
    952 MakeClientGrabImpervious(ClientPtr client)
    953 {
    954     OsCommPtr oc = (OsCommPtr) client->osPrivate;
    955 
    956     oc->flags |= OS_COMM_GRAB_IMPERVIOUS;
    957     set_poll_client(client);
    958 
    959     if (ServerGrabCallback) {
    960         ServerGrabInfoRec grabinfo;
    961 
    962         grabinfo.client = client;
    963         grabinfo.grabstate = CLIENT_IMPERVIOUS;
    964         CallCallbacks(&ServerGrabCallback, &grabinfo);
    965     }
    966 }
    967 
    968 /* make client pervious to grabs; assume only executing client calls this */
    969 
    970 void
    971 MakeClientGrabPervious(ClientPtr client)
    972 {
    973     OsCommPtr oc = (OsCommPtr) client->osPrivate;
    974 
    975     oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS;
    976     set_poll_client(client);
    977     isItTimeToYield = TRUE;
    978 
    979     if (ServerGrabCallback) {
    980         ServerGrabInfoRec grabinfo;
    981 
    982         grabinfo.client = client;
    983         grabinfo.grabstate = CLIENT_PERVIOUS;
    984         CallCallbacks(&ServerGrabCallback, &grabinfo);
    985     }
    986 }
    987 
    988 /* Add a fd (from launchd or similar) to our listeners */
    989 void
    990 ListenOnOpenFD(int fd, int noxauth)
    991 {
    992     char port[256];
    993     XtransConnInfo ciptr;
    994     const char *display_env = getenv("DISPLAY");
    995 
    996     if (display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) {
    997         /* Make the path the launchd socket if our DISPLAY is set right */
    998         strcpy(port, display_env);
    999     }
   1000     else {
   1001         /* Just some default so things don't break and die. */
   1002         snprintf(port, sizeof(port), ":%d", atoi(display));
   1003     }
   1004 
   1005     /* Make our XtransConnInfo
   1006      * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
   1007      */
   1008     ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
   1009     if (ciptr == NULL) {
   1010         ErrorF("Got NULL while trying to Reopen listen port.\n");
   1011         return;
   1012     }
   1013 
   1014     if (noxauth)
   1015         ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
   1016 
   1017     /* Allocate space to store it */
   1018     ListenTransFds =
   1019         xnfreallocarray(ListenTransFds, ListenTransCount + 1, sizeof(int));
   1020     ListenTransConns =
   1021         xnfreallocarray(ListenTransConns, ListenTransCount + 1,
   1022                         sizeof(XtransConnInfo));
   1023 
   1024     /* Store it */
   1025     ListenTransConns[ListenTransCount] = ciptr;
   1026     ListenTransFds[ListenTransCount] = fd;
   1027 
   1028     SetNotifyFd(fd, EstablishNewConnections, X_NOTIFY_READ, NULL);
   1029 
   1030     /* Increment the count */
   1031     ListenTransCount++;
   1032 }
   1033 
   1034 /* based on TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) */
   1035 Bool
   1036 AddClientOnOpenFD(int fd)
   1037 {
   1038     XtransConnInfo ciptr;
   1039     CARD32 connect_time;
   1040     char port[20];
   1041 
   1042     snprintf(port, sizeof(port), ":%d", atoi(display));
   1043     ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
   1044     if (ciptr == NULL)
   1045         return FALSE;
   1046 
   1047     _XSERVTransSetOption(ciptr, TRANS_NONBLOCKING, 1);
   1048     ciptr->flags |= TRANS_NOXAUTH;
   1049 
   1050     connect_time = GetTimeInMillis();
   1051 
   1052     if (!AllocNewConnection(ciptr, fd, connect_time)) {
   1053         ErrorConnMax(ciptr);
   1054         return FALSE;
   1055     }
   1056 
   1057     return TRUE;
   1058 }
   1059 
   1060 Bool
   1061 listen_to_client(ClientPtr client)
   1062 {
   1063     OsCommPtr oc = (OsCommPtr) client->osPrivate;
   1064 
   1065     if (oc->flags & OS_COMM_IGNORED)
   1066         return FALSE;
   1067 
   1068     if (!GrabInProgress)
   1069         return TRUE;
   1070 
   1071     if (client->index == GrabInProgress)
   1072         return TRUE;
   1073 
   1074     if (oc->flags & OS_COMM_GRAB_IMPERVIOUS)
   1075         return TRUE;
   1076 
   1077     return FALSE;
   1078 }
   1079 
   1080 static void
   1081 set_poll_client(ClientPtr client)
   1082 {
   1083     OsCommPtr oc = (OsCommPtr) client->osPrivate;
   1084 
   1085     if (oc->trans_conn) {
   1086         if (listen_to_client(client))
   1087             ospoll_listen(server_poll, oc->trans_conn->fd, X_NOTIFY_READ);
   1088         else
   1089             ospoll_mute(server_poll, oc->trans_conn->fd, X_NOTIFY_READ);
   1090     }
   1091 }
   1092 
   1093 static void
   1094 set_poll_clients(void)
   1095 {
   1096     int i;
   1097 
   1098     for (i = 1; i < currentMaxClients; i++) {
   1099         ClientPtr client = clients[i];
   1100         if (client && !client->clientGone)
   1101             set_poll_client(client);
   1102     }
   1103 }