[mod_dirlisting, mod_trigger_b4_dl] use keyvalue

use keyvalue.[ch] for basic matching

consolidate PCRE logic and leverage PCRE study in keyvalue.[ch]

remove direct link to -lpcre from modules using keyvalue.[ch]
master
Glenn Strauss 2 years ago
parent 7b9c5adda1
commit fe4310cc61

@ -958,12 +958,6 @@ add_test(NAME test_request COMMAND test_request)
if(HAVE_PCRE_H)
target_link_libraries(lighttpd ${PCRE_LDFLAGS})
add_target_properties(lighttpd COMPILE_FLAGS ${PCRE_CFLAGS})
target_link_libraries(mod_rewrite ${PCRE_LDFLAGS})
add_target_properties(mod_rewrite COMPILE_FLAGS ${PCRE_CFLAGS})
target_link_libraries(mod_dirlisting ${PCRE_LDFLAGS})
add_target_properties(mod_dirlisting COMPILE_FLAGS ${PCRE_CFLAGS})
target_link_libraries(mod_redirect ${PCRE_LDFLAGS})
add_target_properties(mod_redirect COMPILE_FLAGS ${PCRE_CFLAGS})
target_link_libraries(test_configfile ${PCRE_LDFLAGS})
add_target_properties(test_configfile COMPILE_FLAGS ${PCRE_CFLAGS})
target_link_libraries(test_keyvalue ${PCRE_LDFLAGS})
@ -972,8 +966,6 @@ endif()
if(WITH_PCRE AND (WITH_MEMCACHED OR WITH_GDBM))
add_and_install_library(mod_trigger_b4_dl mod_trigger_b4_dl.c)
target_link_libraries(mod_trigger_b4_dl ${PCRE_LDFLAGS})
add_target_properties(mod_trigger_b4_dl COMPILE_FLAGS ${PCRE_CFLAGS})
endif()
if(WITH_LUA)

@ -173,7 +173,7 @@ if BUILD_MOD_TRIGGER_B4_DL
lib_LTLIBRARIES += mod_trigger_b4_dl.la
mod_trigger_b4_dl_la_SOURCES = mod_trigger_b4_dl.c
mod_trigger_b4_dl_la_LDFLAGS = $(common_module_ldflags)
mod_trigger_b4_dl_la_LIBADD = $(GDBM_LIB) $(MEMCACHED_LIB) $(PCRE_LIB) $(common_libadd)
mod_trigger_b4_dl_la_LIBADD = $(GDBM_LIB) $(MEMCACHED_LIB) $(common_libadd)
endif
lib_LTLIBRARIES += mod_vhostdb.la
@ -238,7 +238,7 @@ mod_staticfile_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_dirlisting.la
mod_dirlisting_la_SOURCES = mod_dirlisting.c
mod_dirlisting_la_LDFLAGS = $(common_module_ldflags)
mod_dirlisting_la_LIBADD = $(common_libadd) $(PCRE_LIB)
mod_dirlisting_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_indexfile.la
mod_indexfile_la_SOURCES = mod_indexfile.c
@ -433,12 +433,12 @@ endif
lib_LTLIBRARIES += mod_rewrite.la
mod_rewrite_la_SOURCES = mod_rewrite.c
mod_rewrite_la_LDFLAGS = $(common_module_ldflags)
mod_rewrite_la_LIBADD = $(PCRE_LIB) $(common_libadd)
mod_rewrite_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_redirect.la
mod_redirect_la_SOURCES = mod_redirect.c
mod_redirect_la_LDFLAGS = $(common_module_ldflags)
mod_redirect_la_LIBADD = $(PCRE_LIB) $(common_libadd)
mod_redirect_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_status.la
mod_status_la_SOURCES = mod_status.c

