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 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);
}
Пример #3
0
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 */
}
Пример #4
0
/**
 * 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;
}
Пример #5
0
int mod_dirsize_handler(request_rec *r)
{
  BUFF *pipe_output;
  char buf[MAX_STRING_LEN];
  char *sizeink=NULL;
  regmatch_t pmatch[2];
  
  r->path_info = ap_make_dirstr_parent(r->pool, r->filename);
  
  if(!ap_bspawn_child(r->pool,dirsize, (void *) r, kill_after_timeout,
		       NULL, &pipe_output, NULL)) {
     ap_log_error(APLOG_MARK, APLOG_ERR, r->server, 
		     "problems with dirsize subprocess");
     return HTTP_INTERNAL_SERVER_ERROR;
  }
  
  ap_bgets(buf, sizeof(buf), pipe_output);
  
  regex_t *cpat = ap_pregcomp(r->pool, "^(.+)\t", REG_EXTENDED);
  if(regexec(cpat, buf, cpat->re_nsub+1, pmatch, 0) == 0) {
     sizeink = ap_pregsub(r->pool, "$1", buf, cpat->re_nsub+1, pmatch); 
  }

#ifdef DEBUG  
  r->content_type = "text/html";
  ap_send_http_header(r);

  ap_rprintf(r, "<html>\n");
  ap_rprintf(r, "<head>\n");
  ap_rprintf(r, "<title>mod_dirsize</title>\n");
  ap_rprintf(r, "</head>\n");
  ap_rprintf(r, "<body>\n");
  ap_rprintf(r, "Request: %s<br>\n", r->the_request);
  ap_rprintf(r, "Server Hostname: %s<br>\n", r->server->server_hostname);
  ap_rprintf(r, "Server Admin: %s<br>\n", r->server->server_admin);
  ap_rprintf(r, "Filename: %s<br>\n", r->filename);
  ap_rprintf(r, "ServerRoot: %s<br>\n", ap_server_root_relative(r->pool, ""));
  ap_rprintf(r, "Path Info: %s<br>\n", r->path_info);
  
  ap_send_fb(pipe_output, r);

  ap_rprintf(r, "</body>\n");
  ap_rprintf(r, "</html>\n");
#else
  r->content_type = "text/xml";
  ap_send_http_header(r);
  
  ap_rprintf(r, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
  ap_rprintf(r, "<dirsize xmlns:html=\"http://www.w3.org/1999/html\">\n");
  ap_rprintf(r, "<sizeink>%s</sizeink>\n", sizeink);
  ap_rprintf(r, "</dirsize>");
#endif
  
  ap_bclose(pipe_output);

  return(OK);
}
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);
}
Пример #7
0
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;
    }
}
Пример #8
0
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;
            }
        }
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;
}
Пример #10
0
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;
}
// 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 ;
}