|  | @@ -891,6 +891,115 @@ static void mg_fclose(struct file *filep)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void mg_strlcpy(register char *dst, register const char *src, size_t n)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    for (; *src != '\0' && n > 1; n--) {
 | 
	
		
			
				|  |  | +        *dst++ = *src++;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    *dst = '\0';
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int lowercase(const char *s)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    return tolower(* (const unsigned char *) s);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int mg_strncasecmp(const char *s1, const char *s2, size_t len)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int diff = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (len > 0)
 | 
	
		
			
				|  |  | +        do {
 | 
	
		
			
				|  |  | +            diff = lowercase(s1++) - lowercase(s2++);
 | 
	
		
			
				|  |  | +        } while (diff == 0 && s1[-1] != '\0' && --len > 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return diff;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int mg_strcasecmp(const char *s1, const char *s2)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int diff;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    do {
 | 
	
		
			
				|  |  | +        diff = lowercase(s1++) - lowercase(s2++);
 | 
	
		
			
				|  |  | +    } while (diff == 0 && s1[-1] != '\0');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return diff;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static char * mg_strndup(const char *ptr, size_t len)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    char *p;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if ((p = (char *) mg_malloc(len + 1)) != NULL) {
 | 
	
		
			
				|  |  | +        mg_strlcpy(p, ptr, len + 1);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return p;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static char * mg_strdup(const char *str)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    return mg_strndup(str, strlen(str));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const char *mg_strcasestr(const char *big_str, const char *small_str)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int i, big_len = (int)strlen(big_str), small_len = (int)strlen(small_str);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for (i = 0; i <= big_len - small_len; i++) {
 | 
	
		
			
				|  |  | +        if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
 | 
	
		
			
				|  |  | +            return big_str + i;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return NULL;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Like snprintf(), but never returns negative value, or a value
 | 
	
		
			
				|  |  | +   that is larger than a supplied buffer.
 | 
	
		
			
				|  |  | +   Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
 | 
	
		
			
				|  |  | +   in his audit report. */
 | 
	
		
			
				|  |  | +static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
 | 
	
		
			
				|  |  | +                        const char *fmt, va_list ap)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int n;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (buflen == 0)
 | 
	
		
			
				|  |  | +        return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    n = vsnprintf(buf, buflen, fmt, ap);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (n < 0) {
 | 
	
		
			
				|  |  | +        mg_cry(conn, "vsnprintf error");
 | 
	
		
			
				|  |  | +        n = 0;
 | 
	
		
			
				|  |  | +    } else if (n >= (int) buflen) {
 | 
	
		
			
				|  |  | +        mg_cry(conn, "truncating vsnprintf buffer: [%.*s]",
 | 
	
		
			
				|  |  | +               n > 200 ? 200 : n, buf);
 | 
	
		
			
				|  |  | +        n = (int) buflen - 1;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    buf[n] = '\0';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return n;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
 | 
	
		
			
				|  |  | +                       PRINTF_FORMAT_STRING(const char *fmt), ...)
 | 
	
		
			
				|  |  | +PRINTF_ARGS(4, 5);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
 | 
	
		
			
				|  |  | +                       const char *fmt, ...)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    va_list ap;
 | 
	
		
			
				|  |  | +    int n;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    va_start(ap, fmt);
 | 
	
		
			
				|  |  | +    n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
 | 
	
		
			
				|  |  | +    va_end(ap);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return n;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static int get_option_index(const char *name)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      int i;
 | 
	
	
		
			
				|  | @@ -936,7 +1045,7 @@ static void sockaddr_to_string(char *buf, size_t len,
 | 
	
		
			
				|  |  |                (void *) &usa->sin6.sin6_addr, buf, len);
 | 
	
		
			
				|  |  |  #elif defined(_WIN32)
 | 
	
		
			
				|  |  |      /* Only Windows Vista (and newer) have inet_ntop() */
 | 
	
		
			
				|  |  | -    strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
 | 
	
		
			
				|  |  | +    mg_strlcpy(buf, inet_ntoa(usa->sin.sin_addr), len);
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  |      inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
 | 
	
		
			
				|  |  |  #endif
 | 
	
	
		
			
				|  | @@ -951,7 +1060,7 @@ static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
 | 
	
		
			
				|  |  |      if (tm != NULL) {
 | 
	
		
			
				|  |  |          strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  | -        strncpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
 | 
	
		
			
				|  |  | +        mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
 | 
	
		
			
				|  |  |          buf[buf_len - 1] = '\0';
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -1016,115 +1125,6 @@ struct mg_request_info *mg_get_request_info(struct mg_connection *conn)
 | 
	
		
			
				|  |  |      return &conn->request_info;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void mg_strlcpy(register char *dst, register const char *src, size_t n)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    for (; *src != '\0' && n > 1; n--) {
 | 
	
		
			
				|  |  | -        *dst++ = *src++;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    *dst = '\0';
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static int lowercase(const char *s)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    return tolower(* (const unsigned char *) s);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -int mg_strncasecmp(const char *s1, const char *s2, size_t len)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    int diff = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (len > 0)
 | 
	
		
			
				|  |  | -        do {
 | 
	
		
			
				|  |  | -            diff = lowercase(s1++) - lowercase(s2++);
 | 
	
		
			
				|  |  | -        } while (diff == 0 && s1[-1] != '\0' && --len > 0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return diff;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static int mg_strcasecmp(const char *s1, const char *s2)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    int diff;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    do {
 | 
	
		
			
				|  |  | -        diff = lowercase(s1++) - lowercase(s2++);
 | 
	
		
			
				|  |  | -    } while (diff == 0 && s1[-1] != '\0');
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return diff;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static char * mg_strndup(const char *ptr, size_t len)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    char *p;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if ((p = (char *) mg_malloc(len + 1)) != NULL) {
 | 
	
		
			
				|  |  | -        mg_strlcpy(p, ptr, len + 1);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return p;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static char * mg_strdup(const char *str)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    return mg_strndup(str, strlen(str));
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static const char *mg_strcasestr(const char *big_str, const char *small_str)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    int i, big_len = (int)strlen(big_str), small_len = (int)strlen(small_str);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    for (i = 0; i <= big_len - small_len; i++) {
 | 
	
		
			
				|  |  | -        if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
 | 
	
		
			
				|  |  | -            return big_str + i;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return NULL;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/* Like snprintf(), but never returns negative value, or a value
 | 
	
		
			
				|  |  | -   that is larger than a supplied buffer.
 | 
	
		
			
				|  |  | -   Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
 | 
	
		
			
				|  |  | -   in his audit report. */
 | 
	
		
			
				|  |  | -static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
 | 
	
		
			
				|  |  | -                        const char *fmt, va_list ap)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    int n;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (buflen == 0)
 | 
	
		
			
				|  |  | -        return 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    n = vsnprintf(buf, buflen, fmt, ap);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (n < 0) {
 | 
	
		
			
				|  |  | -        mg_cry(conn, "vsnprintf error");
 | 
	
		
			
				|  |  | -        n = 0;
 | 
	
		
			
				|  |  | -    } else if (n >= (int) buflen) {
 | 
	
		
			
				|  |  | -        mg_cry(conn, "truncating vsnprintf buffer: [%.*s]",
 | 
	
		
			
				|  |  | -               n > 200 ? 200 : n, buf);
 | 
	
		
			
				|  |  | -        n = (int) buflen - 1;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    buf[n] = '\0';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return n;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
 | 
	
		
			
				|  |  | -                       PRINTF_FORMAT_STRING(const char *fmt), ...)
 | 
	
		
			
				|  |  | -PRINTF_ARGS(4, 5);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
 | 
	
		
			
				|  |  | -                       const char *fmt, ...)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    va_list ap;
 | 
	
		
			
				|  |  | -    int n;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    va_start(ap, fmt);
 | 
	
		
			
				|  |  | -    n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
 | 
	
		
			
				|  |  | -    va_end(ap);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return n;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /* 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.
 | 
	
	
		
			
				|  | @@ -3006,7 +3006,7 @@ static int parse_auth_header(struct mg_connection *conn, char *buf,
 | 
	
		
			
				|  |  |      /* Convert the nonce from the client to a number and check it. */
 | 
	
		
			
				|  |  |      /* Server side nonce check is valuable in all situations but one: if the server restarts frequently,
 | 
	
		
			
				|  |  |         but the client should not see that, so the server should accept nonces from previous starts. */
 | 
	
		
			
				|  |  | -    íf (ah->nonce == NULL) {
 | 
	
		
			
				|  |  | +    if (ah->nonce == NULL) {
 | 
	
		
			
				|  |  |          return 0;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      nonce = strtoul(ah->nonce, &s, 10);
 | 
	
	
		
			
				|  | @@ -3311,7 +3311,7 @@ static void print_dir_entry(struct de *de)
 | 
	
		
			
				|  |  |      if (tm != NULL) {
 | 
	
		
			
				|  |  |          strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm);
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  | -        strncpy(mod, "01-Jan-1970 00:00", sizeof(mod));
 | 
	
		
			
				|  |  | +        mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
 | 
	
		
			
				|  |  |          mod[sizeof(mod) - 1] = '\0';
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      mg_url_encode(de->file_name, href, sizeof(href));
 | 
	
	
		
			
				|  | @@ -5338,7 +5338,7 @@ static void redirect_to_https_port(struct mg_connection *conn, int ssl_index)
 | 
	
		
			
				|  |  |      if (host_header != NULL) {
 | 
	
		
			
				|  |  |          char *pos;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        strncpy(host, host_header, hostlen);
 | 
	
		
			
				|  |  | +        mg_strlcpy(host, host_header, hostlen);
 | 
	
		
			
				|  |  |          host[hostlen - 1] = '\0';
 | 
	
		
			
				|  |  |          pos = strchr(host, ':');
 | 
	
		
			
				|  |  |          if (pos != NULL) {
 | 
	
	
		
			
				|  | @@ -5747,7 +5747,7 @@ static void log_access(const struct mg_connection *conn)
 | 
	
		
			
				|  |  |      if (tm != NULL) {
 | 
	
		
			
				|  |  |          strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  | -        strncpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
 | 
	
		
			
				|  |  | +        mg_strlcpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
 | 
	
		
			
				|  |  |          date[sizeof(date) - 1] = '\0';
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 |