libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 483d47c90e6073839ab969902fe55d49a7732dd6
parent 496dfffcf70adb71f45466251df61e9e16be5fa4
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Thu,  9 Jun 2022 16:47:57 +0300

Basic Auth: switched to the internal Base64 decoding implementation

Internal implementation able to detect all kind of problems with broken
base64 encoding and more secure.

Diffstat:
Msrc/include/microhttpd.h | 7++++---
Msrc/microhttpd/basicauth.c | 200+++++++++++++++++++++++++++++++++++++------------------------------------------
2 files changed, 98 insertions(+), 109 deletions(-)

diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -4670,9 +4670,10 @@ struct MHD_BasicAuthInfo * sent by the client * * @param connection the MHD connection structure - * @return NULL not valid Basic Authentication header is present in - * current request, or pointer to structure with username and - * password, which must be freed by #MHD_free(). + * @return NULL if no valid Basic Authentication header is present in + * current request, or + * pointer to structure with username and password, which must be + * freed by #MHD_free(). * @note Available since #MHD_VERSION 0x00097517 * @ingroup authentication */ diff --git a/src/microhttpd/basicauth.c b/src/microhttpd/basicauth.c @@ -29,7 +29,6 @@ #include "platform.h" #include "mhd_limits.h" #include "internal.h" -#include "base64.h" #include "mhd_compat.h" #include "mhd_str.h" @@ -60,9 +59,10 @@ get_rq_bauth_params (struct MHD_Connection *connection) * sent by the client * * @param connection the MHD connection structure - * @return NULL not valid Basic Authentication header is present in - * current request, or pointer to structure with username and - * password, which must be freed by #MHD_free(). + * @return NULL if no valid Basic Authentication header is present in + * current request, or + * pointer to structure with username and password, which must be + * freed by #MHD_free(). * @note Available since #MHD_VERSION 0x00097517 * @ingroup authentication */ @@ -70,13 +70,8 @@ _MHD_EXTERN struct MHD_BasicAuthInfo * MHD_basic_auth_get_username_password3 (struct MHD_Connection *connection) { const struct MHD_RqBAuth *params; - char *decoded; - size_t decoded_len; + size_t decoded_max_len; struct MHD_BasicAuthInfo *ret; - size_t username_len; - char *colon; - size_t password_pos; - size_t password_len; params = get_rq_bauth_params (connection); @@ -86,63 +81,66 @@ MHD_basic_auth_get_username_password3 (struct MHD_Connection *connection) if ((NULL == params->token68.str) || (0 == params->token68.len)) return NULL; - decoded = BASE64Decode (params->token68.str, params->token68.len, - &decoded_len); - if ((NULL == decoded) || (0 == decoded_len)) + decoded_max_len = (params->token68.len / 4) * 3; + ret = (struct MHD_BasicAuthInfo *) malloc (sizeof(struct MHD_BasicAuthInfo) + + decoded_max_len + 1); + if (NULL != ret) { + size_t decoded_len; + char *decoded; + + decoded = (char *) (ret + 1); + decoded_len = MHD_base64_to_bin_n (params->token68.str, params->token68.len, + decoded, decoded_max_len); + mhd_assert (decoded_max_len >= decoded_len); + if (0 != decoded_len) + { + size_t username_len; + char *colon; + + colon = memchr (decoded, ':', decoded_len); + if (NULL != colon) + { + size_t password_pos; + size_t password_len; + + username_len = (size_t) (colon - decoded); + password_pos = username_len + 1; + password_len = decoded_len - password_pos; + ret->password = decoded + password_pos; + ret->password[password_len] = 0; /* Zero-terminate the string */ + ret->password_len = password_len; + } + else + { + username_len = decoded_len; + ret->password = NULL; + ret->password_len = 0; + } + ret->username = decoded; + ret->username[username_len] = 0; /* Zero-terminate the string */ + ret->username_len = username_len; + + return ret; /* Success exit point */ + } #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - _ ("Error decoding Basic Authorization authentication.\n")); + else + MHD_DLOG (connection->daemon, + _ ("Error decoding Basic Authorization authentication.\n")); #endif /* HAVE_MESSAGES */ - if (NULL != decoded) - free (decoded); - return NULL; - } - colon = memchr (decoded, ':', decoded_len); - if (NULL != colon) - { - username_len = (size_t) (colon - decoded); - password_pos = username_len + 1; - password_len = decoded_len - password_pos; + + free (ret); } +#ifdef HAVE_MESSAGES else - username_len = decoded_len; - - ret = (struct MHD_BasicAuthInfo *) malloc (sizeof(struct MHD_BasicAuthInfo) - + decoded_len + 1); - if (NULL == ret) { - free (decoded); -#ifdef HAVE_MESSAGES MHD_DLOG (connection->daemon, _ ("Failed to allocate memory to process " \ "Basic Authorization authentication.\n")); -#endif /* HAVE_MESSAGES */ - return NULL; - } - - ret->username = (char *) (ret + 1); - memcpy (ret->username, decoded, decoded_len); - free (decoded); - ret->username[username_len] = 0; /* Zero-terminate the string */ - ret->username_len = username_len; - if (NULL != colon) - { - mhd_assert (decoded_len >= password_pos); - mhd_assert (decoded_len > password_pos || 0 == password_len); - mhd_assert (decoded_len > password_len); - mhd_assert (decoded_len > username_len); - ret->password = ret->username + password_pos; - ret->password[password_len] = 0; /* Zero-terminate the string */ - ret->password_len = password_len; - } - else - { - ret->password = NULL; - ret->password_len = 0; } +#endif /* HAVE_MESSAGES */ - return ret; + return NULL; /* Failure exit point */ } @@ -160,69 +158,59 @@ _MHD_EXTERN char * MHD_basic_auth_get_username_password (struct MHD_Connection *connection, char **password) { - const struct MHD_RqBAuth *params; - char *decode; - size_t decode_len; - const char *separator; - - params = get_rq_bauth_params (connection); + struct MHD_BasicAuthInfo *info; - if (NULL == params) + info = MHD_basic_auth_get_username_password3 (connection); + if (NULL == info) return NULL; - if ((NULL == params->token68.str) || (0 == params->token68.len)) - return NULL; - - decode = BASE64Decode (params->token68.str, params->token68.len, &decode_len); - if ((NULL == decode) || (0 == decode_len)) - { -#ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - _ ("Error decoding basic authentication.\n")); -#endif - if (NULL != decode) - free (decode); - return NULL; - } - /* Find user:password pattern */ - if (NULL != (separator = memchr (decode, - ':', - decode_len))) + /* For backward compatibility this function must return NULL if + * no password is provided */ + if (NULL != info->password) { - char *user; - size_t user_len; - size_t password_len; - - user = decode; /* Reuse already allocated buffer */ - user_len = (size_t) (separator - decode); - user[user_len] = 0; + char *username; - if (NULL == password) - return user; - - password_len = decode_len - user_len - 1; - *password = (char *) malloc (password_len + 1); - if (NULL != *password) + username = malloc (info->username_len + 1); + if (NULL != username) { - if (0 != password_len) - memcpy (*password, decode + user_len + 1, password_len); - (*password)[password_len] = 0; - - return user; + memcpy (username, info->username, info->username_len + 1); + mhd_assert (0 == username[info->username_len]); + if (NULL != password) + { + *password = malloc (info->password_len + 1); + if (NULL != *password) + { + memcpy (*password, info->password, info->password_len + 1); + mhd_assert (0 == (*password)[info->password_len]); + + free (info); + return username; /* Success exit point */ + } +#ifdef HAVE_MESSAGES + else + MHD_DLOG (connection->daemon, + _ ("Failed to allocate memory.\n")); +#endif /* HAVE_MESSAGES */ + } + else + { + free (info); + return username; /* Success exit point */ + } + + free (username); } #ifdef HAVE_MESSAGES else MHD_DLOG (connection->daemon, _ ("Failed to allocate memory.\n")); #endif /* HAVE_MESSAGES */ + } -#ifdef HAVE_MESSAGES - else - MHD_DLOG (connection->daemon, - _ ("Basic authentication doesn't contain ':' separator.\n")); -#endif - free (decode); - return NULL; + free (info); + if (NULL != password) + *password = NULL; + return NULL; /* Failure exit point */ }