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