]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Backport mod_include access checking (r571872,571927,572136)
authorNick Kew <niq@apache.org>
Sun, 2 Dec 2007 22:24:02 +0000 (22:24 +0000)
committerNick Kew <niq@apache.org>
Sun, 2 Dec 2007 22:24:02 +0000 (22:24 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@600393 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
docs/manual/mod/mod_include.xml
modules/filters/mod_include.c

diff --git a/CHANGES b/CHANGES
index e92a6430ec54c4187ff1cdb50ba6aa2af192b736..a3916d9bda27547fb17108f273d975d36736a220 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,11 @@
                                                         -*- coding: utf-8 -*-
 Changes with Apache 2.2.7
 
+  *) mod_include: Add an "if" directive syntax to test whether an URL
+     is accessible, and if so, conditionally display content. This
+     allows a webmaster to hide a link to a private page when the user
+     has no access to that page. [Graham Leggett]
+
   *) Various code cleanups. PR 38699, 39518, 42005, 42006, 42007, 42008, 42009
      [Christophe Jaillet <christophe.jaillet wanadoo.fr>]
 
diff --git a/STATUS b/STATUS
index 5898604ed961feedb6e96f5419788204f3696f55..96aedc4cf8602fa599c5e6a84a181728712cdf1f 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -79,15 +79,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-   * mod_include: Add an "if" directive syntax to test whether an URL
-     is accessible, and if so, conditionally display content. This
-     allows a webmaster to hide a link to a private page when the user
-     has no access to that page.
-     http://svn.apache.org/viewvc?view=rev&revision=571872
-     http://svn.apache.org/viewvc?view=rev&revision=571927
-     http://svn.apache.org/viewvc?view=rev&revision=572136
-     +1: minfrin, jim, niq
-
 PATCHES PROPOSED TO BACKPORT FROM TRUNK:
   [ New proposals should be added at the end of the list ]
 
index b821b91fd61eaf7040d15c2e9aedff67aa77c6e0..851db2eb40942a9f9744d2322b5d44d01ce92d7b 100644 (file)
       <dt><code><var>string</var></code></dt>
       <dd>true if <var>string</var> is not empty</dd>
 
+      <dt><code><var>-A string</var></code></dt>
+      <dd><p>true if the URL represented by the string is accessible by
+      configuration, false otherwise. This test only has an effect if
+      <directive>SSIEnableAccess</directive> is on. This is useful
+      where content on a page is to be hidden from users who are not
+      authorized to view the URL, such as a link to that URL. Note
+      that the URL is only tested for whether access would be granted,
+      not whether the URL exists.</p>
+
+      <example><title>Example</title>
+        &lt;!--#if expr="-A /private" --&gt;<br />
+        <indent>
+          Click &lt;a href="/private"&gt;here&lt;/a&gt; to access private
+          information.<br />
+        </indent>
+        &lt;!--#endif --&gt;
+      </example>
+      </dd>
+
       <dt><code><var>string1</var> = <var>string2</var><br />
       <var>string1</var> == <var>string2</var><br />
       <var>string1</var> != <var>string2</var></code></dt>
@@ -744,6 +763,34 @@ displayed</description>
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSIEnableAccess</name>
+<description>Enable the -A flag during conditional flow control processing.</description>
+<syntax>SSIEnableAccess on|off</syntax>
+<default>SSIEnableAccess off</default>
+<contextlist><context>directory</context><context>.htaccess</context></contextlist>
+
+<usage>
+    <p>The <directive>SSIEnableAccess</directive> directive controls whether
+    the -A test is enabled during conditional flow control processing.
+    <directive>SSIEnableAccess</directive> can take on the following values:</p>
+
+    <dl>
+
+      <dt><code>off</code></dt>
+      <dd>&lt;!--#if expr="-A /foo"--&gt; will be interpreted as a series
+      of string and regular expression tokens, the -A has no special
+      meaning.</dd>
+
+      <dt><code>on</code></dt>
+      <dd>&lt;!--#if expr="-A /foo"--&gt; will evaluate to false if the
+      URL /foo is inaccessible by configuration, or true otherwise.</dd>
+
+    </dl>
+
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>XBitHack</name>
 <description>Parse SSI directives in files with the execute bit
@@ -785,7 +832,7 @@ set</description>
       </dd>
     </dl>
 
-    </usage>
+</usage>
 </directivesynopsis>
 
 </modulesynopsis>
