utils.c revision 65b04b38
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) chmod(tmp, 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); 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 getrlimit (RLIMIT_CORE, &core_limit); 659 core_limit.rlim_cur = core_limit.rlim_max; 660 setrlimit (RLIMIT_CORE, &core_limit); 661#endif 662 CoreDump = TRUE; 663 } 664 else if ( strcmp( argv[i], "-nocursor") == 0) 665 { 666 EnableCursor = FALSE; 667 } 668 else if ( strcmp( argv[i], "-dpi") == 0) 669 { 670 if(++i < argc) 671 monitorResolution = atoi(argv[i]); 672 else 673 UseMsg(); 674 } 675#ifdef DPMSExtension 676 else if ( strcmp( argv[i], "dpms") == 0) 677 /* ignored for compatibility */ ; 678 else if ( strcmp( argv[i], "-dpms") == 0) 679 DPMSDisabledSwitch = TRUE; 680#endif 681 else if ( strcmp( argv[i], "-deferglyphs") == 0) 682 { 683 if(++i >= argc || !ParseGlyphCachingMode(argv[i])) 684 UseMsg(); 685 } 686 else if ( strcmp( argv[i], "-f") == 0) 687 { 688 if(++i < argc) 689 defaultKeyboardControl.bell = atoi(argv[i]); 690 else 691 UseMsg(); 692 } 693 else if ( strcmp( argv[i], "-fc") == 0) 694 { 695 if(++i < argc) 696 defaultCursorFont = argv[i]; 697 else 698 UseMsg(); 699 } 700 else if ( strcmp( argv[i], "-fn") == 0) 701 { 702 if(++i < argc) 703 defaultTextFont = argv[i]; 704 else 705 UseMsg(); 706 } 707 else if ( strcmp( argv[i], "-fp") == 0) 708 { 709 if(++i < argc) 710 { 711 defaultFontPath = argv[i]; 712 } 713 else 714 UseMsg(); 715 } 716 else if ( strcmp( argv[i], "-help") == 0) 717 { 718 UseMsg(); 719 exit(0); 720 } 721 else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) { 722 if (skip>0) 723 i+= skip-1; 724 else UseMsg(); 725 } 726#ifdef RLIMIT_DATA 727 else if ( strcmp( argv[i], "-ld") == 0) 728 { 729 if(++i < argc) 730 { 731 limitDataSpace = atoi(argv[i]); 732 if (limitDataSpace > 0) 733 limitDataSpace *= 1024; 734 } 735 else 736 UseMsg(); 737 } 738#endif 739#ifdef RLIMIT_NOFILE 740 else if ( strcmp( argv[i], "-lf") == 0) 741 { 742 if(++i < argc) 743 limitNoFile = atoi(argv[i]); 744 else 745 UseMsg(); 746 } 747#endif 748#ifdef RLIMIT_STACK 749 else if ( strcmp( argv[i], "-ls") == 0) 750 { 751 if(++i < argc) 752 { 753 limitStackSpace = atoi(argv[i]); 754 if (limitStackSpace > 0) 755 limitStackSpace *= 1024; 756 } 757 else 758 UseMsg(); 759 } 760#endif 761 else if ( strcmp ( argv[i], "-nolock") == 0) 762 { 763#if !defined(WIN32) && !defined(__CYGWIN__) 764 if (getuid() != 0) 765 ErrorF("Warning: the -nolock option can only be used by root\n"); 766 else 767#endif 768 nolock = TRUE; 769 } 770 else if ( strcmp( argv[i], "-nolisten") == 0) 771 { 772 if(++i < argc) { 773 if (_XSERVTransNoListen(argv[i])) 774 FatalError ("Failed to disable listen for %s transport", 775 argv[i]); 776 } else 777 UseMsg(); 778 } 779 else if ( strcmp( argv[i], "-noreset") == 0) 780 { 781 dispatchExceptionAtReset = 0; 782 } 783 else if ( strcmp( argv[i], "-reset") == 0) 784 { 785 dispatchExceptionAtReset = DE_RESET; 786 } 787 else if ( strcmp( argv[i], "-p") == 0) 788 { 789 if(++i < argc) 790 defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) * 791 MILLI_PER_MIN; 792 else 793 UseMsg(); 794 } 795 else if (strcmp(argv[i], "-pogo") == 0) 796 { 797 dispatchException = DE_TERMINATE; 798 } 799 else if ( strcmp( argv[i], "-pn") == 0) 800 PartialNetwork = TRUE; 801 else if ( strcmp( argv[i], "-nopn") == 0) 802 PartialNetwork = FALSE; 803 else if ( strcmp( argv[i], "r") == 0) 804 defaultKeyboardControl.autoRepeat = TRUE; 805 else if ( strcmp( argv[i], "-r") == 0) 806 defaultKeyboardControl.autoRepeat = FALSE; 807 else if ( strcmp( argv[i], "-retro") == 0) 808 party_like_its_1989 = TRUE; 809 else if ( strcmp( argv[i], "-noretro") == 0) 810 party_like_its_1989 = FALSE; 811 else if ( strcmp( argv[i], "-s") == 0) 812 { 813 if(++i < argc) 814 defaultScreenSaverTime = ((CARD32)atoi(argv[i])) * 815 MILLI_PER_MIN; 816 else 817 UseMsg(); 818 } 819 else if ( strcmp( argv[i], "-t") == 0) 820 { 821 if(++i < argc) 822 defaultPointerControl.threshold = atoi(argv[i]); 823 else 824 UseMsg(); 825 } 826 else if ( strcmp( argv[i], "-terminate") == 0) 827 { 828 dispatchExceptionAtReset = DE_TERMINATE; 829 } 830 else if ( strcmp( argv[i], "-to") == 0) 831 { 832 if(++i < argc) 833 TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND; 834 else 835 UseMsg(); 836 } 837 else if ( strcmp( argv[i], "-tst") == 0) 838 { 839 noTestExtensions = TRUE; 840 } 841 else if ( strcmp( argv[i], "v") == 0) 842 defaultScreenSaverBlanking = PreferBlanking; 843 else if ( strcmp( argv[i], "-v") == 0) 844 defaultScreenSaverBlanking = DontPreferBlanking; 845 else if ( strcmp( argv[i], "-wm") == 0) 846 defaultBackingStore = WhenMapped; 847 else if ( strcmp( argv[i], "-wr") == 0) 848 whiteRoot = TRUE; 849 else if ( strcmp( argv[i], "-background") == 0) { 850 if(++i < argc) { 851 if (!strcmp ( argv[i], "none")) 852 bgNoneRoot = TRUE; 853 else 854 UseMsg(); 855 } 856 } 857 else if ( strcmp( argv[i], "-maxbigreqsize") == 0) { 858 if(++i < argc) { 859 long reqSizeArg = atol(argv[i]); 860 861 /* Request size > 128MB does not make much sense... */ 862 if( reqSizeArg > 0L && reqSizeArg < 128L ) { 863 maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; 864 } 865 else 866 { 867 UseMsg(); 868 } 869 } 870 else 871 { 872 UseMsg(); 873 } 874 } 875#ifdef PANORAMIX 876 else if ( strcmp( argv[i], "+xinerama") == 0){ 877 noPanoramiXExtension = FALSE; 878 } 879 else if ( strcmp( argv[i], "-xinerama") == 0){ 880 noPanoramiXExtension = TRUE; 881 } 882 else if ( strcmp( argv[i], "-disablexineramaextension") == 0){ 883 PanoramiXExtensionDisabledHack = TRUE; 884 } 885#endif 886 else if ( strcmp( argv[i], "-I") == 0) 887 { 888 /* ignore all remaining arguments */ 889 break; 890 } 891 else if (strncmp (argv[i], "tty", 3) == 0) 892 { 893 /* init supplies us with this useless information */ 894 } 895#ifdef XDMCP 896 else if ((skip = XdmcpOptions(argc, argv, i)) != i) 897 { 898 i = skip - 1; 899 } 900#endif 901 else if ( strcmp( argv[i], "-dumbSched") == 0) 902 { 903 SmartScheduleDisable = TRUE; 904 } 905 else if ( strcmp( argv[i], "-schedInterval") == 0) 906 { 907 if (++i < argc) 908 { 909 SmartScheduleInterval = atoi(argv[i]); 910 SmartScheduleSlice = SmartScheduleInterval; 911 } 912 else 913 UseMsg(); 914 } 915 else if ( strcmp( argv[i], "-schedMax") == 0) 916 { 917 if (++i < argc) 918 { 919 SmartScheduleMaxSlice = atoi(argv[i]); 920 } 921 else 922 UseMsg(); 923 } 924 else if ( strcmp( argv[i], "-render" ) == 0) 925 { 926 if (++i < argc) 927 { 928 int policy = PictureParseCmapPolicy (argv[i]); 929 930 if (policy != PictureCmapPolicyInvalid) 931 PictureCmapPolicy = policy; 932 else 933 UseMsg (); 934 } 935 else 936 UseMsg (); 937 } 938 else if ( strcmp( argv[i], "-sigstop") == 0) 939 { 940 RunFromSigStopParent = TRUE; 941 } 942 else if ( strcmp( argv[i], "+extension") == 0) 943 { 944 if (++i < argc) 945 { 946 if (!EnableDisableExtension(argv[i], TRUE)) 947 EnableDisableExtensionError(argv[i], TRUE); 948 } 949 else 950 UseMsg(); 951 } 952 else if ( strcmp( argv[i], "-extension") == 0) 953 { 954 if (++i < argc) 955 { 956 if (!EnableDisableExtension(argv[i], FALSE)) 957 EnableDisableExtensionError(argv[i], FALSE); 958 } 959 else 960 UseMsg(); 961 } 962 else 963 { 964 ErrorF("Unrecognized option: %s\n", argv[i]); 965 UseMsg(); 966 FatalError("Unrecognized option: %s\n", argv[i]); 967 } 968 } 969} 970 971/* Implement a simple-minded font authorization scheme. The authorization 972 name is "hp-hostname-1", the contents are simply the host name. */ 973int 974set_font_authorizations(char **authorizations, int *authlen, pointer client) 975{ 976#define AUTHORIZATION_NAME "hp-hostname-1" 977#if defined(TCPCONN) || defined(STREAMSCONN) 978 static char *result = NULL; 979 static char *p = NULL; 980 981 if (p == NULL) 982 { 983 char hname[1024], *hnameptr; 984 unsigned int len; 985#if defined(IPv6) && defined(AF_INET6) 986 struct addrinfo hints, *ai = NULL; 987#else 988 struct hostent *host; 989#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 990 _Xgethostbynameparams hparams; 991#endif 992#endif 993 994 gethostname(hname, 1024); 995#if defined(IPv6) && defined(AF_INET6) 996 memset(&hints, 0, sizeof(hints)); 997 hints.ai_flags = AI_CANONNAME; 998 if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { 999 hnameptr = ai->ai_canonname; 1000 } else { 1001 hnameptr = hname; 1002 } 1003#else 1004 host = _XGethostbyname(hname, hparams); 1005 if (host == NULL) 1006 hnameptr = hname; 1007 else 1008 hnameptr = host->h_name; 1009#endif 1010 1011 len = strlen(hnameptr) + 1; 1012 result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); 1013 1014 p = result; 1015 *p++ = sizeof(AUTHORIZATION_NAME) >> 8; 1016 *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; 1017 *p++ = (len) >> 8; 1018 *p++ = (len & 0xff); 1019 1020 memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); 1021 p += sizeof(AUTHORIZATION_NAME); 1022 memmove(p, hnameptr, len); 1023 p += len; 1024#if defined(IPv6) && defined(AF_INET6) 1025 if (ai) { 1026 freeaddrinfo(ai); 1027 } 1028#endif 1029 } 1030 *authlen = p - result; 1031 *authorizations = result; 1032 return 1; 1033#else /* TCPCONN */ 1034 return 0; 1035#endif /* TCPCONN */ 1036} 1037 1038void * 1039Xalloc(unsigned long amount) 1040{ 1041 /* 1042 * Xalloc used to return NULL when large amount of memory is requested. In 1043 * order to catch the buggy callers this warning has been added, slated to 1044 * removal by anyone who touches this code (or just looks at it) in 2011. 1045 * 1046 * -- Mikhail Gusarov 1047 */ 1048 if ((long)amount <= 0) 1049 ErrorF("Warning: Xalloc: " 1050 "requesting unpleasantly large amount of memory: %lu bytes.\n", 1051 amount); 1052 1053 return malloc(amount); 1054} 1055 1056void * 1057XNFalloc(unsigned long amount) 1058{ 1059 void *ptr = malloc(amount); 1060 if (!ptr) 1061 FatalError("Out of memory"); 1062 return ptr; 1063} 1064 1065void * 1066Xcalloc(unsigned long amount) 1067{ 1068 return calloc(1, amount); 1069} 1070 1071void * 1072XNFcalloc(unsigned long amount) 1073{ 1074 void *ret = calloc(1, amount); 1075 if (!ret) 1076 FatalError("XNFcalloc: Out of memory"); 1077 return ret; 1078} 1079 1080void * 1081Xrealloc(void *ptr, unsigned long amount) 1082{ 1083 /* 1084 * Xrealloc used to return NULL when large amount of memory is requested. In 1085 * order to catch the buggy callers this warning has been added, slated to 1086 * removal by anyone who touches this code (or just looks at it) in 2011. 1087 * 1088 * -- Mikhail Gusarov 1089 */ 1090 if ((long)amount <= 0) 1091 ErrorF("Warning: Xrealloc: " 1092 "requesting unpleasantly large amount of memory: %lu bytes.\n", 1093 amount); 1094 1095 return realloc(ptr, amount); 1096} 1097 1098void * 1099XNFrealloc(void *ptr, unsigned long amount) 1100{ 1101 void *ret = realloc(ptr, amount); 1102 if (!ret) 1103 FatalError("XNFrealloc: Out of memory"); 1104 return ret; 1105} 1106 1107void 1108Xfree(void *ptr) 1109{ 1110 free(ptr); 1111} 1112 1113 1114char * 1115Xstrdup(const char *s) 1116{ 1117 if (s == NULL) 1118 return NULL; 1119 return strdup(s); 1120} 1121 1122char * 1123XNFstrdup(const char *s) 1124{ 1125 char *ret; 1126 1127 if (s == NULL) 1128 return NULL; 1129 1130 ret = strdup(s); 1131 if (!ret) 1132 FatalError("XNFstrdup: Out of memory"); 1133 return ret; 1134} 1135 1136void 1137SmartScheduleStopTimer (void) 1138{ 1139 struct itimerval timer; 1140 1141 if (SmartScheduleDisable) 1142 return; 1143 timer.it_interval.tv_sec = 0; 1144 timer.it_interval.tv_usec = 0; 1145 timer.it_value.tv_sec = 0; 1146 timer.it_value.tv_usec = 0; 1147 (void) setitimer (ITIMER_REAL, &timer, 0); 1148} 1149 1150void 1151SmartScheduleStartTimer (void) 1152{ 1153 struct itimerval timer; 1154 1155 if (SmartScheduleDisable) 1156 return; 1157 timer.it_interval.tv_sec = 0; 1158 timer.it_interval.tv_usec = SmartScheduleInterval * 1000; 1159 timer.it_value.tv_sec = 0; 1160 timer.it_value.tv_usec = SmartScheduleInterval * 1000; 1161 setitimer (ITIMER_REAL, &timer, 0); 1162} 1163 1164static void 1165SmartScheduleTimer (int sig) 1166{ 1167 SmartScheduleTime += SmartScheduleInterval; 1168} 1169 1170void 1171SmartScheduleInit (void) 1172{ 1173 struct sigaction act; 1174 1175 if (SmartScheduleDisable) 1176 return; 1177 1178 memset((char *) &act, 0, sizeof(struct sigaction)); 1179 1180 /* Set up the timer signal function */ 1181 act.sa_handler = SmartScheduleTimer; 1182 sigemptyset (&act.sa_mask); 1183 sigaddset (&act.sa_mask, SIGALRM); 1184 if (sigaction (SIGALRM, &act, 0) < 0) 1185 { 1186 perror ("sigaction for smart scheduler"); 1187 SmartScheduleDisable = TRUE; 1188 } 1189} 1190 1191#ifdef SIG_BLOCK 1192static sigset_t PreviousSignalMask; 1193static int BlockedSignalCount; 1194#endif 1195 1196void 1197OsBlockSignals (void) 1198{ 1199#ifdef SIG_BLOCK 1200 if (BlockedSignalCount++ == 0) 1201 { 1202 sigset_t set; 1203 1204 sigemptyset (&set); 1205 sigaddset (&set, SIGALRM); 1206 sigaddset (&set, SIGVTALRM); 1207#ifdef SIGWINCH 1208 sigaddset (&set, SIGWINCH); 1209#endif 1210#ifdef SIGIO 1211 sigaddset (&set, SIGIO); 1212#endif 1213 sigaddset (&set, SIGTSTP); 1214 sigaddset (&set, SIGTTIN); 1215 sigaddset (&set, SIGTTOU); 1216 sigaddset (&set, SIGCHLD); 1217 sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask); 1218 } 1219#endif 1220} 1221 1222void 1223OsReleaseSignals (void) 1224{ 1225#ifdef SIG_BLOCK 1226 if (--BlockedSignalCount == 0) 1227 { 1228 sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0); 1229 } 1230#endif 1231} 1232 1233/* 1234 * Pending signals may interfere with core dumping. Provide a 1235 * mechanism to block signals when aborting. 1236 */ 1237 1238void 1239OsAbort (void) 1240{ 1241#ifndef __APPLE__ 1242 OsBlockSignals(); 1243#endif 1244 abort(); 1245} 1246 1247#if !defined(WIN32) 1248/* 1249 * "safer" versions of system(3), popen(3) and pclose(3) which give up 1250 * all privs before running a command. 1251 * 1252 * This is based on the code in FreeBSD 2.2 libc. 1253 * 1254 * XXX It'd be good to redirect stderr so that it ends up in the log file 1255 * as well. As it is now, xkbcomp messages don't end up in the log file. 1256 */ 1257 1258int 1259System(char *command) 1260{ 1261 int pid, p; 1262 void (*csig)(int); 1263 int status; 1264 1265 if (!command) 1266 return 1; 1267 1268 csig = signal(SIGCHLD, SIG_DFL); 1269 if (csig == SIG_ERR) { 1270 perror("signal"); 1271 return -1; 1272 } 1273 DebugF("System: `%s'\n", command); 1274 1275 switch (pid = fork()) { 1276 case -1: /* error */ 1277 p = -1; 1278 case 0: /* child */ 1279 if (setgid(getgid()) == -1) 1280 _exit(127); 1281 if (setuid(getuid()) == -1) 1282 _exit(127); 1283 execl("/bin/sh", "sh", "-c", command, (char *)NULL); 1284 _exit(127); 1285 default: /* parent */ 1286 do { 1287 p = waitpid(pid, &status, 0); 1288 } while (p == -1 && errno == EINTR); 1289 1290 } 1291 1292 if (signal(SIGCHLD, csig) == SIG_ERR) { 1293 perror("signal"); 1294 return -1; 1295 } 1296 1297 return p == -1 ? -1 : status; 1298} 1299 1300static struct pid { 1301 struct pid *next; 1302 FILE *fp; 1303 int pid; 1304} *pidlist; 1305 1306OsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */ 1307 1308pointer 1309Popen(char *command, char *type) 1310{ 1311 struct pid *cur; 1312 FILE *iop; 1313 int pdes[2], pid; 1314 1315 if (command == NULL || type == NULL) 1316 return NULL; 1317 1318 if ((*type != 'r' && *type != 'w') || type[1]) 1319 return NULL; 1320 1321 if ((cur = malloc(sizeof(struct pid))) == NULL) 1322 return NULL; 1323 1324 if (pipe(pdes) < 0) { 1325 free(cur); 1326 return NULL; 1327 } 1328 1329 /* Ignore the smart scheduler while this is going on */ 1330 old_alarm = OsSignal(SIGALRM, SIG_IGN); 1331 if (old_alarm == SIG_ERR) { 1332 close(pdes[0]); 1333 close(pdes[1]); 1334 free(cur); 1335 perror("signal"); 1336 return NULL; 1337 } 1338 1339 switch (pid = fork()) { 1340 case -1: /* error */ 1341 close(pdes[0]); 1342 close(pdes[1]); 1343 free(cur); 1344 if (OsSignal(SIGALRM, old_alarm) == SIG_ERR) 1345 perror("signal"); 1346 return NULL; 1347 case 0: /* child */ 1348 if (setgid(getgid()) == -1) 1349 _exit(127); 1350 if (setuid(getuid()) == -1) 1351 _exit(127); 1352 if (*type == 'r') { 1353 if (pdes[1] != 1) { 1354 /* stdout */ 1355 dup2(pdes[1], 1); 1356 close(pdes[1]); 1357 } 1358 close(pdes[0]); 1359 } else { 1360 if (pdes[0] != 0) { 1361 /* stdin */ 1362 dup2(pdes[0], 0); 1363 close(pdes[0]); 1364 } 1365 close(pdes[1]); 1366 } 1367 execl("/bin/sh", "sh", "-c", command, (char *)NULL); 1368 _exit(127); 1369 } 1370 1371 /* Avoid EINTR during stdio calls */ 1372 OsBlockSignals (); 1373 1374 /* parent */ 1375 if (*type == 'r') { 1376 iop = fdopen(pdes[0], type); 1377 close(pdes[1]); 1378 } else { 1379 iop = fdopen(pdes[1], type); 1380 close(pdes[0]); 1381 } 1382 1383 cur->fp = iop; 1384 cur->pid = pid; 1385 cur->next = pidlist; 1386 pidlist = cur; 1387 1388 DebugF("Popen: `%s', fp = %p\n", command, iop); 1389 1390 return iop; 1391} 1392 1393/* fopen that drops privileges */ 1394pointer 1395Fopen(char *file, char *type) 1396{ 1397 FILE *iop; 1398#ifndef HAS_SAVED_IDS_AND_SETEUID 1399 struct pid *cur; 1400 int pdes[2], pid; 1401 1402 if (file == NULL || type == NULL) 1403 return NULL; 1404 1405 if ((*type != 'r' && *type != 'w') || type[1]) 1406 return NULL; 1407 1408 if ((cur = malloc(sizeof(struct pid))) == NULL) 1409 return NULL; 1410 1411 if (pipe(pdes) < 0) { 1412 free(cur); 1413 return NULL; 1414 } 1415 1416 switch (pid = fork()) { 1417 case -1: /* error */ 1418 close(pdes[0]); 1419 close(pdes[1]); 1420 free(cur); 1421 return NULL; 1422 case 0: /* child */ 1423 if (setgid(getgid()) == -1) 1424 _exit(127); 1425 if (setuid(getuid()) == -1) 1426 _exit(127); 1427 if (*type == 'r') { 1428 if (pdes[1] != 1) { 1429 /* stdout */ 1430 dup2(pdes[1], 1); 1431 close(pdes[1]); 1432 } 1433 close(pdes[0]); 1434 } else { 1435 if (pdes[0] != 0) { 1436 /* stdin */ 1437 dup2(pdes[0], 0); 1438 close(pdes[0]); 1439 } 1440 close(pdes[1]); 1441 } 1442 execl("/bin/cat", "cat", file, (char *)NULL); 1443 _exit(127); 1444 } 1445 1446 /* Avoid EINTR during stdio calls */ 1447 OsBlockSignals (); 1448 1449 /* parent */ 1450 if (*type == 'r') { 1451 iop = fdopen(pdes[0], type); 1452 close(pdes[1]); 1453 } else { 1454 iop = fdopen(pdes[1], type); 1455 close(pdes[0]); 1456 } 1457 1458 cur->fp = iop; 1459 cur->pid = pid; 1460 cur->next = pidlist; 1461 pidlist = cur; 1462 1463 DebugF("Fopen(%s), fp = %p\n", file, iop); 1464 1465 return iop; 1466#else 1467 int ruid, euid; 1468 1469 ruid = getuid(); 1470 euid = geteuid(); 1471 1472 if (seteuid(ruid) == -1) { 1473 return NULL; 1474 } 1475 iop = fopen(file, type); 1476 1477 if (seteuid(euid) == -1) { 1478 fclose(iop); 1479 return NULL; 1480 } 1481 return iop; 1482#endif /* HAS_SAVED_IDS_AND_SETEUID */ 1483} 1484 1485int 1486Pclose(pointer iop) 1487{ 1488 struct pid *cur, *last; 1489 int pstat; 1490 int pid; 1491 1492 DebugF("Pclose: fp = %p\n", iop); 1493 fclose(iop); 1494 1495 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1496 if (cur->fp == iop) 1497 break; 1498 if (cur == NULL) 1499 return -1; 1500 1501 do { 1502 pid = waitpid(cur->pid, &pstat, 0); 1503 } while (pid == -1 && errno == EINTR); 1504 1505 if (last == NULL) 1506 pidlist = cur->next; 1507 else 1508 last->next = cur->next; 1509 free(cur); 1510 1511 /* allow EINTR again */ 1512 OsReleaseSignals (); 1513 1514 if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) { 1515 perror("signal"); 1516 return -1; 1517 } 1518 1519 return pid == -1 ? -1 : pstat; 1520} 1521 1522int 1523Fclose(pointer iop) 1524{ 1525#ifdef HAS_SAVED_IDS_AND_SETEUID 1526 return fclose(iop); 1527#else 1528 return Pclose(iop); 1529#endif 1530} 1531 1532#endif /* !WIN32 */ 1533 1534 1535/* 1536 * CheckUserParameters: check for long command line arguments and long 1537 * environment variables. By default, these checks are only done when 1538 * the server's euid != ruid. In 3.3.x, these checks were done in an 1539 * external wrapper utility. 1540 */ 1541 1542/* Consider LD* variables insecure? */ 1543#ifndef REMOVE_ENV_LD 1544#define REMOVE_ENV_LD 1 1545#endif 1546 1547/* Remove long environment variables? */ 1548#ifndef REMOVE_LONG_ENV 1549#define REMOVE_LONG_ENV 1 1550#endif 1551 1552/* 1553 * Disallow stdout or stderr as pipes? It's possible to block the X server 1554 * when piping stdout+stderr to a pipe. 1555 * 1556 * Don't enable this because it looks like it's going to cause problems. 1557 */ 1558#ifndef NO_OUTPUT_PIPES 1559#define NO_OUTPUT_PIPES 0 1560#endif 1561 1562 1563/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 1564#ifndef CHECK_EUID 1565#ifndef WIN32 1566#define CHECK_EUID 1 1567#else 1568#define CHECK_EUID 0 1569#endif 1570#endif 1571 1572/* 1573 * Maybe the locale can be faked to make isprint(3) report that everything 1574 * is printable? Avoid it by default. 1575 */ 1576#ifndef USE_ISPRINT 1577#define USE_ISPRINT 0 1578#endif 1579 1580#define MAX_ARG_LENGTH 128 1581#define MAX_ENV_LENGTH 256 1582#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 1583 1584#if USE_ISPRINT 1585#include <ctype.h> 1586#define checkPrintable(c) isprint(c) 1587#else 1588#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 1589#endif 1590 1591enum BadCode { 1592 NotBad = 0, 1593 UnsafeArg, 1594 ArgTooLong, 1595 UnprintableArg, 1596 EnvTooLong, 1597 OutputIsPipe, 1598 InternalError 1599}; 1600 1601#if defined(VENDORSUPPORT) 1602#define BUGADDRESS VENDORSUPPORT 1603#elif defined(BUILDERADDR) 1604#define BUGADDRESS BUILDERADDR 1605#else 1606#define BUGADDRESS "xorg@freedesktop.org" 1607#endif 1608 1609void 1610CheckUserParameters(int argc, char **argv, char **envp) 1611{ 1612 enum BadCode bad = NotBad; 1613 int i = 0, j; 1614 char *a, *e = NULL; 1615 1616#if CHECK_EUID 1617 if (geteuid() == 0 && getuid() != geteuid()) 1618#endif 1619 { 1620 /* Check each argv[] */ 1621 for (i = 1; i < argc; i++) { 1622 if (strcmp(argv[i], "-fp") == 0) 1623 { 1624 i++; /* continue with next argument. skip the length check */ 1625 if (i >= argc) 1626 break; 1627 } else 1628 { 1629 if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1630 bad = ArgTooLong; 1631 break; 1632 } 1633 } 1634 a = argv[i]; 1635 while (*a) { 1636 if (checkPrintable(*a) == 0) { 1637 bad = UnprintableArg; 1638 break; 1639 } 1640 a++; 1641 } 1642 if (bad) 1643 break; 1644 } 1645 if (!bad) { 1646 /* Check each envp[] */ 1647 for (i = 0; envp[i]; i++) { 1648 1649 /* Check for bad environment variables and values */ 1650#if REMOVE_ENV_LD 1651 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1652 for (j = i; envp[j]; j++) { 1653 envp[j] = envp[j+1]; 1654 } 1655 } 1656#endif 1657 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 1658#if REMOVE_LONG_ENV 1659 for (j = i; envp[j]; j++) { 1660 envp[j] = envp[j+1]; 1661 } 1662 i--; 1663#else 1664 char *eq; 1665 int len; 1666 1667 eq = strchr(envp[i], '='); 1668 if (!eq) 1669 continue; 1670 len = eq - envp[i]; 1671 e = malloc(len + 1); 1672 if (!e) { 1673 bad = InternalError; 1674 break; 1675 } 1676 strncpy(e, envp[i], len); 1677 e[len] = 0; 1678 if (len >= 4 && 1679 (strcmp(e + len - 4, "PATH") == 0 || 1680 strcmp(e, "TERMCAP") == 0)) { 1681 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1682 bad = EnvTooLong; 1683 break; 1684 } else { 1685 free(e); 1686 } 1687 } else { 1688 bad = EnvTooLong; 1689 break; 1690 } 1691#endif 1692 } 1693 } 1694 } 1695#if NO_OUTPUT_PIPES 1696 if (!bad) { 1697 struct stat buf; 1698 1699 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1700 bad = OutputIsPipe; 1701 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1702 bad = OutputIsPipe; 1703 } 1704#endif 1705 } 1706 switch (bad) { 1707 case NotBad: 1708 return; 1709 case UnsafeArg: 1710 ErrorF("Command line argument number %d is unsafe\n", i); 1711 break; 1712 case ArgTooLong: 1713 ErrorF("Command line argument number %d is too long\n", i); 1714 break; 1715 case UnprintableArg: 1716 ErrorF("Command line argument number %d contains unprintable" 1717 " characters\n", i); 1718 break; 1719 case EnvTooLong: 1720 ErrorF("Environment variable `%s' is too long\n", e); 1721 break; 1722 case OutputIsPipe: 1723 ErrorF("Stdout and/or stderr is a pipe\n"); 1724 break; 1725 case InternalError: 1726 ErrorF("Internal Error\n"); 1727 break; 1728 default: 1729 ErrorF("Unknown error\n"); 1730 break; 1731 } 1732 FatalError("X server aborted because of unsafe environment\n"); 1733} 1734 1735/* 1736 * CheckUserAuthorization: check if the user is allowed to start the 1737 * X server. This usually means some sort of PAM checking, and it is 1738 * usually only done for setuid servers (uid != euid). 1739 */ 1740 1741#ifdef USE_PAM 1742#include <security/pam_appl.h> 1743#include <security/pam_misc.h> 1744#include <pwd.h> 1745#endif /* USE_PAM */ 1746 1747void 1748CheckUserAuthorization(void) 1749{ 1750#ifdef USE_PAM 1751 static struct pam_conv conv = { 1752 misc_conv, 1753 NULL 1754 }; 1755 1756 pam_handle_t *pamh = NULL; 1757 struct passwd *pw; 1758 int retval; 1759 1760 if (getuid() != geteuid()) { 1761 pw = getpwuid(getuid()); 1762 if (pw == NULL) 1763 FatalError("getpwuid() failed for uid %d\n", getuid()); 1764 1765 retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 1766 if (retval != PAM_SUCCESS) 1767 FatalError("pam_start() failed.\n" 1768 "\tMissing or mangled PAM config file or module?\n"); 1769 1770 retval = pam_authenticate(pamh, 0); 1771 if (retval != PAM_SUCCESS) { 1772 pam_end(pamh, retval); 1773 FatalError("PAM authentication failed, cannot start X server.\n" 1774 "\tPerhaps you do not have console ownership?\n"); 1775 } 1776 1777 retval = pam_acct_mgmt(pamh, 0); 1778 if (retval != PAM_SUCCESS) { 1779 pam_end(pamh, retval); 1780 FatalError("PAM authentication failed, cannot start X server.\n" 1781 "\tPerhaps you do not have console ownership?\n"); 1782 } 1783 1784 /* this is not a session, so do not do session management */ 1785 pam_end(pamh, PAM_SUCCESS); 1786 } 1787#endif 1788} 1789 1790/* 1791 * Tokenize a string into a NULL terminated array of strings. Always returns 1792 * an allocated array unless an error occurs. 1793 */ 1794char** 1795xstrtokenize(const char *str, const char *separators) 1796{ 1797 char **list, **nlist; 1798 char *tok, *tmp; 1799 unsigned num = 0, n; 1800 1801 if (!str) 1802 return NULL; 1803 list = calloc(1, sizeof(*list)); 1804 if (!list) 1805 return NULL; 1806 tmp = strdup(str); 1807 if (!tmp) 1808 goto error; 1809 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 1810 nlist = realloc(list, (num + 2) * sizeof(*list)); 1811 if (!nlist) 1812 goto error; 1813 list = nlist; 1814 list[num] = strdup(tok); 1815 if (!list[num]) 1816 goto error; 1817 list[++num] = NULL; 1818 } 1819 free(tmp); 1820 return list; 1821 1822error: 1823 free(tmp); 1824 for (n = 0; n < num; n++) 1825 free(list[n]); 1826 free(list); 1827 return NULL; 1828} 1829