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