aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/digestauth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r--src/microhttpd/digestauth.c536
1 files changed, 249 insertions, 287 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index 114f72b8..f4eecd03 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -134,7 +134,7 @@
134/** 134/**
135 * Maximum length of the response in digest authentication. 135 * Maximum length of the response in digest authentication.
136 */ 136 */
137#define MAX_AUTH_RESPONSE_LENGTH 256 137#define MAX_AUTH_RESPONSE_LENGTH (MAX_DIGEST * 2)
138 138
139/** 139/**
140 * The token for MD5 algorithm. 140 * The token for MD5 algorithm.
@@ -1305,19 +1305,56 @@ check_argument_match (struct MHD_Connection *connection,
1305 */ 1305 */
1306#define _MHD_STATIC_UNQ_BUFFER_SIZE 128 1306#define _MHD_STATIC_UNQ_BUFFER_SIZE 128
1307 1307
1308
1308/** 1309/**
1309 * The result of parameter unquoting 1310 * Get the pointer to buffer with required size
1311 * @param tmp1 the first buffer with fixed size
1312 * @param ptmp2 the pointer to pointer to malloc'ed buffer
1313 * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
1314 * @param required_size the required size in buffer
1315 * @return the pointer to the buffer or NULL if failed to allocate buffer with
1316 * requested size
1310 */ 1317 */
1318static char *
1319get_buffer_for_size (char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
1320 char **ptmp2,
1321 size_t *ptmp2_size,
1322 size_t required_size)
1323{
1324 mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2));
1325 mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size));
1326 mhd_assert ((0 == *ptmp2_size) || \
1327 (_MHD_STATIC_UNQ_BUFFER_SIZE < *ptmp2_size));
1328
1329 if (required_size <= _MHD_STATIC_UNQ_BUFFER_SIZE)
1330 return tmp1;
1331
1332 if (required_size <= *ptmp2_size)
1333 return *ptmp2;
1334
1335 if (required_size > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
1336 return NULL;
1337 if (NULL != *ptmp2)
1338 free (*ptmp2);
1339 *ptmp2 = (char *) malloc (required_size);
1340 if (NULL == *ptmp2)
1341 *ptmp2_size = 0;
1342 else
1343 *ptmp2_size = required_size;
1344 return *ptmp2;
1345}
1346
1347
1348/**
1349 * The result of parameter unquoting
1350 */
1311enum _MHD_GetUnqResult 1351enum _MHD_GetUnqResult
1312{ 1352{
1313 _MHD_UNQ_NON_EMPTY = 0, /**< The sting is not empty */ 1353 _MHD_UNQ_OK = 0, /**< Got unquoted string */
1314 _MHD_UNQ_NO_STRING = MHD_DAUTH_WRONG_HEADER, /**< No string (no such parameter) */ 1354 _MHD_UNQ_TOO_LARGE = -7, /**< The string is too large to unqoute */
1315 _MHD_UNQ_EMPTY = 1, /**< The string is empty */ 1355 _MHD_UNQ_OUT_OF_MEM = 3 /**< Out of memory error */
1316 _MHD_UNQ_TOO_LARGE = 2, /**< The string is too large to unqoute */
1317 _MHD_UNQ_OUT_OF_MEM = 3 /**< Out of memory error */
1318}; 1356};
1319 1357
1320
1321/** 1358/**
1322 * Get Digest authorisation parameter as unquoted string. 1359 * Get Digest authorisation parameter as unquoted string.
1323 * @param param the parameter to process 1360 * @param param the parameter to process
@@ -1328,60 +1365,79 @@ enum _MHD_GetUnqResult
1328 * @return enum code indicating result of the process 1365 * @return enum code indicating result of the process
1329 */ 1366 */
1330static enum _MHD_GetUnqResult 1367static enum _MHD_GetUnqResult
1331get_unqouted_param (const struct MHD_RqDAuthParam *param, 1368get_unquoted_param (const struct MHD_RqDAuthParam *param,
1332 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE], 1369 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
1333 char **ptmp2, 1370 char **ptmp2,
1334 size_t *ptmp2_size, 1371 size_t *ptmp2_size,
1335 struct _MHD_cstr_w_len *unquoted) 1372 struct _MHD_str_w_len *unquoted)
1336{ 1373{
1337 char *str; 1374 char *str;
1338 size_t len; 1375 size_t len;
1339 mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2)); 1376 mhd_assert (NULL != param->value.str);
1340 mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size)); 1377 mhd_assert (0 != param->value.len);
1341 mhd_assert ((0 == *ptmp2_size) || \
1342 (_MHD_STATIC_UNQ_BUFFER_SIZE < *ptmp2_size));
1343 1378
1344 if (NULL == param->value.str)
1345 {
1346 const struct _MHD_cstr_w_len res = {NULL, 0};
1347 mhd_assert (! param->quoted);
1348 mhd_assert (0 == param->value.len);
1349 memcpy (unquoted, &res, sizeof(res));
1350 return _MHD_UNQ_NO_STRING;
1351 }
1352 if (! param->quoted) 1379 if (! param->quoted)
1353 { 1380 {
1354 memcpy (unquoted, &param->value, sizeof(param->value)); 1381 unquoted->str = param->value.str;
1355 return (0 == param->value.len) ? _MHD_UNQ_EMPTY : _MHD_UNQ_NON_EMPTY; 1382 unquoted->len = param->value.len;
1383 return _MHD_UNQ_OK;
1356 } 1384 }
1357 /* The value is present and is quoted, needs to be copied and unquoted */ 1385 /* The value is present and is quoted, needs to be copied and unquoted */
1358 mhd_assert (0 != param->value.len); 1386 str = get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len);
1359 if (param->value.len <= _MHD_STATIC_UNQ_BUFFER_SIZE) 1387 if (NULL == str)
1360 str = tmp1; 1388 return (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
1361 else if (param->value.len <= *ptmp2_size) 1389 _MHD_UNQ_TOO_LARGE : _MHD_UNQ_OUT_OF_MEM;
1362 str = *ptmp2;
1363 else
1364 {
1365 if (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
1366 return _MHD_UNQ_TOO_LARGE;
1367 if (NULL != *ptmp2)
1368 free (*ptmp2);
1369 *ptmp2 = (char *) malloc (param->value.len);
1370 if (NULL == *ptmp2)
1371 return _MHD_UNQ_OUT_OF_MEM;
1372 *ptmp2_size = param->value.len;
1373 str = *ptmp2;
1374 }
1375 1390
1376 len = MHD_str_unquote (param->value.str, param->value.len, str); 1391 len = MHD_str_unquote (param->value.str, param->value.len, str);
1377 if (1) 1392 unquoted->str = str;
1393 unquoted->len = len;
1394 mhd_assert (0 != unquoted->len);
1395 mhd_assert (unquoted->len < param->value.len);
1396 return _MHD_UNQ_OK;
1397}
1398
1399
1400/**
1401 * Get copy of Digest authorisation parameter as unquoted string.
1402 * @param param the parameter to process
1403 * @param tmp1 the small buffer in stack
1404 * @param ptmp2 the pointer to pointer to malloc'ed buffer
1405 * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
1406 * @param[out] unquoted the pointer to store the result, NOT zero terminated,
1407 * but with enough space to zero-terminate
1408 * @return enum code indicating result of the process
1409 */
1410static enum _MHD_GetUnqResult
1411get_unquoted_param_copy (const struct MHD_RqDAuthParam *param,
1412 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
1413 char **ptmp2,
1414 size_t *ptmp2_size,
1415 struct _MHD_mstr_w_len *unquoted)
1416{
1417 mhd_assert (NULL != param->value.str);
1418 mhd_assert (0 != param->value.len);
1419
1420 /* The value is present and is quoted, needs to be copied and unquoted */
1421 /* Allocate buffer with one more additional byte for zero-termination */
1422 unquoted->str =
1423 get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len + 1);
1424
1425 if (NULL == unquoted->str)
1426 return (param->value.len + 1 > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
1427 _MHD_UNQ_TOO_LARGE : _MHD_UNQ_OUT_OF_MEM;
1428
1429 if (! param->quoted)
1378 { 1430 {
1379 const struct _MHD_cstr_w_len res = {str, len}; 1431 memcpy (unquoted->str, param->value.str, param->value.len);
1380 memcpy (unquoted, &res, sizeof(res)); 1432 unquoted->len = param->value.len;
1433 return _MHD_UNQ_OK;
1381 } 1434 }
1435
1436 unquoted->len =
1437 MHD_str_unquote (param->value.str, param->value.len, unquoted->str);
1382 mhd_assert (0 != unquoted->len); 1438 mhd_assert (0 != unquoted->len);
1383 mhd_assert (unquoted->len < param->value.len); 1439 mhd_assert (unquoted->len < param->value.len);
1384 return _MHD_UNQ_NON_EMPTY; 1440 return _MHD_UNQ_OK;
1385} 1441}
1386 1442
1387 1443
@@ -1424,18 +1480,21 @@ is_param_equal (const struct MHD_RqDAuthParam *param,
1424 * (must contain "da->digest_size" bytes or be NULL) 1480 * (must contain "da->digest_size" bytes or be NULL)
1425 * @param nonce_timeout The amount of time for a nonce to be 1481 * @param nonce_timeout The amount of time for a nonce to be
1426 * invalid in seconds 1482 * invalid in seconds
1483 * @param[out] pbuf the pointer to pointer to internally malloc'ed buffer,
1484 * to be free if not NULL upon return
1427 * @return #MHD_DAUTH_OK if authenticated, 1485 * @return #MHD_DAUTH_OK if authenticated,
1428 * error code otherwise. 1486 * error code otherwise.
1429 * @ingroup authentication 1487 * @ingroup authentication
1430 */ 1488 */
1431static enum MHD_DigestAuthResult 1489static enum MHD_DigestAuthResult
1432digest_auth_check_all (struct MHD_Connection *connection, 1490digest_auth_check_all_inner (struct MHD_Connection *connection,
1433 struct DigestAlgorithm *da, 1491 struct DigestAlgorithm *da,
1434 const char *realm, 1492 const char *realm,
1435 const char *username, 1493 const char *username,
1436 const char *password, 1494 const char *password,
1437 const uint8_t *digest, 1495 const uint8_t *digest,
1438 unsigned int nonce_timeout) 1496 unsigned int nonce_timeout,
1497 char **pbuf)
1439{ 1498{
1440 struct MHD_Daemon *daemon = MHD_get_master (connection->daemon); 1499 struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
1441 char cnonce[MAX_CLIENT_NONCE_LENGTH]; 1500 char cnonce[MAX_CLIENT_NONCE_LENGTH];
@@ -1452,91 +1511,63 @@ digest_auth_check_all (struct MHD_Connection *connection,
1452 char *qmark; 1511 char *qmark;
1453 const struct MHD_RqDAuth *params; 1512 const struct MHD_RqDAuth *params;
1454 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE]; /**< Temporal buffer in stack for unqouting */ 1513 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE]; /**< Temporal buffer in stack for unqouting */
1455 char *tmp2; /**< Temporal malloc'ed buffer for unqouting */ 1514 char **const ptmp2 = pbuf; /**< Temporal malloc'ed buffer for unqouting */
1456 size_t tmp2_size; /**< The size of @a tmp2 buffer */ 1515 size_t tmp2_size; /**< The size of @a tmp2 buffer */
1457 struct _MHD_cstr_w_len unquoted; 1516 struct _MHD_str_w_len unquoted;
1517 struct _MHD_mstr_w_len unq_copy;
1458 enum _MHD_GetUnqResult unq_res; 1518 enum _MHD_GetUnqResult unq_res;
1459 enum MHD_DigestAuthResult ret; 1519 enum MHD_DigestAuthResult ret;
1460#ifdef HAVE_MESSAGES
1461 bool err_logged;
1462#endif /* HAVE_MESSAGES */
1463 size_t username_len; 1520 size_t username_len;
1464 size_t realm_len; 1521 size_t realm_len;
1465 1522
1466 tmp2 = NULL;
1467 tmp2_size = 0; 1523 tmp2_size = 0;
1468#ifdef HAVE_MESSAGES
1469 err_logged = false;
1470#endif /* HAVE_MESSAGES */
1471 1524
1472 do /* Only to avoid "goto" */ 1525 do /* Only to avoid "goto" */
1473 { 1526 {
1474 1527
1475 params = get_rq_dauth_params (connection); 1528 params = get_rq_dauth_params (connection);
1476 if (NULL == params) 1529 if (NULL == params)
1477 { 1530 return MHD_DAUTH_WRONG_HEADER;
1478 ret = MHD_DAUTH_WRONG_HEADER;
1479 break;
1480 }
1481 1531
1482 /* Check 'username' */ 1532 /* Check 'username' */
1483 if (NULL == params->username.value.str) 1533 if (NULL == params->username.value.str)
1484 { 1534 return MHD_DAUTH_WRONG_HEADER;
1485 ret = MHD_DAUTH_WRONG_HEADER; 1535
1486 break;
1487 }
1488 username_len = strlen (username); 1536 username_len = strlen (username);
1489 if (! is_param_equal (&params->username, username, username_len)) 1537 if (! is_param_equal (&params->username, username, username_len))
1490 { 1538 return MHD_DAUTH_WRONG_USERNAME;
1491 ret = MHD_DAUTH_WRONG_USERNAME;
1492 break;
1493 }
1494 /* 'username' valid */ 1539 /* 'username' valid */
1495 1540
1496 /* Check 'realm' */ 1541 /* Check 'realm' */
1497 if (NULL == params->realm.value.str) 1542 if (NULL == params->realm.value.str)
1498 { 1543 return MHD_DAUTH_WRONG_HEADER;
1499 ret = MHD_DAUTH_WRONG_HEADER;
1500 break;
1501 }
1502 realm_len = strlen (realm); 1544 realm_len = strlen (realm);
1503 if (! is_param_equal (&params->realm, realm, realm_len)) 1545 if (! is_param_equal (&params->realm, realm, realm_len))
1504 { 1546 return MHD_DAUTH_WRONG_REALM;
1505 ret = MHD_DAUTH_WRONG_REALM;
1506 break;
1507 }
1508 /* 'realm' valid */ 1547 /* 'realm' valid */
1509 1548
1510 /* Check 'nonce' */ 1549 /* Check 'nonce' */
1511 unq_res = get_unqouted_param (&params->nonce, tmp1, &tmp2, &tmp2_size, 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
1557 unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
1512 &unquoted); 1558 &unquoted);
1513 if (_MHD_UNQ_NON_EMPTY != unq_res) 1559 if (_MHD_UNQ_OK != unq_res)
1514 { 1560 return MHD_DAUTH_ERROR;
1515 if (_MHD_UNQ_NO_STRING == unq_res) 1561 if (NONCE_STD_LEN (digest_size) != unquoted.len)
1516 ret = MHD_DAUTH_WRONG_HEADER; 1562 return MHD_DAUTH_NONCE_WRONG;
1517 else if (_MHD_UNQ_EMPTY == unq_res) 1563
1518 ret = MHD_DAUTH_NONCE_WRONG;
1519 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1520 ret = MHD_DAUTH_WRONG_HEADER;
1521 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1522 ret = MHD_DAUTH_ERROR;
1523 else
1524 {
1525 mhd_assert (0); /* Must not happen */
1526 ret = MHD_DAUTH_ERROR;
1527 }
1528 break;
1529 }
1530 /* TODO: check correct 'nonce' length */
1531 if (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time)) 1564 if (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time))
1532 { 1565 {
1533#ifdef HAVE_MESSAGES 1566#ifdef HAVE_MESSAGES
1534 MHD_DLOG (daemon, 1567 MHD_DLOG (daemon,
1535 _ ("Authentication failed, invalid timestamp format.\n")); 1568 _ ("Authentication failed, invalid timestamp format.\n"));
1536 err_logged = true;
1537#endif 1569#endif
1538 ret = MHD_DAUTH_NONCE_WRONG; 1570 return MHD_DAUTH_NONCE_WRONG;
1539 break;
1540 } 1571 }
1541 t = MHD_monotonic_msec_counter (); 1572 t = MHD_monotonic_msec_counter ();
1542 /* 1573 /*
@@ -1545,11 +1576,7 @@ digest_auth_check_all (struct MHD_Connection *connection,
1545 * invalid. 1576 * invalid.
1546 */ 1577 */
1547 if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000)) 1578 if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
1548 { 1579 return MHD_DAUTH_NONCE_STALE; /* too old */
1549 /* too old */
1550 ret = MHD_DAUTH_NONCE_STALE;
1551 break;
1552 }
1553 1580
1554 calculate_nonce (nonce_time, 1581 calculate_nonce (nonce_time,
1555 connection->method, 1582 connection->method,
@@ -1571,107 +1598,66 @@ digest_auth_check_all (struct MHD_Connection *connection,
1571 */ 1598 */
1572 if ((0 != strncmp (noncehashexp, unquoted.str, unquoted.len)) || 1599 if ((0 != strncmp (noncehashexp, unquoted.str, unquoted.len)) ||
1573 (0 != noncehashexp[unquoted.len])) 1600 (0 != noncehashexp[unquoted.len]))
1574 { 1601 return MHD_DAUTH_NONCE_WRONG;
1575 ret = MHD_DAUTH_NONCE_WRONG;
1576 break;
1577 }
1578 /* 'nonce' valid */ 1602 /* 'nonce' valid */
1579 1603
1580 /* Get 'cnonce' */ 1604 /* Get 'cnonce' */
1581 unq_res = get_unqouted_param (&params->cnonce, tmp1, &tmp2, &tmp2_size, 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 (&params->cnonce, tmp1, ptmp2, &tmp2_size,
1582 &unquoted); 1610 &unquoted);
1583 if (_MHD_UNQ_NON_EMPTY != unq_res) 1611 if (_MHD_UNQ_OK != unq_res)
1584 { 1612 return (_MHD_UNQ_TOO_LARGE == unq_res) ?
1585 if (_MHD_UNQ_NO_STRING == unq_res) 1613 MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR;
1586 ret = MHD_DAUTH_WRONG_HEADER; 1614
1587 else if (_MHD_UNQ_EMPTY == unq_res)
1588 ret = MHD_DAUTH_WRONG_HEADER;
1589 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1590 ret = MHD_DAUTH_WRONG_HEADER;
1591 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1592 ret = MHD_DAUTH_ERROR;
1593 else
1594 {
1595 mhd_assert (0); /* Must not happen */
1596 ret = MHD_DAUTH_ERROR;
1597 }
1598 break;
1599 }
1600 if (sizeof(cnonce) <= unquoted.len) 1615 if (sizeof(cnonce) <= unquoted.len)
1601 { 1616 return MHD_DAUTH_ERROR; /* TODO: handle large client nonces */
1602 /* TODO: handle large client nonces */ 1617
1603 ret = MHD_DAUTH_ERROR;
1604 break;
1605 }
1606 /* TODO: avoid memcpy() */ 1618 /* TODO: avoid memcpy() */
1607 memcpy (cnonce, unquoted.str, unquoted.len); 1619 memcpy (cnonce, unquoted.str, unquoted.len);
1608 cnonce[unquoted.len] = 0; 1620 cnonce[unquoted.len] = 0;
1609 /* Got 'cnonce' */ 1621 /* Got 'cnonce' */
1610 1622
1611 /* Get 'qop' */ 1623 /* Get 'qop' */
1612 unq_res = get_unqouted_param (&params->qop, tmp1, &tmp2, &tmp2_size, 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 (&params->qop, tmp1, ptmp2, &tmp2_size,
1613 &unquoted); 1631 &unquoted);
1614 if (_MHD_UNQ_NON_EMPTY != unq_res) 1632 if (_MHD_UNQ_OK != unq_res)
1615 { 1633 return MHD_DAUTH_ERROR;
1616 if (_MHD_UNQ_NO_STRING == unq_res) 1634
1617 ret = MHD_DAUTH_WRONG_HEADER;
1618 else if (_MHD_UNQ_EMPTY == unq_res)
1619 ret = MHD_DAUTH_WRONG_HEADER;
1620 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1621 ret = MHD_DAUTH_WRONG_HEADER;
1622 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1623 ret = MHD_DAUTH_ERROR;
1624 else
1625 {
1626 mhd_assert (0); /* Must not happen */
1627 ret = MHD_DAUTH_ERROR;
1628 }
1629 break;
1630 }
1631 if (sizeof(qop) <= unquoted.len) 1635 if (sizeof(qop) <= unquoted.len)
1632 { 1636 return MHD_DAUTH_ERROR; /* TODO: handle large client qop */
1633 /* TODO: handle large client qop */
1634 ret = MHD_DAUTH_ERROR;
1635 break;
1636 }
1637 /* TODO: avoid memcpy() */ 1637 /* TODO: avoid memcpy() */
1638 memcpy (qop, unquoted.str, unquoted.len); 1638 memcpy (qop, unquoted.str, unquoted.len);
1639 qop[unquoted.len] = 0; 1639 qop[unquoted.len] = 0;
1640 /* TODO: use caseless match, use dedicated return code */ 1640 /* TODO: Really support empty value, support "auth-int" */
1641 if ( (0 != strcmp (qop, "auth")) && 1641 if ( ((MHD_STATICSTR_LEN_ ("auth") != unquoted.len) ||
1642 (! MHD_str_equal_caseless_bin_n_ (qop, "auth", unquoted.len))) &&
1642 (0 != strcmp (qop,"")) ) 1643 (0 != strcmp (qop,"")) )
1643 { 1644 return MHD_DAUTH_WRONG_QOP;
1644 ret = MHD_DAUTH_WRONG_HEADER;
1645 break;
1646 }
1647 /* Got 'qop' */ 1645 /* Got 'qop' */
1648 1646
1649 /* Get 'nc' */ 1647 /* Get 'nc' */
1650 unq_res = get_unqouted_param (&params->nc, tmp1, &tmp2, &tmp2_size, 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 (&params->nc, tmp1, ptmp2, &tmp2_size,
1651 &unquoted); 1655 &unquoted);
1652 if (_MHD_UNQ_NON_EMPTY != unq_res) 1656 if (_MHD_UNQ_OK != unq_res)
1653 { 1657 return MHD_DAUTH_ERROR;
1654 if (_MHD_UNQ_NO_STRING == unq_res) 1658
1655 ret = MHD_DAUTH_WRONG_HEADER;
1656 else if (_MHD_UNQ_EMPTY == unq_res)
1657 ret = MHD_DAUTH_WRONG_HEADER;
1658 else if (_MHD_UNQ_TOO_LARGE == unq_res)
1659 ret = MHD_DAUTH_WRONG_HEADER;
1660 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1661 ret = MHD_DAUTH_ERROR;
1662 else
1663 {
1664 mhd_assert (0); /* Must not happen */
1665 ret = MHD_DAUTH_ERROR;
1666 }
1667 break;
1668 }
1669 if (sizeof(nc) <= unquoted.len) 1659 if (sizeof(nc) <= unquoted.len)
1670 { 1660 return MHD_DAUTH_ERROR;
1671 /* TODO: handle large client nc */
1672 ret = MHD_DAUTH_ERROR;
1673 break;
1674 }
1675 /* TODO: avoid memcpy() */ 1661 /* TODO: avoid memcpy() */
1676 memcpy (nc, unquoted.str, unquoted.len); 1662 memcpy (nc, unquoted.str, unquoted.len);
1677 nc[unquoted.len] = 0; 1663 nc[unquoted.len] = 0;
@@ -1682,49 +1668,37 @@ digest_auth_check_all (struct MHD_Connection *connection,
1682#ifdef HAVE_MESSAGES 1668#ifdef HAVE_MESSAGES
1683 MHD_DLOG (daemon, 1669 MHD_DLOG (daemon,
1684 _ ("Authentication failed, invalid nc format.\n")); 1670 _ ("Authentication failed, invalid nc format.\n"));
1685 err_logged = true;
1686#endif 1671#endif
1687 ret = MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */ 1672 return MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */
1688 break;
1689 } 1673 }
1690 if (0 == nci) 1674 if (0 == nci)
1691 { 1675 {
1692#ifdef HAVE_MESSAGES 1676#ifdef HAVE_MESSAGES
1693 MHD_DLOG (daemon, 1677 MHD_DLOG (daemon,
1694 _ ("Authentication failed, invalid 'nc' value.\n")); 1678 _ ("Authentication failed, invalid 'nc' value.\n"));
1695 err_logged = true;
1696#endif 1679#endif
1697 ret = MHD_DAUTH_WRONG_HEADER; /* invalid nc value */ 1680 return MHD_DAUTH_WRONG_HEADER; /* invalid nc value */
1698 break;
1699 } 1681 }
1700 /* Got 'nc' */ 1682 /* Got 'nc' */
1701 1683
1702 /* Get 'response' */ 1684 /* Get 'response' */
1703 unq_res = get_unqouted_param (&params->response, tmp1, &tmp2, &tmp2_size, 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 (&params->response, tmp1, ptmp2, &tmp2_size,
1704 &unquoted); 1692 &unquoted);
1705 if (_MHD_UNQ_NON_EMPTY != unq_res) 1693 if (_MHD_UNQ_OK != unq_res)
1706 { 1694 return MHD_DAUTH_ERROR;
1707 if (_MHD_UNQ_NO_STRING == unq_res) 1695 if (digest_size * 2 != unquoted.len)
1708 ret = MHD_DAUTH_WRONG_HEADER; 1696 return MHD_DAUTH_RESPONSE_WRONG;
1709 else if (_MHD_UNQ_EMPTY == unq_res) 1697
1710 ret = MHD_DAUTH_WRONG_HEADER; 1698 mhd_assert (sizeof(response) > unquoted.len);
1711 else if (_MHD_UNQ_TOO_LARGE == unq_res) 1699
1712 ret = MHD_DAUTH_WRONG_HEADER;
1713 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1714 ret = MHD_DAUTH_ERROR;
1715 else
1716 {
1717 mhd_assert (0); /* Must not happen */
1718 ret = MHD_DAUTH_ERROR;
1719 }
1720 break;
1721 }
1722 if (sizeof(response) <= unquoted.len) 1700 if (sizeof(response) <= unquoted.len)
1723 { 1701 return MHD_DAUTH_ERROR;
1724 /* TODO: handle large client response */
1725 ret = MHD_DAUTH_ERROR;
1726 break;
1727 }
1728 /* TODO: avoid memcpy() */ 1702 /* TODO: avoid memcpy() */
1729 memcpy (response, unquoted.str, unquoted.len); 1703 memcpy (response, unquoted.str, unquoted.len);
1730 response[unquoted.len] = 0; 1704 response[unquoted.len] = 0;
@@ -1749,10 +1723,8 @@ digest_auth_check_all (struct MHD_Connection *connection,
1749 MHD_DLOG (daemon, 1723 MHD_DLOG (daemon,
1750 _ ("Stale nonce received. If this happens a lot, you should " 1724 _ ("Stale nonce received. If this happens a lot, you should "
1751 "probably increase the size of the nonce array.\n")); 1725 "probably increase the size of the nonce array.\n"));
1752 err_logged = true;
1753#endif 1726#endif
1754 ret = MHD_DAUTH_NONCE_STALE; 1727 return MHD_DAUTH_NONCE_STALE;
1755 break;
1756 } 1728 }
1757 else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check) 1729 else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check)
1758 { 1730 {
@@ -1760,34 +1732,23 @@ digest_auth_check_all (struct MHD_Connection *connection,
1760 MHD_DLOG (daemon, 1732 MHD_DLOG (daemon,
1761 _ ("Received nonce that technically valid, but was not " 1733 _ ("Received nonce that technically valid, but was not "
1762 "generated by MHD. This may indicate an attack attempt.\n")); 1734 "generated by MHD. This may indicate an attack attempt.\n"));
1763 err_logged = true;
1764#endif 1735#endif
1765 ret = MHD_DAUTH_NONCE_WRONG; 1736 return MHD_DAUTH_NONCE_WRONG;
1766 break;
1767 } 1737 }
1768 mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check); 1738 mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
1769 } 1739 }
1770 1740
1771 /* Get 'uri' */ 1741 /* Get 'uri' */
1772 unq_res = get_unqouted_param (&params->uri, tmp1, &tmp2, &tmp2_size, 1742 if (NULL == params->uri.value.str)
1773 &unquoted); 1743 return MHD_DAUTH_WRONG_HEADER;
1774 if (_MHD_UNQ_NON_EMPTY != unq_res) 1744 else if (0 == params->uri.value.len)
1775 { 1745 return MHD_DAUTH_WRONG_URI;
1776 if (_MHD_UNQ_NO_STRING == unq_res) 1746 unq_res = get_unquoted_param_copy (&params->uri, tmp1, ptmp2, &tmp2_size,
1777 ret = MHD_DAUTH_WRONG_HEADER; 1747 &unq_copy);
1778 else if (_MHD_UNQ_EMPTY == unq_res) 1748 if (_MHD_UNQ_OK != unq_res)
1779 ret = MHD_DAUTH_WRONG_HEADER; 1749 return (_MHD_UNQ_TOO_LARGE == unq_res) ?
1780 else if (_MHD_UNQ_TOO_LARGE == unq_res) 1750 MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR;
1781 ret = MHD_DAUTH_WRONG_HEADER; 1751
1782 else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
1783 ret = MHD_DAUTH_ERROR;
1784 else
1785 {
1786 mhd_assert (0); /* Must not happen */
1787 ret = MHD_DAUTH_ERROR;
1788 }
1789 break;
1790 }
1791 if (NULL != digest) 1752 if (NULL != digest)
1792 { 1753 {
1793 /* This will initialize da->digest_hex (ha1) */ 1754 /* This will initialize da->digest_hex (ha1) */
@@ -1821,45 +1782,16 @@ digest_auth_check_all (struct MHD_Connection *connection,
1821 cnonce, 1782 cnonce,
1822 qop, 1783 qop,
1823 connection->method, 1784 connection->method,
1824 unquoted.str, 1785 unq_copy.str,
1825 unquoted.len, 1786 unq_copy.len,
1826 hentity, 1787 hentity,
1827 da); 1788 da);
1828 if (1) 1789 if (1)
1829 { 1790 {
1830 char *uri; 1791 char *uri;
1831 size_t uri_len; 1792 size_t uri_len;
1832 uri_len = unquoted.len; 1793 uri = unq_copy.str;
1833 /* TODO: simplify string copy, avoid potential double copy */ 1794 uri_len = unq_copy.len;
1834 if ( ((tmp1 != unquoted.str) && (tmp2 != unquoted.str)) ||
1835 ((tmp1 == unquoted.str) && (sizeof(tmp1) >= unquoted.len)) ||
1836 ((tmp2 == unquoted.str) && (tmp2_size >= unquoted.len)))
1837 {
1838 char *buf;
1839 mhd_assert ((tmp1 != unquoted.str) || \
1840 (sizeof(tmp1) == unquoted.len));
1841 mhd_assert ((tmp2 != unquoted.str) || \
1842 (tmp2_size == unquoted.len));
1843 buf = malloc (unquoted.len + 1);
1844 if (NULL == buf)
1845 {
1846 ret = MHD_DAUTH_ERROR;
1847 break;
1848 }
1849 memcpy (buf, unquoted.str, unquoted.len);
1850 if (NULL != tmp2)
1851 free (tmp2);
1852 tmp2 = buf;
1853 tmp2_size = unquoted.len + 1;
1854 uri = tmp2;
1855 }
1856 else if (tmp1 == unquoted.str)
1857 uri = tmp1;
1858 else
1859 {
1860 mhd_assert (tmp2 == unquoted.str);
1861 uri = tmp2;
1862 }
1863 1795
1864 uri[uri_len] = 0; 1796 uri[uri_len] = 0;
1865 qmark = memchr (uri, 1797 qmark = memchr (uri,
@@ -1878,10 +1810,8 @@ digest_auth_check_all (struct MHD_Connection *connection,
1878#ifdef HAVE_MESSAGES 1810#ifdef HAVE_MESSAGES
1879 MHD_DLOG (daemon, 1811 MHD_DLOG (daemon,
1880 _ ("Authentication failed, URI does not match.\n")); 1812 _ ("Authentication failed, URI does not match.\n"));
1881 err_logged = true;
1882#endif 1813#endif
1883 ret = MHD_DAUTH_WRONG_URI; 1814 return MHD_DAUTH_WRONG_URI;
1884 break;
1885 } 1815 }
1886 1816
1887 if (1) 1817 if (1)
@@ -1899,10 +1829,8 @@ digest_auth_check_all (struct MHD_Connection *connection,
1899#ifdef HAVE_MESSAGES 1829#ifdef HAVE_MESSAGES
1900 MHD_DLOG (daemon, 1830 MHD_DLOG (daemon,
1901 _ ("Authentication failed, arguments do not match.\n")); 1831 _ ("Authentication failed, arguments do not match.\n"));
1902 err_logged = true;
1903#endif 1832#endif
1904 ret = MHD_DAUTH_WRONG_URI; 1833 return MHD_DAUTH_WRONG_URI;
1905 break;
1906 } 1834 }
1907 } 1835 }
1908 1836
@@ -1912,19 +1840,53 @@ digest_auth_check_all (struct MHD_Connection *connection,
1912 : MHD_DAUTH_RESPONSE_WRONG; 1840 : MHD_DAUTH_RESPONSE_WRONG;
1913 } 1841 }
1914 } while (0); 1842 } while (0);
1915 if (NULL != tmp2)
1916 free (tmp2);
1917
1918 if ((MHD_DAUTH_OK != ret) && ! err_logged)
1919 {
1920 (void) 0; /* TODO: add logging */
1921 }
1922 1843
1923 return ret; 1844 return ret;
1924} 1845}
1925 1846
1926 1847
1927/** 1848/**
1849 * Authenticates the authorization header sent by the client
1850 *
1851 * @param connection The MHD connection structure
1852 * @param[in,out] da digest algorithm to use for checking (written to as
1853 * part of the calculations, but the values left in the struct
1854 * are not actually expected to be useful for the caller)
1855 * @param realm The realm presented to the client
1856 * @param username The username needs to be authenticated
1857 * @param password The password used in the authentication
1858 * @param digest An optional binary hash
1859 * of the precalculated hash value "username:realm:password"
1860 * (must contain "da->digest_size" bytes or be NULL)
1861 * @param nonce_timeout The amount of time for a nonce to be
1862 * invalid in seconds
1863 * @return #MHD_DAUTH_OK if authenticated,
1864 * error code otherwise.
1865 * @ingroup authentication
1866 */
1867static enum MHD_DigestAuthResult
1868digest_auth_check_all (struct MHD_Connection *connection,
1869 struct DigestAlgorithm *da,
1870 const char *realm,
1871 const char *username,
1872 const char *password,
1873 const uint8_t *digest,
1874 unsigned int nonce_timeout)
1875{
1876 enum MHD_DigestAuthResult res;
1877 char *buf;
1878
1879 buf = NULL;
1880 res = digest_auth_check_all_inner (connection, da, realm, username, password,
1881 digest, nonce_timeout, &buf);
1882 if (NULL != buf)
1883 free (buf);
1884
1885 return res;
1886}
1887
1888
1889/**
1928 * Authenticates the authorization header sent by the client. 1890 * Authenticates the authorization header sent by the client.
1929 * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility). 1891 * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility).
1930 * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future. 1892 * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future.