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