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

Reply via email to