1 /* 2 3 Copyright 1987, 1998 The Open Group 4 5 Permission to use, copy, modify, distribute, and sell this software and its 6 documentation for any purpose is hereby granted without fee, provided that 7 the above copyright notice appear in all copies and that both that 8 copyright notice and this permission notice appear in supporting 9 documentation. 10 11 The above copyright notice and this permission notice shall be included 12 in all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 OTHER DEALINGS IN THE SOFTWARE. 21 22 Except as contained in this notice, the name of The Open Group shall 23 not be used in advertising or otherwise to promote the sale, use or 24 other dealings in this Software without prior written authorization 25 from The Open Group. 26 27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 28 Copyright 1994 Quarterdeck Office Systems. 29 30 All Rights Reserved 31 32 Permission to use, copy, modify, and distribute this software and its 33 documentation for any purpose and without fee is hereby granted, 34 provided that the above copyright notice appear in all copies and that 35 both that copyright notice and this permission notice appear in 36 supporting documentation, and that the names of Digital and 37 Quarterdeck not be used in advertising or publicity pertaining to 38 distribution of the software without specific, written prior 39 permission. 40 41 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 42 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 43 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT 44 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 45 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 46 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 47 OR PERFORMANCE OF THIS SOFTWARE. 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 117 Bool noTestExtensions; 118 119 #ifdef COMPOSITE 120 Bool noCompositeExtension = FALSE; 121 #endif 122 123 #ifdef DAMAGE 124 Bool noDamageExtension = FALSE; 125 #endif 126 #ifdef DBE 127 Bool noDbeExtension = FALSE; 128 #endif 129 #ifdef DPMSExtension 130 #include "dpmsproc.h" 131 Bool noDPMSExtension = FALSE; 132 #endif 133 #ifdef GLXEXT 134 Bool noGlxExtension = FALSE; 135 #endif 136 #ifdef SCREENSAVER 137 Bool noScreenSaverExtension = FALSE; 138 #endif 139 #ifdef MITSHM 140 Bool noMITShmExtension = FALSE; 141 #endif 142 #ifdef RANDR 143 Bool noRRExtension = FALSE; 144 #endif 145 Bool noRenderExtension = FALSE; 146 147 #ifdef XCSECURITY 148 Bool noSecurityExtension = FALSE; 149 #endif 150 #ifdef RES 151 Bool noResExtension = FALSE; 152 #endif 153 #ifdef XF86BIGFONT 154 Bool noXFree86BigfontExtension = FALSE; 155 #endif 156 #ifdef XFreeXDGA 157 Bool noXFree86DGAExtension = FALSE; 158 #endif 159 #ifdef XF86DRI 160 Bool noXFree86DRIExtension = FALSE; 161 #endif 162 #ifdef XF86VIDMODE 163 Bool noXFree86VidModeExtension = FALSE; 164 #endif 165 Bool noXFixesExtension = FALSE; 166 #ifdef PANORAMIX 167 /* Xinerama is disabled by default unless enabled via +xinerama */ 168 Bool noPanoramiXExtension = TRUE; 169 #endif 170 #ifdef XSELINUX 171 Bool noSELinuxExtension = FALSE; 172 int selinuxEnforcingState = SELINUX_MODE_DEFAULT; 173 #endif 174 #ifdef XV 175 Bool noXvExtension = FALSE; 176 #endif 177 #ifdef DRI2 178 Bool noDRI2Extension = FALSE; 179 #endif 180 181 Bool noGEExtension = FALSE; 182 183 #define X_INCLUDE_NETDB_H 184 #include <X11/Xos_r.h> 185 186 #include <errno.h> 187 188 Bool CoreDump; 189 190 Bool enableIndirectGLX = FALSE; 191 192 Bool AllowByteSwappedClients = TRUE; 193 194 #ifdef PANORAMIX 195 Bool PanoramiXExtensionDisabledHack = FALSE; 196 #endif 197 198 int auditTrailLevel = 1; 199 200 char *SeatId = NULL; 201 202 sig_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 209 static clockid_t clockid; 210 #endif 211 212 OsSigHandlerPtr 213 OsSignal(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 247 void 248 LockServer(void) 249 {} 250 251 void 252 UnlockServer(void) 253 {} 254 #else /* LOCK_SERVER */ 255 static Bool StillLocking = FALSE; 256 static char LockFile[PATH_MAX]; 257 static 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 */ 265 void 266 LockServer(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 */ 398 void 399 UnlockServer(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 413 void 414 AutoResetServer(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 425 void 426 GiveUp(int sig) 427 { 428 int olderrno = errno; 429 430 dispatchException |= DE_TERMINATE; 431 isItTimeToYield = TRUE; 432 errno = olderrno; 433 } 434 435 #ifdef MONOTONIC_CLOCK 436 void 437 ForceClockId(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__) 454 CARD32 455 GetTimeInMillis(void) 456 { 457 return GetTickCount(); 458 } 459 CARD64 460 GetTimeInMicros(void) 461 { 462 return (CARD64) GetTickCount() * 1000; 463 } 464 #else 465 CARD32 466 GetTimeInMillis(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 494 CARD64 495 GetTimeInMicros(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 517 void 518 UseMsg(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 */ 610 static int 611 VerifyDisplayName(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 653 static 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 */ 671 void 672 ProcessCommandLine(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. */ 1079 int 1080 set_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 1146 void * 1147 XNFalloc(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 */ 1160 void * 1161 XNFcalloc(unsigned long amount) 1162 { 1163 return XNFcallocarray(1, amount); 1164 } 1165 1166 void * 1167 XNFcallocarray(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 1176 void * 1177 XNFrealloc(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 1186 void * 1187 XNFreallocarray(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 1196 char * 1197 Xstrdup(const char *s) 1198 { 1199 if (s == NULL) 1200 return NULL; 1201 return strdup(s); 1202 } 1203 1204 char * 1205 XNFstrdup(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 1218 void 1219 SmartScheduleStopTimer(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 1234 void 1235 SmartScheduleStartTimer(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 1251 static void 1252 SmartScheduleTimer(int sig) 1253 { 1254 SmartScheduleTime += SmartScheduleInterval; 1255 } 1256 1257 static int 1258 SmartScheduleEnable(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 1277 static int 1278 SmartSchedulePause(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 1295 void 1296 SmartScheduleInit(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 1307 static sigset_t PreviousSignalMask; 1308 static int BlockedSignalCount; 1309 #endif 1310 1311 void 1312 OsBlockSignals(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 1333 void 1334 OsReleaseSignals(void) 1335 { 1336 #ifdef HAVE_SIGPROCMASK 1337 if (--BlockedSignalCount == 0) { 1338 xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0); 1339 } 1340 #endif 1341 } 1342 1343 void 1344 OsResetSignals(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 1358 void 1359 OsAbort(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 1384 int 1385 System(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 1427 static struct pid { 1428 struct pid *next; 1429 FILE *fp; 1430 int pid; 1431 } *pidlist; 1432 1433 void * 1434 Popen(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 */ 1524 void * 1525 Fopen(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 if (iop) { 1612 fclose(iop); 1613 } 1614 return NULL; 1615 } 1616 return iop; 1617 #endif /* HAS_SAVED_IDS_AND_SETEUID */ 1618 } 1619 1620 int 1621 Pclose(void *iop) 1622 { 1623 struct pid *cur, *last; 1624 int pstat; 1625 int pid; 1626 1627 DebugF("Pclose: fp = %p\n", iop); 1628 fclose(iop); 1629 1630 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1631 if (cur->fp == iop) 1632 break; 1633 if (cur == NULL) 1634 return -1; 1635 1636 do { 1637 pid = waitpid(cur->pid, &pstat, 0); 1638 } while (pid == -1 && errno == EINTR); 1639 1640 if (last == NULL) 1641 pidlist = cur->next; 1642 else 1643 last->next = cur->next; 1644 free(cur); 1645 1646 /* allow EINTR again */ 1647 OsReleaseSignals(); 1648 1649 #ifdef HAVE_SETITIMER 1650 if (SmartScheduleEnable() < 0) { 1651 perror("signal"); 1652 return -1; 1653 } 1654 #endif 1655 1656 return pid == -1 ? -1 : pstat; 1657 } 1658 1659 int 1660 Fclose(void *iop) 1661 { 1662 #ifdef HAS_SAVED_IDS_AND_SETEUID 1663 return fclose(iop); 1664 #else 1665 return Pclose(iop); 1666 #endif 1667 } 1668 1669 #endif /* !WIN32 */ 1670 1671 #ifdef WIN32 1672 1673 #include <X11/Xwindows.h> 1674 1675 const char * 1676 Win32TempDir(void) 1677 { 1678 static char buffer[PATH_MAX]; 1679 1680 if (GetTempPath(sizeof(buffer), buffer)) { 1681 int len; 1682 1683 buffer[sizeof(buffer) - 1] = 0; 1684 len = strlen(buffer); 1685 if (len > 0) 1686 if (buffer[len - 1] == '\\') 1687 buffer[len - 1] = 0; 1688 return buffer; 1689 } 1690 if (getenv("TEMP") != NULL) 1691 return getenv("TEMP"); 1692 else if (getenv("TMP") != NULL) 1693 return getenv("TMP"); 1694 else 1695 return "/tmp"; 1696 } 1697 1698 int 1699 System(const char *cmdline) 1700 { 1701 STARTUPINFO si; 1702 PROCESS_INFORMATION pi; 1703 DWORD dwExitCode; 1704 char *cmd = strdup(cmdline); 1705 1706 ZeroMemory(&si, sizeof(si)); 1707 si.cb = sizeof(si); 1708 ZeroMemory(&pi, sizeof(pi)); 1709 1710 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 1711 LPVOID buffer; 1712 1713 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1714 FORMAT_MESSAGE_FROM_SYSTEM | 1715 FORMAT_MESSAGE_IGNORE_INSERTS, 1716 NULL, 1717 GetLastError(), 1718 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 1719 (LPTSTR) &buffer, 0, NULL)) { 1720 ErrorF("[xkb] Starting '%s' failed!\n", cmdline); 1721 } 1722 else { 1723 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); 1724 LocalFree(buffer); 1725 } 1726 1727 free(cmd); 1728 return -1; 1729 } 1730 /* Wait until child process exits. */ 1731 WaitForSingleObject(pi.hProcess, INFINITE); 1732 1733 GetExitCodeProcess(pi.hProcess, &dwExitCode); 1734 1735 /* Close process and thread handles. */ 1736 CloseHandle(pi.hProcess); 1737 CloseHandle(pi.hThread); 1738 free(cmd); 1739 1740 return dwExitCode; 1741 } 1742 #endif 1743 1744 Bool 1745 PrivsElevated(void) 1746 { 1747 static Bool privsTested = FALSE; 1748 static Bool privsElevated = TRUE; 1749 1750 if (!privsTested) { 1751 #if defined(WIN32) 1752 privsElevated = FALSE; 1753 #else 1754 if ((getuid() != geteuid()) || (getgid() != getegid())) { 1755 privsElevated = TRUE; 1756 } 1757 else { 1758 #if defined(HAVE_ISSETUGID) 1759 privsElevated = issetugid(); 1760 #elif defined(HAVE_GETRESUID) 1761 uid_t ruid, euid, suid; 1762 gid_t rgid, egid, sgid; 1763 1764 if ((getresuid(&ruid, &euid, &suid) == 0) && 1765 (getresgid(&rgid, &egid, &sgid) == 0)) { 1766 privsElevated = (euid != suid) || (egid != sgid); 1767 } 1768 else { 1769 printf("Failed getresuid or getresgid"); 1770 /* Something went wrong, make defensive assumption */ 1771 privsElevated = TRUE; 1772 } 1773 #else 1774 if (getuid() == 0) { 1775 /* running as root: uid==euid==0 */ 1776 privsElevated = FALSE; 1777 } 1778 else { 1779 /* 1780 * If there are saved ID's the process might still be privileged 1781 * even though the above test succeeded. If issetugid() and 1782 * getresgid() aren't available, test this by trying to set 1783 * euid to 0. 1784 */ 1785 unsigned int oldeuid; 1786 1787 oldeuid = geteuid(); 1788 1789 if (seteuid(0) != 0) { 1790 privsElevated = FALSE; 1791 } 1792 else { 1793 if (seteuid(oldeuid) != 0) { 1794 FatalError("Failed to drop privileges. Exiting\n"); 1795 } 1796 privsElevated = TRUE; 1797 } 1798 } 1799 #endif 1800 } 1801 #endif 1802 privsTested = TRUE; 1803 } 1804 return privsElevated; 1805 } 1806 1807 /* 1808 * CheckUserParameters: check for long command line arguments and long 1809 * environment variables. By default, these checks are only done when 1810 * the server's euid != ruid. In 3.3.x, these checks were done in an 1811 * external wrapper utility. 1812 */ 1813 1814 /* Consider LD* variables insecure? */ 1815 #ifndef REMOVE_ENV_LD 1816 #define REMOVE_ENV_LD 1 1817 #endif 1818 1819 /* Remove long environment variables? */ 1820 #ifndef REMOVE_LONG_ENV 1821 #define REMOVE_LONG_ENV 1 1822 #endif 1823 1824 /* 1825 * Disallow stdout or stderr as pipes? It's possible to block the X server 1826 * when piping stdout+stderr to a pipe. 1827 * 1828 * Don't enable this because it looks like it's going to cause problems. 1829 */ 1830 #ifndef NO_OUTPUT_PIPES 1831 #define NO_OUTPUT_PIPES 0 1832 #endif 1833 1834 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 1835 #ifndef CHECK_EUID 1836 #ifndef WIN32 1837 #define CHECK_EUID 1 1838 #else 1839 #define CHECK_EUID 0 1840 #endif 1841 #endif 1842 1843 /* 1844 * Maybe the locale can be faked to make isprint(3) report that everything 1845 * is printable? Avoid it by default. 1846 */ 1847 #ifndef USE_ISPRINT 1848 #define USE_ISPRINT 0 1849 #endif 1850 1851 #define MAX_ARG_LENGTH 128 1852 #define MAX_ENV_LENGTH 256 1853 #define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 1854 1855 #if USE_ISPRINT 1856 #include <ctype.h> 1857 #define checkPrintable(c) isprint(c) 1858 #else 1859 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 1860 #endif 1861 1862 enum BadCode { 1863 NotBad = 0, 1864 UnsafeArg, 1865 ArgTooLong, 1866 UnprintableArg, 1867 EnvTooLong, 1868 OutputIsPipe, 1869 InternalError 1870 }; 1871 1872 #if defined(VENDORSUPPORT) 1873 #define BUGADDRESS VENDORSUPPORT 1874 #elif defined(BUILDERADDR) 1875 #define BUGADDRESS BUILDERADDR 1876 #else 1877 #define BUGADDRESS "xorg (at) freedesktop.org" 1878 #endif 1879 1880 void 1881 CheckUserParameters(int argc, char **argv, char **envp) 1882 { 1883 enum BadCode bad = NotBad; 1884 int i = 0, j; 1885 char *a, *e = NULL; 1886 1887 #if CHECK_EUID 1888 if (PrivsElevated()) 1889 #endif 1890 { 1891 /* Check each argv[] */ 1892 for (i = 1; i < argc; i++) { 1893 if (strcmp(argv[i], "-fp") == 0) { 1894 i++; /* continue with next argument. skip the length check */ 1895 if (i >= argc) 1896 break; 1897 } 1898 else { 1899 if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1900 bad = ArgTooLong; 1901 break; 1902 } 1903 } 1904 a = argv[i]; 1905 while (*a) { 1906 if (checkPrintable(*a) == 0) { 1907 bad = UnprintableArg; 1908 break; 1909 } 1910 a++; 1911 } 1912 if (bad) 1913 break; 1914 } 1915 if (!bad) { 1916 /* Check each envp[] */ 1917 for (i = 0; envp[i]; i++) { 1918 1919 /* Check for bad environment variables and values */ 1920 #if REMOVE_ENV_LD 1921 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1922 for (j = i; envp[j]; j++) { 1923 envp[j] = envp[j + 1]; 1924 } 1925 } 1926 #endif 1927 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 1928 #if REMOVE_LONG_ENV 1929 for (j = i; envp[j]; j++) { 1930 envp[j] = envp[j + 1]; 1931 } 1932 i--; 1933 #else 1934 char *eq; 1935 int len; 1936 1937 eq = strchr(envp[i], '='); 1938 if (!eq) 1939 continue; 1940 len = eq - envp[i]; 1941 e = strndup(envp[i], len); 1942 if (!e) { 1943 bad = InternalError; 1944 break; 1945 } 1946 if (len >= 4 && 1947 (strcmp(e + len - 4, "PATH") == 0 || 1948 strcmp(e, "TERMCAP") == 0)) { 1949 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1950 bad = EnvTooLong; 1951 break; 1952 } 1953 else { 1954 free(e); 1955 } 1956 } 1957 else { 1958 bad = EnvTooLong; 1959 break; 1960 } 1961 #endif 1962 } 1963 } 1964 } 1965 #if NO_OUTPUT_PIPES 1966 if (!bad) { 1967 struct stat buf; 1968 1969 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1970 bad = OutputIsPipe; 1971 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1972 bad = OutputIsPipe; 1973 } 1974 #endif 1975 } 1976 switch (bad) { 1977 case NotBad: 1978 return; 1979 case UnsafeArg: 1980 ErrorF("Command line argument number %d is unsafe\n", i); 1981 break; 1982 case ArgTooLong: 1983 ErrorF("Command line argument number %d is too long\n", i); 1984 break; 1985 case UnprintableArg: 1986 ErrorF("Command line argument number %d contains unprintable" 1987 " characters\n", i); 1988 break; 1989 case EnvTooLong: 1990 ErrorF("Environment variable `%s' is too long\n", e); 1991 break; 1992 case OutputIsPipe: 1993 ErrorF("Stdout and/or stderr is a pipe\n"); 1994 break; 1995 case InternalError: 1996 ErrorF("Internal Error\n"); 1997 break; 1998 default: 1999 ErrorF("Unknown error\n"); 2000 break; 2001 } 2002 FatalError("X server aborted because of unsafe environment\n"); 2003 } 2004 2005 /* 2006 * CheckUserAuthorization: check if the user is allowed to start the 2007 * X server. This usually means some sort of PAM checking, and it is 2008 * usually only done for setuid servers (uid != euid). 2009 */ 2010 2011 #ifdef USE_PAM 2012 #include <security/pam_appl.h> 2013 #include <security/pam_misc.h> 2014 #include <pwd.h> 2015 #endif /* USE_PAM */ 2016 2017 void 2018 CheckUserAuthorization(void) 2019 { 2020 #ifdef USE_PAM 2021 static struct pam_conv conv = { 2022 misc_conv, 2023 NULL 2024 }; 2025 2026 pam_handle_t *pamh = NULL; 2027 struct passwd *pw; 2028 int retval; 2029 2030 if (getuid() != geteuid()) { 2031 pw = getpwuid(getuid()); 2032 if (pw == NULL) 2033 FatalError("getpwuid() failed for uid %d\n", getuid()); 2034 2035 retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 2036 if (retval != PAM_SUCCESS) 2037 FatalError("pam_start() failed.\n" 2038 "\tMissing or mangled PAM config file or module?\n"); 2039 2040 retval = pam_authenticate(pamh, 0); 2041 if (retval != PAM_SUCCESS) { 2042 pam_end(pamh, retval); 2043 FatalError("PAM authentication failed, cannot start X server.\n" 2044 "\tPerhaps you do not have console ownership?\n"); 2045 } 2046 2047 retval = pam_acct_mgmt(pamh, 0); 2048 if (retval != PAM_SUCCESS) { 2049 pam_end(pamh, retval); 2050 FatalError("PAM authentication failed, cannot start X server.\n" 2051 "\tPerhaps you do not have console ownership?\n"); 2052 } 2053 2054 /* this is not a session, so do not do session management */ 2055 pam_end(pamh, PAM_SUCCESS); 2056 } 2057 #endif 2058 } 2059 2060 /* 2061 * Tokenize a string into a NULL terminated array of strings. Always returns 2062 * an allocated array unless an error occurs. 2063 */ 2064 char ** 2065 xstrtokenize(const char *str, const char *separators) 2066 { 2067 char **list, **nlist; 2068 char *tok, *tmp; 2069 unsigned num = 0, n; 2070 2071 if (!str) 2072 return NULL; 2073 list = calloc(1, sizeof(*list)); 2074 if (!list) 2075 return NULL; 2076 tmp = strdup(str); 2077 if (!tmp) 2078 goto error; 2079 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 2080 nlist = reallocarray(list, num + 2, sizeof(*list)); 2081 if (!nlist) 2082 goto error; 2083 list = nlist; 2084 list[num] = strdup(tok); 2085 if (!list[num]) 2086 goto error; 2087 list[++num] = NULL; 2088 } 2089 free(tmp); 2090 return list; 2091 2092 error: 2093 free(tmp); 2094 for (n = 0; n < num; n++) 2095 free(list[n]); 2096 free(list); 2097 return NULL; 2098 } 2099 2100 /* Format a signed number into a string in a signal safe manner. The string 2101 * should be at least 21 characters in order to handle all int64_t values. 2102 */ 2103 void 2104 FormatInt64(int64_t num, char *string) 2105 { 2106 uint64_t unum = num; 2107 2108 if (num < 0) { 2109 string[0] = '-'; 2110 unum = num * -1; 2111 string++; 2112 } 2113 FormatUInt64(unum, string); 2114 } 2115 2116 /* Format a number into a string in a signal safe manner. The string should be 2117 * at least 21 characters in order to handle all uint64_t values. */ 2118 void 2119 FormatUInt64(uint64_t num, char *string) 2120 { 2121 uint64_t divisor; 2122 int len; 2123 int i; 2124 2125 for (len = 1, divisor = 10; 2126 len < 20 && num / divisor; 2127 len++, divisor *= 10); 2128 2129 for (i = len, divisor = 1; i > 0; i--, divisor *= 10) 2130 string[i - 1] = '0' + ((num / divisor) % 10); 2131 2132 string[len] = '\0'; 2133 } 2134 2135 /** 2136 * Format a double number as %.2f. 2137 */ 2138 void 2139 FormatDouble(double dbl, char *string) 2140 { 2141 int slen = 0; 2142 uint64_t frac; 2143 2144 frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; 2145 frac %= 100; 2146 2147 /* write decimal part to string */ 2148 if (dbl < 0 && dbl > -1) 2149 string[slen++] = '-'; 2150 FormatInt64((int64_t)dbl, &string[slen]); 2151 2152 while(string[slen] != '\0') 2153 slen++; 2154 2155 /* append fractional part, but only if we have enough characters. We 2156 * expect string to be 21 chars (incl trailing \0) */ 2157 if (slen <= 17) { 2158 string[slen++] = '.'; 2159 if (frac < 10) 2160 string[slen++] = '0'; 2161 2162 FormatUInt64(frac, &string[slen]); 2163 } 2164 } 2165 2166 2167 /* Format a number into a hexadecimal string in a signal safe manner. The string 2168 * should be at least 17 characters in order to handle all uint64_t values. */ 2169 void 2170 FormatUInt64Hex(uint64_t num, char *string) 2171 { 2172 uint64_t divisor; 2173 int len; 2174 int i; 2175 2176 for (len = 1, divisor = 0x10; 2177 len < 16 && num / divisor; 2178 len++, divisor *= 0x10); 2179 2180 for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { 2181 int val = (num / divisor) % 0x10; 2182 2183 if (val < 10) 2184 string[i - 1] = '0' + val; 2185 else 2186 string[i - 1] = 'a' + val - 10; 2187 } 2188 2189 string[len] = '\0'; 2190 } 2191 2192 #if !defined(WIN32) || defined(__CYGWIN__) 2193 /* Move a file descriptor out of the way of our select mask; this 2194 * is useful for file descriptors which will never appear in the 2195 * select mask to avoid reducing the number of clients that can 2196 * connect to the server 2197 */ 2198 int 2199 os_move_fd(int fd) 2200 { 2201 int newfd; 2202 2203 #ifdef F_DUPFD_CLOEXEC 2204 newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); 2205 #else 2206 newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); 2207 #endif 2208 if (newfd < 0) 2209 return fd; 2210 #ifndef F_DUPFD_CLOEXEC 2211 fcntl(newfd, F_SETFD, FD_CLOEXEC); 2212 #endif 2213 close(fd); 2214 return newfd; 2215 } 2216 #endif 2217