Hello everyone,
here's my first try to contribute to this awesome project :)
My problem is that you can specify a chroot directory for the webserver
itself, but the scripts always run in the normal root.
This patch allows to associate a chroot directory to an information source,
without need for external software.
If specified, the forked process will chroot() to this directory before
executing.
I've implemented it in both local and shm spawn methods, added the admin
entry, and path checking.
I've only tried the shm method though, it's currently running on my
production server without problems.
diff -ru cherokee-0.99.43.orig/admin/PageInfoSource.py cherokee-0.99.43/admin/PageInfoSource.py
--- cherokee-0.99.43.orig/admin/PageInfoSource.py 2010-02-16 12:55:29.000000000 +0100
+++ cherokee-0.99.43/admin/PageInfoSource.py 2010-03-03 02:01:41.000000000 +0100
@@ -18,6 +18,7 @@
NOTE_USAGE = N_('Sources currently in use. Note that the last source of any rule cannot be deleted until the rule has been manually edited.')
NOTE_USER = N_('Execute the interpreter under a different user. Default: Same UID as the server.')
NOTE_GROUP = N_('Execute the interpreter under a different group. Default: Default GID of the new process UID.')
+NOTE_CHROOT = N_('Execute the interpreter under a different root. Default: no.')
NOTE_ENV_INHETIR = N_('Whether the new child process should inherit the environment variables from the server process. Default: yes.')
TABLE_JS = """
@@ -165,13 +166,14 @@
if self.has_errors():
return self._op_render()
- nick = post.pop ('tmp!new_source_nick')
- type = post.pop ('tmp!new_source_type')
- host = post.pop ('tmp!new_source_host')
- inter = post.pop ('tmp!new_source_interpreter')
- time = post.pop ('tmp!new_source_timeout')
- user = post.pop ('tmp!new_source_user')
- group = post.pop ('tmp!new_source_group')
+ nick = post.pop ('tmp!new_source_nick')
+ type = post.pop ('tmp!new_source_type')
+ host = post.pop ('tmp!new_source_host')
+ inter = post.pop ('tmp!new_source_interpreter')
+ time = post.pop ('tmp!new_source_timeout')
+ user = post.pop ('tmp!new_source_user')
+ group = post.pop ('tmp!new_source_group')
+ chroot = post.pop ('tmp!new_source_chroot')
tmp = [int(x) for x in self._cfg.keys('source')]
tmp.sort()
@@ -187,6 +189,7 @@
self._cfg['source!%d!timeout'%(prio)] = time
self._cfg['source!%d!user'%(prio)] = user
self._cfg['source!%d!group'%(prio)] = group
+ self._cfg['source!%d!chroot'%(prio)] = chroot
return '/%s/%d' % (self._id, prio)
@@ -251,6 +254,7 @@
self.AddPropEntry (table, _('Spawning timeout'), 'source!%s!timeout'%(s), _(NOTE_TIMEOUT), optional=True)
self.AddPropEntry (table, _('Execute as User'), 'source!%s!user'%(s), _(NOTE_USER), optional=True)
self.AddPropEntry (table, _('Execute as Group'), 'source!%s!group'%(s), _(NOTE_GROUP), optional=True)
+ self.AddPropEntry (table, _('Chroot Directory'), 'source!%s!chroot'%(s), _(NOTE_CHROOT), optional=True)
self.AddPropCheck (table, _('Inherit Environment'),'source!%s!env_inherited'%(s), True, _(NOTE_ENV_INHETIR))
tmp = self.HiddenInput ('source_num', s)
@@ -279,6 +283,7 @@
self.AddPropEntry (table, _('Spawning timeout'), 'tmp!new_source_timeout', _(NOTE_TIMEOUT), optional=True)
self.AddPropEntry (table, _('Execute as User'), 'tmp!new_source_user', _(NOTE_USER), optional=True)
self.AddPropEntry (table, _('Execute as Group'), 'tmp!new_source_group', _(NOTE_GROUP), optional=True)
+ self.AddPropEntry (table, _('Chroot Directory'), 'tmp!new_source_chroot', _(NOTE_CHROOT), optional=True)
txt += self.Indent(table)
return txt
diff -ru cherokee-0.99.43.orig/cherokee/error_list.py cherokee-0.99.43/cherokee/error_list.py
--- cherokee-0.99.43.orig/cherokee/error_list.py 2010-02-16 12:55:13.000000000 +0100
+++ cherokee-0.99.43/cherokee/error_list.py 2010-03-03 02:01:41.000000000 +0100
@@ -729,6 +729,10 @@
title = "Could not spawn '%s'",
desc = SYSTEM_ISSUE)
+e('SRC_INTER_CHROOT',
+ title = "Could not chroot() to '%s'",
+ desc = SYSTEM_ISSUE)
+
# cherokee/config_reader.c
#
diff -ru cherokee-0.99.43.orig/cherokee/main.c cherokee-0.99.43/cherokee/main.c
--- cherokee-0.99.43.orig/cherokee/main.c 2010-01-20 11:41:58.000000000 +0100
+++ cherokee-0.99.43/cherokee/main.c 2010-03-03 02:01:41.000000000 +0100
@@ -345,6 +345,7 @@
static void
do_spawn (void)
{
+ int re;
int n;
int size;
uid_t uid;
@@ -356,6 +357,7 @@
int log_stderr = 0;
char *log_file = NULL;
char *uid_str = NULL;
+ char *chroot_dir = NULL;
char **envp = NULL;
char *p = spawn_shared;
const char *argv[] = {"sh", "-c", NULL, NULL};
@@ -389,7 +391,16 @@
memcpy (&gid, p, sizeof(gid_t));
p += sizeof(gid_t);
- /* 3.- Environment */
+ /* 3.- Chroot directory */
+ size = *((int *) p);
+ p += sizeof(int);
+ if (size > 0) {
+ chroot_dir = malloc(size + 1);
+ memcpy(chroot_dir, p, size + 1);
+ }
+ p += size + 1;
+
+ /* 4.- Environment */
env_inherit = *((int *)p);
p += sizeof(int);
@@ -413,7 +424,7 @@
p += size + 1;
}
- /* 4.- Error log */
+ /* 5.- Error log */
size = *((int *)p);
p += sizeof(int);
@@ -427,7 +438,7 @@
p += size + 1;
}
- /* 5.- PID: it's -1 now */
+ /* 6.- PID: it's -1 now */
n = *((int *)p);
if (n > 0) {
kill (n, SIGTERM);
@@ -455,6 +466,15 @@
close (STDERR_FILENO);
}
+ /* Change root */
+ if (chroot_dir) {
+ re = chroot(chroot_dir);
+ if (re < 0) {
+ PRINT_MSG ("(critical) Couldn't chroot to %s\n", chroot_dir);
+ exit (1);
+ }
+ }
+
/* Change user & group */
if (uid_str != NULL) {
n = initgroups (uid_str, gid);
@@ -499,13 +519,14 @@
default:
/* Return the PID */
memcpy (p, (char *)&child, sizeof(int));
- printf ("PID %d: launched '/bin/sh -c %s' with uid=%d, gid=%d, env=%s\n", child, interpreter, uid, gid, env_inherit ? "inherited":"custom");
+ printf ("PID %d: launched '/bin/sh -c %s' with uid=%d, gid=%d, chroot=%s, env=%s\n", child, interpreter, uid, gid, chroot_dir, env_inherit ? "inherited":"custom");
break;
}
/* Clean up
*/
free (interpreter);
+ free (chroot_dir);
for (n=0; n<envs; n++) {
free (envp[n]);
diff -ru cherokee-0.99.43.orig/cherokee/source_interpreter.c cherokee-0.99.43/cherokee/source_interpreter.c
--- cherokee-0.99.43.orig/cherokee/source_interpreter.c 2010-01-20 11:41:58.000000000 +0100
+++ cherokee-0.99.43/cherokee/source_interpreter.c 2010-03-03 03:07:15.000000000 +0100
@@ -54,6 +54,7 @@
cherokee_source_init (SOURCE(n));
cherokee_buffer_init (&n->interpreter);
cherokee_buffer_init (&n->change_user_name);
+ cherokee_buffer_init (&n->chroot);
n->custom_env = NULL;
n->custom_env_len = 0;
@@ -114,6 +115,7 @@
kill_pid (src);
cherokee_buffer_mrproper (&src->interpreter);
+ cherokee_buffer_mrproper (&src->chroot);
cherokee_buffer_mrproper (&src->change_user_name);
if (src->custom_env)
@@ -143,17 +145,30 @@
}
static ret_t
-check_interpreter_full (cherokee_buffer_t *fullpath)
+check_interpreter_full (cherokee_buffer_t *fullpath, cherokee_buffer_t *chroot_dir)
{
- int re;
- struct stat inter;
- char *p;
- char tmp;
- const char *end = fullpath->buf + fullpath->len;
+ int ret = ret_error;
+ int re;
+ struct stat inter;
+ char *p;
+ char tmp;
+ const char *end;
+ cherokee_buffer_t completepath = CHEROKEE_BUF_INIT;
+
+ cherokee_buffer_clean(&completepath);
+ if (chroot_dir->len > 0) {
+ /* Chroot and relative path, it doesn't make sense */
+ if (fullpath->len == 0 || fullpath->buf[0] != '/')
+ goto done;
+
+ cherokee_buffer_add_buffer (&completepath, chroot_dir);
+ }
+ cherokee_buffer_add_buffer(&completepath, fullpath);
+ end = completepath.buf + completepath.len;
- p = find_next_stop (fullpath->buf + 1);
+ p = find_next_stop (completepath.buf + 1);
if (p == NULL)
- return ret_error;
+ goto done;
while (p <= end) {
/* Set a temporal end */
@@ -161,12 +176,13 @@
*p = '\0';
/* Does the file exist? */
- re = cherokee_stat (fullpath->buf, &inter);
+ re = cherokee_stat (completepath.buf, &inter);
if ((re == 0) &&
(! S_ISDIR(inter.st_mode)))
{
*p = tmp;
- return ret_ok;
+ ret = ret_ok;
+ goto done;
}
*p = tmp;
@@ -181,12 +197,14 @@
p = (char *)end;
}
- return ret_error;
+done:
+ cherokee_buffer_mrproper(&completepath);
+ return ret;
}
static ret_t
-check_interpreter_path (cherokee_buffer_t *partial_path)
+check_interpreter_path (cherokee_buffer_t *partial_path, cherokee_buffer_t *chroot_dir)
{
ret_t ret;
char *p;
@@ -213,7 +231,7 @@
cherokee_buffer_add_char (&fullpath, '/');
cherokee_buffer_add_buffer (&fullpath, partial_path);
- ret = check_interpreter_full (&fullpath);
+ ret = check_interpreter_full (&fullpath, chroot_dir);
if (ret == ret_ok)
goto done;
@@ -238,14 +256,14 @@
ret_t ret;
if (src->interpreter.buf[0] == '/') {
- ret = check_interpreter_full (&src->interpreter);
+ ret = check_interpreter_full (&src->interpreter, &src->chroot);
if (ret == ret_ok)
return ret_ok;
return ret_error;
}
- return check_interpreter_path (&src->interpreter);
+ return check_interpreter_path (&src->interpreter, &src->chroot);
}
ret_t
@@ -307,6 +325,9 @@
src->change_group = grp.gr_gid;
+ } else if (equal_buf_str (&child->key, "chroot")) {
+ cherokee_buffer_add_buffer (&src->chroot, &child->val);
+
} else if (equal_buf_str (&child->key, "env")) {
cherokee_config_node_foreach (j, child) {
cherokee_config_node_t *child2 = CONFIG_NODE(j);
@@ -414,6 +435,7 @@
&src->change_user_name,
src->change_user,
src->change_group,
+ &src->chroot,
src->env_inherited,
envp,
error_writer,
@@ -490,6 +512,14 @@
}
}
+ if (src->chroot.len > 0) {
+ re = chroot(src->chroot.buf);
+ if (re < 0) {
+ LOG_ERROR (CHEROKEE_ERROR_SRC_INTER_CHROOT, src->chroot.buf);
+ exit (1);
+ }
+ }
+
argv[2] = (char *)tmp.buf;
if (src->env_inherited) {
re = execv ("/bin/sh", (char **)argv);
diff -ru cherokee-0.99.43.orig/cherokee/source_interpreter.h cherokee-0.99.43/cherokee/source_interpreter.h
--- cherokee-0.99.43.orig/cherokee/source_interpreter.h 2010-01-20 11:41:58.000000000 +0100
+++ cherokee-0.99.43/cherokee/source_interpreter.h 2010-03-03 02:01:41.000000000 +0100
@@ -39,6 +39,7 @@
typedef struct {
cherokee_source_t source;
cherokee_buffer_t interpreter;
+ cherokee_buffer_t chroot;
cherokee_boolean_t env_inherited;
char **custom_env;
diff -ru cherokee-0.99.43.orig/cherokee/spawner.c cherokee-0.99.43/cherokee/spawner.c
--- cherokee-0.99.43.orig/cherokee/spawner.c 2010-01-20 11:41:58.000000000 +0100
+++ cherokee-0.99.43/cherokee/spawner.c 2010-03-03 02:01:41.000000000 +0100
@@ -171,6 +171,7 @@
cherokee_buffer_t *user,
uid_t uid,
gid_t gid,
+ cherokee_buffer_t *chroot,
int env_inherited,
char **envp,
cherokee_logger_writer_t *error_writer,
@@ -217,7 +218,12 @@
cherokee_buffer_add (&tmp, (char *)&uid, sizeof(uid_t));
cherokee_buffer_add (&tmp, (char *)&gid, sizeof(gid_t));
- /* 3.- Environment */
+ /* 3.- Chroot directory */
+ cherokee_buffer_add (&tmp, (char *)&chroot->len, sizeof(int));
+ cherokee_buffer_add_buffer (&tmp, chroot);
+ cherokee_buffer_add_char (&tmp, '\0');
+
+ /* 4.- Environment */
for (n=envp; *n; n++) {
envs ++;
}
@@ -232,10 +238,10 @@
cherokee_buffer_add_char (&tmp, '\0');
}
- /* 4.- Error log */
+ /* 5.- Error log */
write_logger (&tmp, error_writer);
- /* 5.- PID (will be rewritten by the other side) */
+ /* 6.- PID (will be rewritten by the other side) */
pid_shm = (int *) (((char *)cherokee_spawn_shared.mem) + tmp.len);
k = *pid_ret;
pid_prev = *pid_ret;
diff -ru cherokee-0.99.43.orig/cherokee/spawner.h cherokee-0.99.43/cherokee/spawner.h
--- cherokee-0.99.43.orig/cherokee/spawner.h 2010-01-20 11:41:58.000000000 +0100
+++ cherokee-0.99.43/cherokee/spawner.h 2010-03-03 02:01:41.000000000 +0100
@@ -57,6 +57,7 @@
cherokee_buffer_t *user_name,
uid_t uid,
gid_t gid,
+ cherokee_buffer_t *chroot,
int env_inherited,
char **envp,
cherokee_logger_writer_t *error_writer,
_______________________________________________
Cherokee mailing list
[email protected]
http://lists.octality.com/listinfo/cherokee