|  | @@ -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) {
 | 
											
												
													
														|  |  
 |  |  
 |