mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 04:50:07 +01:00
merge: branch 'lr/reapply'
https://bugzilla.gnome.org/show_bug.cgi?id=758463
This commit is contained in:
commit
4059b253b7
10 changed files with 637 additions and 40 deletions
|
|
@ -282,11 +282,12 @@ static void
|
|||
usage (void)
|
||||
{
|
||||
g_printerr (_("Usage: nmcli device { COMMAND | help }\n\n"
|
||||
"COMMAND := { status | show | connect | disconnect | delete | monitor | wifi | lldp }\n\n"
|
||||
"COMMAND := { status | show | connect | reapply | disconnect | delete | monitor | wifi | lldp }\n\n"
|
||||
" status\n\n"
|
||||
" show [<ifname>]\n\n"
|
||||
" set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n"
|
||||
" connect <ifname>\n\n"
|
||||
" reapply <ifname> ...\n\n"
|
||||
" disconnect <ifname> ...\n\n"
|
||||
" delete <ifname> ...\n\n"
|
||||
" monitor <ifname> ...\n\n"
|
||||
|
|
@ -337,6 +338,17 @@ usage_device_connect (void)
|
|||
"It will also consider connections that are not set to auto-connect.\n\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
usage_device_reapply (void)
|
||||
{
|
||||
g_printerr (_("Usage: nmcli device reapply { ARGUMENTS | help }\n"
|
||||
"\n"
|
||||
"ARGUMENTS := <ifname> ...\n"
|
||||
"\n"
|
||||
"Attempts to update device with changes to the currently active connection\n"
|
||||
"made since it was last applied.\n\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
usage_device_disconnect (void)
|
||||
{
|
||||
|
|
@ -1813,6 +1825,116 @@ device_cb_info_finish (DeviceCbInfo *info, NMDevice *device)
|
|||
quit ();
|
||||
}
|
||||
|
||||
static void
|
||||
reapply_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE (object);
|
||||
DeviceCbInfo *info = (DeviceCbInfo *) user_data;
|
||||
NmCli *nmc = info->nmc;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!nm_device_reapply_finish (device, result, &error)) {
|
||||
g_string_printf (nmc->return_text, _("Error: not all connections reapplied."));
|
||||
g_printerr (_("Error: Reapplying connection to device '%s' (%s) failed: %s\n"),
|
||||
nm_device_get_iface (device),
|
||||
nm_object_get_path (NM_OBJECT (device)),
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT;
|
||||
device_cb_info_finish (info, device);
|
||||
} else {
|
||||
if (nmc->print_output == NMC_PRINT_PRETTY)
|
||||
nmc_terminal_erase_line ();
|
||||
g_print (_("Connection successfully reapplied to device '%s'.\n"),
|
||||
nm_device_get_iface (device));
|
||||
device_cb_info_finish (info, device);
|
||||
}
|
||||
}
|
||||
|
||||
static NMCResultCode
|
||||
do_device_reapply (NmCli *nmc, int argc, char **argv)
|
||||
{
|
||||
NMDevice **devices;
|
||||
NMDevice *device;
|
||||
DeviceCbInfo *info = NULL;
|
||||
GSList *queue = NULL, *iter;
|
||||
char **arg_arr = NULL;
|
||||
char **arg_ptr = argv;
|
||||
int arg_num = argc;
|
||||
int i;
|
||||
|
||||
/* Set default timeout for reapply operation. */
|
||||
if (nmc->timeout == -1)
|
||||
nmc->timeout = 10;
|
||||
|
||||
if (argc == 0) {
|
||||
if (nmc->ask) {
|
||||
char *line = nmc_readline (PROMPT_INTERFACES);
|
||||
nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num);
|
||||
g_free (line);
|
||||
arg_ptr = arg_arr;
|
||||
}
|
||||
if (arg_num == 0) {
|
||||
g_string_printf (nmc->return_text, _("Error: No interface specified."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
devices = get_devices_sorted (nmc->client);
|
||||
while (arg_num > 0) {
|
||||
device = NULL;
|
||||
for (i = 0; devices[i]; i++) {
|
||||
if (!g_strcmp0 (nm_device_get_iface (devices[i]), *arg_ptr)) {
|
||||
device = devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (device) {
|
||||
if (!g_slist_find (queue, device))
|
||||
queue = g_slist_prepend (queue, device);
|
||||
else
|
||||
g_printerr (_("Warning: argument '%s' is duplicated.\n"), *arg_ptr);
|
||||
} else {
|
||||
g_printerr (_("Error: Device '%s' not found.\n"), *arg_ptr);
|
||||
g_string_printf (nmc->return_text, _("Error: not all devices found."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Take next argument */
|
||||
next_arg (&arg_num, &arg_ptr);
|
||||
}
|
||||
g_free (devices);
|
||||
|
||||
if (!queue) {
|
||||
g_string_printf (nmc->return_text, _("Error: no valid device provided."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
|
||||
goto error;
|
||||
}
|
||||
queue = g_slist_reverse (queue);
|
||||
|
||||
info = g_slice_new0 (DeviceCbInfo);
|
||||
info->nmc = nmc;
|
||||
|
||||
nmc->nowait_flag = (nmc->timeout == 0);
|
||||
nmc->should_wait = TRUE;
|
||||
|
||||
for (iter = queue; iter; iter = g_slist_next (iter)) {
|
||||
device = iter->data;
|
||||
|
||||
info->queue = g_slist_prepend (info->queue, g_object_ref (device));
|
||||
|
||||
/* Now reapply the connection to the device */
|
||||
nm_device_reapply_async (device, NULL, 0, NULL, reapply_device_cb, info);
|
||||
}
|
||||
|
||||
error:
|
||||
g_strfreev (arg_arr);
|
||||
g_slist_free (queue);
|
||||
return nmc->return_value;
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
|
|
@ -3593,6 +3715,13 @@ do_devices (NmCli *nmc, int argc, char **argv)
|
|||
}
|
||||
nmc->return_value = do_device_connect (nmc, argc-1, argv+1);
|
||||
}
|
||||
else if (matches (*argv, "reapply") == 0) {
|
||||
if (nmc_arg_is_help (*(argv+1))) {
|
||||
usage_device_reapply ();
|
||||
goto usage_exit;
|
||||
}
|
||||
nmc->return_value = do_device_reapply (nmc, argc-1, argv+1);
|
||||
}
|
||||
else if (matches (*argv, "disconnect") == 0) {
|
||||
if (nmc_arg_is_help (*(argv+1))) {
|
||||
usage_device_disconnect ();
|
||||
|
|
|
|||
|
|
@ -1419,7 +1419,7 @@ _nmcli()
|
|||
;;
|
||||
d|de|dev|devi|devic|device)
|
||||
if [[ ${#words[@]} -eq 2 ]]; then
|
||||
_nmcli_compl_COMMAND "$command" status show connect disconnect delete monitor wifi set lldp
|
||||
_nmcli_compl_COMMAND "$command" status show connect reapply disconnect delete monitor wifi set lldp
|
||||
elif [[ ${#words[@]} -gt 2 ]]; then
|
||||
case "$command" in
|
||||
s|st|sta|stat|statu|status)
|
||||
|
|
@ -1433,6 +1433,7 @@ _nmcli()
|
|||
_nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)"
|
||||
fi
|
||||
;;
|
||||
r|re|rea|reap|reapp|reappl|reapply| \
|
||||
d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect| \
|
||||
de|del|dele|delet|delete| \
|
||||
m|mo|mon|moni|monit|monito|monitor)
|
||||
|
|
|
|||
|
|
@ -169,6 +169,27 @@
|
|||
</tp:docstring>
|
||||
</property>
|
||||
|
||||
<method name="Reapply">
|
||||
<arg name="connection" type="a{sa{sv}}" direction="in">
|
||||
<tp:docstring>
|
||||
The effective connection settings and properties to use. If empty, the connection
|
||||
settings from the connection that is active on the device will be used.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
<arg name="flags" type="u" direction="in">
|
||||
<tp:docstring>
|
||||
Flags which would modify the behavior of the Reapply call.
|
||||
There are no flags defined currently and the users should use the value of 0.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
<tp:docstring>
|
||||
Attempts to update the configuration of a device without deactivating it.
|
||||
You can either modify the configuration by passing the desired setup via "connection"
|
||||
argument or just omit the argument to bring it in sync with the connection that
|
||||
has been activated but could have been modified since.
|
||||
</tp:docstring>
|
||||
</method>
|
||||
|
||||
<method name="Disconnect">
|
||||
<tp:docstring>
|
||||
Disconnects a device and prevents the device from automatically activating further connections without user intervention.
|
||||
|
|
|
|||
|
|
@ -1037,4 +1037,7 @@ global:
|
|||
nm_vpn_service_plugin_set_ip4_config;
|
||||
nm_vpn_service_plugin_set_ip6_config;
|
||||
nm_vpn_service_plugin_set_login_banner;
|
||||
nm_device_reapply;
|
||||
nm_device_reapply_async;
|
||||
nm_device_reapply_finish;
|
||||
} libnm_1_0_0;
|
||||
|
|
|
|||
|
|
@ -2164,6 +2164,128 @@ nm_device_is_software (NMDevice *device)
|
|||
return !!(NM_DEVICE_GET_PRIVATE (device)->capabilities & NM_DEVICE_CAP_IS_SOFTWARE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_reapply:
|
||||
* @device: a #NMDevice
|
||||
* @connection: the #NMConnection to replace the applied settings with or %NULL to reuse existing
|
||||
* @flags: always set this to zero
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @error: location for a #GError, or %NULL
|
||||
*
|
||||
* Attempts to update device with changes to the currently active connection
|
||||
* made since it was last applied.
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
|
||||
**/
|
||||
gboolean
|
||||
nm_device_reapply (NMDevice *device,
|
||||
NMConnection *connection,
|
||||
guint flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GVariant *dict = NULL;
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
|
||||
|
||||
if (connection)
|
||||
dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
|
||||
if (!dict)
|
||||
dict = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0);
|
||||
|
||||
|
||||
ret = nmdbus_device_call_reapply_sync (NM_DEVICE_GET_PRIVATE (device)->proxy,
|
||||
dict, flags, cancellable, error);
|
||||
if (error && *error)
|
||||
g_dbus_error_strip_remote_error (*error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
device_reapply_cb (GObject *proxy,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (nmdbus_device_call_reapply_finish (NMDBUS_DEVICE (proxy), result, &error))
|
||||
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
|
||||
else {
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_simple_async_result_take_error (simple, error);
|
||||
}
|
||||
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_reapply_async:
|
||||
* @device: a #NMDevice
|
||||
* @connection: the #NMConnection to replace the applied settings with or %NULL to reuse existing
|
||||
* @flags: always set this to zero
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @callback: callback to be called when the reapply operation completes
|
||||
* @user_data: caller-specific data passed to @callback
|
||||
*
|
||||
* Asynchronously begins an attempt to update device with changes to the
|
||||
* currently active connection made since it was last applied.
|
||||
**/
|
||||
void
|
||||
nm_device_reapply_async (NMDevice *device,
|
||||
NMConnection *connection,
|
||||
guint flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GVariant *dict = NULL;
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_if_fail (NM_IS_DEVICE (device));
|
||||
|
||||
if (connection)
|
||||
dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
|
||||
if (!dict)
|
||||
dict = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0);
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (device), callback, user_data,
|
||||
nm_device_reapply_async);
|
||||
|
||||
nmdbus_device_call_reapply (NM_DEVICE_GET_PRIVATE (device)->proxy,
|
||||
dict, flags, cancellable,
|
||||
device_reapply_cb, simple);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_reapply_finish:
|
||||
* @device: a #NMDevice
|
||||
* @result: the result passed to the #GAsyncReadyCallback
|
||||
* @error: location for a #GError, or %NULL
|
||||
*
|
||||
* Gets the result of a call to nm_device_reapply_async().
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE on error, in which case @error
|
||||
* will be set.
|
||||
**/
|
||||
gboolean
|
||||
nm_device_reapply_finish (NMDevice *device,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (device), nm_device_reapply_async), FALSE);
|
||||
|
||||
simple = G_SIMPLE_ASYNC_RESULT (result);
|
||||
if (g_simple_async_result_propagate_error (simple, error))
|
||||
return FALSE;
|
||||
else
|
||||
return g_simple_async_result_get_op_res_gboolean (simple);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_disconnect:
|
||||
* @device: a #NMDevice
|
||||
|
|
|
|||
|
|
@ -138,6 +138,21 @@ GPtrArray * nm_device_get_lldp_neighbors (NMDevice *device);
|
|||
char ** nm_device_disambiguate_names (NMDevice **devices,
|
||||
int num_devices);
|
||||
|
||||
gboolean nm_device_reapply (NMDevice *device,
|
||||
NMConnection *connection,
|
||||
guint flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
void nm_device_reapply_async (NMDevice *device,
|
||||
NMConnection *connection,
|
||||
guint flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean nm_device_reapply_finish (NMDevice *device,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_device_disconnect (NMDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
|
|
|||
|
|
@ -892,7 +892,7 @@ provided, the VPN configuration data will be printed to standard output.
|
|||
.B device - show and manage network interfaces
|
||||
.br
|
||||
.TP
|
||||
.SS \fICOMMAND\fP := { status | show | set | connect | disconnect | delete | monitor | wifi | lldp }
|
||||
.SS \fICOMMAND\fP := { status | show | set | connect | reapply | disconnect | delete | monitor | wifi | lldp }
|
||||
.sp
|
||||
.RS
|
||||
.TP
|
||||
|
|
@ -920,6 +920,11 @@ will be activated. It will also consider connections that are not set to auto co
|
|||
.br
|
||||
If '--wait' option is not specified, the default timeout will be 90 seconds.
|
||||
.TP
|
||||
.B reapply <ifname>
|
||||
.br
|
||||
Attempt to update device with changes to the currently active connection
|
||||
made since it was last applied.
|
||||
.TP
|
||||
.B disconnect <ifname> ...
|
||||
.br
|
||||
Disconnect a device and prevent the device from automatically activating further
|
||||
|
|
|
|||
|
|
@ -6528,7 +6528,7 @@ activate_stage5_ip4_config_commit (NMDevice *self)
|
|||
}
|
||||
|
||||
static void
|
||||
nm_device_queued_ip_config_change_clear (NMDevice *self)
|
||||
queued_ip4_config_change_clear (NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
|
|
@ -6537,6 +6537,13 @@ nm_device_queued_ip_config_change_clear (NMDevice *self)
|
|||
g_source_remove (priv->queued_ip4_config_id);
|
||||
priv->queued_ip4_config_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
queued_ip6_config_change_clear (NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
if (priv->queued_ip6_config_id) {
|
||||
_LOGD (LOGD_DEVICE, "clearing queued IP6 config change");
|
||||
g_source_remove (priv->queued_ip6_config_id);
|
||||
|
|
@ -6556,7 +6563,7 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf
|
|||
if (config)
|
||||
priv->dev_ip4_config = g_object_ref (config);
|
||||
|
||||
nm_device_queued_ip_config_change_clear (self);
|
||||
queued_ip4_config_change_clear (self);
|
||||
activation_source_schedule (self, activate_stage5_ip4_config_commit, AF_INET);
|
||||
}
|
||||
|
||||
|
|
@ -6795,6 +6802,301 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex)
|
|||
ifindex, data->idle_add_id);
|
||||
}
|
||||
|
||||
static void
|
||||
_cleanup_ip4_pre (NMDevice *self, CleanupType cleanup_type)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
priv->ip4_state = IP_NONE;
|
||||
queued_ip4_config_change_clear (self);
|
||||
|
||||
dhcp4_cleanup (self, cleanup_type, FALSE);
|
||||
arp_cleanup (self);
|
||||
dnsmasq_cleanup (self);
|
||||
ipv4ll_cleanup (self);
|
||||
}
|
||||
|
||||
static void
|
||||
_cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
priv->ip6_state = IP_NONE;
|
||||
queued_ip6_config_change_clear (self);
|
||||
|
||||
dhcp6_cleanup (self, cleanup_type, FALSE);
|
||||
linklocal6_cleanup (self);
|
||||
addrconf6_cleanup (self);
|
||||
}
|
||||
|
||||
G_GNUC_NULL_TERMINATED
|
||||
static gboolean
|
||||
_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **error, ...)
|
||||
{
|
||||
va_list ap;
|
||||
const char *key;
|
||||
guint found_keys = 0;
|
||||
|
||||
#if NM_MORE_ASSERTS > 10
|
||||
/* Assert that the keys are unique. */
|
||||
{
|
||||
gs_unref_hashtable GHashTable *check_dups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
|
||||
|
||||
va_start (ap, error);
|
||||
while ((key = va_arg (ap, const char *))) {
|
||||
if (!g_hash_table_add (check_dups, (char *) key))
|
||||
nm_assert (FALSE);
|
||||
}
|
||||
va_end (ap);
|
||||
nm_assert (g_hash_table_size (check_dups) > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!hash || g_hash_table_size (hash) == 0)
|
||||
return TRUE;
|
||||
|
||||
va_start (ap, error);
|
||||
while ((key = va_arg (ap, const char *))) {
|
||||
if (g_hash_table_contains (hash, key))
|
||||
found_keys++;
|
||||
}
|
||||
va_end (ap);
|
||||
|
||||
if (found_keys != g_hash_table_size (hash)) {
|
||||
GHashTableIter iter;
|
||||
const char *k = NULL;
|
||||
const char *first_invalid_key = NULL;
|
||||
|
||||
if (!error)
|
||||
return FALSE;
|
||||
|
||||
g_hash_table_iter_init (&iter, hash);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &k, NULL)) {
|
||||
va_start (ap, error);
|
||||
while ((key = va_arg (ap, const char *))) {
|
||||
if (!strcmp (key, k)) {
|
||||
first_invalid_key = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end (ap);
|
||||
if (first_invalid_key)
|
||||
break;
|
||||
}
|
||||
g_set_error (error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
|
||||
"Can't reapply changes to '%s%s%s' setting",
|
||||
setting_name ? : "",
|
||||
setting_name ? "." : "",
|
||||
first_invalid_key ? : "<UNKNOWN>");
|
||||
g_return_val_if_fail (first_invalid_key, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* reapply_connection:
|
||||
* @connection: the new connection settings to be applied or %NULL to reapply
|
||||
* the current settings connection
|
||||
* @error: the error if %FALSE is returned
|
||||
*
|
||||
* Change configuration of an already configured device if possible.
|
||||
* Updates the device's applied connection upon success.
|
||||
*
|
||||
* Return: %FALSE if the new configuration can not be reapplied.
|
||||
*/
|
||||
static gboolean
|
||||
reapply_connection (NMDevice *self,
|
||||
NMConnection *connection,
|
||||
GError **error)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
NMConnection *applied = nm_device_get_applied_connection (self);
|
||||
gs_unref_object NMConnection *applied_clone = NULL;
|
||||
gs_unref_hashtable GHashTable *diffs = NULL;
|
||||
NMConnection *con_old, *con_new;
|
||||
NMSettingIPConfig *s_ip4_old, *s_ip4_new;
|
||||
NMSettingIPConfig *s_ip6_old, *s_ip6_new;
|
||||
|
||||
if (priv->state != NM_DEVICE_STATE_ACTIVATED) {
|
||||
g_set_error_literal (error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_NOT_ACTIVE,
|
||||
"Device is not activated");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nm_connection_diff (connection,
|
||||
applied,
|
||||
NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP |
|
||||
NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS,
|
||||
&diffs);
|
||||
|
||||
/**************************************************************************
|
||||
* check for unsupported changes and reject to reapply
|
||||
*************************************************************************/
|
||||
if (!_hash_check_invalid_keys (diffs, NULL, error,
|
||||
NM_SETTING_IP4_CONFIG_SETTING_NAME,
|
||||
NM_SETTING_IP6_CONFIG_SETTING_NAME,
|
||||
NM_SETTING_CONNECTION_SETTING_NAME,
|
||||
NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!_hash_check_invalid_keys (diffs ? g_hash_table_lookup (diffs, NM_SETTING_CONNECTION_SETTING_NAME) : NULL,
|
||||
NM_SETTING_CONNECTION_SETTING_NAME,
|
||||
error,
|
||||
NM_SETTING_CONNECTION_ZONE,
|
||||
NM_SETTING_CONNECTION_METERED,
|
||||
NULL))
|
||||
return FALSE;
|
||||
|
||||
_LOGD (LOGD_DEVICE, "reapply");
|
||||
|
||||
/**************************************************************************
|
||||
* Update applied connection
|
||||
*************************************************************************/
|
||||
|
||||
if (diffs) {
|
||||
con_old = applied_clone = nm_simple_connection_new_clone (applied);
|
||||
con_new = applied;
|
||||
nm_connection_replace_settings_from_connection (applied, connection);
|
||||
} else
|
||||
con_old = con_new = applied;
|
||||
|
||||
s_ip4_new = nm_connection_get_setting_ip4_config (con_new);
|
||||
s_ip4_old = nm_connection_get_setting_ip4_config (con_old);
|
||||
s_ip6_new = nm_connection_get_setting_ip6_config (con_new);
|
||||
s_ip6_old = nm_connection_get_setting_ip6_config (con_old);
|
||||
|
||||
/**************************************************************************
|
||||
* Reapply changes
|
||||
*************************************************************************/
|
||||
|
||||
nm_device_update_firewall_zone (self);
|
||||
nm_device_update_metered (self);
|
||||
|
||||
if (priv->ip4_state != IP_NONE) {
|
||||
g_clear_object (&priv->con_ip4_config);
|
||||
priv->con_ip4_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
|
||||
nm_ip4_config_merge_setting (priv->con_ip4_config,
|
||||
s_ip4_new,
|
||||
nm_device_get_ip4_route_metric (self));
|
||||
|
||||
if (strcmp (nm_setting_ip_config_get_method (s_ip4_new),
|
||||
nm_setting_ip_config_get_method (s_ip4_old))) {
|
||||
_cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE);
|
||||
priv->ip4_state = IP_WAIT;
|
||||
if (!nm_device_activate_stage3_ip4_start (self))
|
||||
_LOGW (LOGD_IP4, "Failed to apply IPv4 configuration");
|
||||
} else
|
||||
ip4_config_merge_and_apply (self, NULL, TRUE, NULL);
|
||||
}
|
||||
|
||||
if (priv->ip6_state != IP_NONE) {
|
||||
g_clear_object (&priv->con_ip6_config);
|
||||
priv->con_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
|
||||
nm_ip6_config_merge_setting (priv->con_ip6_config,
|
||||
s_ip6_new,
|
||||
nm_device_get_ip6_route_metric (self));
|
||||
|
||||
if (strcmp (nm_setting_ip_config_get_method (s_ip6_new),
|
||||
nm_setting_ip_config_get_method (s_ip6_old))) {
|
||||
_cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE);
|
||||
priv->ip6_state = IP_WAIT;
|
||||
if (!nm_device_activate_stage3_ip6_start (self))
|
||||
_LOGW (LOGD_IP6, "Failed to apply IPv6 configuration");
|
||||
} else
|
||||
ip6_config_merge_and_apply (self, TRUE, NULL);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
reapply_cb (NMDevice *self,
|
||||
GDBusMethodInvocation *context,
|
||||
NMAuthSubject *subject,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
gs_unref_object NMConnection *connection = NM_CONNECTION (user_data);
|
||||
GError *local = NULL;
|
||||
|
||||
if (error) {
|
||||
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, error->message);
|
||||
g_dbus_method_invocation_return_gerror (context, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reapply_connection (self,
|
||||
connection ? : (NMConnection *) nm_device_get_settings_connection (self),
|
||||
&local)) {
|
||||
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, local->message);
|
||||
g_dbus_method_invocation_take_error (context, local);
|
||||
local = NULL;
|
||||
} else {
|
||||
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, TRUE, subject, NULL);
|
||||
g_dbus_method_invocation_return_value (context, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
impl_device_reapply (NMDevice *self,
|
||||
GDBusMethodInvocation *context,
|
||||
GVariant *settings,
|
||||
guint flags)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
NMSettingsConnection *settings_connection;
|
||||
NMConnection *connection = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
/* No flags supported as of now. */
|
||||
if (flags != 0) {
|
||||
error = g_error_new_literal (NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_NOT_ACTIVE,
|
||||
"Invalid flags specified");
|
||||
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message);
|
||||
g_dbus_method_invocation_take_error (context, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->state != NM_DEVICE_STATE_ACTIVATED) {
|
||||
error = g_error_new_literal (NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_NOT_ACTIVE,
|
||||
"Device is not activated");
|
||||
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message);
|
||||
g_dbus_method_invocation_take_error (context, error);
|
||||
return;
|
||||
}
|
||||
|
||||
settings_connection = nm_device_get_settings_connection (self);
|
||||
g_return_if_fail (settings_connection);
|
||||
|
||||
if (settings && g_variant_n_children (settings)) {
|
||||
/* New settings specified inline. */
|
||||
connection = nm_simple_connection_new_from_dbus (settings, &error);
|
||||
if (!connection) {
|
||||
g_prefix_error (&error, "The settings specified are invalid: ");
|
||||
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message);
|
||||
g_dbus_method_invocation_take_error (context, error);
|
||||
return;
|
||||
}
|
||||
nm_connection_clear_secrets (connection);
|
||||
}
|
||||
|
||||
/* Ask the manager to authenticate this request for us */
|
||||
g_signal_emit (self, signals[AUTH_REQUEST], 0,
|
||||
context,
|
||||
nm_device_get_applied_connection (self),
|
||||
NM_AUTH_PERMISSION_NETWORK_CONTROL,
|
||||
TRUE,
|
||||
reapply_cb,
|
||||
connection);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_cb (NMDevice *self,
|
||||
GDBusMethodInvocation *context,
|
||||
|
|
@ -8939,23 +9241,6 @@ nm_device_has_pending_action (NMDevice *self)
|
|||
|
||||
/***********************************************************/
|
||||
|
||||
static void
|
||||
_cleanup_ip_pre (NMDevice *self, CleanupType cleanup_type)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
priv->ip4_state = priv->ip6_state = IP_NONE;
|
||||
nm_device_queued_ip_config_change_clear (self);
|
||||
|
||||
dhcp4_cleanup (self, cleanup_type, FALSE);
|
||||
arp_cleanup (self);
|
||||
dhcp6_cleanup (self, cleanup_type, FALSE);
|
||||
linklocal6_cleanup (self);
|
||||
addrconf6_cleanup (self);
|
||||
dnsmasq_cleanup (self);
|
||||
ipv4ll_cleanup (self);
|
||||
}
|
||||
|
||||
static void
|
||||
_cancel_activation (NMDevice *self)
|
||||
{
|
||||
|
|
@ -8997,7 +9282,8 @@ _cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type)
|
|||
/* Clear any queued transitions */
|
||||
nm_device_queued_state_clear (self);
|
||||
|
||||
_cleanup_ip_pre (self, cleanup_type);
|
||||
_cleanup_ip4_pre (self, cleanup_type);
|
||||
_cleanup_ip6_pre (self, cleanup_type);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -9536,7 +9822,8 @@ _set_state_full (NMDevice *self,
|
|||
/* Clean up any half-done IP operations if the device's layer2
|
||||
* finds out it needs authentication during IP config.
|
||||
*/
|
||||
_cleanup_ip_pre (self, CLEANUP_TYPE_DECONFIGURE);
|
||||
_cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE);
|
||||
_cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -10905,6 +11192,7 @@ nm_device_class_init (NMDeviceClass *klass)
|
|||
|
||||
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
|
||||
NMDBUS_TYPE_DEVICE_SKELETON,
|
||||
"Reapply", impl_device_reapply,
|
||||
"Disconnect", impl_device_disconnect,
|
||||
"Delete", impl_device_delete,
|
||||
NULL);
|
||||
|
|
|
|||
|
|
@ -165,15 +165,27 @@ nm_audit_log (NMAuditManager *self, GPtrArray *fields, const char *file,
|
|||
static void
|
||||
_audit_log_helper (NMAuditManager *self, GPtrArray *fields, const char *file,
|
||||
guint line, const char *func, const char *op, gboolean result,
|
||||
NMAuthSubject *subject, const char *reason)
|
||||
gpointer subject_context, const char *reason)
|
||||
{
|
||||
AuditField op_field = { }, pid_field = { }, uid_field = { };
|
||||
AuditField result_field = { }, reason_field = { };
|
||||
gulong pid, uid;
|
||||
NMAuthSubject *subject = NULL;
|
||||
gs_unref_object NMAuthSubject *subject_free = NULL;
|
||||
|
||||
_audit_field_init_string (&op_field, "op", op, FALSE, BACKEND_ALL);
|
||||
g_ptr_array_insert (fields, 0, &op_field);
|
||||
|
||||
if (subject_context) {
|
||||
if (NM_IS_AUTH_SUBJECT (subject_context))
|
||||
subject = subject_context;
|
||||
else if (G_IS_DBUS_METHOD_INVOCATION (subject_context)) {
|
||||
GDBusMethodInvocation *context = subject_context;
|
||||
|
||||
subject = subject_free = nm_auth_subject_new_unix_process_from_context (context);
|
||||
} else
|
||||
g_warn_if_reached ();
|
||||
}
|
||||
if (subject && nm_auth_subject_is_unix_process (subject)) {
|
||||
pid = nm_auth_subject_get_unix_process_pid (subject);
|
||||
uid = nm_auth_subject_get_unix_process_uid (subject);
|
||||
|
|
@ -215,7 +227,7 @@ nm_audit_manager_audit_enabled (NMAuditManager *self)
|
|||
void
|
||||
_nm_audit_manager_log_connection_op (NMAuditManager *self, const char *file, guint line,
|
||||
const char *func, const char *op, NMSettingsConnection *connection,
|
||||
gboolean result, NMAuthSubject *subject, const char *reason)
|
||||
gboolean result, gpointer subject_context, const char *reason)
|
||||
{
|
||||
gs_unref_ptrarray GPtrArray *fields = NULL;
|
||||
AuditField uuid_field = { }, name_field = { };
|
||||
|
|
@ -234,13 +246,13 @@ _nm_audit_manager_log_connection_op (NMAuditManager *self, const char *file, gui
|
|||
g_ptr_array_add (fields, &name_field);
|
||||
}
|
||||
|
||||
_audit_log_helper (self, fields, file, line, func, op, result, subject, reason);
|
||||
_audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason);
|
||||
}
|
||||
|
||||
void
|
||||
_nm_audit_manager_log_control_op (NMAuditManager *self, const char *file, guint line,
|
||||
const char *func, const char *op, const char *arg,
|
||||
gboolean result, NMAuthSubject *subject,
|
||||
gboolean result, gpointer subject_context,
|
||||
const char *reason)
|
||||
{
|
||||
gs_unref_ptrarray GPtrArray *fields = NULL;
|
||||
|
|
@ -254,13 +266,13 @@ _nm_audit_manager_log_control_op (NMAuditManager *self, const char *file, guint
|
|||
_audit_field_init_string (&arg_field, "arg", arg, TRUE, BACKEND_ALL);
|
||||
g_ptr_array_add (fields, &arg_field);
|
||||
|
||||
_audit_log_helper (self, fields, file, line, func, op, result, subject, reason);
|
||||
_audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason);
|
||||
}
|
||||
|
||||
void
|
||||
_nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line,
|
||||
const char *func, const char *op, NMDevice *device,
|
||||
gboolean result, NMAuthSubject *subject,
|
||||
gboolean result, gpointer subject_context,
|
||||
const char *reason)
|
||||
{
|
||||
gs_unref_ptrarray GPtrArray *fields = NULL;
|
||||
|
|
@ -282,7 +294,7 @@ _nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint l
|
|||
g_ptr_array_add (fields, &ifindex_field);
|
||||
}
|
||||
|
||||
_audit_log_helper (self, fields, file, line, func, op, result, subject, reason);
|
||||
_audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason);
|
||||
}
|
||||
|
||||
#if HAVE_LIBAUDIT
|
||||
|
|
|
|||
|
|
@ -61,53 +61,54 @@ typedef struct {
|
|||
#define NM_AUDIT_OP_DEVICE_DISCONNECT "device-disconnect"
|
||||
#define NM_AUDIT_OP_DEVICE_DELETE "device-delete"
|
||||
#define NM_AUDIT_OP_DEVICE_MANAGED "device-managed"
|
||||
#define NM_AUDIT_OP_DEVICE_REAPPLY "device-reapply"
|
||||
|
||||
GType nm_audit_manager_get_type (void);
|
||||
NMAuditManager *nm_audit_manager_get (void);
|
||||
gboolean nm_audit_manager_audit_enabled (NMAuditManager *self);
|
||||
|
||||
#define nm_audit_log_connection_op(op, connection, result, subject, reason) \
|
||||
#define nm_audit_log_connection_op(op, connection, result, subject_context, reason) \
|
||||
G_STMT_START { \
|
||||
NMAuditManager *_audit = nm_audit_manager_get (); \
|
||||
\
|
||||
if (nm_audit_manager_audit_enabled (_audit)) { \
|
||||
_nm_audit_manager_log_connection_op (_audit, __FILE__, __LINE__, G_STRFUNC, \
|
||||
(op), (connection), (result), (subject), \
|
||||
(op), (connection), (result), (subject_context), \
|
||||
(reason)); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define nm_audit_log_control_op(op, arg, result, subject, reason) \
|
||||
#define nm_audit_log_control_op(op, arg, result, subject_context, reason) \
|
||||
G_STMT_START { \
|
||||
NMAuditManager *_audit = nm_audit_manager_get (); \
|
||||
\
|
||||
if (nm_audit_manager_audit_enabled (_audit)) { \
|
||||
_nm_audit_manager_log_control_op (_audit, __FILE__, __LINE__, G_STRFUNC, \
|
||||
(op), (arg), (result), (subject), (reason)); \
|
||||
(op), (arg), (result), (subject_context), (reason)); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define nm_audit_log_device_op(op, device, result, subject, reason) \
|
||||
#define nm_audit_log_device_op(op, device, result, subject_context, reason) \
|
||||
G_STMT_START { \
|
||||
NMAuditManager *_audit = nm_audit_manager_get (); \
|
||||
\
|
||||
if (nm_audit_manager_audit_enabled (_audit)) { \
|
||||
_nm_audit_manager_log_device_op (_audit, __FILE__, __LINE__, G_STRFUNC, \
|
||||
(op), (device), (result), (subject), (reason)); \
|
||||
(op), (device), (result), (subject_context), (reason)); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
void _nm_audit_manager_log_connection_op (NMAuditManager *self, const char *file, guint line,
|
||||
const char *func, const char *op, NMSettingsConnection *connection,
|
||||
gboolean result, NMAuthSubject *subject, const char *reason);
|
||||
gboolean result, gpointer subject_context, const char *reason);
|
||||
|
||||
void _nm_audit_manager_log_control_op (NMAuditManager *self, const char *file, guint line,
|
||||
const char *func, const char *op, const char *arg,
|
||||
gboolean result, NMAuthSubject *subject, const char *reason);
|
||||
gboolean result, gpointer subject_context, const char *reason);
|
||||
|
||||
void _nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line,
|
||||
const char *func, const char *op, NMDevice *device,
|
||||
gboolean result, NMAuthSubject *subject, const char *reason);
|
||||
gboolean result, gpointer subject_context, const char *reason);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __NM_AUDIT_MANAGER_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue