Debian Bug report logs - #47951
apache-common: suexec unable to do <--#exec cmd with parameters

version graph

Package: apache-common; Maintainer for apache-common is (unknown);

Reported by: Robert Varga <robi@piros.zold.net>

Date: Thu, 21 Oct 1999 10:18:00 UTC

Severity: wishlist

Found in version 1.3.3-7

Done: Johnie Ingram <johnie@debian.org>

Bug is archived. No further changes may be made.

Toggle useless messages

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to debian-bugs-dist@lists.debian.org, Johnie Ingram <johnie@debian.org>:
Bug#47951; Package apache-common. Full text and rfc822 format available.

Acknowledgement sent to Robert Varga <robi@piros.zold.net>:
New Bug report received and forwarded. Copy sent to Johnie Ingram <johnie@debian.org>. Full text and rfc822 format available.

Message #5 received at submit@bugs.debian.org (full text, mbox):

From: Robert Varga <robi@piros.zold.net>
To: submit@bugs.debian.org
Subject: apache-common: suexec unable to do <--#exec cmd with parameters
Date: 21 Oct 1999 10:09:17 -0000
Package: apache-common
Version: 1.3.3-7

I haven't looked at it but probably it is the same in later apache
versions as well.

Occurs when:
  A server-parsed html document not run as www-data.www-data contains a
  <--#exec tag with a cmd attribute containing more than one words (a
  command with parameters).

Normal behaviour:

  The running a program from an SSI without suexec can be carried out with
  or without parameters.

Problem nature:

  If suexec is used to run the command, it reports:

    [1999-10-18 13:13:11]: cannot stat program: (command parameters)


The problematic code:

  It is due to the fact that suexec tries to use the whole command as a
  filename, not only its first word.

  The other problem in suexec is that even if it would only check the
  first word, the execv() would also fail since the whole command with all
  parameters are received in one char*, which is not the filename of the
  program again, and therefore cannot act as the first parameter of the
  execv() call.


The fix can be carried out at two places:

  1. Parsing the command string and passing each parameter to suexec in a
  separate command line parameter. This needs fixing every place where
  suexec is called.

  2. Separating the command string (argv[3]) to parameters in suexec and
  append all parameters after but not including argv[3] to the end of the
  array holding the separation of argv[3]. Use this array as the parameter
  of execv.

Included is my version of suexec.c containing a routine separating a
command string to parameters, which correctly handles quotes or
apostrophes, and does not give an error code anyway. It can be used in
suexec and in apache modules as well.

Its input is the char* cmd, and the number of additional parameters above
the minimal, and it returns a null-terminated array of char*. The 0-th
element is the program file name. A number of 0 pointers equal to the
second function parameter are left for the parameters above argv[3],
therefore the second parameter is argc-4.

The program filename is used at the lstat() function call in
line 705 (original line 452), and is used in the following error
messages where appropriate for complaining about program file
requirements.

The execv() parameters are replaced with the create parameter array and
its 0-th element for the exec filename.

Now here is my version of suexec, since the bug reporting page would not
allow multipart messages:


/* ====================================================================
 * Copyright (c) 1995-1998 The Apache Group.  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
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the Apache Group
 *    for use in the Apache HTTP server project (http://www.apache.org/)."
 *
 * 4. The names "Apache Server" and "Apache Group" 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 names without prior written
 *    permission of the Apache Group.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the Apache Group
 *    for use in the Apache HTTP server project (http://www.apache.org/)."
 *
 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
 * on public domain software written at the National Center for
 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
 * For more information on the Apache Group and the Apache HTTP server
 * project, please see <http://www.apache.org/>.
 *
 */

/*
 * 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 <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <stdarg.h>
#include <strings.h>

#include "suexec.h"

/*
 ***********************************************************************
 * 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)
#define AP_MAXPATH MAXPATHLEN
#else
#define AP_MAXPATH 8192
#endif

#define AP_ENVBUF 256

extern char **environ;
static FILE *log;

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_PORT",
    "SERVER_PROTOCOL",
    "SERVER_SOFTWARE",
    "UNIQUE_ID",
    "USER_NAME",
    "TZ",
    NULL
};


static void err_output(const char *fmt, va_list ap)
{
#ifdef LOG_EXEC
    time_t timevar;
    struct tm *lt;

    if (!log) {
	if ((log = fopen(LOG_EXEC, "a")) == NULL) {
	    fprintf(stderr, "failed to open log file\n");
	    perror("fopen");
	    exit(1);
	}
    }

    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);
#endif /* LOG_EXEC */
    return;
}

static void log_err(const char *fmt,...)
{
#ifdef LOG_EXEC
    va_list ap;

    va_start(ap, fmt);
    err_output(fmt, ap);
    va_end(ap);
#endif /* LOG_EXEC */
    return;
}

static void clean_env(void)
{
    char pathbuf[512];
    char **cleanenv;
    char **ep;
    int cidx = 0;
    int idx;


    if ((cleanenv = (char **) calloc(AP_ENVBUF, sizeof(char *))) == NULL) {
        log_err("failed to malloc memory for environment\n");
	exit(120);
    }

    sprintf(pathbuf, "PATH=%s", SAFE_PATH);
    cleanenv[cidx] = strdup(pathbuf);
    cidx++;

    for (ep = environ; *ep && cidx < AP_ENVBUF-1; ep++) {
	if (!strncmp(*ep, "HTTP_", 5)) {
	    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;
		}
	    }
	}
    }

    cleanenv[cidx] = NULL;

    environ = cleanenv;
}

#define MY_STATE_NORMAL 0
#define MY_STATE_SPACE 1
#define MY_STATE_QUOTES 2
#define MY_STATE_APOSTROPHES 3
#define MY_STATE_END 4

