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