From: Derek Martin Date: Tue, 8 Mar 2016 21:12:02 +0000 (-0800) Subject: Improve method of determining FQDN. (closes #3298) X-Git-Tag: neomutt-20160404~65 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0aeb67b0893ff3afcc064778b8f30cd72f3c9d5e;p=neomutt 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. --- diff --git a/getdomain.c b/getdomain.c index 71636279c..209848b79 100644 --- a/getdomain.c +++ b/getdomain.c @@ -1,68 +1,69 @@ +/* + * Copyright (C) 2009,2013 Derek Martin + * + * 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 -#include #include +#include +#include +#include +#include #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) +int getdnsdomainname (char *d, size_t len) { - char *p = q; - - for (; *q; q++) - p = q; - - if (*p == '.') - *p = '\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; -int getdnsdomainname (char *s, size_t l) -{ - FILE *f; - char tmp[1024]; - char *p = NULL; - char *q; + *d = '\0'; + memset(&hints, 0, sizeof (struct addrinfo)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_UNSPEC; - 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) + 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; + dprint(1, (debugfile, "getdnsdomainname(): %s\n", d)); } + freeaddrinfo(h); } - - safe_fclose (&f); - return (-1); + FREE (&node); + return ret; } + diff --git a/init.c b/init.c index 959fd1c10..27e349688 100644 --- a/init.c +++ b/init.c @@ -2889,6 +2889,7 @@ void mutt_init (int skip_sys_rc, LIST *commands) 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 @@ void mutt_init (int skip_sys_rc, LIST *commands) #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); - p++; - strfcpy (buffer, p, sizeof (buffer)); /* save the domain for below */ - } 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 != '@') + /* 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), 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);