]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/os/connection.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / programs / Xserver / os / connection.c
1 /* $TOG: connection.c /main/156 1997/06/05 18:43:01 sekhar $ */
2 /***********************************************************
3
4 Copyright (c) 1987, 1989  X Consortium
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the name of the X Consortium shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the X Consortium.
26
27
28 Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
29
30                         All Rights Reserved
31
32 Permission to use, copy, modify, and distribute this software and its 
33 documentation for any purpose and without fee is hereby granted, 
34 provided that the above copyright notice appear in all copies and that
35 both that copyright notice and this permission notice appear in 
36 supporting documentation, and that the name of Digital not be
37 used in advertising or publicity pertaining to distribution of the
38 software without specific, written prior permission.  
39
40 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
41 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
42 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
43 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
44 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
45 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
46 SOFTWARE.
47
48 ******************************************************************/
49 /* $XFree86: xc/programs/Xserver/os/connection.c,v 3.25.2.2 1997/07/05 15:55:45 dawes Exp $ */
50 /*****************************************************************
51  *  Stuff to create connections --- OS dependent
52  *
53  *      EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
54  *      CloseDownConnection, CheckConnections, AddEnabledDevice,
55  *      RemoveEnabledDevice, OnlyListToOneClient,
56  *      ListenToAllClients,
57  *
58  *      (WaitForSomething is in its own file)
59  *
60  *      In this implementation, a client socket table is not kept.
61  *      Instead, what would be the index into the table is just the
62  *      file descriptor of the socket.  This won't work for if the
63  *      socket ids aren't small nums (0 - 2^8)
64  *
65  *****************************************************************/
66
67 #ifdef WIN32
68 #include <X11/Xwinsock.h>
69 #endif
70 #include "X.h"
71 #include "Xproto.h"
72 #include <X11/Xtrans.h>
73 #include <errno.h>
74 #ifdef X_NOT_STDC_ENV
75 extern int errno;
76 #endif
77
78 #include <signal.h>
79 #include <stdio.h>
80
81 #ifndef WIN32
82 #ifndef MINIX
83 #ifndef Lynx
84 #include <sys/socket.h>
85 #else
86 #include <socket.h>
87 #endif
88 #endif
89
90 #ifdef hpux
91 #include <sys/utsname.h>
92 #include <sys/ioctl.h>
93 #endif
94
95 #ifdef AIXV3
96 #include <sys/ioctl.h>
97 #endif
98
99 #ifdef MINIX
100 #include <sys/nbio.h>
101
102 #define select(n,r,w,x,t) nbio_select(n,r,w,x,t)
103 #endif
104
105 #ifdef __EMX__
106 #define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t)
107 extern __const__ int _nfiles;
108 #endif
109
110 #if defined(TCPCONN) || defined(STREAMSCONN)
111 # include <netinet/in.h>
112
113 /*================================================================
114    BEGIN ORL VNC modification
115    include arpa/inet.h for inet_ntoa function prototype */
116
117 #include <arpa/inet.h>
118
119 /* END ORL VNC modification
120 ================================================================*/
121
122 # ifndef hpux
123 #  ifdef apollo
124 #   ifndef NO_TCP_H
125 #    include <netinet/tcp.h>
126 #   endif
127 #  else
128 #   ifdef CSRG_BASED
129 #    include <sys/param.h>
130 #   endif
131 #    ifndef __EMX__
132 #     include <netinet/tcp.h>
133 #    endif
134 #  endif
135 # endif
136 #endif
137
138 #ifdef AMTCPCONN
139 #include <server/ip/types.h>
140 #include <server/ip/gen/in.h>
141 #include <server/ip/gen/inet.h>
142 #endif
143
144 #if !defined(AMOEBA) && !defined(_MINIX) && !defined(__EMX__)
145 #ifndef Lynx
146 #include <sys/uio.h>
147 #else
148 #include <uio.h>
149 #endif
150 #endif
151 #endif /* WIN32 */
152 #include "misc.h"               /* for typedef of pointer */
153 #include <X11/Xpoll.h>
154 #include "osdep.h"
155 #include "opaque.h"
156 #include "dixstruct.h"
157 #ifdef XAPPGROUP
158 #include "extensions/Xagsrv.h"
159 #endif
160 #ifdef XCSECURITY
161 #define _SECURITY_SERVER
162 #include "extensions/security.h"
163 #endif
164 #ifdef LBX
165 #include "lbxserve.h"
166 #endif
167
168 #ifdef X_NOT_POSIX
169 #define Pid_t int
170 #else
171 #define Pid_t pid_t
172 #endif
173
174 #ifdef DNETCONN
175 #include <netdnet/dn.h>
176 #endif /* DNETCONN */
177
178 extern char *display;           /* The display number */
179 int lastfdesc;                  /* maximum file descriptor */
180
181 fd_set WellKnownConnections;    /* Listener mask */
182 fd_set EnabledDevices;          /* mask for input devices that are on */
183 fd_set AllSockets;              /* select on this */
184 fd_set AllClients;              /* available clients */
185 fd_set LastSelectMask;          /* mask returned from last select call */
186 fd_set ClientsWithInput;        /* clients with FULL requests in buffer */
187 fd_set ClientsWriteBlocked;     /* clients who cannot receive output */
188 fd_set OutputPending;           /* clients with reply/event data ready to go */
189 int MaxClients = MAXSOCKS;
190 Bool NewOutputPending;          /* not yet attempted to write some new output */
191 Bool AnyClientsWriteBlocked;    /* true if some client blocked on write */
192
193 Bool RunFromSmartParent;        /* send SIGUSR1 to parent process */
194 Bool PartialNetwork;            /* continue even if unable to bind all addrs */
195 char *protNoListen;             /* don't listen on this protocol */
196 static Pid_t ParentProcess;
197
198 static Bool debug_conns = FALSE;
199
200 fd_set IgnoredClientsWithInput;
201 static fd_set GrabImperviousClients;
202 static fd_set SavedAllClients;
203 static fd_set SavedAllSockets;
204 static fd_set SavedClientsWithInput;
205 int GrabInProgress = 0;
206
207 #ifndef WIN32
208 int ConnectionTranslation[MAXSOCKS];
209 #else
210 /* SPAM ALERT !!!
211  * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is
212  * not even a known maximum value, so use something quite arbitrary for now.
213  * This is clearly boggus and another form of storage which doesn't use the fd
214  * as a direct index should really be implemented for NT.
215  */
216 #define MAXFD 500
217 int ConnectionTranslation[MAXFD];
218 #endif
219
220 XtransConnInfo  *ListenTransConns = NULL;
221 int             *ListenTransFds = NULL;
222 int             ListenTransCount;
223
224 extern int auditTrailLevel;
225
226 static void ErrorConnMax(
227 #if NeedFunctionPrototypes
228 XtransConnInfo /* trans_conn */
229 #endif
230 );
231
232 #ifndef LBX
233 static
234 #endif
235 void CloseDownFileDescriptor(
236 #if NeedFunctionPrototypes
237 #ifdef LBX
238     ClientPtr   client
239 #else
240     register OsCommPtr /*oc*/
241 #endif
242 #endif
243 );
244
245 #ifdef LBX
246 extern int LbxFlushClient();
247 extern void LbxCloseClient();
248 #endif /* LBX */
249
250 static XtransConnInfo
251 lookup_trans_conn (fd)
252     int fd;
253 {
254     if (ListenTransFds)
255     {
256         int i;
257         for (i = 0; i < ListenTransCount; i++)
258             if (ListenTransFds[i] == fd)
259                 return ListenTransConns[i];
260     }
261
262     return (NULL);
263 }
264
265 #ifdef XDMCP
266 void XdmcpOpenDisplay(), XdmcpInit(), XdmcpReset(), XdmcpCloseDisplay();
267 #endif
268
269 /*****************
270  * CreateWellKnownSockets
271  *    At initialization, create the sockets to listen on for new clients.
272  *****************/
273
274 void
275 CreateWellKnownSockets()
276 {
277     int         request, i;
278     int         partial;
279     char        port[20];
280
281     FD_ZERO(&AllSockets);
282     FD_ZERO(&AllClients);
283     FD_ZERO(&LastSelectMask);
284     FD_ZERO(&ClientsWithInput);
285
286 #ifndef WIN32
287     for (i=0; i<MAXSOCKS; i++) ConnectionTranslation[i] = 0;
288 #else
289     for (i=0; i<MAXFD; i++) ConnectionTranslation[i] = 0;
290 #endif
291 #ifdef XNO_SYSCONF      /* should only be on FreeBSD 1.x and NetBSD 0.x */
292 #undef _SC_OPEN_MAX
293 #endif
294 #ifndef __EMX__
295 #ifdef _SC_OPEN_MAX
296     lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
297 #else
298 #ifdef hpux /* || defined(__EMX__) ? */
299     lastfdesc = _NFILE - 1;
300 #else
301     lastfdesc = getdtablesize() - 1;
302 #endif
303 #endif
304 #else
305     lastfdesc = _nfiles - 1;
306 #endif
307
308     if (lastfdesc > MAXSOCKS)
309     {
310         lastfdesc = MAXSOCKS;
311         if (debug_conns)
312             ErrorF( "GOT TO END OF SOCKETS %d\n", MAXSOCKS);
313     }
314
315     FD_ZERO (&WellKnownConnections);
316
317     sprintf (port, "%d", atoi (display));
318
319     if (protNoListen)
320         if (_XSERVTransNoListen(protNoListen))
321         {
322             FatalError ("Failed to disable listen for %s", protNoListen);
323         }
324     
325     if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial,
326         &ListenTransCount, &ListenTransConns) >= 0) &&
327         (ListenTransCount >= 1))
328     {
329         if (!PartialNetwork && partial)
330         {
331             FatalError ("Failed to establish all listening sockets");
332         }
333         else
334         {
335             ListenTransFds = (int *) xalloc (ListenTransCount * sizeof (int));
336
337             for (i = 0; i < ListenTransCount; i++)
338             {
339                 int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
340                 
341                 ListenTransFds[i] = fd;
342                 FD_SET (fd, &WellKnownConnections);
343
344                 if (!_XSERVTransIsLocal (ListenTransConns[i]))
345                 {
346                     DefineSelf (fd);
347                 }
348             }
349         }
350     }
351
352     if (!XFD_ANYSET (&WellKnownConnections))
353         FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running");
354 #ifndef WIN32
355     OsSignal (SIGPIPE, SIG_IGN);
356     OsSignal (SIGHUP, AutoResetServer);
357 #endif
358     OsSignal (SIGINT, GiveUp);
359     OsSignal (SIGTERM, GiveUp);
360     XFD_COPYSET (&WellKnownConnections, &AllSockets);
361     ResetHosts(display);
362     /*
363      * Magic:  If SIGUSR1 was set to SIG_IGN when
364      * the server started, assume that either
365      *
366      *  a- The parent process is ignoring SIGUSR1
367      *
368      * or
369      *
370      *  b- The parent process is expecting a SIGUSR1
371      *     when the server is ready to accept connections
372      *
373      * In the first case, the signal will be harmless,
374      * in the second case, the signal will be quite
375      * useful
376      */
377 #ifndef WIN32
378 /*================================================================
379    BEGIN ORL VNC modification
380    Don't use SIGUSR1 - linuxthread uses this internally */
381
382 /* apparently no longer true. */
383
384     if (OsSignal (SIGUSR1, SIG_IGN) == SIG_IGN)
385         RunFromSmartParent = TRUE;
386     ParentProcess = getppid ();
387     if (RunFromSmartParent) {
388         if (ParentProcess > 0) {
389             kill (ParentProcess, SIGUSR1);
390         }
391     }
392
393
394 /* END ORL VNC modification
395 ================================================================*/
396 #endif
397 #ifdef XDMCP
398     XdmcpInit ();
399 #endif
400 }
401
402 void
403 ResetWellKnownSockets ()
404 {
405     int i;
406
407     ResetOsBuffers();
408
409     for (i = 0; i < ListenTransCount; i++)
410     {
411         int status = _XSERVTransResetListener (ListenTransConns[i]);
412
413         if (status != TRANS_RESET_NOOP)
414         {
415             if (status == TRANS_RESET_FAILURE)
416             {
417                 /*
418                  * ListenTransConns[i] freed by xtrans.
419                  * Remove it from out list.
420                  */
421
422                 FD_CLR (ListenTransFds[i], &WellKnownConnections);
423                 ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
424                 ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
425                 ListenTransCount -= 1;
426                 i -= 1;
427             }
428             else if (status == TRANS_RESET_NEW_FD)
429             {
430                 /*
431                  * A new file descriptor was allocated (the old one was closed)
432                  */
433
434                 int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
435
436                 FD_CLR (ListenTransFds[i], &WellKnownConnections);
437                 ListenTransFds[i] = newfd;
438                 FD_SET(newfd, &WellKnownConnections);
439             }
440         }
441     }
442
443     ResetAuthorization ();
444     ResetHosts(display);
445     /*
446      * See above in CreateWellKnownSockets about SIGUSR1
447      */
448 #ifndef WIN32
449 /*================================================================
450    BEGIN ORL VNC modification
451    Don't use SIGUSR1 - linuxthread uses this internally */
452
453     if (RunFromSmartParent) {
454         if (ParentProcess > 0) {
455             kill (ParentProcess, SIGUSR1);
456         }
457     }
458
459 /* END ORL VNC modification
460 ================================================================*/
461 #endif
462     /*
463      * restart XDMCP
464      */
465 #ifdef XDMCP
466     XdmcpReset ();
467 #endif
468 }
469
470 static void
471 AuthAudit (client, letin, saddr, len, proto_n, auth_proto, auth_id)
472     ClientPtr client;
473     Bool letin;
474     struct sockaddr *saddr;
475     int len;
476     unsigned short proto_n;
477     char *auth_proto;
478     int auth_id;
479 {
480     char addr[128];
481     char *out = addr;
482
483     if (!((OsCommPtr)client->osPrivate)->trans_conn) {
484         strcpy(addr, "LBX proxy at ");
485         out += strlen(addr);
486     }
487     if (!len)
488         strcpy(out, "local host");
489     else
490         switch (saddr->sa_family)
491         {
492         case AF_UNSPEC:
493 #if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN)
494         case AF_UNIX:
495 #endif
496             strcpy(out, "local host");
497             break;
498 #if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN)
499         case AF_INET:
500             sprintf(out, "IP %s port %d",
501                     inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr),
502                     ntohs(((struct sockaddr_in *) saddr)->sin_port));
503             break;
504 #endif
505 #ifdef DNETCONN
506         case AF_DECnet:
507             sprintf(out, "DN %s",
508                     dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add));
509             break;
510 #endif
511 #ifdef AMRPCCONN
512         case FamilyAmoeba:
513             sprintf(addr, "AM %s", saddr);
514             break;
515 #endif
516 #if defined(AMTCPCONN) && !(defined(TCPCONN) || defined(STREAMSCONN))
517         case AF_INET:
518             sprintf(addr, "AMIP %s", inet_ntoa(*((ipaddr_t *) saddr)));
519             break;
520 #endif
521         default:
522             strcpy(out, "unknown address");
523         }
524     if (letin)
525         AuditF("client %d connected from %s\n", client->index, addr);
526     else
527         AuditF("client %d rejected from %s\n", client->index, addr);
528     if (proto_n)
529         AuditF("  Auth name: %.*s ID: %d\n", proto_n, auth_proto, auth_id);
530 }
531
532 XID
533 AuthorizationIDOfClient(client)
534     ClientPtr client;
535 {
536     if (client->osPrivate)
537         return ((OsCommPtr)client->osPrivate)->auth_id;
538     else
539         return None;
540 }
541
542
543 /*****************************************************************
544  * ClientAuthorized
545  *
546  *    Sent by the client at connection setup:
547  *                typedef struct _xConnClientPrefix {
548  *                   CARD8      byteOrder;
549  *                   BYTE       pad;
550  *                   CARD16     majorVersion, minorVersion;
551  *                   CARD16     nbytesAuthProto;    
552  *                   CARD16     nbytesAuthString;   
553  *                 } xConnClientPrefix;
554  *
555  *      It is hoped that eventually one protocol will be agreed upon.  In the
556  *        mean time, a server that implements a different protocol than the
557  *        client expects, or a server that only implements the host-based
558  *        mechanism, will simply ignore this information.
559  *
560  *****************************************************************/
561
562 char * 
563 ClientAuthorized(client, proto_n, auth_proto, string_n, auth_string)
564     ClientPtr client;
565     char *auth_proto, *auth_string;
566     unsigned int proto_n, string_n;
567 {
568     register OsCommPtr  priv;
569     Xtransaddr          *from = NULL;
570     int                 family;
571     int                 fromlen;
572     XID                 auth_id;
573     char                *reason = NULL;
574     XtransConnInfo      trans_conn;
575
576     auth_id = CheckAuthorization (proto_n, auth_proto,
577                                   string_n, auth_string, client, &reason);
578
579     priv = (OsCommPtr)client->osPrivate;
580     trans_conn = priv->trans_conn;
581 #ifdef LBX
582     if (!trans_conn) {
583         ClientPtr lbxpc = LbxProxyClient(priv->proxy);
584         trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn;
585         if (auth_id == (XID) ~0L && !GetAccessControl())
586             auth_id = ((OsCommPtr)lbxpc->osPrivate)->auth_id;
587 #ifdef XCSECURITY
588         else if (auth_id != (XID) ~0L && !SecuritySameLevel(lbxpc, auth_id)) {
589             auth_id = (XID) ~0L;
590             reason = "Client trust level differs from that of LBX Proxy";
591         }
592 #endif
593     }
594 #endif
595     if (auth_id == (XID) ~0L)
596     {
597         if (
598 #ifdef XCSECURITY           
599             (proto_n == 0 ||
600             strncmp (auth_proto, XSecurityAuthorizationName, proto_n) != 0) &&
601 #endif
602             _XSERVTransGetPeerAddr (trans_conn,
603                 &family, &fromlen, &from) != -1)
604         {
605 #ifdef AMRPCCONN
606             /* Amoeba RPC connections are already checked by the capability. */
607             if (family == FamilyAmoeba) {
608                 auth_id = (XID) 0;
609             }
610             else
611 #endif
612             if (
613 #ifdef LBX
614                 !priv->trans_conn ||
615 #endif
616                 InvalidHost ((struct sockaddr *) from, fromlen))
617                 AuthAudit(client, FALSE, (struct sockaddr *) from,
618                           fromlen, proto_n, auth_proto, auth_id);
619             else
620             {
621                 auth_id = (XID) 0;
622                 if (auditTrailLevel > 1)
623                     AuthAudit(client, TRUE,
624                         (struct sockaddr *) from, fromlen,
625                         proto_n, auth_proto, auth_id);
626             }
627
628             xfree ((char *) from);
629         }
630
631         if (auth_id == (XID) ~0L)
632             if (reason)
633                 return reason;
634             else
635                 return "Client is not authorized to connect to Server";
636     }
637     else if (auditTrailLevel > 1)
638     {
639         if (_XSERVTransGetPeerAddr (trans_conn,
640             &family, &fromlen, &from) != -1)
641         {
642             AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
643                       proto_n, auth_proto, auth_id);
644
645             xfree ((char *) from);
646         }
647     }
648     priv->auth_id = auth_id;
649     priv->conn_time = 0;
650
651 #ifdef XDMCP
652     /* indicate to Xdmcp protocol that we've opened new client */
653     XdmcpOpenDisplay(priv->fd);
654 #endif /* XDMCP */
655 #ifdef XAPPGROUP
656     if (ClientStateCallback)
657         XagCallClientStateChange (client);
658 #endif
659     /* At this point, if the client is authorized to change the access control
660      * list, we should getpeername() information, and add the client to
661      * the selfhosts list.  It's not really the host machine, but the
662      * true purpose of the selfhosts list is to see who may change the
663      * access control list.
664      */
665     return((char *)NULL);
666 }
667
668 static ClientPtr
669 #ifdef LBX
670 AllocNewConnection (trans_conn, fd, conn_time, Flush, Close, proxy)
671 #else
672 AllocNewConnection (trans_conn, fd, conn_time)
673 #endif
674     XtransConnInfo trans_conn;
675     int     fd;
676     CARD32  conn_time;
677 #ifdef LBX
678     int     (*Flush)();
679     void    (*Close)();
680     LbxProxyPtr proxy;
681 #endif
682 {
683     OsCommPtr   oc;
684     ClientPtr   client;
685     
686     if (
687 #ifdef LBX
688         trans_conn &&
689 #endif
690 #ifndef WIN32
691         fd >= lastfdesc
692 #else
693         XFD_SETCOUNT(&AllClients) >= MaxClients
694 #endif
695         )
696         return NullClient;
697     oc = (OsCommPtr)xalloc(sizeof(OsCommRec));
698     if (!oc)
699         return NullClient;
700     oc->trans_conn = trans_conn;
701     oc->fd = fd;
702     oc->input = (ConnectionInputPtr)NULL;
703     oc->output = (ConnectionOutputPtr)NULL;
704     oc->auth_id = None;
705     oc->conn_time = conn_time;
706 #ifdef LBX
707     oc->proxy = proxy;
708     oc->Flush = Flush;
709     oc->Close = Close;
710     oc->largereq = (ConnectionInputPtr) NULL;
711 #endif
712     if (!(client = NextAvailableClient((pointer)oc)))
713     {
714         xfree (oc);
715         return NullClient;
716     }
717 #ifdef LBX
718     if (trans_conn)
719 #endif
720     {
721         ConnectionTranslation[fd] = client->index;
722         if (GrabInProgress)
723         {
724             FD_SET(fd, &SavedAllClients);
725             FD_SET(fd, &SavedAllSockets);
726         }
727         else
728         {
729             FD_SET(fd, &AllClients);
730             FD_SET(fd, &AllSockets);
731         }
732     }
733     return client;
734 }
735
736 #ifdef LBX
737
738 int
739 ClientConnectionNumber (client)
740     ClientPtr   client;
741 {
742     OsCommPtr oc = (OsCommPtr) client->osPrivate;
743
744     return oc->fd;
745 }
746
747 ClientPtr
748 AllocLbxClientConnection (client, proxy)
749     ClientPtr client;
750     LbxProxyPtr proxy;
751 {
752     OsCommPtr oc = (OsCommPtr) client->osPrivate;
753
754     return AllocNewConnection ((XtransConnInfo)NULL, oc->fd, GetTimeInMillis(),
755                                LbxFlushClient, LbxCloseClient, proxy);
756 }
757
758 void
759 LbxProxyConnection (client, proxy)
760     ClientPtr   client;
761     LbxProxyPtr proxy;
762 {
763     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
764
765     FlushClient(client, oc, (char *)NULL, 0);
766     oc->proxy = proxy;
767     oc->Flush = LbxFlushClient;
768     oc->Close = LbxCloseClient;
769     LbxPrimeInput(client, proxy);
770 }
771
772 #endif
773
774 /*****************
775  * EstablishNewConnections
776  *    If anyone is waiting on listened sockets, accept them.
777  *    Returns a mask with indices of new clients.  Updates AllClients
778  *    and AllSockets.
779  *****************/
780
781 /*ARGSUSED*/
782 Bool
783 EstablishNewConnections(clientUnused, closure)
784     ClientPtr clientUnused;
785     pointer closure;
786 {
787 #ifndef WIN32
788     fd_mask readyconnections;     /* mask of listeners that are ready */
789 #else
790     fd_set  readyconnections;     /* set of listeners that are ready */
791 #endif
792     int curconn;                  /* fd of listener that's ready */
793     register int newconn;         /* fd of new client */
794     CARD32 connect_time;
795     register int i;
796     register ClientPtr client;
797     register OsCommPtr oc;
798     fd_set tmask;
799
800 #ifndef AMOEBA
801     XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections);
802 #ifndef WIN32
803     readyconnections = tmask.fds_bits[0];
804     if (!readyconnections)
805         return TRUE;
806 #else
807     XFD_COPYSET(&tmask, &readyconnections);
808     if (!XFD_ANYSET(&readyconnections))
809         return TRUE;
810 #endif
811     connect_time = GetTimeInMillis();
812     /* kill off stragglers */
813     for (i=1; i<currentMaxClients; i++)
814     {
815         if (client = clients[i])
816         {
817             oc = (OsCommPtr)(client->osPrivate);
818             if (oc && (oc->conn_time != 0) &&
819                 (connect_time - oc->conn_time) >= TimeOutValue || 
820                 client->noClientException != Success && !client->clientGone)
821                 CloseDownClient(client);     
822         }
823     }
824 #else /* AMOEBA */
825     /* EstablishNewConnections is only called when there is one new
826      * connection waiting on the first transport.
827      */
828     readyconnections = 1;
829 #endif /* AMOEBA */
830 #ifndef WIN32
831     while (readyconnections) 
832 #else
833     for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++) 
834 #endif
835     {
836         XtransConnInfo trans_conn, new_trans_conn;
837         int status;
838
839 #ifndef WIN32
840         curconn = ffs (readyconnections) - 1;
841         readyconnections &= ~(1 << curconn);
842 #else
843         curconn = XFD_FD(&readyconnections, i);
844 #endif
845
846         if ((trans_conn = lookup_trans_conn (curconn)) == NULL)
847             continue;
848
849         if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL)
850             continue;
851
852         newconn = _XSERVTransGetConnectionNumber (new_trans_conn);
853
854         _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
855
856         if (!AllocNewConnection (new_trans_conn, newconn, connect_time
857 #ifdef LBX
858                                  , StandardFlushClient,
859                                  CloseDownFileDescriptor, (LbxProxyPtr)NULL
860 #endif
861                                 ))
862         {
863             ErrorConnMax(new_trans_conn);
864             _XSERVTransClose(new_trans_conn);
865         }
866     }
867     return TRUE;
868 }
869
870 #define NOROOM "Maximum number of clients reached"
871
872 /************
873  *   ErrorConnMax
874  *     Fail a connection due to lack of client or file descriptor space
875  ************/
876
877 static void
878 ErrorConnMax(trans_conn)
879 XtransConnInfo trans_conn;
880 {
881     register 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 #ifndef AMOEBA
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 #endif
899     /* try to read the byte-order of the connection */
900     (void)_XSERVTransRead(trans_conn, &byteOrder, 1);
901     if ((byteOrder == 'l') || (byteOrder == 'B'))
902     {
903         csp.success = xFalse;
904         csp.lengthReason = sizeof(NOROOM) - 1;
905         csp.length = (sizeof(NOROOM) + 2) >> 2;
906         csp.majorVersion = X_PROTOCOL;
907         csp.minorVersion = X_PROTOCOL_REVISION;
908         if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
909             (!(*(char *) &whichbyte) && (byteOrder == 'l')))
910         {
911             swaps(&csp.majorVersion, whichbyte);
912             swaps(&csp.minorVersion, whichbyte);
913             swaps(&csp.length, whichbyte);
914         }
915         iov[0].iov_len = sz_xConnSetupPrefix;
916         iov[0].iov_base = (char *) &csp;
917         iov[1].iov_len = csp.lengthReason;
918         iov[1].iov_base = NOROOM;
919         iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
920         iov[2].iov_base = pad;
921         (void)_XSERVTransWritev(trans_conn, iov, 3);
922     }
923 }
924
925 /************
926  *   CloseDownFileDescriptor:
927  *     Remove this file descriptor and it's I/O buffers, etc.
928  ************/
929
930 #ifdef LBX
931 void
932 CloseDownFileDescriptor(client)
933     ClientPtr   client;
934 #else
935 static void
936 CloseDownFileDescriptor(oc)
937     register OsCommPtr oc;
938 #endif
939 {
940 #ifdef LBX
941     register OsCommPtr oc = (OsCommPtr) client->osPrivate;
942 #endif
943     int connection = oc->fd;
944
945     if (oc->trans_conn) {
946         _XSERVTransDisconnect(oc->trans_conn);
947         _XSERVTransClose(oc->trans_conn);
948     }
949 #ifdef LBX
950     ConnectionTranslation[connection] = 0;
951 #else
952     FreeOsBuffers(oc);
953 #endif
954     FD_CLR(connection, &AllSockets);
955     FD_CLR(connection, &AllClients);
956     FD_CLR(connection, &ClientsWithInput);
957     FD_CLR(connection, &GrabImperviousClients);
958     if (GrabInProgress)
959     {
960         FD_CLR(connection, &SavedAllSockets);
961         FD_CLR(connection, &SavedAllClients);
962         FD_CLR(connection, &SavedClientsWithInput);
963     }
964     FD_CLR(connection, &ClientsWriteBlocked);
965     if (!XFD_ANYSET(&ClientsWriteBlocked))
966         AnyClientsWriteBlocked = FALSE;
967     FD_CLR(connection, &OutputPending);
968 #ifndef LBX
969     xfree(oc);
970 #endif
971 }
972
973 /*****************
974  * CheckConections
975  *    Some connection has died, go find which one and shut it down 
976  *    The file descriptor has been closed, but is still in AllClients.
977  *    If would truly be wonderful if select() would put the bogus
978  *    file descriptors in the exception mask, but nooooo.  So we have
979  *    to check each and every socket individually.
980  *****************/
981
982 void
983 CheckConnections()
984 {
985 #ifndef WIN32
986     fd_mask             mask;
987 #endif
988     fd_set              tmask; 
989     register int        curclient, curoff;
990     int                 i;
991     struct timeval      notime;
992     int r;
993 #ifdef WIN32
994     fd_set savedAllClients;
995 #endif
996
997 #ifndef AMOEBA
998     notime.tv_sec = 0;
999     notime.tv_usec = 0;
1000
1001 #ifndef WIN32
1002     for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
1003     {
1004         mask = AllClients.fds_bits[i];
1005         while (mask)
1006         {
1007             curoff = ffs (mask) - 1;
1008             curclient = curoff + (i << 5);
1009             FD_ZERO(&tmask);
1010             FD_SET(curclient, &tmask);
1011             r = Select (curclient + 1, &tmask, NULL, NULL, &notime);
1012             if (r < 0)
1013                 CloseDownClient(clients[ConnectionTranslation[curclient]]);
1014             mask &= ~(1 << curoff);
1015         }
1016     }   
1017 #else
1018     XFD_COPYSET(&AllClients, &savedAllClients);
1019     for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++)
1020     {
1021         curclient = XFD_FD(&savedAllClients, i);
1022         FD_ZERO(&tmask);
1023         FD_SET(curclient, &tmask);
1024         r = Select (curclient + 1, &tmask, NULL, NULL, &notime);
1025         if (r < 0)
1026             CloseDownClient(clients[ConnectionTranslation[curclient]]);
1027     }   
1028 #endif
1029 #endif
1030 }
1031
1032
1033 /*****************
1034  * CloseDownConnection
1035  *    Delete client from AllClients and free resources 
1036  *****************/
1037
1038 void
1039 CloseDownConnection(client)
1040     ClientPtr client;
1041 {
1042     OsCommPtr oc = (OsCommPtr)client->osPrivate;
1043
1044     if (oc->output && oc->output->count)
1045         FlushClient(client, oc, (char *)NULL, 0);
1046 #ifdef XDMCP
1047     XdmcpCloseDisplay(oc->fd);
1048 #endif
1049 #ifndef LBX
1050     CloseDownFileDescriptor(oc);
1051 #else
1052     (*oc->Close) (client);
1053     FreeOsBuffers(oc);
1054     xfree(oc);
1055 #endif
1056     client->osPrivate = (pointer)NULL;
1057     if (auditTrailLevel > 1)
1058         AuditF("client %d disconnected\n", client->index);
1059 }
1060
1061
1062 AddEnabledDevice(fd)
1063     int fd;
1064 {
1065     FD_SET(fd, &EnabledDevices);
1066     FD_SET(fd, &AllSockets);
1067 }
1068
1069
1070 RemoveEnabledDevice(fd)
1071     int fd;
1072 {
1073     FD_CLR(fd, &EnabledDevices);
1074     FD_CLR(fd, &AllSockets);
1075 }
1076
1077 /*****************
1078  * OnlyListenToOneClient:
1079  *    Only accept requests from  one client.  Continue to handle new
1080  *    connections, but don't take any protocol requests from the new
1081  *    ones.  Note that if GrabInProgress is set, EstablishNewConnections
1082  *    needs to put new clients into SavedAllSockets and SavedAllClients.
1083  *    Note also that there is no timeout for this in the protocol.
1084  *    This routine is "undone" by ListenToAllClients()
1085  *****************/
1086
1087 OnlyListenToOneClient(client)
1088     ClientPtr client;
1089 {
1090     OsCommPtr oc = (OsCommPtr)client->osPrivate;
1091     int connection = oc->fd;
1092
1093     if (! GrabInProgress)
1094     {
1095         XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
1096         XFD_ANDSET(&ClientsWithInput,
1097                        &ClientsWithInput, &GrabImperviousClients);
1098         if (FD_ISSET(connection, &SavedClientsWithInput))
1099         {
1100             FD_CLR(connection, &SavedClientsWithInput);
1101             FD_SET(connection, &ClientsWithInput);
1102         }
1103         XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
1104         XFD_COPYSET(&AllSockets, &SavedAllSockets);
1105         XFD_COPYSET(&AllClients, &SavedAllClients);
1106         XFD_UNSET(&AllSockets, &AllClients);
1107         XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
1108         FD_SET(connection, &AllClients);
1109         XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
1110         GrabInProgress = client->index;
1111     }
1112 }
1113
1114 /****************
1115  * ListenToAllClients:
1116  *    Undoes OnlyListentToOneClient()
1117  ****************/
1118
1119 ListenToAllClients()
1120 {
1121     if (GrabInProgress)
1122     {
1123         XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
1124         XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
1125         XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
1126         GrabInProgress = 0;
1127     }   
1128 }
1129
1130 /****************
1131  * IgnoreClient
1132  *    Removes one client from input masks.
1133  *    Must have cooresponding call to AttendClient.
1134  ****************/
1135
1136 IgnoreClient (client)
1137     ClientPtr   client;
1138 {
1139     OsCommPtr oc = (OsCommPtr)client->osPrivate;
1140     int connection = oc->fd;
1141 #ifdef LBX
1142     LbxClientPtr lbxClient = LbxClient(client);
1143 #endif
1144
1145     isItTimeToYield = TRUE;
1146 #ifdef LBX
1147     if (lbxClient) {
1148         lbxClient->ignored = TRUE;
1149         return;
1150     }
1151 #endif
1152     if (!GrabInProgress || FD_ISSET(connection, &AllClients))
1153     {
1154         if (FD_ISSET (connection, &ClientsWithInput))
1155             FD_SET(connection, &IgnoredClientsWithInput);
1156         else
1157             FD_CLR(connection, &IgnoredClientsWithInput);
1158         FD_CLR(connection, &ClientsWithInput);
1159         FD_CLR(connection, &AllSockets);
1160         FD_CLR(connection, &AllClients);
1161         FD_CLR(connection, &LastSelectMask);
1162     }
1163     else
1164     {
1165         if (FD_ISSET (connection, &SavedClientsWithInput))
1166             FD_SET(connection, &IgnoredClientsWithInput);
1167         else
1168             FD_CLR(connection, &IgnoredClientsWithInput);
1169         FD_CLR(connection, &SavedClientsWithInput);
1170         FD_CLR(connection, &SavedAllSockets);
1171         FD_CLR(connection, &SavedAllClients);
1172     }
1173 }
1174
1175 /****************
1176  * AttendClient
1177  *    Adds one client back into the input masks.
1178  ****************/
1179
1180 AttendClient (client)
1181     ClientPtr   client;
1182 {
1183     OsCommPtr oc = (OsCommPtr)client->osPrivate;
1184     int connection = oc->fd;
1185 #ifdef LBX
1186     LbxClientPtr lbxClient = LbxClient(client);
1187
1188     if (lbxClient) {
1189         lbxClient->ignored = FALSE;
1190         return;
1191     }
1192 #endif
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
1213 MakeClientGrabImpervious(client)
1214     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
1232 MakeClientGrabPervious(client)
1233     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 }