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
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
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
28 Copyright 1994 Quarterdeck Office Systems.
32 Permission to use, copy, modify, and distribute this software and its
33 documentation for any purpose and without fee is hereby granted,
34 provided that the above copyright notice appear in all copies and that
35 both that copyright notice and this permission notice appear in
36 supporting documentation, and that the names of Digital and
37 Quarterdeck not be used in advertising or publicity pertaining to
38 distribution of the software without specific, written prior
41 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
42 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
43 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
44 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
46 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
47 OR PERFORMANCE OF THIS SOFTWARE.
51 #ifdef HAVE_DIX_CONFIG_H
52 #include <dix-config.h>
59 Sigh... We really need a prototype for this to know it is stdcall,
60 but #include-ing <windows.h> here is not a good idea...
62 __stdcall unsigned long GetTickCount(void);
65 #if defined(WIN32) && !defined(__CYGWIN__)
66 #include <X11/Xwinsock.h>
71 #if !defined(WIN32) || !defined(__MINGW32__)
73 #include <sys/resource.h>
80 #include <X11/Xtrans/Xtrans.h>
84 #include "extension.h"
85 #ifdef X_POSIX_C_SOURCE
86 #define _POSIX_C_SOURCE X_POSIX_C_SOURCE
88 #undef _POSIX_C_SOURCE
90 #if defined(_POSIX_SOURCE)
101 #if !defined(SYSV) && !defined(WIN32)
102 #include <sys/resource.h>
104 #include <sys/stat.h>
105 #include <ctype.h> /* for isspace */
108 #include <stdlib.h> /* for malloc() */
110 #if defined(TCPCONN) || defined(STREAMSCONN)
118 #include "dixstruct.h"
124 Bool noTestExtensions;
127 Bool noCompositeExtension = FALSE;
131 Bool noDamageExtension = FALSE;
134 Bool noDbeExtension = FALSE;
137 Bool noDPMSExtension = FALSE;
140 Bool noGlxExtension = FALSE;
143 Bool noScreenSaverExtension = FALSE;
146 Bool noMITShmExtension = FALSE;
149 Bool noRRExtension = FALSE;
151 Bool noRenderExtension = FALSE;
154 Bool noSecurityExtension = FALSE;
157 Bool noResExtension = FALSE;
160 Bool noXFree86BigfontExtension = FALSE;
163 Bool noXFree86DGAExtension = FALSE;
166 Bool noXFree86DRIExtension = FALSE;
169 Bool noXFree86VidModeExtension = FALSE;
172 Bool noXFixesExtension = FALSE;
175 /* Xinerama is disabled by default unless enabled via +xinerama */
176 Bool noPanoramiXExtension = TRUE;
179 Bool noSELinuxExtension = FALSE;
180 int selinuxEnforcingState = SELINUX_MODE_DEFAULT;
183 Bool noSmackExtension = FALSE;
186 Bool noXvExtension = FALSE;
189 Bool noDRI2Extension = FALSE;
192 Bool noGEExtension = FALSE;
194 #define X_INCLUDE_NETDB_H
195 #include <X11/Xos_r.h>
202 Bool PanoramiXExtensionDisabledHack = FALSE;
205 int auditTrailLevel = 1;
209 sig_atomic_t inSignalContext = FALSE;
211 #if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
212 #define HAS_SAVED_IDS_AND_SETEUID
216 OsSignal(int sig, OsSigHandlerPtr handler)
218 struct sigaction act, oact;
220 sigemptyset(&act.sa_mask);
221 if (handler != SIG_IGN)
222 sigaddset(&act.sa_mask, sig);
224 act.sa_handler = handler;
225 if (sigaction(sig, &act, &oact))
227 return oact.sa_handler;
231 * Explicit support for a server lock file like the ones used for UUCP.
232 * For architectures with virtual terminals that can run more than one
233 * server at a time. This keeps the servers from stomping on each other
234 * if the user forgets to give them different display numbers.
236 #define LOCK_DIR "/tmp"
237 #define LOCK_TMP_PREFIX "/.tX"
238 #define LOCK_PREFIX "/.X"
239 #define LOCK_SUFFIX "-lock"
241 static Bool StillLocking = FALSE;
242 static char LockFile[PATH_MAX];
243 static Bool nolock = FALSE;
247 * Check if the server lock file exists. If so, check if the PID
248 * contained inside is valid. If so, then die. Otherwise, create
249 * the lock file containing the PID.
254 char tmp[PATH_MAX], pid_str[12];
255 int lfd, i, haslock, l_pid, t;
256 const char *tmppath = LOCK_DIR;
265 snprintf(port, sizeof(port), "%d", atoi(display));
266 len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
267 strlen(LOCK_TMP_PREFIX);
268 len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
269 if (len > sizeof(LockFile))
270 FatalError("Display name `%s' is too long\n", port);
271 (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
272 (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
275 * Create a temporary file containing our PID. Attempt three times
276 * to create the file.
282 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
293 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
301 FatalError("Could not create lock file in %s\n", tmp);
302 snprintf(pid_str, sizeof(pid_str), "%10ld\n", (long) getpid());
303 (void) write(lfd, pid_str, 11);
304 (void) fchmod(lfd, 0444);
308 * OK. Now the tmp file exists. Try three times to move it in place
313 while ((!haslock) && (i++ < 3)) {
314 haslock = (link(tmp, LockFile) == 0);
323 * Read the pid from the existing file
325 lfd = open(LockFile, O_RDONLY | O_NOFOLLOW);
328 FatalError("Can't read lock file %s\n", LockFile);
331 if (read(lfd, pid_str, 11) != 11) {
340 sscanf(pid_str, "%d", &l_pid);
344 * Now try to kill the PID to see if it exists.
348 if ((t < 0) && (errno == ESRCH)) {
355 else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
357 * Process is still active.
361 ("Server is already active for display %s\n%s %s\n%s\n",
362 port, "\tIf this server is no longer running, remove",
363 LockFile, "\tand start again.");
369 FatalError("Could not create server lock file: %s\n", LockFile);
370 StillLocking = FALSE;
375 * Remove the server lock file.
385 (void) unlink(LockFile);
389 /* Force connections to close on SIGHUP from init */
392 AutoResetServer(int sig)
394 int olderrno = errno;
396 dispatchException |= DE_RESET;
397 isItTimeToYield = TRUE;
401 /* Force connections to close and then exit on SIGTERM, SIGINT */
406 int olderrno = errno;
408 dispatchException |= DE_TERMINATE;
409 isItTimeToYield = TRUE;
413 #if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
415 GetTimeInMillis(void)
417 return GetTickCount();
421 GetTimeInMillis(void)
425 #ifdef MONOTONIC_CLOCK
427 static clockid_t clockid;
430 #ifdef CLOCK_MONOTONIC_COARSE
431 if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
432 (tp.tv_nsec / 1000) <= 1000 &&
433 clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
434 clockid = CLOCK_MONOTONIC_COARSE;
437 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
438 clockid = CLOCK_MONOTONIC;
442 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
443 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
447 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
452 AdjustWaitForDelay(pointer waitTime, unsigned long newdelay)
454 static struct timeval delay_val;
455 struct timeval **wt = (struct timeval **) waitTime;
456 unsigned long olddelay;
459 delay_val.tv_sec = newdelay / 1000;
460 delay_val.tv_usec = 1000 * (newdelay % 1000);
464 olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
465 if (newdelay < olddelay) {
466 (*wt)->tv_sec = newdelay / 1000;
467 (*wt)->tv_usec = 1000 * (newdelay % 1000);
475 ErrorF("use: X [:<display>] [option]\n");
476 ErrorF("-a # default pointer acceleration (factor)\n");
477 ErrorF("-ac disable access control restrictions\n");
478 ErrorF("-audit int set audit trail level\n");
479 ErrorF("-auth file select authorization file\n");
480 ErrorF("-br create root window with black background\n");
481 ErrorF("+bs enable any backing store support\n");
482 ErrorF("-bs disable any backing store support\n");
483 ErrorF("-c turns off key-click\n");
484 ErrorF("c # key-click volume (0-100)\n");
485 ErrorF("-cc int default color visual class\n");
486 ErrorF("-nocursor disable the cursor\n");
487 ErrorF("-core generate core dump on fatal error\n");
488 ErrorF("-dpi int screen resolution in dots per inch\n");
490 ErrorF("-dpms disables VESA DPMS monitor control\n");
491 #ifdef _F_DPMS_PHONE_CTRL_
492 ErrorF("+dpmsphone enable VESA DPMS monitor control for phone\n");
496 ("-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");
504 ErrorF("-ld int limit data space to N Kb\n");
507 ErrorF("-lf int limit number of open files to N\n");
510 ErrorF("-ls int limit stack space to N Kb\n");
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("-s # screen-saver timeout (minutes)\n");
525 ErrorF("-seat string seat to run on\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");
537 ErrorF("+xinerama Enable XINERAMA extension\n");
538 ErrorF("-xinerama Disable XINERAMA extension\n");
541 ("-dumbSched Disable smart scheduling, enable old behavior\n");
542 ErrorF("-schedInterval int Set scheduler interval in msec\n");
543 ErrorF("-sigstop Enable SIGSTOP based startup\n");
544 ErrorF("+extension name Enable extension\n");
545 ErrorF("-extension name Disable extension\n");
553 /* This function performs a rudimentary sanity check
554 * on the display name passed in on the command-line,
555 * since this string is used to generate filenames.
556 * It is especially important that the display name
557 * not contain a "/" and not start with a "-".
561 VerifyDisplayName(const char *d)
566 return 0; /* empty */
568 return 0; /* could be confused for an option */
570 return 0; /* must not equal "." or ".." */
571 if (strchr(d, '/') != (char *) 0)
572 return 0; /* very important!!! */
577 * This function parses the command line. Handles device-independent fields
578 * and allows ddx to handle additional fields. It is not allowed to modify
579 * argc or any of the strings pointed to by argv.
582 ProcessCommandLine(int argc, char *argv[])
586 defaultKeyboardControl.autoRepeat = TRUE;
589 PartialNetwork = FALSE;
591 PartialNetwork = TRUE;
594 for (i = 1; i < argc; i++) {
595 /* call ddx first, so it can peek/override if it wants */
596 if ((skip = ddxProcessArgument(argc, argv, i))) {
599 else if (argv[i][0] == ':') {
600 /* initialize display */
603 if (!VerifyDisplayName(display)) {
604 ErrorF("Bad display name: %s\n", display);
606 FatalError("Bad display name, exiting: %s\n", display);
609 else if (strcmp(argv[i], "-a") == 0) {
611 defaultPointerControl.num = atoi(argv[i]);
615 else if (strcmp(argv[i], "-ac") == 0) {
616 defeatAccessControl = TRUE;
618 else if (strcmp(argv[i], "-audit") == 0) {
620 auditTrailLevel = atoi(argv[i]);
624 else if (strcmp(argv[i], "-auth") == 0) {
626 InitAuthorization(argv[i]);
630 else if (strcmp(argv[i], "-br") == 0); /* default */
631 else if (strcmp(argv[i], "+bs") == 0)
632 enableBackingStore = TRUE;
633 else if (strcmp(argv[i], "-bs") == 0)
634 disableBackingStore = TRUE;
635 else if (strcmp(argv[i], "c") == 0) {
637 defaultKeyboardControl.click = atoi(argv[i]);
641 else if (strcmp(argv[i], "-c") == 0) {
642 defaultKeyboardControl.click = 0;
644 else if (strcmp(argv[i], "-cc") == 0) {
646 defaultColorVisualClass = atoi(argv[i]);
650 else if (strcmp(argv[i], "-core") == 0) {
651 #if !defined(WIN32) || !defined(__MINGW32__)
652 struct rlimit core_limit;
654 getrlimit(RLIMIT_CORE, &core_limit);
655 core_limit.rlim_cur = core_limit.rlim_max;
656 setrlimit(RLIMIT_CORE, &core_limit);
660 else if (strcmp(argv[i], "-nocursor") == 0) {
661 EnableCursor = FALSE;
663 else if (strcmp(argv[i], "-dpi") == 0) {
665 monitorResolution = atoi(argv[i]);
669 else if (strcmp(argv[i], "-displayfd") == 0) {
671 displayfd = atoi(argv[i]);
679 else if (strcmp(argv[i], "dpms") == 0)
680 /* ignored for compatibility */ ;
681 else if (strcmp(argv[i], "-dpms") == 0)
682 DPMSDisabledSwitch = TRUE;
683 #ifdef _F_DPMS_PHONE_CTRL_
684 else if (strcmp(argv[i], "+dpmsphone") == 0)
685 DPMSPhoneCrtl = TRUE;
688 else if (strcmp(argv[i], "-deferglyphs") == 0) {
689 if (++i >= argc || !ParseGlyphCachingMode(argv[i]))
692 else if (strcmp(argv[i], "-f") == 0) {
694 defaultKeyboardControl.bell = atoi(argv[i]);
698 else if (strcmp(argv[i], "-fc") == 0) {
700 defaultCursorFont = argv[i];
704 else if (strcmp(argv[i], "-fn") == 0) {
706 defaultTextFont = argv[i];
710 else if (strcmp(argv[i], "-fp") == 0) {
712 defaultFontPath = argv[i];
717 else if (strcmp(argv[i], "-help") == 0) {
721 else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
728 else if (strcmp(argv[i], "-ld") == 0) {
730 limitDataSpace = atoi(argv[i]);
731 if (limitDataSpace > 0)
732 limitDataSpace *= 1024;
739 else if (strcmp(argv[i], "-lf") == 0) {
741 limitNoFile = atoi(argv[i]);
747 else if (strcmp(argv[i], "-ls") == 0) {
749 limitStackSpace = atoi(argv[i]);
750 if (limitStackSpace > 0)
751 limitStackSpace *= 1024;
757 else if (strcmp(argv[i], "-nolock") == 0) {
758 #if !defined(WIN32) && !defined(__CYGWIN__)
761 ("Warning: the -nolock option can only be used by root\n");
766 else if (strcmp(argv[i], "-nolisten") == 0) {
768 if (_XSERVTransNoListen(argv[i]))
769 ErrorF("Failed to disable listen for %s transport",
775 else if (strcmp(argv[i], "-noreset") == 0) {
776 dispatchExceptionAtReset = 0;
778 else if (strcmp(argv[i], "-reset") == 0) {
779 dispatchExceptionAtReset = DE_RESET;
781 else if (strcmp(argv[i], "-p") == 0) {
783 defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
788 else if (strcmp(argv[i], "-pogo") == 0) {
789 dispatchException = DE_TERMINATE;
791 else if (strcmp(argv[i], "-pn") == 0)
792 PartialNetwork = TRUE;
793 else if (strcmp(argv[i], "-nopn") == 0)
794 PartialNetwork = FALSE;
795 else if (strcmp(argv[i], "r") == 0)
796 defaultKeyboardControl.autoRepeat = TRUE;
797 else if (strcmp(argv[i], "-r") == 0)
798 defaultKeyboardControl.autoRepeat = FALSE;
799 else if (strcmp(argv[i], "-retro") == 0)
800 party_like_its_1989 = TRUE;
801 else if (strcmp(argv[i], "-s") == 0) {
803 defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
808 else if (strcmp(argv[i], "-seat") == 0) {
814 else if (strcmp(argv[i], "-t") == 0) {
816 defaultPointerControl.threshold = atoi(argv[i]);
820 else if (strcmp(argv[i], "-terminate") == 0) {
821 dispatchExceptionAtReset = DE_TERMINATE;
823 else if (strcmp(argv[i], "-to") == 0) {
825 TimeOutValue = ((CARD32) atoi(argv[i])) * MILLI_PER_SECOND;
829 else if (strcmp(argv[i], "-tst") == 0) {
830 noTestExtensions = TRUE;
832 else if (strcmp(argv[i], "v") == 0)
833 defaultScreenSaverBlanking = PreferBlanking;
834 else if (strcmp(argv[i], "-v") == 0)
835 defaultScreenSaverBlanking = DontPreferBlanking;
836 else if (strcmp(argv[i], "-wm") == 0)
837 defaultBackingStore = WhenMapped;
838 else if (strcmp(argv[i], "-wr") == 0)
840 else if (strcmp(argv[i], "-background") == 0) {
842 if (!strcmp(argv[i], "none"))
848 else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
850 long reqSizeArg = atol(argv[i]);
852 /* Request size > 128MB does not make much sense... */
853 if (reqSizeArg > 0L && reqSizeArg < 128L) {
854 maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
865 else if (strcmp(argv[i], "+xinerama") == 0) {
866 noPanoramiXExtension = FALSE;
868 else if (strcmp(argv[i], "-xinerama") == 0) {
869 noPanoramiXExtension = TRUE;
871 else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
872 PanoramiXExtensionDisabledHack = TRUE;
875 else if (strcmp(argv[i], "-I") == 0) {
876 /* ignore all remaining arguments */
879 else if (strncmp(argv[i], "tty", 3) == 0) {
880 /* init supplies us with this useless information */
883 else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
887 else if (strcmp(argv[i], "-dumbSched") == 0) {
888 SmartScheduleDisable = TRUE;
890 else if (strcmp(argv[i], "-schedInterval") == 0) {
892 SmartScheduleInterval = atoi(argv[i]);
893 SmartScheduleSlice = SmartScheduleInterval;
898 else if (strcmp(argv[i], "-schedMax") == 0) {
900 SmartScheduleMaxSlice = atoi(argv[i]);
905 else if (strcmp(argv[i], "-render") == 0) {
907 int policy = PictureParseCmapPolicy(argv[i]);
909 if (policy != PictureCmapPolicyInvalid)
910 PictureCmapPolicy = policy;
917 else if (strcmp(argv[i], "-sigstop") == 0) {
918 RunFromSigStopParent = TRUE;
920 else if (strcmp(argv[i], "+extension") == 0) {
922 if (!EnableDisableExtension(argv[i], TRUE))
923 EnableDisableExtensionError(argv[i], TRUE);
928 else if (strcmp(argv[i], "-extension") == 0) {
930 if (!EnableDisableExtension(argv[i], FALSE))
931 EnableDisableExtensionError(argv[i], FALSE);
937 ErrorF("Unrecognized option: %s\n", argv[i]);
939 FatalError("Unrecognized option: %s\n", argv[i]);
944 /* Implement a simple-minded font authorization scheme. The authorization
945 name is "hp-hostname-1", the contents are simply the host name. */
947 set_font_authorizations(char **authorizations, int *authlen, pointer client)
949 #define AUTHORIZATION_NAME "hp-hostname-1"
950 #if defined(TCPCONN) || defined(STREAMSCONN)
951 static char *result = NULL;
952 static char *p = NULL;
955 char hname[1024], *hnameptr;
958 #if defined(IPv6) && defined(AF_INET6)
959 struct addrinfo hints, *ai = NULL;
961 struct hostent *host;
963 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
964 _Xgethostbynameparams hparams;
968 gethostname(hname, 1024);
969 #if defined(IPv6) && defined(AF_INET6)
970 memset(&hints, 0, sizeof(hints));
971 hints.ai_flags = AI_CANONNAME;
972 if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
973 hnameptr = ai->ai_canonname;
979 host = _XGethostbyname(hname, hparams);
983 hnameptr = host->h_name;
986 len = strlen(hnameptr) + 1;
987 result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
990 *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
991 *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
995 memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
996 p += sizeof(AUTHORIZATION_NAME);
997 memmove(p, hnameptr, len);
999 #if defined(IPv6) && defined(AF_INET6)
1005 *authlen = p - result;
1006 *authorizations = result;
1010 #endif /* TCPCONN */
1014 Xalloc(unsigned long amount)
1017 * Xalloc used to return NULL when large amount of memory is requested. In
1018 * order to catch the buggy callers this warning has been added, slated to
1019 * removal by anyone who touches this code (or just looks at it) in 2011.
1021 * -- Mikhail Gusarov
1023 if ((long) amount <= 0)
1024 ErrorF("Warning: Xalloc: "
1025 "requesting unpleasantly large amount of memory: %lu bytes.\n",
1028 return malloc(amount);
1032 XNFalloc(unsigned long amount)
1034 void *ptr = malloc(amount);
1037 FatalError("Out of memory");
1042 Xcalloc(unsigned long amount)
1044 return calloc(1, amount);
1048 XNFcalloc(unsigned long amount)
1050 void *ret = calloc(1, amount);
1053 FatalError("XNFcalloc: Out of memory");
1058 Xrealloc(void *ptr, unsigned long amount)
1061 * Xrealloc used to return NULL when large amount of memory is requested. In
1062 * order to catch the buggy callers this warning has been added, slated to
1063 * removal by anyone who touches this code (or just looks at it) in 2011.
1065 * -- Mikhail Gusarov
1067 if ((long) amount <= 0)
1068 ErrorF("Warning: Xrealloc: "
1069 "requesting unpleasantly large amount of memory: %lu bytes.\n",
1072 return realloc(ptr, amount);
1076 XNFrealloc(void *ptr, unsigned long amount)
1078 void *ret = realloc(ptr, amount);
1081 FatalError("XNFrealloc: Out of memory");
1092 Xstrdup(const char *s)
1100 XNFstrdup(const char *s)
1109 FatalError("XNFstrdup: Out of memory");
1114 SmartScheduleStopTimer(void)
1116 struct itimerval timer;
1118 if (SmartScheduleDisable)
1120 timer.it_interval.tv_sec = 0;
1121 timer.it_interval.tv_usec = 0;
1122 timer.it_value.tv_sec = 0;
1123 timer.it_value.tv_usec = 0;
1124 (void) setitimer(ITIMER_REAL, &timer, 0);
1128 SmartScheduleStartTimer(void)
1130 struct itimerval timer;
1132 if (SmartScheduleDisable)
1134 timer.it_interval.tv_sec = 0;
1135 timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
1136 timer.it_value.tv_sec = 0;
1137 timer.it_value.tv_usec = SmartScheduleInterval * 1000;
1138 setitimer(ITIMER_REAL, &timer, 0);
1142 SmartScheduleTimer(int sig)
1144 SmartScheduleTime += SmartScheduleInterval;
1148 SmartScheduleInit(void)
1150 struct sigaction act;
1152 if (SmartScheduleDisable)
1155 memset((char *) &act, 0, sizeof(struct sigaction));
1157 /* Set up the timer signal function */
1158 act.sa_handler = SmartScheduleTimer;
1159 sigemptyset(&act.sa_mask);
1160 sigaddset(&act.sa_mask, SIGALRM);
1161 if (sigaction(SIGALRM, &act, 0) < 0) {
1162 perror("sigaction for smart scheduler");
1163 SmartScheduleDisable = TRUE;
1168 static sigset_t PreviousSignalMask;
1169 static int BlockedSignalCount;
1173 OsBlockSignals(void)
1176 if (BlockedSignalCount++ == 0) {
1183 sigaddset(&set, SIGALRM);
1184 sigaddset(&set, SIGVTALRM);
1186 sigaddset(&set, SIGWINCH);
1188 sigaddset(&set, SIGTSTP);
1189 sigaddset(&set, SIGTTIN);
1190 sigaddset(&set, SIGTTOU);
1191 sigaddset(&set, SIGCHLD);
1192 sigprocmask(SIG_BLOCK, &set, &PreviousSignalMask);
1198 static sig_atomic_t sigio_blocked;
1199 static sigset_t PreviousSigIOMask;
1203 * returns zero if this call caused SIGIO to be blocked now, non-zero if it
1204 * was already blocked by a previous call to this function.
1211 if (sigio_blocked++ == 0) {
1216 sigaddset(&set, SIGIO);
1217 sigprocmask(SIG_BLOCK, &set, &PreviousSigIOMask);
1218 ret = sigismember(&PreviousSigIOMask, SIGIO);
1227 OsReleaseSIGIO(void)
1231 if (--sigio_blocked == 0) {
1232 sigprocmask(SIG_SETMASK, &PreviousSigIOMask, 0);
1233 } else if (sigio_blocked < 0) {
1234 BUG_WARN(sigio_blocked < 0);
1242 OsReleaseSignals(void)
1245 if (--BlockedSignalCount == 0) {
1246 sigprocmask(SIG_SETMASK, &PreviousSignalMask, 0);
1253 OsResetSignals(void)
1256 while (BlockedSignalCount > 0)
1259 while (sigio_blocked > 0)
1266 * Pending signals may interfere with core dumping. Provide a
1267 * mechanism to block signals when aborting.
1281 * "safer" versions of system(3), popen(3) and pclose(3) which give up
1282 * all privs before running a command.
1284 * This is based on the code in FreeBSD 2.2 libc.
1286 * XXX It'd be good to redirect stderr so that it ends up in the log file
1287 * as well. As it is now, xkbcomp messages don't end up in the log file.
1291 System(const char *command)
1300 csig = signal(SIGCHLD, SIG_DFL);
1301 if (csig == SIG_ERR) {
1305 DebugF("System: `%s'\n", command);
1307 switch (pid = fork()) {
1308 case -1: /* error */
1311 if (setgid(getgid()) == -1)
1313 if (setuid(getuid()) == -1)
1315 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1317 default: /* parent */
1319 p = waitpid(pid, &status, 0);
1320 } while (p == -1 && errno == EINTR);
1324 if (signal(SIGCHLD, csig) == SIG_ERR) {
1329 return p == -1 ? -1 : status;
1338 OsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */
1341 Popen(const char *command, const char *type)
1347 if (command == NULL || type == NULL)
1350 if ((*type != 'r' && *type != 'w') || type[1])
1353 if ((cur = malloc(sizeof(struct pid))) == NULL)
1356 if (pipe(pdes) < 0) {
1361 /* Ignore the smart scheduler while this is going on */
1362 old_alarm = OsSignal(SIGALRM, SIG_IGN);
1363 if (old_alarm == SIG_ERR) {
1371 switch (pid = fork()) {
1372 case -1: /* error */
1376 if (OsSignal(SIGALRM, old_alarm) == SIG_ERR)
1380 if (setgid(getgid()) == -1)
1382 if (setuid(getuid()) == -1)
1400 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1404 /* Avoid EINTR during stdio calls */
1409 iop = fdopen(pdes[0], type);
1413 iop = fdopen(pdes[1], type);
1419 cur->next = pidlist;
1422 DebugF("Popen: `%s', fp = %p\n", command, iop);
1427 /* fopen that drops privileges */
1429 Fopen(const char *file, const char *type)
1433 #ifndef HAS_SAVED_IDS_AND_SETEUID
1437 if (file == NULL || type == NULL)
1440 if ((*type != 'r' && *type != 'w') || type[1])
1443 if ((cur = malloc(sizeof(struct pid))) == NULL)
1446 if (pipe(pdes) < 0) {
1451 switch (pid = fork()) {
1452 case -1: /* error */
1458 if (setgid(getgid()) == -1)
1460 if (setuid(getuid()) == -1)
1478 execl("/bin/cat", "cat", file, (char *) NULL);
1482 /* Avoid EINTR during stdio calls */
1487 iop = fdopen(pdes[0], type);
1491 iop = fdopen(pdes[1], type);
1497 cur->next = pidlist;
1500 DebugF("Fopen(%s), fp = %p\n", file, iop);
1509 if (seteuid(ruid) == -1) {
1512 iop = fopen(file, type);
1514 if (seteuid(euid) == -1) {
1519 #endif /* HAS_SAVED_IDS_AND_SETEUID */
1525 struct pid *cur, *last;
1529 DebugF("Pclose: fp = %p\n", iop);
1532 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1539 pid = waitpid(cur->pid, &pstat, 0);
1540 } while (pid == -1 && errno == EINTR);
1543 pidlist = cur->next;
1545 last->next = cur->next;
1548 /* allow EINTR again */
1551 if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) {
1556 return pid == -1 ? -1 : pstat;
1562 #ifdef HAS_SAVED_IDS_AND_SETEUID
1573 #include <X11/Xwindows.h>
1578 static char buffer[PATH_MAX];
1580 if (GetTempPath(sizeof(buffer), buffer)) {
1583 buffer[sizeof(buffer) - 1] = 0;
1584 len = strlen(buffer);
1586 if (buffer[len - 1] == '\\')
1587 buffer[len - 1] = 0;
1590 if (getenv("TEMP") != NULL)
1591 return getenv("TEMP");
1592 else if (getenv("TMP") != NULL)
1593 return getenv("TMP");
1599 System(const char *cmdline)
1602 PROCESS_INFORMATION pi;
1604 char *cmd = strdup(cmdline);
1606 ZeroMemory(&si, sizeof(si));
1608 ZeroMemory(&pi, sizeof(pi));
1610 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
1613 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1614 FORMAT_MESSAGE_FROM_SYSTEM |
1615 FORMAT_MESSAGE_IGNORE_INSERTS,
1618 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1619 (LPTSTR) & buffer, 0, NULL)) {
1620 ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
1623 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
1630 /* Wait until child process exits. */
1631 WaitForSingleObject(pi.hProcess, INFINITE);
1633 GetExitCodeProcess(pi.hProcess, &dwExitCode);
1635 /* Close process and thread handles. */
1636 CloseHandle(pi.hProcess);
1637 CloseHandle(pi.hThread);
1645 * CheckUserParameters: check for long command line arguments and long
1646 * environment variables. By default, these checks are only done when
1647 * the server's euid != ruid. In 3.3.x, these checks were done in an
1648 * external wrapper utility.
1651 /* Consider LD* variables insecure? */
1652 #ifndef REMOVE_ENV_LD
1653 #define REMOVE_ENV_LD 1
1656 /* Remove long environment variables? */
1657 #ifndef REMOVE_LONG_ENV
1658 #define REMOVE_LONG_ENV 1
1662 * Disallow stdout or stderr as pipes? It's possible to block the X server
1663 * when piping stdout+stderr to a pipe.
1665 * Don't enable this because it looks like it's going to cause problems.
1667 #ifndef NO_OUTPUT_PIPES
1668 #define NO_OUTPUT_PIPES 0
1671 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
1674 #define CHECK_EUID 1
1676 #define CHECK_EUID 0
1681 * Maybe the locale can be faked to make isprint(3) report that everything
1682 * is printable? Avoid it by default.
1685 #define USE_ISPRINT 0
1688 #define MAX_ARG_LENGTH 128
1689 #define MAX_ENV_LENGTH 256
1690 #define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */
1694 #define checkPrintable(c) isprint(c)
1696 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
1709 #if defined(VENDORSUPPORT)
1710 #define BUGADDRESS VENDORSUPPORT
1711 #elif defined(BUILDERADDR)
1712 #define BUGADDRESS BUILDERADDR
1714 #define BUGADDRESS "xorg@freedesktop.org"
1718 CheckUserParameters(int argc, char **argv, char **envp)
1720 enum BadCode bad = NotBad;
1725 if (geteuid() == 0 && getuid() != geteuid())
1728 /* Check each argv[] */
1729 for (i = 1; i < argc; i++) {
1730 if (strcmp(argv[i], "-fp") == 0) {
1731 i++; /* continue with next argument. skip the length check */
1736 if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1743 if (checkPrintable(*a) == 0) {
1744 bad = UnprintableArg;
1753 /* Check each envp[] */
1754 for (i = 0; envp[i]; i++) {
1756 /* Check for bad environment variables and values */
1758 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1759 for (j = i; envp[j]; j++) {
1760 envp[j] = envp[j + 1];
1764 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
1766 for (j = i; envp[j]; j++) {
1767 envp[j] = envp[j + 1];
1774 eq = strchr(envp[i], '=');
1778 e = strndup(envp[i], len);
1780 bad = InternalError;
1784 (strcmp(e + len - 4, "PATH") == 0 ||
1785 strcmp(e, "TERMCAP") == 0)) {
1786 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1806 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1808 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1817 ErrorF("Command line argument number %d is unsafe\n", i);
1820 ErrorF("Command line argument number %d is too long\n", i);
1822 case UnprintableArg:
1823 ErrorF("Command line argument number %d contains unprintable"
1824 " characters\n", i);
1827 ErrorF("Environment variable `%s' is too long\n", e);
1830 ErrorF("Stdout and/or stderr is a pipe\n");
1833 ErrorF("Internal Error\n");
1836 ErrorF("Unknown error\n");
1839 FatalError("X server aborted because of unsafe environment\n");
1843 * CheckUserAuthorization: check if the user is allowed to start the
1844 * X server. This usually means some sort of PAM checking, and it is
1845 * usually only done for setuid servers (uid != euid).
1849 #include <security/pam_appl.h>
1850 #include <security/pam_misc.h>
1852 #endif /* USE_PAM */
1855 CheckUserAuthorization(void)
1858 static struct pam_conv conv = {
1863 pam_handle_t *pamh = NULL;
1867 if (getuid() != geteuid()) {
1868 pw = getpwuid(getuid());
1870 FatalError("getpwuid() failed for uid %d\n", getuid());
1872 retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
1873 if (retval != PAM_SUCCESS)
1874 FatalError("pam_start() failed.\n"
1875 "\tMissing or mangled PAM config file or module?\n");
1877 retval = pam_authenticate(pamh, 0);
1878 if (retval != PAM_SUCCESS) {
1879 pam_end(pamh, retval);
1880 FatalError("PAM authentication failed, cannot start X server.\n"
1881 "\tPerhaps you do not have console ownership?\n");
1884 retval = pam_acct_mgmt(pamh, 0);
1885 if (retval != PAM_SUCCESS) {
1886 pam_end(pamh, retval);
1887 FatalError("PAM authentication failed, cannot start X server.\n"
1888 "\tPerhaps you do not have console ownership?\n");
1891 /* this is not a session, so do not do session management */
1892 pam_end(pamh, PAM_SUCCESS);
1898 * Tokenize a string into a NULL terminated array of strings. Always returns
1899 * an allocated array unless an error occurs.
1902 xstrtokenize(const char *str, const char *separators)
1904 char **list, **nlist;
1906 unsigned num = 0, n;
1910 list = calloc(1, sizeof(*list));
1916 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
1917 nlist = realloc(list, (num + 2) * sizeof(*list));
1921 list[num] = strdup(tok);
1931 for (n = 0; n < num; n++)
1937 /* Format a signed number into a string in a signal safe manner. The string
1938 * should be at least 21 characters in order to handle all int64_t values.
1941 FormatInt64(int64_t num, char *string)
1948 FormatUInt64(num, string);
1951 /* Format a number into a string in a signal safe manner. The string should be
1952 * at least 21 characters in order to handle all uint64_t values. */
1954 FormatUInt64(uint64_t num, char *string)
1960 for (len = 1, divisor = 10;
1961 len < 20 && num / divisor;
1962 len++, divisor *= 10);
1964 for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
1965 string[i - 1] = '0' + ((num / divisor) % 10);
1970 /* Format a number into a hexadecimal string in a signal safe manner. The string
1971 * should be at least 17 characters in order to handle all uint64_t values. */
1973 FormatUInt64Hex(uint64_t num, char *string)
1979 for (len = 1, divisor = 0x10;
1980 len < 16 && num / divisor;
1981 len++, divisor *= 0x10);
1983 for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
1984 int val = (num / divisor) % 0x10;
1987 string[i - 1] = '0' + val;
1989 string[i - 1] = 'a' + val - 10;