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