chiark / gitweb /
Prep v234: Apply missing upstream fixes in src/basic (1/6)
[elogind.git] / src / basic / hostname-util.c
index 8f6a5b4316e4103c48e37cc5d681c63df0510267..63329d53b265f15644811616c8701aa66101341b 100644 (file)
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
 /***
   This file is part of systemd.
 
 /***
   This file is part of systemd.
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
 #include <sys/utsname.h>
 #include <sys/utsname.h>
-#include <ctype.h>
+#include <unistd.h>
 
 
-#include "util.h"
+//#include "fd-util.h"
+#include "fileio.h"
 #include "hostname-util.h"
 #include "hostname-util.h"
+//#include "macro.h"
+#include "string-util.h"
 
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 bool hostname_is_set(void) {
         struct utsname u;
 
 bool hostname_is_set(void) {
         struct utsname u;
 
@@ -41,17 +45,52 @@ bool hostname_is_set(void) {
 
         return true;
 }
 
         return true;
 }
+#endif // 0
 
 char* gethostname_malloc(void) {
         struct utsname u;
 
 
 char* gethostname_malloc(void) {
         struct utsname u;
 
+        /* This call tries to return something useful, either the actual hostname
+         * or it makes something up. The only reason it might fail is OOM.
+         * It might even return "localhost" if that's set. */
+
         assert_se(uname(&u) >= 0);
 
         if (isempty(u.nodename) || streq(u.nodename, "(none)"))
         assert_se(uname(&u) >= 0);
 
         if (isempty(u.nodename) || streq(u.nodename, "(none)"))
-                return strdup(u.sysname);
+#if 0 /// elogind has no hostnamed and such nonsense
+                return strdup(FALLBACK_HOSTNAME);
+#else
+                return strdup("localhost");
+#endif // 0
 
         return strdup(u.nodename);
 }
 
         return strdup(u.nodename);
 }
+
+#if 0 /// UNNEEDED by elogind
+int gethostname_strict(char **ret) {
+        struct utsname u;
+        char *k;
+
+        /* This call will rather fail than make up a name. It will not return "localhost" either. */
+
+        assert_se(uname(&u) >= 0);
+
+        if (isempty(u.nodename))
+                return -ENXIO;
+
+        if (streq(u.nodename, "(none)"))
+                return -ENXIO;
+
+        if (is_localhost(u.nodename))
+                return -ENXIO;
+
+        k = strdup(u.nodename);
+        if (!k)
+                return -ENOMEM;
+
+        *ret = k;
+        return 0;
+}
 #endif // 0
 
 static bool hostname_valid_char(char c) {
 #endif // 0
 
 static bool hostname_valid_char(char c) {
@@ -64,14 +103,25 @@ static bool hostname_valid_char(char c) {
                 c == '.';
 }
 
                 c == '.';
 }
 
-bool hostname_is_valid(const char *s) {
+/**
+ * Check if s looks like a valid host name or FQDN. This does not do
+ * full DNS validation, but only checks if the name is composed of
+ * allowed characters and the length is not above the maximum allowed
+ * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
+ * allow_trailing_dot is true and at least two components are present
+ * in the name. Note that due to the restricted charset and length
+ * this call is substantially more conservative than
+ * dns_name_is_valid().
+ */
+bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
+        unsigned n_dots = 0;
         const char *p;
         bool dot;
 
         if (isempty(s))
                 return false;
 
         const char *p;
         bool dot;
 
         if (isempty(s))
                 return false;
 
-        /* Doesn't accept empty hostnames, hostnames with trailing or
+        /* Doesn't accept empty hostnames, hostnames with
          * leading dots, and hostnames with multiple dots in a
          * sequence. Also ensures that the length stays below
          * HOST_NAME_MAX. */
          * leading dots, and hostnames with multiple dots in a
          * sequence. Also ensures that the length stays below
          * HOST_NAME_MAX. */
@@ -82,6 +132,7 @@ bool hostname_is_valid(const char *s) {
                                 return false;
 
                         dot = true;
                                 return false;
 
                         dot = true;
+                        n_dots++;
                 } else {
                         if (!hostname_valid_char(*p))
                                 return false;
                 } else {
                         if (!hostname_valid_char(*p))
                                 return false;
@@ -90,21 +141,26 @@ bool hostname_is_valid(const char *s) {
                 }
         }
 
                 }
         }
 
