]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/hostname-util.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / basic / hostname-util.c
index 12a579b38ac0432785d1148448c84e3978dd066c..5bfa028b39306b48a2482fd51d6217a77eafe063 100644 (file)
@@ -1,22 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd.
-
-  Copyright 2015 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd 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
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
 
 #include <errno.h>
 #include <limits.h>
@@ -26,7 +8,6 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
-#include "def.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
@@ -88,12 +69,12 @@ int gethostname_strict(char **ret) {
         return 0;
 }
 
-static bool hostname_valid_char(char c) {
+bool valid_ldh_char(char c) {
         return
                 (c >= 'a' && c <= 'z') ||
                 (c >= 'A' && c <= 'Z') ||
                 (c >= '0' && c <= '9') ||
-                IN_SET(c, '-', '_', '.');
+                c == '-';
 }
 
 /**
@@ -109,7 +90,7 @@ static bool hostname_valid_char(char c) {
 bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
         unsigned n_dots = 0;
         const char *p;
-        bool dot;
+        bool dot, hyphen;
 
         if (isempty(s))
                 return false;
@@ -119,23 +100,34 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
          * sequence. Also ensures that the length stays below
          * HOST_NAME_MAX. */
 
-        for (p = s, dot = true; *p; p++) {
+        for (p = s, dot = hyphen = true; *p; p++)
                 if (*p == '.') {
-                        if (dot)
+                        if (dot || hyphen)
                                 return false;
 
                         dot = true;
+                        hyphen = false;
                         n_dots++;
+
+                } else if (*p == '-') {
+                        if (dot)
+                                return false;
+
+                        dot = false;
+                        hyphen = true;
+
                 } else {
-                        if (!hostname_valid_char(*p))
+                        if (!valid_ldh_char(*p))
                                 return false;
 
                         dot = false;
+                        hyphen = false;
                 }
-        }
 
         if (dot && (n_dots < 2 || !allow_trailing_dot))
                 return false;
+        if (hyphen)
+                return false;
 
         if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
                                   * Linux, but DNS allows domain names
@@ -147,29 +139,38 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
 
 char* hostname_cleanup(char *s) {
         char *p, *d;
-        bool dot;
+        bool dot, hyphen;
 
         assert(s);
 
-        strshorten(s, HOST_NAME_MAX);
-
-        for (p = s, d = s, dot = true; *p; p++) {
+        for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++)
                 if (*p == '.') {
-                        if (dot)
+                        if (dot || hyphen)
                                 continue;
 
                         *(d++) = '.';
                         dot = true;
-                } else if (hostname_valid_char(*p)) {
+                        hyphen = false;
+
+                } else if (*p == '-') {
+                        if (dot)
+                                continue;
+
+                        *(d++) = '-';
+                        dot = false;
+                        hyphen = true;
+
+                } else if (valid_ldh_char(*p)) {
                         *(d++) = *p;
                         dot = false;
+                        hyphen = false;
                 }
-        }
 
-        if (dot && d > s)
-                d[-1] = 0;
-        else
-                *d = 0;
+        if (d > s && IN_SET(d[-1], '-', '.'))
+                /* The dot can occur at most once, but we might have multiple
+                 * hyphens, hence the loop */
+                d--;
+        *d = 0;
 
         return s;
 }
@@ -221,6 +222,38 @@ int sethostname_idempotent(const char *s) {
         return 1;
 }
 
+int shorten_overlong(const char *s, char **ret) {
+        char *h, *p;
+
+        /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
+         * whatever comes earlier. */
+
+        assert(s);
+
+        h = strdup(s);
+        if (!h)
+                return -ENOMEM;
+
+        if (hostname_is_valid(h, false)) {
+                *ret = h;
+                return 0;
+        }
+
+        p = strchr(h, '.');
+        if (p)
+                *p = 0;
+
+        strshorten(h, HOST_NAME_MAX);
+
+        if (!hostname_is_valid(h, false)) {
+                free(h);
+                return -EDOM;
+        }
+
+        *ret = h;
+        return 1;
+}
+
 int read_etc_hostname_stream(FILE *f, char **ret) {
         int r;