Index: [Article Count Order] [Thread]

Date:  Thu, 18 Nov 2004 13:07:51 +0700
From:  David Garamond <lists@...>
Subject:  Re: "admin only mode" (disallowing normal users from using mod_ruby)
To:  modruby@... (modruby ML)
Message-Id:  <419C3C37.6040506@...>
In-Reply-To:  <419AC284.2080302@...>
References:  <4194D2D8.7070206@...> <4199B410.10801@...> <4199C30E.1020604@...> <419AC284.2080302@...>
X-Mail-Count: 01354



Shugo Maeda wrote:
> Can you make a patch? Or may I implement it?

I'm not adept in C and I'm not yet familiar with Apache2 API, but here's 
my attempt. Please review it. Some notes about this patch:

- I've only tested it with Apache 1.3.33;

- The Japanese directives documentation (directives.ja.euc.rd) has not 
been updated.

- With this patch, everytime we add a new directive that can be put in 
dir-specific config, we must add check_restrict_directives() to it.

Regards,
dave



diff -ruN --exclude='*~' mod_ruby-1.2.4.orig/doc/directives.en.rd mod_ruby-1.2.4+rubyrestrictdirectives/doc/directives.en.rd
--- mod_ruby-1.2.4.orig/doc/directives.en.rd	Thu Jul  1 10:49:24 2004
+++ mod_ruby-1.2.4+rubyrestrictdirectives/doc/directives.en.rd	Thu Nov 18 13:01:04 2004
@@ -24,6 +24,7 @@
 * ((<RubyTimeOut|RubyTimeOut sec>))
 * ((<RubySafeLevel|RubySafeLevel level>))
 * ((<RubyOutputMode|RubyOutputMode mode>))
+* ((<RubyRestrictDirectives|RubyRestrictDirectives flag>))
 * ((<RubyKanjiCode|RubyKanjiCode kcode>))
 
 --- RubyAddPath directory...
@@ -258,6 +259,19 @@
 
         RubyOutputMode syncheader
 
+--- RubyRestrictDirectives flag
+      Specifies whether all the other Ruby* directives (like
+      RubyHandler, RubySetEnv, etc.) are restricted from being
+      specified in .htaccess files. Default is (({off})). Setting this
+      to (({on})) can be useful in some multi-user situations
+      (e.g. shared webhosting), in which the server admin wants to use
+      mod_ruby but does not want to allow normal users to get access
+      to it. Only available in server config.
+
+      example:
+
+        RubyRestrictDirectives on
+
 --- RubyKanjiCode kcode
       Specifies the value of ((|$KCODE|)).
 
diff -ruN --exclude='*~' mod_ruby-1.2.4.orig/mod_ruby.c mod_ruby-1.2.4+rubyrestrictdirectives/mod_ruby.c
--- mod_ruby-1.2.4.orig/mod_ruby.c	Mon Sep 27 12:02:36 2004
+++ mod_ruby-1.2.4+rubyrestrictdirectives/mod_ruby.c	Thu Nov 18 10:12:43 2004
@@ -164,6 +164,9 @@
      "set default $SAFE"},
     {"RubyOutputMode", ruby_cmd_output_mode, NULL, OR_ALL, TAKE1,
      "set output mode (nosync|sync|syncheader)"},
