2020-12-23 22:21:36 +01:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2019-09-25 13:13:40 +02:00
|
|
|
/*
|
2019-10-01 09:20:35 +02:00
|
|
|
* Copyright (C) 2017 Red Hat, Inc.
|
2017-04-23 00:40:46 +02:00
|
|
|
*/
|
|
|
|
|
|
2021-02-04 18:04:13 +01:00
|
|
|
#include "src/core/nm-default-daemon.h"
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
#include "nm-hostname-manager.h"
|
|
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
|
|
#if HAVE_SELINUX
|
2021-07-09 08:48:48 +02:00
|
|
|
#include <selinux/selinux.h>
|
|
|
|
|
#include <selinux/label.h>
|
2017-04-23 00:40:46 +02:00
|
|
|
#endif
|
|
|
|
|
|
2021-02-12 15:01:09 +01:00
|
|
|
#include "libnm-core-aux-intern/nm-common-macros.h"
|
2017-04-23 00:40:46 +02:00
|
|
|
#include "nm-dbus-interface.h"
|
|
|
|
|
#include "nm-connection.h"
|
|
|
|
|
#include "nm-utils.h"
|
2021-02-12 15:01:09 +01:00
|
|
|
#include "libnm-core-intern/nm-core-internal.h"
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
#include "NetworkManagerUtils.h"
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1"
|
|
|
|
|
#define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1"
|
|
|
|
|
#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1"
|
|
|
|
|
|
|
|
|
|
#define HOSTNAME_FILE_DEFAULT "/etc/hostname"
|
|
|
|
|
#define HOSTNAME_FILE_UCASE_HOSTNAME "/etc/HOSTNAME"
|
|
|
|
|
#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname"
|
|
|
|
|
|
2018-07-12 10:56:35 +02:00
|
|
|
#define CONF_DHCP SYSCONFDIR "/sysconfig/network/dhcp"
|
2017-06-26 17:19:54 -05:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
#if (defined(HOSTNAME_PERSIST_SUSE) + defined(HOSTNAME_PERSIST_SLACKWARE) \
|
|
|
|
|
+ defined(HOSTNAME_PERSIST_GENTOO)) \
|
|
|
|
|
> 1
|
2021-07-09 08:48:48 +02:00
|
|
|
#error "Can only define one of HOSTNAME_PERSIST_*"
|
2017-04-23 00:40:46 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(HOSTNAME_PERSIST_SUSE)
|
2021-07-09 08:48:48 +02:00
|
|
|
#define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME
|
2017-04-23 00:40:46 +02:00
|
|
|
#elif defined(HOSTNAME_PERSIST_SLACKWARE)
|
2021-07-09 08:48:48 +02:00
|
|
|
#define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME
|
2017-04-23 00:40:46 +02:00
|
|
|
#elif defined(HOSTNAME_PERSIST_GENTOO)
|
2021-07-09 08:48:48 +02:00
|
|
|
#define HOSTNAME_FILE HOSTNAME_FILE_GENTOO
|
2017-04-23 00:40:46 +02:00
|
|
|
#else
|
2021-07-09 08:48:48 +02:00
|
|
|
#define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT
|
2017-04-23 00:40:46 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2022-01-04 18:28:46 +01:00
|
|
|
NM_GOBJECT_PROPERTIES_DEFINE(NMHostnameManager, PROP_STATIC_HOSTNAME, );
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
typedef struct {
|
2022-01-04 18:28:46 +01:00
|
|
|
char *static_hostname;
|
2017-04-23 00:40:46 +02:00
|
|
|
GFileMonitor *monitor;
|
|
|
|
|
GFileMonitor *dhcp_monitor;
|
|
|
|
|
gulong monitor_id;
|
|
|
|
|
gulong dhcp_monitor_id;
|
2021-11-09 13:28:54 +01:00
|
|
|
GDBusProxy *hostnamed_proxy;
|
2017-04-23 00:40:46 +02:00
|
|
|
} NMHostnameManagerPrivate;
|
|
|
|
|
|
|
|
|
|
struct _NMHostnameManager {
|
|
|
|
|
GObject parent;
|
|
|
|
|
NMHostnameManagerPrivate _priv;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _NMHostnameManagerClass {
|
|
|
|
|
GObjectClass parent;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(NMHostnameManager, nm_hostname_manager, G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
|
|
#define NM_HOSTNAME_MANAGER_GET_PRIVATE(self) \
|
|
|
|
|
_NM_GET_PRIVATE(self, NMHostnameManager, NM_IS_HOSTNAME_MANAGER)
|
|
|
|
|
|
|
|
|
|
NM_DEFINE_SINGLETON_GETTER(NMHostnameManager, nm_hostname_manager_get, NM_TYPE_HOSTNAME_MANAGER);
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#define _NMLOG_DOMAIN LOGD_CORE
|
|
|
|
|
#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "hostname", __VA_ARGS__)
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-06-24 15:27:05 +02:00
|
|
|
static inline GFileMonitor *
|
|
|
|
|
_file_monitor_new(const char *path)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_object GFile *file = NULL;
|
|
|
|
|
|
|
|
|
|
nm_assert(path);
|
|
|
|
|
|
|
|
|
|
file = g_file_new_for_path(path);
|
|
|
|
|
return g_file_monitor_file(file, G_FILE_MONITOR_NONE, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
#if defined(HOSTNAME_PERSIST_GENTOO)
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
static char *
|
2017-04-23 00:40:46 +02:00
|
|
|
read_hostname_gentoo(const char *path)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free char *contents = NULL;
|
2017-04-23 00:40:46 +02:00
|
|
|
gs_strfreev char **all_lines = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *tmp;
|
2017-04-23 00:40:46 +02:00
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
if (!g_file_get_contents(path, &contents, NULL, NULL))
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
all_lines = g_strsplit(contents, "\n", 0);
|
|
|
|
|
for (i = 0; all_lines[i]; i++) {
|
|
|
|
|
g_strstrip(all_lines[i]);
|
|
|
|
|
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
|
|
|
|
|
continue;
|
|
|
|
|
if (g_str_has_prefix(all_lines[i], "hostname=")) {
|
|
|
|
|
tmp = &all_lines[i][NM_STRLEN("hostname=")];
|
|
|
|
|
return g_shell_unquote(tmp, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(HOSTNAME_PERSIST_SLACKWARE)
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
static char *
|
2017-04-23 00:40:46 +02:00
|
|
|
read_hostname_slackware(const char *path)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free char *contents = NULL;
|
2017-04-23 00:40:46 +02:00
|
|
|
gs_strfreev char **all_lines = NULL;
|
2017-11-13 00:17:38 -06:00
|
|
|
guint i = 0;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
if (!g_file_get_contents(path, &contents, NULL, NULL))
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
all_lines = g_strsplit(contents, "\n", 0);
|
|
|
|
|
for (i = 0; all_lines[i]; i++) {
|
|
|
|
|
g_strstrip(all_lines[i]);
|
|
|
|
|
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
|
|
|
|
|
continue;
|
2017-11-13 00:17:38 -06:00
|
|
|
return g_shell_unquote(&all_lines[i][0], NULL);
|
2017-04-23 00:40:46 +02:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(HOSTNAME_PERSIST_SUSE)
|
|
|
|
|
static gboolean
|
|
|
|
|
hostname_is_dynamic(void)
|
|
|
|
|
{
|
|
|
|
|
GIOChannel *channel;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *str = NULL;
|
2017-04-23 00:40:46 +02:00
|
|
|
gboolean dynamic = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
channel = g_io_channel_new_file(CONF_DHCP, "r", NULL);
|
|
|
|
|
if (!channel)
|
|
|
|
|
return dynamic;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
while (g_io_channel_read_line(channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
|
|
|
|
|
if (str) {
|
|
|
|
|
g_strstrip(str);
|
|
|
|
|
if (g_str_has_prefix(str, "DHCLIENT_SET_HOSTNAME="))
|
|
|
|
|
dynamic = strcmp(&str[NM_STRLEN("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0;
|
|
|
|
|
g_free(str);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
g_io_channel_shutdown(channel, FALSE, NULL);
|
|
|
|
|
g_io_channel_unref(channel);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
return dynamic;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-04-23 14:20:37 +02:00
|
|
|
const char *
|
2022-01-04 18:28:46 +01:00
|
|
|
nm_hostname_manager_get_static_hostname(NMHostnameManager *self)
|
2017-04-23 14:20:37 +02:00
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_HOSTNAME_MANAGER(self), NULL);
|
2022-01-04 18:28:46 +01:00
|
|
|
|
|
|
|
|
return NM_HOSTNAME_MANAGER_GET_PRIVATE(self)->static_hostname;
|
2017-04-23 14:20:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2021-06-24 15:02:56 +02:00
|
|
|
_set_hostname(NMHostnameManager *self, const char *hostname)
|
2017-04-23 14:20:37 +02:00
|
|
|
{
|
2022-01-04 19:00:34 +01:00
|
|
|
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
|
|
|
|
gs_free char *hostname_free = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *old_hostname;
|
2021-06-24 15:02:56 +02:00
|
|
|
|
|
|
|
|
hostname = nm_str_not_empty(hostname);
|
|
|
|
|
|
2022-01-04 19:00:34 +01:00
|
|
|
if (hostname) {
|
|
|
|
|
/* as we also read the file from disk, it might not be in UTF-8 encoding.
|
|
|
|
|
*
|
|
|
|
|
* A hostname in non-UTF-8 encoding would be odd and cause issues when we
|
|
|
|
|
* try to expose them on D-Bus via the NM_SETTINGS_STATIC_HOSTNAME property.
|
|
|
|
|
*
|
|
|
|
|
* Sanitize somewhat. It's wrong anyway. */
|
|
|
|
|
hostname = nm_utils_str_utf8safe_escape(hostname,
|
|
|
|
|
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
|
|
|
|
|
&hostname_free);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 18:28:46 +01:00
|
|
|
if (nm_streq0(hostname, priv->static_hostname))
|
2021-06-24 15:02:56 +02:00
|
|
|
return;
|
2017-04-23 14:20:37 +02:00
|
|
|
|
2022-01-04 18:28:46 +01:00
|
|
|
_LOGI("static hostname changed from %s%s%s to %s%s%s",
|
|
|
|
|
NM_PRINT_FMT_QUOTED(priv->static_hostname, "\"", priv->static_hostname, "\"", "(none)"),
|
2017-04-23 14:20:37 +02:00
|
|
|
NM_PRINT_FMT_QUOTED(hostname, "\"", hostname, "\"", "(none)"));
|
|
|
|
|
|
2022-01-04 18:28:46 +01:00
|
|
|
old_hostname = priv->static_hostname;
|
|
|
|
|
priv->static_hostname = g_strdup(hostname);
|
2021-06-24 15:02:56 +02:00
|
|
|
g_free(old_hostname);
|
2017-04-23 14:20:37 +02:00
|
|
|
|
2022-01-04 18:28:46 +01:00
|
|
|
_notify(self, PROP_STATIC_HOSTNAME);
|
2017-04-23 14:20:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2021-06-24 15:02:56 +02:00
|
|
|
_set_hostname_read_file(NMHostnameManager *self)
|
2017-04-23 14:20:37 +02:00
|
|
|
{
|
2021-06-24 15:02:56 +02:00
|
|
|
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free char *hostname = NULL;
|
2017-04-23 14:20:37 +02:00
|
|
|
|
|
|
|
|
if (priv->hostnamed_proxy) {
|
|
|
|
|
/* read-hostname returns the current hostname with hostnamed. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 15:02:56 +02:00
|
|
|
#if defined(HOSTNAME_PERSIST_SUSE)
|
|
|
|
|
if (priv->dhcp_monitor_id && hostname_is_dynamic())
|
2017-04-23 14:20:37 +02:00
|
|
|
return;
|
2021-06-24 15:02:56 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(HOSTNAME_PERSIST_GENTOO)
|
|
|
|
|
hostname = read_hostname_gentoo(HOSTNAME_FILE);
|
|
|
|
|
#elif defined(HOSTNAME_PERSIST_SLACKWARE)
|
2022-05-27 11:05:11 +02:00
|
|
|
hostname = read_hostname_slackware(HOSTNAME_FILE);
|
2021-06-24 15:02:56 +02:00
|
|
|
#else
|
|
|
|
|
if (g_file_get_contents(HOSTNAME_FILE, &hostname, NULL, NULL))
|
|
|
|
|
g_strchomp(hostname);
|
|
|
|
|
#endif
|
2017-04-23 14:20:37 +02:00
|
|
|
|
2021-06-24 15:02:56 +02:00
|
|
|
_set_hostname(self, hostname);
|
2017-04-23 14:20:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
static void
|
|
|
|
|
set_transient_hostname_done(GObject *object, GAsyncResult *res, gpointer user_data)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
GDBusProxy *proxy = G_DBUS_PROXY(object);
|
|
|
|
|
gs_unref_variant GVariant *result = NULL;
|
|
|
|
|
gs_free_error GError *error = NULL;
|
|
|
|
|
gs_free char *hostname = NULL;
|
2021-06-24 15:10:08 +02:00
|
|
|
NMHostnameManagerSetHostnameCb cb;
|
|
|
|
|
gpointer cb_user_data;
|
|
|
|
|
|
|
|
|
|
nm_utils_user_data_unpack(user_data, &hostname, &cb, &cb_user_data);
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
result = g_dbus_proxy_call_finish(proxy, res, &error);
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
_LOGW("couldn't set the system hostname to '%s' using hostnamed: %s",
|
2021-06-24 15:10:08 +02:00
|
|
|
hostname,
|
2017-04-23 00:40:46 +02:00
|
|
|
error->message);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 15:10:08 +02:00
|
|
|
cb(hostname, !error, cb_user_data);
|
2017-04-23 00:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_hostname_manager_set_transient_hostname(NMHostnameManager *self,
|
|
|
|
|
const char *hostname,
|
2017-04-23 00:40:46 +02:00
|
|
|
NMHostnameManagerSetHostnameCb cb,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMHostnameManagerPrivate *priv;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
g_return_if_fail(NM_IS_HOSTNAME_MANAGER(self));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
if (!priv->hostnamed_proxy) {
|
|
|
|
|
cb(hostname, FALSE, user_data);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
g_dbus_proxy_call(priv->hostnamed_proxy,
|
|
|
|
|
"SetHostname",
|
|
|
|
|
g_variant_new("(sb)", hostname, FALSE),
|
|
|
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
|
|
|
|
set_transient_hostname_done,
|
2021-06-24 15:10:08 +02:00
|
|
|
nm_utils_user_data_pack(g_strdup(hostname), cb, user_data));
|
2017-04-23 00:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
nm_hostname_manager_get_transient_hostname(NMHostnameManager *self, char **hostname)
|
|
|
|
|
{
|
|
|
|
|
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
2021-11-09 13:28:54 +01:00
|
|
|
GVariant *v_hostname;
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
if (!priv->hostnamed_proxy)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
v_hostname = g_dbus_proxy_get_cached_property(priv->hostnamed_proxy, "Hostname");
|
|
|
|
|
if (!v_hostname) {
|
|
|
|
|
_LOGT("transient hostname retrieval failed");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*hostname = g_variant_dup_string(v_hostname, NULL);
|
|
|
|
|
g_variant_unref(v_hostname);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-27 11:45:50 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_write_hostname_dbus_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_object GTask *task = G_TASK(user_data);
|
|
|
|
|
gs_unref_variant GVariant *res = NULL;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
res = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, &error);
|
|
|
|
|
if (!res) {
|
|
|
|
|
g_task_return_error(task, error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
g_task_return_boolean(task, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_write_hostname_on_idle_cb(gpointer user_data, GCancellable *cancellable)
|
2017-04-23 00:40:46 +02:00
|
|
|
{
|
2022-05-30 18:46:27 +02:00
|
|
|
gs_unref_object GTask *task = G_TASK(user_data);
|
|
|
|
|
NMHostnameManager *self;
|
|
|
|
|
NMHostnameManagerPrivate *priv;
|
|
|
|
|
const char *hostname;
|
|
|
|
|
gs_free char *hostname_eol = NULL;
|
|
|
|
|
gboolean ret;
|
|
|
|
|
gs_free_error GError *error = NULL;
|
|
|
|
|
const char *file = HOSTNAME_FILE;
|
|
|
|
|
gs_free char *link_path = NULL;
|
|
|
|
|
struct stat file_stat;
|
2017-04-23 00:40:46 +02:00
|
|
|
#if HAVE_SELINUX
|
2020-08-12 13:31:31 +02:00
|
|
|
gboolean fcon_was_set = FALSE;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *fcon_prev = NULL;
|
2017-04-23 00:40:46 +02:00
|
|
|
#endif
|
|
|
|
|
|
2022-05-27 11:45:50 +02:00
|
|
|
if (g_task_return_error_if_cancelled(task))
|
|
|
|
|
return;
|
2017-04-23 00:40:46 +02:00
|
|
|
|
2022-05-27 11:45:50 +02:00
|
|
|
self = g_task_get_source_object(task);
|
2017-04-23 00:40:46 +02:00
|
|
|
priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
|
|
|
|
|
2022-05-27 11:45:50 +02:00
|
|
|
nm_assert(!priv->hostnamed_proxy);
|
|
|
|
|
|
|
|
|
|
hostname = g_task_get_task_data(task);
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
/* If the hostname file is a symbolic link, follow it to find where the
|
|
|
|
|
* real file is located, otherwise g_file_set_contents will attempt to
|
|
|
|
|
* replace the link with a plain file.
|
|
|
|
|
*/
|
|
|
|
|
if (lstat(file, &file_stat) == 0 && S_ISLNK(file_stat.st_mode)
|
|
|
|
|
&& (link_path = nm_utils_read_link_absolute(file, NULL)))
|
|
|
|
|
file = link_path;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2022-05-27 11:05:11 +02:00
|
|
|
if (hostname) {
|
2017-04-23 00:40:46 +02:00
|
|
|
#if defined(HOSTNAME_PERSIST_GENTOO)
|
2022-05-27 11:05:11 +02:00
|
|
|
hostname_eol = g_strdup_printf("#Generated by NetworkManager\n"
|
|
|
|
|
"hostname=\"%s\"\n",
|
|
|
|
|
hostname);
|
2017-04-23 00:40:46 +02:00
|
|
|
#else
|
2022-05-27 11:05:11 +02:00
|
|
|
hostname_eol = g_strdup_printf("%s\n", hostname);
|
2017-04-23 00:40:46 +02:00
|
|
|
#endif
|
2022-05-27 11:05:11 +02:00
|
|
|
}
|
2017-04-23 00:40:46 +02:00
|
|
|
|
2020-08-12 13:31:31 +02:00
|
|
|
#if HAVE_SELINUX
|
|
|
|
|
/* Get default context for hostname file and set it for fscreate */
|
|
|
|
|
{
|
|
|
|
|
struct selabel_handle *handle;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-12 13:31:31 +02:00
|
|
|
handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
|
|
|
|
if (handle) {
|
|
|
|
|
mode_t st_mode = 0;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *fcon = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-12 13:31:31 +02:00
|
|
|
if (stat(file, &file_stat) == 0)
|
|
|
|
|
st_mode = file_stat.st_mode;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-12 13:31:31 +02:00
|
|
|
if ((selabel_lookup(handle, &fcon, file, st_mode) == 0)
|
|
|
|
|
&& (getfscreatecon(&fcon_prev) == 0)) {
|
|
|
|
|
setfscreatecon(fcon);
|
|
|
|
|
fcon_was_set = TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-12 13:31:31 +02:00
|
|
|
selabel_close(handle);
|
|
|
|
|
freecon(fcon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-05-27 11:05:11 +02:00
|
|
|
ret = g_file_set_contents(file, hostname_eol ?: "", -1, &error);
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
#if HAVE_SELINUX
|
|
|
|
|
/* Restore previous context and cleanup */
|
2020-08-12 13:31:31 +02:00
|
|
|
if (fcon_was_set)
|
|
|
|
|
setfscreatecon(fcon_prev);
|
|
|
|
|
if (fcon_prev)
|
|
|
|
|
freecon(fcon_prev);
|
2017-04-23 00:40:46 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (!ret) {
|
2022-05-27 11:45:50 +02:00
|
|
|
g_task_return_new_error(task,
|
|
|
|
|
NM_UTILS_ERROR,
|
|
|
|
|
NM_UTILS_ERROR_UNKNOWN,
|
|
|
|
|
"could not save hostname to %s: %s",
|
|
|
|
|
file,
|
|
|
|
|
error->message);
|
|
|
|
|
return;
|
2017-04-23 00:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-27 11:45:50 +02:00
|
|
|
g_task_return_boolean(task, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nm_hostname_manager_write_hostname(NMHostnameManager *self,
|
|
|
|
|
const char *hostname,
|
|
|
|
|
GCancellable *cancellable,
|
|
|
|
|
GAsyncReadyCallback callback,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMHostnameManagerPrivate *priv;
|
|
|
|
|
GTask *task;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(NM_IS_HOSTNAME_MANAGER(self));
|
|
|
|
|
|
|
|
|
|
priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
|
|
|
|
|
|
|
|
|
task =
|
|
|
|
|
nm_g_task_new(self, cancellable, nm_hostname_manager_write_hostname, callback, user_data);
|
|
|
|
|
|
|
|
|
|
g_task_set_task_data(task, g_strdup(hostname), g_free);
|
|
|
|
|
|
|
|
|
|
if (priv->hostnamed_proxy) {
|
|
|
|
|
g_dbus_proxy_call(priv->hostnamed_proxy,
|
|
|
|
|
"SetStaticHostname",
|
|
|
|
|
g_variant_new("(sb)", hostname ?: "", FALSE),
|
|
|
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
|
|
|
15000,
|
|
|
|
|
cancellable,
|
|
|
|
|
_write_hostname_dbus_cb,
|
|
|
|
|
task);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_utils_invoke_on_idle(cancellable, _write_hostname_on_idle_cb, task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
nm_hostname_manager_write_hostname_finish(NMHostnameManager *self,
|
|
|
|
|
GAsyncResult *result,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_HOSTNAME_MANAGER(self), FALSE);
|
|
|
|
|
g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_hostname_manager_write_hostname),
|
|
|
|
|
FALSE);
|
|
|
|
|
|
|
|
|
|
return g_task_propagate_boolean(G_TASK(result), error);
|
2017-04-23 00:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
hostnamed_properties_changed(GDBusProxy *proxy,
|
2021-11-09 13:28:54 +01:00
|
|
|
GVariant *changed_properties,
|
|
|
|
|
char **invalidated_properties,
|
2017-04-23 00:40:46 +02:00
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
NMHostnameManager *self = user_data;
|
|
|
|
|
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
2021-06-24 15:02:56 +02:00
|
|
|
gs_unref_variant GVariant *variant = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-24 15:02:56 +02:00
|
|
|
variant = g_dbus_proxy_get_cached_property(priv->hostnamed_proxy, "StaticHostname");
|
|
|
|
|
if (variant && g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING))
|
|
|
|
|
_set_hostname(self, g_variant_get_string(variant, NULL));
|
2017-04-23 00:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-24 15:27:05 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_file_monitors_file_changed_cb(GFileMonitor *monitor,
|
|
|
|
|
GFile *file,
|
|
|
|
|
GFile *other_file,
|
2021-06-24 15:27:05 +02:00
|
|
|
GFileMonitorEvent event_type,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
_set_hostname_read_file(user_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_file_monitors_clear(NMHostnameManager *self)
|
|
|
|
|
{
|
|
|
|
|
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
|
|
|
|
|
|
|
|
|
if (priv->monitor) {
|
|
|
|
|
nm_clear_g_signal_handler(priv->monitor, &priv->monitor_id);
|
|
|
|
|
g_file_monitor_cancel(priv->monitor);
|
|
|
|
|
g_clear_object(&priv->monitor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (priv->dhcp_monitor) {
|
|
|
|
|
nm_clear_g_signal_handler(priv->dhcp_monitor, &priv->dhcp_monitor_id);
|
|
|
|
|
g_file_monitor_cancel(priv->dhcp_monitor);
|
|
|
|
|
g_clear_object(&priv->dhcp_monitor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
static void
|
2021-06-24 15:27:05 +02:00
|
|
|
_file_monitors_setup(NMHostnameManager *self)
|
2017-04-23 00:40:46 +02:00
|
|
|
{
|
|
|
|
|
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
2021-11-09 13:28:54 +01:00
|
|
|
GFileMonitor *monitor;
|
|
|
|
|
const char *path = HOSTNAME_FILE;
|
|
|
|
|
gs_free char *link_path = NULL;
|
2017-04-23 00:40:46 +02:00
|
|
|
struct stat file_stat;
|
2021-06-24 15:27:05 +02:00
|
|
|
|
|
|
|
|
_file_monitors_clear(self);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
/* resolve the path to the hostname file if it is a symbolic link */
|
|
|
|
|
if (lstat(path, &file_stat) == 0 && S_ISLNK(file_stat.st_mode)
|
|
|
|
|
&& (link_path = nm_utils_read_link_absolute(path, NULL))) {
|
|
|
|
|
path = link_path;
|
|
|
|
|
if (lstat(link_path, &file_stat) == 0 && S_ISLNK(file_stat.st_mode)) {
|
|
|
|
|
_LOGW("only one level of symbolic link indirection is allowed when "
|
|
|
|
|
"monitoring " HOSTNAME_FILE);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
/* monitor changes to hostname file */
|
2021-06-24 15:27:05 +02:00
|
|
|
monitor = _file_monitor_new(path);
|
2017-04-23 00:40:46 +02:00
|
|
|
if (monitor) {
|
|
|
|
|
priv->monitor_id =
|
2021-06-24 15:27:05 +02:00
|
|
|
g_signal_connect(monitor, "changed", G_CALLBACK(_file_monitors_file_changed_cb), self);
|
2017-04-23 00:40:46 +02:00
|
|
|
priv->monitor = monitor;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
#if defined(HOSTNAME_PERSIST_SUSE)
|
|
|
|
|
/* monitor changes to dhcp file to know whether the hostname is valid */
|
2021-06-24 15:27:05 +02:00
|
|
|
monitor = _file_monitor_new(CONF_DHCP);
|
2017-04-23 00:40:46 +02:00
|
|
|
if (monitor) {
|
|
|
|
|
priv->dhcp_monitor_id =
|
2021-06-24 15:27:05 +02:00
|
|
|
g_signal_connect(monitor, "changed", G_CALLBACK(_file_monitors_file_changed_cb), self);
|
2017-04-23 00:40:46 +02:00
|
|
|
priv->dhcp_monitor = monitor;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-06-24 15:02:56 +02:00
|
|
|
_set_hostname_read_file(self);
|
2017-04-23 00:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
NMHostnameManager *self = NM_HOSTNAME_MANAGER(object);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
switch (prop_id) {
|
2022-01-04 18:28:46 +01:00
|
|
|
case PROP_STATIC_HOSTNAME:
|
|
|
|
|
g_value_set_string(value, nm_hostname_manager_get_static_hostname(self));
|
2017-04-23 00:40:46 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_hostname_manager_init(NMHostnameManager *self)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
constructed(GObject *object)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
NMHostnameManager *self = NM_HOSTNAME_MANAGER(object);
|
2017-04-23 00:40:46 +02:00
|
|
|
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
2021-11-09 13:28:54 +01:00
|
|
|
GDBusProxy *proxy;
|
|
|
|
|
GVariant *variant;
|
|
|
|
|
gs_free_error GError *error = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
HOSTNAMED_SERVICE_NAME,
|
|
|
|
|
HOSTNAMED_SERVICE_PATH,
|
|
|
|
|
HOSTNAMED_SERVICE_INTERFACE,
|
|
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
if (proxy) {
|
|
|
|
|
variant = g_dbus_proxy_get_cached_property(proxy, "StaticHostname");
|
|
|
|
|
if (variant) {
|
|
|
|
|
_LOGI("hostname: using hostnamed");
|
|
|
|
|
priv->hostnamed_proxy = proxy;
|
|
|
|
|
g_signal_connect(proxy,
|
|
|
|
|
"g-properties-changed",
|
|
|
|
|
G_CALLBACK(hostnamed_properties_changed),
|
|
|
|
|
self);
|
|
|
|
|
hostnamed_properties_changed(proxy, NULL, NULL, self);
|
|
|
|
|
g_variant_unref(variant);
|
|
|
|
|
} else {
|
|
|
|
|
_LOGI("hostname: couldn't get property from hostnamed");
|
|
|
|
|
g_object_unref(proxy);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
_LOGI("hostname: hostnamed not used as proxy creation failed with: %s", error->message);
|
|
|
|
|
g_clear_error(&error);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
if (!priv->hostnamed_proxy)
|
2021-06-24 15:27:05 +02:00
|
|
|
_file_monitors_setup(self);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-04-23 00:40:46 +02:00
|
|
|
G_OBJECT_CLASS(nm_hostname_manager_parent_class)->constructed(object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dispose(GObject *object)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
NMHostnameManager *self = NM_HOSTNAME_MANAGER(object);
|
2017-04-23 00:40:46 +02:00
|
|
|
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self);
|
|
|
|
|
|
|
|
|
|
if (priv->hostnamed_proxy) {
|
|
|
|
|
g_signal_handlers_disconnect_by_func(priv->hostnamed_proxy,
|
|
|
|
|
G_CALLBACK(hostnamed_properties_changed),
|
|
|
|
|
self);
|
|
|
|
|
g_clear_object(&priv->hostnamed_proxy);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 15:27:05 +02:00
|
|
|
_file_monitors_clear(self);
|
2017-04-23 00:40:46 +02:00
|
|
|
|
2022-01-04 18:28:46 +01:00
|
|
|
nm_clear_g_free(&priv->static_hostname);
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(nm_hostname_manager_parent_class)->dispose(object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_hostname_manager_class_init(NMHostnameManagerClass *class)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS(class);
|
|
|
|
|
|
|
|
|
|
object_class->constructed = constructed;
|
|
|
|
|
object_class->get_property = get_property;
|
|
|
|
|
object_class->dispose = dispose;
|
|
|
|
|
|
2022-01-04 18:28:46 +01:00
|
|
|
obj_properties[PROP_STATIC_HOSTNAME] =
|
|
|
|
|
g_param_spec_string(NM_HOSTNAME_MANAGER_STATIC_HOSTNAME,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
NULL,
|
|
|
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
2017-04-23 00:40:46 +02:00
|
|
|
|
|
|
|
|
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
|
|
|
|
}
|