📄 mod_include.c
字号:
*p = *s; continue; } /* find end of entity */ for (i = 1; s[i] != ';' && s[i] != '\0'; i++) { continue; } if (s[i] == '\0') { /* treat as normal data */ *p = *s; continue; } /* is it numeric ? */ if (s[1] == '#') { for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) { val = val * 10 + s[j] - '0'; } s += i; if (j < i || val <= 8 || (val >= 11 && val <= 31) || (val >= 127 && val <= 160) || val >= 256) { p--; /* no data to output */ } else { *p = RAW_ASCII_CHAR(val); } } else { j = i - 1; if (j > MAXENTLEN || entlist[j] == NULL) { /* wrong length */ *p = '&'; continue; /* skip it */ } for (ents = entlist[j]; *ents != '\0'; ents += i) { if (strncmp(s + 1, ents, j) == 0) { break; } } if (*ents == '\0') { *p = '&'; /* unknown */ } else { *p = RAW_ASCII_CHAR(((const unsigned char *) ents)[j]); s += i; } } } *p = '\0';}/* * Extract the next tag name and value. * If there are no more tags, set the tag name to NULL. * The tag value is html decoded if dodecode is non-zero. * The tag value may be NULL if there is no tag value.. * format: * [WS]<Tag>[WS]=[WS]['|"|`]<Value>[['|"|`|]|WS] */#define SKIP_TAG_WHITESPACE(ptr) while ((*ptr != '\0') && (apr_isspace (*ptr))) ptr++static void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag, char **tag_val, int dodecode){ *tag_val = NULL; if (ctx->curr_tag_pos >= ctx->combined_tag + ctx->tag_length) { *tag = NULL; return; } *tag = ctx->curr_tag_pos; if (!**tag) { *tag = NULL; /* finitio */ ctx->curr_tag_pos = ctx->combined_tag + ctx->tag_length; return; } *tag_val = ap_strchr(*tag, '='); if (!*tag_val) { ctx->curr_tag_pos = ctx->combined_tag + ctx->tag_length; return; } /* if it starts with '=' there was no tag name, just a value */ if (*tag_val == *tag) { *tag = NULL; } *(*tag_val)++ = '\0'; ctx->curr_tag_pos = *tag_val + strlen(*tag_val) + 1; /* skip \0 byte */ if (dodecode) { decodehtml(*tag_val); } return;}/* initial buffer size for power-of-two allocator in ap_ssi_parse_string */#define PARSE_STRING_INITIAL_SIZE 64/* * Do variable substitution on strings * (Note: If out==NULL, this function allocs a buffer for the resulting * string from r->pool. The return value is the parsed string) */static char *ap_ssi_parse_string(request_rec *r, include_ctx_t *ctx, const char *in, char *out, apr_size_t length, int leave_name){ char ch; char *next; char *end_out; apr_size_t out_size; /* allocate an output buffer if needed */ if (!out) { out_size = PARSE_STRING_INITIAL_SIZE; if (out_size > length) { out_size = length; } out = apr_palloc(r->pool, out_size); } else { out_size = length; } /* leave room for nul terminator */ end_out = out + out_size - 1; next = out; while ((ch = *in++) != '\0') { switch (ch) { case '\\': if (next == end_out) { if (out_size < length) { /* double the buffer size */ apr_size_t new_out_size = out_size * 2; apr_size_t current_length = next - out; char *new_out; if (new_out_size > length) { new_out_size = length; } new_out = apr_palloc(r->pool, new_out_size); memcpy(new_out, out, current_length); out = new_out; out_size = new_out_size; end_out = out + out_size - 1; next = out + current_length; } else { /* truncated */ *next = '\0'; return out; } } if (*in == '$') { *next++ = *in++; } else { *next++ = ch; } break; case '$': { const char *start_of_var_name; char *end_of_var_name; /* end of var name + 1 */ const char *expansion, *temp_end, *val; char tmp_store; apr_size_t l; /* guess that the expansion won't happen */ expansion = in - 1; if (*in == '{') { ++in; start_of_var_name = in; in = ap_strchr_c(in, '}'); if (in == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Missing '}' on variable \"%s\"", expansion); *next = '\0'; return out; } temp_end = in; end_of_var_name = (char *)temp_end; ++in; } else { start_of_var_name = in; while (apr_isalnum(*in) || *in == '_') { ++in; } temp_end = in; end_of_var_name = (char *)temp_end; } /* what a pain, too bad there's no table_getn where you can * pass a non-nul terminated string */ l = end_of_var_name - start_of_var_name; if (l != 0) { tmp_store = *end_of_var_name; *end_of_var_name = '\0'; val = get_include_var(r, ctx, start_of_var_name); *end_of_var_name = tmp_store; if (val) { expansion = val; l = strlen(expansion); } else if (leave_name) { l = in - expansion; } else { /* no expansion to be done */ break; } } else { /* zero-length variable name causes just the $ to be * copied */ l = 1; } if ((next + l > end_out) && (out_size < length)) { /* increase the buffer size to accommodate l more chars */ apr_size_t new_out_size = out_size; apr_size_t current_length = next - out; char *new_out; do { new_out_size *= 2; } while (new_out_size < current_length + l + 1); /* +1 for NUL */ if (new_out_size > length) { new_out_size = length; } new_out = apr_palloc(r->pool, new_out_size); memcpy(new_out, out, current_length); out = new_out; out_size = new_out_size; end_out = out + out_size - 1; next = out + current_length; } l = ((int)l > end_out - next) ? (end_out - next) : l; memcpy(next, expansion, l); next += l; break; } default: if (next == end_out) { if (out_size < length) { /* double the buffer size */ apr_size_t new_out_size = out_size * 2; apr_size_t current_length = next - out; char *new_out; if (new_out_size > length) { new_out_size = length; } new_out = apr_palloc(r->pool, new_out_size); memcpy(new_out, out, current_length); out = new_out; out_size = new_out_size; end_out = out + out_size - 1; next = out + current_length; } else { /* truncated */ *next = '\0'; return out; } } *next++ = ch; break; } } *next = '\0'; return out;}/* --------------------------- Action handlers ---------------------------- *//* ensure that path is relative, and does not contain ".." elements * ensentially ensure that it does not match the regex: * (^/|(^|/)\.\.(/|$)) * XXX: Simply replace with apr_filepath_merge */static int is_only_below(const char *path){#ifdef HAVE_DRIVE_LETTERS if (path[1] == ':') return 0;#endif#ifdef NETWARE if (ap_strchr_c(path, ':')) return 0;#endif if (path[0] == '/') { return 0; } while (*path) { int dots = 0; while (path[dots] == '.') ++dots;#if defined(WIN32) /* If the name is canonical this is redundant * but in security, redundancy is worthwhile. * Does OS2 belong here (accepts ... for ..)? */ if (dots > 1 && (!path[dots] || path[dots] == '/')) return 0;#else if (dots == 2 && (!path[dots] || path[dots] == '/')) return 0;#endif path += dots; /* Advance to either the null byte at the end of the * string or the character right after the next slash, * whichever comes first */ while (*path && (*path++ != '/')) { continue; } } return 1;}static int handle_include(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head){ char *tag = NULL; char *tag_val = NULL; apr_bucket *tmp_buck; char *parsed_string; int loglevel = APLOG_ERR; *inserted_head = NULL; if (ctx->flags & FLAG_PRINTING) { while (1) { ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); if (tag_val == NULL) { if (tag == NULL) { return (0); } else { return (1); } } if (!strcmp(tag, "virtual") || !strcmp(tag, "file")) { request_rec *rr = NULL; char *error_fmt = NULL; apr_status_t rc = APR_SUCCESS; SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next, rc); if (rc != APR_SUCCESS) { return rc; } parsed_string = ap_ssi_parse_string(r, ctx, tag_val, NULL, MAX_STRING_LEN, 0); if (tag[0] == 'f') { /* XXX: Port to apr_filepath_merge * be safe; only files in this directory or below allowed */ if (!is_only_below(parsed_string)) { error_fmt = "unable to include file \"%s\" " "in parsed file %s"; } else { rr = ap_sub_req_lookup_uri(parsed_string, r, f->next); } } else { rr = ap_sub_req_lookup_uri(parsed_string, r, f->next); } if (!error_fmt && rr->status != HTTP_OK) { error_fmt = "unable to include \"%s\" in parsed file %s"; } if (!error_fmt && (ctx->flags & FLAG_NO_EXEC) && rr->content_type && (strncmp(rr->content_type, "text/", 5))) { error_fmt = "unable to include potential exec \"%s\" " "in parsed file %s";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -