-/* ====================================================================
- * The Apache Software License, Version 1.1
+/* 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
*
- * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
- * reserved.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Apache" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
+ * 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.
*/
/*
***********************************************************************
*
* 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
+ * 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.
*
*
*/
+#include "apr.h"
#include "ap_config.h"
+#include "suexec.h"
+
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
-
-#include "suexec.h"
+#if APR_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#include <grp.h>
#endif
-/*
- ***********************************************************************
- * There is no initgroups() in QNX, so I believe this is safe :-)
- * Use cc -osuexec -3 -O -mf -DQNX suexec.c to compile.
- *
- * May 17, 1997.
- * Igor N. Kovalenko -- infoh@mail.wplus.net
- ***********************************************************************
- */
-
-#if defined(NEED_INITGROUPS)
-int initgroups(const char *name, gid_t basegid)
-{
- /* QNX and MPE do not appear to support supplementary groups. */
- return 0;
-}
-#endif
-
#if defined(PATH_MAX)
#define AP_MAXPATH PATH_MAX
#elif defined(MAXPATHLEN)
extern char **environ;
static FILE *log = NULL;
-char *safe_env_lst[] =
+static const char *const safe_env_lst[] =
{
- "AUTH_TYPE",
- "CONTENT_LENGTH",
- "CONTENT_TYPE",
- "DATE_GMT",
- "DATE_LOCAL",
- "DOCUMENT_NAME",
- "DOCUMENT_PATH_INFO",
- "DOCUMENT_ROOT",
- "DOCUMENT_URI",
- "FILEPATH_INFO",
- "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_QUERY_STRING",
- "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_SOFTWARE",
- "UNIQUE_ID",
- "USER_NAME",
- "TZ",
+ /* 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
};
-static void err_output(const char *fmt, va_list ap)
+static void err_output(int is_error, const char *fmt, va_list ap)
{
#ifdef AP_LOG_EXEC
time_t timevar;
if (!log) {
if ((log = fopen(AP_LOG_EXEC, "a")) == NULL) {
- fprintf(stderr, "failed to open log file\n");
+ 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);
va_list ap;
va_start(ap, fmt);
- err_output(fmt, ap);
+ err_output(1, fmt, ap); /* 1 == is_error */
+ va_end(ap);
+#endif /* AP_LOG_EXEC */
+ return;
+}
+
+static void log_no_err(const char *fmt,...)
+{
+#ifdef AP_LOG_EXEC
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_output(0, fmt, ap); /* 0 == !is_error */
va_end(ap);
#endif /* AP_LOG_EXEC */
return;
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(AP_ENVBUF, sizeof(char *))) == NULL) {
log_err("failed to malloc memory for environment\n");
cleanenv[cidx] = strdup(pathbuf);
cidx++;
- for (ep = environ; *ep && cidx < AP_ENVBUF-1; ep++) {
- if (!strncmp(*ep, "HTTP_", 5) || !strncmp(*ep, "SSL_", 4)) {
- cleanenv[cidx] = *ep;
- cidx++;
- }
- else {
- 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;
- }
+ for (ep = envp; *ep && cidx < AP_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;
}
}
}
struct stat dir_info; /* directory info holder */
struct stat prg_info; /* program info holder */
+ /*
+ * Start with a "clean" environment
+ */
+ clean_env();
+
prog = argv[0];
/*
* Check existence/validity of the UID of the user
log_err("invalid target group name: (%s)\n", target_gname);
exit(106);
}
- gid = gr->gr_gid;
- actual_gname = strdup(gr->gr_name);
}
else {
- gid = atoi(target_gname);
- actual_gname = strdup(target_gname);
+ 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);
#ifdef _OSD_POSIX
/*
}
}
#endif /*_OSD_POSIX*/
-
+
/*
* Save these for later since initgroups will hose the struct
*/
target_homedir = strdup(pw->pw_dir);
/*
- * Log the transaction here to be sure we have an open log
+ * Log the transaction here to be sure we have an open log
* before we setuid().
*/
- log_err("uid: (%s/%s) gid: (%s/%s) cmd: %s\n",
- target_uname, actual_uname,
- target_gname, actual_gname,
- cmd);
+ log_no_err("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
}
umask(AP_SUEXEC_UMASK);
#endif /* AP_SUEXEC_UMASK */
- clean_env();
- /*
- * Be sure to close the log file so the CGI can't
- * mess with it. If the exec fails, it will be reopened
- * automatically when log_err is called. Note that the log
- * might not actually be open if AP_LOG_EXEC isn't defined.
- * However, the "log" cell isn't ifdef'd so let's be defensive
- * and assume someone might have done something with it
- * outside an ifdef'd AP_LOG_EXEC block.
- */
+ /* Be sure to close the log file so the CGI can't mess with it. */
if (log != NULL) {
+#if APR_HAVE_FCNTL_H
+ /*
+ * 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);
+ }
+#else
+ /*
+ * In this case, exec() errors won't be logged because we have already
+ * dropped privileges and won't be able to reopen the log file.
+ */
fclose(log);
log = NULL;
+#endif
}
/*