From fe4310cc61a44d51f451bfdad16b1db7f6769fd4 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Sun, 14 Mar 2021 11:09:35 -0400 Subject: [PATCH] [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] --- src/CMakeLists.txt | 8 ---- src/Makefile.am | 8 ++-- src/SConscript | 8 ++-- src/meson.build | 8 ++-- src/mod_dirlisting.c | 99 ++++++++++++----------------------------- src/mod_trigger_b4_dl.c | 72 ++++++++++++------------------ 6 files changed, 70 insertions(+), 133 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5e6ab787..664c01ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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) diff --git a/src/Makefile.am b/src/Makefile.am index d79b9075..1cf2feed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/SConscript b/src/SConscript index 55a6a93c..7ce2f2a6 100644 --- a/src/SConscript +++ b/src/SConscript @@ -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'] ] } diff --git a/src/meson.build b/src/meson.build index e3ecd0cc..e16a46a9 100644 --- a/src/meson.build +++ b/src/meson.build @@ -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 diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c index 4a029d8c..df84c3ad 100644 --- a/src/mod_dirlisting.c +++ b/src/mod_dirlisting.c @@ -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 -#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 diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c index cafa70e4..7dc6b7be 100644 --- a/src/mod_trigger_b4_dl.c +++ b/src/mod_trigger_b4_dl.c @@ -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 #include @@ -21,10 +21,6 @@ # include #endif -#if defined(HAVE_PCRE_H) -# include -#endif - #if defined(USE_MEMCACHED) # include #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;