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