char** param_separate(char* params, int addl_slots) {
    int state, actpos, actarg_start, actarg_len, argnum;
    char **res=0;
    char backslash=0;
    
    if (params==0) return(0);
    
    if (*params==0) {
       res=(char**)malloc(sizeof(char*)*(1+addl_slots));
       for (actpos=0;actpos<addl_slots+1;++actpos) res[actpos]=0;
       return(res);
    }
    actpos=0;backslash=0;argnum=0;state=MY_STATE_SPACE;
    while (state!=MY_STATE_END) {
       switch (state) {
       
          case MY_STATE_SPACE: 
              switch (params[actpos]) {
                 case 0 : 
                          state=MY_STATE_END;
                          break;
                          
                 case ' ' :
                 case '\t':
                          break;              
       
                 case '\'':
                          state=MY_STATE_APOSTROPHES;
                          actarg_start=actpos+1;
                          break;
                 case '"':
                          state=MY_STATE_QUOTES;
                          actarg_start=actpos+1;
                          break;
                 default: 
                          state=MY_STATE_NORMAL;
                          actarg_start=actpos;
              }
              break;
                          
          case MY_STATE_NORMAL:
              
              switch (params[actpos]) {
                 case 0 : 
                          state=MY_STATE_END;
                          ++argnum;
                          actarg_len=actpos-actarg_start;
                          break;
                          
                 case ' ':
                 case '\t':
                          state=MY_STATE_SPACE;
                          ++argnum;
                          actarg_len=actpos-actarg_start;
                          break; 
              }
              break;

          case MY_STATE_APOSTROPHES:
              
              switch (params[actpos]) {
                 case 0 : 
                          state=MY_STATE_END;
                          ++argnum;
                          actarg_len=actpos-actarg_start;
                          break;
                 
                 case '\\':
                          backslash=1-backslash;        
                          break;        
                          
                 case '\'':
                          if (! backslash) {
                             state=MY_STATE_SPACE;
                             ++argnum;
                             actarg_len=actpos-actarg_start;
                          }
                          break; 
              }
              if (params[actpos]!='\\') backslash=0;
              break;
          
          case MY_STATE_QUOTES:
              
              switch (params[actpos]) {
                 case 0 : 
                          state=MY_STATE_END;
                          ++argnum;
                          actarg_len=actpos-actarg_start;
                          break;
                 
                 case '\\':
                          backslash=1-backslash;        
                          break;        
                          
                 case '"':
                          if (! backslash) {
                             state=MY_STATE_SPACE;
                             ++argnum;
                             actarg_len=actpos-actarg_start;
                          }
                          break; 
              }
              if (params[actpos]!='\\') backslash=0;
              break;
       }
       actpos++;
    }
    
    res=(char**)malloc(sizeof(char*)*(argnum+1+addl_slots));
    for (actpos=0;actpos<argnum+addl_slots+1;++argnum) res[actpos]=0;
    

    actpos=0;backslash=0;argnum=0;state=MY_STATE_SPACE;
    while (state!=MY_STATE_END) {
       switch (state) {
       
          case MY_STATE_SPACE: 
              switch (params[actpos]) {
                 case 0 : 
                          state=MY_STATE_END;
                          break;
                          
                 case ' ' :
                 case '\t':
                          break;              
       
                 case '\'':
                          state=MY_STATE_APOSTROPHES;
                          actarg_start=actpos+1;
                          break;
                 case '"':
                          state=MY_STATE_QUOTES;
                          actarg_start=actpos+1;
                          break;
                 default: 
                          state=MY_STATE_NORMAL;
                          actarg_start=actpos;
              }
              break;
                          
          case MY_STATE_NORMAL:
              
              switch (params[actpos]) {
                 case 0 : 
                          state=MY_STATE_END;
                          actarg_len=actpos-actarg_start;
                          res[argnum]=(char*)malloc(actarg_len+1);
                          strncpy(res[argnum],&params[actarg_start],actarg_len);
                          res[argnum][actarg_len]=0;
                          ++argnum;
                          break;
                          
                 case ' ':
                 case '\t':
                          state=MY_STATE_SPACE;
                          actarg_len=actpos-actarg_start;
                          res[argnum]=(char*)malloc(actarg_len+1);
                          strncpy(res[argnum],&params[actarg_start],actarg_len);
                          res[argnum][actarg_len]=0;
                          ++argnum;
                          break; 
              }
              break;

          case MY_STATE_APOSTROPHES:
              
              switch (params[actpos]) {
                 case 0 : 
                          state=MY_STATE_END;
                          actarg_len=actpos-actarg_start;
                          res[argnum]=(char*)malloc(actarg_len+1);
                          strncpy(res[argnum],&params[actarg_start],actarg_len);
                          res[argnum][actarg_len]=0;
                          ++argnum;
                          break;
                 
                 case '\\':
                          backslash=1-backslash;        
                          break;        
                          
                 case '\'':
                          if (! backslash) {
                             state=MY_STATE_SPACE;
                             actarg_len=actpos-actarg_start;
                             res[argnum]=(char*)malloc(actarg_len+1);
                             strncpy(res[argnum],&params[actarg_start],actarg_len);
                             res[argnum][actarg_len]=0;
                             ++argnum;
                          }
                          break; 
              }
              if (params[actpos]!='\\') backslash=0;
              break;
          
          case MY_STATE_QUOTES:
              
              switch (params[actpos]) {
                 case 0 : 
                          state=MY_STATE_END;
                          actarg_len=actpos-actarg_start;
                          res[argnum]=(char*)malloc(actarg_len+1);
                          strncpy(res[argnum],&params[actarg_start],actarg_len);
                          res[argnum][actarg_len]=0;
                          ++argnum;
                          break;
                 
                 case '\\':
                          backslash=1-backslash;        
                          break;        
                          
                 case '"':
                          if (! backslash) {
                             state=MY_STATE_SPACE;
                             actarg_len=actpos-actarg_start;
                             res[argnum]=(char*)malloc(actarg_len+1);
                             strncpy(res[argnum],&params[actarg_start],actarg_len);
                             res[argnum][actarg_len]=0;
                             ++argnum;
                          }
                          break; 
              }
              if (params[actpos]!='\\') backslash=0;
              break;
       }
       actpos++;
    }

    return(res);
}    


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    */

    int ind, ind2;    
    char **passedargv = 0;
    
    char cwd[AP_MAXPATH];	/* current working directory */
    char dwd[AP_MAXPATH];	/* docroot working directory */
    struct passwd *pw;		/* password entry holder     */
    struct group *gr;		/* group entry holder        */
    struct stat dir_info;	/* directory info holder     */
    struct stat prg_info;	/* program info holder       */

    /*
     * If there are a proper number of arguments, set
     * all of them to variables.  Otherwise, error out.
     */
    prog = argv[0];
    if (argc < 4) {
	log_err("too few arguments\n");
	exit(101);
    }
    target_uname = argv[1];
    target_gname = argv[2];
    cmd = argv[3];

    /*
     * 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("invalid uid: (%ld)\n", uid);
	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
    /* User name comparisons are case insensitive on BS2000/OSD */
    if (strcasecmp(HTTPD_USER, pw->pw_name)) {
        log_err("user mismatch (%s instead of %s)\n", pw->pw_name, HTTPD_USER);
	exit(103);
    }
