GNU libmicrohttpd  0.9.29
digestauth.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2010, 2011, 2012, 2015 Daniel Pittman and Christian Grothoff
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
25 #include "platform.h"
26 #include "mhd_limits.h"
27 #include "internal.h"
28 #include "md5.h"
29 #include "mhd_mono_clock.h"
30 #include "mhd_str.h"
31 #include "mhd_compat.h"
32 
33 #if defined(_WIN32) && defined(MHD_W32_MUTEX_)
34 #ifndef WIN32_LEAN_AND_MEAN
35 #define WIN32_LEAN_AND_MEAN 1
36 #endif /* !WIN32_LEAN_AND_MEAN */
37 #include <windows.h>
38 #endif /* _WIN32 && MHD_W32_MUTEX_ */
39 
40 #define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
41 /* 32 bit value is 4 bytes */
42 #define TIMESTAMP_BIN_SIZE 4
43 #define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE)
44 
45 /* Standard server nonce length, not including terminating null */
46 #define NONCE_STD_LEN (HASH_MD5_HEX_LEN + TIMESTAMP_HEX_LEN)
47 
51 #define _BASE "Digest "
52 
56 #define MAX_USERNAME_LENGTH 128
57 
61 #define MAX_REALM_LENGTH 256
62 
66 #define MAX_AUTH_RESPONSE_LENGTH 128
67 
68 
76 static void
77 cvthex (const unsigned char *bin,
78  size_t len,
79  char *hex)
80 {
81  size_t i;
82  unsigned int j;
83 
84  for (i = 0; i < len; ++i)
85  {
86  j = (bin[i] >> 4) & 0x0f;
87  hex[i * 2] = (char)((j <= 9) ? (j + '0') : (j - 10 + 'a'));
88  j = bin[i] & 0x0f;
89  hex[i * 2 + 1] = (char)((j <= 9) ? (j + '0') : (j - 10 + 'a'));
90  }
91  hex[len * 2] = '\0';
92 }
93 
94 
107 static void
108 digest_calc_ha1 (const char *alg,
109  const char *username,
110  const char *realm,
111  const char *password,
112  const char *nonce,
113  const char *cnonce,
114  char sessionkey[HASH_MD5_HEX_LEN + 1])
115 {
116  struct MD5Context md5;
117  unsigned char ha1[MD5_DIGEST_SIZE];
118 
119  MD5Init (&md5);
120  MD5Update (&md5,
121  (const unsigned char *) username,
122  strlen (username));
123  MD5Update (&md5,
124  (const unsigned char *) ":",
125  1);
126  MD5Update (&md5,
127  (const unsigned char *) realm,
128  strlen (realm));
129  MD5Update (&md5,
130  (const unsigned char *) ":",
131  1);
132  MD5Update (&md5,
133  (const unsigned char *) password,
134  strlen (password));
135  MD5Final (ha1,
136  &md5);
137  if (MHD_str_equal_caseless_(alg,
138  "md5-sess"))
139  {
140  MD5Init (&md5);
141  MD5Update (&md5,
142  (const unsigned char *) ha1,
143  sizeof (ha1));
144  MD5Update (&md5,
145  (const unsigned char *) ":",
146  1);
147  MD5Update (&md5,
148  (const unsigned char *) nonce,
149  strlen (nonce));
150  MD5Update (&md5,
151  (const unsigned char *) ":",
152  1);
153  MD5Update (&md5,
154  (const unsigned char *) cnonce,
155  strlen (cnonce));
156  MD5Final (ha1,
157  &md5);
158  }
159  cvthex (ha1,
160  sizeof (ha1),
161  sessionkey);
162 }
163 
164 
178 static void
180  const char *nonce,
181  const char *noncecount,
182  const char *cnonce,
183  const char *qop,
184  const char *method,
185  const char *uri,
186  const char *hentity,
187  char response[HASH_MD5_HEX_LEN + 1])
188 {
189  struct MD5Context md5;
190  unsigned char ha2[MD5_DIGEST_SIZE];
191  unsigned char resphash[MD5_DIGEST_SIZE];
192  char ha2hex[HASH_MD5_HEX_LEN + 1];
193 
194  MD5Init (&md5);
195  MD5Update (&md5,
196  (const unsigned char *) method,
197  strlen (method));
198  MD5Update (&md5,
199  (const unsigned char *) ":",
200  1);
201  MD5Update (&md5,
202  (const unsigned char *) uri,
203  strlen (uri));
204 #if 0
205  if (0 == strcasecmp(qop,
206  "auth-int"))
207  {
208  /* This is dead code since the rest of this module does
209  not support auth-int. */
210  MD5Update (&md5,
211  ":",
212  1);
213  if (NULL != hentity)
214  MD5Update (&md5,
215  hentity,
216  strlen (hentity));
217  }
218 #endif
219  MD5Final (ha2,
220  &md5);
221  cvthex (ha2,
223  ha2hex);
224  MD5Init (&md5);
225  /* calculate response */
226  MD5Update (&md5,
227  (const unsigned char *) ha1,
229  MD5Update (&md5,
230  (const unsigned char *) ":",
231  1);
232  MD5Update (&md5,
233  (const unsigned char *) nonce,
234  strlen (nonce));
235  MD5Update (&md5,
236  (const unsigned char*) ":",
237  1);
238  if ('\0' != *qop)
239  {
240  MD5Update (&md5,
241  (const unsigned char *) noncecount,
242  strlen (noncecount));
243  MD5Update (&md5,
244  (const unsigned char *) ":",
245  1);
246  MD5Update (&md5,
247  (const unsigned char *) cnonce,
248  strlen (cnonce));
249  MD5Update (&md5,
250  (const unsigned char *) ":",
251  1);
252  MD5Update (&md5,
253  (const unsigned char *) qop,
254  strlen (qop));
255  MD5Update (&md5,
256  (const unsigned char *) ":",
257  1);
258  }
259  MD5Update (&md5,
260  (const unsigned char *) ha2hex,
262  MD5Final (resphash,
263  &md5);
264  cvthex (resphash,
265  sizeof(resphash),
266  response);
267 }
268 
269 
284 static size_t
285 lookup_sub_value (char *dest,
286  size_t size,
287  const char *data,
288  const char *key)
289 {
290  size_t keylen;
291  size_t len;
292  const char *ptr;
293  const char *eq;
294  const char *q1;
295  const char *q2;
296  const char *qn;
297 
298  if (0 == size)
299  return 0;
300  keylen = strlen (key);
301  ptr = data;
302  while ('\0' != *ptr)
303  {
304  if (NULL == (eq = strchr (ptr,
305  '=')))
306  return 0;
307  q1 = eq + 1;
308  while (' ' == *q1)
309  q1++;
310  if ('\"' != *q1)
311  {
312  q2 = strchr (q1,
313  ',');
314  qn = q2;
315  }
316  else
317  {
318  q1++;
319  q2 = strchr (q1,
320  '\"');
321  if (NULL == q2)
322  return 0; /* end quote not found */
323  qn = q2 + 1;
324  }
325  if ( (MHD_str_equal_caseless_n_(ptr,
326  key,
327  keylen)) &&
328  (eq == &ptr[keylen]) )
329  {
330  if (NULL == q2)
331  {
332  len = strlen (q1) + 1;
333  if (size > len)
334  size = len;
335  size--;
336  strncpy (dest,
337  q1,
338  size);
339  dest[size] = '\0';
340  return size;
341  }
342  else
343  {
344  if (size > (size_t) ((q2 - q1) + 1))
345  size = (q2 - q1) + 1;
346  size--;
347  memcpy (dest,
348  q1,
349  size);
350  dest[size] = '\0';
351  return size;
352  }
353  }
354  if (NULL == qn)
355  return 0;
356  ptr = strchr (qn,
357  ',');
358  if (NULL == ptr)
359  return 0;
360  ptr++;
361  while (' ' == *ptr)
362  ptr++;
363  }
364  return 0;
365 }
366 
367 
377 static int
378 check_nonce_nc (struct MHD_Connection *connection,
379  const char *nonce,
380  uint64_t nc)
381 {
382  struct MHD_Daemon *daemon = connection->daemon;
383  struct MHD_NonceNc *nn;
384  uint32_t off;
385  uint32_t mod;
386  const char *np;
387 
388  if (MAX_NONCE_LENGTH <= strlen (nonce))
389  return MHD_NO; /* This should be impossible, but static analysis
390  tools have a hard time with it *and* this also
391  protects against unsafe modifications that may
392  happen in the future... */
393  mod = daemon->nonce_nc_size;
394  if (0 == mod)
395  return MHD_NO; /* no array! */
396  /* super-fast xor-based "hash" function for HT lookup in nonce array */
397  off = 0;
398  np = nonce;
399  while ('\0' != *np)
400  {
401  off = (off << 8) | (*np ^ (off >> 24));
402  np++;
403  }
404  off = off % mod;
405  /*
406  * Look for the nonce, if it does exist and its corresponding
407  * nonce counter is less than the current nonce counter by 1,
408  * then only increase the nonce counter by one.
409  */
410  nn = &daemon->nnc[off];
411  MHD_mutex_lock_chk_ (&daemon->nnc_lock);
412  if (0 == nc)
413  {
414  /* Fresh nonce, reinitialize array */
415  strcpy (nn->nonce,
416  nonce);
417  nn->nc = 0;
418  nn->nmask = 0;
419  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
420  return MHD_YES;
421  }
422  /* Note that we use 64 here, as we do not store the
423  bit for 'nn->nc' itself in 'nn->nmask' */
424  if ( (nc < nn->nc) &&
425  (nc + 64 > nc /* checking for overflow */) &&
426  (nc + 64 >= nn->nc) &&
427  (0 == ((1LLU << (nn->nc - nc - 1)) & nn->nmask)) )
428  {
429  /* Out-of-order nonce, but within 64-bit bitmask, set bit */
430  nn->nmask |= (1LLU < (nn->nc - nc - 1));
431  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
432  return MHD_YES;
433  }
434 
435  if ( (nc <= nn->nc) ||
436  (0 != strcmp (nn->nonce,
437  nonce)) )
438  {
439  /* Nonce does not match, fail */
440  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
441 #ifdef HAVE_MESSAGES
442  MHD_DLOG (daemon,
443  _("Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n"));
444 #endif
445  return MHD_NO;
446  }
447  /* Nonce is larger, shift bitmask and bump limit */
448  if (64 > nc - nn->nc)
449  nn->nmask <<= (nc - nn->nc); /* small jump, less than mask width */
450  else
451  nn->nmask = 0; /* big jump, unset all bits in the mask */
452  nn->nc = nc;
453  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
454  return MHD_YES;
455 }
456 
457 
466 char *
468 {
469  size_t len;
470  char user[MAX_USERNAME_LENGTH];
471  const char *header;
472 
473  if (NULL == (header =
474  MHD_lookup_connection_value (connection,
477  return NULL;
478  if (0 != strncmp (header,
479  _BASE,
481  return NULL;
482  header += MHD_STATICSTR_LEN_ (_BASE);
483  if (0 == (len = lookup_sub_value (user,
484  sizeof (user),
485  header,
486  "username")))
487  return NULL;
488  return strdup (user);
489 }
490 
491 
505 static void
506 calculate_nonce (uint32_t nonce_time,
507  const char *method,
508  const char *rnd,
509  size_t rnd_size,
510  const char *uri,
511  const char *realm,
512  char nonce[NONCE_STD_LEN + 1])
513 {
514  struct MD5Context md5;
515  unsigned char timestamp[TIMESTAMP_BIN_SIZE];
516  unsigned char tmpnonce[MD5_DIGEST_SIZE];
517  char timestamphex[TIMESTAMP_HEX_LEN + 1];
518 
519  MD5Init (&md5);
520  timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18);
521  timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10);
522  timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08);
523  timestamp[3] = (unsigned char)((nonce_time & 0x000000ff));
524  MD5Update (&md5,
525  timestamp,
526  sizeof (timestamp));
527  MD5Update (&md5,
528  (const unsigned char *) ":",
529  1);
530  MD5Update (&md5,
531  (const unsigned char *) method,
532  strlen (method));
533  MD5Update (&md5,
534  (const unsigned char *) ":",
535  1);
536  if (rnd_size > 0)
537  MD5Update (&md5,
538  (const unsigned char *) rnd,
539  rnd_size);
540  MD5Update (&md5,
541  (const unsigned char *) ":",
542  1);
543  MD5Update (&md5,
544  (const unsigned char *) uri,
545  strlen (uri));
546  MD5Update (&md5,
547  (const unsigned char *) ":",
548  1);
549  MD5Update (&md5,
550  (const unsigned char *) realm,
551  strlen (realm));
552  MD5Final (tmpnonce,
553  &md5);
554  cvthex (tmpnonce,
555  sizeof (tmpnonce),
556  nonce);
557  cvthex (timestamp,
558  sizeof (timestamp),
559  timestamphex);
560  strncat (nonce,
561  timestamphex,
562  8);
563 }
564 
565 
577 static int
578 test_header (struct MHD_Connection *connection,
579  const char *key,
580  const char *value,
581  enum MHD_ValueKind kind)
582 {
583  struct MHD_HTTP_Header *pos;
584 
585  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
586  {
587  if (kind != pos->kind)
588  continue;
589  if (0 != strcmp (key,
590  pos->header))
591  continue;
592  if ( (NULL == value) &&
593  (NULL == pos->value) )
594  return MHD_YES;
595  if ( (NULL == value) ||
596  (NULL == pos->value) ||
597  (0 != strcmp (value,
598  pos->value)) )
599  continue;
600  return MHD_YES;
601  }
602  return MHD_NO;
603 }
604 
605 
616 static int
618  const char *args)
619 {
620  struct MHD_HTTP_Header *pos;
621  char *argb;
622  unsigned int num_headers;
623  int ret;
624 
625  argb = strdup (args);
626  if (NULL == argb)
627  {
628 #ifdef HAVE_MESSAGES
629  MHD_DLOG (connection->daemon,
630  _("Failed to allocate memory for copy of URI arguments\n"));
631 #endif /* HAVE_MESSAGES */
632  return MHD_NO;
633  }
634  ret = MHD_parse_arguments_ (connection,
636  argb,
637  &test_header,
638  &num_headers);
639  free (argb);
640  if (MHD_YES != ret)
641  return MHD_NO;
642  /* also check that the number of headers matches */
643  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
644  {
645  if (MHD_GET_ARGUMENT_KIND != pos->kind)
646  continue;
647  num_headers--;
648  }
649  if (0 != num_headers)
650  {
651  /* argument count mismatch */
652  return MHD_NO;
653  }
654  return MHD_YES;
655 }
656 
657 
671 int
673  const char *realm,
674  const char *username,
675  const char *password,
676  unsigned int nonce_timeout)
677 {
678  struct MHD_Daemon *daemon = connection->daemon;
679  size_t len;
680  const char *header;
681  char nonce[MAX_NONCE_LENGTH];
682  char cnonce[MAX_NONCE_LENGTH];
683  char qop[15]; /* auth,auth-int */
684  char nc[20];
685  char response[MAX_AUTH_RESPONSE_LENGTH];
686  const char *hentity = NULL; /* "auth-int" is not supported */
687  char ha1[HASH_MD5_HEX_LEN + 1];
688  char respexp[HASH_MD5_HEX_LEN + 1];
689  char noncehashexp[NONCE_STD_LEN + 1];
690  uint32_t nonce_time;
691  uint32_t t;
692  size_t left; /* number of characters left in 'header' for 'uri' */
693  uint64_t nci;
694 
695  header = MHD_lookup_connection_value (connection,
698  if (NULL == header)
699  return MHD_NO;
700  if (0 != strncmp (header,
701  _BASE,
703  return MHD_NO;
704  header += MHD_STATICSTR_LEN_ (_BASE);
705  left = strlen (header);
706 
707  {
708  char un[MAX_USERNAME_LENGTH];
709 
710  len = lookup_sub_value (un,
711  sizeof (un),
712  header,
713  "username");
714  if ( (0 == len) ||
715  (0 != strcmp (username,
716  un)) )
717  return MHD_NO;
718  left -= strlen ("username") + len;
719  }
720 
721  {
722  char r[MAX_REALM_LENGTH];
723 
724  len = lookup_sub_value (r,
725  sizeof (r),
726  header,
727  "realm");
728  if ( (0 == len) ||
729  (0 != strcmp (realm,
730  r)) )
731  return MHD_NO;
732  left -= strlen ("realm") + len;
733  }
734 
735  if (0 == (len = lookup_sub_value (nonce,
736  sizeof (nonce),
737  header,
738  "nonce")))
739  return MHD_NO;
740  left -= strlen ("nonce") + len;
741  if (left > 32 * 1024)
742  {
743  /* we do not permit URIs longer than 32k, as we want to
744  make sure to not blow our stack (or per-connection
745  heap memory limit). Besides, 32k is already insanely
746  large, but of course in theory the
747  #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
748  and would thus permit sending a >32k authorization
749  header value. */
750  return MHD_NO;
751  }
752  if (TIMESTAMP_HEX_LEN !=
755  &nonce_time))
756  {
757 #ifdef HAVE_MESSAGES
758  MHD_DLOG (daemon,
759  _("Authentication failed, invalid timestamp format.\n"));
760 #endif
761  return MHD_NO;
762  }
763  t = (uint32_t) MHD_monotonic_sec_counter();
764  /*
765  * First level vetting for the nonce validity: if the timestamp
766  * attached to the nonce exceeds `nonce_timeout', then the nonce is
767  * invalid.
768  */
769  if ( (t > nonce_time + nonce_timeout) ||
770  (nonce_time + nonce_timeout < nonce_time) )
771  {
772  /* too old */
773  return MHD_INVALID_NONCE;
774  }
775 
776  calculate_nonce (nonce_time,
777  connection->method,
778  daemon->digest_auth_random,
779  daemon->digest_auth_rand_size,
780  connection->url,
781  realm,
782  noncehashexp);
783  /*
784  * Second level vetting for the nonce validity
785  * if the timestamp attached to the nonce is valid
786  * and possibly fabricated (in case of an attack)
787  * the attacker must also know the random seed to be
788  * able to generate a "sane" nonce, which if he does
789  * not, the nonce fabrication process going to be
790  * very hard to achieve.
791  */
792 
793  if (0 != strcmp (nonce, noncehashexp))
794  {
795  return MHD_INVALID_NONCE;
796  }
797  if ( (0 == lookup_sub_value (cnonce,
798  sizeof (cnonce),
799  header,
800  "cnonce")) ||
801  (0 == lookup_sub_value (qop,
802  sizeof (qop),
803  header,
804  "qop")) ||
805  ( (0 != strcmp (qop,
806  "auth")) &&
807  (0 != strcmp (qop,
808  "")) ) ||
809  (0 == (len = lookup_sub_value (nc,
810  sizeof (nc),
811  header,
812  "nc")) ) ||
813  (0 == lookup_sub_value (response,
814  sizeof (response),
815  header,
816  "response")) )
817  {
818 #ifdef HAVE_MESSAGES
819  MHD_DLOG (daemon,
820  _("Authentication failed, invalid format.\n"));
821 #endif
822  return MHD_NO;
823  }
824  if (len != MHD_strx_to_uint64_n_ (nc,
825  len,
826  &nci))
827  {
828 #ifdef HAVE_MESSAGES
829  MHD_DLOG (daemon,
830  _("Authentication failed, invalid nc format.\n"));
831 #endif
832  return MHD_NO; /* invalid nonce format */
833  }
834 
835  /*
836  * Checking if that combination of nonce and nc is sound
837  * and not a replay attack attempt. Also adds the nonce
838  * to the nonce-nc map if it does not exist there.
839  */
840  if (MHD_YES !=
841  check_nonce_nc (connection,
842  nonce,
843  nci))
844  {
845  return MHD_NO;
846  }
847 
848  {
849  char *uri;
850 
851  uri = malloc (left + 1);
852  if (NULL == uri)
853  {
854 #ifdef HAVE_MESSAGES
855  MHD_DLOG(daemon,
856  _("Failed to allocate memory for auth header processing\n"));
857 #endif /* HAVE_MESSAGES */
858  return MHD_NO;
859  }
860  if (0 == lookup_sub_value (uri,
861  left + 1,
862  header,
863  "uri"))
864  {
865  free (uri);
866  return MHD_NO;
867  }
868 
869  digest_calc_ha1 ("md5",
870  username,
871  realm,
872  password,
873  nonce,
874  cnonce,
875  ha1);
877  nonce,
878  nc,
879  cnonce,
880  qop,
881  connection->method,
882  uri,
883  hentity,
884  respexp);
885 
886  /* Need to unescape URI before comparing with connection->url */
887  daemon->unescape_callback (daemon->unescape_callback_cls,
888  connection,
889  uri);
890  if (0 != strncmp (uri,
891  connection->url,
892  strlen (connection->url)))
893  {
894 #ifdef HAVE_MESSAGES
895  MHD_DLOG (daemon,
896  _("Authentication failed, URI does not match.\n"));
897 #endif
898  free (uri);
899  return MHD_NO;
900  }
901 
902  {
903  const char *args = strchr (uri,
904  '?');
905 
906  if (NULL == args)
907  args = "";
908  else
909  args++;
910  if (MHD_YES !=
911  check_argument_match (connection,
912  args) )
913  {
914 #ifdef HAVE_MESSAGES
915  MHD_DLOG (daemon,
916  _("Authentication failed, arguments do not match.\n"));
917 #endif
918  free (uri);
919  return MHD_NO;
920  }
921  }
922  free (uri);
923  return (0 == strcmp(response,
924  respexp))
925  ? MHD_YES
926  : MHD_NO;
927  }
928 }
929 
930 
945 int
947  const char *realm,
948  const char *opaque,
949  struct MHD_Response *response,
950  int signal_stale)
951 {
952  int ret;
953  int hlen;
954  char nonce[NONCE_STD_LEN + 1];
955 
956  /* Generating the server nonce */
958  connection->method,
959  connection->daemon->digest_auth_random,
960  connection->daemon->digest_auth_rand_size,
961  connection->url,
962  realm,
963  nonce);
964  if (MHD_YES !=
965  check_nonce_nc (connection,
966  nonce,
967  0))
968  {
969 #ifdef HAVE_MESSAGES
970  MHD_DLOG (connection->daemon,
971  _("Could not register nonce (is the nonce array size zero?).\n"));
972 #endif
973  return MHD_NO;
974  }
975  /* Building the authentication header */
976  hlen = MHD_snprintf_ (NULL,
977  0,
978  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
979  realm,
980  nonce,
981  opaque,
982  signal_stale
983  ? ",stale=\"true\""
984  : "");
985  if (hlen > 0)
986  {
987  char *header;
988 
989  header = MHD_calloc_ (1, hlen + 1);
990  if (NULL == header)
991  {
992 #ifdef HAVE_MESSAGES
993  MHD_DLOG(connection->daemon,
994  _("Failed to allocate memory for auth response header\n"));
995 #endif /* HAVE_MESSAGES */
996  return MHD_NO;
997  }
998 
999  if (MHD_snprintf_ (header,
1000  hlen + 1,
1001  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
1002  realm,
1003  nonce,
1004  opaque,
1005  signal_stale
1006  ? ",stale=\"true\""
1007  : "") == hlen)
1008  ret = MHD_add_response_header(response,
1010  header);
1011  else
1012  ret = MHD_NO;
1013  free (header);
1014  }
1015  else
1016  ret = MHD_NO;
1017 
1018  if (MHD_YES == ret)
1019  {
1020  ret = MHD_queue_response (connection,
1022  response);
1023  }
1024  else
1025  {
1026 #ifdef HAVE_MESSAGES
1027  MHD_DLOG (connection->daemon,
1028  _("Failed to add Digest auth header\n"));
1029 #endif /* HAVE_MESSAGES */
1030  }
1031  return ret;
1032 }
1033 
1034 
1035 /* end of digestauth.c */
#define MAX_NONCE_LENGTH
Definition: internal.h:213
void * unescape_callback_cls
Definition: internal.h:1401
#define MAX_AUTH_RESPONSE_LENGTH
Definition: digestauth.c:66
static void digest_calc_response(const char ha1[HASH_MD5_HEX_LEN+1], const char *nonce, const char *noncecount, const char *cnonce, const char *qop, const char *method, const char *uri, const char *hentity, char response[HASH_MD5_HEX_LEN+1])
Definition: digestauth.c:179
int MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition: response.c:118
#define NULL
Definition: reason_phrase.c:31
static void cvthex(const unsigned char *bin, size_t len, char *hex)
Definition: digestauth.c:77
static size_t lookup_sub_value(char *dest, size_t size, const char *data, const char *key)
Definition: digestauth.c:285
#define TIMESTAMP_BIN_SIZE
Definition: digestauth.c:42
#define MHD_YES
Definition: microhttpd.h:134
Header for platform missing functions.
enum MHD_ValueKind kind
Definition: internal.h:278
int MHD_digest_auth_check(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout)
Definition: digestauth.c:672
#define NONCE_STD_LEN
Definition: digestauth.c:46
platform-specific includes for libmicrohttpd
int MHD_parse_arguments_(struct MHD_Connection *connection, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers)
Definition: internal.c:186
char * value
Definition: internal.h:272
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:349
struct MHD_Daemon * daemon
Definition: internal.h:641
#define MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:168
void MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len)
Definition: md5.c:67
#define HASH_MD5_HEX_LEN
Definition: digestauth.c:40
uint64_t nmask
Definition: internal.h:233
#define MHD_STATICSTR_LEN_(macro)
Definition: internal.h:124
size_t MHD_strx_to_uint32_n_(const char *str, size_t maxlen, uint32_t *out_val)
Definition: mhd_str.c:571
#define MHD_HTTP_HEADER_AUTHORIZATION
Definition: microhttpd.h:434
const char * url
Definition: internal.h:694
int MHD_queue_auth_fail_response(struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale)
Definition: digestauth.c:946
char * method
Definition: internal.h:688
static int test_header(struct MHD_Connection *connection, const char *key, const char *value, enum MHD_ValueKind kind)
Definition: digestauth.c:578
char nonce[MAX_NONCE_LENGTH]
Definition: internal.h:238
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition: microhttpd.h:512
const char * MHD_lookup_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key)
Definition: connection.c:450
static int check_argument_match(struct MHD_Connection *connection, const char *args)
Definition: digestauth.c:617
static void digest_calc_ha1(const char *alg, const char *username, const char *realm, const char *password, const char *nonce, const char *cnonce, char sessionkey[HASH_MD5_HEX_LEN+1])
Definition: digestauth.c:108
MHD_ValueKind
Definition: microhttpd.h:1524
limits values definitions
internal shared structures
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:96
UnescapeCallback unescape_callback
Definition: internal.h:1396
int MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:3579
internal monotonic clock functions implementations
#define MHD_HTTP_UNAUTHORIZED
Definition: microhttpd.h:330
#define _BASE
Definition: digestauth.c:51
char * header
Definition: internal.h:267
void MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx)
Definition: md5.c:135
static void calculate_nonce(uint32_t nonce_time, const char *method, const char *rnd, size_t rnd_size, const char *uri, const char *realm, char nonce[NONCE_STD_LEN+1])
Definition: digestauth.c:506
void MD5Init(struct MD5Context *ctx)
Definition: md5.c:50
#define MHD_INVALID_NONCE
Definition: microhttpd.h:144
char * MHD_digest_auth_get_username(struct MHD_Connection *connection)
Definition: digestauth.c:467
uint64_t nc
Definition: internal.h:227
time_t MHD_monotonic_sec_counter(void)
Header for string manipulating helpers.
Definition: md5.h:27
struct MHD_HTTP_Header * next
Definition: internal.h:262
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:319
static int check_nonce_nc(struct MHD_Connection *connection, const char *nonce, uint64_t nc)
Definition: digestauth.c:378
#define MD5_DIGEST_SIZE
Definition: md5.h:24
#define MAX_USERNAME_LENGTH
Definition: digestauth.c:56
#define _(String)
Definition: mhd_options.h:42
#define MAX_REALM_LENGTH
Definition: digestauth.c:61
#define MHD_NO
Definition: microhttpd.h:139
#define TIMESTAMP_HEX_LEN
Definition: digestauth.c:43
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:656
struct MHD_HTTP_Header * headers_received
Definition: internal.h:646
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:142