|
Packit |
875988 |
/*
|
|
Packit |
875988 |
This file is part of libmicrohttpd
|
|
Packit |
875988 |
Copyright (C) 2010, 2011, 2012, 2015 Daniel Pittman and Christian Grothoff
|
|
Packit |
875988 |
|
|
Packit |
875988 |
This library is free software; you can redistribute it and/or
|
|
Packit |
875988 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
875988 |
License as published by the Free Software Foundation; either
|
|
Packit |
875988 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
875988 |
|
|
Packit |
875988 |
This library is distributed in the hope that it will be useful,
|
|
Packit |
875988 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
875988 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
875988 |
Lesser General Public License for more details.
|
|
Packit |
875988 |
|
|
Packit |
875988 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
875988 |
License along with this library; if not, write to the Free Software
|
|
Packit |
875988 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* @file digestauth.c
|
|
Packit |
875988 |
* @brief Implements HTTP digest authentication
|
|
Packit |
875988 |
* @author Amr Ali
|
|
Packit |
875988 |
* @author Matthieu Speder
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#include "platform.h"
|
|
Packit |
875988 |
#include "mhd_limits.h"
|
|
Packit |
875988 |
#include "internal.h"
|
|
Packit |
875988 |
#include "md5.h"
|
|
Packit |
875988 |
#include "mhd_mono_clock.h"
|
|
Packit |
875988 |
#include "mhd_str.h"
|
|
Packit |
875988 |
#include "mhd_compat.h"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if defined(MHD_W32_MUTEX_)
|
|
Packit |
875988 |
#ifndef WIN32_LEAN_AND_MEAN
|
|
Packit |
875988 |
#define WIN32_LEAN_AND_MEAN 1
|
|
Packit |
875988 |
#endif /* !WIN32_LEAN_AND_MEAN */
|
|
Packit |
875988 |
#include <windows.h>
|
|
Packit |
875988 |
#endif /* MHD_W32_MUTEX_ */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
|
|
Packit |
875988 |
/* 32 bit value is 4 bytes */
|
|
Packit |
875988 |
#define TIMESTAMP_BIN_SIZE 4
|
|
Packit |
875988 |
#define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE)
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Standard server nonce length, not including terminating null */
|
|
Packit |
875988 |
#define NONCE_STD_LEN (HASH_MD5_HEX_LEN + TIMESTAMP_HEX_LEN)
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Beginning string for any valid Digest authentication header.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define _BASE "Digest "
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Maximum length of a username for digest authentication.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define MAX_USERNAME_LENGTH 128
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Maximum length of a realm for digest authentication.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define MAX_REALM_LENGTH 256
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Maximum length of the response in digest authentication.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define MAX_AUTH_RESPONSE_LENGTH 128
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* convert bin to hex
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param bin binary data
|
|
Packit |
875988 |
* @param len number of bytes in bin
|
|
Packit |
875988 |
* @param hex pointer to len*2+1 bytes
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
cvthex (const unsigned char *bin,
|
|
Packit |
875988 |
size_t len,
|
|
Packit |
875988 |
char *hex)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
size_t i;
|
|
Packit |
875988 |
unsigned int j;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
for (i = 0; i < len; ++i)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
j = (bin[i] >> 4) & 0x0f;
|
|
Packit |
875988 |
hex[i * 2] = (char)((j <= 9) ? (j + '0') : (j - 10 + 'a'));
|
|
Packit |
875988 |
j = bin[i] & 0x0f;
|
|
Packit |
875988 |
hex[i * 2 + 1] = (char)((j <= 9) ? (j + '0') : (j - 10 + 'a'));
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
hex[len * 2] = '\0';
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* calculate H(A1) as per RFC2617 spec and store the
|
|
Packit |
875988 |
* result in 'sessionkey'.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param alg The hash algorithm used, can be "md5" or "md5-sess"
|
|
Packit |
875988 |
* @param username A `char *' pointer to the username value
|
|
Packit |
875988 |
* @param realm A `char *' pointer to the realm value
|
|
Packit |
875988 |
* @param password A `char *' pointer to the password value
|
|
Packit |
875988 |
* @param nonce A `char *' pointer to the nonce value
|
|
Packit |
875988 |
* @param cnonce A `char *' pointer to the cnonce value
|
|
Packit |
875988 |
* @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
digest_calc_ha1 (const char *alg,
|
|
Packit |
875988 |
const char *username,
|
|
Packit |
875988 |
const char *realm,
|
|
Packit |
875988 |
const char *password,
|
|
Packit |
875988 |
const char *nonce,
|
|
Packit |
875988 |
const char *cnonce,
|
|
Packit |
875988 |
char sessionkey[HASH_MD5_HEX_LEN + 1])
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MD5Context md5;
|
|
Packit |
875988 |
unsigned char ha1[MD5_DIGEST_SIZE];
|
|
Packit |
875988 |
|
|
Packit |
875988 |
MD5Init (&md5;;
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) username,
|
|
Packit |
875988 |
strlen (username));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) realm,
|
|
Packit |
875988 |
strlen (realm));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) password,
|
|
Packit |
875988 |
strlen (password));
|
|
Packit |
875988 |
MD5Final (ha1,
|
|
Packit |
875988 |
&md5;;
|
|
Packit |
875988 |
if (MHD_str_equal_caseless_(alg,
|
|
Packit |
875988 |
"md5-sess"))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
MD5Init (&md5;;
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ha1,
|
|
Packit |
875988 |
sizeof (ha1));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) nonce,
|
|
Packit |
875988 |
strlen (nonce));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) cnonce,
|
|
Packit |
875988 |
strlen (cnonce));
|
|
Packit |
875988 |
MD5Final (ha1,
|
|
Packit |
875988 |
&md5;;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
cvthex (ha1,
|
|
Packit |
875988 |
sizeof (ha1),
|
|
Packit |
875988 |
sessionkey);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Calculate request-digest/response-digest as per RFC2617 spec
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param ha1 H(A1)
|
|
Packit |
875988 |
* @param nonce nonce from server
|
|
Packit |
875988 |
* @param noncecount 8 hex digits
|
|
Packit |
875988 |
* @param cnonce client nonce
|
|
Packit |
875988 |
* @param qop qop-value: "", "auth" or "auth-int"
|
|
Packit |
875988 |
* @param method method from request
|
|
Packit |
875988 |
* @param uri requested URL
|
|
Packit |
875988 |
* @param hentity H(entity body) if qop="auth-int"
|
|
Packit |
875988 |
* @param response request-digest or response-digest
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1],
|
|
Packit |
875988 |
const char *nonce,
|
|
Packit |
875988 |
const char *noncecount,
|
|
Packit |
875988 |
const char *cnonce,
|
|
Packit |
875988 |
const char *qop,
|
|
Packit |
875988 |
const char *method,
|
|
Packit |
875988 |
const char *uri,
|
|
Packit |
875988 |
const char *hentity,
|
|
Packit |
875988 |
char response[HASH_MD5_HEX_LEN + 1])
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MD5Context md5;
|
|
Packit |
875988 |
unsigned char ha2[MD5_DIGEST_SIZE];
|
|
Packit |
875988 |
unsigned char resphash[MD5_DIGEST_SIZE];
|
|
Packit |
875988 |
char ha2hex[HASH_MD5_HEX_LEN + 1];
|
|
Packit |
875988 |
(void)hentity; /* Unused. Silent compiler warning. */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
MD5Init (&md5;;
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) method,
|
|
Packit |
875988 |
strlen (method));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) uri,
|
|
Packit |
875988 |
strlen (uri));
|
|
Packit |
875988 |
#if 0
|
|
Packit |
875988 |
if (0 == strcasecmp(qop,
|
|
Packit |
875988 |
"auth-int"))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* This is dead code since the rest of this module does
|
|
Packit |
875988 |
not support auth-int. */
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
if (NULL != hentity)
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
hentity,
|
|
Packit |
875988 |
strlen (hentity));
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
MD5Final (ha2,
|
|
Packit |
875988 |
&md5;;
|
|
Packit |
875988 |
cvthex (ha2,
|
|
Packit |
875988 |
MD5_DIGEST_SIZE,
|
|
Packit |
875988 |
ha2hex);
|
|
Packit |
875988 |
MD5Init (&md5;;
|
|
Packit |
875988 |
/* calculate response */
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ha1,
|
|
Packit |
875988 |
HASH_MD5_HEX_LEN);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) nonce,
|
|
Packit |
875988 |
strlen (nonce));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char*) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
if ('\0' != *qop)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) noncecount,
|
|
Packit |
875988 |
strlen (noncecount));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) cnonce,
|
|
Packit |
875988 |
strlen (cnonce));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) qop,
|
|
Packit |
875988 |
strlen (qop));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ha2hex,
|
|
Packit |
875988 |
HASH_MD5_HEX_LEN);
|
|
Packit |
875988 |
MD5Final (resphash,
|
|
Packit |
875988 |
&md5;;
|
|
Packit |
875988 |
cvthex (resphash,
|
|
Packit |
875988 |
sizeof(resphash),
|
|
Packit |
875988 |
response);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Lookup subvalue off of the HTTP Authorization header.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* A description of the input format for 'data' is at
|
|
Packit |
875988 |
* http://en.wikipedia.org/wiki/Digest_access_authentication
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param dest where to store the result (possibly truncated if
|
|
Packit |
875988 |
* the buffer is not big enough).
|
|
Packit |
875988 |
* @param size size of dest
|
|
Packit |
875988 |
* @param data pointer to the Authorization header
|
|
Packit |
875988 |
* @param key key to look up in data
|
|
Packit |
875988 |
* @return size of the located value, 0 if otherwise
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static size_t
|
|
Packit |
875988 |
lookup_sub_value (char *dest,
|
|
Packit |
875988 |
size_t size,
|
|
Packit |
875988 |
const char *data,
|
|
Packit |
875988 |
const char *key)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
size_t keylen;
|
|
Packit |
875988 |
size_t len;
|
|
Packit |
875988 |
const char *ptr;
|
|
Packit |
875988 |
const char *eq;
|
|
Packit |
875988 |
const char *q1;
|
|
Packit |
875988 |
const char *q2;
|
|
Packit |
875988 |
const char *qn;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (0 == size)
|
|
Packit |
875988 |
return 0;
|
|
Packit |
875988 |
keylen = strlen (key);
|
|
Packit |
875988 |
ptr = data;
|
|
Packit |
875988 |
while ('\0' != *ptr)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (NULL == (eq = strchr (ptr,
|
|
Packit |
875988 |
'=')))
|
|
Packit |
875988 |
return 0;
|
|
Packit |
875988 |
q1 = eq + 1;
|
|
Packit |
875988 |
while (' ' == *q1)
|
|
Packit |
875988 |
q1++;
|
|
Packit |
875988 |
if ('\"' != *q1)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
q2 = strchr (q1,
|
|
Packit |
875988 |
',');
|
|
Packit |
875988 |
qn = q2;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
q1++;
|
|
Packit |
875988 |
q2 = strchr (q1,
|
|
Packit |
875988 |
'\"');
|
|
Packit |
875988 |
if (NULL == q2)
|
|
Packit |
875988 |
return 0; /* end quote not found */
|
|
Packit |
875988 |
qn = q2 + 1;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if ( (MHD_str_equal_caseless_n_(ptr,
|
|
Packit |
875988 |
key,
|
|
Packit |
875988 |
keylen)) &&
|
|
Packit |
875988 |
(eq == &ptr[keylen]) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (NULL == q2)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
len = strlen (q1) + 1;
|
|
Packit |
875988 |
if (size > len)
|
|
Packit |
875988 |
size = len;
|
|
Packit |
875988 |
size--;
|
|
Packit |
875988 |
strncpy (dest,
|
|
Packit |
875988 |
q1,
|
|
Packit |
875988 |
size);
|
|
Packit |
875988 |
dest[size] = '\0';
|
|
Packit |
875988 |
return size;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (size > (size_t) ((q2 - q1) + 1))
|
|
Packit |
875988 |
size = (q2 - q1) + 1;
|
|
Packit |
875988 |
size--;
|
|
Packit |
875988 |
memcpy (dest,
|
|
Packit |
875988 |
q1,
|
|
Packit |
875988 |
size);
|
|
Packit |
875988 |
dest[size] = '\0';
|
|
Packit |
875988 |
return size;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (NULL == qn)
|
|
Packit |
875988 |
return 0;
|
|
Packit |
875988 |
ptr = strchr (qn,
|
|
Packit |
875988 |
',');
|
|
Packit |
875988 |
if (NULL == ptr)
|
|
Packit |
875988 |
return 0;
|
|
Packit |
875988 |
ptr++;
|
|
Packit |
875988 |
while (' ' == *ptr)
|
|
Packit |
875988 |
ptr++;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return 0;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Check nonce-nc map array with either new nonce counter
|
|
Packit |
875988 |
* or a whole new nonce.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param connection The MHD connection structure
|
|
Packit |
875988 |
* @param nonce A pointer that referenced a zero-terminated array of nonce
|
|
Packit |
875988 |
* @param nc The nonce counter, zero to add the nonce to the array
|
|
Packit |
875988 |
* @return #MHD_YES if successful, #MHD_NO if invalid (or we have no NC array)
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static int
|
|
Packit |
875988 |
check_nonce_nc (struct MHD_Connection *connection,
|
|
Packit |
875988 |
const char *nonce,
|
|
Packit |
875988 |
uint64_t nc)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Daemon *daemon = connection->daemon;
|
|
Packit |
875988 |
struct MHD_NonceNc *nn;
|
|
Packit |
875988 |
uint32_t off;
|
|
Packit |
875988 |
uint32_t mod;
|
|
Packit |
875988 |
const char *np;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (MAX_NONCE_LENGTH <= strlen (nonce))
|
|
Packit |
875988 |
return MHD_NO; /* This should be impossible, but static analysis
|
|
Packit |
875988 |
tools have a hard time with it *and* this also
|
|
Packit |
875988 |
protects against unsafe modifications that may
|
|
Packit |
875988 |
happen in the future... */
|
|
Packit |
875988 |
mod = daemon->nonce_nc_size;
|
|
Packit |
875988 |
if (0 == mod)
|
|
Packit |
875988 |
return MHD_NO; /* no array! */
|
|
Packit |
875988 |
/* super-fast xor-based "hash" function for HT lookup in nonce array */
|
|
Packit |
875988 |
off = 0;
|
|
Packit |
875988 |
np = nonce;
|
|
Packit |
875988 |
while ('\0' != *np)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
off = (off << 8) | (*np ^ (off >> 24));
|
|
Packit |
875988 |
np++;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
off = off % mod;
|
|
Packit |
875988 |
/*
|
|
Packit |
875988 |
* Look for the nonce, if it does exist and its corresponding
|
|
Packit |
875988 |
* nonce counter is less than the current nonce counter by 1,
|
|
Packit |
875988 |
* then only increase the nonce counter by one.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
nn = &daemon->nnc[off];
|
|
Packit |
875988 |
MHD_mutex_lock_chk_ (&daemon->nnc_lock);
|
|
Packit |
875988 |
if (0 == nc)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* Fresh nonce, reinitialize array */
|
|
Packit |
875988 |
strcpy (nn->nonce,
|
|
Packit |
875988 |
nonce);
|
|
Packit |
875988 |
nn->nc = 0;
|
|
Packit |
875988 |
nn->nmask = 0;
|
|
Packit |
875988 |
MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* Note that we use 64 here, as we do not store the
|
|
Packit |
875988 |
bit for 'nn->nc' itself in 'nn->nmask' */
|
|
Packit |
875988 |
if ( (nc < nn->nc) &&
|
|
Packit |
875988 |
(nc + 64 > nc /* checking for overflow */) &&
|
|
Packit |
875988 |
(nc + 64 >= nn->nc) &&
|
|
Packit |
875988 |
(0 == ((1LLU << (nn->nc - nc - 1)) & nn->nmask)) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* Out-of-order nonce, but within 64-bit bitmask, set bit */
|
|
Packit |
875988 |
nn->nmask |= (1LLU << (nn->nc - nc - 1));
|
|
Packit |
875988 |
MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (nc <= nn->nc) ||
|
|
Packit |
875988 |
(0 != strcmp (nn->nonce,
|
|
Packit |
875988 |
nonce)) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* Nonce does not match, fail */
|
|
Packit |
875988 |
MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* Nonce is larger, shift bitmask and bump limit */
|
|
Packit |
875988 |
if (64 > nc - nn->nc)
|
|
Packit |
875988 |
nn->nmask <<= (nc - nn->nc); /* small jump, less than mask width */
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
nn->nmask = 0; /* big jump, unset all bits in the mask */
|
|
Packit |
875988 |
nn->nc = nc;
|
|
Packit |
875988 |
MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Get the username from the authorization header sent by the client
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param connection The MHD connection structure
|
|
Packit |
875988 |
* @return NULL if no username could be found, a pointer
|
|
Packit |
875988 |
* to the username if found
|
|
Packit |
875988 |
* @warning Returned value must be freed by #MHD_free().
|
|
Packit |
875988 |
* @ingroup authentication
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
char *
|
|
Packit |
875988 |
MHD_digest_auth_get_username(struct MHD_Connection *connection)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
size_t len;
|
|
Packit |
875988 |
char user[MAX_USERNAME_LENGTH];
|
|
Packit |
875988 |
const char *header;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == (header =
|
|
Packit |
875988 |
MHD_lookup_connection_value (connection,
|
|
Packit |
875988 |
MHD_HEADER_KIND,
|
|
Packit |
875988 |
MHD_HTTP_HEADER_AUTHORIZATION)))
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
if (0 != strncmp (header,
|
|
Packit |
875988 |
_BASE,
|
|
Packit |
875988 |
MHD_STATICSTR_LEN_ (_BASE)))
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
header += MHD_STATICSTR_LEN_ (_BASE);
|
|
Packit |
875988 |
if (0 == (len = lookup_sub_value (user,
|
|
Packit |
875988 |
sizeof (user),
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"username")))
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
return strdup (user);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Calculate the server nonce so that it mitigates replay attacks
|
|
Packit |
875988 |
* The current format of the nonce is ...
|
|
Packit |
875988 |
* H(timestamp ":" method ":" random ":" uri ":" realm) + Hex(timestamp)
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param nonce_time The amount of time in seconds for a nonce to be invalid
|
|
Packit |
875988 |
* @param method HTTP method
|
|
Packit |
875988 |
* @param rnd A pointer to a character array for the random seed
|
|
Packit |
875988 |
* @param rnd_size The size of the random seed array @a rnd
|
|
Packit |
875988 |
* @param uri HTTP URI (in MHD, without the arguments ("?k=v")
|
|
Packit |
875988 |
* @param realm A string of characters that describes the realm of auth.
|
|
Packit |
875988 |
* @param nonce A pointer to a character array for the nonce to put in
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
calculate_nonce (uint32_t nonce_time,
|
|
Packit |
875988 |
const char *method,
|
|
Packit |
875988 |
const char *rnd,
|
|
Packit |
875988 |
size_t rnd_size,
|
|
Packit |
875988 |
const char *uri,
|
|
Packit |
875988 |
const char *realm,
|
|
Packit |
875988 |
char nonce[NONCE_STD_LEN + 1])
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MD5Context md5;
|
|
Packit |
875988 |
unsigned char timestamp[TIMESTAMP_BIN_SIZE];
|
|
Packit |
875988 |
unsigned char tmpnonce[MD5_DIGEST_SIZE];
|
|
Packit |
875988 |
char timestamphex[TIMESTAMP_HEX_LEN + 1];
|
|
Packit |
875988 |
|
|
Packit |
875988 |
MD5Init (&md5;;
|
|
Packit |
875988 |
timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18);
|
|
Packit |
875988 |
timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10);
|
|
Packit |
875988 |
timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08);
|
|
Packit |
875988 |
timestamp[3] = (unsigned char)((nonce_time & 0x000000ff));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
timestamp,
|
|
Packit |
875988 |
sizeof (timestamp));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) method,
|
|
Packit |
875988 |
strlen (method));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
if (rnd_size > 0)
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) rnd,
|
|
Packit |
875988 |
rnd_size);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) uri,
|
|
Packit |
875988 |
strlen (uri));
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) ":",
|
|
Packit |
875988 |
1);
|
|
Packit |
875988 |
MD5Update (&md5,
|
|
Packit |
875988 |
(const unsigned char *) realm,
|
|
Packit |
875988 |
strlen (realm));
|
|
Packit |
875988 |
MD5Final (tmpnonce,
|
|
Packit |
875988 |
&md5;;
|
|
Packit |
875988 |
cvthex (tmpnonce,
|
|
Packit |
875988 |
sizeof (tmpnonce),
|
|
Packit |
875988 |
nonce);
|
|
Packit |
875988 |
cvthex (timestamp,
|
|
Packit |
875988 |
sizeof (timestamp),
|
|
Packit |
875988 |
timestamphex);
|
|
Packit |
875988 |
strncat (nonce,
|
|
Packit |
875988 |
timestamphex,
|
|
Packit |
875988 |
8);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Test if the given key-value pair is in the headers for the
|
|
Packit |
875988 |
* given connection.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param connection the connection
|
|
Packit |
875988 |
* @param key the key
|
|
Packit |
875988 |
* @param value the value, can be NULL
|
|
Packit |
875988 |
* @param kind type of the header
|
|
Packit |
875988 |
* @return #MHD_YES if the key-value pair is in the headers,
|
|
Packit |
875988 |
* #MHD_NO if not
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static int
|
|
Packit |
875988 |
test_header (struct MHD_Connection *connection,
|
|
Packit |
875988 |
const char *key,
|
|
Packit |
875988 |
const char *value,
|
|
Packit |
875988 |
enum MHD_ValueKind kind)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_HTTP_Header *pos;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
for (pos = connection->headers_received; NULL != pos; pos = pos->next)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (kind != pos->kind)
|
|
Packit |
875988 |
continue;
|
|
Packit |
875988 |
if (0 != strcmp (key,
|
|
Packit |
875988 |
pos->header))
|
|
Packit |
875988 |
continue;
|
|
Packit |
875988 |
if ( (NULL == value) &&
|
|
Packit |
875988 |
(NULL == pos->value) )
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
if ( (NULL == value) ||
|
|
Packit |
875988 |
(NULL == pos->value) ||
|
|
Packit |
875988 |
(0 != strcmp (value,
|
|
Packit |
875988 |
pos->value)) )
|
|
Packit |
875988 |
continue;
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Check that the arguments given by the client as part
|
|
Packit |
875988 |
* of the authentication header match the arguments we
|
|
Packit |
875988 |
* got as part of the HTTP request URI.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param connection connections with headers to compare against
|
|
Packit |
875988 |
* @param args argument URI string (after "?" in URI)
|
|
Packit |
875988 |
* @return #MHD_YES if the arguments match,
|
|
Packit |
875988 |
* #MHD_NO if not
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static int
|
|
Packit |
875988 |
check_argument_match (struct MHD_Connection *connection,
|
|
Packit |
875988 |
const char *args)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_HTTP_Header *pos;
|
|
Packit |
875988 |
char *argb;
|
|
Packit |
875988 |
unsigned int num_headers;
|
|
Packit |
875988 |
int ret;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
argb = strdup (args);
|
|
Packit |
875988 |
if (NULL == argb)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (connection->daemon,
|
|
Packit |
875988 |
_("Failed to allocate memory for copy of URI arguments\n"));
|
|
Packit |
875988 |
#endif /* HAVE_MESSAGES */
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
ret = MHD_parse_arguments_ (connection,
|
|
Packit |
875988 |
MHD_GET_ARGUMENT_KIND,
|
|
Packit |
875988 |
argb,
|
|
Packit |
875988 |
&test_header,
|
|
Packit |
875988 |
&num_headers);
|
|
Packit |
875988 |
free (argb);
|
|
Packit |
875988 |
if (MHD_YES != ret)
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
/* also check that the number of headers matches */
|
|
Packit |
875988 |
for (pos = connection->headers_received; NULL != pos; pos = pos->next)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (MHD_GET_ARGUMENT_KIND != pos->kind)
|
|
Packit |
875988 |
continue;
|
|
Packit |
875988 |
num_headers--;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (0 != num_headers)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* argument count mismatch */
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Authenticates the authorization header sent by the client
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param connection The MHD connection structure
|
|
Packit |
875988 |
* @param realm The realm presented to the client
|
|
Packit |
875988 |
* @param username The username needs to be authenticated
|
|
Packit |
875988 |
* @param password The password used in the authentication
|
|
Packit |
875988 |
* @param nonce_timeout The amount of time for a nonce to be
|
|
Packit |
875988 |
* invalid in seconds
|
|
Packit |
875988 |
* @return #MHD_YES if authenticated, #MHD_NO if not,
|
|
Packit |
875988 |
* #MHD_INVALID_NONCE if nonce is invalid
|
|
Packit |
875988 |
* @ingroup authentication
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
MHD_digest_auth_check (struct MHD_Connection *connection,
|
|
Packit |
875988 |
const char *realm,
|
|
Packit |
875988 |
const char *username,
|
|
Packit |
875988 |
const char *password,
|
|
Packit |
875988 |
unsigned int nonce_timeout)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Daemon *daemon = connection->daemon;
|
|
Packit |
875988 |
size_t len;
|
|
Packit |
875988 |
const char *header;
|
|
Packit |
875988 |
char nonce[MAX_NONCE_LENGTH];
|
|
Packit |
875988 |
char cnonce[MAX_NONCE_LENGTH];
|
|
Packit |
875988 |
char qop[15]; /* auth,auth-int */
|
|
Packit |
875988 |
char nc[20];
|
|
Packit |
875988 |
char response[MAX_AUTH_RESPONSE_LENGTH];
|
|
Packit |
875988 |
const char *hentity = NULL; /* "auth-int" is not supported */
|
|
Packit |
875988 |
char ha1[HASH_MD5_HEX_LEN + 1];
|
|
Packit |
875988 |
char respexp[HASH_MD5_HEX_LEN + 1];
|
|
Packit |
875988 |
char noncehashexp[NONCE_STD_LEN + 1];
|
|
Packit |
875988 |
uint32_t nonce_time;
|
|
Packit |
875988 |
uint32_t t;
|
|
Packit |
875988 |
size_t left; /* number of characters left in 'header' for 'uri' */
|
|
Packit |
875988 |
uint64_t nci;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
header = MHD_lookup_connection_value (connection,
|
|
Packit |
875988 |
MHD_HEADER_KIND,
|
|
Packit |
875988 |
MHD_HTTP_HEADER_AUTHORIZATION);
|
|
Packit |
875988 |
if (NULL == header)
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
if (0 != strncmp (header,
|
|
Packit |
875988 |
_BASE,
|
|
Packit |
875988 |
MHD_STATICSTR_LEN_(_BASE)))
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
header += MHD_STATICSTR_LEN_ (_BASE);
|
|
Packit |
875988 |
left = strlen (header);
|
|
Packit |
875988 |
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
char un[MAX_USERNAME_LENGTH];
|
|
Packit |
875988 |
|
|
Packit |
875988 |
len = lookup_sub_value (un,
|
|
Packit |
875988 |
sizeof (un),
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"username");
|
|
Packit |
875988 |
if ( (0 == len) ||
|
|
Packit |
875988 |
(0 != strcmp (username,
|
|
Packit |
875988 |
un)) )
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
left -= strlen ("username") + len;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
char r[MAX_REALM_LENGTH];
|
|
Packit |
875988 |
|
|
Packit |
875988 |
len = lookup_sub_value (r,
|
|
Packit |
875988 |
sizeof (r),
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"realm");
|
|
Packit |
875988 |
if ( (0 == len) ||
|
|
Packit |
875988 |
(0 != strcmp (realm,
|
|
Packit |
875988 |
r)) )
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
left -= strlen ("realm") + len;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (0 == (len = lookup_sub_value (nonce,
|
|
Packit |
875988 |
sizeof (nonce),
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"nonce")))
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
left -= strlen ("nonce") + len;
|
|
Packit |
875988 |
if (left > 32 * 1024)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* we do not permit URIs longer than 32k, as we want to
|
|
Packit |
875988 |
make sure to not blow our stack (or per-connection
|
|
Packit |
875988 |
heap memory limit). Besides, 32k is already insanely
|
|
Packit |
875988 |
large, but of course in theory the
|
|
Packit |
875988 |
#MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
|
|
Packit |
875988 |
and would thus permit sending a >32k authorization
|
|
Packit |
875988 |
header value. */
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (TIMESTAMP_HEX_LEN !=
|
|
Packit |
875988 |
MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_HEX_LEN,
|
|
Packit |
875988 |
TIMESTAMP_HEX_LEN,
|
|
Packit |
875988 |
&nonce_time))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Authentication failed, invalid timestamp format.\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
t = (uint32_t) MHD_monotonic_sec_counter();
|
|
Packit |
875988 |
/*
|
|
Packit |
875988 |
* First level vetting for the nonce validity: if the timestamp
|
|
Packit |
875988 |
* attached to the nonce exceeds `nonce_timeout', then the nonce is
|
|
Packit |
875988 |
* invalid.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
if ( (t > nonce_time + nonce_timeout) ||
|
|
Packit |
875988 |
(nonce_time + nonce_timeout < nonce_time) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* too old */
|
|
Packit |
875988 |
return MHD_INVALID_NONCE;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
calculate_nonce (nonce_time,
|
|
Packit |
875988 |
connection->method,
|
|
Packit |
875988 |
daemon->digest_auth_random,
|
|
Packit |
875988 |
daemon->digest_auth_rand_size,
|
|
Packit |
875988 |
connection->url,
|
|
Packit |
875988 |
realm,
|
|
Packit |
875988 |
noncehashexp);
|
|
Packit |
875988 |
/*
|
|
Packit |
875988 |
* Second level vetting for the nonce validity
|
|
Packit |
875988 |
* if the timestamp attached to the nonce is valid
|
|
Packit |
875988 |
* and possibly fabricated (in case of an attack)
|
|
Packit |
875988 |
* the attacker must also know the random seed to be
|
|
Packit |
875988 |
* able to generate a "sane" nonce, which if he does
|
|
Packit |
875988 |
* not, the nonce fabrication process going to be
|
|
Packit |
875988 |
* very hard to achieve.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (0 != strcmp (nonce, noncehashexp))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return MHD_INVALID_NONCE;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if ( (0 == lookup_sub_value (cnonce,
|
|
Packit |
875988 |
sizeof (cnonce),
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"cnonce")) ||
|
|
Packit |
875988 |
(0 == lookup_sub_value (qop,
|
|
Packit |
875988 |
sizeof (qop),
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"qop")) ||
|
|
Packit |
875988 |
( (0 != strcmp (qop,
|
|
Packit |
875988 |
"auth")) &&
|
|
Packit |
875988 |
(0 != strcmp (qop,
|
|
Packit |
875988 |
"")) ) ||
|
|
Packit |
875988 |
(0 == (len = lookup_sub_value (nc,
|
|
Packit |
875988 |
sizeof (nc),
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"nc")) ) ||
|
|
Packit |
875988 |
(0 == lookup_sub_value (response,
|
|
Packit |
875988 |
sizeof (response),
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"response")) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Authentication failed, invalid format.\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (len != MHD_strx_to_uint64_n_ (nc,
|
|
Packit |
875988 |
len,
|
|
Packit |
875988 |
&nci))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Authentication failed, invalid nc format.\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
return MHD_NO; /* invalid nonce format */
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/*
|
|
Packit |
875988 |
* Checking if that combination of nonce and nc is sound
|
|
Packit |
875988 |
* and not a replay attack attempt. Also adds the nonce
|
|
Packit |
875988 |
* to the nonce-nc map if it does not exist there.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
if (MHD_YES !=
|
|
Packit |
875988 |
check_nonce_nc (connection,
|
|
Packit |
875988 |
nonce,
|
|
Packit |
875988 |
nci))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
char *uri;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
uri = malloc (left + 1);
|
|
Packit |
875988 |
if (NULL == uri)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG(daemon,
|
|
Packit |
875988 |
_("Failed to allocate memory for auth header processing\n"));
|
|
Packit |
875988 |
#endif /* HAVE_MESSAGES */
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (0 == lookup_sub_value (uri,
|
|
Packit |
875988 |
left + 1,
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
"uri"))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (uri);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
digest_calc_ha1 ("md5",
|
|
Packit |
875988 |
username,
|
|
Packit |
875988 |
realm,
|
|
Packit |
875988 |
password,
|
|
Packit |
875988 |
nonce,
|
|
Packit |
875988 |
cnonce,
|
|
Packit |
875988 |
ha1);
|
|
Packit |
875988 |
digest_calc_response (ha1,
|
|
Packit |
875988 |
nonce,
|
|
Packit |
875988 |
nc,
|
|
Packit |
875988 |
cnonce,
|
|
Packit |
875988 |
qop,
|
|
Packit |
875988 |
connection->method,
|
|
Packit |
875988 |
uri,
|
|
Packit |
875988 |
hentity,
|
|
Packit |
875988 |
respexp);
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Need to unescape URI before comparing with connection->url */
|
|
Packit |
875988 |
daemon->unescape_callback (daemon->unescape_callback_cls,
|
|
Packit |
875988 |
connection,
|
|
Packit |
875988 |
uri);
|
|
Packit |
875988 |
if (0 != strncmp (uri,
|
|
Packit |
875988 |
connection->url,
|
|
Packit |
875988 |
strlen (connection->url)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Authentication failed, URI does not match.\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
free (uri);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
const char *args = strchr (uri,
|
|
Packit |
875988 |
'?');
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == args)
|
|
Packit |
875988 |
args = "";
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
args++;
|
|
Packit |
875988 |
if (MHD_YES !=
|
|
Packit |
875988 |
check_argument_match (connection,
|
|
Packit |
875988 |
args) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Authentication failed, arguments do not match.\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
free (uri);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
free (uri);
|
|
Packit |
875988 |
return (0 == strcmp(response,
|
|
Packit |
875988 |
respexp))
|
|
Packit |
875988 |
? MHD_YES
|
|
Packit |
875988 |
: MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Queues a response to request authentication from the client
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param connection The MHD connection structure
|
|
Packit |
875988 |
* @param realm the realm presented to the client
|
|
Packit |
875988 |
* @param opaque string to user for opaque value
|
|
Packit |
875988 |
* @param response reply to send; should contain the "access denied"
|
|
Packit |
875988 |
* body; note that this function will set the "WWW Authenticate"
|
|
Packit |
875988 |
* header and that the caller should not do this
|
|
Packit |
875988 |
* @param signal_stale #MHD_YES if the nonce is invalid to add
|
|
Packit |
875988 |
* 'stale=true' to the authentication header
|
|
Packit |
875988 |
* @return #MHD_YES on success, #MHD_NO otherwise
|
|
Packit |
875988 |
* @ingroup authentication
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
MHD_queue_auth_fail_response (struct MHD_Connection *connection,
|
|
Packit |
875988 |
const char *realm,
|
|
Packit |
875988 |
const char *opaque,
|
|
Packit |
875988 |
struct MHD_Response *response,
|
|
Packit |
875988 |
int signal_stale)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
int ret;
|
|
Packit |
875988 |
int hlen;
|
|
Packit |
875988 |
char nonce[NONCE_STD_LEN + 1];
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Generating the server nonce */
|
|
Packit |
875988 |
calculate_nonce ((uint32_t) MHD_monotonic_sec_counter(),
|
|
Packit |
875988 |
connection->method,
|
|
Packit |
875988 |
connection->daemon->digest_auth_random,
|
|
Packit |
875988 |
connection->daemon->digest_auth_rand_size,
|
|
Packit |
875988 |
connection->url,
|
|
Packit |
875988 |
realm,
|
|
Packit |
875988 |
nonce);
|
|
Packit |
875988 |
if (MHD_YES !=
|
|
Packit |
875988 |
check_nonce_nc (connection,
|
|
Packit |
875988 |
nonce,
|
|
Packit |
875988 |
0))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (connection->daemon,
|
|
Packit |
875988 |
_("Could not register nonce (is the nonce array size zero?).\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* Building the authentication header */
|
|
Packit |
875988 |
hlen = MHD_snprintf_ (NULL,
|
|
Packit |
875988 |
0,
|
|
Packit |
875988 |
"Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
|
|
Packit |
875988 |
realm,
|
|
Packit |
875988 |
nonce,
|
|
Packit |
875988 |
opaque,
|
|
Packit |
875988 |
signal_stale
|
|
Packit |
875988 |
? ",stale=\"true\""
|
|
Packit |
875988 |
: "");
|
|
Packit |
875988 |
if (hlen > 0)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
char *header;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
header = MHD_calloc_ (1, hlen + 1);
|
|
Packit |
875988 |
if (NULL == header)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG(connection->daemon,
|
|
Packit |
875988 |
_("Failed to allocate memory for auth response header\n"));
|
|
Packit |
875988 |
#endif /* HAVE_MESSAGES */
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (MHD_snprintf_ (header,
|
|
Packit |
875988 |
hlen + 1,
|
|
Packit |
875988 |
"Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
|
|
Packit |
875988 |
realm,
|
|
Packit |
875988 |
nonce,
|
|
Packit |
875988 |
opaque,
|
|
Packit |
875988 |
signal_stale
|
|
Packit |
875988 |
? ",stale=\"true\""
|
|
Packit |
875988 |
: "") == hlen)
|
|
Packit |
875988 |
ret = MHD_add_response_header(response,
|
|
Packit |
875988 |
MHD_HTTP_HEADER_WWW_AUTHENTICATE,
|
|
Packit |
875988 |
header);
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
ret = MHD_NO;
|
|
Packit |
875988 |
free (header);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
ret = MHD_NO;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (MHD_YES == ret)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
ret = MHD_queue_response (connection,
|
|
Packit |
875988 |
MHD_HTTP_UNAUTHORIZED,
|
|
Packit |
875988 |
response);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (connection->daemon,
|
|
Packit |
875988 |
_("Failed to add Digest auth header\n"));
|
|
Packit |
875988 |
#endif /* HAVE_MESSAGES */
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return ret;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* end of digestauth.c */
|