Blob Blame History Raw
diff -up dovecot-2.3.8/src/imap/imap-client-hibernate.c.CVE_2020_24386-prereq1 dovecot-2.3.8/src/imap/imap-client-hibernate.c
--- dovecot-2.3.8/src/imap/imap-client-hibernate.c.CVE_2020_24386-prereq1	2019-10-08 10:46:18.000000000 +0200
+++ dovecot-2.3.8/src/imap/imap-client-hibernate.c	2021-01-08 17:14:40.051174282 +0100
@@ -19,24 +19,26 @@
 #define IMAP_HIBERNATE_SEND_TIMEOUT_SECS 10
 #define IMAP_HIBERNATE_HANDSHAKE "VERSION\timap-hibernate\t1\t0\n"
 
-static int imap_hibernate_handshake(int fd, const char *path)
+static int
+imap_hibernate_handshake(int fd, const char *path, const char **error_r)
 {
 	char buf[1024];
 	ssize_t ret;
 
 	if (write_full(fd, IMAP_HIBERNATE_HANDSHAKE,
 		       strlen(IMAP_HIBERNATE_HANDSHAKE)) < 0) {
-		i_error("write(%s) failed: %m", path);
+		*error_r = t_strdup_printf("write(%s) failed: %m", path);
 		return -1;
 	} else if ((ret = read(fd, buf, sizeof(buf)-1)) < 0) {
-		i_error("read(%s) failed: %m", path);
+		*error_r = t_strdup_printf("read(%s) failed: %m", path);
 		return -1;
 	} else if (ret > 0 && buf[ret-1] == '\n') {
 		buf[ret-1] = '\0';
 		if (version_string_verify(buf, "imap-hibernate", 1))
 			return 0;
 	}
-	i_error("%s sent invalid VERSION handshake: %s", path, buf);
+	*error_r = t_strdup_printf("%s sent invalid VERSION handshake: %s",
+				   path, buf);
 	return -1;
 }
 
@@ -105,40 +107,42 @@ static void imap_hibernate_write_cmd(str
 
 static int
 imap_hibernate_process_send_cmd(int fd_socket, const char *path,
-				const string_t *cmd, int fd_client)
+				const string_t *cmd, int fd_client,
+				const char **error_r)
 {
 	ssize_t ret;
 
 	i_assert(fd_socket != -1);
 	i_assert(str_len(cmd) > 1);
 
-	if (imap_hibernate_handshake(fd_socket, path) < 0)
+	if (imap_hibernate_handshake(fd_socket, path, error_r) < 0)
 		return -1;
 	if ((ret = fd_send(fd_socket, fd_client, str_data(cmd), 1)) < 0) {
-		i_error("fd_send(%s) failed: %m", path);
+		*error_r = t_strdup_printf("fd_send(%s) failed: %m", path);
 		return -1;
 	}
 	if ((ret = write_full(fd_socket, str_data(cmd)+1, str_len(cmd)-1)) < 0) {
-		i_error("write(%s) failed: %m", path);
+		*error_r = t_strdup_printf("write(%s) failed: %m", path);
 		return -1;
 	}
 	return 0;
 }
 
-static int imap_hibernate_process_read(int fd, const char *path)
+static int
+imap_hibernate_process_read(int fd, const char *path, const char **error_r)
 {
 	char buf[1024];
 	ssize_t ret;
 
 	if ((ret = read(fd, buf, sizeof(buf)-1)) < 0) {
-		i_error("read(%s) failed: %m", path);
+		*error_r = t_strdup_printf("read(%s) failed: %m", path);
 		return -1;
 	} else if (ret == 0) {
-		i_error("%s disconnected", path);
+		*error_r = t_strdup_printf("%s disconnected", path);
 		return -1;
 	} else if (buf[0] != '+') {
 		buf[ret] = '\0';
-		i_error("%s returned failure: %s", path,
+		*error_r = t_strdup_printf("%s returned failure: %s", path,
 			ret > 0 && buf[0] == '-' ? buf+1 : buf);
 		return -1;
 	} else {
@@ -147,8 +151,8 @@ static int imap_hibernate_process_read(i
 }
 
 static int
-imap_hibernate_process_send(struct client *client,
-			    const buffer_t *state, int fd_notify, int *fd_r)
+imap_hibernate_process_send(struct client *client, const buffer_t *state,
+			    int fd_notify, int *fd_r, const char **error_r)
 {
 	string_t *cmd = t_str_new(512);
 	const char *path;
@@ -171,14 +175,14 @@ imap_hibernate_process_send(struct clien
 	imap_hibernate_write_cmd(client, cmd, state, fd_notify);
 
 	alarm(IMAP_HIBERNATE_SEND_TIMEOUT_SECS);
-	if (imap_hibernate_process_send_cmd(fd, path, cmd, client->fd_in) < 0 ||
-	    imap_hibernate_process_read(fd, path) < 0)
+	if (imap_hibernate_process_send_cmd(fd, path, cmd, client->fd_in, error_r) < 0 ||
+	    imap_hibernate_process_read(fd, path, error_r) < 0)
 		ret = -1;
 	else if (fd_notify != -1) {
 		if ((ret = fd_send(fd, fd_notify, "\n", 1)) < 0)
-			i_error("fd_send(%s) failed: %m", path);
+			*error_r = t_strdup_printf("fd_send(%s) failed: %m", path);
 		else
-			ret = imap_hibernate_process_read(fd, path);
+			ret = imap_hibernate_process_read(fd, path, error_r);
 	}
 	alarm(0);
 	if (ret < 0) {
@@ -229,8 +233,12 @@ bool imap_client_hibernate(struct client
 		}
 	}
 	if (ret > 0) {
-		if (imap_hibernate_process_send(client, state, fd_notify, &fd_hibernate) < 0)
+		if (imap_hibernate_process_send(client, state, fd_notify,
+						&fd_hibernate, &error) < 0) {
+			e_error(client->event,
+				"Couldn't hibernate imap client: %s", error);
 			ret = -1;
+		}
 	}
 	i_close_fd(&fd_notify);
 	if (ret > 0) {