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