Apply by doing:
cd /usr/src
patch -p0 < 013_httpd.patch
And then rebuild and install httpd and its modules:
cd usr.sbin/httpd
make -f Makefile.bsd-wrapper obj
make -f Makefile.bsd-wrapper cleandir
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
before running "make install", and
apachectl start
afterwards.
+API_EXPORT(const char *) ap_auth_nonce(request_rec *r)
+{
+ core_dir_config *conf;
+ conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+ &core_module);
+ if (conf->ap_auth_nonce)
+ return conf->ap_auth_nonce;
+
+ /* Ideally we'd want to mix in some per-directory style
+ * information; as we are likely to want to detect replay
+ * across those boundaries and some randomness. But that
+ * is harder due to the adhoc nature of .htaccess memory
+ * structures, restarts and forks.
+ *
+ * But then again - you should use AuthDigestRealmSeed in your config
+ * file if you care. So the adhoc value should do.
+ */
+ return ap_psprintf(r->pool,"%pp%pp%pp%pp%pp",
+ (void *)&((r->connection->local_addr).sin_addr ),
+ (void *)ap_user_name,
+ (void *)ap_listeners,
+ (void *)ap_server_argv0,
+ (void *)ap_pid_fname);
+}
+
API_EXPORT(const char *) ap_default_type(request_rec *r)
{
core_dir_config *conf;
@@ -2834,6 +2862,28 @@ static const char *set_authname(cmd_parm
return NULL;
}
+/*
+ * Load an authorisation nonce into our location configuration, and
+ * force it to be in the 0-9/A-Z realm.
+ */
+static const char *set_authnonce (cmd_parms *cmd, void *mconfig, char *word1)
+{
+ core_dir_config *aconfig = (core_dir_config *)mconfig;
+ size_t i;
+
+ aconfig->ap_auth_nonce = ap_escape_quotes(cmd->pool, word1);
+
+ if (strlen(aconfig->ap_auth_nonce) > 510)
+ return "AuthDigestRealmSeed length limited to 510 chars for browser compatibility";
+
+ for(i=0;i<strlen(aconfig->ap_auth_nonce );i++)
+ if (!ap_isalnum(aconfig->ap_auth_nonce [i]))
+ return "AuthDigestRealmSeed limited to 0-9 and A-Z range for browser compatibility";
+
+ return NULL;
+}
+
+
#ifdef _OSD_POSIX /* BS2000 Logon Passwd file */
static const char *set_bs2000_account(cmd_parms *cmd, void *dummy, char *name)
{
@@ -3448,6 +3498,9 @@ static const command_rec core_cmds[] = {
"An HTTP authorization type (e.g., \"Basic\")" },
{ "AuthName", set_authname, NULL, OR_AUTHCFG, TAKE1,
"The authentication realm (e.g. \"Members Only\")" },
+{ "AuthDigestRealmSeed", set_authnonce, NULL, OR_AUTHCFG, TAKE1,
+ "An authentication token which should be different for each logical realm. "\
+ "A random value or the servers IP may be a good choise.\n" },
{ "Require", require, NULL, OR_AUTHCFG, RAW_ARGS,
"Selects which authenticated users or groups may access a protected space" },
{ "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1,
Index: usr.sbin/httpd/src/main/http_log.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/src/main/http_log.c,v
retrieving revision 1.14
retrieving revision 1.14.4.1
diff -u -p -r1.14 -r1.14.4.1
--- usr.sbin/httpd/src/main/http_log.c 21 Aug 2003 13:11:35 -0000 1.14
+++ usr.sbin/httpd/src/main/http_log.c 10 Jun 2004 02:09:05 -0000 1.14.4.1
@@ -316,6 +316,9 @@ static void log_error_core(const char *f
const char *fmt, va_list args)
{
char errstr[MAX_STRING_LEN];
+#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
+ char scratch[MAX_STRING_LEN];
+#endif
size_t len;
int save_errno = errno;
FILE *logf;
@@ -447,7 +450,14 @@ static void log_error_core(const char *f
}
#endif
API_EXPORT(void) ap_note_digest_auth_failure(request_rec *r)
{
+ /* We need to create a nonce which:
+ * a) changes all the time (see r->request_time)
+ * below and
+ * b) of which we can verify that it is our own
+ * fairly easily when it comes to veryfing
+ * the digest coming back in the response.
+ * c) and which as a whole should not
+ * be unlikely to be in use anywhere else.
+ */
+ char * nonce_prefix = ap_md5(r->pool,
+ (unsigned char *)
+ ap_psprintf(r->pool, "%s%lu",
+ ap_auth_nonce(r), r->request_time));
+
ap_table_setn(r->err_headers_out,
r->proxyreq == STD_PROXY ? "Proxy-Authenticate"
: "WWW-Authenticate",
- ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%lu\"",
- ap_auth_name(r), (unsigned long)r->request_time));
+ ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%s%lu\"",
+ ap_auth_name(r), nonce_prefix, r->request_time));
}
-static int ssl_rand_choosenum(int, int);
+static int ssl_rand_choosenum(int);
static int ssl_rand_feedfp(pool *, FILE *, int);
int ssl_rand_seed(server_rec *s, pool *p, ssl_rsctx_t nCtx, char *prefix)
@@ -155,7 +155,7 @@ int ssl_rand_seed(server_rec *s, pool *p
/*
* seed in some current state of the run-time stack (128 bytes)
*/
- n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1);
+ n = ssl_rand_choosenum(sizeof(stackdata)-128-1);
RAND_seed(stackdata+n, 128);
nDone += 128;
@@ -165,7 +165,7 @@ int ssl_rand_seed(server_rec *s, pool *p
if (ap_scoreboard_image != NULL && SCOREBOARD_SIZE > 16) {
if ((m = ((SCOREBOARD_SIZE / 2) - 1)) > 1024)
m = 1024;
- n = ssl_rand_choosenum(0, m);
+ n = ssl_rand_choosenum(m);
RAND_seed(((unsigned char *)ap_scoreboard_image)+n, m);
nDone += m;
}
@@ -210,17 +210,9 @@ static int ssl_rand_feedfp(pool *p, FILE
return nDone;
}
-static int ssl_rand_choosenum(int l, int h)
+/* Generate a random number in the range 1-h */
+static int ssl_rand_choosenum(int h)
{
- int i;
- char buf[50];
-
- srand((unsigned int)time(NULL));
- ap_snprintf(buf, sizeof(buf), "%.0f",
- (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
- i = atoi(buf)+1;
- if (i < l) i = l;
- if (i > h) i = h;
- return i;
+ return (int)(arc4random() / ((double)0xffffffffU + 1) * h + 1);
}
+/* Check that a given nonce is actually one which was
+ * issued by this server in the right context.
+ */
+static int check_nonce(pool *p, const char *prefix, const char *nonce) {
+ char *timestamp = (char *)nonce + 2 * MD5_DIGESTSIZE;
+ char *md5;
+
+ if (strlen(nonce) < MD5_DIGESTSIZE)
+ return AUTH_REQUIRED;
+
+ md5 = ap_md5(p, (unsigned char *)ap_pstrcat(p, prefix, timestamp, NULL));
+
+ return strncmp(md5, nonce, 2 * MD5_DIGESTSIZE);
+}
+
+/* Check the digest itself.
+ */
static char *find_digest(request_rec *r, digest_header_rec * h, char *a1)
{
return ap_md5(r->pool,
@@ -355,6 +372,15 @@ static int authenticate_digest_user(requ
if (!sec->pwfile)
return DECLINED;
+
+ /* Check that the nonce was one we actually issued. */
+ if (check_nonce(r->pool, ap_auth_nonce(r), response->nonce)) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Client is using a nonce which was not issued by "
+ "this server for this context: %s", r->uri);
+ ap_note_digest_auth_failure(r);
+ return AUTH_REQUIRED;
+ }
if (!(a1 = get_hash(r, c->user, sec->pwfile))) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,