diff options
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r-- | src/microhttpd/digestauth.c | 570 |
1 files changed, 283 insertions, 287 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c index ca66bff0..e6f68222 100644 --- a/src/microhttpd/digestauth.c +++ b/src/microhttpd/digestauth.c | |||
@@ -1522,324 +1522,320 @@ digest_auth_check_all_inner (struct MHD_Connection *connection, | |||
1522 | 1522 | ||
1523 | tmp2_size = 0; | 1523 | tmp2_size = 0; |
1524 | 1524 | ||
1525 | do /* Only to avoid "goto" */ | 1525 | params = get_rq_dauth_params (connection); |
1526 | { | 1526 | if (NULL == params) |
1527 | 1527 | return MHD_DAUTH_WRONG_HEADER; | |
1528 | params = get_rq_dauth_params (connection); | ||
1529 | if (NULL == params) | ||
1530 | return MHD_DAUTH_WRONG_HEADER; | ||
1531 | |||
1532 | /* Check 'username' */ | ||
1533 | if (NULL == params->username.value.str) | ||
1534 | return MHD_DAUTH_WRONG_HEADER; | ||
1535 | |||
1536 | username_len = strlen (username); | ||
1537 | if (! is_param_equal (¶ms->username, username, username_len)) | ||
1538 | return MHD_DAUTH_WRONG_USERNAME; | ||
1539 | /* 'username' valid */ | ||
1540 | |||
1541 | /* Check 'realm' */ | ||
1542 | if (NULL == params->realm.value.str) | ||
1543 | return MHD_DAUTH_WRONG_HEADER; | ||
1544 | realm_len = strlen (realm); | ||
1545 | if (! is_param_equal (¶ms->realm, realm, realm_len)) | ||
1546 | return MHD_DAUTH_WRONG_REALM; | ||
1547 | /* 'realm' valid */ | ||
1548 | |||
1549 | /* Check 'nonce' */ | ||
1550 | if (NULL == params->nonce.value.str) | ||
1551 | return MHD_DAUTH_WRONG_HEADER; | ||
1552 | else if (0 == params->nonce.value.len) | ||
1553 | return MHD_DAUTH_NONCE_WRONG; | ||
1554 | else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len) | ||
1555 | return MHD_DAUTH_NONCE_WRONG; | ||
1556 | 1528 | ||
1557 | unq_res = get_unquoted_param (¶ms->nonce, tmp1, ptmp2, &tmp2_size, | 1529 | /* Check 'username' */ |
1558 | &unquoted); | 1530 | if (NULL == params->username.value.str) |
1559 | if (_MHD_UNQ_OK != unq_res) | 1531 | return MHD_DAUTH_WRONG_HEADER; |
1560 | return MHD_DAUTH_ERROR; | 1532 | |
1561 | if (NONCE_STD_LEN (digest_size) != unquoted.len) | 1533 | username_len = strlen (username); |
1562 | return MHD_DAUTH_NONCE_WRONG; | 1534 | if (! is_param_equal (¶ms->username, username, username_len)) |
1535 | return MHD_DAUTH_WRONG_USERNAME; | ||
1536 | /* 'username' valid */ | ||
1537 | |||
1538 | /* Check 'realm' */ | ||
1539 | if (NULL == params->realm.value.str) | ||
1540 | return MHD_DAUTH_WRONG_HEADER; | ||
1541 | realm_len = strlen (realm); | ||
1542 | if (! is_param_equal (¶ms->realm, realm, realm_len)) | ||
1543 | return MHD_DAUTH_WRONG_REALM; | ||
1544 | /* 'realm' valid */ | ||
1545 | |||
1546 | /* Check 'nonce' */ | ||
1547 | if (NULL == params->nonce.value.str) | ||
1548 | return MHD_DAUTH_WRONG_HEADER; | ||
1549 | else if (0 == params->nonce.value.len) | ||
1550 | return MHD_DAUTH_NONCE_WRONG; | ||
1551 | else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len) | ||
1552 | return MHD_DAUTH_NONCE_WRONG; | ||
1553 | |||
1554 | unq_res = get_unquoted_param (¶ms->nonce, tmp1, ptmp2, &tmp2_size, | ||
1555 | &unquoted); | ||
1556 | if (_MHD_UNQ_OK != unq_res) | ||
1557 | return MHD_DAUTH_ERROR; | ||
1558 | if (NONCE_STD_LEN (digest_size) != unquoted.len) | ||
1559 | return MHD_DAUTH_NONCE_WRONG; | ||
1560 | |||
1561 | if (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time)) | ||
1562 | { | ||
1563 | #ifdef HAVE_MESSAGES | ||
1564 | MHD_DLOG (daemon, | ||
1565 | _ ("Authentication failed, invalid timestamp format.\n")); | ||
1566 | #endif | ||
1567 | return MHD_DAUTH_NONCE_WRONG; | ||
1568 | } | ||
1569 | t = MHD_monotonic_msec_counter (); | ||
1570 | /* | ||
1571 | * First level vetting for the nonce validity: if the timestamp | ||
1572 | * attached to the nonce exceeds `nonce_timeout', then the nonce is | ||
1573 | * invalid. | ||
1574 | */ | ||
1575 | if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000)) | ||
1576 | return MHD_DAUTH_NONCE_STALE; /* too old */ | ||
1563 | 1577 | ||
1564 | if (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time)) | 1578 | calculate_nonce (nonce_time, |
1565 | { | 1579 | connection->method, |
1580 | daemon->digest_auth_random, | ||
1581 | daemon->digest_auth_rand_size, | ||
1582 | connection->url, | ||
1583 | realm, | ||
1584 | realm_len, | ||
1585 | da, | ||
1586 | noncehashexp); | ||
1587 | /* | ||
1588 | * Second level vetting for the nonce validity | ||
1589 | * if the timestamp attached to the nonce is valid | ||
1590 | * and possibly fabricated (in case of an attack) | ||
1591 | * the attacker must also know the random seed to be | ||
1592 | * able to generate a "sane" nonce, which if he does | ||
1593 | * not, the nonce fabrication process going to be | ||
1594 | * very hard to achieve. | ||
1595 | */ | ||
1596 | if ((0 != strncmp (noncehashexp, unquoted.str, unquoted.len)) || | ||
1597 | (0 != noncehashexp[unquoted.len])) | ||
1598 | return MHD_DAUTH_NONCE_WRONG; | ||
1599 | /* 'nonce' valid */ | ||
1600 | |||
1601 | /* Get 'cnonce' */ | ||
1602 | if (NULL == params->cnonce.value.str) | ||
1603 | return MHD_DAUTH_WRONG_HEADER; | ||
1604 | else if (0 == params->cnonce.value.len) | ||
1605 | return MHD_DAUTH_WRONG_HEADER; | ||
1606 | unq_res = get_unquoted_param (¶ms->cnonce, tmp1, ptmp2, &tmp2_size, | ||
1607 | &unquoted); | ||
1608 | if (_MHD_UNQ_OK != unq_res) | ||
1609 | return (_MHD_UNQ_TOO_LARGE == unq_res) ? | ||
1610 | MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR; | ||
1611 | |||
1612 | if (sizeof(cnonce) <= unquoted.len) | ||
1613 | return MHD_DAUTH_ERROR; /* TODO: handle large client nonces */ | ||
1614 | |||
1615 | /* TODO: avoid memcpy() */ | ||
1616 | memcpy (cnonce, unquoted.str, unquoted.len); | ||
1617 | cnonce[unquoted.len] = 0; | ||
1618 | /* Got 'cnonce' */ | ||
1619 | |||
1620 | /* Get 'qop' */ | ||
1621 | if (NULL == params->qop.value.str) | ||
1622 | return MHD_DAUTH_WRONG_HEADER; | ||
1623 | else if (0 == params->qop.value.len) | ||
1624 | return MHD_DAUTH_WRONG_QOP; | ||
1625 | else if (MHD_STATICSTR_LEN_ ("auth-int") * 2 < params->qop.value.len) | ||
1626 | return MHD_DAUTH_WRONG_QOP; | ||
1627 | unq_res = get_unquoted_param (¶ms->qop, tmp1, ptmp2, &tmp2_size, | ||
1628 | &unquoted); | ||
1629 | if (_MHD_UNQ_OK != unq_res) | ||
1630 | return MHD_DAUTH_ERROR; | ||
1631 | |||
1632 | if (sizeof(qop) <= unquoted.len) | ||
1633 | return MHD_DAUTH_ERROR; /* TODO: handle large client qop */ | ||
1634 | /* TODO: avoid memcpy() */ | ||
1635 | memcpy (qop, unquoted.str, unquoted.len); | ||
1636 | qop[unquoted.len] = 0; | ||
1637 | /* TODO: Really support empty value, support "auth-int" */ | ||
1638 | if ( ((MHD_STATICSTR_LEN_ ("auth") != unquoted.len) || | ||
1639 | (! MHD_str_equal_caseless_bin_n_ (qop, "auth", unquoted.len))) && | ||
1640 | (0 != strcmp (qop,"")) ) | ||
1641 | return MHD_DAUTH_WRONG_QOP; | ||
1642 | /* Got 'qop' */ | ||
1643 | |||
1644 | /* Get 'nc' */ | ||
1645 | if (NULL == params->nc.value.str) | ||
1646 | return MHD_DAUTH_WRONG_HEADER; | ||
1647 | else if (0 == params->nc.value.len) | ||
1648 | return MHD_DAUTH_WRONG_HEADER; | ||
1649 | else if (4 * 8 < params->nc.value.len) /* Four time more than needed */ | ||
1650 | return MHD_DAUTH_NONCE_WRONG; | ||
1651 | unq_res = get_unquoted_param (¶ms->nc, tmp1, ptmp2, &tmp2_size, | ||
1652 | &unquoted); | ||
1653 | if (_MHD_UNQ_OK != unq_res) | ||
1654 | return MHD_DAUTH_ERROR; | ||
1655 | |||
1656 | if (sizeof(nc) <= unquoted.len) | ||
1657 | return MHD_DAUTH_ERROR; | ||
1658 | /* TODO: avoid memcpy() */ | ||
1659 | memcpy (nc, unquoted.str, unquoted.len); | ||
1660 | nc[unquoted.len] = 0; | ||
1661 | if (unquoted.len != MHD_strx_to_uint64_n_ (nc, | ||
1662 | unquoted.len, | ||
1663 | &nci)) | ||
1664 | { | ||
1566 | #ifdef HAVE_MESSAGES | 1665 | #ifdef HAVE_MESSAGES |
1567 | MHD_DLOG (daemon, | 1666 | MHD_DLOG (daemon, |
1568 | _ ("Authentication failed, invalid timestamp format.\n")); | 1667 | _ ("Authentication failed, invalid nc format.\n")); |
1569 | #endif | 1668 | #endif |
1570 | return MHD_DAUTH_NONCE_WRONG; | 1669 | return MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */ |
1571 | } | 1670 | } |
1572 | t = MHD_monotonic_msec_counter (); | 1671 | if (0 == nci) |
1573 | /* | 1672 | { |
1574 | * First level vetting for the nonce validity: if the timestamp | 1673 | #ifdef HAVE_MESSAGES |
1575 | * attached to the nonce exceeds `nonce_timeout', then the nonce is | 1674 | MHD_DLOG (daemon, |
1576 | * invalid. | 1675 | _ ("Authentication failed, invalid 'nc' value.\n")); |
1577 | */ | 1676 | #endif |
1578 | if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000)) | 1677 | return MHD_DAUTH_WRONG_HEADER; /* invalid nc value */ |
1579 | return MHD_DAUTH_NONCE_STALE; /* too old */ | 1678 | } |
1580 | 1679 | /* Got 'nc' */ | |
1581 | calculate_nonce (nonce_time, | 1680 | |
1582 | connection->method, | 1681 | /* Get 'response' */ |
1583 | daemon->digest_auth_random, | 1682 | if (NULL == params->response.value.str) |
1584 | daemon->digest_auth_rand_size, | 1683 | return MHD_DAUTH_WRONG_HEADER; |
1585 | connection->url, | 1684 | else if (0 == params->response.value.len) |
1586 | realm, | 1685 | return MHD_DAUTH_RESPONSE_WRONG; |
1587 | realm_len, | 1686 | else if (digest_size * 4 < params->response.value.len) |
1588 | da, | 1687 | return MHD_DAUTH_RESPONSE_WRONG; |
1589 | noncehashexp); | 1688 | unq_res = get_unquoted_param (¶ms->response, tmp1, ptmp2, &tmp2_size, |
1689 | &unquoted); | ||
1690 | if (_MHD_UNQ_OK != unq_res) | ||
1691 | return MHD_DAUTH_ERROR; | ||
1692 | if (digest_size * 2 != unquoted.len) | ||
1693 | return MHD_DAUTH_RESPONSE_WRONG; | ||
1694 | |||
1695 | mhd_assert (sizeof(response) > unquoted.len); | ||
1696 | |||
1697 | if (sizeof(response) <= unquoted.len) | ||
1698 | return MHD_DAUTH_ERROR; | ||
1699 | /* TODO: avoid memcpy() */ | ||
1700 | memcpy (response, unquoted.str, unquoted.len); | ||
1701 | response[unquoted.len] = 0; | ||
1702 | /* Got 'response' */ | ||
1703 | |||
1704 | if (1) | ||
1705 | { | ||
1706 | enum MHD_CheckNonceNC_ nonce_nc_check; | ||
1590 | /* | 1707 | /* |
1591 | * Second level vetting for the nonce validity | 1708 | * Checking if that combination of nonce and nc is sound |
1592 | * if the timestamp attached to the nonce is valid | 1709 | * and not a replay attack attempt. Refuse if nonce was not |
1593 | * and possibly fabricated (in case of an attack) | 1710 | * generated previously. |
1594 | * the attacker must also know the random seed to be | ||
1595 | * able to generate a "sane" nonce, which if he does | ||
1596 | * not, the nonce fabrication process going to be | ||
1597 | * very hard to achieve. | ||
1598 | */ | 1711 | */ |
1599 | if ((0 != strncmp (noncehashexp, unquoted.str, unquoted.len)) || | 1712 | nonce_nc_check = check_nonce_nc (connection, |
1600 | (0 != noncehashexp[unquoted.len])) | 1713 | noncehashexp, |
1601 | return MHD_DAUTH_NONCE_WRONG; | 1714 | NONCE_STD_LEN (digest_size), |
1602 | /* 'nonce' valid */ | 1715 | nonce_time, |
1603 | 1716 | nci); | |
1604 | /* Get 'cnonce' */ | 1717 | if (MHD_CHECK_NONCENC_STALE == nonce_nc_check) |
1605 | if (NULL == params->cnonce.value.str) | ||
1606 | return MHD_DAUTH_WRONG_HEADER; | ||
1607 | else if (0 == params->cnonce.value.len) | ||
1608 | return MHD_DAUTH_WRONG_HEADER; | ||
1609 | unq_res = get_unquoted_param (¶ms->cnonce, tmp1, ptmp2, &tmp2_size, | ||
1610 | &unquoted); | ||
1611 | if (_MHD_UNQ_OK != unq_res) | ||
1612 | return (_MHD_UNQ_TOO_LARGE == unq_res) ? | ||
1613 | MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR; | ||
1614 | |||
1615 | if (sizeof(cnonce) <= unquoted.len) | ||
1616 | return MHD_DAUTH_ERROR; /* TODO: handle large client nonces */ | ||
1617 | |||
1618 | /* TODO: avoid memcpy() */ | ||
1619 | memcpy (cnonce, unquoted.str, unquoted.len); | ||
1620 | cnonce[unquoted.len] = 0; | ||
1621 | /* Got 'cnonce' */ | ||
1622 | |||
1623 | /* Get 'qop' */ | ||
1624 | if (NULL == params->qop.value.str) | ||
1625 | return MHD_DAUTH_WRONG_HEADER; | ||
1626 | else if (0 == params->qop.value.len) | ||
1627 | return MHD_DAUTH_WRONG_QOP; | ||
1628 | else if (MHD_STATICSTR_LEN_ ("auth-int") * 2 < params->qop.value.len) | ||
1629 | return MHD_DAUTH_WRONG_QOP; | ||
1630 | unq_res = get_unquoted_param (¶ms->qop, tmp1, ptmp2, &tmp2_size, | ||
1631 | &unquoted); | ||
1632 | if (_MHD_UNQ_OK != unq_res) | ||
1633 | return MHD_DAUTH_ERROR; | ||
1634 | |||
1635 | if (sizeof(qop) <= unquoted.len) | ||
1636 | return MHD_DAUTH_ERROR; /* TODO: handle large client qop */ | ||
1637 | /* TODO: avoid memcpy() */ | ||
1638 | memcpy (qop, unquoted.str, unquoted.len); | ||
1639 | qop[unquoted.len] = 0; | ||
1640 | /* TODO: Really support empty value, support "auth-int" */ | ||
1641 | if ( ((MHD_STATICSTR_LEN_ ("auth") != unquoted.len) || | ||
1642 | (! MHD_str_equal_caseless_bin_n_ (qop, "auth", unquoted.len))) && | ||
1643 | (0 != strcmp (qop,"")) ) | ||
1644 | return MHD_DAUTH_WRONG_QOP; | ||
1645 | /* Got 'qop' */ | ||
1646 | |||
1647 | /* Get 'nc' */ | ||
1648 | if (NULL == params->nc.value.str) | ||
1649 | return MHD_DAUTH_WRONG_HEADER; | ||
1650 | else if (0 == params->nc.value.len) | ||
1651 | return MHD_DAUTH_WRONG_HEADER; | ||
1652 | else if (4 * 8 < params->nc.value.len) /* Four time more than needed */ | ||
1653 | return MHD_DAUTH_NONCE_WRONG; | ||
1654 | unq_res = get_unquoted_param (¶ms->nc, tmp1, ptmp2, &tmp2_size, | ||
1655 | &unquoted); | ||
1656 | if (_MHD_UNQ_OK != unq_res) | ||
1657 | return MHD_DAUTH_ERROR; | ||
1658 | |||
1659 | if (sizeof(nc) <= unquoted.len) | ||
1660 | return MHD_DAUTH_ERROR; | ||
1661 | /* TODO: avoid memcpy() */ | ||
1662 | memcpy (nc, unquoted.str, unquoted.len); | ||
1663 | nc[unquoted.len] = 0; | ||
1664 | if (unquoted.len != MHD_strx_to_uint64_n_ (nc, | ||
1665 | unquoted.len, | ||
1666 | &nci)) | ||
1667 | { | 1718 | { |
1668 | #ifdef HAVE_MESSAGES | 1719 | #ifdef HAVE_MESSAGES |
1669 | MHD_DLOG (daemon, | 1720 | MHD_DLOG (daemon, |
1670 | _ ("Authentication failed, invalid nc format.\n")); | 1721 | _ ("Stale nonce received. If this happens a lot, you should " |
1722 | "probably increase the size of the nonce array.\n")); | ||
1671 | #endif | 1723 | #endif |
1672 | return MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */ | 1724 | return MHD_DAUTH_NONCE_STALE; |
1673 | } | 1725 | } |
1674 | if (0 == nci) | 1726 | else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check) |
1675 | { | 1727 | { |
1676 | #ifdef HAVE_MESSAGES | 1728 | #ifdef HAVE_MESSAGES |
1677 | MHD_DLOG (daemon, | 1729 | MHD_DLOG (daemon, |
1678 | _ ("Authentication failed, invalid 'nc' value.\n")); | 1730 | _ ("Received nonce that technically valid, but was not " |
1731 | "generated by MHD. This may indicate an attack attempt.\n")); | ||
1679 | #endif | 1732 | #endif |
1680 | return MHD_DAUTH_WRONG_HEADER; /* invalid nc value */ | 1733 | return MHD_DAUTH_NONCE_WRONG; |
1681 | } | 1734 | } |
1682 | /* Got 'nc' */ | 1735 | mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check); |
1683 | 1736 | } | |
1684 | /* Get 'response' */ | ||
1685 | if (NULL == params->response.value.str) | ||
1686 | return MHD_DAUTH_WRONG_HEADER; | ||
1687 | else if (0 == params->response.value.len) | ||
1688 | return MHD_DAUTH_RESPONSE_WRONG; | ||
1689 | else if (digest_size * 4 < params->response.value.len) | ||
1690 | return MHD_DAUTH_RESPONSE_WRONG; | ||
1691 | unq_res = get_unquoted_param (¶ms->response, tmp1, ptmp2, &tmp2_size, | ||
1692 | &unquoted); | ||
1693 | if (_MHD_UNQ_OK != unq_res) | ||
1694 | return MHD_DAUTH_ERROR; | ||
1695 | if (digest_size * 2 != unquoted.len) | ||
1696 | return MHD_DAUTH_RESPONSE_WRONG; | ||
1697 | |||
1698 | mhd_assert (sizeof(response) > unquoted.len); | ||
1699 | |||
1700 | if (sizeof(response) <= unquoted.len) | ||
1701 | return MHD_DAUTH_ERROR; | ||
1702 | /* TODO: avoid memcpy() */ | ||
1703 | memcpy (response, unquoted.str, unquoted.len); | ||
1704 | response[unquoted.len] = 0; | ||
1705 | /* Got 'response' */ | ||
1706 | 1737 | ||
1707 | if (1) | 1738 | /* Get 'uri' */ |
1739 | if (NULL == params->uri.value.str) | ||
1740 | return MHD_DAUTH_WRONG_HEADER; | ||
1741 | else if (0 == params->uri.value.len) | ||
1742 | return MHD_DAUTH_WRONG_URI; | ||
1743 | unq_res = get_unquoted_param_copy (¶ms->uri, tmp1, ptmp2, &tmp2_size, | ||
1744 | &unq_copy); | ||
1745 | if (_MHD_UNQ_OK != unq_res) | ||
1746 | return (_MHD_UNQ_TOO_LARGE == unq_res) ? | ||
1747 | MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR; | ||
1748 | |||
1749 | if (NULL != digest) | ||
1750 | { | ||
1751 | /* This will initialize da->digest_hex (ha1) */ | ||
1752 | digest_calc_ha1_from_digest (digest_get_algo_name (da), | ||
1753 | da, | ||
1754 | digest, | ||
1755 | noncehashexp, | ||
1756 | cnonce); | ||
1757 | } | ||
1758 | else | ||
1759 | { | ||
1760 | /* This will initialize da->digest_hex (ha1) */ | ||
1761 | mhd_assert (NULL != password); /* NULL == digest => password != NULL */ | ||
1762 | digest_calc_ha1_from_user (digest_get_algo_name (da), | ||
1763 | username, | ||
1764 | username_len, | ||
1765 | realm, | ||
1766 | realm_len, | ||
1767 | password, | ||
1768 | noncehashexp, | ||
1769 | cnonce, | ||
1770 | da); | ||
1771 | } | ||
1772 | memcpy (ha1, | ||
1773 | digest_get_hex_buffer (da), | ||
1774 | digest_size * 2 + 1); | ||
1775 | /* This will initialize da->sessionkey (respexp) */ | ||
1776 | digest_calc_response (ha1, | ||
1777 | noncehashexp, | ||
1778 | nc, | ||
1779 | cnonce, | ||
1780 | qop, | ||
1781 | connection->method, | ||
1782 | unq_copy.str, | ||
1783 | unq_copy.len, | ||
1784 | hentity, | ||
1785 | da); | ||
1786 | if (1) | ||
1787 | { | ||
1788 | char *uri; | ||
1789 | size_t uri_len; | ||
1790 | uri = unq_copy.str; | ||
1791 | uri_len = unq_copy.len; | ||
1792 | |||
1793 | uri[uri_len] = 0; | ||
1794 | qmark = memchr (uri, | ||
1795 | '?', | ||
1796 | uri_len); | ||
1797 | if (NULL != qmark) | ||
1798 | *qmark = '\0'; | ||
1799 | |||
1800 | /* Need to unescape URI before comparing with connection->url */ | ||
1801 | uri_len = daemon->unescape_callback (daemon->unescape_callback_cls, | ||
1802 | connection, | ||
1803 | uri); | ||
1804 | if ((uri_len != connection->url_len) || | ||
1805 | (0 != memcmp (uri, connection->url, uri_len))) | ||
1708 | { | 1806 | { |
1709 | enum MHD_CheckNonceNC_ nonce_nc_check; | ||
1710 | /* | ||
1711 | * Checking if that combination of nonce and nc is sound | ||
1712 | * and not a replay attack attempt. Refuse if nonce was not | ||
1713 | * generated previously. | ||
1714 | */ | ||
1715 | nonce_nc_check = check_nonce_nc (connection, | ||
1716 | noncehashexp, | ||
1717 | NONCE_STD_LEN (digest_size), | ||
1718 | nonce_time, | ||
1719 | nci); | ||
1720 | if (MHD_CHECK_NONCENC_STALE == nonce_nc_check) | ||
1721 | { | ||
1722 | #ifdef HAVE_MESSAGES | 1807 | #ifdef HAVE_MESSAGES |
1723 | MHD_DLOG (daemon, | 1808 | MHD_DLOG (daemon, |
1724 | _ ("Stale nonce received. If this happens a lot, you should " | 1809 | _ ("Authentication failed, URI does not match.\n")); |
1725 | "probably increase the size of the nonce array.\n")); | ||
1726 | #endif | ||
1727 | return MHD_DAUTH_NONCE_STALE; | ||
1728 | } | ||
1729 | else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check) | ||
1730 | { | ||
1731 | #ifdef HAVE_MESSAGES | ||
1732 | MHD_DLOG (daemon, | ||
1733 | _ ("Received nonce that technically valid, but was not " | ||
1734 | "generated by MHD. This may indicate an attack attempt.\n")); | ||
1735 | #endif | 1810 | #endif |
1736 | return MHD_DAUTH_NONCE_WRONG; | ||
1737 | } | ||
1738 | mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check); | ||
1739 | } | ||
1740 | |||
1741 | /* Get 'uri' */ | ||
1742 | if (NULL == params->uri.value.str) | ||
1743 | return MHD_DAUTH_WRONG_HEADER; | ||
1744 | else if (0 == params->uri.value.len) | ||
1745 | return MHD_DAUTH_WRONG_URI; | 1811 | return MHD_DAUTH_WRONG_URI; |
1746 | unq_res = get_unquoted_param_copy (¶ms->uri, tmp1, ptmp2, &tmp2_size, | ||
1747 | &unq_copy); | ||
1748 | if (_MHD_UNQ_OK != unq_res) | ||
1749 | return (_MHD_UNQ_TOO_LARGE == unq_res) ? | ||
1750 | MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR; | ||
1751 | |||
1752 | if (NULL != digest) | ||
1753 | { | ||
1754 | /* This will initialize da->digest_hex (ha1) */ | ||
1755 | digest_calc_ha1_from_digest (digest_get_algo_name (da), | ||
1756 | da, | ||
1757 | digest, | ||
1758 | noncehashexp, | ||
1759 | cnonce); | ||
1760 | } | ||
1761 | else | ||
1762 | { | ||
1763 | /* This will initialize da->digest_hex (ha1) */ | ||
1764 | mhd_assert (NULL != password); /* NULL == digest => password != NULL */ | ||
1765 | digest_calc_ha1_from_user (digest_get_algo_name (da), | ||
1766 | username, | ||
1767 | username_len, | ||
1768 | realm, | ||
1769 | realm_len, | ||
1770 | password, | ||
1771 | noncehashexp, | ||
1772 | cnonce, | ||
1773 | da); | ||
1774 | } | 1812 | } |
1775 | memcpy (ha1, | 1813 | |
1776 | digest_get_hex_buffer (da), | ||
1777 | digest_size * 2 + 1); | ||
1778 | /* This will initialize da->sessionkey (respexp) */ | ||
1779 | digest_calc_response (ha1, | ||
1780 | noncehashexp, | ||
1781 | nc, | ||
1782 | cnonce, | ||
1783 | qop, | ||
1784 | connection->method, | ||
1785 | unq_copy.str, | ||
1786 | unq_copy.len, | ||
1787 | hentity, | ||
1788 | da); | ||
1789 | if (1) | 1814 | if (1) |
1790 | { | 1815 | { |
1791 | char *uri; | 1816 | const char *args = qmark; |
1792 | size_t uri_len; | 1817 | |
1793 | uri = unq_copy.str; | 1818 | if (NULL == args) |
1794 | uri_len = unq_copy.len; | 1819 | args = ""; |
1795 | 1820 | else | |
1796 | uri[uri_len] = 0; | 1821 | args++; |
1797 | qmark = memchr (uri, | 1822 | if (MHD_NO == |
1798 | '?', | 1823 | check_argument_match (connection, |
1799 | uri_len); | 1824 | args) ) |
1800 | if (NULL != qmark) | ||
1801 | *qmark = '\0'; | ||
1802 | |||
1803 | /* Need to unescape URI before comparing with connection->url */ | ||
1804 | uri_len = daemon->unescape_callback (daemon->unescape_callback_cls, | ||
1805 | connection, | ||
1806 | uri); | ||
1807 | if ((uri_len != connection->url_len) || | ||
1808 | (0 != memcmp (uri, connection->url, uri_len))) | ||
1809 | { | 1825 | { |
1810 | #ifdef HAVE_MESSAGES | 1826 | #ifdef HAVE_MESSAGES |
1811 | MHD_DLOG (daemon, | 1827 | MHD_DLOG (daemon, |
1812 | _ ("Authentication failed, URI does not match.\n")); | 1828 | _ ("Authentication failed, arguments do not match.\n")); |
1813 | #endif | 1829 | #endif |
1814 | return MHD_DAUTH_WRONG_URI; | 1830 | return MHD_DAUTH_WRONG_URI; |
1815 | } | 1831 | } |
1816 | |||
1817 | if (1) | ||
1818 | { | ||
1819 | const char *args = qmark; | ||
1820 | |||
1821 | if (NULL == args) | ||
1822 | args = ""; | ||
1823 | else | ||
1824 | args++; | ||
1825 | if (MHD_NO == | ||
1826 | check_argument_match (connection, | ||
1827 | args) ) | ||
1828 | { | ||
1829 | #ifdef HAVE_MESSAGES | ||
1830 | MHD_DLOG (daemon, | ||
1831 | _ ("Authentication failed, arguments do not match.\n")); | ||
1832 | #endif | ||
1833 | return MHD_DAUTH_WRONG_URI; | ||
1834 | } | ||
1835 | } | ||
1836 | |||
1837 | ret = (0 == strcmp (response, | ||
1838 | digest_get_hex_buffer (da))) | ||
1839 | ? MHD_DAUTH_OK | ||
1840 | : MHD_DAUTH_RESPONSE_WRONG; | ||
1841 | } | 1832 | } |
1842 | } while (0); | 1833 | |
1834 | ret = (0 == strcmp (response, | ||
1835 | digest_get_hex_buffer (da))) | ||
1836 | ? MHD_DAUTH_OK | ||
1837 | : MHD_DAUTH_RESPONSE_WRONG; | ||
1838 | } | ||
1843 | 1839 | ||
1844 | return ret; | 1840 | return ret; |
1845 | } | 1841 | } |