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