You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2010/01/27 11:00:35 UTC

svn commit: r903586 - in /commons/sandbox/runtime/trunk/src/main/native: Makefile.in configure support/suexec.c support/suexec.h support/win32/suexec.c

Author: mturk
Date: Wed Jan 27 10:00:34 2010
New Revision: 903586

URL: http://svn.apache.org/viewvc?rev=903586&view=rev
Log:
Add Httpd's suEXEC. Modified from httpd trunk

Added:
    commons/sandbox/runtime/trunk/src/main/native/support/suexec.c   (with props)
    commons/sandbox/runtime/trunk/src/main/native/support/suexec.h   (with props)
Modified:
    commons/sandbox/runtime/trunk/src/main/native/Makefile.in
    commons/sandbox/runtime/trunk/src/main/native/configure
    commons/sandbox/runtime/trunk/src/main/native/support/win32/suexec.c

Modified: commons/sandbox/runtime/trunk/src/main/native/Makefile.in
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/Makefile.in?rev=903586&r1=903585&r2=903586&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/Makefile.in (original)
+++ commons/sandbox/runtime/trunk/src/main/native/Makefile.in Wed Jan 27 10:00:34 2010
@@ -38,13 +38,15 @@
 ASFLAGS=@asflags@
 RANLIB=@ranlib@
 PREFIX=@prefix@
+BINDIR=@bindir@
 LIBDIR=@libdir@
 TOPDIR=@topdir@
 CPP=@cpp@
 CXX=@cxx@
 CFLAGS=@ccflags@
 CSFLAGS=@ccshare@
-EXLFLAGS=@exflags@
+LDRPATH=@ldrpath@
+LDARCH=@lddarch@
 CPPFLAGS=@cppopts@
 CXXFLAGS=@cxxopts@
 LDFLAGS=@ldflags@
@@ -62,6 +64,7 @@
 SHAREDLIB=lib$(NAME)$(SO)
 SSLMODLIB=lib$(NAME)ssl$(SO)
 SQLMODLIB=lib$(NAME)sql$(SO)
+SUEXECBIN=suexec$(EXE)
 TESTSUITE=testsuite$(EXE)
 
 SRCDIR=$(TOPDIR)
@@ -383,6 +386,9 @@
 $(SRCDIR)/modules/network/ssl/%.$(OBJ) : $(SRCDIR)/modules/network/ssl/%.c
 	$(CC) $(CFLAGS) $(CSFLAGS) $(CPPFLAGS) $(INCLUDES) -c -o $@ $<
 
+$(SRCDIR)/support/%.$(OBJ) : $(SRCDIR)/support/%.c
+	$(CC) $(CFLAGS) $(CSFLAGS) $(CPPFLAGS) $(INCLUDES) -c -o $@ $<
+
 $(SRCDIR)/test/%.$(OBJ) : $(SRCDIR)/test/%.c
 	$(CC) $(CFLAGS) $(CSFLAGS) $(CPPFLAGS) $(INCLUDES) -c -o $@ $<
 
@@ -397,21 +403,24 @@
 	$(CC) $(SHFLAGS) $(PPORT_OBJS) $(COMMON_OBJS) $(@platform@_OBJS) $(REGEX_OBJS) $(BZIP2_OBJS) $(EXPAT_OBJS) $(ZLIB_OBJS) @testobjs@ $(LDFLAGS) -o $@
 
 $(SSLMODLIB): $(SHAREDLIB) $(OPENSSL_OBJS)
-	$(CC) $(EXLFLAGS) $(SHFLAGS) $(OPENSSL_OBJS) $(LDFLAGS) $(SSLFLAGS) -L. -l$(NAME) -o $@
+	$(CC) $(LDARCH) $(LDRPATH) $(SHFLAGS) $(OPENSSL_OBJS) $(LDFLAGS) $(SSLFLAGS) -L. -l$(NAME) -o $@
 
 $(SQLMODLIB): $(SHAREDLIB) $(SQLITE_OBJS) @sqliteobjs@
-	$(CC) $(EXLFLAGS) $(SHFLAGS) $(SQLITE_OBJS) @sqliteobjs@ $(LDFLAGS) $(SQLFLAGS) -L. -l$(NAME) -o $@
+	$(CC) $(LDARCH) $(LDRPATH) $(SHFLAGS) $(SQLITE_OBJS) @sqliteobjs@ $(LDFLAGS) $(SQLFLAGS) -L. -l$(NAME) -o $@
+
+$(SUEXECBIN): $(SRCDIR)/support/suexec.$(OBJ)
+	$(CC) $(LDARCH) $(SRCDIR)/support/suexec.$(OBJ) -o $@
 
 $(TESTSUITE): $(STATICLIB) $(SHAREDLIB) @modules@ $(SRCDIR)/test/testsuite.$(OBJ)
-	$(CC) $(EXLFLAGS) $(SRCDIR)/test/testsuite.$(OBJ) $(LDFLAGS) -L. -l$(NAME) -o $@
+	$(CC) $(LDARCH) $(LDRPATH) $(SRCDIR)/test/testsuite.$(OBJ) $(LDFLAGS) -L. -l$(NAME) -o $@
 
 test: $(TESTSUITE)
 
 clean:
