| /* |
| This file is part of libmicrohttpd |
| Copyright (C) 2022 Evgeny Grin (Karlson2k) |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with this library. |
| If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| /** |
| * @file microhttpd/gen_auth.c |
| * @brief HTTP authorisation general functions |
| * @author Karlson2k (Evgeny Grin) |
| */ |
| |
| #include "gen_auth.h" |
| #include "internal.h" |
| #include "connection.h" |
| #include "mhd_str.h" |
| #include "mhd_assert.h" |
| |
| #ifdef BAUTH_SUPPORT |
| #include "basicauth.h" |
| #endif /* BAUTH_SUPPORT */ |
| #ifdef DAUTH_SUPPORT |
| #include "digestauth.h" |
| #endif /* DAUTH_SUPPORT */ |
| |
| #if ! defined(BAUTH_SUPPORT) && ! defined(DAUTH_SUPPORT) |
| #error This file requires Basic or Digest authentication support |
| #endif |
| |
| /** |
| * Type of authorisation |
| */ |
| enum MHD_AuthType |
| { |
| MHD_AUTHTYPE_NONE = 0,/**< No authorisation, unused */ |
| MHD_AUTHTYPE_BASIC, /**< Basic Authorisation, RFC 7617 */ |
| MHD_AUTHTYPE_DIGEST, /**< Digest Authorisation, RFC 7616 */ |
| MHD_AUTHTYPE_UNKNOWN, /**< Unknown/Unsupported authorisation type, unused */ |
| MHD_AUTHTYPE_INVALID /**< Wrong/broken authorisation header, unused */ |
| }; |
| |
| /** |
| * Find required "Authorization" request header |
| * @param c the connection with request |
| * @param type the type of the authorisation: basic or digest |
| * @param[out] auth_value will be set to the remaining of header value after |
| * authorisation token (after "Basic " or "Digest ") |
| * @return true if requested header is found, |
| * false otherwise |
| */ |
| static bool |
| find_auth_rq_header_ (const struct MHD_Connection *c, enum MHD_AuthType type, |
| struct _MHD_str_w_len *auth_value) |
| { |
| const struct MHD_HTTP_Req_Header *h; |
| const char *token; |
| size_t token_len; |
| |
| mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED <= c->state); |
| if (MHD_CONNECTION_HEADERS_PROCESSED > c->state) |
| return false; |
| |
| #ifdef DAUTH_SUPPORT |
| if (MHD_AUTHTYPE_DIGEST == type) |
| { |
| token = _MHD_AUTH_DIGEST_BASE; |
| token_len = MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE); |
| } |
| else /* combined with the next line */ |
| #endif /* DAUTH_SUPPORT */ |
| #ifdef BAUTH_SUPPORT |
| if (MHD_AUTHTYPE_BASIC == type) |
| { |
| token = _MHD_AUTH_BASIC_BASE; |
| token_len = MHD_STATICSTR_LEN_ (_MHD_AUTH_BASIC_BASE); |
| } |
| else /* combined with the next line */ |
| #endif /* BAUTH_SUPPORT */ |
| { |
| mhd_assert (0); |
| return false; |
| } |
| |
| for (h = c->rq.headers_received; NULL != h; h = h->next) |
| { |
| if (MHD_HEADER_KIND != h->kind) |
| continue; |
| if (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_AUTHORIZATION) != h->header_size) |
| continue; |
| if (token_len > h->value_size) |
| continue; |
| if (! MHD_str_equal_caseless_bin_n_ (MHD_HTTP_HEADER_AUTHORIZATION, |
| h->header, |
| MHD_STATICSTR_LEN_ ( \ |
| MHD_HTTP_HEADER_AUTHORIZATION))) |
| continue; |
| if (! MHD_str_equal_caseless_bin_n_ (h->value, token, token_len)) |
| continue; |
| /* Match only if token string is full header value or token is |
| * followed by space or tab |
| * Note: RFC 9110 (and RFC 7234) allows only space character, but |
| * tab is supported here as well for additional flexibility and uniformity |
| * as tabs are supported as separators between parameters. |
| */ |
| if ((token_len == h->value_size) || |
| (' ' == h->value[token_len]) || ('\t' == h->value[token_len])) |
| { |
| if (token_len != h->value_size) |
| { /* Skip whitespace */ |
| auth_value->str = h->value + token_len + 1; |
| auth_value->len = h->value_size - (token_len + 1); |
| } |
| else |
| { /* No whitespace to skip */ |
| auth_value->str = h->value + token_len; |
| auth_value->len = h->value_size - token_len; |
| } |
| return true; /* Found a match */ |
| } |
| } |
| return false; /* No matching header has been found */ |
| } |
| |
| |
| #ifdef BAUTH_SUPPORT |
| |
| |
| /** |
| * Parse request Authorization header parameters for Basic Authentication |
| * @param str the header string, everything after "Basic " substring |
| * @param str_len the length of @a str in characters |
| * @param[out] pbauth the pointer to the structure with Basic Authentication |
| * parameters |
| * @return true if parameters has been successfully parsed, |
| * false if format of the @a str is invalid |
| */ |
| static bool |
| parse_bauth_params (const char *str, |
| size_t str_len, |
| struct MHD_RqBAuth *pbauth) |
| { |
| size_t i; |
| |
| i = 0; |
| |
| /* Skip all whitespaces at start */ |
| while (i < str_len && (' ' == str[i] || '\t' == str[i])) |
| i++; |
| |
| if (str_len > i) |
| { |
| size_t token68_start; |
| size_t token68_len; |
| |
| /* 'i' points to the first non-whitespace char after scheme token */ |
| token68_start = i; |
| /* Find end of the token. Token cannot contain whitespace. */ |
| while (i < str_len && ' ' != str[i] && '\t' != str[i]) |
| { |
| if (0 == str[i]) |
| return false; /* Binary zero is not allowed */ |
| if ((',' == str[i]) || (';' == str[i])) |
| return false; /* Only single token68 is allowed */ |
| i++; |
| } |
| token68_len = i - token68_start; |
| mhd_assert (0 != token68_len); |
| |
| /* Skip all whitespaces */ |
| while (i < str_len && (' ' == str[i] || '\t' == str[i])) |
| i++; |
| /* Check whether any garbage is present at the end of the string */ |
| if (str_len != i) |
| return false; |
| else |
| { |
| /* No more data in the string, only single token68. */ |
| pbauth->token68.str = str + token68_start; |
| pbauth->token68.len = token68_len; |
| } |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Return request's Basic Authorisation parameters. |
| * |
| * Function return result of parsing of the request's "Authorization" header or |
| * returns cached parsing result if the header was already parsed for |
| * the current request. |
| * @param connection the connection to process |
| * @return the pointer to structure with Authentication parameters, |
| * NULL if no memory in memory pool, if called too early (before |
| * header has been received) or if no valid Basic Authorisation header |
| * found. |
| */ |
| const struct MHD_RqBAuth * |
| MHD_get_rq_bauth_params_ (struct MHD_Connection *connection) |
| { |
| struct _MHD_str_w_len h_auth_value; |
| struct MHD_RqBAuth *bauth; |
| |
| mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED <= connection->state); |
| |
| if (connection->rq.bauth_tried) |
| return connection->rq.bauth; |
| |
| if (MHD_CONNECTION_HEADERS_PROCESSED > connection->state) |
| return NULL; |
| |
| if (! find_auth_rq_header_ (connection, MHD_AUTHTYPE_BASIC, &h_auth_value)) |
| { |
| connection->rq.bauth_tried = true; |
| connection->rq.bauth = NULL; |
| return NULL; |
| } |
| |
| bauth = |
| (struct MHD_RqBAuth *) |
| MHD_connection_alloc_memory_ (connection, sizeof (struct MHD_RqBAuth)); |
| |
| if (NULL == bauth) |
| { |
| #ifdef HAVE_MESSAGES |
| MHD_DLOG (connection->daemon, |
| _ ("Not enough memory in the connection's pool to allocate " \ |
| "for Basic Authorization header parsing.\n")); |
| #endif /* HAVE_MESSAGES */ |
| return NULL; |
| } |
| |
| memset (bauth, 0, sizeof(struct MHD_RqBAuth)); |
| if (parse_bauth_params (h_auth_value.str, h_auth_value.len, bauth)) |
| connection->rq.bauth = bauth; |
| else |
| { |
| #ifdef HAVE_MESSAGES |
| MHD_DLOG (connection->daemon, |
| _ ("The Basic Authorization client's header has " |
| "incorrect format.\n")); |
| #endif /* HAVE_MESSAGES */ |
| connection->rq.bauth = NULL; |
| /* Memory in the pool remains allocated until next request */ |
| } |
| connection->rq.bauth_tried = true; |
| return connection->rq.bauth; |
| } |
| |
| |
| #endif /* BAUTH_SUPPORT */ |
| |
| #ifdef DAUTH_SUPPORT |
| |
| /** |
| * Helper structure to map token name to position where to put token's value |
| */ |
| struct dauth_token_param |
| { |
| const struct _MHD_cstr_w_len *const tk_name; |
| struct MHD_RqDAuthParam *const param; |
| }; |
| |
| |
| /** |
| * Get client's Digest Authorization algorithm type. |
| * If no algorithm is specified by client, MD5 is assumed. |
| * @param params the Digest Authorization 'algorithm' parameter |
| * @return the algorithm type |
| */ |
| static enum MHD_DigestAuthAlgo3 |
| get_rq_dauth_algo (const struct MHD_RqDAuthParam *const algo_param) |
| { |
| if (NULL == algo_param->value.str) |
| return MHD_DIGEST_AUTH_ALGO3_MD5; /* Assume MD5 by default */ |
| |
| if (algo_param->quoted) |
| { |
| if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ |
| algo_param->value.len, \ |
| _MHD_MD5_TOKEN)) |
| return MHD_DIGEST_AUTH_ALGO3_MD5; |
| if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ |
| algo_param->value.len, \ |
| _MHD_SHA256_TOKEN)) |
| return MHD_DIGEST_AUTH_ALGO3_SHA256; |
| if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ |
| algo_param->value.len, \ |
| _MHD_MD5_TOKEN _MHD_SESS_TOKEN)) |
| return MHD_DIGEST_AUTH_ALGO3_SHA512_256; |
| if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ |
| algo_param->value.len, \ |
| _MHD_SHA512_256_TOKEN \ |
| _MHD_SESS_TOKEN)) |
| |
| /* Algorithms below are not supported by MHD for authentication */ |
| |
| return MHD_DIGEST_AUTH_ALGO3_MD5_SESSION; |
| if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ |
| algo_param->value.len, \ |
| _MHD_SHA256_TOKEN \ |
| _MHD_SESS_TOKEN)) |
| return MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION; |
| if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ |
| algo_param->value.len, \ |
| _MHD_SHA512_256_TOKEN)) |
| return MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION; |
| |
| /* No known algorithm has been detected */ |
| return MHD_DIGEST_AUTH_ALGO3_INVALID; |
| } |
| /* The algorithm value is not quoted */ |
| if (MHD_str_equal_caseless_s_bin_n_ (_MHD_MD5_TOKEN, \ |
| algo_param->value.str, \ |
| algo_param->value.len)) |
| return MHD_DIGEST_AUTH_ALGO3_MD5; |
| if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA256_TOKEN, \ |
| algo_param->value.str, \ |
| algo_param->value.len)) |
| return MHD_DIGEST_AUTH_ALGO3_SHA256; |
| if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA512_256_TOKEN, \ |
| algo_param->value.str, \ |
| algo_param->value.len)) |
| return MHD_DIGEST_AUTH_ALGO3_SHA512_256; |
| |
| /* Algorithms below are not supported by MHD for authentication */ |
| |
| if (MHD_str_equal_caseless_s_bin_n_ (_MHD_MD5_TOKEN _MHD_SESS_TOKEN, \ |
| algo_param->value.str, \ |
| algo_param->value.len)) |
| return MHD_DIGEST_AUTH_ALGO3_MD5_SESSION; |
| if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA256_TOKEN _MHD_SESS_TOKEN, \ |
| algo_param->value.str, \ |
| algo_param->value.len)) |
| return MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION; |
| if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA512_256_TOKEN _MHD_SESS_TOKEN, \ |
| algo_param->value.str, \ |
| algo_param->value.len)) |
| return MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION; |
| |
| /* No known algorithm has been detected */ |
| return MHD_DIGEST_AUTH_ALGO3_INVALID; |
| } |
| |
| |
| /** |
| * Get QOP ('quality of protection') type. |
| * @param qop_param the Digest Authorization 'QOP' parameter |
| * @return detected QOP ('quality of protection') type. |
| */ |
| static enum MHD_DigestAuthQOP |
| get_rq_dauth_qop (const struct MHD_RqDAuthParam *const qop_param) |
| { |
| if (NULL == qop_param->value.str) |
| return MHD_DIGEST_AUTH_QOP_NONE; |
| if (qop_param->quoted) |
| { |
| if (MHD_str_equal_caseless_quoted_s_bin_n (qop_param->value.str, \ |
| qop_param->value.len, \ |
| MHD_TOKEN_AUTH_)) |
| return MHD_DIGEST_AUTH_QOP_AUTH; |
| if (MHD_str_equal_caseless_quoted_s_bin_n (qop_param->value.str, \ |
| qop_param->value.len, \ |
| MHD_TOKEN_AUTH_INT_)) |
| return MHD_DIGEST_AUTH_QOP_AUTH_INT; |
| } |
| else |
| { |
| if (MHD_str_equal_caseless_s_bin_n_ (MHD_TOKEN_AUTH_, \ |
| qop_param->value.str, \ |
| qop_param->value.len)) |
| return MHD_DIGEST_AUTH_QOP_AUTH; |
| if (MHD_str_equal_caseless_s_bin_n_ (MHD_TOKEN_AUTH_INT_, \ |
| qop_param->value.str, \ |
| qop_param->value.len)) |
| return MHD_DIGEST_AUTH_QOP_AUTH_INT; |
| } |
| /* No know QOP has been detected */ |
| return MHD_DIGEST_AUTH_QOP_INVALID; |
| } |
| |
| |
| /** |
| * Parse request Authorization header parameters for Digest Authentication |
| * @param str the header string, everything after "Digest " substring |
| * @param str_len the length of @a str in characters |
| * @param[out] pdauth the pointer to the structure with Digest Authentication |
| * parameters |
| * @return true if parameters has been successfully parsed, |
| * false if format of the @a str is invalid |
| */ |
| static bool |
| parse_dauth_params (const char *str, |
| const size_t str_len, |
| struct MHD_RqDAuth *pdauth) |
| { |
| static const struct _MHD_cstr_w_len nonce_tk = _MHD_S_STR_W_LEN ("nonce"); |
| static const struct _MHD_cstr_w_len opaque_tk = _MHD_S_STR_W_LEN ("opaque"); |
| static const struct _MHD_cstr_w_len algorithm_tk = |
| _MHD_S_STR_W_LEN ("algorithm"); |
| static const struct _MHD_cstr_w_len response_tk = |
| _MHD_S_STR_W_LEN ("response"); |
| static const struct _MHD_cstr_w_len username_tk = |
| _MHD_S_STR_W_LEN ("username"); |
| static const struct _MHD_cstr_w_len username_ext_tk = |
| _MHD_S_STR_W_LEN ("username*"); |
| static const struct _MHD_cstr_w_len realm_tk = _MHD_S_STR_W_LEN ("realm"); |
| static const struct _MHD_cstr_w_len uri_tk = _MHD_S_STR_W_LEN ("uri"); |
| static const struct _MHD_cstr_w_len qop_tk = _MHD_S_STR_W_LEN ("qop"); |
| static const struct _MHD_cstr_w_len cnonce_tk = _MHD_S_STR_W_LEN ("cnonce"); |
| static const struct _MHD_cstr_w_len nc_tk = _MHD_S_STR_W_LEN ("nc"); |
| static const struct _MHD_cstr_w_len userhash_tk = |
| _MHD_S_STR_W_LEN ("userhash"); |
| struct MHD_RqDAuthParam userhash; |
| struct MHD_RqDAuthParam algorithm; |
| struct dauth_token_param map[] = { |
| {&nonce_tk, &(pdauth->nonce)}, |
| {&opaque_tk, &(pdauth->opaque)}, |
| {&algorithm_tk, &algorithm}, |
| {&response_tk, &(pdauth->response)}, |
| {&username_tk, &(pdauth->username)}, |
| {&username_ext_tk, &(pdauth->username_ext)}, |
| {&realm_tk, &(pdauth->realm)}, |
| {&uri_tk, &(pdauth->uri)}, |
| {&qop_tk, &(pdauth->qop_raw)}, |
| {&cnonce_tk, &(pdauth->cnonce)}, |
| {&nc_tk, &(pdauth->nc)}, |
| {&userhash_tk, &userhash} |
| }; |
| size_t i; |
| size_t p; |
| |
| memset (&userhash, 0, sizeof(userhash)); |
| memset (&algorithm, 0, sizeof(algorithm)); |
| i = 0; |
| |
| /* Skip all whitespaces at start */ |
| while (i < str_len && (' ' == str[i] || '\t' == str[i])) |
| i++; |
| |
| while (str_len > i) |
| { |
| size_t left; |
| mhd_assert (' ' != str[i]); |
| mhd_assert ('\t' != str[i]); |
| |
| left = str_len - i; |
| if ('=' == str[i]) |
| return false; /* The equal sign is not allowed as the first character */ |
| for (p = 0; p < sizeof(map) / sizeof(map[0]); p++) |
| { |
| struct dauth_token_param *const aparam = map + p; |
| if ( (aparam->tk_name->len <= left) && |
| MHD_str_equal_caseless_bin_n_ (str + i, aparam->tk_name->str, |
| aparam->tk_name->len) && |
| ((aparam->tk_name->len == left) || |
| ('=' == str[i + aparam->tk_name->len]) || |
| (' ' == str[i + aparam->tk_name->len]) || |
| ('\t' == str[i + aparam->tk_name->len]) || |
| (',' == str[i + aparam->tk_name->len]) || |
| (';' == str[i + aparam->tk_name->len])) ) |
| { |
| size_t value_start; |
| size_t value_len; |
| bool quoted; /* Only mark as "quoted" if backslash-escape used */ |
| |
| if (aparam->tk_name->len == left) |
| return false; /* No equal sign after parameter name, broken data */ |
| |
| quoted = false; |
| i += aparam->tk_name->len; |
| /* Skip all whitespaces before '=' */ |
| while (str_len > i && (' ' == str[i] || '\t' == str[i])) |
| i++; |
| if ((i == str_len) || ('=' != str[i])) |
| return false; /* No equal sign, broken data */ |
| i++; |
| /* Skip all whitespaces after '=' */ |
| while (str_len > i && (' ' == str[i] || '\t' == str[i])) |
| i++; |
| if ((str_len > i) && ('"' == str[i])) |
| { /* Value is in quotation marks */ |
| i++; /* Advance after the opening quote */ |
| value_start = i; |
| while (str_len > i && '"' != str[i]) |
| { |
| if ('\\' == str[i]) |
| { |
| i++; |
| quoted = true; /* Have escaped chars */ |
| } |
| if (0 == str[i]) |
| return false; /* Binary zero in parameter value */ |
| i++; |
| } |
| if (str_len <= i) |
| return false; /* No closing quote */ |
| mhd_assert ('"' == str[i]); |
| value_len = i - value_start; |
| i++; /* Advance after the closing quote */ |
| } |
| else |
| { |
| value_start = i; |
| while (str_len > i && ',' != str[i] && |
| ' ' != str[i] && '\t' != str[i] && ';' != str[i]) |
| { |
| if (0 == str[i]) |
| return false; /* Binary zero in parameter value */ |
| i++; |
| } |
| if (';' == str[i]) |
| return false; /* Semicolon in parameter value */ |
| value_len = i - value_start; |
| } |
| /* Skip all whitespaces after parameter value */ |
| while (str_len > i && (' ' == str[i] || '\t' == str[i])) |
| i++; |
| if ((str_len > i) && (',' != str[i])) |
| return false; /* Garbage after parameter value */ |
| |
| /* Have valid parameter name and value */ |
| mhd_assert (! quoted || 0 != value_len); |
| aparam->param->value.str = str + value_start; |
| aparam->param->value.len = value_len; |
| aparam->param->quoted = quoted; |
| |
| break; /* Found matching parameter name */ |
| } |
| } |
| if (p == sizeof(map) / sizeof(map[0])) |
| { |
| /* No matching parameter name */ |
| while (str_len > i && ',' != str[i]) |
| { |
| if ((0 == str[i]) || (';' == str[i])) |
| return false; /* Not allowed characters */ |
| if ('"' == str[i]) |
| { /* Skip quoted part */ |
| i++; /* Advance after the opening quote */ |
| while (str_len > i && '"' != str[i]) |
| { |
| if (0 == str[i]) |
| return false; /* Binary zero is not allowed */ |
| if ('\\' == str[i]) |
| i++; /* Skip escaped char */ |
| i++; |
| } |
| if (str_len <= i) |
| return false; /* No closing quote */ |
| mhd_assert ('"' == str[i]); |
| } |
| i++; |
| } |
| } |
| mhd_assert (str_len == i || ',' == str[i]); |
| if (str_len > i) |
| i++; /* Advance after ',' */ |
| /* Skip all whitespaces before next parameter name */ |
| while (i < str_len && (' ' == str[i] || '\t' == str[i])) |
| i++; |
| } |
| |
| /* Postprocess values */ |
| |
| if (NULL != userhash.value.str) |
| { |
| if (userhash.quoted) |
| pdauth->userhash = |
| MHD_str_equal_caseless_quoted_s_bin_n (userhash.value.str, \ |
| userhash.value.len, \ |
| "true"); |
| else |
| pdauth->userhash = |
| MHD_str_equal_caseless_s_bin_n_ ("true", userhash.value.str, \ |
| userhash.value.len); |
| |
| } |
| else |
| pdauth->userhash = false; |
| |
| pdauth->algo3 = get_rq_dauth_algo (&algorithm); |
| pdauth->qop = get_rq_dauth_qop (&pdauth->qop_raw); |
| |
| return true; |
| } |
| |
| |
| /** |
| * Return request's Digest Authorisation parameters. |
| * |
| * Function return result of parsing of the request's "Authorization" header or |
| * returns cached parsing result if the header was already parsed for |
| * the current request. |
| * @param connection the connection to process |
| * @return the pointer to structure with Authentication parameters, |
| * NULL if no memory in memory pool, if called too early (before |
| * header has been received) or if no valid Basic Authorisation header |
| * found. |
| */ |
| const struct MHD_RqDAuth * |
| MHD_get_rq_dauth_params_ (struct MHD_Connection *connection) |
| { |
| struct _MHD_str_w_len h_auth_value; |
| struct MHD_RqDAuth *dauth; |
| |
| mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED <= connection->state); |
| |
| if (connection->rq.dauth_tried) |
| return connection->rq.dauth; |
| |
| if (MHD_CONNECTION_HEADERS_PROCESSED > connection->state) |
| return NULL; |
| |
| if (! find_auth_rq_header_ (connection, MHD_AUTHTYPE_DIGEST, &h_auth_value)) |
| { |
| connection->rq.dauth_tried = true; |
| connection->rq.dauth = NULL; |
| return NULL; |
| } |
| |
| dauth = |
| (struct MHD_RqDAuth *) |
| MHD_connection_alloc_memory_ (connection, sizeof (struct MHD_RqDAuth)); |
| |
| if (NULL == dauth) |
| { |
| #ifdef HAVE_MESSAGES |
| MHD_DLOG (connection->daemon, |
| _ ("Not enough memory in the connection's pool to allocate " \ |
| "for Digest Authorization header parsing.\n")); |
| #endif /* HAVE_MESSAGES */ |
| return NULL; |
| } |
| |
| memset (dauth, 0, sizeof(struct MHD_RqDAuth)); |
| if (parse_dauth_params (h_auth_value.str, h_auth_value.len, dauth)) |
| connection->rq.dauth = dauth; |
| else |
| { |
| #ifdef HAVE_MESSAGES |
| MHD_DLOG (connection->daemon, |
| _ ("The Digest Authorization client's header has " |
| "incorrect format.\n")); |
| #endif /* HAVE_MESSAGES */ |
| connection->rq.dauth = NULL; |
| /* Memory in the pool remains allocated until next request */ |
| } |
| connection->rq.dauth_tried = true; |
| return connection->rq.dauth; |
| } |
| |
| |
| #endif /* DAUTH_SUPPORT */ |