aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/digestauth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/digestauth.c')
-rw-r--r--src/daemon/digestauth.c165
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 */
440static int
441test_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 */
475static int
476check_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