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