Home | History | Annotate | Download | only in microhttpd
      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2010, 2011, 2012 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 */
     19 /**
     20  * @file digestauth.c
     21  * @brief Implements HTTP digest authentication
     22  * @author Amr Ali
     23  * @author Matthieu Speder
     24  */
     25 #include "platform.h"
     26 #include <limits.h>
     27 #include "internal.h"
     28 #include "md5.h"
     29 
     30 #if defined(_WIN32) && defined(MHD_W32_MUTEX_)
     31 #ifndef WIN32_LEAN_AND_MEAN
     32 #define WIN32_LEAN_AND_MEAN 1
     33 #endif /* !WIN32_LEAN_AND_MEAN */
     34 #include <windows.h>
     35 #endif /* _WIN32 && MHD_W32_MUTEX_ */
     36 
     37 #define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
     38 
     39 /**
     40  * Beginning string for any valid Digest authentication header.
     41  */
     42 #define _BASE		"Digest "
     43 
     44 /**
     45  * Maximum length of a username for digest authentication.
     46  */
     47 #define MAX_USERNAME_LENGTH 128
     48 
     49 /**
     50  * Maximum length of a realm for digest authentication.
     51  */
     52 #define MAX_REALM_LENGTH 256
     53 
     54 /**
     55  * Maximum length of the response in digest authentication.
     56  */
     57 #define MAX_AUTH_RESPONSE_LENGTH 128
     58 
     59 
     60 /**
     61  * convert bin to hex
     62  *
     63  * @param bin binary data
     64  * @param len number of bytes in bin
     65  * @param hex pointer to len*2+1 bytes
     66  */
     67 static void
     68 cvthex (const unsigned char *bin,
     69 	size_t len,
     70 	char *hex)
     71 {
     72   size_t i;
     73   unsigned int j;
     74 
     75   for (i = 0; i < len; ++i)
     76     {
     77       j = (bin[i] >> 4) & 0x0f;
     78       hex[i * 2] = j <= 9 ? (j + '0') : (j + 'a' - 10);
     79       j = bin[i] & 0x0f;
     80       hex[i * 2 + 1] = j <= 9 ? (j + '0') : (j + 'a' - 10);
     81     }
     82   hex[len * 2] = '\0';
     83 }
     84 
     85 
     86 /**
     87  * calculate H(A1) as per RFC2617 spec and store the
     88  * result in 'sessionkey'.
     89  *
     90  * @param alg The hash algorithm used, can be "md5" or "md5-sess"
     91  * @param username A `char *' pointer to the username value
     92  * @param realm A `char *' pointer to the realm value
     93  * @param password A `char *' pointer to the password value
     94  * @param nonce A `char *' pointer to the nonce value
     95  * @param cnonce A `char *' pointer to the cnonce value
     96  * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
     97  */
     98 static void
     99 digest_calc_ha1 (const char *alg,
    100 		 const char *username,
    101 		 const char *realm,
    102 		 const char *password,
    103 		 const char *nonce,
    104 		 const char *cnonce,
    105 		 char *sessionkey)
    106 {
    107   struct MD5Context md5;
    108   unsigned char ha1[MD5_DIGEST_SIZE];
    109 
    110   MD5Init (&md5);
    111   MD5Update (&md5, username, strlen (username));
    112   MD5Update (&md5, ":", 1);
    113   MD5Update (&md5, realm, strlen (realm));
    114   MD5Update (&md5, ":", 1);
    115   MD5Update (&md5, password, strlen (password));
    116   MD5Final (ha1, &md5);
    117   if (MHD_str_equal_caseless_(alg, "md5-sess"))
    118     {
    119       MD5Init (&md5);
    120       MD5Update (&md5, ha1, sizeof (ha1));
    121       MD5Update (&md5, ":", 1);
    122       MD5Update (&md5, nonce, strlen (nonce));
    123       MD5Update (&md5, ":", 1);
    124       MD5Update (&md5, cnonce, strlen (cnonce));
    125       MD5Final (ha1, &md5);
    126     }
    127   cvthex (ha1, sizeof (ha1), sessionkey);
    128 }
    129 
    130 
    131 /**
    132  * Calculate request-digest/response-digest as per RFC2617 spec
    133  *
    134  * @param ha1 H(A1)
    135  * @param nonce nonce from server
    136  * @param noncecount 8 hex digits
    137  * @param cnonce client nonce
    138  * @param qop qop-value: "", "auth" or "auth-int"
    139  * @param method method from request
    140  * @param uri requested URL
    141  * @param hentity H(entity body) if qop="auth-int"
    142  * @param response request-digest or response-digest
    143  */
    144 static void
    145 digest_calc_response (const char *ha1,
    146 		      const char *nonce,
    147 		      const char *noncecount,
    148 		      const char *cnonce,
    149 		      const char *qop,
    150 		      const char *method,
    151 		      const char *uri,
    152 		      const char *hentity,
    153 		      char *response)
    154 {
    155   struct MD5Context md5;
    156   unsigned char ha2[MD5_DIGEST_SIZE];
    157   unsigned char resphash[MD5_DIGEST_SIZE];
    158   char ha2hex[HASH_MD5_HEX_LEN + 1];
    159 
    160   MD5Init (&md5);
    161   MD5Update (&md5, method, strlen(method));
    162   MD5Update (&md5, ":", 1);
    163   MD5Update (&md5, uri, strlen(uri));
    164 #if 0
    165   if (0 == strcasecmp(qop, "auth-int"))
    166     {
    167       /* This is dead code since the rest of this module does
    168 	 not support auth-int. */
    169       MD5Update (&md5, ":", 1);
    170       if (NULL != hentity)
    171 	MD5Update (&md5, hentity, strlen(hentity));
    172     }
    173 #endif
    174   MD5Final (ha2, &md5);
    175   cvthex (ha2, MD5_DIGEST_SIZE, ha2hex);
    176   MD5Init (&md5);
    177   /* calculate response */
    178   MD5Update (&md5, ha1, HASH_MD5_HEX_LEN);
    179   MD5Update (&md5, ":", 1);
    180   MD5Update (&md5, nonce, strlen(nonce));
    181   MD5Update (&md5, ":", 1);
    182   if ('\0' != *qop)
    183     {
    184       MD5Update (&md5, noncecount, strlen(noncecount));
    185       MD5Update (&md5, ":", 1);
    186       MD5Update (&md5, cnonce, strlen(cnonce));
    187       MD5Update (&md5, ":", 1);
    188       MD5Update (&md5, qop, strlen(qop));
    189       MD5Update (&md5, ":", 1);
    190     }
    191   MD5Update (&md5, ha2hex, HASH_MD5_HEX_LEN);
    192   MD5Final (resphash, &md5);
    193   cvthex (resphash, sizeof (resphash), response);
    194 }
    195 
    196 
    197 /**
    198  * Lookup subvalue off of the HTTP Authorization header.
    199  *
    200  * A description of the input format for 'data' is at
    201  * http://en.wikipedia.org/wiki/Digest_access_authentication
    202  *
    203  *
    204  * @param dest where to store the result (possibly truncated if
    205  *             the buffer is not big enough).
    206  * @param size size of dest
    207  * @param data pointer to the Authorization header
    208  * @param key key to look up in data
    209  * @return size of the located value, 0 if otherwise
    210  */
    211 static size_t
    212 lookup_sub_value (char *dest,
    213 		  size_t size,
    214 		  const char *data,
    215 		  const char *key)
    216 {
    217   size_t keylen;
    218   size_t len;
    219   const char *ptr;
    220   const char *eq;
    221   const char *q1;
    222   const char *q2;
    223   const char *qn;
    224 
    225   if (0 == size)
    226     return 0;
    227   keylen = strlen (key);
    228   ptr = data;
    229   while ('\0' != *ptr)
    230     {
    231       if (NULL == (eq = strchr (ptr, '=')))
    232 	return 0;
    233       q1 = eq + 1;
    234       while (' ' == *q1)
    235 	q1++;
    236       if ('\"' != *q1)
    237 	{
    238 	  q2 = strchr (q1, ',');
    239 	  qn = q2;
    240 	}
    241       else
    242 	{
    243 	  q1++;
    244 	  q2 = strchr (q1, '\"');
    245 	  if (NULL == q2)
    246 	    return 0; /* end quote not found */
    247 	  qn = q2 + 1;
    248 	}
    249       if ((MHD_str_equal_caseless_n_(ptr,
    250 			      key,
    251 			      keylen)) &&
    252 	   (eq == &ptr[keylen]) )
    253 	{
    254 	  if (NULL == q2)
    255 	    {
    256 	      len = strlen (q1) + 1;
    257 	      if (size > len)
    258 		size = len;
    259 	      size--;
    260 	      strncpy (dest,
    261 		       q1,
    262 		       size);
    263 	      dest[size] = '\0';
    264 	      return size;
    265 	    }
    266 	  else
    267 	    {
    268 	      if (size > (size_t) ((q2 - q1) + 1))
    269 		size = (q2 - q1) + 1;
    270 	      size--;
    271 	      memcpy (dest,
    272 		      q1,
    273 		      size);
    274 	      dest[size] = '\0';
    275 	      return size;
    276 	    }
    277 	}
    278       if (NULL == qn)
    279 	return 0;
    280       ptr = strchr (qn, ',');
    281       if (NULL == ptr)
    282 	return 0;
    283       ptr++;
    284       while (' ' == *ptr)
    285 	ptr++;
    286     }
    287   return 0;
    288 }
    289 
    290 
    291 /**
    292  * Check nonce-nc map array with either new nonce counter
    293  * or a whole new nonce.
    294  *
    295  * @param connection The MHD connection structure
    296  * @param nonce A pointer that referenced a zero-terminated array of nonce
    297  * @param nc The nonce counter, zero to add the nonce to the array
    298  * @return MHD_YES if successful, MHD_NO if invalid (or we have no NC array)
    299  */
    300 static int
    301 check_nonce_nc (struct MHD_Connection *connection,
    302 		const char *nonce,
    303 		unsigned long int nc)
    304 {
    305   uint32_t off;
    306   uint32_t mod;
    307   const char *np;
    308 
    309   mod = connection->daemon->nonce_nc_size;
    310   if (0 == mod)
    311     return MHD_NO; /* no array! */
    312   /* super-fast xor-based "hash" function for HT lookup in nonce array */
    313   off = 0;
    314   np = nonce;
    315   while ('\0' != *np)
    316     {
    317       off = (off << 8) | (*np ^ (off >> 24));
    318       np++;
    319     }
    320   off = off % mod;
    321   /*
    322    * Look for the nonce, if it does exist and its corresponding
    323    * nonce counter is less than the current nonce counter by 1,
    324    * then only increase the nonce counter by one.
    325    */
    326 
    327   (void) MHD_mutex_lock_ (&connection->daemon->nnc_lock);
    328   if (0 == nc)
    329     {
    330       strcpy(connection->daemon->nnc[off].nonce,
    331 	     nonce);
    332       connection->daemon->nnc[off].nc = 0;
    333       (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock);
    334       return MHD_YES;
    335     }
    336   if ( (nc <= connection->daemon->nnc[off].nc) ||
    337        (0 != strcmp(connection->daemon->nnc[off].nonce, nonce)) )
    338     {
    339       (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock);
    340 #if HAVE_MESSAGES
    341       MHD_DLOG (connection->daemon,
    342 		"Stale nonce received.  If this happens a lot, you should probably increase the size of the nonce array.\n");
    343 #endif
    344       return MHD_NO;
    345     }
    346   connection->daemon->nnc[off].nc = nc;
    347   (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock);
    348   return MHD_YES;
    349 }
    350 
    351 
    352 /**
    353  * Get the username from the authorization header sent by the client
    354  *
    355  * @param connection The MHD connection structure
    356  * @return NULL if no username could be found, a pointer
    357  * 			to the username if found
    358  * @ingroup authentication
    359  */
    360 char *
    361 MHD_digest_auth_get_username(struct MHD_Connection *connection)
    362 {
    363   size_t len;
    364   char user[MAX_USERNAME_LENGTH];
    365   const char *header;
    366 
    367   if (NULL == (header = MHD_lookup_connection_value (connection,
    368 						     MHD_HEADER_KIND,
    369 						     MHD_HTTP_HEADER_AUTHORIZATION)))
    370     return NULL;
    371   if (0 != strncmp (header, _BASE, strlen (_BASE)))
    372     return NULL;
    373   header += strlen (_BASE);
    374   if (0 == (len = lookup_sub_value (user,
    375 				    sizeof (user),
    376 				    header,
    377 				    "username")))
    378     return NULL;
    379   return strdup (user);
    380 }
    381 
    382 
    383 /**
    384  * Calculate the server nonce so that it mitigates replay attacks
    385  * The current format of the nonce is ...
    386  * H(timestamp ":" method ":" random ":" uri ":" realm) + Hex(timestamp)
    387  *
    388  * @param nonce_time The amount of time in seconds for a nonce to be invalid
    389  * @param method HTTP method
    390  * @param rnd A pointer to a character array for the random seed
    391  * @param rnd_size The size of the random seed array @a rnd
    392  * @param uri HTTP URI (in MHD, without the arguments ("?k=v")
    393  * @param realm A string of characters that describes the realm of auth.
    394  * @param nonce A pointer to a character array for the nonce to put in
    395  */
    396 static void
    397 calculate_nonce (uint32_t nonce_time,
    398 		 const char *method,
    399 		 const char *rnd,
    400 		 size_t rnd_size,
    401 		 const char *uri,
    402 		 const char *realm,
    403 		 char *nonce)
    404 {
    405   struct MD5Context md5;
    406   unsigned char timestamp[4];
    407   unsigned char tmpnonce[MD5_DIGEST_SIZE];
    408   char timestamphex[sizeof(timestamp) * 2 + 1];
    409 
    410   MD5Init (&md5);
    411   timestamp[0] = (nonce_time & 0xff000000) >> 0x18;
    412   timestamp[1] = (nonce_time & 0x00ff0000) >> 0x10;
    413   timestamp[2] = (nonce_time & 0x0000ff00) >> 0x08;
    414   timestamp[3] = (nonce_time & 0x000000ff);
    415   MD5Update (&md5, timestamp, 4);
    416   MD5Update (&md5, ":", 1);
    417   MD5Update (&md5, method, strlen (method));
    418   MD5Update (&md5, ":", 1);
    419   if (rnd_size > 0)
    420     MD5Update (&md5, rnd, rnd_size);
    421   MD5Update (&md5, ":", 1);
    422   MD5Update (&md5, uri, strlen (uri));
    423   MD5Update (&md5, ":", 1);
    424   MD5Update (&md5, realm, strlen (realm));
    425   MD5Final (tmpnonce, &md5);
    426   cvthex (tmpnonce, sizeof (tmpnonce), nonce);
    427   cvthex (timestamp, 4, timestamphex);
    428   strncat (nonce, timestamphex, 8);
    429 }
    430 
    431 
    432 /**
    433  * Test if the given key-value pair is in the headers for the
    434  * given connection.
    435  *
    436  * @param connection the connection
    437  * @param key the key
    438  * @param value the value, can be NULL
    439  * @return #MHD_YES if the key-value pair is in the headers,
    440  *         #MHD_NO if not
    441  */
    442 static int
    443 test_header (struct MHD_Connection *connection,
    444 	     const char *key,
    445 	     const char *value)
    446 {
    447   struct MHD_HTTP_Header *pos;
    448 
    449   for (pos = connection->headers_received; NULL != pos; pos = pos->next)
    450     {
    451       if (MHD_GET_ARGUMENT_KIND != pos->kind)
    452 	continue;
    453       if (0 != strcmp (key, pos->header))
    454 	continue;
    455       if ( (NULL == value) &&
    456 	   (NULL == pos->value) )
    457 	return MHD_YES;
    458       if ( (NULL == value) ||
    459 	   (NULL == pos->value) ||
    460 	   (0 != strcmp (value, pos->value)) )
    461 	continue;
    462       return MHD_YES;
    463     }
    464   return MHD_NO;
    465 }
    466 
    467 
    468 /**
    469  * Check that the arguments given by the client as part
    470  * of the authentication header match the arguments we
    471  * got as part of the HTTP request URI.
    472  *
    473  * @param connection connections with headers to compare against
    474  * @param args argument URI string (after "?" in URI)
    475  * @return MHD_YES if the arguments match,
    476  *         MHD_NO if not
    477  */
    478 static int
    479 check_argument_match (struct MHD_Connection *connection,
    480 		      const char *args)
    481 {
    482   struct MHD_HTTP_Header *pos;
    483   char *argb;
    484   char *argp;
    485   char *equals;
    486   char *amper;
    487   unsigned int num_headers;
    488 
    489   argb = strdup(args);
    490   if (NULL == argb)
    491   {
    492 #if HAVE_MESSAGES
    493     MHD_DLOG(connection->daemon,
    494              "Failed to allocate memory for copy of URI arguments\n");
    495 #endif /* HAVE_MESSAGES */
    496     return MHD_NO;
    497   }
    498   num_headers = 0;
    499   argp = argb;
    500   while ( (NULL != argp) &&
    501 	  ('\0' != argp[0]) )
    502     {
    503       equals = strchr (argp, '=');
    504       if (NULL == equals)
    505 	{
    506 	  /* add with 'value' NULL */
    507 	  connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
    508 						 connection,
    509 						 argp);
    510 	  if (MHD_YES != test_header (connection, argp, NULL))
    511 	    return MHD_NO;
    512 	  num_headers++;
    513 	  break;
    514 	}
    515       equals[0] = '\0';
    516       equals++;
    517       amper = strchr (equals, '&');
    518       if (NULL != amper)
    519 	{
    520 	  amper[0] = '\0';
    521 	  amper++;
    522 	}
    523       connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
    524 					     connection,
    525 					     argp);
    526       connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
    527 					     connection,
    528 					     equals);
    529       if (! test_header (connection, argp, equals))
    530 	return MHD_NO;
    531       num_headers++;
    532       argp = amper;
    533     }
    534 
    535   /* also check that the number of headers matches */
    536   for (pos = connection->headers_received; NULL != pos; pos = pos->next)
    537     {
    538       if (MHD_GET_ARGUMENT_KIND != pos->kind)
    539 	continue;
    540       num_headers--;
    541     }
    542   if (0 != num_headers)
    543     return MHD_NO;
    544   return MHD_YES;
    545 }
    546 
    547 
    548 /**
    549  * Authenticates the authorization header sent by the client
    550  *
    551  * @param connection The MHD connection structure
    552  * @param realm The realm presented to the client
    553  * @param username The username needs to be authenticated
    554  * @param password The password used in the authentication
    555  * @param nonce_timeout The amount of time for a nonce to be
    556  * 			invalid in seconds
    557  * @return #MHD_YES if authenticated, #MHD_NO if not,
    558  * 			#MHD_INVALID_NONCE if nonce is invalid
    559  * @ingroup authentication
    560  */
    561 int
    562 MHD_digest_auth_check (struct MHD_Connection *connection,
    563 		       const char *realm,
    564 		       const char *username,
    565 		       const char *password,
    566 		       unsigned int nonce_timeout)
    567 {
    568   size_t len;
    569   const char *header;
    570   char *end;
    571   char nonce[MAX_NONCE_LENGTH];
    572   char cnonce[MAX_NONCE_LENGTH];
    573   char qop[15]; /* auth,auth-int */
    574   char nc[20];
    575   char response[MAX_AUTH_RESPONSE_LENGTH];
    576   const char *hentity = NULL; /* "auth-int" is not supported */
    577   char ha1[HASH_MD5_HEX_LEN + 1];
    578   char respexp[HASH_MD5_HEX_LEN + 1];
    579   char noncehashexp[HASH_MD5_HEX_LEN + 9];
    580   uint32_t nonce_time;
    581   uint32_t t;
    582   size_t left; /* number of characters left in 'header' for 'uri' */
    583   unsigned long int nci;
    584 
    585   header = MHD_lookup_connection_value (connection,
    586 					MHD_HEADER_KIND,
    587 					MHD_HTTP_HEADER_AUTHORIZATION);
    588   if (NULL == header)
    589     return MHD_NO;
    590   if (0 != strncmp(header, _BASE, strlen(_BASE)))
    591     return MHD_NO;
    592   header += strlen (_BASE);
    593   left = strlen (header);
    594 
    595   {
    596     char un[MAX_USERNAME_LENGTH];
    597 
    598     len = lookup_sub_value (un,
    599 			    sizeof (un),
    600 			    header, "username");
    601     if ( (0 == len) ||
    602 	 (0 != strcmp(username, un)) )
    603       return MHD_NO;
    604     left -= strlen ("username") + len;
    605   }
    606 
    607   {
    608     char r[MAX_REALM_LENGTH];
    609 
    610     len = lookup_sub_value(r,
    611 			   sizeof (r),
    612 			   header, "realm");
    613     if ( (0 == len) ||
    614 	 (0 != strcmp(realm, r)) )
    615       return MHD_NO;
    616     left -= strlen ("realm") + len;
    617   }
    618 
    619   if (0 == (len = lookup_sub_value (nonce,
    620 				    sizeof (nonce),
    621 				    header, "nonce")))
    622     return MHD_NO;
    623   left -= strlen ("nonce") + len;
    624   if (left > 32 * 1024)
    625   {
    626     /* we do not permit URIs longer than 32k, as we want to
    627        make sure to not blow our stack (or per-connection
    628        heap memory limit).  Besides, 32k is already insanely
    629        large, but of course in theory the
    630        #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
    631        and would thus permit sending a >32k authorization
    632        header value. */
    633     return MHD_NO;
    634   }
    635   {
    636     char *uri;
    637 
    638     uri = malloc(left + 1);
    639     if (NULL == uri)
    640     {
    641 #if HAVE_MESSAGES
    642       MHD_DLOG(connection->daemon,
    643                "Failed to allocate memory for auth header processing\n");
    644 #endif /* HAVE_MESSAGES */
    645       return MHD_NO;
    646     }
    647     if (0 == lookup_sub_value (uri,
    648                                left + 1,
    649                                header, "uri"))
    650     {
    651       free(uri);
    652       return MHD_NO;
    653     }
    654 
    655     /* 8 = 4 hexadecimal numbers for the timestamp */
    656     nonce_time = strtoul (nonce + len - 8, (char **)NULL, 16);
    657     t = (uint32_t) MHD_monotonic_time();
    658     /*
    659      * First level vetting for the nonce validity: if the timestamp
    660      * attached to the nonce exceeds `nonce_timeout', then the nonce is
    661      * invalid.
    662      */
    663     if ( (t > nonce_time + nonce_timeout) ||
    664 	 (nonce_time + nonce_timeout < nonce_time) )
    665     {
    666       free(uri);
    667       return MHD_INVALID_NONCE;
    668     }
    669     if (0 != strncmp (uri,
    670 		      connection->url,
    671 		      strlen (connection->url)))
    672     {
    673 #if HAVE_MESSAGES
    674       MHD_DLOG (connection->daemon,
    675 		"Authentication failed, URI does not match.\n");
    676 #endif
    677       free(uri);
    678       return MHD_NO;
    679     }
    680     {
    681       const char *args = strchr (uri, '?');
    682 
    683       if (NULL == args)
    684 	args = "";
    685       else
    686 	args++;
    687       if (MHD_YES !=
    688 	  check_argument_match (connection,
    689 				args) )
    690       {
    691 #if HAVE_MESSAGES
    692 	MHD_DLOG (connection->daemon,
    693 		  "Authentication failed, arguments do not match.\n");
    694 #endif
    695        free(uri);
    696        return MHD_NO;
    697       }
    698     }
    699     calculate_nonce (nonce_time,
    700 		     connection->method,
    701 		     connection->daemon->digest_auth_random,
    702 		     connection->daemon->digest_auth_rand_size,
    703 		     connection->url,
    704 		     realm,
    705 		     noncehashexp);
    706     /*
    707      * Second level vetting for the nonce validity
    708      * if the timestamp attached to the nonce is valid
    709      * and possibly fabricated (in case of an attack)
    710      * the attacker must also know the random seed to be
    711      * able to generate a "sane" nonce, which if he does
    712      * not, the nonce fabrication process going to be
    713      * very hard to achieve.
    714      */
    715 
    716     if (0 != strcmp (nonce, noncehashexp))
    717     {
    718       free(uri);
    719       return MHD_INVALID_NONCE;
    720     }
    721     if ( (0 == lookup_sub_value (cnonce,
    722 				 sizeof (cnonce),
    723 				 header, "cnonce")) ||
    724 	 (0 == lookup_sub_value (qop, sizeof (qop), header, "qop")) ||
    725 	 ( (0 != strcmp (qop, "auth")) &&
    726 	   (0 != strcmp (qop, "")) ) ||
    727 	 (0 == lookup_sub_value (nc, sizeof (nc), header, "nc"))  ||
    728 	 (0 == lookup_sub_value (response, sizeof (response), header, "response")) )
    729     {
    730 #if HAVE_MESSAGES
    731       MHD_DLOG (connection->daemon,
    732 		"Authentication failed, invalid format.\n");
    733 #endif
    734       free(uri);
    735       return MHD_NO;
    736     }
    737     nci = strtoul (nc, &end, 16);
    738     if ( ('\0' != *end) ||
    739 	 ( (LONG_MAX == nci) &&
    740 	   (ERANGE == errno) ) )
    741     {
    742 #if HAVE_MESSAGES
    743       MHD_DLOG (connection->daemon,
    744 		"Authentication failed, invalid format.\n");
    745 #endif
    746       free(uri);
    747       return MHD_NO; /* invalid nonce format */
    748     }
    749     /*
    750      * Checking if that combination of nonce and nc is sound
    751      * and not a replay attack attempt. Also adds the nonce
    752      * to the nonce-nc map if it does not exist there.
    753      */
    754 
    755     if (MHD_YES != check_nonce_nc (connection, nonce, nci))
    756     {
    757       free(uri);
    758       return MHD_NO;
    759     }
    760 
    761     digest_calc_ha1("md5",
    762 		    username,
    763 		    realm,
    764 		    password,
    765 		    nonce,
    766 		    cnonce,
    767 		    ha1);
    768     digest_calc_response (ha1,
    769 			  nonce,
    770 			  nc,
    771 			  cnonce,
    772 			  qop,
    773 			  connection->method,
    774 			  uri,
    775 			  hentity,
    776 			  respexp);
    777     free(uri);
    778     return (0 == strcmp(response, respexp))
    779       ? MHD_YES
    780       : MHD_NO;
    781   }
    782 }
    783 
    784 
    785 /**
    786  * Queues a response to request authentication from the client
    787  *
    788  * @param connection The MHD connection structure
    789  * @param realm the realm presented to the client
    790  * @param opaque string to user for opaque value
    791  * @param response reply to send; should contain the "access denied"
    792  *        body; note that this function will set the "WWW Authenticate"
    793  *        header and that the caller should not do this
    794  * @param signal_stale #MHD_YES if the nonce is invalid to add
    795  * 			'stale=true' to the authentication header
    796  * @return #MHD_YES on success, #MHD_NO otherwise
    797  * @ingroup authentication
    798  */
    799 int
    800 MHD_queue_auth_fail_response (struct MHD_Connection *connection,
    801 			      const char *realm,
    802 			      const char *opaque,
    803 			      struct MHD_Response *response,
    804 			      int signal_stale)
    805 {
    806   int ret;
    807   size_t hlen;
    808   char nonce[HASH_MD5_HEX_LEN + 9];
    809 
    810   /* Generating the server nonce */
    811   calculate_nonce ((uint32_t) MHD_monotonic_time(),
    812 		   connection->method,
    813 		   connection->daemon->digest_auth_random,
    814 		   connection->daemon->digest_auth_rand_size,
    815 		   connection->url,
    816 		   realm,
    817 		   nonce);
    818   if (MHD_YES != check_nonce_nc (connection, nonce, 0))
    819     {
    820 #if HAVE_MESSAGES
    821       MHD_DLOG (connection->daemon,
    822 		"Could not register nonce (is the nonce array size zero?).\n");
    823 #endif
    824       return MHD_NO;
    825     }
    826   /* Building the authentication header */
    827   hlen = MHD_snprintf_(NULL,
    828 		   0,
    829 		   "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
    830 		   realm,
    831 		   nonce,
    832 		   opaque,
    833 		   signal_stale
    834 		   ? ",stale=\"true\""
    835 		   : "");
    836   {
    837     char *header;
    838 
    839     header = malloc(hlen + 1);
    840     if (NULL == header)
    841     {
    842 #if HAVE_MESSAGES
    843       MHD_DLOG(connection->daemon,
    844                "Failed to allocate memory for auth response header\n");
    845 #endif /* HAVE_MESSAGES */
    846       return MHD_NO;
    847     }
    848 
    849     MHD_snprintf_(header,
    850 	      hlen + 1,
    851 	      "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
    852 	      realm,
    853 	      nonce,
    854 	      opaque,
    855 	      signal_stale
    856 	      ? ",stale=\"true\""
    857 	      : "");
    858     ret = MHD_add_response_header(response,
    859 				  MHD_HTTP_HEADER_WWW_AUTHENTICATE,
    860 				  header);
    861     free(header);
    862   }
    863   if (MHD_YES == ret)
    864     ret = MHD_queue_response(connection,
    865 			     MHD_HTTP_UNAUTHORIZED,
    866 			     response);
    867   return ret;
    868 }
    869 
    870 
    871 /* end of digestauth.c */
    872