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