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