1917 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1917 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 | 
						|
Copyright 1987, 1998  The Open Group
 | 
						|
 | 
						|
Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
documentation for any purpose is hereby granted without fee, provided that
 | 
						|
the above copyright notice appear in all copies and that both that
 | 
						|
copyright notice and this permission notice appear in supporting
 | 
						|
documentation.
 | 
						|
 | 
						|
The above copyright notice and this permission notice shall be included
 | 
						|
in all copies or substantial portions of the Software.
 | 
						|
 | 
						|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | 
						|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
						|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
						|
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
						|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
						|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
						|
OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
 | 
						|
Except as contained in this notice, the name of The Open Group shall
 | 
						|
not be used in advertising or otherwise to promote the sale, use or
 | 
						|
other dealings in this Software without prior written authorization
 | 
						|
from The Open Group.
 | 
						|
 | 
						|
 | 
						|
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
 | 
						|
Copyright 1994 Quarterdeck Office Systems.
 | 
						|
 | 
						|
                        All Rights Reserved
 | 
						|
 | 
						|
Permission to use, copy, modify, and distribute this software and its
 | 
						|
documentation for any purpose and without fee is hereby granted,
 | 
						|
provided that the above copyright notice appear in all copies and that
 | 
						|
both that copyright notice and this permission notice appear in
 | 
						|
supporting documentation, and that the names of Digital and
 | 
						|
Quarterdeck not be used in advertising or publicity pertaining to
 | 
						|
distribution of the software without specific, written prior
 | 
						|
permission.
 | 
						|
 | 
						|
DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
						|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
						|
FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
 | 
						|
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 | 
						|
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 | 
						|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
 | 
						|
OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef __CYGWIN__
 | 
						|
#include <stdlib.h>
 | 
						|
#include <signal.h>
 | 
						|
/*
 | 
						|
   Sigh... We really need a prototype for this to know it is stdcall,
 | 
						|
   but #include-ing <windows.h> here is not a good idea...
 | 
						|
*/
 | 
						|
__stdcall unsigned long GetTickCount(void);
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(WIN32) && !defined(__CYGWIN__)
 | 
						|
#include <X11/Xwinsock.h>
 | 
						|
#endif
 | 
						|
#include <X11/Xos.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <time.h>
 | 
						|
#if !defined(WIN32) || !defined(__MINGW32__)
 | 
						|
#include <sys/time.h>
 | 
						|
#include <sys/resource.h>
 | 
						|
#endif
 | 
						|
#include "misc.h"
 | 
						|
#include <X11/X.h>
 | 
						|
#define XSERV_t
 | 
						|
#define TRANS_SERVER
 | 
						|
#define TRANS_REOPEN
 | 
						|
#include <X11/Xtrans/Xtrans.h>
 | 
						|
#include "input.h"
 | 
						|
#include "dixfont.h"
 | 
						|
#include "osdep.h"
 | 
						|
#include "extension.h"
 | 
						|
#ifdef X_POSIX_C_SOURCE
 | 
						|
#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
 | 
						|
#include <signal.h>
 | 
						|
#undef _POSIX_C_SOURCE
 | 
						|
#else
 | 
						|
#if defined(_POSIX_SOURCE)
 | 
						|
#include <signal.h>
 | 
						|
#else
 | 
						|
#define _POSIX_SOURCE
 | 
						|
#include <signal.h>
 | 
						|
#undef _POSIX_SOURCE
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
#ifndef WIN32
 | 
						|
#include <sys/wait.h>
 | 
						|
#endif
 | 
						|
#if !defined(SYSV) && !defined(WIN32) 
 | 
						|
#include <sys/resource.h>
 | 
						|
#endif
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <ctype.h>    /* for isspace */
 | 
						|
#include <stdarg.h>
 | 
						|
 | 
						|
#include <stdlib.h>	/* for malloc() */
 | 
						|
 | 
						|
#if defined(TCPCONN) || defined(STREAMSCONN)
 | 
						|
# ifndef WIN32
 | 
						|
#  include <netdb.h>
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
 | 
						|
#include "opaque.h"
 | 
						|
 | 
						|
#include "dixstruct.h"
 | 
						|
 | 
						|
#include "xkbsrv.h"
 | 
						|
 | 
						|
#ifdef RENDER
 | 
						|
#include "picture.h"
 | 
						|
#endif
 | 
						|
 | 
						|
Bool noTestExtensions;
 | 
						|
#ifdef COMPOSITE
 | 
						|
Bool noCompositeExtension = FALSE;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef DAMAGE
 | 
						|
Bool noDamageExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef DBE
 | 
						|
Bool noDbeExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef DPMSExtension
 | 
						|
Bool noDPMSExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef GLXEXT
 | 
						|
Bool noGlxExtension = FALSE;
 | 
						|
Bool noGlxVisualInit = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef SCREENSAVER
 | 
						|
Bool noScreenSaverExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef MITSHM
 | 
						|
Bool noMITShmExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef MULTIBUFFER
 | 
						|
Bool noMultibufferExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef RANDR
 | 
						|
Bool noRRExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef RENDER
 | 
						|
Bool noRenderExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef XCSECURITY
 | 
						|
Bool noSecurityExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef RES
 | 
						|
Bool noResExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef XF86BIGFONT
 | 
						|
Bool noXFree86BigfontExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef XFreeXDGA
 | 
						|
Bool noXFree86DGAExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef XF86DRI
 | 
						|
Bool noXFree86DRIExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef XF86VIDMODE
 | 
						|
Bool noXFree86VidModeExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef XFIXES
 | 
						|
Bool noXFixesExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef PANORAMIX
 | 
						|
/* Xinerama is disabled by default unless enabled via +xinerama */
 | 
						|
Bool noPanoramiXExtension = TRUE;
 | 
						|
#endif
 | 
						|
#ifdef XSELINUX
 | 
						|
Bool noSELinuxExtension = FALSE;
 | 
						|
int selinuxEnforcingState = SELINUX_MODE_DEFAULT;
 | 
						|
#endif
 | 
						|
#ifdef XV
 | 
						|
Bool noXvExtension = FALSE;
 | 
						|
#endif
 | 
						|
#ifdef DRI2
 | 
						|
Bool noDRI2Extension = FALSE;
 | 
						|
#endif
 | 
						|
 | 
						|
Bool noGEExtension = FALSE;
 | 
						|
 | 
						|
#define X_INCLUDE_NETDB_H
 | 
						|
#include <X11/Xos_r.h>
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
Bool CoreDump;
 | 
						|
 | 
						|
#ifdef PANORAMIX
 | 
						|
Bool PanoramiXExtensionDisabledHack = FALSE;
 | 
						|
#endif
 | 
						|
 | 
						|
int auditTrailLevel = 1;
 | 
						|
 | 
						|
#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
 | 
						|
#define HAS_SAVED_IDS_AND_SETEUID
 | 
						|
#endif
 | 
						|
 | 
						|
static char *dev_tty_from_init = NULL;	/* since we need to parse it anyway */
 | 
						|
 | 
						|
OsSigHandlerPtr
 | 
						|
