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