Hello,
we've needed functionality of Apache 2 MPM's specially one which
allows VirtualHost to run under different UID.
Because Apache 2 is still in beta I patched our production 1.3.20
by attached patch. It simply does seteuid instead of setuid and
later in ap_read_request it regains root and uses setuid to UID
set by User directive. Furthermore I have to ensure that child
processes only one connection and exits.
I tested it with PHP and seems to work smoothly.
Maybe it could help someone looking for better PHP security
than safemode and who can't use CGI version of PHP.
It would be nice if someone experienced with apache internals
could comment the patch.
I'm aware of performance problem: only one connection handled
by single child. I measured 7% slowdown on our server. It is
worth of better security for us.
I'm not sure whether real-uid == 0 between child start and
ap_read_request can impose security/stability problem. I found
nothing such.
best regards, devik
diff -pru src/main/old/http_core.c src/main/http_core.c
--- src/main/old/http_core.c Thu Jan 24 13:54:25 2002
+++ src/main/http_core.c Thu Jan 24 14:11:46 2002
@@ -2038,15 +2038,7 @@ static const char *set_user(cmd_parms *c
cmd->server->server_uid = ap_user_id = ap_uname2id(arg);
}
else {
- if (ap_suexec_enabled) {
cmd->server->server_uid = ap_uname2id(arg);
- }
- else {
- cmd->server->server_uid = ap_user_id;
- fprintf(stderr,
- "Warning: User directive in <VirtualHost> "
- "requires SUEXEC wrapper.\n");
- }
}
#if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
if (cmd->server->server_uid == 0) {
diff -pru src/main/old/http_main.c src/main/http_main.c
--- src/main/old/http_main.c Thu Jan 24 13:54:25 2002
+++ src/main/http_main.c Thu Jan 24 14:58:03 2002
@@ -3963,9 +3963,9 @@ static void child_main(int child_num_arg
#ifdef _OSD_POSIX
os_init_job_environment(server_conf, ap_user_name, one_process) != 0 ||
#endif
- setuid(ap_user_id) == -1)) {
+ seteuid(ap_user_id) == -1)) {
ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
- "setuid: unable to change to uid: %ld", (long) ap_user_id);
+ "seteuid: unable to change to uid: %ld", (long) ap_user_id);
clean_child_exit(APEXIT_CHILDFATAL);
}
#endif
@@ -4361,6 +4361,7 @@ static void child_main(int child_num_arg
ap_bclose(conn_io);
}
#endif
+ clean_child_exit(0); /* only one request in our hacked mode */
}
}
@@ -5178,10 +5179,10 @@ int REALMAIN(int argc, char *argv[])
}
GETUSERMODE();
#else
- /* Only try to switch if we're running as root */
- if (!geteuid() && setuid(ap_user_id) == -1) {
+ /* Only try to switch if we're running as root; HACK: we use seteuid now */
+ if (!geteuid() && seteuid(ap_user_id) == -1) {
ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
- "setuid: unable to change to uid: %ld",
+ "seteuid: unable to change to uid: %ld",
(long) ap_user_id);
exit(1);
}
diff -pru src/main/old/http_protocol.c src/main/http_protocol.c
--- src/main/old/http_protocol.c Thu Jan 24 13:54:25 2002
+++ src/main/http_protocol.c Thu Jan 24 14:35:51 2002
@@ -1173,6 +1173,13 @@ request_rec *ap_read_request(conn_rec *c
*/
ap_update_vhost_from_headers(r);
+ /* HACK: regain root & become indicated user */
+ if (seteuid (0)) ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "can't regain root");
+
+ if (setuid (r->server->server_uid) || setgid (r->server->server_gid))
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "can't setuid to user defined UID (%d)", r->server->server_uid);
+
/* we may have switched to another server */
r->per_dir_config = r->server->lookup_defaults;