suexec.c revision b99dbaab171d91e1b664397cc40e039d0c087c65
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
* reserved.
*
* 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
* 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
*/
/*
* 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.
*
***********************************************************************
*
*
*/
#include "ap_config.h"
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "suexec.h"
#include "ap_config_auto.h"
#if HAVE_PWD_H
#include <pwd.h>
#endif
#if HAVE_GRP_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)
{
/* 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)
#define AP_MAXPATH MAXPATHLEN
#else
#define AP_MAXPATH 8192
#endif
#define AP_ENVBUF 256
extern char **environ;
char *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",
"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",
};
{
#ifdef AP_LOG_EXEC
if (!log) {
perror("fopen");
exit(1);
}
}
#endif /* AP_LOG_EXEC */
return;
}
{
#ifdef AP_LOG_EXEC
#endif /* AP_LOG_EXEC */
return;
}
static void clean_env(void)
{
char pathbuf[512];
char **cleanenv;
char **ep;
int cidx = 0;
int idx;
log_err("failed to malloc memory for environment\n");
exit(120);
}
cidx++;
cidx++;
}
else {
cidx++;
break;
}
}
}
}
}
{
int userdir = 0; /* ~userdir flag */
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 */
/*
* 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);
}
/*
* running this program. Error out if invalid.
*/
exit(102);
}
/*
* 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.
*/
#ifdef _OSD_POSIX
exit(103);
}
#else /*_OSD_POSIX*/
exit(103);
}
#endif /*_OSD_POSIX*/
/*
* 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.
*/
exit(104);
}
/*
* Check to see if this is a ~userdir request. If
* so, set the flag, and remove the '~' from the
* target username.
*/
target_uname++;
userdir = 1;
}
/*
* Error out if the target username is invalid.
*/
exit(105);
}
}
else {
exit(121);
}
}
/*
* Error out if the target group name is invalid.
*/
exit(106);
}
}
else {
}
#ifdef _OSD_POSIX
/*
* Initialize BS2000 user environment
*/
{
int status;
{
case -1: /* Error */
log_err("failed to setup bs2000 environment for user %s: %s\n",
exit(150);
case 0: /* Child */
break;
default: /* Father */
;
/* @@@ FIXME: should we deal with STOP signals as well? */
if (WIFSIGNALED(status))
}
}
#endif /*_OSD_POSIX*/
/*
* Save these for later since initgroups will hose the struct
*/
/*
* 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",
cmd);
/*
* Error out if attempt is made to execute as root or as
* a UID less than AP_UID_MIN. Tsk tsk.
*/
exit(107);
}
/*
* Error out if attempt is made to execute as root group
* or as a GID less than AP_GID_MIN. Tsk tsk.
*/
exit(108);
}
/*
*
* Initialize the group access list for the target user,
* and setgid() to the target group. If unsuccessful, error out.
*/
exit(109);
}
/*
* setuid() to the target user. Error out on fail.
*/
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.
*/
log_err("cannot get current working directory\n");
exit(111);
}
if (userdir) {
if (((chdir(target_homedir)) != 0) ||
((chdir(AP_USERDIR_SUFFIX)) != 0) ||
exit(112);
}
}
else {
if (((chdir(AP_DOC_ROOT)) != 0) ||
exit(113);
}
}
exit(114);
}
/*
* Stat the cwd and verify it is a directory, or error out.
*/
exit(115);
}
/*
* Error out if cwd is writable by others.
*/
exit(116);
}
/*
* Error out if we cannot stat the program.
*/
exit(117);
}
/*
* Error out if the program is writable by others.
*/
exit(118);
}
/*
* Error out if the file is setuid or setgid.
*/
exit(119);
}
/*
*/
"with directory (%ld/%ld) or program (%ld/%ld)\n",
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: ..."
*/
exit(121);
}
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.
*/
}
/*
* Execute the command, replacing our image with its own.
*/
#ifdef NEED_HASHBANG_EMUL
/* We need the #! emulation when we want to execute scripts */
{
extern char **environ;
}
#else /*NEED_HASHBANG_EMUL*/
#endif /*NEED_HASHBANG_EMUL*/
/*
* (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.
*/
exit(255);
}