-	for i in $(SRCDIR) $(ARCH_DIRS) ; do rm -f $$i/*.$(OBJ) ; done
+	for i in $(SRCDIR) $(SRCDIR)/support $(ARCH_DIRS) ; do rm -f $$i/*.$(OBJ) ; done
+	for i in $(TESTSUITE) $(SUEXECBIN) ; do rm -f $$i ; done
 	rm -f *$(SO)
 	rm -f *$(LIB)
-	rm -f $(TESTSUITE)
 
 distclean: clean
 	rm -f $(TOPDIR)/Makefile
@@ -420,6 +429,7 @@
 install: all
 	@mkdir -p $(DESTDIR)/include
 	@mkdir -p $(DESTDIR)/$(LIBDIR)
+	@mkdir -p $(DESTDIR)/$(BINDIR)
 	cp -rf $(INCDIR)/* $(DESTDIR)/include/
 	cp -f *$(LIB) $(DESTDIR)/lib/
 	cp -f *$(SO) $(DESTDIR)/lib/

Modified: commons/sandbox/runtime/trunk/src/main/native/configure
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/configure?rev=903586&r1=903585&r2=903586&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/configure (original)
+++ commons/sandbox/runtime/trunk/src/main/native/configure Wed Jan 27 10:00:34 2010
@@ -75,7 +75,8 @@
 ldflags="$LDFLAGS"
 shflags="$SHFLAGS"
 rcflags="$RCFLAGS"
-exflags=""
+ldrpath=""
+lddarch=""
 includes="-I$topdir/include -I$topdir/port -I$topdir/srclib"
 ssldflags=""
 modules=""
@@ -120,12 +121,10 @@
 mach=unknown
 has_legacy_code=no
 
-with_suexec_root=/var/www
-with_suexec_log=/var/log/apachecommons/suexec.log
 with_suexec_user=www
-with_suexec_uid_min=100
-with_suexec_gid_min=100
-with_suexec_user_dir=public_html
+with_suexec_uidmin=100
+with_suexec_gidmin=100
+with_suexec_userdir=public_html
 
 for o
 do
@@ -324,6 +323,34 @@
                           will be used.
                           If DIR equals 'embedded' local sqlite sources will
                           be used
+  --enable-suexec         Enable compilation of suEXEC utility
+                              [disabled]
+  --enable-suexec-log     Enable suEXEC error logging
+                              [disabled]
+  --with-suexec-logfile   Defines the filename of the suEXEC logfile. 
+                              [/var/log/suexec.log]
+  --with-suexec-user      Defines the user allowed to call suEXEC. It should be
+                          the same as the user under which the service usually
+                          runs.
+                              [www]
+  --with-suexec-userdir  Defines the subdirectory under the user's directory
+                         that contains all executables for which suEXEC access
+                         is allowed.
+                              [public_html]
+  --with-suexec-docroot  Defines the directory tree under which suEXEC access
+                         is allowed for executables.
+                              [/var/www]
+  --with-suexec-umask    Set umask for processes started by suEXEC.
+                              [Platform default]
+  --with-suexec-uidmin   Define this as the lowest UID allowed to be a target
+                         user for suEXEC
+                              [100]
+  --with-suexec-gidmin   Define this as the lowest GID allowed to be a target
+                         group for suEXEC
+                              [100]
+  --with-suexec-safepath Define the value of the environment variable
+                         PATH to be set for processes started by suEXEC.
+                              [/usr/local/bin:/usr/bin:/bin]
 
 EOH
         exit 1
@@ -507,7 +534,7 @@
         varadds asflags -c -fPIC -g -D$mcpu
         varadds ldflags -lrt -lpthread -ldl
         varadds shflags -shared -fPIC -Wl,-soname '-Wl,??@'
-        varadds exflags '-Wl,-rpath,??(PREFIX)/??(LIBDIR):????ORIGIN'
+        varadds ldrpath '-Wl,-rpath,??(PREFIX)/??(LIBDIR):????ORIGIN'
         as=gcc
         test ".$java_pinc" = . && java_pinc=linux
         ;;
@@ -522,7 +549,7 @@
         varadds asflags -c -KPIC -D$mcpu
         varadds ldflags -lpthread -ldl
         varadds shflags -G -KPIC -dy
-        varadds exflags '-R:??(PREFIX)/??(LIBDIR):.'
+        varadds ldrpath '-R:??(PREFIX)/??(LIBDIR):.'
         test ".$cxx_set" = .no && cxx=CC
         cpp="cc -E"
         as=cc
@@ -535,7 +562,7 @@
         varadds ccshare -fPIC -g
         varadds asflags -c -fPIC -g -D$mcpu
         varadds ldflags -lpthread -ldl
-        varadds exflags '-Wl,-rpath,??(PREFIX)/??(LIBDIR):.'
+        varadds ldrpath '-Wl,-rpath,??(PREFIX)/??(LIBDIR):.'
         if [ ".$has_jni" = .yes ]; then so=".jnilib"; else so=".dynlib"; fi
         varadds shflags -dynamiclib -flat_namespace -undefined suppress -fPIC -Wl,-dylib_install_name '-Wl,??@'
         as=gcc
@@ -560,7 +587,7 @@
         varadds ccshare -KPIC
         varadds ldflags -lrt -ldl -lthread -lsendfile -lsocket -lnsl
         varadds shflags -G -KPIC -dy
-        varadds exflags '-R:??(PREFIX)/??(LIBDIR):.'
+        varadds ldrpath '-R:??(PREFIX)/??(LIBDIR):.'
         test ".$cxx_set" = .no && cxx=CC
         cpp="cc -E"
         as=cc
@@ -609,7 +636,7 @@
         varadds ccshare -fPIC -g
         varadds ldflags -lrt -lpthreads -lnsl
         varadds shflags -shared -fPIC -Wl,-soname '-Wl,??@' -Wl,-brtl
-        varadds exflags '-Wl,-rpath,??(PREFIX)/??(LIBDIR):????ORIGIN'
+        varadds ldrpath '-Wl,-rpath,??(PREFIX)/??(LIBDIR):????ORIGIN'
         echo "Warning : WORK IN PROGRESS"
         ;;
     *       )
@@ -648,11 +675,11 @@
         varadds ccflags +DD64
         varadds asflags +DD64
         varadds shflags +DD64
-        varadds exflags +DD64
+        varadds lddarch +DD64
         if [ ".$mach" = .parisc64 ]; then
             varadds ccflags +DA2.0W
             varadds asflags +DA2.0W
-            varadds exflags +DA2.0W
+            varadds lddarch +DA2.0W
             varadds asflags +DA2.0W
         fi
         ;;
@@ -660,7 +687,7 @@
         varadds ccflags +DD32
         varadds asflags +DD32
         varadds shflags +DD32
-        varadds exflags +DD32
+        varadds lddarch +DD32
         ;;
     windows-cl|windows32-cl )
         varadds asflags -coff -Cx -Zm -Di386 -DQUIET -D?QUIET
@@ -686,13 +713,13 @@
         varadds ccflags -m64
         varadds asflags -m64
         varadds shflags -m64
-        varadds exflags -m64
+        varadds lddarch -m64
         ;;
     *32-*        )
         varadds ccflags -m32
         varadds asflags -m32
         varadds shflags -m32
-        varadds exflags -m32
+        varadds lddarch -m32
         ;;
 esac
 
@@ -1146,9 +1173,12 @@
     sqliteobjs=""
 fi
 
+have_suexec_log=0
 if [ ".$has_suexec" = .yes ]; then
     varadds modules '??(SUEXECBIN)'
     have_suexec=1
+    test ".$has_suexec_log" = .yes && have_suexec_log=1
+    varadds includes "-I$topdir/support"
 else
     have_suexec=0
 fi
@@ -1200,6 +1230,7 @@
 #define HAVE_PORT_H           $have_port
 #define HAVE_SQLITE3          $have_sqlite3
 #define HAVE_SUEXEC           $have_suexec
+#define HAVE_SUEXEC_LOG       $have_suexec_log
 
 #define HAVE_UNISTD_H         `have_include x unistd`
 #define HAVE_STRING_H         `have_include w string`
@@ -1277,16 +1308,29 @@
 if [ ".$has_suexec" = .yes ]; then
 cat >> $topdir/include/acr_cc$bits.h << EOF
 
-#define AC_SUEXEC_ROOT        "$with_suexec_root"
+#define AC_SUEXEC_UID_MIN     $with_suexec_uidmin
+#define AC_SUEXEC_GID_MIN     $with_suexec_gidmin
 #define AC_SUEXEC_USER        "$with_suexec_user"
-#define AC_SUEXEC_USERDIR     "$with_suexec_user_dir"
-#define AC_SUEXEC_LOG_EXEC    "$with_suexec_log"
-#define AC_SUEXEC_UID_MIN     $with_suexec_uid_min
-#define AC_SUEXEC_GID_MIN     $with_suexec_gid_min
+#define AC_SUEXEC_USERDIR     "$with_suexec_userdir"
+EOF
+    if [ ".$have_suexec_docroot" = .yes ]; then
+cat >> $topdir/include/acr_cc$bits.h << EOF
+#define AC_SUEXEC_DOCROOT     "$with_suexec_docroot"
 EOF
-    if [ ".$have_suexec_safe_path" = .yes ]; then
+    fi
+    if [ ".$have_suexec_logfile" = .yes ]; then
+cat >> $topdir/include/acr_cc$bits.h << EOF
+#define AC_SUEXEC_LOGFILE     "$with_suexec_logfile"
+EOF
+    fi
+    if [ ".$have_suexec_safepath" = .yes ]; then
+cat >> $topdir/include/acr_cc$bits.h << EOF
+#define AC_SUEXEC_SAFE_PATH   "$with_suexec_safepath"
+EOF
+    fi
+    if [ ".$have_suexec_umask" = .yes ]; then
 cat >> $topdir/include/acr_cc$bits.h << EOF
-#define AC_SUEXEC_SAFE_PATH   "$with_suexec_safe_path"
+#define AC_SUEXEC_UMASK       $with_suexec_umask
 EOF
     fi
 fi
@@ -1322,7 +1366,8 @@
 fi
 
 shflags=`echo $shflags | sed 's/??/\\$/g'`
-exflags=`echo $exflags | sed 's/??/\\$/g'`
+ldrpath=`echo $ldrpath | sed 's/??/\\$/g'`
+lddarch=`echo $lddarch | sed 's/??/\\$/g'`
 modules=`echo $modules | sed 's/??/\\$/g'`
 includes=`echo $includes | sed 's/??/\\$/g'`
 sslflags=`echo $sslflags | sed 's/??/\\$/g'`
@@ -1355,7 +1400,8 @@
     -e 's|@asflags@|'"$asflags"'|g' \
     -e 's|@ccflags@|'"$ccflags"'|g' \
     -e 's|@ccshare@|'"$ccshare"'|g' \
-    -e 's|@exflags@|'"$exflags"'|g' \
+    -e 's|@ldrpath@|'"$ldrpath"'|g' \
+    -e 's|@lddarch@|'"$lddarch"'|g' \
     -e 's|@cppopts@|'"$cppopts"'|g' \
     -e 's|@cxxopts@|'"$cxxopts"'|g' \
     -e 's|@ldflags@|'"$ldflags"'|g' \

Added: commons/sandbox/runtime/trunk/src/main/native/support/suexec.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/support/suexec.c?rev=903586&view=auto
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/support/suexec.c (added)
+++ commons/sandbox/runtime/trunk/src/main/native/support/suexec.c Wed Jan 27 10:00:34 2010
@@ -0,0 +1,556 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * suexec.c -- "Wrapper" support program for suEXEC behaviour for Apache
+ *
+ ***********************************************************************
+ *
+ * NOTE! : DO NOT edit this code!!!  Unless you know what you are doing,
+ *         editing this code might open up your system in unexpected
+ *         ways to would-be crackers.  Every precaution has been taken
+ *         to make this code as safe as possible; alter it at your own
+ *         risk.
+ *
+ ***********************************************************************
+ *
+ *
+ */
+
+/*
+ * Apache Common Runtime NOTE:
+ * The code is copy of Httpd suexec with modified #defines so it fits
+ * our configure system. Other then that, there is no functional change
+ * from the Httpd's suexec util.
+ */
+
+#include "acr.h"
+#include "acr_private.h"
+#include "acr_arch.h"
+#include "suexec.h"
+
+#include <pwd.h>
+#include <grp.h>
+
+#define SUEXEC_ENVBUF 256
+
+extern char **environ;
+
+static const char *const safe_env_lst[] =
+{
+    /* variable name starts with */
+    "HTTP_",
+    "SSL_",
+
+    /* variable name is */
+    "AUTH_TYPE=",
+    "CONTENT_LENGTH=",
+    "CONTENT_TYPE=",
+    "DATE_GMT=",
+    "DATE_LOCAL=",
+    "DOCUMENT_NAME=",
+    "DOCUMENT_PATH_INFO=",
+    "DOCUMENT_ROOT=",
+    "DOCUMENT_URI=",
+    "GATEWAY_INTERFACE=",
+    "HTTPS=",
+    "LAST_MODIFIED=",
+    "PATH_INFO=",
+    "PATH_TRANSLATED=",
+    "QUERY_STRING=",
+    "QUERY_STRING_UNESCAPED=",
+    "REMOTE_ADDR=",
+    "REMOTE_HOST=",
+    "REMOTE_IDENT=",
+    "REMOTE_PORT=",
+    "REMOTE_USER=",
+    "REDIRECT_HANDLER=",
+    "REDIRECT_QUERY_STRING=",
+    "REDIRECT_REMOTE_USER=",
+    "REDIRECT_STATUS=",
+    "REDIRECT_URL=",
+    "REQUEST_METHOD=",
+    "REQUEST_URI=",
+    "SCRIPT_FILENAME=",
+    "SCRIPT_NAME=",
+    "SCRIPT_URI=",
+    "SCRIPT_URL=",
+    "SERVER_ADMIN=",
+    "SERVER_NAME=",
+    "SERVER_ADDR=",
+    "SERVER_PORT=",
+    "SERVER_PROTOCOL=",
+    "SERVER_SIGNATURE=",
+    "SERVER_SOFTWARE=",
+    "UNIQUE_ID=",
+    "USER_NAME=",
+    "TZ=",
+    NULL
+};
+
+#if HAVE_SUEXEC_LOG
+static FILE *log = NULL;
+static void err_output(int is_error, const char *fmt, va_list ap)
+{
+    time_t timevar;
+    struct tm *lt;
+
+    if (!log) {
+        if ((log = fopen(AC_SUEXEC_LOGFILE, "a")) == NULL) {
+            fprintf(stderr, "suexec failure: could not open log file\n");
+            perror("fopen");
+            exit(1);
+        }
+    }
+
+    if (is_error) {
+        fprintf(stderr, "suexec policy violation: see suexec log for more "
+                        "details\n");
+    }
+
+    time(&timevar);
+    lt = localtime(&timevar);
+
+    fprintf(log, "[%d-%.2d-%.2d %.2d:%.2d:%.2d]: ",
+            lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday,
+            lt->tm_hour, lt->tm_min, lt->tm_sec);
+
+    vfprintf(log, fmt, ap);
+
+    fflush(log);
+    return;
+}
+
+static void log_err(const char *fmt,...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    err_output(1, fmt, ap); /* 1 == is_error */
+    va_end(ap);
+    return;
+}
+
+static void log_no_err(const char *fmt,...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    err_output(0, fmt, ap); /* 0 == !is_error */
+    va_end(ap);
+    return;
+}
+
+#define LOG_ERR(x)      log_err x
+#define LOG_INFO(x)     log_no_err x
+
+#else
+
+#define LOG_ERR(x)      (void)0
+#define LOG_INFO(x)     (void)0
+
+#endif /* HAVE_SUEXEC_LOG */
+
+static void clean_env(void)
+{
+    char pathbuf[512];
+    char **cleanenv;
+    char **ep;
+    int cidx = 0;
+    int idx;
+
+    /* While cleaning the environment, the environment should be clean.
+     * (e.g. malloc() may get the name of a file for writing debugging info.
+     * Bad news if MALLOC_DEBUG_FILE is set to /etc/passwd.  Sprintf() may be
+     * susceptible to bad locale settings....)
+     * (from PR 2790)
+     */
+    char **envp = environ;
+    char *empty_ptr = NULL;
+
+    environ = &empty_ptr; /* VERY safe environment */
+
+    if ((cleanenv = (char **) calloc(SUEXEC_ENVBUF, sizeof(char *))) == NULL) {
+        LOG_ERR(("failed to malloc memory for environment\n"));
+        exit(120);
+    }
+
+    sprintf(pathbuf, "PATH=%s", AC_SUEXEC_SAFE_PATH);
+    cleanenv[cidx] = strdup(pathbuf);
+    cidx++;
+
+    for (ep = envp; *ep && cidx < SUEXEC_ENVBUF-1; ep++) {
+        for (idx = 0; safe_env_lst[idx]; idx++) {
+            if (!strncmp(*ep, safe_env_lst[idx],
+                         strlen(safe_env_lst[idx]))) {
+                cleanenv[cidx] = *ep;
+                cidx++;
+                break;
+            }
+        }
+    }
+
+    cleanenv[cidx] = NULL;
+
+    environ = cleanenv;
+}
+
+int main(int argc, char *argv[])
+{
+    int userdir = 0;        /* ~userdir flag             */
+    uid_t uid;              /* user information          */
+    gid_t gid;              /* target group placeholder  */
+    char *target_uname;     /* target user name          */
+    char *target_gname;     /* target group name         */
+    char *target_homedir;   /* target home directory     */
+    char *actual_uname;     /* actual user name          */
+    char *actual_gname;     /* actual group name         */
+    char *prog;             /* name of this program      */
+    char *cmd;              /* command to be executed    */
+    char cwd[PATH_MAX];     /* current working directory */
+    char dwd[PATH_MAX];     /* docroot working directory */
+    struct passwd *pw;      /* password entry holder     */
+    struct group *gr;       /* group entry holder        */
+    struct_stat_t dir_info;   /* directory info holder     */
+    struct_stat_t prg_info;   /* program info holder       */
+
+    /*
+     * Start with a "clean" environment
+     */
+    clean_env();
+
+    prog = argv[0];
+    /*
+     * Check existence/validity of the UID of the user
+     * running this program.  Error out if invalid.
+     */
+    uid = getuid();
+    if ((pw = getpwuid(uid)) == NULL) {
+        LOG_ERR(("crit: invalid uid: (%ld)\n", uid));
+        exit(102);
+    }
+    /*
+     * See if this is a 'how were you compiled' request, and
+     * comply if so.
+     */
+    if ((argc > 1)
+        && (! strcmp(argv[1], "-V"))
+        && ((uid == 0)
+        || (! strcmp(AC_SUEXEC_USER, pw->pw_name)))) {
+#ifdef AC_SUEXEC_DOCROOT
+        fprintf(stderr, " -D SUEXEC_DOCROOT=\"%s\"\n", AC_SUEXEC_DOCROOT);
+#endif
+#ifdef AC_SUEXEC_GID_MIN
+        fprintf(stderr, " -D SUEXEC_GID_MIN=%d\n", AC_SUEXEC_GID_MIN);
+#endif
+#ifdef AC_SUEXEC_USER
+        fprintf(stderr, " -D SUEXEC_USER=\"%s\"\n", AC_SUEXEC_USER);
+#endif
+#if HAVE_SUEXEC_LOG
+#ifdef AC_SUEXEC_LOGFILE
+        fprintf(stderr, " -D SUEXEC_LOGFILE=\"%s\"\n", AC_SUEXEC_LOGFILE);
+#endif
+#endif
+#ifdef AC_SUEXEC_SAFE_PATH
+        fprintf(stderr, " -D SUEXEC_SAFE_PATH=\"%s\"\n", AC_SUEXEC_SAFE_PATH);
+#endif
+#ifdef AP_SUEXEC_UMASK
+        fprintf(stderr, " -D SUEXEC_UMASK=%03o\n", AP_SUEXEC_UMASK);
+#endif
+#ifdef AC_SUEXEC_UID_MIN
+        fprintf(stderr, " -D SUEXEC_UID_MIN=%d\n", AC_SUEXEC_UID_MIN);
+#endif
+#ifdef AC_SUEXEC_USERDIR
+        fprintf(stderr, " -D SUEXEC_USERDIR=\"%s\"\n", AC_SUEXEC_USERDIR);
+#endif
+        exit(0);
+    }
+    /*
+     * If there are a proper number of arguments, set
+     * all of them to variables.  Otherwise, error out.
+     */
+    if (argc < 4) {
+        LOG_ERR(("too few arguments\n"));
+        exit(101);
+    }
+    target_uname = argv[1];
+    target_gname = argv[2];
+    cmd = argv[3];
+
+    /*
+     * Check to see if the user running this program
+     * is the user allowed to do so as defined in
+     * suexec.h.  If not the allowed user, error out.
+     */
+    if (strcmp(AC_SUEXEC_USER, pw->pw_name)) {
+        LOG_ERR(("user mismatch (%s instead of %s)\n",
+                 pw->pw_name, AC_SUEXEC_USER));
+        exit(103);
+    }
+
+    /*
+     * Check for a leading '/' (absolute path) in the command to be executed,
+     * or attempts to back up out of the current directory,
+     * to protect against attacks.  If any are
+     * found, error out.  Naughty naughty crackers.
+     */
+    if ((cmd[0] == '/') || (!strncmp(cmd, "../", 3))
+        || (strstr(cmd, "/../") != NULL)) {
+        LOG_ERR(("invalid command (%s)\n", cmd));
+        exit(104);
+    }
+
+    /*
+     * Check to see if this is a ~userdir request.  If
+     * so, set the flag, and remove the '~' from the
+     * target username.
+     */
+    if (!strncmp("~", target_uname, 1)) {
+        target_uname++;
+        userdir = 1;
+    }
+
+    /*
+     * Error out if the target username is invalid.
+     */
+    if (strspn(target_uname, "1234567890") != strlen(target_uname)) {
+        if ((pw = getpwnam(target_uname)) == NULL) {
+            LOG_ERR(("invalid target user name: (%s)\n", target_uname));
+            exit(105);
+        }
+    }
+    else {
+        if ((pw = getpwuid(atoi(target_uname))) == NULL) {
+            LOG_ERR(("invalid target user id: (%s)\n", target_uname));
+            exit(121);
+        }
+    }
+
+    /*
+     * Error out if the target group name is invalid.
+     */
+    if (strspn(target_gname, "1234567890") != strlen(target_gname)) {
+        if ((gr = getgrnam(target_gname)) == NULL) {
+            LOG_ERR(("invalid target group name: (%s)\n", target_gname));
+            exit(106);
+        }
+    }
+    else {
+        if ((gr = getgrgid(atoi(target_gname))) == NULL) {
+            LOG_ERR(("invalid target group id: (%s)\n", target_gname));
+            exit(106);
+        }
+    }
+    gid = gr->gr_gid;
+    actual_gname = strdup(gr->gr_name);
+
+    /*
+     * Save these for later since initgroups will hose the struct
+     */
+    uid = pw->pw_uid;
+    actual_uname = strdup(pw->pw_name);
+    target_homedir = strdup(pw->pw_dir);
+
+    /*
+     * Log the transaction here to be sure we have an open log
+     * before we setuid().
+     */
+    LOG_INFO(("uid: (%s/%s) gid: (%s/%s) cmd: %s\n",
+              target_uname, actual_uname,
+              target_gname, actual_gname,
+              cmd));
+
+    /*
+     * Error out if attempt is made to execute as root or as
+     * a UID less than AC_SUEXEC_UID_MIN.  Tsk tsk.
+     */
+    if ((uid == 0) || (uid < AC_SUEXEC_UID_MIN)) {
+        LOG_ERR(("cannot run as forbidden uid (%d/%s)\n", uid, cmd));
+        exit(107);
+    }
+
+    /*
+     * Error out if attempt is made to execute as root group
+     * or as a GID less than AC_SUEXEC_GID_MIN.  Tsk tsk.
+     */
+    if ((gid == 0) || (gid < AC_SUEXEC_GID_MIN)) {
+        LOG_ERR(("cannot run as forbidden gid (%d/%s)\n", gid, cmd));
+        exit(108);
+    }
+
+    /*
+     * Change UID/GID here so that the following tests work over NFS.
+     *
+     * Initialize the group access list for the target user,
+     * and setgid() to the target group. If unsuccessful, error out.
+     */
+    if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) {
+        LOG_ERR(("failed to setgid (%ld: %s)\n", gid, cmd));
+        exit(109);
+    }
+
+    /*
+     * setuid() to the target user.  Error out on fail.
+     */
+    if ((setuid(uid)) != 0) {
+        LOG_ERR(("failed to setuid (%ld: %s)\n", uid, cmd));
+        exit(110);
+    }
+
+    /*
+     * Get the current working directory, as well as the proper
+     * document root (dependant upon whether or not it is a
+     * ~userdir request).  Error out if we cannot get either one,
+     * or if the current working directory is not in the docroot.
+     * Use chdir()s and getcwd()s to avoid problems with symlinked
+     * directories.  Yuck.
+     */
+    if (getcwd(cwd, PATH_MAX) == NULL) {
+        LOG_ERR(("cannot get current working directory\n"));
+        exit(111);
+    }
+
+    if (userdir) {
+        if (((chdir(target_homedir)) != 0) ||
+            ((chdir(AC_SUEXEC_USERDIR)) != 0) ||
+            ((getcwd(dwd, PATH_MAX)) == NULL) ||
+            ((chdir(cwd)) != 0)) {
+            LOG_ERR(("cannot get docroot information (%s)\n", target_homedir));
+            exit(112);
+        }
+    }
+    else {
+        if (((chdir(AC_SUEXEC_DOCROOT)) != 0) ||
+            ((getcwd(dwd, PATH_MAX)) == NULL) ||
+            ((chdir(cwd)) != 0)) {
+            LOG_ERR(("cannot get docroot information (%s)\n", AC_SUEXEC_DOCROOT));
+            exit(113);
+        }
+    }
+
+    if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
+        LOG_ERR(("command not in docroot (%s/%s)\n", cwd, cmd));
+        exit(114);
+    }
+
+    /*
+     * Stat the cwd and verify it is a directory, or error out.
+     */
+    if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) {
+        LOG_ERR(("cannot stat directory: (%s)\n", cwd));
+        exit(115);
+    }
+
+    /*
+     * Error out if cwd is writable by others.
+     */
+    if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
+        LOG_ERR(("directory is writable by others: (%s)\n", cwd));
+        exit(116);
+    }
+
+    /*
+     * Error out if we cannot stat the program.
+     */
+    if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
+        LOG_ERR(("cannot stat program: (%s)\n", cmd));
+        exit(117);
+    }
+
+    /*
+     * Error out if the program is writable by others.
+     */
+    if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
+        LOG_ERR(("file is writable by others: (%s/%s)\n", cwd, cmd));
+        exit(118);
+    }
+
+    /*
+     * Error out if the file is setuid or setgid.
+     */
+    if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) {
+        LOG_ERR(("file is either setuid or setgid: (%s/%s)\n", cwd, cmd));
+        exit(119);
+    }
+
+    /*
+     * Error out if the target name/group is different from
+     * the name/group of the cwd or the program.
+     */
+    if ((uid != dir_info.st_uid) ||
+        (gid != dir_info.st_gid) ||
+        (uid != prg_info.st_uid) ||
+        (gid != prg_info.st_gid)) {
+        LOG_ERR(("target uid/gid (%ld/%ld) mismatch "
+                 "with directory (%ld/%ld) or program (%ld/%ld)\n",
+                uid, gid,
+                dir_info.st_uid, dir_info.st_gid,
+                prg_info.st_uid, prg_info.st_gid));
+        exit(120);
+    }
+    /*
+     * Error out if the program is not executable for the user.
+     * Otherwise, she won't find any error in the logs except for
+     * "[error] Premature end of script headers: ..."
+     */
+    if (!(prg_info.st_mode & S_IXUSR)) {
+        LOG_ERR(("file has no execute permission: (%s/%s)\n", cwd, cmd));
+        exit(121);
+    }
+
+#ifdef AC_SUEXEC_UMASK
+    /*
+     * umask() uses inverse logic; bits are CLEAR for allowed access.
+     */
+    if ((~AP_SUEXEC_UMASK) & 0022) {
+        LOG_ERR(("notice: AP_SUEXEC_UMASK of %03o allows "
+                 "write permission to group and/or other\n", AC_SUEXEC_UMASK));
+    }
+    umask(AC_SUEXEC_UMASK);
+#endif /* AC_SUEXEC_UMASK */
+
+#if HAVE_SUEXEC_LOG
+    /* Be sure to close the log file so the CGI can't mess with it. */
+    if (log != NULL) {
+        /*
+         * ask fcntl(2) to set the FD_CLOEXEC flag on the log file,
+         * so it'll be automagically closed if the exec() call succeeds.
+         */
+        fflush(log);
+        setbuf(log, NULL);
+        if ((fcntl(fileno(log), F_SETFD, FD_CLOEXEC) == -1)) {
+            LOG_ERR(("error: can't set close-on-exec flag"));
+            exit(122);
+        }
+    }
+#endif
+
+    /*
+     * Execute the command, replacing our image with its own.
+     */
+    execv(cmd, &argv[3]);
+    /*
+     * (I can't help myself...sorry.)
+     *
+     * Uh oh.  Still here.  Where's the kaboom?  There was supposed to be an
+     * EARTH-shattering kaboom!
+     *
+     * Oh well, log the failure and error out.
+     */
+    LOG_ERR(("(%d)%s: exec failed (%s)\n", errno, strerror(errno), cmd));
+    exit(255);
+}
+

