diff -u -uwr conf/httpd.conf-dist conf/httpd.conf-dist --- conf/httpd.conf-dist Wed Nov 24 20:10:19 2004 +++ conf/httpd.conf-dist Thu Aug 17 15:00:46 2006 @@ -59,6 +59,14 @@ ServerRoot "@@ServerRoot@@" # +# ChrootDir: The directory to chroot to +# +# NOTE: When using this all directory/file references in DocumentRoot, +# and should be relative to this ChrootDir! +# +#ChrootDir "@@ServerRoot@@/htdocs" + +# # The LockFile directive sets the path to the lockfile used when Apache # is compiled with either USE_FCNTL_SERIALIZED_ACCEPT or # USE_FLOCK_SERIALIZED_ACCEPT. This directive should normally be left at diff -u -uwr src/include/http_conf_globals.h src/include/http_conf_globals.h --- src/include/http_conf_globals.h Wed Jul 12 10:16:05 2006 +++ src/include/http_conf_globals.h Thu Aug 17 15:00:46 2006 @@ -75,6 +75,7 @@ extern API_VAR_EXPORT char ap_server_root[MAX_STRING_LEN]; extern API_VAR_EXPORT char ap_server_confname[MAX_STRING_LEN]; +extern API_VAR_EXPORT char ap_chroot_dir[MAX_STRING_LEN]; /* for -C, -c and -D switches */ extern API_VAR_EXPORT array_header *ap_server_pre_read_config; diff -u -uwr src/main/http_core.c src/main/http_core.c --- src/main/http_core.c Wed Jul 12 10:16:05 2006 +++ src/main/http_core.c Thu Aug 17 15:00:46 2006 @@ -2237,6 +2237,31 @@ return NULL; } +static const char *set_chroot_dir(cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + arg = ap_os_canonical_filename(cmd->pool, arg); + + if (!ap_is_directory(arg)) { + return "ChrootDir must be a valid directory"; + } + /* ChrootDir is never '/' terminated */ + while (strlen(ap_chroot_dir) > 1 && ap_chroot_dir[strlen(ap_chroot_dir)-1] == '/') + ap_chroot_dir[strlen(ap_chroot_dir)-1] = '\0'; + ap_cpystrn(ap_chroot_dir, arg, + sizeof(ap_chroot_dir)); + + /* XXX: after ChrootDir we cannot check DocumentRoot easily */ + ap_docrootcheck = 0; + + return NULL; +} + static const char *set_timeout(cmd_parms *cmd, void *dummy, char *arg) { const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); @@ -3577,6 +3602,8 @@ "En-/disable server signature (on|off|email)" }, { "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1, "Common directory of server-related files (logs, confs, etc.)" }, +{ "ChrootDir", set_chroot_dir, NULL, RSRC_CONF, TAKE1, + "The directory to chroot(2) into" }, { "ErrorLog", set_server_string_slot, (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1, "The filename of the error log" }, diff -u -uwr src/main/http_main.c src/main/http_main.c --- src/main/http_main.c Wed Jul 12 10:16:05 2006 +++ src/main/http_main.c Thu Aug 17 15:00:46 2006 @@ -271,6 +271,7 @@ listen_rec *ap_listeners=NULL; static listen_rec *head_listener; +API_VAR_EXPORT char ap_chroot_dir[MAX_STRING_LEN]=""; API_VAR_EXPORT char ap_server_root[MAX_STRING_LEN]=""; API_VAR_EXPORT char ap_server_confname[MAX_STRING_LEN]=""; API_VAR_EXPORT char ap_coredump_dir[MAX_STRING_LEN]=""; @@ -4411,6 +4412,30 @@ } GETUSERMODE(); #else + + if (ap_chroot_dir[0] != '\0') { + if (!ap_standalone) { + ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, + "Cannot chroot when not in standalone mode"); + exit(1); + } + if (geteuid()) { + ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, + "Cannot chroot when not started as root"); + exit(1); + } + if (chdir(ap_chroot_dir)) { + ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, + "Unable to chdir to %s", ap_chroot_dir); + exit(1); + } + if (chroot(ap_chroot_dir)) { + ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, + "Unable to chroot to %s", ap_chroot_dir); + exit(1); + } + } + /* * Only try to switch if we're running as root * In case of Cygwin we have the special super-user named SYSTEM @@ -5360,6 +5385,10 @@ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, "Accept mutex: %s (Default: %s)", amutex->name, ap_default_mutex_method()); + if (ap_chroot_dir[0] != '\0') { + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, + "Chroot directory: %s", ap_chroot_dir); + } restart_pending = shutdown_pending = 0; while (!restart_pending && !shutdown_pending) { diff -u -uwr src/main/http_request.c src/main/http_request.c --- src/main/http_request.c Wed Jul 12 10:16:05 2006 +++ src/main/http_request.c Thu Aug 17 15:00:46 2006 @@ -182,7 +182,10 @@ /* Advance over trailing slashes ... NOT part of filename * if file is not a UNC name (Win32 only). */ - for (cp = end; cp > path && cp[-1] == '/'; --cp) + /* XXX: we need path+1 instead of path here to handle the case + * of path = "/" (this can happen when using ChrootDir) + */ + for (cp = end; cp > path+1 && cp[-1] == '/'; --cp) continue; while (cp > path) {