Apply a patch for fixing TDIS-5990 (CVE-2013-1940 allow physically proximate attacker...
[framework/uifw/xorg/server/xorg-server.git] / os / connection.c
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, CheckConnections, AddEnabledDevice,
51  *      RemoveEnabledDevice, 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) || defined(STREAMSCONN)
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 <X11/Xpoll.h>
107 #include "opaque.h"
108 #include "dixstruct.h"
109 #include "xace.h"
110
111 #define Pid_t pid_t
112
113 #ifdef HAVE_GETPEERUCRED
114 #include <ucred.h>
115 #include <zone.h>
116 #endif
117
118 #ifdef XSERVER_DTRACE
119 #include <sys/types.h>
120 typedef const char *string;
121
122 #ifndef HAVE_GETPEERUCRED
123 #define zoneid_t int
124 #endif
125 #include "../dix/Xserver-dtrace.h"
126 #endif
127
128 static int lastfdesc;           /* maximum file descriptor */
129
130 fd_set WellKnownConnections;    /* Listener mask */
131 fd_set EnabledDevices;          /* mask for input devices that are on */
132 fd_set AllSockets;              /* select on this */
133 fd_set AllClients;              /* available clients */
134 fd_set LastSelectMask;          /* mask returned from last select call */
135 fd_set ClientsWithInput;        /* clients with FULL requests in buffer */
136 fd_set ClientsWriteBlocked;     /* clients who cannot receive output */
137 fd_set OutputPending;           /* clients with reply/event data ready to go */
138 int MaxClients = 0;
139 Bool NewOutputPending;          /* not yet attempted to write some new output */
140 Bool AnyClientsWriteBlocked;    /* true if some client blocked on write */
141
142 static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
143 Bool RunFromSigStopParent;      /* send SIGSTOP to our own process; Upstart (or
144                                    equivalent) will send SIGCONT back. */
145 static char dynamic_display[7]; /* display name */
146 Bool PartialNetwork;            /* continue even if unable to bind all addrs */
147 static Pid_t ParentProcess;
148
149 static Bool debug_conns = FALSE;
150
151 fd_set IgnoredClientsWithInput;
152 static fd_set GrabImperviousClients;
153 static fd_set SavedAllClients;
154 static fd_set SavedAllSockets;
155 static fd_set SavedClientsWithInput;
156 int GrabInProgress = 0;
157
158 #if !defined(WIN32)
159 int *ConnectionTranslation = NULL;
160 #else
161 /*
162  * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is
163  * not even a known maximum value, so use something quite arbitrary for now.
164  * Do storage is a hash table of size 256. Collisions are handled in a linked
165  * list.
166  */
167
168 #undef MAXSOCKS
169 #define MAXSOCKS 500
170 #undef MAXSELECT
171 #ifdef _F_EXCLUDE_NON_MASK_SELECTED_FD_FROM_MAXCLIENTS_
172 #define MAXSELECT 1024
173 #else
174 #define MAXSELECT 500
175 #endif
176
177 struct _ct_node {
178     struct _ct_node *next;
179     int key;
180     int value;
181 };
182
183 struct _ct_node *ct_head[256];
184
185 void
186 InitConnectionTranslation(void)
187 {
188     memset(ct_head, 0, sizeof(ct_head));
189 }
190
191 int
192 GetConnectionTranslation(int conn)
193 {
194     struct _ct_node *node = ct_head[conn & 0xff];
195
196     while (node != NULL) {
197         if (node->key == conn)
198             return node->value;
199         node = node->next;
200     }
201     return 0;
202 }
203
204 void
205 SetConnectionTranslation(int conn, int client)
206 {
207     struct _ct_node **node = ct_head + (conn & 0xff);
208
209     if (client == 0) {          /* remove entry */
210         while (*node != NULL) {
211             if ((*node)->key == conn) {
212                 struct _ct_node *temp = *node;
213
214                 *node = (*node)->next;
215                 free(temp);
216                 return;
217             }
218             node = &((*node)->next);
219         }
220         return;
221     }
222     else {
223         while (*node != NULL) {
224             if ((*node)->key == conn) {
225                 (*node)->value = client;
226                 return;
227             }
228             node = &((*node)->next);
229         }
230         *node = malloc(sizeof(struct _ct_node));
231         (*node)->next = NULL;
232         (*node)->key = conn;
233         (*node)->value = client;
234         return;
235     }
236 }
237
238 void
239 ClearConnectionTranslation(void)
240 {
241     unsigned i;
242
243     for (i = 0; i < 256; i++) {
244         struct _ct_node *node = ct_head[i];
245
246         while (node != NULL) {
247             struct _ct_node *temp = node;
248
249             node = node->next;
250             free(temp);
251         }
252     }
253 }
254 #endif
255
256 static XtransConnInfo *ListenTransConns = NULL;
257 static int *ListenTransFds = NULL;
258 static int ListenTransCount;
259
260 static void ErrorConnMax(XtransConnInfo /* trans_conn */ );
261
262 static XtransConnInfo
263 lookup_trans_conn(int fd)
264 {
265     if (ListenTransFds) {
266         int i;
267
268         for (i = 0; i < ListenTransCount; i++)
269             if (ListenTransFds[i] == fd)
270                 return ListenTransConns[i];
271     }
272
273     return NULL;
274 }
275
276 /* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */
277
278 void
279 InitConnectionLimits(void)
280 {
281     lastfdesc = -1;
282
283 #ifndef __CYGWIN__
284
285 #if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX)
286     lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
287 #endif
288
289 #ifdef HAVE_GETDTABLESIZE
290     if (lastfdesc < 0)
291         lastfdesc = getdtablesize() - 1;
292 #endif
293
294 #ifdef _NFILE
295     if (lastfdesc < 0)
296         lastfdesc = _NFILE - 1;
297 #endif
298
299 #endif                          /* __CYGWIN__ */
300
301 #ifndef _F_EXCLUDE_NON_MASK_SELECTED_FD_FROM_MAXCLIENTS_
302     /* This is the fallback */
303     if (lastfdesc < 0)
304         lastfdesc = MAXSOCKS;
305
306     if (lastfdesc > MAXSELECT)
307         lastfdesc = MAXSELECT;
308
309     if (lastfdesc > MAXCLIENTS) {
310         lastfdesc = MAXCLIENTS;
311         if (debug_conns)
312             ErrorF("REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS);
313     }
314     MaxClients = lastfdesc;
315 #else
316     lastfdesc = MAXSELECT;
317     MaxClients = MAXCLIENTS;
318 #endif
319
320 #ifdef DEBUG
321     ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients);
322 #endif
323
324 #if !defined(WIN32)
325     if (!ConnectionTranslation)
326         ConnectionTranslation = (int *) xnfalloc(sizeof(int) * (lastfdesc + 1));
327 #else
328     InitConnectionTranslation();
329 #endif
330 }
331
332 /*
333  * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
334  *
335  *  a- The parent process is ignoring SIGUSR1
336  *
337  * or
338  *
339  *  b- The parent process is expecting a SIGUSR1
340  *     when the server is ready to accept connections
341  *
342  * In the first case, the signal will be harmless, in the second case,
343  * the signal will be quite useful.
344  */
345 static void
346 InitParentProcess(void)
347 {
348 #if !defined(WIN32)
349     OsSigHandlerPtr handler;
350
351     handler = OsSignal(SIGUSR1, SIG_IGN);
352     if (handler == SIG_IGN)
353         RunFromSmartParent = TRUE;
354     OsSignal(SIGUSR1, handler);
355     ParentProcess = getppid();
356 #endif
357 }
358
359 void
360 NotifyParentProcess(void)
361 {
362 #if !defined(WIN32)
363     if (dynamic_display[0]) {
364         write(displayfd, dynamic_display, strlen(dynamic_display));
365         write(displayfd, "\n", 1);
366         close(displayfd);
367     }
368     if (RunFromSmartParent) {
369         if (ParentProcess > 1) {
370             kill(ParentProcess, SIGUSR1);
371         }
372     }
373     if (RunFromSigStopParent)
374         raise(SIGSTOP);
375 #endif
376 }
377
378 static Bool
379 TryCreateSocket(int num, int *partial)
380 {
381     char port[20];
382
383     snprintf(port, sizeof(port), "%d", num);
384
385     return (_XSERVTransMakeAllCOTSServerListeners(port, partial,
386                                                   &ListenTransCount,
387                                                   &ListenTransConns) >= 0);
388 }
389
390 /*****************
391  * CreateWellKnownSockets
392  *    At initialization, create the sockets to listen on for new clients.
393  *****************/
394
395 void
396 CreateWellKnownSockets(void)
397 {
398     int i;
399     int partial;
400
401     FD_ZERO(&AllSockets);
402     FD_ZERO(&AllClients);
403     FD_ZERO(&LastSelectMask);
404     FD_ZERO(&ClientsWithInput);
405
406 #if !defined(WIN32)
407 #ifndef _F_EXCLUDE_NON_MASK_SELECTED_FD_FROM_MAXCLIENTS_
408     for (i = 0; i < MaxClients; i++)
409 #else
410     for (i = 0; i < lastfdesc; i++)
411 #endif
412         ConnectionTranslation[i] = 0;
413 #else
414     ClearConnectionTranslation();
415 #endif
416
417     FD_ZERO(&WellKnownConnections);
418
419     /* display is initialized to "0" by main(). It is then set to the display
420      * number if specified on the command line, or to NULL when the -displayfd
421      * option is used. */
422     if (display) {
423         if (TryCreateSocket(atoi(display), &partial) &&
424             ListenTransCount >= 1)
425             if (!PartialNetwork && partial)
426                 FatalError ("Failed to establish all listening sockets");
427     }
428     else { /* -displayfd */
429         Bool found = 0;
430         for (i = 0; i < 65535 - X_TCP_PORT; i++) {
431             if (TryCreateSocket(i, &partial) && !partial) {
432                 found = 1;
433                 break;
434             }
435             else
436                 CloseWellKnownConnections();
437         }
438         if (!found)
439             FatalError("Failed to find a socket to listen on");
440         snprintf(dynamic_display, sizeof(dynamic_display), "%d", i);
441         display = dynamic_display;
442     }
443
444     ListenTransFds = malloc(ListenTransCount * sizeof (int));
445
446     for (i = 0; i < ListenTransCount; i++) {
447         int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
448
449         ListenTransFds[i] = fd;
450         FD_SET(fd, &WellKnownConnections);
451
452         if (!_XSERVTransIsLocal(ListenTransConns[i]))
453             DefineSelf (fd);
454     }
455
456     if (!XFD_ANYSET(&WellKnownConnections))
457         FatalError
458             ("Cannot establish any listening sockets - Make sure an X server isn't already running");
459 #if !defined(WIN32)
460     OsSignal(SIGPIPE, SIG_IGN);
461     OsSignal(SIGHUP, AutoResetServer);
462 #endif
463     OsSignal(SIGINT, GiveUp);
464     OsSignal(SIGTERM, GiveUp);
465     XFD_COPYSET(&WellKnownConnections, &AllSockets);
466     ResetHosts(display);
467
468     InitParentProcess();
469
470 #ifdef XDMCP
471     XdmcpInit();
472 #endif
473 }
474
475 void
476 ResetWellKnownSockets(void)
477 {
478     int i;
479
480     ResetOsBuffers();
481
482     for (i = 0; i < ListenTransCount; i++) {
483         int status = _XSERVTransResetListener(ListenTransConns[i]);
484
485         if (status != TRANS_RESET_NOOP) {
486             if (status == TRANS_RESET_FAILURE) {
487                 /*
488                  * ListenTransConns[i] freed by xtrans.
489                  * Remove it from out list.
490                  */
491
492                 FD_CLR(ListenTransFds[i], &WellKnownConnections);
493                 ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
494                 ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
495                 ListenTransCount -= 1;
496                 i -= 1;
497             }
498             else if (status == TRANS_RESET_NEW_FD) {
499                 /*
500                  * A new file descriptor was allocated (the old one was closed)
501                  */
502
503                 int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
504
505                 FD_CLR(ListenTransFds[i], &WellKnownConnections);
506                 ListenTransFds[i] = newfd;
507                 FD_SET(newfd, &WellKnownConnections);
508             }
509         }
510     }
511
512     ResetAuthorization();
513     ResetHosts(display);
514     /*
515      * restart XDMCP
516      */
517 #ifdef XDMCP
518     XdmcpReset();
519 #endif
520 }
521
522 void
523 CloseWellKnownConnections(void)
524 {
525     int i;
526
527     for (i = 0; i < ListenTransCount; i++)
528         _XSERVTransClose(ListenTransConns[i]);
529 }
530
531 static void
532 AuthAudit(ClientPtr client, Bool letin,
533           struct sockaddr *saddr, int len,
534           unsigned int proto_n, char *auth_proto, int auth_id)
535 {
536     char addr[128];
537     char client_uid_string[64];
538     LocalClientCredRec *lcc;
539
540 #ifdef XSERVER_DTRACE
541     pid_t client_pid = -1;
542     zoneid_t client_zid = -1;
543 #endif
544
545     if (!len)
546         strlcpy(addr, "local host", sizeof(addr));
547     else
548         switch (saddr->sa_family) {
549         case AF_UNSPEC:
550 #if defined(UNIXCONN) || defined(LOCALCONN)
551         case AF_UNIX:
552 #endif
553             strlcpy(addr, "local host", sizeof(addr));
554             break;
555 #if defined(TCPCONN) || defined(STREAMSCONN)
556         case AF_INET:
557             snprintf(addr, sizeof(addr), "IP %s",
558                      inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
559             break;
560 #if defined(IPv6) && defined(AF_INET6)
561         case AF_INET6:{
562             char ipaddr[INET6_ADDRSTRLEN];
563
564             inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
565                       ipaddr, sizeof(ipaddr));
566             snprintf(addr, sizeof(addr), "IP %s", ipaddr);
567         }
568             break;
569 #endif
570 #endif
571         default:
572             strlcpy(addr, "unknown address", sizeof(addr));
573         }
574
575     if (GetLocalClientCreds(client, &lcc) != -1) {
576         int slen;               /* length written to client_uid_string */
577
578         strcpy(client_uid_string, " ( ");
579         slen = 3;
580
581         if (lcc->fieldsSet & LCC_UID_SET) {
582             snprintf(client_uid_string + slen,
583                      sizeof(client_uid_string) - slen,
584                      "uid=%ld ", (long) lcc->euid);
585             slen = strlen(client_uid_string);
586         }
587
588         if (lcc->fieldsSet & LCC_GID_SET) {
589             snprintf(client_uid_string + slen,
590                      sizeof(client_uid_string) - slen,
591                      "gid=%ld ", (long) lcc->egid);
592             slen = strlen(client_uid_string);
593         }
594
595         if (lcc->fieldsSet & LCC_PID_SET) {
596 #ifdef XSERVER_DTRACE
597             client_pid = lcc->pid;
598 #endif
599             snprintf(client_uid_string + slen,
600                      sizeof(client_uid_string) - slen,
601                      "pid=%ld ", (long) lcc->pid);
602             slen = strlen(client_uid_string);
603         }
604
605         if (lcc->fieldsSet & LCC_ZID_SET) {
606 #ifdef XSERVER_DTRACE
607             client_zid = lcc->zoneid;
608 #endif
609             snprintf(client_uid_string + slen,
610                      sizeof(client_uid_string) - slen,
611                      "zoneid=%ld ", (long) lcc->zoneid);
612             slen = strlen(client_uid_string);
613         }
614
615         snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
616                  ")");
617         FreeLocalClientCreds(lcc);
618     }
619     else {
620         client_uid_string[0] = '\0';
621     }
622
623 #ifdef XSERVER_DTRACE
624     XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
625 #endif
626     if (auditTrailLevel > 1) {
627         if (proto_n)
628             AuditF("client %d %s from %s%s\n  Auth name: %.*s ID: %d\n",
629                    client->index, letin ? "connected" : "rejected", addr,
630                    client_uid_string, (int) proto_n, auth_proto, auth_id);
631         else
632             AuditF("client %d %s from %s%s\n",
633                    client->index, letin ? "connected" : "rejected", addr,
634                    client_uid_string);
635
636     }
637 }
638
639 XID
640 AuthorizationIDOfClient(ClientPtr client)
641 {
642     if (client->osPrivate)
643         return ((OsCommPtr) client->osPrivate)->auth_id;
644     else
645         return None;
646 }
647
648 /*****************************************************************
649  * ClientAuthorized
650  *
651  *    Sent by the client at connection setup:
652  *                typedef struct _xConnClientPrefix {
653  *                   CARD8      byteOrder;
654  *                   BYTE       pad;
655  *                   CARD16     majorVersion, minorVersion;
656  *                   CARD16     nbytesAuthProto;    
657  *                   CARD16     nbytesAuthString;   
658  *                 } xConnClientPrefix;
659  *
660  *      It is hoped that eventually one protocol will be agreed upon.  In the
661  *        mean time, a server that implements a different protocol than the
662  *        client expects, or a server that only implements the host-based
663  *        mechanism, will simply ignore this information.
664  *
665  *****************************************************************/
666
667 const char *
668 ClientAuthorized(ClientPtr client,
669                  unsigned int proto_n, char *auth_proto,
670                  unsigned int string_n, char *auth_string)
671 {
672     OsCommPtr priv;
673     Xtransaddr *from = NULL;
674     int family;
675     int fromlen;
676     XID auth_id;
677     const char *reason = NULL;
678     XtransConnInfo trans_conn;
679
680     priv = (OsCommPtr) client->osPrivate;
681     trans_conn = priv->trans_conn;
682
683     /* Allow any client to connect without authorization on a launchd socket,
684        because it is securely created -- this prevents a race condition on launch */
685     if (trans_conn->flags & TRANS_NOXAUTH) {
686         auth_id = (XID) 0L;
687     }
688     else {
689         auth_id =
690             CheckAuthorization(proto_n, auth_proto, string_n, auth_string,
691                                client, &reason);
692     }
693
694     if (auth_id == (XID) ~0L) {
695         if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
696             if (InvalidHost((struct sockaddr *) from, fromlen, client))
697                 AuthAudit(client, FALSE, (struct sockaddr *) from,
698                           fromlen, proto_n, auth_proto, auth_id);
699             else {
700                 auth_id = (XID) 0;
701 #ifdef XSERVER_DTRACE
702                 if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
703 #else
704                 if (auditTrailLevel > 1)
705 #endif
706                     AuthAudit(client, TRUE,
707                               (struct sockaddr *) from, fromlen,
708                               proto_n, auth_proto, auth_id);
709             }
710
711             free(from);
712         }
713
714         if (auth_id == (XID) ~0L) {
715             if (reason)
716                 return reason;
717             else
718                 return "Client is not authorized to connect to Server";
719         }
720     }
721 #ifdef XSERVER_DTRACE
722     else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
723 #else
724     else if (auditTrailLevel > 1)
725 #endif
726     {
727         if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
728             AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
729                       proto_n, auth_proto, auth_id);
730
731             free(from);
732         }
733     }
734     priv->auth_id = auth_id;
735     priv->conn_time = 0;
736
737 #ifdef XDMCP
738     /* indicate to Xdmcp protocol that we've opened new client */
739     XdmcpOpenDisplay(priv->fd);
740 #endif                          /* XDMCP */
741
742     XaceHook(XACE_AUTH_AVAIL, client, auth_id);
743
744     /* At this point, if the client is authorized to change the access control
745      * list, we should getpeername() information, and add the client to
746      * the selfhosts list.  It's not really the host machine, but the
747      * true purpose of the selfhosts list is to see who may change the
748      * access control list.
749      */
750     return ((char *) NULL);
751 }
752
753 static ClientPtr
754 AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
755 {
756     OsCommPtr oc;
757     ClientPtr client;
758
759     if (
760 #ifndef WIN32
761            fd >= lastfdesc
762 #else
763            XFD_SETCOUNT(&AllClients) >= MaxClients
764 #endif
765         )
766         return NullClient;
767     oc = malloc(sizeof(OsCommRec));
768     if (!oc)
769         return NullClient;
770     oc->trans_conn = trans_conn;
771     oc->fd = fd;
772     oc->input = (ConnectionInputPtr) NULL;
773     oc->output = (ConnectionOutputPtr) NULL;
774     oc->auth_id = None;
775     oc->conn_time = conn_time;
776     if (!(client = NextAvailableClient((pointer) oc))) {
777         free(oc);
778         return NullClient;
779     }
780     oc->local_client = ComputeLocalClient(client);
781 #if !defined(WIN32)
782     ConnectionTranslation[fd] = client->index;
783 #else
784     SetConnectionTranslation(fd, client->index);
785 #endif
786     if (GrabInProgress) {
787         FD_SET(fd, &SavedAllClients);
788         FD_SET(fd, &SavedAllSockets);
789     }
790     else {
791         FD_SET(fd, &AllClients);
792         FD_SET(fd, &AllSockets);
793     }
794
795 #ifdef DEBUG
796     ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
797            client->index, fd);
798 #endif
799 #ifdef XSERVER_DTRACE
800     XSERVER_CLIENT_CONNECT(client->index, fd);
801 #endif
802
803     return client;
804 }
805
806 /*****************
807  * EstablishNewConnections
808  *    If anyone is waiting on listened sockets, accept them.
809  *    Returns a mask with indices of new clients.  Updates AllClients
810  *    and AllSockets.
811  *****************/
812
813  /*ARGSUSED*/ Bool
814 EstablishNewConnections(ClientPtr clientUnused, pointer closure)
815 {
816     fd_set readyconnections;    /* set of listeners that are ready */
817     int curconn;                /* fd of listener that's ready */
818     register int newconn;       /* fd of new client */
819     CARD32 connect_time;
820     register int i;
821     register ClientPtr client;
822     register OsCommPtr oc;
823     fd_set tmask;
824
825     XFD_ANDSET(&tmask, (fd_set *) closure, &WellKnownConnections);
826     XFD_COPYSET(&tmask, &readyconnections);
827     if (!XFD_ANYSET(&readyconnections))
828         return TRUE;
829     connect_time = GetTimeInMillis();
830     /* kill off stragglers */
831     for (i = 1; i < currentMaxClients; i++) {
832         if ((client = clients[i])) {
833             oc = (OsCommPtr) (client->osPrivate);
834             if ((oc && (oc->conn_time != 0) &&
835                  (connect_time - oc->conn_time) >= TimeOutValue) ||
836                 (client->noClientException != Success && !client->clientGone))
837                 CloseDownClient(client);
838         }
839     }
840 #ifndef WIN32
841     for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
842         while (readyconnections.fds_bits[i])
843 #else
844     for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++)
845 #endif
846     {
847         XtransConnInfo trans_conn, new_trans_conn;
848         int status;
849
850 #ifndef WIN32
851         curconn = mffs(readyconnections.fds_bits[i]) - 1;
852         readyconnections.fds_bits[i] &= ~((fd_mask) 1 << curconn);
853         curconn += (i * (sizeof(fd_mask) * 8));
854 #else
855         curconn = XFD_FD(&readyconnections, i);
856 #endif
857
858         if ((trans_conn = lookup_trans_conn(curconn)) == NULL)
859             continue;
860
861         if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL)
862             continue;
863
864         newconn = _XSERVTransGetConnectionNumber(new_trans_conn);
865
866         if (newconn < lastfdesc) {
867             int clientid;
868
869 #if !defined(WIN32)
870             clientid = ConnectionTranslation[newconn];
871 #else
872             clientid = GetConnectionTranslation(newconn);
873 #endif
874             if (clientid && (client = clients[clientid]))
875                 CloseDownClient(client);
876         }
877
878         _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
879
880         if (trans_conn->flags & TRANS_NOXAUTH)
881             new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
882
883         if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) {
884             ErrorConnMax(new_trans_conn);
885             _XSERVTransClose(new_trans_conn);
886         }
887     }
888 #ifndef WIN32
889 }
890 #endif
891 return TRUE;
892 }
893
894 #define NOROOM "Maximum number of clients reached"
895
896 /************
897  *   ErrorConnMax
898  *     Fail a connection due to lack of client or file descriptor space
899  ************/
900
901 #define BOTIMEOUT 200           /* in milliseconds */
902
903 static void
904 ErrorConnMax(XtransConnInfo trans_conn)
905 {
906     int fd = _XSERVTransGetConnectionNumber(trans_conn);
907     xConnSetupPrefix csp;
908     char pad[3] = { 0, 0, 0 };
909     struct iovec iov[3];
910     char byteOrder = 0;
911     int whichbyte = 1;
912     struct timeval waittime;
913     fd_set mask;
914
915     /* if these seems like a lot of trouble to go to, it probably is */
916     waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND;
917     waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
918         (1000000 / MILLI_PER_SECOND);
919     FD_ZERO(&mask);
920     FD_SET(fd, &mask);
921     (void) Select(fd + 1, &mask, NULL, NULL, &waittime);
922     /* try to read the byte-order of the connection */
923     (void) _XSERVTransRead(trans_conn, &byteOrder, 1);
924     if ((byteOrder == 'l') || (byteOrder == 'B')) {
925         csp.success = xFalse;
926         csp.lengthReason = sizeof(NOROOM) - 1;
927         csp.length = (sizeof(NOROOM) + 2) >> 2;
928         csp.majorVersion = X_PROTOCOL;
929         csp.minorVersion = X_PROTOCOL_REVISION;
930         if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
931             (!(*(char *) &whichbyte) && (byteOrder == 'l'))) {
932             swaps(&csp.majorVersion);
933             swaps(&csp.minorVersion);
934             swaps(&csp.length);
935         }
936         iov[0].iov_len = sz_xConnSetupPrefix;
937         iov[0].iov_base = (char *) &csp;
938         iov[1].iov_len = csp.lengthReason;
939         iov[1].iov_base = NOROOM;
940         iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
941         iov[2].iov_base = pad;
942         (void) _XSERVTransWritev(trans_conn, iov, 3);
943     }
944 }
945
946 /************
947  *   CloseDownFileDescriptor:
948  *     Remove this file descriptor and it's I/O buffers, etc.
949  ************/
950
951 static void
952 CloseDownFileDescriptor(OsCommPtr oc)
953 {
954     int connection = oc->fd;
955
956     if (oc->trans_conn) {
957         _XSERVTransDisconnect(oc->trans_conn);
958         _XSERVTransClose(oc->trans_conn);
959     }
960 #ifndef WIN32
961     ConnectionTranslation[connection] = 0;
962 #else
963     SetConnectionTranslation(connection, 0);
964 #endif
965     FD_CLR(connection, &AllSockets);
966     FD_CLR(connection, &AllClients);
967     FD_CLR(connection, &ClientsWithInput);
968     FD_CLR(connection, &GrabImperviousClients);
969     if (GrabInProgress) {
970         FD_CLR(connection, &SavedAllSockets);
971         FD_CLR(connection, &SavedAllClients);
972         FD_CLR(connection, &SavedClientsWithInput);
973     }
974     FD_CLR(connection, &ClientsWriteBlocked);
975     if (!XFD_ANYSET(&ClientsWriteBlocked))
976         AnyClientsWriteBlocked = FALSE;
977     FD_CLR(connection, &OutputPending);
978 }
979
980 /*****************
981  * CheckConnections
982  *    Some connection has died, go find which one and shut it down 
983  *    The file descriptor has been closed, but is still in AllClients.
984  *    If would truly be wonderful if select() would put the bogus
985  *    file descriptors in the exception mask, but nooooo.  So we have
986  *    to check each and every socket individually.
987  *****************/
988
989 void
990 CheckConnections(void)
991 {
992 #ifndef WIN32
993     fd_mask mask;
994 #endif
995     fd_set tmask;
996     int curclient, curoff;
997     int i;
998     struct timeval notime;
999     int r;
1000
1001 #ifdef WIN32
1002     fd_set savedAllClients;
1003 #endif
1004
1005     notime.tv_sec = 0;
1006     notime.tv_usec = 0;
1007
1008 #ifndef WIN32
1009     for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
1010         mask = AllClients.fds_bits[i];
1011         while (mask) {
1012             curoff = mffs(mask) - 1;
1013             curclient = curoff + (i * (sizeof(fd_mask) * 8));
1014             FD_ZERO(&tmask);
1015             FD_SET(curclient, &tmask);
1016             do {
1017                 r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
1018             } while (r < 0 && (errno == EINTR || errno == EAGAIN));
1019             if (r < 0)
1020                 if (ConnectionTranslation[curclient] > 0)
1021                     CloseDownClient(clients[ConnectionTranslation[curclient]]);
1022             mask &= ~((fd_mask) 1 << curoff);
1023         }
1024     }
1025 #else
1026     XFD_COPYSET(&AllClients, &savedAllClients);
1027     for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) {
1028         curclient = XFD_FD(&savedAllClients, i);
1029         FD_ZERO(&tmask);
1030         FD_SET(curclient, &tmask);
1031         do {
1032             r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
1033         } while (r < 0 && (errno == EINTR || errno == EAGAIN));
1034         if (r < 0)
1035             if (GetConnectionTranslation(curclient) > 0)
1036                 CloseDownClient(clients[GetConnectionTranslation(curclient)]);
1037     }
1038 #endif
1039 }
1040
1041 /*****************
1042  * CloseDownConnection
1043  *    Delete client from AllClients and free resources 
1044  *****************/
1045
1046 void
1047 CloseDownConnection(ClientPtr client)
1048 {
1049     OsCommPtr oc = (OsCommPtr) client->osPrivate;
1050
1051     if (FlushCallback)
1052         CallCallbacks(&FlushCallback, NULL);
1053
1054     if (oc->output && oc->output->count)
1055         FlushClient(client, oc, (char *) NULL, 0);
1056 #ifdef XDMCP
1057     XdmcpCloseDisplay(oc->fd);
1058 #endif
1059     CloseDownFileDescriptor(oc);
1060     FreeOsBuffers(oc);
1061     free(client->osPrivate);
1062     client->osPrivate = (pointer) NULL;
1063     if (auditTrailLevel > 1)
1064         AuditF("client %d disconnected\n", client->index);
1065 }
1066
1067 void
1068 AddGeneralSocket(int fd)
1069 {
1070     FD_SET(fd, &AllSockets);
1071     if (GrabInProgress)
1072         FD_SET(fd, &SavedAllSockets);
1073 }
1074
1075 void
1076 AddEnabledDevice(int fd)
1077 {
1078     FD_SET(fd, &EnabledDevices);
1079     AddGeneralSocket(fd);
1080 }
1081
1082 void
1083 RemoveGeneralSocket(int fd)
1084 {
1085     FD_CLR(fd, &AllSockets);
1086     if (GrabInProgress)
1087         FD_CLR(fd, &SavedAllSockets);
1088 }
1089
1090 void
1091 RemoveEnabledDevice(int fd)
1092 {
1093     FD_CLR(fd, &EnabledDevices);
1094     RemoveGeneralSocket(fd);
1095 }
1096
1097 /*****************
1098  * OnlyListenToOneClient:
1099  *    Only accept requests from  one client.  Continue to handle new
1100  *    connections, but don't take any protocol requests from the new
1101  *    ones.  Note that if GrabInProgress is set, EstablishNewConnections
1102  *    needs to put new clients into SavedAllSockets and SavedAllClients.
1103  *    Note also that there is no timeout for this in the protocol.
1104  *    This routine is "undone" by ListenToAllClients()
1105  *****************/
1106
1107 int
1108 OnlyListenToOneClient(ClientPtr client)
1109 {
1110     OsCommPtr oc = (OsCommPtr) client->osPrivate;
1111     int rc, connection = oc->fd;
1112
1113     rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
1114     if (rc != Success)
1115         return rc;
1116
1117     if (!GrabInProgress) {
1118         XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
1119         XFD_ANDSET(&ClientsWithInput,
1120                    &ClientsWithInput, &GrabImperviousClients);
1121         if (FD_ISSET(connection, &SavedClientsWithInput)) {
1122             FD_CLR(connection, &SavedClientsWithInput);
1123             FD_SET(connection, &ClientsWithInput);
1124         }
1125         XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
1126         XFD_COPYSET(&AllSockets, &SavedAllSockets);
1127         XFD_COPYSET(&AllClients, &SavedAllClients);
1128         XFD_UNSET(&AllSockets, &AllClients);
1129         XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
1130         FD_SET(connection, &AllClients);
1131         XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
1132         GrabInProgress = client->index;
1133     }
1134     return rc;
1135 }
1136
1137 /****************
1138  * ListenToAllClients:
1139  *    Undoes OnlyListentToOneClient()
1140  ****************/
1141
1142 void
1143 ListenToAllClients(void)
1144 {
1145     if (GrabInProgress) {
1146         XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
1147         XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
1148         XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
1149         GrabInProgress = 0;
1150     }
1151 }
1152
1153 /****************
1154  * IgnoreClient
1155  *    Removes one client from input masks.
1156  *    Must have cooresponding call to AttendClient.
1157  ****************/
1158
1159 void
1160 IgnoreClient(ClientPtr client)
1161 {
1162     OsCommPtr oc = (OsCommPtr) client->osPrivate;
1163     int connection = oc->fd;
1164
1165     client->ignoreCount++;
1166     if (client->ignoreCount > 1)
1167         return;
1168
1169     isItTimeToYield = TRUE;
1170     if (!GrabInProgress || FD_ISSET(connection, &AllClients)) {
1171         if (FD_ISSET(connection, &ClientsWithInput))
1172             FD_SET(connection, &IgnoredClientsWithInput);
1173         else
1174             FD_CLR(connection, &IgnoredClientsWithInput);
1175         FD_CLR(connection, &ClientsWithInput);
1176         FD_CLR(connection, &AllSockets);
1177         FD_CLR(connection, &AllClients);
1178         FD_CLR(connection, &LastSelectMask);
1179     }
1180     else {
1181         if (FD_ISSET(connection, &SavedClientsWithInput))
1182             FD_SET(connection, &IgnoredClientsWithInput);
1183         else
1184             FD_CLR(connection, &IgnoredClientsWithInput);
1185         FD_CLR(connection, &SavedClientsWithInput);
1186         FD_CLR(connection, &SavedAllSockets);
1187         FD_CLR(connection, &SavedAllClients);
1188     }
1189 }
1190
1191 /****************
1192  * AttendClient
1193  *    Adds one client back into the input masks.
1194  ****************/
1195
1196 void
1197 AttendClient(ClientPtr client)
1198 {
1199 #ifdef _F_CHECK_NULL_CLIENT_
1200     OsCommPtr oc;
1201     int connection;
1202
1203     if (client == NULL ||client->osPrivate == NULL)
1204         return;
1205
1206     oc = (OsCommPtr)client->osPrivate;
1207     connection = oc->fd;
1208 #else
1209     OsCommPtr oc = (OsCommPtr) client->osPrivate;
1210     int connection = oc->fd;
1211 #endif
1212     client->ignoreCount--;
1213     if (client->ignoreCount)
1214         return;
1215
1216     if (!GrabInProgress || GrabInProgress == client->index ||
1217         FD_ISSET(connection, &GrabImperviousClients)) {
1218         FD_SET(connection, &AllClients);
1219         FD_SET(connection, &AllSockets);
1220         FD_SET(connection, &LastSelectMask);
1221         if (FD_ISSET(connection, &IgnoredClientsWithInput))
1222             FD_SET(connection, &ClientsWithInput);
1223     }
1224     else {
1225         FD_SET(connection, &SavedAllClients);
1226         FD_SET(connection, &SavedAllSockets);
1227         if (FD_ISSET(connection, &IgnoredClientsWithInput))
1228             FD_SET(connection, &SavedClientsWithInput);
1229     }
1230 }
1231
1232 /* make client impervious to grabs; assume only executing client calls this */
1233
1234 void
1235 MakeClientGrabImpervious(ClientPtr client)
1236 {
1237     OsCommPtr oc = (OsCommPtr) client->osPrivate;
1238     int connection = oc->fd;
1239
1240     FD_SET(connection, &GrabImperviousClients);
1241
1242     if (ServerGrabCallback) {
1243         ServerGrabInfoRec grabinfo;
1244
1245         grabinfo.client = client;
1246         grabinfo.grabstate = CLIENT_IMPERVIOUS;
1247         CallCallbacks(&ServerGrabCallback, &grabinfo);
1248     }
1249 }
1250
1251 /* make client pervious to grabs; assume only executing client calls this */
1252
1253 void
1254 MakeClientGrabPervious(ClientPtr client)
1255 {
1256     OsCommPtr oc = (OsCommPtr) client->osPrivate;
1257     int connection = oc->fd;
1258
1259     FD_CLR(connection, &GrabImperviousClients);
1260     if (GrabInProgress && (GrabInProgress != client->index)) {
1261         if (FD_ISSET(connection, &ClientsWithInput)) {
1262             FD_SET(connection, &SavedClientsWithInput);
1263             FD_CLR(connection, &ClientsWithInput);
1264         }
1265         FD_CLR(connection, &AllSockets);
1266         FD_CLR(connection, &AllClients);
1267         isItTimeToYield = TRUE;
1268     }
1269
1270     if (ServerGrabCallback) {
1271         ServerGrabInfoRec grabinfo;
1272
1273         grabinfo.client = client;
1274         grabinfo.grabstate = CLIENT_PERVIOUS;
1275         CallCallbacks(&ServerGrabCallback, &grabinfo);
1276     }
1277 }
1278
1279 #ifdef XQUARTZ
1280 /* Add a fd (from launchd) to our listeners */
1281 void
1282 ListenOnOpenFD(int fd, int noxauth)
1283 {
1284     char port[256];
1285     XtransConnInfo ciptr;
1286     const char *display_env = getenv("DISPLAY");
1287
1288     if (display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) {
1289         /* Make the path the launchd socket if our DISPLAY is set right */
1290         strcpy(port, display_env);
1291     }
1292     else {
1293         /* Just some default so things don't break and die. */
1294         snprintf(port, sizeof(port), ":%d", atoi(display));
1295     }
1296
1297     /* Make our XtransConnInfo
1298      * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
1299      */
1300     ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1301     if (ciptr == NULL) {
1302         ErrorF("Got NULL while trying to Reopen launchd port.\n");
1303         return;
1304     }
1305
1306     if (noxauth)
1307         ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
1308
1309     /* Allocate space to store it */
1310     ListenTransFds =
1311         (int *) realloc(ListenTransFds, (ListenTransCount + 1) * sizeof(int));
1312     ListenTransConns =
1313         (XtransConnInfo *) realloc(ListenTransConns,
1314                                    (ListenTransCount +
1315                                     1) * sizeof(XtransConnInfo));
1316
1317     /* Store it */
1318     ListenTransConns[ListenTransCount] = ciptr;
1319     ListenTransFds[ListenTransCount] = fd;
1320
1321     FD_SET(fd, &WellKnownConnections);
1322     FD_SET(fd, &AllSockets);
1323
1324     /* Increment the count */
1325     ListenTransCount++;
1326
1327     /* This *might* not be needed... /shrug */
1328     ResetAuthorization();
1329     ResetHosts(display);
1330 #ifdef XDMCP
1331     XdmcpReset();
1332 #endif
1333 }
1334
1335 #endif