aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/digestauth.c
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-05-30 21:54:09 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-05-31 11:45:36 +0300
commit9039d65241daf512e7756319cd64d3d54750cb22 (patch)
tree9c109e217ad1014a89de5495fcebdc1723672e31 /src/microhttpd/digestauth.c
parentc15077e312ffe934b242c7ecc6559c6eb4eb62cb (diff)
downloadlibmicrohttpd-9039d65241daf512e7756319cd64d3d54750cb22.tar.gz
libmicrohttpd-9039d65241daf512e7756319cd64d3d54750cb22.zip
authentication: reworked header parsing
Added single function to parse all enabled authentication schemes header strings. The parsing result is cached and reused thus avoiding repetitive header parsing. The new function correctly "unquotes" values (backslashes are removed) as required by RFC.
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r--src/microhttpd/digestauth.c932
1 files changed, 572 insertions, 360 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index 7ac5ad8b..23b41193 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -26,6 +26,7 @@
26 * @author Karlson2k (Evgeny Grin) 26 * @author Karlson2k (Evgeny Grin)
27 */ 27 */
28#include "digestauth.h" 28#include "digestauth.h"
29#include "gen_auth.h"
29#include "platform.h" 30#include "platform.h"
30#include "mhd_limits.h" 31#include "mhd_limits.h"
31#include "internal.h" 32#include "internal.h"
@@ -158,19 +159,19 @@ enum MHD_CheckNonceNC_
158 /** 159 /**
159 * The nonce and NC are OK (valid and NC was not used before). 160 * The nonce and NC are OK (valid and NC was not used before).
160 */ 161 */
161 MHD_DAUTH_NONCENC_OK = MHD_DAUTH_OK, 162 MHD_CHECK_NONCENC_OK = MHD_DAUTH_OK,
162 163
163 /** 164 /**
164 * The 'nonce' was overwritten with newer 'nonce' in the same slot or 165 * The 'nonce' was overwritten with newer 'nonce' in the same slot or
165 * NC was already used. 166 * NC was already used.
166 * The validity of the 'nonce' was not be checked. 167 * The validity of the 'nonce' was not be checked.
167 */ 168 */
168 MHD_DAUTH_NONCENC_STALE = MHD_DAUTH_NONCE_STALE, 169 MHD_CHECK_NONCENC_STALE = MHD_DAUTH_NONCE_STALE,
169 170
170 /** 171 /**
171 * The 'nonce' is wrong, it was not generated before. 172 * The 'nonce' is wrong, it was not generated before.
172 */ 173 */
173 MHD_DAUTH_NONCENC_WRONG = MHD_DAUTH_NONCE_WRONG, 174 MHD_CHECK_NONCENC_WRONG = MHD_DAUTH_NONCE_WRONG,
174}; 175};
175 176
176 177
@@ -536,7 +537,8 @@ digest_calc_ha1_from_user (const char *alg,
536 * @param cnonce client nonce 537 * @param cnonce client nonce
537 * @param qop qop-value: "", "auth" or "auth-int" (NOTE: only 'auth' is supported today.) 538 * @param qop qop-value: "", "auth" or "auth-int" (NOTE: only 'auth' is supported today.)
538 * @param method method from request 539 * @param method method from request
539 * @param uri requested URL 540 * @param uri requested URL, could be not zero-terminated
541 * @param uri_len the length of @a uri, in characters
540 * @param hentity H(entity body) if qop="auth-int" 542 * @param hentity H(entity body) if qop="auth-int"
541 * @param[in,out] da digest algorithm to use, also 543 * @param[in,out] da digest algorithm to use, also
542 * we write da->sessionkey (set to response request-digest or response-digest) 544 * we write da->sessionkey (set to response request-digest or response-digest)
@@ -549,6 +551,7 @@ digest_calc_response (const char *ha1,
549 const char *qop, 551 const char *qop,
550 const char *method, 552 const char *method,
551 const char *uri, 553 const char *uri,
554 size_t uri_len,
552 const char *hentity, 555 const char *hentity,
553 struct DigestAlgorithm *da) 556 struct DigestAlgorithm *da)
554{ 557{
@@ -564,7 +567,7 @@ digest_calc_response (const char *ha1,
564 1); 567 1);
565 digest_update (da, 568 digest_update (da,
566 (const unsigned char *) uri, 569 (const unsigned char *) uri,
567 strlen (uri)); 570 uri_len);
568#if 0 571#if 0
569 if (0 == strcasecmp (qop, 572 if (0 == strcasecmp (qop,
570 "auth-int")) 573 "auth-int"))
@@ -627,101 +630,17 @@ digest_calc_response (const char *ha1,
627} 630}
628 631
629 632
630/** 633static const struct MHD_RqDAuth *
631 * Lookup subvalue off of the HTTP Authorization header. 634get_rq_dauth_params (struct MHD_Connection *connection)
632 *
633 * A description of the input format for 'data' is at
634 * http://en.wikipedia.org/wiki/Digest_access_authentication
635 *
636 *
637 * @param dest where to store the result (possibly truncated if
638 * the buffer is not big enough).
639 * @param size size of dest
640 * @param data pointer to the Authorization header
641 * @param key key to look up in data
642 * @return size of the located value, 0 if otherwise
643 */
644static size_t
645lookup_sub_value (char *dest,
646 size_t size,
647 const char *data,
648 const char *key)
649{ 635{
650 size_t keylen; 636 const struct MHD_AuthRqHeader *rq_params;
651 size_t len; 637
652 const char *ptr; 638 rq_params = MHD_get_auth_rq_params_ (connection);
653 const char *eq; 639 if ( (NULL == rq_params) ||
654 const char *q1; 640 (MHD_AUTHTYPE_DIGEST != rq_params->auth_type) )
655 const char *q2; 641 return NULL;
656 const char *qn; 642
657 643 return rq_params->params.dauth;
658 if (0 == size)
659 return 0;
660 keylen = strlen (key);
661 ptr = data;
662 while ('\0' != *ptr)
663 {
664 if (NULL == (eq = strchr (ptr,
665 '=')))
666 return 0;
667 q1 = eq + 1;
668 while (' ' == *q1)
669 q1++;
670 if ('\"' != *q1)
671 {
672 q2 = strchr (q1,
673 ',');
674 qn = q2;
675 }
676 else
677 {
678 q1++;
679 q2 = strchr (q1,
680 '\"');
681 if (NULL == q2)
682 return 0; /* end quote not found */
683 qn = q2 + 1;
684 }
685 if ( (MHD_str_equal_caseless_n_ (ptr,
686 key,
687 keylen)) &&
688 (eq == &ptr[keylen]) )
689 {
690 if (NULL == q2)
691 {
692 len = strlen (q1) + 1;
693 if (size > len)
694 size = len;
695 size--;
696 memcpy (dest,
697 q1,
698 size);
699 dest[size] = '\0';
700 return size;
701 }
702 else
703 {
704 if (size > (size_t) ((q2 - q1) + 1))
705 size = (size_t) (q2 - q1) + 1;
706 size--;
707 memcpy (dest,
708 q1,
709 size);
710 dest[size] = '\0';
711 return size;
712 }
713 }
714 if (NULL == qn)
715 return 0;
716 ptr = strchr (qn,
717 ',');
718 if (NULL == ptr)
719 return 0;
720 ptr++;
721 while (' ' == *ptr)
722 ptr++;
723 }
724 return 0;
725} 644}
726 645
727 646
@@ -738,7 +657,6 @@ get_nonce_timestamp (const char *const nonce,
738 size_t noncelen, 657 size_t noncelen,
739 uint64_t *const ptimestamp) 658 uint64_t *const ptimestamp)
740{ 659{
741 mhd_assert ((0 == noncelen) || (strlen (nonce) == noncelen));
742 if (0 == noncelen) 660 if (0 == noncelen)
743 noncelen = strlen (nonce); 661 noncelen = strlen (nonce);
744 662
@@ -826,18 +744,19 @@ check_nonce_nc (struct MHD_Connection *connection,
826 uint32_t mod; 744 uint32_t mod;
827 enum MHD_CheckNonceNC_ ret; 745 enum MHD_CheckNonceNC_ ret;
828 746
747 mhd_assert (0 != noncelen);
829 mhd_assert (strlen (nonce) == noncelen); 748 mhd_assert (strlen (nonce) == noncelen);
830 mhd_assert (0 != nc); 749 mhd_assert (0 != nc);
831 if (MAX_NONCE_LENGTH < noncelen) 750 if (MAX_NONCE_LENGTH < noncelen)
832 return MHD_DAUTH_NONCENC_WRONG; /* This should be impossible, but static analysis 751 return MHD_CHECK_NONCENC_WRONG; /* This should be impossible, but static analysis
833 tools have a hard time with it *and* this also 752 tools have a hard time with it *and* this also
834 protects against unsafe modifications that may 753 protects against unsafe modifications that may
835 happen in the future... */ 754 happen in the future... */
836 mod = daemon->nonce_nc_size; 755 mod = daemon->nonce_nc_size;
837 if (0 == mod) 756 if (0 == mod)
838 return MHD_DAUTH_NONCENC_STALE; /* no array! */ 757 return MHD_CHECK_NONCENC_STALE; /* no array! */
839 if (nc >= UINT64_MAX - 64) 758 if (nc >= UINT64_MAX - 64)
840 return MHD_DAUTH_NONCENC_STALE; /* Overflow, unrealistically high value */ 759 return MHD_CHECK_NONCENC_STALE; /* Overflow, unrealistically high value */
841 760
842 nn = &daemon->nnc[get_nonce_nc_idx (mod, nonce, noncelen)]; 761 nn = &daemon->nnc[get_nonce_nc_idx (mod, nonce, noncelen)];
843 762
@@ -851,11 +770,11 @@ check_nonce_nc (struct MHD_Connection *connection,
851 if (0 == nn->nonce[0]) 770 if (0 == nn->nonce[0])
852 { /* The slot was never used, while the client's nonce value should be 771 { /* The slot was never used, while the client's nonce value should be
853 * recorded when it was generated by MHD */ 772 * recorded when it was generated by MHD */
854 ret = MHD_DAUTH_NONCENC_WRONG; 773 ret = MHD_CHECK_NONCENC_WRONG;
855 } 774 }
856 else if (0 != nn->nonce[noncelen]) 775 else if (0 != nn->nonce[noncelen])
857 { /* The value is the slot is wrong */ 776 { /* The value is the slot is wrong */
858 ret = MHD_DAUTH_NONCENC_STALE; 777 ret = MHD_CHECK_NONCENC_STALE;
859 } 778 }
860 else 779 else
861 { 780 {
@@ -863,7 +782,7 @@ check_nonce_nc (struct MHD_Connection *connection,
863 if (! get_nonce_timestamp (nn->nonce, 0, &slot_ts)) 782 if (! get_nonce_timestamp (nn->nonce, 0, &slot_ts))
864 { 783 {
865 mhd_assert (0); /* The value is the slot is wrong */ 784 mhd_assert (0); /* The value is the slot is wrong */
866 ret = MHD_DAUTH_NONCENC_STALE; 785 ret = MHD_CHECK_NONCENC_STALE;
867 } 786 }
868 else 787 else
869 { 788 {
@@ -873,21 +792,21 @@ check_nonce_nc (struct MHD_Connection *connection,
873 { 792 {
874 /* The nonce from the client may not have been placed in the slot 793 /* The nonce from the client may not have been placed in the slot
875 * because another nonce in that slot has not yet expired. */ 794 * because another nonce in that slot has not yet expired. */
876 ret = MHD_DAUTH_NONCENC_STALE; 795 ret = MHD_CHECK_NONCENC_STALE;
877 } 796 }
878 else if (TRIM_TO_TIMESTAMP (UINT64_MAX) / 2 >= ts_diff) 797 else if (TRIM_TO_TIMESTAMP (UINT64_MAX) / 2 >= ts_diff)
879 { 798 {
880 /* Too large value means that nonce_time is less than slot_ts. 799 /* Too large value means that nonce_time is less than slot_ts.
881 * The nonce from the client may have been overwritten by the newer 800 * The nonce from the client may have been overwritten by the newer
882 * nonce. */ 801 * nonce. */
883 ret = MHD_DAUTH_NONCENC_STALE; 802 ret = MHD_CHECK_NONCENC_STALE;
884 } 803 }
885 else 804 else
886 { 805 {
887 /* The nonce from the client should be generated after the nonce 806 /* The nonce from the client should be generated after the nonce
888 * in the slot has been expired, the nonce must be recorded, but 807 * in the slot has been expired, the nonce must be recorded, but
889 * it's not. */ 808 * it's not. */
890 ret = MHD_DAUTH_NONCENC_WRONG; 809 ret = MHD_CHECK_NONCENC_WRONG;
891 } 810 }
892 } 811 }
893 } 812 }
@@ -908,7 +827,7 @@ check_nonce_nc (struct MHD_Connection *connection,
908 else 827 else
909 nn->nmask = 0; /* big jump, unset all bits in the mask */ 828 nn->nmask = 0; /* big jump, unset all bits in the mask */
910 nn->nc = nc; 829 nn->nc = nc;
911 ret = MHD_DAUTH_NONCENC_OK; 830 ret = MHD_CHECK_NONCENC_OK;
912 } 831 }
913 else if (nc < nn->nc) 832 else if (nc < nn->nc)
914 { 833 {
@@ -919,15 +838,15 @@ check_nonce_nc (struct MHD_Connection *connection,
919 { 838 {
920 /* Out-of-order nonce, but within 64-bit bitmask, set bit */ 839 /* Out-of-order nonce, but within 64-bit bitmask, set bit */
921 nn->nmask |= (UINT64_C (1) << (nn->nc - nc - 1)); 840 nn->nmask |= (UINT64_C (1) << (nn->nc - nc - 1));
922 ret = MHD_DAUTH_NONCENC_OK; 841 ret = MHD_CHECK_NONCENC_OK;
923 } 842 }
924 else 843 else
925 /* 'nc' was already used or too old (more then 64 values ago) */ 844 /* 'nc' was already used or too old (more then 64 values ago) */
926 ret = MHD_DAUTH_NONCENC_STALE; 845 ret = MHD_CHECK_NONCENC_STALE;
927 } 846 }
928 else /* if (nc == nn->nc) */ 847 else /* if (nc == nn->nc) */
929 /* 'nc' was already used */ 848 /* 'nc' was already used */
930 ret = MHD_DAUTH_NONCENC_STALE; 849 ret = MHD_CHECK_NONCENC_STALE;
931 850
932 MHD_mutex_unlock_chk_ (&daemon->nnc_lock); 851 MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
933 852
@@ -947,28 +866,40 @@ check_nonce_nc (struct MHD_Connection *connection,
947_MHD_EXTERN char * 866_MHD_EXTERN char *
948MHD_digest_auth_get_username (struct MHD_Connection *connection) 867MHD_digest_auth_get_username (struct MHD_Connection *connection)
949{ 868{
950 char user[MAX_USERNAME_LENGTH]; 869 const struct MHD_RqDAuth *params;
951 const char *header; 870 char *username;
952 871 size_t username_len;
953 if (MHD_NO == MHD_lookup_connection_value_n (connection, 872
954 MHD_HEADER_KIND, 873 params = get_rq_dauth_params (connection);
955 MHD_HTTP_HEADER_AUTHORIZATION, 874 if (NULL == params)
956 MHD_STATICSTR_LEN_ (
957 MHD_HTTP_HEADER_AUTHORIZATION),
958 &header,
959 NULL))
960 return NULL; 875 return NULL;
961 if (0 != strncmp (header, 876
962 _MHD_AUTH_DIGEST_BASE, 877 if (NULL == params->username.value.str)
963 MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE)))
964 return NULL; 878 return NULL;
965 header += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE); 879
966 if (0 == lookup_sub_value (user, 880 username_len = params->username.value.len;
967 sizeof (user), 881 username = malloc (username_len + 1);
968 header, 882 if (NULL == username)
969 "username"))
970 return NULL; 883 return NULL;
971 return strdup (user); 884
885 if (! params->username.quoted)
886 {
887 /* The username is not quoted, no need to unquote */
888 if (0 != username_len)
889 memcpy (username, params->username.value.str, username_len);
890 username[username_len] = 0; /* Zero-terminate */
891 }
892 else
893 {
894 /* Need to properly unquote the username */
895 mhd_assert (0 != username_len); /* Quoted string may not be zero-legth */
896 username_len = MHD_str_unquote (params->username.value.str, username_len,
897 username);
898 mhd_assert (0 != username_len); /* The unquoted string cannot be empty */
899 username[username_len] = 0; /* Zero-terminate */
900 }
901
902 return username;
972} 903}
973 904
974 905
@@ -1347,6 +1278,91 @@ check_argument_match (struct MHD_Connection *connection,
1347 1278
1348 1279
1349/** 1280/**
1281 * The size of the unquoting buffer in stack
1282 */
1283#define _MHD_STATIC_UNQ_BUFFER_SIZE 128
1284
1285/**
1286 * The result of parameter unquoting
1287 */
1288enum _MHD_GetUnqResult
1289{
1290 _MHD_UNQ_NON_EMPTY = 0, /**< The sting is not empty */
1291 _MHD_UNQ_NO_STRING = MHD_DAUTH_WRONG_HEADER, /**< No string (no such parameter) */
1292 _MHD_UNQ_EMPTY = 1, /**< The string is empty */
1293 _MHD_UNQ_TOO_LARGE = 2, /**< The string is too large to unqoute */
1294 _MHD_UNQ_OUT_OF_MEM = 3 /**< Out of memory error */
1295};
1296
1297
1298/**
1299 * Get Digest authorisation parameter as unquoted string.
1300 * @param param the parameter to process
1301 * @param tmp1 the small buffer in stack
1302 * @param ptmp2 the pointer to pointer to malloc'ed buffer
1303 * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
1304 * @param[out] unquoted the pointer to store the result, NOT zero terminated
1305 * @return enum code indicating result of the process
1306 */
1307static enum _MHD_GetUnqResult
1308get_unqouted_param (const struct MHD_RqDAuthParam *param,
1309 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
1310 char **ptmp2,
1311 size_t *ptmp2_size,
1312 struct _MHD_cstr_w_len *unquoted)
1313{
1314 char *str;
1315 size_t len;
1316 mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2));
1317 mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size));
1318 mhd_assert ((0 == *ptmp2_size) || \
1319 (_MHD_STATIC_UNQ_BUFFER_SIZE < *ptmp2_size));
1320
1321 if (NULL == param->value.str)
1322 {
1323 const struct _MHD_cstr_w_len res = {NULL, 0};
1324 mhd_assert (! param->quoted);
1325 mhd_assert (0 == param->value.len);
1326 memcpy (unquoted, &res, sizeof(res));
1327 return _MHD_UNQ_NO_STRING;
1328 }
1329 if (! param->quoted)
1330 {
1331 memcpy (unquoted, &param->value, sizeof(param->value));
1332 return (0 == param->value.len) ? _MHD_UNQ_EMPTY : _MHD_UNQ_NON_EMPTY;
1333 }
1334 /* The value is present and is quoted, needs to be copied and unquoted */
1335 mhd_assert (0 != param->value.len);
1336 if (param->value.len <= _MHD_STATIC_UNQ_BUFFER_SIZE)
1337 str = tmp1;
1338 else if (param->value.len <= *ptmp2_size)
1339 str = *ptmp2;
1340 else
1341 {
1342 if (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
1343 return _MHD_UNQ_TOO_LARGE;
1344 if (NULL != *ptmp2)
1345 free (*ptmp2);
1346 *ptmp2 = (char *) malloc (param->value.len);
1347 if (NULL == *ptmp2)
1348 return _MHD_UNQ_OUT_OF_MEM;
1349 *ptmp2_size = param->value.len;
1350 str = *ptmp2;
1351 }
1352
1353 len = MHD_str_unquote (param->value.str, param->value.len, str);
1354 if (1)
1355 {
1356 const struct _MHD_cstr_w_len res = {str, len};
1357 memcpy (unquoted, &res, sizeof(res));
1358 }
1359 mhd_assert (0 != unquoted->len);
1360 mhd_assert (unquoted->len < param->value.len);
1361 return _MHD_UNQ_NON_EMPTY;
1362}
1363
1364
1365/**
1350 * Authenticates the authorization header sent by the client 1366 * Authenticates the authorization header sent by the client
1351 * 1367 *
1352 * @param connection The MHD connection structure 1368 * @param connection The MHD connection structure
@@ -1375,10 +1391,6 @@ digest_auth_check_all (struct MHD_Connection *connection,
1375 unsigned int nonce_timeout) 1391 unsigned int nonce_timeout)
1376{ 1392{
1377 struct MHD_Daemon *daemon = MHD_get_master (connection->daemon); 1393 struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
1378 size_t len;
1379 const char *header;
1380 char nonce[MAX_NONCE_LENGTH];
1381 size_t nonce_len;
1382 char cnonce[MAX_NONCE_LENGTH]; 1394 char cnonce[MAX_NONCE_LENGTH];
1383 const unsigned int digest_size = digest_get_size (da); 1395 const unsigned int digest_size = digest_get_size (da);
1384 char ha1[VLA_ARRAY_LEN_DIGEST (digest_size) * 2 + 1]; 1396 char ha1[VLA_ARRAY_LEN_DIGEST (digest_size) * 2 + 1];
@@ -1389,219 +1401,368 @@ digest_auth_check_all (struct MHD_Connection *connection,
1389 char noncehashexp[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_size)) + 1]; 1401 char noncehashexp[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_size)) + 1];
1390 uint64_t nonce_time; 1402 uint64_t nonce_time;
1391 uint64_t t; 1403 uint64_t t;
1392 size_t left; /* number of characters left in 'header' for 'uri' */
1393 uint64_t nci; 1404 uint64_t nci;
1394 char *qmark; 1405 char *qmark;
1406 const struct MHD_RqDAuth *params;
1407 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE]; /**< Temporal buffer in stack for unqouting */
1408 char *tmp2; /**< Temporal malloc'ed buffer for unqouting */
1409 size_t tmp2_size; /**< The size of @a tmp2 buffer */
1410 struct _MHD_cstr_w_len unquoted;
1411 enum _MHD_GetUnqResult unq_res;
1412 enum MHD_DigestAuthResult ret;
1413#ifdef HAVE_MESSAGES
1414 bool err_logged;
1415#endif /* HAVE_MESSAGES */
1395 1416
1396 VLA_CHECK_LEN_DIGEST (digest_size); 1417 tmp2 = NULL;
1397 if (MHD_NO == MHD_lookup_connection_value_n (connection, 1418 tmp2_size = 0;
1398 MHD_HEADER_KIND,
1399 MHD_HTTP_HEADER_AUTHORIZATION,
1400 MHD_STATICSTR_LEN_ (
1401 MHD_HTTP_HEADER_AUTHORIZATION),
1402 &header,
1403 NULL))
1404 return MHD_DAUTH_WRONG_HEADER;
1405 if (0 != strncmp (header,
1406 _MHD_AUTH_DIGEST_BASE,
1407 MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE)))
1408 return MHD_DAUTH_WRONG_HEADER;
1409 header += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE);
1410 left = strlen (header);
1411
1412 if (1)
1413 {
1414 char un[MAX_USERNAME_LENGTH];
1415
1416 len = lookup_sub_value (un,
1417 sizeof (un),
1418 header,
1419 "username");
1420 if (0 == len)
1421 return MHD_DAUTH_WRONG_HEADER;
1422 if (0 != strcmp (username,
1423 un))
1424 return MHD_DAUTH_WRONG_USERNAME;
1425 left -= strlen ("username") + len;
1426 }
1427
1428 if (1)
1429 {
1430 char r[MAX_REALM_LENGTH];
1431
1432 len = lookup_sub_value (r,
1433 sizeof (r),
1434 header,
1435 "realm");
1436 if (0 == len)
1437 return MHD_DAUTH_WRONG_HEADER;
1438 if (0 != strcmp (realm,
1439 r))
1440 return MHD_DAUTH_WRONG_REALM;
1441 left -= strlen ("realm") + len;
1442 }
1443
1444 if (0 == (len = lookup_sub_value (nonce,
1445 sizeof (nonce),
1446 header,
1447 "nonce")))
1448 return MHD_DAUTH_WRONG_HEADER;
1449 nonce_len = len;
1450 left -= strlen ("nonce") + len;
1451 if (left > 32 * 1024)
1452 {
1453 /* we do not permit URIs longer than 32k, as we want to
1454 make sure to not blow our stack (or per-connection
1455 heap memory limit). Besides, 32k is already insanely
1456 large, but of course in theory the
1457 #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
1458 and would thus permit sending a >32k authorization
1459 header value. */
1460 return MHD_DAUTH_WRONG_HEADER;
1461 }
1462 if (! get_nonce_timestamp (nonce, nonce_len, &nonce_time))
1463 {
1464#ifdef HAVE_MESSAGES 1419#ifdef HAVE_MESSAGES
1465 MHD_DLOG (daemon, 1420 err_logged = false;
1466 _ ("Authentication failed, invalid timestamp format.\n")); 1421#endif /* HAVE_MESSAGES */
1467#endif 1422
1423 params = get_rq_dauth_params (connection);
1424 if (NULL == params)
1468 return MHD_DAUTH_WRONG_HEADER; 1425 return MHD_DAUTH_WRONG_HEADER;
1469 }
1470 1426
1471 t = MHD_monotonic_msec_counter (); 1427 do /* Only to avoid "goto" */
1472 /*
1473 * First level vetting for the nonce validity: if the timestamp
1474 * attached to the nonce exceeds `nonce_timeout', then the nonce is
1475 * invalid.
1476 */
1477 if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
1478 { 1428 {
1479 /* too old */ 1429 /* Check 'username' */
1480 return MHD_DAUTH_NONCE_STALE; 1430 unq_res = get_unqouted_param (&params->username, tmp1, &tmp2, &tmp2_size,
1481 } 1431 &unquoted);
1432 if (_MHD_UNQ_NON_EMPTY != unq_res)
1433 {
1434 if (_MHD_UNQ_NO_STRING == unq_res)
1435 ret = MHD_DAUTH_WRONG_HEADER;
1436 else if (_MHD_UNQ_EMPTY == unq_res)
1437 ret = MHD_DAUTH_WRONG_USERNAME;
1438 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1439 ret = MHD_DAUTH_WRONG_HEADER;
1440 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1441 ret = MHD_DAUTH_ERROR;
1442 else
1443 {
1444 mhd_assert (0); /* Must not happen */
1445 ret = MHD_DAUTH_ERROR;
1446 }
1447 break;
1448 }
1449 /* 'unquoted" may not contain binary zero */
1450 if ( (0 != strncmp (username, unquoted.str, unquoted.len)) ||
1451 (0 != username[unquoted.len]) )
1452 {
1453 ret = MHD_DAUTH_WRONG_USERNAME;
1454 break;
1455 }
1456 /* 'username' valid */
1482 1457
1483 calculate_nonce (nonce_time, 1458 /* Check 'realm' */
1484 connection->method, 1459 unq_res = get_unqouted_param (&params->realm, tmp1, &tmp2, &tmp2_size,
1485 daemon->digest_auth_random, 1460 &unquoted);
1486 daemon->digest_auth_rand_size, 1461 if (_MHD_UNQ_NON_EMPTY != unq_res)
1487 connection->url, 1462 {
1488 realm, 1463 if (_MHD_UNQ_NO_STRING == unq_res)
1489 da, 1464 ret = MHD_DAUTH_WRONG_HEADER;
1490 noncehashexp); 1465 else if (_MHD_UNQ_EMPTY == unq_res)
1491 /* 1466 ret = MHD_DAUTH_WRONG_REALM;
1492 * Second level vetting for the nonce validity 1467 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1493 * if the timestamp attached to the nonce is valid 1468 ret = MHD_DAUTH_WRONG_HEADER;
1494 * and possibly fabricated (in case of an attack) 1469 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1495 * the attacker must also know the random seed to be 1470 ret = MHD_DAUTH_ERROR;
1496 * able to generate a "sane" nonce, which if he does 1471 else
1497 * not, the nonce fabrication process going to be 1472 {
1498 * very hard to achieve. 1473 mhd_assert (0); /* Must not happen */
1499 */ 1474 ret = MHD_DAUTH_ERROR;
1500 if (0 != strcmp (nonce, 1475 }
1501 noncehashexp)) 1476 break;
1502 { 1477 }
1503 return MHD_DAUTH_NONCE_WRONG; 1478 /* 'unquoted" may not contain binary zero */
1504 } 1479 if ( (0 != strncmp (realm, unquoted.str, unquoted.len)) ||
1505 if ( (0 == lookup_sub_value (cnonce, 1480 (0 != realm[unquoted.len]) )
1506 sizeof (cnonce), 1481 {
1507 header, 1482 ret = MHD_DAUTH_WRONG_REALM;
1508 "cnonce")) || 1483 break;
1509 (0 == lookup_sub_value (qop, 1484 }
1510 sizeof (qop), 1485 /* 'realm' valid */
1511 header, 1486
1512 "qop")) || 1487 /* Check 'nonce' */
1513 ( (0 != strcmp (qop, 1488 unq_res = get_unqouted_param (&params->nonce, tmp1, &tmp2, &tmp2_size,
1514 "auth")) && 1489 &unquoted);
1515 (0 != strcmp (qop, 1490 if (_MHD_UNQ_NON_EMPTY != unq_res)
1516 "")) ) || 1491 {
1517 (0 == (len = lookup_sub_value (nc, 1492 if (_MHD_UNQ_NO_STRING == unq_res)
1518 sizeof (nc), 1493 ret = MHD_DAUTH_WRONG_HEADER;
1519 header, 1494 else if (_MHD_UNQ_EMPTY == unq_res)
1520 "nc")) ) || 1495 ret = MHD_DAUTH_NONCE_WRONG;
1521 (0 == lookup_sub_value (response, 1496 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1522 sizeof (response), 1497 ret = MHD_DAUTH_WRONG_HEADER;
1523 header, 1498 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1524 "response")) ) 1499 ret = MHD_DAUTH_ERROR;
1525 { 1500 else
1526#ifdef HAVE_MESSAGES 1501 {
1527 MHD_DLOG (daemon, 1502 mhd_assert (0); /* Must not happen */
1528 _ ("Authentication failed, invalid format.\n")); 1503 ret = MHD_DAUTH_ERROR;
1529#endif 1504 }
1530 return MHD_DAUTH_WRONG_HEADER; 1505 break;
1531 } 1506 }
1532 if (len != MHD_strx_to_uint64_n_ (nc, 1507 /* TODO: check correct 'nonce' length */
1533 len, 1508 if (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time))
1534 &nci)) 1509 {
1535 {
1536#ifdef HAVE_MESSAGES
1537 MHD_DLOG (daemon,
1538 _ ("Authentication failed, invalid nc format.\n"));
1539#endif
1540 return MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */
1541 }
1542 if (0 == nci)
1543 {
1544#ifdef HAVE_MESSAGES 1510#ifdef HAVE_MESSAGES
1545 MHD_DLOG (daemon, 1511 MHD_DLOG (daemon,
1546 _ ("Authentication failed, invalid 'nc' value.\n")); 1512 _ ("Authentication failed, invalid timestamp format.\n"));
1513 err_logged = true;
1547#endif 1514#endif
1548 return MHD_DAUTH_WRONG_HEADER; /* invalid nc value */ 1515 ret = MHD_DAUTH_NONCE_WRONG;
1549 } 1516 break;
1517 }
1518 t = MHD_monotonic_msec_counter ();
1519 /*
1520 * First level vetting for the nonce validity: if the timestamp
1521 * attached to the nonce exceeds `nonce_timeout', then the nonce is
1522 * invalid.
1523 */
1524 if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
1525 {
1526 /* too old */
1527 ret = MHD_DAUTH_NONCE_STALE;
1528 break;
1529 }
1550 1530
1551 if (1) 1531 calculate_nonce (nonce_time,
1552 { 1532 connection->method,
1553 enum MHD_CheckNonceNC_ nonce_nc_check; 1533 daemon->digest_auth_random,
1534 daemon->digest_auth_rand_size,
1535 connection->url,
1536 realm,
1537 da,
1538 noncehashexp);
1554 /* 1539 /*
1555 * Checking if that combination of nonce and nc is sound 1540 * Second level vetting for the nonce validity
1556 * and not a replay attack attempt. Refuse if nonce was not 1541 * if the timestamp attached to the nonce is valid
1557 * generated previously. 1542 * and possibly fabricated (in case of an attack)
1543 * the attacker must also know the random seed to be
1544 * able to generate a "sane" nonce, which if he does
1545 * not, the nonce fabrication process going to be
1546 * very hard to achieve.
1558 */ 1547 */
1559 nonce_nc_check = check_nonce_nc (connection, 1548 if ((0 != strncmp (noncehashexp, unquoted.str, unquoted.len)) ||
1560 nonce, 1549 (0 != noncehashexp[unquoted.len]))
1561 nonce_len, 1550 {
1562 nonce_time, 1551 ret = MHD_DAUTH_NONCE_WRONG;
1563 nci); 1552 break;
1564 if (MHD_DAUTH_NONCENC_STALE == nonce_nc_check) 1553 }
1554 /* 'nonce' valid */
1555
1556 /* Get 'cnonce' */
1557 unq_res = get_unqouted_param (&params->cnonce, tmp1, &tmp2, &tmp2_size,
1558 &unquoted);
1559 if (_MHD_UNQ_NON_EMPTY != unq_res)
1560 {
1561 if (_MHD_UNQ_NO_STRING == unq_res)
1562 ret = MHD_DAUTH_WRONG_HEADER;
1563 else if (_MHD_UNQ_EMPTY == unq_res)
1564 ret = MHD_DAUTH_WRONG_HEADER;
1565 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1566 ret = MHD_DAUTH_WRONG_HEADER;
1567 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1568 ret = MHD_DAUTH_ERROR;
1569 else
1570 {
1571 mhd_assert (0); /* Must not happen */
1572 ret = MHD_DAUTH_ERROR;
1573 }
1574 break;
1575 }
1576 if (sizeof(cnonce) <= unquoted.len)
1577 {
1578 /* TODO: handle large client nonces */
1579 ret = MHD_DAUTH_ERROR;
1580 break;
1581 }
1582 /* TODO: avoid memcpy() */
1583 memcpy (cnonce, unquoted.str, unquoted.len);
1584 cnonce[unquoted.len] = 0;
1585 /* Got 'cnonce' */
1586
1587 /* Get 'qop' */
1588 unq_res = get_unqouted_param (&params->qop, tmp1, &tmp2, &tmp2_size,
1589 &unquoted);
1590 if (_MHD_UNQ_NON_EMPTY != unq_res)
1591 {
1592 if (_MHD_UNQ_NO_STRING == unq_res)
1593 ret = MHD_DAUTH_WRONG_HEADER;
1594 else if (_MHD_UNQ_EMPTY == unq_res)
1595 ret = MHD_DAUTH_WRONG_HEADER;
1596 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1597 ret = MHD_DAUTH_WRONG_HEADER;
1598 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1599 ret = MHD_DAUTH_ERROR;
1600 else
1601 {
1602 mhd_assert (0); /* Must not happen */
1603 ret = MHD_DAUTH_ERROR;
1604 }
1605 break;
1606 }
1607 if (sizeof(qop) <= unquoted.len)
1608 {
1609 /* TODO: handle large client qop */
1610 ret = MHD_DAUTH_ERROR;
1611 break;
1612 }
1613 /* TODO: avoid memcpy() */
1614 memcpy (qop, unquoted.str, unquoted.len);
1615 qop[unquoted.len] = 0;
1616 /* TODO: use caseless match, use dedicated return code */
1617 if ( (0 != strcmp (qop, "auth")) &&
1618 (0 != strcmp (qop,"")) )
1619 {
1620 ret = MHD_DAUTH_WRONG_HEADER;
1621 break;
1622 }
1623 /* Got 'qop' */
1624
1625 /* Get 'nc' */
1626 unq_res = get_unqouted_param (&params->nc, tmp1, &tmp2, &tmp2_size,
1627 &unquoted);
1628 if (_MHD_UNQ_NON_EMPTY != unq_res)
1629 {
1630 if (_MHD_UNQ_NO_STRING == unq_res)
1631 ret = MHD_DAUTH_WRONG_HEADER;
1632 else if (_MHD_UNQ_EMPTY == unq_res)
1633 ret = MHD_DAUTH_WRONG_HEADER;
1634 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1635 ret = MHD_DAUTH_WRONG_HEADER;
1636 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1637 ret = MHD_DAUTH_ERROR;
1638 else
1639 {
1640 mhd_assert (0); /* Must not happen */
1641 ret = MHD_DAUTH_ERROR;
1642 }
1643 break;
1644 }
1645 if (sizeof(nc) <= unquoted.len)
1646 {
1647 /* TODO: handle large client nc */
1648 ret = MHD_DAUTH_ERROR;
1649 break;
1650 }
1651 /* TODO: avoid memcpy() */
1652 memcpy (nc, unquoted.str, unquoted.len);
1653 nc[unquoted.len] = 0;
1654 if (unquoted.len != MHD_strx_to_uint64_n_ (nc,
1655 unquoted.len,
1656 &nci))
1565 { 1657 {
1566#ifdef HAVE_MESSAGES 1658#ifdef HAVE_MESSAGES
1567 MHD_DLOG (daemon, 1659 MHD_DLOG (daemon,
1568 _ ("Stale nonce received. If this happens a lot, you should " 1660 _ ("Authentication failed, invalid nc format.\n"));
1569 "probably increase the size of the nonce array.\n")); 1661 err_logged = true;
1570#endif 1662#endif
1571 return MHD_DAUTH_NONCE_STALE; 1663 ret = MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */
1664 break;
1572 } 1665 }
1573 else if (MHD_DAUTH_NONCENC_WRONG == nonce_nc_check) 1666 if (0 == nci)
1574 { 1667 {
1575#ifdef HAVE_MESSAGES 1668#ifdef HAVE_MESSAGES
1576 MHD_DLOG (daemon, 1669 MHD_DLOG (daemon,
1577 _ ("Received nonce that technically valid, but was not " 1670 _ ("Authentication failed, invalid 'nc' value.\n"));
1578 "generated by MHD. This may indicate an attack attempt.\n")); 1671 err_logged = true;
1579#endif 1672#endif
1580 return MHD_DAUTH_NONCE_WRONG; 1673 ret = MHD_DAUTH_WRONG_HEADER; /* invalid nc value */
1674 break;
1581 } 1675 }
1582 mhd_assert (MHD_DAUTH_NONCENC_OK == nonce_nc_check); 1676 /* Got 'nc' */
1583 }
1584 1677
1585 if (1) 1678 /* Get 'response' */
1586 { 1679 unq_res = get_unqouted_param (&params->response, tmp1, &tmp2, &tmp2_size,
1587 char *uri; 1680 &unquoted);
1681 if (_MHD_UNQ_NON_EMPTY != unq_res)
1682 {
1683 if (_MHD_UNQ_NO_STRING == unq_res)
1684 ret = MHD_DAUTH_WRONG_HEADER;
1685 else if (_MHD_UNQ_EMPTY == unq_res)
1686 ret = MHD_DAUTH_WRONG_HEADER;
1687 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1688 ret = MHD_DAUTH_WRONG_HEADER;
1689 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1690 ret = MHD_DAUTH_ERROR;
1691 else
1692 {
1693 mhd_assert (0); /* Must not happen */
1694 ret = MHD_DAUTH_ERROR;
1695 }
1696 break;
1697 }
1698 if (sizeof(response) <= unquoted.len)
1699 {
1700 /* TODO: handle large client response */
1701 ret = MHD_DAUTH_ERROR;
1702 break;
1703 }
1704 /* TODO: avoid memcpy() */
1705 memcpy (response, unquoted.str, unquoted.len);
1706 response[unquoted.len] = 0;
1707 /* Got 'response' */
1588 1708
1589 uri = malloc (left + 1); 1709 if (1)
1590 if (NULL == uri)
1591 { 1710 {
1711 enum MHD_CheckNonceNC_ nonce_nc_check;
1712 /*
1713 * Checking if that combination of nonce and nc is sound
1714 * and not a replay attack attempt. Refuse if nonce was not
1715 * generated previously.
1716 */
1717 nonce_nc_check = check_nonce_nc (connection,
1718 noncehashexp,
1719 NONCE_STD_LEN (digest_size),
1720 nonce_time,
1721 nci);
1722 if (MHD_CHECK_NONCENC_STALE == nonce_nc_check)
1723 {
1592#ifdef HAVE_MESSAGES 1724#ifdef HAVE_MESSAGES
1593 MHD_DLOG (daemon, 1725 MHD_DLOG (daemon,
1594 _ ("Failed to allocate memory for auth header processing.\n")); 1726 _ ("Stale nonce received. If this happens a lot, you should "
1595#endif /* HAVE_MESSAGES */ 1727 "probably increase the size of the nonce array.\n"));
1596 return MHD_DAUTH_ERROR; 1728 err_logged = true;
1729#endif
1730 ret = MHD_DAUTH_NONCE_STALE;
1731 break;
1732 }
1733 else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check)
1734 {
1735#ifdef HAVE_MESSAGES
1736 MHD_DLOG (daemon,
1737 _ ("Received nonce that technically valid, but was not "
1738 "generated by MHD. This may indicate an attack attempt.\n"));
1739 err_logged = true;
1740#endif
1741 ret = MHD_DAUTH_NONCE_WRONG;
1742 break;
1743 }
1744 mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
1597 } 1745 }
1598 if (0 == lookup_sub_value (uri, 1746
1599 left + 1, 1747 /* Get 'uri' */
1600 header, 1748 unq_res = get_unqouted_param (&params->uri, tmp1, &tmp2, &tmp2_size,
1601 "uri")) 1749 &unquoted);
1750 if (_MHD_UNQ_NON_EMPTY != unq_res)
1602 { 1751 {
1603 free (uri); 1752 if (_MHD_UNQ_NO_STRING == unq_res)
1604 return MHD_DAUTH_WRONG_HEADER; 1753 ret = MHD_DAUTH_WRONG_HEADER;
1754 else if (_MHD_UNQ_EMPTY == unq_res)
1755 ret = MHD_DAUTH_WRONG_HEADER;
1756 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1757 ret = MHD_DAUTH_WRONG_HEADER;
1758 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1759 ret = MHD_DAUTH_ERROR;
1760 else
1761 {
1762 mhd_assert (0); /* Must not happen */
1763 ret = MHD_DAUTH_ERROR;
1764 }
1765 break;
1605 } 1766 }
1606 if (NULL != digest) 1767 if (NULL != digest)
1607 { 1768 {
@@ -1609,7 +1770,7 @@ digest_auth_check_all (struct MHD_Connection *connection,
1609 digest_calc_ha1_from_digest (digest_get_algo_name (da), 1770 digest_calc_ha1_from_digest (digest_get_algo_name (da),
1610 da, 1771 da,
1611 digest, 1772 digest,
1612 nonce, 1773 noncehashexp,
1613 cnonce); 1774 cnonce);
1614 } 1775 }
1615 else 1776 else
@@ -1620,7 +1781,7 @@ digest_auth_check_all (struct MHD_Connection *connection,
1620 username, 1781 username,
1621 realm, 1782 realm,
1622 password, 1783 password,
1623 nonce, 1784 noncehashexp,
1624 cnonce, 1785 cnonce,
1625 da); 1786 da);
1626 } 1787 }
@@ -1629,60 +1790,111 @@ digest_auth_check_all (struct MHD_Connection *connection,
1629 digest_size * 2 + 1); 1790 digest_size * 2 + 1);
1630 /* This will initialize da->sessionkey (respexp) */ 1791 /* This will initialize da->sessionkey (respexp) */
1631 digest_calc_response (ha1, 1792 digest_calc_response (ha1,
1632 nonce, 1793 noncehashexp,
1633 nc, 1794 nc,
1634 cnonce, 1795 cnonce,
1635 qop, 1796 qop,
1636 connection->method, 1797 connection->method,
1637 uri, 1798 unquoted.str,
1799 unquoted.len,
1638 hentity, 1800 hentity,
1639 da); 1801 da);
1640 qmark = strchr (uri,
1641 '?');
1642 if (NULL != qmark)
1643 *qmark = '\0';
1644
1645 /* Need to unescape URI before comparing with connection->url */
1646 daemon->unescape_callback (daemon->unescape_callback_cls,
1647 connection,
1648 uri);
1649 if (0 != strcmp (uri,
1650 connection->url))
1651 {
1652#ifdef HAVE_MESSAGES
1653 MHD_DLOG (daemon,
1654 _ ("Authentication failed, URI does not match.\n"));
1655#endif
1656 free (uri);
1657 return MHD_DAUTH_WRONG_URI;
1658 }
1659
1660 if (1) 1802 if (1)
1661 { 1803 {
1662 const char *args = qmark; 1804 char *uri;
1663 1805 size_t uri_len;
1664 if (NULL == args) 1806 uri_len = unquoted.len;
1665 args = ""; 1807 /* TODO: simplify string copy, avoid potential double copy */
1808 if ( ((tmp1 != unquoted.str) && (tmp2 != unquoted.str)) ||
1809 ((tmp1 == unquoted.str) && (sizeof(tmp1) >= unquoted.len)) ||
1810 ((tmp2 == unquoted.str) && (tmp2_size >= unquoted.len)))
1811 {
1812 char *buf;
1813 mhd_assert ((tmp1 != unquoted.str) || \
1814 (sizeof(tmp1) == unquoted.len));
1815 mhd_assert ((tmp2 != unquoted.str) || \
1816 (tmp2_size == unquoted.len));
1817 buf = malloc (unquoted.len + 1);
1818 if (NULL == buf)
1819 {
1820 ret = MHD_DAUTH_ERROR;
1821 break;
1822 }
1823 memcpy (buf, unquoted.str, unquoted.len);
1824 if (NULL != tmp2)
1825 free (tmp2);
1826 tmp2 = buf;
1827 tmp2_size = unquoted.len + 1;
1828 uri = tmp2;
1829 }
1830 else if (tmp1 == unquoted.str)
1831 uri = tmp1;
1666 else 1832 else
1667 args++; 1833 {
1668 if (MHD_NO == 1834 mhd_assert (tmp2 == unquoted.str);
1669 check_argument_match (connection, 1835 uri = tmp2;
1670 args) ) 1836 }
1837
1838 uri[uri_len] = 0;
1839 qmark = memchr (uri,
1840 '?',
1841 uri_len);
1842 if (NULL != qmark)
1843 *qmark = '\0';
1844
1845 /* Need to unescape URI before comparing with connection->url */
1846 daemon->unescape_callback (daemon->unescape_callback_cls,
1847 connection,
1848 uri);
1849 if (0 != strcmp (uri,
1850 connection->url))
1671 { 1851 {
1672#ifdef HAVE_MESSAGES 1852#ifdef HAVE_MESSAGES
1673 MHD_DLOG (daemon, 1853 MHD_DLOG (daemon,
1674 _ ("Authentication failed, arguments do not match.\n")); 1854 _ ("Authentication failed, URI does not match.\n"));
1855 err_logged = true;
1675#endif 1856#endif
1676 free (uri); 1857 ret = MHD_DAUTH_WRONG_URI;
1677 return MHD_DAUTH_WRONG_URI; 1858 break;
1678 } 1859 }
1860
1861 if (1)
1862 {
1863 const char *args = qmark;
1864
1865 if (NULL == args)
1866 args = "";
1867 else
1868 args++;
1869 if (MHD_NO ==
1870 check_argument_match (connection,
1871 args) )
1872 {
1873#ifdef HAVE_MESSAGES
1874 MHD_DLOG (daemon,
1875 _ ("Authentication failed, arguments do not match.\n"));
1876 err_logged = true;
1877#endif
1878 ret = MHD_DAUTH_WRONG_URI;
1879 break;
1880 }
1881 }
1882
1883 ret = (0 == strcmp (response,
1884 digest_get_hex_buffer (da)))
1885 ? MHD_DAUTH_OK
1886 : MHD_DAUTH_RESPONSE_WRONG;
1679 } 1887 }
1680 free (uri); 1888 } while (0);
1889 if (NULL != tmp2)
1890 free (tmp2);
1891
1892 if ((MHD_DAUTH_OK != ret) && ! err_logged)
1893 {
1894 (void) 0; /* TODO: add logging */
1681 } 1895 }
1682 return (0 == strcmp (response, 1896
1683 digest_get_hex_buffer (da))) 1897 return ret;
1684 ? MHD_DAUTH_OK
1685 : MHD_DAUTH_RESPONSE_WRONG;
1686} 1898}
1687 1899
1688 1900