changeset: 6563:ce71d168c819 user: Derek Martin <[email protected]> date: Tue Mar 08 13:12:02 2016 -0800 link: http://dev.mutt.org/hg/mutt/rev/ce71d168c819
Improve method of determining FQDN. (closes #3298) Rather than reading /etc/resolv.conf, use gethostname() and getaddrinfo() to get the canonical domain. Thanks to Vincent Lefèvre for the memory leak fix. diffs (213 lines): diff -r 8e77637a1a69 -r ce71d168c819 getdomain.c --- a/getdomain.c Wed Mar 02 15:08:54 2016 -0800 +++ b/getdomain.c Tue Mar 08 13:12:02 2016 -0800 @@ -1,68 +1,69 @@ +/* + * Copyright (C) 2009,2013 Derek Martin <[email protected]> + * + * 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. - */ +int getdnsdomainname (char *d, size_t len) +{ + /* 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; -static void strip_trailing_dot (char *q) -{ - char *p = q; - - for (; *q; q++) - p = q; - - if (*p == '.') - *p = '\0'; + *d = '\0'; + memset(&hints, 0, sizeof (struct addrinfo)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_UNSPEC; + + 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 + { + if (!(p = strchr(h->ai_canonname, '.'))) + ret = -1; + else + { + strfcpy(d, ++p, len); + ret = 0; + dprint(1, (debugfile, "getdnsdomainname(): %s\n", d)); + } + freeaddrinfo(h); + } + FREE (&node); + return ret; } -int getdnsdomainname (char *s, size_t l) -{ - 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; - - l--; /* save room for the terminal \0 */ - - while (fgets (tmp, sizeof (tmp) - 1, f) != NULL) - { - p = tmp; - while (ISSPACE (*p)) p++; - if (mutt_strncmp ("domain", p, 6) == 0 || mutt_strncmp ("search", p, 6) == 0) - { - 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; - } - - } - } - - safe_fclose (&f); - return (-1); -} diff -r 8e77637a1a69 -r ce71d168c819 init.c --- a/init.c Wed Mar 02 15:08:54 2016 -0800 +++ b/init.c Tue Mar 08 13:12:02 2016 -0800 @@ -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); + perror (_("unable to determine nodename via uname()")); + exit (1); + } + /* some systems report the FQDN instead of just the hostname */ if ((p = strchr (utsname.nodename, '.'))) + Hostname = mutt_substrdup (utsname.nodename, p); + else + Hostname = safe_strdup (utsname.nodename); + + /* now get FQDN. Use configured domain first, DNS next, then uname */ + if (domain) { - Hostname = mutt_substrdup (utsname.nodename, p); - p++; - strfcpy (buffer, p, sizeof (buffer)); /* save the domain for below */ + /* 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), buffer); /* __SPRINTF_CHECKED__ */ } else - Hostname = safe_strdup (utsname.nodename); - -#ifndef DOMAIN -#define DOMAIN buffer - if (!p && getdnsdomainname (buffer, sizeof (buffer)) == -1) - Fqdn = safe_strdup ("@"); - else -#endif /* DOMAIN */ - if (*DOMAIN != '@') - { - Fqdn = safe_malloc (mutt_strlen (DOMAIN) + mutt_strlen (Hostname) + 2); - sprintf (Fqdn, "%s.%s", NONULL(Hostname), DOMAIN); /* __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);
