On 2016-03-05 14:31:16 -0800, Kevin J. McCarthy wrote:
> There are a few more things I want to finish up (the -E patch
> improvements and reviewing outstanding patches), so I propose the
> following schedule:
>   - 3/19 last day for non-bugfix commits.  translation strings frozen.

I think that until 1.6 is released, we should now avoid completely
new features that do not fix any problem or are not related to
security.

I'm attaching 2 patches made by other users and which I've updated
for the latest changes in the trunk. The first one concerns security
with unsafe headers in mailto URL's.

patch-1.5.21hg.me.mailto_allow.vl.1 is from Michael Elkins, written
in 2010:
  http://marc.info/?l=mutt-dev&m=128146115227196&w=2

There was also the following thread about this subject, but I don't
think that it matters any longer with the above patch:
  http://marc.info/?l=mutt-dev&m=115272028620011&w=2

patch-1.5.23hg.dm.domain.vl.1 is from Derek Martin, written in 2013,
and I've modified the patch to avoid a memory leak. It fixes:
  https://dev.mutt.org//trac/ticket/3298

-- 
Vincent Lefèvre <vinc...@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
diff -r 940e528ef852 doc/manual.xml.head
--- a/doc/manual.xml.head       Tue Dec 18 20:46:33 2012 -0800
+++ b/doc/manual.xml.head       Wed Dec 19 12:22:14 2012 +0100
@@ -4621,6 +4621,37 @@
 
 </sect1>
 
+<sect1 id="mailto-allow">
+<title>Control allowed header fields in a mailto: URL</title>
+
+<para>Usage:</para>
+
+<cmdsynopsis>
+<command>mailto_allow</command>
+<group choice="req">
+<arg choice="plain">
+<replaceable class="parameter">*</replaceable>
+</arg>
+<arg choice="plain" rep="repeat">
+<replaceable class="parameter">header-field</replaceable>
+</arg>
+</group>
+</cmdsynopsis>
+
+<para>
+As a security measure, Mutt will only add user-approved header fields from a
+<literal>mailto:</literal> URL.  This is necessary since Mutt will handle
+certain header fields, such as <literal>Attach:</literal>, in a special way.
+The <literal>mailto_allow</literal> and <literal>unmailto_allow</literal>
+commands allow the user to modify the list of approved headers.
+</para>
+<para>
+Mutt initializes the default list to contain only the 
<literal>Subject</literal>
+and <literal>body</literal> header fields, which are the only requirement 
specified
+by the <literal>mailto:</literal> specification in RFC2368.
+</para>
+</sect1>
+
 </chapter>
 
 <chapter id="advancedusage">
