diff options
Diffstat (limited to 'src/daemon/digestauth.c')
-rw-r--r-- | src/daemon/digestauth.c | 165 |
1 files changed, 154 insertions, 11 deletions
diff --git a/src/daemon/digestauth.c b/src/daemon/digestauth.c index 472811e8..1e976bb6 100644 --- a/src/daemon/digestauth.c +++ b/src/daemon/digestauth.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of libmicrohttpd | 2 | This file is part of libmicrohttpd |
3 | (C) 2010 Daniel Pittman and Christian Grothoff | 3 | (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff |
4 | 4 | ||
5 | This library is free software; you can redistribute it and/or | 5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public | 6 | modify it under the terms of the GNU Lesser General Public |
@@ -387,7 +387,7 @@ MHD_digest_auth_get_username(struct MHD_Connection *connection) | |||
387 | * @param method HTTP method | 387 | * @param method HTTP method |
388 | * @param rnd A pointer to a character array for the random seed | 388 | * @param rnd A pointer to a character array for the random seed |
389 | * @param rnd_size The size of the random seed array | 389 | * @param rnd_size The size of the random seed array |
390 | * @param uri HTTP URI | 390 | * @param uri HTTP URI (in MHD, without the arguments ("?k=v") |
391 | * @param realm A string of characters that describes the realm of auth. | 391 | * @param realm A string of characters that describes the realm of auth. |
392 | * @param nonce A pointer to a character array for the nonce to put in | 392 | * @param nonce A pointer to a character array for the nonce to put in |
393 | */ | 393 | */ |
@@ -428,6 +428,114 @@ calculate_nonce (uint32_t nonce_time, | |||
428 | 428 | ||
429 | 429 | ||
430 | /** | 430 | /** |
431 | * Test if the given key-value pair is in the headers for the | ||
432 | * given connection. | ||
433 | * | ||
434 | * @param connection the connection | ||
435 | * @param key the key | ||
436 | * @param value the value, can be NULL | ||
437 | * @return MHD_YES if the key-value pair is in the headers, | ||
438 | * MHD_NO if not | ||
439 | */ | ||
440 | static int | ||
441 | test_header (struct MHD_Connection *connection, | ||
442 | const char *key, | ||
443 | const char *value) | ||
444 | { | ||
445 | struct MHD_HTTP_Header *pos; | ||
446 | |||
447 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | ||
448 | { | ||
449 | if (MHD_GET_ARGUMENT_KIND != pos->kind) | ||
450 | continue; | ||
451 | if (0 != strcmp (key, pos->header)) | ||
452 | continue; | ||
453 | if ( (NULL == value) && (NULL == pos->value)) | ||
454 | return MHD_YES; | ||
455 | if ( (NULL == value) || (NULL == pos->value)) | ||
456 | continue; | ||
457 | if (0 != strcmp (value, pos->value)) | ||
458 | continue; | ||
459 | return MHD_YES; | ||
460 | } | ||
461 | return MHD_NO; | ||
462 | } | ||
463 | |||
464 | |||
465 | /** | ||
466 | * Check that the arguments given by the client as part | ||
467 | * of the authentication header match the arguments we | ||
468 | * got as part of the HTTP request URI. | ||
469 | * | ||
470 | * @param connection connections with headers to compare against | ||
471 | * @param args argument URI string (after "?" in URI) | ||
472 | * @return MHD_YES if the arguments match, | ||
473 | * MHD_NO if not | ||
474 | */ | ||
475 | static int | ||
476 | check_argument_match (struct MHD_Connection *connection, | ||
477 | const char *args) | ||
478 | { | ||
479 | struct MHD_HTTP_Header *pos; | ||
480 | size_t slen = strlen (args) + 1; | ||
481 | char argb[slen]; | ||
482 | char *argp; | ||
483 | char *equals; | ||
484 | char *amper; | ||
485 | unsigned int num_headers; | ||
486 | |||
487 | num_headers = 0; | ||
488 | memcpy (argb, args, slen); | ||
489 | argp = argb; | ||
490 | while ( (argp != NULL) && | ||
491 | (argp[0] != '\0') ) | ||
492 | { | ||
493 | equals = strstr (argp, "="); | ||
494 | if (equals == NULL) | ||
495 | { | ||
496 | /* add with 'value' NULL */ | ||
497 | connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, | ||
498 | connection, | ||
499 | argp); | ||
500 | if (MHD_YES != test_header (connection, argp, NULL)) | ||
501 | return MHD_NO; | ||
502 | num_headers++; | ||
503 | break; | ||
504 | } | ||
505 | equals[0] = '\0'; | ||
506 | equals++; | ||
507 | amper = strstr (equals, "&"); | ||
508 | if (amper != NULL) | ||
509 | { | ||
510 | amper[0] = '\0'; | ||
511 | amper++; | ||
512 | } | ||
513 | connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, | ||
514 | connection, | ||
515 | argp); | ||
516 | connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, | ||
517 | connection, | ||
518 | equals); | ||
519 | if (! test_header (connection, argp, equals)) | ||
520 | return MHD_NO; | ||
521 | num_headers++; | ||
522 | argp = amper; | ||
523 | } | ||
524 | |||
525 | /* also check that the number of headers matches */ | ||
526 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | ||
527 | { | ||
528 | if (MHD_GET_ARGUMENT_KIND != pos->kind) | ||
529 | continue; | ||
530 | num_headers--; | ||
531 | } | ||
532 | if (0 != num_headers) | ||
533 | return MHD_NO; | ||
534 | return MHD_YES; | ||
535 | } | ||
536 | |||
537 | |||
538 | /** | ||
431 | * Authenticates the authorization header sent by the client | 539 | * Authenticates the authorization header sent by the client |
432 | * | 540 | * |
433 | * @param connection The MHD connection structure | 541 | * @param connection The MHD connection structure |
@@ -513,16 +621,40 @@ MHD_digest_auth_check(struct MHD_Connection *connection, | |||
513 | nonce_time = strtoul(nonce + len - 8, (char **)NULL, 16); | 621 | nonce_time = strtoul(nonce + len - 8, (char **)NULL, 16); |
514 | t = (uint32_t) time(NULL); | 622 | t = (uint32_t) time(NULL); |
515 | /* | 623 | /* |
516 | * First level vetting for the nonce validity | 624 | * First level vetting for the nonce validity if the timestamp |
517 | * if the timestamp attached to the nonce | 625 | * attached to the nonce exceeds `nonce_timeout' then the nonce is |
518 | * exceeds `nonce_timeout' then the nonce is | ||
519 | * invalid. | 626 | * invalid. |
520 | */ | 627 | */ |
521 | if ( (t > nonce_time + nonce_timeout) || | 628 | if ( (t > nonce_time + nonce_timeout) || |
522 | (0 != strncmp (uri, | 629 | (nonce_time + nonce_timeout < nonce_time) ) |
523 | connection->url, | 630 | return MHD_INVALID_NONCE; |
524 | strlen (connection->url))) ) | 631 | if (0 != strncmp (uri, |
525 | return MHD_INVALID_NONCE; | 632 | connection->url, |
633 | strlen (connection->url))) | ||
634 | { | ||
635 | #if HAVE_MESSAGES | ||
636 | MHD_DLOG (connection->daemon, | ||
637 | "Authentication failed, URI does not match.\n"); | ||
638 | #endif | ||
639 | return MHD_NO; | ||
640 | } | ||
641 | { | ||
642 | const char *args = strstr (uri, "?"); | ||
643 | if (args == NULL) | ||
644 | args = ""; | ||
645 | else | ||
646 | args++; | ||
647 | if (MHD_YES != | ||
648 | check_argument_match (connection, | ||
649 | args) ) | ||
650 | { | ||
651 | #if HAVE_MESSAGES | ||
652 | MHD_DLOG (connection->daemon, | ||
653 | "Authentication failed, arguments do not match.\n"); | ||
654 | #endif | ||
655 | return MHD_NO; | ||
656 | } | ||
657 | } | ||
526 | calculate_nonce (nonce_time, | 658 | calculate_nonce (nonce_time, |
527 | connection->method, | 659 | connection->method, |
528 | connection->daemon->digest_auth_random, | 660 | connection->daemon->digest_auth_random, |
@@ -550,12 +682,23 @@ MHD_digest_auth_check(struct MHD_Connection *connection, | |||
550 | (0 != strcmp (qop, "")) ) || | 682 | (0 != strcmp (qop, "")) ) || |
551 | (0 == lookup_sub_value(nc, sizeof (nc), header, "nc")) || | 683 | (0 == lookup_sub_value(nc, sizeof (nc), header, "nc")) || |
552 | (0 == lookup_sub_value(response, sizeof (response), header, "response")) ) | 684 | (0 == lookup_sub_value(response, sizeof (response), header, "response")) ) |
685 | { | ||
686 | #if HAVE_MESSAGES | ||
687 | MHD_DLOG (connection->daemon, | ||
688 | "Authentication failed, invalid format.\n"); | ||
689 | #endif | ||
553 | return MHD_NO; | 690 | return MHD_NO; |
691 | } | ||
554 | nci = strtoul (nc, &end, 16); | 692 | nci = strtoul (nc, &end, 16); |
555 | if ( ('\0' != *end) || | 693 | if ( ('\0' != *end) || |
556 | ( (LONG_MAX == nci) && (errno == ERANGE) ) ) | 694 | ( (LONG_MAX == nci) && (errno == ERANGE) ) ) |
557 | return MHD_NO; /* invalid nonce */ | 695 | { |
558 | 696 | #if HAVE_MESSAGES | |
697 | MHD_DLOG (connection->daemon, | ||
698 | "Authentication failed, invalid format.\n"); | ||
699 | #endif | ||
700 | return MHD_NO; /* invalid nonce format */ | ||
701 | } | ||
559 | /* | 702 | /* |
560 | * Checking if that combination of nonce and nc is sound | 703 | * Checking if that combination of nonce and nc is sound |
561 | * and not a replay attack attempt. Also adds the nonce | 704 | * and not a replay attack attempt. Also adds the nonce |