randy       97/01/12 11:20:35

  Modified:    src       CHANGES
  Log:
  Add suexec CHANGES
  
  Revision  Changes    Path
  1.118     +11 -0     apache/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /export/home/cvs/apache/src/CHANGES,v
  retrieving revision 1.117
  retrieving revision 1.118
  diff -C3 -r1.117 -r1.118
  *** CHANGES   1997/01/12 16:58:00     1.117
  --- CHANGES   1997/01/12 19:18:46     1.118
  ***************
  *** 1,5 ****
  --- 1,16 ----
    Changes with Apache 1.2b5
    
  +   *) Several security enhancements to suexec wrapper. It is _highly_
  +      recommended that previously installed versions of the wrapper
  +      be replaced with this version.  [Randy Terbush, Jason Dour]
  + 
  +     - ~user execution now properly restricted to ~user's home
  +       directory and below.
  +     - execution restricted to UID/GID > 100
  +     - restrict passed environment to known variables
  +     - call setgid() before initgroups() (portability fix)
  +     - remove use of setenv() (portability fix)
  + 
      *) Add HTTP/1.0 response forcing. [Ben Laurie]
    
      *) Add access control via environment variables. [Ben Laurie]
  
  
  

  Modified:    support   suexec.c suexec.h
  Log:
  Add serveral security enhancements.
          - ~user execution now properly restricted to ~user's home
            directory and below.
          - execution restricted to UID/GID > 100
          - restrict passed environment to known variables
          - call setgid() before initgroups() (portability fix)
          - remove use of setenv() (portability fix)
  
  Reviewed-by: Marc Slemko, Jason Dour, Randy Terbush
  
  Revision  Changes    Path
  1.11      +99 -18    apache/support/suexec.c
  
  Index: suexec.c
  ===================================================================
  RCS file: /export/home/cvs/apache/support/suexec.c,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -C3 -r1.10 -r1.11
  *** suexec.c  1997/01/01 18:26:17     1.10
  --- suexec.c  1997/01/12 19:20:33     1.11
  ***************
  *** 81,89 ****
  --- 81,132 ----
    #include <time.h>
    #include <sys/stat.h>
    
  + #define CLEAN_ENV_BUF 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",
  +     "SCRIPT_FILENAME",
  +     "SCRIPT_NAME",
  +     "SCRIPT_URI",
  +     "SCRIPT_URL",
  +     "SERVER_ADMIN",
  +     "SERVER_NAME",
  +     "SERVER_PORT",
  +     "SERVER_PROTOCOL",
  +     "SERVER_SOFTWARE",
  +     "USER_NAME",
  +     NULL
  + };
  + 
  + 
    static void err_output(const char *fmt, va_list ap)
    {
        time_t timevar;
  ***************
  *** 120,128 ****
        return;
    }
    
  ! int main(int argc, char *argv[], char **env)
    {
  -     int doclen;             /* length of the docroot     */
        int userdir = 0;        /* ~userdir flag             */
        uid_t uid;              /* user information          */
        gid_t gid;              /* target group placeholder  */
  --- 163,208 ----
        return;
    }
    
  ! void clean_env() 
  ! {
  !     char pathbuf[512];
  !     char **cleanenv;
  !     char **ep;
  !     int cidx = 0;
  !     int idx;
  !     
  ! 
  !     if ((cleanenv = (char **)malloc(CLEAN_ENV_BUF * (sizeof(char *)))) == 
NULL) {
  !     log_err("failed to malloc env mem\n");
  !     exit(120);
  !     }
  !     
  !     for (ep = environ; *ep; 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;
  !             }
  !         }
  !     }
  !     }
  ! 
  !     sprintf(pathbuf, "PATH=%s", SAFE_PATH);
  !     cleanenv[cidx] = pathbuf;
  !     cleanenv[++cidx] = NULL;
  !         
  !     environ = cleanenv;
  !     free(cleanenv);
  ! }
  ! 
  ! int main(int argc, char *argv[])
    {
        int userdir = 0;        /* ~userdir flag             */
        uid_t uid;              /* user information          */
        gid_t gid;              /* target group placeholder  */
  ***************
  *** 211,217 ****
        /*
         * 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.
  --- 291,297 ----
        /*
         * 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.
  ***************
  *** 223,228 ****
  --- 303,309 ----
        
        if (userdir) {
            if (((chdir(pw->pw_dir)) != 0) ||
  +             ((chdir(USERDIR_SUFFIX)) != 0) ||
            ((getcwd(dwd, MAXPATHLEN)) == NULL) ||
                ((chdir(cwd)) != 0))
            {
  ***************
  *** 239,247 ****
                exit(108);
            }
        }
  !     
  !     doclen = strlen(dwd);
  !     if ((strncmp(cwd, dwd, doclen)) != 0) {
            log_err("command not in docroot (%s/%s)\n", cwd, cmd);
            exit(109);
        }
  --- 320,327 ----
                exit(108);
            }
        }
  ! 
  !     if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
            log_err("command not in docroot (%s/%s)\n", cwd, cmd);
            exit(109);
        }
  ***************
  *** 303,320 ****
        }
    
        /*
  !      * Error out if attempt is made to execute as root.  Tsk tsk.
         */
  !     if (pw->pw_uid == 0) {
  !     log_err("cannot run as uid 0 (%s)\n", cmd);
        exit(116);
        }
    
        /*
  !      * Error out if attempt is made to execute as root group.  Tsk tsk.
         */
  !     if (gr->gr_gid == 0) {
  !     log_err("cannot run as gid 0 (%s)\n", cmd);
        exit(117);
        }
    
  --- 383,404 ----
        }
    
        /*
  !      * Error out if attempt is made to execute as root or as
  !      * a UID less than UID_MIN.  Tsk tsk.
         */
  !     if ((pw->pw_uid == 0) ||
  !         (pw->pw_uid < UID_MIN)) {
  !     log_err("cannot run as forbidden uid (%d/%s)\n", pw->pw_uid, cmd);
        exit(116);
        }
    
        /*
  !      * Error out if attempt is made to execute as root group
  !      * or as a GID less than GID_MIN.  Tsk tsk.
         */
  !     if ((gr->gr_gid == 0) ||
  !         (gr->gr_gid < GID_MIN)) {
  !     log_err("cannot run as forbidden gid (%d/%s)\n", gr->gr_gid, cmd);
        exit(117);
        }
    
  ***************
  *** 333,339 ****
         */
        uid = pw->pw_uid;
        gid = gr->gr_gid;
  !     if ((initgroups(target_uname,gid) != 0) || ((setgid(gid)) != 0)) {
            log_err("failed to setgid (%ld: %s/%s)\n", gid, cwd, cmd);
            exit(118);
        }
  --- 417,423 ----
         */
        uid = pw->pw_uid;
        gid = gr->gr_gid;
  !     if (((setgid(gid)) != 0) || (initgroups(pw->pw_name,gid) != 0)) {
            log_err("failed to setgid (%ld: %s/%s)\n", gid, cwd, cmd);
            exit(118);
        }
  ***************
  *** 346,360 ****
        exit(119);
        }
    
  !     if ((setenv("PATH", SAFE_PATH, 1)) != 0) {
  !     log_err("cannot reset environment PATH\n");
  !     exit(120);
  !     }
        
        /*
         * Execute the command, replacing our image with its own.
         */
  !     execve(cmd, &argv[3], env);
    
        /*
         * (I can't help myself...sorry.)
  --- 430,441 ----
        exit(119);
        }
    
  !     clean_env();
        
        /*
         * Execute the command, replacing our image with its own.
         */
  !     execv(cmd, argv);
    
        /*
         * (I can't help myself...sorry.)
  
  
  
  1.7       +30 -0     apache/support/suexec.h
  
  Index: suexec.h
  ===================================================================
  RCS file: /export/home/cvs/apache/support/suexec.h,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -C3 -r1.6 -r1.7
  *** suexec.h  1997/01/01 18:26:18     1.6
  --- suexec.h  1997/01/12 19:20:34     1.7
  ***************
  *** 68,73 ****
  --- 68,103 ----
    #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 UID_MIN
  + #define UID_MIN 500
  + #endif
  + 
  + /*
  +  * GID_MIN -- Define this as the lowest GID allowed to be a target group
  +  *            for suEXEC.  For most systems, 100 is common.
  +  */
  + #ifndef GID_MIN
  + #define GID_MIN 100
  + #endif
  + 
  + /*
  +  * USERDIR_SUFFIX -- Define to be the same as the UserDir in the conf
  +  *                   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 USERDIR_SUFFIX
  + #define USERDIR_SUFFIX "public_html"
  + #endif
  + 
  + /*
     * LOG_EXEC -- Define this as a filename if you want all suEXEC
     *             transactions and errors logged for auditing and
     *             debugging purposes.
  
  
  

Reply via email to