#else  /*_OSD_POSIX*/
    if (strcmp(HTTPD_USER, pw->pw_name)) {
        log_err("user mismatch (%s instead of %s)\n", pw->pw_name, HTTPD_USER);
	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.
     */
    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 ((pw = getpwnam(target_uname)) == NULL) {
	log_err("invalid target user name: (%s)\n", target_uname);
	exit(105);
    }

    /*
     * 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);
	}
	gid = gr->gr_gid;
	actual_gname = strdup(gr->gr_name);
    }
    else {
	gid = atoi(target_gname);
	actual_gname = strdup(target_gname);
    }

    /*
     * 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_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
     * a UID less than UID_MIN.  Tsk tsk.
     */
    if ((uid == 0) || (uid < 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 GID_MIN.  Tsk tsk.
     */
    if ((gid == 0) || (gid < 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, AP_MAXPATH) == NULL) {
	log_err("cannot get current working directory\n");
	exit(111);
    }

    if (userdir) {
	if (((chdir(target_homedir)) != 0) ||
	    ((chdir(USERDIR_SUFFIX)) != 0) ||
	    ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
	    ((chdir(cwd)) != 0)) {
	    log_err("cannot get docroot information (%s)\n", target_homedir);
	    exit(112);
	}
    }
    else {
	if (((chdir(DOC_ROOT)) != 0) ||
	    ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
	    ((chdir(cwd)) != 0)) {
	    log_err("cannot get docroot information (%s)\n", DOC_ROOT);
	    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.
     */
    passedargv=param_separate(cmd,argc-4);
    for (ind=0; passedargv[ind]; ++ind);
    for (ind2=4;ind2<argc;++ind2,++ind) {
        if (argv[ind2]!=0) if (argv[ind2][0]!=0) passedargv[ind]=strdup(argv[ind2]);
        if (passedargv[ind]==0) {
            passedargv[ind]=malloc(1);
            passedargv[ind][0]=0;
        }
    }
    
    if (((lstat(passedargv[0], &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
	log_err("cannot stat program: (%s)\n", passedargv[0]);
	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, passedargv[0]);
	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, passedargv[0]);
	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, passedargv[0]);
	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.
     */
    fclose(log);
    log = NULL;

    /*
     * Execute the command, replacing our image with its own.
     */
    execv(passedargv[0], passedargv);
    /*
     * (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);

    for (ind=0;passedargv[ind];++ind) free(passedargv[ind]);
    free(passedargv);
    passedargv=0;

    exit(255);
}



-- System Information
Debian Release: 2.1
Kernel Version: Linux piros 2.0.37 #1 Fri Jul 9 01:15:08 CEST 1999 i686 unknown

Versions of the packages apache-common depends on:
ii  libc6           2.0.7.19981211 GNU C Library: shared libraries
ii  libgdbmg1       1.7.3-25       GNU dbm database routines (runtime version).
ii  perl            5.004.05-1     Fake package used for a smooth upgrade





---325989904-461358477-940421347=:30938--



Information forwarded to debian-bugs-dist@lists.debian.org, Johnie Ingram <johnie@debian.org>:
Bug#47951; Package apache-common. Full text and rfc822 format available.

Acknowledgement sent to Robert Varga <robi@piros.zold.net>:
Extra info received and forwarded to list. Copy sent to Johnie Ingram <johnie@debian.org>. Full text and rfc822 format available.

Message #10 received at 47951@bugs.debian.org (full text, mbox):

From: Robert Varga <robi@piros.zold.net>
To: 47951@bugs.debian.org
Subject: bug in my suexec
Date: Thu, 21 Oct 1999 14:00:40 +0200 (CEST)
In the line 355 of my suexec.c (the following line) has a bug

    for (actpos=0;actpos<argnum+addl_slots+1;++argnum) res[actpos]=0;


It should be instead:

    for (actpos=0;actpos<argnum+addl_slots+1;++actpos) res[actpos]=0;

Sorry for the inconvenience,

Robert Varga



Severity set to `wishlist'. Request was from Johnie Ingram <johnie@netgod.net> to control@bugs.debian.org. Full text and rfc822 format available.

Reply sent to Johnie Ingram <johnie@debian.org>:
You have taken responsibility. Full text and rfc822 format available.

Notification sent to Robert Varga <robi@piros.zold.net>:
Bug acknowledged by developer. Full text and rfc822 format available.

Message #17 received at 47951-close@bugs.debian.org (full text, mbox):

From: Johnie Ingram <johnie@debian.org>
To: 47951-close@bugs.debian.org
Subject: Bug#47951: fixed in apache 1.3.9-12
Date: 9 Mar 2000 12:34:49 -0000
We believe that the bug you reported is fixed in the latest version of
apache, which has been installed in the Debian FTP archive:
apache-dev_1.3.9-12_i386.deb
  to dists/potato/main/binary-i386/web/apache-dev_1.3.9-12.deb
  replacing apache-dev_1.3.9-11.deb
apache-dev_1.3.9-12_i386.deb
  to dists/woody/main/binary-i386/web/apache-dev_1.3.9-12.deb
  replacing apache-dev_1.3.9-11.deb
apache_1.3.9-12.diff.gz
  to dists/potato/main/source/web/apache_1.3.9-12.diff.gz
  replacing apache_1.3.9-11.diff.gz
apache_1.3.9-12.diff.gz
  to dists/woody/main/source/web/apache_1.3.9-12.diff.gz
  replacing apache_1.3.9-11.diff.gz
apache-common_1.3.9-12_i386.deb
  to dists/potato/main/binary-i386/web/apache-common_1.3.9-12.deb
  replacing apache-common_1.3.9-11.deb
apache-common_1.3.9-12_i386.deb
  to dists/woody/main/binary-i386/web/apache-common_1.3.9-12.deb
  replacing apache-common_1.3.9-11.deb
apache_1.3.9-12.dsc
  to dists/potato/main/source/web/apache_1.3.9-12.dsc
  replacing apache_1.3.9-11.dsc
apache_1.3.9-12.dsc
  to dists/woody/main/source/web/apache_1.3.9-12.dsc
  replacing apache_1.3.9-11.dsc
apache_1.3.9-12_i386.deb
  to dists/potato/main/binary-i386/web/apache_1.3.9-12.deb
  replacing apache_1.3.9-11.deb
apache_1.3.9-12_i386.deb
  to dists/woody/main/binary-i386/web/apache_1.3.9-12.deb
  replacing apache_1.3.9-11.deb
apache-doc_1.3.9-12_all.deb
  to dists/potato/main/binary-all/doc/apache-doc_1.3.9-12.deb
  replacing apache-doc_1.3.9-11.deb
apache-doc_1.3.9-12_all.deb
  to dists/woody/main/binary-all/doc/apache-doc_1.3.9-12.deb
  replacing apache-doc_1.3.9-11.deb

Note that this package is not part of the released stable Debian
distribution.  It may have dependencies on other unreleased software,
or other instabilities.  Please take care if you wish to install it.
The update will eventually make its way into the next released Debian
distribution.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to 47951@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Johnie Ingram <johnie@debian.org> (supplier of updated apache package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmaster@debian.org)


-----BEGIN PGP SIGNED MESSAGE-----

Format: 1.6
Date: Thu,  9 Mar 2000 05:15:12 -0600
Source: apache
Binary: apache-doc apache-dev apache-common apache
Architecture: source i386 all
Version: 1.3.9-12
Distribution: frozen unstable
Urgency: low
Maintainer: Johnie Ingram <johnie@debian.org>
Description: 
 apache     - Versatile, high-performance HTTP server
 apache-common - Support files for all Apache webservers
 apache-dev - Apache webserver development kit
 apache-doc - Apache webserver docs
Closes: 23848 27701 38066 38068 38068 39304 42202 44096 45301 47033 47038 47951 51733 52893 54465 58465 58848 59365 59588 59647 59659 59672 59694
Changes: 
 apache (1.3.9-12) frozen unstable; urgency=low
 .
   * [RC] Cron script avoids killing itself, closes: #59365, #59647,
     #59672, #59659, #59694.
   * [RC] Order of mod_rewrite and mod_alias loading fixed, closes: #47038,
     #52893, #58465.
   * [RC] Deleted line 284 of debian/rules (suid suexec), set it
     unexecutable by default, closes: #59588, #44096.
   * Loophole in console message policy exploited, closes: #23848,
     #39304, #47033, #58848.
   * Webmaster mail alias is added if needed, so apacheconfig doesn't
     ask about this during package install, closes: #38068.
   * Option --manual-modules added to apacheeconfig, so default (and
     correct in amost all cases) is to work module magic automatically,
     closes: #38068, #45301.
   * New full-auto mode added to apacheconfig for postinst "initial setup"
     use: unlike mere --update, httpd.conf and srm.conf are installed, no
     questions are asked, and some backups are omitted.
   * Added LANG=C to init script, so apache doesn't write unparsable
     logfiles, closes: #42202.
   * Apacheconfig does not attempt to set non-/var/www documentroot (since
     1.3.9 T3B), closes: #27701, #38066, #51733.
   * All incorrect manpage references to "httpd" are corrected by ubersed,
     closes: #54465.
   * Apacheconfig script does not stop apache if it isn't running.
   * Included improved suexec from Robert Varga that understands <--#exec
     with parameters (ported from 1.3.3), and includes HTTPS and
     REDIRECT_HTTPS vars, closes: #47951.
Files: 
 a9adccfca437fb06cac82c773231ff08 756 web optional apache_1.3.9-12.dsc
 be3ada0d3d32775645c8d4a9f891ac18 314437 web optional apache_1.3.9-12.diff.gz
 7d453a1531d26ffbb617a497632ecc2b 541538 doc optional apache-doc_1.3.9-12_all.deb
 3b4cadf9a1eb7bda3366da7652fd5c14 357010 web optional apache_1.3.9-12_i386.deb
 c17959264a39dd85bc8b29d95fdc7480 545108 web extra apache-dev_1.3.9-12_i386.deb
 eeb394a61f190fc3e16fb660d284f961 717342 web optional apache-common_1.3.9-12_i386.deb

-----BEGIN PGP SIGNATURE-----
Version: 2.6.3ia
Charset: latin1

iQCVAwUBOMeMxBCswmGWXGp9AQEdvAP/df8sQP+c7q5EyCAZT1AZk0ITPRe02gaS
DcHhg/62t7E2yhI0mW+cp/w24GLVbSFlqa60pA19mH9/WApcLGjJV5z4rkDz8CPi
W3i+8COnhtBCXCOaoGkOJnvaXJjoZjgpElXl2aLBqkXQRqa57HDQNNfvaN9h05eA
g96gnycCGwo=
=e/ol
-----END PGP SIGNATURE-----



Send a report that this bug log contains spam.


Debian bug tracking system administrator <owner@bugs.debian.org>. Last modified: Fri Apr 18 11:42:31 2014; Machine Name: buxtehude.debian.org

Debian Bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.