xref: /lighttpd1.4/src/mod_auth.c (revision e11f72b1)
1 #include "first.h"
2 
3 #include "base.h"
4 #include "plugin.h"
5 #include "http_auth.h"
6 #include "http_header.h"
7 #include "log.h"
8 
9 #include "sys-crypto.h" /* USE_OPENSSL_CRYPTO */
10 #ifdef USE_OPENSSL_CRYPTO
11 #include <openssl/sha.h>
12 #endif
13 
14 #include <stdlib.h>
15 #include <string.h>
16 
17 /**
18  * auth framework
19  */
20 
21 typedef struct {
22     const http_auth_backend_t *auth_backend;
23     const array *auth_require;
24     unsigned int auth_extern_authn;
25 } plugin_config;
26 
27 typedef struct {
28     PLUGIN_DATA;
29     plugin_config defaults;
30     plugin_config conf;
31 } plugin_data;
32 
33 static handler_t mod_auth_check_basic(request_st *r, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
34 static handler_t mod_auth_check_digest(request_st *r, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
35 static handler_t mod_auth_check_extern(request_st *r, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
36 
37 INIT_FUNC(mod_auth_init) {
38 	static const http_auth_scheme_t http_auth_scheme_basic  = { "basic",  mod_auth_check_basic,  NULL };
39 	static const http_auth_scheme_t http_auth_scheme_digest = { "digest", mod_auth_check_digest, NULL };
40 	static const http_auth_scheme_t http_auth_scheme_extern = { "extern", mod_auth_check_extern, NULL };
41 	plugin_data *p;
42 
43 	/* register http_auth_scheme_* */
44 	http_auth_scheme_set(&http_auth_scheme_basic);
45 	http_auth_scheme_set(&http_auth_scheme_digest);
46 	http_auth_scheme_set(&http_auth_scheme_extern);
47 
48 	p = calloc(1, sizeof(*p));
49 
50 	return p;
51 }
52 
53 FREE_FUNC(mod_auth_free) {
54     plugin_data * const p = p_d;
55     if (NULL == p->cvlist) return;
56     /* (init i to 0 if global context; to 1 to skip empty global context) */
57     for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
58         config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
59         for (; -1 != cpv->k_id; ++cpv) {
60             if (cpv->vtype != T_CONFIG_LOCAL || NULL == cpv->v.v) continue;
61             switch (cpv->k_id) {
62               case 1: /* auth.require */
63                 array_free(cpv->v.v);
64                 break;
65               default:
66                 break;
67             }
68         }
69     }
70 }
71 
72 /* data type for mod_auth structured data
73  * (parsed from auth.require array of strings) */
74 typedef struct {
75     DATA_UNSET;
76     http_auth_require_t *require;
77 } data_auth;
78 
79 static void data_auth_free(data_unset *d)
80 {
81     data_auth * const dauth = (data_auth *)d;
82     free(dauth->key.ptr);
83     http_auth_require_free(dauth->require);
84     free(dauth);
85 }
86 
87 static data_auth *data_auth_init(void)
88 {
89     static const struct data_methods fn = {
90       NULL, /* copy must not be called on this data */
91       data_auth_free,
92       NULL, /* insert_dup must not be called on this data */
93       NULL  /* print must not be called on this data */
94     };
95     data_auth * const dauth = calloc(1, sizeof(*dauth));
96     force_assert(NULL != dauth);
97     dauth->type       = TYPE_OTHER;
98     dauth->fn         = &fn;
99 
100     dauth->require = http_auth_require_init();
101 
102     return dauth;
103 }
104 
105 static int mod_auth_algorithm_parse(http_auth_info_t *ai, const char *s) {
106     size_t len;
107     if (NULL == s) {
108         ai->dalgo = HTTP_AUTH_DIGEST_MD5;
109         ai->dlen  = HTTP_AUTH_DIGEST_MD5_BINLEN;
110         return 1;
111     }
112 
113     len = strlen(s);
114     if (len > 5
115         && (s[len-5]       ) == '-'
116         && (s[len-4] | 0x20) == 's'
117         && (s[len-3] | 0x20) == 'e'
118         && (s[len-2] | 0x20) == 's'
119         && (s[len-1] | 0x20) == 's') {
120         ai->dalgo = HTTP_AUTH_DIGEST_SESS;
121         len -= 5;
122     }
123     else {
124         ai->dalgo = HTTP_AUTH_DIGEST_NONE;
125     }
126 
127     if (3 == len
128         && 'm' == (s[0] | 0x20)
129         && 'd' == (s[1] | 0x20)
130         && '5' == (s[2]       )) {
131         ai->dalgo |= HTTP_AUTH_DIGEST_MD5;
132         ai->dlen   = HTTP_AUTH_DIGEST_MD5_BINLEN;
133         return 1;
134     }
135   #ifdef USE_OPENSSL_CRYPTO
136     else if (len >= 7
137              && 's' == (s[0] | 0x20)
138              && 'h' == (s[1] | 0x20)
139              && 'a' == (s[2] | 0x20)
140              && '-' == (s[3]       )) {
141         if (len == 7 && s[4] == '2' && s[5] == '5' && s[6] == '6') {
142             ai->dalgo |= HTTP_AUTH_DIGEST_SHA256;
143             ai->dlen   = HTTP_AUTH_DIGEST_SHA256_BINLEN;
144             return 1;
145         }
146       #ifdef SHA512_256_DIGEST_LENGTH
147         if (len == 11 && 0 == memcmp(s+4, "512-256", 7)) {
148             ai->dalgo |= HTTP_AUTH_DIGEST_SHA512_256;
149             ai->dlen   = HTTP_AUTH_DIGEST_SHA512_256_BINLEN;
150             return 1;
151         }
152       #endif
153     }
154   #endif
155     return 0; /*(error)*/
156 }
157 
158 static int mod_auth_algorithms_parse(int *algorithm, buffer *algos) {
159     for (char *s = algos->ptr, *p; s; s = p ? p+1 : NULL) {
160         http_auth_info_t ai;
161         int rc;
162         p = strchr(s, '|');
163         if (p) *p = '\0';
164         rc = mod_auth_algorithm_parse(&ai, s);
165         if (p) *p = '|';
166         if (!rc) return 0;
167         *algorithm |= ai.dalgo;
168     }
169     return 1;
170 }
171 
172 static int mod_auth_require_parse (http_auth_require_t * const require, const buffer *b, log_error_st *errh)
173 {
174     /* user=name1|user=name2|group=name3|host=name4 */
175 
176     const char *str = b->ptr;
177     const char *p;
178 
179     if (buffer_is_equal_string(b, CONST_STR_LEN("valid-user"))) {
180         require->valid_user = 1;
181         return 1; /* success */
182     }
183 
184     do {
185         const char *eq;
186         size_t len;
187         p = strchr(str, '|');
188         len = NULL != p ? (size_t)(p - str) : strlen(str);
189         eq = memchr(str, '=', len);
190         if (NULL == eq) {
191             log_error(errh, __FILE__, __LINE__,
192               "error parsing auth.require 'require' field: missing '=' "
193               "(expecting \"valid-user\" or \"user=a|user=b|group=g|host=h\"). "
194               "error value: %s error near: %s", b->ptr, str);
195             return 0;
196         }
197         if (eq[1] == '|' || eq[1] == '\0') {
198             log_error(errh, __FILE__, __LINE__,
199               "error parsing auth.require 'require' field: "
200               "missing token after '=' "
201               "(expecting \"valid-user\" or \"user=a|user=b|group=g|host=h\"). "
202               "error value: %s error near: %s", b->ptr, str);
203             return 0;
204         }
205 
206         switch ((int)(eq - str)) {
207           case 4:
208             if (0 == memcmp(str, CONST_STR_LEN("user"))) {
209                 /*("user=" is 5)*/
210                 array_set_key_value(&require->user, str+5, len-5, CONST_STR_LEN(""));
211                 continue;
212             }
213             else if (0 == memcmp(str, CONST_STR_LEN("host"))) {
214                 /*("host=" is 5)*/
215                 array_set_key_value(&require->host, str+5, len-5, CONST_STR_LEN(""));
216                 log_error(errh, __FILE__, __LINE__,
217                   "warning parsing auth.require 'require' field: "
218                   "'host' not implemented; field value: %s", b->ptr);
219                 continue;
220             }
221             break; /* to error */
222           case 5:
223             if (0 == memcmp(str, CONST_STR_LEN("group"))) {
224                 /*("group=" is 6)*/
225                 array_set_key_value(&require->group, str+6, len-6, CONST_STR_LEN(""));
226               #if 0/*(supported by mod_authn_ldap, but not all other backends)*/
227                 log_error(errh, __FILE__, __LINE__,
228                   "warning parsing auth.require 'require' field: "
229                   "'group' not implemented; field value: %s", b->ptr);
230               #endif
231                 continue;
232             }
233             break; /* to error */
234           case 10:
235             if (0 == memcmp(str, CONST_STR_LEN("valid-user"))) {
236                 log_error(errh, __FILE__, __LINE__,
237                   "error parsing auth.require 'require' field: "
238                   "valid user can not be combined with other require rules "
239                   "(expecting \"valid-user\" or "
240                   "\"user=a|user=b|group=g|host=h\"). error value: %s", b->ptr);
241                 return 0;
242             }
243             break; /* to error */
244           default:
245             break; /* to error */
246         }
247 
248         log_error(errh, __FILE__, __LINE__,
249           "error parsing auth.require 'require' field: "
250           "invalid/unsupported token "
251           "(expecting \"valid-user\" or \"user=a|user=b|group=g|host=h\"). "
252           "error value: %s error near: %s", b->ptr, str);
253         return 0;
254 
255     } while (p && *((str = p+1)));
256 
257     return 1; /* success */
258 }
259 
260 static handler_t mod_auth_require_parse_array(const array *value, array * const auth_require, log_error_st *errh)
261 {
262 		for (uint32_t n = 0; n < value->used; ++n) {
263 			size_t m;
264 			data_array *da_file = (data_array *)value->data[n];
265 			const buffer *method = NULL, *realm = NULL, *require = NULL;
266 			const buffer *nonce_secret = NULL;
267 			const http_auth_scheme_t *auth_scheme;
268 			buffer *algos = NULL;
269 			int algorithm = HTTP_AUTH_DIGEST_SESS;
270 
271 			if (!array_is_kvstring(&da_file->value)) {
272 				log_error(errh, __FILE__, __LINE__,
273 				  "unexpected value for auth.require; expected "
274 				  "auth.require = ( \"urlpath\" => ( \"option\" => \"value\" ) )");
275 
276 				return HANDLER_ERROR;
277 			}
278 
279 			for (m = 0; m < da_file->value.used; m++) {
280 				if (da_file->value.data[m]->type == TYPE_STRING) {
281 					data_string *ds = (data_string *)da_file->value.data[m];
282 					if (buffer_is_equal_string(&ds->key, CONST_STR_LEN("method"))) {
283 						method = &ds->value;
284 					} else if (buffer_is_equal_string(&ds->key, CONST_STR_LEN("realm"))) {
285 						realm = &ds->value;
286 					} else if (buffer_is_equal_string(&ds->key, CONST_STR_LEN("require"))) {
287 						require = &ds->value;
288 					} else if (buffer_is_equal_string(&ds->key, CONST_STR_LEN("algorithm"))) {
289 						algos = &ds->value;
290 					} else if (buffer_is_equal_string(&ds->key, CONST_STR_LEN("nonce_secret"))) {
291 						nonce_secret = &ds->value;
292 					} else {
293 						log_error(errh, __FILE__, __LINE__,
294 						  "the field is unknown in: "
295 						  "auth.require = ( \"...\" => ( ..., -> \"%s\" <- => \"...\" ) )",
296 						  da_file->value.data[m]->key.ptr);
297 
298 						return HANDLER_ERROR;
299 					}
300 				} else {
301 					log_error(errh, __FILE__, __LINE__,
302 					  "a string was expected for: "
303 					  "auth.require = ( \"...\" => ( ..., -> \"%s\" <- => \"...\" ) )",
304 					  da_file->value.data[m]->key.ptr);
305 
306 					return HANDLER_ERROR;
307 				}
308 			}
309 
310 			if (buffer_string_is_empty(method)) {
311 				log_error(errh, __FILE__, __LINE__,
312 				  "the method field is missing or blank in: "
313 				  "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
314 				return HANDLER_ERROR;
315 			} else {
316 				auth_scheme = http_auth_scheme_get(method);
317 				if (NULL == auth_scheme) {
318 					log_error(errh, __FILE__, __LINE__,
319 					  "unknown method %s (e.g. \"basic\", \"digest\" or \"extern\") in "
320 					  "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )", method->ptr);
321 					return HANDLER_ERROR;
322 				}
323 			}
324 
325 			if (buffer_is_empty(realm)) {
326 				log_error(errh, __FILE__, __LINE__,
327 				  "the realm field is missing in: "
328 				  "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
329 				return HANDLER_ERROR;
330 			}
331 
332 			if (buffer_string_is_empty(require)) {
333 				log_error(errh, __FILE__, __LINE__,
334 				  "the require field is missing or blank in: "
335 				  "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
336 				return HANDLER_ERROR;
337 			}
338 
339 			if (buffer_string_is_empty(algos)) {
340 				algorithm |= HTTP_AUTH_DIGEST_MD5;
341 			} else if (!mod_auth_algorithms_parse(&algorithm, algos)) {
342 				log_error(errh, __FILE__, __LINE__,
343 				  "invalid algorithm in: "
344 				  "auth.require = ( \"...\" => ( ..., \"algorithm\" => \"...\" ) )");
345 				return HANDLER_ERROR;
346 			}
347 
348 			if (require) { /*(always true at this point)*/
349 				data_auth * const dauth = data_auth_init();
350 				buffer_copy_buffer(&dauth->key, &da_file->key);
351 				dauth->require->scheme = auth_scheme;
352 				dauth->require->algorithm = algorithm;
353 				dauth->require->realm = realm;
354 				dauth->require->nonce_secret = nonce_secret; /*(NULL is ok)*/
355 				if (!mod_auth_require_parse(dauth->require, require, errh)) {
356 					dauth->fn->free((data_unset *)dauth);
357 					return HANDLER_ERROR;
358 				}
359 				array_insert_unique(auth_require, (data_unset *)dauth);
360 			}
361 		}
362 
363 	return HANDLER_GO_ON;
364 }
365 
366 static void mod_auth_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
367     switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
368       case 0: /* auth.backend */
369         if (cpv->vtype == T_CONFIG_LOCAL)
370             pconf->auth_backend = cpv->v.v;
371         break;
372       case 1: /* auth.require */
373         if (cpv->vtype == T_CONFIG_LOCAL)
374             pconf->auth_require = cpv->v.v;
375         break;
376       case 2: /* auth.extern-authn */
377         pconf->auth_extern_authn = cpv->v.u;
378       default:/* should not happen */
379         return;
380     }
381 }
382 
383 static void mod_auth_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
384     do {
385         mod_auth_merge_config_cpv(pconf, cpv);
386     } while ((++cpv)->k_id != -1);
387 }
388 
389 static void mod_auth_patch_config(request_st * const r, plugin_data * const p) {
390     p->conf = p->defaults; /* copy small struct instead of memcpy() */
391     /*memcpy(&p->conf, &p->defaults, sizeof(plugin_config));*/
392     for (int i = 1, used = p->nconfig; i < used; ++i) {
393         if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
394             mod_auth_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
395     }
396 }
397 
398 SETDEFAULTS_FUNC(mod_auth_set_defaults) {
399     static const config_plugin_keys_t cpk[] = {
400       { CONST_STR_LEN("auth.backend"),
401         T_CONFIG_STRING,
402         T_CONFIG_SCOPE_CONNECTION }
403      ,{ CONST_STR_LEN("auth.require"),
404         T_CONFIG_ARRAY_KVARRAY,
405         T_CONFIG_SCOPE_CONNECTION }
406      ,{ CONST_STR_LEN("auth.extern-authn"),
407         T_CONFIG_BOOL,
408         T_CONFIG_SCOPE_CONNECTION }
409      ,{ NULL, 0,
410         T_CONFIG_UNSET,
411         T_CONFIG_SCOPE_UNSET }
412     };
413 
414     plugin_data * const p = p_d;
415     if (!config_plugin_values_init(srv, p, cpk, "mod_auth"))
416         return HANDLER_ERROR;
417 
418     /* process and validate config directives
419      * (init i to 0 if global context; to 1 to skip empty global context) */
420     for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
421         config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
422         for (; -1 != cpv->k_id; ++cpv) {
423             switch (cpv->k_id) {
424               case 0: /* auth.backend */
425                 if (!buffer_string_is_empty(cpv->v.b)) {
426                     const http_auth_backend_t * const auth_backend =
427                       http_auth_backend_get(cpv->v.b);
428                     if (NULL == auth_backend) {
429                         log_error(srv->errh, __FILE__, __LINE__,
430                           "auth.backend not supported: %s", cpv->v.b->ptr);
431                         return HANDLER_ERROR;
432                     }
433                     *(const http_auth_backend_t **)&cpv->v.v = auth_backend;
434                     cpv->vtype = T_CONFIG_LOCAL;
435                 }
436                 break;
437               case 1: /* auth.require */
438                 {
439                     array * const a = array_init(4);
440                     if (HANDLER_GO_ON !=
441                         mod_auth_require_parse_array(cpv->v.a, a, srv->errh)) {
442                         array_free(a);
443                         return HANDLER_ERROR;
444                     }
445                     cpv->v.a = a;
446                     cpv->vtype = T_CONFIG_LOCAL;
447                 }
448                 break;
449               case 2: /* auth.extern-authn */
450                 break;
451               default:/* should not happen */
452                 break;
453             }
454         }
455     }
456 
457     /* initialize p->defaults from global config context */
458     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
459         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
460         if (-1 != cpv->k_id)
461             mod_auth_merge_config(&p->defaults, cpv);
462     }
463 
464     return HANDLER_GO_ON;
465 }
466 
467 static handler_t mod_auth_uri_handler(request_st * const r, void *p_d) {
468 	plugin_data *p = p_d;
469 	data_auth *dauth;
470 
471 	mod_auth_patch_config(r, p);
472 
473 	if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
474 
475 	/* search auth directives for first prefix match against URL path */
476 	/* if we have a case-insensitive FS we have to lower-case the URI here too */
477 	dauth = (!r->conf.force_lowercase_filenames)
478 	   ? (data_auth *)array_match_key_prefix(p->conf.auth_require, &r->uri.path)
479 	   : (data_auth *)array_match_key_prefix_nc(p->conf.auth_require, &r->uri.path);
480 	if (NULL == dauth) return HANDLER_GO_ON;
481 
482 	{
483 			const http_auth_scheme_t * const scheme = dauth->require->scheme;
484 			if (p->conf.auth_extern_authn) {
485 				const buffer *vb = http_header_env_get(r, CONST_STR_LEN("REMOTE_USER"));
486 				if (NULL != vb && http_auth_match_rules(dauth->require, vb->ptr, NULL, NULL)) {
487 					return HANDLER_GO_ON;
488 				}
489 			}
490 			return scheme->checkfn(r, scheme->p_d, dauth->require, p->conf.auth_backend);
491 	}
492 }
493 
494 int mod_auth_plugin_init(plugin *p);
495 int mod_auth_plugin_init(plugin *p) {
496 	p->version     = LIGHTTPD_VERSION_ID;
497 	p->name        = "auth";
498 	p->init        = mod_auth_init;
499 	p->set_defaults = mod_auth_set_defaults;
500 	p->handle_uri_clean = mod_auth_uri_handler;
501 	p->cleanup     = mod_auth_free;
502 
503 	return 0;
504 }
505 
506 
507 
508 
509 /*
510  * auth schemes (basic, digest, extern)
511  *
512  * (could be in separate file from mod_auth.c as long as registration occurs)
513  */
514 
515 #include "base64.h"
516 #include "md5.h"
517 #include "rand.h"
518 #include "http_header.h"
519 
520 __attribute_cold__
521 static handler_t mod_auth_send_400_bad_request(request_st * const r) {
522 
523 	/* a field was missing or invalid */
524 	r->http_status = 400; /* Bad Request */
525 	r->handler_module = NULL;
526 
527 	return HANDLER_FINISHED;
528 }
529 
530 static handler_t mod_auth_send_401_unauthorized_basic(request_st * const r, const buffer * const realm) {
531 	r->http_status = 401;
532 	r->handler_module = NULL;
533 
534 	buffer * const tb = r->tmp_buf;
535 	buffer_copy_string_len(tb, CONST_STR_LEN("Basic realm=\""));
536 	buffer_append_string_buffer(tb, realm);
537 	buffer_append_string_len(tb, CONST_STR_LEN("\", charset=\"UTF-8\""));
538 
539 	http_header_response_set(r, HTTP_HEADER_OTHER, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(tb));
540 
541 	return HANDLER_FINISHED;
542 }
543 
544 static handler_t mod_auth_check_basic(request_st * const r, void *p_d, const struct http_auth_require_t * const require, const struct http_auth_backend_t * const backend) {
545 	const buffer *b = http_header_request_get(r, HTTP_HEADER_AUTHORIZATION, CONST_STR_LEN("Authorization"));
546 	buffer *username;
547 	char *pw;
548 	handler_t rc = HANDLER_UNSET;
549 
550 	UNUSED(p_d);
551 
552 	if (NULL == backend) {
553 		log_error(r->conf.errh, __FILE__, __LINE__, "auth.backend not configured for %s", r->uri.path.ptr);
554 		r->http_status = 500;
555 		r->handler_module = NULL;
556 		return HANDLER_FINISHED;
557 	}
558 
559 	if (NULL == b) {
560 		return mod_auth_send_401_unauthorized_basic(r, require->realm);
561 	}
562 
563 	if (!buffer_eq_icase_ssn(b->ptr, CONST_STR_LEN("Basic "))) {
564 		return mod_auth_send_401_unauthorized_basic(r, require->realm);
565 	}
566       #ifdef __COVERITY__
567 	if (buffer_string_length(b) < sizeof("Basic ")-1) {
568 		return mod_auth_send_400_bad_request(r);
569 	}
570       #endif
571 
572 	username = buffer_init();
573 
574 	/* coverity[overflow_sink : FALSE] */
575 	if (!buffer_append_base64_decode(username, b->ptr+sizeof("Basic ")-1, buffer_string_length(b)-(sizeof("Basic ")-1), BASE64_STANDARD)) {
576 		log_error(r->conf.errh, __FILE__, __LINE__, "decoding base64-string failed %s", b->ptr+sizeof("Basic ")-1);
577 
578 		buffer_free(username);
579 		return mod_auth_send_400_bad_request(r);
580 	}
581 
582 	/* r2 == user:password */
583 	if (NULL == (pw = strchr(username->ptr, ':'))) {
584 		log_error(r->conf.errh, __FILE__, __LINE__, "missing ':' in %s", username->ptr);
585 
586 		buffer_free(username);
587 		return mod_auth_send_400_bad_request(r);
588 	}
589 
590 	buffer_string_set_length(username, pw - username->ptr);
591 	pw++;
592 
593 	rc = backend->basic(r, backend->p_d, require, username, pw);
594 	switch (rc) {
595 	case HANDLER_GO_ON:
596 		http_auth_setenv(r, CONST_BUF_LEN(username), CONST_STR_LEN("Basic"));
597 		break;
598 	case HANDLER_WAIT_FOR_EVENT:
599 	case HANDLER_FINISHED:
600 		break;
601 	case HANDLER_ERROR:
602 	default:
603 		log_error(r->conf.errh, __FILE__, __LINE__,
604 		  "password doesn't match for %s username: %s IP: %s",
605 		  r->uri.path.ptr, username->ptr, r->con->dst_addr_buf->ptr);
606 		r->keep_alive = 0; /*(disable keep-alive if bad password)*/
607 		rc = HANDLER_UNSET;
608 		break;
609 	}
610 
611 	buffer_free(username);
612 	return (HANDLER_UNSET != rc) ? rc : mod_auth_send_401_unauthorized_basic(r, require->realm);
613 }
614 
615 
616 #ifdef USE_OPENSSL_CRYPTO
617 
618 static void mod_auth_digest_mutate_sha256(http_auth_info_t *ai, const char *m, const char *uri, const char *nonce, const char *cnonce, const char *nc, const char *qop) {
619     SHA256_CTX ctx;
620     char a1[HTTP_AUTH_DIGEST_SHA256_BINLEN*2+1];
621     char a2[HTTP_AUTH_DIGEST_SHA256_BINLEN*2+1];
622 
623     if (ai->dalgo & HTTP_AUTH_DIGEST_SESS) {
624         SHA256_Init(&ctx);
625         li_tohex(a1, sizeof(a1), (const char *)ai->digest, ai->dlen);
626         SHA256_Update(&ctx, (unsigned char *)a1, sizeof(a1)-1);
627         SHA256_Update(&ctx, CONST_STR_LEN(":"));
628         SHA256_Update(&ctx, (unsigned char *)nonce, strlen(nonce));
629         SHA256_Update(&ctx, CONST_STR_LEN(":"));
630         SHA256_Update(&ctx, (unsigned char *)cnonce, strlen(cnonce));
631         SHA256_Final(ai->digest, &ctx);
632     }
633 
634     li_tohex(a1, sizeof(a1), (const char *)ai->digest, ai->dlen);
635 
636     /* calculate H(A2) */
637     SHA256_Init(&ctx);
638     SHA256_Update(&ctx, (unsigned char *)m, strlen(m));
639     SHA256_Update(&ctx, CONST_STR_LEN(":"));
640     SHA256_Update(&ctx, (unsigned char *)uri, strlen(uri));
641   #if 0
642     /* qop=auth-int not supported, already checked in caller */
643     if (qop && buffer_eq_icase_ss(qop, strlen(qop), CONST_STR_LEN("auth-int"))){
644         SHA256_Update(&ctx, CONST_STR_LEN(":"));
645         SHA256_Update(&ctx, (unsigned char *) [body checksum], ai->dlen*2);
646     }
647   #endif
648     SHA256_Final(ai->digest, &ctx);
649     li_tohex(a2, sizeof(a2), (const char *)ai->digest, ai->dlen);
650 
651     /* calculate response */
652     SHA256_Init(&ctx);
653     SHA256_Update(&ctx, (unsigned char *)a1, sizeof(a1)-1);
654     SHA256_Update(&ctx, CONST_STR_LEN(":"));
655     SHA256_Update(&ctx, (unsigned char *)nonce, strlen(nonce));
656     SHA256_Update(&ctx, CONST_STR_LEN(":"));
657     if (qop && *qop) {
658         SHA256_Update(&ctx, (unsigned char *)nc, strlen(nc));
659         SHA256_Update(&ctx, CONST_STR_LEN(":"));
660         SHA256_Update(&ctx, (unsigned char *)cnonce, strlen(cnonce));
661         SHA256_Update(&ctx, CONST_STR_LEN(":"));
662         SHA256_Update(&ctx, (unsigned char *)qop, strlen(qop));
663         SHA256_Update(&ctx, CONST_STR_LEN(":"));
664     }
665     SHA256_Update(&ctx, (unsigned char *)a2, sizeof(a2)-1);
666     SHA256_Final(ai->digest, &ctx);
667 }
668 
669 static void mod_auth_digest_nonce_sha256(buffer *b, time_t cur_ts, int rnd, const buffer *secret) {
670     SHA256_CTX ctx;
671     size_t len;
672     unsigned char h[HTTP_AUTH_DIGEST_SHA256_BINLEN];
673     char hh[HTTP_AUTH_DIGEST_SHA256_BINLEN*2+1];
674     force_assert(sizeof(hh) >= LI_ITOSTRING_LENGTH);
675     SHA256_Init(&ctx);
676     len = li_itostrn(hh, sizeof(hh), cur_ts);
677     SHA256_Update(&ctx, (unsigned char *)hh, len);
678     len = li_itostrn(hh, sizeof(hh), rnd);
679     SHA256_Update(&ctx, (unsigned char *)hh, len);
680     if (secret) {
681         len = buffer_string_length(secret);
682         SHA256_Update(&ctx, (unsigned char *)secret->ptr, len);
683     }
684     SHA256_Final(h, &ctx);
685     li_tohex(hh, sizeof(hh), (const char *)h, sizeof(h));
686     buffer_append_string_len(b, hh, sizeof(hh)-1);
687 }
688 
689 #ifdef SHA512_256_DIGEST_LENGTH
690 
691 static void mod_auth_digest_mutate_sha512_256(http_auth_info_t *ai, const char *m, const char *uri, const char *nonce, const char *cnonce, const char *nc, const char *qop) {
692     SHA512_CTX ctx;
693     char a1[HTTP_AUTH_DIGEST_SHA512_256_BINLEN*2+1];
694     char a2[HTTP_AUTH_DIGEST_SHA512_256_BINLEN*2+1];
695 
696     if (ai->dalgo & HTTP_AUTH_DIGEST_SESS) {
697         SHA512_256_Init(&ctx);
698         li_tohex(a1, sizeof(a1), (const char *)ai->digest, ai->dlen);
699         SHA512_256_Update(&ctx, (unsigned char *)a1, sizeof(a1)-1);
700         SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
701         SHA512_256_Update(&ctx, (unsigned char *)nonce, strlen(nonce));
702         SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
703         SHA512_256_Update(&ctx, (unsigned char *)cnonce, strlen(cnonce));
704         SHA512_256_Final(ai->digest, &ctx);
705     }
706 
707     li_tohex(a1, sizeof(a1), (const char *)ai->digest, ai->dlen);
708 
709     /* calculate H(A2) */
710     SHA512_256_Init(&ctx);
711     SHA512_256_Update(&ctx, (unsigned char *)m, strlen(m));
712     SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
713     SHA512_256_Update(&ctx, (unsigned char *)uri, strlen(uri));
714   #if 0
715     /* qop=auth-int not supported, already checked in caller */
716     if (qop && buffer_eq_icase_ss(qop, strlen(qop), CONST_STR_LEN("auth-int"))){
717         SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
718         SHA512_256_Update(&ctx, (unsigned char *)[body checksum], ai->dlen*2);
719     }
720   #endif
721     SHA512_256_Final(ai->digest, &ctx);
722     li_tohex(a2, sizeof(a2), (const char *)ai->digest, ai->dlen);
723 
724     /* calculate response */
725     SHA512_256_Init(&ctx);
726     SHA512_256_Update(&ctx, (unsigned char *)a1, sizeof(a1)-1);
727     SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
728     SHA512_256_Update(&ctx, (unsigned char *)nonce, strlen(nonce));
729     SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
730     if (qop && *qop) {
731         SHA512_256_Update(&ctx, (unsigned char *)nc, strlen(nc));
732         SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
733         SHA512_256_Update(&ctx, (unsigned char *)cnonce, strlen(cnonce));
734         SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
735         SHA512_256_Update(&ctx, (unsigned char *)qop, strlen(qop));
736         SHA512_256_Update(&ctx, CONST_STR_LEN(":"));
737     }
738     SHA512_256_Update(&ctx, (unsigned char *)a2, sizeof(a2)-1);
739     SHA512_256_Final(ai->digest, &ctx);
740 }
741 
742 static void mod_auth_digest_nonce_sha512_256(buffer *b, time_t cur_ts, int rnd, const buffer *secret) {
743     SHA512_CTX ctx;
744     size_t len;
745     unsigned char h[HTTP_AUTH_DIGEST_SHA512_256_BINLEN];
746     char hh[HTTP_AUTH_DIGEST_SHA512_256_BINLEN*2+1];
747     force_assert(sizeof(hh) >= LI_ITOSTRING_LENGTH);
748     SHA512_256_Init(&ctx);
749     len = li_itostrn(hh, sizeof(hh), cur_ts);
750     SHA512_256_Update(&ctx, (unsigned char *)hh, len);
751     len = li_itostrn(hh, sizeof(hh), rnd);
752     SHA512_256_Update(&ctx, (unsigned char *)hh, len);
753     if (secret) {
754         len = buffer_string_length(secret);
755         SHA512_256_Update(&ctx, (unsigned char *)secret->ptr, len);
756     }
757     SHA512_256_Final(h, &ctx);
758     li_tohex(hh, sizeof(hh), (const char *)h, sizeof(h));
759     buffer_append_string_len(b, hh, sizeof(hh)-1);
760 }
761 
762 #endif /* SHA512_256_DIGEST_LENGTH */
763 
764 #endif /* USE_OPENSSL_CRYPTO */
765 
766 static void mod_auth_digest_mutate_md5(http_auth_info_t *ai, const char *m, const char *uri, const char *nonce, const char *cnonce, const char *nc, const char *qop) {
767     li_MD5_CTX ctx;
768     char a1[HTTP_AUTH_DIGEST_MD5_BINLEN*2+1];
769     char a2[HTTP_AUTH_DIGEST_MD5_BINLEN*2+1];
770 
771     if (ai->dalgo & HTTP_AUTH_DIGEST_SESS) {
772         li_MD5_Init(&ctx);
773         /* http://www.rfc-editor.org/errata_search.php?rfc=2617
774          * Errata ID: 1649 */
775         li_tohex(a1, sizeof(a1), (const char *)ai->digest, ai->dlen);
776         li_MD5_Update(&ctx, (unsigned char *)a1, sizeof(a1)-1);
777         li_MD5_Update(&ctx, CONST_STR_LEN(":"));
778         li_MD5_Update(&ctx, (unsigned char *)nonce, strlen(nonce));
779         li_MD5_Update(&ctx, CONST_STR_LEN(":"));
780         li_MD5_Update(&ctx, (unsigned char *)cnonce, strlen(cnonce));
781         li_MD5_Final(ai->digest, &ctx);
782     }
783 
784     li_tohex(a1, sizeof(a1), (const char *)ai->digest, ai->dlen);
785 
786     /* calculate H(A2) */
787     li_MD5_Init(&ctx);
788     li_MD5_Update(&ctx, (unsigned char *)m, strlen(m));
789     li_MD5_Update(&ctx, CONST_STR_LEN(":"));
790     li_MD5_Update(&ctx, (unsigned char *)uri, strlen(uri));
791   #if 0
792     /* qop=auth-int not supported, already checked in caller */
793     if (qop && buffer_eq_icase_ss(qop, strlen(qop), CONST_STR_LEN("auth-int"))){
794         li_MD5_Update(&ctx, CONST_STR_LEN(":"));
795         li_MD5_Update(&ctx, (unsigned char *) [body checksum], ai->dlen*2);
796     }
797   #endif
798     li_MD5_Final(ai->digest, &ctx);
799     li_tohex(a2, sizeof(a2), (const char *)ai->digest, ai->dlen);
800 
801     /* calculate response */
802     li_MD5_Init(&ctx);
803     li_MD5_Update(&ctx, (unsigned char *)a1, sizeof(a1)-1);
804     li_MD5_Update(&ctx, CONST_STR_LEN(":"));
805     li_MD5_Update(&ctx, (unsigned char *)nonce, strlen(nonce));
806     li_MD5_Update(&ctx, CONST_STR_LEN(":"));
807     if (qop && *qop) {
808         li_MD5_Update(&ctx, (unsigned char *)nc, strlen(nc));
809         li_MD5_Update(&ctx, CONST_STR_LEN(":"));
810         li_MD5_Update(&ctx, (unsigned char *)cnonce, strlen(cnonce));
811         li_MD5_Update(&ctx, CONST_STR_LEN(":"));
812         li_MD5_Update(&ctx, (unsigned char *)qop, strlen(qop));
813         li_MD5_Update(&ctx, CONST_STR_LEN(":"));
814     }
815     li_MD5_Update(&ctx, (unsigned char *)a2, sizeof(a2)-1);
816     li_MD5_Final(ai->digest, &ctx);
817 }
818 
819 static void mod_auth_digest_nonce_md5(buffer *b, time_t cur_ts, int rnd, const buffer *secret) {
820     li_MD5_CTX ctx;
821     size_t len;
822     unsigned char h[HTTP_AUTH_DIGEST_MD5_BINLEN];
823     char hh[HTTP_AUTH_DIGEST_MD5_BINLEN*2+1];
824     force_assert(sizeof(hh) >= LI_ITOSTRING_LENGTH);
825     li_MD5_Init(&ctx);
826     len = li_itostrn(hh, sizeof(hh), cur_ts);
827     li_MD5_Update(&ctx, (unsigned char *)hh, len);
828     len = li_itostrn(hh, sizeof(hh), rnd);
829     li_MD5_Update(&ctx, (unsigned char *)hh, len);
830     if (secret) {
831         len = buffer_string_length(secret);
832         li_MD5_Update(&ctx, (unsigned char *)secret->ptr, len);
833     }
834     li_MD5_Final(h, &ctx);
835     li_tohex(hh, sizeof(hh), (const char *)h, sizeof(h));
836     buffer_append_string_len(b, hh, sizeof(hh)-1);
837 }
838 
839 static void mod_auth_digest_mutate(http_auth_info_t *ai, const char *m, const char *uri, const char *nonce, const char *cnonce, const char *nc, const char *qop) {
840     if (ai->dalgo & HTTP_AUTH_DIGEST_MD5)
841         mod_auth_digest_mutate_md5(ai, m, uri, nonce, cnonce, nc, qop);
842   #ifdef USE_OPENSSL_CRYPTO
843     else if (ai->dalgo & HTTP_AUTH_DIGEST_SHA256)
844         mod_auth_digest_mutate_sha256(ai, m, uri, nonce, cnonce, nc, qop);
845    #ifdef SHA512_256_DIGEST_LENGTH
846     else if (ai->dalgo & HTTP_AUTH_DIGEST_SHA512_256)
847         mod_auth_digest_mutate_sha512_256(ai, m, uri, nonce, cnonce, nc, qop);
848    #endif
849   #endif
850 }
851 
852 static void mod_auth_append_nonce(buffer *b, time_t cur_ts, const struct http_auth_require_t *require, int dalgo, int *rndptr) {
853     buffer_append_uint_hex(b, (uintmax_t)cur_ts);
854     buffer_append_string_len(b, CONST_STR_LEN(":"));
855     const buffer * const nonce_secret = require->nonce_secret;
856     int rnd;
857     if (NULL == nonce_secret)
858         rnd = rndptr ? *rndptr : li_rand_pseudo();
859     else { /*(do not directly expose random number generator single value)*/
860         rndptr
861           ? (void)(rnd = *rndptr)
862           : li_rand_pseudo_bytes((unsigned char *)&rnd, sizeof(rnd));
863         buffer_append_uint_hex(b, (uintmax_t)rnd);
864         buffer_append_string_len(b, CONST_STR_LEN(":"));
865     }
866     switch (dalgo) {
867      #ifdef USE_OPENSSL_CRYPTO
868       #ifdef SHA512_256_DIGEST_LENGTH
869       case HTTP_AUTH_DIGEST_SHA512_256:
870         mod_auth_digest_nonce_sha512_256(b, cur_ts, rnd, nonce_secret);
871         break;
872       #endif
873       case HTTP_AUTH_DIGEST_SHA256:
874         mod_auth_digest_nonce_sha256(b, cur_ts, rnd, nonce_secret);
875         break;
876      #endif
877       /*case HTTP_AUTH_DIGEST_MD5:*/
878       default:
879         mod_auth_digest_nonce_md5(b, cur_ts, rnd, nonce_secret);
880         break;
881     }
882 }
883 
884 static void mod_auth_digest_www_authenticate(buffer *b, time_t cur_ts, const struct http_auth_require_t *require, int nonce_stale) {
885     int algos = nonce_stale ? nonce_stale : require->algorithm;
886     int n = 0;
887     int algoid[3];
888     unsigned int algolen[3];
889     const char *algoname[3];
890   #ifdef USE_OPENSSL_CRYPTO
891    #ifdef SHA512_256_DIGEST_LENGTH
892     if (algos & HTTP_AUTH_DIGEST_SHA512_256) {
893         algoid[n] = HTTP_AUTH_DIGEST_SHA512_256;
894         algoname[n] = "SHA-512-256";
895         algolen[n] = sizeof("SHA-512-256")-1;
896         ++n;
897     }
898    #endif
899     if (algos & HTTP_AUTH_DIGEST_SHA256) {
900         algoid[n] = HTTP_AUTH_DIGEST_SHA256;
901         algoname[n] = "SHA-256";
902         algolen[n] = sizeof("SHA-256")-1;
903         ++n;
904     }
905   #endif
906     if (algos & HTTP_AUTH_DIGEST_MD5) {
907         algoid[n] = HTTP_AUTH_DIGEST_MD5;
908         algoname[n] = "MD5";
909         algolen[n] = sizeof("MD5")-1;
910         ++n;
911     }
912 
913     buffer_clear(b);
914     for (int i = 0; i < n; ++i) {
915         if (i > 0) {
916             buffer_append_string_len(b,CONST_STR_LEN("\r\nWWW-Authenticate: "));
917         }
918         buffer_append_string_len(b, CONST_STR_LEN("Digest realm=\""));
919         buffer_append_string_buffer(b, require->realm);
920         buffer_append_string_len(b, CONST_STR_LEN("\", charset=\"UTF-8\", algorithm="));
921         buffer_append_string_len(b, algoname[i], algolen[i]);
922         buffer_append_string_len(b, CONST_STR_LEN(", nonce=\""));
923         mod_auth_append_nonce(b, cur_ts, require, algoid[i], NULL);
924         buffer_append_string_len(b, CONST_STR_LEN("\", qop=\"auth\""));
925         if (nonce_stale) {
926             buffer_append_string_len(b, CONST_STR_LEN(", stale=true"));
927         }
928     }
929 }
930 
931 static void mod_auth_digest_authentication_info(buffer *b, time_t cur_ts, const struct http_auth_require_t *require, int dalgo) {
932     buffer_clear(b);
933     buffer_append_string_len(b, CONST_STR_LEN("nextnonce=\""));
934     mod_auth_append_nonce(b, cur_ts, require, dalgo, NULL);
935     buffer_append_string_len(b, CONST_STR_LEN("\""));
936 }
937 
938 typedef struct {
939 	const char *key;
940 	int key_len;
941 	char **ptr;
942 } digest_kv;
943 
944 static handler_t mod_auth_send_401_unauthorized_digest(request_st *r, const struct http_auth_require_t *require, int nonce_stale);
945 
946 static handler_t mod_auth_check_digest(request_st * const r, void *p_d, const struct http_auth_require_t * const require, const struct http_auth_backend_t * const backend) {
947 	const buffer *vb = http_header_request_get(r, HTTP_HEADER_AUTHORIZATION, CONST_STR_LEN("Authorization"));
948 
949 	char *username = NULL;
950 	char *realm = NULL;
951 	char *nonce = NULL;
952 	char *uri = NULL;
953 	char *algorithm = NULL;
954 	char *qop = NULL;
955 	char *cnonce = NULL;
956 	char *nc = NULL;
957 	char *respons = NULL;
958 
959 	char *e, *c;
960 	int i;
961 	buffer *b;
962 	http_auth_info_t ai;
963 	unsigned char rdigest[HTTP_AUTH_DIGEST_SHA256_BINLEN];
964 
965 
966 	/* init pointers */
967 #define S(x) \
968 	x, sizeof(x)-1, NULL
969 	digest_kv dkv[10] = {
970 		{ S("username=") },
971 		{ S("realm=") },
972 		{ S("nonce=") },
973 		{ S("uri=") },
974 		{ S("algorithm=") },
975 		{ S("qop=") },
976 		{ S("cnonce=") },
977 		{ S("nc=") },
978 		{ S("response=") },
979 
980 		{ NULL, 0, NULL }
981 	};
982 #undef S
983 
984 	dkv[0].ptr = &username;
985 	dkv[1].ptr = &realm;
986 	dkv[2].ptr = &nonce;
987 	dkv[3].ptr = &uri;
988 	dkv[4].ptr = &algorithm;
989 	dkv[5].ptr = &qop;
990 	dkv[6].ptr = &cnonce;
991 	dkv[7].ptr = &nc;
992 	dkv[8].ptr = &respons;
993 
994 	UNUSED(p_d);
995 
996 	if (NULL == backend) {
997 		log_error(r->conf.errh, __FILE__, __LINE__,
998 		  "auth.backend not configured for %s", r->uri.path.ptr);
999 		r->http_status = 500;
1000 		r->handler_module = NULL;
1001 		return HANDLER_FINISHED;
1002 	}
1003 
1004 	if (NULL == vb) {
1005 		return mod_auth_send_401_unauthorized_digest(r, require, 0);
1006 	}
1007 
1008 	if (!buffer_eq_icase_ssn(vb->ptr, CONST_STR_LEN("Digest "))) {
1009 		return mod_auth_send_401_unauthorized_digest(r, require, 0);
1010 	} else {
1011 		size_t n = buffer_string_length(vb);
1012 	      #ifdef __COVERITY__
1013 		if (n < sizeof("Digest ")-1) {
1014 			return mod_auth_send_400_bad_request(r);
1015 		}
1016 	      #endif
1017 		n -= (sizeof("Digest ")-1);
1018 		b = buffer_init();
1019 		buffer_copy_string_len(b,vb->ptr+sizeof("Digest ")-1,n);
1020 	}
1021 
1022 	/* parse credentials from client */
1023 	for (c = b->ptr; *c; c++) {
1024 		/* skip whitespaces */
1025 		while (*c == ' ' || *c == '\t') c++;
1026 		if (!*c) break;
1027 
1028 		for (i = 0; dkv[i].key; i++) {
1029 			if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
1030 				if ((c[dkv[i].key_len] == '"') &&
1031 				    (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
1032 					/* value with "..." */
1033 					*(dkv[i].ptr) = c + dkv[i].key_len + 1;
1034 					c = e;
1035 
1036 					*e = '\0';
1037 				} else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
1038 					/* value without "...", terminated by ',' */
1039 					*(dkv[i].ptr) = c + dkv[i].key_len;
1040 					c = e;
1041 
1042 					*e = '\0';
1043 				} else {
1044 					/* value without "...", terminated by EOL */
1045 					*(dkv[i].ptr) = c + dkv[i].key_len;
1046 					c += strlen(c) - 1;
1047 				}
1048 				break;
1049 			}
1050 		}
1051 	}
1052 
1053 	/* check if everything is transmitted */
1054 	if (!username ||
1055 	    !realm ||
1056 	    !nonce ||
1057 	    !uri ||
1058 	    (qop && (!nc || !cnonce)) ||
1059 	    !respons ) {
1060 		/* missing field */
1061 
1062 		log_error(r->conf.errh, __FILE__, __LINE__,
1063 		  "digest: missing field");
1064 
1065 		buffer_free(b);
1066 		return mod_auth_send_400_bad_request(r);
1067 	}
1068 
1069 	ai.username = username;
1070 	ai.ulen     = strlen(username);
1071 	ai.realm    = realm;
1072 	ai.rlen     = strlen(realm);
1073 
1074 	if (!buffer_is_equal_string(require->realm, ai.realm, ai.rlen)) {
1075 		log_error(r->conf.errh, __FILE__, __LINE__,
1076 		  "digest: realm mismatch");
1077 		buffer_free(b);
1078 		return mod_auth_send_401_unauthorized_digest(r, require, 0);
1079 	}
1080 
1081 	if (!mod_auth_algorithm_parse(&ai, algorithm)
1082 	    || !(require->algorithm & ai.dalgo & ~HTTP_AUTH_DIGEST_SESS)) {
1083 		log_error(r->conf.errh, __FILE__, __LINE__,
1084 		  "digest: (%s): invalid", algorithm);
1085 		buffer_free(b);
1086 		return mod_auth_send_400_bad_request(r);
1087 	}
1088 
1089 	/**
1090 	 * protect the md5-sess against missing cnonce and nonce
1091 	 */
1092 	if ((ai.dalgo & HTTP_AUTH_DIGEST_SESS) && (!nonce || !cnonce)) {
1093 		log_error(r->conf.errh, __FILE__, __LINE__,
1094 		  "digest: (%s): missing field", algorithm);
1095 
1096 		buffer_free(b);
1097 		return mod_auth_send_400_bad_request(r);
1098 	}
1099 
1100 	{
1101 		size_t resplen = strlen(respons);
1102 		if (0 != http_auth_digest_hex2bin(respons, resplen,
1103 						  rdigest, sizeof(rdigest))
1104 		    || resplen != (ai.dlen << 1)) {
1105 			log_error(r->conf.errh, __FILE__, __LINE__,
1106 			  "digest: (%s): invalid format", respons);
1107 			buffer_free(b);
1108 			return mod_auth_send_400_bad_request(r);
1109 		}
1110 	}
1111 
1112 	if (qop && buffer_eq_icase_ss(qop, strlen(qop), CONST_STR_LEN("auth-int"))){
1113 		log_error(r->conf.errh, __FILE__, __LINE__,
1114 		  "digest: qop=auth-int not supported");
1115 
1116 		buffer_free(b);
1117 		return mod_auth_send_400_bad_request(r);
1118 	}
1119 
1120 	/* detect if attacker is attempting to reuse valid digest for one uri
1121 	 * on a different request uri.  Might also happen if intermediate proxy
1122 	 * altered client request line.  (Altered request would not result in
1123 	 * the same digest as that calculated by the client.)
1124 	 * Internal redirects such as with mod_rewrite will modify request uri.
1125 	 * Reauthentication is done to detect crossing auth realms, but this
1126 	 * uri validation step is bypassed.  r->target_orig is
1127 	 * original request-target sent in client request. */
1128 	{
1129 		const size_t ulen = strlen(uri);
1130 		if (!buffer_is_equal_string(&r->target_orig, uri, ulen)) {
1131 			log_error(r->conf.errh, __FILE__, __LINE__,
1132 			  "digest: auth failed: uri mismatch (%s != %s), IP: %s",
1133 			  r->target_orig.ptr, uri, r->con->dst_addr_buf->ptr);
1134 			buffer_free(b);
1135 			return mod_auth_send_400_bad_request(r);
1136 		}
1137 	}
1138 
1139 	/* check age of nonce.  Note, random data is used in nonce generation
1140 	 * in mod_auth_send_401_unauthorized_digest().  If that were replaced
1141 	 * with nanosecond time, then nonce secret would remain unique enough
1142 	 * for the purposes of Digest auth, and would be reproducible (and
1143 	 * verifiable) if nanoseconds were included with seconds as part of the
1144 	 * nonce "timestamp:secret".  However, doing so would expose a high
1145 	 * precision timestamp of the system to attackers.  timestamp in nonce
1146 	 * could theoretically be modified and still produce same md5sum, but
1147 	 * that is highly unlikely within a 10 min (moving) window of valid
1148 	 * time relative to current time (now).
1149 	 * If it is desired to validate that nonces were generated by server,
1150 	 * then specify auth.require = ( ... => ( "secret" => "..." ) )
1151 	 * When secret is specified, then instead of nanoseconds, the random
1152 	 * data value (included for unique nonces) will be exposed in the nonce
1153 	 * along with the timestamp, and the additional secret will be used to
1154 	 * validate that the server generated the nonce using that secret. */
1155 	int send_nextnonce;
1156 	{
1157 		time_t ts = 0;
1158 		const unsigned char * const nonce_uns = (unsigned char *)nonce;
1159 		for (i = 0; i < 8 && light_isxdigit(nonce_uns[i]); ++i) {
1160 			ts = (ts << 4) + hex2int(nonce_uns[i]);
1161 		}
1162 		const time_t cur_ts = log_epoch_secs;
1163 		if (nonce[i] != ':'
1164 		    || ts > cur_ts || cur_ts - ts > 600) { /*(10 mins)*/
1165 			/* nonce is stale; have client regenerate digest */
1166 			buffer_free(b);
1167 			return mod_auth_send_401_unauthorized_digest(r, require, ai.dalgo);
1168 		}
1169 
1170 		send_nextnonce = (cur_ts - ts > 540); /*(9 mins)*/
1171 
1172 		if (require->nonce_secret) {
1173 			unsigned int rnd = 0;
1174 			for (int j = i+8; i < j && light_isxdigit(nonce_uns[i]); ++i) {
1175 				rnd = (rnd << 4) + hex2int(nonce_uns[i]);
1176 			}
1177 			if (nonce[i] != ':') {
1178 				/* nonce is invalid;
1179 				 * expect extra field w/ require->nonce_secret */
1180 				log_error(r->conf.errh, __FILE__, __LINE__,
1181 				  "digest: nonce invalid");
1182 				buffer_free(b);
1183 				return mod_auth_send_400_bad_request(r);
1184 			}
1185 			buffer * const tb = r->tmp_buf;
1186 			buffer_clear(tb);
1187 			mod_auth_append_nonce(tb, cur_ts, require, ai.dalgo, (int *)&rnd);
1188 			if (!buffer_eq_slen(tb, nonce, strlen(nonce))) {
1189 				/* nonce not generated using current require->nonce_secret */
1190 				log_error(r->conf.errh, __FILE__, __LINE__,
1191 				  "digest: nonce mismatch");
1192 				buffer_free(b);
1193 				return mod_auth_send_401_unauthorized_digest(r, require, 0);
1194 			}
1195 		}
1196 	}
1197 
1198 	switch (backend->digest(r, backend->p_d, &ai)) {
1199 	case HANDLER_GO_ON:
1200 		break;
1201 	case HANDLER_WAIT_FOR_EVENT:
1202 		buffer_free(b);
1203 		return HANDLER_WAIT_FOR_EVENT;
1204 	case HANDLER_FINISHED:
1205 		buffer_free(b);
1206 		return HANDLER_FINISHED;
1207 	case HANDLER_ERROR:
1208 	default:
1209 		r->keep_alive = 0; /*(disable keep-alive if unknown user)*/
1210 		buffer_free(b);
1211 		return mod_auth_send_401_unauthorized_digest(r, require, 0);
1212 	}
1213 
1214 	const char *m = get_http_method_name(r->http_method);
1215 	force_assert(m);
1216 
1217 	mod_auth_digest_mutate(&ai,m,uri,nonce,cnonce,nc,qop);
1218 
1219 	if (!http_auth_const_time_memeq(rdigest, ai.digest, ai.dlen)) {
1220 		/* digest not ok */
1221 		log_error(r->conf.errh, __FILE__, __LINE__,
1222 		  "digest: auth failed for %s: wrong password, IP: %s",
1223 		  username, r->con->dst_addr_buf->ptr);
1224 		r->keep_alive = 0; /*(disable keep-alive if bad password)*/
1225 
1226 		buffer_free(b);
1227 		return mod_auth_send_401_unauthorized_digest(r, require, 0);
1228 	}
1229 
1230 	/* value is our allow-rules */
1231 	if (!http_auth_match_rules(require, username, NULL, NULL)) {
1232 		buffer_free(b);
1233 		return mod_auth_send_401_unauthorized_digest(r, require, 0);
1234 	}
1235 
1236 	if (send_nextnonce) {
1237 			/*(send nextnonce when expiration is approaching)*/
1238 			buffer * const tb = r->tmp_buf;
1239 			const time_t cur_ts = log_epoch_secs;
1240 			mod_auth_digest_authentication_info(tb, cur_ts, require, ai.dalgo);
1241 			http_header_response_set(r, HTTP_HEADER_OTHER,
1242 			                         CONST_STR_LEN("Authentication-Info"),
1243 			                         CONST_BUF_LEN(tb));
1244 	}
1245 
1246 	http_auth_setenv(r, ai.username, ai.ulen, CONST_STR_LEN("Digest"));
1247 
1248 	buffer_free(b);
1249 
1250 	return HANDLER_GO_ON;
1251 }
1252 
1253 static handler_t mod_auth_send_401_unauthorized_digest(request_st * const r, const struct http_auth_require_t * const require, int nonce_stale) {
1254 	buffer * const tb = r->tmp_buf;
1255 	mod_auth_digest_www_authenticate(tb, log_epoch_secs, require, nonce_stale);
1256 	http_header_response_set(r, HTTP_HEADER_OTHER, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(tb));
1257 
1258 	r->http_status = 401;
1259 	r->handler_module = NULL;
1260 	return HANDLER_FINISHED;
1261 }
1262 
1263 static handler_t mod_auth_check_extern(request_st * const r, void *p_d, const struct http_auth_require_t * const require, const struct http_auth_backend_t * const backend) {
1264 	/* require REMOTE_USER already set */
1265 	const buffer *vb = http_header_env_get(r, CONST_STR_LEN("REMOTE_USER"));
1266 	UNUSED(p_d);
1267 	UNUSED(backend);
1268 	if (NULL != vb && http_auth_match_rules(require, vb->ptr, NULL, NULL)) {
1269 		return HANDLER_GO_ON;
1270 	} else {
1271 		r->http_status = 401;
1272 		r->handler_module = NULL;
1273 		return HANDLER_FINISHED;
1274 	}
1275 }
1276