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 #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 129 struct ospoll *server_poll; 130 131 Bool NewOutputPending; /* not yet attempted to write some new output */ 132 Bool NoListenAll; /* Don't establish any listening sockets */ 133 134 static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ 135 Bool RunFromSigStopParent; /* send SIGSTOP to our own process; Upstart (or 136 equivalent) will send SIGCONT back. */ 137 static char dynamic_display[7]; /* display name */ 138 Bool PartialNetwork; /* continue even if unable to bind all addrs */ 139 static Pid_t ParentProcess; 140 141 int GrabInProgress = 0; 142 143 static void 144 EstablishNewConnections(int curconn, int ready, void *data); 145 146 static void 147 set_poll_client(ClientPtr client); 148 149 static void 150 set_poll_clients(void); 151 152 static XtransConnInfo *ListenTransConns = NULL; 153 static int *ListenTransFds = NULL; 154 static int ListenTransCount; 155 156 static void ErrorConnMax(XtransConnInfo /* trans_conn */ ); 157 158 static XtransConnInfo 159 lookup_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 */ 185 static void 186 InitParentProcess(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 199 void 200 NotifyParentProcess(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 226 static Bool 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 244 CreateWellKnownSockets(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 _XSERVTransSetOption(ListenTransConns[i], TRANS_CLOSEONEXEC, 0); 287 SetNotifyFd(fd, EstablishNewConnections, X_NOTIFY_READ, NULL); 288 289 if (!_XSERVTransIsLocal(ListenTransConns[i])) 290 DefineSelf (fd); 291 } 292 293 if (ListenTransCount == 0 && !NoListenAll) 294 FatalError 295 ("Cannot establish any listening sockets - Make sure an X server isn't already running"); 296 297 #if !defined(WIN32) 298 OsSignal(SIGPIPE, SIG_IGN); 299 OsSignal(SIGHUP, AutoResetServer); 300 #endif 301 OsSignal(SIGINT, GiveUp); 302 OsSignal(SIGTERM, GiveUp); 303 ResetHosts(display); 304 305 InitParentProcess(); 306 307 #ifdef XDMCP 308 XdmcpInit(); 309 #endif 310 } 311 312 void 313 ResetWellKnownSockets(void) 314 { 315 int i; 316 317 ResetOsBuffers(); 318 319 for (i = 0; i < ListenTransCount; i++) { 320 int status = _XSERVTransResetListener(ListenTransConns[i]); 321 322 if (status != TRANS_RESET_NOOP) { 323 if (status == TRANS_RESET_FAILURE) { 324 /* 325 * ListenTransConns[i] freed by xtrans. 326 * Remove it from out list. 327 */ 328 329 RemoveNotifyFd(ListenTransFds[i]); 330 ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; 331 ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; 332 ListenTransCount -= 1; 333 i -= 1; 334 } 335 else if (status == TRANS_RESET_NEW_FD) { 336 /* 337 * A new file descriptor was allocated (the old one was closed) 338 */ 339 340 int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]); 341 342 ListenTransFds[i] = newfd; 343 } 344 } 345 } 346 for (i = 0; i < ListenTransCount; i++) 347 SetNotifyFd(ListenTransFds[i], EstablishNewConnections, X_NOTIFY_READ, 348 NULL); 349 350 ResetAuthorization(); 351 ResetHosts(display); 352 /* 353 * restart XDMCP 354 */ 355 #ifdef XDMCP 356 XdmcpReset(); 357 #endif 358 } 359 360 void 361 CloseWellKnownConnections(void) 362 { 363 int i; 364 365 for (i = 0; i < ListenTransCount; i++) { 366 if (ListenTransConns[i] != NULL) { 367 _XSERVTransClose(ListenTransConns[i]); 368 ListenTransConns[i] = NULL; 369 if (ListenTransFds != NULL) 370 RemoveNotifyFd(ListenTransFds[i]); 371 } 372 } 373 ListenTransCount = 0; 374 } 375 376 static void 377 AuthAudit(ClientPtr client, Bool letin, 378 struct sockaddr *saddr, int len, 379 unsigned int proto_n, char *auth_proto, int auth_id) 380 { 381 char addr[128]; 382 char client_uid_string[64]; 383 LocalClientCredRec *lcc; 384 385 #ifdef XSERVER_DTRACE 386 pid_t client_pid = -1; 387 zoneid_t client_zid = -1; 388 #endif 389 390 if (!len) 391 strlcpy(addr, "local host", sizeof(addr)); 392 else 393 switch (saddr->sa_family) { 394 case AF_UNSPEC: 395 #if defined(UNIXCONN) || defined(LOCALCONN) 396 case AF_UNIX: 397 #endif 398 strlcpy(addr, "local host", sizeof(addr)); 399 break; 400 #if defined(TCPCONN) 401 case AF_INET: 402 snprintf(addr, sizeof(addr), "IP %s", 403 inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr)); 404 break; 405 #if defined(IPv6) && defined(AF_INET6) 406 case AF_INET6:{ 407 char ipaddr[INET6_ADDRSTRLEN]; 408 409 inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr, 410 ipaddr, sizeof(ipaddr)); 411 snprintf(addr, sizeof(addr), "IP %s", ipaddr); 412 } 413 break; 414 #endif 415 #endif 416 default: 417 strlcpy(addr, "unknown address", sizeof(addr)); 418 } 419 420 if (GetLocalClientCreds(client, &lcc) != -1) { 421 int slen; /* length written to client_uid_string */ 422 423 strcpy(client_uid_string, " ( "); 424 slen = 3; 425 426 if (lcc->fieldsSet & LCC_UID_SET) { 427 snprintf(client_uid_string + slen, 428 sizeof(client_uid_string) - slen, 429 "uid=%ld ", (long) lcc->euid); 430 slen = strlen(client_uid_string); 431 } 432 433 if (lcc->fieldsSet & LCC_GID_SET) { 434 snprintf(client_uid_string + slen, 435 sizeof(client_uid_string) - slen, 436 "gid=%ld ", (long) lcc->egid); 437 slen = strlen(client_uid_string); 438 } 439 440 if (lcc->fieldsSet & LCC_PID_SET) { 441 #ifdef XSERVER_DTRACE 442 client_pid = lcc->pid; 443 #endif 444 snprintf(client_uid_string + slen, 445 sizeof(client_uid_string) - slen, 446 "pid=%ld ", (long) lcc->pid); 447 slen = strlen(client_uid_string); 448 } 449 450 if (lcc->fieldsSet & LCC_ZID_SET) { 451 #ifdef XSERVER_DTRACE 452 client_zid = lcc->zoneid; 453 #endif 454 snprintf(client_uid_string + slen, 455 sizeof(client_uid_string) - slen, 456 "zoneid=%ld ", (long) lcc->zoneid); 457 slen = strlen(client_uid_string); 458 } 459 460 snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen, 461 ")"); 462 FreeLocalClientCreds(lcc); 463 } 464 else { 465 client_uid_string[0] = '\0'; 466 } 467 468 #ifdef XSERVER_DTRACE 469 XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid); 470 #endif 471 if (auditTrailLevel > 1) { 472 if (proto_n) 473 AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n", 474 client->index, letin ? "connected" : "rejected", addr, 475 client_uid_string, (int) proto_n, auth_proto, auth_id); 476 else 477 AuditF("client %d %s from %s%s\n", 478 client->index, letin ? "connected" : "rejected", addr, 479 client_uid_string); 480 481 } 482 } 483 484 XID 485 AuthorizationIDOfClient(ClientPtr client) 486 { 487 if (client->osPrivate) 488 return ((OsCommPtr) client->osPrivate)->auth_id; 489 else 490 return None; 491 } 492 493 /***************************************************************** 494 * ClientAuthorized 495 * 496 * Sent by the client at connection setup: 497 * typedef struct _xConnClientPrefix { 498 * CARD8 byteOrder; 499 * BYTE pad; 500 * CARD16 majorVersion, minorVersion; 501 * CARD16 nbytesAuthProto; 502 * CARD16 nbytesAuthString; 503 * } xConnClientPrefix; 504 * 505 * It is hoped that eventually one protocol will be agreed upon. In the 506 * mean time, a server that implements a different protocol than the 507 * client expects, or a server that only implements the host-based 508 * mechanism, will simply ignore this information. 509 * 510 *****************************************************************/ 511 512 const char * 513 ClientAuthorized(ClientPtr client, 514 unsigned int proto_n, char *auth_proto, 515 unsigned int string_n, char *auth_string) 516 { 517 OsCommPtr priv; 518 Xtransaddr *from = NULL; 519 int family; 520 int fromlen; 521 XID auth_id; 522 const char *reason = NULL; 523 XtransConnInfo trans_conn; 524 525 priv = (OsCommPtr) client->osPrivate; 526 trans_conn = priv->trans_conn; 527 528 /* Allow any client to connect without authorization on a launchd socket, 529 because it is securely created -- this prevents a race condition on launch */ 530 if (trans_conn->flags & TRANS_NOXAUTH) { 531 auth_id = (XID) 0L; 532 } 533 else { 534 auth_id = 535 CheckAuthorization(proto_n, auth_proto, string_n, auth_string, 536 client, &reason); 537 } 538 539 if (auth_id == (XID) ~0L) { 540 if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) { 541 if (InvalidHost((struct sockaddr *) from, fromlen, client)) 542 AuthAudit(client, FALSE, (struct sockaddr *) from, 543 fromlen, proto_n, auth_proto, auth_id); 544 else { 545 auth_id = (XID) 0; 546 #ifdef XSERVER_DTRACE 547 if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) 548 #else 549 if (auditTrailLevel > 1) 550 #endif 551 AuthAudit(client, TRUE, 552 (struct sockaddr *) from, fromlen, 553 proto_n, auth_proto, auth_id); 554 } 555 556 free(from); 557 } 558 559 if (auth_id == (XID) ~0L) { 560 if (reason) 561 return reason; 562 else 563 return "Client is not authorized to connect to Server"; 564 } 565 } 566 #ifdef XSERVER_DTRACE 567 else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) 568 #else 569 else if (auditTrailLevel > 1) 570 #endif 571 { 572 if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) { 573 AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen, 574 proto_n, auth_proto, auth_id); 575 576 free(from); 577 } 578 } 579 priv->auth_id = auth_id; 580 priv->conn_time = 0; 581 582 #ifdef XDMCP 583 /* indicate to Xdmcp protocol that we've opened new client */ 584 XdmcpOpenDisplay(priv->fd); 585 #endif /* XDMCP */ 586 587 XaceHook(XACE_AUTH_AVAIL, client, auth_id); 588 589 /* At this point, if the client is authorized to change the access control 590 * list, we should getpeername() information, and add the client to 591 * the selfhosts list. It's not really the host machine, but the 592 * true purpose of the selfhosts list is to see who may change the 593 * access control list. 594 */ 595 return ((char *) NULL); 596 } 597 598 static void 599 ClientReady(int fd, int xevents, void *data) 600 { 601 ClientPtr client = data; 602 603 if (xevents & X_NOTIFY_ERROR) { 604 CloseDownClient(client); 605 return; 606 } 607 if (xevents & X_NOTIFY_READ) 608 mark_client_ready(client); 609 if (xevents & X_NOTIFY_WRITE) { 610 ospoll_mute(server_poll, fd, X_NOTIFY_WRITE); 611 NewOutputPending = TRUE; 612 } 613 } 614 615 static ClientPtr 616 AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time) 617 { 618 OsCommPtr oc; 619 ClientPtr client; 620 621 oc = malloc(sizeof(OsCommRec)); 622 if (!oc) 623 return NullClient; 624 oc->trans_conn = trans_conn; 625 oc->fd = fd; 626 oc->input = (ConnectionInputPtr) NULL; 627 oc->output = (ConnectionOutputPtr) NULL; 628 oc->auth_id = None; 629 oc->conn_time = conn_time; 630 oc->flags = 0; 631 if (!(client = NextAvailableClient((void *) oc))) { 632 free(oc); 633 return NullClient; 634 } 635 client->local = ComputeLocalClient(client); 636 ospoll_add(server_poll, fd, 637 ospoll_trigger_edge, 638 ClientReady, 639 client); 640 set_poll_client(client); 641 642 #ifdef DEBUG 643 ErrorF("AllocNewConnection: client index = %d, socket fd = %d, local = %d\n", 644 client->index, fd, client->local); 645 #endif 646 #ifdef XSERVER_DTRACE 647 XSERVER_CLIENT_CONNECT(client->index, fd); 648 #endif 649 650 return client; 651 } 652 653 /***************** 654 * EstablishNewConnections 655 * If anyone is waiting on listened sockets, accept them. Drop pending 656 * connections if they've stuck around for more than one minute. 657 *****************/ 658 #define TimeOutValue 60 * MILLI_PER_SECOND 659 static void 660 EstablishNewConnections(int curconn, int ready, void *data) 661 { 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; 684 685 if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL) 686 return; 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; 699 } 700 701 #define NOROOM "Maximum number of clients reached" 702 703 /************ 704 * ErrorConnMax 705 * Fail a connection due to lack of client or file descriptor space 706 ************/ 707 708 static void 709 ConnMaxNotify(int fd, int events, void *data) 710 { 711 XtransConnInfo trans_conn = data; 712 char order = 0; 713 714 /* try to read the byte-order of the connection */ 715 (void) _XSERVTransRead(trans_conn, &order, 1); 716 if (order == 'l' || order == 'B' || order == 'r' || order == 'R') { 717 xConnSetupPrefix csp; 718 char pad[3] = { 0, 0, 0 }; 719 int whichbyte = 1; 720 struct iovec iov[3]; 721 722 csp.success = xFalse; 723 csp.lengthReason = sizeof(NOROOM) - 1; 724 csp.length = (sizeof(NOROOM) + 2) >> 2; 725 csp.majorVersion = X_PROTOCOL; 726 csp.minorVersion = X_PROTOCOL_REVISION; 727 if (((*(char *) &whichbyte) && (order == 'B' || order == 'R')) || 728 (!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) { 729 swaps(&csp.majorVersion); 730 swaps(&csp.minorVersion); 731 swaps(&csp.length); 732 } 733 iov[0].iov_len = sz_xConnSetupPrefix; 734 iov[0].iov_base = (char *) &csp; 735 iov[1].iov_len = csp.lengthReason; 736 iov[1].iov_base = (void *) NOROOM; 737 iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; 738 iov[2].iov_base = pad; 739 (void) _XSERVTransWritev(trans_conn, iov, 3); 740 } 741 RemoveNotifyFd(trans_conn->fd); 742 _XSERVTransClose(trans_conn); 743 } 744 745 static void 746 ErrorConnMax(XtransConnInfo trans_conn) 747 { 748 if (!SetNotifyFd(trans_conn->fd, ConnMaxNotify, X_NOTIFY_READ, trans_conn)) 749 _XSERVTransClose(trans_conn); 750 } 751 752 /************ 753 * CloseDownFileDescriptor: 754 * Remove this file descriptor 755 ************/ 756 757 void 758 CloseDownFileDescriptor(OsCommPtr oc) 759 { 760 if (oc->trans_conn) { 761 int connection = oc->fd; 762 #ifdef XDMCP 763 XdmcpCloseDisplay(connection); 764 #endif 765 ospoll_remove(server_poll, connection); 766 _XSERVTransDisconnect(oc->trans_conn); 767 _XSERVTransClose(oc->trans_conn); 768 oc->trans_conn = NULL; 769 oc->fd = -1; 770 } 771 } 772 773 /***************** 774 * CloseDownConnection 775 * Delete client from AllClients and free resources 776 *****************/ 777 778 void 779 CloseDownConnection(ClientPtr client) 780 { 781 OsCommPtr oc = (OsCommPtr) client->osPrivate; 782 783 if (FlushCallback) 784 CallCallbacks(&FlushCallback, client); 785 786 if (oc->output) 787 FlushClient(client, oc, (char *) NULL, 0); 788 CloseDownFileDescriptor(oc); 789 FreeOsBuffers(oc); 790 free(client->osPrivate); 791 client->osPrivate = (void *) NULL; 792 if (auditTrailLevel > 1) 793 AuditF("client %d disconnected\n", client->index); 794 } 795 796 struct notify_fd { 797 int mask; 798 NotifyFdProcPtr notify; 799 void *data; 800 }; 801 802 /***************** 803 * HandleNotifyFd 804 * A poll callback to be called when the registered 805 * file descriptor is ready. 806 *****************/ 807 808 static void 809 HandleNotifyFd(int fd, int xevents, void *data) 810 { 811 struct notify_fd *n = data; 812 n->notify(fd, xevents, n->data); 813 } 814 815 /***************** 816 * SetNotifyFd 817 * Registers a callback to be invoked when the specified 818 * file descriptor becomes readable. 819 *****************/ 820 821 Bool 822 SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data) 823 { 824 struct notify_fd *n; 825 826 n = ospoll_data(server_poll, fd); 827 if (!n) { 828 if (mask == 0) 829 return TRUE; 830 831 n = calloc(1, sizeof (struct notify_fd)); 832 if (!n) 833 return FALSE; 834 ospoll_add(server_poll, fd, 835 ospoll_trigger_level, 836 HandleNotifyFd, 837 n); 838 } 839 840 if (mask == 0) { 841 ospoll_remove(server_poll, fd); 842 free(n); 843 } else { 844 int listen = mask & ~n->mask; 845 int mute = n->mask & ~mask; 846 847 if (listen) 848 ospoll_listen(server_poll, fd, listen); 849 if (mute) 850 ospoll_mute(server_poll, fd, mute); 851 n->mask = mask; 852 n->data = data; 853 n->notify = notify; 854 } 855 856 return TRUE; 857 } 858 859 /***************** 860 * OnlyListenToOneClient: 861 * Only accept requests from one client. Continue to handle new 862 * connections, but don't take any protocol requests from the new 863 * ones. Note that if GrabInProgress is set, EstablishNewConnections 864 * needs to put new clients into SavedAllSockets and SavedAllClients. 865 * Note also that there is no timeout for this in the protocol. 866 * This routine is "undone" by ListenToAllClients() 867 *****************/ 868 869 int 870 OnlyListenToOneClient(ClientPtr client) 871 { 872 int rc; 873 874 rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess); 875 if (rc != Success) 876 return rc; 877 878 if (!GrabInProgress) { 879 GrabInProgress = client->index; 880 set_poll_clients(); 881 } 882 883 return rc; 884 } 885 886 /**************** 887 * ListenToAllClients: 888 * Undoes OnlyListentToOneClient() 889 ****************/ 890 891 void 892 ListenToAllClients(void) 893 { 894 if (GrabInProgress) { 895 GrabInProgress = 0; 896 set_poll_clients(); 897 } 898 } 899 900 /**************** 901 * IgnoreClient 902 * Removes one client from input masks. 903 * Must have corresponding call to AttendClient. 904 ****************/ 905 906 void 907 IgnoreClient(ClientPtr client) 908 { 909 OsCommPtr oc = (OsCommPtr) client->osPrivate; 910 911 client->ignoreCount++; 912 if (client->ignoreCount > 1) 913 return; 914 915 isItTimeToYield = TRUE; 916 mark_client_not_ready(client); 917 918 oc->flags |= OS_COMM_IGNORED; 919 set_poll_client(client); 920 } 921 922 /**************** 923 * AttendClient 924 * Adds one client back into the input masks. 925 ****************/ 926 927 void 928 AttendClient(ClientPtr client) 929 { 930 OsCommPtr oc = (OsCommPtr) client->osPrivate; 931 932 if (client->clientGone) { 933 /* 934 * client is gone, so any pending requests will be dropped and its 935 * ignore count doesn't matter. 936 */ 937 return; 938 } 939 940 client->ignoreCount--; 941 if (client->ignoreCount) 942 return; 943 944 oc->flags &= ~OS_COMM_IGNORED; 945 set_poll_client(client); 946 if (listen_to_client(client)) 947 mark_client_ready(client); 948 else { 949 /* grab active, mark ready when grab goes away */ 950 mark_client_saved_ready(client); 951 } 952 } 953 954 /* make client impervious to grabs; assume only executing client calls this */ 955 956 void 957 MakeClientGrabImpervious(ClientPtr client) 958 { 959 OsCommPtr oc = (OsCommPtr) client->osPrivate; 960 961 oc->flags |= OS_COMM_GRAB_IMPERVIOUS; 962 set_poll_client(client); 963 964 if (ServerGrabCallback) { 965 ServerGrabInfoRec grabinfo; 966 967 grabinfo.client = client; 968 grabinfo.grabstate = CLIENT_IMPERVIOUS; 969 CallCallbacks(&ServerGrabCallback, &grabinfo); 970 } 971 } 972 973 /* make client pervious to grabs; assume only executing client calls this */ 974 975 void 976 MakeClientGrabPervious(ClientPtr client) 977 { 978 OsCommPtr oc = (OsCommPtr) client->osPrivate; 979 980 oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS; 981 set_poll_client(client); 982 isItTimeToYield = TRUE; 983 984 if (ServerGrabCallback) { 985 ServerGrabInfoRec grabinfo; 986 987 grabinfo.client = client; 988 grabinfo.grabstate = CLIENT_PERVIOUS; 989 CallCallbacks(&ServerGrabCallback, &grabinfo); 990 } 991 } 992 993 /* Add a fd (from launchd or similar) to our listeners */ 994 void 995 ListenOnOpenFD(int fd, int noxauth) 996 { 997 char port[PATH_MAX]; 998 XtransConnInfo ciptr; 999 const char *display_env = getenv("DISPLAY"); 1000 1001 /* First check if display_env matches a <absolute path to unix socket>[.<screen number>] scheme (eg: launchd) */ 1002 if (display_env && display_env[0] == '/') { 1003 struct stat sbuf; 1004 1005 strlcpy(port, display_env, sizeof(port)); 1006 1007 /* If the path exists, we don't have do do anything else. 1008 * If it doesn't, we need to check for a .<screen number> to strip off and recheck. 1009 */ 1010 if (0 != stat(port, &sbuf)) { 1011 char *dot = strrchr(port, '.'); 1012 if (dot) { 1013 *dot = '\0'; 1014 1015 if (0 != stat(port, &sbuf)) { 1016 display_env = NULL; 1017 } 1018 } else { 1019 display_env = NULL; 1020 } 1021 } 1022 } 1023 1024 if (!display_env) { 1025 /* Just some default so things don't break and die. */ 1026 snprintf(port, sizeof(port), ":%d", atoi(display)); 1027 } 1028 1029 /* Make our XtransConnInfo 1030 * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c 1031 */ 1032 ciptr = _XSERVTransReopenCOTSServer(5, fd, port); 1033 if (ciptr == NULL) { 1034 ErrorF("Got NULL while trying to Reopen listen port.\n"); 1035 return; 1036 } 1037 1038 if (noxauth) 1039 ciptr->flags = ciptr->flags | TRANS_NOXAUTH; 1040 1041 /* Allocate space to store it */ 1042 ListenTransFds = 1043 xnfreallocarray(ListenTransFds, ListenTransCount + 1, sizeof(int)); 1044 ListenTransConns = 1045 xnfreallocarray(ListenTransConns, ListenTransCount + 1, 1046 sizeof(XtransConnInfo)); 1047 1048 /* Store it */ 1049 ListenTransConns[ListenTransCount] = ciptr; 1050 ListenTransFds[ListenTransCount] = fd; 1051 1052 SetNotifyFd(fd, EstablishNewConnections, X_NOTIFY_READ, NULL); 1053 1054 /* Increment the count */ 1055 ListenTransCount++; 1056 } 1057 1058 /* based on TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) */ 1059 Bool 1060 AddClientOnOpenFD(int fd) 1061 { 1062 XtransConnInfo ciptr; 1063 CARD32 connect_time; 1064 char port[20]; 1065 1066 snprintf(port, sizeof(port), ":%d", atoi(display)); 1067 ciptr = _XSERVTransReopenCOTSServer(5, fd, port); 1068 if (ciptr == NULL) 1069 return FALSE; 1070 1071 _XSERVTransSetOption(ciptr, TRANS_NONBLOCKING, 1); 1072 ciptr->flags |= TRANS_NOXAUTH; 1073 1074 connect_time = GetTimeInMillis(); 1075 1076 if (!AllocNewConnection(ciptr, fd, connect_time)) { 1077 ErrorConnMax(ciptr); 1078 return FALSE; 1079 } 1080 1081 return TRUE; 1082 } 1083 1084 Bool 1085 listen_to_client(ClientPtr client) 1086 { 1087 OsCommPtr oc = (OsCommPtr) client->osPrivate; 1088 1089 if (oc->flags & OS_COMM_IGNORED) 1090 return FALSE; 1091 1092 if (!GrabInProgress) 1093 return TRUE; 1094 1095 if (client->index == GrabInProgress) 1096 return TRUE; 1097 1098 if (oc->flags & OS_COMM_GRAB_IMPERVIOUS) 1099 return TRUE; 1100 1101 return FALSE; 1102 } 1103 1104 static void 1105 set_poll_client(ClientPtr client) 1106 { 1107 OsCommPtr oc = (OsCommPtr) client->osPrivate; 1108 1109 if (oc->trans_conn) { 1110 if (listen_to_client(client)) 1111 ospoll_listen(server_poll, oc->trans_conn->fd, X_NOTIFY_READ); 1112 else 1113 ospoll_mute(server_poll, oc->trans_conn->fd, X_NOTIFY_READ); 1114 } 1115 } 1116 1117 static void 1118 set_poll_clients(void) 1119 { 1120 int i; 1121 1122 for (i = 1; i < currentMaxClients; i++) { 1123 ClientPtr client = clients[i]; 1124 if (client && !client->clientGone) 1125 set_poll_client(client); 1126 } 1127 } 1128