1/* 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 28Copyright 1994 Quarterdeck Office Systems. 29 30 All Rights Reserved 31 32Permission to use, copy, modify, and distribute this software and its 33documentation for any purpose and without fee is hereby granted, 34provided that the above copyright notice appear in all copies and that 35both that copyright notice and this permission notice appear in 36supporting documentation, and that the names of Digital and 37Quarterdeck not be used in advertising or publicity pertaining to 38distribution of the software without specific, written prior 39permission. 40 41DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 42SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 43FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT 44OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 45OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 46OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 47OR PERFORMANCE OF THIS SOFTWARE. 48 49*/ 50 51#ifdef HAVE_DIX_CONFIG_H 52#include <dix-config.h> 53#endif 54 55#ifdef __CYGWIN__ 56#include <stdlib.h> 57#include <signal.h> 58/* 59 Sigh... We really need a prototype for this to know it is stdcall, 60 but #include-ing <windows.h> here is not a good idea... 61*/ 62__stdcall unsigned long GetTickCount(void); 63#endif 64 65#if defined(WIN32) && !defined(__CYGWIN__) 66#include <X11/Xwinsock.h> 67#endif 68#include <X11/Xos.h> 69#include <stdio.h> 70#include <time.h> 71#if !defined(WIN32) || !defined(__MINGW32__) 72#include <sys/time.h> 73#include <sys/resource.h> 74#endif 75#include "misc.h" 76#include <X11/X.h> 77#define XSERV_t 78#define TRANS_SERVER 79#define TRANS_REOPEN 80#include <X11/Xtrans/Xtrans.h> 81#include "input.h" 82#include "dixfont.h" 83#include <X11/fonts/libxfont2.h> 84#include "osdep.h" 85#include "extension.h" 86#include <signal.h> 87#ifndef WIN32 88#include <sys/wait.h> 89#endif 90#if !defined(SYSV) && !defined(WIN32) 91#include <sys/resource.h> 92#endif 93#include <sys/stat.h> 94#include <ctype.h> /* for isspace */ 95#include <stdarg.h> 96 97#include <stdlib.h> /* for malloc() */ 98 99#if defined(TCPCONN) 100#ifndef WIN32 101#include <netdb.h> 102#endif 103#endif 104 105#include "opaque.h" 106 107#include "dixstruct.h" 108 109#include "xkbsrv.h" 110 111#include "picture.h" 112 113#include "miinitext.h" 114 115#include "present.h" 116 117Bool noTestExtensions; 118 119#ifdef COMPOSITE 120Bool noCompositeExtension = FALSE; 121#endif 122 123#ifdef DAMAGE 124Bool noDamageExtension = FALSE; 125#endif 126#ifdef DBE 127Bool noDbeExtension = FALSE; 128#endif 129#ifdef DPMSExtension 130#include "dpmsproc.h" 131Bool noDPMSExtension = FALSE; 132#endif 133#ifdef GLXEXT 134Bool noGlxExtension = FALSE; 135#endif 136#ifdef SCREENSAVER 137Bool noScreenSaverExtension = FALSE; 138#endif 139#ifdef MITSHM 140Bool noMITShmExtension = FALSE; 141#endif 142#ifdef RANDR 143Bool noRRExtension = FALSE; 144#endif 145Bool noRenderExtension = FALSE; 146 147#ifdef XCSECURITY 148Bool noSecurityExtension = FALSE; 149#endif 150#ifdef RES 151Bool noResExtension = FALSE; 152#endif 153#ifdef XF86BIGFONT 154Bool noXFree86BigfontExtension = FALSE; 155#endif 156#ifdef XFreeXDGA 157Bool noXFree86DGAExtension = FALSE; 158#endif 159#ifdef XF86DRI 160Bool noXFree86DRIExtension = FALSE; 161#endif 162#ifdef XF86VIDMODE 163Bool noXFree86VidModeExtension = FALSE; 164#endif 165Bool noXFixesExtension = FALSE; 166#ifdef PANORAMIX 167/* Xinerama is disabled by default unless enabled via +xinerama */ 168Bool noPanoramiXExtension = TRUE; 169#endif 170#ifdef XSELINUX 171Bool noSELinuxExtension = FALSE; 172int selinuxEnforcingState = SELINUX_MODE_DEFAULT; 173#endif 174#ifdef XV 175Bool noXvExtension = FALSE; 176#endif 177#ifdef DRI2 178Bool noDRI2Extension = FALSE; 179#endif 180 181Bool noGEExtension = FALSE; 182 183#define X_INCLUDE_NETDB_H 184#include <X11/Xos_r.h> 185 186#include <errno.h> 187 188Bool CoreDump; 189 190Bool enableIndirectGLX = FALSE; 191 192Bool AllowByteSwappedClients = TRUE; 193 194#ifdef PANORAMIX 195Bool PanoramiXExtensionDisabledHack = FALSE; 196#endif 197 198int auditTrailLevel = 1; 199 200char *SeatId = NULL; 201 202sig_atomic_t inSignalContext = FALSE; 203 204#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) 205#define HAS_SAVED_IDS_AND_SETEUID 206#endif 207 208#ifdef MONOTONIC_CLOCK 209static clockid_t clockid; 210#endif 211 212OsSigHandlerPtr 213OsSignal(int sig, OsSigHandlerPtr handler) 214{ 215#if defined(WIN32) && !defined(__CYGWIN__) 216 return signal(sig, handler); 217#else 218 struct sigaction act, oact; 219 220 sigemptyset(&act.sa_mask); 221 if (handler != SIG_IGN) 222 sigaddset(&act.sa_mask, sig); 223 act.sa_flags = 0; 224 act.sa_handler = handler; 225 if (sigaction(sig, &act, &oact)) 226 perror("sigaction"); 227 return oact.sa_handler; 228#endif 229} 230 231/* 232 * Explicit support for a server lock file like the ones used for UUCP. 233 * For architectures with virtual terminals that can run more than one 234 * server at a time. This keeps the servers from stomping on each other 235 * if the user forgets to give them different display numbers. 236 */ 237#define LOCK_DIR "/tmp" 238#define LOCK_TMP_PREFIX "/.tX" 239#define LOCK_PREFIX "/.X" 240#define LOCK_SUFFIX "-lock" 241 242#if !defined(WIN32) || defined(__CYGWIN__) 243#define LOCK_SERVER 244#endif 245 246#ifndef LOCK_SERVER 247void 248LockServer(void) 249{} 250 251void 252UnlockServer(void) 253{} 254#else /* LOCK_SERVER */ 255static Bool StillLocking = FALSE; 256static char LockFile[PATH_MAX]; 257static Bool nolock = FALSE; 258 259/* 260 * LockServer -- 261 * Check if the server lock file exists. If so, check if the PID 262 * contained inside is valid. If so, then die. Otherwise, create 263 * the lock file containing the PID. 264 */ 265void 266LockServer(void) 267{ 268 char tmp[PATH_MAX], pid_str[12]; 269 int lfd, i, haslock, l_pid, t; 270 const char *tmppath = LOCK_DIR; 271 int len; 272 char port[20]; 273 274 if (nolock || NoListenAll) 275 return; 276 /* 277 * Path names 278 */ 279 snprintf(port, sizeof(port), "%d", atoi(display)); 280 len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : 281 strlen(LOCK_TMP_PREFIX); 282 len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; 283 if (len > sizeof(LockFile)) 284 FatalError("Display name `%s' is too long\n", port); 285 (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 286 (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 287 288 /* 289 * Create a temporary file containing our PID. Attempt three times 290 * to create the file. 291 */ 292 StillLocking = TRUE; 293 i = 0; 294 do { 295 i++; 296 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 297 if (lfd < 0) 298 sleep(2); 299 else 300 break; 301 } while (i < 3); 302 if (lfd < 0) { 303 unlink(tmp); 304 i = 0; 305 do { 306 i++; 307 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 308 if (lfd < 0) 309 sleep(2); 310 else 311 break; 312 } while (i < 3); 313 } 314 if (lfd < 0) 315 FatalError("Could not create lock file in %s\n", tmp); 316 snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid()); 317 if (write(lfd, pid_str, 11) != 11) 318 FatalError("Could not write pid to lock file in %s\n", tmp); 319 (void) fchmod(lfd, 0444); 320 (void) close(lfd); 321 322 /* 323 * OK. Now the tmp file exists. Try three times to move it in place 324 * for the lock. 325 */ 326 i = 0; 327 haslock = 0; 328 while ((!haslock) && (i++ < 3)) { 329 haslock = (link(tmp, LockFile) == 0); 330 if (haslock) { 331 /* 332 * We're done. 333 */ 334 break; 335 } 336 else if (errno == EEXIST) { 337 /* 338 * Read the pid from the existing file 339 */ 340 lfd = open(LockFile, O_RDONLY | O_NOFOLLOW); 341 if (lfd < 0) { 342 unlink(tmp); 343 FatalError("Can't read lock file %s\n", LockFile); 344 } 345 pid_str[0] = '\0'; 346 if (read(lfd, pid_str, 11) != 11) { 347 /* 348 * Bogus lock file. 349 */ 350 unlink(LockFile); 351 close(lfd); 352 continue; 353 } 354 pid_str[11] = '\0'; 355 sscanf(pid_str, "%d", &l_pid); 356 close(lfd); 357 358 /* 359 * Now try to kill the PID to see if it exists. 360 */ 361 errno = 0; 362 t = kill(l_pid, 0); 363 if ((t < 0) && (errno == ESRCH)) { 364 /* 365 * Stale lock file. 366 */ 367 unlink(LockFile); 368 continue; 369 } 370 else if (((t < 0) && (errno == EPERM)) || (t == 0)) { 371 /* 372 * Process is still active. 373 */ 374 unlink(tmp); 375 FatalError 376 ("Server is already active for display %s\n%s %s\n%s\n", 377 port, "\tIf this server is no longer running, remove", 378 LockFile, "\tand start again."); 379 } 380 } 381 else { 382 unlink(tmp); 383 FatalError 384 ("Linking lock file (%s) in place failed: %s\n", 385 LockFile, strerror(errno)); 386 } 387 } 388 unlink(tmp); 389 if (!haslock) 390 FatalError("Could not create server lock file: %s\n", LockFile); 391 StillLocking = FALSE; 392} 393 394/* 395 * UnlockServer -- 396 * Remove the server lock file. 397 */ 398void 399UnlockServer(void) 400{ 401 if (nolock || NoListenAll) 402 return; 403 404 if (!StillLocking) { 405 406 (void) unlink(LockFile); 407 } 408} 409#endif /* LOCK_SERVER */ 410 411/* Force connections to close on SIGHUP from init */ 412 413void 414AutoResetServer(int sig) 415{ 416 int olderrno = errno; 417 418 dispatchException |= DE_RESET; 419 isItTimeToYield = TRUE; 420 errno = olderrno; 421} 422 423/* Force connections to close and then exit on SIGTERM, SIGINT */ 424 425void 426GiveUp(int sig) 427{ 428 int olderrno = errno; 429 430 dispatchException |= DE_TERMINATE; 431 isItTimeToYield = TRUE; 432 errno = olderrno; 433} 434 435#ifdef MONOTONIC_CLOCK 436void 437ForceClockId(clockid_t forced_clockid) 438{ 439 struct timespec tp; 440 441 BUG_RETURN (clockid); 442 443 clockid = forced_clockid; 444 445 if (clock_gettime(clockid, &tp) != 0) { 446 FatalError("Forced clock id failed to retrieve current time: %s\n", 447 strerror(errno)); 448 return; 449 } 450} 451#endif 452 453#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__) 454CARD32 455GetTimeInMillis(void) 456{ 457 return GetTickCount(); 458} 459CARD64 460GetTimeInMicros(void) 461{ 462 return (CARD64) GetTickCount() * 1000; 463} 464#else 465CARD32 466GetTimeInMillis(void) 467{ 468 struct timeval tv; 469 470#ifdef MONOTONIC_CLOCK 471 struct timespec tp; 472 473 if (!clockid) { 474#ifdef CLOCK_MONOTONIC_COARSE 475 if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 && 476 (tp.tv_nsec / 1000) <= 1000 && 477 clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0) 478 clockid = CLOCK_MONOTONIC_COARSE; 479 else 480#endif 481 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 482 clockid = CLOCK_MONOTONIC; 483 else 484 clockid = ~0L; 485 } 486 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0) 487 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); 488#endif 489 490 X_GETTIMEOFDAY(&tv); 491 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 492} 493 494CARD64 495GetTimeInMicros(void) 496{ 497 struct timeval tv; 498#ifdef MONOTONIC_CLOCK 499 struct timespec tp; 500 static clockid_t uclockid; 501 502 if (!uclockid) { 503 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 504 uclockid = CLOCK_MONOTONIC; 505 else 506 uclockid = ~0L; 507 } 508 if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0) 509 return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000; 510#endif 511 512 X_GETTIMEOFDAY(&tv); 513 return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec; 514} 515#endif 516 517void 518UseMsg(void) 519{ 520 ErrorF("use: X [:<display>] [option]\n"); 521 ErrorF("-a # default pointer acceleration (factor)\n"); 522 ErrorF("-ac disable access control restrictions\n"); 523 ErrorF("-audit int set audit trail level\n"); 524 ErrorF("-auth file select authorization file\n"); 525 ErrorF("-br create root window with black background\n"); 526 ErrorF("+bs enable any backing store support\n"); 527 ErrorF("-bs disable any backing store support\n"); 528 ErrorF("+byteswappedclients Allow clients with endianess different to that of the server\n"); 529 ErrorF("-byteswappedclients Prohibit clients with endianess different to that of the server\n"); 530 ErrorF("-c turns off key-click\n"); 531 ErrorF("c # key-click volume (0-100)\n"); 532 ErrorF("-cc int default color visual class\n"); 533 ErrorF("-nocursor disable the cursor\n"); 534 ErrorF("-core generate core dump on fatal error\n"); 535 ErrorF("-displayfd fd file descriptor to write display number to when ready to connect\n"); 536 ErrorF("-dpi int screen resolution in dots per inch\n"); 537#ifdef DPMSExtension 538 ErrorF("-dpms disables VESA DPMS monitor control\n"); 539#endif 540 ErrorF 541 ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); 542 ErrorF("-f # bell base (0-100)\n"); 543 ErrorF("-fakescreenfps # fake screen default fps (1-600)\n"); 544 ErrorF("-fp string default font path\n"); 545 ErrorF("-help prints message with these options\n"); 546 ErrorF("+iglx Allow creating indirect GLX contexts\n"); 547 ErrorF("-iglx Prohibit creating indirect GLX contexts (default)\n"); 548 ErrorF("-I ignore all remaining arguments\n"); 549#ifdef RLIMIT_DATA 550 ErrorF("-ld int limit data space to N Kb\n"); 551#endif 552#ifdef RLIMIT_NOFILE 553 ErrorF("-lf int limit number of open files to N\n"); 554#endif 555#ifdef RLIMIT_STACK 556 ErrorF("-ls int limit stack space to N Kb\n"); 557#endif 558#ifdef LOCK_SERVER 559 ErrorF("-nolock disable the locking mechanism\n"); 560#endif 561 ErrorF("-maxclients n set maximum number of clients (power of two)\n"); 562 ErrorF("-nolisten string don't listen on protocol\n"); 563 ErrorF("-listen string listen on protocol\n"); 564 ErrorF("-noreset don't reset after last client exists\n"); 565 ErrorF("-background [none] create root window with no background\n"); 566 ErrorF("-reset reset after last client exists\n"); 567 ErrorF("-p # screen-saver pattern duration (minutes)\n"); 568 ErrorF("-pn accept failure to listen on all ports\n"); 569 ErrorF("-nopn reject failure to listen on all ports\n"); 570 ErrorF("-r turns off auto-repeat\n"); 571 ErrorF("r turns on auto-repeat \n"); 572 ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); 573 ErrorF("-retro start with classic stipple and cursor\n"); 574 ErrorF("-noretro start with black background and no cursor\n"); 575 ErrorF("-s # screen-saver timeout (minutes)\n"); 576 ErrorF("-seat string seat to run on\n"); 577 ErrorF("-t # default pointer threshold (pixels/t)\n"); 578 ErrorF("-terminate [delay] terminate at server reset (optional delay in sec)\n"); 579 ErrorF("-tst disable testing extensions\n"); 580 ErrorF("ttyxx server started from init on /dev/ttyxx\n"); 581 ErrorF("v video blanking for screen-saver\n"); 582 ErrorF("-v screen-saver without video blanking\n"); 583 ErrorF("-wr create root window with white background\n"); 584 ErrorF("-maxbigreqsize set maximal bigrequest size \n"); 585#ifdef PANORAMIX 586 ErrorF("+xinerama Enable XINERAMA extension\n"); 587 ErrorF("-xinerama Disable XINERAMA extension\n"); 588#endif 589 ErrorF 590 ("-dumbSched Disable smart scheduling and threaded input, enable old behavior\n"); 591 ErrorF("-schedInterval int Set scheduler interval in msec\n"); 592 ErrorF("-sigstop Enable SIGSTOP based startup\n"); 593 ErrorF("+extension name Enable extension\n"); 594 ErrorF("-extension name Disable extension\n"); 595 ListStaticExtensions(); 596#ifdef XDMCP 597 XdmcpUseMsg(); 598#endif 599 XkbUseMsg(); 600 ddxUseMsg(); 601} 602 603/* This function performs a rudimentary sanity check 604 * on the display name passed in on the command-line, 605 * since this string is used to generate filenames. 606 * It is especially important that the display name 607 * not contain a "/" and not start with a "-". 608 * --kvajk 609 */ 610static int 611VerifyDisplayName(const char *d) 612{ 613 int i; 614 int period_found = FALSE; 615 int after_period = 0; 616 617 if (d == (char *) 0) 618 return 0; /* null */ 619 if (*d == '\0') 620 return 0; /* empty */ 621 if (*d == '-') 622 return 0; /* could be confused for an option */ 623 if (*d == '.') 624 return 0; /* must not equal "." or ".." */ 625 if (strchr(d, '/') != (char *) 0) 626 return 0; /* very important!!! */ 627 628 /* Since we run atoi() on the display later, only allow 629 for digits, or exception of :0.0 and similar (two decimal points max) 630 */ 631 for (i = 0; i < strlen(d); i++) { 632 if (!isdigit(d[i])) { 633 if (d[i] != '.' || period_found) 634 return 0; 635 period_found = TRUE; 636 } else if (period_found) 637 after_period++; 638 639 if (after_period > 2) 640 return 0; 641 } 642 643 /* don't allow for :0. */ 644 if (period_found && after_period == 0) 645 return 0; 646 647 if (atol(d) > INT_MAX) 648 return 0; 649 650 return 1; 651} 652 653static const char *defaultNoListenList[] = { 654#ifndef LISTEN_TCP 655 "tcp", 656#endif 657#ifndef LISTEN_UNIX 658 "unix", 659#endif 660#ifndef LISTEN_LOCAL 661 "local", 662#endif 663 NULL 664}; 665 666/* 667 * This function parses the command line. Handles device-independent fields 668 * and allows ddx to handle additional fields. It is not allowed to modify 669 * argc or any of the strings pointed to by argv. 670 */ 671void 672ProcessCommandLine(int argc, char *argv[]) 673{ 674 int i, skip; 675 676 defaultKeyboardControl.autoRepeat = TRUE; 677 678#ifdef NO_PART_NET 679 PartialNetwork = FALSE; 680#else 681 PartialNetwork = TRUE; 682#endif 683 684 for (i = 0; defaultNoListenList[i] != NULL; i++) { 685 if (_XSERVTransNoListen(defaultNoListenList[i])) 686 ErrorF("Failed to disable listen for %s transport", 687 defaultNoListenList[i]); 688 } 689 690 for (i = 1; i < argc; i++) { 691 /* call ddx first, so it can peek/override if it wants */ 692 if ((skip = ddxProcessArgument(argc, argv, i))) { 693 i += (skip - 1); 694 } 695 else if (argv[i][0] == ':') { 696 /* initialize display */ 697 display = argv[i]; 698 explicit_display = TRUE; 699 display++; 700 if (!VerifyDisplayName(display)) { 701 ErrorF("Bad display name: %s\n", display); 702 UseMsg(); 703 FatalError("Bad display name, exiting: %s\n", display); 704 } 705 } 706 else if (strcmp(argv[i], "-a") == 0) { 707 if (++i < argc) 708 defaultPointerControl.num = atoi(argv[i]); 709 else 710 UseMsg(); 711 } 712 else if (strcmp(argv[i], "-ac") == 0) { 713 defeatAccessControl = TRUE; 714 } 715 else if (strcmp(argv[i], "-audit") == 0) { 716 if (++i < argc) 717 auditTrailLevel = atoi(argv[i]); 718 else 719 UseMsg(); 720 } 721 else if (strcmp(argv[i], "-auth") == 0) { 722 if (++i < argc) 723 InitAuthorization(argv[i]); 724 else 725 UseMsg(); 726 } 727 else if (strcmp(argv[i], "-byteswappedclients") == 0) { 728 AllowByteSwappedClients = FALSE; 729 } else if (strcmp(argv[i], "+byteswappedclients") == 0) { 730 AllowByteSwappedClients = TRUE; 731 } 732 else if (strcmp(argv[i], "-br") == 0); /* default */ 733 else if (strcmp(argv[i], "+bs") == 0) 734 enableBackingStore = TRUE; 735 else if (strcmp(argv[i], "-bs") == 0) 736 disableBackingStore = TRUE; 737 else if (strcmp(argv[i], "c") == 0) { 738 if (++i < argc) 739 defaultKeyboardControl.click = atoi(argv[i]); 740 else 741 UseMsg(); 742 } 743 else if (strcmp(argv[i], "-c") == 0) { 744 defaultKeyboardControl.click = 0; 745 } 746 else if (strcmp(argv[i], "-cc") == 0) { 747 if (++i < argc) 748 defaultColorVisualClass = atoi(argv[i]); 749 else 750 UseMsg(); 751 } 752 else if (strcmp(argv[i], "-core") == 0) { 753#if !defined(WIN32) || !defined(__MINGW32__) 754 struct rlimit core_limit; 755 756 if (getrlimit(RLIMIT_CORE, &core_limit) != -1) { 757 core_limit.rlim_cur = core_limit.rlim_max; 758 setrlimit(RLIMIT_CORE, &core_limit); 759 } 760#endif 761 CoreDump = TRUE; 762 } 763 else if (strcmp(argv[i], "-nocursor") == 0) { 764 EnableCursor = FALSE; 765 } 766 else if (strcmp(argv[i], "-dpi") == 0) { 767 if (++i < argc) 768 monitorResolution = atoi(argv[i]); 769 else 770 UseMsg(); 771 } 772 else if (strcmp(argv[i], "-displayfd") == 0) { 773 if (++i < argc) { 774 displayfd = atoi(argv[i]); 775#ifdef LOCK_SERVER 776 nolock = TRUE; 777#endif 778 } 779 else 780 UseMsg(); 781 } 782#ifdef DPMSExtension 783 else if (strcmp(argv[i], "dpms") == 0) 784 /* ignored for compatibility */ ; 785 else if (strcmp(argv[i], "-dpms") == 0) 786 DPMSDisabledSwitch = TRUE; 787#endif 788 else if (strcmp(argv[i], "-deferglyphs") == 0) { 789 if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i])) 790 UseMsg(); 791 } 792 else if (strcmp(argv[i], "-f") == 0) { 793 if (++i < argc) 794 defaultKeyboardControl.bell = atoi(argv[i]); 795 else 796 UseMsg(); 797 } 798 else if (strcmp(argv[i], "-fakescreenfps") == 0) { 799#ifdef PRESENT 800 if (++i < argc) { 801 FakeScreenFps = (uint32_t) atoi(argv[i]); 802 if (FakeScreenFps < 1 || FakeScreenFps > 600) 803 FatalError("fakescreenfps must be an integer in [1;600] range\n"); 804 } 805 else 806 UseMsg(); 807#else 808 FatalError("fakescreenfps not available without PRESENT\n"); 809 UseMsg(); 810#endif 811 } 812 else if (strcmp(argv[i], "-fp") == 0) { 813 if (++i < argc) { 814 defaultFontPath = argv[i]; 815 } 816 else 817 UseMsg(); 818 } 819 else if (strcmp(argv[i], "-help") == 0) { 820 UseMsg(); 821 exit(0); 822 } 823 else if (strcmp(argv[i], "+iglx") == 0) 824 enableIndirectGLX = TRUE; 825 else if (strcmp(argv[i], "-iglx") == 0) 826 enableIndirectGLX = FALSE; 827 else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) { 828 if (skip > 0) 829 i += skip - 1; 830 else 831 UseMsg(); 832 } 833#ifdef RLIMIT_DATA 834 else if (strcmp(argv[i], "-ld") == 0) { 835 if (++i < argc) { 836 limitDataSpace = atoi(argv[i]); 837 if (limitDataSpace > 0) 838 limitDataSpace *= 1024; 839 } 840 else 841 UseMsg(); 842 } 843#endif 844#ifdef RLIMIT_NOFILE 845 else if (strcmp(argv[i], "-lf") == 0) { 846 if (++i < argc) 847 limitNoFile = atoi(argv[i]); 848 else 849 UseMsg(); 850 } 851#endif 852#ifdef RLIMIT_STACK 853 else if (strcmp(argv[i], "-ls") == 0) { 854 if (++i < argc) { 855 limitStackSpace = atoi(argv[i]); 856 if (limitStackSpace > 0) 857 limitStackSpace *= 1024; 858 } 859 else 860 UseMsg(); 861 } 862#endif 863#ifdef LOCK_SERVER 864 else if (strcmp(argv[i], "-nolock") == 0) { 865#if !defined(WIN32) && !defined(__CYGWIN__) 866 if (getuid() != 0) 867 ErrorF 868 ("Warning: the -nolock option can only be used by root\n"); 869 else 870#endif 871 nolock = TRUE; 872 } 873#endif 874 else if ( strcmp( argv[i], "-maxclients") == 0) 875 { 876 if (++i < argc) { 877 LimitClients = atoi(argv[i]); 878 if (LimitClients != 64 && 879 LimitClients != 128 && 880 LimitClients != 256 && 881 LimitClients != 512 && 882 LimitClients != 1024 && 883 LimitClients != 2048) { 884 FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n"); 885 } 886 } else 887 UseMsg(); 888 } 889 else if (strcmp(argv[i], "-nolisten") == 0) { 890 if (++i < argc) { 891 if (_XSERVTransNoListen(argv[i])) 892 ErrorF("Failed to disable listen for %s transport", 893 argv[i]); 894 } 895 else 896 UseMsg(); 897 } 898 else if (strcmp(argv[i], "-listen") == 0) { 899 if (++i < argc) { 900 if (_XSERVTransListen(argv[i])) 901 ErrorF("Failed to enable listen for %s transport", 902 argv[i]); 903 } 904 else 905 UseMsg(); 906 } 907 else if (strcmp(argv[i], "-noreset") == 0) { 908 dispatchExceptionAtReset = 0; 909 } 910 else if (strcmp(argv[i], "-reset") == 0) { 911 dispatchExceptionAtReset = DE_RESET; 912 } 913 else if (strcmp(argv[i], "-p") == 0) { 914 if (++i < argc) 915 defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) * 916 MILLI_PER_MIN; 917 else 918 UseMsg(); 919 } 920 else if (strcmp(argv[i], "-pogo") == 0) { 921 dispatchException = DE_TERMINATE; 922 } 923 else if (strcmp(argv[i], "-pn") == 0) 924 PartialNetwork = TRUE; 925 else if (strcmp(argv[i], "-nopn") == 0) 926 PartialNetwork = FALSE; 927 else if (strcmp(argv[i], "r") == 0) 928 defaultKeyboardControl.autoRepeat = TRUE; 929 else if (strcmp(argv[i], "-r") == 0) 930 defaultKeyboardControl.autoRepeat = FALSE; 931 else if (strcmp(argv[i], "-retro") == 0) 932 party_like_its_1989 = TRUE; 933 else if (strcmp(argv[i], "-noretro") == 0) 934 party_like_its_1989 = FALSE; 935 else if (strcmp(argv[i], "-s") == 0) { 936 if (++i < argc) 937 defaultScreenSaverTime = ((CARD32) atoi(argv[i])) * 938 MILLI_PER_MIN; 939 else 940 UseMsg(); 941 } 942 else if (strcmp(argv[i], "-seat") == 0) { 943 if (++i < argc) 944 SeatId = argv[i]; 945 else 946 UseMsg(); 947 } 948 else if (strcmp(argv[i], "-t") == 0) { 949 if (++i < argc) 950 defaultPointerControl.threshold = atoi(argv[i]); 951 else 952 UseMsg(); 953 } 954 else if (strcmp(argv[i], "-terminate") == 0) { 955 dispatchExceptionAtReset = DE_TERMINATE; 956 terminateDelay = -1; 957 if ((i + 1 < argc) && (isdigit(*argv[i + 1]))) 958 terminateDelay = atoi(argv[++i]); 959 terminateDelay = max(0, terminateDelay); 960 } 961 else if (strcmp(argv[i], "-tst") == 0) { 962 noTestExtensions = TRUE; 963 } 964 else if (strcmp(argv[i], "v") == 0) 965 defaultScreenSaverBlanking = PreferBlanking; 966 else if (strcmp(argv[i], "-v") == 0) 967 defaultScreenSaverBlanking = DontPreferBlanking; 968 else if (strcmp(argv[i], "-wr") == 0) 969 whiteRoot = TRUE; 970 else if (strcmp(argv[i], "-background") == 0) { 971 if (++i < argc) { 972 if (!strcmp(argv[i], "none")) 973 bgNoneRoot = TRUE; 974 else 975 UseMsg(); 976 } 977 } 978 else if (strcmp(argv[i], "-maxbigreqsize") == 0) { 979 if (++i < argc) { 980 long reqSizeArg = atol(argv[i]); 981 982 /* Request size > 128MB does not make much sense... */ 983 if (reqSizeArg > 0L && reqSizeArg < 128L) { 984 maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; 985 } 986 else { 987 UseMsg(); 988 } 989 } 990 else { 991 UseMsg(); 992 } 993 } 994#ifdef PANORAMIX 995 else if (strcmp(argv[i], "+xinerama") == 0) { 996 noPanoramiXExtension = FALSE; 997 } 998 else if (strcmp(argv[i], "-xinerama") == 0) { 999 noPanoramiXExtension = TRUE; 1000 } 1001 else if (strcmp(argv[i], "-disablexineramaextension") == 0) { 1002 PanoramiXExtensionDisabledHack = TRUE; 1003 } 1004#endif 1005 else if (strcmp(argv[i], "-I") == 0) { 1006 /* ignore all remaining arguments */ 1007 break; 1008 } 1009 else if (strncmp(argv[i], "tty", 3) == 0) { 1010 /* init supplies us with this useless information */ 1011 } 1012#ifdef XDMCP 1013 else if ((skip = XdmcpOptions(argc, argv, i)) != i) { 1014 i = skip - 1; 1015 } 1016#endif 1017 else if (strcmp(argv[i], "-dumbSched") == 0) { 1018 InputThreadEnable = FALSE; 1019#ifdef HAVE_SETITIMER 1020 SmartScheduleSignalEnable = FALSE; 1021#endif 1022 } 1023 else if (strcmp(argv[i], "-schedInterval") == 0) { 1024 if (++i < argc) { 1025 SmartScheduleInterval = atoi(argv[i]); 1026 SmartScheduleSlice = SmartScheduleInterval; 1027 } 1028 else 1029 UseMsg(); 1030 } 1031 else if (strcmp(argv[i], "-schedMax") == 0) { 1032 if (++i < argc) { 1033 SmartScheduleMaxSlice = atoi(argv[i]); 1034 } 1035 else 1036 UseMsg(); 1037 } 1038 else if (strcmp(argv[i], "-render") == 0) { 1039 if (++i < argc) { 1040 int policy = PictureParseCmapPolicy(argv[i]); 1041 1042 if (policy != PictureCmapPolicyInvalid) 1043 PictureCmapPolicy = policy; 1044 else 1045 UseMsg(); 1046 } 1047 else 1048 UseMsg(); 1049 } 1050 else if (strcmp(argv[i], "-sigstop") == 0) { 1051 RunFromSigStopParent = TRUE; 1052 } 1053 else if (strcmp(argv[i], "+extension") == 0) { 1054 if (++i < argc) { 1055 if (!EnableDisableExtension(argv[i], TRUE)) 1056 EnableDisableExtensionError(argv[i], TRUE); 1057 } 1058 else 1059 UseMsg(); 1060 } 1061 else if (strcmp(argv[i], "-extension") == 0) { 1062 if (++i < argc) { 1063 if (!EnableDisableExtension(argv[i], FALSE)) 1064 EnableDisableExtensionError(argv[i], FALSE); 1065 } 1066 else 1067 UseMsg(); 1068 } 1069 else { 1070 ErrorF("Unrecognized option: %s\n", argv[i]); 1071 UseMsg(); 1072 FatalError("Unrecognized option: %s\n", argv[i]); 1073 } 1074 } 1075} 1076 1077/* Implement a simple-minded font authorization scheme. The authorization 1078 name is "hp-hostname-1", the contents are simply the host name. */ 1079int 1080set_font_authorizations(char **authorizations, int *authlen, void *client) 1081{ 1082#define AUTHORIZATION_NAME "hp-hostname-1" 1083#if defined(TCPCONN) 1084 static char *result = NULL; 1085 static char *p = NULL; 1086 1087 if (p == NULL) { 1088 char hname[1024], *hnameptr; 1089 unsigned int len; 1090 1091#if defined(IPv6) && defined(AF_INET6) 1092 struct addrinfo hints, *ai = NULL; 1093#else 1094 struct hostent *host; 1095 1096#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1097 _Xgethostbynameparams hparams; 1098#endif 1099#endif 1100 1101 gethostname(hname, 1024); 1102#if defined(IPv6) && defined(AF_INET6) 1103 memset(&hints, 0, sizeof(hints)); 1104 hints.ai_flags = AI_CANONNAME; 1105 if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { 1106 hnameptr = ai->ai_canonname; 1107 } 1108 else { 1109 hnameptr = hname; 1110 } 1111#else 1112 host = _XGethostbyname(hname, hparams); 1113 if (host == NULL) 1114 hnameptr = hname; 1115 else 1116 hnameptr = host->h_name; 1117#endif 1118 1119 len = strlen(hnameptr) + 1; 1120 result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); 1121 1122 p = result; 1123 *p++ = sizeof(AUTHORIZATION_NAME) >> 8; 1124 *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; 1125 *p++ = (len) >> 8; 1126 *p++ = (len & 0xff); 1127 1128 memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); 1129 p += sizeof(AUTHORIZATION_NAME); 1130 memmove(p, hnameptr, len); 1131 p += len; 1132#if defined(IPv6) && defined(AF_INET6) 1133 if (ai) { 1134 freeaddrinfo(ai); 1135 } 1136#endif 1137 } 1138 *authlen = p - result; 1139 *authorizations = result; 1140 return 1; 1141#else /* TCPCONN */ 1142 return 0; 1143#endif /* TCPCONN */ 1144} 1145 1146void * 1147XNFalloc(unsigned long amount) 1148{ 1149 void *ptr = malloc(amount); 1150 1151 if (!ptr) 1152 FatalError("Out of memory"); 1153 return ptr; 1154} 1155 1156/* The original XNFcalloc was used with the xnfcalloc macro which multiplied 1157 * the arguments at the call site without allowing calloc to check for overflow. 1158 * XNFcallocarray was added to fix that without breaking ABI. 1159 */ 1160void * 1161XNFcalloc(unsigned long amount) 1162{ 1163 return XNFcallocarray(1, amount); 1164} 1165 1166void * 1167XNFcallocarray(size_t nmemb, size_t size) 1168{ 1169 void *ret = calloc(nmemb, size); 1170 1171 if (!ret) 1172 FatalError("XNFcalloc: Out of memory"); 1173 return ret; 1174} 1175 1176void * 1177XNFrealloc(void *ptr, unsigned long amount) 1178{ 1179 void *ret = realloc(ptr, amount); 1180 1181 if (!ret) 1182 FatalError("XNFrealloc: Out of memory"); 1183 return ret; 1184} 1185 1186void * 1187XNFreallocarray(void *ptr, size_t nmemb, size_t size) 1188{ 1189 void *ret = reallocarray(ptr, nmemb, size); 1190 1191 if (!ret) 1192 FatalError("XNFreallocarray: Out of memory"); 1193 return ret; 1194} 1195 1196char * 1197Xstrdup(const char *s) 1198{ 1199 if (s == NULL) 1200 return NULL; 1201 return strdup(s); 1202} 1203 1204char * 1205XNFstrdup(const char *s) 1206{ 1207 char *ret; 1208 1209 if (s == NULL) 1210 return NULL; 1211 1212 ret = strdup(s); 1213 if (!ret) 1214 FatalError("XNFstrdup: Out of memory"); 1215 return ret; 1216} 1217 1218void 1219SmartScheduleStopTimer(void) 1220{ 1221#ifdef HAVE_SETITIMER 1222 struct itimerval timer; 1223 1224 if (!SmartScheduleSignalEnable) 1225 return; 1226 timer.it_interval.tv_sec = 0; 1227 timer.it_interval.tv_usec = 0; 1228 timer.it_value.tv_sec = 0; 1229 timer.it_value.tv_usec = 0; 1230 (void) setitimer(ITIMER_REAL, &timer, 0); 1231#endif 1232} 1233 1234void 1235SmartScheduleStartTimer(void) 1236{ 1237#ifdef HAVE_SETITIMER 1238 struct itimerval timer; 1239 1240 if (!SmartScheduleSignalEnable) 1241 return; 1242 timer.it_interval.tv_sec = 0; 1243 timer.it_interval.tv_usec = SmartScheduleInterval * 1000; 1244 timer.it_value.tv_sec = 0; 1245 timer.it_value.tv_usec = SmartScheduleInterval * 1000; 1246 setitimer(ITIMER_REAL, &timer, 0); 1247#endif 1248} 1249 1250#ifdef HAVE_SETITIMER 1251static void 1252SmartScheduleTimer(int sig) 1253{ 1254 SmartScheduleTime += SmartScheduleInterval; 1255} 1256 1257static int 1258SmartScheduleEnable(void) 1259{ 1260 int ret = 0; 1261 struct sigaction act; 1262 1263 if (!SmartScheduleSignalEnable) 1264 return 0; 1265 1266 memset((char *) &act, 0, sizeof(struct sigaction)); 1267 1268 /* Set up the timer signal function */ 1269 act.sa_flags = SA_RESTART; 1270 act.sa_handler = SmartScheduleTimer; 1271 sigemptyset(&act.sa_mask); 1272 sigaddset(&act.sa_mask, SIGALRM); 1273 ret = sigaction(SIGALRM, &act, 0); 1274 return ret; 1275} 1276 1277static int 1278SmartSchedulePause(void) 1279{ 1280 int ret = 0; 1281 struct sigaction act; 1282 1283 if (!SmartScheduleSignalEnable) 1284 return 0; 1285 1286 memset((char *) &act, 0, sizeof(struct sigaction)); 1287 1288 act.sa_handler = SIG_IGN; 1289 sigemptyset(&act.sa_mask); 1290 ret = sigaction(SIGALRM, &act, 0); 1291 return ret; 1292} 1293#endif 1294 1295void 1296SmartScheduleInit(void) 1297{ 1298#ifdef HAVE_SETITIMER 1299 if (SmartScheduleEnable() < 0) { 1300 perror("sigaction for smart scheduler"); 1301 SmartScheduleSignalEnable = FALSE; 1302 } 1303#endif 1304} 1305 1306#ifdef HAVE_SIGPROCMASK 1307static sigset_t PreviousSignalMask; 1308static int BlockedSignalCount; 1309#endif 1310 1311void 1312OsBlockSignals(void) 1313{ 1314#ifdef HAVE_SIGPROCMASK 1315 if (BlockedSignalCount++ == 0) { 1316 sigset_t set; 1317 1318 sigemptyset(&set); 1319 sigaddset(&set, SIGALRM); 1320 sigaddset(&set, SIGVTALRM); 1321#ifdef SIGWINCH 1322 sigaddset(&set, SIGWINCH); 1323#endif 1324 sigaddset(&set, SIGTSTP); 1325 sigaddset(&set, SIGTTIN); 1326 sigaddset(&set, SIGTTOU); 1327 sigaddset(&set, SIGCHLD); 1328 xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask); 1329 } 1330#endif 1331} 1332 1333void 1334OsReleaseSignals(void) 1335{ 1336#ifdef HAVE_SIGPROCMASK 1337 if (--BlockedSignalCount == 0) { 1338 xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0); 1339 } 1340#endif 1341} 1342 1343void 1344OsResetSignals(void) 1345{ 1346#ifdef HAVE_SIGPROCMASK 1347 while (BlockedSignalCount > 0) 1348 OsReleaseSignals(); 1349 input_force_unlock(); 1350#endif 1351} 1352 1353/* 1354 * Pending signals may interfere with core dumping. Provide a 1355 * mechanism to block signals when aborting. 1356 */ 1357 1358void 1359OsAbort(void) 1360{ 1361#ifndef __APPLE__ 1362 OsBlockSignals(); 1363#endif 1364#if !defined(WIN32) || defined(__CYGWIN__) 1365 /* abort() raises SIGABRT, so we have to stop handling that to prevent 1366 * recursion 1367 */ 1368 OsSignal(SIGABRT, SIG_DFL); 1369#endif 1370 abort(); 1371} 1372 1373#if !defined(WIN32) 1374/* 1375 * "safer" versions of system(3), popen(3) and pclose(3) which give up 1376 * all privs before running a command. 1377 * 1378 * This is based on the code in FreeBSD 2.2 libc. 1379 * 1380 * XXX It'd be good to redirect stderr so that it ends up in the log file 1381 * as well. As it is now, xkbcomp messages don't end up in the log file. 1382 */ 1383 1384int 1385System(const char *command) 1386{ 1387 int pid, p; 1388 void (*csig) (int); 1389 int status; 1390 1391 if (!command) 1392 return 1; 1393 1394 csig = OsSignal(SIGCHLD, SIG_DFL); 1395 if (csig == SIG_ERR) { 1396 perror("signal"); 1397 return -1; 1398 } 1399 DebugF("System: `%s'\n", command); 1400 1401 switch (pid = fork()) { 1402 case -1: /* error */ 1403 p = -1; 1404 break; 1405 case 0: /* child */ 1406 if (setgid(getgid()) == -1) 1407 _exit(127); 1408 if (setuid(getuid()) == -1) 1409 _exit(127); 1410 execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1411 _exit(127); 1412 default: /* parent */ 1413 do { 1414 p = waitpid(pid, &status, 0); 1415 } while (p == -1 && errno == EINTR); 1416 1417 } 1418 1419 if (OsSignal(SIGCHLD, csig) == SIG_ERR) { 1420 perror("signal"); 1421 return -1; 1422 } 1423 1424 return p == -1 ? -1 : status; 1425} 1426 1427static struct pid { 1428 struct pid *next; 1429 FILE *fp; 1430 int pid; 1431} *pidlist; 1432 1433void * 1434Popen(const char *command, const char *type) 1435{ 1436 struct pid *cur; 1437 FILE *iop; 1438 int pdes[2], pid; 1439 1440 if (command == NULL || type == NULL) 1441 return NULL; 1442 1443 if ((*type != 'r' && *type != 'w') || type[1]) 1444 return NULL; 1445 1446 if ((cur = malloc(sizeof(struct pid))) == NULL) 1447 return NULL; 1448 1449 if (pipe(pdes) < 0) { 1450 free(cur); 1451 return NULL; 1452 } 1453 1454 /* Ignore the smart scheduler while this is going on */ 1455#ifdef HAVE_SETITIMER 1456 if (SmartSchedulePause() < 0) { 1457 close(pdes[0]); 1458 close(pdes[1]); 1459 free(cur); 1460 perror("signal"); 1461 return NULL; 1462 } 1463#endif 1464 1465 switch (pid = fork()) { 1466 case -1: /* error */ 1467 close(pdes[0]); 1468 close(pdes[1]); 1469 free(cur); 1470#ifdef HAVE_SETITIMER 1471 if (SmartScheduleEnable() < 0) 1472 perror("signal"); 1473#endif 1474 return NULL; 1475 case 0: /* child */ 1476 if (setgid(getgid()) == -1) 1477 _exit(127); 1478 if (setuid(getuid()) == -1) 1479 _exit(127); 1480 if (*type == 'r') { 1481 if (pdes[1] != 1) { 1482 /* stdout */ 1483 dup2(pdes[1], 1); 1484 close(pdes[1]); 1485 } 1486 close(pdes[0]); 1487 } 1488 else { 1489 if (pdes[0] != 0) { 1490 /* stdin */ 1491 dup2(pdes[0], 0); 1492 close(pdes[0]); 1493 } 1494 close(pdes[1]); 1495 } 1496 execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1497 _exit(127); 1498 } 1499 1500 /* Avoid EINTR during stdio calls */ 1501 OsBlockSignals(); 1502 1503 /* parent */ 1504 if (*type == 'r') { 1505 iop = fdopen(pdes[0], type); 1506 close(pdes[1]); 1507 } 1508 else { 1509 iop = fdopen(pdes[1], type); 1510 close(pdes[0]); 1511 } 1512 1513 cur->fp = iop; 1514 cur->pid = pid; 1515 cur->next = pidlist; 1516 pidlist = cur; 1517 1518 DebugF("Popen: `%s', fp = %p\n", command, iop); 1519 1520 return iop; 1521} 1522 1523/* fopen that drops privileges */ 1524void * 1525Fopen(const char *file, const char *type) 1526{ 1527 FILE *iop; 1528 1529#ifndef HAS_SAVED_IDS_AND_SETEUID 1530 struct pid *cur; 1531 int pdes[2], pid; 1532 1533 if (file == NULL || type == NULL) 1534 return NULL; 1535 1536 if ((*type != 'r' && *type != 'w') || type[1]) 1537 return NULL; 1538 1539 if ((cur = malloc(sizeof(struct pid))) == NULL) 1540 return NULL; 1541 1542 if (pipe(pdes) < 0) { 1543 free(cur); 1544 return NULL; 1545 } 1546 1547 switch (pid = fork()) { 1548 case -1: /* error */ 1549 close(pdes[0]); 1550 close(pdes[1]); 1551 free(cur); 1552 return NULL; 1553 case 0: /* child */ 1554 if (setgid(getgid()) == -1) 1555 _exit(127); 1556 if (setuid(getuid()) == -1) 1557 _exit(127); 1558 if (*type == 'r') { 1559 if (pdes[1] != 1) { 1560 /* stdout */ 1561 dup2(pdes[1], 1); 1562 close(pdes[1]); 1563 } 1564 close(pdes[0]); 1565 } 1566 else { 1567 if (pdes[0] != 0) { 1568 /* stdin */ 1569 dup2(pdes[0], 0); 1570 close(pdes[0]); 1571 } 1572 close(pdes[1]); 1573 } 1574 execl("/bin/cat", "cat", file, (char *) NULL); 1575 _exit(127); 1576 } 1577 1578 /* Avoid EINTR during stdio calls */ 1579 OsBlockSignals(); 1580 1581 /* parent */ 1582 if (*type == 'r') { 1583 iop = fdopen(pdes[0], type); 1584 close(pdes[1]); 1585 } 1586 else { 1587 iop = fdopen(pdes[1], type); 1588 close(pdes[0]); 1589 } 1590 1591 cur->fp = iop; 1592 cur->pid = pid; 1593 cur->next = pidlist; 1594 pidlist = cur; 1595 1596 DebugF("Fopen(%s), fp = %p\n", file, iop); 1597 1598 return iop; 1599#else 1600 int ruid, euid; 1601 1602 ruid = getuid(); 1603 euid = geteuid(); 1604 1605 if (seteuid(ruid) == -1) { 1606 return NULL; 1607 } 1608 iop = fopen(file, type); 1609 1610 if (seteuid(euid) == -1) { 1611 fclose(iop); 1612 return NULL; 1613 } 1614 return iop; 1615#endif /* HAS_SAVED_IDS_AND_SETEUID */ 1616} 1617 1618int 1619Pclose(void *iop) 1620{ 1621 struct pid *cur, *last; 1622 int pstat; 1623 int pid; 1624 1625 DebugF("Pclose: fp = %p\n", iop); 1626 fclose(iop); 1627 1628 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1629 if (cur->fp == iop) 1630 break; 1631 if (cur == NULL) 1632 return -1; 1633 1634 do { 1635 pid = waitpid(cur->pid, &pstat, 0); 1636 } while (pid == -1 && errno == EINTR); 1637 1638 if (last == NULL) 1639 pidlist = cur->next; 1640 else 1641 last->next = cur->next; 1642 free(cur); 1643 1644 /* allow EINTR again */ 1645 OsReleaseSignals(); 1646 1647#ifdef HAVE_SETITIMER 1648 if (SmartScheduleEnable() < 0) { 1649 perror("signal"); 1650 return -1; 1651 } 1652#endif 1653 1654 return pid == -1 ? -1 : pstat; 1655} 1656 1657int 1658Fclose(void *iop) 1659{ 1660#ifdef HAS_SAVED_IDS_AND_SETEUID 1661 return fclose(iop); 1662#else 1663 return Pclose(iop); 1664#endif 1665} 1666 1667#endif /* !WIN32 */ 1668 1669#ifdef WIN32 1670 1671#include <X11/Xwindows.h> 1672 1673const char * 1674Win32TempDir(void) 1675{ 1676 static char buffer[PATH_MAX]; 1677 1678 if (GetTempPath(sizeof(buffer), buffer)) { 1679 int len; 1680 1681 buffer[sizeof(buffer) - 1] = 0; 1682 len = strlen(buffer); 1683 if (len > 0) 1684 if (buffer[len - 1] == '\\') 1685 buffer[len - 1] = 0; 1686 return buffer; 1687 } 1688 if (getenv("TEMP") != NULL) 1689 return getenv("TEMP"); 1690 else if (getenv("TMP") != NULL) 1691 return getenv("TMP"); 1692 else 1693 return "/tmp"; 1694} 1695 1696int 1697System(const char *cmdline) 1698{ 1699 STARTUPINFO si; 1700 PROCESS_INFORMATION pi; 1701 DWORD dwExitCode; 1702 char *cmd = strdup(cmdline); 1703 1704 ZeroMemory(&si, sizeof(si)); 1705 si.cb = sizeof(si); 1706 ZeroMemory(&pi, sizeof(pi)); 1707 1708 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 1709 LPVOID buffer; 1710 1711 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1712 FORMAT_MESSAGE_FROM_SYSTEM | 1713 FORMAT_MESSAGE_IGNORE_INSERTS, 1714 NULL, 1715 GetLastError(), 1716 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 1717 (LPTSTR) &buffer, 0, NULL)) { 1718 ErrorF("[xkb] Starting '%s' failed!\n", cmdline); 1719 } 1720 else { 1721 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); 1722 LocalFree(buffer); 1723 } 1724 1725 free(cmd); 1726 return -1; 1727 } 1728 /* Wait until child process exits. */ 1729 WaitForSingleObject(pi.hProcess, INFINITE); 1730 1731 GetExitCodeProcess(pi.hProcess, &dwExitCode); 1732 1733 /* Close process and thread handles. */ 1734 CloseHandle(pi.hProcess); 1735 CloseHandle(pi.hThread); 1736 free(cmd); 1737 1738 return dwExitCode; 1739} 1740#endif 1741 1742Bool 1743PrivsElevated(void) 1744{ 1745 static Bool privsTested = FALSE; 1746 static Bool privsElevated = TRUE; 1747 1748 if (!privsTested) { 1749#if defined(WIN32) 1750 privsElevated = FALSE; 1751#else 1752 if ((getuid() != geteuid()) || (getgid() != getegid())) { 1753 privsElevated = TRUE; 1754 } 1755 else { 1756#if defined(HAVE_ISSETUGID) 1757 privsElevated = issetugid(); 1758#elif defined(HAVE_GETRESUID) 1759 uid_t ruid, euid, suid; 1760 gid_t rgid, egid, sgid; 1761 1762 if ((getresuid(&ruid, &euid, &suid) == 0) && 1763 (getresgid(&rgid, &egid, &sgid) == 0)) { 1764 privsElevated = (euid != suid) || (egid != sgid); 1765 } 1766 else { 1767 printf("Failed getresuid or getresgid"); 1768 /* Something went wrong, make defensive assumption */ 1769 privsElevated = TRUE; 1770 } 1771#else 1772 if (getuid() == 0) { 1773 /* running as root: uid==euid==0 */ 1774 privsElevated = FALSE; 1775 } 1776 else { 1777 /* 1778 * If there are saved ID's the process might still be privileged 1779 * even though the above test succeeded. If issetugid() and 1780 * getresgid() aren't available, test this by trying to set 1781 * euid to 0. 1782 */ 1783 unsigned int oldeuid; 1784 1785 oldeuid = geteuid(); 1786 1787 if (seteuid(0) != 0) { 1788 privsElevated = FALSE; 1789 } 1790 else { 1791 if (seteuid(oldeuid) != 0) { 1792 FatalError("Failed to drop privileges. Exiting\n"); 1793 } 1794 privsElevated = TRUE; 1795 } 1796 } 1797#endif 1798 } 1799#endif 1800 privsTested = TRUE; 1801 } 1802 return privsElevated; 1803} 1804 1805/* 1806 * CheckUserParameters: check for long command line arguments and long 1807 * environment variables. By default, these checks are only done when 1808 * the server's euid != ruid. In 3.3.x, these checks were done in an 1809 * external wrapper utility. 1810 */ 1811 1812/* Consider LD* variables insecure? */ 1813#ifndef REMOVE_ENV_LD 1814#define REMOVE_ENV_LD 1 1815#endif 1816 1817/* Remove long environment variables? */ 1818#ifndef REMOVE_LONG_ENV 1819#define REMOVE_LONG_ENV 1 1820#endif 1821 1822/* 1823 * Disallow stdout or stderr as pipes? It's possible to block the X server 1824 * when piping stdout+stderr to a pipe. 1825 * 1826 * Don't enable this because it looks like it's going to cause problems. 1827 */ 1828#ifndef NO_OUTPUT_PIPES 1829#define NO_OUTPUT_PIPES 0 1830#endif 1831 1832/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 1833#ifndef CHECK_EUID 1834#ifndef WIN32 1835#define CHECK_EUID 1 1836#else 1837#define CHECK_EUID 0 1838#endif 1839#endif 1840 1841/* 1842 * Maybe the locale can be faked to make isprint(3) report that everything 1843 * is printable? Avoid it by default. 1844 */ 1845#ifndef USE_ISPRINT 1846#define USE_ISPRINT 0 1847#endif 1848 1849#define MAX_ARG_LENGTH 128 1850#define MAX_ENV_LENGTH 256 1851#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 1852 1853#if USE_ISPRINT 1854#include <ctype.h> 1855#define checkPrintable(c) isprint(c) 1856#else 1857#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 1858#endif 1859 1860enum BadCode { 1861 NotBad = 0, 1862 UnsafeArg, 1863 ArgTooLong, 1864 UnprintableArg, 1865 EnvTooLong, 1866 OutputIsPipe, 1867 InternalError 1868}; 1869 1870#if defined(VENDORSUPPORT) 1871#define BUGADDRESS VENDORSUPPORT 1872#elif defined(BUILDERADDR) 1873#define BUGADDRESS BUILDERADDR 1874#else 1875#define BUGADDRESS "xorg@freedesktop.org" 1876#endif 1877 1878void 1879CheckUserParameters(int argc, char **argv, char **envp) 1880{ 1881 enum BadCode bad = NotBad; 1882 int i = 0, j; 1883 char *a, *e = NULL; 1884 1885#if CHECK_EUID 1886 if (PrivsElevated()) 1887#endif 1888 { 1889 /* Check each argv[] */ 1890 for (i = 1; i < argc; i++) { 1891 if (strcmp(argv[i], "-fp") == 0) { 1892 i++; /* continue with next argument. skip the length check */ 1893 if (i >= argc) 1894 break; 1895 } 1896 else { 1897 if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1898 bad = ArgTooLong; 1899 break; 1900 } 1901 } 1902 a = argv[i]; 1903 while (*a) { 1904 if (checkPrintable(*a) == 0) { 1905 bad = UnprintableArg; 1906 break; 1907 } 1908 a++; 1909 } 1910 if (bad) 1911 break; 1912 } 1913 if (!bad) { 1914 /* Check each envp[] */ 1915 for (i = 0; envp[i]; i++) { 1916 1917 /* Check for bad environment variables and values */ 1918#if REMOVE_ENV_LD 1919 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1920 for (j = i; envp[j]; j++) { 1921 envp[j] = envp[j + 1]; 1922 } 1923 } 1924#endif 1925 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 1926#if REMOVE_LONG_ENV 1927 for (j = i; envp[j]; j++) { 1928 envp[j] = envp[j + 1]; 1929 } 1930 i--; 1931#else 1932 char *eq; 1933 int len; 1934 1935 eq = strchr(envp[i], '='); 1936 if (!eq) 1937 continue; 1938 len = eq - envp[i]; 1939 e = strndup(envp[i], len); 1940 if (!e) { 1941 bad = InternalError; 1942 break; 1943 } 1944 if (len >= 4 && 1945 (strcmp(e + len - 4, "PATH") == 0 || 1946 strcmp(e, "TERMCAP") == 0)) { 1947 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1948 bad = EnvTooLong; 1949 break; 1950 } 1951 else { 1952 free(e); 1953 } 1954 } 1955 else { 1956 bad = EnvTooLong; 1957 break; 1958 } 1959#endif 1960 } 1961 } 1962 } 1963#if NO_OUTPUT_PIPES 1964 if (!bad) { 1965 struct stat buf; 1966 1967 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1968 bad = OutputIsPipe; 1969 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1970 bad = OutputIsPipe; 1971 } 1972#endif 1973 } 1974 switch (bad) { 1975 case NotBad: 1976 return; 1977 case UnsafeArg: 1978 ErrorF("Command line argument number %d is unsafe\n", i); 1979 break; 1980 case ArgTooLong: 1981 ErrorF("Command line argument number %d is too long\n", i); 1982 break; 1983 case UnprintableArg: 1984 ErrorF("Command line argument number %d contains unprintable" 1985 " characters\n", i); 1986 break; 1987 case EnvTooLong: 1988 ErrorF("Environment variable `%s' is too long\n", e); 1989 break; 1990 case OutputIsPipe: 1991 ErrorF("Stdout and/or stderr is a pipe\n"); 1992 break; 1993 case InternalError: 1994 ErrorF("Internal Error\n"); 1995 break; 1996 default: 1997 ErrorF("Unknown error\n"); 1998 break; 1999 } 2000 FatalError("X server aborted because of unsafe environment\n"); 2001} 2002 2003/* 2004 * CheckUserAuthorization: check if the user is allowed to start the 2005 * X server. This usually means some sort of PAM checking, and it is 2006 * usually only done for setuid servers (uid != euid). 2007 */ 2008 2009#ifdef USE_PAM 2010#include <security/pam_appl.h> 2011#include <security/pam_misc.h> 2012#include <pwd.h> 2013#endif /* USE_PAM */ 2014 2015void 2016CheckUserAuthorization(void) 2017{ 2018#ifdef USE_PAM 2019 static struct pam_conv conv = { 2020 misc_conv, 2021 NULL 2022 }; 2023 2024 pam_handle_t *pamh = NULL; 2025 struct passwd *pw; 2026 int retval; 2027 2028 if (getuid() != geteuid()) { 2029 pw = getpwuid(getuid()); 2030 if (pw == NULL) 2031 FatalError("getpwuid() failed for uid %d\n", getuid()); 2032 2033 retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 2034 if (retval != PAM_SUCCESS) 2035 FatalError("pam_start() failed.\n" 2036 "\tMissing or mangled PAM config file or module?\n"); 2037 2038 retval = pam_authenticate(pamh, 0); 2039 if (retval != PAM_SUCCESS) { 2040 pam_end(pamh, retval); 2041 FatalError("PAM authentication failed, cannot start X server.\n" 2042 "\tPerhaps you do not have console ownership?\n"); 2043 } 2044 2045 retval = pam_acct_mgmt(pamh, 0); 2046 if (retval != PAM_SUCCESS) { 2047 pam_end(pamh, retval); 2048 FatalError("PAM authentication failed, cannot start X server.\n" 2049 "\tPerhaps you do not have console ownership?\n"); 2050 } 2051 2052 /* this is not a session, so do not do session management */ 2053 pam_end(pamh, PAM_SUCCESS); 2054 } 2055#endif 2056} 2057 2058/* 2059 * Tokenize a string into a NULL terminated array of strings. Always returns 2060 * an allocated array unless an error occurs. 2061 */ 2062char ** 2063xstrtokenize(const char *str, const char *separators) 2064{ 2065 char **list, **nlist; 2066 char *tok, *tmp; 2067 unsigned num = 0, n; 2068 2069 if (!str) 2070 return NULL; 2071 list = calloc(1, sizeof(*list)); 2072 if (!list) 2073 return NULL; 2074 tmp = strdup(str); 2075 if (!tmp) 2076 goto error; 2077 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 2078 nlist = reallocarray(list, num + 2, sizeof(*list)); 2079 if (!nlist) 2080 goto error; 2081 list = nlist; 2082 list[num] = strdup(tok); 2083 if (!list[num]) 2084 goto error; 2085 list[++num] = NULL; 2086 } 2087 free(tmp); 2088 return list; 2089 2090 error: 2091 free(tmp); 2092 for (n = 0; n < num; n++) 2093 free(list[n]); 2094 free(list); 2095 return NULL; 2096} 2097 2098/* Format a signed number into a string in a signal safe manner. The string 2099 * should be at least 21 characters in order to handle all int64_t values. 2100 */ 2101void 2102FormatInt64(int64_t num, char *string) 2103{ 2104 if (num < 0) { 2105 string[0] = '-'; 2106 num *= -1; 2107 string++; 2108 } 2109 FormatUInt64(num, string); 2110} 2111 2112/* Format a number into a string in a signal safe manner. The string should be 2113 * at least 21 characters in order to handle all uint64_t values. */ 2114void 2115FormatUInt64(uint64_t num, char *string) 2116{ 2117 uint64_t divisor; 2118 int len; 2119 int i; 2120 2121 for (len = 1, divisor = 10; 2122 len < 20 && num / divisor; 2123 len++, divisor *= 10); 2124 2125 for (i = len, divisor = 1; i > 0; i--, divisor *= 10) 2126 string[i - 1] = '0' + ((num / divisor) % 10); 2127 2128 string[len] = '\0'; 2129} 2130 2131/** 2132 * Format a double number as %.2f. 2133 */ 2134void 2135FormatDouble(double dbl, char *string) 2136{ 2137 int slen = 0; 2138 uint64_t frac; 2139 2140 frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; 2141 frac %= 100; 2142 2143 /* write decimal part to string */ 2144 if (dbl < 0 && dbl > -1) 2145 string[slen++] = '-'; 2146 FormatInt64((int64_t)dbl, &string[slen]); 2147 2148 while(string[slen] != '\0') 2149 slen++; 2150 2151 /* append fractional part, but only if we have enough characters. We 2152 * expect string to be 21 chars (incl trailing \0) */ 2153 if (slen <= 17) { 2154 string[slen++] = '.'; 2155 if (frac < 10) 2156 string[slen++] = '0'; 2157 2158 FormatUInt64(frac, &string[slen]); 2159 } 2160} 2161 2162 2163/* Format a number into a hexadecimal string in a signal safe manner. The string 2164 * should be at least 17 characters in order to handle all uint64_t values. */ 2165void 2166FormatUInt64Hex(uint64_t num, char *string) 2167{ 2168 uint64_t divisor; 2169 int len; 2170 int i; 2171 2172 for (len = 1, divisor = 0x10; 2173 len < 16 && num / divisor; 2174 len++, divisor *= 0x10); 2175 2176 for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { 2177 int val = (num / divisor) % 0x10; 2178 2179 if (val < 10) 2180 string[i - 1] = '0' + val; 2181 else 2182 string[i - 1] = 'a' + val - 10; 2183 } 2184 2185 string[len] = '\0'; 2186} 2187 2188#if !defined(WIN32) || defined(__CYGWIN__) 2189/* Move a file descriptor out of the way of our select mask; this 2190 * is useful for file descriptors which will never appear in the 2191 * select mask to avoid reducing the number of clients that can 2192 * connect to the server 2193 */ 2194int 2195os_move_fd(int fd) 2196{ 2197 int newfd; 2198 2199#ifdef F_DUPFD_CLOEXEC 2200 newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); 2201#else 2202 newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); 2203#endif 2204 if (newfd < 0) 2205 return fd; 2206#ifndef F_DUPFD_CLOEXEC 2207 fcntl(newfd, F_SETFD, FD_CLOEXEC); 2208#endif 2209 close(fd); 2210 return newfd; 2211} 2212#endif 2213