From 4090716d96180caaeb807033e0c9a3b4a3092f9b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 18 Feb 2016 18:19:30 +0100 Subject: [PATCH 1/3] core: use hostnamed to set the transient hostname In commit 6dc35e66d45e ("settings: add hostnamed support") we started to use systemd-hostnamed for setting the system static hostname (i.e. the one written to /etc/hostname), but nm-policy.c still called sethostname() to set the transient (dynamic) hostname when this needs to be changed, for example after a reverse lookup of our dynamic IP address. Thus, when using systemd the hostname change failed because process' capabilities are restricted and sethostname() requires CAP_SYS_ADMIN. We should set also the transient hostname through hostnamed when this is available. https://bugzilla.redhat.com/show_bug.cgi?id=1308974 --- src/nm-policy.c | 48 ++++++++++++++++++++----------- src/settings/nm-settings.c | 59 ++++++++++++++++++++++++++++++++++++++ src/settings/nm-settings.h | 7 +++++ 3 files changed, 97 insertions(+), 17 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index bbfc3dd638..c564ff0a52 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -127,9 +127,32 @@ get_best_ip6_device (NMPolicy *self, gboolean fully_activated) #define FALLBACK_HOSTNAME4 "localhost.localdomain" -static gboolean -set_system_hostname (const char *new_hostname, const char *msg) +static void settings_set_hostname_cb (const char *hostname, + gboolean result, + gpointer user_data) { + int ret = 0; + + if (!result) { + ret = sethostname (hostname, strlen (hostname)); + if (ret != 0) { + int errsv = errno; + + _LOGW (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s", + hostname, errsv, strerror (errsv)); + if (errsv == EPERM) + _LOGW (LOGD_DNS, "you should use hostnamed when systemd hardening is in effect!"); + } + } + + if (!ret) + nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL); +} + +static void +set_system_hostname (NMPolicy *self, const char *new_hostname, const char *msg) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); char old_hostname[HOST_NAME_MAX + 1]; const char *name; int ret; @@ -147,23 +170,15 @@ set_system_hostname (const char *new_hostname, const char *msg) /* Don't set the hostname if it isn't actually changing */ if ( (new_hostname && !strcmp (old_hostname, new_hostname)) || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME4))) - return FALSE; + return; } name = (new_hostname && strlen (new_hostname)) ? new_hostname : FALLBACK_HOSTNAME4; - _LOGI (LOGD_DNS, "setting system hostname to '%s' (%s)", name, msg); - ret = sethostname (name, strlen (name)); - if (ret != 0) { - int errsv = errno; - - _LOGW (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s", - name, errsv, strerror (errsv)); - if (errsv == EPERM) - _LOGW (LOGD_DNS, "you should use hostnamed when systemd hardening is in effect!"); - } - - return (ret == 0); + nm_settings_set_transient_hostname (priv->settings, + name, + settings_set_hostname_cb, + NULL); } static void @@ -205,8 +220,7 @@ _set_hostname (NMPolicy *policy, nm_dns_manager_set_hostname (priv->dns_manager, priv->cur_hostname); - if (set_system_hostname (priv->cur_hostname, msg)) - nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL); + set_system_hostname (policy, priv->cur_hostname, msg); } static void diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index f9bac4ded6..f090185480 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -1527,6 +1527,65 @@ impl_settings_reload_connections (NMSettings *self, g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE)); } +typedef struct { + char *hostname; + NMSettingsSetHostnameCb cb; + gpointer user_data; +} SetHostnameInfo; + +static void +set_transient_hostname_done (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusProxy *proxy = G_DBUS_PROXY (object); + gs_free SetHostnameInfo *info = user_data; + gs_unref_variant GVariant *result = NULL; + gs_free_error GError *error = NULL; + + result = g_dbus_proxy_call_finish (proxy, res, &error); + + if (error) { + _LOGW ("couldn't set the system hostname to '%s' using hostnamed: %s", + info->hostname, error->message); + } + + info->cb (info->hostname, !error, info->user_data); + g_free (info->hostname); +} + +void +nm_settings_set_transient_hostname (NMSettings *self, + const char *hostname, + NMSettingsSetHostnameCb cb, + gpointer user_data) +{ + NMSettingsPrivate *priv; + SetHostnameInfo *info; + + g_return_if_fail (NM_IS_SETTINGS (self)); + priv = NM_SETTINGS_GET_PRIVATE (self); + + if (!priv->hostname.hostnamed_proxy) { + cb (hostname, FALSE, user_data); + return; + } + + info = g_new0 (SetHostnameInfo, 1); + info->hostname = g_strdup (hostname); + info->cb = cb; + info->user_data = user_data; + + g_dbus_proxy_call (priv->hostname.hostnamed_proxy, + "SetHostname", + g_variant_new ("(sb)", hostname, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + set_transient_hostname_done, + info); +} + static gboolean write_hostname (NMSettingsPrivate *priv, const char *hostname) { diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index 923b164b04..051c209423 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -71,6 +71,8 @@ typedef struct { void (*agent_registered) (NMSettings *self, NMSecretAgent *agent); } NMSettingsClass; +typedef void (*NMSettingsSetHostnameCb) (const char *name, gboolean result, gpointer user_data); + GType nm_settings_get_type (void); NMSettings *nm_settings_new (void); @@ -127,4 +129,9 @@ gint nm_settings_sort_connections (gconstpointer a, gconstpointer b); gboolean nm_settings_get_startup_complete (NMSettings *self); +void nm_settings_set_transient_hostname (NMSettings *self, + const char *hostname, + NMSettingsSetHostnameCb cb, + gpointer user_data); + #endif /* __NM_SETTINGS_H__ */ From f87d25f7a1cce12e9906f2fa74b3c8b2a24b8da2 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 22 Feb 2016 10:01:30 +0100 Subject: [PATCH 2/3] policy: simplify set_system_hostname() Move some conditionals to the beginning of the function. --- src/nm-policy.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index c564ff0a52..c331df2dfe 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -157,8 +157,13 @@ set_system_hostname (NMPolicy *self, const char *new_hostname, const char *msg) const char *name; int ret; - if (new_hostname) - g_warn_if_fail (strlen (new_hostname)); + if (!new_hostname) + name = FALLBACK_HOSTNAME4; + else if (!new_hostname[0]) { + g_warn_if_reached (); + name = FALLBACK_HOSTNAME4; + } else + name = new_hostname; old_hostname[HOST_NAME_MAX] = '\0'; errno = 0; @@ -168,12 +173,10 @@ set_system_hostname (NMPolicy *self, const char *new_hostname, const char *msg) errno, strerror (errno)); } else { /* Don't set the hostname if it isn't actually changing */ - if ( (new_hostname && !strcmp (old_hostname, new_hostname)) - || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME4))) + if (nm_streq (name, old_hostname)) return; } - name = (new_hostname && strlen (new_hostname)) ? new_hostname : FALLBACK_HOSTNAME4; _LOGI (LOGD_DNS, "setting system hostname to '%s' (%s)", name, msg); nm_settings_set_transient_hostname (priv->settings, name, From 14d3103ba971c40ba147da8657b9ddaae2a931ab Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 22 Feb 2016 10:10:15 +0100 Subject: [PATCH 3/3] policy: move code from set_system_hostname() to _set_hostname() --- src/nm-policy.c | 72 ++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index c331df2dfe..60bf48bb4f 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -149,47 +149,15 @@ static void settings_set_hostname_cb (const char *hostname, nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL); } -static void -set_system_hostname (NMPolicy *self, const char *new_hostname, const char *msg) -{ - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - char old_hostname[HOST_NAME_MAX + 1]; - const char *name; - int ret; - - if (!new_hostname) - name = FALLBACK_HOSTNAME4; - else if (!new_hostname[0]) { - g_warn_if_reached (); - name = FALLBACK_HOSTNAME4; - } else - name = new_hostname; - - old_hostname[HOST_NAME_MAX] = '\0'; - errno = 0; - ret = gethostname (old_hostname, HOST_NAME_MAX); - if (ret != 0) { - _LOGW (LOGD_DNS, "couldn't get the system hostname: (%d) %s", - errno, strerror (errno)); - } else { - /* Don't set the hostname if it isn't actually changing */ - if (nm_streq (name, old_hostname)) - return; - } - - _LOGI (LOGD_DNS, "setting system hostname to '%s' (%s)", name, msg); - nm_settings_set_transient_hostname (priv->settings, - name, - settings_set_hostname_cb, - NULL); -} - static void _set_hostname (NMPolicy *policy, const char *new_hostname, const char *msg) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); + char old_hostname[HOST_NAME_MAX + 1]; + const char *name; + int ret; /* The incoming hostname *can* be NULL, which will get translated to * 'localhost.localdomain' or such in the hostname policy code, but we @@ -221,9 +189,41 @@ _set_hostname (NMPolicy *policy, priv->cur_hostname = g_strdup (new_hostname); priv->hostname_changed = TRUE; + /* Notify the DNS manager of the hostname change so that the domain part, if + * present, can be added to the search list. + */ nm_dns_manager_set_hostname (priv->dns_manager, priv->cur_hostname); - set_system_hostname (policy, priv->cur_hostname, msg); + /* Finally, set kernel hostname */ + + if (!priv->cur_hostname) + name = FALLBACK_HOSTNAME4; + else if (!priv->cur_hostname[0]) { + g_warn_if_reached (); + name = FALLBACK_HOSTNAME4; + } else + name = priv->cur_hostname; + + old_hostname[HOST_NAME_MAX] = '\0'; + errno = 0; + ret = gethostname (old_hostname, HOST_NAME_MAX); + if (ret != 0) { + _LOGW (LOGD_DNS, "couldn't get the system hostname: (%d) %s", + errno, strerror (errno)); + } else { + /* Don't set the hostname if it isn't actually changing */ + if (nm_streq (name, old_hostname)) + return; + } + + _LOGI (LOGD_DNS, "setting system hostname to '%s' (%s)", name, msg); + + /* Ask NMSettings to update the transient hostname using its + * systemd-hostnamed proxy */ + nm_settings_set_transient_hostname (priv->settings, + name, + settings_set_hostname_cb, + NULL); } static void