diff options
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r-- | src/microhttpd/digestauth.c | 172 |
1 files changed, 124 insertions, 48 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c index a92d99ed..d870902e 100644 --- a/src/microhttpd/digestauth.c +++ b/src/microhttpd/digestauth.c | |||
@@ -147,6 +147,63 @@ | |||
147 | */ | 147 | */ |
148 | #define _MHD_SESS_TOKEN "-sess" | 148 | #define _MHD_SESS_TOKEN "-sess" |
149 | 149 | ||
150 | |||
151 | /** | ||
152 | * The result of digest authentication of the client. | ||
153 | */ | ||
154 | enum MHD_DigestAuthResult | ||
155 | { | ||
156 | /** | ||
157 | * Authentication OK | ||
158 | */ | ||
159 | MHD_DAUTH_OK = 1, | ||
160 | |||
161 | /** | ||
162 | * General error, like "out of memory" | ||
163 | */ | ||
164 | MHD_DAUTH_ERROR = 0, | ||
165 | |||
166 | /** | ||
167 | * No "Authorization" header or wrong format of the header. | ||
168 | */ | ||
169 | MHD_DAUTH_WRONG_HEADER = -1, | ||
170 | |||
171 | /** | ||
172 | * Wrong 'username'. | ||
173 | */ | ||
174 | MHD_DAUTH_WRONG_USERNAME = -2, | ||
175 | |||
176 | /** | ||
177 | * Wrong 'realm'. | ||
178 | */ | ||
179 | MHD_DAUTH_WRONG_REALM = -3, | ||
180 | |||
181 | /** | ||
182 | * Wrong 'URI' (or URI parameters). | ||
183 | */ | ||
184 | MHD_DAUTH_WRONG_URI = -4, | ||
185 | |||
186 | /* The different form of naming is intentionally used for the results below, | ||
187 | * as they are more important */ | ||
188 | |||
189 | /** | ||
190 | * The 'nonce' is too old. Suggest the client to retry with the same | ||
191 | * username and password to get the fresh 'nonce'. | ||
192 | * The validity of the 'nonce' may not be checked. | ||
193 | */ | ||
194 | MHD_DAUTH_NONCE_STALE = -16, | ||
195 | |||
196 | /** | ||
197 | * The 'nonce' is wrong. May indicate an attack attempt. | ||
198 | */ | ||
199 | MHD_DAUTH_NONCE_WRONG = -32, | ||
200 | |||
201 | /** | ||
202 | * The 'response' is wrong. May indicate an attack attempt. | ||
203 | */ | ||
204 | MHD_DAUTH_RESPONSE_WRONG = -33, | ||
205 | }; | ||
206 | |||
150 | /** | 207 | /** |
151 | * Context passed to functions that need to calculate | 208 | * Context passed to functions that need to calculate |
152 | * a digest but are orthogonal to the specific | 209 | * a digest but are orthogonal to the specific |
@@ -1129,11 +1186,11 @@ check_argument_match (struct MHD_Connection *connection, | |||
1129 | * (must contain "da->digest_size" bytes or be NULL) | 1186 | * (must contain "da->digest_size" bytes or be NULL) |
1130 | * @param nonce_timeout The amount of time for a nonce to be | 1187 | * @param nonce_timeout The amount of time for a nonce to be |
1131 | * invalid in seconds | 1188 | * invalid in seconds |
1132 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 1189 | * @return #MHD_DAUTH_OK if authenticated, |
1133 | * #MHD_INVALID_NONCE if nonce is invalid | 1190 | * error code otherwise. |
1134 | * @ingroup authentication | 1191 | * @ingroup authentication |
1135 | */ | 1192 | */ |
1136 | static int | 1193 | static enum MHD_DigestAuthResult |
1137 | digest_auth_check_all (struct MHD_Connection *connection, | 1194 | digest_auth_check_all (struct MHD_Connection *connection, |
1138 | struct DigestAlgorithm *da, | 1195 | struct DigestAlgorithm *da, |
1139 | const char *realm, | 1196 | const char *realm, |
@@ -1169,14 +1226,15 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1169 | MHD_HTTP_HEADER_AUTHORIZATION), | 1226 | MHD_HTTP_HEADER_AUTHORIZATION), |
1170 | &header, | 1227 | &header, |
1171 | NULL)) | 1228 | NULL)) |
1172 | return MHD_NO; | 1229 | return MHD_DAUTH_WRONG_HEADER; |
1173 | if (0 != strncmp (header, | 1230 | if (0 != strncmp (header, |
1174 | _BASE, | 1231 | _BASE, |
1175 | MHD_STATICSTR_LEN_ (_BASE))) | 1232 | MHD_STATICSTR_LEN_ (_BASE))) |
1176 | return MHD_NO; | 1233 | return MHD_DAUTH_WRONG_HEADER; |
1177 | header += MHD_STATICSTR_LEN_ (_BASE); | 1234 | header += MHD_STATICSTR_LEN_ (_BASE); |
1178 | left = strlen (header); | 1235 | left = strlen (header); |
1179 | 1236 | ||
1237 | if (1) | ||
1180 | { | 1238 | { |
1181 | char un[MAX_USERNAME_LENGTH]; | 1239 | char un[MAX_USERNAME_LENGTH]; |
1182 | 1240 | ||
@@ -1184,13 +1242,15 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1184 | sizeof (un), | 1242 | sizeof (un), |
1185 | header, | 1243 | header, |
1186 | "username"); | 1244 | "username"); |
1187 | if ( (0 == len) || | 1245 | if (0 == len) |
1188 | (0 != strcmp (username, | 1246 | return MHD_DAUTH_WRONG_HEADER; |
1189 | un)) ) | 1247 | if (0 != strcmp (username, |
1190 | return MHD_NO; | 1248 | un)) |
1249 | return MHD_DAUTH_WRONG_USERNAME; | ||
1191 | left -= strlen ("username") + len; | 1250 | left -= strlen ("username") + len; |
1192 | } | 1251 | } |
1193 | 1252 | ||
1253 | if (1) | ||
1194 | { | 1254 | { |
1195 | char r[MAX_REALM_LENGTH]; | 1255 | char r[MAX_REALM_LENGTH]; |
1196 | 1256 | ||
@@ -1198,10 +1258,11 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1198 | sizeof (r), | 1258 | sizeof (r), |
1199 | header, | 1259 | header, |
1200 | "realm"); | 1260 | "realm"); |
1201 | if ( (0 == len) || | 1261 | if (0 == len) |
1202 | (0 != strcmp (realm, | 1262 | return MHD_DAUTH_WRONG_HEADER; |
1203 | r)) ) | 1263 | if (0 != strcmp (realm, |
1204 | return MHD_NO; | 1264 | r)) |
1265 | return MHD_DAUTH_WRONG_REALM; | ||
1205 | left -= strlen ("realm") + len; | 1266 | left -= strlen ("realm") + len; |
1206 | } | 1267 | } |
1207 | 1268 | ||
@@ -1209,7 +1270,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1209 | sizeof (nonce), | 1270 | sizeof (nonce), |
1210 | header, | 1271 | header, |
1211 | "nonce"))) | 1272 | "nonce"))) |
1212 | return MHD_NO; | 1273 | return MHD_DAUTH_WRONG_HEADER; |
1213 | nonce_len = len; | 1274 | nonce_len = len; |
1214 | left -= strlen ("nonce") + len; | 1275 | left -= strlen ("nonce") + len; |
1215 | if (left > 32 * 1024) | 1276 | if (left > 32 * 1024) |
@@ -1221,7 +1282,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1221 | #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large | 1282 | #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large |
1222 | and would thus permit sending a >32k authorization | 1283 | and would thus permit sending a >32k authorization |
1223 | header value. */ | 1284 | header value. */ |
1224 | return MHD_NO; | 1285 | return MHD_DAUTH_WRONG_HEADER; |
1225 | } | 1286 | } |
1226 | if (! get_nonce_timestamp (nonce, nonce_len, &nonce_time)) | 1287 | if (! get_nonce_timestamp (nonce, nonce_len, &nonce_time)) |
1227 | { | 1288 | { |
@@ -1229,7 +1290,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1229 | MHD_DLOG (daemon, | 1290 | MHD_DLOG (daemon, |
1230 | _ ("Authentication failed, invalid timestamp format.\n")); | 1291 | _ ("Authentication failed, invalid timestamp format.\n")); |
1231 | #endif | 1292 | #endif |
1232 | return MHD_NO; | 1293 | return MHD_DAUTH_WRONG_HEADER; |
1233 | } | 1294 | } |
1234 | 1295 | ||
1235 | t = MHD_monotonic_msec_counter (); | 1296 | t = MHD_monotonic_msec_counter (); |
@@ -1241,7 +1302,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1241 | if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000)) | 1302 | if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000)) |
1242 | { | 1303 | { |
1243 | /* too old */ | 1304 | /* too old */ |
1244 | return MHD_INVALID_NONCE; | 1305 | return MHD_DAUTH_NONCE_STALE; |
1245 | } | 1306 | } |
1246 | 1307 | ||
1247 | calculate_nonce (nonce_time, | 1308 | calculate_nonce (nonce_time, |
@@ -1264,7 +1325,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1264 | if (0 != strcmp (nonce, | 1325 | if (0 != strcmp (nonce, |
1265 | noncehashexp)) | 1326 | noncehashexp)) |
1266 | { | 1327 | { |
1267 | return MHD_INVALID_NONCE; | 1328 | return MHD_DAUTH_NONCE_WRONG; |
1268 | } | 1329 | } |
1269 | if ( (0 == lookup_sub_value (cnonce, | 1330 | if ( (0 == lookup_sub_value (cnonce, |
1270 | sizeof (cnonce), | 1331 | sizeof (cnonce), |
@@ -1291,7 +1352,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1291 | MHD_DLOG (daemon, | 1352 | MHD_DLOG (daemon, |
1292 | _ ("Authentication failed, invalid format.\n")); | 1353 | _ ("Authentication failed, invalid format.\n")); |
1293 | #endif | 1354 | #endif |
1294 | return MHD_NO; | 1355 | return MHD_DAUTH_WRONG_HEADER; |
1295 | } | 1356 | } |
1296 | if (len != MHD_strx_to_uint64_n_ (nc, | 1357 | if (len != MHD_strx_to_uint64_n_ (nc, |
1297 | len, | 1358 | len, |
@@ -1301,7 +1362,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1301 | MHD_DLOG (daemon, | 1362 | MHD_DLOG (daemon, |
1302 | _ ("Authentication failed, invalid nc format.\n")); | 1363 | _ ("Authentication failed, invalid nc format.\n")); |
1303 | #endif | 1364 | #endif |
1304 | return MHD_NO; /* invalid nonce format */ | 1365 | return MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */ |
1305 | } | 1366 | } |
1306 | if (0 == nci) | 1367 | if (0 == nci) |
1307 | { | 1368 | { |
@@ -1309,7 +1370,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1309 | MHD_DLOG (daemon, | 1370 | MHD_DLOG (daemon, |
1310 | _ ("Authentication failed, invalid 'nc' value.\n")); | 1371 | _ ("Authentication failed, invalid 'nc' value.\n")); |
1311 | #endif | 1372 | #endif |
1312 | return MHD_NO; /* invalid nc value */ | 1373 | return MHD_DAUTH_WRONG_HEADER; /* invalid nc value */ |
1313 | } | 1374 | } |
1314 | 1375 | ||
1315 | /* | 1376 | /* |
@@ -1322,9 +1383,10 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1322 | nonce_len, | 1383 | nonce_len, |
1323 | nci)) | 1384 | nci)) |
1324 | { | 1385 | { |
1325 | return MHD_NO; | 1386 | return MHD_DAUTH_NONCE_STALE; |
1326 | } | 1387 | } |
1327 | 1388 | ||
1389 | if (1) | ||
1328 | { | 1390 | { |
1329 | char *uri; | 1391 | char *uri; |
1330 | 1392 | ||
@@ -1335,7 +1397,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1335 | MHD_DLOG (daemon, | 1397 | MHD_DLOG (daemon, |
1336 | _ ("Failed to allocate memory for auth header processing.\n")); | 1398 | _ ("Failed to allocate memory for auth header processing.\n")); |
1337 | #endif /* HAVE_MESSAGES */ | 1399 | #endif /* HAVE_MESSAGES */ |
1338 | return MHD_NO; | 1400 | return MHD_DAUTH_ERROR; |
1339 | } | 1401 | } |
1340 | if (0 == lookup_sub_value (uri, | 1402 | if (0 == lookup_sub_value (uri, |
1341 | left + 1, | 1403 | left + 1, |
@@ -1343,7 +1405,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1343 | "uri")) | 1405 | "uri")) |
1344 | { | 1406 | { |
1345 | free (uri); | 1407 | free (uri); |
1346 | return MHD_NO; | 1408 | return MHD_DAUTH_WRONG_HEADER; |
1347 | } | 1409 | } |
1348 | if (NULL != digest) | 1410 | if (NULL != digest) |
1349 | { | 1411 | { |
@@ -1396,9 +1458,10 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1396 | _ ("Authentication failed, URI does not match.\n")); | 1458 | _ ("Authentication failed, URI does not match.\n")); |
1397 | #endif | 1459 | #endif |
1398 | free (uri); | 1460 | free (uri); |
1399 | return MHD_NO; | 1461 | return MHD_DAUTH_WRONG_URI; |
1400 | } | 1462 | } |
1401 | 1463 | ||
1464 | if (1) | ||
1402 | { | 1465 | { |
1403 | const char *args = qmark; | 1466 | const char *args = qmark; |
1404 | 1467 | ||
@@ -1415,15 +1478,15 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1415 | _ ("Authentication failed, arguments do not match.\n")); | 1478 | _ ("Authentication failed, arguments do not match.\n")); |
1416 | #endif | 1479 | #endif |
1417 | free (uri); | 1480 | free (uri); |
1418 | return MHD_NO; | 1481 | return MHD_DAUTH_WRONG_URI; |
1419 | } | 1482 | } |
1420 | } | 1483 | } |
1421 | free (uri); | 1484 | free (uri); |
1422 | return (0 == strcmp (response, | ||
1423 | da->sessionkey)) | ||
1424 | ? MHD_YES | ||
1425 | : MHD_NO; | ||
1426 | } | 1485 | } |
1486 | return (0 == strcmp (response, | ||
1487 | da->sessionkey)) | ||
1488 | ? MHD_DAUTH_OK | ||
1489 | : MHD_DAUTH_RESPONSE_WRONG; | ||
1427 | } | 1490 | } |
1428 | 1491 | ||
1429 | 1492 | ||
@@ -1441,7 +1504,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1441 | * @param nonce_timeout The amount of time for a nonce to be | 1504 | * @param nonce_timeout The amount of time for a nonce to be |
1442 | * invalid in seconds | 1505 | * invalid in seconds |
1443 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 1506 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
1444 | * #MHD_INVALID_NONCE if nonce is invalid | 1507 | * #MHD_INVALID_NONCE if nonce is invalid or stale |
1445 | * @ingroup authentication | 1508 | * @ingroup authentication |
1446 | */ | 1509 | */ |
1447 | _MHD_EXTERN int | 1510 | _MHD_EXTERN int |
@@ -1520,7 +1583,7 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
1520 | * invalid in seconds | 1583 | * invalid in seconds |
1521 | * @param algo digest algorithms allowed for verification | 1584 | * @param algo digest algorithms allowed for verification |
1522 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 1585 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
1523 | * #MHD_INVALID_NONCE if nonce is invalid | 1586 | * #MHD_INVALID_NONCE if nonce is invalid or stale |
1524 | * @ingroup authentication | 1587 | * @ingroup authentication |
1525 | */ | 1588 | */ |
1526 | _MHD_EXTERN int | 1589 | _MHD_EXTERN int |
@@ -1531,18 +1594,25 @@ MHD_digest_auth_check2 (struct MHD_Connection *connection, | |||
1531 | unsigned int nonce_timeout, | 1594 | unsigned int nonce_timeout, |
1532 | enum MHD_DigestAuthAlgorithm algo) | 1595 | enum MHD_DigestAuthAlgorithm algo) |
1533 | { | 1596 | { |
1597 | enum MHD_DigestAuthResult res; | ||
1534 | SETUP_DA (algo, da); | 1598 | SETUP_DA (algo, da); |
1535 | 1599 | ||
1536 | mhd_assert (NULL != password); | 1600 | mhd_assert (NULL != password); |
1537 | if (0 == da.digest_size) | 1601 | if (0 == da.digest_size) |
1538 | MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */ | 1602 | MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */ |
1539 | return digest_auth_check_all (connection, | 1603 | res = digest_auth_check_all (connection, |
1540 | &da, | 1604 | &da, |
1541 | realm, | 1605 | realm, |
1542 | username, | 1606 | username, |
1543 | password, | 1607 | password, |
1544 | NULL, | 1608 | NULL, |
1545 | nonce_timeout); | 1609 | nonce_timeout); |
1610 | if (MHD_DAUTH_OK == res) | ||
1611 | return MHD_YES; | ||
1612 | else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res)) | ||
1613 | return MHD_INVALID_NONCE; | ||
1614 | return MHD_NO; | ||
1615 | |||
1546 | } | 1616 | } |
1547 | 1617 | ||
1548 | 1618 | ||
@@ -1560,7 +1630,7 @@ MHD_digest_auth_check2 (struct MHD_Connection *connection, | |||
1560 | * invalid in seconds | 1630 | * invalid in seconds |
1561 | * @param algo digest algorithms allowed for verification | 1631 | * @param algo digest algorithms allowed for verification |
1562 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 1632 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
1563 | * #MHD_INVALID_NONCE if nonce is invalid | 1633 | * #MHD_INVALID_NONCE if nonce is invalid or stale |
1564 | * @ingroup authentication | 1634 | * @ingroup authentication |
1565 | */ | 1635 | */ |
1566 | _MHD_EXTERN int | 1636 | _MHD_EXTERN int |
@@ -1572,18 +1642,24 @@ MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, | |||
1572 | unsigned int nonce_timeout, | 1642 | unsigned int nonce_timeout, |
1573 | enum MHD_DigestAuthAlgorithm algo) | 1643 | enum MHD_DigestAuthAlgorithm algo) |
1574 | { | 1644 | { |
1645 | enum MHD_DigestAuthResult res; | ||
1575 | SETUP_DA (algo, da); | 1646 | SETUP_DA (algo, da); |
1576 | 1647 | ||
1577 | mhd_assert (NULL != digest); | 1648 | mhd_assert (NULL != digest); |
1578 | if ((da.digest_size != digest_size) || (0 == digest_size)) | 1649 | if ((da.digest_size != digest_size) || (0 == digest_size)) |
1579 | MHD_PANIC (_ ("Digest size mismatch.\n")); /* API violation! */ | 1650 | MHD_PANIC (_ ("Digest size mismatch.\n")); /* API violation! */ |
1580 | return digest_auth_check_all (connection, | 1651 | res = digest_auth_check_all (connection, |
1581 | &da, | 1652 | &da, |
1582 | realm, | 1653 | realm, |
1583 | username, | 1654 | username, |
1584 | NULL, | 1655 | NULL, |
1585 | digest, | 1656 | digest, |
1586 | nonce_timeout); | 1657 | nonce_timeout); |
1658 | if (MHD_DAUTH_OK == res) | ||
1659 | return MHD_YES; | ||
1660 | else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res)) | ||
1661 | return MHD_INVALID_NONCE; | ||
1662 | return MHD_NO; | ||
1587 | } | 1663 | } |
1588 | 1664 | ||
1589 | 1665 | ||
@@ -1601,7 +1677,7 @@ MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, | |||
1601 | * @param nonce_timeout The amount of time for a nonce to be | 1677 | * @param nonce_timeout The amount of time for a nonce to be |
1602 | * invalid in seconds | 1678 | * invalid in seconds |
1603 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 1679 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
1604 | * #MHD_INVALID_NONCE if nonce is invalid | 1680 | * #MHD_INVALID_NONCE if nonce is invalid or stale |
1605 | * @ingroup authentication | 1681 | * @ingroup authentication |
1606 | */ | 1682 | */ |
1607 | _MHD_EXTERN int | 1683 | _MHD_EXTERN int |