Bug 1101573 - (CVE-2018-14357)
Bug 1101578 - (CVE-2018-14354)

Based on 185152818541f5cdc059cbff3f3e8b654fc27c1d Mon Sep 17 00:00:00 2001
From: Kevin McCarthy <kevin@8t8.us>
Date: Sat, 7 Jul 2018 19:03:44 -0700
Subject: [PATCH] Properly quote IMAP mailbox names when (un)subscribing.

When handling automatic subscription (via $imap_check_subscribed), or
manual subscribe/unsubscribe commands, mutt generating a "mailboxes"
command but failed to properly escape backquotes.

Thanks to Jeriko One for the detailed bug report and patch, which this
commit is based upon.
---
 imap/command.c      |    7 ++++++-
 imap/imap.c         |    7 +++++--
 imap/imap_private.h |    3 ++-
 imap/util.c         |   26 +++++++++++++++++++++-----
 4 files changed, 34 insertions(+), 9 deletions(-)

--- imap/command.c
+++ imap/command.c	2018-07-23 13:58:28.656838145 +0000
@@ -696,12 +696,17 @@ static void cmd_parse_lsub (IMAP_DATA* i
 
   strfcpy (buf, "mailboxes \"", sizeof (buf));
   mutt_account_tourl (&idata->conn->account, &url);
-  url.path = list.name;
+  /* escape \ and ". Also escape ` because the resulting
+   * string will be passed to mutt_parse_rc_line. */
+  imap_quote_string_and_backquotes (errstr, sizeof (errstr), list.name);
+  url.path = errstr + 1;
+  url.path[strlen(url.path) - 1] = '\0';
   if (!mutt_strcmp (url.user, ImapUser))
     url.user = NULL;
   url_ciss_tostring (&url, buf + 11, sizeof (buf) - 10, 0);
   safe_strcat (buf, sizeof (buf), "\"");
   memset (&token, 0, sizeof (token));
+  memset (&errstr, 0, sizeof (errstr));
   err.data = errstr;
   err.dsize = sizeof (errstr);
   if (mutt_parse_rc_line (buf, &token, &err))
--- imap/imap.c
+++ imap/imap.c	2018-07-23 13:56:55.306524564 +0000
@@ -1790,6 +1790,7 @@ int imap_subscribe (char *path, int subs
   char buf[LONG_STRING];
   char mbox[LONG_STRING];
   char errstr[STRING];
+  int mblen;
   BUFFER err, token;
   IMAP_MBOX mx;
 
@@ -1810,8 +1811,10 @@ int imap_subscribe (char *path, int subs
     memset (&token, 0, sizeof (token));
     err.data = errstr;
     err.dsize = sizeof (errstr);
-    snprintf (mbox, sizeof (mbox), "%smailboxes \"%s\"",
-              subscribe ? "" : "un", path);
+    mblen = snprintf (mbox, sizeof (mbox), "%smailboxes ",
+                      subscribe ? "" : "un");
+    imap_quote_string_and_backquotes (mbox + mblen, sizeof(mbox) - mblen,
+                                      path);
     if (mutt_parse_rc_line (mbox, &token, &err))
       dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr));
     FREE (&token.data);
--- imap/imap_private.h
+++ imap/imap_private.h	2018-07-23 13:56:55.306524564 +0000
@@ -281,7 +281,8 @@ int imap_mxcmp (const char* mx1, const c
 char* imap_next_word (char* s);
 time_t imap_parse_date (char* s);
 void imap_qualify_path (char *dest, size_t len, IMAP_MBOX *mx, char* path);
-void imap_quote_string (char* dest, size_t slen, const char* src);
+void imap_quote_string (char* dest, size_t dlen, const char* src);
+void imap_quote_string_and_backquotes (char *dest, size_t dlen, const char *src);
 void imap_unquote_string (char* s);
 void imap_munge_mbox_name (char *dest, size_t dlen, const char *src);
 void imap_unmunge_mbox_name (char *s);
--- imap/util.c
+++ imap/util.c	2018-07-23 13:59:30.339723846 +0000
@@ -553,11 +553,10 @@ void imap_qualify_path (char *dest, size
 }
 
 
-/* imap_quote_string: quote string according to IMAP rules:
- *   surround string with quotes, escape " and \ with \ */
-void imap_quote_string (char *dest, size_t dlen, const char *src)
+static void _imap_quote_string (char *dest, size_t dlen, const char *src,
+	                        const char *to_quote)
 {
-  char quote[] = "\"\\", *pt;
+  char *pt;
   const char *s;
 
   pt = dest;
@@ -569,7 +568,7 @@ void imap_quote_string (char *dest, size
   
   for (; *s && dlen; s++)
   {
-    if (strchr (quote, *s))
+    if (strchr (to_quote, *s))
     {
       dlen -= 2;
       if (!dlen)
@@ -587,6 +586,23 @@ void imap_quote_string (char *dest, size
   *pt = 0;
 }
 
+/* imap_quote_string: quote string according to IMAP rules:
+ *   surround string with quotes, escape " and \ with \ */
+void imap_quote_string (char *dest, size_t dlen, const char *src)
+{
+  _imap_quote_string (dest, dlen, src, "\"\\");
+}
+
+/* imap_quote_string_and_backquotes: quote string according to IMAP rules:
+ *   surround string with quotes, escape " and \ with \.
+ * Additionally, escape backquotes with \ to protect against code injection
+ * when using the resulting string in mutt_parse_rc_line().
+ */
+void imap_quote_string_and_backquotes (char *dest, size_t dlen, const char *src)
+{
+  _imap_quote_string (dest, dlen, src, "\"\\`");
+}
+
 /* imap_unquote_string: equally stupid unquoting routine */
 void imap_unquote_string (char *s)
 {
