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