mirror of
https://github.com/apache/httpd.git
synced 2025-08-01 07:26:57 +03:00
Replace ap_expr with a parser derived from mod_ssl's parser. Make mod_ssl use
the new parser. Rework ap_expr's public interface and provide hooks for modules to add variables and functions. The Netware and Windows build files still need to be adjusted git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1032073 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
6
CHANGES
6
CHANGES
@ -6,6 +6,12 @@ Changes with Apache 2.3.9
|
||||
Fix a denial of service attack against mod_reqtimeout.
|
||||
[Stefan Fritsch]
|
||||
|
||||
*) core, mod_include, mod_ssl: Move the expression parser derived from
|
||||
mod_include back into mod_include. Replace ap_expr with a parser
|
||||
derived from mod_ssl's parser. Make mod_ssl use the new parser. Rework
|
||||
ap_expr's public interface and provide hooks for modules to add variables
|
||||
and functions. [Stefan Fritsch]
|
||||
|
||||
*) core: Do the hook sorting earlier so that the hooks are properly sorted
|
||||
for the pre_config hook and during parsing the config. [Stefan Fritsch]
|
||||
|
||||
|
14
buildconf
14
buildconf
@ -226,15 +226,15 @@ if [ -f `which cut` ]; then
|
||||
> httpd.spec )
|
||||
fi
|
||||
|
||||
# ensure that the mod_ssl expression parser sources are never regenerated
|
||||
# ensure that the ap_expr expression parser sources are never regenerated
|
||||
# when running make
|
||||
echo fixing timestamps for mod_ssl sources
|
||||
cd modules/ssl
|
||||
touch ssl_expr_parse.y
|
||||
echo fixing timestamps for ap_expr sources
|
||||
cd server
|
||||
touch util_expr_parse.y
|
||||
sleep 1
|
||||
touch ssl_expr_parse.c ssl_expr_parse.h ssl_expr_scan.l
|
||||
touch util_expr_parse.c util_expr_parse.h util_expr_scan.l
|
||||
sleep 1
|
||||
touch ssl_expr_scan.c
|
||||
cd ../..
|
||||
touch util_expr_scan.c
|
||||
cd ..
|
||||
|
||||
exit 0
|
||||
|
@ -23,128 +23,193 @@
|
||||
#define AP_EXPR_H
|
||||
|
||||
#include "httpd.h"
|
||||
#include "http_config.h"
|
||||
#include "ap_regex.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* conditional expression parser stuff */
|
||||
typedef enum {
|
||||
TOKEN_STRING,
|
||||
TOKEN_RE,
|
||||
TOKEN_AND,
|
||||
TOKEN_OR,
|
||||
TOKEN_NOT,
|
||||
TOKEN_EQ,
|
||||
TOKEN_NE,
|
||||
TOKEN_RBRACE,
|
||||
TOKEN_LBRACE,
|
||||
TOKEN_GROUP,
|
||||
TOKEN_GE,
|
||||
TOKEN_LE,
|
||||
TOKEN_GT,
|
||||
TOKEN_LT,
|
||||
TOKEN_ACCESS,
|
||||
TOKEN_IN
|
||||
} token_type_t;
|
||||
/** A node in the expression parse tree */
|
||||
typedef struct ap_expr_node ap_expr;
|
||||
|
||||
/** Struct describing a parsed expression */
|
||||
typedef struct {
|
||||
token_type_t type;
|
||||
const char *value;
|
||||
#ifdef DEBUG_INCLUDE
|
||||
const char *s;
|
||||
#endif
|
||||
} token_t;
|
||||
/** The root of the actual expression parse tree */
|
||||
ap_expr *root_node;
|
||||
/** The filename where the expression has been defined (for logging).
|
||||
* May be NULL
|
||||
*/
|
||||
const char *filename;
|
||||
/** The line number where the expression has been defined (for logging). */
|
||||
unsigned int line_number;
|
||||
#define AP_EXPR_FLAGS_SSL_EXPR_COMPAT 1
|
||||
/** Flags relevant for the expression */
|
||||
unsigned int flags;
|
||||
/** The module that is used for loglevel configuration (XXX put into eval_ctx?) */
|
||||
int module_index;
|
||||
} ap_expr_info_t;
|
||||
|
||||
typedef struct parse_node {
|
||||
struct parse_node *parent;
|
||||
struct parse_node *left;
|
||||
struct parse_node *right;
|
||||
token_t token;
|
||||
int value;
|
||||
int done;
|
||||
#ifdef DEBUG_INCLUDE
|
||||
int dump_done;
|
||||
#endif
|
||||
} ap_parse_node_t;
|
||||
|
||||
/**
|
||||
* Evaluate a parse tree
|
||||
* @param r The current request
|
||||
* @param expr The expression to be evaluated
|
||||
* @param err A more detailed error string
|
||||
* @return > 0 if expression evaluates to true, == 0 if false, < 0 on error
|
||||
*/
|
||||
AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *expr,
|
||||
const char **err);
|
||||
|
||||
/** Context used during evaluation of a parse tree, created by ap_expr_exec */
|
||||
typedef struct {
|
||||
const char *source;
|
||||
const char *rexp;
|
||||
apr_size_t nsub;
|
||||
ap_regmatch_t match[AP_MAX_REG_MATCH];
|
||||
int have_match;
|
||||
} backref_t;
|
||||
/** the current request */
|
||||
request_rec *r;
|
||||
/** the current connection */
|
||||
conn_rec *c;
|
||||
/** the current connection */
|
||||
server_rec *s;
|
||||
/** the pool to use */
|
||||
apr_pool_t *p;
|
||||
/** where to store the error string */
|
||||
const char **err;
|
||||
/** ap_expr_info_t for the expression */
|
||||
const ap_expr_info_t *info;
|
||||
} ap_expr_eval_ctx;
|
||||
|
||||
typedef const char *(*string_func_t)(request_rec*, const char*);
|
||||
typedef int (*opt_func_t)(request_rec*, ap_parse_node_t*, string_func_t);
|
||||
|
||||
/**
|
||||
* The parse can be extended with variable lookup, functions, and
|
||||
* and operators.
|
||||
*
|
||||
* During parsing, the parser calls the lookup function to resolve a
|
||||
* name into a function pointer and an opaque context for the function.
|
||||
*
|
||||
* The default lookup function is the hook 'ap_run_expr_lookup'.
|
||||
* Modules can use it to make functions and variables generally available.
|
||||
*
|
||||
* An ap_expr consumer can also provide its own custom lookup function to
|
||||
* modify the set of variables and functions that are available. The custom
|
||||
* lookup function can in turn call 'ap_run_expr_lookup'.
|
||||
*/
|
||||
|
||||
/** Unary operator, takes one string argument and returns a bool value.
|
||||
* The name must have the form '-z' (one letter only).
|
||||
* @param ctx The evaluation context
|
||||
* @param data An opaque context provided by the lookup hook function
|
||||
* @param arg The (right) operand
|
||||
* @return 0 or 1
|
||||
*/
|
||||
typedef int ap_expr_op_unary_t(ap_expr_eval_ctx *ctx, const void *data,
|
||||
const char *arg);
|
||||
|
||||
/** Binary operator, takes two string arguments and returns a bool value.
|
||||
* The name must have the form '-cmp' (at least two letters).
|
||||
* @param ctx The evaluation context
|
||||
* @param data An opaque context provided by the lookup hook function
|
||||
* @param arg1 The left operand
|
||||
* @param arg2 The right operand
|
||||
* @return 0 or 1
|
||||
*/
|
||||
typedef int ap_expr_op_binary_t(ap_expr_eval_ctx *ctx, const void *data,
|
||||
const char *arg1, const char *arg2);
|
||||
|
||||
/** String valued function, takes a string argument and returns a string
|
||||
* @param ctx The evaluation context
|
||||
* @param data An opaque context provided by the lookup hook function
|
||||
* @param arg The argument
|
||||
* @return The functions result string, may be NULL for 'empty string'
|
||||
*/
|
||||
typedef const char *(ap_expr_string_func_t)(ap_expr_eval_ctx *ctx, const void *data,
|
||||
const char *arg);
|
||||
|
||||
/** List valued function, takes a string argument and returns a list of strings
|
||||
* Can currently only be called following the builtin '-in' operator.
|
||||
* @param ctx The evaluation context
|
||||
* @param data An opaque context provided by the lookup hook function
|
||||
* @param arg The argument
|
||||
* @return The functions result list of strings, may be NULL for 'empty array'
|
||||
*/
|
||||
typedef apr_array_header_t *(ap_expr_list_func_t)(ap_expr_eval_ctx *ctx, const void *data,
|
||||
const char *arg);
|
||||
|
||||
/** Variable lookup function, takes no argument and returns a string
|
||||
* @param ctx The evaluation context
|
||||
* @param data An opaque context provided by the lookup hook function
|
||||
* @return The expanded variable
|
||||
*/
|
||||
typedef const char *(ap_expr_var_func_t)(ap_expr_eval_ctx *ctx, const void *data);
|
||||
|
||||
/** parameter struct passed to the lookup hook functions */
|
||||
typedef struct {
|
||||
/** type of the looked up object */
|
||||
int type;
|
||||
#define AP_EXPR_FUNC_VAR 0
|
||||
#define AP_EXPR_FUNC_STRING 1
|
||||
#define AP_EXPR_FUNC_LIST 2
|
||||
#define AP_EXPR_FUNC_OP_UNARY 3
|
||||
#define AP_EXPR_FUNC_OP_BINARY 4
|
||||
/** name of the looked up object */
|
||||
const char *name;
|
||||
|
||||
int flags;
|
||||
|
||||
apr_pool_t *pool;
|
||||
apr_pool_t *ptemp;
|
||||
|
||||
/** where to store the function pointer */
|
||||
const void **func;
|
||||
/** where to store the function's context */
|
||||
const void **data;
|
||||
/** Where to store the error message (if any) */
|
||||
const char **err;
|
||||
} ap_expr_lookup_parms;
|
||||
|
||||
/** Function for looking up the provider function for a variable, operator
|
||||
* or function in an expression.
|
||||
* @param parms The parameter struct, also determins where the result is
|
||||
* stored.
|
||||
* @return OK on success,
|
||||
* !OK on failure,
|
||||
* DECLINED if the requested name is not handled by this function
|
||||
*/
|
||||
typedef int (ap_expr_lookup_fn)(ap_expr_lookup_parms *parms);
|
||||
|
||||
AP_DECLARE_HOOK(int, expr_lookup, (ap_expr_lookup_parms *parms))
|
||||
|
||||
/**
|
||||
* Parse an expression into a parse tree
|
||||
* @param pool Pool
|
||||
* @param expr The expression to parse
|
||||
* @param was_error On return, set to zero if parse successful, nonzero on error
|
||||
* @return The parse tree
|
||||
* @param ptemp temp pool
|
||||
* @param info The ap_expr_info_t struct (with values filled in)
|
||||
* @param expr The expression string to parse
|
||||
* @param lookup_fn The lookup function to use, NULL for default
|
||||
* @return NULL on success, error message on error.
|
||||
* A pointer to the resulting parse tree will be stored in
|
||||
* info->root_node.
|
||||
*/
|
||||
AP_DECLARE(ap_parse_node_t*) ap_expr_parse(apr_pool_t *pool, const char *expr,
|
||||
int *was_error);
|
||||
/**
|
||||
* Evaluate a parse tree
|
||||
* @param r The current request
|
||||
* @param root The root node of the parse tree
|
||||
* @param was_error On return, set to zero if parse successful, nonzero on error
|
||||
* @param reptr Regular expression memory for backreferencing if a regexp was parsed
|
||||
* @param string_func String parser function - perform variable substitutions
|
||||
* Use ap_expr_string where applicable
|
||||
* @param eval_func Option evaluation function (e.g. -A filename)
|
||||
* @return the value the expression parsed to
|
||||
*/
|
||||
AP_DECLARE(int) ap_expr_eval(request_rec *r, const ap_parse_node_t *root,
|
||||
int *was_error, backref_t **reptr,
|
||||
string_func_t string_func, opt_func_t eval_func);
|
||||
/**
|
||||
* Evaluate an expression. This is functionally equivalent to
|
||||
* ap_expr_parse followed by ap_expr_eval, but faster and more efficient
|
||||
* when an expression only needs to be parsed once and discarded.
|
||||
* @param r The current request
|
||||
* @param expr The expression to parse
|
||||
* @param was_error On return, set to zero if parse successful, nonzero on error
|
||||
* @param reptr Regular expression memory for backreferencing if a regexp was parsed
|
||||
* @param string_func String parser function - perform variable substitutions
|
||||
* Use ap_expr_string where applicable
|
||||
* @param eval_func Option evaluation function (e.g. -A filename)
|
||||
* @return the value the expression parsed to
|
||||
*/
|
||||
AP_DECLARE(int) ap_expr_evalstring(request_rec *r, const char *expr,
|
||||
int *was_error, backref_t **reptr,
|
||||
string_func_t string_func,
|
||||
opt_func_t eval_func);
|
||||
AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
|
||||
ap_expr_info_t *info, const char *expr,
|
||||
ap_expr_lookup_fn *lookup_fn);
|
||||
|
||||
/**
|
||||
* Internal initialisation of ap_expr (for httpd)
|
||||
* @param pool Pool
|
||||
* @return APR_SUCCESS or error
|
||||
* High level interface to ap_expr_parse that also creates ap_expr_info_t and
|
||||
* uses info from cmd_parms to fill in most of it.
|
||||
* @param cmd The cmd_parms struct
|
||||
* @param expr The expression string to parse
|
||||
* @param err Set to NULL on success, error message on error
|
||||
* @return The parsed expression
|
||||
*/
|
||||
AP_DECLARE(apr_status_t) ap_expr_init(apr_pool_t *pool);
|
||||
AP_DECLARE(ap_expr_info_t *) ap_expr_parse_cmd(const cmd_parms *cmd,
|
||||
const char *expr,
|
||||
const char **err,
|
||||
ap_expr_lookup_fn *lookup_fn);
|
||||
|
||||
|
||||
/**
|
||||
* Default string evaluation function for passing to ap_expr_eval and
|
||||
* ap_expr_evalstring. Use this (and update as necessary) to offer
|
||||
* a consistent expression syntax across different modules.
|
||||
* Supports the following:
|
||||
* $req{foo} - request header "foo"
|
||||
* $resp{foo} - response header "foo"
|
||||
* $env{foo} - environment variable "foo"
|
||||
* $handler - r->handler
|
||||
* $content-type - r->content_type
|
||||
* Other strings are returned unmodified.
|
||||
* @param r The current request
|
||||
* @param str The string to evaluate
|
||||
* @return The evaluated string
|
||||
* Internal initialisation of ap_expr (for httpd internal use)
|
||||
*/
|
||||
AP_DECLARE_NONSTD(const char*) ap_expr_string(request_rec *r,
|
||||
const char *str);
|
||||
void ap_expr_init(apr_pool_t *pool);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -277,12 +277,16 @@
|
||||
* 20101016.0 (2.3.9-dev) Remove ap_cache_check_allowed().
|
||||
* 20101017.0 (2.3.9-dev) Make ap_cache_control() public, add cache_control_t
|
||||
* to mod_disk_cache format.
|
||||
* 20101106.0 (2.3.9-dev) Replace the ap_expr parser derived from
|
||||
* mod_include's parser with one derived from
|
||||
* mod_ssl's parser. Clean up ap_expr's public
|
||||
* interface.
|
||||
*/
|
||||
|
||||
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
|
||||
|
||||
#ifndef MODULE_MAGIC_NUMBER_MAJOR
|
||||
#define MODULE_MAGIC_NUMBER_MAJOR 20101017
|
||||
#define MODULE_MAGIC_NUMBER_MAJOR 20101106
|
||||
#endif
|
||||
#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */
|
||||
|
||||
|
@ -534,7 +534,7 @@ typedef struct {
|
||||
#define USE_CANONICAL_PHYS_PORT_UNSET (2)
|
||||
unsigned use_canonical_phys_port : 2;
|
||||
|
||||
ap_parse_node_t *condition; /* Conditionally merge <If> sections */
|
||||
ap_expr_info_t *condition; /* Conditionally merge <If> sections */
|
||||
|
||||
/** per-dir log config */
|
||||
struct ap_logconf *log;
|
||||
|
@ -988,20 +988,22 @@ static authz_status expr_check_authorization(request_rec *r,
|
||||
const char *require_line,
|
||||
const void *parsed_require_line)
|
||||
{
|
||||
int err = 0;
|
||||
const ap_parse_node_t *expr = parsed_require_line;
|
||||
const char *err = NULL;
|
||||
const ap_expr_info_t *expr = parsed_require_line;
|
||||
int rc = ap_expr_exec(r, expr, &err);
|
||||
|
||||
if (ap_expr_eval(r, expr, &err, NULL, ap_expr_string, NULL))
|
||||
return AUTHZ_GRANTED;
|
||||
else
|
||||
if (err || !rc)
|
||||
/* XXX: real error handling? */
|
||||
return AUTHZ_DENIED;
|
||||
else
|
||||
return AUTHZ_GRANTED;
|
||||
}
|
||||
|
||||
static const char *expr_parse_config(cmd_parms *cmd, const char *require_line,
|
||||
const void **parsed_require_line)
|
||||
{
|
||||
int expr_err = 0;
|
||||
ap_parse_node_t *expr = ap_expr_parse(cmd->pool, require_line, &expr_err);
|
||||
const char *expr_err = NULL;
|
||||
ap_expr_info_t *expr = ap_expr_parse_cmd(cmd, require_line, &expr_err, NULL);
|
||||
|
||||
if (expr_err)
|
||||
return "Cannot parse expression in require line";
|
||||
|
@ -36,7 +36,7 @@ module AP_MODULE_DECLARE_DATA filter_module;
|
||||
* (2.0-compatible) ap_filter_rec_t* frec.
|
||||
*/
|
||||
struct ap_filter_provider_t {
|
||||
ap_parse_node_t *expr;
|
||||
ap_expr_info_t *expr;
|
||||
|
||||
/** The filter that implements this provider */
|
||||
ap_filter_rec_t *frec;
|
||||
@ -134,7 +134,7 @@ static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter)
|
||||
{
|
||||
ap_filter_provider_t *provider;
|
||||
int match;
|
||||
int err = 0;
|
||||
const char *err = NULL;
|
||||
unsigned int proto_flags;
|
||||
request_rec *r = f->r;
|
||||
harness_ctx *ctx = f->ctx;
|
||||
@ -146,11 +146,12 @@ static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter)
|
||||
|
||||
/* Check registered providers in order */
|
||||
for (provider = filter->providers; provider; provider = provider->next) {
|
||||
match = ap_expr_eval(r, provider->expr, &err, NULL, ap_expr_string, NULL);
|
||||
match = ap_expr_exec(r, provider->expr, &err);
|
||||
if (err) {
|
||||
/* log error but accept match value ? */
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"Error evaluating filter dispatch condition");
|
||||
"Error evaluating filter dispatch condition: %s",
|
||||
err);
|
||||
}
|
||||
|
||||
if (match) {
|
||||
@ -402,8 +403,8 @@ static const char *filter_provider(cmd_parms *cmd, void *CFG,
|
||||
const char *c;
|
||||
ap_filter_rec_t* frec;
|
||||
ap_filter_rec_t* provider_frec;
|
||||
ap_parse_node_t *node;
|
||||
int err = 0;
|
||||
ap_expr_info_t *node;
|
||||
const char *err = NULL;
|
||||
|
||||
/* fname has been declared with DeclareFilter, so we can look it up */
|
||||
frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
|
||||
@ -426,9 +427,11 @@ static const char *filter_provider(cmd_parms *cmd, void *CFG,
|
||||
if (!provider_frec) {
|
||||
return apr_psprintf(cmd->pool, "Unknown filter provider %s", pname);
|
||||
}
|
||||
node = ap_expr_parse(cmd->pool, expr, &err);
|
||||
node = ap_expr_parse_cmd(cmd, expr, &err, NULL);
|
||||
if (err) {
|
||||
return "Error parsing FilterProvider expression.";
|
||||
return apr_pstrcat(cmd->pool,
|
||||
"Error parsing FilterProvider expression:", err,
|
||||
NULL);
|
||||
}
|
||||
|
||||
provider = apr_palloc(cmd->pool, sizeof(ap_filter_provider_t));
|
||||
@ -545,7 +548,7 @@ static const char *filter_bytype1(cmd_parms *cmd, void *CFG,
|
||||
*p++ = *type++;
|
||||
} while (*type);
|
||||
*p = 0;
|
||||
expr = apr_psprintf(cmd->temp_pool, "$content-type = /^%s/", etype);
|
||||
expr = apr_psprintf(cmd->temp_pool, "%%{CONTENT_TYPE} =~ m!^%s!", etype);
|
||||
|
||||
rv = filter_provider(cmd, CFG, fname, pname, expr);
|
||||
|
||||
|
@ -130,7 +130,7 @@ typedef struct {
|
||||
ap_regex_t *regex;
|
||||
const char *condition_var;
|
||||
const char *subs;
|
||||
ap_parse_node_t *expr;
|
||||
ap_expr_info_t *expr;
|
||||
} header_entry;
|
||||
|
||||
/* echo_do is used for Header echo to iterate through the request headers*/
|
||||
@ -398,7 +398,7 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
|
||||
const char *condition_var = NULL;
|
||||
const char *colon;
|
||||
header_entry *new;
|
||||
ap_parse_node_t *expr = NULL;
|
||||
ap_expr_info_t *expr = NULL;
|
||||
|
||||
apr_array_header_t *fixup = (cmd->info == &hdr_in)
|
||||
? dirconf->fixup_in : (cmd->info == &hdr_out_always)
|
||||
@ -491,10 +491,12 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
|
||||
condition_var = envclause + 4;
|
||||
}
|
||||
else {
|
||||
int err = 0;
|
||||
expr = ap_expr_parse(cmd->pool, envclause, &err);
|
||||
const char *err = NULL;
|
||||
expr = ap_expr_parse_cmd(cmd, envclause, &err, NULL);
|
||||
if (err) {
|
||||
return "Can't parse envclause/expression";
|
||||
return apr_pstrcat(cmd->pool,
|
||||
"Can't parse envclause/expression: ", err,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -645,12 +647,12 @@ static void do_headers_fixup(request_rec *r, apr_table_t *headers,
|
||||
}
|
||||
/* Do we have an expression to evaluate? */
|
||||
else if (hdr->expr != NULL) {
|
||||
int err = 0;
|
||||
int eval = ap_expr_eval(r, hdr->expr, &err, NULL,
|
||||
ap_expr_string, NULL);
|
||||
const char *err = NULL;
|
||||
int eval = ap_expr_exec(r, hdr->expr, &err);
|
||||
if (err) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"Failed to evaluate expression - ignoring");
|
||||
"Failed to evaluate expression (%s) - ignoring",
|
||||
err);
|
||||
}
|
||||
else if (!eval) {
|
||||
continue;
|
||||
|
@ -18,20 +18,3 @@
|
||||
#
|
||||
|
||||
include $(top_srcdir)/build/special.mk
|
||||
|
||||
#
|
||||
# developer stuff
|
||||
# (we really don't expect end users to use these targets!)
|
||||
#
|
||||
|
||||
ssl_expr_scan.c: $(top_srcdir)/modules/ssl/ssl_expr_scan.l ssl_expr_parse.h
|
||||
flex -Pssl_expr_yy -o ssl_expr_scan.c $(top_srcdir)/ssl_expr_scan.l
|
||||
mv ssl_expr_scan.c ssl_expr_scan.c.tmp
|
||||
sed -e "s|\"`pwd`/|\"|g" <ssl_expr_scan.c.tmp >ssl_expr_scan.c
|
||||
rm -f ssl_expr_scan.c.tmp
|
||||
|
||||
ssl_expr_parse.c ssl_expr_parse.h: $(top_srcdir)/modules/ssl/ssl_expr_parse.y
|
||||
bison -pssl_expr_yy --defines=ssl_expr_parse.h -o ssl_expr_parse.c $(top_srcdir)/modules/ssl/ssl_expr_parse.y
|
||||
mv ssl_expr_parse.c ssl_expr_parse.c.tmp
|
||||
sed -e "s|\"`pwd`/|\"|g" < ssl_expr_parse.c.tmp > ssl_expr_parse.c
|
||||
rm -f ssl_expr_parse.c.tmp
|
||||
|
@ -35,10 +35,6 @@ ssl_engine_mutex.lo dnl
|
||||
ssl_engine_pphrase.lo dnl
|
||||
ssl_engine_rand.lo dnl
|
||||
ssl_engine_vars.lo dnl
|
||||
ssl_expr.lo dnl
|
||||
ssl_expr_eval.lo dnl
|
||||
ssl_expr_parse.lo dnl
|
||||
ssl_expr_scan.lo dnl
|
||||
ssl_scache.lo dnl
|
||||
ssl_util_stapling.lo dnl
|
||||
ssl_util.lo dnl
|
||||
|
@ -565,11 +565,6 @@ static void ssl_register_hooks(apr_pool_t *p)
|
||||
&ssl_authz_provider_verify_client,
|
||||
AP_AUTH_INTERNAL_PER_CONF);
|
||||
|
||||
ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl-require",
|
||||
AUTHZ_PROVIDER_VERSION,
|
||||
&ssl_authz_provider_sslrequire,
|
||||
AP_AUTH_INTERNAL_PER_CONF);
|
||||
|
||||
}
|
||||
|
||||
module AP_MODULE_DECLARE_DATA ssl_module = {
|
||||
|
@ -1147,17 +1147,21 @@ const char *ssl_cmd_SSLRequire(cmd_parms *cmd,
|
||||
const char *arg)
|
||||
{
|
||||
SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
|
||||
ssl_expr *expr;
|
||||
ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
|
||||
ssl_require_t *require;
|
||||
const char *errstring;
|
||||
|
||||
if (!(expr = ssl_expr_comp(cmd->pool, arg, &errstring))) {
|
||||
info->flags = AP_EXPR_FLAGS_SSL_EXPR_COMPAT;
|
||||
info->filename = cmd->directive->filename;
|
||||
info->line_number = cmd->directive->line_num;
|
||||
errstring = ap_expr_parse(cmd->pool, cmd->temp_pool, info, arg, NULL);
|
||||
if (errstring) {
|
||||
return apr_pstrcat(cmd->pool, "SSLRequire: ", errstring, NULL);
|
||||
}
|
||||
|
||||
require = apr_array_push(dc->aRequirement);
|
||||
require->cpExpr = apr_pstrdup(cmd->pool, arg);
|
||||
require->mpExpr = expr;
|
||||
require->mpExpr = info;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -302,7 +302,6 @@ int ssl_hook_Access(request_rec *r)
|
||||
SSL_CTX *ctx = NULL;
|
||||
apr_array_header_t *requires;
|
||||
ssl_require_t *ssl_requires;
|
||||
char *cp;
|
||||
int ok, i;
|
||||
BOOL renegotiate = FALSE, renegotiate_quick = FALSE;
|
||||
X509 *cert;
|
||||
@ -900,17 +899,13 @@ int ssl_hook_Access(request_rec *r)
|
||||
for (i = 0; i < requires->nelts; i++) {
|
||||
ssl_require_t *req = &ssl_requires[i];
|
||||
const char *errstring;
|
||||
ok = ssl_expr_exec(r, req->mpExpr, &errstring);
|
||||
ok = ap_expr_exec(r, req->mpExpr, &errstring);
|
||||
|
||||
if (ok < 0) {
|
||||
cp = apr_psprintf(r->pool,
|
||||
"Failed to execute "
|
||||
"SSL requirement expression: %s",
|
||||
errstring);
|
||||
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"access to %s failed, reason: %s",
|
||||
r->filename, cp);
|
||||
"access to %s failed, reason: Failed to execute "
|
||||
"SSL requirement expression: %s",
|
||||
r->filename, errstring);
|
||||
|
||||
/* remember forbidden access for strict require option */
|
||||
apr_table_setn(r->notes, "ssl-access-forbidden", "1");
|
||||
@ -1282,54 +1277,6 @@ const authz_provider ssl_authz_provider_verify_client =
|
||||
};
|
||||
|
||||
|
||||
static authz_status ssl_authz_sslrequire_check(request_rec *r,
|
||||
const char *require_line,
|
||||
const void *parsed)
|
||||
{
|
||||
const ssl_expr *expr = parsed;
|
||||
const char *errstring;
|
||||
int ok = ssl_expr_exec(r, expr, &errstring);
|
||||
|
||||
if (ok < 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"Failed to execute SSL requirement expression in "
|
||||
"'Require ssl-require': %s",
|
||||
errstring);
|
||||
return AUTHZ_DENIED;
|
||||
}
|
||||
|
||||
if (ok != 1) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
"SSL requirement expression in 'Require ssl-require' "
|
||||
"not fulfilled");
|
||||
return AUTHZ_DENIED;
|
||||
}
|
||||
|
||||
return AUTHZ_GRANTED;
|
||||
}
|
||||
|
||||
static const char *ssl_authz_sslrequire_parse(cmd_parms *cmd,
|
||||
const char *require_line,
|
||||
const void **parsed)
|
||||
{
|
||||
const char *errstring;
|
||||
ssl_expr *expr = ssl_expr_comp(cmd->pool, require_line, &errstring);
|
||||
|
||||
if (!expr)
|
||||
return apr_psprintf(cmd->pool, "Error in 'Require require-ssl': %s",
|
||||
errstring);
|
||||
|
||||
*parsed = expr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const authz_provider ssl_authz_provider_sslrequire =
|
||||
{
|
||||
&ssl_authz_sslrequire_check,
|
||||
&ssl_authz_sslrequire_parse,
|
||||
};
|
||||
|
||||
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
|
@ -29,6 +29,7 @@
|
||||
-- Unknown */
|
||||
#include "ssl_private.h"
|
||||
#include "mod_ssl.h"
|
||||
#include "ap_expr.h"
|
||||
|
||||
#include "apr_time.h"
|
||||
|
||||
@ -62,6 +63,45 @@ static const char var_interface[] = "mod_ssl/" MOD_SSL_VERSION;
|
||||
static char var_library_interface[] = SSL_LIBRARY_TEXT;
|
||||
static char *var_library = NULL;
|
||||
|
||||
static apr_array_header_t *expr_peer_ext_list_fn(ap_expr_eval_ctx *ctx,
|
||||
const void *dummy,
|
||||
const char *arg)
|
||||
{
|
||||
return ssl_ext_list(ctx->p, ctx->c, 1, arg);
|
||||
}
|
||||
|
||||
static const char *expr_var_fn(ap_expr_eval_ctx *ctx, const void *data)
|
||||
{
|
||||
char *var = (char *)data;
|
||||
return ssl_var_lookup_ssl(ctx->p, ctx->c, var);
|
||||
}
|
||||
|
||||
static int ssl_expr_lookup(ap_expr_lookup_parms *parms)
|
||||
{
|
||||
switch (parms->type) {
|
||||
case AP_EXPR_FUNC_VAR:
|
||||
/* for now, we just handle everything that starts with SSL_, but
|
||||
* register our hook as APR_HOOK_LAST
|
||||
* XXX: This can be optimized
|
||||
*/
|
||||
if (strcEQn(parms->name, "SSL_", 4)) {
|
||||
*parms->func = expr_var_fn;
|
||||
*parms->data = parms->name + 4;
|
||||
return OK;
|
||||
}
|
||||
break;
|
||||
case AP_EXPR_FUNC_LIST:
|
||||
if (strcEQ(parms->name, "PeerExtList")) {
|
||||
*parms->func = expr_peer_ext_list_fn;
|
||||
*parms->data = "PeerExtList";
|
||||
return OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
|
||||
void ssl_var_register(apr_pool_t *p)
|
||||
{
|
||||
char *cp, *cp2;
|
||||
@ -84,6 +124,8 @@ void ssl_var_register(apr_pool_t *p)
|
||||
if ((cp2 = strchr(cp, ' ')) != NULL)
|
||||
*cp2 = NUL;
|
||||
}
|
||||
|
||||
ap_hook_expr_lookup(ssl_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
}
|
||||
|
||||
/* This function must remain safe to use for a non-SSL connection. */
|
||||
@ -984,3 +1026,4 @@ static const char *ssl_var_log_handler_x(request_rec *r, char *a)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,85 +0,0 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* _ _
|
||||
* _ __ ___ ___ __| | ___ ___| | mod_ssl
|
||||
* | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
|
||||
* | | | | | | (_) | (_| | \__ \__ \ |
|
||||
* |_| |_| |_|\___/ \__,_|___|___/___/_|
|
||||
* |_____|
|
||||
* ssl_expr.c
|
||||
* Expression Handling
|
||||
*/
|
||||
/* ``It is hard to fly with
|
||||
the eagles when you work
|
||||
with the turkeys.''
|
||||
-- Unknown */
|
||||
#include "ssl_private.h"
|
||||
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
** Expression Handling
|
||||
** _________________________________________________________________
|
||||
*/
|
||||
|
||||
|
||||
ssl_expr *ssl_expr_comp(apr_pool_t *p, const char *expr, const char **err)
|
||||
{
|
||||
ssl_expr_info_type context;
|
||||
int rc;
|
||||
|
||||
context.pool = p;
|
||||
context.inputbuf = expr;
|
||||
context.inputlen = strlen(expr);
|
||||
context.inputptr = context.inputbuf;
|
||||
context.expr = FALSE;
|
||||
context.error = NULL;
|
||||
|
||||
ssl_expr_yylex_init(&context.scanner);
|
||||
ssl_expr_yyset_extra(&context, context.scanner);
|
||||
rc = ssl_expr_yyparse(&context);
|
||||
ssl_expr_yylex_destroy(context.scanner);
|
||||
*err = context.error;
|
||||
|
||||
if (rc)
|
||||
return NULL;
|
||||
|
||||
return context.expr;
|
||||
}
|
||||
|
||||
ssl_expr *ssl_expr_make(ssl_expr_node_op op, void *a1, void *a2,
|
||||
ssl_expr_info_type *context)
|
||||
{
|
||||
ssl_expr *node;
|
||||
|
||||
node = (ssl_expr *)apr_palloc(context->pool, sizeof(ssl_expr));
|
||||
node->node_op = op;
|
||||
node->node_arg1 = (char *)a1;
|
||||
node->node_arg2 = (char *)a2;
|
||||
return node;
|
||||
}
|
||||
|
||||
int ssl_expr_exec(request_rec *r, const ssl_expr *expr, const char **err)
|
||||
{
|
||||
BOOL rc;
|
||||
|
||||
*err = NULL;
|
||||
rc = ssl_expr_eval(r, expr, err);
|
||||
if (*err != NULL)
|
||||
return (-1);
|
||||
else
|
||||
return (rc ? 1 : 0);
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @verbatim
|
||||
_ _
|
||||
_ __ ___ ___ __| | ___ ___| | mod_ssl
|
||||
| '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
|
||||
| | | | | | (_) | (_| | \__ \__ \ |
|
||||
|_| |_| |_|\___/ \__,_|___|___/___/_|
|
||||
|_____|
|
||||
@endverbatim
|
||||
* @file ssl_expr.h
|
||||
* @brief Expression Handling (Header).
|
||||
* ``May all your PUSHes be POPed.''
|
||||
*
|
||||
* @defgroup MOD_SSL_EXPR Expression Handling
|
||||
* @ingroup MOD_SSL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __SSL_EXPR_H__
|
||||
#define __SSL_EXPR_H__
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE !FALSE
|
||||
#endif
|
||||
|
||||
#ifndef YY_NULL
|
||||
#define YY_NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef BOOL
|
||||
#define BOOL unsigned int
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (void *)0
|
||||
#endif
|
||||
|
||||
#ifndef NUL
|
||||
#define NUL '\0'
|
||||
#endif
|
||||
|
||||
#ifndef YYDEBUG
|
||||
#define YYDEBUG 0
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
op_NOP, op_ListElement, op_PeerExtElement,
|
||||
op_True, op_False, op_Not, op_Or, op_And, op_Comp,
|
||||
op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN, op_REG, op_NRE,
|
||||
op_Digit, op_String, op_Regex, op_Var, op_Func
|
||||
} ssl_expr_node_op;
|
||||
|
||||
typedef struct {
|
||||
ssl_expr_node_op node_op;
|
||||
void *node_arg1;
|
||||
void *node_arg2;
|
||||
} ssl_expr_node;
|
||||
|
||||
typedef ssl_expr_node ssl_expr;
|
||||
|
||||
typedef struct {
|
||||
apr_pool_t *pool;
|
||||
const char *inputbuf;
|
||||
int inputlen;
|
||||
const char *inputptr;
|
||||
ssl_expr *expr;
|
||||
void *scanner;
|
||||
char *error;
|
||||
} ssl_expr_info_type;
|
||||
|
||||
int ssl_expr_yyparse(ssl_expr_info_type *context);
|
||||
int ssl_expr_yyerror(ssl_expr_info_type *context, char *errstring);
|
||||
int ssl_expr_yylex_init(void **scanner);
|
||||
int ssl_expr_yylex_destroy(void *scanner);
|
||||
void ssl_expr_yyset_extra(ssl_expr_info_type *context, void *scanner);
|
||||
|
||||
ssl_expr *ssl_expr_comp(apr_pool_t *p, const char *exprstr, const char **err);
|
||||
int ssl_expr_exec(request_rec *r, const ssl_expr *expr, const char **err);
|
||||
ssl_expr *ssl_expr_make(ssl_expr_node_op op, void *arg1, void *arg2,
|
||||
ssl_expr_info_type *context);
|
||||
BOOL ssl_expr_eval(request_rec *r, const ssl_expr *expr, const char **err);
|
||||
|
||||
#endif /* __SSL_EXPR_H__ */
|
||||
/** @} */
|
||||
|
@ -1,290 +0,0 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* _ _
|
||||
* _ __ ___ ___ __| | ___ ___| | mod_ssl
|
||||
* | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
|
||||
* | | | | | | (_) | (_| | \__ \__ \ |
|
||||
* |_| |_| |_|\___/ \__,_|___|___/___/_|
|
||||
* |_____|
|
||||
* ssl_expr_eval.c
|
||||
* Expression Evaluation
|
||||
*/
|
||||
/* ``Make love,
|
||||
not software!''
|
||||
-- Unknown */
|
||||
#include "ssl_private.h"
|
||||
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
** Expression Evaluation
|
||||
** _________________________________________________________________
|
||||
*/
|
||||
|
||||
static BOOL ssl_expr_eval_comp(request_rec *, ssl_expr *, const char **err);
|
||||
static char *ssl_expr_eval_word(request_rec *, ssl_expr *, const char **err);
|
||||
static BOOL ssl_expr_eval_oid(request_rec *r, const char *word,
|
||||
const char *oidstr, const char **err);
|
||||
static char *ssl_expr_eval_func_file(request_rec *, char *, const char **err);
|
||||
static int ssl_expr_eval_strcmplex(char *, char *, const char **err);
|
||||
|
||||
BOOL ssl_expr_eval(request_rec *r, const ssl_expr *node, const char **err)
|
||||
{
|
||||
switch (node->node_op) {
|
||||
case op_True: {
|
||||
return TRUE;
|
||||
}
|
||||
case op_False: {
|
||||
return FALSE;
|
||||
}
|
||||
case op_Not: {
|
||||
ssl_expr *e = (ssl_expr *)node->node_arg1;
|
||||
return (!ssl_expr_eval(r, e, err));
|
||||
}
|
||||
case op_Or: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
return (ssl_expr_eval(r, e1, err) || ssl_expr_eval(r, e2, err));
|
||||
}
|
||||
case op_And: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
return (ssl_expr_eval(r, e1, err) && ssl_expr_eval(r, e2, err));
|
||||
}
|
||||
case op_Comp: {
|
||||
ssl_expr *e = (ssl_expr *)node->node_arg1;
|
||||
return ssl_expr_eval_comp(r, e, err);
|
||||
}
|
||||
default: {
|
||||
*err = "Internal evaluation error: Unknown expression node";
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL ssl_expr_eval_comp(request_rec *r, ssl_expr *node, const char **err)
|
||||
{
|
||||
switch (node->node_op) {
|
||||
case op_EQ: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
return (strcmp(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err)) == 0);
|
||||
}
|
||||
case op_NE: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
return (strcmp(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err)) != 0);
|
||||
}
|
||||
case op_LT: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) < 0);
|
||||
}
|
||||
case op_LE: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) <= 0);
|
||||
}
|
||||
case op_GT: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) > 0);
|
||||
}
|
||||
case op_GE: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) >= 0);
|
||||
}
|
||||
case op_IN: {
|
||||
ssl_expr *e1 = (ssl_expr *)node->node_arg1;
|
||||
ssl_expr *e2 = (ssl_expr *)node->node_arg2;
|
||||
ssl_expr *e3;
|
||||
char *w1 = ssl_expr_eval_word(r, e1, err);
|
||||
BOOL found = FALSE;
|
||||
do {
|
||||
ssl_expr_node_op op = e2->node_op;
|
||||
e3 = (ssl_expr *)e2->node_arg1;
|
||||
e2 = (ssl_expr *)e2->node_arg2;
|
||||
|
||||
if (op == op_PeerExtElement) {
|
||||
char *w3 = ssl_expr_eval_word(r, e3, err);
|
||||
|
||||
found = ssl_expr_eval_oid(r, w1, w3, err);
|
||||
|
||||
/* There will be no more nodes on the list, so the result is authoritative */
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(w1, ssl_expr_eval_word(r, e3, err)) == 0) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
} while (e2 != NULL);
|
||||
return found;
|
||||
}
|
||||
case op_REG: {
|
||||
ssl_expr *e1;
|
||||
ssl_expr *e2;
|
||||
char *word;
|
||||
ap_regex_t *regex;
|
||||
|
||||
e1 = (ssl_expr *)node->node_arg1;
|
||||
e2 = (ssl_expr *)node->node_arg2;
|
||||
word = ssl_expr_eval_word(r, e1, err);
|
||||
regex = (ap_regex_t *)(e2->node_arg1);
|
||||
return (ap_regexec(regex, word, 0, NULL, 0) == 0);
|
||||
}
|
||||
case op_NRE: {
|
||||
ssl_expr *e1;
|
||||
ssl_expr *e2;
|
||||
char *word;
|
||||
ap_regex_t *regex;
|
||||
|
||||
e1 = (ssl_expr *)node->node_arg1;
|
||||
e2 = (ssl_expr *)node->node_arg2;
|
||||
word = ssl_expr_eval_word(r, e1, err);
|
||||
regex = (ap_regex_t *)(e2->node_arg1);
|
||||
return !(ap_regexec(regex, word, 0, NULL, 0) == 0);
|
||||
}
|
||||
default: {
|
||||
*err = "Internal evaluation error: Unknown expression node";
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *ssl_expr_eval_word(request_rec *r, ssl_expr *node, const char **err)
|
||||
{
|
||||
switch (node->node_op) {
|
||||
case op_Digit: {
|
||||
char *string = (char *)node->node_arg1;
|
||||
return string;
|
||||
}
|
||||
case op_String: {
|
||||
char *string = (char *)node->node_arg1;
|
||||
return string;
|
||||
}
|
||||
case op_Var: {
|
||||
char *var = (char *)node->node_arg1;
|
||||
char *val = ssl_var_lookup(r->pool, r->server, r->connection, r, var);
|
||||
return (val == NULL ? "" : val);
|
||||
}
|
||||
case op_Func: {
|
||||
char *name = (char *)node->node_arg1;
|
||||
ssl_expr *args = (ssl_expr *)node->node_arg2;
|
||||
if (strEQ(name, "file"))
|
||||
return ssl_expr_eval_func_file(r, (char *)(args->node_arg1), err);
|
||||
else {
|
||||
*err = "Internal evaluation error: Unknown function name";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
default: {
|
||||
*err = "Internal evaluation error: Unknown expression node";
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL ssl_expr_eval_oid(request_rec *r, const char *word,
|
||||
const char *oidstr, const char **err)
|
||||
{
|
||||
int j;
|
||||
BOOL result = FALSE;
|
||||
apr_array_header_t *oid_array;
|
||||
char **oid_value;
|
||||
|
||||
if (NULL == (oid_array = ssl_ext_list(r->pool, r->connection, 1, oidstr))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
oid_value = (char **) oid_array->elts;
|
||||
for (j = 0; j < oid_array->nelts; j++) {
|
||||
if (strcmp(word, oid_value[j]) == 0) {
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static char *ssl_expr_eval_func_file(request_rec *r, char *filename, const char **err)
|
||||
{
|
||||
apr_file_t *fp;
|
||||
char *buf;
|
||||
apr_off_t offset;
|
||||
apr_size_t len;
|
||||
apr_finfo_t finfo;
|
||||
|
||||
if (apr_file_open(&fp, filename, APR_READ|APR_BUFFERED,
|
||||
APR_OS_DEFAULT, r->pool) != APR_SUCCESS) {
|
||||
*err = "Cannot open file";
|
||||
return "";
|
||||
}
|
||||
apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
|
||||
if ((finfo.size + 1) != ((apr_size_t)finfo.size + 1)) {
|
||||
*err = "Huge file cannot be read";
|
||||
apr_file_close(fp);
|
||||
return "";
|
||||
}
|
||||
len = (apr_size_t)finfo.size;
|
||||
if (len == 0) {
|
||||
buf = (char *)apr_palloc(r->pool, sizeof(char) * 1);
|
||||
*buf = NUL;
|
||||
}
|
||||
else {
|
||||
if ((buf = (char *)apr_palloc(r->pool, sizeof(char)*(len+1))) == NULL) {
|
||||
*err = "Cannot allocate memory";
|
||||
apr_file_close(fp);
|
||||
return "";
|
||||
}
|
||||
offset = 0;
|
||||
apr_file_seek(fp, APR_SET, &offset);
|
||||
if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
|
||||
*err = "Cannot read from file";
|
||||
apr_file_close(fp);
|
||||
return "";
|
||||
}
|
||||
buf[len] = NUL;
|
||||
}
|
||||
apr_file_close(fp);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* a variant of strcmp(3) which works correctly also for number strings */
|
||||
static int ssl_expr_eval_strcmplex(char *cpNum1, char *cpNum2, const char **err)
|
||||
{
|
||||
int i, n1, n2;
|
||||
|
||||
if (cpNum1 == NULL)
|
||||
return -1;
|
||||
if (cpNum2 == NULL)
|
||||
return +1;
|
||||
n1 = strlen(cpNum1);
|
||||
n2 = strlen(cpNum2);
|
||||
if (n1 > n2)
|
||||
return 1;
|
||||
if (n1 < n2)
|
||||
return -1;
|
||||
for (i = 0; i < n1; i++) {
|
||||
if (cpNum1[i] > cpNum2[i])
|
||||
return 1;
|
||||
if (cpNum1[i] < cpNum2[i])
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* _ _
|
||||
* _ __ ___ ___ __| | ___ ___| |
|
||||
* | '_ ` _ \ / _ \ / _` | / __/ __| |
|
||||
* | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL
|
||||
* |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/
|
||||
* |_____|
|
||||
* ssl_expr_parse.y
|
||||
* Expression LR(1) Parser
|
||||
*/
|
||||
/* ``What you see is all you get.''
|
||||
-- Brian Kernighan */
|
||||
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
** Expression Parser
|
||||
** _________________________________________________________________
|
||||
*/
|
||||
|
||||
%pure-parser
|
||||
%defines
|
||||
%error-verbose
|
||||
%lex-param { void *yyscanner }
|
||||
%parse-param { ssl_expr_info_type *context }
|
||||
|
||||
%{
|
||||
#include "ssl_private.h"
|
||||
%}
|
||||
|
||||
%union {
|
||||
char *cpVal;
|
||||
ssl_expr *exVal;
|
||||
}
|
||||
|
||||
%token T_TRUE
|
||||
%token T_FALSE
|
||||
|
||||
%token <cpVal> T_DIGIT
|
||||
%token <cpVal> T_ID
|
||||
%token <cpVal> T_STRING
|
||||
%token <cpVal> T_REGEX
|
||||
%token <cpVal> T_REGEX_I
|
||||
|
||||
%token T_FUNC_FILE
|
||||
|
||||
%token T_OP_EQ
|
||||
%token T_OP_NE
|
||||
%token T_OP_LT
|
||||
%token T_OP_LE
|
||||
%token T_OP_GT
|
||||
%token T_OP_GE
|
||||
%token T_OP_REG
|
||||
%token T_OP_NRE
|
||||
%token T_OP_IN
|
||||
%token T_OP_PEEREXTLIST
|
||||
|
||||
%token T_OP_OR
|
||||
%token T_OP_AND
|
||||
%token T_OP_NOT
|
||||
|
||||
%left T_OP_OR
|
||||
%left T_OP_AND
|
||||
%left T_OP_NOT
|
||||
|
||||
%type <exVal> expr
|
||||
%type <exVal> comparison
|
||||
%type <exVal> funccall
|
||||
%type <exVal> regex
|
||||
%type <exVal> words
|
||||
%type <exVal> wordlist
|
||||
%type <exVal> word
|
||||
|
||||
%{
|
||||
#include "ssl_expr.h"
|
||||
#define yyscanner context->scanner
|
||||
|
||||
int ssl_expr_yyerror(ssl_expr_info_type *context, char *err);
|
||||
int ssl_expr_yylex(YYSTYPE *lvalp, void *scanner);
|
||||
%}
|
||||
|
||||
|
||||
%%
|
||||
|
||||
root : expr { context->expr = $1; }
|
||||
;
|
||||
|
||||
expr : T_TRUE { $$ = ssl_expr_make(op_True, NULL, NULL, context); }
|
||||
| T_FALSE { $$ = ssl_expr_make(op_False, NULL, NULL, context); }
|
||||
| T_OP_NOT expr { $$ = ssl_expr_make(op_Not, $2, NULL, context); }
|
||||
| expr T_OP_OR expr { $$ = ssl_expr_make(op_Or, $1, $3, context); }
|
||||
| expr T_OP_AND expr { $$ = ssl_expr_make(op_And, $1, $3, context); }
|
||||
| comparison { $$ = ssl_expr_make(op_Comp, $1, NULL, context); }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
comparison: word T_OP_EQ word { $$ = ssl_expr_make(op_EQ, $1, $3, context); }
|
||||
| word T_OP_NE word { $$ = ssl_expr_make(op_NE, $1, $3, context); }
|
||||
| word T_OP_LT word { $$ = ssl_expr_make(op_LT, $1, $3, context); }
|
||||
| word T_OP_LE word { $$ = ssl_expr_make(op_LE, $1, $3, context); }
|
||||
| word T_OP_GT word { $$ = ssl_expr_make(op_GT, $1, $3, context); }
|
||||
| word T_OP_GE word { $$ = ssl_expr_make(op_GE, $1, $3, context); }
|
||||
| word T_OP_IN wordlist { $$ = ssl_expr_make(op_IN, $1, $3, context); }
|
||||
| word T_OP_REG regex { $$ = ssl_expr_make(op_REG, $1, $3, context); }
|
||||
| word T_OP_NRE regex { $$ = ssl_expr_make(op_NRE, $1, $3, context); }
|
||||
;
|
||||
|
||||
wordlist : T_OP_PEEREXTLIST '(' word ')' { $$ = ssl_expr_make(op_PeerExtElement, $3, NULL, context); }
|
||||
| '{' words '}' { $$ = $2 ; }
|
||||
;
|
||||
|
||||
words : word { $$ = ssl_expr_make(op_ListElement, $1, NULL, context); }
|
||||
| words ',' word { $$ = ssl_expr_make(op_ListElement, $3, $1, context); }
|
||||
;
|
||||
|
||||
word : T_DIGIT { $$ = ssl_expr_make(op_Digit, $1, NULL, context); }
|
||||
| T_STRING { $$ = ssl_expr_make(op_String, $1, NULL, context); }
|
||||
| '%' '{' T_ID '}' { $$ = ssl_expr_make(op_Var, $3, NULL, context); }
|
||||
| funccall { $$ = $1; }
|
||||
;
|
||||
|
||||
regex : T_REGEX {
|
||||
ap_regex_t *regex;
|
||||
if ((regex = ap_pregcomp(context->pool, $1,
|
||||
AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) {
|
||||
context->error = "Failed to compile regular expression";
|
||||
YYERROR;
|
||||
}
|
||||
$$ = ssl_expr_make(op_Regex, regex, NULL, context);
|
||||
}
|
||||
| T_REGEX_I {
|
||||
ap_regex_t *regex;
|
||||
if ((regex = ap_pregcomp(context->pool, $1,
|
||||
AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) {
|
||||
context->error = "Failed to compile regular expression";
|
||||
YYERROR;
|
||||
}
|
||||
$$ = ssl_expr_make(op_Regex, regex, NULL, context);
|
||||
}
|
||||
;
|
||||
|
||||
funccall : T_FUNC_FILE '(' T_STRING ')' {
|
||||
ssl_expr *args = ssl_expr_make(op_ListElement, $3, NULL, context);
|
||||
$$ = ssl_expr_make(op_Func, "file", args, context);
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
int yyerror(ssl_expr_info_type *context, char *s)
|
||||
{
|
||||
context->error = s;
|
||||
return 2;
|
||||
}
|
||||
|
@ -1,230 +0,0 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* _ _
|
||||
* _ __ ___ ___ __| | ___ ___| |
|
||||
* | '_ ` _ \ / _ \ / _` | / __/ __| |
|
||||
* | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL
|
||||
* |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/
|
||||
* |_____|
|
||||
* ssl_expr_scan.l
|
||||
* Expression Scanner
|
||||
*/
|
||||
/* ``Killing for peace is
|
||||
like fucking for virginity.''
|
||||
-- Unknown */
|
||||
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
** Expression Scanner
|
||||
** _________________________________________________________________
|
||||
*/
|
||||
|
||||
%pointer
|
||||
%option batch
|
||||
%option never-interactive
|
||||
%option nodefault
|
||||
%option noyywrap
|
||||
%option reentrant
|
||||
%option bison-bridge
|
||||
%option warn
|
||||
%option noinput nounput
|
||||
%x str
|
||||
%x regex regex_flags
|
||||
|
||||
%{
|
||||
#include "ssl_private.h"
|
||||
|
||||
#include "ssl_expr_parse.h"
|
||||
#include "ssl_expr.h"
|
||||
|
||||
#undef YY_INPUT
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
{ \
|
||||
if ((result = MIN(max_size, yyextra->inputbuf \
|
||||
+ yyextra->inputlen \
|
||||
- yyextra->inputptr)) <= 0) \
|
||||
{ \
|
||||
result = YY_NULL; \
|
||||
} \
|
||||
else { \
|
||||
memcpy(buf, yyextra->inputptr, result); \
|
||||
yyextra->inputptr += result; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAX_STR_LEN 2048
|
||||
#define YY_EXTRA_TYPE ssl_expr_info_type*
|
||||
%}
|
||||
|
||||
|
||||
%%
|
||||
|
||||
char caStr[MAX_STR_LEN];
|
||||
char *cpStr = NULL;
|
||||
char caRegex[MAX_STR_LEN];
|
||||
char *cpRegex = NULL;
|
||||
char cRegexDel = NUL;
|
||||
|
||||
/*
|
||||
* Whitespaces
|
||||
*/
|
||||
[ \t\n]+ {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
/*
|
||||
* C-style strings ("...")
|
||||
*/
|
||||
\" {
|
||||
cpStr = caStr;
|
||||
BEGIN(str);
|
||||
}
|
||||
<str>\" {
|
||||
BEGIN(INITIAL);
|
||||
*cpStr = NUL;
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, caStr);
|
||||
return T_STRING;
|
||||
}
|
||||
<str>\n {
|
||||
ssl_expr_yyerror(yyextra, "Unterminated string");
|
||||
}
|
||||
<str>\\[0-7]{1,3} {
|
||||
int result;
|
||||
|
||||
(void)sscanf(yytext+1, "%o", &result);
|
||||
if (result > 0xff)
|
||||
ssl_expr_yyerror(yyextra, "Escape sequence out of bound");
|
||||
else
|
||||
*cpStr++ = result;
|
||||
}
|
||||
<str>\\[0-9]+ {
|
||||
ssl_expr_yyerror(yyextra, "Bad escape sequence");
|
||||
}
|
||||
<str>\\n { *cpStr++ = '\n'; }
|
||||
<str>\\r { *cpStr++ = '\r'; }
|
||||
<str>\\t { *cpStr++ = '\t'; }
|
||||
<str>\\b { *cpStr++ = '\b'; }
|
||||
<str>\\f { *cpStr++ = '\f'; }
|
||||
<str>\\(.|\n) {
|
||||
*cpStr++ = yytext[1];
|
||||
}
|
||||
<str>[^\\\n\"]+ {
|
||||
char *cp = yytext;
|
||||
while (*cp != NUL)
|
||||
*cpStr++ = *cp++;
|
||||
}
|
||||
<str>. {
|
||||
*cpStr++ = yytext[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Regular Expression
|
||||
*/
|
||||
"m". {
|
||||
cRegexDel = yytext[1];
|
||||
cpRegex = caRegex;
|
||||
BEGIN(regex);
|
||||
}
|
||||
<regex>.|\n {
|
||||
if (yytext[0] == cRegexDel) {
|
||||
*cpRegex = NUL;
|
||||
BEGIN(regex_flags);
|
||||
}
|
||||
else {
|
||||
*cpRegex++ = yytext[0];
|
||||
}
|
||||
}
|
||||
<regex_flags>i {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
|
||||
BEGIN(INITIAL);
|
||||
return T_REGEX_I;
|
||||
}
|
||||
<regex_flags>.|\n {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
|
||||
yyless(0);
|
||||
BEGIN(INITIAL);
|
||||
return T_REGEX;
|
||||
}
|
||||
<regex_flags><<EOF>> {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
|
||||
BEGIN(INITIAL);
|
||||
return T_REGEX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Operators
|
||||
*/
|
||||
"eq" { return T_OP_EQ; }
|
||||
"==" { return T_OP_EQ; }
|
||||
"ne" { return T_OP_NE; }
|
||||
"!=" { return T_OP_NE; }
|
||||
"lt" { return T_OP_LT; }
|
||||
"<" { return T_OP_LT; }
|
||||
"le" { return T_OP_LE; }
|
||||
"<=" { return T_OP_LE; }
|
||||
"gt" { return T_OP_GT; }
|
||||
">" { return T_OP_GT; }
|
||||
"ge" { return T_OP_GE; }
|
||||
">=" { return T_OP_GE; }
|
||||
"=~" { return T_OP_REG; }
|
||||
"!~" { return T_OP_NRE; }
|
||||
"and" { return T_OP_AND; }
|
||||
"&&" { return T_OP_AND; }
|
||||
"or" { return T_OP_OR; }
|
||||
"||" { return T_OP_OR; }
|
||||
"not" { return T_OP_NOT; }
|
||||
"!" { return T_OP_NOT; }
|
||||
"in" { return T_OP_IN; }
|
||||
[Pp][Ee][Ee][Rr][Ee][Xx][Tt][Ll][Ii][Ss][Tt] { return T_OP_PEEREXTLIST; }
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
"file" { return T_FUNC_FILE; }
|
||||
|
||||
/*
|
||||
* Specials
|
||||
*/
|
||||
"true" { return T_TRUE; }
|
||||
"false" { return T_FALSE; }
|
||||
|
||||
/*
|
||||
* Digits
|
||||
*/
|
||||
[0-9]+ {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
|
||||
return T_DIGIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identifiers
|
||||
*/
|
||||
[a-zA-Z][a-zA-Z0-9_:-]* {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
|
||||
return T_ID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Anything else is returned as is...
|
||||
*/
|
||||
.|\n {
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
|
@ -55,9 +55,38 @@
|
||||
|
||||
#define MOD_SSL_VERSION AP_SERVER_BASEREVISION
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE !FALSE
|
||||
#endif
|
||||
|
||||
#ifndef YY_NULL
|
||||
#define YY_NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef BOOL
|
||||
#define BOOL unsigned int
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (void *)0
|
||||
#endif
|
||||
|
||||
#ifndef NUL
|
||||
#define NUL '\0'
|
||||
#endif
|
||||
|
||||
|
||||
/* mod_ssl headers */
|
||||
#include "ssl_toolkit_compat.h"
|
||||
#include "ssl_expr.h"
|
||||
#include "ap_expr.h"
|
||||
#include "ssl_util_ssl.h"
|
||||
|
||||
/* The #ifdef macros are only defined AFTER including the above
|
||||
@ -273,7 +302,7 @@ typedef enum {
|
||||
*/
|
||||
typedef struct {
|
||||
char *cpExpr;
|
||||
ssl_expr *mpExpr;
|
||||
ap_expr_info_t *mpExpr;
|
||||
} ssl_require_t;
|
||||
|
||||
/**
|
||||
@ -617,7 +646,6 @@ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s);
|
||||
/** Apache authz provisders */
|
||||
extern const authz_provider ssl_authz_provider_require_ssl;
|
||||
extern const authz_provider ssl_authz_provider_verify_client;
|
||||
extern const authz_provider ssl_authz_provider_sslrequire;
|
||||
|
||||
/** OpenSSL callbacks */
|
||||
RSA *ssl_callback_TmpRSA(SSL *, int, int);
|
||||
|
@ -12,9 +12,10 @@ LTLIBRARY_SOURCES = \
|
||||
util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c \
|
||||
connection.c listen.c util_mutex.c mpm_common.c mpm_unix.c \
|
||||
util_charset.c util_cookies.c util_debug.c util_xml.c \
|
||||
util_expr.c util_filter.c util_pcre.c util_regex.c exports.c \
|
||||
util_filter.c util_pcre.c util_regex.c exports.c \
|
||||
scoreboard.c error_bucket.c protocol.c core.c request.c provider.c \
|
||||
eoc_bucket.c eor_bucket.c core_filters.c
|
||||
eoc_bucket.c eor_bucket.c core_filters.c \
|
||||
util_expr_parse.c util_expr_scan.c util_expr_eval.c
|
||||
|
||||
TARGETS = delete-exports $(LTLIBRARY_NAME) $(CORE_IMPLIB_FILE) export_vars.h httpd.exp
|
||||
|
||||
@ -83,3 +84,19 @@ httpd.exp: exports.c export_vars.h
|
||||
@echo "* Please do not edit by hand." >> $@
|
||||
$(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) exports.c | grep "ap_hack_" | grep -v apr_ | sed -e 's/^.*[)]\(.*\);$$/\1/' >> $@
|
||||
$(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) export_vars.h | grep -v apr_ | sed -e 's/^\#[^!]*//' | sed -e '/^$$/d' >> $@
|
||||
|
||||
|
||||
# developer stuff
|
||||
# (we really don't expect end users to use these targets!)
|
||||
#
|
||||
util_expr_scan.c util_expr_parse.c util_expr_parse.h: util_expr_scan.l util_expr_parse.y
|
||||
bison -pap_expr_yy --defines=$(builddir)/util_expr_parse.h \
|
||||
-o $(builddir)/util_expr_parse.c $(srcdir)/util_expr_parse.y
|
||||
flex -Pap_expr_yy -o $(builddir)/util_expr_scan.c $(srcdir)/util_expr_scan.l
|
||||
set -e ; \
|
||||
for f in util_expr_scan.c util_expr_parse.c util_expr_parse.h ; do \
|
||||
sed -e "s|\"$(builddir)/|\"|g" < $(builddir)/$$f > \
|
||||
$(builddir)/$$f.$$$$ && \
|
||||
mv $(builddir)/$$f.$$$$ $(builddir)/$$f ; \
|
||||
done
|
||||
|
||||
|
@ -1986,7 +1986,7 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
|
||||
const char *err = ap_check_cmd_context(cmd,
|
||||
NOT_IN_LOCATION | NOT_IN_LIMIT);
|
||||
const char *condition;
|
||||
int expr_err = 0;
|
||||
const char *expr_err;
|
||||
|
||||
if (err != NULL) {
|
||||
return err;
|
||||
@ -2012,9 +2012,9 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
|
||||
conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
|
||||
&core_module, cmd->pool);
|
||||
|
||||
conf->condition = ap_expr_parse(cmd->pool, condition, &expr_err);
|
||||
conf->condition = ap_expr_parse_cmd(cmd, condition, &expr_err, NULL);
|
||||
if (expr_err) {
|
||||
return "Cannot parse condition clause";
|
||||
return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s", expr_err);
|
||||
}
|
||||
|
||||
errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
|
||||
@ -4133,6 +4133,7 @@ static void register_hooks(apr_pool_t *p)
|
||||
{
|
||||
errorlog_hash = apr_hash_make(p);
|
||||
ap_register_log_hooks(p);
|
||||
ap_expr_init(p);
|
||||
|
||||
/* create_connection and pre_connection should always be hooked
|
||||
* APR_HOOK_REALLY_LAST by core to give other modules the opportunity
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include "apr_uri.h"
|
||||
#include "util_ebcdic.h"
|
||||
#include "ap_mpm.h"
|
||||
#include "ap_expr.h"
|
||||
|
||||
#if APR_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
@ -472,9 +471,6 @@ int main(int argc, const char * const argv[])
|
||||
destroy_and_exit_process(process, 1);
|
||||
}
|
||||
#endif
|
||||
if (ap_expr_init(ap_pglobal) != APR_SUCCESS) {
|
||||
destroy_and_exit_process(process, 1);
|
||||
}
|
||||
|
||||
apr_pool_create(&pcommands, ap_pglobal);
|
||||
apr_pool_tag(pcommands, "pcommands");
|
||||
|
@ -1529,13 +1529,13 @@ AP_DECLARE(int) ap_file_walk(request_rec *r)
|
||||
* really try them with the most general first.
|
||||
*/
|
||||
for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
|
||||
int err = 0;
|
||||
const char *err = NULL;
|
||||
core_dir_config *entry_core;
|
||||
entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module);
|
||||
|
||||
if (entry_core->condition) {
|
||||
if (!ap_expr_eval(r, entry_core->condition, &err, NULL,
|
||||
ap_expr_string, NULL)) {
|
||||
/* XXX: error handling */
|
||||
if (!ap_expr_exec(r, entry_core->condition, &err)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
1282
server/util_expr.c
1282
server/util_expr.c
File diff suppressed because it is too large
Load Diff
1024
server/util_expr_eval.c
Normal file
1024
server/util_expr_eval.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -41,25 +41,37 @@
|
||||
enum yytokentype {
|
||||
T_TRUE = 258,
|
||||
T_FALSE = 259,
|
||||
T_DIGIT = 260,
|
||||
T_ID = 261,
|
||||
T_STRING = 262,
|
||||
T_REGEX = 263,
|
||||
T_REGEX_I = 264,
|
||||
T_FUNC_FILE = 265,
|
||||
T_OP_EQ = 266,
|
||||
T_OP_NE = 267,
|
||||
T_OP_LT = 268,
|
||||
T_OP_LE = 269,
|
||||
T_OP_GT = 270,
|
||||
T_OP_GE = 271,
|
||||
T_OP_REG = 272,
|
||||
T_OP_NRE = 273,
|
||||
T_OP_IN = 274,
|
||||
T_OP_PEEREXTLIST = 275,
|
||||
T_OP_OR = 276,
|
||||
T_OP_AND = 277,
|
||||
T_OP_NOT = 278
|
||||
ERROR = 260,
|
||||
T_DIGIT = 261,
|
||||
T_ID = 262,
|
||||
T_STRING = 263,
|
||||
T_REGEX = 264,
|
||||
T_REGEX_I = 265,
|
||||
T_OP_UNARY = 266,
|
||||
T_OP_BINARY = 267,
|
||||
T_STR_BEGIN = 268,
|
||||
T_STR_END = 269,
|
||||
T_VAR_BEGIN = 270,
|
||||
T_VAR_END = 271,
|
||||
T_OP_EQ = 272,
|
||||
T_OP_NE = 273,
|
||||
T_OP_LT = 274,
|
||||
T_OP_LE = 275,
|
||||
T_OP_GT = 276,
|
||||
T_OP_GE = 277,
|
||||
T_OP_REG = 278,
|
||||
T_OP_NRE = 279,
|
||||
T_OP_IN = 280,
|
||||
T_OP_STR_EQ = 281,
|
||||
T_OP_STR_NE = 282,
|
||||
T_OP_STR_LT = 283,
|
||||
T_OP_STR_LE = 284,
|
||||
T_OP_STR_GT = 285,
|
||||
T_OP_STR_GE = 286,
|
||||
T_OP_CONCAT = 287,
|
||||
T_OP_OR = 288,
|
||||
T_OP_AND = 289,
|
||||
T_OP_NOT = 290
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -70,15 +82,15 @@ typedef union YYSTYPE
|
||||
{
|
||||
|
||||
/* Line 1676 of yacc.c */
|
||||
#line 45 "ssl_expr_parse.y"
|
||||
#line 35 "util_expr_parse.y"
|
||||
|
||||
char *cpVal;
|
||||
ssl_expr *exVal;
|
||||
ap_expr *exVal;
|
||||
|
||||
|
||||
|
||||
/* Line 1676 of yacc.c */
|
||||
#line 82 "ssl_expr_parse.h"
|
||||
#line 94 "util_expr_parse.h"
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
199
server/util_expr_parse.y
Normal file
199
server/util_expr_parse.y
Normal file
@ -0,0 +1,199 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* based on ap_expr_parse.y from mod_ssl */
|
||||
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
** Expression Parser
|
||||
** _________________________________________________________________
|
||||
*/
|
||||
|
||||
%pure-parser
|
||||
%error-verbose
|
||||
%defines
|
||||
%lex-param { void *yyscanner }
|
||||
%parse-param { ap_expr_parse_ctx *ctx }
|
||||
|
||||
%{
|
||||
#include "util_expr_private.h"
|
||||
%}
|
||||
|
||||
%union {
|
||||
char *cpVal;
|
||||
ap_expr *exVal;
|
||||
}
|
||||
|
||||
%token T_TRUE
|
||||
%token T_FALSE
|
||||
|
||||
%token <cpVal> ERROR
|
||||
|
||||
%token <cpVal> T_DIGIT
|
||||
%token <cpVal> T_ID
|
||||
%token <cpVal> T_STRING
|
||||
%token <cpVal> T_REGEX
|
||||
%token <cpVal> T_REGEX_I
|
||||
%token <cpVal> T_OP_UNARY
|
||||
%token <cpVal> T_OP_BINARY
|
||||
|
||||
%token T_STR_BEGIN
|
||||
%token T_STR_END
|
||||
%token T_VAR_BEGIN
|
||||
%token T_VAR_END
|
||||
|
||||
%token T_OP_EQ
|
||||
%token T_OP_NE
|
||||
%token T_OP_LT
|
||||
%token T_OP_LE
|
||||
%token T_OP_GT
|
||||
%token T_OP_GE
|
||||
%token T_OP_REG
|
||||
%token T_OP_NRE
|
||||
%token T_OP_IN
|
||||
%token T_OP_STR_EQ
|
||||
%token T_OP_STR_NE
|
||||
%token T_OP_STR_LT
|
||||
%token T_OP_STR_LE
|
||||
%token T_OP_STR_GT
|
||||
%token T_OP_STR_GE
|
||||
%token T_OP_CONCAT
|
||||
|
||||
%token T_OP_OR
|
||||
%token T_OP_AND
|
||||
%token T_OP_NOT
|
||||
|
||||
%left T_OP_OR
|
||||
%left T_OP_AND
|
||||
%left T_OP_NOT
|
||||
%left T_OP_CONCAT
|
||||
|
||||
%type <exVal> expr
|
||||
%type <exVal> comparison
|
||||
%type <exVal> strfunccall
|
||||
%type <exVal> lstfunccall
|
||||
%type <exVal> regex
|
||||
%type <exVal> words
|
||||
%type <exVal> wordlist
|
||||
%type <exVal> word
|
||||
%type <exVal> string
|
||||
%type <exVal> strpart
|
||||
%type <exVal> var
|
||||
|
||||
%{
|
||||
#include "util_expr_private.h"
|
||||
#define yyscanner ctx->scanner
|
||||
|
||||
int ap_expr_yylex(YYSTYPE *lvalp, void *scanner);
|
||||
%}
|
||||
|
||||
|
||||
%%
|
||||
|
||||
root : expr { ctx->expr = $1; }
|
||||
| ERROR { YYABORT; }
|
||||
;
|
||||
|
||||
expr : T_TRUE { $$ = ap_expr_make(op_True, NULL, NULL, ctx); }
|
||||
| T_FALSE { $$ = ap_expr_make(op_False, NULL, NULL, ctx); }
|
||||
| T_OP_NOT expr { $$ = ap_expr_make(op_Not, $2, NULL, ctx); }
|
||||
| expr T_OP_OR expr { $$ = ap_expr_make(op_Or, $1, $3, ctx); }
|
||||
| expr T_OP_AND expr { $$ = ap_expr_make(op_And, $1, $3, ctx); }
|
||||
| comparison { $$ = ap_expr_make(op_Comp, $1, NULL, ctx); }
|
||||
| T_OP_UNARY word { $$ = ap_expr_unary_op_make( $1, $2, ctx); }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
comparison: word T_OP_EQ word { $$ = ap_expr_make(op_EQ, $1, $3, ctx); }
|
||||
| word T_OP_NE word { $$ = ap_expr_make(op_NE, $1, $3, ctx); }
|
||||
| word T_OP_LT word { $$ = ap_expr_make(op_LT, $1, $3, ctx); }
|
||||
| word T_OP_LE word { $$ = ap_expr_make(op_LE, $1, $3, ctx); }
|
||||
| word T_OP_GT word { $$ = ap_expr_make(op_GT, $1, $3, ctx); }
|
||||
| word T_OP_GE word { $$ = ap_expr_make(op_GE, $1, $3, ctx); }
|
||||
| word T_OP_STR_EQ word { $$ = ap_expr_make(op_STR_EQ, $1, $3, ctx); }
|
||||
| word T_OP_STR_NE word { $$ = ap_expr_make(op_STR_NE, $1, $3, ctx); }
|
||||
| word T_OP_STR_LT word { $$ = ap_expr_make(op_STR_LT, $1, $3, ctx); }
|
||||
| word T_OP_STR_LE word { $$ = ap_expr_make(op_STR_LE, $1, $3, ctx); }
|
||||
| word T_OP_STR_GT word { $$ = ap_expr_make(op_STR_GT, $1, $3, ctx); }
|
||||
| word T_OP_STR_GE word { $$ = ap_expr_make(op_STR_GE, $1, $3, ctx); }
|
||||
| word T_OP_IN wordlist { $$ = ap_expr_make(op_IN, $1, $3, ctx); }
|
||||
| word T_OP_REG regex { $$ = ap_expr_make(op_REG, $1, $3, ctx); }
|
||||
| word T_OP_NRE regex { $$ = ap_expr_make(op_NRE, $1, $3, ctx); }
|
||||
| word T_OP_BINARY word { $$ = ap_expr_binary_op_make($2, $1, $3, ctx); }
|
||||
;
|
||||
|
||||
wordlist : lstfunccall { $$ = $1; }
|
||||
| '{' words '}' { $$ = $2; }
|
||||
;
|
||||
|
||||
words : word { $$ = ap_expr_make(op_ListElement, $1, NULL, ctx); }
|
||||
| words ',' word { $$ = ap_expr_make(op_ListElement, $3, $1, ctx); }
|
||||
;
|
||||
|
||||
string : string strpart { $$ = ap_expr_make(op_Concat, $1, $2, ctx); }
|
||||
| strpart { $$ = $1; }
|
||||
;
|
||||
|
||||
|
||||
strpart : T_STRING { $$ = ap_expr_make(op_String, $1, NULL, ctx); }
|
||||
| var { $$ = $1; }
|
||||
;
|
||||
|
||||
var : T_VAR_BEGIN T_ID T_VAR_END { $$ = ap_expr_var_make($2, ctx); }
|
||||
| T_VAR_BEGIN T_ID ':' string T_VAR_END { $$ = ap_expr_str_func_make($2, $4, ctx); }
|
||||
;
|
||||
|
||||
word : T_DIGIT { $$ = ap_expr_make(op_Digit, $1, NULL, ctx); }
|
||||
| word T_OP_CONCAT word { $$ = ap_expr_make(op_Concat, $1, $3, ctx); }
|
||||
| var { $$ = $1; }
|
||||
| strfunccall { $$ = $1; }
|
||||
| T_STR_BEGIN string T_STR_END { $$ = $2; }
|
||||
| T_STR_BEGIN T_STR_END { $$ = ap_expr_make(op_String, "", NULL, ctx); }
|
||||
;
|
||||
|
||||
regex : T_REGEX {
|
||||
ap_regex_t *regex;
|
||||
if ((regex = ap_pregcomp(ctx->pool, $1,
|
||||
AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) {
|
||||
ctx->error = "Failed to compile regular expression";
|
||||
YYERROR;
|
||||
}
|
||||
$$ = ap_expr_make(op_Regex, regex, NULL, ctx);
|
||||
}
|
||||
| T_REGEX_I {
|
||||
ap_regex_t *regex;
|
||||
if ((regex = ap_pregcomp(ctx->pool, $1,
|
||||
AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) {
|
||||
ctx->error = "Failed to compile regular expression";
|
||||
YYERROR;
|
||||
}
|
||||
$$ = ap_expr_make(op_Regex, regex, NULL, ctx);
|
||||
}
|
||||
;
|
||||
|
||||
lstfunccall : T_ID '(' word ')' { $$ = ap_expr_list_func_make($1, $3, ctx); }
|
||||
;
|
||||
|
||||
strfunccall : T_ID '(' word ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void yyerror(ap_expr_parse_ctx *ctx, char *s)
|
||||
{
|
||||
ctx->error = s;
|
||||
}
|
||||
|
129
server/util_expr_private.h
Normal file
129
server/util_expr_private.h
Normal file
@ -0,0 +1,129 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __AP_EXPR_PRIVATE_H__
|
||||
#define __AP_EXPR_PRIVATE_H__
|
||||
|
||||
#include "httpd.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_tables.h"
|
||||
#include "ap_expr.h"
|
||||
|
||||
#ifndef YY_NULL
|
||||
#define YY_NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef YYDEBUG
|
||||
#define YYDEBUG 0
|
||||
#endif
|
||||
|
||||
/** The operations in a parse tree node */
|
||||
typedef enum {
|
||||
op_NOP,
|
||||
op_True, op_False,
|
||||
op_Not, op_Or, op_And,
|
||||
op_Comp,
|
||||
op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN,
|
||||
op_REG, op_NRE,
|
||||
op_STR_EQ, op_STR_NE, op_STR_LT, op_STR_LE, op_STR_GT, op_STR_GE,
|
||||
op_Concat,
|
||||
op_Digit, op_String, op_Regex,
|
||||
op_Var,
|
||||
op_ListElement,
|
||||
/*
|
||||
* call external functions/operators.
|
||||
* The info node contains the function pointer and some function specific
|
||||
* info.
|
||||
* For Binary operators, the Call node links to the Info node and the
|
||||
* Args node, which in turn links to the left and right operand.
|
||||
* For all other variants, the Call node links to the Info node and the
|
||||
* argument.
|
||||
*/
|
||||
op_UnaryOpCall, op_UnaryOpInfo,
|
||||
op_BinaryOpCall, op_BinaryOpInfo, op_BinaryOpArgs,
|
||||
op_StringFuncCall, op_StringFuncInfo,
|
||||
op_ListFuncCall, op_ListFuncInfo
|
||||
} ap_expr_node_op;
|
||||
|
||||
/** The basic parse tree node */
|
||||
struct ap_expr_node {
|
||||
ap_expr_node_op node_op;
|
||||
const void *node_arg1;
|
||||
const void *node_arg2;
|
||||
};
|
||||
|
||||
/** The context used by scanner and parser */
|
||||
typedef struct {
|
||||
/* internal state of the scanner */
|
||||
const char *inputbuf;
|
||||
int inputlen;
|
||||
const char *inputptr;
|
||||
void *scanner;
|
||||
char *scan_ptr;
|
||||
char scan_buf[MAX_STRING_LEN];
|
||||
char scan_del;
|
||||
|
||||
/* pools for result and temporary usage */
|
||||
apr_pool_t *pool;
|
||||
apr_pool_t *ptemp;
|
||||
|
||||
/* The created parse tree */
|
||||
ap_expr *expr;
|
||||
|
||||
const char *error;
|
||||
const char *error2;
|
||||
unsigned flags;
|
||||
|
||||
/*
|
||||
* The function to use to lookup provider functions for variables
|
||||
* and funtctions
|
||||
*/
|
||||
ap_expr_lookup_fn *lookup_fn;
|
||||
} ap_expr_parse_ctx;
|
||||
|
||||
/* flex/bison functions */
|
||||
int ap_expr_yyparse(ap_expr_parse_ctx *context);
|
||||
void ap_expr_yyerror(ap_expr_parse_ctx *context, char *err);
|
||||
int ap_expr_yylex_init(void **scanner);
|
||||
int ap_expr_yylex_destroy(void *scanner);
|
||||
void ap_expr_yyset_extra(ap_expr_parse_ctx *context, void *scanner);
|
||||
|
||||
/* create a parse tree node */
|
||||
ap_expr *ap_expr_make(ap_expr_node_op op, const void *arg1, const void *arg2,
|
||||
ap_expr_parse_ctx *ctx);
|
||||
/* create parse tree node for the string-returning function 'name' */
|
||||
ap_expr *ap_expr_str_func_make(const char *name, const ap_expr *arg,
|
||||
ap_expr_parse_ctx *ctx);
|
||||
/* create parse tree node for the list-returning function 'name' */
|
||||
ap_expr *ap_expr_list_func_make(const char *name, const ap_expr *arg,
|
||||
ap_expr_parse_ctx *ctx);
|
||||
/* create parse tree node for the variable 'name' */
|
||||
ap_expr *ap_expr_var_make(const char *name, ap_expr_parse_ctx *ctx);
|
||||
/* create parse tree node for the unary operator 'name' */
|
||||
ap_expr *ap_expr_unary_op_make(const char *name, const ap_expr *arg,
|
||||
ap_expr_parse_ctx *ctx);
|
||||
/* create parse tree node for the binary operator 'name' */
|
||||
ap_expr *ap_expr_binary_op_make(const char *name, const ap_expr *arg1,
|
||||
const ap_expr *arg2, ap_expr_parse_ctx *ctx);
|
||||
|
||||
|
||||
#endif /* __AP_EXPR_PRIVATE_H__ */
|
||||
/** @} */
|
||||
|
File diff suppressed because it is too large
Load Diff
344
server/util_expr_scan.l
Normal file
344
server/util_expr_scan.l
Normal file
@ -0,0 +1,344 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl
|
||||
*/
|
||||
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
** Expression Scanner
|
||||
** _________________________________________________________________
|
||||
*/
|
||||
|
||||
%pointer
|
||||
%option batch
|
||||
%option never-interactive
|
||||
%option nodefault
|
||||
%option noyywrap
|
||||
%option reentrant
|
||||
%option bison-bridge
|
||||
%option warn
|
||||
%option noinput nounput
|
||||
%option stack
|
||||
%x str
|
||||
%x var
|
||||
%x vararg
|
||||
%x regex regex_flags
|
||||
|
||||
%{
|
||||
#include "util_expr_private.h"
|
||||
#include "util_expr_parse.h"
|
||||
|
||||
#undef YY_INPUT
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
{ \
|
||||
if ((result = MIN(max_size, yyextra->inputbuf \
|
||||
+ yyextra->inputlen \
|
||||
- yyextra->inputptr)) <= 0) \
|
||||
{ \
|
||||
result = YY_NULL; \
|
||||
} \
|
||||
else { \
|
||||
memcpy(buf, yyextra->inputptr, result); \
|
||||
yyextra->inputptr += result; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define YY_EXTRA_TYPE ap_expr_parse_ctx*
|
||||
|
||||
#define PERROR(msg) yyextra->error2 = msg ; return ERROR;
|
||||
|
||||
#define str_ptr (yyextra->scan_ptr)
|
||||
#define str_buf (yyextra->scan_buf)
|
||||
#define str_del (yyextra->scan_del)
|
||||
|
||||
%}
|
||||
|
||||
|
||||
%%
|
||||
|
||||
char regex_buf[MAX_STRING_LEN];
|
||||
char *regex_ptr = NULL;
|
||||
char regex_del = '\0';
|
||||
|
||||
/*
|
||||
* Whitespaces
|
||||
*/
|
||||
[ \t\n]+ {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
/*
|
||||
* strings ("..." and '...')
|
||||
*/
|
||||
["'] {
|
||||
str_ptr = str_buf;
|
||||
str_del = yytext[0];
|
||||
BEGIN(str);
|
||||
return T_STR_BEGIN;
|
||||
}
|
||||
<str>["'] {
|
||||
if (yytext[0] == str_del) {
|
||||
if (YY_START == var) {
|
||||
PERROR("Unterminated variable in string");
|
||||
}
|
||||
else if (str_ptr == str_buf) {
|
||||
BEGIN(INITIAL);
|
||||
return T_STR_END;
|
||||
}
|
||||
else {
|
||||
/* return what we have so far and scan delimiter again */
|
||||
*str_ptr = '\0';
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
|
||||
yyless(0);
|
||||
str_ptr = str_buf;
|
||||
return T_STRING;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*str_ptr++ = yytext[0];
|
||||
}
|
||||
}
|
||||
<str,var,vararg>\n {
|
||||
PERROR("Unterminated string or variable");
|
||||
}
|
||||
<str,var,vararg><<EOF>> {
|
||||
PERROR("Unterminated string or variable");
|
||||
}
|
||||
<str,vararg>\\[0-7]{1,3} {
|
||||
int result;
|
||||
|
||||
(void)sscanf(yytext+1, "%o", &result);
|
||||
if (result > 0xff) {
|
||||
PERROR("Escape sequence out of bound");
|
||||
}
|
||||
else {
|
||||
*str_ptr++ = result;
|
||||
}
|
||||
}
|
||||
<str,vararg>\\[0-9]+ {
|
||||
PERROR("Bad escape sequence");
|
||||
}
|
||||
<str,vararg>\\n { *str_ptr++ = '\n'; }
|
||||
<str,vararg>\\r { *str_ptr++ = '\r'; }
|
||||
<str,vararg>\\t { *str_ptr++ = '\t'; }
|
||||
<str,vararg>\\b { *str_ptr++ = '\b'; }
|
||||
<str,vararg>\\f { *str_ptr++ = '\f'; }
|
||||
<str,vararg>\\(.|\n) {
|
||||
*str_ptr++ = yytext[1];
|
||||
}
|
||||
|
||||
<str,vararg>[^\\\n"'%}]+ {
|
||||
char *cp = yytext;
|
||||
while (*cp != '\0')
|
||||
*str_ptr++ = *cp++;
|
||||
}
|
||||
|
||||
/* variable inside string */
|
||||
<str>%\{ {
|
||||
if (str_ptr != str_buf) {
|
||||
/* return what we have so far and scan '%{' again */
|
||||
*str_ptr = '\0';
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
|
||||
yyless(0);
|
||||
str_ptr = str_buf;
|
||||
return T_STRING;
|
||||
}
|
||||
else {
|
||||
yy_push_state(var, yyscanner);
|
||||
return T_VAR_BEGIN;
|
||||
}
|
||||
}
|
||||
|
||||
<vararg>% {
|
||||
*str_ptr++ = yytext[0];
|
||||
}
|
||||
|
||||
<str>[%}] {
|
||||
*str_ptr++ = yytext[0];
|
||||
}
|
||||
|
||||
%\{ {
|
||||
yy_push_state(var, yyscanner);
|
||||
return T_VAR_BEGIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* fixed name variable expansion %{XXX} and function call in %{func:arg} syntax
|
||||
*/
|
||||
<var>[a-zA-Z][a-zA-Z0-9_]* {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
|
||||
return T_ID;
|
||||
}
|
||||
|
||||
<var>\} {
|
||||
yy_pop_state(yyscanner);
|
||||
return T_VAR_END;
|
||||
}
|
||||
|
||||
<var>: {
|
||||
BEGIN(vararg);
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
<var>.|\n {
|
||||
char c[2] = { yytext[0], '\0' };
|
||||
char *msg = apr_psprintf(yyextra->pool,
|
||||
"Invalid character in variable name '%s'", c);
|
||||
PERROR(msg);
|
||||
}
|
||||
|
||||
<vararg>\} {
|
||||
if (str_ptr != str_buf) {
|
||||
/* return what we have so far and scan '}' again */
|
||||
*str_ptr = '\0';
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
|
||||
str_ptr = str_buf;
|
||||
yyless(0);
|
||||
return T_STRING;
|
||||
}
|
||||
else {
|
||||
yy_pop_state(yyscanner);
|
||||
return T_VAR_END;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Regular Expression
|
||||
*/
|
||||
"m"[/#$%^,;:_\?\|\^\-\!\.\'\"] {
|
||||
regex_del = yytext[1];
|
||||
regex_ptr = regex_buf;
|
||||
BEGIN(regex);
|
||||
}
|
||||
"/" {
|
||||
regex_del = yytext[0];
|
||||
regex_ptr = regex_buf;
|
||||
BEGIN(regex);
|
||||
}
|
||||
<regex>.|\n {
|
||||
if (yytext[0] == regex_del) {
|
||||
*regex_ptr = '\0';
|
||||
BEGIN(regex_flags);
|
||||
}
|
||||
else {
|
||||
*regex_ptr++ = yytext[0];
|
||||
}
|
||||
}
|
||||
<regex_flags>i {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
|
||||
BEGIN(INITIAL);
|
||||
return T_REGEX_I;
|
||||
}
|
||||
<regex_flags>.|\n {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
|
||||
yyless(0);
|
||||
BEGIN(INITIAL);
|
||||
return T_REGEX;
|
||||
}
|
||||
<regex_flags><<EOF>> {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
|
||||
BEGIN(INITIAL);
|
||||
return T_REGEX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Operators
|
||||
*/
|
||||
==? { return T_OP_STR_EQ; }
|
||||
"!=" { return T_OP_STR_NE; }
|
||||
"<" { return T_OP_STR_LT; }
|
||||
"<=" { return T_OP_STR_LE; }
|
||||
">" { return T_OP_STR_GT; }
|
||||
">=" { return T_OP_STR_GE; }
|
||||
"=~" { return T_OP_REG; }
|
||||
"!~" { return T_OP_NRE; }
|
||||
"and" { return T_OP_AND; }
|
||||
"&&" { return T_OP_AND; }
|
||||
"or" { return T_OP_OR; }
|
||||
"||" { return T_OP_OR; }
|
||||
"not" { return T_OP_NOT; }
|
||||
"!" { return T_OP_NOT; }
|
||||
"." { return T_OP_CONCAT; }
|
||||
"-in" { return T_OP_IN; }
|
||||
"-eq" { return T_OP_EQ; }
|
||||
"-ne" { return T_OP_NE; }
|
||||
"-ge" { return T_OP_GE; }
|
||||
"-le" { return T_OP_LE; }
|
||||
"-gt" { return T_OP_GT; }
|
||||
"-lt" { return T_OP_LT; }
|
||||
|
||||
/* for compatibility with ssl_expr */
|
||||
"lt" { return T_OP_LT; }
|
||||
"le" { return T_OP_LE; }
|
||||
"gt" { return T_OP_GT; }
|
||||
"ge" { return T_OP_GE; }
|
||||
"ne" { return T_OP_NE; }
|
||||
"eq" { return T_OP_EQ; }
|
||||
"in" { return T_OP_IN; }
|
||||
|
||||
"-"[a-zA-Z_] {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
|
||||
return T_OP_UNARY;
|
||||
}
|
||||
|
||||
"-"[a-zA-Z_][a-zA-Z_0-9] {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
|
||||
return T_OP_BINARY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specials
|
||||
*/
|
||||
"true" { return T_TRUE; }
|
||||
"false" { return T_FALSE; }
|
||||
|
||||
/*
|
||||
* Digits
|
||||
*/
|
||||
-?[0-9]+ {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
|
||||
return T_DIGIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identifiers
|
||||
*/
|
||||
[a-zA-Z][a-zA-Z0-9_]* {
|
||||
yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
|
||||
return T_ID;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are parts of the grammar and are returned as is
|
||||
*/
|
||||
[(){},:] {
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Anything else is an error
|
||||
*/
|
||||
.|\n {
|
||||
char c[2] = { yytext[0], '\0' };
|
||||
char *msg = apr_psprintf(yyextra->pool, "Parse error near '%s'", c);
|
||||
PERROR(msg);
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
|
Reference in New Issue
Block a user