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