diff --git a/src/civetweb.c b/src/civetweb.c index 9bd466e4..a68e9c02 100755 --- a/src/civetweb.c +++ b/src/civetweb.c @@ -149,12 +149,12 @@ clock_gettime(int clk_id, struct timespec *t) return 0; } 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}; 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); #if defined(DEBUG) assert(mach_status == KERN_SUCCESS); @@ -162,10 +162,11 @@ clock_gettime(int clk_id, struct timespec *t) /* appease "unused variable" warning for release builds */ (void)mach_status; #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); t->tv_sec = now / 1000000000; @@ -270,6 +271,7 @@ typedef long off_t; #endif /* !EWOULDBLOCK */ #define _POSIX_ #define INT64_FMT "I64d" +#define UINT64_FMT "I64u" #define WINCDECL __cdecl #define SHUT_RD (0) @@ -426,6 +428,7 @@ typedef unsigned short int in_port_t; #define ERRNO (errno) #define INVALID_SOCKET (-1) #define INT64_FMT PRId64 +#define UINT64_FMT PRIu64 typedef int SOCKET; #define WINCDECL @@ -1160,7 +1163,8 @@ struct mg_context { cfg_worker_threads; /* The number of configured worker threads. */ 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 */ unsigned long nonce_count; /* Used nonces, used for authentication */ @@ -1556,6 +1560,7 @@ mg_vsnprintf(const struct mg_connection *conn, buf[n] = '\0'; } + static void mg_snprintf(const struct mg_connection *conn, 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 get_option_index(const char *name) { @@ -1618,6 +1590,7 @@ get_option_index(const char *name) return -1; } + const char * 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 * mg_get_context(const struct mg_connection *conn) { return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx); } + void * mg_get_user_data(const struct mg_context *ctx) { return (ctx == NULL) ? NULL : ctx->user_data; } + void 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 * 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; } + size_t 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; } + int mg_get_server_ports(const struct mg_context *ctx, int size, @@ -1712,6 +1691,7 @@ mg_get_server_ports(const struct mg_context *ctx, return cnt; } + static void 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 } + /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be * included in all responses other than 100, 101, 5xx. */ 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. */ static double 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); } + /* Print error message to the opened error log stream. */ void 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 * is not applicable at the moment of logging. */ static struct mg_connection * @@ -1825,12 +1809,14 @@ fc(struct mg_context *ctx) return &fake_connection; } + const char * mg_version(void) { return CIVETWEB_VERSION; } + const struct mg_request_info * 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; } + /* Skip the characters until one of the delimiters characters found. * 0-terminate resulting word. Skip the delimiter and following whitespaces. * Advance pointer to buffer to the next word. Return found 0-terminated word. @@ -1894,6 +1881,7 @@ skip_quoted(char **buf, return begin_word; } + /* Simplified version of skip_quoted without quote char * and whitespace == delimiters */ static char * @@ -1902,6 +1890,7 @@ skip(char **buf, const char *delimiters) return skip_quoted(buf, delimiters, delimiters, 0); } + /* Return HTTP header value, or NULL if not found. */ static const char * 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; } + const char * 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); } + /* 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 * of the list found. @@ -3355,6 +3346,42 @@ set_non_blocking_mode(SOCKET sock) return 0; } #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 * descriptor. Return number of bytes written. */ @@ -4841,7 +4868,7 @@ parse_auth_header(struct mg_connection *conn, { char *name, *value, *s; const char *auth_header; - unsigned long nonce; + uint64_t nonce; if (!ah || !conn) { return 0; @@ -4902,13 +4929,13 @@ parse_auth_header(struct mg_connection *conn, return 0; } s = NULL; - nonce = strtoul(ah->nonce, &s, 10); + nonce = strtoull(ah->nonce, &s, 10); if ((s == NULL) || (*s != 0)) { return 0; } /* 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 * 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 * previous start, so if anyone changed the access rights between * 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 * (replay attack?) */ return 0; } /* Check if the nonce is too high, so it has not (yet) been used by the * 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; } #endif @@ -5155,14 +5182,14 @@ send_authorization_request(struct mg_connection *conn) time_t curtime = time(NULL); 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); nonce += conn->ctx->nonce_count; ++conn->ctx->nonce_count; (void)pthread_mutex_unlock(&conn->ctx->nonce_mutex); - nonce ^= (uintptr_t)(conn->ctx); + nonce ^= conn->ctx->auth_nonce_mask; conn->status_code = 401; conn->must_close = 1; @@ -5174,7 +5201,7 @@ send_authorization_request(struct mg_connection *conn) "Connection: %s\r\n" "Content-Length: 0\r\n" "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", " - "nonce=\"%lu\"\r\n\r\n", + "nonce=\"%" UINT64_FMT "\"\r\n\r\n", date, suggest_connection_header(conn), conn->ctx->config[AUTHENTICATION_DOMAIN], @@ -11607,7 +11634,7 @@ master_thread_run(void *thread_func_param) pthread_setspecific(sTlsKey, &tls); /* 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 */ pfd = @@ -11867,7 +11894,8 @@ mg_start(const struct mg_callbacks *callbacks, } /* 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) {