mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-05 22:00:32 +01:00
core: move handling of hostname from plugins to core
How to write and read the machine hostname is something that has been handled until now by plugins; this is questionable since the method using for storing the hostname should depend only on the distro used and not on which plugins are enabled. This commit moves all hostname-related functions from plugins to the core and allows to specify the method used to load and store the hostname at build time with the --with-hostname-persist=default|suse|gentoo configure option. 'default' method stores the hostname to /etc/hostname and monitors it to detect runtime changes. When the selected method is 'suse', the hostname gets read from and written to /etc/HOSTNAME; the file /etc/sysconfig/network/dhcp is also read to detect if the hostname is dynamic and thus invalid. Both files are monitored for changes. 'gentoo' method relies on /etc/conf.d/hostname for storing the hostname.
This commit is contained in:
parent
fb304bc6b9
commit
6c3d71c431
2 changed files with 258 additions and 46 deletions
26
configure.ac
26
configure.ac
|
|
@ -119,6 +119,13 @@ if test -z "$config_plugins_default" -o "$config_plugins_default" = no; then
|
|||
test "$enable_config_plugin_ibft" = "yes" && config_plugins_default="$config_plugins_default,ibft"
|
||||
config_plugins_default="${config_plugins_default#,}"
|
||||
fi
|
||||
|
||||
test "$enable_ifcfg_rh" = "yes" && distro_plugins="$distro_plugins,ifcfg-rh"
|
||||
test "$enable_ifcfg_suse" = "yes" && distro_plugins="$distro_plugins,ifcfg-suse"
|
||||
test "$enable_ifupdown" = "yes" && distro_plugins="$distro_plugins,ifupdown"
|
||||
test "$enable_ifnet" = "yes" && distro_plugins="$distro_plugins,ifnet"
|
||||
distro_plugins="${distro_plugins#,}"
|
||||
|
||||
AC_DEFINE_UNQUOTED(CONFIG_PLUGINS_DEFAULT, "$config_plugins_default", [Default configuration option for main.plugins setting])
|
||||
|
||||
if test "$enable_ifcfg_rh" = "yes"; then
|
||||
|
|
@ -347,6 +354,24 @@ fi
|
|||
PKG_CHECK_MODULES(SYSTEMD_200, [systemd >= 200], [have_systemd_200=yes],[have_systemd_200=no])
|
||||
AM_CONDITIONAL(HAVE_SYSTEMD_200, test "${have_systemd_200}" = "yes")
|
||||
|
||||
# Hostname persist mode
|
||||
AC_ARG_WITH(hostname-persist, AS_HELP_STRING([--with-hostname-persist=default|suse|gentoo],
|
||||
[Hostname persist method]))
|
||||
|
||||
AS_IF([test "$with_hostname_persist" = "suse"], hostname_persist=suse)
|
||||
AS_IF([test "$with_hostname_persist" = "gentoo"], hostname_persist=gentoo)
|
||||
AS_IF([test "$with_hostname_persist" = "default"], hostname_persist=default)
|
||||
# if the method was not explicitly set, try to guess it from the enabled plugins
|
||||
AS_IF([test -z "$hostname_persist" -a "$distro_plugins" = "ifcfg-suse"], hostname_persist=suse)
|
||||
AS_IF([test -z "$hostname_persist" -a "$distro_plugins" = "ifnet"], hostname_persist=gentoo)
|
||||
AS_IF([test -z "$hostname_persist"], hostname_persist=default)
|
||||
|
||||
if test "$hostname_persist" = suse; then
|
||||
AC_DEFINE(HOSTNAME_PERSIST_SUSE, 1, [Enable SuSE hostname persist method])
|
||||
elif test "$hostname_persist" = gentoo; then
|
||||
AC_DEFINE(HOSTNAME_PERSIST_GENTOO, 1, [Enable Gentoo hostname persist method])
|
||||
fi
|
||||
|
||||
# Session tracking support
|
||||
AC_ARG_WITH(systemd-logind, AS_HELP_STRING([--with-systemd-logind=yes|no],
|
||||
[Support systemd session tracking]))
|
||||
|
|
@ -1063,6 +1088,7 @@ else
|
|||
fi
|
||||
echo " polkit agent: ${enable_polkit_agent}"
|
||||
echo " selinux: $have_selinux"
|
||||
echo " hostname persist: ${hostname_persist}"
|
||||
echo
|
||||
|
||||
echo "Features:"
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@
|
|||
#include <dbus/dbus.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
#if HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#include "gsystem-local-alloc.h"
|
||||
#include <nm-dbus-interface.h>
|
||||
#include <nm-connection.h>
|
||||
|
|
@ -94,6 +98,20 @@ EXPORT(nm_settings_connection_replace_settings)
|
|||
EXPORT(nm_settings_connection_replace_and_commit)
|
||||
/* END LINKER CRACKROCK */
|
||||
|
||||
#define HOSTNAME_FILE_DEFAULT "/etc/hostname"
|
||||
#define HOSTNAME_FILE_SUSE "/etc/HOSTNAME"
|
||||
#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname"
|
||||
#define IFCFG_DIR SYSCONFDIR "/sysconfig/network"
|
||||
#define CONF_DHCP IFCFG_DIR "/dhcp"
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_SUSE)
|
||||
#define HOSTNAME_FILE HOSTNAME_FILE_SUSE
|
||||
#elif defined(HOSTNAME_PERSIST_GENTOO)
|
||||
#define HOSTNAME_FILE HOSTNAME_FILE_GENTOO
|
||||
#else
|
||||
#define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT
|
||||
#endif
|
||||
|
||||
static void claim_connection (NMSettings *self,
|
||||
NMSettingsConnection *connection);
|
||||
|
||||
|
|
@ -152,6 +170,15 @@ typedef struct {
|
|||
GSList *get_connections_cache;
|
||||
|
||||
gboolean startup_complete;
|
||||
|
||||
struct {
|
||||
char *value;
|
||||
char *file;
|
||||
GFileMonitor *monitor;
|
||||
GFileMonitor *dhcp_monitor;
|
||||
guint monitor_id;
|
||||
guint dhcp_monitor_id;
|
||||
} hostname;
|
||||
} NMSettingsPrivate;
|
||||
|
||||
#define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate))
|
||||
|
|
@ -497,7 +524,7 @@ get_plugin (NMSettings *self, guint32 capability)
|
|||
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
|
||||
/* Do any of the plugins support setting the hostname? */
|
||||
/* Do any of the plugins support the given capability? */
|
||||
for (iter = priv->plugins; iter; iter = iter->next) {
|
||||
NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
|
||||
|
||||
|
|
@ -509,30 +536,88 @@ get_plugin (NMSettings *self, guint32 capability)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_GENTOO)
|
||||
static gchar *
|
||||
read_hostname_gentoo (const char *path)
|
||||
{
|
||||
gchar *contents = NULL, *result = NULL, *tmp;
|
||||
gchar **all_lines = NULL;
|
||||
guint line_num, i;
|
||||
|
||||
if (!g_file_get_contents (path, &contents, NULL, NULL))
|
||||
return NULL;
|
||||
all_lines = g_strsplit (contents, "\n", 0);
|
||||
line_num = g_strv_length (all_lines);
|
||||
for (i = 0; i < line_num; 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][STRLEN ("hostname=")];
|
||||
result = g_shell_unquote (tmp, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_strfreev (all_lines);
|
||||
g_free (contents);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_SUSE)
|
||||
static gboolean
|
||||
hostname_is_dynamic (void)
|
||||
{
|
||||
GIOChannel *channel;
|
||||
char *str = NULL;
|
||||
gboolean dynamic = FALSE;
|
||||
|
||||
channel = g_io_channel_new_file (CONF_DHCP, "r", NULL);
|
||||
if (!channel)
|
||||
return dynamic;
|
||||
|
||||
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[STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0;
|
||||
g_free (str);
|
||||
}
|
||||
}
|
||||
|
||||
g_io_channel_shutdown (channel, FALSE, NULL);
|
||||
g_io_channel_unref (channel);
|
||||
|
||||
return dynamic;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Returns an allocated string which the caller owns and must eventually free */
|
||||
char *
|
||||
nm_settings_get_hostname (NMSettings *self)
|
||||
{
|
||||
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
|
||||
GSList *iter;
|
||||
char *hostname = NULL;
|
||||
|
||||
/* Hostname returned is the hostname returned from the first plugin
|
||||
* that provides one.
|
||||
*/
|
||||
for (iter = priv->plugins; iter; iter = iter->next) {
|
||||
NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
|
||||
#if defined(HOSTNAME_PERSIST_GENTOO)
|
||||
hostname = read_hostname_gentoo (priv->hostname.file);
|
||||
#else
|
||||
|
||||
g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
|
||||
if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) {
|
||||
g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, &hostname, NULL);
|
||||
if (hostname && strlen (hostname))
|
||||
return hostname;
|
||||
g_free (hostname);
|
||||
}
|
||||
#if defined(HOSTNAME_PERSIST_SUSE)
|
||||
if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ())
|
||||
return NULL;
|
||||
#endif
|
||||
if (g_file_get_contents (priv->hostname.file, &hostname, NULL, NULL))
|
||||
g_strchomp (hostname);
|
||||
|
||||
#endif /* HOSTNAME_PERSIST_GENTOO */
|
||||
|
||||
if (hostname && !hostname[0]) {
|
||||
g_free (hostname);
|
||||
hostname = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return hostname;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -595,14 +680,6 @@ unrecognized_specs_changed (NMSystemConfigInterface *config,
|
|||
nm_system_config_interface_get_unrecognized_specs);
|
||||
}
|
||||
|
||||
static void
|
||||
hostname_changed (NMSystemConfigInterface *config,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME);
|
||||
}
|
||||
|
||||
static void
|
||||
add_plugin (NMSettings *self, NMSystemConfigInterface *plugin)
|
||||
{
|
||||
|
|
@ -616,9 +693,6 @@ add_plugin (NMSettings *self, NMSystemConfigInterface *plugin)
|
|||
priv = NM_SETTINGS_GET_PRIVATE (self);
|
||||
|
||||
priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
|
||||
|
||||
g_signal_connect (plugin, "notify::"NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, G_CALLBACK (hostname_changed), self);
|
||||
|
||||
nm_system_config_interface_init (plugin, NULL);
|
||||
|
||||
g_object_get (G_OBJECT (plugin),
|
||||
|
|
@ -1442,6 +1516,56 @@ impl_settings_reload_connections (NMSettings *self,
|
|||
dbus_g_method_return (context, TRUE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
write_hostname (NMSettingsPrivate *priv, const char *hostname)
|
||||
{
|
||||
char *hostname_eol;
|
||||
gboolean ret;
|
||||
gs_free_error GError *error = NULL;
|
||||
const char *file = priv->hostname.file;
|
||||
#if HAVE_SELINUX
|
||||
security_context_t se_ctx_prev = NULL, se_ctx = NULL;
|
||||
struct stat file_stat = { .st_mode = 0 };
|
||||
mode_t st_mode = 0;
|
||||
|
||||
/* Get default context for hostname file and set it for fscreate */
|
||||
if (stat (file, &file_stat) == 0)
|
||||
st_mode = file_stat.st_mode;
|
||||
matchpathcon (file, st_mode, &se_ctx);
|
||||
matchpathcon_fini ();
|
||||
getfscreatecon (&se_ctx_prev);
|
||||
setfscreatecon (se_ctx);
|
||||
#endif
|
||||
|
||||
#if defined (HOSTNAME_PERSIST_GENTOO)
|
||||
hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n"
|
||||
"hostname=\"%s\"\n", hostname);
|
||||
#else
|
||||
hostname_eol = g_strdup_printf ("%s\n", hostname);
|
||||
#endif
|
||||
|
||||
/* FIXME: g_file_set_contents() writes first to a temporary file
|
||||
* and renames it atomically. We should hack g_file_set_contents()
|
||||
* to set the SELINUX labels before renaming the file. */
|
||||
ret = g_file_set_contents (file, hostname_eol, -1, &error);
|
||||
|
||||
#if HAVE_SELINUX
|
||||
/* Restore previous context and cleanup */
|
||||
setfscreatecon (se_ctx_prev);
|
||||
freecon (se_ctx);
|
||||
freecon (se_ctx_prev);
|
||||
#endif
|
||||
|
||||
g_free (hostname_eol);
|
||||
|
||||
if (!ret) {
|
||||
nm_log_warn (LOGD_SETTINGS, "Could not save hostname to %s: %s", file, error->message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pk_hostname_cb (NMAuthChain *chain,
|
||||
GError *chain_error,
|
||||
|
|
@ -1452,7 +1576,6 @@ pk_hostname_cb (NMAuthChain *chain,
|
|||
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
|
||||
NMAuthCallResult result;
|
||||
GError *error = NULL;
|
||||
GSList *iter;
|
||||
const char *hostname;
|
||||
|
||||
g_assert (context);
|
||||
|
|
@ -1472,21 +1595,12 @@ pk_hostname_cb (NMAuthChain *chain,
|
|||
NM_SETTINGS_ERROR_PERMISSION_DENIED,
|
||||
"Insufficient privileges.");
|
||||
} else {
|
||||
/* Set the hostname in all plugins */
|
||||
hostname = nm_auth_chain_get_data (chain, "hostname");
|
||||
for (iter = priv->plugins; iter; iter = iter->next) {
|
||||
NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
|
||||
|
||||
/* error will be cleared if any plugin supports saving the hostname */
|
||||
if (!write_hostname (priv, hostname)) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_FAILED,
|
||||
"Saving the hostname failed.");
|
||||
|
||||
g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
|
||||
if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) {
|
||||
g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, hostname, NULL);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1543,14 +1657,6 @@ impl_settings_save_hostname (NMSettings *self,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* Do any of the plugins support setting the hostname? */
|
||||
if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_NOT_SUPPORTED,
|
||||
"None of the registered plugins support setting the hostname.");
|
||||
goto done;
|
||||
}
|
||||
|
||||
chain = nm_auth_chain_new_context (context, pk_hostname_cb, self);
|
||||
if (!chain) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
|
|
@ -1569,6 +1675,37 @@ done:
|
|||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
static void
|
||||
hostname_maybe_changed (NMSettings *settings)
|
||||
{
|
||||
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (settings);
|
||||
char *new_hostname;
|
||||
|
||||
new_hostname = nm_settings_get_hostname (settings);
|
||||
|
||||
if ( (new_hostname && !priv->hostname.value)
|
||||
|| (!new_hostname && priv->hostname.value)
|
||||
|| (priv->hostname.value && new_hostname && strcmp (priv->hostname.value, new_hostname))) {
|
||||
|
||||
nm_log_info (LOGD_SETTINGS, "hostname changed from '%s' to '%s'",
|
||||
priv->hostname.value, new_hostname);
|
||||
g_free (priv->hostname.value);
|
||||
priv->hostname.value = new_hostname;
|
||||
g_object_notify (G_OBJECT (settings), NM_SETTINGS_HOSTNAME);
|
||||
} else
|
||||
g_free (new_hostname);
|
||||
}
|
||||
|
||||
static void
|
||||
hostname_file_changed_cb (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
hostname_maybe_changed (user_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
have_connection_for_device (NMSettings *self, NMDevice *device)
|
||||
{
|
||||
|
|
@ -1872,6 +2009,8 @@ nm_settings_new (GError **error)
|
|||
{
|
||||
NMSettings *self;
|
||||
NMSettingsPrivate *priv;
|
||||
GFile *file;
|
||||
GFileMonitor *monitor;
|
||||
|
||||
self = g_object_new (NM_TYPE_SETTINGS, NULL);
|
||||
|
||||
|
|
@ -1889,6 +2028,34 @@ nm_settings_new (GError **error)
|
|||
load_connections (self);
|
||||
check_startup_complete (self);
|
||||
|
||||
priv->hostname.file = HOSTNAME_FILE;
|
||||
priv->hostname.value = nm_settings_get_hostname (self);
|
||||
|
||||
/* monitor changes to hostname file */
|
||||
file = g_file_new_for_path (priv->hostname.file);
|
||||
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
if (monitor) {
|
||||
priv->hostname.monitor_id = g_signal_connect (monitor, "changed",
|
||||
G_CALLBACK (hostname_file_changed_cb),
|
||||
self);
|
||||
priv->hostname.monitor = monitor;
|
||||
}
|
||||
|
||||
#if defined (HOSTNAME_PERSIST_SUSE)
|
||||
/* monitor changes to dhcp file to know whether the hostname is valid */
|
||||
file = g_file_new_for_path (CONF_DHCP);
|
||||
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
if (monitor) {
|
||||
priv->hostname.dhcp_monitor_id = g_signal_connect (monitor, "changed",
|
||||
G_CALLBACK (hostname_file_changed_cb),
|
||||
self);
|
||||
priv->hostname.dhcp_monitor = monitor;
|
||||
}
|
||||
#endif
|
||||
|
||||
hostname_maybe_changed (self);
|
||||
nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self);
|
||||
return self;
|
||||
}
|
||||
|
|
@ -1932,6 +2099,25 @@ dispose (GObject *object)
|
|||
|
||||
g_object_unref (priv->agent_mgr);
|
||||
|
||||
if (priv->hostname.monitor) {
|
||||
if (priv->hostname.monitor_id)
|
||||
g_signal_handler_disconnect (priv->hostname.monitor, priv->hostname.monitor_id);
|
||||
|
||||
g_file_monitor_cancel (priv->hostname.monitor);
|
||||
g_clear_object (&priv->hostname.monitor);
|
||||
}
|
||||
|
||||
if (priv->hostname.dhcp_monitor) {
|
||||
if (priv->hostname.dhcp_monitor_id)
|
||||
g_signal_handler_disconnect (priv->hostname.dhcp_monitor,
|
||||
priv->hostname.dhcp_monitor_id);
|
||||
|
||||
g_file_monitor_cancel (priv->hostname.dhcp_monitor);
|
||||
g_clear_object (&priv->hostname.dhcp_monitor);
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->hostname.value, g_free);
|
||||
|
||||
G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
|
@ -2001,7 +2187,7 @@ static void
|
|||
nm_settings_class_init (NMSettingsClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
|
||||
g_type_class_add_private (class, sizeof (NMSettingsPrivate));
|
||||
|
||||
/* virtual methods */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue