utils.c revision 6b007147
105b261ecSmrg/* 205b261ecSmrg 305b261ecSmrgCopyright 1987, 1998 The Open Group 405b261ecSmrg 505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that 705b261ecSmrgthe above copyright notice appear in all copies and that both that 805b261ecSmrgcopyright notice and this permission notice appear in supporting 905b261ecSmrgdocumentation. 1005b261ecSmrg 1105b261ecSmrgThe above copyright notice and this permission notice shall be included 1205b261ecSmrgin all copies or substantial portions of the Software. 1305b261ecSmrg 1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE. 2105b261ecSmrg 2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall 2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or 2405b261ecSmrgother dealings in this Software without prior written authorization 2505b261ecSmrgfrom The Open Group. 2605b261ecSmrg 2705b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 2805b261ecSmrgCopyright 1994 Quarterdeck Office Systems. 2905b261ecSmrg 3005b261ecSmrg All Rights Reserved 3105b261ecSmrg 3205b261ecSmrgPermission to use, copy, modify, and distribute this software and its 3305b261ecSmrgdocumentation for any purpose and without fee is hereby granted, 3405b261ecSmrgprovided that the above copyright notice appear in all copies and that 3505b261ecSmrgboth that copyright notice and this permission notice appear in 3605b261ecSmrgsupporting documentation, and that the names of Digital and 3705b261ecSmrgQuarterdeck not be used in advertising or publicity pertaining to 3805b261ecSmrgdistribution of the software without specific, written prior 3905b261ecSmrgpermission. 4005b261ecSmrg 4105b261ecSmrgDIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 4205b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 4305b261ecSmrgFITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT 4405b261ecSmrgOR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 4505b261ecSmrgOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 4605b261ecSmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 4705b261ecSmrgOR PERFORMANCE OF THIS SOFTWARE. 4805b261ecSmrg 4905b261ecSmrg*/ 5005b261ecSmrg 5105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 5205b261ecSmrg#include <dix-config.h> 5305b261ecSmrg#endif 5405b261ecSmrg 5505b261ecSmrg#ifdef __CYGWIN__ 5605b261ecSmrg#include <stdlib.h> 5705b261ecSmrg#include <signal.h> 584202a189Smrg/* 594202a189Smrg Sigh... We really need a prototype for this to know it is stdcall, 604202a189Smrg but #include-ing <windows.h> here is not a good idea... 614202a189Smrg*/ 624202a189Smrg__stdcall unsigned long GetTickCount(void); 6305b261ecSmrg#endif 6405b261ecSmrg 6505b261ecSmrg#if defined(WIN32) && !defined(__CYGWIN__) 6605b261ecSmrg#include <X11/Xwinsock.h> 6705b261ecSmrg#endif 6805b261ecSmrg#include <X11/Xos.h> 6905b261ecSmrg#include <stdio.h> 7005b261ecSmrg#include <time.h> 7105b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__) 7205b261ecSmrg#include <sys/time.h> 7305b261ecSmrg#include <sys/resource.h> 7405b261ecSmrg#endif 7505b261ecSmrg#include "misc.h" 7605b261ecSmrg#include <X11/X.h> 7705b261ecSmrg#define XSERV_t 7805b261ecSmrg#define TRANS_SERVER 7905b261ecSmrg#define TRANS_REOPEN 8005b261ecSmrg#include <X11/Xtrans/Xtrans.h> 8105b261ecSmrg#include "input.h" 8205b261ecSmrg#include "dixfont.h" 837e31ba66Smrg#include <X11/fonts/libxfont2.h> 8405b261ecSmrg#include "osdep.h" 8505b261ecSmrg#include "extension.h" 8605b261ecSmrg#include <signal.h> 8705b261ecSmrg#ifndef WIN32 8805b261ecSmrg#include <sys/wait.h> 8905b261ecSmrg#endif 90f7df2e56Smrg#if !defined(SYSV) && !defined(WIN32) 9105b261ecSmrg#include <sys/resource.h> 9205b261ecSmrg#endif 9305b261ecSmrg#include <sys/stat.h> 94f7df2e56Smrg#include <ctype.h> /* for isspace */ 9505b261ecSmrg#include <stdarg.h> 9605b261ecSmrg 97f7df2e56Smrg#include <stdlib.h> /* for malloc() */ 9805b261ecSmrg 997e31ba66Smrg#if defined(TCPCONN) 100f7df2e56Smrg#ifndef WIN32 101f7df2e56Smrg#include <netdb.h> 102f7df2e56Smrg#endif 10305b261ecSmrg#endif 10405b261ecSmrg 10505b261ecSmrg#include "opaque.h" 10605b261ecSmrg 10705b261ecSmrg#include "dixstruct.h" 10805b261ecSmrg 1094202a189Smrg#include "xkbsrv.h" 11005b261ecSmrg 11105b261ecSmrg#include "picture.h" 11205b261ecSmrg 1135a112b11Smrg#include "miinitext.h" 1145a112b11Smrg 1155a112b11Smrg#include "present.h" 1165a112b11Smrg 1174202a189SmrgBool noTestExtensions; 118f7df2e56Smrg 11905b261ecSmrg#ifdef COMPOSITE 1204202a189SmrgBool noCompositeExtension = FALSE; 12105b261ecSmrg#endif 12205b261ecSmrg 12305b261ecSmrg#ifdef DAMAGE 1244202a189SmrgBool noDamageExtension = FALSE; 12505b261ecSmrg#endif 12605b261ecSmrg#ifdef DBE 1274202a189SmrgBool noDbeExtension = FALSE; 12805b261ecSmrg#endif 12905b261ecSmrg#ifdef DPMSExtension 1307e31ba66Smrg#include "dpmsproc.h" 1314202a189SmrgBool noDPMSExtension = FALSE; 13205b261ecSmrg#endif 13305b261ecSmrg#ifdef GLXEXT 1344202a189SmrgBool noGlxExtension = FALSE; 13505b261ecSmrg#endif 13605b261ecSmrg#ifdef SCREENSAVER 1374202a189SmrgBool noScreenSaverExtension = FALSE; 13805b261ecSmrg#endif 13905b261ecSmrg#ifdef MITSHM 1404202a189SmrgBool noMITShmExtension = FALSE; 14105b261ecSmrg#endif 14205b261ecSmrg#ifdef RANDR 1434202a189SmrgBool noRRExtension = FALSE; 14405b261ecSmrg#endif 1454202a189SmrgBool noRenderExtension = FALSE; 146f7df2e56Smrg 14705b261ecSmrg#ifdef XCSECURITY 1484202a189SmrgBool noSecurityExtension = FALSE; 14905b261ecSmrg#endif 15005b261ecSmrg#ifdef RES 1514202a189SmrgBool noResExtension = FALSE; 15205b261ecSmrg#endif 15305b261ecSmrg#ifdef XF86BIGFONT 1544202a189SmrgBool noXFree86BigfontExtension = FALSE; 15505b261ecSmrg#endif 15605b261ecSmrg#ifdef XFreeXDGA 1574202a189SmrgBool noXFree86DGAExtension = FALSE; 15805b261ecSmrg#endif 15905b261ecSmrg#ifdef XF86DRI 1604202a189SmrgBool noXFree86DRIExtension = FALSE; 16105b261ecSmrg#endif 16205b261ecSmrg#ifdef XF86VIDMODE 1634202a189SmrgBool noXFree86VidModeExtension = FALSE; 16405b261ecSmrg#endif 1654202a189SmrgBool noXFixesExtension = FALSE; 16605b261ecSmrg#ifdef PANORAMIX 16705b261ecSmrg/* Xinerama is disabled by default unless enabled via +xinerama */ 1684202a189SmrgBool noPanoramiXExtension = TRUE; 16905b261ecSmrg#endif 1704642e01fSmrg#ifdef XSELINUX 1714202a189SmrgBool noSELinuxExtension = FALSE; 1724202a189Smrgint selinuxEnforcingState = SELINUX_MODE_DEFAULT; 17305b261ecSmrg#endif 17405b261ecSmrg#ifdef XV 1754202a189SmrgBool noXvExtension = FALSE; 17605b261ecSmrg#endif 1774642e01fSmrg#ifdef DRI2 1784202a189SmrgBool noDRI2Extension = FALSE; 1794642e01fSmrg#endif 1804642e01fSmrg 1814202a189SmrgBool noGEExtension = FALSE; 18205b261ecSmrg 18305b261ecSmrg#define X_INCLUDE_NETDB_H 18405b261ecSmrg#include <X11/Xos_r.h> 18505b261ecSmrg 18605b261ecSmrg#include <errno.h> 18705b261ecSmrg 18805b261ecSmrgBool CoreDump; 18905b261ecSmrg 190f7df2e56SmrgBool enableIndirectGLX = FALSE; 191f7df2e56Smrg 19205b261ecSmrg#ifdef PANORAMIX 19305b261ecSmrgBool PanoramiXExtensionDisabledHack = FALSE; 19405b261ecSmrg#endif 19505b261ecSmrg 19605b261ecSmrgint auditTrailLevel = 1; 19705b261ecSmrg 198f7df2e56Smrgchar *SeatId = NULL; 199f7df2e56Smrg 200f7df2e56Smrgsig_atomic_t inSignalContext = FALSE; 201f7df2e56Smrg 20205b261ecSmrg#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) 20305b261ecSmrg#define HAS_SAVED_IDS_AND_SETEUID 20405b261ecSmrg#endif 20505b261ecSmrg 2067e31ba66Smrg#ifdef MONOTONIC_CLOCK 2077e31ba66Smrgstatic clockid_t clockid; 2087e31ba66Smrg#endif 2097e31ba66Smrg 21005b261ecSmrgOsSigHandlerPtr 2114202a189SmrgOsSignal(int sig, OsSigHandlerPtr handler) 21205b261ecSmrg{ 213f7df2e56Smrg#if defined(WIN32) && !defined(__CYGWIN__) 214f7df2e56Smrg return signal(sig, handler); 215f7df2e56Smrg#else 21605b261ecSmrg struct sigaction act, oact; 21705b261ecSmrg 21805b261ecSmrg sigemptyset(&act.sa_mask); 21905b261ecSmrg if (handler != SIG_IGN) 220f7df2e56Smrg sigaddset(&act.sa_mask, sig); 22105b261ecSmrg act.sa_flags = 0; 22205b261ecSmrg act.sa_handler = handler; 22305b261ecSmrg if (sigaction(sig, &act, &oact)) 224f7df2e56Smrg perror("sigaction"); 22505b261ecSmrg return oact.sa_handler; 226f7df2e56Smrg#endif 22705b261ecSmrg} 2284642e01fSmrg 22905b261ecSmrg/* 23005b261ecSmrg * Explicit support for a server lock file like the ones used for UUCP. 23105b261ecSmrg * For architectures with virtual terminals that can run more than one 23205b261ecSmrg * server at a time. This keeps the servers from stomping on each other 23305b261ecSmrg * if the user forgets to give them different display numbers. 23405b261ecSmrg */ 23505b261ecSmrg#define LOCK_DIR "/tmp" 23605b261ecSmrg#define LOCK_TMP_PREFIX "/.tX" 23705b261ecSmrg#define LOCK_PREFIX "/.X" 23805b261ecSmrg#define LOCK_SUFFIX "-lock" 23905b261ecSmrg 240f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__) 241f7df2e56Smrg#define LOCK_SERVER 24205b261ecSmrg#endif 24305b261ecSmrg 244f7df2e56Smrg#ifndef LOCK_SERVER 245f7df2e56Smrgvoid 246f7df2e56SmrgLockServer(void) 247f7df2e56Smrg{} 248f7df2e56Smrg 249f7df2e56Smrgvoid 250f7df2e56SmrgUnlockServer(void) 251f7df2e56Smrg{} 252f7df2e56Smrg#else /* LOCK_SERVER */ 25305b261ecSmrgstatic Bool StillLocking = FALSE; 25405b261ecSmrgstatic char LockFile[PATH_MAX]; 25505b261ecSmrgstatic Bool nolock = FALSE; 25605b261ecSmrg 25705b261ecSmrg/* 25805b261ecSmrg * LockServer -- 25905b261ecSmrg * Check if the server lock file exists. If so, check if the PID 26005b261ecSmrg * contained inside is valid. If so, then die. Otherwise, create 26105b261ecSmrg * the lock file containing the PID. 26205b261ecSmrg */ 26305b261ecSmrgvoid 26405b261ecSmrgLockServer(void) 26505b261ecSmrg{ 266f7df2e56Smrg char tmp[PATH_MAX], pid_str[12]; 267f7df2e56Smrg int lfd, i, haslock, l_pid, t; 268f7df2e56Smrg const char *tmppath = LOCK_DIR; 269f7df2e56Smrg int len; 270f7df2e56Smrg char port[20]; 271f7df2e56Smrg 272f7df2e56Smrg if (nolock || NoListenAll) 273f7df2e56Smrg return; 274f7df2e56Smrg /* 275f7df2e56Smrg * Path names 276f7df2e56Smrg */ 277f7df2e56Smrg snprintf(port, sizeof(port), "%d", atoi(display)); 278f7df2e56Smrg len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : 279f7df2e56Smrg strlen(LOCK_TMP_PREFIX); 280f7df2e56Smrg len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; 281f7df2e56Smrg if (len > sizeof(LockFile)) 282f7df2e56Smrg FatalError("Display name `%s' is too long\n", port); 283f7df2e56Smrg (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 284f7df2e56Smrg (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 285f7df2e56Smrg 286f7df2e56Smrg /* 287f7df2e56Smrg * Create a temporary file containing our PID. Attempt three times 288f7df2e56Smrg * to create the file. 289f7df2e56Smrg */ 290f7df2e56Smrg StillLocking = TRUE; 29105b261ecSmrg i = 0; 29205b261ecSmrg do { 293f7df2e56Smrg i++; 294f7df2e56Smrg lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 295f7df2e56Smrg if (lfd < 0) 296f7df2e56Smrg sleep(2); 297f7df2e56Smrg else 298f7df2e56Smrg break; 29905b261ecSmrg } while (i < 3); 300f7df2e56Smrg if (lfd < 0) { 30105b261ecSmrg unlink(tmp); 302f7df2e56Smrg i = 0; 303f7df2e56Smrg do { 304f7df2e56Smrg i++; 305f7df2e56Smrg lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 306f7df2e56Smrg if (lfd < 0) 307f7df2e56Smrg sleep(2); 308f7df2e56Smrg else 309f7df2e56Smrg break; 310f7df2e56Smrg } while (i < 3); 31105b261ecSmrg } 312f7df2e56Smrg if (lfd < 0) 313f7df2e56Smrg FatalError("Could not create lock file in %s\n", tmp); 3147e31ba66Smrg snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid()); 315f7df2e56Smrg if (write(lfd, pid_str, 11) != 11) 316f7df2e56Smrg FatalError("Could not write pid to lock file in %s\n", tmp); 317f7df2e56Smrg (void) fchmod(lfd, 0444); 318f7df2e56Smrg (void) close(lfd); 319f7df2e56Smrg 320f7df2e56Smrg /* 321f7df2e56Smrg * OK. Now the tmp file exists. Try three times to move it in place 322f7df2e56Smrg * for the lock. 323f7df2e56Smrg */ 324f7df2e56Smrg i = 0; 325f7df2e56Smrg haslock = 0; 326f7df2e56Smrg while ((!haslock) && (i++ < 3)) { 327f7df2e56Smrg haslock = (link(tmp, LockFile) == 0); 328f7df2e56Smrg if (haslock) { 329f7df2e56Smrg /* 330f7df2e56Smrg * We're done. 331f7df2e56Smrg */ 332f7df2e56Smrg break; 333f7df2e56Smrg } 3345a112b11Smrg else if (errno == EEXIST) { 335f7df2e56Smrg /* 336f7df2e56Smrg * Read the pid from the existing file 337f7df2e56Smrg */ 338f7df2e56Smrg lfd = open(LockFile, O_RDONLY | O_NOFOLLOW); 339f7df2e56Smrg if (lfd < 0) { 340f7df2e56Smrg unlink(tmp); 341f7df2e56Smrg FatalError("Can't read lock file %s\n", LockFile); 342f7df2e56Smrg } 343f7df2e56Smrg pid_str[0] = '\0'; 344f7df2e56Smrg if (read(lfd, pid_str, 11) != 11) { 345f7df2e56Smrg /* 346f7df2e56Smrg * Bogus lock file. 347f7df2e56Smrg */ 348f7df2e56Smrg unlink(LockFile); 349f7df2e56Smrg close(lfd); 350f7df2e56Smrg continue; 351f7df2e56Smrg } 352f7df2e56Smrg pid_str[11] = '\0'; 353f7df2e56Smrg sscanf(pid_str, "%d", &l_pid); 354f7df2e56Smrg close(lfd); 355f7df2e56Smrg 356f7df2e56Smrg /* 357f7df2e56Smrg * Now try to kill the PID to see if it exists. 358f7df2e56Smrg */ 359f7df2e56Smrg errno = 0; 360f7df2e56Smrg t = kill(l_pid, 0); 361f7df2e56Smrg if ((t < 0) && (errno == ESRCH)) { 362f7df2e56Smrg /* 363f7df2e56Smrg * Stale lock file. 364f7df2e56Smrg */ 365f7df2e56Smrg unlink(LockFile); 366f7df2e56Smrg continue; 367f7df2e56Smrg } 368f7df2e56Smrg else if (((t < 0) && (errno == EPERM)) || (t == 0)) { 369f7df2e56Smrg /* 370f7df2e56Smrg * Process is still active. 371f7df2e56Smrg */ 372f7df2e56Smrg unlink(tmp); 373f7df2e56Smrg FatalError 374f7df2e56Smrg ("Server is already active for display %s\n%s %s\n%s\n", 375f7df2e56Smrg port, "\tIf this server is no longer running, remove", 376f7df2e56Smrg LockFile, "\tand start again."); 377f7df2e56Smrg } 378f7df2e56Smrg } 3795a112b11Smrg else { 3805a112b11Smrg unlink(tmp); 3815a112b11Smrg FatalError 3825a112b11Smrg ("Linking lock file (%s) in place failed: %s\n", 3835a112b11Smrg LockFile, strerror(errno)); 3845a112b11Smrg } 385f7df2e56Smrg } 386f7df2e56Smrg unlink(tmp); 387f7df2e56Smrg if (!haslock) 388f7df2e56Smrg FatalError("Could not create server lock file: %s\n", LockFile); 389f7df2e56Smrg StillLocking = FALSE; 39005b261ecSmrg} 39105b261ecSmrg 39205b261ecSmrg/* 39305b261ecSmrg * UnlockServer -- 39405b261ecSmrg * Remove the server lock file. 39505b261ecSmrg */ 39605b261ecSmrgvoid 39705b261ecSmrgUnlockServer(void) 39805b261ecSmrg{ 399f7df2e56Smrg if (nolock || NoListenAll) 400f7df2e56Smrg return; 40105b261ecSmrg 402f7df2e56Smrg if (!StillLocking) { 40305b261ecSmrg 404f7df2e56Smrg (void) unlink(LockFile); 405f7df2e56Smrg } 40605b261ecSmrg} 407f7df2e56Smrg#endif /* LOCK_SERVER */ 40805b261ecSmrg 40905b261ecSmrg/* Force connections to close on SIGHUP from init */ 41005b261ecSmrg 4114202a189Smrgvoid 412f7df2e56SmrgAutoResetServer(int sig) 41305b261ecSmrg{ 41405b261ecSmrg int olderrno = errno; 41505b261ecSmrg 41605b261ecSmrg dispatchException |= DE_RESET; 41705b261ecSmrg isItTimeToYield = TRUE; 41805b261ecSmrg errno = olderrno; 41905b261ecSmrg} 42005b261ecSmrg 42105b261ecSmrg/* Force connections to close and then exit on SIGTERM, SIGINT */ 42205b261ecSmrg 4234202a189Smrgvoid 42405b261ecSmrgGiveUp(int sig) 42505b261ecSmrg{ 42605b261ecSmrg int olderrno = errno; 42705b261ecSmrg 42805b261ecSmrg dispatchException |= DE_TERMINATE; 42905b261ecSmrg isItTimeToYield = TRUE; 43005b261ecSmrg errno = olderrno; 43105b261ecSmrg} 43205b261ecSmrg 4337e31ba66Smrg#ifdef MONOTONIC_CLOCK 4347e31ba66Smrgvoid 4357e31ba66SmrgForceClockId(clockid_t forced_clockid) 4367e31ba66Smrg{ 4377e31ba66Smrg struct timespec tp; 4387e31ba66Smrg 4397e31ba66Smrg BUG_RETURN (clockid); 4407e31ba66Smrg 4417e31ba66Smrg clockid = forced_clockid; 4427e31ba66Smrg 4437e31ba66Smrg if (clock_gettime(clockid, &tp) != 0) { 4447e31ba66Smrg FatalError("Forced clock id failed to retrieve current time: %s\n", 4457e31ba66Smrg strerror(errno)); 4467e31ba66Smrg return; 4477e31ba66Smrg } 4487e31ba66Smrg} 4497e31ba66Smrg#endif 4507e31ba66Smrg 4514202a189Smrg#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__) 4524202a189SmrgCARD32 453f7df2e56SmrgGetTimeInMillis(void) 454f7df2e56Smrg{ 455f7df2e56Smrg return GetTickCount(); 456f7df2e56Smrg} 457f7df2e56SmrgCARD64 458f7df2e56SmrgGetTimeInMicros(void) 45905b261ecSmrg{ 460f7df2e56Smrg return (CARD64) GetTickCount() * 1000; 46105b261ecSmrg} 46205b261ecSmrg#else 4634202a189SmrgCARD32 46405b261ecSmrgGetTimeInMillis(void) 46505b261ecSmrg{ 46605b261ecSmrg struct timeval tv; 46705b261ecSmrg 46805b261ecSmrg#ifdef MONOTONIC_CLOCK 46905b261ecSmrg struct timespec tp; 470f7df2e56Smrg 4711b684552Smrg if (!clockid) { 4721b684552Smrg#ifdef CLOCK_MONOTONIC_COARSE 4731b684552Smrg if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 && 4741b684552Smrg (tp.tv_nsec / 1000) <= 1000 && 4751b684552Smrg clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0) 4761b684552Smrg clockid = CLOCK_MONOTONIC_COARSE; 4771b684552Smrg else 4781b684552Smrg#endif 4791b684552Smrg if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 4801b684552Smrg clockid = CLOCK_MONOTONIC; 4811b684552Smrg else 4821b684552Smrg clockid = ~0L; 4831b684552Smrg } 4841b684552Smrg if (clockid != ~0L && clock_gettime(clockid, &tp) == 0) 48505b261ecSmrg return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); 48605b261ecSmrg#endif 48705b261ecSmrg 48805b261ecSmrg X_GETTIMEOFDAY(&tv); 489f7df2e56Smrg return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 490f7df2e56Smrg} 491f7df2e56Smrg 492f7df2e56SmrgCARD64 493f7df2e56SmrgGetTimeInMicros(void) 494f7df2e56Smrg{ 495f7df2e56Smrg struct timeval tv; 496f7df2e56Smrg#ifdef MONOTONIC_CLOCK 497f7df2e56Smrg struct timespec tp; 498bf8e669cSmrg static clockid_t uclockid; 499f7df2e56Smrg 500bf8e669cSmrg if (!uclockid) { 501f7df2e56Smrg if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 502bf8e669cSmrg uclockid = CLOCK_MONOTONIC; 503f7df2e56Smrg else 504bf8e669cSmrg uclockid = ~0L; 505f7df2e56Smrg } 506bf8e669cSmrg if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0) 507f7df2e56Smrg return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000; 508f7df2e56Smrg#endif 509f7df2e56Smrg 510f7df2e56Smrg X_GETTIMEOFDAY(&tv); 5117e31ba66Smrg return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec; 51205b261ecSmrg} 51305b261ecSmrg#endif 51405b261ecSmrg 515f7df2e56Smrgvoid 516f7df2e56SmrgUseMsg(void) 51705b261ecSmrg{ 51805b261ecSmrg ErrorF("use: X [:<display>] [option]\n"); 5194202a189Smrg ErrorF("-a # default pointer acceleration (factor)\n"); 52005b261ecSmrg ErrorF("-ac disable access control restrictions\n"); 521f7df2e56Smrg ErrorF("-audit int set audit trail level\n"); 522f7df2e56Smrg ErrorF("-auth file select authorization file\n"); 52305b261ecSmrg ErrorF("-br create root window with black background\n"); 52405b261ecSmrg ErrorF("+bs enable any backing store support\n"); 52505b261ecSmrg ErrorF("-bs disable any backing store support\n"); 52605b261ecSmrg ErrorF("-c turns off key-click\n"); 52705b261ecSmrg ErrorF("c # key-click volume (0-100)\n"); 52805b261ecSmrg ErrorF("-cc int default color visual class\n"); 5294202a189Smrg ErrorF("-nocursor disable the cursor\n"); 53005b261ecSmrg ErrorF("-core generate core dump on fatal error\n"); 531f7df2e56Smrg ErrorF("-displayfd fd file descriptor to write display number to when ready to connect\n"); 53205b261ecSmrg ErrorF("-dpi int screen resolution in dots per inch\n"); 53305b261ecSmrg#ifdef DPMSExtension 53405b261ecSmrg ErrorF("-dpms disables VESA DPMS monitor control\n"); 53505b261ecSmrg#endif 536f7df2e56Smrg ErrorF 537f7df2e56Smrg ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); 53805b261ecSmrg ErrorF("-f # bell base (0-100)\n"); 5395a112b11Smrg ErrorF("-fakescreenfps # fake screen default fps (1-600)\n"); 54005b261ecSmrg ErrorF("-fp string default font path\n"); 54105b261ecSmrg ErrorF("-help prints message with these options\n"); 542f7df2e56Smrg ErrorF("+iglx Allow creating indirect GLX contexts\n"); 543f7df2e56Smrg ErrorF("-iglx Prohibit creating indirect GLX contexts (default)\n"); 54405b261ecSmrg ErrorF("-I ignore all remaining arguments\n"); 54505b261ecSmrg#ifdef RLIMIT_DATA 54605b261ecSmrg ErrorF("-ld int limit data space to N Kb\n"); 54705b261ecSmrg#endif 54805b261ecSmrg#ifdef RLIMIT_NOFILE 54905b261ecSmrg ErrorF("-lf int limit number of open files to N\n"); 55005b261ecSmrg#endif 55105b261ecSmrg#ifdef RLIMIT_STACK 55205b261ecSmrg ErrorF("-ls int limit stack space to N Kb\n"); 55305b261ecSmrg#endif 554f7df2e56Smrg#ifdef LOCK_SERVER 55505b261ecSmrg ErrorF("-nolock disable the locking mechanism\n"); 556f7df2e56Smrg#endif 557f7df2e56Smrg ErrorF("-maxclients n set maximum number of clients (power of two)\n"); 55805b261ecSmrg ErrorF("-nolisten string don't listen on protocol\n"); 559f7df2e56Smrg ErrorF("-listen string listen on protocol\n"); 56005b261ecSmrg ErrorF("-noreset don't reset after last client exists\n"); 56165b04b38Smrg ErrorF("-background [none] create root window with no background\n"); 56205b261ecSmrg ErrorF("-reset reset after last client exists\n"); 56305b261ecSmrg ErrorF("-p # screen-saver pattern duration (minutes)\n"); 56405b261ecSmrg ErrorF("-pn accept failure to listen on all ports\n"); 56505b261ecSmrg ErrorF("-nopn reject failure to listen on all ports\n"); 56605b261ecSmrg ErrorF("-r turns off auto-repeat\n"); 56705b261ecSmrg ErrorF("r turns on auto-repeat \n"); 56805b261ecSmrg ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); 5694642e01fSmrg ErrorF("-retro start with classic stipple and cursor\n"); 570daf23d7fSsnj ErrorF("-noretro start with black background and no cursor\n"); 57105b261ecSmrg ErrorF("-s # screen-saver timeout (minutes)\n"); 572f7df2e56Smrg ErrorF("-seat string seat to run on\n"); 5734202a189Smrg ErrorF("-t # default pointer threshold (pixels/t)\n"); 5745a112b11Smrg ErrorF("-terminate [delay] terminate at server reset (optional delay in sec)\n"); 57505b261ecSmrg ErrorF("-tst disable testing extensions\n"); 57605b261ecSmrg ErrorF("ttyxx server started from init on /dev/ttyxx\n"); 57705b261ecSmrg ErrorF("v video blanking for screen-saver\n"); 57805b261ecSmrg ErrorF("-v screen-saver without video blanking\n"); 57905b261ecSmrg ErrorF("-wr create root window with white background\n"); 58005b261ecSmrg ErrorF("-maxbigreqsize set maximal bigrequest size \n"); 58105b261ecSmrg#ifdef PANORAMIX 58205b261ecSmrg ErrorF("+xinerama Enable XINERAMA extension\n"); 58305b261ecSmrg ErrorF("-xinerama Disable XINERAMA extension\n"); 58405b261ecSmrg#endif 585f7df2e56Smrg ErrorF 5867e31ba66Smrg ("-dumbSched Disable smart scheduling and threaded input, enable old behavior\n"); 58705b261ecSmrg ErrorF("-schedInterval int Set scheduler interval in msec\n"); 58865b04b38Smrg ErrorF("-sigstop Enable SIGSTOP based startup\n"); 58905b261ecSmrg ErrorF("+extension name Enable extension\n"); 59005b261ecSmrg ErrorF("-extension name Disable extension\n"); 5915a112b11Smrg ListStaticExtensions(); 59205b261ecSmrg#ifdef XDMCP 59305b261ecSmrg XdmcpUseMsg(); 59405b261ecSmrg#endif 59505b261ecSmrg XkbUseMsg(); 59605b261ecSmrg ddxUseMsg(); 59705b261ecSmrg} 59805b261ecSmrg 59905b261ecSmrg/* This function performs a rudimentary sanity check 60005b261ecSmrg * on the display name passed in on the command-line, 60105b261ecSmrg * since this string is used to generate filenames. 60205b261ecSmrg * It is especially important that the display name 60305b261ecSmrg * not contain a "/" and not start with a "-". 60405b261ecSmrg * --kvajk 60505b261ecSmrg */ 606f7df2e56Smrgstatic int 60705b261ecSmrgVerifyDisplayName(const char *d) 60805b261ecSmrg{ 609f7df2e56Smrg int i; 610f7df2e56Smrg int period_found = FALSE; 611f7df2e56Smrg int after_period = 0; 612f7df2e56Smrg 613f7df2e56Smrg if (d == (char *) 0) 614f7df2e56Smrg return 0; /* null */ 615f7df2e56Smrg if (*d == '\0') 616f7df2e56Smrg return 0; /* empty */ 617f7df2e56Smrg if (*d == '-') 618f7df2e56Smrg return 0; /* could be confused for an option */ 619f7df2e56Smrg if (*d == '.') 620f7df2e56Smrg return 0; /* must not equal "." or ".." */ 621f7df2e56Smrg if (strchr(d, '/') != (char *) 0) 622f7df2e56Smrg return 0; /* very important!!! */ 623f7df2e56Smrg 624f7df2e56Smrg /* Since we run atoi() on the display later, only allow 625f7df2e56Smrg for digits, or exception of :0.0 and similar (two decimal points max) 626f7df2e56Smrg */ 627f7df2e56Smrg for (i = 0; i < strlen(d); i++) { 628f7df2e56Smrg if (!isdigit(d[i])) { 629f7df2e56Smrg if (d[i] != '.' || period_found) 630f7df2e56Smrg return 0; 631f7df2e56Smrg period_found = TRUE; 632f7df2e56Smrg } else if (period_found) 633f7df2e56Smrg after_period++; 634f7df2e56Smrg 635f7df2e56Smrg if (after_period > 2) 636f7df2e56Smrg return 0; 637f7df2e56Smrg } 638f7df2e56Smrg 639f7df2e56Smrg /* don't allow for :0. */ 640f7df2e56Smrg if (period_found && after_period == 0) 641f7df2e56Smrg return 0; 642f7df2e56Smrg 643f7df2e56Smrg if (atol(d) > INT_MAX) 644f7df2e56Smrg return 0; 645f7df2e56Smrg 6464202a189Smrg return 1; 64705b261ecSmrg} 64805b261ecSmrg 649f7df2e56Smrgstatic const char *defaultNoListenList[] = { 650f7df2e56Smrg#ifndef LISTEN_TCP 651f7df2e56Smrg "tcp", 652f7df2e56Smrg#endif 653f7df2e56Smrg#ifndef LISTEN_UNIX 654f7df2e56Smrg "unix", 655f7df2e56Smrg#endif 656f7df2e56Smrg#ifndef LISTEN_LOCAL 657f7df2e56Smrg "local", 658f7df2e56Smrg#endif 659f7df2e56Smrg NULL 660f7df2e56Smrg}; 661f7df2e56Smrg 66205b261ecSmrg/* 66305b261ecSmrg * This function parses the command line. Handles device-independent fields 66405b261ecSmrg * and allows ddx to handle additional fields. It is not allowed to modify 66505b261ecSmrg * argc or any of the strings pointed to by argv. 66605b261ecSmrg */ 66705b261ecSmrgvoid 66805b261ecSmrgProcessCommandLine(int argc, char *argv[]) 66905b261ecSmrg{ 67005b261ecSmrg int i, skip; 67105b261ecSmrg 67205b261ecSmrg defaultKeyboardControl.autoRepeat = TRUE; 67305b261ecSmrg 67405b261ecSmrg#ifdef NO_PART_NET 67505b261ecSmrg PartialNetwork = FALSE; 67605b261ecSmrg#else 67705b261ecSmrg PartialNetwork = TRUE; 67805b261ecSmrg#endif 67905b261ecSmrg 680f7df2e56Smrg for (i = 0; defaultNoListenList[i] != NULL; i++) { 681f7df2e56Smrg if (_XSERVTransNoListen(defaultNoListenList[i])) 682f7df2e56Smrg ErrorF("Failed to disable listen for %s transport", 683f7df2e56Smrg defaultNoListenList[i]); 684f7df2e56Smrg } 685f7df2e56Smrg 686f7df2e56Smrg for (i = 1; i < argc; i++) { 687f7df2e56Smrg /* call ddx first, so it can peek/override if it wants */ 688f7df2e56Smrg if ((skip = ddxProcessArgument(argc, argv, i))) { 689f7df2e56Smrg i += (skip - 1); 690f7df2e56Smrg } 691f7df2e56Smrg else if (argv[i][0] == ':') { 692f7df2e56Smrg /* initialize display */ 693f7df2e56Smrg display = argv[i]; 694f7df2e56Smrg explicit_display = TRUE; 695f7df2e56Smrg display++; 696f7df2e56Smrg if (!VerifyDisplayName(display)) { 69705b261ecSmrg ErrorF("Bad display name: %s\n", display); 69805b261ecSmrg UseMsg(); 699f7df2e56Smrg FatalError("Bad display name, exiting: %s\n", display); 70005b261ecSmrg } 701f7df2e56Smrg } 702f7df2e56Smrg else if (strcmp(argv[i], "-a") == 0) { 703f7df2e56Smrg if (++i < argc) 704f7df2e56Smrg defaultPointerControl.num = atoi(argv[i]); 705f7df2e56Smrg else 706f7df2e56Smrg UseMsg(); 707f7df2e56Smrg } 708f7df2e56Smrg else if (strcmp(argv[i], "-ac") == 0) { 709f7df2e56Smrg defeatAccessControl = TRUE; 710f7df2e56Smrg } 711f7df2e56Smrg else if (strcmp(argv[i], "-audit") == 0) { 712f7df2e56Smrg if (++i < argc) 713f7df2e56Smrg auditTrailLevel = atoi(argv[i]); 714f7df2e56Smrg else 715f7df2e56Smrg UseMsg(); 716f7df2e56Smrg } 717f7df2e56Smrg else if (strcmp(argv[i], "-auth") == 0) { 718f7df2e56Smrg if (++i < argc) 719f7df2e56Smrg InitAuthorization(argv[i]); 720f7df2e56Smrg else 721f7df2e56Smrg UseMsg(); 722f7df2e56Smrg } 723f7df2e56Smrg else if (strcmp(argv[i], "-br") == 0); /* default */ 724f7df2e56Smrg else if (strcmp(argv[i], "+bs") == 0) 725f7df2e56Smrg enableBackingStore = TRUE; 726f7df2e56Smrg else if (strcmp(argv[i], "-bs") == 0) 727f7df2e56Smrg disableBackingStore = TRUE; 728f7df2e56Smrg else if (strcmp(argv[i], "c") == 0) { 729f7df2e56Smrg if (++i < argc) 730f7df2e56Smrg defaultKeyboardControl.click = atoi(argv[i]); 731f7df2e56Smrg else 732f7df2e56Smrg UseMsg(); 733f7df2e56Smrg } 734f7df2e56Smrg else if (strcmp(argv[i], "-c") == 0) { 735f7df2e56Smrg defaultKeyboardControl.click = 0; 736f7df2e56Smrg } 737f7df2e56Smrg else if (strcmp(argv[i], "-cc") == 0) { 738f7df2e56Smrg if (++i < argc) 739f7df2e56Smrg defaultColorVisualClass = atoi(argv[i]); 740f7df2e56Smrg else 741f7df2e56Smrg UseMsg(); 742f7df2e56Smrg } 743f7df2e56Smrg else if (strcmp(argv[i], "-core") == 0) { 74405b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__) 745f7df2e56Smrg struct rlimit core_limit; 746f7df2e56Smrg 747f7df2e56Smrg if (getrlimit(RLIMIT_CORE, &core_limit) != -1) { 748f7df2e56Smrg core_limit.rlim_cur = core_limit.rlim_max; 749f7df2e56Smrg setrlimit(RLIMIT_CORE, &core_limit); 750f7df2e56Smrg } 75105b261ecSmrg#endif 752f7df2e56Smrg CoreDump = TRUE; 753f7df2e56Smrg } 754f7df2e56Smrg else if (strcmp(argv[i], "-nocursor") == 0) { 7554202a189Smrg EnableCursor = FALSE; 7564202a189Smrg } 757f7df2e56Smrg else if (strcmp(argv[i], "-dpi") == 0) { 758f7df2e56Smrg if (++i < argc) 759f7df2e56Smrg monitorResolution = atoi(argv[i]); 760f7df2e56Smrg else 761f7df2e56Smrg UseMsg(); 762f7df2e56Smrg } 763f7df2e56Smrg else if (strcmp(argv[i], "-displayfd") == 0) { 764f7df2e56Smrg if (++i < argc) { 765f7df2e56Smrg displayfd = atoi(argv[i]); 766f7df2e56Smrg#ifdef LOCK_SERVER 767f7df2e56Smrg nolock = TRUE; 768f7df2e56Smrg#endif 769f7df2e56Smrg } 770f7df2e56Smrg else 771f7df2e56Smrg UseMsg(); 772f7df2e56Smrg } 77305b261ecSmrg#ifdef DPMSExtension 774f7df2e56Smrg else if (strcmp(argv[i], "dpms") == 0) 775f7df2e56Smrg /* ignored for compatibility */ ; 776f7df2e56Smrg else if (strcmp(argv[i], "-dpms") == 0) 777f7df2e56Smrg DPMSDisabledSwitch = TRUE; 77805b261ecSmrg#endif 779f7df2e56Smrg else if (strcmp(argv[i], "-deferglyphs") == 0) { 7807e31ba66Smrg if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i])) 781f7df2e56Smrg UseMsg(); 782f7df2e56Smrg } 783f7df2e56Smrg else if (strcmp(argv[i], "-f") == 0) { 784f7df2e56Smrg if (++i < argc) 785f7df2e56Smrg defaultKeyboardControl.bell = atoi(argv[i]); 786f7df2e56Smrg else 787f7df2e56Smrg UseMsg(); 788f7df2e56Smrg } 7895a112b11Smrg else if (strcmp(argv[i], "-fakescreenfps") == 0) { 7906b007147Smrg#ifdef PRESENT 7915a112b11Smrg if (++i < argc) { 7925a112b11Smrg FakeScreenFps = (uint32_t) atoi(argv[i]); 7935a112b11Smrg if (FakeScreenFps < 1 || FakeScreenFps > 600) 7945a112b11Smrg FatalError("fakescreenfps must be an integer in [1;600] range\n"); 7955a112b11Smrg } 796f7df2e56Smrg else 797f7df2e56Smrg UseMsg(); 7986b007147Smrg#else 7996b007147Smrg FatalError("fakescreenfps not available without PRESENT\n"); 8006b007147Smrg UseMsg(); 8016b007147Smrg#endif 802f7df2e56Smrg } 803f7df2e56Smrg else if (strcmp(argv[i], "-fp") == 0) { 804f7df2e56Smrg if (++i < argc) { 805f7df2e56Smrg defaultFontPath = argv[i]; 806f7df2e56Smrg } 807f7df2e56Smrg else 808f7df2e56Smrg UseMsg(); 809f7df2e56Smrg } 810f7df2e56Smrg else if (strcmp(argv[i], "-help") == 0) { 811f7df2e56Smrg UseMsg(); 812f7df2e56Smrg exit(0); 813f7df2e56Smrg } 814f7df2e56Smrg else if (strcmp(argv[i], "+iglx") == 0) 815f7df2e56Smrg enableIndirectGLX = TRUE; 816f7df2e56Smrg else if (strcmp(argv[i], "-iglx") == 0) 817f7df2e56Smrg enableIndirectGLX = FALSE; 818f7df2e56Smrg else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) { 819f7df2e56Smrg if (skip > 0) 820f7df2e56Smrg i += skip - 1; 821f7df2e56Smrg else 822f7df2e56Smrg UseMsg(); 823f7df2e56Smrg } 82405b261ecSmrg#ifdef RLIMIT_DATA 825f7df2e56Smrg else if (strcmp(argv[i], "-ld") == 0) { 826f7df2e56Smrg if (++i < argc) { 827f7df2e56Smrg limitDataSpace = atoi(argv[i]); 828f7df2e56Smrg if (limitDataSpace > 0) 829f7df2e56Smrg limitDataSpace *= 1024; 830f7df2e56Smrg } 831f7df2e56Smrg else 832f7df2e56Smrg UseMsg(); 833f7df2e56Smrg } 83405b261ecSmrg#endif 83505b261ecSmrg#ifdef RLIMIT_NOFILE 836f7df2e56Smrg else if (strcmp(argv[i], "-lf") == 0) { 837f7df2e56Smrg if (++i < argc) 838f7df2e56Smrg limitNoFile = atoi(argv[i]); 839f7df2e56Smrg else 840f7df2e56Smrg UseMsg(); 841f7df2e56Smrg } 84205b261ecSmrg#endif 84305b261ecSmrg#ifdef RLIMIT_STACK 844f7df2e56Smrg else if (strcmp(argv[i], "-ls") == 0) { 845f7df2e56Smrg if (++i < argc) { 846f7df2e56Smrg limitStackSpace = atoi(argv[i]); 847f7df2e56Smrg if (limitStackSpace > 0) 848f7df2e56Smrg limitStackSpace *= 1024; 849f7df2e56Smrg } 850f7df2e56Smrg else 851f7df2e56Smrg UseMsg(); 852f7df2e56Smrg } 85305b261ecSmrg#endif 854f7df2e56Smrg#ifdef LOCK_SERVER 855f7df2e56Smrg else if (strcmp(argv[i], "-nolock") == 0) { 85605b261ecSmrg#if !defined(WIN32) && !defined(__CYGWIN__) 857f7df2e56Smrg if (getuid() != 0) 858f7df2e56Smrg ErrorF 859f7df2e56Smrg ("Warning: the -nolock option can only be used by root\n"); 860f7df2e56Smrg else 86105b261ecSmrg#endif 862f7df2e56Smrg nolock = TRUE; 863f7df2e56Smrg } 864f7df2e56Smrg#endif 865f7df2e56Smrg else if ( strcmp( argv[i], "-maxclients") == 0) 86605b261ecSmrg { 867f7df2e56Smrg if (++i < argc) { 868f7df2e56Smrg LimitClients = atoi(argv[i]); 869f7df2e56Smrg if (LimitClients != 64 && 870f7df2e56Smrg LimitClients != 128 && 871f7df2e56Smrg LimitClients != 256 && 8727e31ba66Smrg LimitClients != 512 && 8737e31ba66Smrg LimitClients != 1024 && 8747e31ba66Smrg LimitClients != 2048) { 8757e31ba66Smrg FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n"); 876f7df2e56Smrg } 877f7df2e56Smrg } else 87805b261ecSmrg UseMsg(); 87905b261ecSmrg } 880f7df2e56Smrg else if (strcmp(argv[i], "-nolisten") == 0) { 881f7df2e56Smrg if (++i < argc) { 882f7df2e56Smrg if (_XSERVTransNoListen(argv[i])) 883f7df2e56Smrg ErrorF("Failed to disable listen for %s transport", 884f7df2e56Smrg argv[i]); 885f7df2e56Smrg } 886f7df2e56Smrg else 887f7df2e56Smrg UseMsg(); 888f7df2e56Smrg } 889f7df2e56Smrg else if (strcmp(argv[i], "-listen") == 0) { 890f7df2e56Smrg if (++i < argc) { 891f7df2e56Smrg if (_XSERVTransListen(argv[i])) 892f7df2e56Smrg ErrorF("Failed to enable listen for %s transport", 893f7df2e56Smrg argv[i]); 894f7df2e56Smrg } 895f7df2e56Smrg else 896f7df2e56Smrg UseMsg(); 897f7df2e56Smrg } 898f7df2e56Smrg else if (strcmp(argv[i], "-noreset") == 0) { 899f7df2e56Smrg dispatchExceptionAtReset = 0; 900f7df2e56Smrg } 901f7df2e56Smrg else if (strcmp(argv[i], "-reset") == 0) { 902f7df2e56Smrg dispatchExceptionAtReset = DE_RESET; 903f7df2e56Smrg } 904f7df2e56Smrg else if (strcmp(argv[i], "-p") == 0) { 905f7df2e56Smrg if (++i < argc) 906f7df2e56Smrg defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) * 907f7df2e56Smrg MILLI_PER_MIN; 908f7df2e56Smrg else 909f7df2e56Smrg UseMsg(); 910f7df2e56Smrg } 911f7df2e56Smrg else if (strcmp(argv[i], "-pogo") == 0) { 912f7df2e56Smrg dispatchException = DE_TERMINATE; 913f7df2e56Smrg } 914f7df2e56Smrg else if (strcmp(argv[i], "-pn") == 0) 915f7df2e56Smrg PartialNetwork = TRUE; 916f7df2e56Smrg else if (strcmp(argv[i], "-nopn") == 0) 917f7df2e56Smrg PartialNetwork = FALSE; 918f7df2e56Smrg else if (strcmp(argv[i], "r") == 0) 919f7df2e56Smrg defaultKeyboardControl.autoRepeat = TRUE; 920f7df2e56Smrg else if (strcmp(argv[i], "-r") == 0) 921f7df2e56Smrg defaultKeyboardControl.autoRepeat = FALSE; 922f7df2e56Smrg else if (strcmp(argv[i], "-retro") == 0) 923f7df2e56Smrg party_like_its_1989 = TRUE; 924f7df2e56Smrg else if (strcmp(argv[i], "-noretro") == 0) 925daf23d7fSsnj party_like_its_1989 = FALSE; 926f7df2e56Smrg else if (strcmp(argv[i], "-s") == 0) { 927f7df2e56Smrg if (++i < argc) 928f7df2e56Smrg defaultScreenSaverTime = ((CARD32) atoi(argv[i])) * 929f7df2e56Smrg MILLI_PER_MIN; 930f7df2e56Smrg else 931f7df2e56Smrg UseMsg(); 932f7df2e56Smrg } 933f7df2e56Smrg else if (strcmp(argv[i], "-seat") == 0) { 934f7df2e56Smrg if (++i < argc) 935f7df2e56Smrg SeatId = argv[i]; 936f7df2e56Smrg else 937f7df2e56Smrg UseMsg(); 938f7df2e56Smrg } 939f7df2e56Smrg else if (strcmp(argv[i], "-t") == 0) { 940f7df2e56Smrg if (++i < argc) 941f7df2e56Smrg defaultPointerControl.threshold = atoi(argv[i]); 942f7df2e56Smrg else 943f7df2e56Smrg UseMsg(); 944f7df2e56Smrg } 945f7df2e56Smrg else if (strcmp(argv[i], "-terminate") == 0) { 946f7df2e56Smrg dispatchExceptionAtReset = DE_TERMINATE; 9475a112b11Smrg terminateDelay = -1; 9485a112b11Smrg if ((i + 1 < argc) && (isdigit(*argv[i + 1]))) 9495a112b11Smrg terminateDelay = atoi(argv[++i]); 9505a112b11Smrg terminateDelay = max(0, terminateDelay); 951f7df2e56Smrg } 952f7df2e56Smrg else if (strcmp(argv[i], "-tst") == 0) { 953f7df2e56Smrg noTestExtensions = TRUE; 954f7df2e56Smrg } 955f7df2e56Smrg else if (strcmp(argv[i], "v") == 0) 956f7df2e56Smrg defaultScreenSaverBlanking = PreferBlanking; 957f7df2e56Smrg else if (strcmp(argv[i], "-v") == 0) 958f7df2e56Smrg defaultScreenSaverBlanking = DontPreferBlanking; 959f7df2e56Smrg else if (strcmp(argv[i], "-wr") == 0) 96005b261ecSmrg whiteRoot = TRUE; 961f7df2e56Smrg else if (strcmp(argv[i], "-background") == 0) { 962f7df2e56Smrg if (++i < argc) { 963f7df2e56Smrg if (!strcmp(argv[i], "none")) 96465b04b38Smrg bgNoneRoot = TRUE; 96565b04b38Smrg else 96665b04b38Smrg UseMsg(); 96765b04b38Smrg } 96865b04b38Smrg } 969f7df2e56Smrg else if (strcmp(argv[i], "-maxbigreqsize") == 0) { 970f7df2e56Smrg if (++i < argc) { 971f7df2e56Smrg long reqSizeArg = atol(argv[i]); 972f7df2e56Smrg 973f7df2e56Smrg /* Request size > 128MB does not make much sense... */ 974f7df2e56Smrg if (reqSizeArg > 0L && reqSizeArg < 128L) { 975f7df2e56Smrg maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; 976f7df2e56Smrg } 977f7df2e56Smrg else { 978f7df2e56Smrg UseMsg(); 979f7df2e56Smrg } 980f7df2e56Smrg } 981f7df2e56Smrg else { 982f7df2e56Smrg UseMsg(); 983f7df2e56Smrg } 984f7df2e56Smrg } 985f7df2e56Smrg#ifdef PANORAMIX 986f7df2e56Smrg else if (strcmp(argv[i], "+xinerama") == 0) { 987f7df2e56Smrg noPanoramiXExtension = FALSE; 988f7df2e56Smrg } 989f7df2e56Smrg else if (strcmp(argv[i], "-xinerama") == 0) { 990f7df2e56Smrg noPanoramiXExtension = TRUE; 991f7df2e56Smrg } 992f7df2e56Smrg else if (strcmp(argv[i], "-disablexineramaextension") == 0) { 993f7df2e56Smrg PanoramiXExtensionDisabledHack = TRUE; 994f7df2e56Smrg } 995f7df2e56Smrg#endif 996f7df2e56Smrg else if (strcmp(argv[i], "-I") == 0) { 997f7df2e56Smrg /* ignore all remaining arguments */ 998f7df2e56Smrg break; 999f7df2e56Smrg } 1000f7df2e56Smrg else if (strncmp(argv[i], "tty", 3) == 0) { 1001f7df2e56Smrg /* init supplies us with this useless information */ 1002f7df2e56Smrg } 1003f7df2e56Smrg#ifdef XDMCP 1004f7df2e56Smrg else if ((skip = XdmcpOptions(argc, argv, i)) != i) { 1005f7df2e56Smrg i = skip - 1; 1006f7df2e56Smrg } 1007f7df2e56Smrg#endif 1008f7df2e56Smrg else if (strcmp(argv[i], "-dumbSched") == 0) { 10097e31ba66Smrg InputThreadEnable = FALSE; 10107e31ba66Smrg#ifdef HAVE_SETITIMER 10117e31ba66Smrg SmartScheduleSignalEnable = FALSE; 10127e31ba66Smrg#endif 1013f7df2e56Smrg } 1014f7df2e56Smrg else if (strcmp(argv[i], "-schedInterval") == 0) { 1015f7df2e56Smrg if (++i < argc) { 1016f7df2e56Smrg SmartScheduleInterval = atoi(argv[i]); 1017f7df2e56Smrg SmartScheduleSlice = SmartScheduleInterval; 1018f7df2e56Smrg } 1019f7df2e56Smrg else 1020f7df2e56Smrg UseMsg(); 1021f7df2e56Smrg } 1022f7df2e56Smrg else if (strcmp(argv[i], "-schedMax") == 0) { 1023f7df2e56Smrg if (++i < argc) { 1024f7df2e56Smrg SmartScheduleMaxSlice = atoi(argv[i]); 1025f7df2e56Smrg } 1026f7df2e56Smrg else 1027f7df2e56Smrg UseMsg(); 1028f7df2e56Smrg } 1029f7df2e56Smrg else if (strcmp(argv[i], "-render") == 0) { 1030f7df2e56Smrg if (++i < argc) { 1031f7df2e56Smrg int policy = PictureParseCmapPolicy(argv[i]); 1032f7df2e56Smrg 1033f7df2e56Smrg if (policy != PictureCmapPolicyInvalid) 1034f7df2e56Smrg PictureCmapPolicy = policy; 1035f7df2e56Smrg else 1036f7df2e56Smrg UseMsg(); 1037f7df2e56Smrg } 1038f7df2e56Smrg else 1039f7df2e56Smrg UseMsg(); 1040f7df2e56Smrg } 1041f7df2e56Smrg else if (strcmp(argv[i], "-sigstop") == 0) { 1042f7df2e56Smrg RunFromSigStopParent = TRUE; 1043f7df2e56Smrg } 1044f7df2e56Smrg else if (strcmp(argv[i], "+extension") == 0) { 1045f7df2e56Smrg if (++i < argc) { 1046f7df2e56Smrg if (!EnableDisableExtension(argv[i], TRUE)) 1047f7df2e56Smrg EnableDisableExtensionError(argv[i], TRUE); 1048f7df2e56Smrg } 1049f7df2e56Smrg else 1050f7df2e56Smrg UseMsg(); 1051f7df2e56Smrg } 1052f7df2e56Smrg else if (strcmp(argv[i], "-extension") == 0) { 1053f7df2e56Smrg if (++i < argc) { 1054f7df2e56Smrg if (!EnableDisableExtension(argv[i], FALSE)) 1055f7df2e56Smrg EnableDisableExtensionError(argv[i], FALSE); 1056f7df2e56Smrg } 1057f7df2e56Smrg else 1058f7df2e56Smrg UseMsg(); 1059f7df2e56Smrg } 1060f7df2e56Smrg else { 1061f7df2e56Smrg ErrorF("Unrecognized option: %s\n", argv[i]); 1062f7df2e56Smrg UseMsg(); 1063f7df2e56Smrg FatalError("Unrecognized option: %s\n", argv[i]); 106405b261ecSmrg } 106505b261ecSmrg } 106605b261ecSmrg} 106705b261ecSmrg 106805b261ecSmrg/* Implement a simple-minded font authorization scheme. The authorization 106905b261ecSmrg name is "hp-hostname-1", the contents are simply the host name. */ 107005b261ecSmrgint 1071f7df2e56Smrgset_font_authorizations(char **authorizations, int *authlen, void *client) 107205b261ecSmrg{ 107305b261ecSmrg#define AUTHORIZATION_NAME "hp-hostname-1" 10747e31ba66Smrg#if defined(TCPCONN) 107505b261ecSmrg static char *result = NULL; 107605b261ecSmrg static char *p = NULL; 107705b261ecSmrg 1078f7df2e56Smrg if (p == NULL) { 1079f7df2e56Smrg char hname[1024], *hnameptr; 1080f7df2e56Smrg unsigned int len; 1081f7df2e56Smrg 108205b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1083f7df2e56Smrg struct addrinfo hints, *ai = NULL; 108405b261ecSmrg#else 1085f7df2e56Smrg struct hostent *host; 1086f7df2e56Smrg 108705b261ecSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1088f7df2e56Smrg _Xgethostbynameparams hparams; 108905b261ecSmrg#endif 109005b261ecSmrg#endif 109105b261ecSmrg 1092f7df2e56Smrg gethostname(hname, 1024); 109305b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1094f7df2e56Smrg memset(&hints, 0, sizeof(hints)); 1095f7df2e56Smrg hints.ai_flags = AI_CANONNAME; 1096f7df2e56Smrg if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { 1097f7df2e56Smrg hnameptr = ai->ai_canonname; 1098f7df2e56Smrg } 1099f7df2e56Smrg else { 1100f7df2e56Smrg hnameptr = hname; 1101f7df2e56Smrg } 110205b261ecSmrg#else 1103f7df2e56Smrg host = _XGethostbyname(hname, hparams); 1104f7df2e56Smrg if (host == NULL) 1105f7df2e56Smrg hnameptr = hname; 1106f7df2e56Smrg else 1107f7df2e56Smrg hnameptr = host->h_name; 110805b261ecSmrg#endif 110905b261ecSmrg 1110f7df2e56Smrg len = strlen(hnameptr) + 1; 1111f7df2e56Smrg result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); 111205b261ecSmrg 1113f7df2e56Smrg p = result; 111405b261ecSmrg *p++ = sizeof(AUTHORIZATION_NAME) >> 8; 111505b261ecSmrg *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; 111605b261ecSmrg *p++ = (len) >> 8; 111705b261ecSmrg *p++ = (len & 0xff); 111805b261ecSmrg 1119f7df2e56Smrg memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); 1120f7df2e56Smrg p += sizeof(AUTHORIZATION_NAME); 1121f7df2e56Smrg memmove(p, hnameptr, len); 1122f7df2e56Smrg p += len; 112305b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1124f7df2e56Smrg if (ai) { 1125f7df2e56Smrg freeaddrinfo(ai); 1126f7df2e56Smrg } 112705b261ecSmrg#endif 112805b261ecSmrg } 112905b261ecSmrg *authlen = p - result; 113005b261ecSmrg *authorizations = result; 113105b261ecSmrg return 1; 1132f7df2e56Smrg#else /* TCPCONN */ 113305b261ecSmrg return 0; 1134f7df2e56Smrg#endif /* TCPCONN */ 113505b261ecSmrg} 113605b261ecSmrg 11374202a189Smrgvoid * 113805b261ecSmrgXNFalloc(unsigned long amount) 113905b261ecSmrg{ 11404202a189Smrg void *ptr = malloc(amount); 1141f7df2e56Smrg 114205b261ecSmrg if (!ptr) 114305b261ecSmrg FatalError("Out of memory"); 11444642e01fSmrg return ptr; 114505b261ecSmrg} 114605b261ecSmrg 1147f7df2e56Smrg/* The original XNFcalloc was used with the xnfcalloc macro which multiplied 1148f7df2e56Smrg * the arguments at the call site without allowing calloc to check for overflow. 1149f7df2e56Smrg * XNFcallocarray was added to fix that without breaking ABI. 1150f7df2e56Smrg */ 11514202a189Smrgvoid * 1152f7df2e56SmrgXNFcalloc(unsigned long amount) 115305b261ecSmrg{ 1154f7df2e56Smrg return XNFcallocarray(1, amount); 115505b261ecSmrg} 115605b261ecSmrg 11574202a189Smrgvoid * 1158f7df2e56SmrgXNFcallocarray(size_t nmemb, size_t size) 115905b261ecSmrg{ 1160f7df2e56Smrg void *ret = calloc(nmemb, size); 1161f7df2e56Smrg 11624202a189Smrg if (!ret) 11634202a189Smrg FatalError("XNFcalloc: Out of memory"); 116405b261ecSmrg return ret; 116505b261ecSmrg} 116605b261ecSmrg 11674202a189Smrgvoid * 11684202a189SmrgXNFrealloc(void *ptr, unsigned long amount) 116905b261ecSmrg{ 11704202a189Smrg void *ret = realloc(ptr, amount); 1171f7df2e56Smrg 11724202a189Smrg if (!ret) 1173f7df2e56Smrg FatalError("XNFrealloc: Out of memory"); 11744202a189Smrg return ret; 117505b261ecSmrg} 117605b261ecSmrg 1177f7df2e56Smrgvoid * 1178f7df2e56SmrgXNFreallocarray(void *ptr, size_t nmemb, size_t size) 117905b261ecSmrg{ 1180f7df2e56Smrg void *ret = reallocarray(ptr, nmemb, size); 118105b261ecSmrg 1182f7df2e56Smrg if (!ret) 1183f7df2e56Smrg FatalError("XNFreallocarray: Out of memory"); 1184f7df2e56Smrg return ret; 1185f7df2e56Smrg} 118605b261ecSmrg 118705b261ecSmrgchar * 118805b261ecSmrgXstrdup(const char *s) 118905b261ecSmrg{ 119005b261ecSmrg if (s == NULL) 1191f7df2e56Smrg return NULL; 11924202a189Smrg return strdup(s); 119305b261ecSmrg} 119405b261ecSmrg 11954202a189Smrgchar * 119605b261ecSmrgXNFstrdup(const char *s) 119705b261ecSmrg{ 11984202a189Smrg char *ret; 119905b261ecSmrg 120005b261ecSmrg if (s == NULL) 1201f7df2e56Smrg return NULL; 120205b261ecSmrg 12034202a189Smrg ret = strdup(s); 12044202a189Smrg if (!ret) 1205f7df2e56Smrg FatalError("XNFstrdup: Out of memory"); 12064202a189Smrg return ret; 120705b261ecSmrg} 120805b261ecSmrg 12094642e01fSmrgvoid 1210f7df2e56SmrgSmartScheduleStopTimer(void) 121105b261ecSmrg{ 12127e31ba66Smrg#ifdef HAVE_SETITIMER 1213f7df2e56Smrg struct itimerval timer; 1214f7df2e56Smrg 12157e31ba66Smrg if (!SmartScheduleSignalEnable) 1216f7df2e56Smrg return; 121705b261ecSmrg timer.it_interval.tv_sec = 0; 121805b261ecSmrg timer.it_interval.tv_usec = 0; 121905b261ecSmrg timer.it_value.tv_sec = 0; 122005b261ecSmrg timer.it_value.tv_usec = 0; 1221f7df2e56Smrg (void) setitimer(ITIMER_REAL, &timer, 0); 1222f7df2e56Smrg#endif 122305b261ecSmrg} 122405b261ecSmrg 12254642e01fSmrgvoid 1226f7df2e56SmrgSmartScheduleStartTimer(void) 122705b261ecSmrg{ 12287e31ba66Smrg#ifdef HAVE_SETITIMER 1229f7df2e56Smrg struct itimerval timer; 1230f7df2e56Smrg 12317e31ba66Smrg if (!SmartScheduleSignalEnable) 1232f7df2e56Smrg return; 123305b261ecSmrg timer.it_interval.tv_sec = 0; 123405b261ecSmrg timer.it_interval.tv_usec = SmartScheduleInterval * 1000; 123505b261ecSmrg timer.it_value.tv_sec = 0; 123605b261ecSmrg timer.it_value.tv_usec = SmartScheduleInterval * 1000; 1237f7df2e56Smrg setitimer(ITIMER_REAL, &timer, 0); 1238f7df2e56Smrg#endif 123905b261ecSmrg} 124005b261ecSmrg 12417e31ba66Smrg#ifdef HAVE_SETITIMER 124205b261ecSmrgstatic void 1243f7df2e56SmrgSmartScheduleTimer(int sig) 124405b261ecSmrg{ 124505b261ecSmrg SmartScheduleTime += SmartScheduleInterval; 124605b261ecSmrg} 124705b261ecSmrg 1248f7df2e56Smrgstatic int 1249f7df2e56SmrgSmartScheduleEnable(void) 125005b261ecSmrg{ 1251f7df2e56Smrg int ret = 0; 1252f7df2e56Smrg struct sigaction act; 125305b261ecSmrg 12547e31ba66Smrg if (!SmartScheduleSignalEnable) 1255f7df2e56Smrg return 0; 125665b04b38Smrg 12574202a189Smrg memset((char *) &act, 0, sizeof(struct sigaction)); 125805b261ecSmrg 125905b261ecSmrg /* Set up the timer signal function */ 1260f7df2e56Smrg act.sa_flags = SA_RESTART; 126105b261ecSmrg act.sa_handler = SmartScheduleTimer; 1262f7df2e56Smrg sigemptyset(&act.sa_mask); 1263f7df2e56Smrg sigaddset(&act.sa_mask, SIGALRM); 1264f7df2e56Smrg ret = sigaction(SIGALRM, &act, 0); 1265f7df2e56Smrg return ret; 1266f7df2e56Smrg} 1267f7df2e56Smrg 1268f7df2e56Smrgstatic int 1269f7df2e56SmrgSmartSchedulePause(void) 1270f7df2e56Smrg{ 1271f7df2e56Smrg int ret = 0; 1272f7df2e56Smrg struct sigaction act; 1273f7df2e56Smrg 12747e31ba66Smrg if (!SmartScheduleSignalEnable) 1275f7df2e56Smrg return 0; 1276f7df2e56Smrg 1277f7df2e56Smrg memset((char *) &act, 0, sizeof(struct sigaction)); 1278f7df2e56Smrg 1279f7df2e56Smrg act.sa_handler = SIG_IGN; 1280f7df2e56Smrg sigemptyset(&act.sa_mask); 1281f7df2e56Smrg ret = sigaction(SIGALRM, &act, 0); 1282f7df2e56Smrg return ret; 1283f7df2e56Smrg} 12847e31ba66Smrg#endif 1285f7df2e56Smrg 1286f7df2e56Smrgvoid 1287f7df2e56SmrgSmartScheduleInit(void) 1288f7df2e56Smrg{ 12897e31ba66Smrg#ifdef HAVE_SETITIMER 1290f7df2e56Smrg if (SmartScheduleEnable() < 0) { 1291f7df2e56Smrg perror("sigaction for smart scheduler"); 12927e31ba66Smrg SmartScheduleSignalEnable = FALSE; 129305b261ecSmrg } 12947e31ba66Smrg#endif 129505b261ecSmrg} 129605b261ecSmrg 12975a112b11Smrg#ifdef HAVE_SIGPROCMASK 1298f7df2e56Smrgstatic sigset_t PreviousSignalMask; 1299f7df2e56Smrgstatic int BlockedSignalCount; 130005b261ecSmrg#endif 130105b261ecSmrg 130205b261ecSmrgvoid 1303f7df2e56SmrgOsBlockSignals(void) 130405b261ecSmrg{ 13055a112b11Smrg#ifdef HAVE_SIGPROCMASK 1306f7df2e56Smrg if (BlockedSignalCount++ == 0) { 1307f7df2e56Smrg sigset_t set; 1308f7df2e56Smrg 1309f7df2e56Smrg sigemptyset(&set); 1310f7df2e56Smrg sigaddset(&set, SIGALRM); 1311f7df2e56Smrg sigaddset(&set, SIGVTALRM); 131205b261ecSmrg#ifdef SIGWINCH 1313f7df2e56Smrg sigaddset(&set, SIGWINCH); 1314f7df2e56Smrg#endif 1315f7df2e56Smrg sigaddset(&set, SIGTSTP); 1316f7df2e56Smrg sigaddset(&set, SIGTTIN); 1317f7df2e56Smrg sigaddset(&set, SIGTTOU); 1318f7df2e56Smrg sigaddset(&set, SIGCHLD); 13197e31ba66Smrg xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask); 132005b261ecSmrg } 132105b261ecSmrg#endif 132205b261ecSmrg} 132305b261ecSmrg 132405b261ecSmrgvoid 1325f7df2e56SmrgOsReleaseSignals(void) 132605b261ecSmrg{ 13275a112b11Smrg#ifdef HAVE_SIGPROCMASK 1328f7df2e56Smrg if (--BlockedSignalCount == 0) { 13297e31ba66Smrg xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0); 133005b261ecSmrg } 133105b261ecSmrg#endif 133205b261ecSmrg} 133305b261ecSmrg 1334f7df2e56Smrgvoid 1335f7df2e56SmrgOsResetSignals(void) 1336f7df2e56Smrg{ 13375a112b11Smrg#ifdef HAVE_SIGPROCMASK 1338f7df2e56Smrg while (BlockedSignalCount > 0) 1339f7df2e56Smrg OsReleaseSignals(); 13407e31ba66Smrg input_force_unlock(); 1341f7df2e56Smrg#endif 1342f7df2e56Smrg} 1343f7df2e56Smrg 13444202a189Smrg/* 13454202a189Smrg * Pending signals may interfere with core dumping. Provide a 13464202a189Smrg * mechanism to block signals when aborting. 13474202a189Smrg */ 13484202a189Smrg 13494202a189Smrgvoid 1350f7df2e56SmrgOsAbort(void) 13514202a189Smrg{ 13524202a189Smrg#ifndef __APPLE__ 13534202a189Smrg OsBlockSignals(); 13547e31ba66Smrg#endif 13557e31ba66Smrg#if !defined(WIN32) || defined(__CYGWIN__) 13567e31ba66Smrg /* abort() raises SIGABRT, so we have to stop handling that to prevent 13577e31ba66Smrg * recursion 13587e31ba66Smrg */ 13597e31ba66Smrg OsSignal(SIGABRT, SIG_DFL); 13604202a189Smrg#endif 13614202a189Smrg abort(); 13624202a189Smrg} 13634202a189Smrg 136405b261ecSmrg#if !defined(WIN32) 136505b261ecSmrg/* 136605b261ecSmrg * "safer" versions of system(3), popen(3) and pclose(3) which give up 136705b261ecSmrg * all privs before running a command. 136805b261ecSmrg * 136905b261ecSmrg * This is based on the code in FreeBSD 2.2 libc. 137005b261ecSmrg * 137105b261ecSmrg * XXX It'd be good to redirect stderr so that it ends up in the log file 137205b261ecSmrg * as well. As it is now, xkbcomp messages don't end up in the log file. 137305b261ecSmrg */ 137405b261ecSmrg 137505b261ecSmrgint 1376f7df2e56SmrgSystem(const char *command) 137705b261ecSmrg{ 137805b261ecSmrg int pid, p; 1379f7df2e56Smrg void (*csig) (int); 138005b261ecSmrg int status; 138105b261ecSmrg 138205b261ecSmrg if (!command) 1383f7df2e56Smrg return 1; 138405b261ecSmrg 13857e31ba66Smrg csig = OsSignal(SIGCHLD, SIG_DFL); 138605b261ecSmrg if (csig == SIG_ERR) { 1387f7df2e56Smrg perror("signal"); 1388f7df2e56Smrg return -1; 138905b261ecSmrg } 139065b04b38Smrg DebugF("System: `%s'\n", command); 139105b261ecSmrg 139205b261ecSmrg switch (pid = fork()) { 1393f7df2e56Smrg case -1: /* error */ 1394f7df2e56Smrg p = -1; 1395f7df2e56Smrg break; 1396f7df2e56Smrg case 0: /* child */ 1397f7df2e56Smrg if (setgid(getgid()) == -1) 1398f7df2e56Smrg _exit(127); 1399f7df2e56Smrg if (setuid(getuid()) == -1) 1400f7df2e56Smrg _exit(127); 1401f7df2e56Smrg execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1402f7df2e56Smrg _exit(127); 1403f7df2e56Smrg default: /* parent */ 1404f7df2e56Smrg do { 1405f7df2e56Smrg p = waitpid(pid, &status, 0); 1406f7df2e56Smrg } while (p == -1 && errno == EINTR); 1407f7df2e56Smrg 140805b261ecSmrg } 140905b261ecSmrg 14107e31ba66Smrg if (OsSignal(SIGCHLD, csig) == SIG_ERR) { 1411f7df2e56Smrg perror("signal"); 1412f7df2e56Smrg return -1; 141305b261ecSmrg } 141405b261ecSmrg 141505b261ecSmrg return p == -1 ? -1 : status; 141605b261ecSmrg} 141705b261ecSmrg 141805b261ecSmrgstatic struct pid { 141905b261ecSmrg struct pid *next; 142005b261ecSmrg FILE *fp; 142105b261ecSmrg int pid; 142205b261ecSmrg} *pidlist; 142305b261ecSmrg 1424f7df2e56Smrgvoid * 1425f7df2e56SmrgPopen(const char *command, const char *type) 142605b261ecSmrg{ 142705b261ecSmrg struct pid *cur; 142805b261ecSmrg FILE *iop; 142905b261ecSmrg int pdes[2], pid; 143005b261ecSmrg 143105b261ecSmrg if (command == NULL || type == NULL) 1432f7df2e56Smrg return NULL; 143305b261ecSmrg 143405b261ecSmrg if ((*type != 'r' && *type != 'w') || type[1]) 1435f7df2e56Smrg return NULL; 143605b261ecSmrg 14374202a189Smrg if ((cur = malloc(sizeof(struct pid))) == NULL) 1438f7df2e56Smrg return NULL; 143905b261ecSmrg 144005b261ecSmrg if (pipe(pdes) < 0) { 1441f7df2e56Smrg free(cur); 1442f7df2e56Smrg return NULL; 144305b261ecSmrg } 144405b261ecSmrg 144505b261ecSmrg /* Ignore the smart scheduler while this is going on */ 14467e31ba66Smrg#ifdef HAVE_SETITIMER 1447f7df2e56Smrg if (SmartSchedulePause() < 0) { 1448f7df2e56Smrg close(pdes[0]); 1449f7df2e56Smrg close(pdes[1]); 1450f7df2e56Smrg free(cur); 1451f7df2e56Smrg perror("signal"); 1452f7df2e56Smrg return NULL; 145305b261ecSmrg } 14547e31ba66Smrg#endif 145505b261ecSmrg 145605b261ecSmrg switch (pid = fork()) { 1457f7df2e56Smrg case -1: /* error */ 1458f7df2e56Smrg close(pdes[0]); 1459f7df2e56Smrg close(pdes[1]); 1460f7df2e56Smrg free(cur); 14617e31ba66Smrg#ifdef HAVE_SETITIMER 1462f7df2e56Smrg if (SmartScheduleEnable() < 0) 1463f7df2e56Smrg perror("signal"); 14647e31ba66Smrg#endif 1465f7df2e56Smrg return NULL; 1466f7df2e56Smrg case 0: /* child */ 1467f7df2e56Smrg if (setgid(getgid()) == -1) 1468f7df2e56Smrg _exit(127); 1469f7df2e56Smrg if (setuid(getuid()) == -1) 1470f7df2e56Smrg _exit(127); 1471f7df2e56Smrg if (*type == 'r') { 1472f7df2e56Smrg if (pdes[1] != 1) { 1473f7df2e56Smrg /* stdout */ 1474f7df2e56Smrg dup2(pdes[1], 1); 1475f7df2e56Smrg close(pdes[1]); 1476f7df2e56Smrg } 1477f7df2e56Smrg close(pdes[0]); 1478f7df2e56Smrg } 1479f7df2e56Smrg else { 1480f7df2e56Smrg if (pdes[0] != 0) { 1481f7df2e56Smrg /* stdin */ 1482f7df2e56Smrg dup2(pdes[0], 0); 1483f7df2e56Smrg close(pdes[0]); 1484f7df2e56Smrg } 1485f7df2e56Smrg close(pdes[1]); 1486f7df2e56Smrg } 1487f7df2e56Smrg execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1488f7df2e56Smrg _exit(127); 148905b261ecSmrg } 149005b261ecSmrg 149105b261ecSmrg /* Avoid EINTR during stdio calls */ 1492f7df2e56Smrg OsBlockSignals(); 1493f7df2e56Smrg 149405b261ecSmrg /* parent */ 149505b261ecSmrg if (*type == 'r') { 1496f7df2e56Smrg iop = fdopen(pdes[0], type); 1497f7df2e56Smrg close(pdes[1]); 1498f7df2e56Smrg } 1499f7df2e56Smrg else { 1500f7df2e56Smrg iop = fdopen(pdes[1], type); 1501f7df2e56Smrg close(pdes[0]); 150205b261ecSmrg } 150305b261ecSmrg 150405b261ecSmrg cur->fp = iop; 150505b261ecSmrg cur->pid = pid; 150605b261ecSmrg cur->next = pidlist; 150705b261ecSmrg pidlist = cur; 150805b261ecSmrg 150965b04b38Smrg DebugF("Popen: `%s', fp = %p\n", command, iop); 151005b261ecSmrg 151105b261ecSmrg return iop; 151205b261ecSmrg} 151305b261ecSmrg 151405b261ecSmrg/* fopen that drops privileges */ 1515f7df2e56Smrgvoid * 1516f7df2e56SmrgFopen(const char *file, const char *type) 151705b261ecSmrg{ 151805b261ecSmrg FILE *iop; 1519f7df2e56Smrg 152005b261ecSmrg#ifndef HAS_SAVED_IDS_AND_SETEUID 152105b261ecSmrg struct pid *cur; 152205b261ecSmrg int pdes[2], pid; 152305b261ecSmrg 152405b261ecSmrg if (file == NULL || type == NULL) 1525f7df2e56Smrg return NULL; 152605b261ecSmrg 152705b261ecSmrg if ((*type != 'r' && *type != 'w') || type[1]) 1528f7df2e56Smrg return NULL; 152905b261ecSmrg 15304202a189Smrg if ((cur = malloc(sizeof(struct pid))) == NULL) 1531f7df2e56Smrg return NULL; 153205b261ecSmrg 153305b261ecSmrg if (pipe(pdes) < 0) { 1534f7df2e56Smrg free(cur); 1535f7df2e56Smrg return NULL; 153605b261ecSmrg } 153705b261ecSmrg 153805b261ecSmrg switch (pid = fork()) { 1539f7df2e56Smrg case -1: /* error */ 1540f7df2e56Smrg close(pdes[0]); 1541f7df2e56Smrg close(pdes[1]); 1542f7df2e56Smrg free(cur); 1543f7df2e56Smrg return NULL; 1544f7df2e56Smrg case 0: /* child */ 1545f7df2e56Smrg if (setgid(getgid()) == -1) 1546f7df2e56Smrg _exit(127); 1547f7df2e56Smrg if (setuid(getuid()) == -1) 1548f7df2e56Smrg _exit(127); 1549f7df2e56Smrg if (*type == 'r') { 1550f7df2e56Smrg if (pdes[1] != 1) { 1551f7df2e56Smrg /* stdout */ 1552f7df2e56Smrg dup2(pdes[1], 1); 1553f7df2e56Smrg close(pdes[1]); 1554f7df2e56Smrg } 1555f7df2e56Smrg close(pdes[0]); 1556f7df2e56Smrg } 1557f7df2e56Smrg else { 1558f7df2e56Smrg if (pdes[0] != 0) { 1559f7df2e56Smrg /* stdin */ 1560f7df2e56Smrg dup2(pdes[0], 0); 1561f7df2e56Smrg close(pdes[0]); 1562f7df2e56Smrg } 1563f7df2e56Smrg close(pdes[1]); 1564f7df2e56Smrg } 1565f7df2e56Smrg execl("/bin/cat", "cat", file, (char *) NULL); 1566f7df2e56Smrg _exit(127); 156705b261ecSmrg } 156805b261ecSmrg 156905b261ecSmrg /* Avoid EINTR during stdio calls */ 1570f7df2e56Smrg OsBlockSignals(); 1571f7df2e56Smrg 157205b261ecSmrg /* parent */ 157305b261ecSmrg if (*type == 'r') { 1574f7df2e56Smrg iop = fdopen(pdes[0], type); 1575f7df2e56Smrg close(pdes[1]); 1576f7df2e56Smrg } 1577f7df2e56Smrg else { 1578f7df2e56Smrg iop = fdopen(pdes[1], type); 1579f7df2e56Smrg close(pdes[0]); 158005b261ecSmrg } 158105b261ecSmrg 158205b261ecSmrg cur->fp = iop; 158305b261ecSmrg cur->pid = pid; 158405b261ecSmrg cur->next = pidlist; 158505b261ecSmrg pidlist = cur; 158605b261ecSmrg 158765b04b38Smrg DebugF("Fopen(%s), fp = %p\n", file, iop); 158805b261ecSmrg 158905b261ecSmrg return iop; 159005b261ecSmrg#else 159105b261ecSmrg int ruid, euid; 159205b261ecSmrg 159305b261ecSmrg ruid = getuid(); 159405b261ecSmrg euid = geteuid(); 1595f7df2e56Smrg 159605b261ecSmrg if (seteuid(ruid) == -1) { 1597f7df2e56Smrg return NULL; 159805b261ecSmrg } 159905b261ecSmrg iop = fopen(file, type); 160005b261ecSmrg 160105b261ecSmrg if (seteuid(euid) == -1) { 1602f7df2e56Smrg fclose(iop); 1603f7df2e56Smrg return NULL; 160405b261ecSmrg } 160505b261ecSmrg return iop; 1606f7df2e56Smrg#endif /* HAS_SAVED_IDS_AND_SETEUID */ 160705b261ecSmrg} 160805b261ecSmrg 160905b261ecSmrgint 1610f7df2e56SmrgPclose(void *iop) 161105b261ecSmrg{ 161205b261ecSmrg struct pid *cur, *last; 161305b261ecSmrg int pstat; 161405b261ecSmrg int pid; 161505b261ecSmrg 161665b04b38Smrg DebugF("Pclose: fp = %p\n", iop); 161705b261ecSmrg fclose(iop); 161805b261ecSmrg 161905b261ecSmrg for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1620f7df2e56Smrg if (cur->fp == iop) 1621f7df2e56Smrg break; 162205b261ecSmrg if (cur == NULL) 1623f7df2e56Smrg return -1; 162405b261ecSmrg 162505b261ecSmrg do { 1626f7df2e56Smrg pid = waitpid(cur->pid, &pstat, 0); 162705b261ecSmrg } while (pid == -1 && errno == EINTR); 162805b261ecSmrg 162905b261ecSmrg if (last == NULL) 1630f7df2e56Smrg pidlist = cur->next; 163105b261ecSmrg else 1632f7df2e56Smrg last->next = cur->next; 16334202a189Smrg free(cur); 163405b261ecSmrg 163505b261ecSmrg /* allow EINTR again */ 1636f7df2e56Smrg OsReleaseSignals(); 1637f7df2e56Smrg 16387e31ba66Smrg#ifdef HAVE_SETITIMER 1639f7df2e56Smrg if (SmartScheduleEnable() < 0) { 1640f7df2e56Smrg perror("signal"); 1641f7df2e56Smrg return -1; 164205b261ecSmrg } 16437e31ba66Smrg#endif 164405b261ecSmrg 164505b261ecSmrg return pid == -1 ? -1 : pstat; 164605b261ecSmrg} 164705b261ecSmrg 16484202a189Smrgint 1649f7df2e56SmrgFclose(void *iop) 165005b261ecSmrg{ 165105b261ecSmrg#ifdef HAS_SAVED_IDS_AND_SETEUID 165205b261ecSmrg return fclose(iop); 165305b261ecSmrg#else 165405b261ecSmrg return Pclose(iop); 165505b261ecSmrg#endif 165605b261ecSmrg} 165705b261ecSmrg 1658f7df2e56Smrg#endif /* !WIN32 */ 1659f7df2e56Smrg 1660f7df2e56Smrg#ifdef WIN32 1661f7df2e56Smrg 1662f7df2e56Smrg#include <X11/Xwindows.h> 1663f7df2e56Smrg 1664f7df2e56Smrgconst char * 1665f7df2e56SmrgWin32TempDir(void) 1666f7df2e56Smrg{ 1667f7df2e56Smrg static char buffer[PATH_MAX]; 1668f7df2e56Smrg 1669f7df2e56Smrg if (GetTempPath(sizeof(buffer), buffer)) { 1670f7df2e56Smrg int len; 1671f7df2e56Smrg 1672f7df2e56Smrg buffer[sizeof(buffer) - 1] = 0; 1673f7df2e56Smrg len = strlen(buffer); 1674f7df2e56Smrg if (len > 0) 1675f7df2e56Smrg if (buffer[len - 1] == '\\') 1676f7df2e56Smrg buffer[len - 1] = 0; 1677f7df2e56Smrg return buffer; 1678f7df2e56Smrg } 1679f7df2e56Smrg if (getenv("TEMP") != NULL) 1680f7df2e56Smrg return getenv("TEMP"); 1681f7df2e56Smrg else if (getenv("TMP") != NULL) 1682f7df2e56Smrg return getenv("TMP"); 1683f7df2e56Smrg else 1684f7df2e56Smrg return "/tmp"; 1685f7df2e56Smrg} 1686f7df2e56Smrg 1687f7df2e56Smrgint 1688f7df2e56SmrgSystem(const char *cmdline) 1689f7df2e56Smrg{ 1690f7df2e56Smrg STARTUPINFO si; 1691f7df2e56Smrg PROCESS_INFORMATION pi; 1692f7df2e56Smrg DWORD dwExitCode; 1693f7df2e56Smrg char *cmd = strdup(cmdline); 1694f7df2e56Smrg 1695f7df2e56Smrg ZeroMemory(&si, sizeof(si)); 1696f7df2e56Smrg si.cb = sizeof(si); 1697f7df2e56Smrg ZeroMemory(&pi, sizeof(pi)); 1698f7df2e56Smrg 1699f7df2e56Smrg if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 1700f7df2e56Smrg LPVOID buffer; 1701f7df2e56Smrg 1702f7df2e56Smrg if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1703f7df2e56Smrg FORMAT_MESSAGE_FROM_SYSTEM | 1704f7df2e56Smrg FORMAT_MESSAGE_IGNORE_INSERTS, 1705f7df2e56Smrg NULL, 1706f7df2e56Smrg GetLastError(), 1707f7df2e56Smrg MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 1708f7df2e56Smrg (LPTSTR) &buffer, 0, NULL)) { 1709f7df2e56Smrg ErrorF("[xkb] Starting '%s' failed!\n", cmdline); 1710f7df2e56Smrg } 1711f7df2e56Smrg else { 1712f7df2e56Smrg ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); 1713f7df2e56Smrg LocalFree(buffer); 1714f7df2e56Smrg } 1715f7df2e56Smrg 1716f7df2e56Smrg free(cmd); 1717f7df2e56Smrg return -1; 1718f7df2e56Smrg } 1719f7df2e56Smrg /* Wait until child process exits. */ 1720f7df2e56Smrg WaitForSingleObject(pi.hProcess, INFINITE); 1721f7df2e56Smrg 1722f7df2e56Smrg GetExitCodeProcess(pi.hProcess, &dwExitCode); 172305b261ecSmrg 1724f7df2e56Smrg /* Close process and thread handles. */ 1725f7df2e56Smrg CloseHandle(pi.hProcess); 1726f7df2e56Smrg CloseHandle(pi.hThread); 1727f7df2e56Smrg free(cmd); 1728f7df2e56Smrg 1729f7df2e56Smrg return dwExitCode; 1730f7df2e56Smrg} 1731f7df2e56Smrg#endif 173205b261ecSmrg 17337e31ba66SmrgBool 17347e31ba66SmrgPrivsElevated(void) 17357e31ba66Smrg{ 17367e31ba66Smrg static Bool privsTested = FALSE; 17377e31ba66Smrg static Bool privsElevated = TRUE; 17387e31ba66Smrg 17397e31ba66Smrg if (!privsTested) { 17407e31ba66Smrg#if defined(WIN32) 17417e31ba66Smrg privsElevated = FALSE; 17427e31ba66Smrg#else 17437e31ba66Smrg if ((getuid() != geteuid()) || (getgid() != getegid())) { 17447e31ba66Smrg privsElevated = TRUE; 17457e31ba66Smrg } 17467e31ba66Smrg else { 17477e31ba66Smrg#if defined(HAVE_ISSETUGID) 17487e31ba66Smrg privsElevated = issetugid(); 17497e31ba66Smrg#elif defined(HAVE_GETRESUID) 17507e31ba66Smrg uid_t ruid, euid, suid; 17517e31ba66Smrg gid_t rgid, egid, sgid; 17527e31ba66Smrg 17537e31ba66Smrg if ((getresuid(&ruid, &euid, &suid) == 0) && 17547e31ba66Smrg (getresgid(&rgid, &egid, &sgid) == 0)) { 17557e31ba66Smrg privsElevated = (euid != suid) || (egid != sgid); 17567e31ba66Smrg } 17577e31ba66Smrg else { 17587e31ba66Smrg printf("Failed getresuid or getresgid"); 17597e31ba66Smrg /* Something went wrong, make defensive assumption */ 17607e31ba66Smrg privsElevated = TRUE; 17617e31ba66Smrg } 17627e31ba66Smrg#else 17637e31ba66Smrg if (getuid() == 0) { 17647e31ba66Smrg /* running as root: uid==euid==0 */ 17657e31ba66Smrg privsElevated = FALSE; 17667e31ba66Smrg } 17677e31ba66Smrg else { 17687e31ba66Smrg /* 17697e31ba66Smrg * If there are saved ID's the process might still be privileged 17707e31ba66Smrg * even though the above test succeeded. If issetugid() and 17717e31ba66Smrg * getresgid() aren't available, test this by trying to set 17727e31ba66Smrg * euid to 0. 17737e31ba66Smrg */ 17747e31ba66Smrg unsigned int oldeuid; 17757e31ba66Smrg 17767e31ba66Smrg oldeuid = geteuid(); 17777e31ba66Smrg 17787e31ba66Smrg if (seteuid(0) != 0) { 17797e31ba66Smrg privsElevated = FALSE; 17807e31ba66Smrg } 17817e31ba66Smrg else { 17827e31ba66Smrg if (seteuid(oldeuid) != 0) { 17837e31ba66Smrg FatalError("Failed to drop privileges. Exiting\n"); 17847e31ba66Smrg } 17857e31ba66Smrg privsElevated = TRUE; 17867e31ba66Smrg } 17877e31ba66Smrg } 17887e31ba66Smrg#endif 17897e31ba66Smrg } 17907e31ba66Smrg#endif 17917e31ba66Smrg privsTested = TRUE; 17927e31ba66Smrg } 17937e31ba66Smrg return privsElevated; 17947e31ba66Smrg} 17957e31ba66Smrg 179605b261ecSmrg/* 179705b261ecSmrg * CheckUserParameters: check for long command line arguments and long 179805b261ecSmrg * environment variables. By default, these checks are only done when 179905b261ecSmrg * the server's euid != ruid. In 3.3.x, these checks were done in an 180005b261ecSmrg * external wrapper utility. 180105b261ecSmrg */ 180205b261ecSmrg 180305b261ecSmrg/* Consider LD* variables insecure? */ 180405b261ecSmrg#ifndef REMOVE_ENV_LD 180505b261ecSmrg#define REMOVE_ENV_LD 1 180605b261ecSmrg#endif 180705b261ecSmrg 180805b261ecSmrg/* Remove long environment variables? */ 180905b261ecSmrg#ifndef REMOVE_LONG_ENV 181005b261ecSmrg#define REMOVE_LONG_ENV 1 181105b261ecSmrg#endif 181205b261ecSmrg 181305b261ecSmrg/* 181405b261ecSmrg * Disallow stdout or stderr as pipes? It's possible to block the X server 181505b261ecSmrg * when piping stdout+stderr to a pipe. 181605b261ecSmrg * 181705b261ecSmrg * Don't enable this because it looks like it's going to cause problems. 181805b261ecSmrg */ 181905b261ecSmrg#ifndef NO_OUTPUT_PIPES 182005b261ecSmrg#define NO_OUTPUT_PIPES 0 182105b261ecSmrg#endif 182205b261ecSmrg 182305b261ecSmrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 182405b261ecSmrg#ifndef CHECK_EUID 182505b261ecSmrg#ifndef WIN32 182605b261ecSmrg#define CHECK_EUID 1 182705b261ecSmrg#else 182805b261ecSmrg#define CHECK_EUID 0 182905b261ecSmrg#endif 183005b261ecSmrg#endif 183105b261ecSmrg 183205b261ecSmrg/* 183305b261ecSmrg * Maybe the locale can be faked to make isprint(3) report that everything 183405b261ecSmrg * is printable? Avoid it by default. 183505b261ecSmrg */ 183605b261ecSmrg#ifndef USE_ISPRINT 183705b261ecSmrg#define USE_ISPRINT 0 183805b261ecSmrg#endif 183905b261ecSmrg 184005b261ecSmrg#define MAX_ARG_LENGTH 128 184105b261ecSmrg#define MAX_ENV_LENGTH 256 1842f7df2e56Smrg#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 184305b261ecSmrg 184405b261ecSmrg#if USE_ISPRINT 184505b261ecSmrg#include <ctype.h> 184605b261ecSmrg#define checkPrintable(c) isprint(c) 184705b261ecSmrg#else 184805b261ecSmrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 184905b261ecSmrg#endif 185005b261ecSmrg 185105b261ecSmrgenum BadCode { 185205b261ecSmrg NotBad = 0, 185305b261ecSmrg UnsafeArg, 185405b261ecSmrg ArgTooLong, 185505b261ecSmrg UnprintableArg, 185605b261ecSmrg EnvTooLong, 185705b261ecSmrg OutputIsPipe, 185805b261ecSmrg InternalError 185905b261ecSmrg}; 186005b261ecSmrg 186105b261ecSmrg#if defined(VENDORSUPPORT) 186205b261ecSmrg#define BUGADDRESS VENDORSUPPORT 186305b261ecSmrg#elif defined(BUILDERADDR) 186405b261ecSmrg#define BUGADDRESS BUILDERADDR 186505b261ecSmrg#else 186605b261ecSmrg#define BUGADDRESS "xorg@freedesktop.org" 186705b261ecSmrg#endif 186805b261ecSmrg 186905b261ecSmrgvoid 187005b261ecSmrgCheckUserParameters(int argc, char **argv, char **envp) 187105b261ecSmrg{ 187205b261ecSmrg enum BadCode bad = NotBad; 187305b261ecSmrg int i = 0, j; 187405b261ecSmrg char *a, *e = NULL; 187505b261ecSmrg 187605b261ecSmrg#if CHECK_EUID 18777e31ba66Smrg if (PrivsElevated()) 187805b261ecSmrg#endif 187905b261ecSmrg { 1880f7df2e56Smrg /* Check each argv[] */ 1881f7df2e56Smrg for (i = 1; i < argc; i++) { 1882f7df2e56Smrg if (strcmp(argv[i], "-fp") == 0) { 1883f7df2e56Smrg i++; /* continue with next argument. skip the length check */ 1884f7df2e56Smrg if (i >= argc) 1885f7df2e56Smrg break; 1886f7df2e56Smrg } 1887f7df2e56Smrg else { 1888f7df2e56Smrg if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1889f7df2e56Smrg bad = ArgTooLong; 1890f7df2e56Smrg break; 1891f7df2e56Smrg } 1892f7df2e56Smrg } 1893f7df2e56Smrg a = argv[i]; 1894f7df2e56Smrg while (*a) { 1895f7df2e56Smrg if (checkPrintable(*a) == 0) { 1896f7df2e56Smrg bad = UnprintableArg; 1897f7df2e56Smrg break; 1898f7df2e56Smrg } 1899f7df2e56Smrg a++; 1900f7df2e56Smrg } 1901f7df2e56Smrg if (bad) 1902f7df2e56Smrg break; 1903f7df2e56Smrg } 1904f7df2e56Smrg if (!bad) { 1905f7df2e56Smrg /* Check each envp[] */ 1906f7df2e56Smrg for (i = 0; envp[i]; i++) { 190705b261ecSmrg 1908f7df2e56Smrg /* Check for bad environment variables and values */ 190905b261ecSmrg#if REMOVE_ENV_LD 1910f7df2e56Smrg while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1911f7df2e56Smrg for (j = i; envp[j]; j++) { 1912f7df2e56Smrg envp[j] = envp[j + 1]; 1913f7df2e56Smrg } 1914f7df2e56Smrg } 1915f7df2e56Smrg#endif 1916f7df2e56Smrg if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 191705b261ecSmrg#if REMOVE_LONG_ENV 1918f7df2e56Smrg for (j = i; envp[j]; j++) { 1919f7df2e56Smrg envp[j] = envp[j + 1]; 1920f7df2e56Smrg } 1921f7df2e56Smrg i--; 192205b261ecSmrg#else 1923f7df2e56Smrg char *eq; 1924f7df2e56Smrg int len; 1925f7df2e56Smrg 1926f7df2e56Smrg eq = strchr(envp[i], '='); 1927f7df2e56Smrg if (!eq) 1928f7df2e56Smrg continue; 1929f7df2e56Smrg len = eq - envp[i]; 1930f7df2e56Smrg e = strndup(envp[i], len); 1931f7df2e56Smrg if (!e) { 1932f7df2e56Smrg bad = InternalError; 1933f7df2e56Smrg break; 1934f7df2e56Smrg } 1935f7df2e56Smrg if (len >= 4 && 1936f7df2e56Smrg (strcmp(e + len - 4, "PATH") == 0 || 1937f7df2e56Smrg strcmp(e, "TERMCAP") == 0)) { 1938f7df2e56Smrg if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1939f7df2e56Smrg bad = EnvTooLong; 1940f7df2e56Smrg break; 1941f7df2e56Smrg } 1942f7df2e56Smrg else { 1943f7df2e56Smrg free(e); 1944f7df2e56Smrg } 1945f7df2e56Smrg } 1946f7df2e56Smrg else { 1947f7df2e56Smrg bad = EnvTooLong; 1948f7df2e56Smrg break; 1949f7df2e56Smrg } 1950f7df2e56Smrg#endif 1951f7df2e56Smrg } 1952f7df2e56Smrg } 1953f7df2e56Smrg } 195405b261ecSmrg#if NO_OUTPUT_PIPES 1955f7df2e56Smrg if (!bad) { 1956f7df2e56Smrg struct stat buf; 195705b261ecSmrg 1958f7df2e56Smrg if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1959f7df2e56Smrg bad = OutputIsPipe; 1960f7df2e56Smrg if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1961f7df2e56Smrg bad = OutputIsPipe; 1962f7df2e56Smrg } 196305b261ecSmrg#endif 196405b261ecSmrg } 196505b261ecSmrg switch (bad) { 196605b261ecSmrg case NotBad: 1967f7df2e56Smrg return; 196805b261ecSmrg case UnsafeArg: 1969f7df2e56Smrg ErrorF("Command line argument number %d is unsafe\n", i); 1970f7df2e56Smrg break; 197105b261ecSmrg case ArgTooLong: 1972f7df2e56Smrg ErrorF("Command line argument number %d is too long\n", i); 1973f7df2e56Smrg break; 197405b261ecSmrg case UnprintableArg: 1975f7df2e56Smrg ErrorF("Command line argument number %d contains unprintable" 1976f7df2e56Smrg " characters\n", i); 1977f7df2e56Smrg break; 197805b261ecSmrg case EnvTooLong: 1979f7df2e56Smrg ErrorF("Environment variable `%s' is too long\n", e); 1980f7df2e56Smrg break; 198105b261ecSmrg case OutputIsPipe: 1982f7df2e56Smrg ErrorF("Stdout and/or stderr is a pipe\n"); 1983f7df2e56Smrg break; 198405b261ecSmrg case InternalError: 1985f7df2e56Smrg ErrorF("Internal Error\n"); 1986f7df2e56Smrg break; 198705b261ecSmrg default: 1988f7df2e56Smrg ErrorF("Unknown error\n"); 1989f7df2e56Smrg break; 199005b261ecSmrg } 199105b261ecSmrg FatalError("X server aborted because of unsafe environment\n"); 199205b261ecSmrg} 199305b261ecSmrg 199405b261ecSmrg/* 199505b261ecSmrg * CheckUserAuthorization: check if the user is allowed to start the 199605b261ecSmrg * X server. This usually means some sort of PAM checking, and it is 199705b261ecSmrg * usually only done for setuid servers (uid != euid). 199805b261ecSmrg */ 199905b261ecSmrg 200005b261ecSmrg#ifdef USE_PAM 200105b261ecSmrg#include <security/pam_appl.h> 200205b261ecSmrg#include <security/pam_misc.h> 200305b261ecSmrg#include <pwd.h> 2004f7df2e56Smrg#endif /* USE_PAM */ 200505b261ecSmrg 200605b261ecSmrgvoid 200705b261ecSmrgCheckUserAuthorization(void) 200805b261ecSmrg{ 200905b261ecSmrg#ifdef USE_PAM 201005b261ecSmrg static struct pam_conv conv = { 2011f7df2e56Smrg misc_conv, 2012f7df2e56Smrg NULL 201305b261ecSmrg }; 201405b261ecSmrg 201505b261ecSmrg pam_handle_t *pamh = NULL; 201605b261ecSmrg struct passwd *pw; 201705b261ecSmrg int retval; 201805b261ecSmrg 201905b261ecSmrg if (getuid() != geteuid()) { 2020f7df2e56Smrg pw = getpwuid(getuid()); 2021f7df2e56Smrg if (pw == NULL) 2022f7df2e56Smrg FatalError("getpwuid() failed for uid %d\n", getuid()); 2023f7df2e56Smrg 2024f7df2e56Smrg retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 2025f7df2e56Smrg if (retval != PAM_SUCCESS) 2026f7df2e56Smrg FatalError("pam_start() failed.\n" 2027f7df2e56Smrg "\tMissing or mangled PAM config file or module?\n"); 2028f7df2e56Smrg 2029f7df2e56Smrg retval = pam_authenticate(pamh, 0); 2030f7df2e56Smrg if (retval != PAM_SUCCESS) { 2031f7df2e56Smrg pam_end(pamh, retval); 2032f7df2e56Smrg FatalError("PAM authentication failed, cannot start X server.\n" 2033f7df2e56Smrg "\tPerhaps you do not have console ownership?\n"); 2034f7df2e56Smrg } 203505b261ecSmrg 2036f7df2e56Smrg retval = pam_acct_mgmt(pamh, 0); 2037f7df2e56Smrg if (retval != PAM_SUCCESS) { 2038f7df2e56Smrg pam_end(pamh, retval); 2039f7df2e56Smrg FatalError("PAM authentication failed, cannot start X server.\n" 2040f7df2e56Smrg "\tPerhaps you do not have console ownership?\n"); 2041f7df2e56Smrg } 204205b261ecSmrg 2043f7df2e56Smrg /* this is not a session, so do not do session management */ 2044f7df2e56Smrg pam_end(pamh, PAM_SUCCESS); 204505b261ecSmrg } 204605b261ecSmrg#endif 204705b261ecSmrg} 204805b261ecSmrg 20494202a189Smrg/* 20504202a189Smrg * Tokenize a string into a NULL terminated array of strings. Always returns 20514202a189Smrg * an allocated array unless an error occurs. 20524202a189Smrg */ 2053f7df2e56Smrgchar ** 20544202a189Smrgxstrtokenize(const char *str, const char *separators) 205505b261ecSmrg{ 20564202a189Smrg char **list, **nlist; 20574202a189Smrg char *tok, *tmp; 20584202a189Smrg unsigned num = 0, n; 205905b261ecSmrg 20604202a189Smrg if (!str) 20614202a189Smrg return NULL; 20624202a189Smrg list = calloc(1, sizeof(*list)); 20634202a189Smrg if (!list) 20644202a189Smrg return NULL; 20654202a189Smrg tmp = strdup(str); 20664202a189Smrg if (!tmp) 20674202a189Smrg goto error; 20684202a189Smrg for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 2069f7df2e56Smrg nlist = reallocarray(list, num + 2, sizeof(*list)); 20704202a189Smrg if (!nlist) 20714202a189Smrg goto error; 20724202a189Smrg list = nlist; 20734202a189Smrg list[num] = strdup(tok); 20744202a189Smrg if (!list[num]) 20754202a189Smrg goto error; 20764202a189Smrg list[++num] = NULL; 20774202a189Smrg } 20784202a189Smrg free(tmp); 20794202a189Smrg return list; 20804202a189Smrg 2081f7df2e56Smrg error: 20824202a189Smrg free(tmp); 20834202a189Smrg for (n = 0; n < num; n++) 20844202a189Smrg free(list[n]); 20854202a189Smrg free(list); 20864202a189Smrg return NULL; 208705b261ecSmrg} 2088f7df2e56Smrg 2089f7df2e56Smrg/* Format a signed number into a string in a signal safe manner. The string 2090f7df2e56Smrg * should be at least 21 characters in order to handle all int64_t values. 2091f7df2e56Smrg */ 2092f7df2e56Smrgvoid 2093f7df2e56SmrgFormatInt64(int64_t num, char *string) 2094f7df2e56Smrg{ 2095f7df2e56Smrg if (num < 0) { 2096f7df2e56Smrg string[0] = '-'; 2097f7df2e56Smrg num *= -1; 2098f7df2e56Smrg string++; 2099f7df2e56Smrg } 2100f7df2e56Smrg FormatUInt64(num, string); 2101f7df2e56Smrg} 2102f7df2e56Smrg 2103f7df2e56Smrg/* Format a number into a string in a signal safe manner. The string should be 2104f7df2e56Smrg * at least 21 characters in order to handle all uint64_t values. */ 2105f7df2e56Smrgvoid 2106f7df2e56SmrgFormatUInt64(uint64_t num, char *string) 2107f7df2e56Smrg{ 2108f7df2e56Smrg uint64_t divisor; 2109f7df2e56Smrg int len; 2110f7df2e56Smrg int i; 2111f7df2e56Smrg 2112f7df2e56Smrg for (len = 1, divisor = 10; 2113f7df2e56Smrg len < 20 && num / divisor; 2114f7df2e56Smrg len++, divisor *= 10); 2115f7df2e56Smrg 2116f7df2e56Smrg for (i = len, divisor = 1; i > 0; i--, divisor *= 10) 2117f7df2e56Smrg string[i - 1] = '0' + ((num / divisor) % 10); 2118f7df2e56Smrg 2119f7df2e56Smrg string[len] = '\0'; 2120f7df2e56Smrg} 2121f7df2e56Smrg 2122f7df2e56Smrg/** 2123f7df2e56Smrg * Format a double number as %.2f. 2124f7df2e56Smrg */ 2125f7df2e56Smrgvoid 2126f7df2e56SmrgFormatDouble(double dbl, char *string) 2127f7df2e56Smrg{ 2128f7df2e56Smrg int slen = 0; 2129f7df2e56Smrg uint64_t frac; 2130f7df2e56Smrg 2131f7df2e56Smrg frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; 2132f7df2e56Smrg frac %= 100; 2133f7df2e56Smrg 2134f7df2e56Smrg /* write decimal part to string */ 2135f7df2e56Smrg if (dbl < 0 && dbl > -1) 2136f7df2e56Smrg string[slen++] = '-'; 2137f7df2e56Smrg FormatInt64((int64_t)dbl, &string[slen]); 2138f7df2e56Smrg 2139f7df2e56Smrg while(string[slen] != '\0') 2140f7df2e56Smrg slen++; 2141f7df2e56Smrg 2142f7df2e56Smrg /* append fractional part, but only if we have enough characters. We 2143f7df2e56Smrg * expect string to be 21 chars (incl trailing \0) */ 2144f7df2e56Smrg if (slen <= 17) { 2145f7df2e56Smrg string[slen++] = '.'; 2146f7df2e56Smrg if (frac < 10) 2147f7df2e56Smrg string[slen++] = '0'; 2148f7df2e56Smrg 2149f7df2e56Smrg FormatUInt64(frac, &string[slen]); 2150f7df2e56Smrg } 2151f7df2e56Smrg} 2152f7df2e56Smrg 2153f7df2e56Smrg 2154f7df2e56Smrg/* Format a number into a hexadecimal string in a signal safe manner. The string 2155f7df2e56Smrg * should be at least 17 characters in order to handle all uint64_t values. */ 2156f7df2e56Smrgvoid 2157f7df2e56SmrgFormatUInt64Hex(uint64_t num, char *string) 2158f7df2e56Smrg{ 2159f7df2e56Smrg uint64_t divisor; 2160f7df2e56Smrg int len; 2161f7df2e56Smrg int i; 2162f7df2e56Smrg 2163f7df2e56Smrg for (len = 1, divisor = 0x10; 2164f7df2e56Smrg len < 16 && num / divisor; 2165f7df2e56Smrg len++, divisor *= 0x10); 2166f7df2e56Smrg 2167f7df2e56Smrg for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { 2168f7df2e56Smrg int val = (num / divisor) % 0x10; 2169f7df2e56Smrg 2170f7df2e56Smrg if (val < 10) 2171f7df2e56Smrg string[i - 1] = '0' + val; 2172f7df2e56Smrg else 2173f7df2e56Smrg string[i - 1] = 'a' + val - 10; 2174f7df2e56Smrg } 2175f7df2e56Smrg 2176f7df2e56Smrg string[len] = '\0'; 2177f7df2e56Smrg} 2178f7df2e56Smrg 2179f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__) 2180f7df2e56Smrg/* Move a file descriptor out of the way of our select mask; this 2181f7df2e56Smrg * is useful for file descriptors which will never appear in the 2182f7df2e56Smrg * select mask to avoid reducing the number of clients that can 2183f7df2e56Smrg * connect to the server 2184f7df2e56Smrg */ 2185f7df2e56Smrgint 2186f7df2e56Smrgos_move_fd(int fd) 2187f7df2e56Smrg{ 2188f7df2e56Smrg int newfd; 2189f7df2e56Smrg 2190f7df2e56Smrg#ifdef F_DUPFD_CLOEXEC 2191f7df2e56Smrg newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); 2192f7df2e56Smrg#else 2193f7df2e56Smrg newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); 2194f7df2e56Smrg#endif 2195f7df2e56Smrg if (newfd < 0) 2196f7df2e56Smrg return fd; 2197f7df2e56Smrg#ifndef F_DUPFD_CLOEXEC 2198f7df2e56Smrg fcntl(newfd, F_SETFD, FD_CLOEXEC); 2199f7df2e56Smrg#endif 2200f7df2e56Smrg close(fd); 2201f7df2e56Smrg return newfd; 2202f7df2e56Smrg} 2203f7df2e56Smrg#endif 2204