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