|  | @@ -177,7 +177,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	const char *content_type;
 | 
	
		
			
				|  |  |  	char path[512];
 | 
	
		
			
				|  |  | -	char buf[1024];
 | 
	
		
			
				|  |  | +	char buf[1024]; /* Must not be smaller than ~900 - see sanity check */
 | 
	
		
			
				|  |  |  	int field_storage;
 | 
	
		
			
				|  |  |  	int buf_fill = 0;
 | 
	
		
			
				|  |  |  	int r;
 | 
	
	
		
			
				|  | @@ -517,7 +517,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  		/* The form data is in the request body data, encoded as multipart
 | 
	
		
			
				|  |  |  		 * content (see https://www.ietf.org/rfc/rfc1867.txt,
 | 
	
		
			
				|  |  |  		 * https://www.ietf.org/rfc/rfc2388.txt). */
 | 
	
		
			
				|  |  | -		const char *boundary;
 | 
	
		
			
				|  |  | +		char *boundary;
 | 
	
		
			
				|  |  |  		size_t bl;
 | 
	
		
			
				|  |  |  		ptrdiff_t used;
 | 
	
		
			
				|  |  |  		struct mg_request_info part_header;
 | 
	
	
		
			
				|  | @@ -540,27 +540,57 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			return -1;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		boundary = content_type + bl + 9;
 | 
	
		
			
				|  |  | -		bl = strlen(boundary);
 | 
	
		
			
				|  |  | +		/* Copy boundary string to variable "boundary" */
 | 
	
		
			
				|  |  | +		fbeg = content_type + bl + 9;
 | 
	
		
			
				|  |  | +		bl = strlen(fbeg);
 | 
	
		
			
				|  |  | +		if (*fbeg == '\"') {
 | 
	
		
			
				|  |  | +			/* RFC 2046 permits the boundary string to be quoted. */
 | 
	
		
			
				|  |  | +			/* If the boundary is quoted, trim the quotes */
 | 
	
		
			
				|  |  | +			fbeg++;
 | 
	
		
			
				|  |  | +			bl--;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		boundary = mg_malloc(bl + 1);
 | 
	
		
			
				|  |  | +		if (!boundary) {
 | 
	
		
			
				|  |  | +			/* Out of memory */
 | 
	
		
			
				|  |  | +			mg_cry(conn,
 | 
	
		
			
				|  |  | +			       "%s: Cannot allocate memory for boundary [%lu]",
 | 
	
		
			
				|  |  | +			       __func__,
 | 
	
		
			
				|  |  | +			       (unsigned long)bl);
 | 
	
		
			
				|  |  | +			return -1;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		memcpy(boundary, fbeg, bl);
 | 
	
		
			
				|  |  | +		boundary[bl] = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +		/* Trim, if string is quoted */
 | 
	
		
			
				|  |  |  		if (boundary[0] == '"') {
 | 
	
		
			
				|  |  |  			/* RFC 2046 permits the boundary string to be quoted. */
 | 
	
		
			
				|  |  |  			hbuf = strchr(boundary + 1, '"');
 | 
	
		
			
				|  |  | -			if (!hbuf) {
 | 
	
		
			
				|  |  | -				/* Malformed request */
 | 
	
		
			
				|  |  | -				return -1;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			if (*hbuf) {
 | 
	
		
			
				|  |  | -				*hbuf = 0;
 | 
	
		
			
				|  |  | -				boundary++;
 | 
	
		
			
				|  |  | -				bl = strlen(boundary);
 | 
	
		
			
				|  |  | -			} else {
 | 
	
		
			
				|  |  | +			if ((!hbuf) || (*hbuf != '"')) {
 | 
	
		
			
				|  |  |  				/* Malformed request */
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  | +			*hbuf = 0;
 | 
	
		
			
				|  |  | +			memmove(boundary, boundary + 1, bl);
 | 
	
		
			
				|  |  | +			bl = strlen(boundary);
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		if (bl + 800 > sizeof(buf)) {
 | 
	
		
			
				|  |  | +		/* Do some sanity checks for boundary lengths */
 | 
	
		
			
				|  |  | +		if (bl > 70) {
 | 
	
		
			
				|  |  | +			/* From RFC 2046:
 | 
	
		
			
				|  |  | +			 * Boundary delimiters must not appear within the
 | 
	
		
			
				|  |  | +			 * encapsulated material, and must be no longer
 | 
	
		
			
				|  |  | +			 * than 70 characters, not counting the two
 | 
	
		
			
				|  |  | +			 * leading hyphens.
 | 
	
		
			
				|  |  | +			 */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			/* The initial sanity check
 | 
	
		
			
				|  |  | +			 * (bl + 800 > sizeof(buf))
 | 
	
		
			
				|  |  | +			 * is no longer required, since sizeof(buf) == 1024
 | 
	
		
			
				|  |  | +			 *
 | 
	
		
			
				|  |  | +			 * Original comment:
 | 
	
		
			
				|  |  | +			 */
 | 
	
		
			
				|  |  |  			/* Sanity check:  The algorithm can not work if bl >= sizeof(buf),
 | 
	
		
			
				|  |  |  			 * and it will not work effectively, if the buf is only a few byte
 | 
	
		
			
				|  |  |  			 * larger than bl, or if buf can not hold the multipart header
 | 
	
	
		
			
				|  | @@ -569,11 +599,13 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			 * any reasonable request from every browser. If it is not
 | 
	
		
			
				|  |  |  			 * fulfilled, it might be a hand-made request, intended to
 | 
	
		
			
				|  |  |  			 * interfere with the algorithm. */
 | 
	
		
			
				|  |  | +			mg_free(boundary);
 | 
	
		
			
				|  |  |  			return -1;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		if (bl < 4) {
 | 
	
		
			
				|  |  |  			/* Sanity check:  A boundary string of less than 4 bytes makes
 | 
	
		
			
				|  |  |  			 * no sense either. */
 | 
	
		
			
				|  |  | +			mg_free(boundary);
 | 
	
		
			
				|  |  |  			return -1;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -586,12 +618,14 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			            sizeof(buf) - 1 - (size_t)buf_fill);
 | 
	
		
			
				|  |  |  			if (r < 0) {
 | 
	
		
			
				|  |  |  				/* read error */
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  			buf_fill += r;
 | 
	
		
			
				|  |  |  			buf[buf_fill] = 0;
 | 
	
		
			
				|  |  |  			if (buf_fill < 1) {
 | 
	
		
			
				|  |  |  				/* No data */
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -609,10 +643,12 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			if (buf[0] != '-' || buf[1] != '-') {
 | 
	
		
			
				|  |  |  				/* Malformed request */
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  			if (strncmp(buf + 2, boundary, bl)) {
 | 
	
		
			
				|  |  |  				/* Malformed request */
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  			if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
 | 
	
	
		
			
				|  | @@ -621,6 +657,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  				if (((size_t)buf_fill != (size_t)(bl + 6))
 | 
	
		
			
				|  |  |  				    || (strncmp(buf + bl + 2, "--\r\n", 4))) {
 | 
	
		
			
				|  |  |  					/* Malformed request */
 | 
	
		
			
				|  |  | +					mg_free(boundary);
 | 
	
		
			
				|  |  |  					return -1;
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  				/* End of the request */
 | 
	
	
		
			
				|  | @@ -632,6 +669,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			hend = strstr(hbuf, "\r\n\r\n");
 | 
	
		
			
				|  |  |  			if (!hend) {
 | 
	
		
			
				|  |  |  				/* Malformed request */
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -639,6 +677,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			    parse_http_headers(&hbuf, part_header.http_headers);
 | 
	
		
			
				|  |  |  			if ((hend + 2) != hbuf) {
 | 
	
		
			
				|  |  |  				/* Malformed request */
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -652,6 +691,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			                          "Content-Disposition");
 | 
	
		
			
				|  |  |  			if (!content_disp) {
 | 
	
		
			
				|  |  |  				/* Malformed request */
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -675,6 +715,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  				nend = strchr(nbeg, '\"');
 | 
	
		
			
				|  |  |  				if (!nend) {
 | 
	
		
			
				|  |  |  					/* Malformed request */
 | 
	
		
			
				|  |  | +					mg_free(boundary);
 | 
	
		
			
				|  |  |  					return -1;
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  			} else {
 | 
	
	
		
			
				|  | @@ -686,6 +727,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  				if (!nbeg) {
 | 
	
		
			
				|  |  |  					/* Malformed request */
 | 
	
		
			
				|  |  | +					mg_free(boundary);
 | 
	
		
			
				|  |  |  					return -1;
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  				nbeg += 5;
 | 
	
	
		
			
				|  | @@ -720,6 +762,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  				if (!fend) {
 | 
	
		
			
				|  |  |  					/* Malformed request (the filename field is optional, but if
 | 
	
		
			
				|  |  |  					 * it exists, it needs to be terminated correctly). */
 | 
	
		
			
				|  |  | +					mg_free(boundary);
 | 
	
		
			
				|  |  |  					return -1;
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -747,6 +790,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			 * filename do not overlap. */
 | 
	
		
			
				|  |  |  			if (!(((ptrdiff_t)fbeg > (ptrdiff_t)nend)
 | 
	
		
			
				|  |  |  			      || ((ptrdiff_t)nbeg > (ptrdiff_t)fend))) {
 | 
	
		
			
				|  |  | +				mg_free(boundary);
 | 
	
		
			
				|  |  |  				return -1;
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -830,12 +874,14 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  				            sizeof(buf) - 1 - (size_t)buf_fill);
 | 
	
		
			
				|  |  |  				if (r < 0) {
 | 
	
		
			
				|  |  |  					/* read error */
 | 
	
		
			
				|  |  | +					mg_free(boundary);
 | 
	
		
			
				|  |  |  					return -1;
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  				buf_fill += r;
 | 
	
		
			
				|  |  |  				buf[buf_fill] = 0;
 | 
	
		
			
				|  |  |  				if (buf_fill < 1) {
 | 
	
		
			
				|  |  |  					/* No data */
 | 
	
		
			
				|  |  | +					mg_free(boundary);
 | 
	
		
			
				|  |  |  					return -1;
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -898,6 +944,7 @@ mg_handle_form_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		/* All parts handled */
 | 
	
		
			
				|  |  | +		mg_free(boundary);
 | 
	
		
			
				|  |  |  		return field_count;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 |