Thomas Haller 2019-07-25 21:43:53 +02:00
commit 40355d03a4
19 changed files with 845 additions and 265 deletions

View file

@ -176,6 +176,7 @@ EXTRA_DIST += \
examples/python/gi/get-active-connections.py \
examples/python/gi/get_ips.py \
examples/python/gi/list-connections.py \
examples/python/gi/nm-add-connection2.py \
examples/python/gi/nm-connection-update-stable-id.py \
examples/python/gi/nm-wg-set \
examples/python/gi/setting-user-data.py \

View file

@ -41,6 +41,8 @@
#include "devices.h"
#include "polkit-agent.h"
/*****************************************************************************/
typedef enum {
PROPERTY_INF_FLAG_NONE = 0x0,
PROPERTY_INF_FLAG_DISABLED = 0x1, /* Don't ask due to runtime decision. */
@ -50,14 +52,13 @@ typedef enum {
typedef char *(*CompEntryFunc) (const char *, int);
typedef struct _OptionInfo OptionInfo;
struct _OptionInfo {
typedef struct _OptionInfo {
const NMMetaSettingInfoEditor *setting_info;
const char *property;
const char *option;
gboolean (*check_and_set)(NmCli *nmc, NMConnection *connection, const OptionInfo *option, const char *value, GError **error);
gboolean (*check_and_set)(NmCli *nmc, NMConnection *connection, const struct _OptionInfo *option, const char *value, GError **error);
CompEntryFunc generator_func;
};
} OptionInfo;
/* define some prompts for connection editor */
#define EDITOR_PROMPT_SETTING _("Setting name? ")
@ -96,6 +97,47 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (vpn_connection_state_to_string, NMVpnConnecti
NM_UTILS_LOOKUP_ITEM_IGNORE (NM_VPN_CONNECTION_STATE_UNKNOWN),
)
/*****************************************************************************/
typedef struct {
NmCli *nmc;
char *orig_id;
char *orig_uuid;
char *new_id;
} AddConnectionInfo;
static AddConnectionInfo *
_add_connection_info_new (NmCli *nmc,
NMConnection *orig_connection,
NMConnection *new_connection)
{
AddConnectionInfo *info;
info = g_slice_new (AddConnectionInfo);
*info = (AddConnectionInfo) {
.nmc = nmc,
.orig_id = orig_connection ? g_strdup (nm_connection_get_id (orig_connection)) : NULL,
.orig_uuid = orig_connection ? g_strdup (nm_connection_get_uuid (orig_connection)) : NULL,
.new_id = g_strdup (nm_connection_get_id (new_connection)),
};
return info;
}
static void
_add_connection_info_free (AddConnectionInfo *info)
{
g_free (info->orig_id);
g_free (info->orig_uuid);
g_free (info->new_id);
nm_g_slice_free (info);
}
NM_AUTO_DEFINE_FCN (AddConnectionInfo *, _nm_auto_free_add_connection_info, _add_connection_info_free)
#define nm_auto_free_add_connection_info nm_auto (_nm_auto_free_add_connection_info)
/*****************************************************************************/
/* Essentially a version of nm_setting_connection_get_connection_type() that
* prefers an alias instead of the settings name when in pretty print mode.
* That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */
@ -4755,28 +4797,23 @@ nmc_read_connection_properties (NmCli *nmc,
return TRUE;
}
typedef struct {
NmCli *nmc;
char *con_name;
} AddConnectionInfo;
static void
add_connection_cb (GObject *client,
GAsyncResult *result,
gpointer user_data)
{
AddConnectionInfo *info = (AddConnectionInfo *) user_data;
nm_auto_free_add_connection_info AddConnectionInfo *info = user_data;
NmCli *nmc = info->nmc;
NMRemoteConnection *connection;
GError *error = NULL;
const GPtrArray *connections;
guint i, found;
connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
connection = nm_client_add_connection2_finish (NM_CLIENT (client), result, NULL, &error);
if (error) {
g_string_printf (nmc->return_text,
_("Error: Failed to add '%s' connection: %s"),
info->con_name, error->message);
info->new_id, error->message);
g_error_free (error);
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
} else {
@ -4788,7 +4825,7 @@ add_connection_cb (GObject *client,
if ((NMConnection *) connection == candidate)
continue;
if (nm_streq0 (nm_connection_get_id (candidate), info->con_name))
if (nm_streq0 (nm_connection_get_id (candidate), info->new_id))
found++;
}
if (found > 0) {
@ -4796,7 +4833,7 @@ add_connection_cb (GObject *client,
"Warning: There is another connection with the name '%1$s'. Reference the connection by its uuid '%2$s'\n",
"Warning: There are %3$u other connections with the name '%1$s'. Reference the connection by its uuid '%2$s'\n",
found),
info->con_name,
info->new_id,
nm_connection_get_uuid (NM_CONNECTION (connection)),
found);
}
@ -4808,30 +4845,39 @@ add_connection_cb (GObject *client,
g_object_unref (connection);
}
g_free (info->con_name);
g_free (info);
quit ();
}
static void
add_new_connection (gboolean persistent,
NMClient *client,
NMConnection *connection,
GAsyncReadyCallback callback,
gpointer user_data)
add_connection (NMClient *client,
NMConnection *connection,
gboolean temporary,
GAsyncReadyCallback callback,
gpointer user_data)
{
nm_client_add_connection_async (client, connection, persistent,
NULL, callback, user_data);
nm_client_add_connection2 (client,
nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL),
temporary
? NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY
: NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK,
NULL,
TRUE,
NULL,
callback,
user_data);
}
static void
update_connection (gboolean persistent,
NMRemoteConnection *connection,
update_connection (NMRemoteConnection *connection,
gboolean temporary,
GAsyncReadyCallback callback,
gpointer user_data)
{
nm_remote_connection_commit_changes_async (connection, persistent,
NULL, callback, user_data);
nm_remote_connection_commit_changes_async (connection,
!temporary,
NULL,
callback,
user_data);
}
static gboolean
@ -5150,7 +5196,6 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
gs_unref_object NMConnection *connection = NULL;
NMSettingConnection *s_con;
gs_free_error GError *error = NULL;
AddConnectionInfo *info = NULL;
gboolean save_bool = TRUE;
gboolean seen_dash_dash = FALSE;
NMMetaSettingType s;
@ -5295,19 +5340,13 @@ read_properties:
}
}
add_connection (nmc->client,
connection,
!save_bool,
add_connection_cb,
_add_connection_info_new (nmc, NULL, connection));
nmc->should_wait++;
info = g_malloc0 (sizeof (AddConnectionInfo));
info->nmc = nmc;
info->con_name = g_strdup (nm_connection_get_id (connection));
/* Tell the settings service to add the new connection */
add_new_connection (save_bool,
nmc->client,
connection,
add_connection_cb,
info);
finish:
reset_options ();
return nmc->return_value;
@ -6656,14 +6695,11 @@ add_connection_editor_cb (GObject *client,
GAsyncResult *result,
gpointer user_data)
{
NMRemoteConnection *connection;
GError *error = NULL;
gs_unref_object NMRemoteConnection *connection = NULL;
gs_free_error GError *error = NULL;
connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
connection = nm_client_add_connection2_finish (NM_CLIENT (client), result, NULL, &error);
set_info_and_signal_editor_thread (error, NULL);
g_clear_object (&connection);
g_clear_error (&error);
}
static void
@ -7242,7 +7278,6 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
const NMMetaSettingValidPartItem *const*valid_settings_slave;
gs_free char *valid_settings_str = NULL;
const char *s_type = NULL;
AddConnectionInfo *info = NULL;
gboolean temp_changes;
GError *err1 = NULL;
NmcEditorMenuContext menu_ctx = { 0 };
@ -7761,7 +7796,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
case NMC_EDITOR_MAIN_CMD_SAVE:
/* Save the connection */
if (nm_connection_verify (connection, &err1)) {
gboolean persistent = TRUE;
gboolean temporary = FALSE;
gboolean connection_changed;
nm_auto_unref_gsource GSource *source = NULL;
gboolean timeout = FALSE;
@ -7770,9 +7805,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
/* parse argument */
if (cmd_arg) {
if (matches (cmd_arg, "temporary"))
persistent = FALSE;
temporary = TRUE;
else if (matches (cmd_arg, "persistent"))
persistent = TRUE;
temporary = FALSE;
else {
g_print (_("Error: invalid argument '%s'\n"), cmd_arg);
break;
@ -7788,21 +7823,17 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
}
if (!rem_con) {
/* Tell the settings service to add the new connection */
info = g_malloc0 (sizeof (AddConnectionInfo));
info->nmc = nmc;
info->con_name = g_strdup (nm_connection_get_id (connection));
add_new_connection (persistent,
nmc->client,
connection,
add_connection_editor_cb,
info);
add_connection (nmc->client,
connection,
temporary,
add_connection_editor_cb,
NULL);
connection_changed = TRUE;
} else {
/* Save/update already saved (existing) connection */
nm_connection_replace_settings_from_connection (NM_CONNECTION (rem_con),
connection);
update_connection (persistent, rem_con, update_connection_editor_cb, NULL);
update_connection (rem_con, temporary, update_connection_editor_cb, NULL);
handler_id = g_signal_connect (rem_con,
NM_CONNECTION_CHANGED,
@ -8403,35 +8434,27 @@ do_connection_modify (NmCli *nmc,
if (nmc->complete)
return nmc->return_value;
update_connection (!temporary, rc, modify_connection_cb, nmc);
update_connection (rc, temporary, modify_connection_cb, nmc);
nmc->should_wait++;
return nmc->return_value;
}
typedef struct {
NmCli *nmc;
char *orig_id;
char *orig_uuid;
char *con_id;
} CloneConnectionInfo;
static void
clone_connection_cb (GObject *client,
GAsyncResult *result,
gpointer user_data)
{
CloneConnectionInfo *info = (CloneConnectionInfo *) user_data;
nm_auto_free_add_connection_info AddConnectionInfo *info = user_data;
NmCli *nmc = info->nmc;
NMRemoteConnection *connection;
GError *error = NULL;
gs_unref_object NMRemoteConnection *connection = NULL;
gs_free_error GError *error = NULL;
connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
connection = nm_client_add_connection2_finish (NM_CLIENT (client), result, NULL, &error);
if (error) {
g_string_printf (nmc->return_text,
_("Error: Failed to add '%s' connection: %s"),
info->con_id, error->message);
g_error_free (error);
info->new_id, error->message);
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
} else {
g_print (_("%s (%s) cloned as %s (%s).\n"),
@ -8439,13 +8462,8 @@ clone_connection_cb (GObject *client,
info->orig_uuid,
nm_connection_get_id (NM_CONNECTION (connection)),
nm_connection_get_uuid (NM_CONNECTION (connection)));
g_object_unref (connection);
}
g_free (info->con_id);
g_free (info->orig_id);
g_free (info->orig_uuid);
g_slice_free (CloneConnectionInfo, info);
quit ();
}
@ -8454,11 +8472,9 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
{
NMConnection *connection = NULL;
gs_unref_object NMConnection *new_connection = NULL;
NMSettingConnection *s_con;
CloneConnectionInfo *info;
const char *new_name;
gs_free char *new_name_ask = NULL;
char *uuid;
gs_free char *new_name_free = NULL;
gs_free char *uuid = NULL;
gboolean temporary = FALSE;
char **arg_arr = NULL;
int arg_num;
@ -8499,8 +8515,8 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
if (argv[0])
new_name = *argv;
else if (nmc->ask) {
new_name = new_name_ask = nmc_readline (&nmc->nmc_config,
_("New connection name: "));
new_name = new_name_free = nmc_readline (&nmc->nmc_config,
_("New connection name: "));
} else {
g_string_printf (nmc->return_text, _("Error: <new name> argument is missing."));
NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
@ -8511,35 +8527,23 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
}
/* Copy the connection */
new_connection = nm_simple_connection_new_clone (connection);
s_con = nm_connection_get_setting_connection (new_connection);
g_assert (s_con);
uuid = nm_utils_uuid_generate ();
g_object_set (s_con,
g_object_set (nm_connection_get_setting_connection (new_connection),
NM_SETTING_CONNECTION_ID, new_name,
NM_SETTING_CONNECTION_UUID, uuid,
NULL);
g_free (uuid);
/* Merge secrets into the new connection */
update_secrets_in_connection (NM_REMOTE_CONNECTION (connection), new_connection);
info = g_slice_new0 (CloneConnectionInfo);
info->nmc = nmc;
info->orig_id = g_strdup (nm_connection_get_id (connection));
info->orig_uuid = g_strdup (nm_connection_get_uuid (connection));
info->con_id = g_strdup (nm_connection_get_id (new_connection));
/* Add the new cloned connection to NetworkManager */
add_new_connection (!temporary,
nmc->client,
new_connection,
clone_connection_cb,
info);
add_connection (nmc->client,
new_connection,
temporary,
clone_connection_cb,
_add_connection_info_new (nmc, connection, new_connection));
nmc->should_wait++;
return nmc->return_value;
}
@ -8826,7 +8830,6 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
const char *type = NULL, *filename = NULL;
gs_free char *type_ask = NULL;
gs_free char *filename_ask = NULL;
AddConnectionInfo *info;
gs_unref_object NMConnection *connection = NULL;
NMVpnEditorPlugin *plugin;
gs_free char *service_type = NULL;
@ -8943,18 +8946,13 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
}
info = g_malloc0 (sizeof (AddConnectionInfo));
info->nmc = nmc;
info->con_name = g_strdup (nm_connection_get_id (connection));
/* Add the new imported connection to NetworkManager */
add_new_connection (!temporary,
nmc->client,
connection,
add_connection_cb,
info);
add_connection (nmc->client,
connection,
temporary,
add_connection_cb,
_add_connection_info_new (nmc, NULL, connection));
nmc->should_wait++;
return nmc->return_value;
}

View file

@ -0,0 +1,156 @@
#!/usr/bin/env python
#
# 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.
#
# Copyright 2019 Red Hat, Inc.
#
import sys
import re
import gi
gi.require_version('NM', '1.0')
from gi.repository import GLib, NM
def find_connections(nm_client, arg_type, arg_id):
for c in nm_client.get_connections():
if arg_type in [None, 'id'] and c.get_id() == arg_id:
yield c
if arg_type in [None, 'uuid'] and c.get_uuid() == arg_id:
yield c
def find_connection_first(nm_client, arg_type, arg_id):
for f in find_connections(nm_client, arg_type, arg_id):
return f
def con_to_str(con):
s_con = con.get_setting_connection()
return '"%s" (%s)' % (s_con.get_id(), s_con.get_uuid())
def usage():
print('Usage: %s --clone [[id] <id>]' % (sys.argv[0]))
print(' %s --clone [[uuid] <uuid>]' % (sys.argv[0]))
return 1
def die(msg, print_usage=False):
print(msg)
if print_usage:
usage()
sys.exit(1)
def main():
main_loop = GLib.MainLoop()
nm_client = NM.Client.new(None)
arg_mode = None
arg_block_autoconnect = NM.SettingsAddConnection2Flags.NONE
arg_id = None
arg_uuid = None
cons = []
argv = list(sys.argv[1:])
while argv:
if argv[0] == '--clone':
match_type = None
if len(argv) < 2:
die('missing argument for --clone option')
if argv[0] in ['id', 'uuid']:
match_type = argv[0]
if len(argv) < 3:
die('missing argument for "--clone %s" option' % (match_type))
argv = argv[1:]
if cons:
die('cannot specify --clone argument more than once')
cons.extend(find_connections(nm_client, match_type, argv[1]))
if len(cons) == 0:
die('could not find connection for "--clone %s%s"' % ((match_type or ''), argv[1]))
if len(cons) != 1:
die('could not find unique connection for "--clone %s%s"' % ((match_type or ''), argv[1]))
argv = argv[2:]
continue
if argv[0] in ['--block-autoconnect']:
arg_block_autoconnect = NM.SettingsAddConnection2Flags.BLOCK_AUTOCONNECT
argv = argv[1:]
continue
if argv[0] in ['--to-disk', '--in-memory']:
if argv[0] == '--to-disk':
v = NM.SettingsAddConnection2Flags.TO_DISK
elif argv[0] == '--in-memory':
v = NM.SettingsAddConnection2Flags.IN_MEMORY
else:
assert(False)
if arg_mode is not None:
die('duplicate storage modes ("%s")' % (argv[0]))
arg_mode = v
argv = argv[1:]
continue
if argv[0] in ['--id']:
if len(argv) < 2:
die('missing argument for --id option')
arg_id = argv[1]
argv = argv[2:]
continue
if argv[0] in ['--uuid']:
if len(argv) < 2:
die('missing argument for --uuid option')
arg_uuid = argv[1]
argv = argv[2:]
continue
die('unknown argument "%s"' % (argv[0]))
if len(cons) != 1:
die('missing --clone argument', True)
con = cons[0]
con2 = NM.SimpleConnection.new_clone(con)
s_con = con2.get_setting_connection()
if arg_id:
s_con.set_property(NM.SETTING_CONNECTION_ID, arg_id)
s_con.set_property(NM.SETTING_CONNECTION_UUID, arg_uuid or NM.utils_uuid_generate())
result = {}
def _add_connection2_cb(cl, async_result, user_data):
try:
c, r = nm_client.add_connection2_finish(async_result)
except Exception as e:
result['error'] = e
else:
result['result'] = r
result['connection'] = c
main_loop.quit()
nm_client.add_connection2(con2.to_dbus(NM.ConnectionSerializationFlags.ALL),
(arg_mode if arg_mode is not None else NM.SettingsAddConnection2Flags.TO_DISK)
| arg_block_autoconnect,
None,
False,
None,
_add_connection2_cb,
None)
main_loop.run()
if 'error' in result:
die('update connection %s failed [%s]: %s' % (con_to_str(con2), ' '.join(sys.argv), result['error']))
print('update connection %s succeeded [%s]: %s, %s' % (con_to_str(con2), ' '.join(sys.argv), result['connection'].get_path(), result['result']))
if __name__ == '__main__':
main()

View file

@ -63,6 +63,41 @@
<arg name="path" type="o" direction="out"/>
</method>
<!--
AddConnection2:
@settings: New connection settings, properties, and (optionally) secrets.
@flags: optional flags argument. Currently the following flags are supported:
"0x1" (to-disk),
"0x2" (in-memory),
"0x20" (block-autoconnect).
Unknown flags cause the call to fail.
@args: optional arguments dictionary, for extensibility. Currently no
arguments are accepted. Specifying unknown keys causes the call
to fail.
@path: Object path of the new connection that was just added.
@result: output argument, currently no additional results are returned.
Add a new connection profile.
Either the flags 0x1 (to-disk) or 0x2 (in-memory) must be specified.
The effect is whether to behave like AddConnection or AddConnectionUnsaved.
If 0x20 (block-autoconnect) is specified, autoconnect for the new profile
is blocked from the beginnin. Otherwise, the profile might automatically
connect if a suitable device is around.
AddConnection2 is a extensible alternative to AddConnection, and AddConnectionUnsaved.
The new variant can do everything that the older variants could, and more.
Since: 1.20
-->
<method name="AddConnection2">
<arg name="settings" type="a{sa{sv}}" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="args" type="a{sv}" direction="in"/>
<arg name="path" type="o" direction="out"/>
<arg name="result" type="a{sv}" direction="out"/>
</method>
<!--
LoadConnections:
@filenames: Array of paths to on-disk connection profiles in directories monitored by NetworkManager.

View file

@ -1005,6 +1005,27 @@ typedef enum { /*< flags >*/
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY = 0x40,
} NMActivationStateFlags;
/**
* NMSettingsAddConnection2Flags:
* @NM_SETTINGS_ADD_CONNECTION2_FLAG_NONE: an alias for numeric zero, no flags set.
* @NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK: to persist the connection to disk.
* @NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY: to make the connection in-memory only.
* @NM_SETTINGS_ADD_CONNECTION2_FLAG_BLOCK_AUTOCONNECT: usually, when the connection
* has autoconnect enabled and gets added, it becomes eligible to autoconnect
* right away. Setting this flag, disables autoconnect until the connection
* is manually activated.
*
* Numeric flags for the "flags" argument of AddConnection2() D-Bus API.
*
* Since: 1.20
*/
typedef enum { /*< flags >*/
NM_SETTINGS_ADD_CONNECTION2_FLAG_NONE = 0,
NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK = 0x1,
NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY = 0x2,
NM_SETTINGS_ADD_CONNECTION2_FLAG_BLOCK_AUTOCONNECT = 0x20,
} NMSettingsAddConnection2Flags;
/**
* NMSettingsUpdate2Flags:
* @NM_SETTINGS_UPDATE2_FLAG_NONE: an alias for numeric zero, no flags set.
@ -1039,6 +1060,13 @@ typedef enum { /*< flags >*/
* has autoconnect enabled and is modified, it becomes eligible to autoconnect
* right away. Setting this flag, disables autoconnect until the connection
* is manually activated.
* @NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY: when a profile gets modified that is
* currently active, then these changes don't take effect for the active
* device unless the profile gets reactivated or the configuration reapplied.
* There are two exceptions: by default "connection.zone" and "connection.metered"
* properties take effect immediately. Specify this flag to prevent these
* properties to take effect, so that the change is restricted to modify
* the profile. Since: 1.20.
*
* Since: 1.12
*/
@ -1050,6 +1078,7 @@ typedef enum { /*< flags >*/
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY = 0x8,
NM_SETTINGS_UPDATE2_FLAG_VOLATILE = 0x10,
NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT = 0x20,
NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY = 0x40,
} NMSettingsUpdate2Flags;
/**

View file

@ -1611,6 +1611,8 @@ global:
libnm_1_20_0 {
global:
nm_client_add_connection2;
nm_client_add_connection2_finish;
nm_client_connectivity_check_get_uri;
nm_device_modem_get_apn;
nm_device_modem_get_device_id;
@ -1622,4 +1624,5 @@ global:
nm_setting_ovs_dpdk_get_devargs;
nm_setting_ovs_dpdk_get_type;
nm_setting_ovs_dpdk_new;
nm_settings_add_connection2_flags_get_type;
} libnm_1_18_0;

View file

@ -1631,23 +1631,55 @@ nm_client_get_connection_by_uuid (NMClient *client, const char *uuid)
return nm_remote_settings_get_connection_by_uuid (NM_CLIENT_GET_PRIVATE (client)->settings, uuid);
}
static void
add_connection_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GSimpleAsyncResult *simple = user_data;
NMRemoteConnection *conn;
GError *error = NULL;
typedef struct {
NMRemoteConnection *connection;
GVariant *results;
} AddConnection2CbData;
conn = nm_remote_settings_add_connection_finish (NM_REMOTE_SETTINGS (object), result, &error);
if (conn)
g_simple_async_result_set_op_res_gpointer (simple, conn, g_object_unref);
else
g_simple_async_result_take_error (simple, error);
static void
add_connection2_cb_data_destroy (gpointer user_data)
{
AddConnection2CbData *data = user_data;
g_object_unref (data->connection);
nm_g_variant_unref (data->results);
nm_g_slice_free (data);
}
static void
add_connection2_cb (NMRemoteSettings *self,
NMRemoteConnection *connection,
GVariant *results,
GError *error,
gpointer user_data)
{
gs_unref_object GSimpleAsyncResult *simple = user_data;
if (error) {
g_simple_async_result_take_error (simple,
g_error_new_literal (error->domain,
error->code,
error->message));
} else if (g_simple_async_result_get_source_tag (simple) == nm_client_add_connection_async) {
g_simple_async_result_set_op_res_gpointer (simple,
g_object_ref (connection),
g_object_unref);
} else {
AddConnection2CbData *data;
nm_assert (g_simple_async_result_get_source_tag (simple) == nm_client_add_connection2);
data = g_slice_new (AddConnection2CbData);
*data = (AddConnection2CbData) {
.connection = g_object_ref (connection),
.results = nm_g_variant_ref (results),
};
g_simple_async_result_set_op_res_gpointer (simple,
data,
add_connection2_cb_data_destroy);
}
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
/**
@ -1698,9 +1730,17 @@ nm_client_add_connection_async (NMClient *client,
nm_client_add_connection_async);
if (cancellable)
g_simple_async_result_set_check_cancellable (simple, cancellable);
nm_remote_settings_add_connection_async (NM_CLIENT_GET_PRIVATE (client)->settings,
connection, save_to_disk,
cancellable, add_connection_cb, simple);
nm_remote_settings_add_connection2 (NM_CLIENT_GET_PRIVATE (client)->settings,
nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL),
save_to_disk
? NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK
: NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY,
NULL,
TRUE,
cancellable,
add_connection2_cb,
simple);
}
/**
@ -1722,13 +1762,111 @@ nm_client_add_connection_finish (NMClient *client,
GSimpleAsyncResult *simple;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), nm_client_add_connection_async), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error))
return NULL;
else
return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
}
/**
* nm_client_add_connection2:
* @client: the %NMClient
* @settings: the "a{sa{sv}}" #GVariant with the content of the setting.
* @flags: the %NMSettingsAddConnection2Flags argument.
* @args: (allow-none): the "a{sv}" #GVariant with extra argument or %NULL
* for no extra arguments.
* @ignore_out_result: this function wraps AddConnection2(), which has an
* additional result "a{sv}" output parameter. By setting this to %TRUE,
* you signal that you are not interested in that output parameter.
* This allows the function to fall back to AddConnection() and AddConnectionUnsaved(),
* which is interesting if you run against an older server version that does
* not yet provide AddConnection2(). By setting this to %FALSE, the function
* under the hood always calls AddConnection2().
* @cancellable: a #GCancellable, or %NULL
* @callback: (scope async): callback to be called when the add operation completes
* @user_data: (closure): caller-specific data passed to @callback
*
* Call AddConnection2() D-Bus API asynchronously.
*
* Since: 1.20
**/
void
nm_client_add_connection2 (NMClient *client,
GVariant *settings,
NMSettingsAddConnection2Flags flags,
GVariant *args,
gboolean ignore_out_result,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
GError *error = NULL;
g_return_if_fail (NM_IS_CLIENT (client));
g_return_if_fail (g_variant_is_of_type (settings, G_VARIANT_TYPE ("a{sa{sv}}")));
g_return_if_fail (!args || g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}")));
if (!_nm_client_check_nm_running (client, &error)) {
g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
return;
}
simple = g_simple_async_result_new (G_OBJECT (client),
callback,
user_data,
nm_client_add_connection2);
if (cancellable)
g_simple_async_result_set_check_cancellable (simple, cancellable);
nm_remote_settings_add_connection2 (NM_CLIENT_GET_PRIVATE (client)->settings,
settings,
flags,
args,
ignore_out_result,
cancellable,
add_connection2_cb,
simple);
}
/**
* nm_client_add_connection2_finish:
* @client: the #NMClient
* @result: the #GAsyncResult
* @out_result: (allow-none) (transfer full) (out): the output #GVariant
* from AddConnection2().
* If you care about the output result, then the "ignore_out_result"
* parameter of nm_client_add_connection2() must not be set to %TRUE.
* @error: (allow-none): the error argument.
*
* Returns: (transfer full): on success, a pointer to the added
* #NMRemoteConnection.
*
* Since: 1.20
*/
NMRemoteConnection *
nm_client_add_connection2_finish (NMClient *client,
GAsyncResult *result,
GVariant **out_result,
GError **error)
{
GSimpleAsyncResult *simple;
AddConnection2CbData *data;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), nm_client_add_connection2), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error)) {
NM_SET_OUT (out_result, NULL);
return NULL;
}
data = g_simple_async_result_get_op_res_gpointer (simple);
NM_SET_OUT (out_result, g_variant_ref (data->results));
return g_object_ref (data->connection);
}
/**

View file

@ -389,6 +389,22 @@ NMRemoteConnection *nm_client_add_connection_finish (NMClient *client,
GAsyncResult *result,
GError **error);
NM_AVAILABLE_IN_1_20
void nm_client_add_connection2 (NMClient *client,
GVariant *settings,
NMSettingsAddConnection2Flags flags,
GVariant *args,
gboolean ignore_out_result,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
NM_AVAILABLE_IN_1_20
NMRemoteConnection *nm_client_add_connection2_finish (NMClient *client,
GAsyncResult *result,
GVariant **out_result,
GError **error);
gboolean nm_client_load_connections (NMClient *client,
char **filenames,
char ***failures,

View file

@ -22,6 +22,7 @@
#include "nm-remote-settings.h"
#include "c-list/src/c-list.h"
#include "nm-dbus-interface.h"
#include "nm-connection.h"
#include "nm-client.h"
@ -43,7 +44,7 @@ typedef struct {
GPtrArray *visible_connections;
/* AddConnectionInfo objects that are waiting for the connection to become initialized */
GSList *add_list;
CList add_lst_head;
char *hostname;
gboolean can_modify;
@ -70,51 +71,78 @@ static guint signals[LAST_SIGNAL] = { 0 };
/*****************************************************************************/
typedef struct {
CList add_lst;
NMRemoteSettings *self;
GSimpleAsyncResult *simple;
NMRemoteSettingAddConnection2Callback callback;
gpointer user_data;
GCancellable *cancellable;
char *path;
gboolean saved;
GVariant *results;
gulong cancellable_id;
NMSettingsAddConnection2Flags flags;
bool ignore_out_result:1;
} AddConnectionInfo;
static AddConnectionInfo *
add_connection_info_find (NMRemoteSettings *self, const char *path)
_add_connection_info_find (NMRemoteSettings *self, const char *path)
{
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
GSList *iter;
AddConnectionInfo *info;
for (iter = priv->add_list; iter; iter = g_slist_next (iter)) {
AddConnectionInfo *info = iter->data;
if (!g_strcmp0 (info->path, path))
c_list_for_each_entry (info, &priv->add_lst_head, add_lst) {
if (nm_streq0 (info->path, path))
return info;
}
return NULL;
}
static void
add_connection_info_complete (NMRemoteSettings *self,
AddConnectionInfo *info,
NMRemoteConnection *connection,
GError *error)
_add_connection_info_complete (AddConnectionInfo *info,
NMRemoteConnection *connection,
GError *error_take)
{
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
nm_assert (info);
g_return_if_fail (info != NULL);
c_list_unlink_stale (&info->add_lst);
if (connection) {
g_simple_async_result_set_op_res_gpointer (info->simple,
g_object_ref (connection),
g_object_unref);
} else
g_simple_async_result_set_from_error (info->simple, error);
g_simple_async_result_complete (info->simple);
nm_clear_g_signal_handler (info->cancellable, &info->cancellable_id);
g_object_unref (info->simple);
priv->add_list = g_slist_remove (priv->add_list, info);
if ( info->cancellable
&& !nm_utils_error_is_cancelled (error_take, FALSE)) {
GError *error2 = NULL;
g_free (info->path);
g_slice_free (AddConnectionInfo, info);
if (g_cancellable_set_error_if_cancelled (info->cancellable, &error2)) {
g_clear_error (&error_take);
error_take = error2;
connection = NULL;
}
}
info->callback (info->self,
connection,
connection ? info->results : NULL,
error_take,
info->user_data);
g_clear_error (&error_take);
g_object_unref (info->self);
nm_g_object_unref (info->cancellable);
nm_clear_g_free (&info->path);
nm_g_variant_unref (info->results);
nm_g_slice_free (info);
}
static void
_add_connection_info_cancelled (GCancellable *cancellable,
AddConnectionInfo *info)
{
_add_connection_info_complete (info,
NULL,
g_error_new_literal (G_IO_ERROR,
G_IO_ERROR_CANCELLED,
"Operation was cancelled"));
}
typedef const char * (*ConnectionStringGetter) (NMConnection *);
@ -216,7 +244,7 @@ connection_added (NMRemoteSettings *self,
NMRemoteConnection *remote)
{
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
AddConnectionInfo *addinfo;
AddConnectionInfo *info;
const char *path;
if (!g_signal_handler_find (remote, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL,
@ -233,26 +261,27 @@ connection_added (NMRemoteSettings *self,
g_signal_stop_emission (self, signals[CONNECTION_ADDED], 0);
path = nm_connection_get_path (NM_CONNECTION (remote));
addinfo = add_connection_info_find (self, path);
if (addinfo)
add_connection_info_complete (self, addinfo, remote, NULL);
info = _add_connection_info_find (self, path);
if (info)
_add_connection_info_complete (info, remote, NULL);
}
static void
object_creation_failed (NMObject *object, const char *failed_path)
object_creation_failed (NMObject *object,
const char *failed_path)
{
NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
AddConnectionInfo *addinfo;
GError *add_error;
AddConnectionInfo *info;
addinfo = add_connection_info_find (self, failed_path);
if (addinfo) {
add_error = g_error_new_literal (NM_CLIENT_ERROR,
NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
_("Connection removed before it was initialized"));
add_connection_info_complete (self, addinfo, NULL, add_error);
g_error_free (add_error);
}
info = _add_connection_info_find (self, failed_path);
if (!info)
return;
_add_connection_info_complete (info,
NULL,
g_error_new_literal (NM_CLIENT_ERROR,
NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
_("Connection removed before it was initialized")));
}
const GPtrArray *
@ -269,83 +298,114 @@ add_connection_done (GObject *proxy, GAsyncResult *result, gpointer user_data)
AddConnectionInfo *info = user_data;
GError *error = NULL;
if (info->saved) {
if ( info->ignore_out_result
&& info->flags == NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK) {
nmdbus_settings_call_add_connection_finish (NMDBUS_SETTINGS (proxy),
&info->path,
result, &error);
} else {
result,
&error);
} else if ( info->ignore_out_result
&& info->flags == NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY) {
nmdbus_settings_call_add_connection_unsaved_finish (NMDBUS_SETTINGS (proxy),
&info->path,
result, &error);
result,
&error);
} else {
nmdbus_settings_call_add_connection2_finish (NMDBUS_SETTINGS (proxy),
&info->path,
&info->results,
result,
&error);
if (info->ignore_out_result) {
/* despite we have the result, the caller didn't ask for it.
* Through it away, so we consistently don't return a result. */
nm_clear_pointer (&info->results, g_variant_unref);
}
}
if (error) {
g_dbus_error_strip_remote_error (error);
add_connection_info_complete (info->self, info, NULL, error);
g_clear_error (&error);
_add_connection_info_complete (info, NULL, error);
return;
}
/* On success, we still have to wait until the connection is fully
* initialized before calling the callback.
*/
if (info->cancellable) {
gulong id;
id = g_cancellable_connect (info->cancellable,
G_CALLBACK (_add_connection_info_cancelled),
info,
NULL);
if (id == 0) {
/* the callback was invoked synchronously, which destroyed @info.
* We must not touch @info anymore. */
} else
info->cancellable_id = id;
}
}
void
nm_remote_settings_add_connection_async (NMRemoteSettings *settings,
NMConnection *connection,
gboolean save_to_disk,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
nm_remote_settings_add_connection2 (NMRemoteSettings *self,
GVariant *settings,
NMSettingsAddConnection2Flags flags,
GVariant *args,
gboolean ignore_out_result,
GCancellable *cancellable,
NMRemoteSettingAddConnection2Callback callback,
gpointer user_data)
{
NMRemoteSettingsPrivate *priv;
AddConnectionInfo *info;
GVariant *new_settings;
g_return_if_fail (NM_IS_REMOTE_SETTINGS (settings));
g_return_if_fail (NM_IS_CONNECTION (connection));
nm_assert (NM_IS_REMOTE_SETTINGS (self));
nm_assert (g_variant_is_of_type (settings, G_VARIANT_TYPE ("a{sa{sv}}")));
nm_assert (!args || g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}")));
nm_assert (callback);
priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
info = g_slice_new0 (AddConnectionInfo);
info->self = settings;
info->simple = g_simple_async_result_new (G_OBJECT (settings), callback, user_data,
nm_remote_settings_add_connection_async);
if (cancellable)
g_simple_async_result_set_check_cancellable (info->simple, cancellable);
info->saved = save_to_disk;
info = g_slice_new (AddConnectionInfo);
*info = (AddConnectionInfo) {
.self = g_object_ref (self),
.cancellable = nm_g_object_ref (cancellable),
.flags = flags,
.ignore_out_result = ignore_out_result,
.callback = callback,
.user_data = user_data,
};
c_list_link_tail (&priv->add_lst_head, &info->add_lst);
new_settings = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
if (save_to_disk) {
/* Although AddConnection2() being capable to handle also AddConnection() and
* AddConnectionUnsaved() variants, we prefer to use the old D-Bus methods when
* they are sufficient. The reason is that libnm should avoid hard dependencies
* on 1.20 API whenever possible. */
if ( ignore_out_result
&& flags == NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK) {
nmdbus_settings_call_add_connection (priv->proxy,
new_settings,
NULL,
add_connection_done, info);
} else {
settings,
cancellable,
add_connection_done,
info);
} else if ( ignore_out_result
&& flags == NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY) {
nmdbus_settings_call_add_connection_unsaved (priv->proxy,
new_settings,
NULL,
add_connection_done, info);
settings,
cancellable,
add_connection_done,
info);
} else {
nmdbus_settings_call_add_connection2 (priv->proxy,
settings,
flags,
args
?: g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0),
cancellable,
add_connection_done,
info);
}
priv->add_list = g_slist_append (priv->add_list, info);
}
NMRemoteConnection *
nm_remote_settings_add_connection_finish (NMRemoteSettings *settings,
GAsyncResult *result,
GError **error)
{
GSimpleAsyncResult *simple;
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (settings), nm_remote_settings_add_connection_async), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error))
return NULL;
else
return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
}
gboolean
@ -606,6 +666,7 @@ nm_remote_settings_init (NMRemoteSettings *self)
{
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
c_list_init (&priv->add_lst_head);
priv->all_connections = g_ptr_array_new ();
priv->visible_connections = g_ptr_array_new ();
}
@ -664,7 +725,7 @@ dispose (GObject *object)
{
NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
int i;
guint i;
if (priv->all_connections) {
for (i = 0; i < priv->all_connections->len; i++)

View file

@ -73,15 +73,20 @@ NMRemoteConnection *nm_remote_settings_get_connection_by_path (NMRemoteSettings
NMRemoteConnection *nm_remote_settings_get_connection_by_uuid (NMRemoteSettings *settings,
const char *uuid);
void nm_remote_settings_add_connection_async (NMRemoteSettings *settings,
NMConnection *connection,
gboolean save_to_disk,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
NMRemoteConnection *nm_remote_settings_add_connection_finish (NMRemoteSettings *settings,
GAsyncResult *result,
GError **error);
typedef void (*NMRemoteSettingAddConnection2Callback) (NMRemoteSettings *self,
NMRemoteConnection *connection,
GVariant *results,
GError *error,
gpointer user_data);
void nm_remote_settings_add_connection2 (NMRemoteSettings *self,
GVariant *settings,
NMSettingsAddConnection2Flags flags,
GVariant *args,
gboolean ignore_out_result,
GCancellable *cancellable,
NMRemoteSettingAddConnection2Callback callback,
gpointer user_data);
gboolean nm_remote_settings_load_connections (NMRemoteSettings *settings,
char **filenames,

View file

@ -1569,6 +1569,11 @@ nm_strcmp_p (gconstpointer a, gconstpointer b)
/*****************************************************************************/
#define nm_g_slice_free(ptr) \
g_slice_free (typeof (*(ptr)), ptr)
/*****************************************************************************/
/* like g_memdup(). The difference is that the @size argument is of type
* gsize, while g_memdup() has type guint. Since, the size of container types
* like GArray is guint as well, this means trying to g_memdup() an

View file

@ -238,6 +238,7 @@ pan_connection_check_create (NMBluezDevice *self)
nm_settings_add_connection (priv->settings,
connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED,
&added,
&error);

View file

@ -472,6 +472,7 @@ mirror_8021x_connection (NMIwdManager *self,
if (!nm_settings_add_connection (priv->settings,
connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED,
&settings_connection,
&error)) {

View file

@ -258,6 +258,7 @@ restore_and_activate_connection (NMCheckpoint *self,
if (!nm_settings_add_connection (NM_SETTINGS_GET,
dev_checkpoint->settings_connection,
persist_mode,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
sett_flags,
&connection,
&local_error)) {

View file

@ -2674,6 +2674,7 @@ get_existing_connection (NMManager *self,
if (!nm_settings_add_connection (priv->settings,
connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE
| NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED,
&added,
@ -5419,6 +5420,7 @@ _add_and_activate_auth_done (NMManager *self,
nm_settings_add_connection_dbus (priv->settings,
connection,
persist_mode,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
( is_volatile
? NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE
: NM_SETTINGS_CONNECTION_INT_FLAGS_NONE),

View file

@ -1438,7 +1438,7 @@ update_complete (NMSettingsConnection *self,
g_variant_builder_init (&result, G_VARIANT_TYPE ("a{sv}"));
g_dbus_method_invocation_return_value (info->context,
g_variant_new ("(@a{sv})", g_variant_builder_end (&result)));
g_variant_new ("(a{sv})", &result));
} else
g_dbus_method_invocation_return_value (info->context, NULL);
@ -1514,12 +1514,6 @@ update_auth_cb (NMSettingsConnection *self,
} else
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP;
if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)) {
nm_settings_connection_autoconnect_blocked_reason_set (self,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
TRUE);
}
nm_settings_connection_update (self,
info->new_settings,
persist_mode,
@ -1529,9 +1523,14 @@ update_auth_cb (NMSettingsConnection *self,
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED
| NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE,
NM_SETTINGS_CONNECTION_UPDATE_REASON_FORCE_RENAME
| NM_SETTINGS_CONNECTION_UPDATE_REASON_REAPPLY_PARTIAL
| ( NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY)
? NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE
: NM_SETTINGS_CONNECTION_UPDATE_REASON_REAPPLY_PARTIAL)
| NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS
| NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS,
| NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS
| ( NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)
? NM_SETTINGS_CONNECTION_UPDATE_REASON_BLOCK_AUTOCONNECT
: NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE),
"update-from-dbus",
&local);
@ -1733,9 +1732,10 @@ impl_settings_connection_update2 (NMDBusObject *obj,
g_variant_get (parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args);
if (NM_FLAGS_ANY (flags_u, ~((guint32) (ALL_PERSIST_MODES |
NM_SETTINGS_UPDATE2_FLAG_VOLATILE |
NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)))) {
if (NM_FLAGS_ANY (flags_u, ~((guint32) ( ALL_PERSIST_MODES
| NM_SETTINGS_UPDATE2_FLAG_VOLATILE
| NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT
| NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY)))) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"Unknown flags");
@ -1757,13 +1757,7 @@ impl_settings_connection_update2 (NMDBusObject *obj,
return;
}
if (!g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}"))) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"args is of invalid type");
g_dbus_method_invocation_take_error (invocation, error);
return;
}
nm_assert (g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}")));
g_variant_iter_init (&iter, args);
while (g_variant_iter_next (&iter, "{&sv}", &args_name, NULL)) {

View file

@ -28,6 +28,14 @@
/*****************************************************************************/
typedef enum {
NM_SETTINGS_CONNECTION_ADD_REASON_NONE = 0,
NM_SETTINGS_CONNECTION_ADD_REASON_BLOCK_AUTOCONNECT = (1u << 0),
} NMSettingsConnectionAddReason;
typedef enum {
NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE = 0,
@ -50,7 +58,10 @@ typedef enum {
/* Usually, changing a profile that is currently active does not immediately
* reapply the changes. The exception are connection.zone and connection.metered
* properties. When this flag is set, then these two properties are reapplied
* right away. */
* right away.
*
* See also %NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY flag, to prevent partial reapply
* during Update2(). */
NM_SETTINGS_CONNECTION_UPDATE_REASON_REAPPLY_PARTIAL = (1u << 2),
NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_SYSTEM_SECRETS = (1u << 3),
@ -64,6 +75,8 @@ typedef enum {
* to disk and it the purpose why the profile was created should be forgotten. */
NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_DEFAULT_WIRED = (1u << 7),
NM_SETTINGS_CONNECTION_UPDATE_REASON_BLOCK_AUTOCONNECT = (1u << 8),
} NMSettingsConnectionUpdateReason;
typedef enum {

View file

@ -923,7 +923,12 @@ _connection_changed_update (NMSettings *self,
priv->connections_generation++;
g_signal_connect (sett_conn, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, G_CALLBACK (connection_flags_changed), self);
}
if (NM_FLAGS_HAS (update_reason, NM_SETTINGS_CONNECTION_UPDATE_REASON_BLOCK_AUTOCONNECT)) {
nm_settings_connection_autoconnect_blocked_reason_set (sett_conn,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
TRUE);
}
sett_mask |= NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE;
@ -1371,6 +1376,7 @@ _add_connection_to_first_plugin (NMSettings *self,
* @self: the #NMSettings object
* @connection: the source connection to create a new #NMSettingsConnection from
* @persist_mode: the persist-mode for this profile.
* @add_reason: the add-reason flags.
* @sett_flags: the settings flags to set.
* @out_sett_conn: (allow-none) (transfer none): the added settings connection on success.
* @error: on return, a location to store any errors that may occur
@ -1385,6 +1391,7 @@ gboolean
nm_settings_add_connection (NMSettings *self,
NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionAddReason add_reason,
NMSettingsConnectionIntFlags sett_flags,
NMSettingsConnection **out_sett_conn,
GError **error)
@ -1408,6 +1415,8 @@ nm_settings_add_connection (NMSettings *self,
nm_assert ( !NM_FLAGS_HAS (sett_flags, NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE)
|| persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY);
nm_assert (!NM_FLAGS_ANY (add_reason, ~NM_SETTINGS_CONNECTION_ADD_REASON_BLOCK_AUTOCONNECT));
NM_SET_OUT (out_sett_conn, NULL);
uuid = nm_connection_get_uuid (connection);
@ -1486,7 +1495,10 @@ nm_settings_add_connection (NMSettings *self,
_NM_SETTINGS_CONNECTION_INT_FLAGS_PERSISTENT_MASK,
FALSE,
NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS
| NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS);
| NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS
| ( NM_FLAGS_HAS (add_reason, NM_SETTINGS_CONNECTION_ADD_REASON_BLOCK_AUTOCONNECT)
? NM_SETTINGS_CONNECTION_UPDATE_REASON_BLOCK_AUTOCONNECT
: NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE));
nm_assert (sett_conn_entry == _sett_conn_entries_get (self, sett_conn_entry->uuid));
nm_assert (NM_IS_SETTINGS_CONNECTION (sett_conn_entry->sett_conn));
@ -1972,6 +1984,7 @@ pk_add_cb (NMAuthChain *chain,
nm_settings_add_connection (self,
connection,
GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "persist-mode")),
GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "add-reason")),
GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "sett-flags")),
&added,
&error);
@ -1999,6 +2012,7 @@ void
nm_settings_add_connection_dbus (NMSettings *self,
NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionAddReason add_reason,
NMSettingsConnectionIntFlags sett_flags,
NMAuthSubject *subject,
GDBusMethodInvocation *context,
@ -2073,6 +2087,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);
nm_auth_chain_set_data (chain, "subject", g_object_ref (subject), g_object_unref);
nm_auth_chain_set_data (chain, "persist-mode", GUINT_TO_POINTER (persist_mode), NULL);
nm_auth_chain_set_data (chain, "add-reason", GUINT_TO_POINTER (add_reason), NULL);
nm_auth_chain_set_data (chain, "sett-flags", GUINT_TO_POINTER (sett_flags), NULL);
nm_auth_chain_add_call_unsafe (chain, perm, TRUE);
return;
@ -2091,27 +2106,42 @@ settings_add_connection_add_cb (NMSettings *self,
NMAuthSubject *subject,
gpointer user_data)
{
gboolean is_add_connection_2 = GPOINTER_TO_INT (user_data);
if (error) {
g_dbus_method_invocation_return_gerror (context, error);
nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, NULL, subject, error->message);
return;
}
if (is_add_connection_2) {
GVariantBuilder builder;
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
g_dbus_method_invocation_return_value (context,
g_variant_new ("(oa{sv})",
nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)),
&builder));
} else {
g_dbus_method_invocation_return_value (context,
g_variant_new ("(o)",
nm_dbus_object_get_path (NM_DBUS_OBJECT (connection))));
nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE, NULL,
subject, NULL);
}
nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE, NULL,
subject, NULL);
}
static void
settings_add_connection_helper (NMSettings *self,
GDBusMethodInvocation *context,
gboolean is_add_connection_2,
GVariant *settings,
NMSettingsConnectionPersistMode persist_mode)
NMSettingsAddConnection2Flags flags)
{
gs_unref_object NMConnection *connection = NULL;
GError *error = NULL;
gs_unref_object NMAuthSubject *subject = NULL;
NMSettingsConnectionPersistMode persist_mode;
connection = _nm_simple_connection_new_from_dbus (settings,
NM_SETTING_PARSE_FLAGS_STRICT
@ -2133,14 +2163,24 @@ settings_add_connection_helper (NMSettings *self,
return;
}
if (NM_FLAGS_HAS (flags, NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK))
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK;
else {
nm_assert (NM_FLAGS_HAS (flags, NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY));
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY;
}
nm_settings_add_connection_dbus (self,
connection,
persist_mode,
NM_FLAGS_HAS (flags, NM_SETTINGS_ADD_CONNECTION2_FLAG_BLOCK_AUTOCONNECT)
? NM_SETTINGS_CONNECTION_ADD_REASON_BLOCK_AUTOCONNECT
: NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
NM_SETTINGS_CONNECTION_INT_FLAGS_NONE,
subject,
context,
settings_add_connection_add_cb,
NULL);
GINT_TO_POINTER (!!is_add_connection_2));
}
static void
@ -2156,7 +2196,7 @@ impl_settings_add_connection (NMDBusObject *obj,
gs_unref_variant GVariant *settings = NULL;
g_variant_get (parameters, "(@a{sa{sv}})", &settings);
settings_add_connection_helper (self, invocation, settings, NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK);
settings_add_connection_helper (self, invocation, FALSE, settings, NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK);
}
static void
@ -2172,7 +2212,70 @@ impl_settings_add_connection_unsaved (NMDBusObject *obj,
gs_unref_variant GVariant *settings = NULL;
g_variant_get (parameters, "(@a{sa{sv}})", &settings);
settings_add_connection_helper (self, invocation, settings, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY);
settings_add_connection_helper (self, invocation, FALSE, settings, NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY);
}
static void
impl_settings_add_connection2 (NMDBusObject *obj,
const NMDBusInterfaceInfoExtended *interface_info,
const NMDBusMethodInfoExtended *method_info,
GDBusConnection *connection,
const char *sender,
GDBusMethodInvocation *invocation,
GVariant *parameters)
{
NMSettings *self = NM_SETTINGS (obj);
gs_unref_variant GVariant *settings = NULL;
gs_unref_variant GVariant *args = NULL;
NMSettingsAddConnection2Flags flags;
const char *args_name;
GVariantIter iter;
guint32 flags_u;
g_variant_get (parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args);
if (NM_FLAGS_ANY (flags_u, ~((guint32) ( NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK
| NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY
| NM_SETTINGS_ADD_CONNECTION2_FLAG_BLOCK_AUTOCONNECT)))) {
g_dbus_method_invocation_take_error (invocation,
g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"Unknown flags"));
return;
}
flags = flags_u;
if (!NM_FLAGS_ANY (flags, NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK
| NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY)) {
g_dbus_method_invocation_take_error (invocation,
g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"Requires either to-disk (0x1) or in-memory (0x2) flags"));
return;
}
if (NM_FLAGS_ALL (flags, NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK
| NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY)) {
g_dbus_method_invocation_take_error (invocation,
g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"Cannot set to-disk (0x1) and in-memory (0x2) flags together"));
return;
}
nm_assert (g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}")));
g_variant_iter_init (&iter, args);
while (g_variant_iter_next (&iter, "{&sv}", &args_name, NULL)) {
g_dbus_method_invocation_take_error (invocation,
g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"Unsupported argument '%s'", args_name));
return;
}
settings_add_connection_helper (self, invocation, TRUE, settings, flags);
}
/*****************************************************************************/
@ -2941,6 +3044,7 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
nm_settings_add_connection (self,
connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED,
&added,
&error);
@ -3438,6 +3542,21 @@ static const NMDBusInterfaceInfoExtended interface_info_settings = {
),
.handle = impl_settings_add_connection_unsaved,
),
NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
NM_DEFINE_GDBUS_METHOD_INFO_INIT (
"AddConnection2",
.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("settings", "a{sa{sv}}"),
NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"),
NM_DEFINE_GDBUS_ARG_INFO ("args", "a{sv}"),
),
.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("path", "o"),
NM_DEFINE_GDBUS_ARG_INFO ("result", "a{sv}"),
),
),
.handle = impl_settings_add_connection2,
),
NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
NM_DEFINE_GDBUS_METHOD_INFO_INIT (
"LoadConnections",

View file

@ -82,6 +82,7 @@ typedef void (*NMSettingsAddCallback) (NMSettings *settings,
void nm_settings_add_connection_dbus (NMSettings *self,
NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionAddReason add_reason,
NMSettingsConnectionIntFlags sett_flags,
NMAuthSubject *subject,
GDBusMethodInvocation *context,
@ -100,6 +101,7 @@ NMSettingsConnection **nm_settings_get_connections_clone (NMSettings *self,
gboolean nm_settings_add_connection (NMSettings *settings,
NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionAddReason add_reason,
NMSettingsConnectionIntFlags sett_flags,
NMSettingsConnection **out_sett_conn,
GError **error);