]> granicus.if.org Git - neomutt/commitdiff
Improve method of determining FQDN. (closes #3298)
authorDerek Martin <code@pizzashack.org>
Tue, 8 Mar 2016 21:12:02 +0000 (13:12 -0800)
committerDerek Martin <code@pizzashack.org>
Tue, 8 Mar 2016 21:12:02 +0000 (13:12 -0800)
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.

getdomain.c
init.c

index 71636279cf7b86b532aa06fd50aa404b1ae7a792..209848b7956a8ed748f61e645b801f0288fb7ce1 100644 (file)
@@ -1,68 +1,69 @@
+/*
+ * Copyright (C) 2009,2013 Derek Martin <code@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)
+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 959fd1c106224389c097da0d8a9abc35539117de..27e349688ba2b939d317993149762635d75629fe 100644 (file)
--- 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);