static xmlCharEncoding sniff_encoding(saxctxt* ctx, const char* cbuf, size_t bytes) { request_rec* r = ctx->f->r; cdn_conf* cfg = ctx->cfg; xmlCharEncoding ret; char* p; ap_regmatch_t match[2]; char* buf = (char*)cbuf; const char *encoding = 0; /* If we've got it in the HTTP headers, there's nothing to do */ if(r->content_type && (p = ap_strcasestr(r->content_type, "charset=")) && p != NULL) { p += 8; if((encoding = apr_pstrndup(r->pool, p, strcspn(p, " ;")))) { ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, "sniff_encoding: found charset %s in Content-Type", encoding); ret = xmlParseCharEncoding(encoding); if(((ret != XML_CHAR_ENCODING_ERROR) && (ret != XML_CHAR_ENCODING_NONE))) return ret; } } /* to sniff, first we look for BOM */ if(encoding == NULL) { if((ret = xmlDetectCharEncoding((const xmlChar*)buf, bytes)) != XML_CHAR_ENCODING_NONE) { ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, "sniff_encoding: got charset from XML rules"); return ret; } /* If none of the above, look for a META-thingey */ if(ap_regexec(seek_meta_ctype, buf, 1, match, 0) == 0) { p = apr_pstrndup(r->pool, buf + match[0].rm_so, match[0].rm_eo - match[0].rm_so); if(ap_regexec(seek_charset, p, 2, match, 0) == 0) encoding = apr_pstrndup(r->pool, p+match[1].rm_so, match[1].rm_eo - match[1].rm_so); } } /* either it's set to something we found or it's still the default */ if(encoding) { ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, "sniff_encoding: got charset %s from HTML META", encoding); ret = xmlParseCharEncoding(encoding); if(ret != XML_CHAR_ENCODING_ERROR && ret != XML_CHAR_ENCODING_NONE) return ret; ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, "sniff_encoding: charset %s not supported", encoding); } /* Use configuration default as a last resort */ ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, "sniff_encoding: no suitable charset information"); return (cfg->default_encoding == XML_CHAR_ENCODING_NONE) ? XML_CHAR_ENCODING_8859_1 : cfg->default_encoding ; }
/* * match version against a regular expression */ static int match_version(apr_pool_t *pool, char *version_string, const char **error) { regex_t *compiled; const char *to_match; int rc; compiled = ap_pregcomp(pool, version_string, REG_EXTENDED); if (!compiled) { *error = "Unable to compile regular expression"; return 0; } *error = NULL; to_match = apr_psprintf(pool, "%d.%d.%d%s", httpd_version.major, httpd_version.minor, httpd_version.patch, httpd_version.add_string); rc = !ap_regexec(compiled, to_match, 0, NULL, 0); ap_pregfree(pool, compiled); return rc; }
static int cdn_request_handler(request_rec *r) { cdn_conf *cfg = ap_get_module_config(r->per_dir_config, &cdn_module); /* * first, do originification, which only touches output headers, if * the object's request URL matches one of the CDNActAsOrigin * regexes */ if(cfg->originify) { int i, verify_auth; act_as_origin_t *orig = (act_as_origin_t *)cfg->originify->elts; for(i = 0; i < cfg->originify->nelts; ++i) { if(!ap_regexec(&(orig[i].regex), r->uri, 0, 0, 0)) { ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, "cdn_request_handler: adding CDN origin headers for %s", r->uri); verify_auth = add_origin_headers(cfg, r, &orig[i]); if(verify_auth && verify_auth_token(cfg, r) != OK) return HTTP_UNAUTHORIZED; break; } } } /* decide whether to install cdn_html_filter */ if(cfg->content_types && cfg->links && cfg->map) { ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, "cdn_request_handler: adding cdn_html_filter for %s", r->uri); ap_add_output_filter_handle(cdn_html_filter_handle, NULL, r, r->connection); } return DECLINED; }
/** * Return the list of encoding(s) (defaults to (list "UTF-8")) * which named client is expected to send. * * @param r Apache request object structure * @param encmap Table of UA-to-encoding(s) * @param lookup Name of the useragent to look for */ static array_header * get_client_encoding(request_rec *r, array_header *encmap, const char *lookup) { void **list = (void **)encmap->elts; array_header *encs = ap_make_array(r->pool, 1, sizeof(char *)); int i; LOG(APLOG_DEBUG, r->server, "get_client_encoding: entered"); /* push UTF-8 as the first candidate of expected encoding */ *((char **)ap_push_array(encs)) = ap_pstrdup(r->pool, "UTF-8"); if (! lookup) return encs; LOG(APLOG_DEBUG, r->server, "get_client_encoding: lookup == %s", lookup); for (i = 0 ; i < encmap->nelts ; i += 2) { if (ap_regexec((regex_t *)list[i], lookup, 0, NULL, 0) == 0) { LOG(APLOG_DEBUG, r->server, "get_client_encoding: entry found"); ap_array_cat(encs, (array_header *)list[i + 1]); return encs; } } LOG(APLOG_DEBUG, r->server, "get_client_encoding: entry not found"); return encs; }
/** * The device is specified from UserAgent. * @param r Request_rec is appointed. * @param userAgent UserAgent is appointed here, * @return The style which corresponds is returned. */ static device_table * s_specified_device_from_xml(request_rec *r, mod_chxj_config * conf, const char *user_agent) { ap_regmatch_t match[10]; device_table *returnType = &UNKNOWN_DEVICE; device_table_list *dtl; device_table *dt; char *device_id; DBG(r, "REQ[%X] start %s()", TO_ADDR(r),__func__); if (! user_agent) { DBG(r, "REQ[%X] end %s() (user_agent is not set)", TO_ADDR(r),__func__); return returnType; } if (! conf->devices) { ERR(r, "REQ[%X] device_data.xml load failure", TO_ADDR(r)); DBG(r, "REQ[%X] end %s()", TO_ADDR(r), __func__); return returnType; } for (dtl = conf->devices; dtl; dtl = dtl->next) { if (! dtl->pattern) { continue; } /* DBG(r, "pattern is [%s]", dtl->pattern); */ if (! dtl->regexp) { ERR(r,"REQ[%X] compile failed.", TO_ADDR(r)); DBG(r, "REQ[%X] %s()", TO_ADDR(r),__func__); return returnType; } if (ap_regexec((const ap_regex_t *)dtl->regexp, user_agent, (apr_size_t)dtl->regexp->re_nsub + 1, match, 0) == 0) { device_id = ap_pregsub(r->pool, "$1", user_agent, dtl->regexp->re_nsub + 1, match); DBG(r, "REQ[%X] device_id:[%s]", TO_ADDR(r), device_id); dt = s_get_device_data(r, device_id, dtl); if (! dt) { dt = dtl->tail; if (dt){ if (conf->detect_device_type > CHXJ_ADD_DETECT_DEVICE_TYPE_NONE ){ dt->device_id = device_id; } DBG(r,"REQ[%X] end %s() (Not Found) use [%s]", TO_ADDR(r), __func__, dt->device_id); return dt; } } DBG(r,"REQ[%X] end %s() (Found) use [%s]", TO_ADDR(r), __func__, dt->device_id); return dt; } } DBG(r,"REQ[%X] end %s()", TO_ADDR(r), __func__); return returnType; }
static int find_cookie(request_rec *r,char **user,uint8_t *secret,int secretLen) { char *cookie=0l; char *cookie_expire=0l; char *cookie_valid=0l; ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; authn_google_config_rec *conf = ap_get_module_config(r->per_dir_config, &authn_google_module); cookie = (char *) apr_table_get(r->headers_in, "Cookie"); if (cookie) { if (conf->debugLevel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Found cookie \"%s\"",cookie); if (!ap_regexec(cookie_regexp, cookie, AP_MAX_REG_MATCH, regmatch, 0)) { if (user) *user = ap_pregsub(r->pool, "$2", cookie,AP_MAX_REG_MATCH,regmatch); cookie_expire = ap_pregsub(r->pool, "$3", cookie,AP_MAX_REG_MATCH,regmatch); cookie_valid = ap_pregsub(r->pool, "$4", cookie,AP_MAX_REG_MATCH,regmatch); if (conf->debugLevel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Found cookie Expires \"%s\" Valid \"%s\"",cookie_expire,cookie_valid); if (cookie_expire && cookie_valid && *user) { long unsigned int exp = apr_atoi64(cookie_expire); long unsigned int now = apr_time_now()/1000000; if (exp < now) { if (conf->debugLevel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Expired. Now=%lu Expire=%lu\n",now,exp); return 0; /* Expired */ } if (!secret) { secret = getUserSecret(r,*user,&secretLen,0L); } char *h = hash_cookie(r->pool,secret,secretLen,exp); if (conf->debugLevel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Match cookie \"%s\" vs \"%s\"",h,cookie_valid); if (apr_strnatcmp(h,cookie_valid)==0) return 1; /* Valid Cookie */ else { if (conf->debugLevel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "MISMATCHED cookie \"%s\" vs \"%s\"",h,cookie_valid); return 0; /* Mismatched */ } } } } return 0; /* Not found */ }
void password_test(apr_pool_t *pool,char *cookie) { char *user=0l; ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; printf("will regexec \n"); if (!ap_regexec(passwd_regexp, cookie, AP_MAX_REG_MATCH, regmatch, 0)) { printf("regexec done\n"); user = ap_pregsub(pool, "$1", cookie,AP_MAX_REG_MATCH,regmatch); printf("PASSWORD GOOD: \"%s\"\n",user); } else printf ("INVALID PASSWORD: \"%s\"\n",cookie); }
static void dump_content(saxctxt *ctx) { urlmap *m; char *found; size_t s_from, s_to; size_t match; char c = 0; int nmatch; ap_regmatch_t pmatch[10]; char *subs; size_t len, offs; urlmap *themap = ctx->map; #ifndef GO_FASTER int verbose = APLOGrtrace1(ctx->f->r); #endif pappend(ctx, &c, 1); /* append null byte */ /* parse the text for URLs */ for (m = themap; m; m = m->next) { if (!(m->flags & M_CDATA)) continue; if (m->flags & M_REGEX) { nmatch = 10; offs = 0; while (!ap_regexec(m->from.r, ctx->buf+offs, nmatch, pmatch, 0)) { match = pmatch[0].rm_so; s_from = pmatch[0].rm_eo - match; subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs, nmatch, pmatch); s_to = strlen(subs); len = strlen(ctx->buf); offs += match; VERBOSEB( const char *f = apr_pstrndup(ctx->f->r->pool, ctx->buf + offs, s_from); ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r, "C/RX: match at %s, substituting %s", f, subs); ) if (s_to > s_from) { preserve(ctx, s_to - s_from); memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from, len + 1 - s_from - offs); memcpy(ctx->buf+offs, subs, s_to); } else { memcpy(ctx->buf + offs, subs, s_to); memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from, len + 1 - s_from - offs); } offs += s_to; } }
void cookie_test(apr_pool_t *pool,char *cookie) { char *user=0l; char *cookie_expire=0l; char *cookie_valid=0l; ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; //authn_google_config_rec *conf = ap_get_module_config(r->per_dir_config, &authn_google_module); if (!ap_regexec(cookie_regexp, cookie, AP_MAX_REG_MATCH, regmatch, 0)) { user = ap_pregsub(pool, "$2", cookie,AP_MAX_REG_MATCH,regmatch); cookie_expire = ap_pregsub(pool, "$3", cookie,AP_MAX_REG_MATCH,regmatch); cookie_valid = ap_pregsub(pool, "$4", cookie,AP_MAX_REG_MATCH,regmatch); printf("COOKIE GOOD: \"%s\" \"%s\" \"%s\"\n",user,cookie_expire,cookie_valid); } else printf ("INVALID COOKIE: \"%s\"\n",cookie); }
static int spot_cookie(request_rec *r) { cookie_dir_rec *dcfg = ap_get_module_config(r->per_dir_config, &usertrack_module); const char *cookie_header; ap_regmatch_t regm[NUM_SUBS]; /* Do not run in subrequests */ if (!dcfg->enabled || r->main) { return DECLINED; } if ((cookie_header = apr_table_get(r->headers_in, "Cookie"))) { if (!ap_regexec(dcfg->regexp, cookie_header, NUM_SUBS, regm, 0)) { char *cookieval = NULL; int err = 0; /* Our regexp, * ^cookie_name=([^;]+)|;[ \t]+cookie_name=([^;]+) * only allows for $1 or $2 to be available. ($0 is always * filled with the entire matched expression, not just * the part in parentheses.) So just check for either one * and assign to cookieval if present. */ if (regm[1].rm_so != -1) { cookieval = ap_pregsub(r->pool, "$1", cookie_header, NUM_SUBS, regm); if (cookieval == NULL) err = 1; } if (regm[2].rm_so != -1) { cookieval = ap_pregsub(r->pool, "$2", cookie_header, NUM_SUBS, regm); if (cookieval == NULL) err = 1; } if (err) { ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01499) "Failed to extract cookie value (out of mem?)"); return HTTP_INTERNAL_SERVER_ERROR; } /* Set the cookie in a note, for logging */ apr_table_setn(r->notes, "cookie", cookieval); return DECLINED; /* There's already a cookie, no new one */ } } make_cookie(r); return OK; /* We set our cookie */ }
static sqlalias_filter_ret sqlalias_filter(request_rec *r, apr_array_header_t *filters) { int i; sqlalias_filter_entry *entries; entries = (sqlalias_filter_entry *) filters->elts; for (i = 0; i < filters->nelts; i++) { sqlalias_filter_entry *filter = &entries[i]; if(!ap_regexec((ap_regex_t *)filter->regexp, r->uri, 0, NULL, 0)) { DEBUG_MSG(r->server, "sqlalias: %s ignored as defined by SQLAliasFilter rule (%s)", r->uri, filter->pattern); return FILTERED_URI; } } return VALID_URI; }
static int is_contenttype_ignored(dosdetector_dir_config *cfg, request_rec *r) { const char *content_type; content_type = ap_sub_req_lookup_uri(r->uri, r, NULL)->content_type; ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; ap_regex_t **contenttype_regexp = (ap_regex_t **) cfg->contenttype_regexp->elts; int i, ignore = 0; for (i = 0; i < cfg->contenttype_regexp->nelts; i++) { if(!ap_regexec(contenttype_regexp[i], content_type, AP_MAX_REG_MATCH, regmatch, 0)) { ignore = 1; break; } } DEBUGLOG_R("content-type=%s, result=%s", content_type, (ignore ? "ignored":"processed")); return ignore; }
static char *getSharedKey(request_rec *r,char *filename, char **static_pw) { ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; char l[MAX_STRING_LEN]; char *sharedKey = 0L; apr_status_t status; ap_configfile_t *f; authn_google_config_rec *conf = ap_get_module_config(r->per_dir_config, &authn_google_module); status = ap_pcfg_openfile(&f, r->pool, filename); ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, "OPENING FILENAME %s",filename); if (status != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, "check_password: Couldn't open password file: %s", filename); return 0L; } while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { /* If we have a password entry - return it, if the caller has asked for it */ if ((static_pw) && (!ap_regexec(passwd_regexp, l, AP_MAX_REG_MATCH, regmatch, 0))) { *static_pw = ap_pregsub(r->pool, "$1", l,AP_MAX_REG_MATCH,regmatch); if (conf->debugLevel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Using static password \"%s\"",*static_pw); } /* Skip comment or blank lines. */ if ((l[0] == '"') || (!l[0])) { continue; } if (!sharedKey) { sharedKey = apr_pstrdup(r->pool,l); } /* Scratch codes to follow */ } ap_cfg_closefile(f); return sharedKey; }
extern apr_status_t check_regular_expression(request_rec *r, char *haystack, char *needle) { ap_regex_t *regexp = (ap_regex_t *)NULL; ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; // Validation Check if (haystack == (char *)NULL) { return DECLINED; } if (needle == (char *)NULL) { return DECLINED; } if (strlen(haystack) > 0) { regexp = (ap_regex_t *)ap_pregcomp(r->pool, (const char *)haystack, REG_EXTENDED|REG_ICASE); if (regexp != (ap_regex_t *)NULL && ap_regexec(regexp, (const char*)needle, regexp->re_nsub + 1, regmatch, 0) == 0) { ap_pregfree(r->pool, regexp); return APR_SUCCESS; } ap_pregfree(r->pool, regexp); } return DECLINED; }
static apr_status_t parse_request_uri(request_rec *r, char **uri, char **size) { int nmatch = 10; ap_regmatch_t match[nmatch]; ap_regex_t *reg; reg = ap_pregcomp(r->pool, "^/(original|large|medium|small)/(.*)$", AP_REG_EXTENDED); if (ap_regexec(reg, r->unparsed_uri, nmatch, match, 0) == 0) { *size = ap_pregsub(r->pool, "$1", r->unparsed_uri, nmatch, match); *uri = ap_pregsub(r->pool, "$2", r->unparsed_uri, nmatch, match); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Parse URI: %s, %s", *size, *uri); ap_pregfree(r->pool, reg); return APR_SUCCESS; } else { return APR_EGENERAL; } }
/* Here-in lies the meat */ static int dosblock_main(request_rec *r) { const apr_table_entry_t *dosrulemap_elts = NULL; const apr_array_header_t *dosrulemap_arr = NULL; char *subrule=NULL, *dosrulematch=NULL, *urlpattern=NULL; char *req_header = NULL; int matchfound = 0; int gotlock = 0; dosblockipc_data *base = NULL; apr_status_t rs; dosblock_cfg *cfg = (dosblock_cfg *)ap_get_module_config(r->server->module_config, &mod_dosblock_module); /* Here we try to find if the request matches a dos rule */ dosrulemap_arr = apr_table_elts(cfg->dosrulemap); if (dosrulemap_arr) { dosrulemap_elts = (const apr_table_entry_t *)dosrulemap_arr->elts; int i; for (i=0; i<dosrulemap_arr->nelts; ++i) { subrule = dosrulemap_elts[i].val; char *subrule_type = (char *)apr_table_get(cfg->ruletype, subrule); if (subrule_type == NULL) continue; /* Check if it is a url based subrule */ if (0 == apr_strnatcmp(subrule_type, RULEURL)) { urlpattern = (char *)apr_table_get(cfg->urlrules, subrule); if (urlpattern == NULL) continue; ap_regex_t *pattern = ap_pregcomp(r->pool, urlpattern, AP_REG_EXTENDED); if (0 == ap_regexec(pattern, r->uri, 0, NULL, 0)) /* This is where the dos url subrule would match */ { dosrulematch = dosrulemap_elts[i].key; matchfound = 1; break; } } /* Check if it is a header based subrule */ else if (0 == apr_strnatcmp(subrule_type, RULEHEADER)) { headerrulestruct *h = NULL; h = apr_hash_get(cfg->headerrules, subrule, APR_HASH_KEY_STRING); if (h == NULL) continue; req_header = (char *)apr_table_get(r->headers_in, h->headername); if (req_header == NULL) continue; ap_regex_t *pattern = ap_pregcomp(r->pool, h->headerpattern, AP_REG_EXTENDED); if (0 == ap_regexec(pattern, req_header, 0, NULL, 0)) /* This is where the dos header subrule would match */ { dosrulematch = dosrulemap_elts[i].key; matchfound = 1; break; } } } } if (matchfound && dosrulematch) { int blocked = 0; /* apr_table_set(r->headers_out, "DOSRULE_MATCHED", dosrulematch);*/ /* Check if we have the corresponding shared memory segment for * the matching dos rule. If not we do not go further. */ if (!apr_hash_get(cfg->dosrule_shm_map, dosrulematch, APR_HASH_KEY_STRING)) { return DECLINED; } apr_int64_t index = apr_atoi64(apr_hash_get(cfg->dosrule_shm_map, dosrulematch, APR_HASH_KEY_STRING)); /* Take the mutex lock here. Be careful of not 'returning' before releasing the lock*/ rs = apr_global_mutex_lock(dosblockipc_mutex[index]); if (APR_SUCCESS == rs) { gotlock = 1; } else { /* Some error, log and bail */ ap_log_error(APLOG_MARK, APLOG_ERR, rs, r->server, "Child %ld failed to acquire lock", (long int)getpid()); } base = (dosblockipc_data *)apr_shm_baseaddr_get(dosblockipc_shm[index]); /* check if the Dos rule is already blocked */ if (base->ds.isblocked) { /* The dos rule is blocked at this moment. Need to check the time stamp * (time till blockage) and act accordingly */ apr_time_t time_now = apr_time_now(); apr_time_t time_to_blockage = base->ds.t; /* apr_table_set(r->headers_out, "Blocked till", apr_psprintf(r->pool, "%d",time_to_blockage)); */ if(cfg->verbosity) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Dos rule %s is blocked", dosrulematch); if (time_now < time_to_blockage) { /* Keep blocking */ blocked = 1; if(cfg->verbosity) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Keep dos rule %s blocked", dosrulematch); } else { /* Time to unblock */ base->ds.isblocked = 0; base->ds.t = 0; /* apr_table_set(r->headers_out, "Time-to-unblock", "Unblock"); */ if(cfg->verbosity) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Time to unblock dos rule %s", dosrulematch); } } /* Here we age entries, try to account for the matched hit, calculate the * rate and take some action if needed. */ int i; apr_int64_t sum_counter = 0; int hit_accounted = 0; /* Loop through the array of structs */ for (i=0; i<ARSIZE; i++) { if (base->dh[i].t) { if ((r->request_time - base->dh[i].t)/APR_USEC_PER_SEC > ARSIZE ) { /* Ageing entries */ base->dh[i].t = 0; base->dh[i].counter = 0; if(cfg->verbosity) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Ageing entry for dos rule %s", dosrulematch); continue; } if (base->dh[i].t/APR_USEC_PER_SEC == r->request_time/APR_USEC_PER_SEC ) { /* There is already an entry for this sec. Increment the corresponding * counter */ base->dh[i].counter++; sum_counter+= base->dh[i].counter; hit_accounted = 1; /*apr_table_set(r->headers_out, "Entry-for-this-sec", "Exists"); */ if(cfg->verbosity) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "We have an Entry-for-this-sec for dos rule %s", dosrulematch); continue; } sum_counter+= base->dh[i].counter; } } /* Add an element in our array of structs for this second if the hit was not accounted above */ if (! hit_accounted) { if(cfg->verbosity) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Hit is not accounted for dos rule %s", dosrulematch); if ((ARSIZE - base->next) == 0) base->next = 0; base->dh[base->next].t = r->request_time; base->dh[base->next].counter = 1; sum_counter+= base->dh[base->next].counter; base->next++; /*apr_table_set(r->headers_out, "Entry-for-this-sec", "Does-not-Exist");*/ if(cfg->verbosity) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "We do not have an entry for this second (dos rule %s) and sum of counter is %" APR_INT64_T_FMT, dosrulematch, sum_counter); } if ( ! blocked) { float rate = (float)sum_counter/ARSIZE; /* Get the configured rate threshold */ dosrulestruct *d = apr_hash_get(cfg->dosrules, dosrulematch, APR_HASH_KEY_STRING); if(cfg->verbosity) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s sum of counter is %" APR_INT64_T_FMT, dosrulematch, sum_counter); ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s rate is %f", dosrulematch, rate); ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s configured rate is %" APR_INT64_T_FMT, dosrulematch, apr_atoi64(d->threshold)); } if (rate > apr_atoi64(d->threshold)) { /* Block it */ base->ds.isblocked = 1; base->ds.t = (apr_time_now() + (apr_atoi64(d->timetoblock)*APR_USEC_PER_SEC)); base->ds.rate_when_blocked = rate; if(cfg->verbosity) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s getting blocked after rate calulation", dosrulematch); ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s getting blocked till %" APR_TIME_T_FMT, dosrulematch, base->ds.t); } blocked = 1; } } /* Release the lock. We have to be careful of not 'returning' before * releasing the lock */ if (gotlock) rs = apr_global_mutex_unlock(dosblockipc_mutex[index]); /* Swallowing the result because what are we going to do with it at * this stage */ if (blocked) return HTTP_SERVICE_UNAVAILABLE; } else { /* apr_table_set(r->headers_out, "DOSRULE_MATCHED", "None");*/ } return DECLINED; }
static void do_pattmatch(ap_filter_t *f, apr_bucket *inb, apr_bucket_brigade *mybb, apr_pool_t *tmp_pool) { int i; int force_quick = 0; ap_regmatch_t regm[AP_MAX_REG_MATCH]; apr_size_t bytes; apr_size_t len; apr_size_t fbytes; const char *buff; const char *repl; char *scratch; char *p; char *s1; char *s2; apr_bucket *b; apr_bucket *tmp_b; apr_pool_t *tpool; subst_dir_conf *cfg = (subst_dir_conf *) ap_get_module_config(f->r->per_dir_config, &substitute_module); subst_pattern_t *script; APR_BRIGADE_INSERT_TAIL(mybb, inb); script = (subst_pattern_t *) cfg->patterns->elts; apr_pool_create(&tpool, tmp_pool); scratch = NULL; fbytes = 0; /* * Simple optimization. If we only have one pattern, then * we can safely avoid the overhead of flattening */ if (cfg->patterns->nelts == 1) { force_quick = 1; } for (i = 0; i < cfg->patterns->nelts; i++) { for (b = APR_BRIGADE_FIRST(mybb); b != APR_BRIGADE_SENTINEL(mybb); b = APR_BUCKET_NEXT(b)) { if (APR_BUCKET_IS_METADATA(b)) { /* * we should NEVER see this, because we should never * be passed any, but "handle" it just in case. */ continue; } if (apr_bucket_read(b, &buff, &bytes, APR_BLOCK_READ) == APR_SUCCESS) { s1 = NULL; if (script->pattern) { while ((repl = apr_strmatch(script->pattern, buff, bytes))) { /* get offset into buff for pattern */ len = (apr_size_t) (repl - buff); if (script->flatten && !force_quick) { /* * We are flattening the buckets here, meaning * that we don't do the fast bucket splits. * Instead we copy over what the buckets would * contain and use them. This is slow, since we * are constanting allocing space and copying * strings. */ SEDSCAT(s1, s2, tmp_pool, buff, len, script->replacement); } else { /* * We now split off the stuff before the regex * as its own bucket, then isolate the pattern * and delete it. */ SEDRMPATBCKT(b, len, tmp_b, script->patlen); /* * Finally, we create a bucket that contains the * replacement... */ tmp_b = apr_bucket_transient_create(script->replacement, script->replen, f->r->connection->bucket_alloc); /* ... and insert it */ APR_BUCKET_INSERT_BEFORE(b, tmp_b); } /* now we need to adjust buff for all these changes */ len += script->patlen; bytes -= len; buff += len; } if (script->flatten && s1 && !force_quick) { /* * we've finished looking at the bucket, so remove the * old one and add in our new one */ s2 = apr_pstrmemdup(tmp_pool, buff, bytes); s1 = apr_pstrcat(tmp_pool, s1, s2, NULL); tmp_b = apr_bucket_transient_create(s1, strlen(s1), f->r->connection->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, tmp_b); apr_bucket_delete(b); b = tmp_b; } } else if (script->regexp) { /* * we need a null terminated string here :(. To hopefully * save time and memory, we don't alloc for each run * through, but only if we need to have a larger chunk * to save the string to. So we keep track of how much * we've allocated and only re-alloc when we need it. * NOTE: this screams for a macro. */ if (!scratch || (bytes > (fbytes + 1))) { fbytes = bytes + 1; scratch = apr_palloc(tpool, fbytes); } /* reset pointer to the scratch space */ p = scratch; memcpy(p, buff, bytes); p[bytes] = '\0'; while (!ap_regexec(script->regexp, p, AP_MAX_REG_MATCH, regm, 0)) { /* first, grab the replacement string */ repl = ap_pregsub(tmp_pool, script->replacement, p, AP_MAX_REG_MATCH, regm); if (script->flatten && !force_quick) { SEDSCAT(s1, s2, tmp_pool, p, regm[0].rm_so, repl); } else { len = (apr_size_t) (regm[0].rm_eo - regm[0].rm_so); SEDRMPATBCKT(b, regm[0].rm_so, tmp_b, len); tmp_b = apr_bucket_transient_create(repl, strlen(repl), f->r->connection->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, tmp_b); } /* * reset to past what we just did. buff now maps to b * again */ p += regm[0].rm_eo; } if (script->flatten && s1 && !force_quick) { s1 = apr_pstrcat(tmp_pool, s1, p, NULL); tmp_b = apr_bucket_transient_create(s1, strlen(s1), f->r->connection->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, tmp_b); apr_bucket_delete(b); b = tmp_b; } } else { /* huh? */ continue; } } } script++; } apr_pool_destroy(tpool); return; }
static void pstartElement(void *ctxt, const xmlChar * uname, const xmlChar ** uattrs) { int num_match; char *subs; int is_uri; const char **a; size_t s_to, s_from; saxctxt *ctx = (saxctxt *) ctxt; apr_array_header_t *linkattrs; int i; const char *name = (const char *) uname; const char **attrs = (const char **) uattrs; const htmlElemDesc *desc = htmlTagLookup(uname); /* VoxCDN FIXME: rewrite this, it's ridiculously bad */ #if 0 /* for now, err on the side of leaving stuff alone */ int enforce = 0; if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) { /* enforce html */ enforce = 2; if (!desc || desc->depr) return; } else if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) { enforce = 1; /* enforce html legacy */ if (!desc) { return; } } if (!desc && enforce) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, "Bogus HTML element %s dropped", name) ; return; } if (desc && desc->depr && (enforce == 2) ) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, "Deprecated HTML element %s dropped", name) ; return; } #endif ap_fputc(ctx->f->next, ctx->bb, '<'); ap_fputs(ctx->f->next, ctx->bb, name); if (attrs) { linkattrs = apr_hash_get(ctx->cfg->links, name, APR_HASH_KEY_STRING); for (a = attrs; *a; a += 2) { ctx->offset = 0; if (a[1]) { pappend(ctx, a[1], strlen(a[1]) + 1); is_uri = 0; if (linkattrs) { tattr *attrs = (tattr *) linkattrs->elts; for (i = 0; i < linkattrs->nelts; ++i) { if (!strcmp(*a, attrs[i].val)) { is_uri = 1; break; } } } if(is_uri) { /* first do the server replacements */ if(ctx->cfg->map) { server_remap_t *remaps = (server_remap_t *)ctx->cfg->map->elts; for(i = 0; i < ctx->cfg->map->nelts; ++i) { if(!ap_regexec(&(remaps[i].regex), ctx->buf, 0, 0, 0)) { int add_auth = ctx->cfg->global_auth | (remaps[i].flags & REMAP_FLAG_AUTH); int add_qstring_ignore = ctx->cfg->global_qstring_ignore | (remaps[i].flags & REMAP_FLAG_QSTRING_IGNORE); subs = remap_url(ctx, ctx->buf, add_auth, add_qstring_ignore); if(subs) { ++num_match; s_to = strlen(subs); s_from = strlen(ctx->buf); if(s_to > s_from) preserve(ctx, s_to - s_from); memcpy(ctx->buf, subs, s_to+1); break; /* only do one substitution per link */ } } } } } } if (!a[1]) ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], NULL); else { /* write the attribute */ ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], "=\"", NULL); pcharacters(ctx, (const xmlChar *) ctx->buf, strlen(ctx->buf)); ap_fputc(ctx->f->next, ctx->bb, '"'); } } } ctx->offset = 0; if(desc && desc->empty) ap_fputs(ctx->f->next, ctx->bb, "/>"); else ap_fputc(ctx->f->next, ctx->bb, '>'); }
/* * Get the stuff from LDAP */ static int getldaphome(request_rec *r, vhx_config_rec *vhr, const char *hostname, vhx_request_t *reqc) { /* LDAP associated variable and stuff */ const char **vals = NULL; char *filtbuf = NULL; int result = 0; const char *dn = NULL; util_ldap_connection_t *ldc = NULL; int failures = 0; VH_AP_LOG_RERROR(APLOG_MARK, APLOG_DEBUG, 0, r, "getldaphome(): BEGIN ***,pid=%d",getpid()); /* Check for illegal characters in hostname that would mess up the LDAP query */ ap_regex_t *cpat = ap_pregcomp(r->pool, "\\[\\/\\*\\(\\)&\\]", REG_EXTENDED|REG_ICASE); if(cpat != NULL) { if (ap_regexec(cpat, hostname, 0, NULL, 0) == 0 ) { VH_AP_LOG_RERROR(APLOG_MARK, APLOG_WARNING, 0, r, "%s: (getldaphome) bad characters in hostname %s", VH_NAME, hostname); return DECLINED; } } start_over: if (vhr->ldap_host) { VH_AP_LOG_RERROR(APLOG_MARK, APLOG_DEBUG, 0, r, "getldaphome(): util_ldap_connection_find(r,%s,%d,%s,%s,%d,%d);",vhr->ldap_host, vhr->ldap_port, vhr->ldap_binddn, vhr->ldap_bindpw, vhr->ldap_deref, vhr->ldap_secure); ldc = util_ldap_connection_find(r, vhr->ldap_host, vhr->ldap_port, vhr->ldap_binddn, vhr->ldap_bindpw, vhr->ldap_deref, vhr->ldap_secure); } else { return DECLINED; } filtbuf = apr_psprintf(r->pool, "(&(%s)(|(apacheServerName=%s)(apacheServerAlias=%s)))", vhr->ldap_filter, hostname, hostname); VH_AP_LOG_RERROR(APLOG_MARK, APLOG_DEBUG, 0, r, "getldaphome(): filtbuf = %s",filtbuf); //VH_AP_LOG_RERROR(APLOG_MARK, APLOG_DEBUG, 0, r, "getldaphome(): %s %s %d %s %s",vhr->ldap_url,vhr->ldap_basedn,vhr->ldap_scope,ldap_attributes[0],filtbuf); result = util_ldap_cache_getuserdn(r, ldc, vhr->ldap_url, vhr->ldap_basedn, vhr->ldap_scope, ldap_attributes, filtbuf, &dn, &vals); util_ldap_connection_close(ldc); // sanity check - if server is down, retry it up to 5 times if (result == LDAP_SERVER_DOWN) { if (failures++ <= 5) { apr_sleep(1000000); goto start_over; } } if ((result == LDAP_NO_SUCH_OBJECT)) { VH_AP_LOG_RERROR(APLOG_MARK, APLOG_DEBUG, 0, r, "getldaphome(): virtual host %s not found", hostname); return DECLINED; } /* handle bind failure */ if (result != LDAP_SUCCESS) { VH_AP_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, "%s: (getldaphome) translate failed; virtual host %s; URI %s LDAP Error: [%s]", VH_NAME, hostname, r->uri, ldap_err2string(result)); return DECLINED; } int i = 0; while (ldap_attributes[i]) { if (apr_strnatcasecmp (ldap_attributes[i], "apacheServerName") == 0) { reqc->name = apr_pstrdup (r->pool, vals[i]); } else if (apr_strnatcasecmp (ldap_attributes[i], "apacheServerAdmin") == 0) { reqc->admin = apr_pstrdup (r->pool, vals[i]); } else if (apr_strnatcasecmp (ldap_attributes[i], "apacheDocumentRoot") == 0) { reqc->docroot = apr_pstrdup (r->pool, vals[i]); } else if (apr_strnatcasecmp (ldap_attributes[i], "homeDirectory") == 0) { reqc->homedirectory = apr_pstrdup (r->pool, vals[i]); } else if (apr_strnatcasecmp (ldap_attributes[i], "phpOptions") == 0) { reqc->phpoptions = apr_pstrdup (r->pool, vals[i]); } else if (apr_strnatcasecmp (ldap_attributes[i], "uidNumber") == 0) { reqc->uid = apr_pstrdup(r->pool, vals[i]); } else if (apr_strnatcasecmp (ldap_attributes[i], "gidNumber") == 0) { reqc->gid = apr_pstrdup(r->pool, vals[i]); } else if (apr_strnatcasecmp (ldap_attributes[i], "apacheChrootDir") == 0) { reqc->chroot_dir = apr_pstrdup(r->pool, vals[i]); } i++; } reqc->vhost_found = VH_VHOST_INFOS_FOUND; VH_AP_LOG_RERROR(APLOG_MARK, APLOG_DEBUG, 0, r, "getldaphome(): END ***"); /* If we don't have a document root then we can't honour the request */ if (reqc->docroot == NULL) { VH_AP_LOG_RERROR(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, "%s: (getldaphome) no document root found for %s", VH_NAME, hostname); return DECLINED; } /* We have a document root so, this is ok */ return OK; }
// Find the cookie and figure out what to do static int spot_cookie(request_rec *r) { cookietrack_settings_rec *dcfg = ap_get_module_config(r->per_dir_config, &cookietrack_module); const char *cookie_header; ap_regmatch_t regm[NUM_SUBS]; /* Do not run in subrequests */ if (!dcfg->enabled || r->main) { return DECLINED; } /* Is DNT set? */ const char *dnt_is_set = apr_table_get( r->headers_in, "DNT" ); _DEBUG && fprintf( stderr, "DNT: %s\n", dnt_is_set ); /* Do we already have a cookie? */ char *cur_cookie_value = NULL; if( (cookie_header = apr_table_get(r->headers_in, "Cookie")) ){ // this will match the FIRST occurance of the cookiename, not // subsequent ones. if( !ap_regexec(dcfg->regexp, cookie_header, NUM_SUBS, regm, 0) ) { /* Our regexp, * ^cookie_name=([^;]+)|;[ \t]+cookie_name=([^;]+) * only allows for $1 or $2 to be available. ($0 is always * filled with the entire matched expression, not just * the part in parentheses.) So just check for either one * and assign to cookieval if present. */ if( regm[1].rm_so != -1 ) { cur_cookie_value = ap_pregsub(r->pool, "$1", cookie_header, NUM_SUBS, regm); } if( regm[2].rm_so != -1 ) { cur_cookie_value = ap_pregsub(r->pool, "$2", cookie_header, NUM_SUBS, regm); } } } _DEBUG && fprintf( stderr, "Current Cookie: %s\n", cur_cookie_value ); /* XFF support inspired by this patch: http://www.mail-archive.com/[email protected]/msg17378.html And this implementation for scanning for remote ip: http://apache.wirebrain.de/lxr/source/modules/metadata/mod_remoteip.c?v=2.3-trunk#267 */ // Get the IP address of the originating request const char *rname = NULL; // Originating IP address char *xff = NULL; // X-Forwarded-For, or equivalent header type // Should we look at a header? if( xff = apr_table_get(r->headers_in, dcfg->cookie_ip_header) ) { // There might be multiple addresses in the header // Check if there's a comma in there somewhere // no comma, this is the address we can use if( (rname = strrchr(xff, ',')) == NULL ) { rname = xff; // whitespace/commas left, remove 'm } else { // move past the comma rname++; // and any whitespace we might find while( *rname == ' ' ) { rname++; } } // otherwise, get it from the remote host } else { rname = ap_get_remote_host( r->connection, r->per_dir_config, REMOTE_NAME, NULL ); } _DEBUG && fprintf( stderr, "Remote Address: %s\n", rname ); /* Determine the value of the cookie we're going to set: */ /* Make sure we have enough room here... */ char new_cookie_value[ _MAX_COOKIE_LENGTH ]; // dnt is set, and we care about that if( dnt_is_set && dcfg->comply_with_dnt ) { // you don't want us to set a cookie, alright then our work is done. if( !dcfg->set_dnt_cookie ) { return DECLINED; } char *dnt_value = dcfg->dnt_value; // you already ahve a cookie, but it might be whitelisted if( cur_cookie_value ) { // you might have whitelisted this value; let's check // Following tutorial code here again: // http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html int i; for( i = 0; i < dcfg->dnt_exempt->nelts; i++ ) { _DEBUG && fprintf( stderr, "e: %d\n", i ); char *exempt = ((char **)dcfg->dnt_exempt->elts)[i]; //it's indeed whiteliested, we should use this value instead if( strcasecmp( cur_cookie_value, exempt ) == 0 ) { _DEBUG && fprintf( stderr, "Cookie %s is DNT exempt\n", cur_cookie_value ); dnt_value = exempt; } } } // dnt_value is a pointer, hence the sprintf sprintf( new_cookie_value, "%s", dnt_value ); // No DNT header, so we need a cookie value to set } else { // there already is a cookie set if( cur_cookie_value ) { // but it's set to the DNT cookie if( strcasecmp( cur_cookie_value, dcfg->dnt_value ) == 0 ) { // if we have some sort of library that's generating the // UID, call that with the cookie we would be setting if( _EXTERNAL_UID_FUNCTION ) { char ts[ _MAX_COOKIE_LENGTH ]; sprintf( ts, "%" APR_TIME_T_FMT, apr_time_now() ); gen_uid( new_cookie_value, ts, rname ); // otherwise, just set it } else { sprintf( new_cookie_value, "%s.%" APR_TIME_T_FMT, rname, apr_time_now() ); } // it's set to something reasonable - note we're still setting // a new cookie, even when there's no expires requested, because // we don't know if there's an expires on the /current/ cookie. // this could be added, but this seems to work for now. } else { // XXX we use a apr_pstrndup instead, so we can't overflow // the buffer if we get sent garbage // The return value is a sprintf( new_cookie_value, "%s", apr_pstrndup( r->pool, cur_cookie_value, _MAX_COOKIE_LENGTH ) ); } // it's either carbage, or not set; either way, // we need to generate a new one } else { // if we have some sort of library that's generating the // UID, call that with the cookie we would be setting if( _EXTERNAL_UID_FUNCTION ) { char ts[ _MAX_COOKIE_LENGTH ]; sprintf( ts, "%" APR_TIME_T_FMT, apr_time_now() ); gen_uid( new_cookie_value, ts, rname ); // otherwise, just set it } else { sprintf( new_cookie_value, "%s.%" APR_TIME_T_FMT, rname, apr_time_now() ); } } } _DEBUG && fprintf( stderr, "New cookie: %s\n", new_cookie_value ); /* Set the cookie in a note, for logging */ apr_table_setn(r->notes, dcfg->note_name, new_cookie_value); make_cookie(r, new_cookie_value, cur_cookie_value, (dnt_is_set && dcfg->comply_with_dnt) // should we use dnt expires? ); // We need to flush the stream for messages to appear right away. // Performing an fflush() in a production system is not good for // performance - don't do this for real. _DEBUG && fflush(stderr); return OK; /* We set our cookie */ }
static apr_status_t line_edit_filter(ap_filter_t* f, apr_bucket_brigade* bb) { int i, j; unsigned int match ; unsigned int nmatch = 10 ; ap_regmatch_t pmatch[10] ; const char* bufp; const char* subs ; apr_size_t bytes ; apr_size_t fbytes ; apr_size_t offs ; const char* buf ; const char* le = NULL ; const char* le_n ; const char* le_r ; char* fbuf ; apr_bucket* b = APR_BRIGADE_FIRST(bb) ; apr_bucket* b1 ; int found = 0 ; apr_status_t rv ; apr_bucket_brigade* bbline ; line_edit_cfg* cfg = ap_get_module_config(f->r->per_dir_config, &line_edit_module) ; rewriterule* rules = (rewriterule*) cfg->rewriterules->elts ; rewriterule* newrule; line_edit_ctx* ctx = f->ctx ; if (ctx == NULL) { /* check env to see if we're wanted, to give basic control with 2.0 */ buf = apr_table_get(f->r->subprocess_env, "LineEdit"); if (buf && f->r->content_type) { char* lcbuf = apr_pstrdup(f->r->pool, buf) ; char* lctype = apr_pstrdup(f->r->pool, f->r->content_type) ; char* c ; for (c = lcbuf; *c; ++c) if (isupper(*c)) *c = tolower(*c) ; for (c = lctype; *c; ++c) if (isupper(*c)) *c = tolower(*c) ; else if (*c == ';') { *c = 0 ; break ; } if (!strstr(lcbuf, lctype)) { /* don't filter this content type */ ap_filter_t* fnext = f->next ; ap_remove_output_filter(f) ; return ap_pass_brigade(fnext, bb) ; } } ctx = f->ctx = apr_palloc(f->r->pool, sizeof(line_edit_ctx)) ; ctx->bbsave = apr_brigade_create(f->r->pool, f->c->bucket_alloc) ; /* If we have any regex matches, we'll need to copy everything, so we * have null-terminated strings to parse. That's a lot of memory if * we're streaming anything big. So we'll use (and reuse) a local * subpool. Fall back to the request pool if anything bad happens. */ ctx->lpool = f->r->pool ; for (i = 0; i < cfg->rewriterules->nelts; ++i) { if ( rules[i].flags & M_REGEX ) { if (apr_pool_create(&ctx->lpool, f->r->pool) != APR_SUCCESS) { ctx->lpool = f->r->pool ; } break ; } } /* If we have env interpolation, we'll need a private copy of * our rewrite rules with this requests env. Otherwise we can * save processing time by using the original. * * If one ENV is found, we also have to copy all previous and * subsequent rules, even those with no interpolation. */ ctx->rewriterules = cfg->rewriterules; for (i = 0; i < cfg->rewriterules->nelts; ++i) { found |= (rules[i].flags & M_ENV) ; if ( found ) { if (ctx->rewriterules == cfg->rewriterules) { ctx->rewriterules = apr_array_make(f->r->pool, cfg->rewriterules->nelts, sizeof(rewriterule)); for (j = 0; j < i; ++j) { newrule = apr_array_push (((line_edit_ctx*)ctx)->rewriterules) ; newrule->from = rules[j].from; newrule->to = rules[j].to; newrule->flags = rules[j].flags; newrule->length = rules[j].length; } } /* this rule needs to be interpolated */ newrule = apr_array_push (((line_edit_ctx*)ctx)->rewriterules) ; newrule->from = rules[i].from; if (rules[i].flags & M_ENV) { newrule->to = interpolate_env(f->r, rules[i].to); } else { newrule->to = rules[i].to ; } newrule->flags = rules[i].flags; newrule->length = rules[i].length; } } /* for back-compatibility with Apache 2.0, set some protocol stuff */ apr_table_unset(f->r->headers_out, "Content-Length") ; apr_table_unset(f->r->headers_out, "Content-MD5") ; apr_table_unset(f->r->headers_out, "Accept-Ranges") ; } /* by now our rules are in ctx->rewriterules */ rules = (rewriterule*) ctx->rewriterules->elts ; /* bbline is what goes to the next filter, * so we (can) have a new one each time. */ bbline = apr_brigade_create(f->r->pool, f->c->bucket_alloc) ; /* first ensure we have no mid-line breaks that might be in the * middle of a search string causing us to miss it! At the same * time we split into lines to avoid pattern-matching over big * chunks of memory. */ while ( b != APR_BRIGADE_SENTINEL(bb) ) { if ( !APR_BUCKET_IS_METADATA(b) ) { if ( apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS ) { if ( bytes == 0 ) { APR_BUCKET_REMOVE(b) ; } else while ( bytes > 0 ) { switch (cfg->lineend) { case LINEEND_UNIX: le = memchr(buf, '\n', bytes) ; break ; case LINEEND_MAC: le = memchr(buf, '\r', bytes) ; break ; case LINEEND_DOS: /* Edge-case issue: if a \r\n spans buckets it'll get missed. * Not a problem for present purposes, but would be an issue * if we claimed to support pattern matching on the lineends. */ found = 0 ; le = memchr(buf+1, '\n', bytes-1) ; while ( le && !found ) { if ( le[-1] == '\r' ) { found = 1 ; } else { le = memchr(le+1, '\n', bytes-1 - (le+1 - buf)) ; } } if ( !found ) le = 0 ; break; case LINEEND_ANY: case LINEEND_UNSET: /* Edge-case notabug: if a \r\n spans buckets it'll get seen as * two line-ends. It'll insert the \n as a one-byte bucket. */ le_n = memchr(buf, '\n', bytes) ; le_r = memchr(buf, '\r', bytes) ; if ( le_n != NULL ) if ( le_n == le_r + sizeof(char)) le = le_n ; else if ( (le_r < le_n) && (le_r != NULL) ) le = le_r ; else le = le_n ; else le = le_r ; break; case LINEEND_NONE: le = 0 ; break; case LINEEND_CUSTOM: le = memchr(buf, cfg->lechar, bytes) ; break; } if ( le ) { /* found a lineend in this bucket. */ offs = 1 + ((unsigned int)le-(unsigned int)buf) / sizeof(char) ; apr_bucket_split(b, offs) ; bytes -= offs ; buf += offs ; b1 = APR_BUCKET_NEXT(b) ; APR_BUCKET_REMOVE(b); /* Is there any previous unterminated content ? */ if ( !APR_BRIGADE_EMPTY(ctx->bbsave) ) { /* append this to any content waiting for a lineend */ APR_BRIGADE_INSERT_TAIL(ctx->bbsave, b) ; rv = apr_brigade_pflatten(ctx->bbsave, &fbuf, &fbytes, f->r->pool) ; /* make b a new bucket of the flattened stuff */ b = apr_bucket_pool_create(fbuf, fbytes, f->r->pool, f->r->connection->bucket_alloc) ; /* bbsave has been consumed, so clear it */ apr_brigade_cleanup(ctx->bbsave) ; } /* b now contains exactly one line */ APR_BRIGADE_INSERT_TAIL(bbline, b); b = b1 ; } else { /* no lineend found. Remember the dangling content */ APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(ctx->bbsave, b); bytes = 0 ; } } /* while bytes > 0 */ } else { /* bucket read failed - oops ! Let's remove it. */ APR_BUCKET_REMOVE(b); } } else if ( APR_BUCKET_IS_EOS(b) ) { /* If there's data to pass, send it in one bucket */ if ( !APR_BRIGADE_EMPTY(ctx->bbsave) ) { rv = apr_brigade_pflatten(ctx->bbsave, &fbuf, &fbytes, f->r->pool) ; b1 = apr_bucket_pool_create(fbuf, fbytes, f->r->pool, f->r->connection->bucket_alloc) ; APR_BRIGADE_INSERT_TAIL(bbline, b1); } apr_brigade_cleanup(ctx->bbsave) ; /* start again rather than segfault if a seriously buggy * filter in front of us sent a bogus EOS */ f->ctx = NULL ; /* move the EOS to the new brigade */ APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(bbline, b); } else { /* chop flush or unknown metadata bucket types */ apr_bucket_delete(b); } /* OK, reset pointer to what's left (since we're not in a for-loop) */ b = APR_BRIGADE_FIRST(bb) ; } /* OK, now we have a bunch of complete lines in bbline, * so we can apply our edit rules */ /* When we get a match, we split the line into before+match+after. * To flatten that back into one buf every time would be inefficient. * So we treat it as three separate bufs to apply future rules. * * We can only reasonably do that by looping over buckets *inside* * the loop over rules. * * That means concepts like one-match-per-line or start-of-line-only * won't work, except for the first rule. So we won't pretend. */ for (i = 0; i < ctx->rewriterules->nelts; ++i) { for ( b = APR_BRIGADE_FIRST(bbline) ; b != APR_BRIGADE_SENTINEL(bbline) ; b = APR_BUCKET_NEXT(b) ) { if ( !APR_BUCKET_IS_METADATA(b) && (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS)) { if ( rules[i].flags & M_REGEX ) { bufp = apr_pstrmemdup(ctx->lpool, buf, bytes) ; while ( ! ap_regexec(rules[i].from.r, bufp, nmatch, pmatch, 0) ) { match = pmatch[0].rm_so ; subs = ap_pregsub(f->r->pool, rules[i].to, bufp, nmatch, pmatch) ; apr_bucket_split(b, match) ; b1 = APR_BUCKET_NEXT(b) ; apr_bucket_split(b1, pmatch[0].rm_eo - match) ; b = APR_BUCKET_NEXT(b1) ; apr_bucket_delete(b1) ; b1 = apr_bucket_pool_create(subs, strlen(subs), f->r->pool, f->r->connection->bucket_alloc) ; APR_BUCKET_INSERT_BEFORE(b, b1) ; bufp += pmatch[0].rm_eo ; } } else { bufp = buf ; while (subs = apr_strmatch(rules[i].from.s, bufp, bytes), subs != NULL) { match = ((unsigned int)subs - (unsigned int)bufp) / sizeof(char) ; bytes -= match ; bufp += match ; apr_bucket_split(b, match) ; b1 = APR_BUCKET_NEXT(b) ; apr_bucket_split(b1, rules[i].length) ; b = APR_BUCKET_NEXT(b1) ; apr_bucket_delete(b1) ; bytes -= rules[i].length ; bufp += rules[i].length ; b1 = apr_bucket_immortal_create(rules[i].to, strlen(rules[i].to), f->r->connection->bucket_alloc) ; APR_BUCKET_INSERT_BEFORE(b, b1) ; } } } } /* If we used a local pool, clear it now */ if ( (ctx->lpool != f->r->pool) && (rules[i].flags & M_REGEX) ) { apr_pool_clear(ctx->lpool) ; } } /* now pass it down the chain */ rv = ap_pass_brigade(f->next, bbline) ; /* if we have leftover data, don't risk it going out of scope */ for ( b = APR_BRIGADE_FIRST(ctx->bbsave) ; b != APR_BRIGADE_SENTINEL(ctx->bbsave) ; b = APR_BUCKET_NEXT(b)) { apr_bucket_setaside(b, f->r->pool) ; } return rv ; }
static apr_status_t google_analytics_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) { request_rec *r = f->r; google_analytics_filter_ctx *ctx = f->ctx; google_analytics_filter_config *c; apr_bucket *b = APR_BRIGADE_FIRST(bb); apr_size_t bytes; apr_size_t fbytes; apr_size_t offs; const char *buf; const char *le = NULL; const char *le_n; const char *le_r; const char *bufp; const char *subs; unsigned int match; apr_bucket *b1; char *fbuf; int found = 0; apr_status_t rv; apr_bucket_brigade *bbline; // サブリクエストならなにもしない if (r->main) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } c = ap_get_module_config(r->per_dir_config, &google_analytics_module); if (ctx == NULL) { ctx = f->ctx = apr_pcalloc(r->pool, sizeof(google_analytics_filter_ctx)); ctx->bbsave = apr_brigade_create(r->pool, f->c->bucket_alloc); } // length かわってしまうので unset で OK? apr_table_unset(r->headers_out, "Content-Length"); apr_table_unset(r->headers_out, "Content-MD5"); apr_table_unset(r->headers_out, "Accept-Ranges"); apr_table_unset(r->headers_out, "ETag"); bbline = apr_brigade_create(r->pool, f->c->bucket_alloc); // 改行毎なbucketに編成しなおす while ( b != APR_BRIGADE_SENTINEL(bb) ) { if ( !APR_BUCKET_IS_METADATA(b) ) { if ( apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS ) { if ( bytes == 0 ) { APR_BUCKET_REMOVE(b); } else { while ( bytes > 0 ) { le_n = memchr(buf, '\n', bytes); le_r = memchr(buf, '\r', bytes); if ( le_n != NULL ) { if ( le_n == le_r + sizeof(char)) { le = le_n; } else if ( (le_r < le_n) && (le_r != NULL) ) { le = le_r; } else { le = le_n; } } else { le = le_r; } if ( le ) { offs = 1 + ((unsigned int)le-(unsigned int)buf) / sizeof(char); apr_bucket_split(b, offs); bytes -= offs; buf += offs; b1 = APR_BUCKET_NEXT(b); APR_BUCKET_REMOVE(b); if ( !APR_BRIGADE_EMPTY(ctx->bbsave) ) { APR_BRIGADE_INSERT_TAIL(ctx->bbsave, b); rv = apr_brigade_pflatten(ctx->bbsave, &fbuf, &fbytes, r->pool); b = apr_bucket_pool_create(fbuf, fbytes, r->pool, r->connection->bucket_alloc); apr_brigade_cleanup(ctx->bbsave); } APR_BRIGADE_INSERT_TAIL(bbline, b); b = b1; } else { APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(ctx->bbsave, b); bytes = 0; } } /* while bytes > 0 */ } } else { APR_BUCKET_REMOVE(b); } } else if ( APR_BUCKET_IS_EOS(b) ) { if ( !APR_BRIGADE_EMPTY(ctx->bbsave) ) { rv = apr_brigade_pflatten(ctx->bbsave, &fbuf, &fbytes, r->pool); b1 = apr_bucket_pool_create(fbuf, fbytes, r->pool, r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bbline, b1); } apr_brigade_cleanup(ctx->bbsave); f->ctx = NULL; APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(bbline, b); } else { apr_bucket_delete(b); } b = APR_BRIGADE_FIRST(bb); } // 改行毎なbucketをまわす for ( b = APR_BRIGADE_FIRST(bbline); b != APR_BRIGADE_SENTINEL(bbline); b = APR_BUCKET_NEXT(b) ) { if ( !APR_BUCKET_IS_METADATA(b) && (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS)) { bufp = buf; if (ap_regexec(regex_tag_exists, bufp, 0, NULL, 0) == 0) { break; } subs = apr_strmatch(pattern_body_end_tag, bufp, bytes); if (subs != NULL) { match = ((unsigned int)subs - (unsigned int)bufp) / sizeof(char); bytes -= match; bufp += match; apr_bucket_split(b, match); b1 = APR_BUCKET_NEXT(b); apr_bucket_split(b1, body_end_tag_length); b = APR_BUCKET_NEXT(b1); apr_bucket_delete(b1); bytes -= body_end_tag_length; bufp += body_end_tag_length; b1 = apr_bucket_immortal_create(c->replace, strlen(c->replace), r->connection->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, b1); } } } rv = ap_pass_brigade(f->next, bbline); for ( b = APR_BRIGADE_FIRST(ctx->bbsave); b != APR_BRIGADE_SENTINEL(ctx->bbsave); b = APR_BUCKET_NEXT(b)) { apr_bucket_setaside(b, r->pool); } return rv; }
static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter) { ap_filter_provider_t *provider; const char *str = NULL; char *str1; int match; unsigned int proto_flags; request_rec *r = f->r; harness_ctx *ctx = f->ctx; provider_ctx *pctx; mod_filter_ctx *rctx = ap_get_module_config(r->request_config, &filter_module); /* Check registered providers in order */ for (provider = filter->providers; provider; provider = provider->next) { match = 1; switch (provider->dispatch) { case REQUEST_HEADERS: str = apr_table_get(r->headers_in, provider->value); break; case RESPONSE_HEADERS: str = apr_table_get(r->headers_out, provider->value); break; case SUBPROCESS_ENV: str = apr_table_get(r->subprocess_env, provider->value); break; case CONTENT_TYPE: str = r->content_type; break; case HANDLER: str = r->handler; break; } /* treat nulls so we don't have to check every strcmp individually * Not sure if there's anything better to do with them */ if (!str) { if (provider->match_type == DEFINED && provider->match.string) { match = 0; } } else if (!provider->match.string) { match = 0; } else { /* Now we have no nulls, so we can do string and regexp matching */ switch (provider->match_type) { case STRING_MATCH: if (strcasecmp(str, provider->match.string)) { match = 0; } break; case STRING_CONTAINS: str1 = apr_pstrdup(r->pool, str); ap_str_tolower(str1); if (!strstr(str1, provider->match.string)) { match = 0; } break; case REGEX_MATCH: if (ap_regexec(provider->match.regex, str, 0, NULL, 0) == AP_REG_NOMATCH) { match = 0; } break; case INT_EQ: if (atoi(str) != provider->match.number) { match = 0; } break; case INT_LT: if (atoi(str) < provider->match.number) { match = 0; } break; case INT_LE: if (atoi(str) <= provider->match.number) { match = 0; } break; case INT_GT: if (atoi(str) > provider->match.number) { match = 0; } break; case INT_GE: if (atoi(str) >= provider->match.number) { match = 0; } break; case DEFINED: /* we already handled this:-) */ break; } } if (match != provider->not) { /* condition matches this provider */ #ifndef NO_PROTOCOL /* check protocol * * FIXME: * This is a quick hack and almost certainly buggy. * The idea is that by putting this in mod_filter, we relieve * filter implementations of the burden of fixing up HTTP headers * for cases that are routinely affected by filters. * * Default is ALWAYS to do nothing, so as not to tread on the * toes of filters which want to do it themselves. * */ proto_flags = provider->frec->proto_flags; /* some specific things can't happen in a proxy */ if (r->proxyreq) { if (proto_flags & AP_FILTER_PROTO_NO_PROXY) { /* can't use this provider; try next */ continue; } if (proto_flags & AP_FILTER_PROTO_TRANSFORM) { str = apr_table_get(r->headers_out, "Cache-Control"); if (str) { str1 = apr_pstrdup(r->pool, str); ap_str_tolower(str1); if (strstr(str1, "no-transform")) { /* can't use this provider; try next */ continue; } } apr_table_addn(r->headers_out, "Warning", apr_psprintf(r->pool, "214 %s Transformation applied", r->hostname)); } } /* things that are invalidated if the filter transforms content */ if (proto_flags & AP_FILTER_PROTO_CHANGE) { apr_table_unset(r->headers_out, "Content-MD5"); apr_table_unset(r->headers_out, "ETag"); if (proto_flags & AP_FILTER_PROTO_CHANGE_LENGTH) { apr_table_unset(r->headers_out, "Content-Length"); } } /* no-cache is for a filter that has different effect per-hit */ if (proto_flags & AP_FILTER_PROTO_NO_CACHE) { apr_table_unset(r->headers_out, "Last-Modified"); apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); } if (proto_flags & AP_FILTER_PROTO_NO_BYTERANGE) { apr_table_unset(r->headers_out, "Accept-Ranges"); } else if (rctx && rctx->range) { /* restore range header we saved earlier */ apr_table_setn(r->headers_in, "Range", rctx->range); rctx->range = NULL; } #endif for (pctx = ctx->init_ctx; pctx; pctx = pctx->next) { if (pctx->provider == provider) { ctx->fctx = pctx->ctx ; } } ctx->func = provider->frec->filter_func.out_func; return 1; } } /* No provider matched */ return 0; }
static int dosdetector_handler(request_rec *r) { //DEBUGLOG("dosdetector_handler is called"); dosdetector_dir_config *cfg = (dosdetector_dir_config *) ap_get_module_config(r->per_dir_config, &dosdetector_module); if(cfg->detection) return DECLINED; if (!ap_is_initial_req(r)) return DECLINED; //char **ignore_contenttype = (char **) cfg->ignore_contenttype->elts; const char *content_type; const char *address_tmp; const char *address = NULL; int i; content_type = ap_sub_req_lookup_uri(r->uri, r, NULL)->content_type; if (!content_type) { #if (AP_SERVER_MINORVERSION_NUMBER > 2) content_type = DefaultContentType; #else content_type = ap_default_type(r); #endif } if (cfg->forwarded){ if ((address_tmp = apr_table_get(r->headers_in, "X-Forwarded-For")) != NULL){ const char *i = address_tmp; while(*i != 0 && *i != ',') i++; address = apr_pstrndup(r->pool, address_tmp, i - address_tmp); } } if (address == NULL) { #if (AP_SERVER_MINORVERSION_NUMBER > 2) address = r->connection->client_ip; #else address = r->connection->remote_ip; #endif } ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; ap_regex_t **contenttype_regexp = (ap_regex_t **) cfg->contenttype_regexp->elts; for (i = 0; i < cfg->contenttype_regexp->nelts; i++) { if(!ap_regexec(contenttype_regexp[i], content_type, AP_MAX_REG_MATCH, regmatch, 0)){ //ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, 0, "ignoring content-type: %s", content_type); return OK; } } DEBUGLOG("dosdetector: processing content-type: %s", content_type); struct in_addr addr; if(!cfg->forwarded) { #if (AP_SERVER_MINORVERSION_NUMBER > 2) addr = r->connection->client_addr->sa.sin.sin_addr; #else addr = r->connection->remote_addr->sa.sin.sin_addr; #endif } if(cfg->forwarded || addr.s_addr == 0){ if (inet_aton(address, &addr) == 0) { TRACELOG("dosdetector: '%s' is not a valid IP addresss", address); return DECLINED; } } if (lock) apr_global_mutex_lock(lock); client_t *client = get_client(client_list, addr, cfg->period); if (lock) apr_global_mutex_unlock(lock); #ifdef _DEBUG int last_count = client->count; #endif count_increment(client, cfg->threshold); DEBUGLOG("dosdetector: %s, count: %d -> %d, interval: %d", address, last_count, client->count, (int)client->interval); //DEBUGLOG("dosdetector: %s, count: %d -> %d, interval: %d on tid %d, pid %d", address, last_count, client->count, (int)client->interval, gettid(), getpid()); time_t now = time((time_t *)0); if(client->suspected > 0 && client->suspected + cfg->ban_period > now){ apr_table_setn(r->subprocess_env, "SuspectDoS", "1"); //apr_table_setn(r->notes, "SuspectDoS", "1"); DEBUGLOG("dosdetector: '%s' has been still suspected as DoS attack! (suspected %d sec ago)", address, now - client->suspected); if(client->count > cfg->ban_threshold){ if(client->hard_suspected == 0) TRACELOG("dosdetector: '%s' is suspected as Hard DoS attack! (counter: %d)", address, client->count); client->hard_suspected = now; apr_table_setn(r->subprocess_env, "SuspectHardDoS", "1"); //apr_table_setn(r->notes, "SuspectHardDoS", "1"); } } else { if(client->suspected > 0){ client->suspected = 0; client->hard_suspected = 0; client->count = 0; } //int last_count = client->count; //client->count = client->count - client->interval * cfg->threshold; //if(client->count < 0) // client->count = 0; //client->count ++; //DEBUGLOG("client address: %s, count: %d -> %d, interval: %d", address, last_count, client->count, client->interval); if(client->count > cfg->threshold){ client->suspected = now; apr_table_setn(r->subprocess_env, "SuspectDoS", "1"); //apr_table_setn(r->notes, "SuspectDoS", "1"); TRACELOG("dosdetector: '%s' is suspected as DoS attack! (counter: %d)", address, client->count); } } return DECLINED; }