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