@ -109,7 +109,7 @@ modules = {
'mod_authn_file' : { 'src' : [ 'mod_authn_file.c' ], 'lib' : [ env['LIBCRYPT'], env['LIBCRYPTO'] ] },
'mod_cgi' : { 'src' : [ 'mod_cgi.c' ] },
'mod_deflate' : { 'src' : [ 'mod_deflate.c' ], 'lib' : [ env['LIBZ'], env['LIBZSTD'], env['LIBBZ2'], env['LIBBROTLI'], 'm' ] },
'mod_dirlisting' : { 'src' : [ 'mod_dirlisting.c' ], 'lib' : [ env['LIBPCRE'] ] },
'mod_dirlisting' : { 'src' : [ 'mod_dirlisting.c' ] },
'mod_evasive' : { 'src' : [ 'mod_evasive.c' ] },
'mod_evhost' : { 'src' : [ 'mod_evhost.c' ] },
'mod_expire' : { 'src' : [ 'mod_expire.c' ] },
@ -118,8 +118,8 @@ modules = {
'mod_flv_streaming' : { 'src' : [ 'mod_flv_streaming.c' ] },
'mod_indexfile' : { 'src' : [ 'mod_indexfile.c' ] },
'mod_proxy' : { 'src' : [ 'mod_proxy.c' ] },
'mod_redirect' : { 'src' : [ 'mod_redirect.c' ], 'lib' : [ env['LIBPCRE'] ] },
'mod_rewrite' : { 'src' : [ 'mod_rewrite.c' ], 'lib' : [ env['LIBPCRE'] ] },
'mod_redirect' : { 'src' : [ 'mod_redirect.c' ] },
'mod_rewrite' : { 'src' : [ 'mod_rewrite.c' ] },
'mod_rrdtool' : { 'src' : [ 'mod_rrdtool.c' ] },
'mod_scgi' : { 'src' : [ 'mod_scgi.c' ] },
'mod_secdownload' : { 'src' : [ 'mod_secdownload.c' ], 'lib' : [ env['LIBCRYPTO'] ] },
@ -161,7 +161,7 @@ if env['with_pam']:
modules['mod_authn_pam'] = { 'src' : [ 'mod_authn_pam.c' ], 'lib' : [ env['LIBPAM'] ] }
if env['with_pcre'] and (env['with_memcached'] or env['with_gdbm']):
modules['mod_trigger_b4_dl'] = { 'src' : [ 'mod_trigger_b4_dl.c' ], 'lib' : [ env['LIBPCRE'], env['LIBMEMCACHED'], env['LIBGDBM'] ] }
modules['mod_trigger_b4_dl'] = { 'src' : [ 'mod_trigger_b4_dl.c' ], 'lib' : [ env['LIBMEMCACHED'], env['LIBGDBM'] ] }
if env['with_mysql']:
modules['mod_authn_mysql'] = { 'src' : [ 'mod_authn_mysql.c' ], 'lib' : [ env['LIBCRYPT'], env['LIBMYSQL'], env['LIBCRYPTO'] ] }

@ -997,7 +997,7 @@ modules = [
[ 'mod_auth', [ 'mod_auth.c' ], [ libcrypto ] ],
[ 'mod_authn_file', [ 'mod_authn_file.c' ], [ libcrypt, libcrypto ] ],
[ 'mod_deflate', [ 'mod_deflate.c' ], libbz2 + libz + libzstd + libbrotli ],
[ 'mod_dirlisting', [ 'mod_dirlisting.c' ], libpcre ],
[ 'mod_dirlisting', [ 'mod_dirlisting.c' ] ],
[ 'mod_evasive', [ 'mod_evasive.c' ] ],
[ 'mod_evhost', [ 'mod_evhost.c' ] ],
[ 'mod_expire', [ 'mod_expire.c' ] ],
@ -1006,8 +1006,8 @@ modules = [
[ 'mod_flv_streaming', [ 'mod_flv_streaming.c' ] ],
[ 'mod_indexfile', [ 'mod_indexfile.c' ] ],
[ 'mod_proxy', [ 'mod_proxy.c' ], libws2_32 ],
[ 'mod_redirect', [ 'mod_redirect.c' ], libpcre ],
[ 'mod_rewrite', [ 'mod_rewrite.c' ], libpcre ],
[ 'mod_redirect', [ 'mod_redirect.c' ] ],
[ 'mod_rewrite', [ 'mod_rewrite.c' ] ],
[ 'mod_rrdtool', [ 'mod_rrdtool.c' ] ],
[ 'mod_scgi', [ 'mod_scgi.c' ], libws2_32 ],
[ 'mod_secdownload', [ 'mod_secdownload.c' ], libcrypto ],
@ -1033,7 +1033,7 @@ endif
if get_option('with_pcre') and (get_option('with_memcached') or get_option('with_gdbm'))
modules += [
[ 'mod_trigger_b4_dl', [ 'mod_trigger_b4_dl.c' ], libpcre + libmemcached + libgdbm ],
[ 'mod_trigger_b4_dl', [ 'mod_trigger_b4_dl.c' ], libmemcached + libgdbm ],
]
endif

@ -18,6 +18,7 @@
#include "buffer.h"
#include "fdevent.h"
#include "http_header.h"
#include "keyvalue.h"
#include "plugin.h"
@ -44,10 +45,6 @@
#endif
#endif
#ifdef HAVE_PCRE_H
#include <pcre.h>
#endif
/**
* this is a dirlisting for a lighttpd plugin
*/
@ -61,11 +58,7 @@ typedef struct {
char encode_header;
char auto_layout;
#ifdef HAVE_PCRE_H
pcre **excludes;
#else
void *excludes;
#endif
pcre_keyvalue_buffer *excludes;
const buffer *show_readme;
const buffer *show_header;
@ -83,53 +76,38 @@ typedef struct {
buffer tmp_buf;
} plugin_data;
#ifdef HAVE_PCRE_H
static pcre ** mod_dirlisting_parse_excludes(server *srv, const array *a) {
pcre **regexes = calloc(a->used + 1, sizeof(pcre *));
force_assert(regexes);
static pcre_keyvalue_buffer * mod_dirlisting_parse_excludes(server *srv, const array *a) {
const int pcre_jit =
!srv->srvconf.feature_flags
|| config_plugin_value_tobool(
array_get_element_klen(srv->srvconf.feature_flags,
CONST_STR_LEN("server.pcre_jit")), 1);
pcre_keyvalue_buffer * const kvb = pcre_keyvalue_buffer_init();
buffer empty = { NULL, 0, 0 };
for (uint32_t j = 0; j < a->used; ++j) {
const data_string *ds = (const data_string *)a->data[j];
const char *errptr;
int erroff;
regexes[j] = pcre_compile(ds->value.ptr, 0, &errptr, &erroff, NULL);
if (NULL == regexes[j]) {
const data_string *ds = (data_string *)a->data[j];
if (!pcre_keyvalue_buffer_append(srv->errh, kvb, &ds->value, &empty,
pcre_jit)) {
log_error(srv->errh, __FILE__, __LINE__,
"pcre_compile failed for: %s", ds->value.ptr);
for (pcre **regex = regexes; *regex; ++regex) pcre_free(*regex);
free(regexes);
"pcre_compile failed for %s", ds->key.ptr);
pcre_keyvalue_buffer_free(kvb);
return NULL;
}
}
return regexes;
return kvb;
}
static int mod_dirlisting_exclude(log_error_st *errh, pcre **regex, const char *name, size_t len) {
for(; *regex; ++regex) {
#define N 10
int ovec[N * 3];
int n;
if ((n = pcre_exec(*regex, NULL, name, len, 0, 0, ovec, 3 * N)) < 0) {
if (n == PCRE_ERROR_NOMATCH) continue;
log_error(errh, __FILE__, __LINE__,
"execution error while matching: %d", n);
/* aborting would require a lot of manual cleanup here.
* skip instead (to not leak names that break pcre matching)
*/
}
return 1;
#undef N
}
return 0; /* no match */
static int mod_dirlisting_exclude(pcre_keyvalue_buffer * const kvb, const char * const name, const uint32_t len) {
/*(re-use keyvalue.[ch] for match-only;
* must have been configured with empty kvb 'value' during init)*/
buffer input = { NULL, len+1, 0 };
*(const char **)&input.ptr = name;
pcre_keyvalue_ctx ctx = { NULL, NULL, 0, -1 };
/*(fail closed (simulate match to exclude) if there is an error)*/
return HANDLER_ERROR == pcre_keyvalue_buffer_process(kvb,&ctx,&input,NULL)
|| -1 != ctx.m;
}
#else
#define mod_dirlisting_exclude(a, b, c, d) 0
#endif
INIT_FUNC(mod_dirlisting_init) {
return calloc(1, sizeof(plugin_data));
@ -144,14 +122,10 @@ FREE_FUNC(mod_dirlisting_free) {
config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
for (; -1 != cpv->k_id; ++cpv) {
switch (cpv->k_id) {
#ifdef HAVE_PCRE_H
case 2: /* dir-listing.exclude */
if (cpv->vtype != T_CONFIG_LOCAL) continue;
for (pcre **regex = cpv->v.v; *regex; ++regex)
pcre_free(*regex);
free(cpv->v.v);
pcre_keyvalue_buffer_free(cpv->v.v);
break;
#endif
default:
break;
}
@ -290,23 +264,9 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
case 1: /* server.dir-listing *//*(historical)*/
break;
case 2: /* dir-listing.exclude */
#ifndef HAVE_PCRE_H
if (cpv->v.a->used > 0) {
log_error(srv->errh, __FILE__, __LINE__,
"pcre support is missing for: %s, "
"please install libpcre and the headers",
cpk[cpv->k_id].k);
return HANDLER_ERROR;
}
#else
cpv->v.v = mod_dirlisting_parse_excludes(srv, cpv->v.a);
if (NULL == cpv->v.v) {
log_error(srv->errh, __FILE__, __LINE__,
"unexpected value for %s", cpk[cpv->k_id].k);
return HANDLER_ERROR;
}
if (NULL == cpv->v.v) return HANDLER_ERROR;
cpv->vtype = T_CONFIG_LOCAL;
#endif
break;
case 3: /* dir-listing.hide-dotfiles */
case 4: /* dir-listing.external-css */
@ -854,7 +814,6 @@ static int http_list_directory(request_st * const r, plugin_data * const p, buff
#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) || !defined(_ATFILE_SOURCE)
char *path_file = path + dlen;
#endif
log_error_st * const errh = r->conf.errh;
struct dirent *dent;
#ifndef _ATFILE_SOURCE /*(not using fdopendir unless _ATFILE_SOURCE)*/
@ -865,7 +824,7 @@ static int http_list_directory(request_st * const r, plugin_data * const p, buff
DIR * const dp = (dfd >= 0) ? fdopendir(dfd) : NULL;
#endif
if (NULL == dp) {
log_perror(errh, __FILE__, __LINE__, "opendir %s", path);
log_perror(r->conf.errh, __FILE__, __LINE__, "opendir %s", path);
if (dfd >= 0) close(dfd);
free(path);
return -1;
@ -908,7 +867,7 @@ static int http_list_directory(request_st * const r, plugin_data * const p, buff
* elements, skipping any that match.
*/
if (p->conf.excludes
&& mod_dirlisting_exclude(errh, p->conf.excludes, d_name, dsz))
&& mod_dirlisting_exclude(p->conf.excludes, d_name, dsz))
continue;
/* NOTE: the manual says, d_name is never more than NAME_MAX

@ -3,7 +3,6 @@
#include "plugin.h"
#if defined(HAVE_PCRE_H) /* do nothing if PCRE not available */
#if defined(HAVE_GDBM_H) || defined(USE_MEMCACHED) /* at least one required */
@ -11,6 +10,7 @@
#include "log.h"
#include "buffer.h"
#include "http_header.h"
#include "keyvalue.h"
#include <sys/stat.h>
#include <stdlib.h>
@ -21,10 +21,6 @@
# include <gdbm.h>
#endif
#if defined(HAVE_PCRE_H)
# include <pcre.h>
#endif
#if defined(USE_MEMCACHED)
# include <libmemcached/memcached.h>
#endif
@ -36,8 +32,8 @@
typedef struct {
const buffer *deny_url;
pcre *trigger_regex;
pcre *download_regex;
pcre_keyvalue_buffer *trigger_regex;
pcre_keyvalue_buffer *download_regex;
#if defined(HAVE_GDBM_H)
GDBM_FILE db;
#endif
@ -74,10 +70,10 @@ FREE_FUNC(mod_trigger_b4_dl_free) {
break;
#endif
case 1: /* trigger-before-download.trigger-url */
pcre_free(cpv->v.v);
pcre_keyvalue_buffer_free(cpv->v.v);
break;
case 2: /* trigger-before-download.download-url */
pcre_free(cpv->v.v);
pcre_keyvalue_buffer_free(cpv->v.v);
break;
#if defined(USE_MEMCACHED)
case 5: /* trigger-before-download.memcache-hosts */
@ -168,20 +164,30 @@ static int mod_trigger_b4_dl_init_regex(server * const srv, config_plugin_value_
return 1;
}
const char *errptr;
int erroff;
cpv->v.v = pcre_compile(b->ptr, 0, &errptr, &erroff, NULL);
if (cpv->v.v) {
cpv->vtype = T_CONFIG_LOCAL;
return 1;
}
else {
const int pcre_jit =
!srv->srvconf.feature_flags
|| config_plugin_value_tobool(
array_get_element_klen(srv->srvconf.feature_flags,
CONST_STR_LEN("server.pcre_jit")), 1);
pcre_keyvalue_buffer * const kvb = pcre_keyvalue_buffer_init();
buffer empty = { NULL, 0, 0 };
if (!pcre_keyvalue_buffer_append(srv->errh, kvb, b, &empty, pcre_jit)) {
log_error(srv->errh, __FILE__, __LINE__,
"compiling regex for %s failed: %s pos: %d",
str, b->ptr, erroff);
"pcre_compile failed for %s %s", str, b->ptr);
pcre_keyvalue_buffer_free(kvb);
return 0;
}
cpv->v.v = kvb;
cpv->vtype = T_CONFIG_LOCAL;
return 1;
}
static int mod_trigger_b4_dl_match(pcre_keyvalue_buffer * const kvb, const buffer * const input) {
/*(re-use keyvalue.[ch] for match-only;
* must have been configured with empty kvb 'value' during init)*/
pcre_keyvalue_ctx ctx = { NULL, NULL, 0, -1 };
return HANDLER_GO_ON == pcre_keyvalue_buffer_process(kvb, &ctx, input, NULL)
&& -1 != ctx.m;
}
static void mod_trigger_b4_dl_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
@ -352,10 +358,6 @@ static handler_t mod_trigger_b4_dl_deny(request_st * const r, const plugin_data
URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
plugin_data *p = p_d;
int n;
# define N 10
int ovec[N * 3];
if (NULL != r->handler_module) return HANDLER_GO_ON;
mod_trigger_b4_dl_patch_config(r, p);
@ -392,17 +394,10 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
const time_t cur_ts = log_epoch_secs;
/* check if URL is a trigger -> insert IP into DB */
if ((n = pcre_exec(p->conf.trigger_regex, NULL, CONST_BUF_LEN(&r->uri.path), 0, 0, ovec, 3 * N)) < 0) {
if (n != PCRE_ERROR_NOMATCH) {
log_error(r->conf.errh, __FILE__, __LINE__,
"execution error while matching: %d", n);
return HANDLER_ERROR;
}
} else {
if (mod_trigger_b4_dl_match(p->conf.trigger_regex, &r->uri.path)) {
/* the trigger matched */
# if defined(HAVE_GDBM_H)
if (p->conf.db) {
/* the trigger matched */
datum key, val;
*(const char **)&key.dptr = remote_ip->ptr;
@ -436,13 +431,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
}
/* check if URL is a download -> check IP in DB, update timestamp */
if ((n = pcre_exec(p->conf.download_regex, NULL, CONST_BUF_LEN(&r->uri.path), 0, 0, ovec, 3 * N)) < 0) {
if (n != PCRE_ERROR_NOMATCH) {
log_error(r->conf.errh, __FILE__, __LINE__,
"execution error while matching: %d", n);
return HANDLER_ERROR;
}
} else {
if (mod_trigger_b4_dl_match(p->conf.download_regex, &r->uri.path)) {
/* the download uri matched */
# if defined(HAVE_GDBM_H)
if (p->conf.db) {
@ -585,7 +574,6 @@ TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
#endif
#endif /* defined(HAVE_PCRE_H) */
#endif /* defined(HAVE_GDBM_H) || defined(USE_MEMCACHED) */
@ -594,7 +582,6 @@ int mod_trigger_b4_dl_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = "trigger_b4_dl";
#if defined(HAVE_PCRE_H) /* do nothing if PCRE not available */
#if defined(HAVE_GDBM_H) || defined(USE_MEMCACHED) /* at least one required */
p->init = mod_trigger_b4_dl_init;
@ -605,7 +592,6 @@ int mod_trigger_b4_dl_plugin_init(plugin *p) {
#endif
p->cleanup = mod_trigger_b4_dl_free;
#endif
#endif
return 0;

Loading…
Cancel
Save