diff -r 940e528ef852 doc/muttrc.man.head
--- a/doc/muttrc.man.head       Tue Dec 18 20:46:33 2012 -0800
+++ b/doc/muttrc.man.head       Wed Dec 19 12:22:14 2012 +0100
@@ -399,6 +399,16 @@
 This command will remove all hooks of a given type, or all hooks
 when \(lq\fB*\fP\(rq is used as an argument.  \fIhook-type\fP
 can be any of the \fB-hook\fP commands documented above.
+.PP
+.nf
+\fBmailto_allow\fP \fIheader-field\fP [ ... ]
+\fBunmailto_allow\fP [ \fB*\fP | \fIheader-field\fP ... ]
+.fi
+.IP
+These commands allow the user to modify the list of allowed header
+fields in a \fImailto:\fP URL that Mutt will include in the
+the generated message.  By default the list contains only
+\fBsubject\fP and \fBbody\fP, as specified by RFC2368.
 .SH PATTERNS
 .PP
 In various places with mutt, including some of the above mentioned
diff -r 940e528ef852 globals.h
--- a/globals.h Tue Dec 18 20:46:33 2012 -0800
+++ b/globals.h Wed Dec 19 12:22:14 2012 +0100
@@ -159,6 +159,7 @@
 WHERE LIST *InlineExclude INITVAL(0);
 WHERE LIST *HeaderOrderList INITVAL(0);
 WHERE LIST *Ignore INITVAL(0);
+WHERE LIST *MailtoAllow INITVAL(0);
 WHERE LIST *MimeLookupList INITVAL(0);
 WHERE LIST *UnIgnore INITVAL(0);
 
diff -r 940e528ef852 init.c
--- a/init.c    Tue Dec 18 20:46:33 2012 -0800
+++ b/init.c    Wed Dec 19 12:22:14 2012 +0100
@@ -3063,6 +3063,15 @@
 
   mutt_init_history ();
 
+  /* RFC2368, "4. Unsafe headers"
+   * The creator of a mailto URL cannot expect the resolver of a URL to
+   * understand more than the "subject" and "body" headers. Clients that
+   * resolve mailto URLs into mail messages should be able to correctly
+   * create RFC 822-compliant mail messages using the "subject" and "body"
+   * headers.
+   */
+  add_to_list(&MailtoAllow, "body");
+  add_to_list(&MailtoAllow, "subject");
   
   
   
diff -r 940e528ef852 init.h
--- a/init.h    Tue Dec 18 20:46:33 2012 -0800
+++ b/init.h    Wed Dec 19 12:22:14 2012 +0100
@@ -3544,6 +3544,8 @@
   { "macro",           mutt_parse_macro,       0 },
   { "mailboxes",       mutt_parse_mailboxes,   M_MAILBOXES },
   { "unmailboxes",     mutt_parse_mailboxes,   M_UNMAILBOXES },
+  { "mailto_allow",    parse_list,             UL &MailtoAllow },
+  { "unmailto_allow",  parse_unlist,           UL &MailtoAllow },
   { "message-hook",    mutt_parse_hook,        M_MESSAGEHOOK },
   { "mbox-hook",       mutt_parse_hook,        M_MBOXHOOK },
   { "mime_lookup",     parse_list,     UL &MimeLookupList },
diff -r 940e528ef852 url.c
--- a/url.c     Tue Dec 18 20:46:33 2012 -0800
+++ b/url.c     Wed Dec 19 12:22:14 2012 +0100
@@ -283,21 +283,35 @@
     if (url_pct_decode (value) < 0)
       goto out;
 
-    if (!ascii_strcasecmp (tag, "body"))
+    /* Determine if this header field is on the allowed list.  Since Mutt
+     * interprets some header fields specially (such as
+     * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
+     * only safe fields are allowed.
+     *
+     * RFC2368, "4. Unsafe headers"
+     * The user agent interpreting a mailto URL SHOULD choose not to create
+     * a message if any of the headers are considered dangerous; it may also
+     * choose to create a message with only a subset of the headers given in
+     * the URL.
+     */
+    if (mutt_matches_ignore(tag, MailtoAllow))
     {
-      if (body)
-       mutt_str_replace (body, value);
-    }
-    else
-    {
-      char *scratch;
-      size_t taglen = mutt_strlen (tag);
-     
-      safe_asprintf (&scratch, "%s: %s", tag, value);
-      scratch[taglen] = 0; /* overwrite the colon as mutt_parse_rfc822_line 
expects */
-      value = skip_email_wsp(&scratch[taglen + 1]);
-      mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
-      FREE (&scratch);
+      if (!ascii_strcasecmp (tag, "body"))
+      {
+       if (body)
+         mutt_str_replace (body, value);
+      }
+      else
+      {
+       char *scratch;
+       size_t taglen = mutt_strlen (tag);
+
+       safe_asprintf (&scratch, "%s: %s", tag, value);
+       scratch[taglen] = 0; /* overwrite the colon as mutt_parse_rfc822_line 
expects */
+       value = skip_email_wsp(&scratch[taglen + 1]);
+       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
+       FREE (&scratch);
+      }
     }
   }
 
diff -Naurd mutt-hg/getdomain.c mutt/getdomain.c
--- mutt-hg/getdomain.c 2015-06-26 11:08:48.618633080 +0000
+++ mutt/getdomain.c    2015-07-29 10:18:13.823687209 +0000
@@ -1,68 +1,68 @@
+/*
+ * Copyright © 2009,2013 Derek Martin <c...@pizzashack.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
02110-1301, USA.
+ */
+
 #if HAVE_CONFIG_H
 # include "config.h"
 #endif
 
-#include <stdio.h>
-#include <ctype.h>
 #include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
 
 #include "mutt.h"
 
-#ifndef STDC_HEADERS
-int fclose ();
-#endif
 
-/* poor man's version of getdomainname() for systems where it does not return
- * return the DNS domain, but the NIS domain.
- */
-
-static void strip_trailing_dot (char *q)
-{
-  char *p = q;
-  
-  for (; *q; q++)
-    p = q;
-  
-  if (*p == '.')
-    *p = '\0';
-}
-
-int getdnsdomainname (char *s, size_t l)
+int getdnsdomainname (char *d, size_t len)
 {
-  FILE *f;
-  char tmp[1024];
-  char *p = NULL;
-  char *q;
-
-  if ((f = fopen ("/etc/resolv.conf", "r")) == NULL) return (-1);
-
-  tmp[sizeof (tmp) - 1] = 0;
+  /* A DNS name can actually be only 253 octets, string is 256 */
+  char *node;
+  long node_len;
+  struct addrinfo hints;
+  struct addrinfo *h;
+  char *p;
+  int ret;
 
-  l--; /* save room for the terminal \0 */
+  *d = '\0';
+  memset(&hints, 0, sizeof (struct addrinfo));
+  hints.ai_flags = AI_CANONNAME;
+  hints.ai_family = AF_UNSPEC;
 
-  while (fgets (tmp, sizeof (tmp) - 1, f) != NULL)
+  if ((node_len = sysconf(_SC_HOST_NAME_MAX)) == -1)
+    node_len = STRING;
+  node = safe_malloc(node_len + 1);
+  if (gethostname(node, node_len))
+    ret = -1;
+  else if (getaddrinfo(node, NULL, &hints, &h))
+    ret = -1;
+  else
   {
-    p = tmp;
-    while (ISSPACE (*p)) p++;
-    if (mutt_strncmp ("domain", p, 6) == 0 || mutt_strncmp ("search", p, 6) == 
0)
+    if (!(p = strchr(h->ai_canonname, '.')))
+      ret = -1;
+    else
     {
-      p += 6;
-      
-      for (q = strtok (p, " \t\n"); q; q = strtok (NULL, " \t\n"))
-       if (strcmp (q, "."))
-         break;
-
-      if (q)
-      {
-       strip_trailing_dot (q);
-       strfcpy (s, q, l);
-       safe_fclose (&f);
-       return 0;
-      }
-      
+      strfcpy(d, ++p, len);
+      ret = 0;
     }
+    freeaddrinfo(h);
   }
-
-  safe_fclose (&f);
-  return (-1);
+  FREE (&node);
+  return ret;
 }
+
diff -Naurd mutt-hg/init.c mutt/init.c
--- mutt-hg/init.c      2015-06-26 11:08:48.646632474 +0000
+++ mutt/init.c 2015-07-29 10:12:41.129742424 +0000
@@ -2889,6 +2889,7 @@
   struct passwd *pw;
   struct utsname utsname;
   char *p, buffer[STRING];
+  char *domain = NULL;
   int i, default_rc = 0, need_pause = 0;
   BUFFER err;
 
@@ -2953,30 +2954,53 @@
 #endif
 
   /* And about the host... */
-  uname (&utsname);
+
+#ifdef DOMAIN
+  domain = safe_strdup (DOMAIN);
+#endif /* DOMAIN */
+
+  /* 
+   * The call to uname() shouldn't fail, but if it does, the system is horribly
+   * broken, and the system's networking configuration is in an unreliable
+   * state.  We should bail.
+   */
+  if ((uname (&utsname)) == -1)
+  {
+    mutt_endwin (NULL);
+    fputs (_("unable to determine nodename via uname()"), stderr);
+    exit (1);
+  }
+
   /* some systems report the FQDN instead of just the hostname */
   if ((p = strchr (utsname.nodename, '.')))
-  {
     Hostname = mutt_substrdup (utsname.nodename, p);
-    p++;
-    strfcpy (buffer, p, sizeof (buffer)); /* save the domain for below */
-  }
   else
-    Hostname = safe_strdup (utsname.nodename);
+    Hostname = safe_strdup(NONULL(utsname.nodename));
 
-#ifndef DOMAIN
-#define DOMAIN buffer
-  if (!p && getdnsdomainname (buffer, sizeof (buffer)) == -1)
-    Fqdn = safe_strdup ("@");
-  else
-#endif /* DOMAIN */
-    if (*DOMAIN != '@')
+  /* now get FQDN.  Use configured domain first, DNS next, then uname */
+  if (domain) 
   {
-    Fqdn = safe_malloc (mutt_strlen (DOMAIN) + mutt_strlen (Hostname) + 2);
-    sprintf (Fqdn, "%s.%s", NONULL(Hostname), DOMAIN); /* __SPRINTF_CHECKED__ 
*/
+    /* we have a compile-time domain name, use that for Fqdn */
+    Fqdn = safe_malloc (mutt_strlen (domain) + mutt_strlen (Hostname) + 2);
+    sprintf (Fqdn, "%s.%s", NONULL(Hostname), domain); /* __SPRINTF_CHECKED__ 
*/
+  }
+  else if (!(getdnsdomainname (buffer, sizeof buffer)))
+  {
+    Fqdn = safe_malloc (mutt_strlen (buffer) + mutt_strlen (Hostname) + 2);
+    sprintf (Fqdn, "%s.%s", NONULL(Hostname), NONULL(buffer)); /* 
__SPRINTF_CHECKED__ */
   }
   else
-    Fqdn = safe_strdup(NONULL(Hostname));
+    /* 
+     * DNS failed, use the nodename.  Whether or not the nodename had a '.' in
+     * it, we can use the nodename as the FQDN.  On hosts where DNS is not
+     * being used, e.g. small network that relies on hosts files, a short host
+     * name is all that is required for SMTP to work correctly.  It could be
+     * wrong, but we've done the best we can, at this point the onus is on the
+     * user to provide the correct hostname if the nodename won't work in their
+     * network.
+     */
+    Fqdn = safe_strdup(utsname.nodename);
+
 
   if ((p = getenv ("MAIL")))
     Spoolfile = safe_strdup (p);

Reply via email to