static void
remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection)
{
	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
	gboolean unmanaged, unrecognized;

	g_return_if_fail (self != NULL);
	g_return_if_fail (connection != NULL);

	_LOGI ("remove "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection));

	unmanaged = !!nm_ifcfg_connection_get_unmanaged_spec (connection);
	unrecognized = !!nm_ifcfg_connection_get_unrecognized_spec (connection);

	g_object_ref (connection);
	g_hash_table_remove (priv->connections, nm_connection_get_uuid (NM_CONNECTION (connection)));
	nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection));
	g_object_unref (connection);

	/* Emit changes _after_ removing the connection */
	if (unmanaged)
		g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
	if (unrecognized)
		g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
}
Ejemplo n.º 2
0
static void
update_connection_settings_commit_cb (NMSettingsConnection *orig, GError *error, gpointer user_data)
{
	if (error) {
		g_warning ("%s: '%s' / '%s' invalid: %d",
		       	   __func__,
		       	   error ? g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)) : "(none)",
		       	   (error && error->message) ? error->message : "(none)",
		       	   error ? error->code : -1);
		g_clear_error (&error);

		nm_settings_connection_signal_remove (orig);
	}
}
Ejemplo n.º 3
0
static void
update_connection_settings_commit_cb (NMSettingsConnection *orig, GError *error, gpointer user_data)
{
	/* If there was an error updating the connection's internal stuff, then
	 * we can't do anything except log it and remove the connection.  This might
	 * happen due to invalid data, but as the data would already have been
	 * verified before it ever got to this plugin, we shouldn't ever get
	 * an error here.
	 */
	if (error) {
		nm_log_warn (LOGD_SETTINGS, "%s: connection invalid: %s",
		             __func__, error->message);
		g_clear_error (&error);

		nm_settings_connection_signal_remove (orig);
	}
}
Ejemplo n.º 4
0
static void
remove_connection (SCPluginKeyfile *self, NMKeyfileConnection *connection)
{
	gboolean removed;

	g_return_if_fail (connection != NULL);

	nm_log_info (LOGD_SETTINGS, "keyfile: removed " NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection));

	/* Removing from the hash table should drop the last reference */
	g_object_ref (connection);
	g_signal_handlers_disconnect_by_func (connection, connection_removed_cb, self);
	removed = g_hash_table_remove (SC_PLUGIN_KEYFILE_GET_PRIVATE (self)->connections,
	                               nm_connection_get_uuid (NM_CONNECTION (connection)));
	nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection));
	g_object_unref (connection);

	g_return_if_fail (removed);
}
Ejemplo n.º 5
0
static void
remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection)
{
    SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
    gboolean managed = FALSE;
    const char *path;

    g_return_if_fail (self != NULL);
    g_return_if_fail (connection != NULL);

    managed = !nm_ifcfg_connection_get_unmanaged_spec (connection);
    path = nm_ifcfg_connection_get_path (connection);

    g_object_ref (connection);
    g_hash_table_remove (priv->connections, path);
    nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection));
    g_object_unref (connection);

    /* Emit unmanaged changes _after_ removing the connection */
    if (managed == FALSE)
        g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
}
static NMIfcfgConnection *
update_connection (SCPluginIfcfg *self,
                   NMConnection *source,
                   const char *full_path,
                   NMIfcfgConnection *connection,
                   gboolean protect_existing_connection,
                   GHashTable *protected_connections,
                   GError **error)
{
	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
	NMIfcfgConnection *connection_new;
	NMIfcfgConnection *connection_by_uuid;
	GError *local = NULL;
	const char *new_unmanaged = NULL, *old_unmanaged = NULL;
	const char *new_unrecognized = NULL, *old_unrecognized = NULL;
	gboolean unmanaged_changed = FALSE, unrecognized_changed = FALSE;
	const char *uuid;

	g_return_val_if_fail (!source || NM_IS_CONNECTION (source), NULL);
	g_return_val_if_fail (full_path || source, NULL);

	if (full_path)
		_LOGD ("loading from file \"%s\"...", full_path);

	/* Create a NMIfcfgConnection instance, either by reading from @full_path or
	 * based on @source. */
	connection_new = nm_ifcfg_connection_new (source, full_path, error);
	if (!connection_new) {
		/* Unexpected failure. Probably the file is invalid? */
		if (   connection
		    && !protect_existing_connection
		    && (!protected_connections || !g_hash_table_contains (protected_connections, connection)))
			remove_connection (self, connection);
		return NULL;
	}

	uuid = nm_connection_get_uuid (NM_CONNECTION (connection_new));
	connection_by_uuid = g_hash_table_lookup (priv->connections, uuid);

	if (   connection
	    && connection != connection_by_uuid) {

		if (   (protect_existing_connection && connection_by_uuid != NULL)
		    || (protected_connections && g_hash_table_contains (protected_connections, connection))) {
			NMIfcfgConnection *conflicting = (protect_existing_connection && connection_by_uuid != NULL) ? connection_by_uuid : connection;

			if (source)
				_LOGW ("cannot update protected connection "NM_IFCFG_CONNECTION_LOG_FMT" due to conflicting UUID %s", NM_IFCFG_CONNECTION_LOG_ARG (conflicting), uuid);
			else
				_LOGW ("cannot load %s due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, full_path, NM_IFCFG_CONNECTION_LOG_ARG (conflicting));
			g_object_unref (connection_new);
			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
			                     "Cannot update protected connection due to conflicting UUID");
			return NULL;
		}

		/* The new connection has a different UUID then the original one that we
		 * are about to update. Remove @connection. */
		remove_connection (self, connection);
	}

	/* Check if the found connection with the same UUID is not protected from updating. */
	if (   connection_by_uuid
	    && (   (!connection && protect_existing_connection)
	        || (protected_connections && g_hash_table_contains (protected_connections, connection_by_uuid)))) {
		if (source)
			_LOGW ("cannot update connection due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_by_uuid));
		else
			_LOGW ("cannot load %s due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, full_path, NM_IFCFG_CONNECTION_LOG_ARG (connection_by_uuid));
		g_object_unref (connection_new);
		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
		                      "Skip updating protected connection during reload");
		return NULL;
	}

	/* Evaluate unmanaged/unrecognized flags. */
	if (connection_by_uuid)
		old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection_by_uuid);
	new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection_new);
	unmanaged_changed = g_strcmp0 (old_unmanaged, new_unmanaged);

	if (connection_by_uuid)
		old_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (connection_by_uuid);
	new_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (connection_new);
	unrecognized_changed = g_strcmp0 (old_unrecognized, new_unrecognized);

	if (connection_by_uuid) {
		const char *old_path;

		old_path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid));

		if (   !unmanaged_changed
		    && !unrecognized_changed
		    && nm_connection_compare (NM_CONNECTION (connection_by_uuid),
		                              NM_CONNECTION (connection_new),
		                              NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
		                              NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
			if (old_path && g_strcmp0 (old_path, full_path) != 0)
				_LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT" without other changes", nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid)), NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
		} else {

			/*******************************************************
			 * UPDATE
			 *******************************************************/

			if (source)
				_LOGI ("update "NM_IFCFG_CONNECTION_LOG_FMT" from %s", NM_IFCFG_CONNECTION_LOG_ARG (connection_new), NM_IFCFG_CONNECTION_LOG_PATH (old_path));
			else if (!g_strcmp0 (old_path, nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_new))))
				_LOGI ("update "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
			else if (old_path)
				_LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT, old_path, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
			else
				_LOGI ("update and persist "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));

			g_object_set (connection_by_uuid,
			              NM_IFCFG_CONNECTION_UNMANAGED_SPEC, new_unmanaged,
			              NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, new_unrecognized,
			              NULL);

			if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid),
			                                              NM_CONNECTION (connection_new),
			                                              FALSE,  /* don't set Unsaved */
			                                              "ifcfg-update",
			                                              &local)) {
				/* Shouldn't ever get here as 'connection_new' was verified by the reader already
				 * and the UUID did not change. */
				g_assert_not_reached ();
			}
			g_assert_no_error (local);

			if (new_unmanaged || new_unrecognized) {
				if (!old_unmanaged && !old_unrecognized) {
					g_object_ref (connection_by_uuid);
					/* Unexport the connection by telling the settings service it's
					 * been removed.
					 */
					nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection_by_uuid));
					/* Remove the path so that claim_connection() doesn't complain later when
					 * interface gets managed and connection is re-added. */
					nm_connection_set_path (NM_CONNECTION (connection_by_uuid), NULL);

					/* signal_remove() will end up removing the connection from our hash,
					 * so add it back now.
					 */
					g_hash_table_insert (priv->connections,
					                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection_by_uuid))),
					                     connection_by_uuid);
				}
			} else {
				if (old_unmanaged /* && !new_unmanaged */) {
					_LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" and its device because NM_CONTROLLED was true.",
					       NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
					g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_by_uuid);
				} else if (old_unrecognized /* && !new_unrecognized */) {
					_LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" because it is now a recognized type.",
					       NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
					g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_by_uuid);
				}
			}

			if (unmanaged_changed)
				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
			if (unrecognized_changed)
				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
		}
		nm_settings_connection_set_filename (NM_SETTINGS_CONNECTION (connection_by_uuid), full_path);
		g_object_unref (connection_new);
		return connection_by_uuid;
	} else {

		/*******************************************************
		 * ADD
		 *******************************************************/

		if (source)
			_LOGI ("add connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
		else
			_LOGI ("new connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
		g_hash_table_insert (priv->connections, g_strdup (uuid), connection_new);

		g_signal_connect (connection_new, NM_SETTINGS_CONNECTION_REMOVED,
		                  G_CALLBACK (connection_removed_cb),
		                  self);

		if (nm_ifcfg_connection_get_unmanaged_spec (connection_new)) {
			const char *spec;
			const char *device_id;

			spec = nm_ifcfg_connection_get_unmanaged_spec (connection_new);
			device_id = strchr (spec, ':');
			if (device_id)
				device_id++;
			else
				device_id = spec;
			_LOGW ("Ignoring connection "NM_IFCFG_CONNECTION_LOG_FMT" / device '%s' due to NM_CONTROLLED=no.",
			       NM_IFCFG_CONNECTION_LOG_ARG (connection_new), device_id);
		} else if (nm_ifcfg_connection_get_unrecognized_spec (connection_new))
			_LOGW ("Ignoring connection "NM_IFCFG_CONNECTION_LOG_FMT" of unrecognized type.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new));

		/* watch changes of ifcfg hardlinks */
		g_signal_connect (G_OBJECT (connection_new), "ifcfg-changed",
		                  G_CALLBACK (connection_ifcfg_changed), self);

		if (!source) {
			/* Only raise the signal if we were called without source, i.e. if we read the connection from file.
			 * Otherwise, we were called by add_connection() which does not expect the signal. */
			if (nm_ifcfg_connection_get_unmanaged_spec (connection_new))
				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
			else if (nm_ifcfg_connection_get_unrecognized_spec (connection_new))
				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
			else
				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_new);
		}
		return connection_new;
	}
}