-        if (dot)
+        if (dot && (n_dots < 2 || !allow_trailing_dot))
                 return false;
 
                 return false;
 
-        if (p-s > HOST_NAME_MAX)
+        if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
+                                  * Linux, but DNS allows domain names
+                                  * up to 255 characters */
                 return false;
 
         return true;
 }
 
                 return false;
 
         return true;
 }
 
-char* hostname_cleanup(char *s, bool lowercase) {
+#if 0 /// UNNEEDED by elogind
+char* hostname_cleanup(char *s) {
         char *p, *d;
         bool dot;
 
         assert(s);
 
         char *p, *d;
         bool dot;
 
         assert(s);
 
+        strshorten(s, HOST_NAME_MAX);
+
         for (p = s, d = s, dot = true; *p; p++) {
                 if (*p == '.') {
                         if (dot)
         for (p = s, d = s, dot = true; *p; p++) {
                 if (*p == '.') {
                         if (dot)
@@ -113,10 +169,9 @@ char* hostname_cleanup(char *s, bool lowercase) {
                         *(d++) = '.';
                         dot = true;
                 } else if (hostname_valid_char(*p)) {
                         *(d++) = '.';
                         dot = true;
                 } else if (hostname_valid_char(*p)) {
-                        *(d++) = lowercase ? tolower(*p) : *p;
+                        *(d++) = *p;
                         dot = false;
                 }
                         dot = false;
                 }
-
         }
 
         if (dot && d > s)
         }
 
         if (dot && d > s)
@@ -124,29 +179,38 @@ char* hostname_cleanup(char *s, bool lowercase) {
         else
                 *d = 0;
 
         else
                 *d = 0;
 
-        strshorten(s, HOST_NAME_MAX);
-
         return s;
 }
         return s;
 }
+#endif // 0
 
 bool is_localhost(const char *hostname) {
         assert(hostname);
 
         /* This tries to identify local host and domain names
 
 bool is_localhost(const char *hostname) {
         assert(hostname);
 
         /* This tries to identify local host and domain names
-         * described in RFC6761 plus the redhatism of .localdomain */
-
-        return streq(hostname, "localhost") ||
-               streq(hostname, "localhost.") ||
-               streq(hostname, "localdomain.") ||
-               streq(hostname, "localdomain") ||
-               endswith(hostname, ".localhost") ||
-               endswith(hostname, ".localhost.") ||
-               endswith(hostname, ".localdomain") ||
-               endswith(hostname, ".localdomain.");
+         * described in RFC6761 plus the redhatism of localdomain */
+
+        return strcaseeq(hostname, "localhost") ||
+               strcaseeq(hostname, "localhost.") ||
+               strcaseeq(hostname, "localhost.localdomain") ||
+               strcaseeq(hostname, "localhost.localdomain.") ||
+               endswith_no_case(hostname, ".localhost") ||
+               endswith_no_case(hostname, ".localhost.") ||
+               endswith_no_case(hostname, ".localhost.localdomain") ||
+               endswith_no_case(hostname, ".localhost.localdomain.");
+}
+
+#if 0 /// UNNEEDED by elogind
+bool is_gateway_hostname(const char *hostname) {
+        assert(hostname);
+
+        /* This tries to identify the valid syntaxes for the our
+         * synthetic "gateway" host. */
+
+        return
+                strcaseeq(hostname, "gateway") ||
+                strcaseeq(hostname, "gateway.");
 }
 
 }
 
-/// UNNEEDED by elogind
-#if 0
 int sethostname_idempotent(const char *s) {
         char buf[HOST_NAME_MAX + 1] = {};
 
 int sethostname_idempotent(const char *s) {
         char buf[HOST_NAME_MAX + 1] = {};
 
@@ -181,7 +245,7 @@ int read_hostname_config(const char *path, char **hostname) {
                 truncate_nl(l);
                 if (l[0] != '\0' && l[0] != '#') {
                         /* found line with value */
                 truncate_nl(l);
                 if (l[0] != '\0' && l[0] != '#') {
                         /* found line with value */
-                        name = hostname_cleanup(l, false);
+                        name = hostname_cleanup(l);
                         name = strdup(name);
                         if (!name)
                                 return -ENOMEM;
                         name = strdup(name);
                         if (!name)
                                 return -ENOMEM;