OsSignal(int sig, OsSigHandlerPtr handler)
 | 
						|
{
 | 
						|
    struct sigaction act, oact;
 | 
						|
 | 
						|
    sigemptyset(&act.sa_mask);
 | 
						|
    if (handler != SIG_IGN)
 | 
						|
	sigaddset(&act.sa_mask, sig);
 | 
						|
    act.sa_flags = 0;
 | 
						|
    act.sa_handler = handler;
 | 
						|
    if (sigaction(sig, &act, &oact))
 | 
						|
      perror("sigaction");
 | 
						|
    return oact.sa_handler;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Explicit support for a server lock file like the ones used for UUCP.
 | 
						|
 * For architectures with virtual terminals that can run more than one
 | 
						|
 * server at a time.  This keeps the servers from stomping on each other
 | 
						|
 * if the user forgets to give them different display numbers.
 | 
						|
 */
 | 
						|
#define LOCK_DIR "/tmp"
 | 
						|
#define LOCK_TMP_PREFIX "/.tX"
 | 
						|
#define LOCK_PREFIX "/.X"
 | 
						|
#define LOCK_SUFFIX "-lock"
 | 
						|
 | 
						|
#ifndef PATH_MAX
 | 
						|
#include <sys/param.h>
 | 
						|
#ifndef PATH_MAX
 | 
						|
#ifdef MAXPATHLEN
 | 
						|
#define PATH_MAX MAXPATHLEN
 | 
						|
#else
 | 
						|
#define PATH_MAX 1024
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
static Bool StillLocking = FALSE;
 | 
						|
static char LockFile[PATH_MAX];
 | 
						|
static Bool nolock = FALSE;
 | 
						|
 | 
						|
/*
 | 
						|
 * LockServer --
 | 
						|
 *      Check if the server lock file exists.  If so, check if the PID
 | 
						|
 *      contained inside is valid.  If so, then die.  Otherwise, create
 | 
						|
 *      the lock file containing the PID.
 | 
						|
 */
 | 
						|
void
 | 
						|
LockServer(void)
 | 
						|
{
 | 
						|
  char tmp[PATH_MAX], pid_str[12];
 | 
						|
  int lfd, i, haslock, l_pid, t;
 | 
						|
  char *tmppath = NULL;
 | 
						|
  int len;
 | 
						|
  char port[20];
 | 
						|
 | 
						|
  if (nolock) return;
 | 
						|
  /*
 | 
						|
   * Path names
 | 
						|
   */
 | 
						|
  tmppath = LOCK_DIR;
 | 
						|
 | 
						|
  sprintf(port, "%d", atoi(display));
 | 
						|
  len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
 | 
						|
						strlen(LOCK_TMP_PREFIX);
 | 
						|
  len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
 | 
						|
  if (len > sizeof(LockFile))
 | 
						|
    FatalError("Display name `%s' is too long\n", port);
 | 
						|
  (void)sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
 | 
						|
  (void)sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
 | 
						|
 | 
						|
  /*
 | 
						|
   * Create a temporary file containing our PID.  Attempt three times
 | 
						|
   * to create the file.
 | 
						|
   */
 | 
						|
  StillLocking = TRUE;
 | 
						|
  i = 0;
 | 
						|
  do {
 | 
						|
    i++;
 | 
						|
    lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
 | 
						|
    if (lfd < 0)
 | 
						|
       sleep(2);
 | 
						|
    else
 | 
						|
       break;
 | 
						|
  } while (i < 3);
 | 
						|
  if (lfd < 0) {
 | 
						|
    unlink(tmp);
 | 
						|
    i = 0;
 | 
						|
    do {
 | 
						|
      i++;
 | 
						|
      lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
 | 
						|
      if (lfd < 0)
 | 
						|
         sleep(2);
 | 
						|
      else
 | 
						|
         break;
 | 
						|
    } while (i < 3);
 | 
						|
  }
 | 
						|
  if (lfd < 0)
 | 
						|
    FatalError("Could not create lock file in %s\n", tmp);
 | 
						|
  (void) sprintf(pid_str, "%10ld\n", (long)getpid());
 | 
						|
  (void) write(lfd, pid_str, 11);
 | 
						|
  (void) chmod(tmp, 0444);
 | 
						|
  (void) close(lfd);
 | 
						|
 | 
						|
  /*
 | 
						|
   * OK.  Now the tmp file exists.  Try three times to move it in place
 | 
						|
   * for the lock.
 | 
						|
   */
 | 
						|
  i = 0;
 | 
						|
  haslock = 0;
 | 
						|
  while ((!haslock) && (i++ < 3)) {
 | 
						|
    haslock = (link(tmp,LockFile) == 0);
 | 
						|
    if (haslock) {
 | 
						|
      /*
 | 
						|
       * We're done.
 | 
						|
       */
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      /*
 | 
						|
       * Read the pid from the existing file
 | 
						|
       */
 | 
						|
      lfd = open(LockFile, O_RDONLY);
 | 
						|
      if (lfd < 0) {
 | 
						|
        unlink(tmp);
 | 
						|
        FatalError("Can't read lock file %s\n", LockFile);
 | 
						|
      }
 | 
						|
      pid_str[0] = '\0';
 | 
						|
      if (read(lfd, pid_str, 11) != 11) {
 | 
						|
        /*
 | 
						|
         * Bogus lock file.
 | 
						|
         */
 | 
						|
        unlink(LockFile);
 | 
						|
        close(lfd);
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      pid_str[11] = '\0';
 | 
						|
      sscanf(pid_str, "%d", &l_pid);
 | 
						|
      close(lfd);
 | 
						|
 | 
						|
      /*
 | 
						|
       * Now try to kill the PID to see if it exists.
 | 
						|
       */
 | 
						|
      errno = 0;
 | 
						|
      t = kill(l_pid, 0);
 | 
						|
      if ((t< 0) && (errno == ESRCH)) {
 | 
						|
        /*
 | 
						|
         * Stale lock file.
 | 
						|
         */
 | 
						|
        unlink(LockFile);
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
 | 
						|
        /*
 | 
						|
         * Process is still active.
 | 
						|
         */
 | 
						|
        unlink(tmp);
 | 
						|
	FatalError("Server is already active for display %s\n%s %s\n%s\n",
 | 
						|
		   port, "\tIf this server is no longer running, remove",
 | 
						|
		   LockFile, "\tand start again.");
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  unlink(tmp);
 | 
						|
  if (!haslock)
 | 
						|
    FatalError("Could not create server lock file: %s\n", LockFile);
 | 
						|
  StillLocking = FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * UnlockServer --
 | 
						|
 *      Remove the server lock file.
 | 
						|
 */
 | 
						|
void
 | 
						|
UnlockServer(void)
 | 
						|
{
 | 
						|
  if (nolock) return;
 | 
						|
 | 
						|
  if (!StillLocking){
 | 
						|
 | 
						|
  (void) unlink(LockFile);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Force connections to close on SIGHUP from init */
 | 
						|
 | 
						|
void
 | 
						|
AutoResetServer (int sig)
 | 
						|
{
 | 
						|
    int olderrno = errno;
 | 
						|
 | 
						|
    dispatchException |= DE_RESET;
 | 
						|
    isItTimeToYield = TRUE;
 | 
						|
    errno = olderrno;
 | 
						|
}
 | 
						|
 | 
						|
/* Force connections to close and then exit on SIGTERM, SIGINT */
 | 
						|
 | 
						|
void
 | 
						|
GiveUp(int sig)
 | 
						|
{
 | 
						|
    int olderrno = errno;
 | 
						|
 | 
						|
    dispatchException |= DE_TERMINATE;
 | 
						|
    isItTimeToYield = TRUE;
 | 
						|
    errno = olderrno;
 | 
						|
}
 | 
						|
 | 
						|
#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
 | 
						|
CARD32
 | 
						|
GetTimeInMillis (void)
 | 
						|
{
 | 
						|
  return GetTickCount ();
 | 
						|
}
 | 
						|
#else
 | 
						|
CARD32
 | 
						|
GetTimeInMillis(void)
 | 
						|
{
 | 
						|
    struct timeval tv;
 | 
						|
 | 
						|
#ifdef MONOTONIC_CLOCK
 | 
						|
    struct timespec tp;
 | 
						|
    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
 | 
						|
        return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
 | 
						|
#endif
 | 
						|
 | 
						|
    X_GETTIMEOFDAY(&tv);
 | 
						|
    return(tv.tv_sec * 1000) + (tv.tv_usec / 1000);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
void
 | 
						|
AdjustWaitForDelay (pointer waitTime, unsigned long newdelay)
 | 
						|
{
 | 
						|
    static struct timeval   delay_val;
 | 
						|
    struct timeval	    **wt = (struct timeval **) waitTime;
 | 
						|
    unsigned long	    olddelay;
 | 
						|
 | 
						|
    if (*wt == NULL)
 | 
						|
    {
 | 
						|
	delay_val.tv_sec = newdelay / 1000;
 | 
						|
	delay_val.tv_usec = 1000 * (newdelay % 1000);
 | 
						|
	*wt = &delay_val;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
 | 
						|
	if (newdelay < olddelay)
 | 
						|
	{
 | 
						|
	    (*wt)->tv_sec = newdelay / 1000;
 | 
						|
	    (*wt)->tv_usec = 1000 * (newdelay % 1000);
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void UseMsg(void)
 | 
						|
{
 | 
						|
    ErrorF("use: X [:<display>] [option]\n");
 | 
						|
    ErrorF("-a #                   mouse acceleration (pixels)\n");
 | 
						|
    ErrorF("-ac                    disable access control restrictions\n");
 | 
						|
    ErrorF("-audit int             set audit trail level\n");	
 | 
						|
    ErrorF("-auth file             select authorization file\n");	
 | 
						|
    ErrorF("-br                    create root window with black background\n");
 | 
						|
    ErrorF("+bs                    enable any backing store support\n");
 | 
						|
    ErrorF("-bs                    disable any backing store support\n");
 | 
						|
    ErrorF("-c                     turns off key-click\n");
 | 
						|
    ErrorF("c #                    key-click volume (0-100)\n");
 | 
						|
    ErrorF("-cc int                default color visual class\n");
 | 
						|
    ErrorF("-core                  generate core dump on fatal error\n");
 | 
						|
    ErrorF("-dpi int               screen resolution in dots per inch\n");
 | 
						|
#ifdef DPMSExtension
 | 
						|
    ErrorF("-dpms                  disables VESA DPMS monitor control\n");
 | 
						|
#endif
 | 
						|
    ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
 | 
						|
    ErrorF("-f #                   bell base (0-100)\n");
 | 
						|
    ErrorF("-fc string             cursor font\n");
 | 
						|
    ErrorF("-fn string             default font name\n");
 | 
						|
    ErrorF("-fp string             default font path\n");
 | 
						|
    ErrorF("-help                  prints message with these options\n");
 | 
						|
    ErrorF("-I                     ignore all remaining arguments\n");
 | 
						|
#ifdef RLIMIT_DATA
 | 
						|
    ErrorF("-ld int                limit data space to N Kb\n");
 | 
						|
#endif
 | 
						|
#ifdef RLIMIT_NOFILE
 | 
						|
    ErrorF("-lf int                limit number of open files to N\n");
 | 
						|
#endif
 | 
						|
#ifdef RLIMIT_STACK
 | 
						|
    ErrorF("-ls int                limit stack space to N Kb\n");
 | 
						|
#endif
 | 
						|
#ifdef SERVER_LOCK
 | 
						|
    ErrorF("-nolock                disable the locking mechanism\n");
 | 
						|
#endif
 | 
						|
#ifndef NOLOGOHACK
 | 
						|
    ErrorF("-logo                  enable logo in screen saver\n");
 | 
						|
    ErrorF("nologo                 disable logo in screen saver\n");
 | 
						|
#endif
 | 
						|
    ErrorF("-nolisten string       don't listen on protocol\n");
 | 
						|
    ErrorF("-noreset               don't reset after last client exists\n");
 | 
						|
    ErrorF("-reset                 reset after last client exists\n");
 | 
						|
    ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
 | 
						|
    ErrorF("-pn                    accept failure to listen on all ports\n");
 | 
						|
    ErrorF("-nopn                  reject failure to listen on all ports\n");
 | 
						|
    ErrorF("-r                     turns off auto-repeat\n");
 | 
						|
    ErrorF("r                      turns on auto-repeat \n");
 | 
						|
#ifdef RENDER
 | 
						|
    ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
 | 
						|
#endif
 | 
						|
    ErrorF("-retro                 start with classic stipple and cursor\n");
 | 
						|
    ErrorF("-s #                   screen-saver timeout (minutes)\n");
 | 
						|
    ErrorF("-t #                   mouse threshold (pixels)\n");
 | 
						|
    ErrorF("-terminate             terminate at server reset\n");
 | 
						|
    ErrorF("-to #                  connection time out\n");
 | 
						|
    ErrorF("-tst                   disable testing extensions\n");
 | 
						|
    ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
 | 
						|
    ErrorF("v                      video blanking for screen-saver\n");
 | 
						|
    ErrorF("-v                     screen-saver without video blanking\n");
 | 
						|
    ErrorF("-wm                    WhenMapped default backing-store\n");
 | 
						|
    ErrorF("-wr                    create root window with white background\n");
 | 
						|
    ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
 | 
						|
#ifdef PANORAMIX
 | 
						|
    ErrorF("+xinerama              Enable XINERAMA extension\n");
 | 
						|
    ErrorF("-xinerama              Disable XINERAMA extension\n");
 | 
						|
#endif
 | 
						|
    ErrorF("-dumbSched             Disable smart scheduling, enable old behavior\n");
 | 
						|
    ErrorF("-schedInterval int     Set scheduler interval in msec\n");
 | 
						|
    ErrorF("+extension name        Enable extension\n");
 | 
						|
    ErrorF("-extension name        Disable extension\n");
 | 
						|
#ifdef XDMCP
 | 
						|
    XdmcpUseMsg();
 | 
						|
#endif
 | 
						|
    XkbUseMsg();
 | 
						|
    ddxUseMsg();
 | 
						|
}
 | 
						|
 | 
						|
/*  This function performs a rudimentary sanity check
 | 
						|
 *  on the display name passed in on the command-line,
 | 
						|
 *  since this string is used to generate filenames.
 | 
						|
 *  It is especially important that the display name
 | 
						|
 *  not contain a "/" and not start with a "-".
 | 
						|
 *                                            --kvajk
 | 
						|
 */
 | 
						|
static int 
 | 
						|
VerifyDisplayName(const char *d)
 | 
						|
{
 | 
						|
    if ( d == (char *)0 ) return( 0 );  /*  null  */
 | 
						|
    if ( *d == '\0' ) return( 0 );  /*  empty  */
 | 
						|
    if ( *d == '-' ) return( 0 );  /*  could be confused for an option  */
 | 
						|
    if ( *d == '.' ) return( 0 );  /*  must not equal "." or ".."  */
 | 
						|
    if ( strchr(d, '/') != (char *)0 ) return( 0 );  /*  very important!!!  */
 | 
						|
    return( 1 );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This function parses the command line. Handles device-independent fields
 | 
						|
 * and allows ddx to handle additional fields.  It is not allowed to modify
 | 
						|
 * argc or any of the strings pointed to by argv.
 | 
						|
 */
 | 
						|
void
 | 
						|
ProcessCommandLine(int argc, char *argv[])
 | 
						|
{
 | 
						|
    int i, skip;
 | 
						|
 | 
						|
    defaultKeyboardControl.autoRepeat = TRUE;
 | 
						|
 | 
						|
#ifdef NO_PART_NET
 | 
						|
    PartialNetwork = FALSE;
 | 
						|
#else
 | 
						|
    PartialNetwork = TRUE;
 | 
						|
#endif
 | 
						|
 | 
						|
    for ( i = 1; i < argc; i++ )
 | 
						|
    {
 | 
						|
	/* call ddx first, so it can peek/override if it wants */
 | 
						|
        if((skip = ddxProcessArgument(argc, argv, i)))
 | 
						|
	{
 | 
						|
	    i += (skip - 1);
 | 
						|
	}
 | 
						|
	else if(argv[i][0] ==  ':')  
 | 
						|
	{
 | 
						|
	    /* initialize display */
 | 
						|
	    display = argv[i];
 | 
						|
	    display++;
 | 
						|
            if( ! VerifyDisplayName( display ) ) {
 | 
						|
                ErrorF("Bad display name: %s\n", display);
 | 
						|
                UseMsg();
 | 
						|
		FatalError("Bad display name, exiting: %s\n", display);
 | 
						|
            }
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-a") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultPointerControl.num = atoi(argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-ac") == 0)
 | 
						|
	{
 | 
						|
	    defeatAccessControl = TRUE;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-audit") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        auditTrailLevel = atoi(argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-auth") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        InitAuthorization (argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-br") == 0) ; /* default */
 | 
						|
	else if ( strcmp( argv[i], "+bs") == 0)
 | 
						|
	    enableBackingStore = TRUE;
 | 
						|
	else if ( strcmp( argv[i], "-bs") == 0)
 | 
						|
	    disableBackingStore = TRUE;
 | 
						|
	else if ( strcmp( argv[i], "c") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultKeyboardControl.click = atoi(argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-c") == 0)
 | 
						|
	{
 | 
						|
	    defaultKeyboardControl.click = 0;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-cc") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultColorVisualClass = atoi(argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-core") == 0)
 | 
						|
	{
 | 
						|
#if !defined(WIN32) || !defined(__MINGW32__)
 | 
						|
	    struct rlimit   core_limit;
 | 
						|
	    getrlimit (RLIMIT_CORE, &core_limit);
 | 
						|
	    core_limit.rlim_cur = core_limit.rlim_max;
 | 
						|
	    setrlimit (RLIMIT_CORE, &core_limit);
 | 
						|
#endif
 | 
						|
	    CoreDump = TRUE;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-dpi") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        monitorResolution = atoi(argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
#ifdef DPMSExtension
 | 
						|
	else if ( strcmp( argv[i], "dpms") == 0)
 | 
						|
	    /* ignored for compatibility */ ;
 | 
						|
	else if ( strcmp( argv[i], "-dpms") == 0)
 | 
						|
	    DPMSDisabledSwitch = TRUE;
 | 
						|
#endif
 | 
						|
	else if ( strcmp( argv[i], "-deferglyphs") == 0)
 | 
						|
	{
 | 
						|
	    if(++i >= argc || !ParseGlyphCachingMode(argv[i]))
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-f") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultKeyboardControl.bell = atoi(argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-fc") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultCursorFont = argv[i];
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-fn") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultTextFont = argv[i];
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-fp") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	    {
 | 
						|
	        defaultFontPath = argv[i];
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-help") == 0)
 | 
						|
	{
 | 
						|
	    UseMsg();
 | 
						|
	    exit(0);
 | 
						|
	}
 | 
						|
        else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) {
 | 
						|
	    if (skip>0)
 | 
						|
		 i+= skip-1;
 | 
						|
	    else UseMsg();
 | 
						|
	}
 | 
						|
#ifdef RLIMIT_DATA
 | 
						|
	else if ( strcmp( argv[i], "-ld") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	    {
 | 
						|
	        limitDataSpace = atoi(argv[i]);
 | 
						|
		if (limitDataSpace > 0)
 | 
						|
		    limitDataSpace *= 1024;
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef RLIMIT_NOFILE
 | 
						|
	else if ( strcmp( argv[i], "-lf") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        limitNoFile = atoi(argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef RLIMIT_STACK
 | 
						|
	else if ( strcmp( argv[i], "-ls") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	    {
 | 
						|
	        limitStackSpace = atoi(argv[i]);
 | 
						|
		if (limitStackSpace > 0)
 | 
						|
		    limitStackSpace *= 1024;
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef SERVER_LOCK
 | 
						|
	else if ( strcmp ( argv[i], "-nolock") == 0)
 | 
						|
	{
 | 
						|
#if !defined(WIN32) && !defined(__CYGWIN__)
 | 
						|
	  if (getuid() != 0)
 | 
						|
	    ErrorF("Warning: the -nolock option can only be used by root\n");
 | 
						|
	  else
 | 
						|
#endif
 | 
						|
	    nolock = TRUE;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifndef NOLOGOHACK
 | 
						|
	else if ( strcmp( argv[i], "-logo") == 0)
 | 
						|
	{
 | 
						|
	    logoScreenSaver = 1;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "nologo") == 0)
 | 
						|
	{
 | 
						|
	    logoScreenSaver = 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	else if ( strcmp( argv[i], "-nolisten") == 0)
 | 
						|
	{
 | 
						|
            if(++i < argc) {
 | 
						|
		if (_XSERVTransNoListen(argv[i])) 
 | 
						|
		    FatalError ("Failed to disable listen for %s transport",
 | 
						|
				argv[i]);
 | 
						|
	   } else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-noreset") == 0)
 | 
						|
	{
 | 
						|
	    dispatchExceptionAtReset = 0;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-reset") == 0)
 | 
						|
	{
 | 
						|
	    dispatchExceptionAtReset = DE_RESET;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-p") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) *
 | 
						|
					     MILLI_PER_MIN;
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if (strcmp(argv[i], "-pogo") == 0)
 | 
						|
	{
 | 
						|
	    dispatchException = DE_TERMINATE;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-pn") == 0)
 | 
						|
	    PartialNetwork = TRUE;
 | 
						|
	else if ( strcmp( argv[i], "-nopn") == 0)
 | 
						|
	    PartialNetwork = FALSE;
 | 
						|
	else if ( strcmp( argv[i], "r") == 0)
 | 
						|
	    defaultKeyboardControl.autoRepeat = TRUE;
 | 
						|
	else if ( strcmp( argv[i], "-r") == 0)
 | 
						|
	    defaultKeyboardControl.autoRepeat = FALSE;
 | 
						|
	else if ( strcmp( argv[i], "-retro") == 0)
 | 
						|
	    party_like_its_1989 = TRUE;
 | 
						|
	else if ( strcmp( argv[i], "-s") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultScreenSaverTime = ((CARD32)atoi(argv[i])) *
 | 
						|
					 MILLI_PER_MIN;
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-t") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
	        defaultPointerControl.threshold = atoi(argv[i]);
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-terminate") == 0)
 | 
						|
	{
 | 
						|
	    dispatchExceptionAtReset = DE_TERMINATE;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-to") == 0)
 | 
						|
	{
 | 
						|
	    if(++i < argc)
 | 
						|
		TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND;
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-tst") == 0)
 | 
						|
	{
 | 
						|
	    noTestExtensions = TRUE;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "v") == 0)
 | 
						|
	    defaultScreenSaverBlanking = PreferBlanking;
 | 
						|
	else if ( strcmp( argv[i], "-v") == 0)
 | 
						|
	    defaultScreenSaverBlanking = DontPreferBlanking;
 | 
						|
	else if ( strcmp( argv[i], "-wm") == 0)
 | 
						|
	    defaultBackingStore = WhenMapped;
 | 
						|
        else if ( strcmp( argv[i], "-wr") == 0)
 | 
						|
            whiteRoot = TRUE;
 | 
						|
        else if ( strcmp( argv[i], "-maxbigreqsize") == 0) {
 | 
						|
             if(++i < argc) {
 | 
						|
                 long reqSizeArg = atol(argv[i]);
 | 
						|
 | 
						|
                 /* Request size > 128MB does not make much sense... */
 | 
						|
                 if( reqSizeArg > 0L && reqSizeArg < 128L ) {
 | 
						|
                     maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
 | 
						|
                 }
 | 
						|
                 else
 | 
						|
                 {
 | 
						|
                     UseMsg();
 | 
						|
                 }
 | 
						|
             }
 | 
						|
             else
 | 
						|
             {
 | 
						|
                 UseMsg();
 | 
						|
             }
 | 
						|
         }
 | 
						|
#ifdef PANORAMIX
 | 
						|
	else if ( strcmp( argv[i], "+xinerama") == 0){
 | 
						|
	    noPanoramiXExtension = FALSE;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-xinerama") == 0){
 | 
						|
	    noPanoramiXExtension = TRUE;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-disablexineramaextension") == 0){
 | 
						|
	    PanoramiXExtensionDisabledHack = TRUE;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	else if ( strcmp( argv[i], "-I") == 0)
 | 
						|
	{
 | 
						|
	    /* ignore all remaining arguments */
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
	else if (strncmp (argv[i], "tty", 3) == 0)
 | 
						|
	{
 | 
						|
	    /* just in case any body is interested */
 | 
						|
	    dev_tty_from_init = argv[i];
 | 
						|
	}
 | 
						|
#ifdef XDMCP
 | 
						|
	else if ((skip = XdmcpOptions(argc, argv, i)) != i)
 | 
						|
	{
 | 
						|
	    i = skip - 1;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	else if ( strcmp( argv[i], "-dumbSched") == 0)
 | 
						|
	{
 | 
						|
	    SmartScheduleDisable = TRUE;
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-schedInterval") == 0)
 | 
						|
	{
 | 
						|
	    if (++i < argc)
 | 
						|
	    {
 | 
						|
		SmartScheduleInterval = atoi(argv[i]);
 | 
						|
		SmartScheduleSlice = SmartScheduleInterval;
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-schedMax") == 0)
 | 
						|
	{
 | 
						|
	    if (++i < argc)
 | 
						|
	    {
 | 
						|
		SmartScheduleMaxSlice = atoi(argv[i]);
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
#ifdef RENDER
 | 
						|
	else if ( strcmp( argv[i], "-render" ) == 0)
 | 
						|
	{
 | 
						|
	    if (++i < argc)
 | 
						|
	    {
 | 
						|
		int policy = PictureParseCmapPolicy (argv[i]);
 | 
						|
 | 
						|
		if (policy != PictureCmapPolicyInvalid)
 | 
						|
		    PictureCmapPolicy = policy;
 | 
						|
		else
 | 
						|
		    UseMsg ();
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		UseMsg ();
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	else if ( strcmp( argv[i], "+extension") == 0)
 | 
						|
	{
 | 
						|
	    if (++i < argc)
 | 
						|
	    {
 | 
						|
		if (!EnableDisableExtension(argv[i], TRUE))
 | 
						|
		    EnableDisableExtensionError(argv[i], TRUE);
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
	else if ( strcmp( argv[i], "-extension") == 0)
 | 
						|
	{
 | 
						|
	    if (++i < argc)
 | 
						|
	    {
 | 
						|
		if (!EnableDisableExtension(argv[i], FALSE))
 | 
						|
		    EnableDisableExtensionError(argv[i], FALSE);
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		UseMsg();
 | 
						|
	}
 | 
						|
 	else
 | 
						|
 	{
 | 
						|
	    ErrorF("Unrecognized option: %s\n", argv[i]);
 | 
						|
	    UseMsg();
 | 
						|
	    FatalError("Unrecognized option: %s\n", argv[i]);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Implement a simple-minded font authorization scheme.  The authorization
 | 
						|
   name is "hp-hostname-1", the contents are simply the host name. */
 | 
						|
int
 | 
						|
set_font_authorizations(char **authorizations, int *authlen, pointer client)
 | 
						|
{
 | 
						|
#define AUTHORIZATION_NAME "hp-hostname-1"
 | 
						|
#if defined(TCPCONN) || defined(STREAMSCONN)
 | 
						|
    static char *result = NULL;
 | 
						|
    static char *p = NULL;
 | 
						|
 | 
						|
    if (p == NULL)
 | 
						|
    {
 | 
						|
	char hname[1024], *hnameptr;
 | 
						|
	unsigned int len;
 | 
						|
#if defined(IPv6) && defined(AF_INET6)
 | 
						|
	struct addrinfo hints, *ai = NULL;
 | 
						|
#else
 | 
						|
	struct hostent *host;
 | 
						|
#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
 | 
						|
	_Xgethostbynameparams hparams;
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
	gethostname(hname, 1024);
 | 
						|
#if defined(IPv6) && defined(AF_INET6)
 | 
						|
	bzero(&hints, sizeof(hints));
 | 
						|
	hints.ai_flags = AI_CANONNAME;
 | 
						|
	if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
 | 
						|
	    hnameptr = ai->ai_canonname;
 | 
						|
	} else {
 | 
						|
	    hnameptr = hname;
 | 
						|
	}
 | 
						|
#else
 | 
						|
	host = _XGethostbyname(hname, hparams);
 | 
						|
	if (host == NULL)
 | 
						|
	    hnameptr = hname;
 | 
						|
	else
 | 
						|
	    hnameptr = host->h_name;
 | 
						|
#endif
 | 
						|
 | 
						|
	len = strlen(hnameptr) + 1;
 | 
						|
	result = xalloc(len + sizeof(AUTHORIZATION_NAME) + 4);
 | 
						|
 | 
						|
	p = result;
 | 
						|
        *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
 | 
						|
        *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
 | 
						|
        *p++ = (len) >> 8;
 | 
						|
        *p++ = (len & 0xff);
 | 
						|
 | 
						|
	memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
 | 
						|
	p += sizeof(AUTHORIZATION_NAME);
 | 
						|
	memmove(p, hnameptr, len);
 | 
						|
	p += len;
 | 
						|
#if defined(IPv6) && defined(AF_INET6)
 | 
						|
	if (ai) {
 | 
						|
	    freeaddrinfo(ai);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    *authlen = p - result;
 | 
						|
    *authorizations = result;
 | 
						|
    return 1;
 | 
						|
#else /* TCPCONN */
 | 
						|
    return 0;
 | 
						|
#endif /* TCPCONN */
 | 
						|
}
 | 
						|
 | 
						|
#ifndef INTERNAL_MALLOC
 | 
						|
 | 
						|
void *
 | 
						|
Xalloc(unsigned long amount)
 | 
						|
{
 | 
						|
    void *ptr;
 | 
						|
 | 
						|
    if ((long)amount <= 0) {
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    /* aligned extra on long word boundary */
 | 
						|
    amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
 | 
						|
    ptr = malloc(amount);
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
 | 
						|
/*****************
 | 
						|
 * XNFalloc 
 | 
						|
 * "no failure" realloc
 | 
						|
 *****************/
 | 
						|
 | 
						|
void *
 | 
						|
XNFalloc(unsigned long amount)
 | 
						|
{
 | 
						|
    void *ptr;
 | 
						|
 | 
						|
    if ((long)amount <= 0)
 | 
						|
        return NULL;
 | 
						|
    /* aligned extra on long word boundary */
 | 
						|
    amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
 | 
						|
    ptr = malloc(amount);
 | 
						|
    if (!ptr)
 | 
						|
        FatalError("Out of memory");
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
 | 
						|
/*****************
 | 
						|
 * Xcalloc
 | 
						|
 *****************/
 | 
						|
 | 
						|
void *
 | 
						|
Xcalloc(unsigned long amount)
 | 
						|
{
 | 
						|
    void *ret;
 | 
						|
 | 
						|
    ret = Xalloc (amount);
 | 
						|
    if (ret)
 | 
						|
	bzero (ret, (int) amount);
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
/*****************
 | 
						|
 * XNFcalloc
 | 
						|
 *****************/
 | 
						|
 | 
						|
void *
 | 
						|
XNFcalloc(unsigned long amount)
 | 
						|
{
 | 
						|
    void *ret;
 | 
						|
 | 
						|
    ret = Xalloc (amount);
 | 
						|
    if (ret)
 | 
						|
	bzero (ret, (int) amount);
 | 
						|
    else if ((long)amount > 0)
 | 
						|
        FatalError("Out of memory");
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
/*****************
 | 
						|
 * Xrealloc
 | 
						|
 *****************/
 | 
						|
 | 
						|
void *
 | 
						|
Xrealloc(pointer ptr, unsigned long amount)
 | 
						|
{
 | 
						|
    if ((long)amount <= 0)
 | 
						|
    {
 | 
						|
	if (ptr && !amount)
 | 
						|
	    free(ptr);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
 | 
						|
    if (ptr)
 | 
						|
        ptr = realloc(ptr, amount);
 | 
						|
    else
 | 
						|
	ptr = malloc(amount);
 | 
						|
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
                    
 | 
						|
/*****************
 | 
						|
 * XNFrealloc 
 | 
						|
 * "no failure" realloc
 | 
						|
 *****************/
 | 
						|
 | 
						|
void *
 | 
						|
XNFrealloc(pointer ptr, unsigned long amount)
 | 
						|
{
 | 
						|
    if ((ptr = Xrealloc(ptr, amount)) == NULL)
 | 
						|
    {
 | 
						|
	if ((long)amount > 0)
 | 
						|
            FatalError( "Out of memory" );
 | 
						|
    }
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
 | 
						|
/*****************
 | 
						|
 *  Xfree
 | 
						|
 *    calls free 
 | 
						|
 *****************/    
 | 
						|
 | 
						|
void
 | 
						|
Xfree(pointer ptr)
 | 
						|
{
 | 
						|
    if (ptr)
 | 
						|
	free(ptr); 
 | 
						|
}
 | 
						|
#endif /* !INTERNAL_MALLOC */
 | 
						|
 | 
						|
 | 
						|
char *
 | 
						|
Xstrdup(const char *s)
 | 
						|
{
 | 
						|
    char *sd;
 | 
						|
 | 
						|
    if (s == NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    sd = Xalloc(strlen(s) + 1);
 | 
						|
    if (sd != NULL)
 | 
						|
	strcpy(sd, s);
 | 
						|
    return sd;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
char *
 | 
						|
XNFstrdup(const char *s)
 | 
						|
{
 | 
						|
    char *sd;
 | 
						|
 | 
						|
    if (s == NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    sd = XNFalloc(strlen(s) + 1);
 | 
						|
    strcpy(sd, s);
 | 
						|
    return sd;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef SIGVTALRM
 | 
						|
#define SMART_SCHEDULE_POSSIBLE
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef SMART_SCHEDULE_POSSIBLE
 | 
						|
#define SMART_SCHEDULE_SIGNAL		SIGALRM
 | 
						|
#define SMART_SCHEDULE_TIMER		ITIMER_REAL
 | 
						|
#endif
 | 
						|
 | 
						|
void
 | 
						|
SmartScheduleStopTimer (void)
 | 
						|
{
 | 
						|
#ifdef SMART_SCHEDULE_POSSIBLE
 | 
						|
    struct itimerval	timer;
 | 
						|
    
 | 
						|
    if (SmartScheduleDisable)
 | 
						|
	return;
 | 
						|
    timer.it_interval.tv_sec = 0;
 | 
						|
    timer.it_interval.tv_usec = 0;
 | 
						|
    timer.it_value.tv_sec = 0;
 | 
						|
    timer.it_value.tv_usec = 0;
 | 
						|
    (void) setitimer (ITIMER_REAL, &timer, 0);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
SmartScheduleStartTimer (void)
 | 
						|
{
 | 
						|
#ifdef SMART_SCHEDULE_POSSIBLE
 | 
						|
    struct itimerval	timer;
 | 
						|
    
 | 
						|
    if (SmartScheduleDisable)
 | 
						|
	return;
 | 
						|
    timer.it_interval.tv_sec = 0;
 | 
						|
    timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
 | 
						|
    timer.it_value.tv_sec = 0;
 | 
						|
    timer.it_value.tv_usec = SmartScheduleInterval * 1000;
 | 
						|
    setitimer (ITIMER_REAL, &timer, 0);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#ifdef SMART_SCHEDULE_POSSIBLE
 | 
						|
static void
 | 
						|
SmartScheduleTimer (int sig)
 | 
						|
{
 | 
						|
    SmartScheduleTime += SmartScheduleInterval;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
Bool
 | 
						|
SmartScheduleInit (void)
 | 
						|
{
 | 
						|
#ifdef SMART_SCHEDULE_POSSIBLE
 | 
						|
    struct sigaction	act;
 | 
						|
 | 
						|
    if (SmartScheduleDisable)
 | 
						|
	return TRUE;
 | 
						|
    
 | 
						|
    bzero ((char *) &act, sizeof(struct sigaction));
 | 
						|
 | 
						|
    /* Set up the timer signal function */
 | 
						|
    act.sa_handler = SmartScheduleTimer;
 | 
						|
    sigemptyset (&act.sa_mask);
 | 
						|
    sigaddset (&act.sa_mask, SMART_SCHEDULE_SIGNAL);
 | 
						|
    if (sigaction (SMART_SCHEDULE_SIGNAL, &act, 0) < 0)
 | 
						|
    {
 | 
						|
	perror ("sigaction for smart scheduler");
 | 
						|
	return FALSE;
 | 
						|
    }
 | 
						|
    return TRUE;
 | 
						|
#else
 | 
						|
    return FALSE;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#ifdef SIG_BLOCK
 | 
						|
static sigset_t	PreviousSignalMask;
 | 
						|
static int	BlockedSignalCount;
 | 
						|
#endif
 | 
						|
 | 
						|
void
 | 
						|
OsBlockSignals (void)
 | 
						|
{
 | 
						|
#ifdef SIG_BLOCK
 | 
						|
    if (BlockedSignalCount++ == 0)
 | 
						|
    {
 | 
						|
	sigset_t    set;
 | 
						|
	
 | 
						|
	sigemptyset (&set);
 | 
						|
#ifdef SIGALRM
 | 
						|
	sigaddset (&set, SIGALRM);
 | 
						|
#endif
 | 
						|
#ifdef SIGVTALRM
 | 
						|
	sigaddset (&set, SIGVTALRM);
 | 
						|
#endif
 | 
						|
#ifdef SIGWINCH
 | 
						|
	sigaddset (&set, SIGWINCH);
 | 
						|
#endif
 | 
						|
#ifdef SIGIO
 | 
						|
	sigaddset (&set, SIGIO);
 | 
						|
#endif
 | 
						|
#ifdef SIGTSTP
 | 
						|
	sigaddset (&set, SIGTSTP);
 | 
						|
#endif
 | 
						|
#ifdef SIGTTIN
 | 
						|
	sigaddset (&set, SIGTTIN);
 | 
						|
#endif
 | 
						|
#ifdef SIGTTOU
 | 
						|
	sigaddset (&set, SIGTTOU);
 | 
						|
#endif
 | 
						|
#ifdef SIGCHLD
 | 
						|
	sigaddset (&set, SIGCHLD);
 | 
						|
#endif
 | 
						|
	sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
OsReleaseSignals (void)
 | 
						|
{
 | 
						|
#ifdef SIG_BLOCK
 | 
						|
    if (--BlockedSignalCount == 0)
 | 
						|
    {
 | 
						|
	sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#if !defined(WIN32)
 | 
						|
/*
 | 
						|
 * "safer" versions of system(3), popen(3) and pclose(3) which give up
 | 
						|
 * all privs before running a command.
 | 
						|
 *
 | 
						|
 * This is based on the code in FreeBSD 2.2 libc.
 | 
						|
 *
 | 
						|
 * XXX It'd be good to redirect stderr so that it ends up in the log file
 | 
						|
 * as well.  As it is now, xkbcomp messages don't end up in the log file.
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
System(char *command)
 | 
						|
{
 | 
						|
    int pid, p;
 | 
						|
#ifdef SIGCHLD
 | 
						|
    void (*csig)(int);
 | 
						|
#endif
 | 
						|
    int status;
 | 
						|
 | 
						|
    if (!command)
 | 
						|
	return(1);
 | 
						|
 | 
						|
#ifdef SIGCHLD
 | 
						|
    csig = signal(SIGCHLD, SIG_DFL);
 | 
						|
    if (csig == SIG_ERR) {
 | 
						|
      perror("signal");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
    ErrorF("System: `%s'\n", command);
 | 
						|
#endif
 | 
						|
 | 
						|
    switch (pid = fork()) {
 | 
						|
    case -1:	/* error */
 | 
						|
	p = -1;
 | 
						|
    case 0:	/* child */
 | 
						|
	if (setgid(getgid()) == -1)
 | 
						|
	    _exit(127);
 | 
						|
	if (setuid(getuid()) == -1)
 | 
						|
	    _exit(127);
 | 
						|
	execl("/bin/sh", "sh", "-c", command, (char *)NULL);
 | 
						|
	_exit(127);
 | 
						|
    default:	/* parent */
 | 
						|
	do {
 | 
						|
	    p = waitpid(pid, &status, 0);
 | 
						|
	} while (p == -1 && errno == EINTR);
 | 
						|
	
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef SIGCHLD
 | 
						|
    if (signal(SIGCHLD, csig) == SIG_ERR) {
 | 
						|
      perror("signal");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    return p == -1 ? -1 : status;
 | 
						|
}
 | 
						|
 | 
						|
static struct pid {
 | 
						|
    struct pid *next;
 | 
						|
    FILE *fp;
 | 
						|
    int pid;
 | 
						|
} *pidlist;
 | 
						|
 | 
						|
OsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */
 | 
						|
 | 
						|
pointer
 | 
						|
Popen(char *command, char *type)
 | 
						|
{
 | 
						|
    struct pid *cur;
 | 
						|
    FILE *iop;
 | 
						|
    int pdes[2], pid;
 | 
						|
 | 
						|
    if (command == NULL || type == NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    if ((*type != 'r' && *type != 'w') || type[1])
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    if ((cur = xalloc(sizeof(struct pid))) == NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    if (pipe(pdes) < 0) {
 | 
						|
	xfree(cur);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Ignore the smart scheduler while this is going on */
 | 
						|
    old_alarm = OsSignal(SIGALRM, SIG_IGN);
 | 
						|
    if (old_alarm == SIG_ERR) {
 | 
						|
      perror("signal");
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (pid = fork()) {
 | 
						|
    case -1: 	/* error */
 | 
						|
	close(pdes[0]);
 | 
						|
	close(pdes[1]);
 | 
						|
	xfree(cur);
 | 
						|
	if (OsSignal(SIGALRM, old_alarm) == SIG_ERR)
 | 
						|
	  perror("signal");
 | 
						|
	return NULL;
 | 
						|
    case 0:	/* child */
 | 
						|
	if (setgid(getgid()) == -1)
 | 
						|
	    _exit(127);
 | 
						|
	if (setuid(getuid()) == -1)
 | 
						|
	    _exit(127);
 | 
						|
	if (*type == 'r') {
 | 
						|
	    if (pdes[1] != 1) {
 | 
						|
		/* stdout */
 | 
						|
		dup2(pdes[1], 1);
 | 
						|
		close(pdes[1]);
 | 
						|
	    }
 | 
						|
	    close(pdes[0]);
 | 
						|
	} else {
 | 
						|
	    if (pdes[0] != 0) {
 | 
						|
		/* stdin */
 | 
						|
		dup2(pdes[0], 0);
 | 
						|
		close(pdes[0]);
 | 
						|
	    }
 | 
						|
	    close(pdes[1]);
 | 
						|
	}
 | 
						|
	execl("/bin/sh", "sh", "-c", command, (char *)NULL);
 | 
						|
	_exit(127);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Avoid EINTR during stdio calls */
 | 
						|
    OsBlockSignals ();
 | 
						|
    
 | 
						|
    /* parent */
 | 
						|
    if (*type == 'r') {
 | 
						|
	iop = fdopen(pdes[0], type);
 | 
						|
	close(pdes[1]);
 | 
						|
    } else {
 | 
						|
	iop = fdopen(pdes[1], type);
 | 
						|
	close(pdes[0]);
 | 
						|
    }
 | 
						|
 | 
						|
    cur->fp = iop;
 | 
						|
    cur->pid = pid;
 | 
						|
    cur->next = pidlist;
 | 
						|
    pidlist = cur;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
    ErrorF("Popen: `%s', fp = %p\n", command, iop);
 | 
						|
#endif
 | 
						|
 | 
						|
    return iop;
 | 
						|
}
 | 
						|
 | 
						|
/* fopen that drops privileges */
 | 
						|
pointer
 | 
						|
Fopen(char *file, char *type)
 | 
						|
{
 | 
						|
    FILE *iop;
 | 
						|
#ifndef HAS_SAVED_IDS_AND_SETEUID
 | 
						|
    struct pid *cur;
 | 
						|
    int pdes[2], pid;
 | 
						|
 | 
						|
    if (file == NULL || type == NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    if ((*type != 'r' && *type != 'w') || type[1])
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    if ((cur = xalloc(sizeof(struct pid))) == NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    if (pipe(pdes) < 0) {
 | 
						|
	xfree(cur);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (pid = fork()) {
 | 
						|
    case -1: 	/* error */
 | 
						|
	close(pdes[0]);
 | 
						|
	close(pdes[1]);
 | 
						|
	xfree(cur);
 | 
						|
	return NULL;
 | 
						|
    case 0:	/* child */
 | 
						|
	if (setgid(getgid()) == -1)
 | 
						|
	    _exit(127);
 | 
						|
	if (setuid(getuid()) == -1)
 | 
						|
	    _exit(127);
 | 
						|
	if (*type == 'r') {
 | 
						|
	    if (pdes[1] != 1) {
 | 
						|
		/* stdout */
 | 
						|
		dup2(pdes[1], 1);
 | 
						|
		close(pdes[1]);
 | 
						|
	    }
 | 
						|
	    close(pdes[0]);
 | 
						|
	} else {
 | 
						|
	    if (pdes[0] != 0) {
 | 
						|
		/* stdin */
 | 
						|
		dup2(pdes[0], 0);
 | 
						|
		close(pdes[0]);
 | 
						|
	    }
 | 
						|
	    close(pdes[1]);
 | 
						|
	}
 | 
						|
	execl("/bin/cat", "cat", file, (char *)NULL);
 | 
						|
	_exit(127);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Avoid EINTR during stdio calls */
 | 
						|
    OsBlockSignals ();
 | 
						|
    
 | 
						|
    /* parent */
 | 
						|
    if (*type == 'r') {
 | 
						|
	iop = fdopen(pdes[0], type);
 | 
						|
	close(pdes[1]);
 | 
						|
    } else {
 | 
						|
	iop = fdopen(pdes[1], type);
 | 
						|
	close(pdes[0]);
 | 
						|
    }
 | 
						|
 | 
						|
    cur->fp = iop;
 | 
						|
    cur->pid = pid;
 | 
						|
    cur->next = pidlist;
 | 
						|
    pidlist = cur;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
    ErrorF("Fopen(%s), fp = %p\n", file, iop);
 | 
						|
#endif
 | 
						|
 | 
						|
    return iop;
 | 
						|
#else
 | 
						|
    int ruid, euid;
 | 
						|
 | 
						|
    ruid = getuid();
 | 
						|
    euid = geteuid();
 | 
						|
    
 | 
						|
    if (seteuid(ruid) == -1) {
 | 
						|
	    return NULL;
 | 
						|
    }
 | 
						|
    iop = fopen(file, type);
 | 
						|
 | 
						|
    if (seteuid(euid) == -1) {
 | 
						|
	    fclose(iop);
 | 
						|
	    return NULL;
 | 
						|
    }
 | 
						|
    return iop;
 | 
						|
#endif /* HAS_SAVED_IDS_AND_SETEUID */
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
Pclose(pointer iop)
 | 
						|
{
 | 
						|
    struct pid *cur, *last;
 | 
						|
    int pstat;
 | 
						|
    int pid;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
    ErrorF("Pclose: fp = %p\n", iop);
 | 
						|
#endif
 | 
						|
 | 
						|
    fclose(iop);
 | 
						|
 | 
						|
    for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
 | 
						|
	if (cur->fp == iop)
 | 
						|
	    break;
 | 
						|
    if (cur == NULL)
 | 
						|
	return -1;
 | 
						|
 | 
						|
    do {
 | 
						|
	pid = waitpid(cur->pid, &pstat, 0);
 | 
						|
    } while (pid == -1 && errno == EINTR);
 | 
						|
 | 
						|
    if (last == NULL)
 | 
						|
	pidlist = cur->next;
 | 
						|
    else
 | 
						|
	last->next = cur->next;
 | 
						|
    xfree(cur);
 | 
						|
 | 
						|
    /* allow EINTR again */
 | 
						|
    OsReleaseSignals ();
 | 
						|
    
 | 
						|
    if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) {
 | 
						|
      perror("signal");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    return pid == -1 ? -1 : pstat;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
Fclose(pointer iop)
 | 
						|
{
 | 
						|
#ifdef HAS_SAVED_IDS_AND_SETEUID
 | 
						|
    return fclose(iop);
 | 
						|
#else
 | 
						|
    return Pclose(iop);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#endif /* !WIN32 */
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * CheckUserParameters: check for long command line arguments and long
 | 
						|
 * environment variables.  By default, these checks are only done when
 | 
						|
 * the server's euid != ruid.  In 3.3.x, these checks were done in an
 | 
						|
 * external wrapper utility.
 | 
						|
 */
 | 
						|
 | 
						|
/* Consider LD* variables insecure? */
 | 
						|
#ifndef REMOVE_ENV_LD
 | 
						|
#define REMOVE_ENV_LD 1
 | 
						|
#endif
 | 
						|
 | 
						|
/* Remove long environment variables? */
 | 
						|
#ifndef REMOVE_LONG_ENV
 | 
						|
#define REMOVE_LONG_ENV 1
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Disallow stdout or stderr as pipes?  It's possible to block the X server
 | 
						|
 * when piping stdout+stderr to a pipe.
 | 
						|
 *
 | 
						|
 * Don't enable this because it looks like it's going to cause problems.
 | 
						|
 */
 | 
						|
#ifndef NO_OUTPUT_PIPES
 | 
						|
#define NO_OUTPUT_PIPES 0
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
 | 
						|
#ifndef CHECK_EUID
 | 
						|
#ifndef WIN32
 | 
						|
#define CHECK_EUID 1
 | 
						|
#else
 | 
						|
#define CHECK_EUID 0
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Maybe the locale can be faked to make isprint(3) report that everything
 | 
						|
 * is printable?  Avoid it by default.
 | 
						|
 */
 | 
						|
#ifndef USE_ISPRINT
 | 
						|
#define USE_ISPRINT 0
 | 
						|
#endif
 | 
						|
 | 
						|
#define MAX_ARG_LENGTH          128
 | 
						|
#define MAX_ENV_LENGTH          256
 | 
						|
#define MAX_ENV_PATH_LENGTH     2048	/* Limit for *PATH and TERMCAP */
 | 
						|
 | 
						|
#if USE_ISPRINT
 | 
						|
#include <ctype.h>
 | 
						|
#define checkPrintable(c) isprint(c)
 | 
						|
#else
 | 
						|
#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
 | 
						|
#endif
 | 
						|
 | 
						|
enum BadCode {
 | 
						|
    NotBad = 0,
 | 
						|
    UnsafeArg,
 | 
						|
    ArgTooLong,
 | 
						|
    UnprintableArg,
 | 
						|
    EnvTooLong,
 | 
						|
    OutputIsPipe,
 | 
						|
    InternalError
 | 
						|
};
 | 
						|
 | 
						|
#if defined(VENDORSUPPORT)
 | 
						|
#define BUGADDRESS VENDORSUPPORT
 | 
						|
#elif defined(BUILDERADDR)
 | 
						|
#define BUGADDRESS BUILDERADDR
 | 
						|
#else
 | 
						|
#define BUGADDRESS "xorg@freedesktop.org"
 | 
						|
#endif
 | 
						|
 | 
						|
void
 | 
						|
CheckUserParameters(int argc, char **argv, char **envp)
 | 
						|
{
 | 
						|
    enum BadCode bad = NotBad;
 | 
						|
    int i = 0, j;
 | 
						|
    char *a, *e = NULL;
 | 
						|
 | 
						|
#if CHECK_EUID
 | 
						|
    if (geteuid() == 0 && getuid() != geteuid())
 | 
						|
#endif
 | 
						|
    {
 | 
						|
	/* Check each argv[] */
 | 
						|
	for (i = 1; i < argc; i++) {
 | 
						|
	    if (strcmp(argv[i], "-fp") == 0)
 | 
						|
	    {
 | 
						|
		i++; /* continue with next argument. skip the length check */
 | 
						|
		if (i >= argc)
 | 
						|
		    break;
 | 
						|
	    } else
 | 
						|
	    {
 | 
						|
		if (strlen(argv[i]) > MAX_ARG_LENGTH) {
 | 
						|
		    bad = ArgTooLong;
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    a = argv[i];
 | 
						|
	    while (*a) {
 | 
						|
		if (checkPrintable(*a) == 0) {
 | 
						|
		    bad = UnprintableArg;
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
		a++;
 | 
						|
	    }
 | 
						|
	    if (bad)
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	if (!bad) {
 | 
						|
	    /* Check each envp[] */
 | 
						|
	    for (i = 0; envp[i]; i++) {
 | 
						|
 | 
						|
		/* Check for bad environment variables and values */
 | 
						|
#if REMOVE_ENV_LD
 | 
						|
		while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
 | 
						|
		    for (j = i; envp[j]; j++) {
 | 
						|
			envp[j] = envp[j+1];
 | 
						|
		    }
 | 
						|
		}
 | 
						|
#endif   
 | 
						|
		if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
 | 
						|
#if REMOVE_LONG_ENV
 | 
						|
		    for (j = i; envp[j]; j++) {
 | 
						|
			envp[j] = envp[j+1];
 | 
						|
		    }
 | 
						|
		    i--;
 | 
						|
#else
 | 
						|
		    char *eq;
 | 
						|
		    int len;
 | 
						|
 | 
						|
		    eq = strchr(envp[i], '=');
 | 
						|
		    if (!eq)
 | 
						|
			continue;
 | 
						|
		    len = eq - envp[i];
 | 
						|
		    e = malloc(len + 1);
 | 
						|
		    if (!e) {
 | 
						|
			bad = InternalError;
 | 
						|
			break;
 | 
						|
		    }
 | 
						|
		    strncpy(e, envp[i], len);
 | 
						|
		    e[len] = 0;
 | 
						|
		    if (len >= 4 &&
 | 
						|
			(strcmp(e + len - 4, "PATH") == 0 ||
 | 
						|
			 strcmp(e, "TERMCAP") == 0)) {
 | 
						|
			if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
 | 
						|
			    bad = EnvTooLong;
 | 
						|
			    break;
 | 
						|
			} else {
 | 
						|
			    free(e);
 | 
						|
			}
 | 
						|
		    } else {
 | 
						|
			bad = EnvTooLong;
 | 
						|
			break;
 | 
						|
		    }
 | 
						|
#endif
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
#if NO_OUTPUT_PIPES
 | 
						|
	if (!bad) {
 | 
						|
	    struct stat buf;
 | 
						|
 | 
						|
	    if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
 | 
						|
		bad = OutputIsPipe;
 | 
						|
	    if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
 | 
						|
		bad = OutputIsPipe;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    switch (bad) {
 | 
						|
    case NotBad:
 | 
						|
	return;
 | 
						|
    case UnsafeArg:
 | 
						|
	ErrorF("Command line argument number %d is unsafe\n", i);
 | 
						|
	break;
 | 
						|
    case ArgTooLong:
 | 
						|
	ErrorF("Command line argument number %d is too long\n", i);
 | 
						|
	break;
 | 
						|
    case UnprintableArg:
 | 
						|
	ErrorF("Command line argument number %d contains unprintable"
 | 
						|
		" characters\n", i);
 | 
						|
	break;
 | 
						|
    case EnvTooLong:
 | 
						|
	ErrorF("Environment variable `%s' is too long\n", e);
 | 
						|
	break;
 | 
						|
    case OutputIsPipe:
 | 
						|
	ErrorF("Stdout and/or stderr is a pipe\n");
 | 
						|
	break;
 | 
						|
    case InternalError:
 | 
						|
	ErrorF("Internal Error\n");
 | 
						|
	break;
 | 
						|
    default:
 | 
						|
	ErrorF("Unknown error\n");
 | 
						|
	break;
 | 
						|
    }
 | 
						|
    FatalError("X server aborted because of unsafe environment\n");
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * CheckUserAuthorization: check if the user is allowed to start the
 | 
						|
 * X server.  This usually means some sort of PAM checking, and it is
 | 
						|
 * usually only done for setuid servers (uid != euid).
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef USE_PAM
 | 
						|
#include <security/pam_appl.h>
 | 
						|
#include <security/pam_misc.h>
 | 
						|
#include <pwd.h>
 | 
						|
#endif /* USE_PAM */
 | 
						|
 | 
						|
void
 | 
						|
CheckUserAuthorization(void)
 | 
						|
{
 | 
						|
#ifdef USE_PAM
 | 
						|
    static struct pam_conv conv = {
 | 
						|
	misc_conv,
 | 
						|
	NULL
 | 
						|
    };
 | 
						|
 | 
						|
    pam_handle_t *pamh = NULL;
 | 
						|
    struct passwd *pw;
 | 
						|
    int retval;
 | 
						|
 | 
						|
    if (getuid() != geteuid()) {
 | 
						|
	pw = getpwuid(getuid());
 | 
						|
	if (pw == NULL)
 | 
						|
	    FatalError("getpwuid() failed for uid %d\n", getuid());
 | 
						|
 | 
						|
	retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
 | 
						|
	if (retval != PAM_SUCCESS)
 | 
						|
	    FatalError("pam_start() failed.\n"
 | 
						|
			"\tMissing or mangled PAM config file or module?\n");
 | 
						|
 | 
						|
	retval = pam_authenticate(pamh, 0);
 | 
						|
	if (retval != PAM_SUCCESS) {
 | 
						|
	    pam_end(pamh, retval);
 | 
						|
	    FatalError("PAM authentication failed, cannot start X server.\n"
 | 
						|
			"\tPerhaps you do not have console ownership?\n");
 | 
						|
	}
 | 
						|
 | 
						|
	retval = pam_acct_mgmt(pamh, 0);
 | 
						|
	if (retval != PAM_SUCCESS) {
 | 
						|
	    pam_end(pamh, retval);
 | 
						|
	    FatalError("PAM authentication failed, cannot start X server.\n"
 | 
						|
			"\tPerhaps you do not have console ownership?\n");
 | 
						|
	}
 | 
						|
 | 
						|
	/* this is not a session, so do not do session management */
 | 
						|
	pam_end(pamh, PAM_SUCCESS);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#ifdef __SCO__
 | 
						|
#include <fcntl.h>
 | 
						|
 | 
						|
static void
 | 
						|
lockit (int fd, short what)
 | 
						|
{
 | 
						|
  struct flock lck;
 | 
						|
 | 
						|
  lck.l_whence = 0;
 | 
						|
  lck.l_start = 0;
 | 
						|
  lck.l_len = 1;
 | 
						|
  lck.l_type = what;
 | 
						|
 | 
						|
  (void)fcntl (fd, F_SETLKW, &lck);
 | 
						|
}
 | 
						|
 | 
						|
/* SCO OpenServer 5 lacks pread/pwrite. Emulate them. */
 | 
						|
ssize_t
 | 
						|
pread (int fd, void *buf, size_t nbytes, off_t offset)
 | 
						|
{
 | 
						|
  off_t saved;
 | 
						|
  ssize_t ret;
 | 
						|
 | 
						|
  lockit (fd, F_RDLCK);
 | 
						|
  saved = lseek (fd, 0, SEEK_CUR);
 | 
						|
  lseek (fd, offset, SEEK_SET);
 | 
						|
  ret = read (fd, buf, nbytes);
 | 
						|
  lseek (fd, saved, SEEK_SET);
 | 
						|
  lockit (fd, F_UNLCK);
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ssize_t
 | 
						|
pwrite (int fd, const void *buf, size_t nbytes, off_t offset)
 | 
						|
{
 | 
						|
  off_t saved;
 | 
						|
  ssize_t ret;
 | 
						|
 | 
						|
  lockit (fd, F_WRLCK);
 | 
						|
  saved = lseek (fd, 0, SEEK_CUR);
 | 
						|
  lseek (fd, offset, SEEK_SET);
 | 
						|
  ret = write (fd, buf, nbytes);
 | 
						|
  lseek (fd, saved, SEEK_SET);
 | 
						|
  lockit (fd, F_UNLCK);
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
#endif /* __SCO__ */
 |