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 25 26Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46******************************************************************/ 47/***************************************************************** 48 * Stuff to create connections --- OS dependent 49 * 50 * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets, 51 * CloseDownConnection, CheckConnections, AddEnabledDevice, 52 * RemoveEnabledDevice, OnlyListToOneClient, 53 * ListenToAllClients, 54 * 55 * (WaitForSomething is in its own file) 56 * 57 * In this implementation, a client socket table is not kept. 58 * Instead, what would be the index into the table is just the 59 * file descriptor of the socket. This won't work for if the 60 * socket ids aren't small nums (0 - 2^8) 61 * 62 *****************************************************************/ 63 64#include <X11/Xpoll.h> 65 66#ifdef HAVE_DIX_CONFIG_H 67#include <dix-config.h> 68#endif 69 70#ifdef WIN32 71#include <X11/Xwinsock.h> 72#endif 73#include <X11/X.h> 74#include <X11/Xproto.h> 75#define XSERV_t 76#define TRANS_SERVER 77#define TRANS_REOPEN 78#include <X11/Xtrans/Xtrans.h> 79#include <X11/Xtrans/Xtransint.h> 80#include <errno.h> 81#include <signal.h> 82#include <stdio.h> 83#include <stdlib.h> 84 85#ifndef WIN32 86#include <sys/socket.h> 87 88 89 90#if defined(TCPCONN) || defined(STREAMSCONN) 91# include <netinet/in.h> 92# include <arpa/inet.h> 93# ifdef apollo 94# ifndef NO_TCP_H 95# include <netinet/tcp.h> 96# endif 97# else 98# ifdef CSRG_BASED 99# include <sys/param.h> 100# endif 101# include <netinet/tcp.h> 102# endif 103# include <arpa/inet.h> 104#endif 105 106#include <sys/uio.h> 107 108#endif /* WIN32 */ 109#include "misc.h" /* for typedef of pointer */ 110#include "osdep.h" 111#include "opaque.h" 112#include "dixstruct.h" 113#include "xace.h" 114 115#define Pid_t pid_t 116 117 118#ifdef HAS_GETPEERUCRED 119# include <ucred.h> 120# include <zone.h> 121#endif 122 123#ifdef XSERVER_DTRACE 124# include <sys/types.h> 125typedef const char *string; 126# ifndef HAS_GETPEERUCRED 127# define zoneid_t int 128# endif 129# include "../dix/Xserver-dtrace.h" 130#endif 131 132static int lastfdesc; /* maximum file descriptor */ 133 134fd_set WellKnownConnections; /* Listener mask */ 135fd_set EnabledDevices; /* mask for input devices that are on */ 136fd_set AllSockets; /* select on this */ 137fd_set AllClients; /* available clients */ 138fd_set LastSelectMask; /* mask returned from last select call */ 139fd_set ClientsWithInput; /* clients with FULL requests in buffer */ 140fd_set ClientsWriteBlocked; /* clients who cannot receive output */ 141fd_set OutputPending; /* clients with reply/event data ready to go */ 142int MaxClients = 0; 143Bool NewOutputPending; /* not yet attempted to write some new output */ 144Bool AnyClientsWriteBlocked; /* true if some client blocked on write */ 145 146static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ 147Bool RunFromSigStopParent; /* send SIGSTOP to our own process; Upstart (or 148 equivalent) will send SIGCONT back. */ 149Bool PartialNetwork; /* continue even if unable to bind all addrs */ 150static Pid_t ParentProcess; 151 152static Bool debug_conns = FALSE; 153 154fd_set IgnoredClientsWithInput; 155static fd_set GrabImperviousClients; 156static fd_set SavedAllClients; 157static fd_set SavedAllSockets; 158static fd_set SavedClientsWithInput; 159int GrabInProgress = 0; 160 161#if !defined(WIN32) 162int *ConnectionTranslation = NULL; 163#else 164/* 165 * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is 166 * not even a known maximum value, so use something quite arbitrary for now. 167 * Do storage is a hash table of size 256. Collisions are handled in a linked 168 * list. 169 */ 170 171#undef MAXSOCKS 172#define MAXSOCKS 500 173#undef MAXSELECT 174#define MAXSELECT 500 175 176struct _ct_node { 177 struct _ct_node *next; 178 int key; 179 int value; 180}; 181 182struct _ct_node *ct_head[256]; 183 184void InitConnectionTranslation(void) 185{ 186 memset(ct_head, 0, sizeof(ct_head)); 187} 188 189int GetConnectionTranslation(int conn) 190{ 191 struct _ct_node *node = ct_head[conn & 0xff]; 192 while (node != NULL) 193 { 194 if (node->key == conn) 195 return node->value; 196 node = node->next; 197 } 198 return 0; 199} 200 201void SetConnectionTranslation(int conn, int client) 202{ 203 struct _ct_node **node = ct_head + (conn & 0xff); 204 if (client == 0) /* remove entry */ 205 { 206 while (*node != NULL) 207 { 208 if ((*node)->key == conn) 209 { 210 struct _ct_node *temp = *node; 211 *node = (*node)->next; 212 free(temp); 213 return; 214 } 215 node = &((*node)->next); 216 } 217 return; 218 } else 219 { 220 while (*node != NULL) 221 { 222 if ((*node)->key == conn) 223 { 224 (*node)->value = client; 225 return; 226 } 227 node = &((*node)->next); 228 } 229 *node = malloc(sizeof(struct _ct_node)); 230 (*node)->next = NULL; 231 (*node)->key = conn; 232 (*node)->value = client; 233 return; 234 } 235} 236 237void ClearConnectionTranslation(void) 238{ 239 unsigned i; 240 for (i = 0; i < 256; i++) 241 { 242 struct _ct_node *node = ct_head[i]; 243 while (node != NULL) 244 { 245 struct _ct_node *temp = node; 246 node = node->next; 247 free(temp); 248 } 249 } 250} 251#endif 252 253static XtransConnInfo *ListenTransConns = NULL; 254static int *ListenTransFds = NULL; 255static int ListenTransCount; 256 257static void ErrorConnMax(XtransConnInfo /* trans_conn */); 258 259static XtransConnInfo 260lookup_trans_conn (int fd) 261{ 262 if (ListenTransFds) 263 { 264 int i; 265 for (i = 0; i < ListenTransCount; i++) 266 if (ListenTransFds[i] == fd) 267 return ListenTransConns[i]; 268 } 269 270 return NULL; 271} 272 273/* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */ 274 275void 276InitConnectionLimits(void) 277{ 278 lastfdesc = -1; 279 280#ifndef __CYGWIN__ 281 282#if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX) 283 lastfdesc = sysconf(_SC_OPEN_MAX) - 1; 284#endif 285 286#ifdef HAS_GETDTABLESIZE 287 if (lastfdesc < 0) 288 lastfdesc = getdtablesize() - 1; 289#endif 290 291#ifdef _NFILE 292 if (lastfdesc < 0) 293 lastfdesc = _NFILE - 1; 294#endif 295 296#endif /* __CYGWIN__ */ 297 298 /* This is the fallback */ 299 if (lastfdesc < 0) 300 lastfdesc = MAXSOCKS; 301 302 if (lastfdesc > MAXSELECT) 303 lastfdesc = MAXSELECT; 304 305 if (lastfdesc > MAXCLIENTS) 306 { 307 lastfdesc = MAXCLIENTS; 308 if (debug_conns) 309 ErrorF( "REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS); 310 } 311 MaxClients = lastfdesc; 312 313#ifdef DEBUG 314 ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients); 315#endif 316 317#if !defined(WIN32) 318 if (!ConnectionTranslation) 319 ConnectionTranslation = (int *)xnfalloc(sizeof(int)*(lastfdesc + 1)); 320#else 321 InitConnectionTranslation(); 322#endif 323} 324 325/* 326 * If SIGUSR1 was set to SIG_IGN when the server started, assume that either 327 * 328 * a- The parent process is ignoring SIGUSR1 329 * 330 * or 331 * 332 * b- The parent process is expecting a SIGUSR1 333 * when the server is ready to accept connections 334 * 335 * In the first case, the signal will be harmless, in the second case, 336 * the signal will be quite useful. 337 */ 338static void 339InitParentProcess(void) 340{ 341#if !defined(WIN32) 342 OsSigHandlerPtr handler; 343 handler = OsSignal (SIGUSR1, SIG_IGN); 344 if ( handler == SIG_IGN) 345 RunFromSmartParent = TRUE; 346 OsSignal(SIGUSR1, handler); 347 ParentProcess = getppid (); 348#endif 349} 350 351void 352NotifyParentProcess(void) 353{ 354#if !defined(WIN32) 355 if (RunFromSmartParent) { 356 if (ParentProcess > 1) { 357 kill (ParentProcess, SIGUSR1); 358 } 359 } 360 if (RunFromSigStopParent) 361 raise (SIGSTOP); 362#endif 363} 364 365/***************** 366 * CreateWellKnownSockets 367 * At initialization, create the sockets to listen on for new clients. 368 *****************/ 369 370void 371CreateWellKnownSockets(void) 372{ 373 int i; 374 int partial; 375 char port[20]; 376 377 FD_ZERO(&AllSockets); 378 FD_ZERO(&AllClients); 379 FD_ZERO(&LastSelectMask); 380 FD_ZERO(&ClientsWithInput); 381 382#if !defined(WIN32) 383 for (i=0; i<MaxClients; i++) ConnectionTranslation[i] = 0; 384#else 385 ClearConnectionTranslation(); 386#endif 387 388 FD_ZERO (&WellKnownConnections); 389 390 sprintf (port, "%d", atoi (display)); 391 392 if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial, 393 &ListenTransCount, &ListenTransConns) >= 0) && 394 (ListenTransCount >= 1)) 395 { 396 if (!PartialNetwork && partial) 397 { 398 FatalError ("Failed to establish all listening sockets"); 399 } 400 else 401 { 402 ListenTransFds = malloc(ListenTransCount * sizeof (int)); 403 404 for (i = 0; i < ListenTransCount; i++) 405 { 406 int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); 407 408 ListenTransFds[i] = fd; 409 FD_SET (fd, &WellKnownConnections); 410 411 if (!_XSERVTransIsLocal (ListenTransConns[i])) 412 { 413 DefineSelf (fd); 414 } 415 } 416 } 417 } 418 419 if (!XFD_ANYSET (&WellKnownConnections)) 420 FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running"); 421#if !defined(WIN32) 422 OsSignal (SIGPIPE, SIG_IGN); 423 OsSignal (SIGHUP, AutoResetServer); 424#endif 425 OsSignal (SIGINT, GiveUp); 426 OsSignal (SIGTERM, GiveUp); 427 XFD_COPYSET (&WellKnownConnections, &AllSockets); 428 ResetHosts(display); 429 430 InitParentProcess(); 431 432#ifdef XDMCP 433 XdmcpInit (); 434#endif 435} 436 437void 438ResetWellKnownSockets (void) 439{ 440 int i; 441 442 ResetOsBuffers(); 443 444 for (i = 0; i < ListenTransCount; i++) 445 { 446 int status = _XSERVTransResetListener (ListenTransConns[i]); 447 448 if (status != TRANS_RESET_NOOP) 449 { 450 if (status == TRANS_RESET_FAILURE) 451 { 452 /* 453 * ListenTransConns[i] freed by xtrans. 454 * Remove it from out list. 455 */ 456 457 FD_CLR (ListenTransFds[i], &WellKnownConnections); 458 ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; 459 ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; 460 ListenTransCount -= 1; 461 i -= 1; 462 } 463 else if (status == TRANS_RESET_NEW_FD) 464 { 465 /* 466 * A new file descriptor was allocated (the old one was closed) 467 */ 468 469 int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); 470 471 FD_CLR (ListenTransFds[i], &WellKnownConnections); 472 ListenTransFds[i] = newfd; 473 FD_SET(newfd, &WellKnownConnections); 474 } 475 } 476 } 477 478 ResetAuthorization (); 479 ResetHosts(display); 480 /* 481 * restart XDMCP 482 */ 483#ifdef XDMCP 484 XdmcpReset (); 485#endif 486} 487 488void 489CloseWellKnownConnections(void) 490{ 491 int i; 492 493 for (i = 0; i < ListenTransCount; i++) 494 _XSERVTransClose (ListenTransConns[i]); 495} 496 497static void 498AuthAudit (ClientPtr client, Bool letin, 499 struct sockaddr *saddr, int len, 500 unsigned int proto_n, char *auth_proto, int auth_id) 501{ 502 char addr[128]; 503 char *out = addr; 504 char client_uid_string[64]; 505 LocalClientCredRec *lcc; 506#ifdef XSERVER_DTRACE 507 pid_t client_pid = -1; 508 zoneid_t client_zid = -1; 509#endif 510 511 if (!len) 512 strcpy(out, "local host"); 513 else 514 switch (saddr->sa_family) 515 { 516 case AF_UNSPEC: 517#if defined(UNIXCONN) || defined(LOCALCONN) 518 case AF_UNIX: 519#endif 520 strcpy(out, "local host"); 521 break; 522#if defined(TCPCONN) || defined(STREAMSCONN) 523 case AF_INET: 524 sprintf(out, "IP %s", 525 inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr)); 526 break; 527#if defined(IPv6) && defined(AF_INET6) 528 case AF_INET6: { 529 char ipaddr[INET6_ADDRSTRLEN]; 530 inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr, 531 ipaddr, sizeof(ipaddr)); 532 sprintf(out, "IP %s", ipaddr); 533 } 534 break; 535#endif 536#endif 537 default: 538 strcpy(out, "unknown address"); 539 } 540 541 if (GetLocalClientCreds(client, &lcc) != -1) { 542 int slen; /* length written to client_uid_string */ 543 544 strcpy(client_uid_string, " ( "); 545 slen = 3; 546 547 if (lcc->fieldsSet & LCC_UID_SET) { 548 snprintf(client_uid_string + slen, 549 sizeof(client_uid_string) - slen, 550 "uid=%ld ", (long) lcc->euid); 551 slen = strlen(client_uid_string); 552 } 553 554 if (lcc->fieldsSet & LCC_GID_SET) { 555 snprintf(client_uid_string + slen, 556 sizeof(client_uid_string) - slen, 557 "gid=%ld ", (long) lcc->egid); 558 slen = strlen(client_uid_string); 559 } 560 561 if (lcc->fieldsSet & LCC_PID_SET) { 562#ifdef XSERVER_DTRACE 563 client_pid = lcc->pid; 564#endif 565 snprintf(client_uid_string + slen, 566 sizeof(client_uid_string) - slen, 567 "pid=%ld ", (long) lcc->pid); 568 slen = strlen(client_uid_string); 569 } 570 571 if (lcc->fieldsSet & LCC_ZID_SET) { 572#ifdef XSERVER_DTRACE 573 client_zid = lcc->zoneid; 574#endif 575 snprintf(client_uid_string + slen, 576 sizeof(client_uid_string) - slen, 577 "zoneid=%ld ", (long) lcc->zoneid); 578 slen = strlen(client_uid_string); 579 } 580 581 snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen, 582 ")"); 583 FreeLocalClientCreds(lcc); 584 } 585 else { 586 client_uid_string[0] = '\0'; 587 } 588 589#ifdef XSERVER_DTRACE 590 XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid); 591#endif 592 if (auditTrailLevel > 1) { 593 if (proto_n) 594 AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n", 595 client->index, letin ? "connected" : "rejected", addr, 596 client_uid_string, (int)proto_n, auth_proto, auth_id); 597 else 598 AuditF("client %d %s from %s%s\n", 599 client->index, letin ? "connected" : "rejected", addr, 600 client_uid_string); 601 602 } 603} 604 605XID 606AuthorizationIDOfClient(ClientPtr client) 607{ 608 if (client->osPrivate) 609 return ((OsCommPtr)client->osPrivate)->auth_id; 610 else 611 return None; 612} 613 614 615/***************************************************************** 616 * ClientAuthorized 617 * 618 * Sent by the client at connection setup: 619 * typedef struct _xConnClientPrefix { 620 * CARD8 byteOrder; 621 * BYTE pad; 622 * CARD16 majorVersion, minorVersion; 623 * CARD16 nbytesAuthProto; 624 * CARD16 nbytesAuthString; 625 * } xConnClientPrefix; 626 * 627 * It is hoped that eventually one protocol will be agreed upon. In the 628 * mean time, a server that implements a different protocol than the 629 * client expects, or a server that only implements the host-based 630 * mechanism, will simply ignore this information. 631 * 632 *****************************************************************/ 633 634char * 635ClientAuthorized(ClientPtr client, 636 unsigned int proto_n, char *auth_proto, 637 unsigned int string_n, char *auth_string) 638{ 639 OsCommPtr priv; 640 Xtransaddr *from = NULL; 641 int family; 642 int fromlen; 643 XID auth_id; 644 char *reason = NULL; 645 XtransConnInfo trans_conn; 646 647 priv = (OsCommPtr)client->osPrivate; 648 trans_conn = priv->trans_conn; 649 650 /* Allow any client to connect without authorization on a launchd socket, 651 because it is securely created -- this prevents a race condition on launch */ 652 if(trans_conn->flags & TRANS_NOXAUTH) { 653 auth_id = (XID) 0L; 654 } else { 655 auth_id = CheckAuthorization (proto_n, auth_proto, string_n, auth_string, client, &reason); 656 } 657 658 if (auth_id == (XID) ~0L) 659 { 660 if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) 661 { 662 if (InvalidHost ((struct sockaddr *) from, fromlen, client)) 663 AuthAudit(client, FALSE, (struct sockaddr *) from, 664 fromlen, proto_n, auth_proto, auth_id); 665 else 666 { 667 auth_id = (XID) 0; 668#ifdef XSERVER_DTRACE 669 if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) 670#else 671 if (auditTrailLevel > 1) 672#endif 673 AuthAudit(client, TRUE, 674 (struct sockaddr *) from, fromlen, 675 proto_n, auth_proto, auth_id); 676 } 677 678 free(from); 679 } 680 681 if (auth_id == (XID) ~0L) { 682 if (reason) 683 return reason; 684 else 685 return "Client is not authorized to connect to Server"; 686 } 687 } 688#ifdef XSERVER_DTRACE 689 else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) 690#else 691 else if (auditTrailLevel > 1) 692#endif 693 { 694 if (_XSERVTransGetPeerAddr (trans_conn, 695 &family, &fromlen, &from) != -1) 696 { 697 AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen, 698 proto_n, auth_proto, auth_id); 699 700 free(from); 701 } 702 } 703 priv->auth_id = auth_id; 704 priv->conn_time = 0; 705 706#ifdef XDMCP 707 /* indicate to Xdmcp protocol that we've opened new client */ 708 XdmcpOpenDisplay(priv->fd); 709#endif /* XDMCP */ 710 711 XaceHook(XACE_AUTH_AVAIL, client, auth_id); 712 713 /* At this point, if the client is authorized to change the access control 714 * list, we should getpeername() information, and add the client to 715 * the selfhosts list. It's not really the host machine, but the 716 * true purpose of the selfhosts list is to see who may change the 717 * access control list. 718 */ 719 return((char *)NULL); 720} 721 722static ClientPtr 723AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) 724{ 725 OsCommPtr oc; 726 ClientPtr client; 727 728 if ( 729#ifndef WIN32 730 fd >= lastfdesc 731#else 732 XFD_SETCOUNT(&AllClients) >= MaxClients 733#endif 734 ) 735 return NullClient; 736 oc = malloc(sizeof(OsCommRec)); 737 if (!oc) 738 return NullClient; 739 oc->trans_conn = trans_conn; 740 oc->fd = fd; 741 oc->input = (ConnectionInputPtr)NULL; 742 oc->output = (ConnectionOutputPtr)NULL; 743 oc->auth_id = None; 744 oc->conn_time = conn_time; 745 if (!(client = NextAvailableClient((pointer)oc))) 746 { 747 free(oc); 748 return NullClient; 749 } 750 oc->local_client = ComputeLocalClient(client); 751#if !defined(WIN32) 752 ConnectionTranslation[fd] = client->index; 753#else 754 SetConnectionTranslation(fd, client->index); 755#endif 756 if (GrabInProgress) 757 { 758 FD_SET(fd, &SavedAllClients); 759 FD_SET(fd, &SavedAllSockets); 760 } 761 else 762 { 763 FD_SET(fd, &AllClients); 764 FD_SET(fd, &AllSockets); 765 } 766 767#ifdef DEBUG 768 ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n", 769 client->index, fd); 770#endif 771#ifdef XSERVER_DTRACE 772 XSERVER_CLIENT_CONNECT(client->index, fd); 773#endif 774 775 return client; 776} 777 778/***************** 779 * EstablishNewConnections 780 * If anyone is waiting on listened sockets, accept them. 781 * Returns a mask with indices of new clients. Updates AllClients 782 * and AllSockets. 783 *****************/ 784 785/*ARGSUSED*/ 786Bool 787EstablishNewConnections(ClientPtr clientUnused, pointer closure) 788{ 789 fd_set readyconnections; /* set of listeners that are ready */ 790 int curconn; /* fd of listener that's ready */ 791 register int newconn; /* fd of new client */ 792 CARD32 connect_time; 793 register int i; 794 register ClientPtr client; 795 register OsCommPtr oc; 796 fd_set tmask; 797 798 XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections); 799 XFD_COPYSET(&tmask, &readyconnections); 800 if (!XFD_ANYSET(&readyconnections)) 801 return TRUE; 802 connect_time = GetTimeInMillis(); 803 /* kill off stragglers */ 804 for (i=1; i<currentMaxClients; i++) 805 { 806 if ((client = clients[i])) 807 { 808 oc = (OsCommPtr)(client->osPrivate); 809 if ((oc && (oc->conn_time != 0) && 810 (connect_time - oc->conn_time) >= TimeOutValue) || 811 (client->noClientException != Success && !client->clientGone)) 812 CloseDownClient(client); 813 } 814 } 815#ifndef WIN32 816 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) 817 { 818 while (readyconnections.fds_bits[i]) 819#else 820 for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++) 821#endif 822 { 823 XtransConnInfo trans_conn, new_trans_conn; 824 int status; 825 826#ifndef WIN32 827 curconn = mffs (readyconnections.fds_bits[i]) - 1; 828 readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); 829 curconn += (i * (sizeof(fd_mask)*8)); 830#else 831 curconn = XFD_FD(&readyconnections, i); 832#endif 833 834 if ((trans_conn = lookup_trans_conn (curconn)) == NULL) 835 continue; 836 837 if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) 838 continue; 839 840 newconn = _XSERVTransGetConnectionNumber (new_trans_conn); 841 842 if (newconn < lastfdesc) 843 { 844 int clientid; 845#if !defined(WIN32) 846 clientid = ConnectionTranslation[newconn]; 847#else 848 clientid = GetConnectionTranslation(newconn); 849#endif 850 if(clientid && (client = clients[clientid])) 851 CloseDownClient(client); 852 } 853 854 _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); 855 856 if (!AllocNewConnection (new_trans_conn, newconn, connect_time)) 857 { 858 ErrorConnMax(new_trans_conn); 859 _XSERVTransClose(new_trans_conn); 860 } 861 862 if(trans_conn->flags & TRANS_NOXAUTH) 863 new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH; 864 865 } 866#ifndef WIN32 867 } 868#endif 869 return TRUE; 870} 871 872#define NOROOM "Maximum number of clients reached" 873 874/************ 875 * ErrorConnMax 876 * Fail a connection due to lack of client or file descriptor space 877 ************/ 878 879static void 880ErrorConnMax(XtransConnInfo trans_conn) 881{ 882 int fd = _XSERVTransGetConnectionNumber (trans_conn); 883 xConnSetupPrefix csp; 884 char pad[3]; 885 struct iovec iov[3]; 886 char byteOrder = 0; 887 int whichbyte = 1; 888 struct timeval waittime; 889 fd_set mask; 890 891 /* if these seems like a lot of trouble to go to, it probably is */ 892 waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND; 893 waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * 894 (1000000 / MILLI_PER_SECOND); 895 FD_ZERO(&mask); 896 FD_SET(fd, &mask); 897 (void)Select(fd + 1, &mask, NULL, NULL, &waittime); 898 /* try to read the byte-order of the connection */ 899 (void)_XSERVTransRead(trans_conn, &byteOrder, 1); 900 if ((byteOrder == 'l') || (byteOrder == 'B')) 901 { 902 csp.success = xFalse; 903 csp.lengthReason = sizeof(NOROOM) - 1; 904 csp.length = (sizeof(NOROOM) + 2) >> 2; 905 csp.majorVersion = X_PROTOCOL; 906 csp.minorVersion = X_PROTOCOL_REVISION; 907 if (((*(char *) &whichbyte) && (byteOrder == 'B')) || 908 (!(*(char *) &whichbyte) && (byteOrder == 'l'))) 909 { 910 swaps(&csp.majorVersion, whichbyte); 911 swaps(&csp.minorVersion, whichbyte); 912 swaps(&csp.length, whichbyte); 913 } 914 iov[0].iov_len = sz_xConnSetupPrefix; 915 iov[0].iov_base = (char *) &csp; 916 iov[1].iov_len = csp.lengthReason; 917 iov[1].iov_base = NOROOM; 918 iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; 919 iov[2].iov_base = pad; 920 (void)_XSERVTransWritev(trans_conn, iov, 3); 921 } 922} 923 924/************ 925 * CloseDownFileDescriptor: 926 * Remove this file descriptor and it's I/O buffers, etc. 927 ************/ 928 929static void 930CloseDownFileDescriptor(OsCommPtr oc) 931{ 932 int connection = oc->fd; 933 934 if (oc->trans_conn) { 935 _XSERVTransDisconnect(oc->trans_conn); 936 _XSERVTransClose(oc->trans_conn); 937 } 938#ifndef WIN32 939 ConnectionTranslation[connection] = 0; 940#else 941 SetConnectionTranslation(connection, 0); 942#endif 943 FD_CLR(connection, &AllSockets); 944 FD_CLR(connection, &AllClients); 945 FD_CLR(connection, &ClientsWithInput); 946 FD_CLR(connection, &GrabImperviousClients); 947 if (GrabInProgress) 948 { 949 FD_CLR(connection, &SavedAllSockets); 950 FD_CLR(connection, &SavedAllClients); 951 FD_CLR(connection, &SavedClientsWithInput); 952 } 953 FD_CLR(connection, &ClientsWriteBlocked); 954 if (!XFD_ANYSET(&ClientsWriteBlocked)) 955 AnyClientsWriteBlocked = FALSE; 956 FD_CLR(connection, &OutputPending); 957} 958 959/***************** 960 * CheckConnections 961 * Some connection has died, go find which one and shut it down 962 * The file descriptor has been closed, but is still in AllClients. 963 * If would truly be wonderful if select() would put the bogus 964 * file descriptors in the exception mask, but nooooo. So we have 965 * to check each and every socket individually. 966 *****************/ 967 968void 969CheckConnections(void) 970{ 971#ifndef WIN32 972 fd_mask mask; 973#endif 974 fd_set tmask; 975 int curclient, curoff; 976 int i; 977 struct timeval notime; 978 int r; 979#ifdef WIN32 980 fd_set savedAllClients; 981#endif 982 983 notime.tv_sec = 0; 984 notime.tv_usec = 0; 985 986#ifndef WIN32 987 for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) 988 { 989 mask = AllClients.fds_bits[i]; 990 while (mask) 991 { 992 curoff = mffs (mask) - 1; 993 curclient = curoff + (i * (sizeof(fd_mask)*8)); 994 FD_ZERO(&tmask); 995 FD_SET(curclient, &tmask); 996 do { 997 r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); 998 } while (r < 0 && (errno == EINTR || errno == EAGAIN)); 999 if (r < 0) 1000 if (ConnectionTranslation[curclient] > 0) 1001 CloseDownClient(clients[ConnectionTranslation[curclient]]); 1002 mask &= ~((fd_mask)1 << curoff); 1003 } 1004 } 1005#else 1006 XFD_COPYSET(&AllClients, &savedAllClients); 1007 for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) 1008 { 1009 curclient = XFD_FD(&savedAllClients, i); 1010 FD_ZERO(&tmask); 1011 FD_SET(curclient, &tmask); 1012 do { 1013 r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); 1014 } while (r < 0 && (errno == EINTR || errno == EAGAIN)); 1015 if (r < 0) 1016 if (GetConnectionTranslation(curclient) > 0) 1017 CloseDownClient(clients[GetConnectionTranslation(curclient)]); 1018 } 1019#endif 1020} 1021 1022 1023/***************** 1024 * CloseDownConnection 1025 * Delete client from AllClients and free resources 1026 *****************/ 1027 1028void 1029CloseDownConnection(ClientPtr client) 1030{ 1031 OsCommPtr oc = (OsCommPtr)client->osPrivate; 1032 1033 if (FlushCallback) 1034 CallCallbacks(&FlushCallback, NULL); 1035 1036 if (oc->output && oc->output->count) 1037 FlushClient(client, oc, (char *)NULL, 0); 1038#ifdef XDMCP 1039 XdmcpCloseDisplay(oc->fd); 1040#endif 1041 CloseDownFileDescriptor(oc); 1042 FreeOsBuffers(oc); 1043 free(client->osPrivate); 1044 client->osPrivate = (pointer)NULL; 1045 if (auditTrailLevel > 1) 1046 AuditF("client %d disconnected\n", client->index); 1047} 1048 1049void 1050AddGeneralSocket(int fd) 1051{ 1052 FD_SET(fd, &AllSockets); 1053 if (GrabInProgress) 1054 FD_SET(fd, &SavedAllSockets); 1055} 1056 1057void 1058AddEnabledDevice(int fd) 1059{ 1060 FD_SET(fd, &EnabledDevices); 1061 AddGeneralSocket(fd); 1062} 1063 1064void 1065RemoveGeneralSocket(int fd) 1066{ 1067 FD_CLR(fd, &AllSockets); 1068 if (GrabInProgress) 1069 FD_CLR(fd, &SavedAllSockets); 1070} 1071 1072void 1073RemoveEnabledDevice(int fd) 1074{ 1075 FD_CLR(fd, &EnabledDevices); 1076 RemoveGeneralSocket(fd); 1077} 1078 1079/***************** 1080 * OnlyListenToOneClient: 1081 * Only accept requests from one client. Continue to handle new 1082 * connections, but don't take any protocol requests from the new 1083 * ones. Note that if GrabInProgress is set, EstablishNewConnections 1084 * needs to put new clients into SavedAllSockets and SavedAllClients. 1085 * Note also that there is no timeout for this in the protocol. 1086 * This routine is "undone" by ListenToAllClients() 1087 *****************/ 1088 1089int 1090OnlyListenToOneClient(ClientPtr client) 1091{ 1092 OsCommPtr oc = (OsCommPtr)client->osPrivate; 1093 int rc, connection = oc->fd; 1094 1095 rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess); 1096 if (rc != Success) 1097 return rc; 1098 1099 if (! GrabInProgress) 1100 { 1101 XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput); 1102 XFD_ANDSET(&ClientsWithInput, 1103 &ClientsWithInput, &GrabImperviousClients); 1104 if (FD_ISSET(connection, &SavedClientsWithInput)) 1105 { 1106 FD_CLR(connection, &SavedClientsWithInput); 1107 FD_SET(connection, &ClientsWithInput); 1108 } 1109 XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients); 1110 XFD_COPYSET(&AllSockets, &SavedAllSockets); 1111 XFD_COPYSET(&AllClients, &SavedAllClients); 1112 XFD_UNSET(&AllSockets, &AllClients); 1113 XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients); 1114 FD_SET(connection, &AllClients); 1115 XFD_ORSET(&AllSockets, &AllSockets, &AllClients); 1116 GrabInProgress = client->index; 1117 } 1118 return rc; 1119} 1120 1121/**************** 1122 * ListenToAllClients: 1123 * Undoes OnlyListentToOneClient() 1124 ****************/ 1125 1126void 1127ListenToAllClients(void) 1128{ 1129 if (GrabInProgress) 1130 { 1131 XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets); 1132 XFD_ORSET(&AllClients, &AllClients, &SavedAllClients); 1133 XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput); 1134 GrabInProgress = 0; 1135 } 1136} 1137 1138/**************** 1139 * IgnoreClient 1140 * Removes one client from input masks. 1141 * Must have cooresponding call to AttendClient. 1142 ****************/ 1143 1144void 1145IgnoreClient (ClientPtr client) 1146{ 1147 OsCommPtr oc = (OsCommPtr)client->osPrivate; 1148 int connection = oc->fd; 1149 1150 client->ignoreCount++; 1151 if (client->ignoreCount > 1) 1152 return; 1153 1154 isItTimeToYield = TRUE; 1155 if (!GrabInProgress || FD_ISSET(connection, &AllClients)) 1156 { 1157 if (FD_ISSET (connection, &ClientsWithInput)) 1158 FD_SET(connection, &IgnoredClientsWithInput); 1159 else 1160 FD_CLR(connection, &IgnoredClientsWithInput); 1161 FD_CLR(connection, &ClientsWithInput); 1162 FD_CLR(connection, &AllSockets); 1163 FD_CLR(connection, &AllClients); 1164 FD_CLR(connection, &LastSelectMask); 1165 } 1166 else 1167 { 1168 if (FD_ISSET (connection, &SavedClientsWithInput)) 1169 FD_SET(connection, &IgnoredClientsWithInput); 1170 else 1171 FD_CLR(connection, &IgnoredClientsWithInput); 1172 FD_CLR(connection, &SavedClientsWithInput); 1173 FD_CLR(connection, &SavedAllSockets); 1174 FD_CLR(connection, &SavedAllClients); 1175 } 1176} 1177 1178/**************** 1179 * AttendClient 1180 * Adds one client back into the input masks. 1181 ****************/ 1182 1183void 1184AttendClient (ClientPtr client) 1185{ 1186 OsCommPtr oc = (OsCommPtr)client->osPrivate; 1187 int connection = oc->fd; 1188 1189 client->ignoreCount--; 1190 if (client->ignoreCount) 1191 return; 1192 1193 if (!GrabInProgress || GrabInProgress == client->index || 1194 FD_ISSET(connection, &GrabImperviousClients)) 1195 { 1196 FD_SET(connection, &AllClients); 1197 FD_SET(connection, &AllSockets); 1198 FD_SET(connection, &LastSelectMask); 1199 if (FD_ISSET (connection, &IgnoredClientsWithInput)) 1200 FD_SET(connection, &ClientsWithInput); 1201 } 1202 else 1203 { 1204 FD_SET(connection, &SavedAllClients); 1205 FD_SET(connection, &SavedAllSockets); 1206 if (FD_ISSET(connection, &IgnoredClientsWithInput)) 1207 FD_SET(connection, &SavedClientsWithInput); 1208 } 1209} 1210 1211/* make client impervious to grabs; assume only executing client calls this */ 1212 1213void 1214MakeClientGrabImpervious(ClientPtr client) 1215{ 1216 OsCommPtr oc = (OsCommPtr)client->osPrivate; 1217 int connection = oc->fd; 1218 1219 FD_SET(connection, &GrabImperviousClients); 1220 1221 if (ServerGrabCallback) 1222 { 1223 ServerGrabInfoRec grabinfo; 1224 grabinfo.client = client; 1225 grabinfo.grabstate = CLIENT_IMPERVIOUS; 1226 CallCallbacks(&ServerGrabCallback, &grabinfo); 1227 } 1228} 1229 1230/* make client pervious to grabs; assume only executing client calls this */ 1231 1232void 1233MakeClientGrabPervious(ClientPtr client) 1234{ 1235 OsCommPtr oc = (OsCommPtr)client->osPrivate; 1236 int connection = oc->fd; 1237 1238 FD_CLR(connection, &GrabImperviousClients); 1239 if (GrabInProgress && (GrabInProgress != client->index)) 1240 { 1241 if (FD_ISSET(connection, &ClientsWithInput)) 1242 { 1243 FD_SET(connection, &SavedClientsWithInput); 1244 FD_CLR(connection, &ClientsWithInput); 1245 } 1246 FD_CLR(connection, &AllSockets); 1247 FD_CLR(connection, &AllClients); 1248 isItTimeToYield = TRUE; 1249 } 1250 1251 if (ServerGrabCallback) 1252 { 1253 ServerGrabInfoRec grabinfo; 1254 grabinfo.client = client; 1255 grabinfo.grabstate = CLIENT_PERVIOUS; 1256 CallCallbacks(&ServerGrabCallback, &grabinfo); 1257 } 1258} 1259 1260#ifdef XQUARTZ 1261/* Add a fd (from launchd) to our listeners */ 1262void ListenOnOpenFD(int fd, int noxauth) { 1263 char port[256]; 1264 XtransConnInfo ciptr; 1265 const char *display_env = getenv("DISPLAY"); 1266 1267 if(display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) { 1268 /* Make the path the launchd socket if our DISPLAY is set right */ 1269 strcpy(port, display_env); 1270 } else { 1271 /* Just some default so things don't break and die. */ 1272 sprintf(port, ":%d", atoi(display)); 1273 } 1274 1275 /* Make our XtransConnInfo 1276 * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c 1277 */ 1278 ciptr = _XSERVTransReopenCOTSServer(5, fd, port); 1279 if(ciptr == NULL) { 1280 ErrorF("Got NULL while trying to Reopen launchd port.\n"); 1281 return; 1282 } 1283 1284 if(noxauth) 1285 ciptr->flags = ciptr->flags | TRANS_NOXAUTH; 1286 1287 /* Allocate space to store it */ 1288 ListenTransFds = (int *) realloc(ListenTransFds, (ListenTransCount + 1) * sizeof (int)); 1289 ListenTransConns = (XtransConnInfo *) realloc(ListenTransConns, (ListenTransCount + 1) * sizeof (XtransConnInfo)); 1290 1291 /* Store it */ 1292 ListenTransConns[ListenTransCount] = ciptr; 1293 ListenTransFds[ListenTransCount] = fd; 1294 1295 FD_SET(fd, &WellKnownConnections); 1296 FD_SET(fd, &AllSockets); 1297 1298 /* Increment the count */ 1299 ListenTransCount++; 1300 1301 /* This *might* not be needed... /shrug */ 1302 ResetAuthorization(); 1303 ResetHosts(display); 1304#ifdef XDMCP 1305 XdmcpReset(); 1306#endif 1307} 1308 1309#endif 1310