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 if (!iop) 1508 close(pdes[0]); 1509 } 1510 else { 1511 iop = fdopen(pdes[1], type); 1512 close(pdes[0]); 1513 if (!iop) 1514 close(pdes[1]); 1515 } 1516 1517 if (!iop) { 1518 free(cur); 1519 #ifdef HAVE_SETITIMER 1520 if (SmartScheduleEnable() < 0) 1521 perror("signal"); 1522 #endif 1523 return NULL; 1524 } 1525 1526 cur->fp = iop; 1527 cur->pid = pid; 1528 cur->next = pidlist; 1529 pidlist = cur; 1530 1531 DebugF("Popen: `%s', fp = %p\n", command, iop); 1532 1533 return iop; 1534 } 1535 1536 /* fopen that drops privileges */ 1537 void * 1538 Fopen(const char *file, const char *type) 1539 { 1540 FILE *iop; 1541 1542 #ifndef HAS_SAVED_IDS_AND_SETEUID 1543 struct pid *cur; 1544 int pdes[2], pid; 1545 1546 if (file == NULL || type == NULL) 1547 return NULL; 1548 1549 if ((*type != 'r' && *type != 'w') || type[1]) 1550 return NULL; 1551 1552 if ((cur = malloc(sizeof(struct pid))) == NULL) 1553 return NULL; 1554 1555 if (pipe(pdes) < 0) { 1556 free(cur); 1557 return NULL; 1558 } 1559 1560 switch (pid = fork()) { 1561 case -1: /* error */ 1562 close(pdes[0]); 1563 close(pdes[1]); 1564 free(cur); 1565 return NULL; 1566 case 0: /* child */ 1567 if (setgid(getgid()) == -1) 1568 _exit(127); 1569 if (setuid(getuid()) == -1) 1570 _exit(127); 1571 if (*type == 'r') { 1572 if (pdes[1] != 1) { 1573 /* stdout */ 1574 dup2(pdes[1], 1); 1575 close(pdes[1]); 1576 } 1577 close(pdes[0]); 1578 } 1579 else { 1580 if (pdes[0] != 0) { 1581 /* stdin */ 1582 dup2(pdes[0], 0); 1583 close(pdes[0]); 1584 } 1585 close(pdes[1]); 1586 } 1587 execl("/bin/cat", "cat", file, (char *) NULL); 1588 _exit(127); 1589 } 1590 1591 /* Avoid EINTR during stdio calls */ 1592 OsBlockSignals(); 1593 1594 /* parent */ 1595 if (*type == 'r') { 1596 iop = fdopen(pdes[0], type); 1597 close(pdes[1]); 1598 } 1599 else { 1600 iop = fdopen(pdes[1], type); 1601 close(pdes[0]); 1602 } 1603 1604 cur->fp = iop; 1605 cur->pid = pid; 1606 cur->next = pidlist; 1607 pidlist = cur; 1608 1609 DebugF("Fopen(%s), fp = %p\n", file, iop); 1610 1611 return iop; 1612 #else 1613 int ruid, euid; 1614 1615 ruid = getuid(); 1616 euid = geteuid(); 1617 1618 if (seteuid(ruid) == -1) { 1619 return NULL; 1620 } 1621 iop = fopen(file, type); 1622 1623 if (seteuid(euid) == -1) { 1624 if (iop) { 1625 fclose(iop); 1626 } 1627 return NULL; 1628 } 1629 return iop; 1630 #endif /* HAS_SAVED_IDS_AND_SETEUID */ 1631 } 1632 1633 int 1634 Pclose(void *iop) 1635 { 1636 struct pid *cur, *last; 1637 int pstat; 1638 int pid; 1639 1640 DebugF("Pclose: fp = %p\n", iop); 1641 fclose(iop); 1642 1643 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1644 if (cur->fp == iop) 1645 break; 1646 if (cur == NULL) 1647 return -1; 1648 1649 do { 1650 pid = waitpid(cur->pid, &pstat, 0); 1651 } while (pid == -1 && errno == EINTR); 1652 1653 if (last == NULL) 1654 pidlist = cur->next; 1655 else 1656 last->next = cur->next; 1657 free(cur); 1658 1659 /* allow EINTR again */ 1660 OsReleaseSignals(); 1661 1662 #ifdef HAVE_SETITIMER 1663 if (SmartScheduleEnable() < 0) { 1664 perror("signal"); 1665 return -1; 1666 } 1667 #endif 1668 1669 return pid == -1 ? -1 : pstat; 1670 } 1671 1672 int 1673 Fclose(void *iop) 1674 { 1675 #ifdef HAS_SAVED_IDS_AND_SETEUID 1676 return fclose(iop); 1677 #else 1678 return Pclose(iop); 1679 #endif 1680 } 1681 1682 #endif /* !WIN32 */ 1683 1684 #ifdef WIN32 1685 1686 #include <X11/Xwindows.h> 1687 1688 const char * 1689 Win32TempDir(void) 1690 { 1691 static char buffer[PATH_MAX]; 1692 1693 if (GetTempPath(sizeof(buffer), buffer)) { 1694 int len; 1695 1696 buffer[sizeof(buffer) - 1] = 0; 1697 len = strlen(buffer); 1698 if (len > 0) 1699 if (buffer[len - 1] == '\\') 1700 buffer[len - 1] = 0; 1701 return buffer; 1702 } 1703 if (getenv("TEMP") != NULL) 1704 return getenv("TEMP"); 1705 else if (getenv("TMP") != NULL) 1706 return getenv("TMP"); 1707 else 1708 return "/tmp"; 1709 } 1710 1711 int 1712 System(const char *cmdline) 1713 { 1714 STARTUPINFO si; 1715 PROCESS_INFORMATION pi; 1716 DWORD dwExitCode; 1717 char *cmd = strdup(cmdline); 1718 1719 ZeroMemory(&si, sizeof(si)); 1720 si.cb = sizeof(si); 1721 ZeroMemory(&pi, sizeof(pi)); 1722 1723 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 1724 LPVOID buffer; 1725 1726 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1727 FORMAT_MESSAGE_FROM_SYSTEM | 1728 FORMAT_MESSAGE_IGNORE_INSERTS, 1729 NULL, 1730 GetLastError(), 1731 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 1732 (LPTSTR) &buffer, 0, NULL)) { 1733 ErrorF("[xkb] Starting '%s' failed!\n", cmdline); 1734 } 1735 else { 1736 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); 1737 LocalFree(buffer); 1738 } 1739 1740 free(cmd); 1741 return -1; 1742 } 1743 /* Wait until child process exits. */ 1744 WaitForSingleObject(pi.hProcess, INFINITE); 1745 1746 GetExitCodeProcess(pi.hProcess, &dwExitCode); 1747 1748 /* Close process and thread handles. */ 1749 CloseHandle(pi.hProcess); 1750 CloseHandle(pi.hThread); 1751 free(cmd); 1752 1753 return dwExitCode; 1754 } 1755 #endif 1756 1757 Bool 1758 PrivsElevated(void) 1759 { 1760 static Bool privsTested = FALSE; 1761 static Bool privsElevated = TRUE; 1762 1763 if (!privsTested) { 1764 #if defined(WIN32) 1765 privsElevated = FALSE; 1766 #else 1767 if ((getuid() != geteuid()) || (getgid() != getegid())) { 1768 privsElevated = TRUE; 1769 } 1770 else { 1771 #if defined(HAVE_ISSETUGID) 1772 privsElevated = issetugid(); 1773 #elif defined(HAVE_GETRESUID) 1774 uid_t ruid, euid, suid; 1775 gid_t rgid, egid, sgid; 1776 1777 if ((getresuid(&ruid, &euid, &suid) == 0) && 1778 (getresgid(&rgid, &egid, &sgid) == 0)) { 1779 privsElevated = (euid != suid) || (egid != sgid); 1780 } 1781 else { 1782 printf("Failed getresuid or getresgid"); 1783 /* Something went wrong, make defensive assumption */ 1784 privsElevated = TRUE; 1785 } 1786 #else 1787 if (getuid() == 0) { 1788 /* running as root: uid==euid==0 */ 1789 privsElevated = FALSE; 1790 } 1791 else { 1792 /* 1793 * If there are saved ID's the process might still be privileged 1794 * even though the above test succeeded. If issetugid() and 1795 * getresgid() aren't available, test this by trying to set 1796 * euid to 0. 1797 */ 1798 unsigned int oldeuid; 1799 1800 oldeuid = geteuid(); 1801 1802 if (seteuid(0) != 0) { 1803 privsElevated = FALSE; 1804 } 1805 else { 1806 if (seteuid(oldeuid) != 0) { 1807 FatalError("Failed to drop privileges. Exiting\n"); 1808 } 1809 privsElevated = TRUE; 1810 } 1811 } 1812 #endif 1813 } 1814 #endif 1815 privsTested = TRUE; 1816 } 1817 return privsElevated; 1818 } 1819 1820 /* 1821 * CheckUserParameters: check for long command line arguments and long 1822 * environment variables. By default, these checks are only done when 1823 * the server's euid != ruid. In 3.3.x, these checks were done in an 1824 * external wrapper utility. 1825 */ 1826 1827 /* Consider LD* variables insecure? */ 1828 #ifndef REMOVE_ENV_LD 1829 #define REMOVE_ENV_LD 1 1830 #endif 1831 1832 /* Remove long environment variables? */ 1833 #ifndef REMOVE_LONG_ENV 1834 #define REMOVE_LONG_ENV 1 1835 #endif 1836 1837 /* 1838 * Disallow stdout or stderr as pipes? It's possible to block the X server 1839 * when piping stdout+stderr to a pipe. 1840 * 1841 * Don't enable this because it looks like it's going to cause problems. 1842 */ 1843 #ifndef NO_OUTPUT_PIPES 1844 #define NO_OUTPUT_PIPES 0 1845 #endif 1846 1847 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 1848 #ifndef CHECK_EUID 1849 #ifndef WIN32 1850 #define CHECK_EUID 1 1851 #else 1852 #define CHECK_EUID 0 1853 #endif 1854 #endif 1855 1856 /* 1857 * Maybe the locale can be faked to make isprint(3) report that everything 1858 * is printable? Avoid it by default. 1859 */ 1860 #ifndef USE_ISPRINT 1861 #define USE_ISPRINT 0 1862 #endif 1863 1864 #define MAX_ARG_LENGTH 128 1865 #define MAX_ENV_LENGTH 256 1866 #define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 1867 1868 #if USE_ISPRINT 1869 #include <ctype.h> 1870 #define checkPrintable(c) isprint(c) 1871 #else 1872 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 1873 #endif 1874 1875 enum BadCode { 1876 NotBad = 0, 1877 UnsafeArg, 1878 ArgTooLong, 1879 UnprintableArg, 1880 EnvTooLong, 1881 OutputIsPipe, 1882 InternalError 1883 }; 1884 1885 #if defined(VENDORSUPPORT) 1886 #define BUGADDRESS VENDORSUPPORT 1887 #elif defined(BUILDERADDR) 1888 #define BUGADDRESS BUILDERADDR 1889 #else 1890 #define BUGADDRESS "xorg (at) freedesktop.org" 1891 #endif 1892 1893 void 1894 CheckUserParameters(int argc, char **argv, char **envp) 1895 { 1896 enum BadCode bad = NotBad; 1897 int i = 0, j; 1898 char *a, *e = NULL; 1899 1900 #if CHECK_EUID 1901 if (PrivsElevated()) 1902 #endif 1903 { 1904 /* Check each argv[] */ 1905 for (i = 1; i < argc; i++) { 1906 if (strcmp(argv[i], "-fp") == 0) { 1907 i++; /* continue with next argument. skip the length check */ 1908 if (i >= argc) 1909 break; 1910 } 1911 else { 1912 if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1913 bad = ArgTooLong; 1914 break; 1915 } 1916 } 1917 a = argv[i]; 1918 while (*a) { 1919 if (checkPrintable(*a) == 0) { 1920 bad = UnprintableArg; 1921 break; 1922 } 1923 a++; 1924 } 1925 if (bad) 1926 break; 1927 } 1928 if (!bad) { 1929 /* Check each envp[] */ 1930 for (i = 0; envp[i]; i++) { 1931 1932 /* Check for bad environment variables and values */ 1933 #if REMOVE_ENV_LD 1934 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1935 for (j = i; envp[j]; j++) { 1936 envp[j] = envp[j + 1]; 1937 } 1938 } 1939 #endif 1940 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 1941 #if REMOVE_LONG_ENV 1942 for (j = i; envp[j]; j++) { 1943 envp[j] = envp[j + 1]; 1944 } 1945 i--; 1946 #else 1947 char *eq; 1948 int len; 1949 1950 eq = strchr(envp[i], '='); 1951 if (!eq) 1952 continue; 1953 len = eq - envp[i]; 1954 e = strndup(envp[i], len); 1955 if (!e) { 1956 bad = InternalError; 1957 break; 1958 } 1959 if (len >= 4 && 1960 (strcmp(e + len - 4, "PATH") == 0 || 1961 strcmp(e, "TERMCAP") == 0)) { 1962 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1963 bad = EnvTooLong; 1964 break; 1965 } 1966 else { 1967 free(e); 1968 } 1969 } 1970 else { 1971 bad = EnvTooLong; 1972 break; 1973 } 1974 #endif 1975 } 1976 } 1977 } 1978 #if NO_OUTPUT_PIPES 1979 if (!bad) { 1980 struct stat buf; 1981 1982 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1983 bad = OutputIsPipe; 1984 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1985 bad = OutputIsPipe; 1986 } 1987 #endif 1988 } 1989 switch (bad) { 1990 case NotBad: 1991 return; 1992 case UnsafeArg: 1993 ErrorF("Command line argument number %d is unsafe\n", i); 1994 break; 1995 case ArgTooLong: 1996 ErrorF("Command line argument number %d is too long\n", i); 1997 break; 1998 case UnprintableArg: 1999 ErrorF("Command line argument number %d contains unprintable" 2000 " characters\n", i); 2001 break; 2002 case EnvTooLong: 2003 ErrorF("Environment variable `%s' is too long\n", e); 2004 break; 2005 case OutputIsPipe: 2006 ErrorF("Stdout and/or stderr is a pipe\n"); 2007 break; 2008 case InternalError: 2009 ErrorF("Internal Error\n"); 2010 break; 2011 default: 2012 ErrorF("Unknown error\n"); 2013 break; 2014 } 2015 FatalError("X server aborted because of unsafe environment\n"); 2016 } 2017 2018 /* 2019 * CheckUserAuthorization: check if the user is allowed to start the 2020 * X server. This usually means some sort of PAM checking, and it is 2021 * usually only done for setuid servers (uid != euid). 2022 */ 2023 2024 #ifdef USE_PAM 2025 #include <security/pam_appl.h> 2026 #include <security/pam_misc.h> 2027 #include <pwd.h> 2028 #endif /* USE_PAM */ 2029 2030 void 2031 CheckUserAuthorization(void) 2032 { 2033 #ifdef USE_PAM 2034 static struct pam_conv conv = { 2035 misc_conv, 2036 NULL 2037 }; 2038 2039 pam_handle_t *pamh = NULL; 2040 struct passwd *pw; 2041 int retval; 2042 2043 if (getuid() != geteuid()) { 2044 pw = getpwuid(getuid()); 2045 if (pw == NULL) 2046 FatalError("getpwuid() failed for uid %d\n", getuid()); 2047 2048 retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 2049 if (retval != PAM_SUCCESS) 2050 FatalError("pam_start() failed.\n" 2051 "\tMissing or mangled PAM config file or module?\n"); 2052 2053 retval = pam_authenticate(pamh, 0); 2054 if (retval != PAM_SUCCESS) { 2055 pam_end(pamh, retval); 2056 FatalError("PAM authentication failed, cannot start X server.\n" 2057 "\tPerhaps you do not have console ownership?\n"); 2058 } 2059 2060 retval = pam_acct_mgmt(pamh, 0); 2061 if (retval != PAM_SUCCESS) { 2062 pam_end(pamh, retval); 2063 FatalError("PAM authentication failed, cannot start X server.\n" 2064 "\tPerhaps you do not have console ownership?\n"); 2065 } 2066 2067 /* this is not a session, so do not do session management */ 2068 pam_end(pamh, PAM_SUCCESS); 2069 } 2070 #endif 2071 } 2072 2073 /* 2074 * Tokenize a string into a NULL terminated array of strings. Always returns 2075 * an allocated array unless an error occurs. 2076 */ 2077 char ** 2078 xstrtokenize(const char *str, const char *separators) 2079 { 2080 char **list, **nlist; 2081 char *tok, *tmp; 2082 unsigned num = 0, n; 2083 2084 if (!str) 2085 return NULL; 2086 list = calloc(1, sizeof(*list)); 2087 if (!list) 2088 return NULL; 2089 tmp = strdup(str); 2090 if (!tmp) 2091 goto error; 2092 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 2093 nlist = reallocarray(list, num + 2, sizeof(*list)); 2094 if (!nlist) 2095 goto error; 2096 list = nlist; 2097 list[num] = strdup(tok); 2098 if (!list[num]) 2099 goto error; 2100 list[++num] = NULL; 2101 } 2102 free(tmp); 2103 return list; 2104 2105 error: 2106 free(tmp); 2107 for (n = 0; n < num; n++) 2108 free(list[n]); 2109 free(list); 2110 return NULL; 2111 } 2112 2113 /* Format a signed number into a string in a signal safe manner. The string 2114 * should be at least 21 characters in order to handle all int64_t values. 2115 */ 2116 void 2117 FormatInt64(int64_t num, char *string) 2118 { 2119 uint64_t unum = num; 2120 2121 if (num < 0) { 2122 string[0] = '-'; 2123 unum = num * -1; 2124 string++; 2125 } 2126 FormatUInt64(unum, string); 2127 } 2128 2129 /* Format a number into a string in a signal safe manner. The string should be 2130 * at least 21 characters in order to handle all uint64_t values. */ 2131 void 2132 FormatUInt64(uint64_t num, char *string) 2133 { 2134 uint64_t divisor; 2135 int len; 2136 int i; 2137 2138 for (len = 1, divisor = 10; 2139 len < 20 && num / divisor; 2140 len++, divisor *= 10); 2141 2142 for (i = len, divisor = 1; i > 0; i--, divisor *= 10) 2143 string[i - 1] = '0' + ((num / divisor) % 10); 2144 2145 string[len] = '\0'; 2146 } 2147 2148 /** 2149 * Format a double number as %.2f. 2150 */ 2151 void 2152 FormatDouble(double dbl, char *string) 2153 { 2154 int slen = 0; 2155 uint64_t frac; 2156 2157 frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; 2158 frac %= 100; 2159 2160 /* write decimal part to string */ 2161 if (dbl < 0 && dbl > -1) 2162 string[slen++] = '-'; 2163 FormatInt64((int64_t)dbl, &string[slen]); 2164 2165 while(string[slen] != '\0') 2166 slen++; 2167 2168 /* append fractional part, but only if we have enough characters. We 2169 * expect string to be 21 chars (incl trailing \0) */ 2170 if (slen <= 17) { 2171 string[slen++] = '.'; 2172 if (frac < 10) 2173 string[slen++] = '0'; 2174 2175 FormatUInt64(frac, &string[slen]); 2176 } 2177 } 2178 2179 2180 /* Format a number into a hexadecimal string in a signal safe manner. The string 2181 * should be at least 17 characters in order to handle all uint64_t values. */ 2182 void 2183 FormatUInt64Hex(uint64_t num, char *string) 2184 { 2185 uint64_t divisor; 2186 int len; 2187 int i; 2188 2189 for (len = 1, divisor = 0x10; 2190 len < 16 && num / divisor; 2191 len++, divisor *= 0x10); 2192 2193 for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { 2194 int val = (num / divisor) % 0x10; 2195 2196 if (val < 10) 2197 string[i - 1] = '0' + val; 2198 else 2199 string[i - 1] = 'a' + val - 10; 2200 } 2201 2202 string[len] = '\0'; 2203 } 2204 2205 #if !defined(WIN32) || defined(__CYGWIN__) 2206 /* Move a file descriptor out of the way of our select mask; this 2207 * is useful for file descriptors which will never appear in the 2208 * select mask to avoid reducing the number of clients that can 2209 * connect to the server 2210 */ 2211 int 2212 os_move_fd(int fd) 2213 { 2214 int newfd; 2215 2216 #ifdef F_DUPFD_CLOEXEC 2217 newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); 2218 #else 2219 newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); 2220 #endif 2221 if (newfd < 0) 2222 return fd; 2223 #ifndef F_DUPFD_CLOEXEC 2224 fcntl(newfd, F_SETFD, FD_CLOEXEC); 2225 #endif 2226 close(fd); 2227 return newfd; 2228 } 2229 #endif 2230