index 3d5c4667789a19df76840ce20921d58c61e947c8..db8b5faa946bae9d192703ce4de671304e5928ce 100644 (file)
@@ -80,7 +80,8 @@ typedef enum {
     TOKEN_GE,
     TOKEN_LE,
     TOKEN_GT,
-    TOKEN_LT
+    TOKEN_LT,
+    TOKEN_ACCESS
 } token_type_t;
 
 typedef struct {
@@ -114,6 +115,7 @@ typedef struct {
     const char *default_time_fmt;
     const char *undefined_echo;
     xbithack_t  xbithack;
+    const int accessenable;
 } include_dir_config;
 
 typedef struct {
@@ -190,6 +192,8 @@ struct ssi_internal_ctx {
     const char   *undefined_echo;
     apr_size_t    undefined_echo_len;
 
+    int         accessenable;    /* is using the access tests allowed? */
+
 #ifdef DEBUG_INCLUDE
     struct {
         ap_filter_t *f;
@@ -941,7 +945,7 @@ static APR_INLINE int re_check(include_ctx_t *ctx, const char *string,
     return rc;
 }
 
-static int get_ptoken(apr_pool_t *pool, const char **parse, token_t *token)
+static int get_ptoken(include_ctx_t *ctx, const char **parse, token_t *token, token_t *previous)
 {
     const char *p;
     apr_size_t shift;
@@ -990,6 +994,10 @@ static int get_ptoken(apr_pool_t *pool, const char **parse, token_t *token)
         unmatched = '\'';
         break;
     case '/':
+        /* if last token was ACCESS, this token is STRING */
+        if (previous != NULL && TOKEN_ACCESS == previous->type) {
+            break;
+        }
         TYPE_TOKEN(token, TOKEN_RE);
         unmatched = '/';
         break;
@@ -1023,6 +1031,13 @@ static int get_ptoken(apr_pool_t *pool, const char **parse, token_t *token)
         }
         TYPE_TOKEN(token, TOKEN_LT);
         return 0;
+    case '-':
+        if (**parse == 'A' && (ctx->intern->accessenable)) {
+            TYPE_TOKEN(token, TOKEN_ACCESS);
+            ++*parse;
+            return 0;
+        }
+        break;
     }
 
     /* It's a string or regex token
@@ -1079,11 +1094,11 @@ static int get_ptoken(apr_pool_t *pool, const char **parse, token_t *token)
     }
 
     if (unmatched) {
-        token->value = apr_pstrdup(pool, "");
+        token->value = apr_pstrdup(ctx->dpool, "");
     }
     else {
         apr_size_t len = p - token->value - shift;
-        char *c = apr_palloc(pool, len + 1);
+        char *c = apr_palloc(ctx->dpool, len + 1);
 
         p = token->value;
         token->value = c;
@@ -1111,6 +1126,7 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
 {
     parse_node_t *new, *root = NULL, *current = NULL;
     request_rec *r = ctx->intern->r;
+    request_rec *rr = NULL;
     const char *error = "Invalid expression \"%s\" in file %s";
     const char *parse = expr;
     int was_unmatched = 0;
@@ -1130,7 +1146,8 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
          */
         CREATE_NODE(ctx, new);
 
-        was_unmatched = get_ptoken(ctx->dpool, &parse, &new->token);
+        was_unmatched = get_ptoken(ctx, &parse, &new->token,
+                         (current != NULL ? &current->token : NULL));
         if (!parse) {
             break;
         }
@@ -1142,6 +1159,7 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
             switch (new->token.type) {
             case TOKEN_STRING:
             case TOKEN_NOT:
+            case TOKEN_ACCESS:
             case TOKEN_LBRACE:
                 root = current = new;
                 continue;
@@ -1276,6 +1294,7 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
             break;
 
         case TOKEN_NOT:
+        case TOKEN_ACCESS:
         case TOKEN_LBRACE:
             switch (current->token.type) {
             case TOKEN_STRING:
@@ -1462,6 +1481,34 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
             }
             break;
 
+        case TOKEN_ACCESS:
+            if (current->left || !current->right ||
+                (current->right->token.type != TOKEN_STRING &&
+                 current->right->token.type != TOKEN_RE)) {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                            "Invalid expression \"%s\" in file %s: Token '-A' must be followed by a URI string.",
+                            expr, r->filename);
+                *was_error = 1;
+                return 0;
+            }
+            current->right->token.value =
+                ap_ssi_parse_string(ctx, current->right->token.value, NULL, 0,
+                                    SSI_EXPAND_DROP_NAME);
+            rr = ap_sub_req_lookup_uri(current->right->token.value, r, NULL);
+            /* 400 and higher are considered access denied */
+            if (rr->status < HTTP_BAD_REQUEST) {
+                current->value = 1;
+            }
+            else {
+                current->value = 0;
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rr->status, r, 
+                              "mod_include: The tested "
+                              "subrequest -A \"%s\" returned an error code.",
+                              current->right->token.value);
+            }
+            ap_destroy_sub_req(rr);
+            break;
+
         case TOKEN_RE:
             if (!error) {
                 error = "No operator before regex in expr \"%s\" in file %s";
@@ -3526,6 +3573,7 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
         if (ap_allow_options(r) & OPT_INCNOEXEC) {
             ctx->flags |= SSI_FLAG_NO_EXEC;
         }
+        intern->accessenable = conf->accessenable;
 
         ctx->if_nesting_level = 0;
         intern->re = NULL;
@@ -3808,6 +3856,9 @@ static const command_rec includes_cmds[] =
                   "SSI End String Tag"),
     AP_INIT_TAKE1("SSIUndefinedEcho", set_undefined_echo, NULL, OR_ALL,
                   "String to be displayed if an echoed variable is undefined"),
+    AP_INIT_FLAG("SSIAccessEnable", ap_set_flag_slot,
+                  (void *)APR_OFFSETOF(include_dir_config, accessenable),
+                  OR_LIMIT, "Whether testing access is enabled. Limited to 'on' or 'off'"),
     {NULL}
 };