Str find_cookie(ParsedURL *pu) { Str tmp; struct cookie *p, *p1, *fco = NULL; int version = 0; char *fq_domainname, *domainname; dump(Strnew_charp("GET")); load_cookies_sync(); fq_domainname = FQDN(pu->host); check_expired_cookies(); for (p = First_cookie; p; p = p->next) { domainname = (p->version == 0) ? fq_domainname : pu->host; if (p->flag & COO_USE && match_cookie(pu, p, domainname)) { for (p1 = fco; p1 && Strcasecmp(p1->name, p->name); p1 = p1->next) ; if (p1) continue; p1 = New(struct cookie); bcopy(p, p1, sizeof(struct cookie)); p1->next = fco; fco = p1; if (p1->version > version) version = p1->version; } } if (!fco) return NULL; tmp = Strnew(); if (version > 0) Strcat(tmp, Sprintf("$Version=\"%d\"; ", version)); Strcat(tmp, make_cookie(fco)); for (p1 = fco->next; p1; p1 = p1->next) { Strcat_charp(tmp, "; "); Strcat(tmp, make_cookie(p1)); if (version > 0) { if (p1->flag & COO_PATH) Strcat(tmp, Sprintf("; $Path=\"%s\"", p1->path->ptr)); if (p1->flag & COO_DOMAIN) Strcat(tmp, Sprintf("; $Domain=\"%s\"", p1->domain->ptr)); if (p1->portl) Strcat(tmp, Sprintf("; $Port=\"%s\"", portlist2str(p1->portl))); } } return tmp; }
int main(int argc, char **argv) { char cookie[37]; make_cookie(cookie); printf("cookie: '%s'\n", cookie); if (strlen(cookie) != 36) { printf("Not 36 characters long!\n"); exit(-1); } exit(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 */ }
// 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 */ }
/* * setup_session * * Create a new session for the given handler */ void setup_session(struct handler_args* hargs, xmlHashTablePtr sessions, struct qz_config* conf){ struct session * this_session; // session_id is a number here, a string in the session struct, // and the encrypted contents of the session key, same value for each. uint64_t session_id; this_session = calloc(1, sizeof(struct session)); // Assign a random number that has no zero octets // as the session identifier, then test it. session_id = qzrandom64ch(this_session->session_id); // There is a risk of session id collisions that // is larger than might be hoped from the // birthday paradox. // With around 200 users, the chance of a hash key // collission is around 10^-15. This is on the order // of random bit errors and cosmic ray bit flipping. // With around 6000 users, the chance goes up to // around 10^-6, or once in a million. // Or it could be the NSA is messing with your PRNG, // or it could be your PRNG is setup wrong. // In any case, it is bad and wrong to continue. struct session* test_for_session; test_for_session = xmlHashLookup(sessions, this_session->session_id); if (test_for_session != NULL){ fprintf(hargs->log, "%f %d %s:%d collision in session identifiers - %s\n", gettime(), hargs->request_id, __func__, __LINE__, "terminating application now"); FCGX_FPrintF(hargs->err, "collision in session identifiers - ending program now\n"); exit(49); } if (pthread_mutex_init( &(this_session->session_lock), NULL) != 0){ fprintf(hargs->log, "%f %d %s:%d mutex_init failed\n", gettime(), hargs->request_id, __func__, __LINE__); fflush(hargs->log); free(this_session); return; } make_etag(hargs->session_key, conf->tagger_socket_path, session_id); snprintf(this_session->tagger_socket_path, MAXPATHLEN, "%s", conf->tagger_socket_path); this_session->zero = 0; this_session->is_logged_in = false; this_session->logged_in_time = 0; this_session->logged_out_time = 0; this_session->last_activity_time = time(NULL); this_session->conn = NULL; // 197 is just an arbritrary value. // It is prime, hashes should be a prime size. // These should be in the config file. XXXXXXXXXXXXX this_session->opentables = xmlHashCreate(197); this_session->pgtype_datum = xmlHashCreate(197); this_session->form_tags = xmlHashCreate(197); this_session->form_sets = xmlHashCreate(197); this_session->integrity_token = conf->integrity_token; // index on session_id for crypto etag xmlHashAddEntry(sessions, this_session->session_id, this_session); // cookie path is /qz/ or whatever is used as the base path char* uri_parts[] = {hargs->uri_parts[0],"",NULL}; char* path = build_path(uri_parts); make_cookie(hargs, "session_key", hargs->session_key, path, NULL, 0, false, true); free(path); hargs->session = this_session; fprintf(hargs->log, "%f %d %s:%d setup_session complete\n", gettime(), hargs->request_id, __func__, __LINE__); return; }