]> granicus.if.org Git - apache/blobdiff - modules/filters/mod_include.c
Fix a segfault in mod_include when the original request has no
[apache] / modules / filters / mod_include.c
index 7e2e182d62c3679ddb027e22eed252578f3d5b7d..b65a50ba10d1c576b664610ebcdf4c55fc63d4f0 100644 (file)
@@ -165,7 +165,7 @@ static apr_bucket *find_start_sequence(apr_bucket *dptr, include_ctx_t *ctx,
             break;
         }
         c = buf;
-        while (c - buf != len) {
+        while (c < buf + len) {
             if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {
                 apr_bucket *start_bucket;
 
@@ -182,6 +182,8 @@ static apr_bucket *find_start_sequence(apr_bucket *dptr, include_ctx_t *ctx,
                 if (ctx->head_start_index > 0) {
                     ctx->head_start_index  = 0;
                     ctx->head_start_bucket = tmp_bkt;
+                    ctx->parse_pos = 0;
+                    ctx->state = PRE_HEAD;
                 }
 
                 return tmp_bkt;
@@ -268,8 +270,13 @@ static apr_bucket *find_end_sequence(apr_bucket *dptr, include_ctx_t *ctx, apr_b
         else {
             c = buf;
         }
-        while (c - buf != len) {
+        while (c < buf + len) {
             if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {
+                if (ctx->state == PARSE_DIRECTIVE) {
+                    /* gonna start over parsing the directive next time through */
+                    ctx->directive_length = 0;
+                    ctx->tag_length       = 0;
+                }
                 return dptr;
             }
 
@@ -366,10 +373,11 @@ static apr_bucket *find_end_sequence(apr_bucket *dptr, include_ctx_t *ctx, apr_b
 static apr_status_t get_combined_directive (include_ctx_t *ctx,
                                             request_rec *r,
                                             apr_bucket_brigade *bb,
-                                            char *tmp_buf, int tmp_buf_size)
+                                            char *tmp_buf, 
+                                            apr_size_t tmp_buf_size)
 {
-    int         done = 0;
-    apr_bucket  *dptr;
+    int        done = 0;
+    apr_bucket *dptr;
     const char *tmp_from;
     apr_size_t tmp_from_len;
 
@@ -414,7 +422,7 @@ static apr_status_t get_combined_directive (include_ctx_t *ctx,
             }
         }
     } while ((!done) &&
-             ((ctx->curr_tag_pos - ctx->combined_tag) < ctx->tag_length));
+             (ctx->curr_tag_pos < ctx->combined_tag + ctx->tag_length));
 
     ctx->combined_tag[ctx->tag_length] = '\0';
     ctx->curr_tag_pos = ctx->combined_tag;
@@ -592,8 +600,8 @@ static void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag,
         }
     }
     
-    *c++ = '\0'; /* Overwrites delimiter (term or WS) with NULL. */
-    ctx->curr_tag_pos = c;
+    *(c-shift_val) = '\0'; /* Overwrites delimiter (term or WS) with NULL. */
+    ctx->curr_tag_pos = ++c;
     if (dodecode) {
         decodehtml(*tag_val);
     }
@@ -824,8 +832,8 @@ static int handle_include(include_ctx_t *ctx, apr_bucket_brigade **bb, request_r
                     for (p = r; p != NULL && !founddupe; p = p->main) {
                    request_rec *q;
                    for (q = p; q != NULL; q = q->prev) {
-                       if ( (strcmp(q->filename, rr->filename) == 0) ||
-                            (strcmp(q->uri, rr->uri) == 0) ){
+                       if ((q->filename && rr->filename && (strcmp(q->filename, rr->filename) == 0)) ||
+                            (strcmp(q->uri, rr->uri) == 0){
                            founddupe = 1;
                            break;
                        }
@@ -914,7 +922,7 @@ static int handle_echo(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec
                     tmp_buck = apr_bucket_heap_create(echo_text, e_len, 1, &e_wrt);
                 }
                 else {
-                    tmp_buck = apr_bucket_immortal_create("(none)", sizeof("none"));
+                    tmp_buck = apr_bucket_immortal_create("(none)", sizeof("(none)")-1);
                 }
                 APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
                 if (*inserted_head == NULL) {
@@ -1079,33 +1087,6 @@ static int find_file(request_rec *r, const char *directive, const char *tag,
     }
 }
 
-#define NEG_SIGN  "    -"
-#define ZERO_K    "   0k"
-#define ONE_K     "   1k"
-
-static void generate_size(apr_ssize_t size, char *buff, apr_size_t buff_size)
-{
-    /* XXX: this -1 thing is a gross hack */
-    if (size == (apr_ssize_t)-1) {
-       memcpy (buff, NEG_SIGN, sizeof(NEG_SIGN)+1);
-    }
-    else if (!size) {
-       memcpy (buff, ZERO_K, sizeof(ZERO_K)+1);
-    }
-    else if (size < 1024) {
-       memcpy (buff, ONE_K, sizeof(ONE_K)+1);
-    }
-    else if (size < 1048576) {
-        apr_snprintf(buff, buff_size, "%4" APR_SSIZE_T_FMT "k", (size + 512) / 1024);
-    }
-    else if (size < 103809024) {
-        apr_snprintf(buff, buff_size, "%4.1fM", size / 1048576.0);
-    }
-    else {
-        apr_snprintf(buff, buff_size, "%4" APR_SSIZE_T_FMT "M", (size + 524288) / 1048576);
-    }
-}
-
 static int handle_fsize(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
                         ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
 {
@@ -1134,7 +1115,7 @@ static int handle_fsize(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec
                     char buff[50];
 
                     if (!(ctx->flags & FLAG_SIZE_IN_BYTES)) {
-                        generate_size(finfo.size, buff, sizeof(buff));
+                        apr_strfsize(finfo.size, buff);
                         s_len = strlen (buff);
                     }
                     else {
@@ -2345,14 +2326,15 @@ static int handle_printenv(include_ctx_t *ctx, apr_bucket_brigade **bb, request_
 
 /* -------------------------- The main function --------------------------- */
 
-static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r
-                                ap_filter_t *f)
+static apr_status_t send_parsed_content(apr_bucket_brigade **bb
+                                        request_rec *r, ap_filter_t *f)
 {
     include_ctx_t *ctx = f->ctx;
     apr_bucket *dptr = APR_BRIGADE_FIRST(*bb);
     apr_bucket *tmp_dptr;
     apr_bucket_brigade *tag_and_after;
     int ret;
+    apr_status_t rv;
 
     if (r->args) {              /* add QUERY stuff to env cause it ain't yet */
         char *arg_copy = apr_pstrdup(r->pool, r->args);
@@ -2378,13 +2360,10 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
             if ((do_cleanup) && (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade))) {
                 apr_bucket *tmp_bkt;
 
-                tmp_bkt = apr_bucket_immortal_create(STARTING_SEQUENCE, cleanup_bytes);
+                tmp_bkt = apr_bucket_immortal_create(STARTING_SEQUENCE,
+                                                     cleanup_bytes);
                 APR_BRIGADE_INSERT_HEAD(*bb, tmp_bkt);
-
-                while (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
-                    tmp_bkt = APR_BRIGADE_FIRST(ctx->ssi_tag_brigade);
-                    apr_bucket_delete(tmp_bkt);
-                }
+                apr_brigade_cleanup(ctx->ssi_tag_brigade);
             }
 
             /* If I am inside a conditional (if, elif, else) that is false
@@ -2413,7 +2392,10 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
             else if ((tmp_dptr != NULL) && (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD)) {
                                /* Send the large chunk of pre-tag bytes...  */
                 tag_and_after = apr_brigade_split(*bb, tmp_dptr);
-                ap_pass_brigade(f->next, *bb);
+                rv = ap_pass_brigade(f->next, *bb);
+                if (rv != APR_SUCCESS) {
+                    return rv;
+                }
                 *bb  = tag_and_after;
                 dptr = tmp_dptr;
                 ctx->bytes_parsed = 0;
@@ -2480,10 +2462,7 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
                 /* DO CLEANUP HERE!!!!! */
                 tmp_dptr = ctx->head_start_bucket;
                 if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
-                    while (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
-                        tmp_bkt = APR_BRIGADE_FIRST(ctx->ssi_tag_brigade);
-                        apr_bucket_delete(tmp_bkt);
-                    }
+                    apr_brigade_cleanup(ctx->ssi_tag_brigade);
                 }
                 else {
                     do {
@@ -2494,7 +2473,7 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
                              (tmp_dptr != APR_BRIGADE_SENTINEL(*bb)));
                 }
 
-                return;
+                return APR_SUCCESS;
             }
 
             /* Can't destroy the tag buckets until I'm done processing
@@ -2515,9 +2494,9 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
             ctx->curr_tag_pos = &ctx->combined_tag[ctx->directive_length+1];
 
             handle_func = 
-                (int (*)(include_ctx_t *, apr_bucket_brigade **, request_rec *,
-                    ap_filter_t *, apr_bucket *, apr_bucket **))
-                apr_hash_get(include_hash, ctx->combined_tag, ctx->directive_length+1);
+                (include_handler_fn_t *)apr_hash_get(include_hash, 
+                                                     ctx->combined_tag, 
+                                                     ctx->directive_length+1);
             if (handle_func != NULL) {
                 ret = (*handle_func)(ctx, bb, r, f, dptr, &content_head);
             }
@@ -2551,10 +2530,7 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
             }
             tmp_dptr = ctx->head_start_bucket;
             if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
-                while (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
-                    tmp_bkt = APR_BRIGADE_FIRST(ctx->ssi_tag_brigade);
-                    apr_bucket_delete(tmp_bkt);
-                }
+                apr_brigade_cleanup(ctx->ssi_tag_brigade);
             }
             else {
                 do {
@@ -2582,10 +2558,7 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
             ctx->directive_length  = 0;
 
             if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
-                while (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
-                    tmp_bkt = APR_BRIGADE_FIRST(ctx->ssi_tag_brigade);
-                    apr_bucket_delete(tmp_bkt);
-                }
+                apr_brigade_cleanup(ctx->ssi_tag_brigade);
             }
 
             ctx->state     = PRE_HEAD;
@@ -2610,7 +2583,10 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
             } while (dptr != APR_BRIGADE_SENTINEL(*bb));
         }
         else { /* Otherwise pass it along... */
-            ap_pass_brigade(f->next, *bb);  /* No SSI tags in this brigade... */
+            rv = ap_pass_brigade(f->next, *bb);  /* No SSI tags in this brigade... */
+            if (rv != APR_SUCCESS) {
+                return rv;
+            }
             ctx->bytes_parsed = 0;
         }
     }
@@ -2632,11 +2608,15 @@ static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
             }
                            /* Set aside tag, pass pre-tag... */
             tag_and_after = apr_brigade_split(*bb, ctx->head_start_bucket);
-            ap_save_brigade(f, &ctx->ssi_tag_brigade, &tag_and_after);
-            ap_pass_brigade(f->next, *bb);
+            ap_save_brigade(f, &ctx->ssi_tag_brigade, &tag_and_after, r->pool);
+            rv = ap_pass_brigade(f->next, *bb);
+            if (rv != APR_SUCCESS) {
+                return rv;
+            }
             ctx->bytes_parsed = 0;
         }
     }
+    return APR_SUCCESS;
 }
 
 /*****************************************************************
@@ -2672,7 +2652,6 @@ static void *create_includes_dir_config(apr_pool_t *p, char *dummy)
     result->default_time_fmt = DEFAULT_TIME_FORMAT;
     result->xbithack = xbh;
     return result;
-    return result;
 }
 
 static const char *set_xbithack(cmd_parms *cmd, void *xbp, const char *arg)
@@ -2695,11 +2674,12 @@ static const char *set_xbithack(cmd_parms *cmd, void *xbp, const char *arg)
     return NULL;
 }
 
-static int includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
+static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
 {
     request_rec *r = f->r;
     include_ctx_t *ctx = f->ctx;
     request_rec *parent;
+    apr_status_t rv;
     include_dir_config *conf = 
                    (include_dir_config *)ap_get_module_config(r->per_dir_config,
                                                               &include_module);
@@ -2707,7 +2687,7 @@ static int includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
     if (!(ap_allow_options(r) & OPT_INCLUDES)) {
         return ap_pass_brigade(f->next, b);
     }
-    r->allowed |= (1 << M_GET);
+    r->allowed |= (AP_METHOD_BIT << M_GET);
     if (r->method_number != M_GET) {
         return ap_pass_brigade(f->next, b);
     }
@@ -2727,8 +2707,7 @@ static int includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
             ctx->error_length = strlen(ctx->error_str);
         }
         else {
-            ap_pass_brigade(f->next, b);
-            return APR_ENOMEM;
+            return ap_pass_brigade(f->next, b);
         }
     }
     else {
@@ -2779,7 +2758,7 @@ static int includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
      */
     apr_table_unset(f->r->headers_out, "Content-Length");
 
-    send_parsed_content(&b, r, f);
+    rv = send_parsed_content(&b, r, f);
 
     if (parent) {
        /* signify that the sub request should not be killed */
@@ -2787,10 +2766,10 @@ static int includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
            NESTED_INCLUDE_MAGIC);
     }
 
-    return OK;
+    return rv;
 }
 
-static void ap_register_include_handler(char *tag, include_handler *func)
+static void ap_register_include_handler(char *tag, include_handler_fn_t *func)
 {
     apr_hash_set(include_hash, tag, strlen(tag) + 1, (const void *)func);
 }
@@ -2845,12 +2824,42 @@ static const command_rec includes_cmds[] =
     {NULL}
 };
 
+static int xbithack_handler(request_rec *r)
+{
+#if defined(OS2) || defined(WIN32) || defined(NETWARE)
+    /* OS/2 dosen't currently support the xbithack. This is being worked on. */
+    return DECLINED;
+#else
+    enum xbithack *state;
+    if (ap_strcmp_match(r->handler, "text/html")) {
+        return DECLINED;
+    }
+    if (!(r->finfo.protection & APR_UEXECUTE)) {
+        return DECLINED;
+    }
+    state = (enum xbithack *) ap_get_module_config(r->per_dir_config,
+                                                &include_module);
+    if (*state == xbithack_off) {
+        return DECLINED;
+    }
+    /* We always return declined, because the default handler will actually
+     * serve the file.  All we have to do is add the filter.
+     */
+    ap_add_output_filter("INCLUDES", NULL, r, r->connection);
+    return DECLINED;
+#endif
+}
+
 static void register_hooks(apr_pool_t *p)
 {
     APR_REGISTER_OPTIONAL_FN(ap_ssi_get_tag_and_value);
     APR_REGISTER_OPTIONAL_FN(ap_ssi_parse_string);
     APR_REGISTER_OPTIONAL_FN(ap_register_include_handler);
     ap_hook_post_config(include_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
+    ap_hook_handler(xbithack_handler, NULL, NULL, APR_HOOK_MIDDLE);
     ap_register_output_filter("INCLUDES", includes_filter, AP_FTYPE_CONTENT);
 }