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