From 1827a018cf5a81f9187d68741d364fc849bad280 Mon Sep 17 00:00:00 2001 From: Boiko <boiko@ageless.conectiva> Date: Thu, 8 Jun 2006 14:03:57 -0300 Subject: [PATCH] Use a X wrapper that uses pam and consolehelper to give X root privileges --- Makefile.am | 7 + configure.ac | 14 +++ os/Makefile.am | 7 + os/wrapper.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 340 insertions(+), 1 deletions(-) diff --git a/Makefile.am b/Makefile.am index 847615a..3b2dc3c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,6 +61,13 @@ SUBDIRS = \ exa \ hw +if XSERVER_WRAPPER +bin_PROGRAMS = Xwrapper +Xwrapper_SOURCES = os/wrapper.c +Xwrapper_LDADD = $(PAM_LIBS) +Xwrapper_CFLAGS = $(XWRAPPER_DEFINES) +endif + aclocaldir = $(datadir)/aclocal aclocal_DATA = xorg-server.m4 diff --git a/configure.ac b/configure.ac index 328de9f..2793aea 100644 --- a/configure.ac +++ b/configure.ac @@ -473,6 +473,20 @@ fi AC_MSG_RESULT([$SETUID]) AM_CONDITIONAL(INSTALL_SETUID, [test "x$SETUID" = "xyes"]) +AC_ARG_ENABLE(xwrapper, AS_HELP_STRING([--enable-xwrapper], [Build X with a wrapper (default: yes)]), [XWRAPPER=$enableval], [XWRAPPER=yes]) +AM_CONDITIONAL(XSERVER_WRAPPER, [test "x$XWRAPPER" = "xyes"]) +if test "x$XWRAPPER" = "xyes" ; then + AC_ARG_ENABLE(pam, AS_HELP_STRING([--enable-pam], [Build X wrapper with pam support (default: yes)]), [PAM=$enableval], [PAM=yes]) + AM_CONDITIONAL(USE_PAM, [test "x$PAM" = "xyes"]) + if test "x$PAM" = "xyes" ; then + PAM_DEFINES=-DUSE_PAM + fi + XWRAPPER_DEFINES="-DXSERVER_PATH=\\\"$libdir/xorg/bin/Xgl\\\" $PAM_DEFINES" + AC_SUBST(XWRAPPER_DEFINES) + PAM_LIBS="-lpam -lpam_misc" + AC_SUBST(PAM_LIBS) +fi + dnl Issue an error if xtrans.m4 was not found and XTRANS_CONNECTION_FLAGS macro dnl was not expanded, since xorg-server with no transport types is rather useless. dnl diff --git a/os/Makefile.am b/os/Makefile.am index c4ebf21..a17a5a2 100644 --- a/os/Makefile.am +++ b/os/Makefile.am @@ -1,7 +1,8 @@ noinst_LTLIBRARIES = libos.la libcwrapper.la -AM_CFLAGS = $(DIX_CFLAGS) @SERVER_DEFINES@ @LOADER_DEFINES@ +WRAPPER_SOURCES=wrapper.o +AM_CFLAGS = $(DIX_CFLAGS) $(WRAPPER_DEFINES) # FIXME: Add support for these in configure.ac K5AUTH_SOURCES = k5auth.c SECURERPC_SOURCES = rpcauth.c @@ -41,6 +42,10 @@ if NEED_STRLCAT libos_la_SOURCES += $(STRLCAT_SOURCES) endif +if XSERVER_WRAPPER +libos_la_SOURCES += $(WRAPPER_SOURCES) +endif + libcwrapper_la_SOURCES = \ $(top_srcdir)/hw/xfree86/os-support/shared/libc_wrapper.c libcwrapper_la_CFLAGS = \ diff --git a/os/wrapper.c b/os/wrapper.c new file mode 100644 index 0000000..600e6bd --- /dev/null +++ b/os/wrapper.c @@ -0,0 +1,313 @@ +/* + * X server wrapper. + * + * This wrapper makes some sanity checks on the command line arguments + * and environment variables when run with euid == 0 && euid != uid. + * If the checks fail, the wrapper exits with a message. + * If they succeed, it exec's the Xserver. + */ + +/* + * Copyright (c) 1998 by The XFree86 Project, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * 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 XFREE86 PROJECT 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 XFree86 Project + * 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 XFree86 Project. + */ + +/* $XFree86: xc/programs/Xserver/os/wrapper.c,v 1.1.2.8 1999/07/23 13:23:12 hohndel Exp $ */ + +/* This is normally set in the Imakefile */ +#ifndef XSERVER_PATH +#define XSERVER_PATH "/usr/bin/X" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#ifdef USE_PAM +#include <security/pam_appl.h> +#include <security/pam_misc.h> +#include <pwd.h> +#endif /* USE_PAM */ + +/* Neither of these should be required for XFree86 3.3.2 */ +#ifndef REJECT_CONFIG +#define REJECT_CONFIG 0 +#endif +#ifndef REJECT_XKBDIR +#define REJECT_XKBDIR 0 +#endif + +/* 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 + +/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ +#ifndef CHECK_EUID +#define CHECK_EUID 1 +#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 + +#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, + InternalError, +#ifdef USE_PAM + PamFailed, + PamAuthFailed, +#endif /* USE_PAM */ +}; + +#define ARGMSG \ + "\nIf the arguments used are valid, and have been rejected incorrectly\n" \ + "please send details of the arguments and why they are valid to\n" \ + "XFree86@XFree86.org. In the meantime, you can start the Xserver as\n" \ + "the \"super user\" (root).\n" + +#define ENVMSG \ + "\nIf the environment is valid, and have been rejected incorrectly\n" \ + "please send details of the environment and why it is valid to\n" \ + "XFree86@XFree86.org. In the meantime, you can start the Xserver as\n" \ + "the \"super user\" (root).\n" + +#ifdef USE_PAM +static struct pam_conv conv = { + misc_conv, + NULL +}; +#endif /* USE_PAM */ + + +int +main(int argc, char **argv, char **envp) +{ + enum BadCode bad = NotBad; + int i, j; + char *a, *e; +#if defined(__QNX__) && !defined(__QNXNTO__) + char cmd_name[64]; +#endif +#ifdef USE_PAM + pam_handle_t *pamh = NULL; + struct passwd *pw; + int retval; + + pw = getpwuid(getuid()); + if (pw == NULL) { + bad = InternalError; + } + + if (!bad) { + retval = pam_start("xserver", pw->pw_name, &conv, &pamh); + if (retval != PAM_SUCCESS) + bad = PamFailed; + } + + if (!bad) { + retval = pam_authenticate(pamh, 0); + if (retval != PAM_SUCCESS) { + pam_end(pamh, retval); + bad = PamAuthFailed; + } + } + + if (!bad) { + retval = pam_acct_mgmt(pamh, 0); + if (retval != PAM_SUCCESS) { + pam_end(pamh, retval); + bad = PamAuthFailed; + } + } + + /* this is not a session, so do not do session management */ + + if (!bad) pam_end(pamh, PAM_SUCCESS); +#endif /* USE_PAM */ + +#if CHECK_EUID + if (!bad && geteuid() == 0 && getuid() != geteuid()) { +#else + if (!bad) { +#endif + /* Check each argv[] */ + for (i = 1; i < argc; i++) { + + /* Check for known bad arguments */ +#if REJECT_CONFIG + if (strcmp(argv[i], "-config") == 0) { + bad = UnsafeArg; + break; + } +#endif +#if REJECT_XKBDIR + if (strcmp(argv[i], "-xkbdir") == 0) { + bad = UnsafeArg; + break; + } +#endif + 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; + } + /* Check each envp[] */ + if (!bad) + 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 + } + } + } + switch (bad) { + case NotBad: + argv[0] = XSERVER_PATH; +#if defined(__QNX__) && !defined(__QNXNTO__) + sprintf(cmd_name,"%s.%d",XSERVER_PATH,getnid()); + execve(cmd_name, argv, envp); +#else + execve(XSERVER_PATH, argv, envp); +#endif + fprintf(stderr, "execve failed for %s (errno %d)\n", XSERVER_PATH, + errno); + break; + case UnsafeArg: + fprintf(stderr, "Command line argument number %d is unsafe\n", i); + fprintf(stderr, ARGMSG); + break; + case ArgTooLong: + fprintf(stderr, "Command line argument number %d is too long\n", i); + fprintf(stderr, ARGMSG); + break; + case UnprintableArg: + fprintf(stderr, "Command line argument number %d contains unprintable" + " characters\n", i); + fprintf(stderr, ARGMSG); + break; + case EnvTooLong: + fprintf(stderr, "Environment variable `%s' is too long\n", e); + fprintf(stderr, ENVMSG); + break; + case InternalError: + fprintf(stderr, "Internal Error\n"); + break; +#ifdef USE_PAM + case PamFailed: + fprintf(stderr, "Authentication System Failure, " + "missing or mangled PAM configuration file or module?\n"); + break; + case PamAuthFailed: + fprintf(stderr, "Authentication failed - cannot start X server.\nPerhaps you do not have console ownership?"); + break; +#endif + default: + fprintf(stderr, "Unknown error\n"); + fprintf(stderr, ARGMSG); + fprintf(stderr, ENVMSG); + break; + } + exit(1); +} + -- 1.4.0