+    {"RubyRestrictDirectives", ruby_cmd_restrict_directives, NULL, 
+     RSRC_CONF, FLAG,
+     "whether Ruby* directives are restricted from .htaccess"},
     {"RubyHandler", ruby_cmd_handler, NULL, OR_ALL, TAKE1,
      "set ruby handler object"},
     {"RubyTransHandler", ruby_cmd_trans_handler, NULL, RSRC_CONF, TAKE1,
diff -ruN --exclude='*~' mod_ruby-1.2.4.orig/mod_ruby.h mod_ruby-1.2.4+rubyrestrictdirectives/mod_ruby.h
--- mod_ruby-1.2.4.orig/mod_ruby.h	Mon Sep 27 12:11:32 2004
+++ mod_ruby-1.2.4+rubyrestrictdirectives/mod_ruby.h	Thu Nov 18 07:19:20 2004
@@ -133,6 +133,7 @@
     table *env;
     int timeout;
     array_header *ruby_child_init_handler;
+    int restrict_directives;
 } ruby_server_config;
 
 typedef struct {
@@ -163,6 +164,7 @@
 
 #define MR_DEFAULT_TIMEOUT 270
 #define MR_DEFAULT_SAFE_LEVEL 1
+#define MR_DEFAULT_RESTRICT_DIRECTIVES 0
 
 #define MR_OUTPUT_DEFAULT	0
 #define MR_OUTPUT_NOSYNC	1
diff -ruN --exclude='*~' mod_ruby-1.2.4.orig/ruby_config.c mod_ruby-1.2.4+rubyrestrictdirectives/ruby_config.c
--- mod_ruby-1.2.4.orig/ruby_config.c	Wed Aug 18 23:23:43 2004
+++ mod_ruby-1.2.4+rubyrestrictdirectives/ruby_config.c	Thu Nov 18 12:54:41 2004
@@ -27,10 +27,14 @@
  * SUCH DAMAGE.
  */
 
+#define CORE_PRIVATE
 #include "mod_ruby.h"
 #include "ruby_config.h"
 
 static int default_safe_level = MR_DEFAULT_SAFE_LEVEL;
+static char restrict_directives_error_msg[] = 
+    "RubyRestrictDirectives is enabled, directives not available in "
+    ".htaccess";
 
 #define push_handler(p, handler, arg) { \
     if ((handler) == NULL) \
@@ -46,6 +50,7 @@
     conf->load_path = ap_make_array(p, 1, sizeof(char*));
     conf->env = ap_make_table(p, 1);
     conf->timeout = MR_DEFAULT_TIMEOUT;
+    conf->restrict_directives = MR_DEFAULT_RESTRICT_DIRECTIVES;
     conf->ruby_child_init_handler = NULL;
     return conf;
 }
@@ -79,6 +84,8 @@
     }
     new->env = ap_overlay_tables(p, add->env, base->env);
     new->timeout = add->timeout ? add->timeout : base->timeout;
+    new->restrict_directives = add->restrict_directives ?
+	add->restrict_directives : base->restrict_directives;
     new->ruby_child_init_handler =
 	merge_handlers(p, base->ruby_child_init_handler,
 		       add->ruby_child_init_handler);
@@ -167,8 +174,41 @@
     return (void *) new;
 }
 
+int is_from_htaccess(cmd_parms *cmd, ruby_dir_config *conf)
+{
+    core_server_config *sconf;
+    int access_name_len;
+    int config_file_path_len;
+
+    if (cmd->path == NULL || conf == NULL) return 0;
+    sconf = ap_get_module_config(cmd->server->module_config, &core_module);
+
+    access_name_len = strlen(sconf->access_name);
+    config_file_path_len = strlen(cmd->config_file->name);
+    if (config_file_path_len < access_name_len) return 0;
+    if (strcmp(cmd->config_file->name + config_file_path_len - access_name_len,
+	       sconf->access_name) != 0)
+	return 0;
+
+    return 1;
+}
+
+int is_restrict_directives(server_rec *server)
+{
+    ruby_server_config *sconf = get_server_config(server);
+
+    return sconf->restrict_directives != 0 ? 1 : 0;
+}
+
+#define check_restrict_directives(cmd, dconf) { \
+    if (is_from_htaccess((cmd), (dconf)) && \
+	is_restrict_directives((cmd)->server)) \
+	return restrict_directives_error_msg; \
+}
+
 const char *ruby_cmd_kanji_code(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     conf->kcode = ap_pstrdup(cmd->pool, arg);
     return NULL;
 }
