You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by rb...@locus.apache.org on 2000/07/28 19:45:17 UTC

cvs commit: apache-2.0/src/modules/mpm/perchild perchild.c

rbb         00/07/28 10:45:15

  Modified:    src/modules/mpm/perchild perchild.c
  Log:
  Update the perchild MPM.  At this point, it is possible to specify that
  a child process runs as a specified user.  That child process is not
  currently tied to a virtual host.  Using this MPM, I can launch Apache
  and have it serve as both nobody and rbb.
  
  Revision  Changes    Path
  1.2       +127 -9    apache-2.0/src/modules/mpm/perchild/perchild.c
  
  Index: perchild.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/mpm/perchild/perchild.c,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- perchild.c	2000/07/27 00:16:31	1.1
  +++ perchild.c	2000/07/28 17:45:13	1.2
  @@ -59,6 +59,7 @@
   #define CORE_PRIVATE 
    
   #include "ap_config.h"
  +#include "apr_hash.h"
   #include "apr_strings.h"
   #include "apr_portable.h"
   #include "apr_file_io.h"
  @@ -87,9 +88,20 @@
   #ifdef HAVE_NETINET_TCP_H
   #include <netinet/tcp.h>
   #endif
  +#include <grp.h>
  +#include <pwd.h>
   #include <pthread.h>
   #include <signal.h>
   
  +typedef struct child_info_t child_info_t;
  +
  +struct child_info_t {
  +    uid_t uid;
  +    gid_t gid;
  +};
  +static int curr_child_num = 0;  /* how many children have been setup so
  +                                   far */
  +
   /*
    * Actual definitions of config globals
    */
  @@ -107,6 +119,8 @@
   static int num_listenfds = 0;
   static ap_socket_t **listenfds;
   
  +static ap_hash_t *child_hash;
  +
   struct ap_ctable ap_child_table[HARD_SERVER_LIMIT];
   
   /*
  @@ -650,6 +664,83 @@
       return NULL;
   }
   
  +/* Set group privileges.
  + *
  + * Note that we use the username as set in the config files, rather than
  + * the lookup of to uid --- the same uid may have multiple passwd entries,
  + * with different sets of groups for each.
  + */
  +
  +static int set_group_privs(uid_t uid, gid_t gid)
  +{
  +    if (!geteuid()) {
  +        const char *name;
  +
  +        /* Get username if passed as a uid */
  +
  +        struct passwd *ent;
  +
  +        if ((ent = getpwuid(uid)) == NULL) {
  +            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
  +                     "getpwuid: couldn't determine user name from uid %u, "
  +                     "you probably need to modify the User directive",
  +                     (unsigned)uid);
  +            return -1;
  +        }
  +
  +        name = ent->pw_name;
  +
  +        /*
  +         * Set the GID before initgroups(), since on some platforms
  +         * setgid() is known to zap the group list.
  +         */
  +        if (setgid(gid) == -1) {
  +            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
  +                        "setgid: unable to set group id to Group %u",
  +                        (unsigned)gid);
  +            return -1;
  +        }
  +
  +        /* Reset `groups' attributes. */
  +
  +        if (initgroups(name, gid) == -1) {
  +            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
  +                        "initgroups: unable to set groups for User %s "
  +                        "and Group %u", name, (unsigned)gid);
  +            return -1;
  +        }
  +    }
  +    return 0;
  +}
  +
  +
  +static int perchild_setup_child(int childnum)
  +{
  +    child_info_t *ug;
  +    char child_num_str[5];
  +
  +    ap_snprintf(child_num_str, 5, "%d", childnum); 
  +    ug = ap_hash_get(child_hash, child_num_str, 1); 
  +    if (!ug) {
  +        return unixd_setup_child();
  +    }
  +    if (set_group_privs(ug->uid, ug->gid)) {
  +        return -1;
  +    }
  +    /* Only try to switch if we're running as root */
  +    if (!geteuid() && (
  +#ifdef _OSD_POSIX
  +        os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 ||
  +#endif
  +        setuid(ug->uid) == -1)) {
  +        ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
  +                    "setuid: unable to change to uid: %ld",
  +                    (long) ug->uid);
  +        return -1;
  +    }
  +    return 0;
  +}
  +
   static void child_main(int child_num_arg)
   {
       sigset_t sig_mask;
  @@ -672,7 +763,7 @@
           clean_child_exit(APEXIT_CHILDFATAL);
       }
   
  -    if (unixd_setup_child()) {
  +    if (perchild_setup_child(child_num)) {
   	clean_child_exit(APEXIT_CHILDFATAL);
       }
   
  @@ -1153,6 +1244,7 @@
       lock_fname = DEFAULT_LOCKFILE;
       max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
       ap_perchild_set_maintain_connection_status(1);
  +    child_hash = ap_make_hash(p);
   
       ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
   }
  @@ -1355,16 +1447,42 @@
       ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
       return NULL;
   }
  -static const char *set_childprocess(cmd_parms *cmd, void *dummy, const char *arg) 
  +
  +static ap_status_t reset_child_process(void *data)
   {
  +    curr_child_num = 0;
  +    return APR_SUCCESS;	
   }
  -/*
  +
  +static const char *set_childprocess(cmd_parms *cmd, void *dummy, const char *u,
  +                                    const char *g) 
  +{
  +    child_info_t *ug = ap_palloc(cmd->pool, sizeof(*ug));
  +    char child_num_str[5];
  +
  +    if (curr_child_num > num_daemons) {
  +        return "Trying to use more child ID's than NumServers.  Increase "
  +               "NumServers in your config file.";
  +    }
  +   
  +    ug->uid = atoi(u);
  +    ug->gid = atoi(g); 
  +    ap_snprintf(child_num_str, 5, "%d", curr_child_num++); 
  +    ap_hash_set(child_hash, ap_pstrdup(cmd->pool, child_num_str), 1, ug); 
  +
  +    ap_register_cleanup(cmd->pool, &curr_child_num, reset_child_process, ap_null_cleanup);
  +
  +    return NULL;
  +}
  +    
  +
  +#if 0
       if (unlink(sconf->sockname) < 0 &&
           errno != ENOENT) {
           ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
                        "Couldn't unlink unix domain socket %s",
                        sconf->sockname);
  -        /* just a warning; don't bail out
  +        /* JUSt a warning; don't bail out */
       }
   
       if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  @@ -1377,10 +1495,10 @@
       unix_addr.sun_family = AF_UNIX;
       strcpy(unix_addr.sun_path, sconf->sockname);
   
  -    omask = umask(0077); /* so that only Apache can use socket 
  +    omask = umask(0077); /* so that only Apache can use socket */
       rc = bind(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr));
  -*/
  -
  +}
  +#endif
   
   
   
  @@ -1411,8 +1529,8 @@
                "Whether or not to maintain status information on current connections"),
   AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF,
                 "The location of the directory Apache changes to before dumping core"),
  -AP_INIT_TAKE1("ChildProcess", set_childprocess, NULL, RSRC_CONF,
  -              "Which child process is responsible for serving this virtual host"),
  +AP_INIT_TAKE2("ChildProcess", set_childprocess, NULL, RSRC_CONF,
  +              "The User and Group this child Process should run as."),
   { NULL }
   };