[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libmicrohttpd] 07/15: Added new functions MHD_digest_auth_get_request_i
From: |
gnunet |
Subject: |
[libmicrohttpd] 07/15: Added new functions MHD_digest_auth_get_request_info3() and MHD_digest_auth_get_username3() |
Date: |
Tue, 19 Jul 2022 16:51:15 +0200 |
This is an automated email from the git hooks/post-receive script.
karlson2k pushed a commit to branch master
in repository libmicrohttpd.
commit 98b3c68aabae5e9a095e665f72a3bde209ed8a52
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Wed Jun 22 16:37:14 2022 +0300
Added new functions MHD_digest_auth_get_request_info3() and
MHD_digest_auth_get_username3()
---
src/include/microhttpd.h | 328 ++++++++++++++++++++++++-
src/microhttpd/digestauth.c | 568 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 895 insertions(+), 1 deletion(-)
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 67f26bc3..e8e4da07 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -96,7 +96,7 @@ extern "C"
* they are parsed as decimal numbers.
* Example: 0x01093001 = 1.9.30-1.
*/
-#define MHD_VERSION 0x00097518
+#define MHD_VERSION 0x00097519
/* If generic headers don't work on your platform, include headers
which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t',
@@ -4334,6 +4334,331 @@ MHD_destroy_post_processor (struct MHD_PostProcessor
*pp);
*/
#define MHD_INVALID_NONCE -1
+/**
+ * The flag indicating non-session algorithm types,
+ * like 'MD5' or 'SHA-256'.
+ * @note Available since #MHD_VERSION 0x00097519
+ */
+#define MHD_DIGEST_AUTH_ALGO3_NON_SESSION (1 << 6)
+
+/**
+ * The flag indicating session algorithm types,
+ * like 'MD5-sess' or 'SHA-256-sess'.
+ * @note Available since #MHD_VERSION 0x00097519
+ */
+#define MHD_DIGEST_AUTH_ALGO3_SESSION (1 << 7)
+
+/**
+ * Digest algorithm identification
+ * @warning Do not be confused with #MHD_DigestAuthAlgorithm,
+ * which uses other values!
+ * @note Available since #MHD_VERSION 0x00097519
+ */
+enum MHD_DigestAuthAlgo3
+{
+ /**
+ * Unknown or wrong algorithm type.
+ * Used in struct MHD_DigestAuthInfo to indicate client value that
+ * cannot by identified.
+ */
+ MHD_DIGEST_AUTH_ALGO3_INVALID = 0,
+ /**
+ * The 'MD5' algorithm.
+ */
+ MHD_DIGEST_AUTH_ALGO3_MD5 =
+ (1 << 0) | MHD_DIGEST_AUTH_ALGO3_NON_SESSION,
+ /**
+ * The 'MD5-sess' algorithm.
+ * Not supported by MHD.
+ */
+ MHD_DIGEST_AUTH_ALGO3_MD5_SESSION =
+ (1 << 0) | MHD_DIGEST_AUTH_ALGO3_SESSION,
+ /**
+ * The 'SHA-256' algorithm.
+ */
+ MHD_DIGEST_AUTH_ALGO3_SHA256 =
+ (1 << 1) | MHD_DIGEST_AUTH_ALGO3_NON_SESSION,
+ /**
+ * The 'SHA-256-sess' algorithm.
+ * Not supported by MHD.
+ */
+ MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION =
+ (1 << 1) | MHD_DIGEST_AUTH_ALGO3_SESSION,
+ /**
+ * The 'SHA-512-256' (SHA-512/256) algorithm.
+ * Not supported by MHD.
+ */
+ MHD_DIGEST_AUTH_ALGO3_SHA512_256 =
+ (1 << 2) | MHD_DIGEST_AUTH_ALGO3_NON_SESSION,
+ /**
+ * The 'SHA-512-256-sess' (SHA-512/256 session) algorithm.
+ * Not supported by MHD.
+ */
+ MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION =
+ (1 << 2) | MHD_DIGEST_AUTH_ALGO3_SESSION,
+ /**
+ * Any non-session algorithm, MHD will choose.
+ */
+ MHD_DIGEST_AUTH_ALGO3_ANY_NON_SESSION =
+ (0x3F) | MHD_DIGEST_AUTH_ALGO3_NON_SESSION,
+ /**
+ * Any session algorithm, MHD will choose.
+ * Not supported by MHD.
+ */
+ MHD_DIGEST_AUTH_ALGO3_ANY_SESSION =
+ (0x3F) | MHD_DIGEST_AUTH_ALGO3_SESSION,
+ /**
+ * Any algorithm, MHD will choose.
+ */
+ MHD_DIGEST_AUTH_ALGO3_ANY =
+ (0x3F) | MHD_DIGEST_AUTH_ALGO3_NON_SESSION | MHD_DIGEST_AUTH_ALGO3_SESSION
+} _MHD_FLAGS_ENUM;
+
+/**
+ * The type of username used by client in Digest Authorization header
+ *
+ * @note Available since #MHD_VERSION 0x00097519
+ */
+enum MHD_DigestAuthUsernameType
+{
+ /**
+ * No username parameter in in Digest Authorization header.
+ * This should be treated as an error.
+ */
+ MHD_DIGEST_AUTH_UNAME_TYPE_MISSING = 0,
+ /**
+ * The 'username' parameter is used to specify the username.
+ */
+ MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD = 1,
+ /**
+ * The username is specified by 'username*' parameter with
+ * the extended notation (see RFC 5987 #section-3.2.1).
+ * The only difference between standard and extended types is
+ * the way how username value is encoded in the header.
+ */
+ MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED = 2,
+ /**
+ * The username provided in form of 'userhash' as
+ * specified by RFC 7616 #section-3.4.4.
+ */
+ MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH = 3,
+ /**
+ * The invalid combination of username parameters are used by client.
+ * Either:
+ * * both 'username' and 'username*' are used
+ * * 'username*' is used with 'userhash=true'
+ * * 'username*' used with invalid extended notation
+ * * 'username' is not hexadecimal digits, while 'userhash' set to 'true'
+ */
+ MHD_DIGEST_AUTH_UNAME_TYPE_INVALID = 15
+} _MHD_FIXED_ENUM;
+
+/**
+ * The QOP ('quality of protection') types.
+ * @note Available since #MHD_VERSION 0x00097519
+ */
+enum MHD_DigestAuthQOP
+{
+ /**
+ * Invalid/unknown QOP.
+ * Used in struct MHD_DigestAuthInfo to indicate client value that
+ * cannot by identified.
+ */
+ MHD_DIGEST_AUTH_QOP_INVALID = 0,
+ /**
+ * No QOP value.
+ */
+ MHD_DIGEST_AUTH_QOP_NONE = 1 << 0,
+ /**
+ * The 'auth' QOP type.
+ */
+ MHD_DIGEST_AUTH_QOP_AUTH = 1 << 1,
+ /**
+ * The 'auth-int' QOP type.
+ * Not supported by MHD.
+ */
+ MHD_DIGEST_AUTH_QOP_AUTH_INT = 1 << 2
+} _MHD_FLAGS_ENUM;
+
+/**
+ * The invalid value of 'nc' parameter in client Digest Authorization header.
+ * @note Available since #MHD_VERSION 0x00097519
+ */
+#define MHD_DIGEST_AUTH_INVALID_NC_VALUE (0)
+
+/**
+ * Information from Digest Authorization client's header.
+ *
+ * All buffers pointed by any struct members are freed when #MHD_free() is
+ * called for pointer to this structure.
+ *
+ * Application may modify buffers as needed until #MHD_free() is called for
+ * pointer to this structure
+ * @note Available since #MHD_VERSION 0x00097519
+ */
+struct MHD_DigestAuthInfo
+{
+ /**
+ * The algorithm as defined by client.
+ * Set automatically to MD5 if not specified by client.
+ * No "group" (ALGO3_ANY) values are used.
+ * @warning Do not be confused with #MHD_DigestAuthAlgorithm,
+ * which uses other values!
+ */
+ enum MHD_DigestAuthAlgo3 algo;
+ /**
+ * The type of username used by client.
+ */
+ enum MHD_DigestAuthUsernameType uname_type;
+ /**
+ * The username string.
+ * Valid only if username is standard, extended, or userhash.
+ * For userhash this is unqoted string without decoding of the
+ * hexadecimal digits (as provided by client).
+ * If extended notation is used, this string is pct-decoded string
+ * with charset and language tag removed (i.e. it is original username
+ * extracted from the extended notation).
+ * This can be NULL is username is missing or invalid.
+ */
+ char *username;
+ /**
+ * The length of the @a username.
+ * When the @a username is NULL, this member is always zero.
+ */
+ size_t username_len;
+ /**
+ * The userhash decoded to binary form.
+ * Used only if username type is userhash, always NULL otherwise.
+ * @warning this is a binary data, no zero termination
+ */
+ uint8_t *userhash_bin;
+ /**
+ * The number of bytes pointed by the @a userhash_bin.
+ * When the @a userhash_bin is NULL, this member is always zero.
+ */
+ size_t userhash_bin_size;
+ /**
+ * The 'opaque' parameter value, as specified by client.
+ * NULL if not specified by client.
+ */
+ char *opaque;
+ /**
+ * The length of the @a opaque.
+ * When the @a opaque is NULL, this member is always zero.
+ */
+ size_t opaque_len;
+ /**
+ * The 'realm' parameter value, as specified by client.
+ * NULL if not specified by client.
+ */
+ char *realm;
+ /**
+ * The length of the @a realm.
+ * When the @a realm is NULL, this member is always zero.
+ */
+ size_t realm_len;
+ /**
+ * The 'qop' parameter value.
+ */
+ enum MHD_DigestAuthQOP qop;
+ /**
+ * The length of the 'cnonce' parameter value, including possible
+ * backslash-escape characters.
+ * 'cnonce' is used in hash calculation, which is CPU-intensive procedure.
+ * An applicaion may want to reject too large cnonces to limit the CPU load.
+ * A few kilobytes is a reasonable limit, typically cnonce is just 32-160
+ * characters long.
+ */
+ size_t cnonce_len;
+ /**
+ * The nc parameter value.
+ * Can be used by application to limit the number of nonce re-uses. If @ nc
+ * is higher than application wants to allow, then fail response with
+ * 'stale=true' could be used to ask force client to get the fresh 'nonce'.
+ * If not specified by client or does not have hexadecimal digits only, the
+ * value is #MHD_DIGEST_AUTH_INVALID_NC_VALUE.
+ */
+ uint32_t nc;
+};
+
+/**
+ * Get information about Digest Authorization client's header.
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no valid Digest Authorization header is used in the request;
+ * a pointer to the structure with information if the valid request
+ * header found, free using #MHD_free().
+ * @note Available since #MHD_VERSION 0x00097519
+ * @ingroup authentication
+ */
+_MHD_EXTERN struct MHD_DigestAuthInfo *
+MHD_digest_auth_get_request_info3 (struct MHD_Connection *connection);
+
+
+/**
+ * Information from Digest Authorization client's header.
+ *
+ * All buffers pointed by any struct members are freed when #MHD_free() is
+ * called for pointer to this structure.
+ *
+ * Application may modify buffers as needed until #MHD_free() is called for
+ * pointer to this structure
+ * @note Available since #MHD_VERSION 0x00097519
+ */
+struct MHD_DigestAuthUsernameInfo
+{
+ /**
+ * The type of username used by client.
+ * The 'invalid' and 'missing' types are not used in this structure,
+ * instead NULL is returned by #MHD_digest_auth_get_username3().
+ */
+ enum MHD_DigestAuthUsernameType uname_type;
+ /**
+ * The username string.
+ * Valid only if username is standard, extended, or userhash.
+ * For userhash this is unqoted string without decoding of the
+ * hexadecimal digits (as provided by client).
+ * If extended notation is used, this string is pct-decoded string
+ * with charset and language tag removed (i.e. it is original username
+ * extracted from the extended notation).
+ * This can be NULL is username is missing or invalid.
+ */
+ char *username;
+ /**
+ * The length of the @a username.
+ * When the @a username is NULL, this member is always zero.
+ */
+ size_t username_len;
+ /**
+ * The userhash decoded to binary form.
+ * Used only if username type is userhash, always NULL if not used.
+ * @warning this is a binary data, no zero termination
+ */
+ uint8_t *userhash_bin;
+ /**
+ * The number of bytes pointed by the @a userhash_bin.
+ * When the @a userhash_bin is NULL, this member is always zero.
+ */
+ size_t userhash_bin_size;
+};
+
+/**
+ * Get the username from Digest Authorization client's header.
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no valid Digest Authorization header is used in the request,
+ * or no username parameter is present in the header, or username is
+ * provided incorrectly by client (see description for
+ * #MHD_DIGEST_AUTH_UNAME_TYPE_INVALID);
+ * a pointer structure with information if the valid request header
+ * found, free using #MHD_free().
+ * @sa MHD_digest_auth_get_request_info3() provides more complete information
+ * @note Available since #MHD_VERSION 0x00097519
+ * @ingroup authentication
+ */
+_MHD_EXTERN struct MHD_DigestAuthUsernameInfo *
+MHD_digest_auth_get_username3 (struct MHD_Connection *connection);
+
/**
* Get the username from the authorization header sent by the client
@@ -4341,6 +4666,7 @@ MHD_destroy_post_processor (struct MHD_PostProcessor *pp);
* @param connection The MHD connection structure
* @return NULL if no username could be found, a pointer
* to the username if found, free using #MHD_free().
+ * @deprecated use MHD_digest_auth_get_username3()
* @ingroup authentication
*/
_MHD_EXTERN char *
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index 35c2deb5..5af1cf07 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -146,11 +146,28 @@
*/
#define _MHD_SHA256_TOKEN "SHA-256"
+/**
+ * The token for SHA-512/256 algorithm.
+ * Unsupported currently by MHD for authentication.
+ */
+#define _MHD_SHA512_256_TOKEN "SHA-512-256"
+
/**
* The postfix token for "session" algorithms.
*/
#define _MHD_SESS_TOKEN "-sess"
+/**
+ * The required prefix of parameter with the extended notation
+ */
+#define MHD_DAUTH_EXT_PARAM_PREFIX "UTF-8'"
+
+/**
+ * The minimal size of the prefix for parameter with the extended notation
+ */
+#define MHD_DAUTH_EXT_PARAM_MIN_LEN \
+ MHD_STATICSTR_LEN_(MHD_DAUTH_EXT_PARAM_PREFIX "'")
+
/**
* The result of nonce-nc map array check.
*/
@@ -858,6 +875,557 @@ check_nonce_nc (struct MHD_Connection *connection,
}
+/**
+ * Get username type used by the client.
+ * This function does not check whether userhash can be decoded or
+ * extended notation (if used) is valid.
+ * @param params the Digest Authorization parameters
+ * @return the type of username
+ */
+_MHD_static_inline enum MHD_DigestAuthUsernameType
+get_rq_uname_type (const struct MHD_RqDAuth *params)
+{
+ if (NULL != params->username.value.str)
+ {
+ if (NULL == params->username_ext.value.str)
+ return params->userhash ?
+ MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH :
+ MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD;
+ else /* Both 'username' and 'username*' are used */
+ return MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
+ }
+ else if (NULL != params->username_ext.value.str)
+ {
+ if (! params->username_ext.quoted && ! params->userhash &&
+ (MHD_DAUTH_EXT_PARAM_MIN_LEN <= params->username_ext.value.len) )
+ return MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED;
+ else
+ return MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
+ }
+
+ return MHD_DIGEST_AUTH_UNAME_TYPE_MISSING;
+}
+
+
+/**
+ * Get total size required for 'username' and 'userhash_bin'
+ * @param params the Digest Authorization parameters
+ * @param uname_type the type of username
+ * @return the total size required for 'username' and
+ * 'userhash_bin' is userhash is used
+ */
+_MHD_static_inline size_t
+get_rq_unames_size (const struct MHD_RqDAuth *params,
+ enum MHD_DigestAuthUsernameType uname_type)
+{
+ size_t s;
+
+ mhd_assert (get_rq_uname_type (params) == uname_type);
+ s = 0;
+ if ((MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD == uname_type) ||
+ (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type) )
+ {
+ s += params->username.value.len + 1; /* Add one byte for zero-termination
*/
+ if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type)
+ s += (params->username.value.len + 1) / 2;
+ }
+ else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type)
+ s += params->username_ext.value.len + 1; /* Add one byte for
zero-termination */
+ return s;
+}
+
+
+/**
+ * Get client's Digest Authorization algorithm type.
+ * If no algorithm is specified by client, MD5 is assumed.
+ * @param params the Digest Authorization parameters
+ * @return the algorithm type
+ */
+static enum MHD_DigestAuthAlgo3
+get_rq_algo (const struct MHD_RqDAuth *params)
+{
+ const struct MHD_RqDAuthParam *const algo_param =
+ ¶ms->algorithm;
+ 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_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;
+
+ /* Algorithms below are not supported by MHD for authentication */
+
+ 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;
+ if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \
+ algo_param->value.len, \
+ _MHD_SHA512_256_TOKEN \
+ _MHD_SESS_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_MD5;
+ 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;
+ 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_MD5;
+
+ /* Algorithms below are not supported by MHD for authentication */
+
+ 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_MD5;
+ 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_MD5;
+
+ /* No known algorithm has been detected */
+ return MHD_DIGEST_AUTH_ALGO3_INVALID;
+}
+
+
+/**
+ * Get unquoted version of Digest Authorization parameter.
+ * This function automatically zero-teminate the result.
+ * @param param the parameter to extract
+ * @param[out] buf the output buffer, must be enough size to hold the result,
+ * the recommended size is 'param->value.len + 1'
+ * @return the size of the result, not including the terminating zero
+ */
+static size_t
+get_rq_param_unquoted_copy_z (const struct MHD_RqDAuthParam *param, char *buf)
+{
+ size_t len;
+ mhd_assert (NULL != param->value.str);
+ if (! param->quoted)
+ {
+ memcpy (buf, param->value.str, param->value.len);
+ buf [param->value.len] = 0;
+ return param->value.len;
+ }
+
+ len = MHD_str_unquote (param->value.str, param->value.len, buf);
+ mhd_assert (0 != len);
+ mhd_assert (len < param->value.len);
+ buf[len] = 0;
+ return len;
+}
+
+
+/**
+ * Get decoded version of username from extended notation.
+ * This function automatically zero-teminate the result.
+ * @param uname_ext the string of client's 'username*' parameter value
+ * @param uname_ext_len the length of @a uname_ext in chars
+ * @param[out] buf the output buffer to put decoded username value
+ * @param buf_size the size of @a buf
+ * @return the number of characters copied to the output buffer or
+ * -1 if wrong extended notation is used.
+ */
+static ssize_t
+get_rq_extended_uname_copy_z (const char *uname_ext, size_t uname_ext_len,
+ char *buf, size_t buf_size)
+{
+ size_t r;
+ size_t w;
+ if ((size_t) SSIZE_MAX < uname_ext_len)
+ return -1; /* Too long input string */
+
+ if (MHD_DAUTH_EXT_PARAM_MIN_LEN > uname_ext_len)
+ return -1; /* Required prefix is missing */
+
+ if (! MHD_str_equal_caseless_bin_n_ (uname_ext, MHD_DAUTH_EXT_PARAM_PREFIX,
+ MHD_STATICSTR_LEN_ ( \
+ MHD_DAUTH_EXT_PARAM_PREFIX)))
+ return -1; /* Only UTF-8 is supported, as it is implied by RFC 7616 */
+
+ r = MHD_STATICSTR_LEN_ (MHD_DAUTH_EXT_PARAM_PREFIX);
+ /* Skip language tag */
+ while (r < uname_ext_len && '\'' != uname_ext[r])
+ {
+ const char chr = uname_ext[r];
+ if ((' ' == chr) || ('\t' == chr) || ('\"' == chr) || (',' == chr) ||
+ (';' == chr) )
+ return -1; /* Wrong char in language tag */
+ r++;
+ }
+ if (r >= uname_ext_len)
+ return -1; /* The end of the language tag was not found */
+ r++; /* Advance to the next char */
+
+ w = MHD_str_pct_decode_strict_n_ (uname_ext + r, uname_ext_len - r,
+ buf, buf_size);
+ if ((0 == w) && (0 != uname_ext_len - r))
+ return -1; /* Broken percent encoding */
+ buf[w] = 0; /* Zero terminate the result */
+ mhd_assert (SSIZE_MAX > w);
+ return (ssize_t) w;
+}
+
+
+/**
+ * Get copy of username used by the client.
+ * @param params the Digest Authorization parameters
+ * @param uname_type the type of username
+ * @param[out] unames the pointer to the structure to be filled
+ * @param buf the buffer to be used for usernames
+ * @param buf_size the size of the @a buf
+ * @return the size of the @a buf used by pointers in @a unames structure
+ */
+static size_t
+get_rq_uname (const struct MHD_RqDAuth *params,
+ enum MHD_DigestAuthUsernameType uname_type,
+ struct MHD_DigestAuthUsernameInfo *uname_info,
+ uint8_t *buf,
+ size_t buf_size)
+{
+ size_t buf_used;
+
+ buf_used = 0;
+ mhd_assert (get_rq_uname_type (params) == uname_type);
+ mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID != uname_type);
+ mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_type);
+
+ if ( (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD == uname_type) ||
+ (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type) )
+ {
+ uname_info->username = (char *) (buf + buf_used);
+ uname_info->username_len =
+ get_rq_param_unquoted_copy_z (¶ms->username,
+ uname_info->username);
+ buf_used += uname_info->username_len + 1;
+ if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type)
+ {
+ uname_info->userhash_bin_size = MHD_hex_to_bin (uname_info->username,
+ uname_info->username_len,
+ buf + buf_used);
+ if ( (0 == uname_info->userhash_bin_size) &&
+ (0 != uname_info->username_len) )
+ {
+ uname_info->userhash_bin = NULL;
+ uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
+ }
+ else
+ {
+ uname_info->userhash_bin = (uint8_t *) (buf + buf_used);
+ buf_used += uname_info->userhash_bin_size;
+ }
+ }
+ }
+ else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type)
+ {
+ ssize_t res;
+ res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
+ params->username_ext.value.len,
+ (char *) (buf + buf_used),
+ buf_size - buf_used);
+ if (0 > res)
+ uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
+ else
+ {
+ uname_info->username = (char *) (buf + buf_used);
+ uname_info->username_len = (size_t) res;
+ buf_used += uname_info->username_len + 1;
+ }
+ }
+ mhd_assert (buf_size >= buf_used);
+ return buf_used;
+}
+
+
+/**
+ * Get QOP ('quality of protection') type.
+ * @param params the Digest Authorization parameters
+ * @return detected QOP ('quality of protection') type.
+ */
+static enum MHD_DigestAuthQOP
+get_rq_qop (const struct MHD_RqDAuth *params)
+{
+ const struct MHD_RqDAuthParam *const qop_param =
+ ¶ms->qop;
+ 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, \
+ "auth"))
+ return MHD_DIGEST_AUTH_QOP_AUTH;
+ if (MHD_str_equal_caseless_quoted_s_bin_n (qop_param->value.str, \
+ qop_param->value.len, \
+ "auth-int"))
+ return MHD_DIGEST_AUTH_QOP_AUTH_INT;
+ }
+ else
+ {
+ if (MHD_str_equal_caseless_s_bin_n_ ("auth", \
+ qop_param->value.str, \
+ qop_param->value.len))
+ return MHD_DIGEST_AUTH_QOP_AUTH;
+ if (MHD_str_equal_caseless_s_bin_n_ ("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;
+}
+
+
+/**
+ * Result of request's Digest Authorization 'nc' value extraction
+ */
+enum MHD_GetRqNCResult
+{
+ MHD_GET_RQ_NC_NONE = -1, /**< No 'nc' value */
+ MHD_GET_RQ_NC_VALID = 0, /**< Readable 'nc' value */
+ MHD_GET_RQ_NC_TOO_LONG = 1, /**< The 'nc' value is too long */
+ MHD_GET_RQ_NC_TOO_LARGE = 2,/**< The 'nc' value is too big to fit uint32_t */
+ MHD_GET_RQ_NC_BROKEN = 3 /**< The 'nc' value is not a number */
+};
+
+
+/**
+ * Get 'nc' value from request's Authorization header
+ * @param params the request digest authentication
+ * @param[out] nc the pointer to put nc value to
+ * @return enum value indicating the result
+ */
+static enum MHD_GetRqNCResult
+get_rq_nc (const struct MHD_RqDAuth *params,
+ uint32_t *nc)
+{
+ const struct MHD_RqDAuthParam *const nc_param =
+ ¶ms->nc;
+ char unq[16];
+ const char *val;
+ size_t val_len;
+ size_t res;
+ uint64_t nc_val;
+
+ if (NULL == nc_param->value.str)
+ return MHD_GET_RQ_NC_NONE;
+
+ if (0 == nc_param->value.len)
+ return MHD_GET_RQ_NC_BROKEN;
+
+ if (! nc_param->quoted)
+ {
+ val = nc_param->value.str;
+ val_len = nc_param->value.len;
+ }
+ else
+ {
+ /* Actually no backslashes must be used in 'nc' */
+ if (sizeof(unq) < params->nc.value.len)
+ return MHD_GET_RQ_NC_TOO_LONG;
+ val_len = MHD_str_unquote (nc_param->value.str, nc_param->value.len, unq);
+ if (0 == val_len)
+ return MHD_GET_RQ_NC_BROKEN;
+ val = unq;
+ }
+
+ res = MHD_strx_to_uint64_n_ (val, val_len, &nc_val);
+ if (0 == res)
+ {
+ const char f = val[0];
+ if ( (('9' >= f) && ('0' <= f)) ||
+ (('F' >= f) && ('A' <= f)) ||
+ (('a' <= f) && ('f' >= f)) )
+ return MHD_GET_RQ_NC_TOO_LARGE;
+ else
+ return MHD_GET_RQ_NC_BROKEN;
+ }
+ if (val_len != res)
+ return MHD_GET_RQ_NC_BROKEN;
+ if (UINT32_MAX < nc_val)
+ return MHD_GET_RQ_NC_TOO_LARGE;
+ *nc = (uint32_t) nc_val;
+ return MHD_GET_RQ_NC_VALID;
+}
+
+
+/**
+ * Get information about Digest Authorization client's header.
+ *
+ * @param connection The MHD connection structure
+ * @return NULL no valid Digest Authorization header is used in the request;
+ * a pointer structure with information if the valid request header
+ * found, free using #MHD_free().
+ * @note Available since #MHD_VERSION 0x00097519
+ * @ingroup authentication
+ */
+_MHD_EXTERN struct MHD_DigestAuthInfo *
+MHD_digest_auth_get_request_info3 (struct MHD_Connection *connection)
+{
+ const struct MHD_RqDAuth *params;
+ struct MHD_DigestAuthInfo *info;
+ enum MHD_DigestAuthUsernameType uname_type;
+ size_t unif_buf_size;
+ uint8_t *unif_buf_ptr;
+ size_t unif_buf_used;
+ enum MHD_GetRqNCResult nc_res;
+
+ params = get_rq_dauth_params (connection);
+ if (NULL == params)
+ return NULL;
+
+ unif_buf_size = 0;
+
+ uname_type = get_rq_uname_type (params);
+
+ unif_buf_size += get_rq_unames_size (params, uname_type);
+
+ if (NULL != params->opaque.value.str)
+ unif_buf_size += params->opaque.value.len + 1; /* Add one for
zero-termination */
+ if (NULL != params->realm.value.str)
+ unif_buf_size += params->realm.value.len + 1; /* Add one for
zero-termination */
+ info = (struct MHD_DigestAuthInfo *)
+ MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthInfo)) + unif_buf_size);
+ unif_buf_ptr = (uint8_t *) (info + 1);
+ unif_buf_used = 0;
+
+ info->algo = get_rq_algo (params);
+
+ if ( (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_type) &&
+ (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID != uname_type) )
+ {
+ struct MHD_DigestAuthUsernameInfo uname_strct;
+ memset (&uname_strct, 0, sizeof(uname_strct));
+ unif_buf_used += get_rq_uname (params, uname_type, &uname_strct,
+ unif_buf_ptr + unif_buf_used,
+ unif_buf_size - unif_buf_used);
+ info->uname_type = uname_strct.uname_type;
+ info->username = uname_strct.username;
+ info->username_len = uname_strct.username_len;
+ info->userhash_bin = uname_strct.userhash_bin;
+ info->userhash_bin_size = uname_strct.userhash_bin_size;
+ }
+ else
+ info->uname_type = uname_type;
+
+ if (NULL != params->opaque.value.str)
+ {
+ info->opaque = (char *) (unif_buf_ptr + unif_buf_used);
+ info->opaque_len = get_rq_param_unquoted_copy_z (¶ms->opaque,
+ info->opaque);
+ unif_buf_used += info->opaque_len + 1;
+ }
+ if (NULL != params->realm.value.str)
+ {
+ info->realm = (char *) (unif_buf_ptr + unif_buf_used);
+ info->realm_len = get_rq_param_unquoted_copy_z (¶ms->realm,
+ info->realm);
+ unif_buf_used += info->realm_len + 1;
+ }
+
+ mhd_assert (unif_buf_size >= unif_buf_used);
+
+ info->qop = get_rq_qop (params);
+
+ if (NULL != params->cnonce.value.str)
+ info->cnonce_len = params->cnonce.value.len;
+ else
+ info->cnonce_len = 0;
+
+ nc_res = get_rq_nc (params, &info->nc);
+ if (MHD_GET_RQ_NC_VALID != nc_res)
+ info->nc = MHD_DIGEST_AUTH_INVALID_NC_VALUE;
+
+ return info;
+}
+
+
+/**
+ * Get the username from Digest Authorization client's header.
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no valid Digest Authorization header is used in the request,
+ * or no username parameter is present in the header, or username is
+ * provided incorrectly by client (see description for
+ * #MHD_DIGEST_AUTH_UNAME_TYPE_INVALID);
+ * a pointer structure with information if the valid request header
+ * found, free using #MHD_free().
+ * @sa MHD_digest_auth_get_request_info3() provides more complete information
+ * @note Available since #MHD_VERSION 0x00097519
+ * @ingroup authentication
+ */
+_MHD_EXTERN struct MHD_DigestAuthUsernameInfo *
+MHD_digest_auth_get_username3 (struct MHD_Connection *connection)
+{
+ const struct MHD_RqDAuth *params;
+ struct MHD_DigestAuthUsernameInfo *uname_info;
+ enum MHD_DigestAuthUsernameType uname_type;
+ size_t unif_buf_size;
+ uint8_t *unif_buf_ptr;
+ size_t unif_buf_used;
+
+ params = get_rq_dauth_params (connection);
+ if (NULL == params)
+ return NULL;
+
+ uname_type = get_rq_uname_type (params);
+ if ( (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING == uname_type) ||
+ (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID == uname_type) )
+ return NULL;
+
+ unif_buf_size = get_rq_unames_size (params, uname_type);
+
+ uname_info = (struct MHD_DigestAuthUsernameInfo *)
+ MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthUsernameInfo))
+ + unif_buf_size);
+ unif_buf_ptr = (uint8_t *) (uname_info + 1);
+ unif_buf_used = get_rq_uname (params, uname_type, uname_info, unif_buf_ptr,
+ unif_buf_size);
+ mhd_assert (unif_buf_size >= unif_buf_used);
+ (void) unif_buf_used; /* Mute compiler warning on non-debug builds */
+ mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_info->uname_type);
+
+ if (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID == uname_info->uname_type)
+ {
+ free (uname_info);
+ return NULL;
+ }
+ mhd_assert (uname_type == uname_info->uname_type);
+
+ return uname_info;
+}
+
+
/**
* Get the username from the authorization header sent by the client
*
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [libmicrohttpd] branch master updated (d629ada1 -> 76b5b195), gnunet, 2022/07/19
- [libmicrohttpd] 03/15: Use new functions for decode request URLs, gnunet, 2022/07/19
- [libmicrohttpd] 01/15: mhd_str: added functions for percent-decoding, gnunet, 2022/07/19
- [libmicrohttpd] 02/15: Added tests for percent-decoding functions, gnunet, 2022/07/19
- [libmicrohttpd] 05/15: Added tests for hex <-> binary functions, gnunet, 2022/07/19
- [libmicrohttpd] 12/15: microhttpd.h: added special enum for hash types, gnunet, 2022/07/19
- [libmicrohttpd] 04/15: mhd_str: added MHD_hex_to_bin() internal function, gnunet, 2022/07/19
- [libmicrohttpd] 09/15: Digest: check whether all required parameters are present before doing heavy calculations, gnunet, 2022/07/19
- [libmicrohttpd] 06/15: mhd_str: added macros for simple comparison against static strings, gnunet, 2022/07/19
- [libmicrohttpd] 08/15: Digest: use binary zero to separate get params in digest, gnunet, 2022/07/19
- [libmicrohttpd] 07/15: Added new functions MHD_digest_auth_get_request_info3() and MHD_digest_auth_get_username3(),
gnunet <=
- [libmicrohttpd] 15/15: microhttpd.h: formatted some deprecation warnings, gnunet, 2022/07/19
- [libmicrohttpd] 10/15: Digest: moved URI match check to separate function, avoid one memcpy(), gnunet, 2022/07/19
- [libmicrohttpd] 11/15: digest_auth_check: mostly rewritten, simplified, optimised, gnunet, 2022/07/19
- [libmicrohttpd] 13/15: digest: small internal refactoring to clarify used hash type, gnunet, 2022/07/19
- [libmicrohttpd] 14/15: digest_auth_check(): check and report wrong algorithm, gnunet, 2022/07/19