Apply by doing: cd /usr/src patch -p0 < 008_httpd.patch And then rebuild and install httpd and it's modules: cd usr.sbin/httpd make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper depend make -f Makefile.bsd-wrapper make -f Makefile.bsd-wrapper install If httpd had been started, you might want to run apachectl stop apachectl start afterwards. Index: usr.sbin/httpd/src/main/http_main.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/src/main/http_main.c,v retrieving revision 1.25.2.1 retrieving revision 1.25.2.2 diff -u -p -r1.25.2.1 -r1.25.2.2 --- usr.sbin/httpd/src/main/http_main.c 8 Nov 2002 00:04:04 -0000 1.25.2.1 +++ usr.sbin/httpd/src/main/http_main.c 24 Feb 2003 02:09:38 -0000 1.25.2.2 @@ -1,4 +1,4 @@ -/* $OpenBSD: http_main.c,v 1.25.2.1 2002/11/08 00:04:04 jason Exp $ */ +/* $OpenBSD: http_main.c,v 1.25.2.2 2003/02/24 02:09:38 margarida Exp $ */ /* ==================================================================== * The Apache Software License, Version 1.1 @@ -5176,6 +5176,7 @@ static void standalone_main(int argc, ch } ap_set_version(); /* create our server_version string */ ap_init_modules(pconf, server_conf); + ap_init_etag(pconf); version_locked++; /* no more changes to server_version */ if(!is_graceful && !is_chrooted) Index: usr.sbin/httpd/src/main/http_protocol.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/src/main/http_protocol.c,v retrieving revision 1.13 retrieving revision 1.13.2.1 diff -u -p -r1.13 -r1.13.2.1 --- usr.sbin/httpd/src/main/http_protocol.c 19 Jul 2002 21:31:16 -0000 1.13 +++ usr.sbin/httpd/src/main/http_protocol.c 24 Feb 2003 02:09:39 -0000 1.13.2.1 @@ -1,3 +1,4 @@ +/* $OpenBSD: http_protocol.c,v 1.13.2.1 2003/02/24 02:09:39 margarida Exp $ */ /* ==================================================================== * The Apache Software License, Version 1.1 * @@ -76,6 +77,7 @@ #include "util_date.h" /* For parseHTTPdate and BAD_DATE */ #include #include "http_conf_globals.h" +#include "ap_sha1.h" #define SET_BYTES_SENT(r) \ do { if (r->sent_bodyct) \ @@ -276,7 +278,10 @@ static int byterange_boundary(request_re API_EXPORT(int) ap_set_byterange(request_rec *r) { const char *range, *if_range, *match; + char *bbuf, *b; + u_int32_t rbuf[12]; /* 48 bytes yields 64 base64 chars */ long length, start, end, one_start = 0, one_end = 0; + size_t u; int ranges, empty; if (!r->clength || r->assbackwards) @@ -322,8 +327,20 @@ API_EXPORT(int) ap_set_byterange(request * caller will perform if we return 1. */ r->range = range; - r->boundary = ap_psprintf(r->pool, "%lx%lx", - r->request_time, (long) getpid()); + for (u = 0; u < sizeof(rbuf)/sizeof(rbuf[0]); u++) + rbuf[u] = htonl(arc4random()); + + bbuf = ap_palloc(r->pool, ap_base64encode_len(sizeof(rbuf))); + ap_base64encode(bbuf, (const unsigned char *)rbuf, sizeof(rbuf)); + for (b = bbuf; *b != '\0'; b++) { + if (((b - bbuf) + 1) % 7 == 0) + *b = '-'; + else if (!isalnum(*b)) + *b = 'a'; + } + + r->boundary = bbuf; + length = 0; ranges = 0; empty = 1; @@ -646,7 +663,7 @@ API_EXPORT(int) ap_meets_conditions(requ * could be modified again in as short an interval. We rationalize the * modification time we're given to keep it from being in the future. */ -API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak) +API_EXPORT(char *) ap_make_etag_orig(request_rec *r, int force_weak) { char *etag; char *weak; @@ -3106,4 +3123,164 @@ API_EXPORT(void) ap_send_error_response( ap_kill_timeout(r); ap_finalize_request_protocol(r); ap_rflush(r); +} + +/* + * The shared hash context, copies of which are used by all children for + * etag generation. ap_init_etag() must be called once before all the + * children are created. We use a secret hash initialization value + * so that people can't brute-force inode numbers. + */ +static AP_SHA1_CTX baseCtx; + +int ap_create_etag_state(pool *pconf) +{ + u_int32_t rnd; + unsigned int u; + int fd; + const char* filename; + + filename = ap_server_root_relative(pconf, "logs/etag-state"); + ap_server_strip_chroot(filename, 0); + + if ((fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, 0640)) == + -1) { + ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, + "could not create %s", filename); + exit(-1); + } + + if (fchown(fd, -1, ap_group_id) == -1) { + ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, + "could not chown %s", filename); + exit(-1); + } + + /* generate random bytes and write them */ + for (u = 0; u < 4; u++) { + rnd = arc4random(); + if (write(fd, &rnd, sizeof(rnd)) == -1) { + ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, + "could not write to %s", filename); + exit(-1); + } + } + + close (fd); +} + +API_EXPORT(void) ap_init_etag(pool *pconf) +{ + if (ap_read_etag_state(pconf) == -1) { + ap_create_etag_state(pconf); + if (ap_read_etag_state(pconf) == -1) { + ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, + "could not initialize etag state"); + exit(-1); + } + } +} + +int ap_read_etag_state(pool *pconf) +{ + struct stat st; + u_int32_t rnd; + unsigned int u; + int fd; + const char* filename; + + ap_SHA1Init(&baseCtx); + + filename = ap_server_root_relative(pconf, "logs/etag-state"); + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, NULL, + "Initializing etag from %s", filename); + + ap_server_strip_chroot(filename, 0); + + if ((fd = open(filename, O_RDONLY|O_NOFOLLOW, 0640)) == -1) + return (-1); + + fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP); + fchown(fd, -1, ap_group_id); + + if (fstat(fd, &st) == -1) { + ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, + "could not fstat %s", filename); + exit(-1); + } + + if (st.st_size != sizeof(rnd)*4) { + return (-1); + } + + /* read 4 random 32-bit uints from file and update the hash context */ + for (u = 0; u < 4; u++) { + if (read(fd, &rnd, sizeof(rnd)) < sizeof(rnd)) + return (-1); + + ap_SHA1Update_binary(&baseCtx, (const unsigned char *)&rnd, + sizeof(rnd)); + } + + if (close(fd) == -1) { + ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, + "could not properly close %s", filename); + exit(-1); + } +} + +API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak) +{ + AP_SHA1_CTX hashCtx; + core_dir_config *cfg; + etag_components_t etag_bits; + int weak; + unsigned char md[SHA_DIGESTSIZE]; + unsigned int i; + + memcpy(&hashCtx, &baseCtx, sizeof(hashCtx)); + + cfg = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + etag_bits = (cfg->etag_bits & (~ cfg->etag_remove)) | cfg->etag_add; + if (etag_bits == ETAG_UNSET) + etag_bits = ETAG_BACKWARD; + + weak = ((r->request_time - r->mtime <= 1) || force_weak); + + if (r->finfo.st_mode != 0) { + if (etag_bits & ETAG_NONE) { + ap_table_setn(r->notes, "no-etag", "omit"); + return ""; + } + if (etag_bits & ETAG_INODE) { + ap_SHA1Update_binary(&hashCtx, + (const unsigned char *)&r->finfo.st_dev, + sizeof(r->finfo.st_dev)); + ap_SHA1Update_binary(&hashCtx, + (const unsigned char *)&r->finfo.st_ino, + sizeof(r->finfo.st_ino)); + } + if (etag_bits & ETAG_SIZE) + ap_SHA1Update_binary(&hashCtx, + (const unsigned char *)&r->finfo.st_size, + sizeof(r->finfo.st_size)); + if (etag_bits & ETAG_MTIME) + ap_SHA1Update_binary(&hashCtx, + (const unsigned char *)&r->mtime, + sizeof(r->mtime)); + } + else { + weak = 1; + ap_SHA1Update_binary(&hashCtx, (const unsigned char *)&r->mtime, + sizeof(r->mtime)); + } + ap_SHA1Final(md, &hashCtx); + return ap_psprintf(r->pool, "%s\"" + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "\"", weak ? "W/" : "", + md[0], md[1], md[2], md[3], md[4], md[5], md[6], md[7], + md[8], md[9], md[10], md[11], md[12], md[13], md[14], md[15], + md[16], md[17], md[18], md[19]); }