1
0
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:
Stefan Fritsch
2010-11-06 14:31:16 +00:00
parent 11185f3163
commit 35cdba6976
32 changed files with 3145 additions and 3081 deletions

View File

@ -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]

View File

@ -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

View File

@ -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
}

View File

@ -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 */

View File

@ -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;

View File

@ -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";

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 = {

View File

@ -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;
}

View File

@ -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,
};
/* _________________________________________________________________
**

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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__ */
/** @} */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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];
}
%%

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

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

View File

@ -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
View 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
View 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
View 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);
}
%%