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