mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-06 16:21:50 +00:00
hostname: split out hostname management from NMSettings
Hostname management is complicated. At least, how it is implemented currently. For example, NMPolicy also sets the hostname (NMPolicy calls nm_settings_set_transient_hostname() to have hostnamed set the hostname, but then falls back to sethostname() in settings_set_hostname_cb()). Also, NMManager tracks the hostname in NM_MANAGER_HOSTNAME too, and NMPolicy listens to changes from there -- instead of changes from NMSettings. Eventually, NMHostnameManager should contain the hostname parts from NMSettings and NMPolicy.
This commit is contained in:
parent
f3dfe0f745
commit
5bfb7c3c89
|
@ -1391,6 +1391,9 @@ src_libNetworkManager_la_SOURCES = \
|
|||
src/ppp/nm-ppp-manager.h \
|
||||
src/ppp/nm-ppp-status.h \
|
||||
\
|
||||
src/nm-hostname-manager.c \
|
||||
src/nm-hostname-manager.h \
|
||||
\
|
||||
src/settings/nm-agent-manager.c \
|
||||
src/settings/nm-agent-manager.h \
|
||||
src/settings/nm-inotify-helper.c \
|
||||
|
|
649
src/nm-hostname-manager.c
Normal file
649
src/nm-hostname-manager.c
Normal file
|
@ -0,0 +1,649 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* NetworkManager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2017 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "nm-default.h"
|
||||
|
||||
#include "nm-hostname-manager.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#include "nm-common-macros.h"
|
||||
#include "nm-dbus-interface.h"
|
||||
#include "nm-connection.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-core-internal.h"
|
||||
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-dispatcher.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"
|
||||
|
||||
#if (defined(HOSTNAME_PERSIST_SUSE) + defined(HOSTNAME_PERSIST_SLACKWARE) + defined(HOSTNAME_PERSIST_GENTOO)) > 1
|
||||
#error "Can only define one of HOSTNAME_PERSIST_*"
|
||||
#endif
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_SUSE)
|
||||
#define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME
|
||||
#elif defined(HOSTNAME_PERSIST_SLACKWARE)
|
||||
#define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME
|
||||
#elif defined(HOSTNAME_PERSIST_GENTOO)
|
||||
#define HOSTNAME_FILE HOSTNAME_FILE_GENTOO
|
||||
#else
|
||||
#define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NM_GOBJECT_PROPERTIES_DEFINE (NMHostnameManager,
|
||||
PROP_HOSTNAME,
|
||||
);
|
||||
|
||||
typedef struct {
|
||||
char *value;
|
||||
GFileMonitor *monitor;
|
||||
GFileMonitor *dhcp_monitor;
|
||||
gulong monitor_id;
|
||||
gulong dhcp_monitor_id;
|
||||
GDBusProxy *hostnamed_proxy;
|
||||
} 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__)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_GENTOO)
|
||||
static gchar *
|
||||
read_hostname_gentoo (const char *path)
|
||||
{
|
||||
gs_free char *contents = NULL;
|
||||
gs_strfreev char **all_lines = NULL;
|
||||
const char *tmp;
|
||||
guint i;
|
||||
|
||||
if (!g_file_get_contents (path, &contents, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
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)
|
||||
static gchar *
|
||||
read_hostname_slackware (const char *path)
|
||||
{
|
||||
gs_free char *contents = NULL;
|
||||
gs_strfreev char **all_lines = NULL;
|
||||
char *tmp;
|
||||
guint i, j = 0;
|
||||
|
||||
if (!g_file_get_contents (path, &contents, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
tmp = &all_lines[i][0];
|
||||
/* We only want up to the first '.' -- the rest of the */
|
||||
/* fqdn is defined in /etc/hosts */
|
||||
while (tmp[j] != '\0') {
|
||||
if (tmp[j] == '.') {
|
||||
tmp[j] = '\0';
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
return g_shell_unquote (tmp, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#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[NM_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_hostname_manager_get_hostname (NMHostnameManager *self)
|
||||
{
|
||||
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
|
||||
char *hostname = NULL;
|
||||
|
||||
if (priv->hostnamed_proxy) {
|
||||
hostname = g_strdup (priv->value);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_SUSE)
|
||||
if (priv->dhcp_monitor_id && hostname_is_dynamic ())
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_GENTOO)
|
||||
hostname = read_hostname_gentoo (HOSTNAME_FILE);
|
||||
#elif defined(HOSTNAME_PERSIST_SLACKWARE)
|
||||
hostname = read_hostname_slackware (HOSTNAME_FILE);
|
||||
#else
|
||||
if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL))
|
||||
g_strchomp (hostname);
|
||||
#endif
|
||||
|
||||
out:
|
||||
if (hostname && !hostname[0]) {
|
||||
g_free (hostname);
|
||||
hostname = NULL;
|
||||
}
|
||||
|
||||
return hostname;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char *hostname;
|
||||
NMHostnameManagerSetHostnameCb 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_hostname_manager_set_transient_hostname (NMHostnameManager *self,
|
||||
const char *hostname,
|
||||
NMHostnameManagerSetHostnameCb cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMHostnameManagerPrivate *priv;
|
||||
SetHostnameInfo *info;
|
||||
|
||||
g_return_if_fail (NM_IS_HOSTNAME_MANAGER (self));
|
||||
|
||||
priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
if (!priv->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->hostnamed_proxy,
|
||||
"SetHostname",
|
||||
g_variant_new ("(sb)", hostname, FALSE),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
set_transient_hostname_done,
|
||||
info);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_hostname_manager_get_transient_hostname (NMHostnameManager *self, char **hostname)
|
||||
{
|
||||
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
|
||||
GVariant *v_hostname;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostname)
|
||||
{
|
||||
NMHostnameManagerPrivate *priv;
|
||||
char *hostname_eol;
|
||||
gboolean ret;
|
||||
gs_free_error GError *error = NULL;
|
||||
const char *file = HOSTNAME_FILE;
|
||||
gs_free char *link_path = NULL;
|
||||
gs_unref_variant GVariant *var = NULL;
|
||||
struct stat file_stat;
|
||||
#if HAVE_SELINUX
|
||||
security_context_t se_ctx_prev = NULL, se_ctx = NULL;
|
||||
mode_t st_mode = 0;
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail (NM_IS_HOSTNAME_MANAGER (self), FALSE);
|
||||
|
||||
priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
if (priv->hostnamed_proxy) {
|
||||
var = g_dbus_proxy_call_sync (priv->hostnamed_proxy,
|
||||
"SetStaticHostname",
|
||||
g_variant_new ("(sb)", hostname, FALSE),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
if (error)
|
||||
_LOGW ("could not set hostname: %s", error->message);
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
#if HAVE_SELINUX
|
||||
/* 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
|
||||
|
||||
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) {
|
||||
_LOGW ("could not save hostname to %s: %s", file, error->message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_hostname_manager_validate_hostname (const char *hostname)
|
||||
{
|
||||
const char *p;
|
||||
gboolean dot = TRUE;
|
||||
|
||||
if (!hostname || !hostname[0])
|
||||
return FALSE;
|
||||
|
||||
for (p = hostname; *p; p++) {
|
||||
if (*p == '.') {
|
||||
if (dot)
|
||||
return FALSE;
|
||||
dot = TRUE;
|
||||
} else {
|
||||
if (!g_ascii_isalnum (*p) && (*p != '-') && (*p != '_'))
|
||||
return FALSE;
|
||||
dot = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (dot)
|
||||
return FALSE;
|
||||
|
||||
return (p - hostname <= HOST_NAME_MAX);
|
||||
}
|
||||
|
||||
static void
|
||||
hostname_maybe_changed (NMHostnameManager *settings)
|
||||
{
|
||||
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (settings);
|
||||
char *new_hostname;
|
||||
|
||||
new_hostname = nm_hostname_manager_get_hostname (settings);
|
||||
|
||||
if ( (new_hostname && !priv->value)
|
||||
|| (!new_hostname && priv->value)
|
||||
|| (priv->value && new_hostname && strcmp (priv->value, new_hostname))) {
|
||||
|
||||
_LOGI ("hostname changed from %s%s%s to %s%s%s",
|
||||
NM_PRINT_FMT_QUOTED (priv->value, "\"", priv->value, "\"", "(none)"),
|
||||
NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)"));
|
||||
g_free (priv->value);
|
||||
priv->value = new_hostname;
|
||||
_notify (settings, PROP_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 void
|
||||
hostnamed_properties_changed (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
char **invalidated_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMHostnameManager *self = user_data;
|
||||
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
|
||||
GVariant *v_hostname;
|
||||
const char *hostname;
|
||||
|
||||
v_hostname = g_dbus_proxy_get_cached_property (priv->hostnamed_proxy,
|
||||
"StaticHostname");
|
||||
if (!v_hostname)
|
||||
return;
|
||||
|
||||
hostname = g_variant_get_string (v_hostname, NULL);
|
||||
|
||||
if (g_strcmp0 (priv->value, hostname) != 0) {
|
||||
_LOGI ("hostname changed from %s%s%s to %s%s%s",
|
||||
NM_PRINT_FMT_QUOTED (priv->value, "\"", priv->value, "\"", "(none)"),
|
||||
NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)"));
|
||||
g_free (priv->value);
|
||||
priv->value = g_strdup (hostname);
|
||||
_notify (self, PROP_HOSTNAME);
|
||||
nm_dispatcher_call_hostname (NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
g_variant_unref (v_hostname);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_hostname_file_monitors (NMHostnameManager *self)
|
||||
{
|
||||
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
|
||||
GFileMonitor *monitor;
|
||||
const char *path = HOSTNAME_FILE;
|
||||
char *link_path = NULL;
|
||||
struct stat file_stat;
|
||||
GFile *file;
|
||||
|
||||
priv->value = nm_hostname_manager_get_hostname (self);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* monitor changes to hostname file */
|
||||
file = g_file_new_for_path (path);
|
||||
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
g_free(link_path);
|
||||
if (monitor) {
|
||||
priv->monitor_id = g_signal_connect (monitor, "changed",
|
||||
G_CALLBACK (hostname_file_changed_cb),
|
||||
self);
|
||||
priv->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->dhcp_monitor_id = g_signal_connect (monitor, "changed",
|
||||
G_CALLBACK (hostname_file_changed_cb),
|
||||
self);
|
||||
priv->dhcp_monitor = monitor;
|
||||
}
|
||||
#endif
|
||||
|
||||
hostname_maybe_changed (self);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
NMHostnameManager *self = NM_HOSTNAME_MANAGER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_HOSTNAME:
|
||||
g_value_take_string (value, nm_hostname_manager_get_hostname (self));
|
||||
|
||||
/* Don't ever pass NULL through D-Bus */
|
||||
if (!g_value_get_string (value))
|
||||
g_value_set_static_string (value, "");
|
||||
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)
|
||||
{
|
||||
NMHostnameManager *self = NM_HOSTNAME_MANAGER (object);
|
||||
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
|
||||
GDBusProxy *proxy;
|
||||
GVariant *variant;
|
||||
gs_free GError *error = NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!priv->hostnamed_proxy)
|
||||
setup_hostname_file_monitors (self);
|
||||
|
||||
G_OBJECT_CLASS (nm_hostname_manager_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
NMHostnameManager *self = NM_HOSTNAME_MANAGER (object);
|
||||
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);
|
||||
}
|
||||
|
||||
if (priv->monitor) {
|
||||
if (priv->monitor_id)
|
||||
g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
|
||||
|
||||
g_file_monitor_cancel (priv->monitor);
|
||||
g_clear_object (&priv->monitor);
|
||||
}
|
||||
|
||||
if (priv->dhcp_monitor) {
|
||||
if (priv->dhcp_monitor_id)
|
||||
g_signal_handler_disconnect (priv->dhcp_monitor,
|
||||
priv->dhcp_monitor_id);
|
||||
|
||||
g_file_monitor_cancel (priv->dhcp_monitor);
|
||||
g_clear_object (&priv->dhcp_monitor);
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->value, g_free);
|
||||
|
||||
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;
|
||||
|
||||
obj_properties[PROP_HOSTNAME] =
|
||||
g_param_spec_string (NM_HOSTNAME_MANAGER_HOSTNAME, "", "",
|
||||
NULL,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
||||
}
|
61
src/nm-hostname-manager.h
Normal file
61
src/nm-hostname-manager.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* NetworkManager
|
||||
*
|
||||
* Søren Sandmann <sandmann@daimi.au.dk>
|
||||
* Dan Williams <dcbw@redhat.com>
|
||||
* Tambet Ingo <tambet@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2007 - 2011, 2017 Red Hat, Inc.
|
||||
* (C) Copyright 2008 Novell, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __NM_HOSTNAME_MANAGER_H__
|
||||
#define __NM_HOSTNAME_MANAGER_H__
|
||||
|
||||
#define NM_TYPE_HOSTNAME_MANAGER (nm_hostname_manager_get_type ())
|
||||
#define NM_HOSTNAME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManager))
|
||||
#define NM_HOSTNAME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManagerClass))
|
||||
#define NM_IS_HOSTNAME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_HOSTNAME_MANAGER))
|
||||
#define NM_IS_HOSTNAME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_HOSTNAME_MANAGER))
|
||||
#define NM_HOSTNAME_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManagerClass))
|
||||
|
||||
#define NM_HOSTNAME_MANAGER_HOSTNAME "hostname"
|
||||
|
||||
typedef struct _NMHostnameManager NMHostnameManager;
|
||||
typedef struct _NMHostnameManagerClass NMHostnameManagerClass;
|
||||
|
||||
typedef void (*NMHostnameManagerSetHostnameCb) (const char *name, gboolean result, gpointer user_data);
|
||||
|
||||
GType nm_hostname_manager_get_type (void);
|
||||
|
||||
NMHostnameManager *nm_hostname_manager_get (void);
|
||||
|
||||
char *nm_hostname_manager_get_hostname (NMHostnameManager *self);
|
||||
|
||||
gboolean nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostname);
|
||||
|
||||
void nm_hostname_manager_set_transient_hostname (NMHostnameManager *self,
|
||||
const char *hostname,
|
||||
NMHostnameManagerSetHostnameCb cb,
|
||||
gpointer user_data);
|
||||
|
||||
gboolean nm_hostname_manager_get_transient_hostname (NMHostnameManager *self,
|
||||
char **hostname);
|
||||
|
||||
gboolean nm_hostname_manager_validate_hostname (const char *hostname);
|
||||
|
||||
#endif /* __NM_HOSTNAME_MANAGER_H__ */
|
|
@ -1412,7 +1412,10 @@ system_hostname_changed_cb (NMSettings *settings,
|
|||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
char *hostname;
|
||||
|
||||
hostname = nm_settings_get_hostname (priv->settings);
|
||||
g_object_get (priv->settings,
|
||||
NM_SETTINGS_HOSTNAME,
|
||||
&hostname,
|
||||
NULL);
|
||||
|
||||
/* nm_settings_get_hostname() does not return an empty hostname. */
|
||||
nm_assert (!hostname || *hostname);
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "nm-dhcp6-config.h"
|
||||
#include "nm-config.h"
|
||||
#include "nm-netns.h"
|
||||
#include "nm-hostname-manager.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
@ -73,6 +74,8 @@ typedef struct {
|
|||
|
||||
NMSettings *settings;
|
||||
|
||||
NMHostnameManager *hostname_manager;
|
||||
|
||||
NMDevice *default_device4, *activating_device4;
|
||||
NMDevice *default_device6, *activating_device6;
|
||||
|
||||
|
@ -460,7 +463,7 @@ _get_hostname (NMPolicy *self, char **hostname)
|
|||
}
|
||||
|
||||
/* try to get the hostname via dbus... */
|
||||
if (nm_settings_get_transient_hostname (priv->settings, hostname)) {
|
||||
if (nm_hostname_manager_get_transient_hostname (priv->hostname_manager, hostname)) {
|
||||
_LOGT (LOGD_DNS, "get-hostname: \"%s\" (from dbus)", *hostname);
|
||||
return *hostname;
|
||||
}
|
||||
|
@ -549,10 +552,10 @@ _set_hostname (NMPolicy *self,
|
|||
|
||||
/* Ask NMSettings to update the transient hostname using its
|
||||
* systemd-hostnamed proxy */
|
||||
nm_settings_set_transient_hostname (priv->settings,
|
||||
name,
|
||||
settings_set_hostname_cb,
|
||||
g_object_ref (self));
|
||||
nm_hostname_manager_set_transient_hostname (priv->hostname_manager,
|
||||
name,
|
||||
settings_set_hostname_cb,
|
||||
g_object_ref (self));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2300,6 +2303,8 @@ nm_policy_init (NMPolicy *self)
|
|||
|
||||
priv->netns = g_object_ref (nm_netns_get ());
|
||||
|
||||
priv->hostname_manager = g_object_ref (nm_hostname_manager_get ());
|
||||
|
||||
hostname_mode = nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG,
|
||||
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
||||
NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE,
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-dispatcher.h"
|
||||
#include "nm-inotify-helper.h"
|
||||
#include "nm-hostname-manager.h"
|
||||
|
||||
#include "introspection/org.freedesktop.NetworkManager.Settings.h"
|
||||
|
||||
|
@ -94,13 +95,6 @@ EXPORT(nm_settings_connection_replace_and_commit)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
#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"
|
||||
#define IFCFG_DIR SYSCONFDIR "/sysconfig/network"
|
||||
#define CONF_DHCP IFCFG_DIR "/dhcp"
|
||||
|
||||
|
@ -162,14 +156,9 @@ typedef struct {
|
|||
gboolean started;
|
||||
gboolean startup_complete;
|
||||
|
||||
struct {
|
||||
char *value;
|
||||
GFileMonitor *monitor;
|
||||
GFileMonitor *dhcp_monitor;
|
||||
gulong monitor_id;
|
||||
gulong dhcp_monitor_id;
|
||||
GDBusProxy *hostnamed_proxy;
|
||||
} hostname;
|
||||
char *hostname;
|
||||
NMHostnameManager *hostname_manager;
|
||||
|
||||
} NMSettingsPrivate;
|
||||
|
||||
struct _NMSettings {
|
||||
|
@ -568,131 +557,6 @@ get_plugin (NMSettings *self, guint32 capability)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_GENTOO)
|
||||
static gchar *
|
||||
read_hostname_gentoo (const char *path)
|
||||
{
|
||||
gs_free char *contents = NULL;
|
||||
gs_strfreev char **all_lines = NULL;
|
||||
const char *tmp;
|
||||
guint i;
|
||||
|
||||
if (!g_file_get_contents (path, &contents, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
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)
|
||||
static gchar *
|
||||
read_hostname_slackware (const char *path)
|
||||
{
|
||||
gs_free char *contents = NULL;
|
||||
gs_strfreev char **all_lines = NULL;
|
||||
char *tmp;
|
||||
guint i, j = 0;
|
||||
|
||||
if (!g_file_get_contents (path, &contents, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
tmp = &all_lines[i][0];
|
||||
/* We only want up to the first '.' -- the rest of the */
|
||||
/* fqdn is defined in /etc/hosts */
|
||||
while (tmp[j] != '\0') {
|
||||
if (tmp[j] == '.') {
|
||||
tmp[j] = '\0';
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
return g_shell_unquote (tmp, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#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[NM_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);
|
||||
char *hostname = NULL;
|
||||
|
||||
if (!priv->started)
|
||||
return NULL;
|
||||
|
||||
if (priv->hostname.hostnamed_proxy) {
|
||||
hostname = g_strdup (priv->hostname.value);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_SUSE)
|
||||
if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ())
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
#if defined(HOSTNAME_PERSIST_GENTOO)
|
||||
hostname = read_hostname_gentoo (HOSTNAME_FILE);
|
||||
#elif defined(HOSTNAME_PERSIST_SLACKWARE)
|
||||
hostname = read_hostname_slackware (HOSTNAME_FILE);
|
||||
#else
|
||||
if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL))
|
||||
g_strchomp (hostname);
|
||||
#endif
|
||||
|
||||
out:
|
||||
if (hostname && !hostname[0]) {
|
||||
g_free (hostname);
|
||||
hostname = NULL;
|
||||
}
|
||||
|
||||
return hostname;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
find_spec (GSList *spec_list, const char *spec)
|
||||
{
|
||||
|
@ -1626,160 +1490,7 @@ 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);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_settings_get_transient_hostname (NMSettings *self, char **hostname)
|
||||
{
|
||||
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
|
||||
GVariant *v_hostname;
|
||||
|
||||
if (!priv->hostname.hostnamed_proxy)
|
||||
return FALSE;
|
||||
|
||||
v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.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;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
write_hostname (NMSettingsPrivate *priv, const char *hostname)
|
||||
{
|
||||
char *hostname_eol;
|
||||
gboolean ret;
|
||||
gs_free_error GError *error = NULL;
|
||||
const char *file = HOSTNAME_FILE;
|
||||
gs_free char *link_path = NULL;
|
||||
gs_unref_variant GVariant *var = NULL;
|
||||
struct stat file_stat;
|
||||
#if HAVE_SELINUX
|
||||
security_context_t se_ctx_prev = NULL, se_ctx = NULL;
|
||||
mode_t st_mode = 0;
|
||||
#endif
|
||||
|
||||
if (priv->hostname.hostnamed_proxy) {
|
||||
var = g_dbus_proxy_call_sync (priv->hostname.hostnamed_proxy,
|
||||
"SetStaticHostname",
|
||||
g_variant_new ("(sb)", hostname, FALSE),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
if (error)
|
||||
_LOGW ("could not set hostname: %s", error->message);
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
#if HAVE_SELINUX
|
||||
/* 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
|
||||
|
||||
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) {
|
||||
_LOGW ("could not save hostname to %s: %s", file, error->message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
pk_hostname_cb (NMAuthChain *chain,
|
||||
|
@ -1812,7 +1523,7 @@ pk_hostname_cb (NMAuthChain *chain,
|
|||
} else {
|
||||
hostname = nm_auth_chain_get_data (chain, "hostname");
|
||||
|
||||
if (!write_hostname (priv, hostname)) {
|
||||
if (!nm_hostname_manager_write_hostname (priv->hostname_manager, hostname)) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_FAILED,
|
||||
"Saving the hostname failed.");
|
||||
|
@ -1827,33 +1538,6 @@ pk_hostname_cb (NMAuthChain *chain,
|
|||
nm_auth_chain_unref (chain);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
validate_hostname (const char *hostname)
|
||||
{
|
||||
const char *p;
|
||||
gboolean dot = TRUE;
|
||||
|
||||
if (!hostname || !hostname[0])
|
||||
return FALSE;
|
||||
|
||||
for (p = hostname; *p; p++) {
|
||||
if (*p == '.') {
|
||||
if (dot)
|
||||
return FALSE;
|
||||
dot = TRUE;
|
||||
} else {
|
||||
if (!g_ascii_isalnum (*p) && (*p != '-') && (*p != '_'))
|
||||
return FALSE;
|
||||
dot = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (dot)
|
||||
return FALSE;
|
||||
|
||||
return (p - hostname <= HOST_NAME_MAX);
|
||||
}
|
||||
|
||||
static void
|
||||
impl_settings_save_hostname (NMSettings *self,
|
||||
GDBusMethodInvocation *context,
|
||||
|
@ -1864,7 +1548,7 @@ impl_settings_save_hostname (NMSettings *self,
|
|||
GError *error = NULL;
|
||||
|
||||
/* Minimal validation of the hostname */
|
||||
if (!validate_hostname (hostname)) {
|
||||
if (!nm_hostname_manager_validate_hostname (hostname)) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_INVALID_HOSTNAME,
|
||||
"The hostname was too long or contained invalid characters.");
|
||||
|
@ -1888,37 +1572,7 @@ done:
|
|||
g_dbus_method_invocation_take_error (context, 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))) {
|
||||
|
||||
_LOGI ("hostname changed from %s%s%s to %s%s%s",
|
||||
NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"),
|
||||
NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)"));
|
||||
g_free (priv->hostname.value);
|
||||
priv->hostname.value = new_hostname;
|
||||
_notify (settings, PROP_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)
|
||||
|
@ -2141,95 +1795,34 @@ nm_settings_get_startup_complete (NMSettings *self)
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
hostnamed_properties_changed (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
char **invalidated_properties,
|
||||
gpointer user_data)
|
||||
_hostname_changed (NMSettings *self)
|
||||
{
|
||||
NMSettings *self = user_data;
|
||||
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
|
||||
GVariant *v_hostname;
|
||||
const char *hostname;
|
||||
gs_free char *hostname = NULL;
|
||||
|
||||
v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy,
|
||||
"StaticHostname");
|
||||
if (!v_hostname)
|
||||
hostname = nm_hostname_manager_get_hostname (priv->hostname_manager);
|
||||
|
||||
if (nm_streq0 (hostname, priv->hostname))
|
||||
return;
|
||||
|
||||
hostname = g_variant_get_string (v_hostname, NULL);
|
||||
|
||||
if (g_strcmp0 (priv->hostname.value, hostname) != 0) {
|
||||
_LOGI ("hostname changed from %s%s%s to %s%s%s",
|
||||
NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"),
|
||||
NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)"));
|
||||
g_free (priv->hostname.value);
|
||||
priv->hostname.value = g_strdup (hostname);
|
||||
_notify (self, PROP_HOSTNAME);
|
||||
nm_dispatcher_call_hostname (NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
g_variant_unref (v_hostname);
|
||||
g_free (priv->hostname);
|
||||
priv->hostname = g_steal_pointer (&hostname);
|
||||
_notify (self, PROP_HOSTNAME);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_hostname_file_monitors (NMSettings *self)
|
||||
_hostname_changed_cb (NMHostnameManager *hostname_manager,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
|
||||
GFileMonitor *monitor;
|
||||
const char *path = HOSTNAME_FILE;
|
||||
char *link_path = NULL;
|
||||
struct stat file_stat;
|
||||
GFile *file;
|
||||
|
||||
priv->hostname.value = nm_settings_get_hostname (self);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* monitor changes to hostname file */
|
||||
file = g_file_new_for_path (path);
|
||||
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
g_free(link_path);
|
||||
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);
|
||||
_hostname_changed (NM_SETTINGS (user_data));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean
|
||||
nm_settings_start (NMSettings *self, GError **error)
|
||||
{
|
||||
NMSettingsPrivate *priv;
|
||||
GDBusProxy *proxy;
|
||||
GVariant *variant;
|
||||
GError *local_error = NULL;
|
||||
gs_strfreev char **plugins = NULL;
|
||||
|
||||
priv = NM_SETTINGS_GET_PRIVATE (self);
|
||||
|
@ -2245,33 +1838,12 @@ nm_settings_start (NMSettings *self, GError **error)
|
|||
load_connections (self);
|
||||
check_startup_complete (self);
|
||||
|
||||
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL,
|
||||
HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH,
|
||||
HOSTNAMED_SERVICE_INTERFACE, NULL, &local_error);
|
||||
if (proxy) {
|
||||
variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname");
|
||||
if (variant) {
|
||||
_LOGI ("hostname: using hostnamed");
|
||||
priv->hostname.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",
|
||||
local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
|
||||
if (!priv->hostname.hostnamed_proxy)
|
||||
setup_hostname_file_monitors (self);
|
||||
|
||||
priv->started = TRUE;
|
||||
_notify (self, PROP_HOSTNAME);
|
||||
priv->hostname_manager = g_object_ref (nm_hostname_manager_get ());
|
||||
g_signal_connect (priv->hostname_manager,
|
||||
"notify::"NM_HOSTNAME_MANAGER_HOSTNAME,
|
||||
G_CALLBACK (_hostname_changed_cb),
|
||||
self);
|
||||
_hostname_changed (self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -2298,10 +1870,9 @@ get_property (GObject *object, guint prop_id,
|
|||
g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE));
|
||||
break;
|
||||
case PROP_HOSTNAME:
|
||||
g_value_take_string (value, nm_settings_get_hostname (self));
|
||||
|
||||
/* Don't ever pass NULL through D-Bus */
|
||||
if (!g_value_get_string (value))
|
||||
if (priv->hostname)
|
||||
g_value_set_string (value, priv->hostname);
|
||||
else
|
||||
g_value_set_static_string (value, "");
|
||||
break;
|
||||
case PROP_CAN_MODIFY:
|
||||
|
@ -2362,32 +1933,13 @@ dispose (GObject *object)
|
|||
|
||||
g_object_unref (priv->agent_mgr);
|
||||
|
||||
if (priv->hostname.hostnamed_proxy) {
|
||||
g_signal_handlers_disconnect_by_func (priv->hostname.hostnamed_proxy,
|
||||
G_CALLBACK (hostnamed_properties_changed),
|
||||
if (priv->hostname_manager) {
|
||||
g_signal_handlers_disconnect_by_func (priv->hostname_manager,
|
||||
G_CALLBACK (_hostname_changed_cb),
|
||||
self);
|
||||
g_clear_object (&priv->hostname.hostnamed_proxy);
|
||||
g_clear_object (&priv->hostname_manager);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2405,6 +1957,8 @@ finalize (GObject *object)
|
|||
|
||||
g_slist_free_full (priv->plugins, g_object_unref);
|
||||
|
||||
g_free (priv->hostname);
|
||||
|
||||
g_clear_object (&priv->config);
|
||||
|
||||
G_OBJECT_CLASS (nm_settings_parent_class)->finalize (object);
|
||||
|
|
|
@ -119,20 +119,10 @@ gboolean nm_settings_has_connection (NMSettings *self, NMSettingsConnection *con
|
|||
|
||||
const GSList *nm_settings_get_unmanaged_specs (NMSettings *self);
|
||||
|
||||
char *nm_settings_get_hostname (NMSettings *self);
|
||||
|
||||
void nm_settings_device_added (NMSettings *self, NMDevice *device);
|
||||
|
||||
void nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quitting);
|
||||
|
||||
gboolean nm_settings_get_startup_complete (NMSettings *self);
|
||||
|
||||
void nm_settings_set_transient_hostname (NMSettings *self,
|
||||
const char *hostname,
|
||||
NMSettingsSetHostnameCb cb,
|
||||
gpointer user_data);
|
||||
|
||||
gboolean nm_settings_get_transient_hostname (NMSettings *self,
|
||||
char **hostname);
|
||||
|
||||
#endif /* __NM_SETTINGS_H__ */
|
||||
|
|
Loading…
Reference in a new issue