mirror of
https://github.com/lammertb/libhttp.git
synced 2025-12-22 04:02:04 +03:00
Use 64 bit random number nonce in http digest auth
This commit is contained in:
124
src/civetweb.c
124
src/civetweb.c
@@ -149,12 +149,12 @@ clock_gettime(int clk_id, struct timespec *t)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} else if (clk_id == CLOCK_MONOTONIC) {
|
} else if (clk_id == CLOCK_MONOTONIC) {
|
||||||
static uint64_t start_time = 0;
|
static uint64_t clock_start_time = 0;
|
||||||
static mach_timebase_info_data_t timebase_ifo = {0, 0};
|
static mach_timebase_info_data_t timebase_ifo = {0, 0};
|
||||||
|
|
||||||
uint64_t now = mach_absolute_time();
|
uint64_t now = mach_absolute_time();
|
||||||
|
|
||||||
if (start_time == 0) {
|
if (clock_start_time == 0) {
|
||||||
kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
|
kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
assert(mach_status == KERN_SUCCESS);
|
assert(mach_status == KERN_SUCCESS);
|
||||||
@@ -162,10 +162,11 @@ clock_gettime(int clk_id, struct timespec *t)
|
|||||||
/* appease "unused variable" warning for release builds */
|
/* appease "unused variable" warning for release builds */
|
||||||
(void)mach_status;
|
(void)mach_status;
|
||||||
#endif
|
#endif
|
||||||
start_time = now;
|
clock_start_time = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
now = (uint64_t)((double)(now - start_time) * (double)timebase_ifo.numer
|
now = (uint64_t)((double)(now - clock_start_time)
|
||||||
|
* (double)timebase_ifo.numer
|
||||||
/ (double)timebase_ifo.denom);
|
/ (double)timebase_ifo.denom);
|
||||||
|
|
||||||
t->tv_sec = now / 1000000000;
|
t->tv_sec = now / 1000000000;
|
||||||
@@ -270,6 +271,7 @@ typedef long off_t;
|
|||||||
#endif /* !EWOULDBLOCK */
|
#endif /* !EWOULDBLOCK */
|
||||||
#define _POSIX_
|
#define _POSIX_
|
||||||
#define INT64_FMT "I64d"
|
#define INT64_FMT "I64d"
|
||||||
|
#define UINT64_FMT "I64u"
|
||||||
|
|
||||||
#define WINCDECL __cdecl
|
#define WINCDECL __cdecl
|
||||||
#define SHUT_RD (0)
|
#define SHUT_RD (0)
|
||||||
@@ -426,6 +428,7 @@ typedef unsigned short int in_port_t;
|
|||||||
#define ERRNO (errno)
|
#define ERRNO (errno)
|
||||||
#define INVALID_SOCKET (-1)
|
#define INVALID_SOCKET (-1)
|
||||||
#define INT64_FMT PRId64
|
#define INT64_FMT PRId64
|
||||||
|
#define UINT64_FMT PRIu64
|
||||||
typedef int SOCKET;
|
typedef int SOCKET;
|
||||||
#define WINCDECL
|
#define WINCDECL
|
||||||
|
|
||||||
@@ -1160,7 +1163,8 @@ struct mg_context {
|
|||||||
cfg_worker_threads; /* The number of configured worker threads. */
|
cfg_worker_threads; /* The number of configured worker threads. */
|
||||||
pthread_t *workerthreadids; /* The worker thread IDs */
|
pthread_t *workerthreadids; /* The worker thread IDs */
|
||||||
|
|
||||||
unsigned long start_time; /* Server start time, used for authentication */
|
time_t start_time; /* Server start time, used for authentication */
|
||||||
|
uint64_t auth_nonce_mask; /* Mask for all nonce values */
|
||||||
pthread_mutex_t nonce_mutex; /* Protects nonce_count */
|
pthread_mutex_t nonce_mutex; /* Protects nonce_count */
|
||||||
unsigned long nonce_count; /* Used nonces, used for authentication */
|
unsigned long nonce_count; /* Used nonces, used for authentication */
|
||||||
|
|
||||||
@@ -1556,6 +1560,7 @@ mg_vsnprintf(const struct mg_connection *conn,
|
|||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mg_snprintf(const struct mg_connection *conn,
|
mg_snprintf(const struct mg_connection *conn,
|
||||||
int *truncated,
|
int *truncated,
|
||||||
@@ -1572,39 +1577,6 @@ mg_snprintf(const struct mg_connection *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int64_t
|
|
||||||
get_random(void)
|
|
||||||
{
|
|
||||||
static uint64_t lfsr = 0; /* Linear feedback shift register */
|
|
||||||
static uint64_t lcg = 0; /* Linear congruential generator */
|
|
||||||
struct timespec now;
|
|
||||||
|
|
||||||
memset(&now, 0, sizeof(now));
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
||||||
|
|
||||||
if (lfsr == 0) {
|
|
||||||
/* lfsr will be only 0 if has not been initialized,
|
|
||||||
* so this code is called only once. */
|
|
||||||
lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec)
|
|
||||||
^ ((uint64_t)(ptrdiff_t)&now) ^ ((uint64_t)pthread_self())
|
|
||||||
^ (((uint64_t)time(NULL)) << 33);
|
|
||||||
lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
|
|
||||||
+ (uint64_t)(ptrdiff_t)&now;
|
|
||||||
} else {
|
|
||||||
/* Get the next step of both random number generators. */
|
|
||||||
lfsr = (lfsr >> 1)
|
|
||||||
| ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
|
|
||||||
<< 63);
|
|
||||||
lcg = lcg * 6364136223846793005 + 1442695040888963407;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Combining two pseudo-random number generators and a high resolution part
|
|
||||||
* of the current server time will make it hard (impossible?) to guess the
|
|
||||||
* next number. */
|
|
||||||
return (lfsr ^ lcg ^ now.tv_nsec);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_option_index(const char *name)
|
get_option_index(const char *name)
|
||||||
{
|
{
|
||||||
@@ -1618,6 +1590,7 @@ get_option_index(const char *name)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
mg_get_option(const struct mg_context *ctx, const char *name)
|
mg_get_option(const struct mg_context *ctx, const char *name)
|
||||||
{
|
{
|
||||||
@@ -1631,18 +1604,21 @@ mg_get_option(const struct mg_context *ctx, const char *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct mg_context *
|
struct mg_context *
|
||||||
mg_get_context(const struct mg_connection *conn)
|
mg_get_context(const struct mg_connection *conn)
|
||||||
{
|
{
|
||||||
return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
|
return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
mg_get_user_data(const struct mg_context *ctx)
|
mg_get_user_data(const struct mg_context *ctx)
|
||||||
{
|
{
|
||||||
return (ctx == NULL) ? NULL : ctx->user_data;
|
return (ctx == NULL) ? NULL : ctx->user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
mg_set_user_connection_data(const struct mg_connection *conn, void *data)
|
mg_set_user_connection_data(const struct mg_connection *conn, void *data)
|
||||||
{
|
{
|
||||||
@@ -1651,6 +1627,7 @@ mg_set_user_connection_data(const struct mg_connection *conn, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
mg_get_user_connection_data(const struct mg_connection *conn)
|
mg_get_user_connection_data(const struct mg_connection *conn)
|
||||||
{
|
{
|
||||||
@@ -1660,6 +1637,7 @@ mg_get_user_connection_data(const struct mg_connection *conn)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
|
mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
|
||||||
{
|
{
|
||||||
@@ -1674,6 +1652,7 @@ mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
mg_get_server_ports(const struct mg_context *ctx,
|
mg_get_server_ports(const struct mg_context *ctx,
|
||||||
int size,
|
int size,
|
||||||
@@ -1712,6 +1691,7 @@ mg_get_server_ports(const struct mg_context *ctx,
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sockaddr_to_string(char *buf, size_t len, const union usa *usa)
|
sockaddr_to_string(char *buf, size_t len, const union usa *usa)
|
||||||
{
|
{
|
||||||
@@ -1743,6 +1723,7 @@ sockaddr_to_string(char *buf, size_t len, const union usa *usa)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
|
/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
|
||||||
* included in all responses other than 100, 101, 5xx. */
|
* included in all responses other than 100, 101, 5xx. */
|
||||||
static void
|
static void
|
||||||
@@ -1759,6 +1740,7 @@ gmt_time_string(char *buf, size_t buf_len, time_t *t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* difftime for struct timespec. Return value is in seconds. */
|
/* difftime for struct timespec. Return value is in seconds. */
|
||||||
static double
|
static double
|
||||||
mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
|
mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
|
||||||
@@ -1767,6 +1749,7 @@ mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
|
|||||||
+ (double)(ts_now->tv_sec - ts_before->tv_sec);
|
+ (double)(ts_now->tv_sec - ts_before->tv_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Print error message to the opened error log stream. */
|
/* Print error message to the opened error log stream. */
|
||||||
void
|
void
|
||||||
mg_cry(const struct mg_connection *conn, const char *fmt, ...)
|
mg_cry(const struct mg_connection *conn, const char *fmt, ...)
|
||||||
@@ -1815,6 +1798,7 @@ mg_cry(const struct mg_connection *conn, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return fake connection structure. Used for logging, if connection
|
/* Return fake connection structure. Used for logging, if connection
|
||||||
* is not applicable at the moment of logging. */
|
* is not applicable at the moment of logging. */
|
||||||
static struct mg_connection *
|
static struct mg_connection *
|
||||||
@@ -1825,12 +1809,14 @@ fc(struct mg_context *ctx)
|
|||||||
return &fake_connection;
|
return &fake_connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
mg_version(void)
|
mg_version(void)
|
||||||
{
|
{
|
||||||
return CIVETWEB_VERSION;
|
return CIVETWEB_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const struct mg_request_info *
|
const struct mg_request_info *
|
||||||
mg_get_request_info(const struct mg_connection *conn)
|
mg_get_request_info(const struct mg_connection *conn)
|
||||||
{
|
{
|
||||||
@@ -1840,6 +1826,7 @@ mg_get_request_info(const struct mg_connection *conn)
|
|||||||
return &conn->request_info;
|
return &conn->request_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Skip the characters until one of the delimiters characters found.
|
/* Skip the characters until one of the delimiters characters found.
|
||||||
* 0-terminate resulting word. Skip the delimiter and following whitespaces.
|
* 0-terminate resulting word. Skip the delimiter and following whitespaces.
|
||||||
* Advance pointer to buffer to the next word. Return found 0-terminated word.
|
* Advance pointer to buffer to the next word. Return found 0-terminated word.
|
||||||
@@ -1894,6 +1881,7 @@ skip_quoted(char **buf,
|
|||||||
return begin_word;
|
return begin_word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Simplified version of skip_quoted without quote char
|
/* Simplified version of skip_quoted without quote char
|
||||||
* and whitespace == delimiters */
|
* and whitespace == delimiters */
|
||||||
static char *
|
static char *
|
||||||
@@ -1902,6 +1890,7 @@ skip(char **buf, const char *delimiters)
|
|||||||
return skip_quoted(buf, delimiters, delimiters, 0);
|
return skip_quoted(buf, delimiters, delimiters, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return HTTP header value, or NULL if not found. */
|
/* Return HTTP header value, or NULL if not found. */
|
||||||
static const char *
|
static const char *
|
||||||
get_header(const struct mg_request_info *ri, const char *name)
|
get_header(const struct mg_request_info *ri, const char *name)
|
||||||
@@ -1918,6 +1907,7 @@ get_header(const struct mg_request_info *ri, const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
mg_get_header(const struct mg_connection *conn, const char *name)
|
mg_get_header(const struct mg_connection *conn, const char *name)
|
||||||
{
|
{
|
||||||
@@ -1928,6 +1918,7 @@ mg_get_header(const struct mg_connection *conn, const char *name)
|
|||||||
return get_header(&conn->request_info, name);
|
return get_header(&conn->request_info, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* A helper function for traversing a comma separated list of values.
|
/* A helper function for traversing a comma separated list of values.
|
||||||
* It returns a list pointer shifted to the next value, or NULL if the end
|
* It returns a list pointer shifted to the next value, or NULL if the end
|
||||||
* of the list found.
|
* of the list found.
|
||||||
@@ -3355,6 +3346,42 @@ set_non_blocking_mode(SOCKET sock)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
/* End of initial operating system specific define block. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Get a random number (independent of C rand function) */
|
||||||
|
static int64_t
|
||||||
|
get_random(void)
|
||||||
|
{
|
||||||
|
static uint64_t lfsr = 0; /* Linear feedback shift register */
|
||||||
|
static uint64_t lcg = 0; /* Linear congruential generator */
|
||||||
|
struct timespec now;
|
||||||
|
|
||||||
|
memset(&now, 0, sizeof(now));
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
|
if (lfsr == 0) {
|
||||||
|
/* lfsr will be only 0 if has not been initialized,
|
||||||
|
* so this code is called only once. */
|
||||||
|
lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec)
|
||||||
|
^ ((uint64_t)(ptrdiff_t)&now) ^ ((uint64_t)pthread_self())
|
||||||
|
^ (((uint64_t)time(NULL)) << 33);
|
||||||
|
lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
|
||||||
|
+ (uint64_t)(ptrdiff_t)&now;
|
||||||
|
} else {
|
||||||
|
/* Get the next step of both random number generators. */
|
||||||
|
lfsr = (lfsr >> 1)
|
||||||
|
| ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
|
||||||
|
<< 63);
|
||||||
|
lcg = lcg * 6364136223846793005 + 1442695040888963407;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Combining two pseudo-random number generators and a high resolution part
|
||||||
|
* of the current server time will make it hard (impossible?) to guess the
|
||||||
|
* next number. */
|
||||||
|
return (lfsr ^ lcg ^ (uint64_t)now.tv_nsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write data to the IO channel - opened file descriptor, socket or SSL
|
/* Write data to the IO channel - opened file descriptor, socket or SSL
|
||||||
* descriptor. Return number of bytes written. */
|
* descriptor. Return number of bytes written. */
|
||||||
@@ -4841,7 +4868,7 @@ parse_auth_header(struct mg_connection *conn,
|
|||||||
{
|
{
|
||||||
char *name, *value, *s;
|
char *name, *value, *s;
|
||||||
const char *auth_header;
|
const char *auth_header;
|
||||||
unsigned long nonce;
|
uint64_t nonce;
|
||||||
|
|
||||||
if (!ah || !conn) {
|
if (!ah || !conn) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4902,13 +4929,13 @@ parse_auth_header(struct mg_connection *conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
s = NULL;
|
s = NULL;
|
||||||
nonce = strtoul(ah->nonce, &s, 10);
|
nonce = strtoull(ah->nonce, &s, 10);
|
||||||
if ((s == NULL) || (*s != 0)) {
|
if ((s == NULL) || (*s != 0)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the nonce from the client to a number. */
|
/* Convert the nonce from the client to a number. */
|
||||||
nonce ^= (uintptr_t)(conn->ctx);
|
nonce ^= conn->ctx->auth_nonce_mask;
|
||||||
|
|
||||||
/* The converted number corresponds to the time the nounce has been
|
/* The converted number corresponds to the time the nounce has been
|
||||||
* created. This should not be earlier than the server start. */
|
* created. This should not be earlier than the server start. */
|
||||||
@@ -4918,14 +4945,14 @@ parse_auth_header(struct mg_connection *conn,
|
|||||||
/* However, the reasonable default is to not accept a nonce from a
|
/* However, the reasonable default is to not accept a nonce from a
|
||||||
* previous start, so if anyone changed the access rights between
|
* previous start, so if anyone changed the access rights between
|
||||||
* two restarts, a new login is required. */
|
* two restarts, a new login is required. */
|
||||||
if (nonce < conn->ctx->start_time) {
|
if (nonce < (uint64_t)conn->ctx->start_time) {
|
||||||
/* nonce is from a previous start of the server and no longer valid
|
/* nonce is from a previous start of the server and no longer valid
|
||||||
* (replay attack?) */
|
* (replay attack?) */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Check if the nonce is too high, so it has not (yet) been used by the
|
/* Check if the nonce is too high, so it has not (yet) been used by the
|
||||||
* server. */
|
* server. */
|
||||||
if (nonce >= conn->ctx->start_time + conn->ctx->nonce_count) {
|
if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -5155,14 +5182,14 @@ send_authorization_request(struct mg_connection *conn)
|
|||||||
time_t curtime = time(NULL);
|
time_t curtime = time(NULL);
|
||||||
|
|
||||||
if (conn && conn->ctx) {
|
if (conn && conn->ctx) {
|
||||||
unsigned long nonce = (unsigned long)(conn->ctx->start_time);
|
uint64_t nonce = (uint64_t)(conn->ctx->start_time);
|
||||||
|
|
||||||
(void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
|
(void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
|
||||||
nonce += conn->ctx->nonce_count;
|
nonce += conn->ctx->nonce_count;
|
||||||
++conn->ctx->nonce_count;
|
++conn->ctx->nonce_count;
|
||||||
(void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
|
(void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
|
||||||
|
|
||||||
nonce ^= (uintptr_t)(conn->ctx);
|
nonce ^= conn->ctx->auth_nonce_mask;
|
||||||
conn->status_code = 401;
|
conn->status_code = 401;
|
||||||
conn->must_close = 1;
|
conn->must_close = 1;
|
||||||
|
|
||||||
@@ -5174,7 +5201,7 @@ send_authorization_request(struct mg_connection *conn)
|
|||||||
"Connection: %s\r\n"
|
"Connection: %s\r\n"
|
||||||
"Content-Length: 0\r\n"
|
"Content-Length: 0\r\n"
|
||||||
"WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
|
"WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
|
||||||
"nonce=\"%lu\"\r\n\r\n",
|
"nonce=\"%" UINT64_FMT "\"\r\n\r\n",
|
||||||
date,
|
date,
|
||||||
suggest_connection_header(conn),
|
suggest_connection_header(conn),
|
||||||
conn->ctx->config[AUTHENTICATION_DOMAIN],
|
conn->ctx->config[AUTHENTICATION_DOMAIN],
|
||||||
@@ -11607,7 +11634,7 @@ master_thread_run(void *thread_func_param)
|
|||||||
pthread_setspecific(sTlsKey, &tls);
|
pthread_setspecific(sTlsKey, &tls);
|
||||||
|
|
||||||
/* Server starts *now* */
|
/* Server starts *now* */
|
||||||
ctx->start_time = (unsigned long)time(NULL);
|
ctx->start_time = time(NULL);
|
||||||
|
|
||||||
/* Allocate memory for the listening sockets, and start the server */
|
/* Allocate memory for the listening sockets, and start the server */
|
||||||
pfd =
|
pfd =
|
||||||
@@ -11867,7 +11894,8 @@ mg_start(const struct mg_callbacks *callbacks,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Random number generator will initialize at the first call */
|
/* Random number generator will initialize at the first call */
|
||||||
(void)get_random();
|
ctx->auth_nonce_mask =
|
||||||
|
(uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
|
||||||
|
|
||||||
if (mg_atomic_inc(&sTlsInit) == 1) {
|
if (mg_atomic_inc(&sTlsInit) == 1) {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user