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 <limits.h>
27 #include "internal.h"
28 #include "md5.h"
29 #include "mhd_mono_clock.h"
30 
31 #if defined(_WIN32) && defined(MHD_W32_MUTEX_)
32 #ifndef WIN32_LEAN_AND_MEAN
33 #define WIN32_LEAN_AND_MEAN 1
34 #endif /* !WIN32_LEAN_AND_MEAN */
35 #include <windows.h>
36 #endif /* _WIN32 && MHD_W32_MUTEX_ */
37 
38 #define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
39 /* 32 bit value is 4 bytes */
40 #define TIMESTAMP_BIN_SIZE 4
41 #define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE)
42 
43 /* Standard server nonce length, not including terminating null */
44 #define NONCE_STD_LEN (HASH_MD5_HEX_LEN + TIMESTAMP_HEX_LEN)
45 
49 #define _BASE "Digest "
50 
54 #define MAX_USERNAME_LENGTH 128
55 
59 #define MAX_REALM_LENGTH 256
60 
64 #define MAX_AUTH_RESPONSE_LENGTH 128
65 
66 
74 static void
75 cvthex (const unsigned char *bin,
76  size_t len,
77  char *hex)
78 {
79  size_t i;
80  unsigned int j;
81 
82  for (i = 0; i < len; ++i)
83  {
84  j = (bin[i] >> 4) & 0x0f;
85  hex[i * 2] = (char)((j <= 9) ? (j + '0') : (j - 10 + 'a'));
86  j = bin[i] & 0x0f;
87  hex[i * 2 + 1] = (char)((j <= 9) ? (j + '0') : (j - 10 + 'a'));
88  }
89  hex[len * 2] = '\0';
90 }
91 
92 
105 static void
106 digest_calc_ha1 (const char *alg,
107  const char *username,
108  const char *realm,
109  const char *password,
110  const char *nonce,
111  const char *cnonce,
112  char sessionkey[HASH_MD5_HEX_LEN + 1])
113 {
114  struct MD5Context md5;
115  unsigned char ha1[MD5_DIGEST_SIZE];
116 
117  MD5Init (&md5);
118  MD5Update (&md5, (const unsigned char*)username, strlen (username));
119  MD5Update (&md5, (const unsigned char*)":", 1);
120  MD5Update (&md5, (const unsigned char*)realm, strlen (realm));
121  MD5Update (&md5, (const unsigned char*)":", 1);
122  MD5Update (&md5, (const unsigned char*)password, strlen (password));
123  MD5Final (ha1, &md5);
124  if (MHD_str_equal_caseless_(alg, "md5-sess"))
125  {
126  MD5Init (&md5);
127  MD5Update (&md5, (const unsigned char*)ha1, sizeof (ha1));
128  MD5Update (&md5, (const unsigned char*)":", 1);
129  MD5Update (&md5, (const unsigned char*)nonce, strlen (nonce));
130  MD5Update (&md5, (const unsigned char*)":", 1);
131  MD5Update (&md5, (const unsigned char*)cnonce, strlen (cnonce));
132  MD5Final (ha1, &md5);
133  }
134  cvthex (ha1, sizeof (ha1), sessionkey);
135 }
136 
137 
151 static void
153  const char *nonce,
154  const char *noncecount,
155  const char *cnonce,
156  const char *qop,
157  const char *method,
158  const char *uri,
159  const char *hentity,
160  char response[HASH_MD5_HEX_LEN + 1])
161 {
162  struct MD5Context md5;
163  unsigned char ha2[MD5_DIGEST_SIZE];
164  unsigned char resphash[MD5_DIGEST_SIZE];
165  char ha2hex[HASH_MD5_HEX_LEN + 1];
166 
167  MD5Init (&md5);
168  MD5Update (&md5, (const unsigned char*)method, strlen(method));
169  MD5Update (&md5, (const unsigned char*)":", 1);
170  MD5Update (&md5, (const unsigned char*)uri, strlen(uri));
171 #if 0
172  if (0 == strcasecmp(qop, "auth-int"))
173  {
174  /* This is dead code since the rest of this module does
175  not support auth-int. */
176  MD5Update (&md5, ":", 1);
177  if (NULL != hentity)
178  MD5Update (&md5, hentity, strlen(hentity));
179  }
180 #endif
181  MD5Final (ha2, &md5);
182  cvthex (ha2, MD5_DIGEST_SIZE, ha2hex);
183  MD5Init (&md5);
184  /* calculate response */
185  MD5Update (&md5, (const unsigned char*)ha1, HASH_MD5_HEX_LEN);
186  MD5Update (&md5, (const unsigned char*)":", 1);
187  MD5Update (&md5, (const unsigned char*)nonce, strlen(nonce));
188  MD5Update (&md5, (const unsigned char*)":", 1);
189  if ('\0' != *qop)
190  {
191  MD5Update (&md5, (const unsigned char*)noncecount, strlen(noncecount));
192  MD5Update (&md5, (const unsigned char*)":", 1);
193  MD5Update (&md5, (const unsigned char*)cnonce, strlen(cnonce));
194  MD5Update (&md5, (const unsigned char*)":", 1);
195  MD5Update (&md5, (const unsigned char*)qop, strlen(qop));
196  MD5Update (&md5, (const unsigned char*)":", 1);
197  }
198  MD5Update (&md5, (const unsigned char*)ha2hex, HASH_MD5_HEX_LEN);
199  MD5Final (resphash, &md5);
200  cvthex (resphash, sizeof(resphash), response);
201 }
202 
203 
218 static size_t
219 lookup_sub_value (char *dest,
220  size_t size,
221  const char *data,
222  const char *key)
223 {
224  size_t keylen;
225  size_t len;
226  const char *ptr;
227  const char *eq;
228  const char *q1;
229  const char *q2;
230  const char *qn;
231 
232  if (0 == size)
233  return 0;
234  keylen = strlen (key);
235  ptr = data;
236  while ('\0' != *ptr)
237  {
238  if (NULL == (eq = strchr (ptr, '=')))
239  return 0;
240  q1 = eq + 1;
241  while (' ' == *q1)
242  q1++;
243  if ('\"' != *q1)
244  {
245  q2 = strchr (q1, ',');
246  qn = q2;
247  }
248  else
249  {
250  q1++;
251  q2 = strchr (q1, '\"');
252  if (NULL == q2)
253  return 0; /* end quote not found */
254  qn = q2 + 1;
255  }
256  if ((MHD_str_equal_caseless_n_(ptr,
257  key,
258  keylen)) &&
259  (eq == &ptr[keylen]) )
260  {
261  if (NULL == q2)
262  {
263  len = strlen (q1) + 1;
264  if (size > len)
265  size = len;
266  size--;
267  strncpy (dest,
268  q1,
269  size);
270  dest[size] = '\0';
271  return size;
272  }
273  else
274  {
275  if (size > (size_t) ((q2 - q1) + 1))
276  size = (q2 - q1) + 1;
277  size--;
278  memcpy (dest,
279  q1,
280  size);
281  dest[size] = '\0';
282  return size;
283  }
284  }
285  if (NULL == qn)
286  return 0;
287  ptr = strchr (qn, ',');
288  if (NULL == ptr)
289  return 0;
290  ptr++;
291  while (' ' == *ptr)
292  ptr++;
293  }
294  return 0;
295 }
296 
297 
307 static int
308 check_nonce_nc (struct MHD_Connection *connection,
309  const char *nonce,
310  unsigned long int nc)
311 {
312  uint32_t off;
313  uint32_t mod;
314  const char *np;
315 
316  mod = connection->daemon->nonce_nc_size;
317  if (0 == mod)
318  return MHD_NO; /* no array! */
319  /* super-fast xor-based "hash" function for HT lookup in nonce array */
320  off = 0;
321  np = nonce;
322  while ('\0' != *np)
323  {
324  off = (off << 8) | (*np ^ (off >> 24));
325  np++;
326  }
327  off = off % mod;
328  /*
329  * Look for the nonce, if it does exist and its corresponding
330  * nonce counter is less than the current nonce counter by 1,
331  * then only increase the nonce counter by one.
332  */
333 
334  (void) MHD_mutex_lock_ (&connection->daemon->nnc_lock);
335  if (0 == nc)
336  {
337  strcpy(connection->daemon->nnc[off].nonce,
338  nonce);
339  connection->daemon->nnc[off].nc = 0;
340  (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock);
341  return MHD_YES;
342  }
343  if ( (nc <= connection->daemon->nnc[off].nc) ||
344  (0 != strcmp(connection->daemon->nnc[off].nonce, nonce)) )
345  {
346  (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock);
347 #if HAVE_MESSAGES
348  MHD_DLOG (connection->daemon,
349  "Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n");
350 #endif
351  return MHD_NO;
352  }
353  connection->daemon->nnc[off].nc = nc;
354  (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock);
355  return MHD_YES;
356 }
357 
358 
367 char *
369 {
370  size_t len;
371  char user[MAX_USERNAME_LENGTH];
372  const char *header;
373 
374  if (NULL == (header = MHD_lookup_connection_value (connection,
377  return NULL;
378  if (0 != strncmp (header, _BASE, strlen (_BASE)))
379  return NULL;
380  header += strlen (_BASE);
381  if (0 == (len = lookup_sub_value (user,
382  sizeof (user),
383  header,
384  "username")))
385  return NULL;
386  return strdup (user);
387 }
388 
389 
403 static void
404 calculate_nonce (uint32_t nonce_time,
405  const char *method,
406  const char *rnd,
407  size_t rnd_size,
408  const char *uri,
409  const char *realm,
410  char nonce[NONCE_STD_LEN + 1])
411 {
412  struct MD5Context md5;
413  unsigned char timestamp[TIMESTAMP_BIN_SIZE];
414  unsigned char tmpnonce[MD5_DIGEST_SIZE];
415  char timestamphex[TIMESTAMP_HEX_LEN + 1];
416 
417  MD5Init (&md5);
418  timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18);
419  timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10);
420  timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08);
421  timestamp[3] = (unsigned char)((nonce_time & 0x000000ff));
422  MD5Update (&md5, timestamp, sizeof(timestamp));
423  MD5Update (&md5, (const unsigned char*)":", 1);
424  MD5Update (&md5, (const unsigned char*)method, strlen (method));
425  MD5Update (&md5, (const unsigned char*)":", 1);
426  if (rnd_size > 0)
427  MD5Update (&md5, (const unsigned char*)rnd, rnd_size);
428  MD5Update (&md5, (const unsigned char*)":", 1);
429  MD5Update (&md5, (const unsigned char*)uri, strlen (uri));
430  MD5Update (&md5, (const unsigned char*)":", 1);
431  MD5Update (&md5, (const unsigned char*)realm, strlen (realm));
432  MD5Final (tmpnonce, &md5);
433  cvthex (tmpnonce, sizeof (tmpnonce), nonce);
434  cvthex (timestamp, sizeof(timestamp), timestamphex);
435  strncat (nonce, timestamphex, 8);
436 }
437 
438 
450 static int
451 test_header (struct MHD_Connection *connection,
452  const char *key,
453  const char *value,
454  enum MHD_ValueKind kind)
455 {
456  struct MHD_HTTP_Header *pos;
457 
458  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
459  {
460  if (kind != pos->kind)
461  continue;
462  if (0 != strcmp (key, pos->header))
463  continue;
464  if ( (NULL == value) &&
465  (NULL == pos->value) )
466  return MHD_YES;
467  if ( (NULL == value) ||
468  (NULL == pos->value) ||
469  (0 != strcmp (value, pos->value)) )
470  continue;
471  return MHD_YES;
472  }
473  return MHD_NO;
474 }
475 
476 
487 static int
489  const char *args)
490 {
491  struct MHD_HTTP_Header *pos;
492  char *argb;
493  unsigned int num_headers;
494  int ret;
495 
496  argb = strdup (args);
497  if (NULL == argb)
498  {
499 #if HAVE_MESSAGES
500  MHD_DLOG (connection->daemon,
501  "Failed to allocate memory for copy of URI arguments\n");
502 #endif /* HAVE_MESSAGES */
503  return MHD_NO;
504  }
505  ret = MHD_parse_arguments_ (connection,
507  argb,
508  &test_header,
509  &num_headers);
510  free (argb);
511  if (MHD_YES != ret)
512  return MHD_NO;
513  /* also check that the number of headers matches */
514  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
515  {
516  if (MHD_GET_ARGUMENT_KIND != pos->kind)
517  continue;
518  num_headers--;
519  }
520  if (0 != num_headers)
521  {
522  /* argument count mismatch */
523  return MHD_NO;
524  }
525  return MHD_YES;
526 }
527 
528 
542 int
544  const char *realm,
545  const char *username,
546  const char *password,
547  unsigned int nonce_timeout)
548 {
549  size_t len;
550  const char *header;
551  char *end;
552  char nonce[MAX_NONCE_LENGTH];
553  char cnonce[MAX_NONCE_LENGTH];
554  char qop[15]; /* auth,auth-int */
555  char nc[20];
556  char response[MAX_AUTH_RESPONSE_LENGTH];
557  const char *hentity = NULL; /* "auth-int" is not supported */
558  char ha1[HASH_MD5_HEX_LEN + 1];
559  char respexp[HASH_MD5_HEX_LEN + 1];
560  char noncehashexp[NONCE_STD_LEN + 1];
561  uint32_t nonce_time;
562  uint32_t t;
563  size_t left; /* number of characters left in 'header' for 'uri' */
564  unsigned long int nci;
565 
566  header = MHD_lookup_connection_value (connection,
569  if (NULL == header)
570  return MHD_NO;
571  if (0 != strncmp(header, _BASE, strlen(_BASE)))
572  return MHD_NO;
573  header += strlen (_BASE);
574  left = strlen (header);
575 
576  {
577  char un[MAX_USERNAME_LENGTH];
578 
579  len = lookup_sub_value (un,
580  sizeof (un),
581  header, "username");
582  if ( (0 == len) ||
583  (0 != strcmp(username, un)) )
584  return MHD_NO;
585  left -= strlen ("username") + len;
586  }
587 
588  {
589  char r[MAX_REALM_LENGTH];
590 
591  len = lookup_sub_value (r,
592  sizeof (r),
593  header, "realm");
594  if ( (0 == len) ||
595  (0 != strcmp(realm, r)) )
596  return MHD_NO;
597  left -= strlen ("realm") + len;
598  }
599 
600  if (0 == (len = lookup_sub_value (nonce,
601  sizeof (nonce),
602  header, "nonce")))
603  return MHD_NO;
604  left -= strlen ("nonce") + len;
605  if (left > 32 * 1024)
606  {
607  /* we do not permit URIs longer than 32k, as we want to
608  make sure to not blow our stack (or per-connection
609  heap memory limit). Besides, 32k is already insanely
610  large, but of course in theory the
611  #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
612  and would thus permit sending a >32k authorization
613  header value. */
614  return MHD_NO;
615  }
616  nonce_time = strtoul (nonce + len - TIMESTAMP_HEX_LEN, (char **)NULL, 16);
617  t = (uint32_t) MHD_monotonic_sec_counter();
618  /*
619  * First level vetting for the nonce validity: if the timestamp
620  * attached to the nonce exceeds `nonce_timeout', then the nonce is
621  * invalid.
622  */
623  if ( (t > nonce_time + nonce_timeout) ||
624  (nonce_time + nonce_timeout < nonce_time) )
625  {
626  /* too old */
627  return MHD_INVALID_NONCE;
628  }
629 
630  calculate_nonce (nonce_time,
631  connection->method,
632  connection->daemon->digest_auth_random,
633  connection->daemon->digest_auth_rand_size,
634  connection->url,
635  realm,
636  noncehashexp);
637  /*
638  * Second level vetting for the nonce validity
639  * if the timestamp attached to the nonce is valid
640  * and possibly fabricated (in case of an attack)
641  * the attacker must also know the random seed to be
642  * able to generate a "sane" nonce, which if he does
643  * not, the nonce fabrication process going to be
644  * very hard to achieve.
645  */
646 
647  if (0 != strcmp (nonce, noncehashexp))
648  {
649  return MHD_INVALID_NONCE;
650  }
651  if ( (0 == lookup_sub_value (cnonce,
652  sizeof (cnonce),
653  header, "cnonce")) ||
654  (0 == lookup_sub_value (qop, sizeof (qop), header, "qop")) ||
655  ( (0 != strcmp (qop, "auth")) &&
656  (0 != strcmp (qop, "")) ) ||
657  (0 == lookup_sub_value (nc, sizeof (nc), header, "nc")) ||
658  (0 == lookup_sub_value (response, sizeof (response), header, "response")) )
659  {
660 #if HAVE_MESSAGES
661  MHD_DLOG (connection->daemon,
662  "Authentication failed, invalid format.\n");
663 #endif
664  return MHD_NO;
665  }
666  nci = strtoul (nc, &end, 16);
667  if ( ('\0' != *end) ||
668  ( (LONG_MAX == nci) &&
669  (ERANGE == errno) ) )
670  {
671 #if HAVE_MESSAGES
672  MHD_DLOG (connection->daemon,
673  "Authentication failed, invalid format.\n");
674 #endif
675  return MHD_NO; /* invalid nonce format */
676  }
677  /*
678  * Checking if that combination of nonce and nc is sound
679  * and not a replay attack attempt. Also adds the nonce
680  * to the nonce-nc map if it does not exist there.
681  */
682 
683  if (MHD_YES != check_nonce_nc (connection, nonce, nci))
684  {
685  return MHD_NO;
686  }
687 
688  {
689  char *uri;
690 
691  uri = malloc (left + 1);
692  if (NULL == uri)
693  {
694 #if HAVE_MESSAGES
695  MHD_DLOG(connection->daemon,
696  "Failed to allocate memory for auth header processing\n");
697 #endif /* HAVE_MESSAGES */
698  return MHD_NO;
699  }
700  if (0 == lookup_sub_value (uri,
701  left + 1,
702  header, "uri"))
703  {
704  free (uri);
705  return MHD_NO;
706  }
707 
708  digest_calc_ha1("md5",
709  username,
710  realm,
711  password,
712  nonce,
713  cnonce,
714  ha1);
716  nonce,
717  nc,
718  cnonce,
719  qop,
720  connection->method,
721  uri,
722  hentity,
723  respexp);
724 
725  /* Need to unescape URI before comparing with connection->url */
726  connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
727  connection,
728  uri);
729  if (0 != strncmp (uri,
730  connection->url,
731  strlen (connection->url)))
732  {
733 #if HAVE_MESSAGES
734  MHD_DLOG (connection->daemon,
735  "Authentication failed, URI does not match.\n");
736 #endif
737  free (uri);
738  return MHD_NO;
739  }
740 
741  {
742  const char *args = strchr (uri, '?');
743 
744  if (NULL == args)
745  args = "";
746  else
747  args++;
748  if (MHD_YES !=
749  check_argument_match (connection,
750  args) )
751  {
752 #if HAVE_MESSAGES
753  MHD_DLOG (connection->daemon,
754  "Authentication failed, arguments do not match.\n");
755 #endif
756  free (uri);
757  return MHD_NO;
758  }
759  }
760  free (uri);
761  return (0 == strcmp(response, respexp))
762  ? MHD_YES
763  : MHD_NO;
764  }
765 }
766 
767 
782 int
784  const char *realm,
785  const char *opaque,
786  struct MHD_Response *response,
787  int signal_stale)
788 {
789  int ret;
790  size_t hlen;
791  char nonce[NONCE_STD_LEN + 1];
792 
793  /* Generating the server nonce */
795  connection->method,
796  connection->daemon->digest_auth_random,
797  connection->daemon->digest_auth_rand_size,
798  connection->url,
799  realm,
800  nonce);
801  if (MHD_YES != check_nonce_nc (connection, nonce, 0))
802  {
803 #if HAVE_MESSAGES
804  MHD_DLOG (connection->daemon,
805  "Could not register nonce (is the nonce array size zero?).\n");
806 #endif
807  return MHD_NO;
808  }
809  /* Building the authentication header */
810  hlen = MHD_snprintf_(NULL,
811  0,
812  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
813  realm,
814  nonce,
815  opaque,
816  signal_stale
817  ? ",stale=\"true\""
818  : "");
819  {
820  char *header;
821 
822  header = malloc(hlen + 1);
823  if (NULL == header)
824  {
825 #if HAVE_MESSAGES
826  MHD_DLOG(connection->daemon,
827  "Failed to allocate memory for auth response header\n");
828 #endif /* HAVE_MESSAGES */
829  return MHD_NO;
830  }
831 
832  MHD_snprintf_(header,
833  hlen + 1,
834  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
835  realm,
836  nonce,
837  opaque,
838  signal_stale
839  ? ",stale=\"true\""
840  : "");
841  ret = MHD_add_response_header(response,
843  header);
844  free(header);
845  }
846  if (MHD_YES == ret)
847  ret = MHD_queue_response(connection,
849  response);
850  return ret;
851 }
852 
853 
854 /* end of digestauth.c */
void * unescape_callback_cls
Definition: internal.h:1056
#define MAX_AUTH_RESPONSE_LENGTH
Definition: digestauth.c:64
_MHD_EXTERN const char * MHD_lookup_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key)
Definition: connection.c:219
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:152
void * data
Definition: microhttpd.h:2035
_MHD_EXTERN int MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition: response.c:103
#define NULL
Definition: reason_phrase.c:30
static void cvthex(const unsigned char *bin, size_t len, char *hex)
Definition: digestauth.c:75
static int check_nonce_nc(struct MHD_Connection *connection, const char *nonce, unsigned long int nc)
Definition: digestauth.c:308
static size_t lookup_sub_value(char *dest, size_t size, const char *data, const char *key)
Definition: digestauth.c:219
#define TIMESTAMP_BIN_SIZE
Definition: digestauth.c:40
#define MHD_YES
Definition: microhttpd.h:138
#define MHD_INVALID_NONCE
Definition: microhttpd.h:2476
enum MHD_ValueKind kind
Definition: internal.h:238
_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:543
#define NONCE_STD_LEN
Definition: digestauth.c:44
platform-specific includes for libmicrohttpd
char * value
Definition: internal.h:232
struct MHD_Daemon * daemon
Definition: internal.h:558
#define MHD_str_equal_caseless_(a, b)
void MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len)
Definition: md5.c:67
#define HASH_MD5_HEX_LEN
Definition: digestauth.c:38
int MHD_parse_arguments_(struct MHD_Connection *connection, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers)
Definition: internal.c:189
#define MHD_HTTP_HEADER_AUTHORIZATION
Definition: microhttpd.h:385
_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:783
internal shared structures
char * method
Definition: internal.h:608
static int test_header(struct MHD_Connection *connection, const char *key, const char *value, enum MHD_ValueKind kind)
Definition: digestauth.c:451
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition: microhttpd.h:428
_MHD_EXTERN char * MHD_digest_auth_get_username(struct MHD_Connection *connection)
Definition: digestauth.c:368
#define MAX_NONCE_LENGTH
Definition: internal.h:179
static int check_argument_match(struct MHD_Connection *connection, const char *args)
Definition: digestauth.c:488
#define MHD_snprintf_
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:106
MHD_ValueKind
Definition: microhttpd.h:997
char * url
Definition: internal.h:614
UnescapeCallback unescape_callback
Definition: internal.h:1051
_MHD_EXTERN int MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:2836
internal monotonic clock functions implementations
#define MHD_HTTP_UNAUTHORIZED
Definition: microhttpd.h:311
#define LONG_MAX
Definition: mhd_limits.h:36
#define _BASE
Definition: digestauth.c:49
char * header
Definition: internal.h:227
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:404
void MD5Init(struct MD5Context *ctx)
Definition: md5.c:50
time_t MHD_monotonic_sec_counter(void)
Definition: md5.h:27
struct MHD_HTTP_Header * next
Definition: internal.h:221
#define MD5_DIGEST_SIZE
Definition: md5.h:24
#define MAX_USERNAME_LENGTH
Definition: digestauth.c:54
#define MAX_REALM_LENGTH
Definition: digestauth.c:59
#define MHD_str_equal_caseless_n_(a, b, n)
#define MHD_NO
Definition: microhttpd.h:143
#define TIMESTAMP_HEX_LEN
Definition: digestauth.c:41
struct MHD_HTTP_Header * headers_received
Definition: internal.h:563