test_digestauth2.c 53 KB

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