@@ -177,6 +217,7 @@
 {
     ruby_server_config *sconf;
 
+    check_restrict_directives(cmd, dconf);
     if (cmd->path == NULL) {
 	sconf = get_server_config(cmd->server);
 	*(char **) ap_push_array(sconf->load_path) = arg;
@@ -260,6 +301,7 @@
     ruby_server_config *sconf = get_server_config(cmd->server);
     ruby_library_context *lib;
 
+    check_restrict_directives(cmd, dconf);
     if (ruby_running()) {
 	ruby_require(cmd->pool, arg, cmd->server, sconf, dconf);
     }
@@ -296,6 +338,7 @@
 const char *ruby_cmd_set_env(cmd_parms *cmd, ruby_dir_config *conf,
 			     char *key, char *val)
 {
+    check_restrict_directives(cmd, conf);
     ap_table_set(conf->env, key, val);
     if (cmd->path == NULL) {
 	ruby_server_config *sconf = get_server_config(cmd->server);
@@ -304,6 +347,13 @@
     return NULL;
 }
 
+const char *ruby_cmd_restrict_directives(cmd_parms *cmd, void *dummy, int flag)
+{
+    ruby_server_config *sconf = get_server_config(cmd->server);
+    sconf->restrict_directives = flag;
+    return NULL;
+}
+
 const char *ruby_cmd_timeout(cmd_parms *cmd, void *dummy, char *arg)
 {
     ruby_server_config *conf = get_server_config(cmd->server);
@@ -314,6 +364,7 @@
 
 const char *ruby_cmd_safe_level(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     if (cmd->path == NULL && !cmd->server->is_virtual) {
 	conf->safe_level = default_safe_level = atoi(arg);
     }
@@ -325,6 +376,7 @@
 
 const char *ruby_cmd_output_mode(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     if (strcasecmp(arg, "nosync") == 0) {
 	conf->output_mode = MR_OUTPUT_NOSYNC;
     }
@@ -342,48 +394,56 @@
 
 const char *ruby_cmd_handler(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_handler, arg);
     return NULL;
 }
 
 const char *ruby_cmd_trans_handler(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_trans_handler, arg);
     return NULL;
 }
 
 const char *ruby_cmd_authen_handler(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_authen_handler, arg);
     return NULL;
 }
 
 const char *ruby_cmd_authz_handler(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_authz_handler, arg);
     return NULL;
 }
 
 const char *ruby_cmd_access_handler(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_access_handler, arg);
     return NULL;
 }
 
 const char *ruby_cmd_type_handler(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_type_handler, arg);
     return NULL;
 }
 
 const char *ruby_cmd_fixup_handler(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_fixup_handler, arg);
     return NULL;
 }
 
 const char *ruby_cmd_log_handler(cmd_parms *cmd, ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_log_handler, arg);
     return NULL;
 }
@@ -391,6 +451,7 @@
 const char *ruby_cmd_header_parser_handler(cmd_parms *cmd,
 					   ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_header_parser_handler, arg);
     return NULL;
 }
@@ -398,6 +459,7 @@
 const char *ruby_cmd_post_read_request_handler(cmd_parms *cmd,
 					       ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_post_read_request_handler, arg);
     return NULL;
 }
@@ -405,6 +467,7 @@
 const char *ruby_cmd_init_handler(cmd_parms *cmd,
 				  ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_init_handler, arg);
     return NULL;
 }
@@ -412,6 +475,7 @@
 const char *ruby_cmd_cleanup_handler(cmd_parms *cmd,
 				     ruby_dir_config *conf, char *arg)
 {
+    check_restrict_directives(cmd, conf);
     push_handler(cmd->pool, conf->ruby_cleanup_handler, arg);
     return NULL;
 }
diff -ruN --exclude='*~' mod_ruby-1.2.4.orig/ruby_config.h mod_ruby-1.2.4+rubyrestrictdirectives/ruby_config.h
--- mod_ruby-1.2.4.orig/ruby_config.h	Sun Aug  8 05:40:25 2004
+++ mod_ruby-1.2.4+rubyrestrictdirectives/ruby_config.h	Thu Nov 18 10:34:31 2004
@@ -30,6 +30,8 @@
 #ifndef RUBY_CONFIG_H
 #define RUBY_CONFIG_H
 
+extern char restrict_directives_error_msg[];
+
 void *ruby_create_server_config(pool*, server_rec*);
 void *ruby_merge_server_config(pool*, void*, void*);
 void *ruby_create_dir_config (pool*, char*);
@@ -42,6 +44,7 @@
 const char *ruby_cmd_timeout(cmd_parms*, void*, char*);
 const char *ruby_cmd_safe_level(cmd_parms*, ruby_dir_config*, char*);
 const char *ruby_cmd_output_mode(cmd_parms*, ruby_dir_config*, char*);
+const char *ruby_cmd_restrict_directives(cmd_parms*, void*, int);
 const char *ruby_cmd_handler(cmd_parms*, ruby_dir_config*, char*);
 const char *ruby_cmd_trans_handler(cmd_parms*, ruby_dir_config*, char*);
 const char *ruby_cmd_authen_handler(cmd_parms*, ruby_dir_config*, char*);