Commit d4b55c4c authored by Dmitry Frank's avatar Dmitry Frank Committed by Cesanta Bot

Separate digest auth from HTTP headers parsing

PUBLISHED_FROM=f97569ae2f31ab94ce4875eae4d0a198f719c388
parent 7d547998
...@@ -3,6 +3,7 @@ title: "Server API reference" ...@@ -3,6 +3,7 @@ title: "Server API reference"
symbol_kind: "intro" symbol_kind: "intro"
decl_name: "http_server.h" decl_name: "http_server.h"
items: items:
- { name: mg_check_digest_auth.md }
- { name: mg_file_upload_handler.md } - { name: mg_file_upload_handler.md }
- { name: mg_get_http_basic_auth.md } - { name: mg_get_http_basic_auth.md }
- { name: mg_get_http_header.md } - { name: mg_get_http_header.md }
......
---
title: "mg_check_digest_auth()"
decl_name: "mg_check_digest_auth"
symbol_kind: "func"
signature: |
int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
struct mg_str username, struct mg_str cnonce,
struct mg_str response, struct mg_str qop,
struct mg_str nc, struct mg_str nonce,
struct mg_str auth_domain, FILE *fp);
---
Authenticates given response params against an opened password file.
Returns 1 if authenticated, 0 otherwise.
It's used by mg_http_check_digest_auth().
...@@ -6973,14 +6973,13 @@ static int mg_check_nonce(const char *nonce) { ...@@ -6973,14 +6973,13 @@ static int mg_check_nonce(const char *nonce) {
int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
FILE *fp) { FILE *fp) {
struct mg_str *hdr; struct mg_str *hdr;
char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)]; char username[50], cnonce[64], response[40], uri[200], qop[20], nc[20],
char user[50], cnonce[64], response[40], uri[200], qop[20], nc[20], nonce[30]; nonce[30];
char expected_response[33];
/* Parse "Authorization:" header, fail fast on parse error */ /* Parse "Authorization:" header, fail fast on parse error */
if (hm == NULL || fp == NULL || if (hm == NULL || fp == NULL ||
(hdr = mg_get_http_header(hm, "Authorization")) == NULL || (hdr = mg_get_http_header(hm, "Authorization")) == NULL ||
mg_http_parse_header(hdr, "username", user, sizeof(user)) == 0 || mg_http_parse_header(hdr, "username", username, sizeof(username)) == 0 ||
mg_http_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce)) == 0 || mg_http_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce)) == 0 ||
mg_http_parse_header(hdr, "response", response, sizeof(response)) == 0 || mg_http_parse_header(hdr, "response", response, sizeof(response)) == 0 ||
mg_http_parse_header(hdr, "uri", uri, sizeof(uri)) == 0 || mg_http_parse_header(hdr, "uri", uri, sizeof(uri)) == 0 ||
...@@ -6991,6 +6990,26 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, ...@@ -6991,6 +6990,26 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
return 0; return 0;
} }
/* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */
return mg_check_digest_auth(
hm->method,
mg_mk_str_n(
hm->uri.p,
hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0)),
mg_mk_str(username), mg_mk_str(cnonce), mg_mk_str(response),
mg_mk_str(qop), mg_mk_str(nc), mg_mk_str(nonce), mg_mk_str(auth_domain),
fp);
}
int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
struct mg_str username, struct mg_str cnonce,
struct mg_str response, struct mg_str qop,
struct mg_str nc, struct mg_str nonce,
struct mg_str auth_domain, FILE *fp) {
char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)];
char expected_response[33];
/* /*
* Read passwords file line by line. If should have htdigest format, * Read passwords file line by line. If should have htdigest format,
* i.e. each line should be a colon-separated sequence: * i.e. each line should be a colon-separated sequence:
...@@ -6998,18 +7017,16 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, ...@@ -6998,18 +7017,16 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
*/ */
while (fgets(buf, sizeof(buf), fp) != NULL) { while (fgets(buf, sizeof(buf), fp) != NULL) {
if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 && if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 &&
strcmp(user, f_user) == 0 && mg_vcmp(&username, f_user) == 0 &&
/* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */ mg_vcmp(&auth_domain, f_domain) == 0) {
strcmp(auth_domain, f_domain) == 0) { /* Username and domain matched, check the password */
/* User and domain matched, check the password */ mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1),
mg_mkmd5resp( nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len,
hm->method.p, hm->method.len, hm->uri.p, qop.p, qop.len, expected_response);
hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0),
f_ha1, strlen(f_ha1), nonce, strlen(nonce), nc, strlen(nc), cnonce,
strlen(cnonce), qop, strlen(qop), expected_response);
LOG(LL_DEBUG, LOG(LL_DEBUG,
("%s %s %s %s", user, f_domain, response, expected_response)); ("%.*s %s %.*s %s", (int) username.len, username.p, f_domain,
return mg_casecmp(response, expected_response) == 0; (int) response.len, response.p, expected_response));
return mg_ncasecmp(response.p, expected_response, response.len) == 0;
} }
} }
......
...@@ -4870,6 +4870,18 @@ void mg_register_http_endpoint_opt(struct mg_connection *nc, ...@@ -4870,6 +4870,18 @@ void mg_register_http_endpoint_opt(struct mg_connection *nc,
int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
FILE *fp); FILE *fp);
/*
* Authenticates given response params against an opened password file.
* Returns 1 if authenticated, 0 otherwise.
*
* It's used by mg_http_check_digest_auth().
*/
int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
struct mg_str username, struct mg_str cnonce,
struct mg_str response, struct mg_str qop,
struct mg_str nc, struct mg_str nonce,
struct mg_str auth_domain, FILE *fp);
/* /*
* Sends buffer `buf` of size `len` to the client using chunked HTTP encoding. * Sends buffer `buf` of size `len` to the client using chunked HTTP encoding.
* This function sends the buffer size as hex number + newline first, then * This function sends the buffer size as hex number + newline first, then
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment