gnunet-svn
[Top][All Lists]
Advanced

[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 =
+    &params->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 (&params->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 =
+    &params->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 =
+    &params->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 (&params->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 (&params->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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]