connection.c revision 4e185dc0
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#ifndef WIN32 85#include <sys/socket.h> 86 87#if defined(TCPCONN) 88#include <netinet/in.h> 89#include <arpa/inet.h> 90#ifdef apollo 91#ifndef NO_TCP_H 92#include <netinet/tcp.h> 93#endif 94#else 95#ifdef CSRG_BASED 96#include <sys/param.h> 97#endif 98#include <netinet/tcp.h> 99#endif 100#include <arpa/inet.h> 101#endif 102 103#include <sys/uio.h> 104 105#endif /* WIN32 */ 106#include "misc.h" /* for typedef of pointer */ 107#include "osdep.h" 108#include "opaque.h" 109#include "dixstruct.h" 110#include "xace.h" 111 112#define Pid_t pid_t 113 114#ifdef HAVE_GETPEERUCRED 115#include <ucred.h> 116#include <zone.h> 117#else 118#define zoneid_t int 119#endif 120 121#include "probes.h" 122 123struct ospoll *server_poll; 124 125int MaxClients = 0; 126Bool NewOutputPending; /* not yet attempted to write some new output */ 127Bool NoListenAll; /* Don't establish any listening sockets */ 128 129static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ 130Bool RunFromSigStopParent; /* send SIGSTOP to our own process; Upstart (or 131 equivalent) will send SIGCONT back. */ 132static char dynamic_display[7]; /* display name */ 133Bool PartialNetwork; /* continue even if unable to bind all addrs */ 134static Pid_t ParentProcess; 135 136int GrabInProgress = 0; 137 138static void 139QueueNewConnections(int curconn, int ready, void *data); 140 141static void 142set_poll_client(ClientPtr client); 143 144static void 145set_poll_clients(void); 146 147static XtransConnInfo *ListenTransConns = NULL; 148static int *ListenTransFds = NULL; 149static int ListenTransCount; 150 151static void ErrorConnMax(XtransConnInfo /* trans_conn */ ); 152 153static XtransConnInfo 154lookup_trans_conn(int fd) 155{ 156 if (ListenTransFds) { 157 int i; 158 159 for (i = 0; i < ListenTransCount; i++) 160 if (ListenTransFds[i] == fd) 161 return ListenTransConns[i]; 162 } 163 164 return NULL; 165} 166 167/* Set MaxClients */ 168 169void 170InitConnectionLimits(void) 171{ 172 MaxClients = MAXCLIENTS; 173 174#ifdef DEBUG 175 ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients); 176#endif 177} 178 179/* 180 * If SIGUSR1 was set to SIG_IGN when the server started, assume that either 181 * 182 * a- The parent process is ignoring SIGUSR1 183 * 184 * or 185 * 186 * b- The parent process is expecting a SIGUSR1 187 * when the server is ready to accept connections 188 * 189 * In the first case, the signal will be harmless, in the second case, 190 * the signal will be quite useful. 191 */ 192static void 193InitParentProcess(void) 194{ 195#if !defined(WIN32) 196 OsSigHandlerPtr handler; 197 198 handler = OsSignal(SIGUSR1, SIG_IGN); 199 if (handler == SIG_IGN) 200 RunFromSmartParent = TRUE; 201 OsSignal(SIGUSR1, handler); 202 ParentProcess = getppid(); 203#endif 204} 205 206void 207NotifyParentProcess(void) 208{ 209#if !defined(WIN32) 210 if (displayfd >= 0) { 211 if (write(displayfd, display, strlen(display)) != strlen(display)) 212 FatalError("Cannot write display number to fd %d\n", displayfd); 213 if (write(displayfd, "\n", 1) != 1) 214 FatalError("Cannot write display number to fd %d\n", displayfd); 215 close(displayfd); 216 displayfd = -1; 217 } 218 if (RunFromSmartParent) { 219 if (ParentProcess > 1) { 220 kill(ParentProcess, SIGUSR1); 221 } 222 } 223 if (RunFromSigStopParent) 224 raise(SIGSTOP); 225#endif 226} 227 228static Bool 229TryCreateSocket(int num, int *partial) 230{ 231 char port[20]; 232 233 snprintf(port, sizeof(port), "%d", num); 234 235 return (_XSERVTransMakeAllCOTSServerListeners(port, partial, 236 &ListenTransCount, 237 &ListenTransConns) >= 0); 238} 239 240/***************** 241 * CreateWellKnownSockets 242 * At initialization, create the sockets to listen on for new clients. 243 *****************/ 244 245void 246CreateWellKnownSockets(void) 247{ 248 int i; 249 int partial; 250 251 /* display is initialized to "0" by main(). It is then set to the display 252 * number if specified on the command line. */ 253 254 if (NoListenAll) { 255 ListenTransCount = 0; 256 } 257 else if ((displayfd < 0) || explicit_display) { 258 if (TryCreateSocket(atoi(display), &partial) && 259 ListenTransCount >= 1) 260 if (!PartialNetwork && partial) 261 FatalError ("Failed to establish all listening sockets"); 262 } 263 else { /* -displayfd and no explicit display number */ 264 Bool found = 0; 265 for (i = 0; i < 65536 - X_TCP_PORT; i++) { 266 if (TryCreateSocket(i, &partial) && !partial) { 267 found = 1; 268 break; 269 } 270 else 271 CloseWellKnownConnections(); 272 } 273 if (!found) 274 FatalError("Failed to find a socket to listen on"); 275 snprintf(dynamic_display, sizeof(dynamic_display), "%d", i); 276 display = dynamic_display; 277 LogSetDisplay(); 278 } 279 280 ListenTransFds = xallocarray(ListenTransCount, sizeof (int)); 281 if (ListenTransFds == NULL) 282 FatalError ("Failed to create listening socket array"); 283 284 for (i = 0; i < ListenTransCount; i++) { 285 int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]); 286 287 ListenTransFds[i] = fd; 288 SetNotifyFd(fd, QueueNewConnections, X_NOTIFY_READ, NULL); 289 290 if (!_XSERVTransIsLocal(ListenTransConns[i])) 291 DefineSelf (fd); 292 } 293 294 if (ListenTransCount == 0 && !NoListenAll) 295 FatalError 296 ("Cannot establish any listening sockets - Make sure an X server isn't already running"); 297 298#if !defined(WIN32) 299 OsSignal(SIGPIPE, SIG_IGN); 300 OsSignal(SIGHUP, AutoResetServer); 301#endif 302 OsSignal(SIGINT, GiveUp); 303 OsSignal(SIGTERM, GiveUp); 304 ResetHosts(display); 305 306 InitParentProcess(); 307 308#ifdef XDMCP 309 XdmcpInit(); 310#endif 311} 312 313void 314ResetWellKnownSockets(void) 315{ 316 int i; 317 318 ResetOsBuffers(); 319 320 for (i = 0; i < ListenTransCount; i++) { 321 int status = _XSERVTransResetListener(ListenTransConns[i]); 322 323 if (status != TRANS_RESET_NOOP) { 324 if (status == TRANS_RESET_FAILURE) { 325 /* 326 * ListenTransConns[i] freed by xtrans. 327 * Remove it from out list. 328 */ 329 330 RemoveNotifyFd(ListenTransFds[i]); 331 ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; 332 ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; 333 ListenTransCount -= 1; 334 i -= 1; 335 } 336 else if (status == TRANS_RESET_NEW_FD) { 337 /* 338 * A new file descriptor was allocated (the old one was closed) 339 */ 340 341 int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]); 342 343 ListenTransFds[i] = newfd; 344 } 345 } 346 } 347 for (i = 0; i < ListenTransCount; i++) 348 SetNotifyFd(ListenTransFds[i], QueueNewConnections, X_NOTIFY_READ, NULL); 349 350 ResetAuthorization(); 351 ResetHosts(display); 352 /* 353 * restart XDMCP 354 */ 355#ifdef XDMCP 356 XdmcpReset(); 357#endif 358} 359 360void 361CloseWellKnownConnections(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 376static void 377AuthAudit(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 484XID 485AuthorizationIDOfClient(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 512const char * 513ClientAuthorized(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 598static void 599ClientReady(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 615static ClientPtr 616AllocNewConnection(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\n", 644 client->index, fd); 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. 656 * Returns a mask with indices of new clients. Updates AllClients 657 * and AllSockets. 658 *****************/ 659 660static Bool 661EstablishNewConnections(ClientPtr clientUnused, void *closure) 662{ 663 int curconn = (int) (intptr_t) closure; 664 int newconn; /* fd of new client */ 665 CARD32 connect_time; 666 int i; 667 ClientPtr client; 668 OsCommPtr oc; 669 XtransConnInfo trans_conn, new_trans_conn; 670 int status; 671 672 connect_time = GetTimeInMillis(); 673 /* kill off stragglers */ 674 for (i = 1; i < currentMaxClients; i++) { 675 if ((client = clients[i])) { 676 oc = (OsCommPtr) (client->osPrivate); 677 if ((oc && (oc->conn_time != 0) && 678 (connect_time - oc->conn_time) >= TimeOutValue) || 679 (client->noClientException != Success && !client->clientGone)) 680 CloseDownClient(client); 681 } 682 } 683 684 if ((trans_conn = lookup_trans_conn(curconn)) == NULL) 685 return TRUE; 686 687 if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL) 688 return TRUE; 689 690 newconn = _XSERVTransGetConnectionNumber(new_trans_conn); 691 692 _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); 693 694 if (trans_conn->flags & TRANS_NOXAUTH) 695 new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH; 696 697 if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) { 698 ErrorConnMax(new_trans_conn); 699 } 700 return TRUE; 701} 702 703static void 704QueueNewConnections(int fd, int ready, void *data) 705{ 706 QueueWorkProc(EstablishNewConnections, NULL, (void *) (intptr_t) fd); 707} 708 709#define NOROOM "Maximum number of clients reached" 710 711/************ 712 * ErrorConnMax 713 * Fail a connection due to lack of client or file descriptor space 714 ************/ 715 716static void 717ConnMaxNotify(int fd, int events, void *data) 718{ 719 XtransConnInfo trans_conn = data; 720 char order = 0; 721 722 /* try to read the byte-order of the connection */ 723 (void) _XSERVTransRead(trans_conn, &order, 1); 724 if (order == 'l' || order == 'B' || order == 'r' || order == 'R') { 725 xConnSetupPrefix csp; 726 char pad[3] = { 0, 0, 0 }; 727 int whichbyte = 1; 728 struct iovec iov[3]; 729 730 csp.success = xFalse; 731 csp.lengthReason = sizeof(NOROOM) - 1; 732 csp.length = (sizeof(NOROOM) + 2) >> 2; 733 csp.majorVersion = X_PROTOCOL; 734 csp.minorVersion = X_PROTOCOL_REVISION; 735 if (((*(char *) &whichbyte) && (order == 'B' || order == 'R')) || 736 (!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) { 737 swaps(&csp.majorVersion); 738 swaps(&csp.minorVersion); 739 swaps(&csp.length); 740 } 741 iov[0].iov_len = sz_xConnSetupPrefix; 742 iov[0].iov_base = (char *) &csp; 743 iov[1].iov_len = csp.lengthReason; 744 iov[1].iov_base = (void *) NOROOM; 745 iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; 746 iov[2].iov_base = pad; 747 (void) _XSERVTransWritev(trans_conn, iov, 3); 748 } 749 RemoveNotifyFd(trans_conn->fd); 750 _XSERVTransClose(trans_conn); 751} 752 753static void 754ErrorConnMax(XtransConnInfo trans_conn) 755{ 756 if (!SetNotifyFd(trans_conn->fd, ConnMaxNotify, X_NOTIFY_READ, trans_conn)) 757 _XSERVTransClose(trans_conn); 758} 759 760/************ 761 * CloseDownFileDescriptor: 762 * Remove this file descriptor 763 ************/ 764 765void 766CloseDownFileDescriptor(OsCommPtr oc) 767{ 768 if (oc->trans_conn) { 769 int connection = oc->fd; 770#ifdef XDMCP 771 XdmcpCloseDisplay(connection); 772#endif 773 ospoll_remove(server_poll, connection); 774 _XSERVTransDisconnect(oc->trans_conn); 775 _XSERVTransClose(oc->trans_conn); 776 oc->trans_conn = NULL; 777 oc->fd = -1; 778 } 779} 780 781/***************** 782 * CloseDownConnection 783 * Delete client from AllClients and free resources 784 *****************/ 785 786void 787CloseDownConnection(ClientPtr client) 788{ 789 OsCommPtr oc = (OsCommPtr) client->osPrivate; 790 791 if (FlushCallback) 792 CallCallbacks(&FlushCallback, client); 793 794 if (oc->output) 795 FlushClient(client, oc, (char *) NULL, 0); 796 CloseDownFileDescriptor(oc); 797 FreeOsBuffers(oc); 798 free(client->osPrivate); 799 client->osPrivate = (void *) NULL; 800 if (auditTrailLevel > 1) 801 AuditF("client %d disconnected\n", client->index); 802} 803 804struct notify_fd { 805 int mask; 806 NotifyFdProcPtr notify; 807 void *data; 808}; 809 810/***************** 811 * HandleNotifyFd 812 * A poll callback to be called when the registered 813 * file descriptor is ready. 814 *****************/ 815 816static void 817HandleNotifyFd(int fd, int xevents, void *data) 818{ 819 struct notify_fd *n = data; 820 n->notify(fd, xevents, n->data); 821} 822 823/***************** 824 * SetNotifyFd 825 * Registers a callback to be invoked when the specified 826 * file descriptor becomes readable. 827 *****************/ 828 829Bool 830SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data) 831{ 832 struct notify_fd *n; 833 834 n = ospoll_data(server_poll, fd); 835 if (!n) { 836 if (mask == 0) 837 return TRUE; 838 839 n = calloc(1, sizeof (struct notify_fd)); 840 if (!n) 841 return FALSE; 842 ospoll_add(server_poll, fd, 843 ospoll_trigger_level, 844 HandleNotifyFd, 845 n); 846 } 847 848 if (mask == 0) { 849 ospoll_remove(server_poll, fd); 850 free(n); 851 } else { 852 int listen = mask & ~n->mask; 853 int mute = n->mask & ~mask; 854 855 if (listen) 856 ospoll_listen(server_poll, fd, listen); 857 if (mute) 858 ospoll_mute(server_poll, fd, mute); 859 n->mask = mask; 860 n->data = data; 861 n->notify = notify; 862 } 863 864 return TRUE; 865} 866 867/***************** 868 * OnlyListenToOneClient: 869 * Only accept requests from one client. Continue to handle new 870 * connections, but don't take any protocol requests from the new 871 * ones. Note that if GrabInProgress is set, EstablishNewConnections 872 * needs to put new clients into SavedAllSockets and SavedAllClients. 873 * Note also that there is no timeout for this in the protocol. 874 * This routine is "undone" by ListenToAllClients() 875 *****************/ 876 877int 878OnlyListenToOneClient(ClientPtr client) 879{ 880 int rc; 881 882 rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess); 883 if (rc != Success) 884 return rc; 885 886 if (!GrabInProgress) { 887 GrabInProgress = client->index; 888 set_poll_clients(); 889 } 890 891 return rc; 892} 893 894/**************** 895 * ListenToAllClients: 896 * Undoes OnlyListentToOneClient() 897 ****************/ 898 899void 900ListenToAllClients(void) 901{ 902 if (GrabInProgress) { 903 GrabInProgress = 0; 904 set_poll_clients(); 905 } 906} 907 908/**************** 909 * IgnoreClient 910 * Removes one client from input masks. 911 * Must have cooresponding call to AttendClient. 912 ****************/ 913 914void 915IgnoreClient(ClientPtr client) 916{ 917 OsCommPtr oc = (OsCommPtr) client->osPrivate; 918 919 client->ignoreCount++; 920 if (client->ignoreCount > 1) 921 return; 922 923 isItTimeToYield = TRUE; 924 mark_client_not_ready(client); 925 926 oc->flags |= OS_COMM_IGNORED; 927 set_poll_client(client); 928} 929 930/**************** 931 * AttendClient 932 * Adds one client back into the input masks. 933 ****************/ 934 935void 936AttendClient(ClientPtr client) 937{ 938 OsCommPtr oc = (OsCommPtr) client->osPrivate; 939 940 if (client->clientGone) { 941 /* 942 * client is gone, so any pending requests will be dropped and its 943 * ignore count doesn't matter. 944 */ 945 return; 946 } 947 948 client->ignoreCount--; 949 if (client->ignoreCount) 950 return; 951 952 oc->flags &= ~OS_COMM_IGNORED; 953 set_poll_client(client); 954 if (listen_to_client(client)) 955 mark_client_ready(client); 956 else { 957 /* grab active, mark ready when grab goes away */ 958 mark_client_saved_ready(client); 959 } 960} 961 962/* make client impervious to grabs; assume only executing client calls this */ 963 964void 965MakeClientGrabImpervious(ClientPtr client) 966{ 967 OsCommPtr oc = (OsCommPtr) client->osPrivate; 968 969 oc->flags |= OS_COMM_GRAB_IMPERVIOUS; 970 set_poll_client(client); 971 972 if (ServerGrabCallback) { 973 ServerGrabInfoRec grabinfo; 974 975 grabinfo.client = client; 976 grabinfo.grabstate = CLIENT_IMPERVIOUS; 977 CallCallbacks(&ServerGrabCallback, &grabinfo); 978 } 979} 980 981/* make client pervious to grabs; assume only executing client calls this */ 982 983void 984MakeClientGrabPervious(ClientPtr client) 985{ 986 OsCommPtr oc = (OsCommPtr) client->osPrivate; 987 988 oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS; 989 set_poll_client(client); 990 isItTimeToYield = TRUE; 991 992 if (ServerGrabCallback) { 993 ServerGrabInfoRec grabinfo; 994 995 grabinfo.client = client; 996 grabinfo.grabstate = CLIENT_PERVIOUS; 997 CallCallbacks(&ServerGrabCallback, &grabinfo); 998 } 999} 1000 1001/* Add a fd (from launchd or similar) to our listeners */ 1002void 1003ListenOnOpenFD(int fd, int noxauth) 1004{ 1005 char port[256]; 1006 XtransConnInfo ciptr; 1007 const char *display_env = getenv("DISPLAY"); 1008 1009 if (display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) { 1010 /* Make the path the launchd socket if our DISPLAY is set right */ 1011 strcpy(port, display_env); 1012 } 1013 else { 1014 /* Just some default so things don't break and die. */ 1015 snprintf(port, sizeof(port), ":%d", atoi(display)); 1016 } 1017 1018 /* Make our XtransConnInfo 1019 * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c 1020 */ 1021 ciptr = _XSERVTransReopenCOTSServer(5, fd, port); 1022 if (ciptr == NULL) { 1023 ErrorF("Got NULL while trying to Reopen listen port.\n"); 1024 return; 1025 } 1026 1027 if (noxauth) 1028 ciptr->flags = ciptr->flags | TRANS_NOXAUTH; 1029 1030 /* Allocate space to store it */ 1031 ListenTransFds = 1032 xnfreallocarray(ListenTransFds, ListenTransCount + 1, sizeof(int)); 1033 ListenTransConns = 1034 xnfreallocarray(ListenTransConns, ListenTransCount + 1, 1035 sizeof(XtransConnInfo)); 1036 1037 /* Store it */ 1038 ListenTransConns[ListenTransCount] = ciptr; 1039 ListenTransFds[ListenTransCount] = fd; 1040 1041 SetNotifyFd(fd, QueueNewConnections, X_NOTIFY_READ, NULL); 1042 1043 /* Increment the count */ 1044 ListenTransCount++; 1045} 1046 1047/* based on TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) */ 1048Bool 1049AddClientOnOpenFD(int fd) 1050{ 1051 XtransConnInfo ciptr; 1052 CARD32 connect_time; 1053 char port[20]; 1054 1055 snprintf(port, sizeof(port), ":%d", atoi(display)); 1056 ciptr = _XSERVTransReopenCOTSServer(5, fd, port); 1057 if (ciptr == NULL) 1058 return FALSE; 1059 1060 _XSERVTransSetOption(ciptr, TRANS_NONBLOCKING, 1); 1061 ciptr->flags |= TRANS_NOXAUTH; 1062 1063 connect_time = GetTimeInMillis(); 1064 1065 if (!AllocNewConnection(ciptr, fd, connect_time)) { 1066 ErrorConnMax(ciptr); 1067 return FALSE; 1068 } 1069 1070 return TRUE; 1071} 1072 1073Bool 1074listen_to_client(ClientPtr client) 1075{ 1076 OsCommPtr oc = (OsCommPtr) client->osPrivate; 1077 1078 if (oc->flags & OS_COMM_IGNORED) 1079 return FALSE; 1080 1081 if (!GrabInProgress) 1082 return TRUE; 1083 1084 if (client->index == GrabInProgress) 1085 return TRUE; 1086 1087 if (oc->flags & OS_COMM_GRAB_IMPERVIOUS) 1088 return TRUE; 1089 1090 return FALSE; 1091} 1092 1093static void 1094set_poll_client(ClientPtr client) 1095{ 1096 OsCommPtr oc = (OsCommPtr) client->osPrivate; 1097 1098 if (oc->trans_conn) { 1099 if (listen_to_client(client)) 1100 ospoll_listen(server_poll, oc->trans_conn->fd, X_NOTIFY_READ); 1101 else 1102 ospoll_mute(server_poll, oc->trans_conn->fd, X_NOTIFY_READ); 1103 } 1104} 1105 1106static void 1107set_poll_clients(void) 1108{ 1109 int i; 1110 1111 for (i = 1; i < currentMaxClients; i++) { 1112 ClientPtr client = clients[i]; 1113 if (client && !client->clientGone) 1114 set_poll_client(client); 1115 } 1116} 1117