libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

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                                      &copyBuffer)) ||
   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 }