Propchange: commons/sandbox/runtime/trunk/src/main/native/support/suexec.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/runtime/trunk/src/main/native/support/suexec.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/support/suexec.h?rev=903586&view=auto
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/support/suexec.h (added)
+++ commons/sandbox/runtime/trunk/src/main/native/support/suexec.h Wed Jan 27 10:00:34 2010
@@ -0,0 +1,116 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file  suexec.h
+ * @brief user-definable variables for the suexec wrapper code.
+ *        (See README.configure on how to customize these variables.)
+ */
+
+
+#ifndef _SUEXEC_H
+#define _SUEXEC_H
+
+/*
+ * SUEXEC_USER -- Define as the username under which Apache normally
+ *                runs.  This is the only user allowed to execute
+ *                this program.
+ */
+#ifndef AC_SUEXEC_USER
+#define AC_SUEXEC_USER "www"
+#endif
+
+/*
+ * UID_MIN -- Define this as the lowest UID allowed to be a target user
+ *            for suEXEC.  For most systems, 500 or 100 is common.
+ */
+#ifndef AC_SUEXEC_UID_MIN
+#define AC_SUEXEC_UID_MIN 100
+#endif
+
+/*
+ * GID_MIN -- Define this as the lowest GID allowed to be a target group
+ *            for suEXEC.  For most systems, 100 is common.
+ */
+#ifndef AC_SUEXEC_GID_MIN
+#define AC_SUEXEC_GID_MIN 100
+#endif
+
+/*
+ * SUEXEC_USERDIR -- Define to be the subdirectory under users'
+ *                   home directories where suEXEC access should
+ *                   be allowed.  All executables under this directory
+ *                   will be executable by suEXEC as the user so
+ *                   they should be "safe" programs.  If you are
+ *                   using a "simple" UserDir directive (ie. one
+ *                   without a "*" in it) this should be set to
+ *                   the same value.  suEXEC will not work properly
+ *                   in cases where the UserDir directive points to
+ *                   a location that is not the same as the user's
+ *                   home directory as referenced in the passwd file.
+ *
+ *                   If you have VirtualHosts with a different
+ *                   UserDir for each, you will need to define them to
+ *                   all reside in one parent directory; then name that
+ *                   parent directory here.  IF THIS IS NOT DEFINED
+ *                   PROPERLY, ~USERDIR CGI REQUESTS WILL NOT WORK!
+ *                   See the suEXEC documentation for more detailed
+ *                   information.
+ */
+#ifndef AC_SUEXEC_USERDIR
+#define AC_SUEXEC_USERDIR "public_html"
+#endif
+
+/*
+ * SUEXEC_LOG    -- Define this as a filename if you want all suEXEC
+ *                  transactions and errors logged for auditing and
+ *                  debugging purposes.
+ */
+#ifndef AC_SUEXEC_LOGFILE
+#if defined(WIN32)
+#define AC_SUEXEC_LOGFILE "%SystemRoot%\\Logs\\ApacheCommons\\suexec.log"
+#else
+#define AC_SUEXEC_LOGFILE "/var/log/suexec.log"
+#endif
+#endif
+
+/*
+ * SUEXEC_ROOT -- Define as the DocumentRoot set for Apache.  This
+ *                will be the only hierarchy (aside from UserDirs)
+ *                that can be used for suEXEC behavior.
+ */
+#ifndef AC_SUEXEC_DOCROOT
+#if defined(WIN32)
+#define AC_SUEXEC_DOCROOT "%ProgramFiles%\\Apache Software Foundation\\Apache Commons"
+#else
+#define AC_SUEXEC_DOCROOT "/var/www"
+#endif
+#endif
+
+/*
+ * SAFE_PATH -- Define a safe PATH environment to pass to CGI executables.
+ *
+ */
+#ifndef AC_SUEXEC_SAFE_PATH
+#if defined(WIN32)
+#define AC_SUEXEC_SAFE_PATH "%SystemRoot%\\System32;%SystemRoot%"
+#else
+#define AC_SUEXEC_SAFE_PATH "/usr/local/bin:/usr/bin:/bin"
+#endif
+#endif
+
+#endif /* _SUEXEC_H */
+

Propchange: commons/sandbox/runtime/trunk/src/main/native/support/suexec.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/sandbox/runtime/trunk/src/main/native/support/win32/suexec.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/support/win32/suexec.c?rev=903586&r1=903585&r2=903586&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/support/win32/suexec.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/support/win32/suexec.c Wed Jan 27 10:00:34 2010
@@ -34,6 +34,7 @@
 #include "acr.h"
 #include "acr_private.h"
 #include "acr_arch.h"
+#include "suexec.h"
 
 /*
  * ---------------------------------------------------------------------