/* ** OSSP l2 - Flexible Logging ** Copyright (c) 2001-2005 Cable & Wireless ** Copyright (c) 2001-2005 The OSSP Project ** Copyright (c) 2001-2005 Ralf S. Engelschall ** ** This file is part of OSSP l2, a flexible logging library which ** can be found at http://www.ossp.org/pkg/lib/l2/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** l2_ch_filter.c: filtering channel implementation */ #include "l2.h" #include "l2_ut_pcre.h" /* declare private channel configuration */ typedef struct { char *szRegex; int bNegate; int bNoCase; pcre *pcreRegex; pcre_extra *pcreExtra; } l2_ch_filter_t; /* create channel */ static l2_result_t hook_create(l2_context_t *ctx, l2_channel_t *ch) { l2_ch_filter_t *cfg; /* allocate private channel configuration */ if ((cfg = (l2_ch_filter_t *)malloc(sizeof(l2_ch_filter_t))) == NULL) return L2_ERR_MEM; /* initialize configuration with reasonable defaults */ cfg->szRegex = NULL; cfg->bNegate = FALSE; cfg->bNoCase = FALSE; cfg->pcreRegex = NULL; cfg->pcreExtra = NULL; /* link private channel configuration into channel context */ ctx->vp = cfg; return L2_OK; } /* configure channel */ static l2_result_t hook_configure(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap) { l2_ch_filter_t *cfg = (l2_ch_filter_t *)ctx->vp; l2_env_t *env; l2_param_t pa[4]; l2_result_t rv; const char *szError; int nErrorOffset; int opt; /* feed and call generic parameter parsing engine */ L2_PARAM_SET(pa[0], regex, STR, &cfg->szRegex); L2_PARAM_SET(pa[1], negate, INT, &cfg->bNegate); L2_PARAM_SET(pa[2], nocase, INT, &cfg->bNoCase); L2_PARAM_END(pa[3]); l2_channel_env(ch, &env); if ((rv = l2_util_setparams(env, pa, fmt, ap)) != L2_OK) return rv; /* translate regular expression into finite state machine */ if (cfg->szRegex != NULL) { /* compile regular expression into FSM */ opt = 0; if (cfg->bNoCase) opt |= PCRE_CASELESS; if ((cfg->pcreRegex = pcre_compile(cfg->szRegex, opt, &szError, &nErrorOffset, NULL)) == NULL) { l2_env_errorinfo(env, L2_ERR_ARG, "%s ('%c')", szError, cfg->szRegex[nErrorOffset]); return L2_ERR_ARG; } /* study FSM for more performance */ cfg->pcreExtra = pcre_study(cfg->pcreRegex, 0, &szError); if (szError != NULL) { free(cfg->pcreRegex); cfg->pcreRegex = NULL; l2_env_errorinfo(env, L2_ERR_ARG, "%s", szError); return L2_ERR_ARG; } } return L2_OK; } /* write to channel */ static l2_result_t hook_write(l2_context_t *ctx, l2_channel_t *ch, l2_level_t level, const char *buf, size_t buf_size) { l2_ch_filter_t *cfg = (l2_ch_filter_t *)ctx->vp; int bPass, iCheck; bPass = TRUE; /* apply filter */ if (cfg->pcreRegex != NULL) { iCheck = pcre_exec(cfg->pcreRegex, cfg->pcreExtra, buf, buf_size, 0, 0, NULL, 0); if (iCheck >= 0) bPass = TRUE; else bPass = FALSE; if (cfg->bNegate) bPass = !bPass; } return (bPass ? L2_OK_PASS : L2_OK); } static l2_result_t hook_destroy(l2_context_t *ctx, l2_channel_t *ch) { l2_ch_filter_t *cfg = (l2_ch_filter_t *)ctx->vp; /* destroy channel configuration */ if (cfg->szRegex != NULL) free(cfg->szRegex); if (cfg->pcreRegex != NULL) free(cfg->pcreRegex); if (cfg->pcreExtra != NULL) free(cfg->pcreExtra); free(cfg); return L2_OK_PASS; } l2_handler_t l2_handler_filter = { "filter", L2_CHANNEL_FILTER, hook_create, hook_configure, NULL, hook_write, NULL, NULL, hook_destroy };