1 /*
2
3 Copyright 1987, 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
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
28 Copyright 1994 Quarterdeck Office Systems.
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 names of Digital and
37 Quarterdeck not be used in advertising or publicity pertaining to
38 distribution of the software without specific, written prior
39 permission.
40
41 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
42 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
43 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
44 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
46 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
47 OR PERFORMANCE OF THIS SOFTWARE.
48
49 */
50
51 #ifdef HAVE_DIX_CONFIG_H
52 #include <dix-config.h>
53 #endif
54
55 #ifdef __CYGWIN__
56 #include <stdlib.h>
57 #include <signal.h>
58 /*
59 Sigh... We really need a prototype for this to know it is stdcall,
60 but #include-ing <windows.h> here is not a good idea...
61 */
62 __stdcall unsigned long GetTickCount(void);
63 #endif
64
65 #if defined(WIN32) && !defined(__CYGWIN__)
66 #include <X11/Xwinsock.h>
67 #endif
68 #include <X11/Xos.h>
69 #include <stdio.h>
70 #include <time.h>
71 #if !defined(WIN32) || !defined(__MINGW32__)
72 #include <sys/time.h>
73 #include <sys/resource.h>
74 #endif
75 #include "misc.h"
76 #include <X11/X.h>
77 #define XSERV_t
78 #define TRANS_SERVER
79 #define TRANS_REOPEN
80 #include <X11/Xtrans/Xtrans.h>
81 #include "input.h"
82 #include "dixfont.h"
83 #include <X11/fonts/libxfont2.h>
84 #include "osdep.h"
85 #include "extension.h"
86 #include <signal.h>
87 #ifndef WIN32
88 #include <sys/wait.h>
89 #endif
90 #if !defined(SYSV) && !defined(WIN32)
91 #include <sys/resource.h>
92 #endif
93 #include <sys/stat.h>
94 #include <ctype.h> /* for isspace */
95 #include <stdarg.h>
96
97 #include <stdlib.h> /* for malloc() */
98
99 #if defined(TCPCONN)
100 #ifndef WIN32
101 #include <netdb.h>
102 #endif
103 #endif
104
105 #include "opaque.h"
106
107 #include "dixstruct.h"
108
109 #include "xkbsrv.h"
110
111 #include "picture.h"
112
113 Bool noTestExtensions;
114
115 #ifdef COMPOSITE
116 Bool noCompositeExtension = FALSE;
117 #endif
118
119 #ifdef DAMAGE
120 Bool noDamageExtension = FALSE;
121 #endif
122 #ifdef DBE
123 Bool noDbeExtension = FALSE;
124 #endif
125 #ifdef DPMSExtension
126 #include "dpmsproc.h"
127 Bool noDPMSExtension = FALSE;
128 #endif
129 #ifdef GLXEXT
130 Bool noGlxExtension = FALSE;
131 #endif
132 #ifdef SCREENSAVER
133 Bool noScreenSaverExtension = FALSE;
134 #endif
135 #ifdef MITSHM
136 Bool noMITShmExtension = FALSE;
137 #endif
138 #ifdef RANDR
139 Bool noRRExtension = FALSE;
140 #endif
141 Bool noRenderExtension = FALSE;
142
143 #ifdef XCSECURITY
144 Bool noSecurityExtension = FALSE;
145 #endif
146 #ifdef RES
147 Bool noResExtension = FALSE;
148 #endif
149 #ifdef XF86BIGFONT
150 Bool noXFree86BigfontExtension = FALSE;
151 #endif
152 #ifdef XFreeXDGA
153 Bool noXFree86DGAExtension = FALSE;
154 #endif
155 #ifdef XF86DRI
156 Bool noXFree86DRIExtension = FALSE;
157 #endif
158 #ifdef XF86VIDMODE
159 Bool noXFree86VidModeExtension = FALSE;
160 #endif
161 Bool noXFixesExtension = FALSE;
162 #ifdef PANORAMIX
163 /* Xinerama is disabled by default unless enabled via +xinerama */
164 Bool noPanoramiXExtension = TRUE;
165 #endif
166 #ifdef XSELINUX
167 Bool noSELinuxExtension = FALSE;
168 int selinuxEnforcingState = SELINUX_MODE_DEFAULT;
169 #endif
170 #ifdef XV
171 Bool noXvExtension = FALSE;
172 #endif
173 #ifdef DRI2
174 Bool noDRI2Extension = FALSE;
175 #endif
176
177 Bool noGEExtension = FALSE;
178
179 #define X_INCLUDE_NETDB_H
180 #include <X11/Xos_r.h>
181
182 #include <errno.h>
183
184 Bool CoreDump;
185
186 Bool enableIndirectGLX = FALSE;
187
188 #ifdef PANORAMIX
189 Bool PanoramiXExtensionDisabledHack = FALSE;
190 #endif
191
192 int auditTrailLevel = 1;
193
194 char *SeatId = NULL;
195
196 sig_atomic_t inSignalContext = FALSE;
197
198 #if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
199 #define HAS_SAVED_IDS_AND_SETEUID
200 #endif
201
202 #ifdef MONOTONIC_CLOCK
203 static clockid_t clockid;
204 #endif
205
206 OsSigHandlerPtr
OsSignal(int sig,OsSigHandlerPtr handler)207 OsSignal(int sig, OsSigHandlerPtr handler)
208 {
209 #if defined(WIN32) && !defined(__CYGWIN__)
210 return signal(sig, handler);
211 #else
212 struct sigaction act, oact;
213
214 sigemptyset(&act.sa_mask);
215 if (handler != SIG_IGN)
216 sigaddset(&act.sa_mask, sig);
217 act.sa_flags = 0;
218 act.sa_handler = handler;
219 if (sigaction(sig, &act, &oact))
220 perror("sigaction");
221 return oact.sa_handler;
222 #endif
223 }
224
225 /*
226 * Explicit support for a server lock file like the ones used for UUCP.
227 * For architectures with virtual terminals that can run more than one
228 * server at a time. This keeps the servers from stomping on each other
229 * if the user forgets to give them different display numbers.
230 */
231 #define LOCK_DIR "/tmp"
232 #define LOCK_TMP_PREFIX "/.tX"
233 #define LOCK_PREFIX "/.X"
234 #define LOCK_SUFFIX "-lock"
235
236 #if !defined(WIN32) || defined(__CYGWIN__)
237 #define LOCK_SERVER
238 #endif
239
240 #ifndef LOCK_SERVER
241 void
LockServer(void)242 LockServer(void)
243 {}
244
245 void
UnlockServer(void)246 UnlockServer(void)
247 {}
248 #else /* LOCK_SERVER */
249 static Bool StillLocking = FALSE;
250 static char LockFile[PATH_MAX];
251 static Bool nolock = FALSE;
252
253 /*
254 * LockServer --
255 * Check if the server lock file exists. If so, check if the PID
256 * contained inside is valid. If so, then die. Otherwise, create
257 * the lock file containing the PID.
258 */
259 void
LockServer(void)260 LockServer(void)
261 {
262 char tmp[PATH_MAX], pid_str[12];
263 int lfd, i, haslock, l_pid, t;
264 const char *tmppath = LOCK_DIR;
265 int len;
266 char port[20];
267
268 if (nolock || NoListenAll)
269 return;
270 /*
271 * Path names
272 */
273 snprintf(port, sizeof(port), "%d", atoi(display));
274 len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
275 strlen(LOCK_TMP_PREFIX);
276 len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
277 if (len > sizeof(LockFile))
278 FatalError("Display name `%s' is too long\n", port);
279 (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
280 (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
281
282 /*
283 * Create a temporary file containing our PID. Attempt three times
284 * to create the file.
285 */
286 StillLocking = TRUE;
287 i = 0;
288 do {
289 i++;
290 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
291 if (lfd < 0)
292 sleep(2);
293 else
294 break;
295 } while (i < 3);
296 if (lfd < 0) {
297 unlink(tmp);
298 i = 0;
299 do {
300 i++;
301 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
302 if (lfd < 0)
303 sleep(2);
304 else
305 break;
306 } while (i < 3);
307 }
308 if (lfd < 0)
309 FatalError("Could not create lock file in %s\n", tmp);
310 snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid());
311 if (write(lfd, pid_str, 11) != 11)
312 FatalError("Could not write pid to lock file in %s\n", tmp);
313 (void) fchmod(lfd, 0444);
314 (void) close(lfd);
315
316 /*
317 * OK. Now the tmp file exists. Try three times to move it in place
318 * for the lock.
319 */
320 i = 0;
321 haslock = 0;
322 while ((!haslock) && (i++ < 3)) {
323 haslock = (link(tmp, LockFile) == 0);
324 if (haslock) {
325 /*
326 * We're done.
327 */
328 break;
329 }
330 else {
331 /*
332 * Read the pid from the existing file
333 */
334 lfd = open(LockFile, O_RDONLY | O_NOFOLLOW);
335 if (lfd < 0) {
336 unlink(tmp);
337 FatalError("Can't read lock file %s\n", LockFile);
338 }
339 pid_str[0] = '\0';
340 if (read(lfd, pid_str, 11) != 11) {
341 /*
342 * Bogus lock file.
343 */
344 unlink(LockFile);
345 close(lfd);
346 continue;
347 }
348 pid_str[11] = '\0';
349 sscanf(pid_str, "%d", &l_pid);
350 close(lfd);
351
352 /*
353 * Now try to kill the PID to see if it exists.
354 */
355 errno = 0;
356 t = kill(l_pid, 0);
357 if ((t < 0) && (errno == ESRCH)) {
358 /*
359 * Stale lock file.
360 */
361 unlink(LockFile);
362 continue;
363 }
364 else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
365 /*
366 * Process is still active.
367 */
368 unlink(tmp);
369 FatalError
370 ("Server is already active for display %s\n%s %s\n%s\n",
371 port, "\tIf this server is no longer running, remove",
372 LockFile, "\tand start again.");
373 }
374 }
375 }
376 unlink(tmp);
377 if (!haslock)
378 FatalError("Could not create server lock file: %s\n", LockFile);
379 StillLocking = FALSE;
380 }
381
382 /*
383 * UnlockServer --
384 * Remove the server lock file.
385 */
386 void
UnlockServer(void)387 UnlockServer(void)
388 {
389 if (nolock || NoListenAll)
390 return;
391
392 if (!StillLocking) {
393
394 (void) unlink(LockFile);
395 }
396 }
397 #endif /* LOCK_SERVER */
398
399 /* Force connections to close on SIGHUP from init */
400
401 void
AutoResetServer(int sig)402 AutoResetServer(int sig)
403 {
404 int olderrno = errno;
405
406 dispatchException |= DE_RESET;
407 isItTimeToYield = TRUE;
408 errno = olderrno;
409 }
410
411 /* Force connections to close and then exit on SIGTERM, SIGINT */
412
413 void
GiveUp(int sig)414 GiveUp(int sig)
415 {
416 int olderrno = errno;
417
418 dispatchException |= DE_TERMINATE;
419 isItTimeToYield = TRUE;
420 errno = olderrno;
421 }
422
423 #ifdef MONOTONIC_CLOCK
424 void
ForceClockId(clockid_t forced_clockid)425 ForceClockId(clockid_t forced_clockid)
426 {
427 struct timespec tp;
428
429 BUG_RETURN (clockid);
430
431 clockid = forced_clockid;
432
433 if (clock_gettime(clockid, &tp) != 0) {
434 FatalError("Forced clock id failed to retrieve current time: %s\n",
435 strerror(errno));
436 return;
437 }
438 }
439 #endif
440
441 #if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
442 CARD32
GetTimeInMillis(void)443 GetTimeInMillis(void)
444 {
445 return GetTickCount();
446 }
447 CARD64
GetTimeInMicros(void)448 GetTimeInMicros(void)
449 {
450 return (CARD64) GetTickCount() * 1000;
451 }
452 #else
453 CARD32
GetTimeInMillis(void)454 GetTimeInMillis(void)
455 {
456 struct timeval tv;
457
458 #ifdef MONOTONIC_CLOCK
459 struct timespec tp;
460
461 if (!clockid) {
462 #ifdef CLOCK_MONOTONIC_FAST
463 if (clock_getres(CLOCK_MONOTONIC_FAST, &tp) == 0 &&
464 (tp.tv_nsec / 1000) <= 1000 &&
465 clock_gettime(CLOCK_MONOTONIC_FAST, &tp) == 0)
466 clockid = CLOCK_MONOTONIC_FAST;
467 else
468 #endif
469 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
470 clockid = CLOCK_MONOTONIC;
471 else
472 clockid = ~0L;
473 }
474 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
475 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
476 #endif
477
478 X_GETTIMEOFDAY(&tv);
479 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
480 }
481
482 CARD64
GetTimeInMicros(void)483 GetTimeInMicros(void)
484 {
485 struct timeval tv;
486 #ifdef MONOTONIC_CLOCK
487 struct timespec tp;
488 static clockid_t uclockid;
489
490 if (!uclockid) {
491 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
492 uclockid = CLOCK_MONOTONIC;
493 else
494 uclockid = ~0L;
495 }
496 if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0)
497 return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000;
498 #endif
499
500 X_GETTIMEOFDAY(&tv);
501 return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec;
502 }
503 #endif
504
505 void
UseMsg(void)506 UseMsg(void)
507 {
508 ErrorF("use: X [:<display>] [option]\n");
509 ErrorF("-a # default pointer acceleration (factor)\n");
510 ErrorF("-ac disable access control restrictions\n");
511 ErrorF("-audit int set audit trail level\n");
512 ErrorF("-auth file select authorization file\n");
513 ErrorF("-br create root window with black background\n");
514 ErrorF("+bs enable any backing store support\n");
515 ErrorF("-bs disable any backing store support\n");
516 ErrorF("-c turns off key-click\n");
517 ErrorF("c # key-click volume (0-100)\n");
518 ErrorF("-cc int default color visual class\n");
519 ErrorF("-nocursor disable the cursor\n");
520 ErrorF("-core generate core dump on fatal error\n");
521 ErrorF("-displayfd fd file descriptor to write display number to when ready to connect\n");
522 ErrorF("-dpi int screen resolution in dots per inch\n");
523 #ifdef DPMSExtension
524 ErrorF("-dpms disables VESA DPMS monitor control\n");
525 #endif
526 ErrorF
527 ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
528 ErrorF("-f # bell base (0-100)\n");
529 ErrorF("-fc string cursor font\n");
530 ErrorF("-fn string default font name\n");
531 ErrorF("-fp string default font path\n");
532 ErrorF("-help prints message with these options\n");
533 ErrorF("+iglx Allow creating indirect GLX contexts\n");
534 ErrorF("-iglx Prohibit creating indirect GLX contexts (default)\n");
535 ErrorF("-I ignore all remaining arguments\n");
536 #ifdef RLIMIT_DATA
537 ErrorF("-ld int limit data space to N Kb\n");
538 #endif
539 #ifdef RLIMIT_NOFILE
540 ErrorF("-lf int limit number of open files to N\n");
541 #endif
542 #ifdef RLIMIT_STACK
543 ErrorF("-ls int limit stack space to N Kb\n");
544 #endif
545 #ifdef LOCK_SERVER
546 ErrorF("-nolock disable the locking mechanism\n");
547 #endif
548 ErrorF("-maxclients n set maximum number of clients (power of two)\n");
549 ErrorF("-nolisten string don't listen on protocol\n");
550 ErrorF("-listen string listen on protocol\n");
551 ErrorF("-noreset don't reset after last client exists\n");
552 ErrorF("-background [none] create root window with no background\n");
553 ErrorF("-reset reset after last client exists\n");
554 ErrorF("-p # screen-saver pattern duration (minutes)\n");
555 ErrorF("-pn accept failure to listen on all ports\n");
556 ErrorF("-nopn reject failure to listen on all ports\n");
557 ErrorF("-r turns off auto-repeat\n");
558 ErrorF("r turns on auto-repeat \n");
559 ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
560 ErrorF("-retro start with classic stipple and cursor\n");
561 ErrorF("-s # screen-saver timeout (minutes)\n");
562 ErrorF("-seat string seat to run on\n");
563 ErrorF("-t # default pointer threshold (pixels/t)\n");
564 ErrorF("-terminate terminate at server reset\n");
565 ErrorF("-to # connection time out\n");
566 ErrorF("-tst disable testing extensions\n");
567 ErrorF("ttyxx server started from init on /dev/ttyxx\n");
568 ErrorF("v video blanking for screen-saver\n");
569 ErrorF("-v screen-saver without video blanking\n");
570 ErrorF("-wm WhenMapped default backing-store\n");
571 ErrorF("-wr create root window with white background\n");
572 ErrorF("-maxbigreqsize set maximal bigrequest size \n");
573 #ifdef PANORAMIX
574 ErrorF("+xinerama Enable XINERAMA extension\n");
575 ErrorF("-xinerama Disable XINERAMA extension\n");
576 #endif
577 ErrorF
578 ("-dumbSched Disable smart scheduling and threaded input, enable old behavior\n");
579 ErrorF("-schedInterval int Set scheduler interval in msec\n");
580 ErrorF("-sigstop Enable SIGSTOP based startup\n");
581 ErrorF("+extension name Enable extension\n");
582 ErrorF("-extension name Disable extension\n");
583 #ifdef XDMCP
584 XdmcpUseMsg();
585 #endif
586 XkbUseMsg();
587 ddxUseMsg();
588 }
589
590 /* This function performs a rudimentary sanity check
591 * on the display name passed in on the command-line,
592 * since this string is used to generate filenames.
593 * It is especially important that the display name
594 * not contain a "/" and not start with a "-".
595 * --kvajk
596 */
597 static int
VerifyDisplayName(const char * d)598 VerifyDisplayName(const char *d)
599 {
600 int i;
601 int period_found = FALSE;
602 int after_period = 0;
603
604 if (d == (char *) 0)
605 return 0; /* null */
606 if (*d == '\0')
607 return 0; /* empty */
608 if (*d == '-')
609 return 0; /* could be confused for an option */
610 if (*d == '.')
611 return 0; /* must not equal "." or ".." */
612 if (strchr(d, '/') != (char *) 0)
613 return 0; /* very important!!! */
614
615 /* Since we run atoi() on the display later, only allow
616 for digits, or exception of :0.0 and similar (two decimal points max)
617 */
618 for (i = 0; i < strlen(d); i++) {
619 if (!isdigit(d[i])) {
620 if (d[i] != '.' || period_found)
621 return 0;
622 period_found = TRUE;
623 } else if (period_found)
624 after_period++;
625
626 if (after_period > 2)
627 return 0;
628 }
629
630 /* don't allow for :0. */
631 if (period_found && after_period == 0)
632 return 0;
633
634 if (atol(d) > INT_MAX)
635 return 0;
636
637 return 1;
638 }
639
640 static const char *defaultNoListenList[] = {
641 #ifndef LISTEN_TCP
642 "tcp",
643 #endif
644 #ifndef LISTEN_UNIX
645 "unix",
646 #endif
647 #ifndef LISTEN_LOCAL
648 "local",
649 #endif
650 NULL
651 };
652
653 /*
654 * This function parses the command line. Handles device-independent fields
655 * and allows ddx to handle additional fields. It is not allowed to modify
656 * argc or any of the strings pointed to by argv.
657 */
658 void
ProcessCommandLine(int argc,char * argv[])659 ProcessCommandLine(int argc, char *argv[])
660 {
661 int i, skip;
662
663 defaultKeyboardControl.autoRepeat = TRUE;
664
665 #ifdef NO_PART_NET
666 PartialNetwork = FALSE;
667 #else
668 PartialNetwork = TRUE;
669 #endif
670
671 for (i = 0; defaultNoListenList[i] != NULL; i++) {
672 if (_XSERVTransNoListen(defaultNoListenList[i]))
673 ErrorF("Failed to disable listen for %s transport",
674 defaultNoListenList[i]);
675 }
676
677 for (i = 1; i < argc; i++) {
678 /* call ddx first, so it can peek/override if it wants */
679 if ((skip = ddxProcessArgument(argc, argv, i))) {
680 i += (skip - 1);
681 }
682 else if (argv[i][0] == ':') {
683 /* initialize display */
684 display = argv[i];
685 explicit_display = TRUE;
686 display++;
687 if (!VerifyDisplayName(display)) {
688 ErrorF("Bad display name: %s\n", display);
689 UseMsg();
690 FatalError("Bad display name, exiting: %s\n", display);
691 }
692 }
693 else if (strcmp(argv[i], "-a") == 0) {
694 if (++i < argc)
695 defaultPointerControl.num = atoi(argv[i]);
696 else
697 UseMsg();
698 }
699 else if (strcmp(argv[i], "-ac") == 0) {
700 defeatAccessControl = TRUE;
701 }
702 else if (strcmp(argv[i], "-audit") == 0) {
703 if (++i < argc)
704 auditTrailLevel = atoi(argv[i]);
705 else
706 UseMsg();
707 }
708 else if (strcmp(argv[i], "-auth") == 0) {
709 if (++i < argc)
710 InitAuthorization(argv[i]);
711 else
712 UseMsg();
713 }
714 else if (strcmp(argv[i], "-br") == 0); /* default */
715 else if (strcmp(argv[i], "+bs") == 0)
716 enableBackingStore = TRUE;
717 else if (strcmp(argv[i], "-bs") == 0)
718 disableBackingStore = TRUE;
719 else if (strcmp(argv[i], "c") == 0) {
720 if (++i < argc)
721 defaultKeyboardControl.click = atoi(argv[i]);
722 else
723 UseMsg();
724 }
725 else if (strcmp(argv[i], "-c") == 0) {
726 defaultKeyboardControl.click = 0;
727 }
728 else if (strcmp(argv[i], "-cc") == 0) {
729 if (++i < argc)
730 defaultColorVisualClass = atoi(argv[i]);
731 else
732 UseMsg();
733 }
734 else if (strcmp(argv[i], "-core") == 0) {
735 #if !defined(WIN32) || !defined(__MINGW32__)
736 struct rlimit core_limit;
737
738 getrlimit(RLIMIT_CORE, &core_limit);
739 core_limit.rlim_cur = core_limit.rlim_max;
740 setrlimit(RLIMIT_CORE, &core_limit);
741 #endif
742 CoreDump = TRUE;
743 }
744 else if (strcmp(argv[i], "-nocursor") == 0) {
745 EnableCursor = FALSE;
746 }
747 else if (strcmp(argv[i], "-dpi") == 0) {
748 if (++i < argc)
749 monitorResolution = atoi(argv[i]);
750 else
751 UseMsg();
752 }
753 else if (strcmp(argv[i], "-displayfd") == 0) {
754 if (++i < argc) {
755 displayfd = atoi(argv[i]);
756 #ifdef LOCK_SERVER
757 nolock = TRUE;
758 #endif
759 }
760 else
761 UseMsg();
762 }
763 #ifdef DPMSExtension
764 else if (strcmp(argv[i], "dpms") == 0)
765 /* ignored for compatibility */ ;
766 else if (strcmp(argv[i], "-dpms") == 0)
767 DPMSDisabledSwitch = TRUE;
768 #endif
769 else if (strcmp(argv[i], "-deferglyphs") == 0) {
770 if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i]))
771 UseMsg();
772 }
773 else if (strcmp(argv[i], "-f") == 0) {
774 if (++i < argc)
775 defaultKeyboardControl.bell = atoi(argv[i]);
776 else
777 UseMsg();
778 }
779 else if (strcmp(argv[i], "-fc") == 0) {
780 if (++i < argc)
781 defaultCursorFont = argv[i];
782 else
783 UseMsg();
784 }
785 else if (strcmp(argv[i], "-fn") == 0) {
786 if (++i < argc)
787 defaultTextFont = argv[i];
788 else
789 UseMsg();
790 }
791 else if (strcmp(argv[i], "-fp") == 0) {
792 if (++i < argc) {
793 defaultFontPath = argv[i];
794 }
795 else
796 UseMsg();
797 }
798 else if (strcmp(argv[i], "-help") == 0) {
799 UseMsg();
800 exit(0);
801 }
802 else if (strcmp(argv[i], "+iglx") == 0)
803 enableIndirectGLX = TRUE;
804 else if (strcmp(argv[i], "-iglx") == 0)
805 enableIndirectGLX = FALSE;
806 else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
807 if (skip > 0)
808 i += skip - 1;
809 else
810 UseMsg();
811 }
812 #ifdef RLIMIT_DATA
813 else if (strcmp(argv[i], "-ld") == 0) {
814 if (++i < argc) {
815 limitDataSpace = atoi(argv[i]);
816 if (limitDataSpace > 0)
817 limitDataSpace *= 1024;
818 }
819 else
820 UseMsg();
821 }
822 #endif
823 #ifdef RLIMIT_NOFILE
824 else if (strcmp(argv[i], "-lf") == 0) {
825 if (++i < argc)
826 limitNoFile = atoi(argv[i]);
827 else
828 UseMsg();
829 }
830 #endif
831 #ifdef RLIMIT_STACK
832 else if (strcmp(argv[i], "-ls") == 0) {
833 if (++i < argc) {
834 limitStackSpace = atoi(argv[i]);
835 if (limitStackSpace > 0)
836 limitStackSpace *= 1024;
837 }
838 else
839 UseMsg();
840 }
841 #endif
842 #ifdef LOCK_SERVER
843 else if (strcmp(argv[i], "-nolock") == 0) {
844 #if !defined(WIN32) && !defined(__CYGWIN__)
845 if (getuid() != 0)
846 ErrorF
847 ("Warning: the -nolock option can only be used by root\n");
848 else
849 #endif
850 nolock = TRUE;
851 }
852 #endif
853 else if ( strcmp( argv[i], "-maxclients") == 0)
854 {
855 if (++i < argc) {
856 LimitClients = atoi(argv[i]);
857 if (LimitClients != 64 &&
858 LimitClients != 128 &&
859 LimitClients != 256 &&
860 LimitClients != 512 &&
861 LimitClients != 1024 &&
862 LimitClients != 2048) {
863 FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n");
864 }
865 } else
866 UseMsg();
867 }
868 else if (strcmp(argv[i], "-nolisten") == 0) {
869 if (++i < argc) {
870 if (_XSERVTransNoListen(argv[i]))
871 ErrorF("Failed to disable listen for %s transport",
872 argv[i]);
873 }
874 else
875 UseMsg();
876 }
877 else if (strcmp(argv[i], "-listen") == 0) {
878 if (++i < argc) {
879 if (_XSERVTransListen(argv[i]))
880 ErrorF("Failed to enable listen for %s transport",
881 argv[i]);
882 }
883 else
884 UseMsg();
885 }
886 else if (strcmp(argv[i], "-noreset") == 0) {
887 dispatchExceptionAtReset = 0;
888 }
889 else if (strcmp(argv[i], "-reset") == 0) {
890 dispatchExceptionAtReset = DE_RESET;
891 }
892 else if (strcmp(argv[i], "-p") == 0) {
893 if (++i < argc)
894 defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
895 MILLI_PER_MIN;
896 else
897 UseMsg();
898 }
899 else if (strcmp(argv[i], "-pogo") == 0) {
900 dispatchException = DE_TERMINATE;
901 }
902 else if (strcmp(argv[i], "-pn") == 0)
903 PartialNetwork = TRUE;
904 else if (strcmp(argv[i], "-nopn") == 0)
905 PartialNetwork = FALSE;
906 else if (strcmp(argv[i], "r") == 0)
907 defaultKeyboardControl.autoRepeat = TRUE;
908 else if (strcmp(argv[i], "-r") == 0)
909 defaultKeyboardControl.autoRepeat = FALSE;
910 else if (strcmp(argv[i], "-retro") == 0)
911 party_like_its_1989 = TRUE;
912 else if (strcmp(argv[i], "-s") == 0) {
913 if (++i < argc)
914 defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
915 MILLI_PER_MIN;
916 else
917 UseMsg();
918 }
919 else if (strcmp(argv[i], "-seat") == 0) {
920 if (++i < argc)
921 SeatId = argv[i];
922 else
923 UseMsg();
924 }
925 else if (strcmp(argv[i], "-t") == 0) {
926 if (++i < argc)
927 defaultPointerControl.threshold = atoi(argv[i]);
928 else
929 UseMsg();
930 }
931 else if (strcmp(argv[i], "-terminate") == 0) {
932 dispatchExceptionAtReset = DE_TERMINATE;
933 }
934 else if (strcmp(argv[i], "-to") == 0) {
935 if (++i < argc)
936 TimeOutValue = ((CARD32) atoi(argv[i])) * MILLI_PER_SECOND;
937 else
938 UseMsg();
939 }
940 else if (strcmp(argv[i], "-tst") == 0) {
941 noTestExtensions = TRUE;
942 }
943 else if (strcmp(argv[i], "v") == 0)
944 defaultScreenSaverBlanking = PreferBlanking;
945 else if (strcmp(argv[i], "-v") == 0)
946 defaultScreenSaverBlanking = DontPreferBlanking;
947 else if (strcmp(argv[i], "-wm") == 0)
948 defaultBackingStore = WhenMapped;
949 else if (strcmp(argv[i], "-wr") == 0)
950 whiteRoot = TRUE;
951 else if (strcmp(argv[i], "-background") == 0) {
952 if (++i < argc) {
953 if (!strcmp(argv[i], "none"))
954 bgNoneRoot = TRUE;
955 else
956 UseMsg();
957 }
958 }
959 else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
960 if (++i < argc) {
961 long reqSizeArg = atol(argv[i]);
962
963 /* Request size > 128MB does not make much sense... */
964 if (reqSizeArg > 0L && reqSizeArg < 128L) {
965 maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
966 }
967 else {
968 UseMsg();
969 }
970 }
971 else {
972 UseMsg();
973 }
974 }
975 #ifdef PANORAMIX
976 else if (strcmp(argv[i], "+xinerama") == 0) {
977 noPanoramiXExtension = FALSE;
978 }
979 else if (strcmp(argv[i], "-xinerama") == 0) {
980 noPanoramiXExtension = TRUE;
981 }
982 else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
983 PanoramiXExtensionDisabledHack = TRUE;
984 }
985 #endif
986 else if (strcmp(argv[i], "-I") == 0) {
987 /* ignore all remaining arguments */
988 break;
989 }
990 else if (strncmp(argv[i], "tty", 3) == 0) {
991 /* init supplies us with this useless information */
992 }
993 #ifdef XDMCP
994 else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
995 i = skip - 1;
996 }
997 #endif
998 else if (strcmp(argv[i], "-dumbSched") == 0) {
999 InputThreadEnable = FALSE;
1000 #ifdef HAVE_SETITIMER
1001 SmartScheduleSignalEnable = FALSE;
1002 #endif
1003 }
1004 else if (strcmp(argv[i], "-schedInterval") == 0) {
1005 if (++i < argc) {
1006 SmartScheduleInterval = atoi(argv[i]);
1007 SmartScheduleSlice = SmartScheduleInterval;
1008 }
1009 else
1010 UseMsg();
1011 }
1012 else if (strcmp(argv[i], "-schedMax") == 0) {
1013 if (++i < argc) {
1014 SmartScheduleMaxSlice = atoi(argv[i]);
1015 }
1016 else
1017 UseMsg();
1018 }
1019 else if (strcmp(argv[i], "-render") == 0) {
1020 if (++i < argc) {
1021 int policy = PictureParseCmapPolicy(argv[i]);
1022
1023 if (policy != PictureCmapPolicyInvalid)
1024 PictureCmapPolicy = policy;
1025 else
1026 UseMsg();
1027 }
1028 else
1029 UseMsg();
1030 }
1031 else if (strcmp(argv[i], "-sigstop") == 0) {
1032 RunFromSigStopParent = TRUE;
1033 }
1034 else if (strcmp(argv[i], "+extension") == 0) {
1035 if (++i < argc) {
1036 if (!EnableDisableExtension(argv[i], TRUE))
1037 EnableDisableExtensionError(argv[i], TRUE);
1038 }
1039 else
1040 UseMsg();
1041 }
1042 else if (strcmp(argv[i], "-extension") == 0) {
1043 if (++i < argc) {
1044 if (!EnableDisableExtension(argv[i], FALSE))
1045 EnableDisableExtensionError(argv[i], FALSE);
1046 }
1047 else
1048 UseMsg();
1049 }
1050 else {
1051 ErrorF("Unrecognized option: %s\n", argv[i]);
1052 UseMsg();
1053 FatalError("Unrecognized option: %s\n", argv[i]);
1054 }
1055 }
1056 }
1057
1058 /* Implement a simple-minded font authorization scheme. The authorization
1059 name is "hp-hostname-1", the contents are simply the host name. */
1060 int
set_font_authorizations(char ** authorizations,int * authlen,void * client)1061 set_font_authorizations(char **authorizations, int *authlen, void *client)
1062 {
1063 #define AUTHORIZATION_NAME "hp-hostname-1"
1064 #if defined(TCPCONN)
1065 static char *result = NULL;
1066 static char *p = NULL;
1067
1068 if (p == NULL) {
1069 char hname[1024], *hnameptr;
1070 unsigned int len;
1071
1072 #if defined(IPv6) && defined(AF_INET6)
1073 struct addrinfo hints, *ai = NULL;
1074 #else
1075 struct hostent *host;
1076
1077 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1078 _Xgethostbynameparams hparams;
1079 #endif
1080 #endif
1081
1082 gethostname(hname, 1024);
1083 #if defined(IPv6) && defined(AF_INET6)
1084 memset(&hints, 0, sizeof(hints));
1085 hints.ai_flags = AI_CANONNAME;
1086 if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
1087 hnameptr = ai->ai_canonname;
1088 }
1089 else {
1090 hnameptr = hname;
1091 }
1092 #else
1093 host = _XGethostbyname(hname, hparams);
1094 if (host == NULL)
1095 hnameptr = hname;
1096 else
1097 hnameptr = host->h_name;
1098 #endif
1099
1100 len = strlen(hnameptr) + 1;
1101 result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
1102
1103 p = result;
1104 *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
1105 *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
1106 *p++ = (len) >> 8;
1107 *p++ = (len & 0xff);
1108
1109 memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
1110 p += sizeof(AUTHORIZATION_NAME);
1111 memmove(p, hnameptr, len);
1112 p += len;
1113 #if defined(IPv6) && defined(AF_INET6)
1114 if (ai) {
1115 freeaddrinfo(ai);
1116 }
1117 #endif
1118 }
1119 *authlen = p - result;
1120 *authorizations = result;
1121 return 1;
1122 #else /* TCPCONN */
1123 return 0;
1124 #endif /* TCPCONN */
1125 }
1126
1127 void *
XNFalloc(unsigned long amount)1128 XNFalloc(unsigned long amount)
1129 {
1130 void *ptr = malloc(amount);
1131
1132 if (!ptr)
1133 FatalError("Out of memory");
1134 return ptr;
1135 }
1136
1137 /* The original XNFcalloc was used with the xnfcalloc macro which multiplied
1138 * the arguments at the call site without allowing calloc to check for overflow.
1139 * XNFcallocarray was added to fix that without breaking ABI.
1140 */
1141 void *
XNFcalloc(unsigned long amount)1142 XNFcalloc(unsigned long amount)
1143 {
1144 return XNFcallocarray(1, amount);
1145 }
1146
1147 void *
XNFcallocarray(size_t nmemb,size_t size)1148 XNFcallocarray(size_t nmemb, size_t size)
1149 {
1150 void *ret = calloc(nmemb, size);
1151
1152 if (!ret)
1153 FatalError("XNFcalloc: Out of memory");
1154 return ret;
1155 }
1156
1157 void *
XNFrealloc(void * ptr,unsigned long amount)1158 XNFrealloc(void *ptr, unsigned long amount)
1159 {
1160 void *ret = realloc(ptr, amount);
1161
1162 if (!ret)
1163 FatalError("XNFrealloc: Out of memory");
1164 return ret;
1165 }
1166
1167 void *
XNFreallocarray(void * ptr,size_t nmemb,size_t size)1168 XNFreallocarray(void *ptr, size_t nmemb, size_t size)
1169 {
1170 void *ret = reallocarray(ptr, nmemb, size);
1171
1172 if (!ret)
1173 FatalError("XNFreallocarray: Out of memory");
1174 return ret;
1175 }
1176
1177 char *
Xstrdup(const char * s)1178 Xstrdup(const char *s)
1179 {
1180 if (s == NULL)
1181 return NULL;
1182 return strdup(s);
1183 }
1184
1185 char *
XNFstrdup(const char * s)1186 XNFstrdup(const char *s)
1187 {
1188 char *ret;
1189
1190 if (s == NULL)
1191 return NULL;
1192
1193 ret = strdup(s);
1194 if (!ret)
1195 FatalError("XNFstrdup: Out of memory");
1196 return ret;
1197 }
1198
1199 void
SmartScheduleStopTimer(void)1200 SmartScheduleStopTimer(void)
1201 {
1202 #ifdef HAVE_SETITIMER
1203 struct itimerval timer;
1204
1205 if (!SmartScheduleSignalEnable)
1206 return;
1207 timer.it_interval.tv_sec = 0;
1208 timer.it_interval.tv_usec = 0;
1209 timer.it_value.tv_sec = 0;
1210 timer.it_value.tv_usec = 0;
1211 (void) setitimer(ITIMER_REAL, &timer, 0);
1212 #endif
1213 }
1214
1215 void
SmartScheduleStartTimer(void)1216 SmartScheduleStartTimer(void)
1217 {
1218 #ifdef HAVE_SETITIMER
1219 struct itimerval timer;
1220
1221 if (!SmartScheduleSignalEnable)
1222 return;
1223 timer.it_interval.tv_sec = 0;
1224 timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
1225 timer.it_value.tv_sec = 0;
1226 timer.it_value.tv_usec = SmartScheduleInterval * 1000;
1227 setitimer(ITIMER_REAL, &timer, 0);
1228 #endif
1229 }
1230
1231 #ifdef HAVE_SETITIMER
1232 static void
SmartScheduleTimer(int sig)1233 SmartScheduleTimer(int sig)
1234 {
1235 SmartScheduleTime += SmartScheduleInterval;
1236 }
1237
1238 static int
SmartScheduleEnable(void)1239 SmartScheduleEnable(void)
1240 {
1241 int ret = 0;
1242 struct sigaction act;
1243
1244 if (!SmartScheduleSignalEnable)
1245 return 0;
1246
1247 memset((char *) &act, 0, sizeof(struct sigaction));
1248
1249 /* Set up the timer signal function */
1250 act.sa_flags = SA_RESTART;
1251 act.sa_handler = SmartScheduleTimer;
1252 sigemptyset(&act.sa_mask);
1253 sigaddset(&act.sa_mask, SIGALRM);
1254 ret = sigaction(SIGALRM, &act, 0);
1255 return ret;
1256 }
1257
1258 static int
SmartSchedulePause(void)1259 SmartSchedulePause(void)
1260 {
1261 int ret = 0;
1262 struct sigaction act;
1263
1264 if (!SmartScheduleSignalEnable)
1265 return 0;
1266
1267 memset((char *) &act, 0, sizeof(struct sigaction));
1268
1269 act.sa_handler = SIG_IGN;
1270 sigemptyset(&act.sa_mask);
1271 ret = sigaction(SIGALRM, &act, 0);
1272 return ret;
1273 }
1274 #endif
1275
1276 void
SmartScheduleInit(void)1277 SmartScheduleInit(void)
1278 {
1279 #ifdef HAVE_SETITIMER
1280 if (SmartScheduleEnable() < 0) {
1281 perror("sigaction for smart scheduler");
1282 SmartScheduleSignalEnable = FALSE;
1283 }
1284 #endif
1285 }
1286
1287 #ifdef SIG_BLOCK
1288 static sigset_t PreviousSignalMask;
1289 static int BlockedSignalCount;
1290 #endif
1291
1292 void
OsBlockSignals(void)1293 OsBlockSignals(void)
1294 {
1295 #ifdef SIG_BLOCK
1296 if (BlockedSignalCount++ == 0) {
1297 sigset_t set;
1298
1299 sigemptyset(&set);
1300 sigaddset(&set, SIGALRM);
1301 sigaddset(&set, SIGVTALRM);
1302 #ifdef SIGWINCH
1303 sigaddset(&set, SIGWINCH);
1304 #endif
1305 sigaddset(&set, SIGTSTP);
1306 sigaddset(&set, SIGTTIN);
1307 sigaddset(&set, SIGTTOU);
1308 sigaddset(&set, SIGCHLD);
1309 xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask);
1310 }
1311 #endif
1312 }
1313
1314 void
OsReleaseSignals(void)1315 OsReleaseSignals(void)
1316 {
1317 #ifdef SIG_BLOCK
1318 if (--BlockedSignalCount == 0) {
1319 xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0);
1320 }
1321 #endif
1322 }
1323
1324 void
OsResetSignals(void)1325 OsResetSignals(void)
1326 {
1327 #ifdef SIG_BLOCK
1328 while (BlockedSignalCount > 0)
1329 OsReleaseSignals();
1330 input_force_unlock();
1331 #endif
1332 }
1333
1334 /*
1335 * Pending signals may interfere with core dumping. Provide a
1336 * mechanism to block signals when aborting.
1337 */
1338
1339 void
OsAbort(void)1340 OsAbort(void)
1341 {
1342 #ifndef __APPLE__
1343 OsBlockSignals();
1344 #endif
1345 #if !defined(WIN32) || defined(__CYGWIN__)
1346 /* abort() raises SIGABRT, so we have to stop handling that to prevent
1347 * recursion
1348 */
1349 OsSignal(SIGABRT, SIG_DFL);
1350 #endif
1351 abort();
1352 }
1353
1354 #if !defined(WIN32)
1355 /*
1356 * "safer" versions of system(3), popen(3) and pclose(3) which give up
1357 * all privs before running a command.
1358 *
1359 * This is based on the code in FreeBSD 2.2 libc.
1360 *
1361 * XXX It'd be good to redirect stderr so that it ends up in the log file
1362 * as well. As it is now, xkbcomp messages don't end up in the log file.
1363 */
1364
1365 int
System(const char * command)1366 System(const char *command)
1367 {
1368 int pid, p;
1369 void (*csig) (int);
1370 int status;
1371
1372 if (!command)
1373 return 1;
1374
1375 csig = OsSignal(SIGCHLD, SIG_DFL);
1376 if (csig == SIG_ERR) {
1377 perror("signal");
1378 return -1;
1379 }
1380 DebugF("System: `%s'\n", command);
1381
1382 switch (pid = fork()) {
1383 case -1: /* error */
1384 p = -1;
1385 break;
1386 case 0: /* child */
1387 if (setgid(getgid()) == -1)
1388 _exit(127);
1389 if (setuid(getuid()) == -1)
1390 _exit(127);
1391 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1392 _exit(127);
1393 default: /* parent */
1394 do {
1395 p = waitpid(pid, &status, 0);
1396 } while (p == -1 && errno == EINTR);
1397
1398 }
1399
1400 if (OsSignal(SIGCHLD, csig) == SIG_ERR) {
1401 perror("signal");
1402 return -1;
1403 }
1404
1405 return p == -1 ? -1 : status;
1406 }
1407
1408 static struct pid {
1409 struct pid *next;
1410 FILE *fp;
1411 int pid;
1412 } *pidlist;
1413
1414 void *
Popen(const char * command,const char * type)1415 Popen(const char *command, const char *type)
1416 {
1417 struct pid *cur;
1418 FILE *iop;
1419 int pdes[2], pid;
1420
1421 if (command == NULL || type == NULL)
1422 return NULL;
1423
1424 if ((*type != 'r' && *type != 'w') || type[1])
1425 return NULL;
1426
1427 if ((cur = malloc(sizeof(struct pid))) == NULL)
1428 return NULL;
1429
1430 if (pipe(pdes) < 0) {
1431 free(cur);
1432 return NULL;
1433 }
1434
1435 /* Ignore the smart scheduler while this is going on */
1436 #ifdef HAVE_SETITIMER
1437 if (SmartSchedulePause() < 0) {
1438 close(pdes[0]);
1439 close(pdes[1]);
1440 free(cur);
1441 perror("signal");
1442 return NULL;
1443 }
1444 #endif
1445
1446 switch (pid = fork()) {
1447 case -1: /* error */
1448 close(pdes[0]);
1449 close(pdes[1]);
1450 free(cur);
1451 #ifdef HAVE_SETITIMER
1452 if (SmartScheduleEnable() < 0)
1453 perror("signal");
1454 #endif
1455 return NULL;
1456 case 0: /* child */
1457 if (setgid(getgid()) == -1)
1458 _exit(127);
1459 if (setuid(getuid()) == -1)
1460 _exit(127);
1461 if (*type == 'r') {
1462 if (pdes[1] != 1) {
1463 /* stdout */
1464 dup2(pdes[1], 1);
1465 close(pdes[1]);
1466 }
1467 close(pdes[0]);
1468 }
1469 else {
1470 if (pdes[0] != 0) {
1471 /* stdin */
1472 dup2(pdes[0], 0);
1473 close(pdes[0]);
1474 }
1475 close(pdes[1]);
1476 }
1477 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1478 _exit(127);
1479 }
1480
1481 /* Avoid EINTR during stdio calls */
1482 OsBlockSignals();
1483
1484 /* parent */
1485 if (*type == 'r') {
1486 iop = fdopen(pdes[0], type);
1487 close(pdes[1]);
1488 }
1489 else {
1490 iop = fdopen(pdes[1], type);
1491 close(pdes[0]);
1492 }
1493
1494 cur->fp = iop;
1495 cur->pid = pid;
1496 cur->next = pidlist;
1497 pidlist = cur;
1498
1499 DebugF("Popen: `%s', fp = %p\n", command, iop);
1500
1501 return iop;
1502 }
1503
1504 /* fopen that drops privileges */
1505 void *
Fopen(const char * file,const char * type)1506 Fopen(const char *file, const char *type)
1507 {
1508 FILE *iop;
1509
1510 #ifndef HAS_SAVED_IDS_AND_SETEUID
1511 struct pid *cur;
1512 int pdes[2], pid;
1513
1514 if (file == NULL || type == NULL)
1515 return NULL;
1516
1517 if ((*type != 'r' && *type != 'w') || type[1])
1518 return NULL;
1519
1520 if ((cur = malloc(sizeof(struct pid))) == NULL)
1521 return NULL;
1522
1523 if (pipe(pdes) < 0) {
1524 free(cur);
1525 return NULL;
1526 }
1527
1528 switch (pid = fork()) {
1529 case -1: /* error */
1530 close(pdes[0]);
1531 close(pdes[1]);
1532 free(cur);
1533 return NULL;
1534 case 0: /* child */
1535 if (setgid(getgid()) == -1)
1536 _exit(127);
1537 if (setuid(getuid()) == -1)
1538 _exit(127);
1539 if (*type == 'r') {
1540 if (pdes[1] != 1) {
1541 /* stdout */
1542 dup2(pdes[1], 1);
1543 close(pdes[1]);
1544 }
1545 close(pdes[0]);
1546 }
1547 else {
1548 if (pdes[0] != 0) {
1549 /* stdin */
1550 dup2(pdes[0], 0);
1551 close(pdes[0]);
1552 }
1553 close(pdes[1]);
1554 }
1555 execl("/bin/cat", "cat", file, (char *) NULL);
1556 _exit(127);
1557 }
1558
1559 /* Avoid EINTR during stdio calls */
1560 OsBlockSignals();
1561
1562 /* parent */
1563 if (*type == 'r') {
1564 iop = fdopen(pdes[0], type);
1565 close(pdes[1]);
1566 }
1567 else {
1568 iop = fdopen(pdes[1], type);
1569 close(pdes[0]);
1570 }
1571
1572 cur->fp = iop;
1573 cur->pid = pid;
1574 cur->next = pidlist;
1575 pidlist = cur;
1576
1577 DebugF("Fopen(%s), fp = %p\n", file, iop);
1578
1579 return iop;
1580 #else
1581 int ruid, euid;
1582
1583 ruid = getuid();
1584 euid = geteuid();
1585
1586 if (seteuid(ruid) == -1) {
1587 return NULL;
1588 }
1589 iop = fopen(file, type);
1590
1591 if (seteuid(euid) == -1) {
1592 fclose(iop);
1593 return NULL;
1594 }
1595 return iop;
1596 #endif /* HAS_SAVED_IDS_AND_SETEUID */
1597 }
1598
1599 int
Pclose(void * iop)1600 Pclose(void *iop)
1601 {
1602 struct pid *cur, *last;
1603 int pstat;
1604 int pid;
1605
1606 DebugF("Pclose: fp = %p\n", iop);
1607 fclose(iop);
1608
1609 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1610 if (cur->fp == iop)
1611 break;
1612 if (cur == NULL)
1613 return -1;
1614
1615 do {
1616 pid = waitpid(cur->pid, &pstat, 0);
1617 } while (pid == -1 && errno == EINTR);
1618
1619 if (last == NULL)
1620 pidlist = cur->next;
1621 else
1622 last->next = cur->next;
1623 free(cur);
1624
1625 /* allow EINTR again */
1626 OsReleaseSignals();
1627
1628 #ifdef HAVE_SETITIMER
1629 if (SmartScheduleEnable() < 0) {
1630 perror("signal");
1631 return -1;
1632 }
1633 #endif
1634
1635 return pid == -1 ? -1 : pstat;
1636 }
1637
1638 int
Fclose(void * iop)1639 Fclose(void *iop)
1640 {
1641 #ifdef HAS_SAVED_IDS_AND_SETEUID
1642 return fclose(iop);
1643 #else
1644 return Pclose(iop);
1645 #endif
1646 }
1647
1648 #endif /* !WIN32 */
1649
1650 #ifdef WIN32
1651
1652 #include <X11/Xwindows.h>
1653
1654 const char *
Win32TempDir(void)1655 Win32TempDir(void)
1656 {
1657 static char buffer[PATH_MAX];
1658
1659 if (GetTempPath(sizeof(buffer), buffer)) {
1660 int len;
1661
1662 buffer[sizeof(buffer) - 1] = 0;
1663 len = strlen(buffer);
1664 if (len > 0)
1665 if (buffer[len - 1] == '\\')
1666 buffer[len - 1] = 0;
1667 return buffer;
1668 }
1669 if (getenv("TEMP") != NULL)
1670 return getenv("TEMP");
1671 else if (getenv("TMP") != NULL)
1672 return getenv("TMP");
1673 else
1674 return "/tmp";
1675 }
1676
1677 int
System(const char * cmdline)1678 System(const char *cmdline)
1679 {
1680 STARTUPINFO si;
1681 PROCESS_INFORMATION pi;
1682 DWORD dwExitCode;
1683 char *cmd = strdup(cmdline);
1684
1685 ZeroMemory(&si, sizeof(si));
1686 si.cb = sizeof(si);
1687 ZeroMemory(&pi, sizeof(pi));
1688
1689 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
1690 LPVOID buffer;
1691
1692 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1693 FORMAT_MESSAGE_FROM_SYSTEM |
1694 FORMAT_MESSAGE_IGNORE_INSERTS,
1695 NULL,
1696 GetLastError(),
1697 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1698 (LPTSTR) &buffer, 0, NULL)) {
1699 ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
1700 }
1701 else {
1702 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
1703 LocalFree(buffer);
1704 }
1705
1706 free(cmd);
1707 return -1;
1708 }
1709 /* Wait until child process exits. */
1710 WaitForSingleObject(pi.hProcess, INFINITE);
1711
1712 GetExitCodeProcess(pi.hProcess, &dwExitCode);
1713
1714 /* Close process and thread handles. */
1715 CloseHandle(pi.hProcess);
1716 CloseHandle(pi.hThread);
1717 free(cmd);
1718
1719 return dwExitCode;
1720 }
1721 #endif
1722
1723 Bool
PrivsElevated(void)1724 PrivsElevated(void)
1725 {
1726 static Bool privsTested = FALSE;
1727 static Bool privsElevated = TRUE;
1728
1729 if (!privsTested) {
1730 #if defined(WIN32)
1731 privsElevated = FALSE;
1732 #else
1733 if ((getuid() != geteuid()) || (getgid() != getegid())) {
1734 privsElevated = TRUE;
1735 }
1736 else {
1737 #if defined(HAVE_ISSETUGID)
1738 privsElevated = issetugid();
1739 #elif defined(HAVE_GETRESUID)
1740 uid_t ruid, euid, suid;
1741 gid_t rgid, egid, sgid;
1742
1743 if ((getresuid(&ruid, &euid, &suid) == 0) &&
1744 (getresgid(&rgid, &egid, &sgid) == 0)) {
1745 privsElevated = (euid != suid) || (egid != sgid);
1746 }
1747 else {
1748 printf("Failed getresuid or getresgid");
1749 /* Something went wrong, make defensive assumption */
1750 privsElevated = TRUE;
1751 }
1752 #else
1753 if (getuid() == 0) {
1754 /* running as root: uid==euid==0 */
1755 privsElevated = FALSE;
1756 }
1757 else {
1758 /*
1759 * If there are saved ID's the process might still be privileged
1760 * even though the above test succeeded. If issetugid() and
1761 * getresgid() aren't available, test this by trying to set
1762 * euid to 0.
1763 */
1764 unsigned int oldeuid;
1765
1766 oldeuid = geteuid();
1767
1768 if (seteuid(0) != 0) {
1769 privsElevated = FALSE;
1770 }
1771 else {
1772 if (seteuid(oldeuid) != 0) {
1773 FatalError("Failed to drop privileges. Exiting\n");
1774 }
1775 privsElevated = TRUE;
1776 }
1777 }
1778 #endif
1779 }
1780 #endif
1781 privsTested = TRUE;
1782 }
1783 return privsElevated;
1784 }
1785
1786 /*
1787 * CheckUserParameters: check for long command line arguments and long
1788 * environment variables. By default, these checks are only done when
1789 * the server's euid != ruid. In 3.3.x, these checks were done in an
1790 * external wrapper utility.
1791 */
1792
1793 /* Consider LD* variables insecure? */
1794 #ifndef REMOVE_ENV_LD
1795 #define REMOVE_ENV_LD 1
1796 #endif
1797
1798 /* Remove long environment variables? */
1799 #ifndef REMOVE_LONG_ENV
1800 #define REMOVE_LONG_ENV 1
1801 #endif
1802
1803 /*
1804 * Disallow stdout or stderr as pipes? It's possible to block the X server
1805 * when piping stdout+stderr to a pipe.
1806 *
1807 * Don't enable this because it looks like it's going to cause problems.
1808 */
1809 #ifndef NO_OUTPUT_PIPES
1810 #define NO_OUTPUT_PIPES 0
1811 #endif
1812
1813 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
1814 #ifndef CHECK_EUID
1815 #ifndef WIN32
1816 #define CHECK_EUID 1
1817 #else
1818 #define CHECK_EUID 0
1819 #endif
1820 #endif
1821
1822 /*
1823 * Maybe the locale can be faked to make isprint(3) report that everything
1824 * is printable? Avoid it by default.
1825 */
1826 #ifndef USE_ISPRINT
1827 #define USE_ISPRINT 0
1828 #endif
1829
1830 #define MAX_ARG_LENGTH 128
1831 #define MAX_ENV_LENGTH 256
1832 #define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */
1833
1834 #if USE_ISPRINT
1835 #include <ctype.h>
1836 #define checkPrintable(c) isprint(c)
1837 #else
1838 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
1839 #endif
1840
1841 enum BadCode {
1842 NotBad = 0,
1843 UnsafeArg,
1844 ArgTooLong,
1845 UnprintableArg,
1846 EnvTooLong,
1847 OutputIsPipe,
1848 InternalError
1849 };
1850
1851 #if defined(VENDORSUPPORT)
1852 #define BUGADDRESS VENDORSUPPORT
1853 #elif defined(BUILDERADDR)
1854 #define BUGADDRESS BUILDERADDR
1855 #else
1856 #define BUGADDRESS "xorg@freedesktop.org"
1857 #endif
1858
1859 void
CheckUserParameters(int argc,char ** argv,char ** envp)1860 CheckUserParameters(int argc, char **argv, char **envp)
1861 {
1862 enum BadCode bad = NotBad;
1863 int i = 0, j;
1864 char *a, *e = NULL;
1865
1866 #if CHECK_EUID
1867 if (PrivsElevated())
1868 #endif
1869 {
1870 /* Check each argv[] */
1871 for (i = 1; i < argc; i++) {
1872 if (strcmp(argv[i], "-fp") == 0) {
1873 i++; /* continue with next argument. skip the length check */
1874 if (i >= argc)
1875 break;
1876 }
1877 else {
1878 if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1879 bad = ArgTooLong;
1880 break;
1881 }
1882 }
1883 a = argv[i];
1884 while (*a) {
1885 if (checkPrintable(*a) == 0) {
1886 bad = UnprintableArg;
1887 break;
1888 }
1889 a++;
1890 }
1891 if (bad)
1892 break;
1893 }
1894 if (!bad) {
1895 /* Check each envp[] */
1896 for (i = 0; envp[i]; i++) {
1897
1898 /* Check for bad environment variables and values */
1899 #if REMOVE_ENV_LD
1900 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1901 for (j = i; envp[j]; j++) {
1902 envp[j] = envp[j + 1];
1903 }
1904 }
1905 #endif
1906 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
1907 #if REMOVE_LONG_ENV
1908 for (j = i; envp[j]; j++) {
1909 envp[j] = envp[j + 1];
1910 }
1911 i--;
1912 #else
1913 char *eq;
1914 int len;
1915
1916 eq = strchr(envp[i], '=');
1917 if (!eq)
1918 continue;
1919 len = eq - envp[i];
1920 e = strndup(envp[i], len);
1921 if (!e) {
1922 bad = InternalError;
1923 break;
1924 }
1925 if (len >= 4 &&
1926 (strcmp(e + len - 4, "PATH") == 0 ||
1927 strcmp(e, "TERMCAP") == 0)) {
1928 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1929 bad = EnvTooLong;
1930 break;
1931 }
1932 else {
1933 free(e);
1934 }
1935 }
1936 else {
1937 bad = EnvTooLong;
1938 break;
1939 }
1940 #endif
1941 }
1942 }
1943 }
1944 #if NO_OUTPUT_PIPES
1945 if (!bad) {
1946 struct stat buf;
1947
1948 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1949 bad = OutputIsPipe;
1950 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1951 bad = OutputIsPipe;
1952 }
1953 #endif
1954 }
1955 switch (bad) {
1956 case NotBad:
1957 return;
1958 case UnsafeArg:
1959 ErrorF("Command line argument number %d is unsafe\n", i);
1960 break;
1961 case ArgTooLong:
1962 ErrorF("Command line argument number %d is too long\n", i);
1963 break;
1964 case UnprintableArg:
1965 ErrorF("Command line argument number %d contains unprintable"
1966 " characters\n", i);
1967 break;
1968 case EnvTooLong:
1969 ErrorF("Environment variable `%s' is too long\n", e);
1970 break;
1971 case OutputIsPipe:
1972 ErrorF("Stdout and/or stderr is a pipe\n");
1973 break;
1974 case InternalError:
1975 ErrorF("Internal Error\n");
1976 break;
1977 default:
1978 ErrorF("Unknown error\n");
1979 break;
1980 }
1981 FatalError("X server aborted because of unsafe environment\n");
1982 }
1983
1984 /*
1985 * CheckUserAuthorization: check if the user is allowed to start the
1986 * X server. This usually means some sort of PAM checking, and it is
1987 * usually only done for setuid servers (uid != euid).
1988 */
1989
1990 #ifdef USE_PAM
1991 #include <security/pam_appl.h>
1992 #include <security/pam_misc.h>
1993 #include <pwd.h>
1994 #endif /* USE_PAM */
1995
1996 void
CheckUserAuthorization(void)1997 CheckUserAuthorization(void)
1998 {
1999 #ifdef USE_PAM
2000 static struct pam_conv conv = {
2001 misc_conv,
2002 NULL
2003 };
2004
2005 pam_handle_t *pamh = NULL;
2006 struct passwd *pw;
2007 int retval;
2008
2009 if (getuid() != geteuid()) {
2010 pw = getpwuid(getuid());
2011 if (pw == NULL)
2012 FatalError("getpwuid() failed for uid %d\n", getuid());
2013
2014 retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
2015 if (retval != PAM_SUCCESS)
2016 FatalError("pam_start() failed.\n"
2017 "\tMissing or mangled PAM config file or module?\n");
2018
2019 retval = pam_authenticate(pamh, 0);
2020 if (retval != PAM_SUCCESS) {
2021 pam_end(pamh, retval);
2022 FatalError("PAM authentication failed, cannot start X server.\n"
2023 "\tPerhaps you do not have console ownership?\n");
2024 }
2025
2026 retval = pam_acct_mgmt(pamh, 0);
2027 if (retval != PAM_SUCCESS) {
2028 pam_end(pamh, retval);
2029 FatalError("PAM authentication failed, cannot start X server.\n"
2030 "\tPerhaps you do not have console ownership?\n");
2031 }
2032
2033 /* this is not a session, so do not do session management */
2034 pam_end(pamh, PAM_SUCCESS);
2035 }
2036 #endif
2037 }
2038
2039 /*
2040 * Tokenize a string into a NULL terminated array of strings. Always returns
2041 * an allocated array unless an error occurs.
2042 */
2043 char **
xstrtokenize(const char * str,const char * separators)2044 xstrtokenize(const char *str, const char *separators)
2045 {
2046 char **list, **nlist;
2047 char *tok, *tmp;
2048 unsigned num = 0, n;
2049
2050 if (!str)
2051 return NULL;
2052 list = calloc(1, sizeof(*list));
2053 if (!list)
2054 return NULL;
2055 tmp = strdup(str);
2056 if (!tmp)
2057 goto error;
2058 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
2059 nlist = reallocarray(list, num + 2, sizeof(*list));
2060 if (!nlist)
2061 goto error;
2062 list = nlist;
2063 list[num] = strdup(tok);
2064 if (!list[num])
2065 goto error;
2066 list[++num] = NULL;
2067 }
2068 free(tmp);
2069 return list;
2070
2071 error:
2072 free(tmp);
2073 for (n = 0; n < num; n++)
2074 free(list[n]);
2075 free(list);
2076 return NULL;
2077 }
2078
2079 /* Format a signed number into a string in a signal safe manner. The string
2080 * should be at least 21 characters in order to handle all int64_t values.
2081 */
2082 void
FormatInt64(int64_t num,char * string)2083 FormatInt64(int64_t num, char *string)
2084 {
2085 if (num < 0) {
2086 string[0] = '-';
2087 num *= -1;
2088 string++;
2089 }
2090 FormatUInt64(num, string);
2091 }
2092
2093 /* Format a number into a string in a signal safe manner. The string should be
2094 * at least 21 characters in order to handle all uint64_t values. */
2095 void
FormatUInt64(uint64_t num,char * string)2096 FormatUInt64(uint64_t num, char *string)
2097 {
2098 uint64_t divisor;
2099 int len;
2100 int i;
2101
2102 for (len = 1, divisor = 10;
2103 len < 20 && num / divisor;
2104 len++, divisor *= 10);
2105
2106 for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
2107 string[i - 1] = '0' + ((num / divisor) % 10);
2108
2109 string[len] = '\0';
2110 }
2111
2112 /**
2113 * Format a double number as %.2f.
2114 */
2115 void
FormatDouble(double dbl,char * string)2116 FormatDouble(double dbl, char *string)
2117 {
2118 int slen = 0;
2119 uint64_t frac;
2120
2121 frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5;
2122 frac %= 100;
2123
2124 /* write decimal part to string */
2125 if (dbl < 0 && dbl > -1)
2126 string[slen++] = '-';
2127 FormatInt64((int64_t)dbl, &string[slen]);
2128
2129 while(string[slen] != '\0')
2130 slen++;
2131
2132 /* append fractional part, but only if we have enough characters. We
2133 * expect string to be 21 chars (incl trailing \0) */
2134 if (slen <= 17) {
2135 string[slen++] = '.';
2136 if (frac < 10)
2137 string[slen++] = '0';
2138
2139 FormatUInt64(frac, &string[slen]);
2140 }
2141 }
2142
2143
2144 /* Format a number into a hexadecimal string in a signal safe manner. The string
2145 * should be at least 17 characters in order to handle all uint64_t values. */
2146 void
FormatUInt64Hex(uint64_t num,char * string)2147 FormatUInt64Hex(uint64_t num, char *string)
2148 {
2149 uint64_t divisor;
2150 int len;
2151 int i;
2152
2153 for (len = 1, divisor = 0x10;
2154 len < 16 && num / divisor;
2155 len++, divisor *= 0x10);
2156
2157 for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
2158 int val = (num / divisor) % 0x10;
2159
2160 if (val < 10)
2161 string[i - 1] = '0' + val;
2162 else
2163 string[i - 1] = 'a' + val - 10;
2164 }
2165
2166 string[len] = '\0';
2167 }
2168
2169 #if !defined(WIN32) || defined(__CYGWIN__)
2170 /* Move a file descriptor out of the way of our select mask; this
2171 * is useful for file descriptors which will never appear in the
2172 * select mask to avoid reducing the number of clients that can
2173 * connect to the server
2174 */
2175 int
os_move_fd(int fd)2176 os_move_fd(int fd)
2177 {
2178 int newfd;
2179
2180 #ifdef F_DUPFD_CLOEXEC
2181 newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
2182 #else
2183 newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
2184 #endif
2185 if (newfd < 0)
2186 return fd;
2187 #ifndef F_DUPFD_CLOEXEC
2188 fcntl(newfd, F_SETFD, FD_CLOEXEC);
2189 #endif
2190 close(fd);
2191 return newfd;
2192 }
2193 #endif
2194