aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-01-19 16:40:57 +0000
committerChristian Grothoff <christian@grothoff.org>2012-01-19 16:40:57 +0000
commitb54d68ff219a354920cf650bbb5418c5c2af5b66 (patch)
treee47a810a7bb1c81a2edbcbc14b1b6311d1d28c7f
parent24fe454f1044082ea0f9f457fd7570387d79e50a (diff)
downloadlibmicrohttpd-b54d68ff219a354920cf650bbb5418c5c2af5b66.tar.gz
libmicrohttpd-b54d68ff219a354920cf650bbb5418c5c2af5b66.zip
properly fixing #2059, keeping the check that the uri from the nonce generation is exactly the same as the primary uri we got from the HTTP request
-rw-r--r--ChangeLog4
-rw-r--r--src/daemon/connection.c11
-rw-r--r--src/daemon/digestauth.c165
-rw-r--r--src/include/microhttpd.h2
-rw-r--r--src/testcurl/Makefile.am8
5 files changed, 175 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index 9bc39925..e3004446 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
1Thu Jan 19 13:31:27 CET 2012
2 Fixing digest authentication for GET requests with URI arguments
3 (#2059). -CG
4
1Sat Jan 7 17:30:48 CET 2012 5Sat Jan 7 17:30:48 CET 2012
2 Digest authentication expects nonce count in base 16, not base 10 6 Digest authentication expects nonce count in base 16, not base 10
3 (#2061). -tclaveirole 7 (#2061). -tclaveirole
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
index 70e1ad91..7d973283 100644
--- a/src/daemon/connection.c
+++ b/src/daemon/connection.c
@@ -1066,6 +1066,12 @@ connection_add_header (struct MHD_Connection *connection,
1066} 1066}
1067 1067
1068/** 1068/**
1069 * Parse and unescape the arguments given by the client as part
1070 * of the HTTP request URI.
1071 *
1072 * @param kind header kind to use for adding to the connection
1073 * @param connection connection to add headers to
1074 * @param args argument URI string (after "?" in URI)
1069 * @return MHD_NO on failure (out of memory), MHD_YES for success 1075 * @return MHD_NO on failure (out of memory), MHD_YES for success
1070 */ 1076 */
1071static int 1077static int
@@ -1111,6 +1117,7 @@ parse_arguments (enum MHD_ValueKind kind,
1111 return MHD_YES; 1117 return MHD_YES;
1112} 1118}
1113 1119
1120
1114/** 1121/**
1115 * Parse the cookie header (see RFC 2109). 1122 * Parse the cookie header (see RFC 2109).
1116 * 1123 *
@@ -1238,7 +1245,7 @@ parse_initial_message_line (struct MHD_Connection *connection, char *line)
1238 connection->daemon->uri_log_callback (connection->daemon-> 1245 connection->daemon->uri_log_callback (connection->daemon->
1239 uri_log_callback_cls, uri); 1246 uri_log_callback_cls, uri);
1240 args = strstr (uri, "?"); 1247 args = strstr (uri, "?");
1241 if (args != NULL) 1248 if (NULL != args)
1242 { 1249 {
1243 args[0] = '\0'; 1250 args[0] = '\0';
1244 args++; 1251 args++;
@@ -1248,7 +1255,7 @@ parse_initial_message_line (struct MHD_Connection *connection, char *line)
1248 connection, 1255 connection,
1249 uri); 1256 uri);
1250 connection->url = uri; 1257 connection->url = uri;
1251 if (httpVersion == NULL) 1258 if (NULL == httpVersion)
1252 connection->version = ""; 1259 connection->version = "";
1253 else 1260 else
1254 connection->version = httpVersion; 1261 connection->version = httpVersion;
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
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 4904dcb8..fd15b698 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -106,7 +106,7 @@ extern "C"
106/** 106/**
107 * Current version of the library. 107 * Current version of the library.
108 */ 108 */
109#define MHD_VERSION 0x00091101 109#define MHD_VERSION 0x00091102
110 110
111/** 111/**
112 * MHD-internal return code for "YES". 112 * MHD-internal return code for "YES".
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index 74732f07..8f1563f3 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -63,7 +63,7 @@ noinst_PROGRAMS = \
63 63
64if ENABLE_DAUTH 64if ENABLE_DAUTH
65 check_PROGRAMS += \ 65 check_PROGRAMS += \
66 daemontest_digestauth 66 daemontest_digestauth daemontest_digestauth_with_arguments
67endif 67endif
68 68
69TESTS = $(check_PROGRAMS) 69TESTS = $(check_PROGRAMS)
@@ -115,6 +115,12 @@ daemontest_digestauth_LDADD = \
115 $(top_builddir)/src/daemon/libmicrohttpd.la \ 115 $(top_builddir)/src/daemon/libmicrohttpd.la \
116 @LIBCURL@ 116 @LIBCURL@
117 117
118daemontest_digestauth_with_arguments_SOURCES = \
119 daemontest_digestauth_with_arguments.c
120daemontest_digestauth_with_arguments_LDADD = \
121 $(top_builddir)/src/daemon/libmicrohttpd.la \
122 @LIBCURL@
123
118daemontest_get_sendfile_SOURCES = \ 124daemontest_get_sendfile_SOURCES = \
119 daemontest_get_sendfile.c 125 daemontest_get_sendfile.c
120daemontest_get_sendfile_LDADD = \ 126daemontest_get_sendfile_LDADD = \