test_digestauth2.c (54758B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2010 Christian Grothoff 4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k) 5 6 libmicrohttpd is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published 8 by the Free Software Foundation; either version 2, or (at your 9 option) any later version. 10 11 libmicrohttpd is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with libmicrohttpd; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 */ 21 22 /** 23 * @file test_digest2.c 24 * @brief Testcase for MHD Digest Authorisation 25 * @author Karlson2k (Evgeny Grin) 26 */ 27 28 #include "mhd_options.h" 29 #include "platform.h" 30 #include <curl/curl.h> 31 #include <microhttpd.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <time.h> 35 #include <errno.h> 36 37 #if defined(MHD_HTTPS_REQUIRE_GCRYPT) && \ 38 (defined(MHD_SHA256_TLSLIB) || defined(MHD_MD5_TLSLIB)) 39 #define NEED_GCRYP_INIT 1 40 #include <gcrypt.h> 41 #endif /* MHD_HTTPS_REQUIRE_GCRYPT && (MHD_SHA256_TLSLIB || MHD_MD5_TLSLIB) */ 42 43 #ifndef _WIN32 44 #include <sys/socket.h> 45 #include <unistd.h> 46 #else 47 #include <wincrypt.h> 48 #endif 49 50 #include "mhd_has_param.h" 51 #include "mhd_has_in_name.h" 52 53 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 54 test into a marked, classifiable test error (TESTING.md, P5). */ 55 #include "mhd_panic_tripwire.h" 56 57 #ifndef MHD_STATICSTR_LEN_ 58 /** 59 * Determine length of static string / macro strings at compile time. 60 */ 61 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) 62 #endif /* ! MHD_STATICSTR_LEN_ */ 63 64 #ifndef CURL_VERSION_BITS 65 #define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z)) 66 #endif /* ! CURL_VERSION_BITS */ 67 #ifndef CURL_AT_LEAST_VERSION 68 #define CURL_AT_LEAST_VERSION(x,y,z) \ 69 (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z)) 70 #endif /* ! CURL_AT_LEAST_VERSION */ 71 72 #ifndef _MHD_INSTRMACRO 73 /* Quoted macro parameter */ 74 #define _MHD_INSTRMACRO(a) #a 75 #endif /* ! _MHD_INSTRMACRO */ 76 #ifndef _MHD_STRMACRO 77 /* Quoted expanded macro parameter */ 78 #define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a) 79 #endif /* ! _MHD_STRMACRO */ 80 81 #if defined(HAVE___FUNC__) 82 #define externalErrorExit(ignore) \ 83 _externalErrorExit_func (NULL, __func__, __LINE__) 84 #define externalErrorExitDesc(errDesc) \ 85 _externalErrorExit_func (errDesc, __func__, __LINE__) 86 #define libcurlErrorExit(ignore) \ 87 _libcurlErrorExit_func (NULL, __func__, __LINE__) 88 #define libcurlErrorExitDesc(errDesc) \ 89 _libcurlErrorExit_func (errDesc, __func__, __LINE__) 90 #define mhdErrorExit(ignore) \ 91 _mhdErrorExit_func (NULL, __func__, __LINE__) 92 #define mhdErrorExitDesc(errDesc) \ 93 _mhdErrorExit_func (errDesc, __func__, __LINE__) 94 #define checkCURLE_OK(libcurlcall) \ 95 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \ 96 __func__, __LINE__) 97 #elif defined(HAVE___FUNCTION__) 98 #define externalErrorExit(ignore) \ 99 _externalErrorExit_func (NULL, __FUNCTION__, __LINE__) 100 #define externalErrorExitDesc(errDesc) \ 101 _externalErrorExit_func (errDesc, __FUNCTION__, __LINE__) 102 #define libcurlErrorExit(ignore) \ 103 _libcurlErrorExit_func (NULL, __FUNCTION__, __LINE__) 104 #define libcurlErrorExitDesc(errDesc) \ 105 _libcurlErrorExit_func (errDesc, __FUNCTION__, __LINE__) 106 #define mhdErrorExit(ignore) \ 107 _mhdErrorExit_func (NULL, __FUNCTION__, __LINE__) 108 #define mhdErrorExitDesc(errDesc) \ 109 _mhdErrorExit_func (errDesc, __FUNCTION__, __LINE__) 110 #define checkCURLE_OK(libcurlcall) \ 111 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \ 112 __FUNCTION__, __LINE__) 113 #else 114 #define externalErrorExit(ignore) _externalErrorExit_func (NULL, NULL, __LINE__) 115 #define externalErrorExitDesc(errDesc) \ 116 _externalErrorExit_func (errDesc, NULL, __LINE__) 117 #define libcurlErrorExit(ignore) _libcurlErrorExit_func (NULL, NULL, __LINE__) 118 #define libcurlErrorExitDesc(errDesc) \ 119 _libcurlErrorExit_func (errDesc, NULL, __LINE__) 120 #define mhdErrorExit(ignore) _mhdErrorExit_func (NULL, NULL, __LINE__) 121 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func (errDesc, NULL, __LINE__) 122 #define checkCURLE_OK(libcurlcall) \ 123 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), NULL, \ 124 __LINE__) 125 #endif 126 127 128 _MHD_NORETURN static void 129 _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 130 { 131 fflush (stdout); 132 if ((NULL != errDesc) && (0 != errDesc[0])) 133 fprintf (stderr, "%s", errDesc); 134 else 135 fprintf (stderr, "System or external library call failed"); 136 if ((NULL != funcName) && (0 != funcName[0])) 137 fprintf (stderr, " in %s", funcName); 138 if (0 < lineNum) 139 fprintf (stderr, " at line %d", lineNum); 140 141 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 142 strerror (errno)); 143 #ifdef MHD_WINSOCK_SOCKETS 144 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 145 #endif /* MHD_WINSOCK_SOCKETS */ 146 fflush (stderr); 147 exit (99); 148 } 149 150 151 /* Not actually used in this test */ 152 static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; 153 154 _MHD_NORETURN static void 155 _libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 156 { 157 fflush (stdout); 158 if ((NULL != errDesc) && (0 != errDesc[0])) 159 fprintf (stderr, "%s", errDesc); 160 else 161 fprintf (stderr, "CURL library call failed"); 162 if ((NULL != funcName) && (0 != funcName[0])) 163 fprintf (stderr, " in %s", funcName); 164 if (0 < lineNum) 165 fprintf (stderr, " at line %d", lineNum); 166 167 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 168 strerror (errno)); 169 #ifdef MHD_WINSOCK_SOCKETS 170 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 171 #endif /* MHD_WINSOCK_SOCKETS */ 172 if (0 != libcurl_errbuf[0]) 173 fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf); 174 175 fflush (stderr); 176 exit (99); 177 } 178 179 180 _MHD_NORETURN static void 181 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 182 { 183 fflush (stdout); 184 if ((NULL != errDesc) && (0 != errDesc[0])) 185 fprintf (stderr, "%s", errDesc); 186 else 187 fprintf (stderr, "MHD unexpected error"); 188 if ((NULL != funcName) && (0 != funcName[0])) 189 fprintf (stderr, " in %s", funcName); 190 if (0 < lineNum) 191 fprintf (stderr, " at line %d", lineNum); 192 193 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 194 strerror (errno)); 195 #ifdef MHD_WINSOCK_SOCKETS 196 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 197 #endif /* MHD_WINSOCK_SOCKETS */ 198 199 fflush (stderr); 200 exit (8); 201 } 202 203 204 #if 0 205 /* Function unused in this test */ 206 static void 207 _checkCURLE_OK_func (CURLcode code, const char *curlFunc, 208 const char *funcName, int lineNum) 209 { 210 if (CURLE_OK == code) 211 return; 212 213 fflush (stdout); 214 if ((NULL != curlFunc) && (0 != curlFunc[0])) 215 fprintf (stderr, "'%s' resulted in '%s'", curlFunc, 216 curl_easy_strerror (code)); 217 else 218 fprintf (stderr, "libcurl function call resulted in '%s'", 219 curl_easy_strerror (code)); 220 if ((NULL != funcName) && (0 != funcName[0])) 221 fprintf (stderr, " in %s", funcName); 222 if (0 < lineNum) 223 fprintf (stderr, " at line %d", lineNum); 224 225 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 226 strerror (errno)); 227 if (0 != libcurl_errbuf[0]) 228 fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf); 229 230 fflush (stderr); 231 exit (9); 232 } 233 234 235 #endif 236 237 238 /* Could be increased to facilitate debugging */ 239 #define TIMEOUTS_VAL 10 240 241 #define MHD_URI_BASE_PATH "/bar%20foo?key=value" 242 #define MHD_URI_BASE_PATH2 "/another_path" 243 /* Should not fit buffer in the stack */ 244 #define MHD_URI_BASE_PATH3 \ 245 "/long/long/long/long/long/long/long/long/long/long/long/long/long/long" \ 246 "/long/long/long/long/long/long/long/long/long/long/long/long/long/long" \ 247 "/long/long/long/long/long/long/long/long/long/long/long/long/long/long" \ 248 "/long/long/long/long/long/long/long/long/long/long/long/long/long/long" \ 249 "/long/long/long/long/long/long/long/long/long/long/long/long/long/long" \ 250 "/path?with%20some=parameters" 251 252 #define REALM_VAL "TestRealm" 253 #define USERNAME1 "test_user" 254 /* The hex form of MD5("test_user:TestRealm") */ 255 #define USERHASH1_MD5_HEX "c53c601503ff176f18f623725fba4281" 256 #define USERHASH1_MD5_BIN 0xc5, 0x3c, 0x60, 0x15, 0x03, 0xff, 0x17, 0x6f, \ 257 0x18, 0xf6, 0x23, 0x72, 0x5f, 0xba, 0x42, 0x81 258 /* The hex form of SHA-256("test_user:TestRealm") */ 259 #define USERHASH1_SHA256_HEX \ 260 "090c7e06b77d6614cf5fe6cafa004d2e5f8fb36ba45a0e35eacb2eb7728f34de" 261 /* The binary form of SHA-256("test_user:TestRealm") */ 262 #define USERHASH1_SHA256_BIN 0x09, 0x0c, 0x7e, 0x06, 0xb7, 0x7d, 0x66, 0x14, \ 263 0xcf, 0x5f, 0xe6, 0xca, 0xfa, 0x00, 0x4d, 0x2e, 0x5f, 0x8f, 0xb3, 0x6b, \ 264 0xa4, 0x5a, 0x0e, 0x35, 0xea, 0xcb, 0x2e, 0xb7, 0x72, 0x8f, 0x34, 0xde 265 /* The hex form of MD5("test_user:TestRealm:test pass") */ 266 #define USERDIGEST1_MD5_BIN 0xd8, 0xb4, 0xa6, 0xd0, 0x01, 0x13, 0x07, 0xb7, \ 267 0x67, 0x94, 0xea, 0x66, 0x86, 0x03, 0x6b, 0x43 268 /* The binary form of SHA-256("test_user:TestRealm:test pass") */ 269 #define USERDIGEST1_SHA256_BIN 0xc3, 0x4e, 0x16, 0x5a, 0x17, 0x0f, 0xe5, \ 270 0xac, 0x04, 0xf1, 0x6e, 0x46, 0x48, 0x2b, 0xa0, 0xc6, 0x56, 0xc1, 0xfb, \ 271 0x8f, 0x66, 0xa6, 0xd6, 0x3f, 0x91, 0x12, 0xf8, 0x56, 0xa5, 0xec, 0x6d, \ 272 0x6d 273 #define PASSWORD_VALUE "test pass" 274 #define OPAQUE_VALUE "opaque+content" /* Base64 character set */ 275 276 277 #define PAGE \ 278 "<html><head><title>libmicrohttpd demo page</title>" \ 279 "</head><body>Access granted</body></html>" 280 281 #define DENIED \ 282 "<html><head><title>libmicrohttpd - Access denied</title>" \ 283 "</head><body>Access denied</body></html>" 284 285 /* Global parameters */ 286 static int verbose; 287 static int test_oldapi; 288 static int test_userhash; 289 static int test_userdigest; 290 static int test_sha256; 291 static int test_rfc2069; 292 /* Bind DAuth nonces to everything except URI */ 293 static int test_bind_all; 294 /* Bind DAuth nonces to URI */ 295 static int test_bind_uri; 296 static int curl_uses_usehash; 297 298 /* Static helper variables */ 299 static const char userhash1_md5_hex[] = USERHASH1_MD5_HEX; 300 static const uint8_t userhash1_md5_bin[] = { USERHASH1_MD5_BIN }; 301 static const char userhash1_sha256_hex[] = USERHASH1_SHA256_HEX; 302 static const uint8_t userhash1_sha256_bin[] = { USERHASH1_SHA256_BIN }; 303 static const char *userhash_hex; 304 static size_t userhash_hex_len; 305 static const uint8_t *userhash_bin; 306 static const uint8_t userdigest1_md5_bin[] = { USERDIGEST1_MD5_BIN }; 307 static const uint8_t userdigest1_sha256_bin[] = { USERDIGEST1_SHA256_BIN }; 308 static const uint8_t *userdigest_bin; 309 static size_t userdigest_bin_size; 310 static const char *username_ptr; 311 312 static void 313 test_global_init (void) 314 { 315 libcurl_errbuf[0] = 0; 316 317 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 318 externalErrorExit (); 319 320 username_ptr = USERNAME1; 321 if (! test_sha256) 322 { 323 userhash_hex = userhash1_md5_hex; 324 userhash_hex_len = MHD_STATICSTR_LEN_ (userhash1_md5_hex); 325 userhash_bin = userhash1_md5_bin; 326 if ((userhash_hex_len / 2) != \ 327 (sizeof(userhash1_md5_bin) / sizeof(userhash1_md5_bin[0]))) 328 externalErrorExitDesc ("Wrong size of the 'userhash1_md5_bin' array"); 329 userdigest_bin = userdigest1_md5_bin; 330 userdigest_bin_size = 331 (sizeof(userdigest1_md5_bin) / sizeof(userdigest1_md5_bin[0])); 332 } 333 else 334 { 335 userhash_hex = userhash1_sha256_hex; 336 userhash_hex_len = MHD_STATICSTR_LEN_ (userhash1_sha256_hex); 337 userhash_bin = userhash1_sha256_bin; 338 if ((userhash_hex_len / 2) != \ 339 (sizeof(userhash1_sha256_bin) \ 340 / sizeof(userhash1_sha256_bin[0]))) 341 externalErrorExitDesc ("Wrong size of the 'userhash1_sha256_bin' array"); 342 userdigest_bin = userdigest1_sha256_bin; 343 userdigest_bin_size = 344 (sizeof(userdigest1_sha256_bin) / sizeof(userdigest1_sha256_bin[0])); 345 } 346 } 347 348 349 static void 350 test_global_cleanup (void) 351 { 352 curl_global_cleanup (); 353 } 354 355 356 static int 357 gen_good_rnd (void *rnd_buf, size_t rnd_buf_size) 358 { 359 if (1024 < rnd_buf_size) 360 externalErrorExitDesc ("Too large amount of random data " \ 361 "is requested"); 362 #ifndef _WIN32 363 if (1) 364 { 365 const int urand_fd = open ("/dev/urandom", O_RDONLY); 366 if (0 <= urand_fd) 367 { 368 size_t pos = 0; 369 do 370 { 371 ssize_t res = read (urand_fd, 372 ((uint8_t *) rnd_buf) + pos, rnd_buf_size - pos); 373 if (0 > res) 374 break; 375 pos += (size_t) res; 376 } while (rnd_buf_size > pos); 377 (void) close (urand_fd); 378 379 if (rnd_buf_size == pos) 380 return ! 0; /* Success */ 381 } 382 } 383 #else /* _WIN32 */ 384 if (1) 385 { 386 HCRYPTPROV cpr_hndl; 387 if (CryptAcquireContextW (&cpr_hndl, NULL, NULL, PROV_RSA_FULL, 388 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) 389 { 390 if (CryptGenRandom (cpr_hndl, (DWORD) rnd_buf_size, (BYTE *) rnd_buf)) 391 { 392 (void) CryptReleaseContext (cpr_hndl, 0); 393 return ! 0; /* Success */ 394 } 395 (void) CryptReleaseContext (cpr_hndl, 0); 396 } 397 } 398 #endif /* _WIN32 */ 399 return 0; /* Failure */ 400 } 401 402 403 struct CBC 404 { 405 char *buf; 406 size_t pos; 407 size_t size; 408 }; 409 410 struct req_track 411 { 412 /** 413 * The number of used URI, zero-based 414 */ 415 unsigned int uri_num; 416 417 /** 418 * The number of request for URI. 419 * This includes number of unauthorised requests. 420 */ 421 unsigned int req_num; 422 }; 423 424 425 static size_t 426 copyBuffer (void *ptr, 427 size_t size, 428 size_t nmemb, 429 void *ctx) 430 { 431 struct CBC *cbc = ctx; 432 433 if (cbc->pos + size * nmemb > cbc->size) 434 mhdErrorExitDesc ("Wrong too large data"); /* overflow */ 435 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 436 cbc->pos += size * nmemb; 437 return size * nmemb; 438 } 439 440 441 static enum MHD_Result 442 ahc_echo (void *cls, 443 struct MHD_Connection *connection, 444 const char *url, 445 const char *method, 446 const char *version, 447 const char *upload_data, 448 size_t *upload_data_size, 449 void **req_cls) 450 { 451 struct MHD_Response *response; 452 enum MHD_Result res; 453 static int already_called_marker; 454 struct req_track *const tr_p = (struct req_track *) cls; 455 (void) url; /* Unused. Silent compiler warning. */ 456 (void) method; (void) version; (void) upload_data; /* Unused. Silent compiler warning. */ 457 (void) upload_data_size; /* Unused. Silent compiler warning. */ 458 459 if (&already_called_marker != *req_cls) 460 { /* Called for the first time, request not fully read yet */ 461 *req_cls = &already_called_marker; 462 /* Wait for complete request */ 463 return MHD_YES; 464 } 465 466 if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) 467 mhdErrorExitDesc ("Unexpected HTTP method"); 468 469 tr_p->req_num++; 470 if (2 < tr_p->req_num) 471 mhdErrorExitDesc ("Received more than two requests for the same URI"); 472 473 response = NULL; 474 if (! test_oldapi) 475 { 476 struct MHD_DigestAuthInfo *dinfo; 477 const enum MHD_DigestAuthAlgo3 algo3 = 478 test_sha256 ? MHD_DIGEST_AUTH_ALGO3_SHA256 : MHD_DIGEST_AUTH_ALGO3_MD5; 479 const enum MHD_DigestAuthQOP qop = 480 test_rfc2069 ? MHD_DIGEST_AUTH_QOP_NONE : MHD_DIGEST_AUTH_QOP_AUTH; 481 482 dinfo = MHD_digest_auth_get_request_info3 (connection); 483 if (NULL != dinfo) 484 { 485 /* Got any kind of Digest response. Check it, it must be valid */ 486 struct MHD_DigestAuthUsernameInfo *uname; 487 enum MHD_DigestAuthResult check_res; 488 enum MHD_DigestAuthResult expect_res; 489 490 if (curl_uses_usehash) 491 { 492 if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH != dinfo->uname_type) 493 { 494 fprintf (stderr, "Unexpected 'uname_type'.\n" 495 "Expected: %d\tRecieved: %d. ", 496 (int) MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH, 497 (int) dinfo->uname_type); 498 mhdErrorExitDesc ("Wrong 'uname_type'"); 499 } 500 else if (dinfo->userhash_hex_len != userhash_hex_len) 501 { 502 fprintf (stderr, "'userhash_hex_len' does not match.\n" 503 "Expected: %u\tRecieved: %u. ", 504 (unsigned) userhash_hex_len, 505 (unsigned) dinfo->userhash_hex_len); 506 mhdErrorExitDesc ("Wrong 'userhash_hex_len'"); 507 } 508 else if (0 != memcmp (dinfo->userhash_hex, userhash_hex, 509 dinfo->userhash_hex_len)) 510 { 511 fprintf (stderr, "'userhash_hex' does not match.\n" 512 "Expected: '%s'\tRecieved: '%.*s'. ", 513 userhash_hex, 514 (int) dinfo->userhash_hex_len, 515 dinfo->userhash_hex); 516 mhdErrorExitDesc ("Wrong 'userhash_hex'"); 517 } 518 else if (NULL == dinfo->userhash_bin) 519 mhdErrorExitDesc ("'userhash_bin' is NULL"); 520 else if (0 != memcmp (dinfo->userhash_bin, userhash_bin, 521 dinfo->username_len / 2)) 522 mhdErrorExitDesc ("Wrong 'userhash_bin'"); 523 else if (NULL != dinfo->username) 524 mhdErrorExitDesc ("'username' is NOT NULL"); 525 else if (0 != dinfo->username_len) 526 mhdErrorExitDesc ("'username_len' is NOT zero"); 527 } 528 else 529 { 530 if (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != dinfo->uname_type) 531 { 532 fprintf (stderr, "Unexpected 'uname_type'.\n" 533 "Expected: %d\tRecieved: %d. ", 534 (int) MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD, 535 (int) dinfo->uname_type); 536 mhdErrorExitDesc ("Wrong 'uname_type'"); 537 } 538 else if (NULL == dinfo->username) 539 mhdErrorExitDesc ("'username' is NULL"); 540 else if (dinfo->username_len != strlen (username_ptr)) 541 { 542 fprintf (stderr, "'username_len' does not match.\n" 543 "Expected: %u\tRecieved: %u. ", 544 (unsigned) strlen (username_ptr), 545 (unsigned) dinfo->username_len); 546 mhdErrorExitDesc ("Wrong 'username_len'"); 547 } 548 else if (0 != memcmp (dinfo->username, username_ptr, 549 dinfo->username_len)) 550 { 551 fprintf (stderr, "'username' does not match.\n" 552 "Expected: '%s'\tRecieved: '%.*s'. ", 553 username_ptr, 554 (int) dinfo->username_len, 555 dinfo->username); 556 mhdErrorExitDesc ("Wrong 'username'"); 557 } 558 else if (NULL != dinfo->userhash_hex) 559 mhdErrorExitDesc ("'userhash_hex' is NOT NULL"); 560 else if (0 != dinfo->userhash_hex_len) 561 mhdErrorExitDesc ("'userhash_hex_len' is NOT zero"); 562 else if (NULL != dinfo->userhash_bin) 563 mhdErrorExitDesc ("'userhash_bin' is NOT NULL"); 564 } 565 if (algo3 != dinfo->algo3) 566 { 567 fprintf (stderr, "Unexpected 'algo3'.\n" 568 "Expected: %d\tRecieved: %d. ", 569 (int) algo3, 570 (int) dinfo->algo3); 571 mhdErrorExitDesc ("Wrong 'algo3'"); 572 } 573 if (! test_rfc2069) 574 { 575 if ( 576 #if CURL_AT_LEAST_VERSION (7,37,1) 577 10 >= dinfo->cnonce_len 578 #else /* libcurl before 7.37.1 */ 579 8 > dinfo->cnonce_len 580 #endif /* libcurl before 7.37.1 */ 581 ) 582 { 583 fprintf (stderr, "Unexpected small 'cnonce_len': %ld. ", 584 (long) dinfo->cnonce_len); 585 mhdErrorExitDesc ("Wrong 'cnonce_len'"); 586 } 587 } 588 else 589 { 590 if (0 != dinfo->cnonce_len) 591 { 592 fprintf (stderr, "'cnonce_len' is not zero: %ld. ", 593 (long) dinfo->cnonce_len); 594 mhdErrorExitDesc ("Wrong 'cnonce_len'"); 595 } 596 } 597 if (NULL == dinfo->opaque) 598 mhdErrorExitDesc ("'opaque' is NULL"); 599 else if (dinfo->opaque_len != MHD_STATICSTR_LEN_ (OPAQUE_VALUE)) 600 { 601 fprintf (stderr, "'opaque_len' does not match.\n" 602 "Expected: %u\tRecieved: %u. ", 603 (unsigned) MHD_STATICSTR_LEN_ (OPAQUE_VALUE), 604 (unsigned) dinfo->opaque_len); 605 mhdErrorExitDesc ("Wrong 'opaque_len'"); 606 } 607 else if (0 != memcmp (dinfo->opaque, OPAQUE_VALUE, dinfo->opaque_len)) 608 { 609 fprintf (stderr, "'opaque' does not match.\n" 610 "Expected: '%s'\tRecieved: '%.*s'. ", 611 OPAQUE_VALUE, 612 (int) dinfo->opaque_len, 613 dinfo->opaque); 614 mhdErrorExitDesc ("Wrong 'opaque'"); 615 } 616 else if (qop != dinfo->qop) 617 { 618 fprintf (stderr, "Unexpected 'qop'.\n" 619 "Expected: %d\tRecieved: %d. ", 620 (int) qop, 621 (int) dinfo->qop); 622 mhdErrorExitDesc ("Wrong 'qop'"); 623 } 624 else if (NULL == dinfo->realm) 625 mhdErrorExitDesc ("'realm' is NULL"); 626 else if (dinfo->realm_len != MHD_STATICSTR_LEN_ (REALM_VAL)) 627 { 628 fprintf (stderr, "'realm_len' does not match.\n" 629 "Expected: %u\tRecieved: %u. ", 630 (unsigned) MHD_STATICSTR_LEN_ (REALM_VAL), 631 (unsigned) dinfo->realm_len); 632 mhdErrorExitDesc ("Wrong 'realm_len'"); 633 } 634 else if (0 != memcmp (dinfo->realm, REALM_VAL, dinfo->realm_len)) 635 { 636 fprintf (stderr, "'realm' does not match.\n" 637 "Expected: '%s'\tRecieved: '%.*s'. ", 638 OPAQUE_VALUE, 639 (int) dinfo->realm_len, 640 dinfo->realm); 641 mhdErrorExitDesc ("Wrong 'realm'"); 642 } 643 MHD_free (dinfo); 644 645 uname = MHD_digest_auth_get_username3 (connection); 646 if (NULL == uname) 647 mhdErrorExitDesc ("MHD_digest_auth_get_username3() returned NULL"); 648 if (curl_uses_usehash) 649 { 650 if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH != uname->uname_type) 651 { 652 fprintf (stderr, "Unexpected 'uname_type'.\n" 653 "Expected: %d\tRecieved: %d. ", 654 (int) MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH, 655 (int) uname->uname_type); 656 mhdErrorExitDesc ("Wrong 'uname_type'"); 657 } 658 else if (uname->userhash_hex_len != userhash_hex_len) 659 { 660 fprintf (stderr, "'userhash_hex_len' does not match.\n" 661 "Expected: %u\tRecieved: %u. ", 662 (unsigned) userhash_hex_len, 663 (unsigned) uname->userhash_hex_len); 664 mhdErrorExitDesc ("Wrong 'userhash_hex_len'"); 665 } 666 else if (0 != memcmp (uname->userhash_hex, userhash_hex, 667 uname->userhash_hex_len)) 668 { 669 fprintf (stderr, "'username' does not match.\n" 670 "Expected: '%s'\tRecieved: '%.*s'. ", 671 userhash_hex, 672 (int) uname->userhash_hex_len, 673 uname->userhash_hex); 674 mhdErrorExitDesc ("Wrong 'userhash_hex'"); 675 } 676 else if (NULL == uname->userhash_bin) 677 mhdErrorExitDesc ("'userhash_bin' is NULL"); 678 else if (0 != memcmp (uname->userhash_bin, userhash_bin, 679 uname->username_len / 2)) 680 mhdErrorExitDesc ("Wrong 'userhash_bin'"); 681 else if (NULL != uname->username) 682 mhdErrorExitDesc ("'username' is NOT NULL"); 683 else if (0 != uname->username_len) 684 mhdErrorExitDesc ("'username_len' is NOT zero"); 685 } 686 else 687 { 688 if (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != uname->uname_type) 689 { 690 fprintf (stderr, "Unexpected 'uname_type'.\n" 691 "Expected: %d\tRecieved: %d. ", 692 (int) MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD, 693 (int) uname->uname_type); 694 mhdErrorExitDesc ("Wrong 'uname_type'"); 695 } 696 else if (NULL == uname->username) 697 mhdErrorExitDesc ("'username' is NULL"); 698 else if (uname->username_len != strlen (username_ptr)) 699 { 700 fprintf (stderr, "'username_len' does not match.\n" 701 "Expected: %u\tRecieved: %u. ", 702 (unsigned) strlen (username_ptr), 703 (unsigned) uname->username_len); 704 mhdErrorExitDesc ("Wrong 'username_len'"); 705 } 706 else if (0 != memcmp (uname->username, username_ptr, 707 uname->username_len)) 708 { 709 fprintf (stderr, "'username' does not match.\n" 710 "Expected: '%s'\tRecieved: '%.*s'. ", 711 username_ptr, 712 (int) uname->username_len, 713 uname->username); 714 mhdErrorExitDesc ("Wrong 'username'"); 715 } 716 else if (NULL != uname->userhash_hex) 717 mhdErrorExitDesc ("'userhash_hex' is NOT NULL"); 718 else if (0 != uname->userhash_hex_len) 719 mhdErrorExitDesc ("'userhash_hex_len' is NOT zero"); 720 else if (NULL != uname->userhash_bin) 721 mhdErrorExitDesc ("'userhash_bin' is NOT NULL"); 722 } 723 if (algo3 != uname->algo3) 724 { 725 fprintf (stderr, "Unexpected 'algo3'.\n" 726 "Expected: %d\tRecieved: %d. ", 727 (int) algo3, 728 (int) uname->algo3); 729 mhdErrorExitDesc ("Wrong 'algo3'"); 730 } 731 MHD_free (uname); 732 733 if (! test_userdigest) 734 check_res = 735 MHD_digest_auth_check3 (connection, REALM_VAL, username_ptr, 736 PASSWORD_VALUE, 737 50 * TIMEOUTS_VAL, 738 0, 739 (enum MHD_DigestAuthMultiQOP) qop, 740 (enum MHD_DigestAuthMultiAlgo3) algo3); 741 else 742 check_res = 743 MHD_digest_auth_check_digest3 (connection, REALM_VAL, username_ptr, 744 userdigest_bin, userdigest_bin_size, 745 50 * TIMEOUTS_VAL, 746 0, 747 (enum MHD_DigestAuthMultiQOP) qop, 748 (enum MHD_DigestAuthMultiAlgo3) algo3); 749 750 if (test_rfc2069) 751 { 752 if ((0 != tr_p->uri_num) && (1 == tr_p->req_num)) 753 expect_res = MHD_DAUTH_NONCE_STALE; 754 else 755 expect_res = MHD_DAUTH_OK; 756 } 757 else if (test_bind_uri) 758 { 759 if ((0 != tr_p->uri_num) && (1 == tr_p->req_num)) 760 expect_res = MHD_DAUTH_NONCE_OTHER_COND; 761 else 762 expect_res = MHD_DAUTH_OK; 763 } 764 else 765 expect_res = MHD_DAUTH_OK; 766 767 switch (check_res) 768 { 769 /* Conditionally valid results */ 770 case MHD_DAUTH_OK: 771 if (expect_res == MHD_DAUTH_OK) 772 { 773 if (verbose) 774 printf ("Got valid auth check result: MHD_DAUTH_OK.\n"); 775 } 776 else 777 mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ 778 "MHD_DAUTH_OK"); 779 break; 780 case MHD_DAUTH_NONCE_STALE: 781 if (expect_res == MHD_DAUTH_NONCE_STALE) 782 { 783 if (verbose) 784 printf ("Got expected auth check result: MHD_DAUTH_NONCE_STALE.\n"); 785 } 786 else 787 mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ 788 "MHD_DAUTH_NONCE_STALE"); 789 break; 790 case MHD_DAUTH_NONCE_OTHER_COND: 791 if (expect_res == MHD_DAUTH_NONCE_OTHER_COND) 792 { 793 if (verbose) 794 printf ("Got expected auth check result: " 795 "MHD_DAUTH_NONCE_OTHER_COND.\n"); 796 } 797 else 798 mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ 799 "MHD_DAUTH_NONCE_OTHER_COND"); 800 break; 801 /* Invalid results */ 802 case MHD_DAUTH_NONCE_WRONG: 803 mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ 804 "MHD_DAUTH_NONCE_WRONG"); 805 break; 806 case MHD_DAUTH_ERROR: 807 externalErrorExitDesc ("General error returned " \ 808 "by 'MHD_digest_auth_check[_digest]3()'"); 809 break; 810 case MHD_DAUTH_WRONG_USERNAME: 811 mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ 812 "MHD_DAUTH_WRONG_USERNAME"); 813 break; 814 case MHD_DAUTH_RESPONSE_WRONG: 815 mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ 816 "MHD_DAUTH_RESPONSE_WRONG"); 817 break; 818 case MHD_DAUTH_WRONG_HEADER: 819 mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ 820 "MHD_DAUTH_WRONG_HEADER"); 821 break; 822 case MHD_DAUTH_WRONG_REALM: 823 case MHD_DAUTH_WRONG_URI: 824 case MHD_DAUTH_WRONG_QOP: 825 case MHD_DAUTH_WRONG_ALGO: 826 case MHD_DAUTH_TOO_LARGE: 827 fprintf (stderr, "'MHD_digest_auth_check[_digest]3()' returned " 828 "unexpected result: %d. ", 829 check_res); 830 mhdErrorExitDesc ("Wrong returned code"); 831 break; 832 default: 833 fprintf (stderr, "'MHD_digest_auth_check[_digest]3()' returned " 834 "impossible result code: %d. ", 835 check_res); 836 mhdErrorExitDesc ("Impossible returned code"); 837 } 838 fflush (stderr); 839 fflush (stdout); 840 841 if (MHD_DAUTH_OK == check_res) 842 { 843 response = 844 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE), 845 (const void *) PAGE); 846 if (NULL == response) 847 mhdErrorExitDesc ("Response creation failed"); 848 849 if (MHD_YES != 850 MHD_queue_response (connection, MHD_HTTP_OK, response)) 851 mhdErrorExitDesc ("'MHD_queue_response()' failed"); 852 } 853 else if ((MHD_DAUTH_NONCE_STALE == check_res) || 854 (MHD_DAUTH_NONCE_OTHER_COND == check_res)) 855 { 856 response = 857 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED), 858 (const void *) DENIED); 859 if (NULL == response) 860 mhdErrorExitDesc ("Response creation failed"); 861 res = 862 MHD_queue_auth_required_response3 (connection, REALM_VAL, 863 OPAQUE_VALUE, 864 "/", response, 1, 865 (enum MHD_DigestAuthMultiQOP) qop, 866 (enum MHD_DigestAuthMultiAlgo3) 867 algo3, 868 test_userhash, 0); 869 if (MHD_YES != res) 870 mhdErrorExitDesc ("'MHD_queue_auth_required_response3()' failed"); 871 } 872 else 873 externalErrorExitDesc ("Wrong 'check_res' value"); 874 } 875 else 876 { 877 /* No Digest auth header */ 878 if ((1 != tr_p->req_num) || (0 != tr_p->uri_num)) 879 { 880 fprintf (stderr, "Received request number %u for URI number %u " 881 "without Digest Authorisation header. ", 882 tr_p->req_num, tr_p->uri_num + 1); 883 mhdErrorExitDesc ("Wrong requests sequence"); 884 } 885 886 response = 887 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED), 888 (const void *) DENIED); 889 if (NULL == response) 890 mhdErrorExitDesc ("Response creation failed"); 891 res = 892 MHD_queue_auth_required_response3 ( 893 connection, REALM_VAL, OPAQUE_VALUE, "/", response, 0, 894 (enum MHD_DigestAuthMultiQOP) qop, 895 (enum MHD_DigestAuthMultiAlgo3) algo3, test_userhash, 0); 896 if (MHD_YES != res) 897 mhdErrorExitDesc ("'MHD_queue_auth_required_response3()' failed"); 898 } 899 } 900 else if (2 == test_oldapi) 901 { 902 /* Use old API v2 */ 903 char *username; 904 int check_res; 905 int expect_res; 906 907 username = MHD_digest_auth_get_username (connection); 908 if (NULL != username) 909 { /* Has a valid username in header */ 910 if (0 != strcmp (username, username_ptr)) 911 { 912 fprintf (stderr, "'username' does not match.\n" 913 "Expected: '%s'\tRecieved: '%s'. ", 914 username_ptr, 915 username); 916 mhdErrorExitDesc ("Wrong 'username'"); 917 } 918 MHD_free (username); 919 920 if (! test_userdigest) 921 check_res = 922 MHD_digest_auth_check2 (connection, REALM_VAL, username_ptr, 923 PASSWORD_VALUE, 924 50 * TIMEOUTS_VAL, 925 test_sha256 ? 926 MHD_DIGEST_ALG_SHA256 : MHD_DIGEST_ALG_MD5); 927 else 928 check_res = 929 MHD_digest_auth_check_digest2 (connection, REALM_VAL, username_ptr, 930 userdigest_bin, userdigest_bin_size, 931 50 * TIMEOUTS_VAL, 932 test_sha256 ? 933 MHD_DIGEST_ALG_SHA256 : 934 MHD_DIGEST_ALG_MD5); 935 936 if (test_bind_uri) 937 { 938 if ((0 != tr_p->uri_num) && (1 == tr_p->req_num)) 939 expect_res = MHD_INVALID_NONCE; 940 else 941 expect_res = MHD_YES; 942 } 943 else 944 expect_res = MHD_YES; 945 946 if (expect_res != check_res) 947 { 948 fprintf (stderr, "'MHD_digest_auth_check[_digest]2()' returned " 949 "unexpected result '%d', while expected is '%d. ", 950 check_res, expect_res); 951 mhdErrorExitDesc ("Wrong 'MHD_digest_auth_check[_digest]2()' result"); 952 } 953 response = 954 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE), 955 (const void *) PAGE); 956 if (NULL == response) 957 mhdErrorExitDesc ("Response creation failed"); 958 959 if (MHD_YES == expect_res) 960 { 961 if (MHD_YES != 962 MHD_queue_response (connection, MHD_HTTP_OK, response)) 963 mhdErrorExitDesc ("'MHD_queue_response()' failed"); 964 } 965 else if (MHD_INVALID_NONCE == expect_res) 966 { 967 if (MHD_YES != 968 MHD_queue_auth_fail_response2 (connection, REALM_VAL, OPAQUE_VALUE, 969 response, 1, 970 test_sha256 ? 971 MHD_DIGEST_ALG_SHA256 : 972 MHD_DIGEST_ALG_MD5)) 973 mhdErrorExitDesc ("'MHD_queue_auth_fail_response2()' failed"); 974 } 975 else 976 externalErrorExitDesc ("Wrong 'check_res' value"); 977 } 978 else 979 { 980 /* Has no valid username in header */ 981 if ((1 != tr_p->req_num) || (0 != tr_p->uri_num)) 982 { 983 fprintf (stderr, "Received request number %u for URI number %u " 984 "without Digest Authorisation header. ", 985 tr_p->req_num, tr_p->uri_num + 1); 986 mhdErrorExitDesc ("Wrong requests sequence"); 987 } 988 response = 989 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED), 990 (const void *) DENIED); 991 if (NULL == response) 992 mhdErrorExitDesc ("Response creation failed"); 993 994 res = MHD_queue_auth_fail_response2 (connection, REALM_VAL, OPAQUE_VALUE, 995 response, 0, 996 test_sha256 ? 997 MHD_DIGEST_ALG_SHA256 : 998 MHD_DIGEST_ALG_MD5); 999 if (MHD_YES != res) 1000 mhdErrorExitDesc ("'MHD_queue_auth_fail_response2()' failed"); 1001 } 1002 } 1003 else if (1 == test_oldapi) 1004 { 1005 /* Use old API v1 */ 1006 char *username; 1007 int check_res; 1008 int expect_res; 1009 1010 username = MHD_digest_auth_get_username (connection); 1011 if (NULL != username) 1012 { /* Has a valid username in header */ 1013 if (0 != strcmp (username, username_ptr)) 1014 { 1015 fprintf (stderr, "'username' does not match.\n" 1016 "Expected: '%s'\tRecieved: '%s'. ", 1017 username_ptr, 1018 username); 1019 mhdErrorExitDesc ("Wrong 'username'"); 1020 } 1021 MHD_free (username); 1022 1023 if (! test_userdigest) 1024 check_res = 1025 MHD_digest_auth_check (connection, REALM_VAL, username_ptr, 1026 PASSWORD_VALUE, 1027 50 * TIMEOUTS_VAL); 1028 else 1029 check_res = 1030 MHD_digest_auth_check_digest (connection, REALM_VAL, username_ptr, 1031 userdigest_bin, 1032 50 * TIMEOUTS_VAL); 1033 1034 if (test_bind_uri) 1035 { 1036 if ((0 != tr_p->uri_num) && (1 == tr_p->req_num)) 1037 expect_res = MHD_INVALID_NONCE; 1038 else 1039 expect_res = MHD_YES; 1040 } 1041 else 1042 expect_res = MHD_YES; 1043 1044 if (expect_res != check_res) 1045 { 1046 fprintf (stderr, "'MHD_digest_auth_check[_digest]()' returned " 1047 "unexpected result '%d', while expected is '%d. ", 1048 check_res, expect_res); 1049 mhdErrorExitDesc ("Wrong 'MHD_digest_auth_check[_digest]()' result"); 1050 } 1051 1052 response = 1053 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE), 1054 (const void *) PAGE); 1055 if (NULL == response) 1056 mhdErrorExitDesc ("Response creation failed"); 1057 1058 if (MHD_YES == expect_res) 1059 { 1060 if (MHD_YES != 1061 MHD_queue_response (connection, MHD_HTTP_OK, response)) 1062 mhdErrorExitDesc ("'MHD_queue_response()' failed"); 1063 } 1064 else if (MHD_INVALID_NONCE == expect_res) 1065 { 1066 if (MHD_YES != 1067 MHD_queue_auth_fail_response (connection, REALM_VAL, OPAQUE_VALUE, 1068 response, 1)) 1069 mhdErrorExitDesc ("'MHD_queue_auth_fail_response()' failed"); 1070 } 1071 else 1072 externalErrorExitDesc ("Wrong 'check_res' value"); 1073 } 1074 else 1075 { 1076 /* Has no valid username in header */ 1077 if ((1 != tr_p->req_num) || (0 != tr_p->uri_num)) 1078 { 1079 fprintf (stderr, "Received request number %u for URI number %u " 1080 "without Digest Authorisation header. ", 1081 tr_p->req_num, tr_p->uri_num + 1); 1082 mhdErrorExitDesc ("Wrong requests sequence"); 1083 } 1084 response = 1085 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED), 1086 (const void *) DENIED); 1087 if (NULL == response) 1088 mhdErrorExitDesc ("Response creation failed"); 1089 1090 res = MHD_queue_auth_fail_response (connection, REALM_VAL, OPAQUE_VALUE, 1091 response, 0); 1092 if (MHD_YES != res) 1093 mhdErrorExitDesc ("'MHD_queue_auth_fail_response()' failed"); 1094 } 1095 } 1096 else 1097 externalErrorExitDesc ("Wrong 'test_oldapi' value"); 1098 1099 MHD_destroy_response (response); 1100 return MHD_YES; 1101 } 1102 1103 1104 /** 1105 * 1106 * @param c the CURL handle to use 1107 * @param port the port to set 1108 * @param uri_num the number of URI, should be 0, 1 or 2 1109 */ 1110 static void 1111 setCURL_rq_path (CURL *c, uint16_t port, unsigned int uri_num) 1112 { 1113 const char *req_path; 1114 char uri[512]; 1115 int res; 1116 1117 if (0 == uri_num) 1118 req_path = MHD_URI_BASE_PATH; 1119 else if (1 == uri_num) 1120 req_path = MHD_URI_BASE_PATH2; 1121 else 1122 req_path = MHD_URI_BASE_PATH3; 1123 /* A workaround for some old libcurl versions, which ignore the specified 1124 * port by CURLOPT_PORT when authorisation is used. */ 1125 res = snprintf (uri, (sizeof(uri) / sizeof(uri[0])), 1126 "http://127.0.0.1:%u%s", (unsigned int) port, 1127 req_path); 1128 if ((0 >= res) || ((sizeof(uri) / sizeof(uri[0])) <= (size_t) res)) 1129 externalErrorExitDesc ("Cannot form request URL"); 1130 1131 if (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, uri)) 1132 libcurlErrorExitDesc ("Cannot set request URL"); 1133 } 1134 1135 1136 static CURL * 1137 setupCURL (void *cbc, uint16_t port) 1138 { 1139 CURL *c; 1140 1141 c = curl_easy_init (); 1142 if (NULL == c) 1143 libcurlErrorExitDesc ("curl_easy_init() failed"); 1144 1145 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || 1146 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 1147 ©Buffer)) || 1148 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) || 1149 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 1150 ((long) TIMEOUTS_VAL))) || 1151 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 1152 CURL_HTTP_VERSION_1_1)) || 1153 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, 1154 ((long) TIMEOUTS_VAL))) || 1155 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, 1156 libcurl_errbuf)) || 1157 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) || 1158 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPAUTH, 1159 (long) CURLAUTH_DIGEST)) || 1160 #if CURL_AT_LEAST_VERSION (7,19,1) 1161 /* Need version 7.19.1 for separate username and password */ 1162 (CURLE_OK != curl_easy_setopt (c, CURLOPT_USERNAME, username_ptr)) || 1163 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PASSWORD, PASSWORD_VALUE)) || 1164 #endif /* CURL_AT_LEAST_VERSION(7,19,1) */ 1165 #ifdef _DEBUG 1166 (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) || 1167 #endif /* _DEBUG */ 1168 #if CURL_AT_LEAST_VERSION (7, 85, 0) 1169 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS_STR, "http")) || 1170 #elif CURL_AT_LEAST_VERSION (7, 19, 4) 1171 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) || 1172 #endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */ 1173 #if CURL_AT_LEAST_VERSION (7, 45, 0) 1174 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) || 1175 #endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */ 1176 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port)))) 1177 libcurlErrorExitDesc ("curl_easy_setopt() failed"); 1178 1179 setCURL_rq_path (c, port, 0); 1180 1181 return c; 1182 } 1183 1184 1185 static CURLcode 1186 performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse) 1187 { 1188 CURLM *multi; 1189 time_t start; 1190 struct timeval tv; 1191 CURLcode ret; 1192 1193 ret = CURLE_FAILED_INIT; /* will be replaced with real result */ 1194 if (NULL != *multi_reuse) 1195 multi = *multi_reuse; 1196 else 1197 { 1198 multi = curl_multi_init (); 1199 if (multi == NULL) 1200 libcurlErrorExitDesc ("curl_multi_init() failed"); 1201 *multi_reuse = multi; 1202 } 1203 if (CURLM_OK != curl_multi_add_handle (multi, c)) 1204 libcurlErrorExitDesc ("curl_multi_add_handle() failed"); 1205 1206 start = time (NULL); 1207 while (time (NULL) - start <= TIMEOUTS_VAL) 1208 { 1209 fd_set rs; 1210 fd_set ws; 1211 fd_set es; 1212 MHD_socket maxMhdSk; 1213 int maxCurlSk; 1214 int running; 1215 1216 maxMhdSk = MHD_INVALID_SOCKET; 1217 maxCurlSk = -1; 1218 FD_ZERO (&rs); 1219 FD_ZERO (&ws); 1220 FD_ZERO (&es); 1221 if (NULL != multi) 1222 { 1223 curl_multi_perform (multi, &running); 1224 if (0 == running) 1225 { 1226 struct CURLMsg *msg; 1227 int msgLeft; 1228 int totalMsgs = 0; 1229 do 1230 { 1231 msg = curl_multi_info_read (multi, &msgLeft); 1232 if (NULL == msg) 1233 libcurlErrorExitDesc ("curl_multi_info_read() failed"); 1234 totalMsgs++; 1235 if (CURLMSG_DONE == msg->msg) 1236 ret = msg->data.result; 1237 } while (msgLeft > 0); 1238 if (1 != totalMsgs) 1239 { 1240 fprintf (stderr, 1241 "curl_multi_info_read returned wrong " 1242 "number of results (%d).\n", 1243 totalMsgs); 1244 externalErrorExit (); 1245 } 1246 curl_multi_remove_handle (multi, c); 1247 multi = NULL; 1248 } 1249 else 1250 { 1251 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk)) 1252 libcurlErrorExitDesc ("curl_multi_fdset() failed"); 1253 } 1254 } 1255 if (NULL == multi) 1256 { /* libcurl has finished, check whether MHD still needs to perform cleanup */ 1257 if (0 != MHD_get_timeout64s (d)) 1258 break; /* MHD finished as well */ 1259 } 1260 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk)) 1261 mhdErrorExitDesc ("MHD_get_fdset() failed"); 1262 tv.tv_sec = 0; 1263 tv.tv_usec = 200000; 1264 #ifdef MHD_POSIX_SOCKETS 1265 if (maxMhdSk > maxCurlSk) 1266 maxCurlSk = maxMhdSk; 1267 #endif /* MHD_POSIX_SOCKETS */ 1268 if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv)) 1269 { 1270 #ifdef MHD_POSIX_SOCKETS 1271 if (EINTR != errno) 1272 externalErrorExitDesc ("Unexpected select() error"); 1273 #else 1274 if ((WSAEINVAL != WSAGetLastError ()) || 1275 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 1276 externalErrorExitDesc ("Unexpected select() error"); 1277 Sleep (200); 1278 #endif 1279 } 1280 if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es)) 1281 mhdErrorExitDesc ("MHD_run_from_select() failed"); 1282 } 1283 1284 return ret; 1285 } 1286 1287 1288 /** 1289 * Check request result 1290 * @param curl_code the CURL easy return code 1291 * @param pcbc the pointer struct CBC 1292 * @return non-zero if success, zero if failed 1293 */ 1294 static unsigned int 1295 check_result (CURLcode curl_code, CURL *c, struct CBC *pcbc) 1296 { 1297 long code; 1298 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code)) 1299 libcurlErrorExit (); 1300 1301 if (MHD_HTTP_OK != code) 1302 { 1303 fprintf (stderr, "Request returned wrong code: %ld.\n", 1304 code); 1305 return 0; 1306 } 1307 1308 if (CURLE_OK != curl_code) 1309 { 1310 fflush (stdout); 1311 if (0 != libcurl_errbuf[0]) 1312 fprintf (stderr, "Request failed. " 1313 "libcurl error: '%s'.\n" 1314 "libcurl error description: '%s'.\n", 1315 curl_easy_strerror (curl_code), 1316 libcurl_errbuf); 1317 else 1318 fprintf (stderr, "Request failed. " 1319 "libcurl error: '%s'.\n", 1320 curl_easy_strerror (curl_code)); 1321 fflush (stderr); 1322 return 0; 1323 } 1324 1325 if (pcbc->pos != MHD_STATICSTR_LEN_ (PAGE)) 1326 { 1327 fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", 1328 (unsigned) pcbc->pos, (int) pcbc->pos, pcbc->buf, 1329 (unsigned) MHD_STATICSTR_LEN_ (PAGE)); 1330 mhdErrorExitDesc ("Wrong returned data length"); 1331 } 1332 if (0 != memcmp (PAGE, pcbc->buf, pcbc->pos)) 1333 { 1334 fprintf (stderr, "Got invalid response '%.*s'. ", 1335 (int) pcbc->pos, pcbc->buf); 1336 mhdErrorExitDesc ("Wrong returned data"); 1337 } 1338 return 1; 1339 } 1340 1341 1342 static unsigned int 1343 testDigestAuth (void) 1344 { 1345 unsigned int dauth_nonce_bind; 1346 struct MHD_Daemon *d; 1347 uint16_t port; 1348 struct CBC cbc; 1349 struct req_track rq_tr; 1350 char buf[2048]; 1351 CURL *c; 1352 CURLM *multi_reuse; 1353 int failed = 0; 1354 1355 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 1356 port = 0; 1357 else 1358 port = 4210; 1359 1360 if (1) 1361 { 1362 uint8_t salt[8]; /* Use local variable to test MHD "copy" function */ 1363 if (! gen_good_rnd (salt, sizeof(salt))) 1364 { 1365 fprintf (stderr, "WARNING: the random buffer (used as salt value) is not " 1366 "initialised completely, nonce generation may be " 1367 "predictable in this test.\n"); 1368 fflush (stderr); 1369 } 1370 1371 dauth_nonce_bind = MHD_DAUTH_BIND_NONCE_NONE; 1372 if (test_bind_all) 1373 dauth_nonce_bind |= 1374 (MHD_DAUTH_BIND_NONCE_CLIENT_IP | MHD_DAUTH_BIND_NONCE_REALM); 1375 if (test_bind_uri) 1376 dauth_nonce_bind |= MHD_DAUTH_BIND_NONCE_URI_PARAMS; 1377 1378 d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY, 1379 port, NULL, NULL, 1380 &ahc_echo, &rq_tr, 1381 MHD_OPTION_DIGEST_AUTH_RANDOM_COPY, 1382 sizeof (salt), salt, 1383 MHD_OPTION_NONCE_NC_SIZE, 300, 1384 MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE, 1385 dauth_nonce_bind, 1386 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 1387 MHD_OPTION_END); 1388 } 1389 if (d == NULL) 1390 return 1; 1391 if (0 == port) 1392 { 1393 const union MHD_DaemonInfo *dinfo; 1394 1395 dinfo = MHD_get_daemon_info (d, 1396 MHD_DAEMON_INFO_BIND_PORT); 1397 if ( (NULL == dinfo) || 1398 (0 == dinfo->port) ) 1399 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 1400 port = dinfo->port; 1401 } 1402 1403 /* First request */ 1404 rq_tr.req_num = 0; 1405 rq_tr.uri_num = 0; 1406 cbc.buf = buf; 1407 cbc.size = sizeof (buf); 1408 cbc.pos = 0; 1409 memset (cbc.buf, 0, cbc.size); 1410 c = setupCURL (&cbc, port); 1411 multi_reuse = NULL; 1412 /* First request */ 1413 if (check_result (performQueryExternal (d, c, &multi_reuse), c, &cbc)) 1414 { 1415 fflush (stderr); 1416 if (verbose) 1417 printf ("Got first expected response.\n"); 1418 fflush (stdout); 1419 } 1420 else 1421 { 1422 fprintf (stderr, "First request FAILED.\n"); 1423 failed = 1; 1424 } 1425 cbc.pos = 0; /* Reset buffer position */ 1426 rq_tr.req_num = 0; 1427 /* Second request */ 1428 setCURL_rq_path (c, port, ++rq_tr.uri_num); 1429 if (check_result (performQueryExternal (d, c, &multi_reuse), c, &cbc)) 1430 { 1431 fflush (stderr); 1432 if (verbose) 1433 printf ("Got second expected response.\n"); 1434 fflush (stdout); 1435 } 1436 else 1437 { 1438 fprintf (stderr, "Second request FAILED.\n"); 1439 failed = 1; 1440 } 1441 cbc.pos = 0; /* Reset buffer position */ 1442 rq_tr.req_num = 0; 1443 /* Third request */ 1444 if (NULL != multi_reuse) 1445 curl_multi_cleanup (multi_reuse); 1446 multi_reuse = NULL; /* Force new connection */ 1447 setCURL_rq_path (c, port, ++rq_tr.uri_num); 1448 if (check_result (performQueryExternal (d, c, &multi_reuse), c, &cbc)) 1449 { 1450 fflush (stderr); 1451 if (verbose) 1452 printf ("Got third expected response.\n"); 1453 fflush (stdout); 1454 } 1455 else 1456 { 1457 fprintf (stderr, "Third request FAILED.\n"); 1458 failed = 1; 1459 } 1460 1461 curl_easy_cleanup (c); 1462 if (NULL != multi_reuse) 1463 curl_multi_cleanup (multi_reuse); 1464 1465 MHD_stop_daemon (d); 1466 return failed ? 1 : 0; 1467 } 1468 1469 1470 int 1471 main (int argc, char *const *argv) 1472 { 1473 #if ! CURL_AT_LEAST_VERSION (7,19,1) 1474 (void) argc; (void) argv; /* Unused. Silent compiler warning. */ 1475 /* Need version 7.19.1 or newer for separate username and password */ 1476 fprintf (stderr, "Required libcurl at least version 7.19.1" 1477 " to run this test.\n"); 1478 return 77; 1479 #else /* CURL_AT_LEAST_VERSION(7,19,1) */ 1480 unsigned int errorCount = 0; 1481 const curl_version_info_data *const curl_info = 1482 curl_version_info (CURLVERSION_NOW); 1483 int curl_sspi; 1484 (void) argc; (void) argv; /* Unused. Silent compiler warning. */ 1485 1486 #ifdef NEED_GCRYP_INIT 1487 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); 1488 #ifdef GCRYCTL_INITIALIZATION_FINISHED 1489 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); 1490 #endif /* GCRYCTL_INITIALIZATION_FINISHED */ 1491 #endif /* NEED_GCRYP_INIT */ 1492 /* Test type and test parameters */ 1493 verbose = ! (has_param (argc, argv, "-q") || 1494 has_param (argc, argv, "--quiet") || 1495 has_param (argc, argv, "-s") || 1496 has_param (argc, argv, "--silent")); 1497 test_oldapi = 0; 1498 if (has_in_name (argv[0], "_oldapi1")) 1499 test_oldapi = 1; 1500 if (has_in_name (argv[0], "_oldapi2")) 1501 test_oldapi = 2; 1502 test_userhash = has_in_name (argv[0], "_userhash"); 1503 test_userdigest = has_in_name (argv[0], "_userdigest"); 1504 test_sha256 = has_in_name (argv[0], "_sha256"); 1505 test_rfc2069 = has_in_name (argv[0], "_rfc2069"); 1506 test_bind_all = has_in_name (argv[0], "_bind_all"); 1507 test_bind_uri = has_in_name (argv[0], "_bind_uri"); 1508 1509 /* Wrong test types combinations */ 1510 if (1 == test_oldapi) 1511 { 1512 if (test_sha256) 1513 return 99; 1514 } 1515 if (test_oldapi) 1516 { 1517 if (test_userhash || test_rfc2069) 1518 return 99; 1519 } 1520 if (test_rfc2069) 1521 { 1522 if (test_userhash) 1523 return 99; 1524 } 1525 1526 /* Curl version and known bugs checks */ 1527 curl_sspi = 0; 1528 #ifdef CURL_VERSION_SSPI 1529 if (0 != (curl_info->features & CURL_VERSION_SSPI)) 1530 curl_sspi = 1; 1531 #endif /* CURL_VERSION_SSPI */ 1532 1533 if ((CURL_VERSION_BITS (7,63,0) > curl_info->version_num) && 1534 (CURL_VERSION_BITS (7,62,0) <= curl_info->version_num) ) 1535 { 1536 fprintf (stderr, "libcurl version 7.62.x has bug in processing " 1537 "URI with GET arguments for Digest Auth.\n"); 1538 fprintf (stderr, "This test with libcurl %u.%u.%u cannot be performed.\n", 1539 0xFF & (curl_info->version_num >> 16), 1540 0xFF & (curl_info->version_num >> 8), 1541 0xFF & (curl_info->version_num >> 0)); 1542 return 77; 1543 } 1544 1545 if (test_sha256) 1546 { 1547 if (curl_sspi) 1548 { 1549 fprintf (stderr, "Windows SSPI API does not support SHA-256 digests.\n"); 1550 return 77; 1551 } 1552 else if (CURL_VERSION_BITS (7,57,0) > curl_info->version_num) 1553 { 1554 fprintf (stderr, "Required libcurl at least version 7.57.0 " 1555 "to run this test with SHA-256.\n"); 1556 fprintf (stderr, "This libcurl version %u.%u.%u " 1557 "does not support SHA-256.\n", 1558 0xFF & (curl_info->version_num >> 16), 1559 0xFF & (curl_info->version_num >> 8), 1560 0xFF & (curl_info->version_num >> 0)); 1561 return 77; 1562 } 1563 } 1564 1565 if (test_userhash) 1566 { 1567 if (curl_sspi) 1568 { 1569 printf ("WARNING: Windows SSPI API does not support 'userhash'.\n"); 1570 printf ("This test just checks Digest Auth compatibility with " 1571 "the clients without 'userhash' support " 1572 "when 'userhash=true' is specified by MHD.\n"); 1573 curl_uses_usehash = 0; 1574 } 1575 else if (CURL_VERSION_BITS (7,57,0) > curl_info->version_num) 1576 { 1577 printf ("WARNING: libcurl before version 7.57.0 does not " 1578 "support 'userhash'.\n"); 1579 printf ("This test just checks Digest Auth compatibility with " 1580 "libcurl version %u.%u.%u without 'userhash' support " 1581 "when 'userhash=true' is specified by MHD.\n", 1582 0xFF & (curl_info->version_num >> 16), 1583 0xFF & (curl_info->version_num >> 8), 1584 0xFF & (curl_info->version_num >> 0)); 1585 curl_uses_usehash = 0; 1586 } 1587 else if (CURL_VERSION_BITS (7,81,0) > curl_info->version_num) 1588 { 1589 fprintf (stderr, "Required libcurl at least version 7.81.0 " 1590 "to run this test with userhash.\n"); 1591 fprintf (stderr, "This libcurl version %u.%u.%u has broken digest " 1592 "calculation when userhash is used.\n", 1593 0xFF & (curl_info->version_num >> 16), 1594 0xFF & (curl_info->version_num >> 8), 1595 0xFF & (curl_info->version_num >> 0)); 1596 return 77; 1597 } 1598 else 1599 curl_uses_usehash = ! 0; 1600 } 1601 else 1602 curl_uses_usehash = 0; 1603 1604 test_global_init (); 1605 1606 errorCount += testDigestAuth (); 1607 if (errorCount != 0) 1608 fprintf (stderr, "Error (code: %u)\n", errorCount); 1609 test_global_cleanup (); 1610 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 1611 #endif /* CURL_AT_LEAST_VERSION(7,19,1) */ 1612 }