Pārlūkot izejas kodu

Rewrite string handling (Step 7/?)

bel 10 gadi atpakaļ
vecāks
revīzija
af0eca2684
1 mainītis faili ar 58 papildinājumiem un 31 dzēšanām
  1. 58 31
      src/civetweb.c

+ 58 - 31
src/civetweb.c

@@ -4369,10 +4369,9 @@ open_auth_file(struct mg_connection *conn, const char *path, struct file *filep)
 			            &truncated,
 			            name,
 			            sizeof(name),
-			            "%.*s%c%s",
+			            "%.*s%s",
 			            (int)(e - p),
 			            p,
-			            '/',
 			            PASSWORDS_FILE_NAME);
 
 			if (truncated || !mg_fopen(conn, name, "r", filep)) {
@@ -5179,6 +5178,7 @@ static int remove_directory(struct mg_connection *conn, const char *dir)
 	struct dirent *dp;
 	DIR *dirp;
 	struct de de;
+	int truncated;
 
 	if ((dirp = opendir(dir)) == NULL) {
 		return 0;
@@ -5193,9 +5193,7 @@ static int remove_directory(struct mg_connection *conn, const char *dir)
 			}
 
 			mg_snprintf(
-			    conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
-
-			/* TODO(high): kick client on buffer overflow */
+			    conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
 
 			/* If we don't memset stat structure to zero, mtime will have
 			 * garbage and strftime() will segfault later on in
@@ -5203,6 +5201,12 @@ static int remove_directory(struct mg_connection *conn, const char *dir)
 			 * fails. For more details, see
 			 * http://code.google.com/p/mongoose/issues/detail?id=79 */
 			memset(&de.file, 0, sizeof(de.file));
+
+			if (truncated) {
+				/* Do not delete anything shorter */
+				continue;
+			}
+
 			if (!mg_stat(conn, path, &de.file)) {
 				mg_cry(conn,
 				       "%s: mg_stat(%s) failed: %s",
@@ -5481,7 +5485,7 @@ static void handle_static_file_request(struct mg_connection *conn,
 	time_t curtime = time(NULL);
 	int64_t cl, r1, r2;
 	struct vec mime_vec;
-	int n;
+	int n, truncated;
 	char gz_path[PATH_MAX];
 	const char *encoding = "";
 	const char *cors1, *cors2, *cors3;
@@ -5505,9 +5509,13 @@ static void handle_static_file_request(struct mg_connection *conn,
 	 * it's important to rewrite the filename after resolving
 	 * the mime type from it, to preserve the actual file's type */
 	if (filep->gzipped) {
-		mg_snprintf(conn, gz_path, sizeof(gz_path), "%s.gz", path);
+		mg_snprintf(conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", path);
 
-		/* TODO(high): kick client on buffer overflow */
+		if (truncated) {
+			send_http_error(
+			    conn, 500, "Error: Path of zipped file too long (%s)", path);
+			return;
+		}
 
 		path = gz_path;
 		encoding = "Content-Encoding: gzip\r\n";
@@ -6132,7 +6140,8 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 {
 	char *buf;
 	size_t buflen;
-	int headers_len, data_len, i, fdin[2] = {0, 0}, fdout[2] = {0, 0};
+	int headers_len, data_len, i, truncated;
+	int fdin[2] = {-1, -1}, fdout[2] = {-1, -1};
 	const char *status, *status_text, *connection_state;
 	char *pbuf, dir[PATH_MAX], *p;
 	struct mg_request_info ri;
@@ -6152,9 +6161,12 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 	/* CGI must be executed in its own directory. 'dir' must point to the
 	 * directory containing executable program, 'p' must point to the
 	 * executable program name relative to 'dir'. */
-	(void)mg_snprintf(conn, dir, sizeof(dir), "%s", prog);
+	(void)mg_snprintf(conn, &truncated, dir, sizeof(dir), "%s", prog);
 
-	/* TODO(high): kick client on buffer overflow */
+	if (truncated) {
+		send_http_error(conn, 500, "Error: %s", "CGI path too long");
+		goto done;
+	}
 
 	if ((p = strrchr(dir, '/')) != NULL) {
 		*p++ = '\0';
@@ -6630,6 +6642,7 @@ static void do_ssi_include(struct mg_connection *conn,
 	char file_name[MG_BUF_LEN], path[512], *p;
 	struct file file = STRUCT_FILE_INITIALIZER;
 	size_t len;
+	int truncated = 0;
 
 	if (conn == NULL) {
 		return;
@@ -6642,45 +6655,49 @@ static void do_ssi_include(struct mg_connection *conn,
 		/* File name is relative to the webserver root */
 		file_name[511] = 0;
 		(void)mg_snprintf(conn,
+		                  &truncated,
 		                  path,
 		                  sizeof(path),
-		                  "%s%c%s",
+		                  "%s/%s",
 		                  conn->ctx->config[DOCUMENT_ROOT],
-		                  '/',
 		                  file_name);
 
-		/* TODO(high): kick client on buffer overflow */
-
 	} else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) {
 		/* File name is relative to the webserver working directory
 		 * or it is absolute system path */
 		file_name[511] = 0;
-		(void)mg_snprintf(conn, path, sizeof(path), "%s", file_name);
-
-		/* TODO(high): kick client on buffer overflow */
+		(void)mg_snprintf(
+		    conn, &truncated, path, sizeof(path), "%s", file_name);
 
 	} else if (sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1 ||
 	           sscanf(tag, " \"%511[^\"]\"", file_name) == 1) {
 		/* File name is relative to the currect document */
 		file_name[511] = 0;
-		(void)mg_snprintf(conn, path, sizeof(path), "%s", ssi);
-
-		/* TODO(high): kick client on buffer overflow */
+		(void)mg_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi);
 
-		if ((p = strrchr(path, '/')) != NULL) {
-			p[1] = '\0';
+		if (!truncated) {
+			if ((p = strrchr(path, '/')) != NULL) {
+				p[1] = '\0';
+			}
+			len = strlen(path);
+			(void)mg_snprintf(conn,
+			                  &truncated,
+			                  path + len,
+			                  sizeof(path) - len,
+			                  "%s",
+			                  file_name);
 		}
-		len = strlen(path);
-		(void)mg_snprintf(
-		    conn, path + len, sizeof(path) - len, "%s", file_name);
-
-		/* TODO(high): kick client on buffer overflow */
 
 	} else {
 		mg_cry(conn, "Bad SSI #include: [%s]", tag);
 		return;
 	}
 
+	if (truncated) {
+		mg_cry(conn, "SSI #include path length overflow: [%s]", tag);
+		return;
+	}
+
 	if (!mg_fopen(conn, path, "rb", &file)) {
 		mg_cry(conn,
 		       "Cannot open SSI #include: [%s]: fopen(%s): %s",
@@ -7235,20 +7252,25 @@ static void SHA1Final(unsigned char digest[20], SHA1_CTX *context)
 }
 /* END OF SHA1 CODE */
 
-static void send_websocket_handshake(struct mg_connection *conn)
+static int send_websocket_handshake(struct mg_connection *conn)
 {
 	static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
 	char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
 	SHA1_CTX sha_ctx;
+	int truncated;
 
 	mg_snprintf(conn,
+	            &truncated,
 	            buf,
 	            sizeof(buf),
 	            "%s%s",
 	            mg_get_header(conn, "Sec-WebSocket-Key"),
 	            magic);
 
-	/* TODO(high): kick client on buffer overflow */
+	if (truncated) {
+		conn->must_close = 1;
+		return 0;
+	}
 
 	SHA1Init(&sha_ctx);
 	SHA1Update(&sha_ctx, (unsigned char *)buf, (uint32_t)strlen(buf));
@@ -7262,6 +7284,8 @@ static void send_websocket_handshake(struct mg_connection *conn)
 	          "Sec-WebSocket-Accept: ",
 	          b64_sha,
 	          "\r\n\r\n");
+
+	return 1;
 }
 
 static void read_websocket(struct mg_connection *conn,
@@ -7541,7 +7565,10 @@ handle_websocket_request(struct mg_connection *conn,
 	}
 
 	/* Step 5: The websocket connection has been accepted */
-	send_websocket_handshake(conn);
+	if (!send_websocket_handshake(conn)) {
+		send_http_error(conn, 500, "%s", "Websocket handshake failed");
+		return;
+	}
 
 	/* Step 6: Call the ready handler */
 	if (is_callback_resource) {