summary refs log tree commit diff
path: root/src/nm-policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-policy.c')
-rw-r--r--src/nm-policy.c285
1 files changed, 200 insertions, 85 deletions
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 455545b6..e8a18d02 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -19,6 +19,7 @@
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
+#include <config.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
@@ -39,7 +40,7 @@
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-connection.h"
 #include "nm-system.h"
-#include "nm-named-manager.h"
+#include "nm-dns-manager.h"
 #include "nm-vpn-manager.h"
 #include "nm-policy-hosts.h"
 #include "nm-policy-hostname.h"
@@ -61,6 +62,7 @@ struct NMPolicy {
 	HostnameThread *lookup;
 
 	char *orig_hostname; /* hostname at NM start time */
+	char *cur_hostname;  /* hostname we want to assign */
 };
 
 #define INVALID_TAG "invalid"
@@ -137,7 +139,8 @@ get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
 			continue;
 
 		/* 'never-default' devices can't ever be the default */
-		if (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
+		if (   (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
+		    || nm_ip4_config_get_never_default (ip4_config))
 			continue;
 
 		prio = nm_device_get_priority (dev);
@@ -225,9 +228,62 @@ get_best_ip6_device (NMManager *manager, NMActRequest **out_req)
 }
 
 static void
-_set_hostname (const char *new_hostname, const char *msg)
+_set_hostname (NMPolicy *policy,
+               gboolean change_hostname,
+               const char *new_hostname,
+               const char *msg)
 {
-	if (nm_policy_set_system_hostname (new_hostname, msg))
+	char ip4_addr[INET_ADDRSTRLEN + 1];
+	char ip6_addr[INET6_ADDRSTRLEN + 1];
+
+	if (change_hostname) {
+		NMDnsManager *dns_mgr;
+
+		g_free (policy->cur_hostname);
+		policy->cur_hostname = g_strdup (new_hostname);
+
+		dns_mgr = nm_dns_manager_get (NULL);
+		nm_dns_manager_set_hostname (dns_mgr, policy->cur_hostname);
+		g_object_unref (dns_mgr);
+	}
+
+	/* Get the default IPv4 and IPv6 addresses so we can assign
+	 * the hostname to them in /etc/hosts.
+	 */
+	memset (ip4_addr, 0, sizeof (ip4_addr));
+	if (policy->default_device4) {
+		NMIP4Config *config = NULL;
+		NMIP4Address *addr = NULL;
+
+		config = nm_device_get_ip4_config (policy->default_device4);
+		if (config)
+			addr = nm_ip4_config_get_address (config, 0);
+
+		if (addr) {
+			struct in_addr tmp;
+
+			tmp.s_addr = nm_ip4_address_get_address (addr);
+			inet_ntop (AF_INET, &tmp, ip4_addr, sizeof (ip4_addr));
+		}
+	}
+
+	memset (ip6_addr, 0, sizeof (ip6_addr));
+	if (policy->default_device6) {
+		NMIP6Config *config = NULL;
+		NMIP6Address *addr = NULL;
+
+		config = nm_device_get_ip6_config (policy->default_device6);
+		if (config)
+			addr = nm_ip6_config_get_address (config, 0);
+
+		if (addr)
+			inet_ntop (AF_INET6, nm_ip6_address_get_address (addr), ip6_addr, sizeof (ip6_addr));
+	}
+
+	if (nm_policy_set_system_hostname (policy->cur_hostname,
+	                                   strlen (ip4_addr) ? ip4_addr : NULL,
+	                                   strlen (ip6_addr) ? ip6_addr : NULL,
+	                                   msg))
 		nm_utils_call_dispatcher ("hostname", NULL, NULL, NULL);
 }
 
@@ -244,24 +300,23 @@ lookup_callback (HostnameThread *thread,
 	if (!hostname_thread_is_dead (thread) && (thread == policy->lookup)) {
 		policy->lookup = NULL;
 		if (!hostname) {
-			/* No valid IP4 config (!!); fall back to localhost.localdomain */
+			/* Fall back to localhost.localdomain */
 			msg = g_strdup_printf ("address lookup failed: %d", result);
-			_set_hostname (NULL, msg);
+			_set_hostname (policy, TRUE, NULL, msg);
 			g_free (msg);
 		} else
-			_set_hostname (hostname, "from address lookup");
+			_set_hostname (policy, TRUE, hostname, "from address lookup");
 	}
 	hostname_thread_free (thread);
 }
 
 static void
-update_system_hostname (NMPolicy *policy, NMDevice *best)
+update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
 {
 	char *configured_hostname = NULL;
-	NMActRequest *best_req = NULL;
-	NMDHCP4Config *dhcp4_config;
-	NMIP4Config *ip4_config;
-	NMIP4Address *addr;
+	NMActRequest *best_req4 = NULL;
+	NMActRequest *best_req6 = NULL;
+	const char *dhcp_hostname, *p;
 
 	g_return_if_fail (policy != NULL);
 
@@ -282,39 +337,62 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
 	/* Try a persistent hostname first */
 	g_object_get (G_OBJECT (policy->manager), NM_MANAGER_HOSTNAME, &configured_hostname, NULL);
 	if (configured_hostname) {
-		_set_hostname (configured_hostname, "from system configuration");
+		_set_hostname (policy, TRUE, configured_hostname, "from system configuration");
 		g_free (configured_hostname);
 		return;
 	}
 
 	/* Try automatically determined hostname from the best device's IP config */
-	if (!best)
-		best = get_best_ip4_device (policy->manager, &best_req);
+	if (!best4)
+		best4 = get_best_ip4_device (policy->manager, &best_req4);
+	if (!best6)
+		best6 = get_best_ip6_device (policy->manager, &best_req6);
 
-	if (!best) {
+	if (!best4 && !best6) {
 		/* No best device; fall back to original hostname or if there wasn't
 		 * one, 'localhost.localdomain'
 		 */
-		_set_hostname (policy->orig_hostname, "no default device");
+		_set_hostname (policy, TRUE, policy->orig_hostname, "no default device");
 		return;
 	}
 
-	/* Grab a hostname out of the device's DHCP4 config */
-	dhcp4_config = nm_device_get_dhcp4_config (best);
-	if (dhcp4_config) {
-		const char *dhcp4_hostname, *p;
-
-		p = dhcp4_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name");
-		if (dhcp4_hostname && strlen (dhcp4_hostname)) {
-			/* Sanity check */
-			while (*p) {
-				if (!isblank (*p++)) {
-					_set_hostname (dhcp4_hostname, "from DHCP");
-					return;
+	if (best4) {
+		NMDHCP4Config *dhcp4_config;
+
+		/* Grab a hostname out of the device's DHCP4 config */
+		dhcp4_config = nm_device_get_dhcp4_config (best4);
+		if (dhcp4_config) {
+			p = dhcp_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name");
+			if (dhcp_hostname && strlen (dhcp_hostname)) {
+				/* Sanity check; strip leading spaces */
+				while (*p) {
+					if (!isblank (*p++)) {
+						_set_hostname (policy, TRUE, dhcp_hostname, "from DHCPv4");
+						return;
+					}
 				}
+				nm_log_warn (LOGD_DNS, "DHCPv4-provided hostname '%s' looks invalid; ignoring it",
+					         dhcp_hostname);
+			}
+		}
+	} else if (best6) {
+		NMDHCP6Config *dhcp6_config;
+
+		/* Grab a hostname out of the device's DHCP4 config */
+		dhcp6_config = nm_device_get_dhcp6_config (best6);
+		if (dhcp6_config) {
+			p = dhcp_hostname = nm_dhcp6_config_get_option (dhcp6_config, "host_name");
+			if (dhcp_hostname && strlen (dhcp_hostname)) {
+				/* Sanity check; strip leading spaces */
+				while (*p) {
+					if (!isblank (*p++)) {
+						_set_hostname (policy, TRUE, dhcp_hostname, "from DHCPv6");
+						return;
+					}
+				}
+				nm_log_warn (LOGD_DNS, "DHCPv6-provided hostname '%s' looks invalid; ignoring it",
+					         dhcp_hostname);
 			}
-			nm_log_warn (LOGD_DNS, "DHCP-provided hostname '%s' looks invalid; ignoring it",
-			             dhcp4_hostname);
 		}
 	}
 
@@ -322,40 +400,64 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
 	 * when NM started up.
 	 */
 	if (policy->orig_hostname) {
-		_set_hostname (policy->orig_hostname, "from system startup");
+		_set_hostname (policy, TRUE, policy->orig_hostname, "from system startup");
 		return;
 	}
 
-	/* No configured hostname, no automatically determined hostname, and
-	 * no bootup hostname. Start reverse DNS of the current IP address.
+	/* No configured hostname, no automatically determined hostname, and no
+	 * bootup hostname. Start reverse DNS of the current IPv4 or IPv6 address.
 	 */
-	ip4_config = nm_device_get_ip4_config (best);
-	if (   !ip4_config
-	    || (nm_ip4_config_get_num_nameservers (ip4_config) == 0)
-	    || (nm_ip4_config_get_num_addresses (ip4_config) == 0)) {
-		/* No valid IP4 config (!!); fall back to localhost.localdomain */
-		_set_hostname (NULL, "no IPv4 config");
-		return;
-	}
+	if (best4) {
+		NMIP4Config *ip4_config;
+		NMIP4Address *addr4;
 
-	addr = nm_ip4_config_get_address (ip4_config, 0);
-	g_assert (addr); /* checked for > 1 address above */
+		ip4_config = nm_device_get_ip4_config (best4);
+		if (   !ip4_config
+		    || (nm_ip4_config_get_num_nameservers (ip4_config) == 0)
+		    || (nm_ip4_config_get_num_addresses (ip4_config) == 0)) {
+			/* No valid IP4 config (!!); fall back to localhost.localdomain */
+			_set_hostname (policy, TRUE, NULL, "no IPv4 config");
+			return;
+		}
+
+		addr4 = nm_ip4_config_get_address (ip4_config, 0);
+		g_assert (addr4); /* checked for > 1 address above */
+
+		/* Start the hostname lookup thread */
+		policy->lookup = hostname4_thread_new (nm_ip4_address_get_address (addr4), lookup_callback, policy);
+	} else if (best6) {
+		NMIP6Config *ip6_config;
+		NMIP6Address *addr6;
+
+		ip6_config = nm_device_get_ip6_config (best6);
+		if (   !ip6_config
+		    || (nm_ip6_config_get_num_nameservers (ip6_config) == 0)
+		    || (nm_ip6_config_get_num_addresses (ip6_config) == 0)) {
+			/* No valid IP6 config (!!); fall back to localhost.localdomain */
+			_set_hostname (policy, TRUE, NULL, "no IPv6 config");
+			return;
+		}
+
+		addr6 = nm_ip6_config_get_address (ip6_config, 0);
+		g_assert (addr6); /* checked for > 1 address above */
+
+		/* Start the hostname lookup thread */
+		policy->lookup = hostname6_thread_new (nm_ip6_address_get_address (addr6), lookup_callback, policy);
+	}
 
-	/* Start the hostname lookup thread */
-	policy->lookup = hostname_thread_new (nm_ip4_address_get_address (addr), lookup_callback, policy);
 	if (!policy->lookup) {
 		/* Fall back to 'localhost.localdomain' */
-		_set_hostname (NULL, "error starting hostname thread");
+		_set_hostname (policy, TRUE, NULL, "error starting hostname thread");
 	}
 }
 
 static void
 update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 {
-	NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
+	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
 	NMDevice *best = NULL;
 	NMActRequest *best_req = NULL;
-	NMNamedManager *named_mgr;
+	NMDnsManager *dns_mgr;
 	GSList *devices = NULL, *iter, *vpns;
 	NMIP4Config *ip4_config = NULL;
 	NMIP4Address *addr;
@@ -382,6 +484,13 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 		/* If it's marked 'never-default', don't make it default */
 		vpn_connection = nm_vpn_connection_get_connection (candidate);
 		g_assert (vpn_connection);
+
+		/* Check the active IP4 config from the VPN service daemon */
+		ip4_config = nm_vpn_connection_get_ip4_config (candidate);
+		if (ip4_config && nm_ip4_config_get_never_default (ip4_config))
+			can_default = FALSE;
+
+		/* Check the user's preference from the NMConnection */
 		s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (vpn_connection, NM_TYPE_SETTING_IP4_CONFIG);
 		if (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
 			can_default = FALSE;
@@ -393,7 +502,6 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 
 			ip_iface = nm_vpn_connection_get_ip_iface (candidate);
 			connection = nm_vpn_connection_get_connection (candidate);
-			ip4_config = nm_vpn_connection_get_ip4_config (candidate);
 			addr = nm_ip4_config_get_address (ip4_config, 0);
 
 			parent = nm_vpn_connection_get_parent_device (candidate);
@@ -406,7 +514,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 			                                         nm_device_get_ip_iface (parent),
 			                                         nm_ip4_config_get_mss (parent_ip4));
 
-			dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN;
+			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
 		}
 		g_object_unref (candidate);
 	}
@@ -422,7 +530,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 
 		nm_system_replace_default_ip4_route (ip_iface, nm_ip4_address_get_gateway (addr), nm_ip4_config_get_mss (ip4_config));
 
-		dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
+		dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
 	}
 
 	if (!ip_iface || !ip4_config) {
@@ -446,9 +554,9 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 			nm_act_request_set_default (req, FALSE);
 	}
 
-	named_mgr = nm_named_manager_get ();
-	nm_named_manager_add_ip4_config (named_mgr, ip_iface, ip4_config, dns_type);
-	g_object_unref (named_mgr);
+	dns_mgr = nm_dns_manager_get (NULL);
+	nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, ip4_config, dns_type);
+	g_object_unref (dns_mgr);
 
 	/* Now set new default active connection _after_ updating DNS info, so that
 	 * if the connection is shared dnsmasq picks up the right stuff.
@@ -473,10 +581,10 @@ out:
 static void
 update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 {
-	NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
+	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
 	NMDevice *best = NULL;
 	NMActRequest *best_req = NULL;
-	NMNamedManager *named_mgr;
+	NMDnsManager *dns_mgr;
 	GSList *devices = NULL, *iter;
 #if NOT_YET
 	GSList *vpns;
@@ -531,7 +639,7 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 			                                         nm_device_get_ip_iface (parent),
 			                                         nm_ip6_config_get_mss (parent_ip4));
 
-			dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN;
+			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
 		}
 		g_object_unref (candidate);
 	}
@@ -548,7 +656,7 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 
 		nm_system_replace_default_ip6_route (ip_iface, nm_ip6_address_get_gateway (addr));
 
-		dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
+		dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
 	}
 
 	if (!ip_iface || !ip6_config) {
@@ -572,9 +680,9 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 			nm_act_request_set_default6 (req, FALSE);
 	}
 
-	named_mgr = nm_named_manager_get ();
-	nm_named_manager_add_ip6_config (named_mgr, ip_iface, ip6_config, dns_type);
-	g_object_unref (named_mgr);
+	dns_mgr = nm_dns_manager_get (NULL);
+	nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type);
+	g_object_unref (dns_mgr);
 
 	/* Now set new default active connection _after_ updating DNS info, so that
 	 * if the connection is shared dnsmasq picks up the right stuff.
@@ -603,7 +711,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
 	update_ip6_routing_and_dns (policy, force_update);
 
 	/* Update the system hostname */
-	update_system_hostname (policy, policy->default_device4);
+	update_system_hostname (policy, policy->default_device4, policy->default_device6);
 }
 
 typedef struct {
@@ -633,7 +741,8 @@ auto_activate_device (gpointer user_data)
 
 	/* System connections first, then user connections */
 	connections = nm_manager_get_connections (policy->manager, NM_CONNECTION_SCOPE_SYSTEM);
-	connections = g_slist_concat (connections, nm_manager_get_connections (policy->manager, NM_CONNECTION_SCOPE_USER));
+	if (nm_manager_auto_user_connections_allowed (policy->manager))
+		connections = g_slist_concat (connections, nm_manager_get_connections (policy->manager, NM_CONNECTION_SCOPE_USER));
 
 	/* Remove connections that are in the invalid list. */
 	iter = connections;
@@ -652,13 +761,11 @@ auto_activate_device (gpointer user_data)
 	best_connection = nm_device_get_best_auto_connection (data->device, connections, &specific_object);
 	if (best_connection) {
 		GError *error = NULL;
-		const char *device_path;
 
-		device_path = nm_device_get_path (data->device);
 		if (!nm_manager_activate_connection (policy->manager,
 		                                     best_connection,
 		                                     specific_object,
-		                                     device_path,
+		                                     nm_device_get_path (data->device),
 		                                     FALSE,
 		                                     &error)) {
 			NMSettingConnection *s_con;
@@ -712,7 +819,7 @@ global_state_changed (NMManager *manager, NMState state, gpointer user_data)
 static void
 hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
 {
-	update_system_hostname ((NMPolicy *) user_data, NULL);
+	update_system_hostname ((NMPolicy *) user_data, NULL, NULL);
 }
 
 static void
@@ -793,23 +900,10 @@ device_state_changed (NMDevice *device,
 		/* Mark the connection invalid if it failed during activation so that
 		 * it doesn't get automatically chosen over and over and over again.
 		 */
-		if (connection) {
-			gboolean fail = FALSE;
-
-			if (IS_ACTIVATING_STATE (old_state)) {
-				nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", get_connection_id (connection));
-				fail = TRUE;
-			} else if (   (old_state == NM_DEVICE_STATE_ACTIVATED)
-			         && (reason == NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED)) {
-				nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid because IP configuration expired.",
-				             get_connection_id (connection));
-				fail = TRUE;
-			}
-
-			if (fail) {
-				g_object_set_data (G_OBJECT (connection), INVALID_TAG, GUINT_TO_POINTER (TRUE));
-				nm_connection_clear_secrets (connection);
-			}
+		if (connection && IS_ACTIVATING_STATE (old_state)) {
+			g_object_set_data (G_OBJECT (connection), INVALID_TAG, GUINT_TO_POINTER (TRUE));
+			nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", get_connection_id (connection));
+			nm_connection_clear_secrets (connection);
 		}
 		schedule_activate_check (policy, device, 3);
 		break;
@@ -1013,6 +1107,12 @@ connection_removed (NMManager *manager,
 	g_ptr_array_free (list, TRUE);
 }
 
+static void
+manager_user_permissions_changed (NMManager *manager, NMPolicy *policy)
+{
+	schedule_activate_all (policy);
+}
+
 NMPolicy *
 nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager)
 {
@@ -1088,6 +1188,10 @@ nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager)
 	                       G_CALLBACK (connection_removed), policy);
 	policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
 
+	id = g_signal_connect (manager, "user-permissions-changed",
+	                       G_CALLBACK (manager_user_permissions_changed), policy);
+	policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
+
 	return policy;
 }
 
@@ -1117,6 +1221,7 @@ nm_policy_destroy (NMPolicy *policy)
 
 	g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_activated_id);
 	g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_deactivated_id);
+	g_object_unref (policy->vpn_manager);
 
 	for (iter = policy->signal_ids; iter; iter = g_slist_next (iter))
 		g_signal_handler_disconnect (policy->manager, (gulong) iter->data);
@@ -1130,7 +1235,17 @@ nm_policy_destroy (NMPolicy *policy)
 	}
 	g_slist_free (policy->dev_signal_ids);
 
+	/* Rewrite /etc/hosts on exit to ensure we don't leave stale IP addresses
+	 * lying around.  FIXME: this will take out a valid IP address of an
+	 * ethernet device we're leaving active (ie, a connection we can "assume"
+	 * when NM starts again).
+	 */
+	policy->default_device4 = NULL;
+	policy->default_device6 = NULL;
+	update_system_hostname (policy, NULL, NULL);
+
 	g_free (policy->orig_hostname);
+	g_free (policy->cur_hostname);
 
 	g_object_unref (policy->manager);
 	g_free (policy);