GNU libmicrohttpd  0.9.59
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(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 /* 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  (void)hentity; /* Unused. Silent compiler warning. */
194 
195  MD5Init (&md5);
196  MD5Update (&md5,
197  (const unsigned char *) method,
198  strlen (method));
199  MD5Update (&md5,
200  (const unsigned char *) ":",
201  1);
202  MD5Update (&md5,
203  (const unsigned char *) uri,
204  strlen (uri));
205 #if 0
206  if (0 == strcasecmp(qop,
207  "auth-int"))
208  {
209  /* This is dead code since the rest of this module does
210  not support auth-int. */
211  MD5Update (&md5,
212  ":",
213  1);
214  if (NULL != hentity)
215  MD5Update (&md5,
216  hentity,
217  strlen (hentity));
218  }
219 #endif
220  MD5Final (ha2,
221  &md5);
222  cvthex (ha2,
224  ha2hex);
225  MD5Init (&md5);
226  /* calculate response */
227  MD5Update (&md5,
228  (const unsigned char *) ha1,
230  MD5Update (&md5,
231  (const unsigned char *) ":",
232  1);
233  MD5Update (&md5,
234  (const unsigned char *) nonce,
235  strlen (nonce));
236  MD5Update (&md5,
237  (const unsigned char*) ":",
238  1);
239  if ('\0' != *qop)
240  {
241  MD5Update (&md5,
242  (const unsigned char *) noncecount,
243  strlen (noncecount));
244  MD5Update (&md5,
245  (const unsigned char *) ":",
246  1);
247  MD5Update (&md5,
248  (const unsigned char *) cnonce,
249  strlen (cnonce));
250  MD5Update (&md5,
251  (const unsigned char *) ":",
252  1);
253  MD5Update (&md5,
254  (const unsigned char *) qop,
255  strlen (qop));
256  MD5Update (&md5,
257  (const unsigned char *) ":",
258  1);
259  }
260  MD5Update (&md5,
261  (const unsigned char *) ha2hex,
263  MD5Final (resphash,
264  &md5);
265  cvthex (resphash,
266  sizeof(resphash),
267  response);
268 }
269 
270 
285 static size_t
286 lookup_sub_value (char *dest,
287  size_t size,
288  const char *data,
289  const char *key)
290 {
291  size_t keylen;
292  size_t len;
293  const char *ptr;
294  const char *eq;
295  const char *q1;
296  const char *q2;
297  const char *qn;
298 
299  if (0 == size)
300  return 0;
301  keylen = strlen (key);
302  ptr = data;
303  while ('\0' != *ptr)
304  {
305  if (NULL == (eq = strchr (ptr,
306  '=')))
307  return 0;
308  q1 = eq + 1;
309  while (' ' == *q1)
310  q1++;
311  if ('\"' != *q1)
312  {
313  q2 = strchr (q1,
314  ',');
315  qn = q2;
316  }
317  else
318  {
319  q1++;
320  q2 = strchr (q1,
321  '\"');
322  if (NULL == q2)
323  return 0; /* end quote not found */
324  qn = q2 + 1;
325  }
326  if ( (MHD_str_equal_caseless_n_(ptr,
327  key,
328  keylen)) &&
329  (eq == &ptr[keylen]) )
330  {
331  if (NULL == q2)
332  {
333  len = strlen (q1) + 1;
334  if (size > len)
335  size = len;
336  size--;
337  strncpy (dest,
338  q1,
339  size);
340  dest[size] = '\0';
341  return size;
342  }
343  else
344  {
345  if (size > (size_t) ((q2 - q1) + 1))
346  size = (q2 - q1) + 1;
347  size--;
348  memcpy (dest,
349  q1,
350  size);
351  dest[size] = '\0';
352  return size;
353  }
354  }
355  if (NULL == qn)
356  return 0;
357  ptr = strchr (qn,
358  ',');
359  if (NULL == ptr)
360  return 0;
361  ptr++;
362  while (' ' == *ptr)
363  ptr++;
364  }
365  return 0;
366 }
367 
368 
378 static int
379 check_nonce_nc (struct MHD_Connection *connection,
380  const char *nonce,
381  uint64_t nc)
382 {
383  struct MHD_Daemon *daemon = connection->daemon;
384  struct MHD_NonceNc *nn;
385  uint32_t off;
386  uint32_t mod;
387  const char *np;
388 
389  if (MAX_NONCE_LENGTH <= strlen (nonce))
390  return MHD_NO; /* This should be impossible, but static analysis
391  tools have a hard time with it *and* this also
392  protects against unsafe modifications that may
393  happen in the future... */
394  mod = daemon->nonce_nc_size;
395  if (0 == mod)
396  return MHD_NO; /* no array! */
397  /* super-fast xor-based "hash" function for HT lookup in nonce array */
398  off = 0;
399  np = nonce;
400  while ('\0' != *np)
401  {
402  off = (off << 8) | (*np ^ (off >> 24));
403  np++;
404  }
405  off = off % mod;
406  /*
407  * Look for the nonce, if it does exist and its corresponding
408  * nonce counter is less than the current nonce counter by 1,
409  * then only increase the nonce counter by one.
410  */
411  nn = &daemon->nnc[off];
412  MHD_mutex_lock_chk_ (&daemon->nnc_lock);
413  if (0 == nc)
414  {
415  /* Fresh nonce, reinitialize array */
416  strcpy (nn->nonce,
417  nonce);
418  nn->nc = 0;
419  nn->nmask = 0;
420  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
421  return MHD_YES;
422  }
423  /* Note that we use 64 here, as we do not store the
424  bit for 'nn->nc' itself in 'nn->nmask' */
425  if ( (nc < nn->nc) &&
426  (nc + 64 > nc /* checking for overflow */) &&
427  (nc + 64 >= nn->nc) &&
428  (0 == ((1LLU << (nn->nc - nc - 1)) & nn->nmask)) )
429  {
430  /* Out-of-order nonce, but within 64-bit bitmask, set bit */
431  nn->nmask |= (1LLU << (nn->nc - nc - 1));
432  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
433  return MHD_YES;
434  }
435 
436  if ( (nc <= nn->nc) ||
437  (0 != strcmp (nn->nonce,
438  nonce)) )
439  {
440  /* Nonce does not match, fail */
441  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
442 #ifdef HAVE_MESSAGES
443  MHD_DLOG (daemon,
444  _("Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n"));
445 #endif
446  return MHD_NO;
447  }
448  /* Nonce is larger, shift bitmask and bump limit */
449  if (64 > nc - nn->nc)
450  nn->nmask <<= (nc - nn->nc); /* small jump, less than mask width */
451  else
452  nn->nmask = 0; /* big jump, unset all bits in the mask */
453  nn->nc = nc;
454  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
455  return MHD_YES;
456 }
457 
458 
468 char *
470 {
471  size_t len;
472  char user[MAX_USERNAME_LENGTH];
473  const char *header;
474 
475  if (NULL == (header =
476  MHD_lookup_connection_value (connection,
479  return NULL;
480  if (0 != strncmp (header,
481  _BASE,
483  return NULL;
484  header += MHD_STATICSTR_LEN_ (_BASE);
485  if (0 == (len = lookup_sub_value (user,
486  sizeof (user),
487  header,
488  "username")))
489  return NULL;
490  return strdup (user);
491 }
492 
493 
507 static void
508 calculate_nonce (uint32_t nonce_time,
509  const char *method,
510  const char *rnd,
511  size_t rnd_size,
512  const char *uri,
513  const char *realm,
514  char nonce[NONCE_STD_LEN + 1])
515 {
516  struct MD5Context md5;
517  unsigned char timestamp[TIMESTAMP_BIN_SIZE];
518  unsigned char tmpnonce[MD5_DIGEST_SIZE];
519  char timestamphex[TIMESTAMP_HEX_LEN + 1];
520 
521  MD5Init (&md5);
522  timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18);
523  timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10);
524  timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08);
525  timestamp[3] = (unsigned char)((nonce_time & 0x000000ff));
526  MD5Update (&md5,
527  timestamp,
528  sizeof (timestamp));
529  MD5Update (&md5,
530  (const unsigned char *) ":",
531  1);
532  MD5Update (&md5,
533  (const unsigned char *) method,
534  strlen (method));
535  MD5Update (&md5,
536  (const unsigned char *) ":",
537  1);
538  if (rnd_size > 0)
539  MD5Update (&md5,
540  (const unsigned char *) rnd,
541  rnd_size);
542  MD5Update (&md5,
543  (const unsigned char *) ":",
544  1);
545  MD5Update (&md5,
546  (const unsigned char *) uri,
547  strlen (uri));
548  MD5Update (&md5,
549  (const unsigned char *) ":",
550  1);
551  MD5Update (&md5,
552  (const unsigned char *) realm,
553  strlen (realm));
554  MD5Final (tmpnonce,
555  &md5);
556  cvthex (tmpnonce,
557  sizeof (tmpnonce),
558  nonce);
559  cvthex (timestamp,
560  sizeof (timestamp),
561  timestamphex);
562  strncat (nonce,
563  timestamphex,
564  8);
565 }
566 
567 
579 static int
580 test_header (struct MHD_Connection *connection,
581  const char *key,
582  const char *value,
583  enum MHD_ValueKind kind)
584 {
585  struct MHD_HTTP_Header *pos;
586 
587  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
588  {
589  if (kind != pos->kind)
590  continue;
591  if (0 != strcmp (key,
592  pos->header))
593  continue;
594  if ( (NULL == value) &&
595  (NULL == pos->value) )
596  return MHD_YES;
597  if ( (NULL == value) ||
598  (NULL == pos->value) ||
599  (0 != strcmp (value,
600  pos->value)) )
601  continue;
602  return MHD_YES;
603  }
604  return MHD_NO;
605 }
606 
607 
618 static int
620  const char *args)
621 {
622  struct MHD_HTTP_Header *pos;
623  char *argb;
624  unsigned int num_headers;
625  int ret;
626 
627  argb = strdup (args);
628  if (NULL == argb)
629  {
630 #ifdef HAVE_MESSAGES
631  MHD_DLOG (connection->daemon,
632  _("Failed to allocate memory for copy of URI arguments\n"));
633 #endif /* HAVE_MESSAGES */
634  return MHD_NO;
635  }
636  ret = MHD_parse_arguments_ (connection,
638  argb,
639  &test_header,
640  &num_headers);
641  free (argb);
642  if (MHD_YES != ret)
643  return MHD_NO;
644  /* also check that the number of headers matches */
645  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
646  {
647  if (MHD_GET_ARGUMENT_KIND != pos->kind)
648  continue;
649  num_headers--;
650  }
651  if (0 != num_headers)
652  {
653  /* argument count mismatch */
654  return MHD_NO;
655  }
656  return MHD_YES;
657 }
658 
659 
673 int
675  const char *realm,
676  const char *username,
677  const char *password,
678  unsigned int nonce_timeout)
679 {
680  struct MHD_Daemon *daemon = connection->daemon;
681  size_t len;
682  const char *header;
683  char nonce[MAX_NONCE_LENGTH];
684  char cnonce[MAX_NONCE_LENGTH];
685  char qop[15]; /* auth,auth-int */
686  char nc[20];
687  char response[MAX_AUTH_RESPONSE_LENGTH];
688  const char *hentity = NULL; /* "auth-int" is not supported */
689  char ha1[HASH_MD5_HEX_LEN + 1];
690  char respexp[HASH_MD5_HEX_LEN + 1];
691  char noncehashexp[NONCE_STD_LEN + 1];
692  uint32_t nonce_time;
693  uint32_t t;
694  size_t left; /* number of characters left in 'header' for 'uri' */
695  uint64_t nci;
696 
697  header = MHD_lookup_connection_value (connection,
700  if (NULL == header)
701  return MHD_NO;
702  if (0 != strncmp (header,
703  _BASE,
705  return MHD_NO;
706  header += MHD_STATICSTR_LEN_ (_BASE);
707  left = strlen (header);
708 
709  {
710  char un[MAX_USERNAME_LENGTH];
711 
712  len = lookup_sub_value (un,
713  sizeof (un),
714  header,
715  "username");
716  if ( (0 == len) ||
717  (0 != strcmp (username,
718  un)) )
719  return MHD_NO;
720  left -= strlen ("username") + len;
721  }
722 
723  {
724  char r[MAX_REALM_LENGTH];
725 
726  len = lookup_sub_value (r,
727  sizeof (r),
728  header,
729  "realm");
730  if ( (0 == len) ||
731  (0 != strcmp (realm,
732  r)) )
733  return MHD_NO;
734  left -= strlen ("realm") + len;
735  }
736 
737  if (0 == (len = lookup_sub_value (nonce,
738  sizeof (nonce),
739  header,
740  "nonce")))
741  return MHD_NO;
742  left -= strlen ("nonce") + len;
743  if (left > 32 * 1024)
744  {
745  /* we do not permit URIs longer than 32k, as we want to
746  make sure to not blow our stack (or per-connection
747  heap memory limit). Besides, 32k is already insanely
748  large, but of course in theory the
749  #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
750  and would thus permit sending a >32k authorization
751  header value. */
752  return MHD_NO;
753  }
754  if (TIMESTAMP_HEX_LEN !=
757  &nonce_time))
758  {
759 #ifdef HAVE_MESSAGES
760  MHD_DLOG (daemon,
761  _("Authentication failed, invalid timestamp format.\n"));
762 #endif
763  return MHD_NO;
764  }
765  t = (uint32_t) MHD_monotonic_sec_counter();
766  /*
767  * First level vetting for the nonce validity: if the timestamp
768  * attached to the nonce exceeds `nonce_timeout', then the nonce is
769  * invalid.
770  */
771  if ( (t > nonce_time + nonce_timeout) ||
772  (nonce_time + nonce_timeout < nonce_time) )
773  {
774  /* too old */
775  return MHD_INVALID_NONCE;
776  }
777 
778  calculate_nonce (nonce_time,
779  connection->method,
780  daemon->digest_auth_random,
781  daemon->digest_auth_rand_size,
782  connection->url,
783  realm,
784  noncehashexp);
785  /*
786  * Second level vetting for the nonce validity
787  * if the timestamp attached to the nonce is valid
788  * and possibly fabricated (in case of an attack)
789  * the attacker must also know the random seed to be
790  * able to generate a "sane" nonce, which if he does
791  * not, the nonce fabrication process going to be
792  * very hard to achieve.
793  */
794 
795  if (0 != strcmp (nonce, noncehashexp))
796  {
797  return MHD_INVALID_NONCE;
798  }
799  if ( (0 == lookup_sub_value (cnonce,
800  sizeof (cnonce),
801  header,
802  "cnonce")) ||
803  (0 == lookup_sub_value (qop,
804  sizeof (qop),
805  header,
806  "qop")) ||
807  ( (0 != strcmp (qop,
808  "auth")) &&
809  (0 != strcmp (qop,
810  "")) ) ||
811  (0 == (len = lookup_sub_value (nc,
812  sizeof (nc),
813  header,
814  "nc")) ) ||
815  (0 == lookup_sub_value (response,
816  sizeof (response),
817  header,
818  "response")) )
819  {
820 #ifdef HAVE_MESSAGES
821  MHD_DLOG (daemon,
822  _("Authentication failed, invalid format.\n"));
823 #endif
824  return MHD_NO;
825  }
826  if (len != MHD_strx_to_uint64_n_ (nc,
827  len,
828  &nci))
829  {
830 #ifdef HAVE_MESSAGES
831  MHD_DLOG (daemon,
832  _("Authentication failed, invalid nc format.\n"));
833 #endif
834  return MHD_NO; /* invalid nonce format */
835  }
836 
837  /*
838  * Checking if that combination of nonce and nc is sound
839  * and not a replay attack attempt. Also adds the nonce
840  * to the nonce-nc map if it does not exist there.
841  */
842  if (MHD_YES !=
843  check_nonce_nc (connection,
844  nonce,
845  nci))
846  {
847  return MHD_NO;
848  }
849 
850  {
851  char *uri;
852 
853  uri = malloc (left + 1);
854  if (NULL == uri)
855  {
856 #ifdef HAVE_MESSAGES
857  MHD_DLOG(daemon,
858  _("Failed to allocate memory for auth header processing\n"));
859 #endif /* HAVE_MESSAGES */
860  return MHD_NO;
861  }
862  if (0 == lookup_sub_value (uri,
863  left + 1,
864  header,
865  "uri"))
866  {
867  free (uri);
868  return MHD_NO;
869  }
870 
871  digest_calc_ha1 ("md5",
872  username,
873  realm,
874  password,
875  nonce,
876  cnonce,
877  ha1);
879  nonce,
880  nc,
881  cnonce,
882  qop,
883  connection->method,
884  uri,
885  hentity,
886  respexp);
887 
888  /* Need to unescape URI before comparing with connection->url */
889  daemon->unescape_callback (daemon->unescape_callback_cls,
890  connection,
891  uri);
892  if (0 != strncmp (uri,
893  connection->url,
894  strlen (connection->url)))
895  {
896 #ifdef HAVE_MESSAGES
897  MHD_DLOG (daemon,
898  _("Authentication failed, URI does not match.\n"));
899 #endif
900  free (uri);
901  return MHD_NO;
902  }
903 
904  {
905  const char *args = strchr (uri,
906  '?');
907 
908  if (NULL == args)
909  args = "";
910  else
911  args++;
912  if (MHD_YES !=
913  check_argument_match (connection,
914  args) )
915  {
916 #ifdef HAVE_MESSAGES
917  MHD_DLOG (daemon,
918  _("Authentication failed, arguments do not match.\n"));
919 #endif
920  free (uri);
921  return MHD_NO;
922  }
923  }
924  free (uri);
925  return (0 == strcmp(response,
926  respexp))
927  ? MHD_YES
928  : MHD_NO;
929  }
930 }
931 
932 
947 int
949  const char *realm,
950  const char *opaque,
951  struct MHD_Response *response,
952  int signal_stale)
953 {
954  int ret;
955  int hlen;
956  char nonce[NONCE_STD_LEN + 1];
957 
958  /* Generating the server nonce */
960  connection->method,
961  connection->daemon->digest_auth_random,
962  connection->daemon->digest_auth_rand_size,
963  connection->url,
964  realm,
965  nonce);
966  if (MHD_YES !=
967  check_nonce_nc (connection,
968  nonce,
969  0))
970  {
971 #ifdef HAVE_MESSAGES
972  MHD_DLOG (connection->daemon,
973  _("Could not register nonce (is the nonce array size zero?).\n"));
974 #endif
975  return MHD_NO;
976  }
977  /* Building the authentication header */
978  hlen = MHD_snprintf_ (NULL,
979  0,
980  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
981  realm,
982  nonce,
983  opaque,
984  signal_stale
985  ? ",stale=\"true\""
986  : "");
987  if (hlen > 0)
988  {
989  char *header;
990 
991  header = MHD_calloc_ (1, hlen + 1);
992  if (NULL == header)
993  {
994 #ifdef HAVE_MESSAGES
995  MHD_DLOG(connection->daemon,
996  _("Failed to allocate memory for auth response header\n"));
997 #endif /* HAVE_MESSAGES */
998  return MHD_NO;
999  }
1000 
1001  if (MHD_snprintf_ (header,
1002  hlen + 1,
1003  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
1004  realm,
1005  nonce,
1006  opaque,
1007  signal_stale
1008  ? ",stale=\"true\""
1009  : "") == hlen)
1010  ret = MHD_add_response_header(response,
1012  header);
1013  else
1014  ret = MHD_NO;
1015  free (header);
1016  }
1017  else
1018  ret = MHD_NO;
1019 
1020  if (MHD_YES == ret)
1021  {
1022  ret = MHD_queue_response (connection,
1024  response);
1025  }
1026  else
1027  {
1028 #ifdef HAVE_MESSAGES
1029  MHD_DLOG (connection->daemon,
1030  _("Failed to add Digest auth header\n"));
1031 #endif /* HAVE_MESSAGES */
1032  }
1033  return ret;
1034 }
1035 
1036 
1037 /* end of digestauth.c */
#define MAX_NONCE_LENGTH
Definition: internal.h:215
void * unescape_callback_cls
Definition: internal.h:1392
#define MAX_AUTH_RESPONSE_LENGTH
Definition: digestauth.c:66
_MHD_EXTERN const char * MHD_lookup_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key)
Definition: connection.c:794
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
void * data
Definition: microhttpd.h:2661
_MHD_EXTERN 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:286
#define TIMESTAMP_BIN_SIZE
Definition: digestauth.c:42
#define MHD_YES
Definition: microhttpd.h:134
Header for platform missing functions.
#define MHD_INVALID_NONCE
Definition: microhttpd.h:3101
enum MHD_ValueKind kind
Definition: internal.h:280
_MHD_EXTERN 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:674
#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:184
char * value
Definition: internal.h:274
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:359
struct MHD_Daemon * daemon
Definition: internal.h:650
#define MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:177
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:235
#define MHD_STATICSTR_LEN_(macro)
Definition: internal.h:126
size_t MHD_strx_to_uint32_n_(const char *str, size_t maxlen, uint32_t *out_val)
Definition: mhd_str.c:581
#define MHD_HTTP_HEADER_AUTHORIZATION
Definition: microhttpd.h:434
const char * url
Definition: internal.h:703
_MHD_EXTERN 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:948
char * method
Definition: internal.h:697
static int test_header(struct MHD_Connection *connection, const char *key, const char *value, enum MHD_ValueKind kind)
Definition: digestauth.c:580
char nonce[MAX_NONCE_LENGTH]
Definition: internal.h:240
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition: microhttpd.h:512
_MHD_EXTERN char * MHD_digest_auth_get_username(struct MHD_Connection *connection)
Definition: digestauth.c:469
static int check_argument_match(struct MHD_Connection *connection, const char *args)
Definition: digestauth.c:619
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:1517
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:1387
_MHD_EXTERN int MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:3931
internal monotonic clock functions implementations
#define MHD_HTTP_UNAUTHORIZED
Definition: microhttpd.h:330
#define _BASE
Definition: digestauth.c:51
char * header
Definition: internal.h:269
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:508
void MD5Init(struct MD5Context *ctx)
Definition: md5.c:50
uint64_t nc
Definition: internal.h:229
time_t MHD_monotonic_sec_counter(void)
Header for string manipulating helpers.
Definition: md5.h:27
struct MHD_HTTP_Header * next
Definition: internal.h:264
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:329
static int check_nonce_nc(struct MHD_Connection *connection, const char *nonce, uint64_t nc)
Definition: digestauth.c:379
#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:666
struct MHD_HTTP_Header * headers_received
Definition: internal.h:655
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:151