diff --git a/.gitignore b/.gitignore index 201955cec8..cd8aa6a879 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ *.lo *.la *.bz2 +*.gir +*.typelib Makefile Makefile.in* configure @@ -59,6 +61,12 @@ docs/generate-settings-spec docs/settings-spec.html docs/spec.html +examples/C/add-connection-glib +examples/C/get-active-connections +examples/C/get-ap-info-libnm-glib +examples/C/list-connections-dbus +examples/C/list-connections-libnm-glib + callouts/nm-dhcp-client.action callouts/nm-avahi-autoipd.action callouts/nm-dispatcher.action @@ -91,8 +99,10 @@ libnm-util/tests/test-settings-defaults libnm-util/tests/test-general libnm-util/tests/test-need-secrets libnm-util/tests/test-setting-8021x +libnm-glib/tests/test-remote-settings-client src/tests/test-dhcp-options src/tests/test-policy-hosts +src/tests/test-wifi-ap-utils src/dhcp-manager/tests/test-dhcp-dhclient system-settings/plugins/keyfile/tests/test-keyfile @@ -101,6 +111,7 @@ system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh-utils system-settings/plugins/ifcfg-rh/tests/network-scripts/Test_Write_* system-settings/plugins/ifcfg-rh/tests/network-scripts/*-Test_Write_* system-settings/plugins/ifupdown/tests/test-ifupdown +system-settings/plugins/ifnet/tests/check_ifnet m4/gtk-doc.m4 m4/intltool.m4 diff --git a/Makefile.am b/Makefile.am index 64be5c8526..78924ab7da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,12 +1,12 @@ SUBDIRS = \ marshallers \ + include \ libnm-util \ libnm-glib \ - src \ - include \ introspection \ - callouts \ system-settings \ + src \ + callouts \ cli \ tools \ policy \ @@ -29,7 +29,8 @@ DISTCHECK_CONFIGURE_FLAGS = \ --with-tests=yes \ --with-docs=yes \ --with-udev-dir=$$dc_install_base/lib/udev \ - --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) + --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) \ + --enable-wimax=no DISTCLEANFILES = intltool-extract intltool-merge intltool-update diff --git a/callouts/nm-dispatcher-action.h b/callouts/nm-dispatcher-action.h index 39aefd8f83..e4f2fab2f4 100644 --- a/callouts/nm-dispatcher-action.h +++ b/callouts/nm-dispatcher-action.h @@ -22,7 +22,6 @@ #define NM_DISPATCHER_DBUS_IFACE "org.freedesktop.nm_dispatcher" #define NM_DISPATCHER_DBUS_PATH "/org/freedesktop/nm_dispatcher" -#define NMD_CONNECTION_PROPS_SERVICE_NAME "service-name" #define NMD_CONNECTION_PROPS_PATH "path" #define NMD_DEVICE_PROPS_INTERFACE "interface" diff --git a/cli/src/connections.c b/cli/src/connections.c index 8e88a4527e..f96f774f6c 100644 --- a/cli/src/connections.c +++ b/cli/src/connections.c @@ -47,9 +47,6 @@ #include //#include #include -#include -#include -#include #include #include "utils.h" @@ -62,32 +59,29 @@ static NmcOutputField nmc_fields_con_status[] = { {"NAME", N_("NAME"), 25, NULL, 0}, /* 0 */ {"UUID", N_("UUID"), 38, NULL, 0}, /* 1 */ {"DEVICES", N_("DEVICES"), 10, NULL, 0}, /* 2 */ - {"SCOPE", N_("SCOPE"), 8, NULL, 0}, /* 3 */ - {"DEFAULT", N_("DEFAULT"), 8, NULL, 0}, /* 4 */ - {"DBUS-SERVICE", N_("DBUS-SERVICE"), 45, NULL, 0}, /* 5 */ - {"SPEC-OBJECT", N_("SPEC-OBJECT"), 10, NULL, 0}, /* 6 */ - {"VPN", N_("VPN"), 5, NULL, 0}, /* 7 */ - {"DBUS-PATH", N_("DBUS-PATH"), 51, NULL, 0}, /* 8 */ + {"DEFAULT", N_("DEFAULT"), 8, NULL, 0}, /* 3 */ + {"SPEC-OBJECT", N_("SPEC-OBJECT"), 10, NULL, 0}, /* 4 */ + {"VPN", N_("VPN"), 5, NULL, 0}, /* 5 */ + {"DBUS-PATH", N_("DBUS-PATH"), 51, NULL, 0}, /* 6 */ {NULL, NULL, 0, NULL, 0} }; -#define NMC_FIELDS_CON_STATUS_ALL "NAME,UUID,DEVICES,SCOPE,DEFAULT,VPN,DBUS-SERVICE,DBUS-PATH,SPEC-OBJECT" -#define NMC_FIELDS_CON_STATUS_COMMON "NAME,UUID,DEVICES,SCOPE,DEFAULT,VPN" +#define NMC_FIELDS_CON_STATUS_ALL "NAME,UUID,DEVICES,DEFAULT,VPN,DBUS-PATH,SPEC-OBJECT" +#define NMC_FIELDS_CON_STATUS_COMMON "NAME,UUID,DEVICES,DEFAULT,VPN" /* Available fields for 'con list' */ static NmcOutputField nmc_fields_con_list[] = { {"NAME", N_("NAME"), 25, NULL, 0}, /* 0 */ {"UUID", N_("UUID"), 38, NULL, 0}, /* 1 */ {"TYPE", N_("TYPE"), 17, NULL, 0}, /* 2 */ - {"SCOPE", N_("SCOPE"), 8, NULL, 0}, /* 3 */ - {"TIMESTAMP", N_("TIMESTAMP"), 12, NULL, 0}, /* 4 */ - {"TIMESTAMP-REAL", N_("TIMESTAMP-REAL"), 34, NULL, 0}, /* 5 */ - {"AUTOCONNECT", N_("AUTOCONNECT"), 13, NULL, 0}, /* 6 */ - {"READONLY", N_("READONLY"), 10, NULL, 0}, /* 7 */ - {"DBUS-PATH", N_("DBUS-PATH"), 42, NULL, 0}, /* 8 */ + {"TIMESTAMP", N_("TIMESTAMP"), 12, NULL, 0}, /* 3 */ + {"TIMESTAMP-REAL", N_("TIMESTAMP-REAL"), 34, NULL, 0}, /* 4 */ + {"AUTOCONNECT", N_("AUTOCONNECT"), 13, NULL, 0}, /* 5 */ + {"READONLY", N_("READONLY"), 10, NULL, 0}, /* 6 */ + {"DBUS-PATH", N_("DBUS-PATH"), 42, NULL, 0}, /* 7 */ {NULL, NULL, 0, NULL, 0} }; -#define NMC_FIELDS_CON_LIST_ALL "NAME,UUID,TYPE,SCOPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH" -#define NMC_FIELDS_CON_LIST_COMMON "NAME,UUID,TYPE,SCOPE,TIMESTAMP-REAL" +#define NMC_FIELDS_CON_LIST_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH" +#define NMC_FIELDS_CON_LIST_COMMON "NAME,UUID,TYPE,TIMESTAMP-REAL" /* Helper macro to define fields */ @@ -150,8 +144,8 @@ static gboolean find_device_for_connection (NmCli *nmc, NMConnection *connection const char *nsp, NMDevice **device, const char **spec_object, GError **error); static const char *active_connection_state_to_string (NMActiveConnectionState state); static void active_connection_state_cb (NMActiveConnection *active, GParamSpec *pspec, gpointer user_data); -static void activate_connection_cb (gpointer user_data, const char *path, GError *error); -static void get_connections_cb (NMSettingsInterface *settings, gpointer user_data); +static void activate_connection_cb (NMClient *client, const char *path, GError *error, gpointer user_data); +static void get_connections_cb (NMRemoteSettings *settings, gpointer user_data); static NMCResultCode do_connections_list (NmCli *nmc, int argc, char **argv); static NMCResultCode do_connections_status (NmCli *nmc, int argc, char **argv); static NMCResultCode do_connection_up (NmCli *nmc, int argc, char **argv); @@ -163,7 +157,7 @@ usage (void) fprintf (stderr, _("Usage: nmcli con { COMMAND | help }\n" " COMMAND := { list | status | up | down }\n\n" - " list [id | uuid | system | user]\n" + " list [id | uuid ]\n" " status\n" " up id | uuid [iface ] [ap ] [nsp ] [--nowait] [--timeout ]\n" " down id | uuid \n")); @@ -395,12 +389,11 @@ show_connection (NMConnection *data, gpointer user_data) nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con); nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con); nmc->allowed_fields[2].value = nm_setting_connection_get_connection_type (s_con); - nmc->allowed_fields[3].value = nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM ? _("system") : _("user"); - nmc->allowed_fields[4].value = timestamp_str; - nmc->allowed_fields[5].value = timestamp ? timestamp_real_str : _("never"); - nmc->allowed_fields[6].value = nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no"); - nmc->allowed_fields[7].value = nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"); - nmc->allowed_fields[8].value = nm_connection_get_path (connection); + nmc->allowed_fields[3].value = timestamp_str; + nmc->allowed_fields[4].value = timestamp ? timestamp_real_str : _("never"); + nmc->allowed_fields[5].value = nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no"); + nmc->allowed_fields[6].value = nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"); + nmc->allowed_fields[7].value = nm_connection_get_path (connection); nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */ print_fields (nmc->print_fields, nmc->allowed_fields); @@ -471,22 +464,15 @@ do_connections_list (NmCli *nmc, int argc, char **argv) goto error; valid_param_specified = TRUE; - nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; - nmc->print_fields.header_name = _("System connections"); + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES; print_fields (nmc->print_fields, nmc->allowed_fields); g_slist_foreach (nmc->system_connections, (GFunc) show_connection, nmc); - - nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; - nmc->print_fields.header_name = _("User connections"); - print_fields (nmc->print_fields, nmc->allowed_fields); - g_slist_foreach (nmc->user_connections, (GFunc) show_connection, nmc); } else { while (argc > 0) { if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) { const char *selector = *argv; - NMConnection *con1; - NMConnection *con2; + NMConnection *con; if (next_arg (&argc, &argv) != 0) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv); @@ -497,42 +483,16 @@ do_connections_list (NmCli *nmc, int argc, char **argv) if (!nmc->mode_specified) nmc->multiline_output = TRUE; /* multiline mode is default for 'con list id|uuid' */ - con1 = find_connection (nmc->system_connections, selector, *argv); - con2 = find_connection (nmc->user_connections, selector, *argv); - if (con1) nmc_connection_detail (con1, nmc); - if (con2) nmc_connection_detail (con2, nmc); - if (!con1 && !con2) { + con = find_connection (nmc->system_connections, selector, *argv); + if (con) { + nmc_connection_detail (con, nmc); + } + else { g_string_printf (nmc->return_text, _("Error: %s - no such connection."), *argv); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } break; } - else if (strcmp (*argv, "system") == 0) { - if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error2)) - goto error; - if (error1) - goto error; - valid_param_specified = TRUE; - - nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; - nmc->print_fields.header_name = _("System connections"); - print_fields (nmc->print_fields, nmc->allowed_fields); - g_slist_foreach (nmc->system_connections, (GFunc) show_connection, nmc); - break; - } - else if (strcmp (*argv, "user") == 0) { - if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error2)) - goto error; - if (error1) - goto error; - valid_param_specified = TRUE; - - nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; - nmc->print_fields.header_name = _("User connections"); - print_fields (nmc->print_fields, nmc->allowed_fields); - g_slist_foreach (nmc->user_connections, (GFunc) show_connection, nmc); - break; - } else { fprintf (stderr, _("Unknown parameter: %s\n"), *argv); } @@ -566,29 +526,19 @@ error: return nmc->return_value; } -typedef struct { - NmCli *nmc; - NMConnectionScope scope; -} StatusInfo; - static void show_active_connection (gpointer data, gpointer user_data) { NMActiveConnection *active = NM_ACTIVE_CONNECTION (data); - StatusInfo *info = (StatusInfo *) user_data; + NmCli *nmc = (NmCli *) user_data; GSList *con_list, *iter; const char *active_path; - NMConnectionScope active_service_scope; NMSettingConnection *s_con; const GPtrArray *devices; GString *dev_str; int i; active_path = nm_active_connection_get_connection (active); - active_service_scope = nm_active_connection_get_scope (active); - - if (active_service_scope != info->scope) - return; /* Get devices of the active connection */ dev_str = g_string_new (NULL); @@ -602,7 +552,7 @@ show_active_connection (gpointer data, gpointer user_data) if (dev_str->len > 0) g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */ - con_list = (info->scope == NM_CONNECTION_SCOPE_SYSTEM) ? info->nmc->system_connections : info->nmc->user_connections; + con_list = nmc->system_connections; for (iter = con_list; iter; iter = g_slist_next (iter)) { NMConnection *connection = (NMConnection *) iter->data; const char *con_path = nm_connection_get_path (connection); @@ -613,18 +563,16 @@ show_active_connection (gpointer data, gpointer user_data) g_assert (s_con != NULL); /* Obtain field values */ - info->nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con); - info->nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con); - info->nmc->allowed_fields[2].value = dev_str->str; - info->nmc->allowed_fields[3].value = active_service_scope == NM_CONNECTION_SCOPE_SYSTEM ? _("system") : _("user"); - info->nmc->allowed_fields[4].value = nm_active_connection_get_default (active) ? _("yes") : _("no"); - info->nmc->allowed_fields[5].value = nm_active_connection_get_service_name (active); - info->nmc->allowed_fields[6].value = nm_active_connection_get_specific_object (active); - info->nmc->allowed_fields[7].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no"); - info->nmc->allowed_fields[8].value = nm_object_get_path (NM_OBJECT (active)); + nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con); + nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con); + nmc->allowed_fields[2].value = dev_str->str; + nmc->allowed_fields[3].value = nm_active_connection_get_default (active) ? _("yes") : _("no"); + nmc->allowed_fields[4].value = nm_active_connection_get_specific_object (active); + nmc->allowed_fields[5].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no"); + nmc->allowed_fields[6].value = nm_object_get_path (NM_OBJECT (active)); - info->nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */ - print_fields (info->nmc->print_fields, info->nmc->allowed_fields); + nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */ + print_fields (nmc->print_fields, nmc->allowed_fields); break; } } @@ -637,7 +585,6 @@ do_connections_status (NmCli *nmc, int argc, char **argv) { const GPtrArray *active_cons; GError *error = NULL; - StatusInfo *info; char *fields_str; char *fields_all = NMC_FIELDS_CON_STATUS_ALL; char *fields_common = NMC_FIELDS_CON_STATUS_COMMON; @@ -686,15 +633,8 @@ do_connections_status (NmCli *nmc, int argc, char **argv) nmc->get_client (nmc); active_cons = nm_client_get_active_connections (nmc->client); - if (active_cons && active_cons->len) { - info = g_malloc0 (sizeof (StatusInfo)); - info->nmc = nmc; - info->scope = NM_CONNECTION_SCOPE_SYSTEM; - g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) info); - info->scope = NM_CONNECTION_SCOPE_USER; - g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) info); - g_free (info); - } + if (active_cons && active_cons->len) + g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc); error: return nmc->return_value; @@ -1393,11 +1333,11 @@ foo_active_connections_changed_cb (NMClient *client, /* Call again activate_connection_cb with dummy arguments; * the correct ones are taken from its first call. */ - activate_connection_cb (NULL, NULL, NULL); + activate_connection_cb (NULL, NULL, NULL, NULL); } static void -activate_connection_cb (gpointer user_data, const char *path, GError *error) +activate_connection_cb (NMClient *client, const char *path, GError *error, gpointer user_data) { NmCli *nmc = (NmCli *) user_data; NMActiveConnection *active; @@ -1471,7 +1411,6 @@ do_connection_up (NmCli *nmc, int argc, char **argv) gboolean device_found; NMConnection *connection = NULL; NMSettingConnection *s_con; - gboolean is_system; const char *con_path; const char *con_type; const char *iface = NULL; @@ -1497,8 +1436,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv) goto error; } - if ((connection = find_connection (nmc->system_connections, selector, *argv)) == NULL) - connection = find_connection (nmc->user_connections, selector, *argv); + connection = find_connection (nmc->system_connections, selector, *argv); if (!connection) { g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), *argv); @@ -1578,7 +1516,6 @@ do_connection_up (NmCli *nmc, int argc, char **argv) /* create NMClient */ nmc->get_client (nmc); - is_system = (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM) ? TRUE : FALSE; con_path = nm_connection_get_path (connection); s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); @@ -1602,7 +1539,6 @@ do_connection_up (NmCli *nmc, int argc, char **argv) nmc->nowait_flag = !wait; nmc->should_wait = TRUE; nm_client_activate_connection (nmc->client, - is_system ? NM_DBUS_SERVICE_SYSTEM_SETTINGS : NM_DBUS_SERVICE_USER_SETTINGS, con_path, device, spec_object, @@ -1624,7 +1560,6 @@ do_connection_down (NmCli *nmc, int argc, char **argv) const GPtrArray *active_cons; const char *con_path; const char *active_path; - NMConnectionScope active_service_scope, con_scope; gboolean id_specified = FALSE; gboolean wait = TRUE; int i; @@ -1640,8 +1575,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv) goto error; } - if ((connection = find_connection (nmc->system_connections, selector, *argv)) == NULL) - connection = find_connection (nmc->user_connections, selector, *argv); + connection = find_connection (nmc->system_connections, selector, *argv); if (!connection) { g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), *argv); @@ -1682,20 +1616,21 @@ do_connection_down (NmCli *nmc, int argc, char **argv) nmc->get_client (nmc); con_path = nm_connection_get_path (connection); - con_scope = nm_connection_get_scope (connection); active_cons = nm_client_get_active_connections (nmc->client); for (i = 0; active_cons && (i < active_cons->len); i++) { NMActiveConnection *candidate = g_ptr_array_index (active_cons, i); active_path = nm_active_connection_get_connection (candidate); - active_service_scope = nm_active_connection_get_scope (candidate); - if (!strcmp (active_path, con_path) && active_service_scope == con_scope) { + if (!strcmp (active_path, con_path)) { active = candidate; break; } } + /* TODO: fail gracefully if we are using an old N-M with user settings + * support */ + if (active) nm_client_deactivate_connection (nmc->client, active); else { @@ -1710,26 +1645,12 @@ error: /* callback called when connections are obtained from the settings service */ static void -get_connections_cb (NMSettingsInterface *settings, gpointer user_data) +get_connections_cb (NMRemoteSettings *settings, gpointer user_data) { ArgsInfo *args = (ArgsInfo *) user_data; - static gboolean system_cb_called = FALSE; - static gboolean user_cb_called = FALSE; GError *error = NULL; - if (NM_IS_REMOTE_SETTINGS_SYSTEM (settings)) { - system_cb_called = TRUE; - args->nmc->system_connections = nm_settings_interface_list_connections (settings); - } - else { - user_cb_called = TRUE; - args->nmc->user_connections = nm_settings_interface_list_connections (settings); - } - - /* return and wait for the callback of the second settings is called */ - if ( (args->nmc->system_settings_running && !system_cb_called) - || (args->nmc->user_settings_running && !user_cb_called)) - return; + args->nmc->system_connections = nm_remote_settings_list_connections (settings); if (args->argc == 0) { if (!nmc_terse_option_check (args->nmc->print_output, args->nmc->required_fields, &error)) @@ -1798,38 +1719,26 @@ do_connections (NmCli *nmc, int argc, char **argv) } /* get system settings */ - if (!(nmc->system_settings = nm_remote_settings_system_new (bus))) { + if (!(nmc->system_settings = nm_remote_settings_new (bus))) { g_string_printf (nmc->return_text, _("Error: Could not get system settings.")); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; return nmc->return_value; } - /* get user settings */ - if (!(nmc->user_settings = nm_remote_settings_new (bus, NM_CONNECTION_SCOPE_USER))) { - g_string_printf (nmc->return_text, _("Error: Could not get user settings.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return nmc->return_value; - } - - /* find out whether setting services are running */ + /* find out whether settings service is running */ g_object_get (nmc->system_settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &nmc->system_settings_running, NULL); - g_object_get (nmc->user_settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &nmc->user_settings_running, NULL); - if (!nmc->system_settings_running && !nmc->user_settings_running) { - g_string_printf (nmc->return_text, _("Error: Can't obtain connections: settings services are not running.")); + if (!nmc->system_settings_running) { + g_string_printf (nmc->return_text, _("Error: Can't obtain connections: settings service is not running.")); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; return nmc->return_value; } /* connect to signal "connections-read" - emitted when connections are fetched and ready */ - if (nmc->system_settings_running) - g_signal_connect (nmc->system_settings, NM_SETTINGS_INTERFACE_CONNECTIONS_READ, - G_CALLBACK (get_connections_cb), &args_info); + g_signal_connect (nmc->system_settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ, + G_CALLBACK (get_connections_cb), &args_info); - if (nmc->user_settings_running) - g_signal_connect (nmc->user_settings, NM_SETTINGS_INTERFACE_CONNECTIONS_READ, - G_CALLBACK (get_connections_cb), &args_info); dbus_g_connection_unref (bus); diff --git a/cli/src/nmcli.c b/cli/src/nmcli.c index 4a54802441..832893a1f8 100644 --- a/cli/src/nmcli.c +++ b/cli/src/nmcli.c @@ -33,9 +33,6 @@ #include #include #include -#include -#include -#include #include "nmcli.h" #include "utils.h" @@ -275,13 +272,8 @@ nmc_init (NmCli *nmc) nmc->timeout = 10; nmc->system_settings = NULL; - nmc->user_settings = NULL; - nmc->system_settings_running = FALSE; - nmc->user_settings_running = FALSE; - nmc->system_connections = NULL; - nmc->user_connections = NULL; nmc->should_wait = FALSE; nmc->nowait_flag = TRUE; @@ -302,10 +294,7 @@ nmc_cleanup (NmCli *nmc) g_string_free (nmc->return_text, TRUE); if (nmc->system_settings) g_object_unref (nmc->system_settings); - if (nmc->user_settings) g_object_unref (nmc->user_settings); - g_slist_free (nmc->system_connections); - g_slist_free (nmc->user_connections); g_free (nmc->required_fields); if (nmc->print_fields.indices) diff --git a/cli/src/nmcli.h b/cli/src/nmcli.h index a208e79e71..115b276e6d 100644 --- a/cli/src/nmcli.h +++ b/cli/src/nmcli.h @@ -24,7 +24,6 @@ #include #include -#include /* nmcli exit codes */ typedef enum { @@ -95,14 +94,9 @@ typedef struct _NmCli { int timeout; /* Operation timeout */ - NMRemoteSettingsSystem *system_settings; /* System settings */ - NMRemoteSettings *user_settings; /* User settings */ - + NMRemoteSettings *system_settings; /* System settings */ gboolean system_settings_running; /* Is system settings service running? */ - gboolean user_settings_running; /* Is user settings service running? */ - GSList *system_connections; /* List of system connections */ - GSList *user_connections; /* List of user connections */ gboolean should_wait; /* Indication that nmcli should not end yet */ gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */ diff --git a/cli/src/settings.c b/cli/src/settings.c index 35711d9238..fbec9ab34a 100644 --- a/cli/src/settings.c +++ b/cli/src/settings.c @@ -93,8 +93,7 @@ static NmcOutputField nmc_fields_setting_8021X[] = { SETTING_FIELD (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, 20), /* 18 */ SETTING_FIELD (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, 20), /* 19 */ SETTING_FIELD (NM_SETTING_802_1X_PIN, 8), /* 20 */ - SETTING_FIELD (NM_SETTING_802_1X_PSK, 8), /* 21 */ - SETTING_FIELD (NM_SETTING_802_1X_SYSTEM_CA_CERTS, 17), /* 22 */ + SETTING_FIELD (NM_SETTING_802_1X_SYSTEM_CA_CERTS, 17), /* 21 */ {NULL, NULL, 0, NULL, 0} }; #define NMC_FIELDS_SETTING_802_1X_ALL "name"","\ @@ -118,7 +117,6 @@ static NmcOutputField nmc_fields_setting_8021X[] = { NM_SETTING_802_1X_PHASE2_PRIVATE_KEY","\ NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD","\ NM_SETTING_802_1X_PIN","\ - NM_SETTING_802_1X_PSK","\ NM_SETTING_802_1X_SYSTEM_CA_CERTS #define NMC_FIELDS_SETTING_802_1X_COMMON NMC_FIELDS_SETTING_802_1X_ALL @@ -660,8 +658,7 @@ setting_802_1X_details (NMSetting *setting, NmCli *nmc) nmc->allowed_fields[18].value = phase2_private_key_str; nmc->allowed_fields[19].value = nm_setting_802_1x_get_phase2_private_key_password (s_8021X); nmc->allowed_fields[20].value = nm_setting_802_1x_get_pin (s_8021X); - nmc->allowed_fields[21].value = nm_setting_802_1x_get_psk (s_8021X); - nmc->allowed_fields[22].value = nm_setting_802_1x_get_system_ca_certs (s_8021X) ? _("yes") : _("no"); + nmc->allowed_fields[21].value = nm_setting_802_1x_get_system_ca_certs (s_8021X) ? _("yes") : _("no"); nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX; print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */ diff --git a/configure.ac b/configure.ac index 32591ced91..05fde82a4b 100644 --- a/configure.ac +++ b/configure.ac @@ -241,6 +241,8 @@ PKG_CHECK_MODULES(GIO, gio-2.0) AC_SUBST(GIO_CFLAGS) AC_SUBST(GIO_LIBS) +GOBJECT_INTROSPECTION_CHECK([0.9.6]) + AC_ARG_WITH(udev-dir, AS_HELP_STRING([--with-udev-dir=DIR], [where the udev base directory is])) if test -n "$with_udev_dir" ; then UDEV_BASE_DIR="$with_udev_dir" @@ -259,6 +261,19 @@ if test "x$with_systemdsystemunitdir" != xno; then fi AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ]) +dnl +dnl Disable ConsoleKit support +dnl +AC_ARG_WITH(ck, AS_HELP_STRING([--without-ck], [Build NetworkManager without ConsoleKit session tracking support])) +AM_CONDITIONAL(WITH_CONSOLEKIT, test x"$with_ck" != xno) +no_ck=0 +if test x"$with_ck" = x"no"; then + no_ck="1" +else + with_ck="yes" +fi +AC_DEFINE_UNQUOTED(NO_CONSOLEKIT, $no_ck, [Define to disable use of ConsoleKit]) + PKG_CHECK_MODULES(LIBNL, libnl-1 >= 1.0-pre8) AC_SUBST(LIBNL_CFLAGS) AC_SUBST(LIBNL_LIBS) @@ -537,8 +552,8 @@ src/ppp-manager/Makefile src/dnsmasq-manager/Makefile src/modem-manager/Makefile src/bluez-manager/Makefile +src/settings/Makefile src/wimax/Makefile -src/system-settings/Makefile src/backends/Makefile libnm-util/libnm-util.pc libnm-util/Makefile @@ -547,6 +562,7 @@ libnm-util/tests/certs/Makefile libnm-glib/libnm-glib.pc libnm-glib/libnm-glib-vpn.pc libnm-glib/Makefile +libnm-glib/tests/Makefile callouts/Makefile tools/Makefile system-settings/Makefile @@ -630,6 +646,12 @@ else echo systemd support: no fi +if test -n "${with_ck}"; then + echo ConsoleKit support: ${with_ck} +else + echo ConsoleKit support: no +fi + if test "${enable_wimax}" = "yes"; then echo WiMAX support: yes else diff --git a/docs/libnm-glib/Makefile.am b/docs/libnm-glib/Makefile.am index dc658a0b50..66826cb8af 100644 --- a/docs/libnm-glib/Makefile.am +++ b/docs/libnm-glib/Makefile.am @@ -45,13 +45,11 @@ IGNORE_HFILES= \ nm-device-wifi-bindings.h \ nm-dhcp4-config-bindings.h \ nm-dhcp6-config-bindings.h \ - nm-exported-connection-bindings.h \ - nm-exported-connection-glue.h \ + nm-settings-connection-glue.h \ nm-ip4-config-bindings.h \ nm-ip6-config-bindings.h \ nm-settings-bindings.h \ nm-settings-glue.h \ - nm-settings-system-bindings.h \ nm-vpn-connection-bindings.h \ nm-vpn-plugin-glue.h diff --git a/docs/libnm-glib/libnm-glib-docs.sgml b/docs/libnm-glib/libnm-glib-docs.sgml index b4e5dac25a..85e626e280 100644 --- a/docs/libnm-glib/libnm-glib-docs.sgml +++ b/docs/libnm-glib/libnm-glib-docs.sgml @@ -22,20 +22,15 @@ + - - - - - - diff --git a/examples/C/add-connection-glib.c b/examples/C/add-connection-glib.c index 4cdcfa2310..433c7124aa 100644 --- a/examples/C/add-connection-glib.c +++ b/examples/C/add-connection-glib.c @@ -13,7 +13,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2010 Red Hat, Inc. + * (C) Copyright 2011 Red Hat, Inc. */ /* @@ -74,7 +74,7 @@ add_connection (DBusGProxy *proxy, const char *con_name) NULL); nm_connection_add_setting (connection, NM_SETTING (s_ip4)); - hash = nm_connection_to_hash (connection); + hash = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL); /* Call AddConnection with the hash as argument */ dbus_g_proxy_call (proxy, "AddConnection", &error, @@ -99,7 +99,7 @@ int main (int argc, char *argv[]) /* Create a D-Bus proxy; NM_DBUS_* defined in NetworkManager.h */ proxy = dbus_g_proxy_new_for_name (bus, - NM_DBUS_SERVICE_SYSTEM_SETTINGS, + NM_DBUS_SERVICE, NM_DBUS_PATH_SETTINGS, NM_DBUS_IFACE_SETTINGS); diff --git a/examples/C/list-connections-dbus.c b/examples/C/list-connections-dbus.c index 957723c4e9..2cb584b59b 100644 --- a/examples/C/list-connections-dbus.c +++ b/examples/C/list-connections-dbus.c @@ -13,7 +13,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2010 Red Hat, Inc. + * (C) Copyright 2011 Red Hat, Inc. */ /* @@ -69,7 +69,7 @@ int main (int argc, char *argv[]) /* Create a D-Bus proxy; NM_DBUS_* defined in NetworkManager.h */ proxy = dbus_g_proxy_new_for_name (bus, - NM_DBUS_SERVICE_SYSTEM_SETTINGS, + NM_DBUS_SERVICE, NM_DBUS_PATH_SETTINGS, NM_DBUS_IFACE_SETTINGS); diff --git a/examples/C/list-connections-libnm-glib.c b/examples/C/list-connections-libnm-glib.c index 4fc2556a4c..edb5ccc34b 100644 --- a/examples/C/list-connections-libnm-glib.c +++ b/examples/C/list-connections-libnm-glib.c @@ -13,7 +13,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2010 Red Hat, Inc. + * (C) Copyright 2011 Red Hat, Inc. */ /* @@ -36,8 +36,6 @@ #include #include #include -#include -#include /* Global variables */ @@ -101,17 +99,17 @@ show_connection (NMConnection *data, gpointer user_data) * Now the connections can be listed. */ static void -get_connections_cb (NMSettingsInterface *settings, gpointer user_data) +get_connections_cb (NMRemoteSettings *settings, gpointer user_data) { - GSList *system_connections; + GSList *connections; - system_connections = nm_settings_interface_list_connections (settings); + connections = nm_remote_settings_list_connections (settings); - printf ("System connections:\n===================\n"); + printf ("Connections:\n===================\n"); - g_slist_foreach (system_connections, (GFunc) show_connection, NULL); + g_slist_foreach (connections, (GFunc) show_connection, NULL); - g_slist_free (system_connections); + g_slist_free (connections); g_object_unref (settings); /* We are done, exit main loop */ @@ -123,11 +121,11 @@ static gboolean list_connections (gpointer data) { DBusGConnection *bus = (DBusGConnection *) data; - NMRemoteSettingsSystem *system_settings; - gboolean system_settings_running; + NMRemoteSettings *settings; + gboolean settings_running; /* Get system settings */ - if (!(system_settings = nm_remote_settings_system_new (bus))) { + if (!(settings = nm_remote_settings_new (bus))) { g_message ("Error: Could not get system settings."); result = EXIT_FAILURE; g_main_loop_quit (loop); @@ -135,9 +133,9 @@ list_connections (gpointer data) } /* Find out whether setting service is running */ - g_object_get (system_settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &system_settings_running, NULL); + g_object_get (settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &settings_running, NULL); - if (!system_settings_running) { + if (!settings_running) { g_message ("Error: Can't obtain connections: settings service is not running."); result = EXIT_FAILURE; g_main_loop_quit (loop); @@ -145,7 +143,7 @@ list_connections (gpointer data) } /* Connect to signal "connections-read" - emitted when connections are fetched and ready */ - g_signal_connect (system_settings, NM_SETTINGS_INTERFACE_CONNECTIONS_READ, + g_signal_connect (settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ, G_CALLBACK (get_connections_cb), NULL); return FALSE; diff --git a/examples/python/add-system-connection.py b/examples/python/add-system-connection.py index 39eaabee0d..d508e8c6eb 100755 --- a/examples/python/add-system-connection.py +++ b/examples/python/add-system-connection.py @@ -41,8 +41,8 @@ con = dbus.Dictionary({ bus = dbus.SystemBus() -proxy = bus.get_object("org.freedesktop.NetworkManagerSystemSettings", "/org/freedesktop/NetworkManagerSettings") -settings = dbus.Interface(proxy, "org.freedesktop.NetworkManagerSettings") +proxy = bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/Settings") +settings = dbus.Interface(proxy, "org.freedesktop.NetworkManager.Settings") settings.AddConnection(con) diff --git a/examples/python/list-connections.py b/examples/python/list-connections.py index ad8d9047c4..9c3e1771c6 100644 --- a/examples/python/list-connections.py +++ b/examples/python/list-connections.py @@ -70,25 +70,24 @@ def connection_to_string(config): print "" -def print_one_services_connections(service_name, desc): +def print_connections(): # Ask the settings service for the list of connections it provides - proxy = bus.get_object(service_name, "/org/freedesktop/NetworkManagerSettings") - settings = dbus.Interface(proxy, "org.freedesktop.NetworkManagerSettings") + service_name = "org.freedesktop.NetworkManager" + proxy = bus.get_object(service_name, "/org/freedesktop/NetworkManager/Settings") + settings = dbus.Interface(proxy, "org.freedesktop.NetworkManager.Settings") connection_paths = settings.ListConnections() - print "%s connections --------------------------------------------\n" % desc - # List each connection's name, UUID, and type for path in connection_paths: con_proxy = bus.get_object(service_name, path) - connection = dbus.Interface(con_proxy, "org.freedesktop.NetworkManagerSettings.Connection") + connection = dbus.Interface(con_proxy, "org.freedesktop.NetworkManager.Settings.Connection") config = connection.GetSettings() # Now get secrets too; we grab the secrets for each type of connection # (since there isn't a "get all secrets" call because most of the time # you only need 'wifi' secrets or '802.1x' secrets, not everything) and # merge that into the configuration data - connection_secrets = dbus.Interface(con_proxy, "org.freedesktop.NetworkManagerSettings.Connection.Secrets") + connection_secrets = dbus.Interface(con_proxy, "org.freedesktop.NetworkManager.Settings.Connection.Secrets") merge_secrets(connection_secrets, config, '802-11-wireless') merge_secrets(connection_secrets, config, '802-11-wireless-security') merge_secrets(connection_secrets, config, '802-1x') @@ -106,7 +105,5 @@ def print_one_services_connections(service_name, desc): print "" -# Print out connection information for all connections -print_one_services_connections("org.freedesktop.NetworkManagerSystemSettings", "System") -print_one_services_connections("org.freedesktop.NetworkManagerUserSettings", "User") +print_connections() diff --git a/examples/python/nm-state.py b/examples/python/nm-state.py index 2bbdd2db4a..051e8ce087 100644 --- a/examples/python/nm-state.py +++ b/examples/python/nm-state.py @@ -53,11 +53,8 @@ for a in active: # needed to connect to a specific network. Lets get those details so we # can find the user-readable name of the connection. con_path = prop_iface.Get("org.freedesktop.NetworkManager.Connection.Active", "Connection") - con_service = prop_iface.Get("org.freedesktop.NetworkManager.Connection.Active", "ServiceName") - - # ask the provider of the connection for its details - service_proxy = bus.get_object(con_service, con_path) - con_iface = dbus.Interface(service_proxy, "org.freedesktop.NetworkManagerSettings.Connection") + service_proxy = bus.get_object("org.freedesktop.NetworkManager", con_path) + con_iface = dbus.Interface(service_proxy, "org.freedesktop.NetworkManager.Settings.Connection") con_details = con_iface.GetSettings() con_name = con_details['connection']['id'] diff --git a/examples/python/vpn.py b/examples/python/vpn.py index 4b4057fc2b..7e3e19f378 100644 --- a/examples/python/vpn.py +++ b/examples/python/vpn.py @@ -37,16 +37,16 @@ DBusGMainLoop(set_as_default=True) def get_connections(): bus = dbus.SystemBus() - proxy = bus.get_object('org.freedesktop.NetworkManagerUserSettings', '/org/freedesktop/NetworkManagerSettings') - iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManagerSettings') + proxy = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager/Settings') + iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManager.Settings') return iface.ListConnections() def get_connection_by_uuid(uuid): bus = dbus.SystemBus() for c in get_connections(): - proxy = bus.get_object('org.freedesktop.NetworkManagerUserSettings', c) - iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManagerSettings.Connection') + proxy = bus.get_object('org.freedesktop.NetworkManager', c) + iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManager.Settings.Connection') settings = iface.GetSettings() if settings['connection']['uuid'] == uuid: return c @@ -57,8 +57,8 @@ def get_connection_by_uuid(uuid): def list_uuids(): bus = dbus.SystemBus() for c in get_connections(): - proxy = bus.get_object('org.freedesktop.NetworkManagerUserSettings', c) - iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManagerSettings.Connection') + proxy = bus.get_object('org.freedesktop.NetworkManager', c) + iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManager.Settings.Connection') settings = iface.GetSettings() conn = settings['connection'] print "%s - %s (%s)" % (conn['uuid'], conn['id'], conn['type']) @@ -76,8 +76,8 @@ def get_active_connection_path(uuid): iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.DBus.Properties') path = iface.Get('org.freedesktop.NetworkManager.Connection.Active', 'Connection') - proxy = bus.get_object('org.freedesktop.NetworkManagerUserSettings', path) - iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManagerSettings.Connection') + proxy = bus.get_object('org.freedesktop.NetworkManager', path) + iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManager.Settings.Connection') settings = iface.GetSettings() if settings['connection']['uuid'] == uuid: @@ -112,7 +112,7 @@ def activate_connection(connection_path, device_path): bus = dbus.SystemBus() proxy = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager') iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.NetworkManager') - iface.ActivateConnection('org.freedesktop.NetworkManagerUserSettings', + iface.ActivateConnection('org.freedesktop.NetworkManager', connection_path, device_path, "/", diff --git a/include/NetworkManager.h b/include/NetworkManager.h index b2a0098caf..924d044eef 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -48,16 +48,18 @@ #define NM_DBUS_INTERFACE_DHCP6_CONFIG NM_DBUS_INTERFACE ".DHCP6Config" -#define NM_DBUS_SERVICE_USER_SETTINGS "org.freedesktop.NetworkManagerUserSettings" -#define NM_DBUS_SERVICE_SYSTEM_SETTINGS "org.freedesktop.NetworkManagerSystemSettings" -#define NM_DBUS_IFACE_SETTINGS "org.freedesktop.NetworkManagerSettings" -#define NM_DBUS_IFACE_SETTINGS_SYSTEM "org.freedesktop.NetworkManagerSettings.System" -#define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManagerSettings" +#define NM_DBUS_IFACE_SETTINGS "org.freedesktop.NetworkManager.Settings" +#define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings" -#define NM_DBUS_IFACE_SETTINGS_CONNECTION "org.freedesktop.NetworkManagerSettings.Connection" -#define NM_DBUS_PATH_SETTINGS_CONNECTION "/org/freedesktop/NetworkManagerSettings/Connection" -#define NM_DBUS_IFACE_SETTINGS_CONNECTION_SECRETS "org.freedesktop.NetworkManagerSettings.Connection.Secrets" +#define NM_DBUS_IFACE_SETTINGS_CONNECTION "org.freedesktop.NetworkManager.Settings.Connection" +#define NM_DBUS_PATH_SETTINGS_CONNECTION "/org/freedesktop/NetworkManager/Settings/Connection" +#define NM_DBUS_IFACE_SETTINGS_CONNECTION_SECRETS "org.freedesktop.NetworkManager.Settings.Connection.Secrets" +#define NM_DBUS_INTERFACE_AGENT_MANAGER NM_DBUS_INTERFACE ".AgentManager" +#define NM_DBUS_PATH_AGENT_MANAGER "/org/freedesktop/NetworkManager/AgentManager" + +#define NM_DBUS_INTERFACE_SECRET_AGENT NM_DBUS_INTERFACE ".SecretAgent" +#define NM_DBUS_PATH_SECRET_AGENT "/org/freedesktop/NetworkManager/SecretAgent" /* * Types of NetworkManager states @@ -154,7 +156,7 @@ typedef enum { * NMBluetoothCapabilities: * @NM_BT_CAPABILITY_NONE: device has no usable capabilities * @NM_BT_CAPABILITY_DUN: device provides Dial-Up Networking capability - * @NM_BT_CAPABILITY_PAN: device provides Personal Area Networking capability + * @NM_BT_CAPABILITY_NAP: device provides Network Access Point capability * * #NMBluetoothCapabilities values indicate the usable capabilities of a * Bluetooth device. diff --git a/introspection/Makefile.am b/introspection/Makefile.am index 9c6958894d..6cf8dc6069 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -18,13 +18,14 @@ EXTRA_DIST = \ nm-manager.xml \ nm-manager-client.xml \ nm-settings.xml \ - nm-settings-system.xml \ - nm-exported-connection.xml \ + nm-settings-connection.xml \ nm-vpn-plugin.xml \ nm-vpn-connection.xml \ nm-ppp-manager.xml \ nm-active-connection.xml \ nm-dhcp4-config.xml \ nm-dhcp6-config.xml \ - nm-wimax-nsp.xml + nm-agent-manager.xml \ + nm-wimax-nsp.xml \ + nm-secret-agent.xml diff --git a/introspection/all.xml b/introspection/all.xml index 521ab017d5..edb22dc516 100644 --- a/introspection/all.xml +++ b/introspection/all.xml @@ -42,8 +42,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - + + diff --git a/introspection/errors.xml b/introspection/errors.xml index 444b325d5e..f2db86679f 100644 --- a/introspection/errors.xml +++ b/introspection/errors.xml @@ -5,7 +5,7 @@ - Connection was not provided by any known settings service. + Connection was not provided by the settings service. @@ -15,18 +15,6 @@ - - - Invalid settings service (not a recognized system or user settings service name). - - - - - - Connection was superseded by a system connection. - - - User does not have the permission to activate this connection. diff --git a/introspection/nm-active-connection.xml b/introspection/nm-active-connection.xml index 765830a1dc..494eba42b2 100644 --- a/introspection/nm-active-connection.xml +++ b/introspection/nm-active-connection.xml @@ -2,9 +2,6 @@ - - The D-Bus service name providing this connection. - The path of the connection. diff --git a/introspection/nm-agent-manager.xml b/introspection/nm-agent-manager.xml new file mode 100644 index 0000000000..0b1e3e6e86 --- /dev/null +++ b/introspection/nm-agent-manager.xml @@ -0,0 +1,38 @@ + + + + + + + + Called by secret Agents to register their ability to provide and save + network secrets. + + + + + + Identifies this agent; only one agent in each user session may use the + same identifier. Identifier formatting follows the same rules as + D-Bus bus names with the exception that the ':' character is not + allowed. The valid set of characters is "[A-Z][a-z][0-9]_-." and the + identifier is limited in length to 255 characters with a minimum + of 3 characters. An example valid identifier is 'org.gnome.nm-applet' + (without quotes). + + + + + + + Called by secret Agents to notify NetworkManager that they will no + longer handle requests for network secrets. Agents are automatically + unregistered when they disconnect from D-Bus. + + + + + + + + diff --git a/introspection/nm-manager-client.xml b/introspection/nm-manager-client.xml index aae7a5f745..ba2b25b91a 100644 --- a/introspection/nm-manager-client.xml +++ b/introspection/nm-manager-client.xml @@ -22,13 +22,22 @@ object. dbus-glib generates the same bound function names for D-Bus the methods - + + + + + + + + + + diff --git a/introspection/nm-manager.xml b/introspection/nm-manager.xml index 9e8f0dff40..9a8f34dea7 100644 --- a/introspection/nm-manager.xml +++ b/introspection/nm-manager.xml @@ -27,11 +27,6 @@ Activate a connection using the supplied device. - - - The D-Bus service name of the settings service that provides this connection. - - The connection to activate the devices with. @@ -62,7 +57,6 @@ - Another connection is already activating or the same connection is already active. FIXME: check if the error name is correct. FIXME: split into 2 errors? @@ -72,6 +66,55 @@ + + + + + Adds a new connection using the given details (if any) as a template + (automatically filling in missing settings with the capabilities of the + given device and specific object), then activate the new connection. + Cannot be used for VPN connections at this time. + + + + Connection settings and properties; if incomplete missing settings will + be automatically completed using the given device and specific object. + + + + + The object path of device to be activated using the given connection. + + + + + The path of a connection-type-specific object this activation should use. + This parameter is currently ignored for wired and mobile broadband connections, + and the value of "/" should be used (ie, no specific object). For WiFi + connections, pass the object path of a specific AP from the card's scan + list, which will be used to complete the details of the newly added + connection. + + + + + Object path of the new connection that was just added. + + + + + The path of the active connection object representing this active connection. + + + + + + + The connection is invalid for this device. + + + + Deactivate an active connection. diff --git a/introspection/nm-secret-agent.xml b/introspection/nm-secret-agent.xml new file mode 100644 index 0000000000..9655c2b9df --- /dev/null +++ b/introspection/nm-secret-agent.xml @@ -0,0 +1,158 @@ + + + + + + + Private D-Bus interface used by secret agents that store and provide + secrets to NetworkManager. + + + + + Retrieve and return stored secrets, if any, or request new + secrets from the agent's user. + + + + + + Nested settings maps containing the connection for which + secrets are being requested. This may contain system-owned + secrets if the agent has successfully authenticated to + modify system network settings and the GetSecrets request + flags allow user interaction. + + + + + Object path of the connection for which secrets are being + requested. + + + + + Setting name for which secrets are being requested. + + + + + Array of strings of key names in the requested setting for + which NetworkManager thinks a secrets may be required. The + Agent should return any secrets it has, or that it thinks + are required, regardless of what hints NetworkManager sends + in this request. + + + + + Flags which modify the behavior of the secrets request. + If true, new secrets are assumed to be invalid or incorrect, + and the agent should ask the user for new secrets. If false, + existing secrets should be retrieved from storage and + returned without interrupting the user. + + + + + + Nested settings maps containing secrets. Each setting MUST + contain at least the 'name' field, containing the name of + the setting, and one or more secrets. + + + + + + + Flags modifying the behavior of GetSecrets request. + + + + No special behavior; by default no user interaction is allowed and + requests for secrets are fulfilled from persistent storage, or + if no secrets are available an error is returned. + + + + + Allows the request to interact with the user, possibly prompting + via UI for secrets if any are required, or if none are found in + persistent storage. + + + + + Explicitly prompt for new secrets from the user. This flag + signals that NetworkManager thinks any existing secrets are + invalid or wrong. This flag implies that interaction is allowed. + + + + + + + Cancel a pending GetSecrets request for secrets of the given + connection. Any matching request should be canceled. + + + + + + Object path of the connection for which, if secrets are being + requested, the request should be canceled. + + + + + Setting name for which secrets for this connection were + originally being requested. + + + + + + + Save given secrets to backing storage. + + + + + + Nested settings maps containing the entire connection + (including secrets), for which the agent should save the + secrets to backing storage. + + + + + Object path of the connection for which the agent should + save secrets to backing storage. + + + + + + + Delete secrets from backing storage. + + + + + + Nested settings maps containing the connection properties + (sans secrets), for which the agent should delete the + secrets from backing storage. + + + + + Object path of the connection for which the agent should + delete secrets from backing storage. + + + + + + + diff --git a/introspection/nm-exported-connection.xml b/introspection/nm-settings-connection.xml similarity index 52% rename from introspection/nm-exported-connection.xml rename to introspection/nm-settings-connection.xml index 46907c05e9..82e53451cd 100644 --- a/introspection/nm-exported-connection.xml +++ b/introspection/nm-settings-connection.xml @@ -2,20 +2,23 @@ - + Represents a single network connection configuration. - Update the connection with new settings and properties, replacing all previous settings and properties. + Update the connection with new settings and properties, replacing + all previous settings and properties. Secrets may be part of the + update request, and will be either stored in persistent storage or + given to a Secret Agent for storage, depending on the request. - + - New connection properties. + New connection settings, properties, and (optionally) secrets. @@ -24,15 +27,19 @@ Delete the connection. - + - Get the settings maps describing this object. + Get the settings maps describing this network configuration. + This will never include any secrets required for connection + to the network, as those are often protected. Secrets must + be requested separately using the GetSecrets() call. - + + The nested settings maps describing this object. @@ -40,60 +47,47 @@ - - - Emitted when some settings changed. - - - - Contains complete connection setting parameters, including changes. - - - - - - - Emitted when this connection has been deleted/removed. After receipt of this signal, the object no longer exists. - - - - - - - - Secrets have a separate interface so that they can be locked down. - - - Get the secrets encapsulated in this object. + Get the secrets belonging to this network configuration. Only + secrets from persistent storage or a Secret Agent running in + the requestor's session will be returned. The user will never + be prompted for secrets as a result of this request. - + - Name of the setting to return. - - - - - Array of strings of key names in the Setting for which NM thinks - a secrets may be required. - - - - - Indicates whether new secrets should be requested or if the request can be fulfilled from storage. + Name of the setting to return secrets for. If empty, all + all secrets will be returned. - Nested settings maps containing secrets. Each setting MUST contain at least the 'name' field, containing the name of the setting, and one or more secrets. + Nested settings maps containing secrets. + + + Emitted when any settings or permissions change. When handling + this signal, clients should re-read the connection using the + GetSettings method to get the changes and to ensure the client + still has permission to access the connection. + + + + + + Emitted when this connection is no longer available. This + happens when the connection is deleted or if it is no longer + accessable by any of the system's logged-in users. After + receipt of this signal, the object no longer exists. + + + diff --git a/introspection/nm-settings-system.xml b/introspection/nm-settings-system.xml deleted file mode 100644 index 598274c0d1..0000000000 --- a/introspection/nm-settings-system.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - Implemented by the system settings service to provide additional settings to NetworkManager. - - - - - Save the hostname to persistent configuration. - - - - - - The hostname to save to persistent configuration. If blank, the persistent hostname is cleared. - - - - - - - The machine hostname stored in persistent configuration. - - - - - - If true, adding and modifying connections is supported. - - - - - - - A dictionary mapping property names to variant boxed values - - - - - - - Emitted when system authorization details change, indicating that clients may wish to recheck permissions with GetPermissions. - - - - - - Returns a bitfield indicating certain operations the caller is permitted to perform. Some of these operations may require authorization by the user. - - - - - - A bitfield of permitted operations. Some of these operations may require the user to authorize via password entry or other means. - - - - - - - No permissions. - - - Can modify/add/delete connections. - - - Can share connections via a encrypted user-created WiFi network. - - - Can share connections via a open/unencrypted user-created WiFi network. - - - Can modify the persistent system hostname. - - - - - - diff --git a/introspection/nm-settings.xml b/introspection/nm-settings.xml index b252c00d59..f816b08706 100644 --- a/introspection/nm-settings.xml +++ b/introspection/nm-settings.xml @@ -1,9 +1,9 @@ - + - The NetworkManagerSettings interface is provided by the service which provides connections to NetworkManager. + The Settings interface allows clients to view and administrate the connections stored and used by NetworkManager. @@ -29,8 +29,46 @@ Connection settings and properties. + + + Object path of the new connection that was just added. + + + + + Save the hostname to persistent configuration. + + + + + + The hostname to save to persistent configuration. If blank, the persistent hostname is cleared. + + + + + + + The machine hostname stored in persistent configuration. + + + + + + If true, adding and modifying connections is supported. + + + + + + + A dictionary mapping property names to variant boxed values + + + + Emitted when a new connection has been added. diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am index a3b5577986..7dbd6103bf 100644 --- a/libnm-glib/Makefile.am +++ b/libnm-glib/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS=. tests + INCLUDES = \ -I$(top_srcdir)/include \ -I$(top_srcdir)/libnm-util \ @@ -10,26 +12,27 @@ BUILT_SOURCES = \ nm-device-ethernet-bindings.h \ nm-device-wifi-bindings.h \ nm-device-bt-bindings.h \ + nm-settings-connection-bindings.h \ nm-device-wimax-bindings.h \ - nm-exported-connection-glue.h \ - nm-exported-connection-bindings.h \ - nm-settings-glue.h \ nm-settings-bindings.h \ - nm-settings-system-bindings.h \ nm-vpn-connection-bindings.h \ nm-vpn-plugin-glue.h \ nm-active-connection-bindings.h \ nm-ip4-config-bindings.h \ nm-dhcp4-config-bindings.h \ nm-ip6-config-bindings.h \ - nm-dhcp6-config-bindings.h + nm-dhcp6-config-bindings.h \ + nm-secret-agent-glue.h + + +noinst_LTLIBRARIES = \ + libdeprecated-nm-glib.la \ + libnm-glib-test.la ##################################################### # Deprecated original libnm_glib bits ##################################################### -noinst_LTLIBRARIES = libdeprecated-nm-glib.la - libdeprecated_nm_glib_la_SOURCES = \ libnm_glib.h \ libnm_glib.c @@ -44,6 +47,9 @@ libdeprecated_nm_glib_la_LIBADD = \ $(DBUS_LIBS) \ $(GLIB_LIBS) +libdeprecateddir = $(includedir)/libnm-glib +libdeprecated_HEADERS = libnm_glib.h + ##################################################### # Real libnm-glib stuff ##################################################### @@ -56,9 +62,9 @@ libnm_glib_la_CFLAGS = \ $(GUDEV_CFLAGS) libnmincludedir = $(includedir)/libnm-glib +libnmvpndir = $(includedir)/libnm-glib libnminclude_HEADERS = \ - libnm_glib.h \ nm-object.h \ nm-client.h \ nm-device.h \ @@ -71,32 +77,27 @@ libnminclude_HEADERS = \ nm-cdma-device.h \ nm-serial-device.h \ nm-vpn-connection.h \ - nm-vpn-plugin.h \ - nm-vpn-plugin-ui-interface.h \ nm-types.h \ nm-active-connection.h \ nm-dhcp4-config.h \ nm-ip6-config.h \ nm-dhcp6-config.h \ nm-remote-connection.h \ - nm-settings-interface.h \ - nm-settings-system-interface.h \ nm-remote-settings.h \ - nm-remote-settings-system.h \ - nm-settings-connection-interface.h \ - nm-exported-connection.h \ - nm-settings-service.h \ + nm-secret-agent.h \ nm-device-wimax.h \ nm-wimax-nsp.h -libnm_glib_la_SOURCES = \ +libnmvpn_HEADERS = \ + nm-vpn-plugin.h \ + nm-vpn-plugin-ui-interface.h \ + nm-vpn-plugin-utils.h + +libnm_glib_la_csources = \ nm-object.c \ - nm-object-private.h \ nm-client.c \ nm-dbus-utils.c \ - nm-dbus-utils.h \ nm-device.c \ - nm-device-private.h \ nm-device-ethernet.c \ nm-device-wifi.c \ nm-device-bt.c \ @@ -107,25 +108,29 @@ libnm_glib_la_SOURCES = \ nm-serial-device.c \ nm-vpn-connection.c \ nm-types.c \ - nm-types-private.h \ nm-object-cache.c \ - nm-object-cache.h \ nm-active-connection.c \ nm-dhcp4-config.c \ nm-ip6-config.c \ nm-dhcp6-config.c \ nm-remote-connection.c \ - nm-remote-connection-private.h \ - nm-settings-interface.c \ - nm-settings-system-interface.c \ nm-remote-settings.c \ - nm-remote-settings-system.c \ - nm-settings-connection-interface.c \ - nm-exported-connection.c \ - nm-settings-service.c \ + nm-secret-agent.c \ nm-device-wimax.c \ nm-wimax-nsp.c +libnm_glib_la_private_headers = \ + nm-object-private.h \ + nm-dbus-utils.h \ + nm-device-private.h \ + nm-types-private.h \ + nm-object-cache.h \ + nm-remote-connection-private.h + +libnm_glib_la_SOURCES = \ + $(libnm_glib_la_csources) \ + $(libnm_glib_la_private_headers) + libnm_glib_la_LIBADD = \ $(top_builddir)/libnm-util/libnm-util.la \ $(top_builddir)/marshallers/libmarshallers.la \ @@ -135,7 +140,7 @@ libnm_glib_la_LIBADD = \ $(GUDEV_LIBS) libnm_glib_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib.ver \ - -version-info "6:2:4" + -version-info "7:0:5" noinst_PROGRAMS = libnm-glib-test @@ -144,12 +149,37 @@ libnm_glib_test_CFLAGS = $(GLIB_CFLAGS) $(DBUS_CFLAGS) libnm_glib_test_LDADD = libnm-glib.la $(top_builddir)/libnm-util/libnm-util.la $(GLIB_LIBS) $(DBUS_LIBS) -libnm_glib_vpn_la_SOURCES = nm-vpn-plugin.c nm-vpn-plugin-ui-interface.c +libnm_glib_vpn_la_SOURCES = \ + nm-vpn-plugin.c \ + nm-vpn-plugin-ui-interface.c \ + nm-vpn-plugin-utils.c libnm_glib_vpn_la_CFLAGS = $(GLIB_CFLAGS) $(DBUS_CFLAGS) libnm_glib_vpn_la_LIBADD = $(top_builddir)/libnm-util/libnm-util.la $(GLIB_LIBS) $(DBUS_LIBS) libnm_glib_vpn_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib-vpn.ver \ -version-info "1:0:0" +##################################################### +# Test libnm-glib stuff +##################################################### + +libnm_glib_test_la_CFLAGS = \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) \ + $(GUDEV_CFLAGS) \ + -DLIBNM_GLIB_TEST + +libnm_glib_test_la_SOURCES = \ + $(libnminclude_HEADERS) \ + $(libnm_glib_la_SOURCES) + +libnm_glib_test_la_LIBADD = \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(top_builddir)/marshallers/libmarshallers.la \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) \ + $(GUDEV_LIBS) + +##################################################### nm-client-bindings.h: $(top_srcdir)/introspection/nm-manager-client.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_client --mode=glib-client --output=$@ $< @@ -169,20 +199,11 @@ nm-device-bt-bindings.h: $(top_srcdir)/introspection/nm-device-bt.xml nm-access-point-bindings.h: $(top_srcdir)/introspection/nm-access-point.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_access_point --mode=glib-client --output=$@ $< -nm-settings-glue.h: $(top_srcdir)/introspection/nm-settings.xml - $(AM_V_GEN) dbus-binding-tool --prefix=nm_settings --mode=glib-server --output=$@ $< - nm-settings-bindings.h: $(top_srcdir)/introspection/nm-settings.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_settings --mode=glib-client --output=$@ $< -nm-settings-system-bindings.h: $(top_srcdir)/introspection/nm-settings-system.xml - $(AM_V_GEN) dbus-binding-tool --prefix=nm_settings_system --mode=glib-client --output=$@ $< - -nm-exported-connection-glue.h: $(top_srcdir)/introspection/nm-exported-connection.xml - $(AM_V_GEN) dbus-binding-tool --prefix=nm_exported_connection --mode=glib-server --output=$@ $< - -nm-exported-connection-bindings.h: $(top_srcdir)/introspection/nm-exported-connection.xml - $(AM_V_GEN) dbus-binding-tool --prefix=nm_exported_connection --mode=glib-client --output=$@ $< +nm-settings-connection-bindings.h: $(top_srcdir)/introspection/nm-settings-connection.xml + $(AM_V_GEN) dbus-binding-tool --prefix=nm_settings_connection --mode=glib-client --output=$@ $< nm-vpn-connection-bindings.h: $(top_srcdir)/introspection/nm-vpn-connection.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_vpn_connection --mode=glib-client --output=$@ $< @@ -205,6 +226,9 @@ nm-ip6-config-bindings.h: $(top_srcdir)/introspection/nm-ip6-config.xml nm-dhcp6-config-bindings.h: $(top_srcdir)/introspection/nm-dhcp6-config.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_dhcp6_config --mode=glib-client --output=$@ $< +nm-secret-agent-glue.h: $(top_srcdir)/introspection/nm-secret-agent.xml + $(AM_V_GEN) dbus-binding-tool --prefix=nm_secret_agent --mode=glib-server --output=$@ $< + nm-device-wimax-bindings.h: $(top_srcdir)/introspection/nm-device-wimax.xml dbus-binding-tool --prefix=nm_device_wimax --mode=glib-client --output=$@ $< @@ -216,3 +240,28 @@ DISTCLEANFILES = libnm-glib.pc libnm-glib.pc EXTRA_DIST = libnm-glib.pc.in libnm-glib-vpn.pc.in libnm-glib.ver libnm-glib-vpn.ver CLEANFILES = $(BUILT_SOURCES) + +-include $(INTROSPECTION_MAKEFILE) +INTROSPECTION_GIRS = +INTROSPECTION_COMPILER_ARGS = --includedir=$(top_builddir)/libnm-util + +if HAVE_INTROSPECTION +introspection_sources = $(libnminclude_HEADERS) $(libnm_glib_la_csources) + +NMClient-1.0.gir: libnm-glib.la +NMClient_1_0_gir_INCLUDES = GObject-2.0 DBusGLib-1.0 +NMClient_1_0_gir_PACKAGES = gobject-2.0 dbus-glib-1 gudev-1.0 +NMClient_1_0_gir_CFLAGS = $(INCLUDES) -I$(top_srcdir)/libnm-glib -I$(top_srcdir)/libnm-util +NMClient_1_0_gir_LIBS = libnm-glib.la +NMClient_1_0_gir_FILES = $(introspection_sources) +NMClient_1_0_gir_SCANNERFLAGS = --warn-all --identifier-prefix=NM --symbol-prefix=nm_ --include-uninstalled=$(top_builddir)/libnm-util/NetworkManager-1.0.gir +INTROSPECTION_GIRS += NMClient-1.0.gir + +girdir = $(datadir)/gir-1.0 +gir_DATA = $(INTROSPECTION_GIRS) + +typelibdir = $(libdir)/girepository-1.0 +typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) + +CLEANFILES += $(gir_DATA) $(typelib_DATA) +endif diff --git a/libnm-glib/libnm-glib-vpn.ver b/libnm-glib/libnm-glib-vpn.ver index 16643d2ea1..9d2bad5e2d 100644 --- a/libnm-glib/libnm-glib-vpn.ver +++ b/libnm-glib/libnm-glib-vpn.ver @@ -21,6 +21,8 @@ global: nm_vpn_plugin_ui_widget_interface_get_widget; nm_vpn_plugin_ui_widget_interface_save_secrets; nm_vpn_plugin_ui_widget_interface_update_connection; + nm_vpn_plugin_utils_get_secret_flags; + nm_vpn_plugin_utils_read_vpn_details; local: *; }; diff --git a/libnm-glib/libnm-glib.pc.in b/libnm-glib/libnm-glib.pc.in index 5c3471b16e..a1010baabf 100644 --- a/libnm-glib/libnm-glib.pc.in +++ b/libnm-glib/libnm-glib.pc.in @@ -6,7 +6,7 @@ includedir=@includedir@ Name: libnm-glib Description: Convenience library for clients of NetworkManager Version: @VERSION@ -Requires: NetworkManager >= 0.7.999 glib-2.0 dbus-glib-1 +Requires: NetworkManager >= 0.7.999 gobject-2.0 dbus-glib-1 Cflags: -I${includedir}/libnm-glib Libs: -L${libdir} -lnm-glib diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver index 16c24e2621..dc9d854794 100644 --- a/libnm-glib/libnm-glib.ver +++ b/libnm-glib/libnm-glib.ver @@ -20,8 +20,6 @@ global: nm_active_connection_get_default; nm_active_connection_get_default6; nm_active_connection_get_devices; - nm_active_connection_get_scope; - nm_active_connection_get_service_name; nm_active_connection_get_specific_object; nm_active_connection_get_state; nm_active_connection_get_type; @@ -29,6 +27,7 @@ global: nm_cdma_device_get_type; nm_cdma_device_new; nm_client_activate_connection; + nm_client_add_and_activate_connection; nm_client_deactivate_connection; nm_client_get_active_connections; nm_client_get_device_by_path; @@ -94,6 +93,17 @@ global: nm_device_wifi_get_mode; nm_device_wifi_get_type; nm_device_wifi_new; + nm_device_wimax_get_bsid; + nm_device_wimax_get_center_frequency; + nm_device_wimax_get_cinr; + nm_device_wimax_get_hw_address; + nm_device_wimax_get_active_nsp; + nm_device_wimax_get_nsp_by_path; + nm_device_wimax_get_nsps; + nm_device_wimax_get_rssi; + nm_device_wimax_get_tx_power; + nm_device_wimax_get_type; + nm_device_wimax_new; nm_dhcp4_config_get_one_option; nm_dhcp4_config_get_options; nm_dhcp4_config_get_type; @@ -102,9 +112,6 @@ global: nm_dhcp6_config_get_options; nm_dhcp6_config_get_type; nm_dhcp6_config_new; - nm_exported_connection_export; - nm_exported_connection_get_type; - nm_exported_connection_new; nm_gsm_device_get_type; nm_gsm_device_new; nm_ip4_config_get_addresses; @@ -128,38 +135,31 @@ global: nm_object_get_connection; nm_object_get_path; nm_object_get_type; + nm_remote_connection_delete; + nm_remote_connection_get_secrets; + nm_remote_connection_commit_changes; nm_remote_connection_get_type; nm_remote_connection_new; + nm_remote_settings_add_connection; + nm_remote_settings_error_get_type; + nm_remote_settings_error_quark; + nm_remote_settings_get_connection_by_path; + nm_remote_settings_get_permissions; nm_remote_settings_get_type; + nm_remote_settings_list_connections; nm_remote_settings_new; - nm_remote_settings_system_get_type; - nm_remote_settings_system_new; + nm_remote_settings_save_hostname; + nm_secret_agent_delete_secrets; + nm_secret_agent_error_get_type; + nm_secret_agent_error_quark; + nm_secret_agent_get_secrets; + nm_secret_agent_get_type; + nm_secret_agent_register; + nm_secret_agent_save_secrets; + nm_secret_agent_unregister; nm_serial_device_get_bytes_received; nm_serial_device_get_bytes_sent; nm_serial_device_get_type; - nm_settings_connection_interface_delete; - nm_settings_connection_interface_emit_updated; - nm_settings_connection_interface_get_secrets; - nm_settings_connection_interface_get_type; - nm_settings_connection_interface_update; - nm_settings_interface_add_connection; - nm_settings_interface_error_get_type; - nm_settings_interface_error_quark; - nm_settings_interface_get_connection_by_path; - nm_settings_interface_get_type; - nm_settings_interface_list_connections; - nm_settings_service_export; - nm_settings_service_export_connection; - nm_settings_service_get_connection_by_path; - nm_settings_service_get_type; - nm_settings_system_interface_get_type; - nm_settings_system_interface_add_connection; - nm_settings_system_interface_get_permissions; - nm_settings_system_interface_save_hostname; - nm_settings_error_quark; - nm_settings_get_type; - nm_settings_list_connections; - nm_settings_signal_new_connection; nm_ssid_get_type; nm_string_array_get_type; nm_uint_array_get_type; @@ -167,17 +167,6 @@ global: nm_vpn_connection_get_type; nm_vpn_connection_get_vpn_state; nm_vpn_connection_new; - nm_device_wimax_get_bsid; - nm_device_wimax_get_center_frequency; - nm_device_wimax_get_cinr; - nm_device_wimax_get_hw_address; - nm_device_wimax_get_active_nsp; - nm_device_wimax_get_nsp_by_path; - nm_device_wimax_get_nsps; - nm_device_wimax_get_rssi; - nm_device_wimax_get_tx_power; - nm_device_wimax_get_type; - nm_device_wimax_new; nm_wimax_nsp_get_name; nm_wimax_nsp_get_network_type; nm_wimax_nsp_get_signal_quality; diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c index 2468da099f..46ca12f5c0 100644 --- a/libnm-glib/nm-active-connection.c +++ b/libnm-glib/nm-active-connection.c @@ -43,8 +43,6 @@ typedef struct { gboolean disposed; DBusGProxy *proxy; - char *service_name; - NMConnectionScope scope; char *connection; char *specific_object; GPtrArray *devices; @@ -55,7 +53,6 @@ typedef struct { enum { PROP_0, - PROP_SERVICE_NAME, PROP_CONNECTION, PROP_SPECIFIC_OBJECT, PROP_DEVICES, @@ -66,7 +63,6 @@ enum { LAST_PROP }; -#define DBUS_PROP_SERVICE_NAME "ServiceName" #define DBUS_PROP_CONNECTION "Connection" #define DBUS_PROP_SPECIFIC_OBJECT "SpecificObject" #define DBUS_PROP_DEVICES "Devices" @@ -95,62 +91,6 @@ nm_active_connection_new (DBusGConnection *connection, const char *path) NULL); } -static NMConnectionScope -get_scope_for_service_name (const char *service_name) -{ - if (service_name && !strcmp (service_name, NM_DBUS_SERVICE_USER_SETTINGS)) - return NM_CONNECTION_SCOPE_USER; - else if (service_name && !strcmp (service_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS)) - return NM_CONNECTION_SCOPE_SYSTEM; - - return NM_CONNECTION_SCOPE_UNKNOWN; -} - -/** - * nm_active_connection_get_service_name: - * @connection: a #NMActiveConnection - * - * Gets the service name of the active connection. - * - * Returns: the service name. This is the internal string used by the - * connection, and must not be modified. - **/ -const char * -nm_active_connection_get_service_name (NMActiveConnection *connection) -{ - NMActiveConnectionPrivate *priv; - - g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL); - - priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection); - if (!priv->service_name) { - priv->service_name = _nm_object_get_string_property (NM_OBJECT (connection), - NM_DBUS_INTERFACE_ACTIVE_CONNECTION, - DBUS_PROP_SERVICE_NAME); - priv->scope = get_scope_for_service_name (priv->service_name); - } - - return priv->service_name; -} - -/** - * nm_active_connection_get_scope: - * @connection: a #NMActiveConnection - * - * Gets the scope of the active connection. - * - * Returns: the connection's scope - **/ -NMConnectionScope -nm_active_connection_get_scope (NMActiveConnection *connection) -{ - g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NM_CONNECTION_SCOPE_UNKNOWN); - - /* Make sure service_name and scope are up-to-date */ - nm_active_connection_get_service_name (connection); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->scope; -} - /** * nm_active_connection_get_connection: * @connection: a #NMActiveConnection @@ -209,7 +149,7 @@ nm_active_connection_get_specific_object (NMActiveConnection *connection) * * Gets the #NMDevices used for the active connections. * - * Returns: the #GPtrArray containing #NMDevices. + * Returns: (element-type NMClient.Device): the #GPtrArray containing #NMDevices. * This is the internal copy used by the connection, and must not be modified. **/ const GPtrArray * @@ -345,7 +285,6 @@ finalize (GObject *object) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); - g_free (priv->service_name); g_free (priv->connection); g_free (priv->specific_object); @@ -361,11 +300,8 @@ get_property (GObject *object, NMActiveConnection *self = NM_ACTIVE_CONNECTION (object); switch (prop_id) { - case PROP_SERVICE_NAME: - g_value_set_string (value, nm_active_connection_get_service_name (self)); - break; case PROP_CONNECTION: - g_value_set_boxed (value, nm_active_connection_get_connection (self)); + g_value_set_string (value, nm_active_connection_get_connection (self)); break; case PROP_SPECIFIC_OBJECT: g_value_set_boxed (value, nm_active_connection_get_specific_object (self)); @@ -401,24 +337,11 @@ demarshal_devices (NMObject *object, GParamSpec *pspec, GValue *value, gpointer return TRUE; } -static gboolean -demarshal_service (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); - - if (_nm_object_demarshal_generic (object, pspec, value, field)) { - priv->scope = get_scope_for_service_name (priv->service_name); - return TRUE; - } - return FALSE; -} - static void register_for_property_changed (NMActiveConnection *connection) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection); const NMPropertiesChangedInfo property_changed_info[] = { - { NM_ACTIVE_CONNECTION_SERVICE_NAME, demarshal_service, &priv->service_name }, { NM_ACTIVE_CONNECTION_CONNECTION, _nm_object_demarshal_generic, &priv->connection }, { NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, _nm_object_demarshal_generic, &priv->specific_object }, { NM_ACTIVE_CONNECTION_DEVICES, demarshal_devices, &priv->devices }, @@ -475,19 +398,6 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class) /* properties */ - /** - * NMActiveConnection:service-name: - * - * The service name of the active connection. - **/ - g_object_class_install_property - (object_class, PROP_SERVICE_NAME, - g_param_spec_string (NM_ACTIVE_CONNECTION_SERVICE_NAME, - "Service Name", - "Service Name", - NULL, - G_PARAM_READABLE)); - /** * NMActiveConnection:connection: * diff --git a/libnm-glib/nm-active-connection.h b/libnm-glib/nm-active-connection.h index 30edf047a0..a641e7c1a5 100644 --- a/libnm-glib/nm-active-connection.h +++ b/libnm-glib/nm-active-connection.h @@ -39,7 +39,6 @@ G_BEGIN_DECLS #define NM_IS_ACTIVE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_ACTIVE_CONNECTION)) #define NM_ACTIVE_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionClass)) -#define NM_ACTIVE_CONNECTION_SERVICE_NAME "service-name" #define NM_ACTIVE_CONNECTION_CONNECTION "connection" #define NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT "specific-object" #define NM_ACTIVE_CONNECTION_DEVICES "devices" @@ -67,8 +66,6 @@ GType nm_active_connection_get_type (void); GObject *nm_active_connection_new (DBusGConnection *connection, const char *path); -const char * nm_active_connection_get_service_name (NMActiveConnection *connection); -NMConnectionScope nm_active_connection_get_scope (NMActiveConnection *connection); const char * nm_active_connection_get_connection (NMActiveConnection *connection); const char * nm_active_connection_get_specific_object (NMActiveConnection *connection); const GPtrArray *nm_active_connection_get_devices (NMActiveConnection *connection); diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c index b68a6786bf..0bfc520d0b 100644 --- a/libnm-glib/nm-client.c +++ b/libnm-glib/nm-client.c @@ -327,11 +327,17 @@ register_for_property_changed (NMClient *client) property_changed_info); } -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI "org.freedesktop.NetworkManager.enable-disable-wifi" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN "org.freedesktop.NetworkManager.enable-disable-wwan" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX "org.freedesktop.NetworkManager.enable-disable-wimax" -#define NM_AUTH_PERMISSION_USE_USER_CONNECTIONS "org.freedesktop.NetworkManager.use-user-connections" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI "org.freedesktop.NetworkManager.enable-disable-wifi" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN "org.freedesktop.NetworkManager.enable-disable-wwan" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX "org.freedesktop.NetworkManager.enable-disable-wimax" +#define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake" +#define NM_AUTH_PERMISSION_NETWORK_CONTROL "org.freedesktop.NetworkManager.network-control" +#define NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED "org.freedesktop.NetworkManager.wifi.share.protected" +#define NM_AUTH_PERMISSION_WIFI_SHARE_OPEN "org.freedesktop.NetworkManager.wifi.share.open" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM "org.freedesktop.NetworkManager.settings.modify.system" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN "org.freedesktop.NetworkManager.settings.modify.own" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME "org.freedesktop.NetworkManager.settings.modify.hostname" static NMClientPermission nm_permission_to_client (const char *nm) @@ -344,8 +350,21 @@ nm_permission_to_client (const char *nm) return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN; else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX)) return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX; - else if (!strcmp (nm, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS)) - return NM_CLIENT_PERMISSION_USE_USER_CONNECTIONS; + else if (!strcmp (nm, NM_AUTH_PERMISSION_SLEEP_WAKE)) + return NM_CLIENT_PERMISSION_SLEEP_WAKE; + else if (!strcmp (nm, NM_AUTH_PERMISSION_NETWORK_CONTROL)) + return NM_CLIENT_PERMISSION_NETWORK_CONTROL; + else if (!strcmp (nm, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED)) + return NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED; + else if (!strcmp (nm, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN)) + return NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN; + else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM)) + return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM; + else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN)) + return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN; + else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME)) + return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME; + return NM_CLIENT_PERMISSION_NONE; } @@ -504,9 +523,9 @@ constructor (GType type, get_permissions_sync (NM_CLIENT (object)); priv->bus_proxy = dbus_g_proxy_new_for_name (connection, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus"); + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); dbus_g_proxy_add_signal (priv->bus_proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, @@ -648,7 +667,7 @@ get_property (GObject *object, g_value_set_boolean (value, priv->manager_running); break; case PROP_NETWORKING_ENABLED: - g_value_set_boolean (value, priv->networking_enabled); + g_value_set_boolean (value, nm_client_networking_get_enabled (self)); break; case PROP_WIRELESS_ENABLED: g_value_set_boolean (value, priv->wireless_enabled); @@ -813,6 +832,7 @@ nm_client_class_init (NMClientClass *client_class) * NMClient::active-connections: * * The active connections. + * Type: GPtrArray **/ g_object_class_install_property (object_class, PROP_ACTIVE_CONNECTIONS, @@ -827,7 +847,7 @@ nm_client_class_init (NMClientClass *client_class) /** * NMClient::device-added: * @client: the client that received the signal - * @device: the new device + * @device: (type NMClient.Device): the new device * * Notifies that a #NMDevice is added. **/ @@ -844,7 +864,7 @@ nm_client_class_init (NMClientClass *client_class) /** * NMClient::device-removed: * @widget: the client that received the signal - * @device: the removed device + * @device: (type NMClient.Device): the removed device * * Notifies that a #NMDevice is removed. **/ @@ -888,7 +908,11 @@ nm_client_new (void) DBusGConnection *connection; GError *err = NULL; +#ifdef LIBNM_GLIB_TEST + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &err); +#else connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err); +#endif if (!connection) { g_warning ("Couldn't connect to system bus: %s", err->message); g_error_free (err); @@ -992,7 +1016,7 @@ client_device_removed_proxy (DBusGProxy *proxy, char *path, gpointer user_data) * * Gets all the detected devices. * - * Returns: a #GPtrArray containing all the #NMDevices. + * Returns: (transfer none) (element-type NMClient.Device): a #GPtrArray containing all the #NMDevices. * The returned array is owned by the client and should not be modified. **/ const GPtrArray * @@ -1032,7 +1056,7 @@ nm_client_get_devices (NMClient *client) * * Gets a #NMDevice from a #NMClient. * - * Returns: the #NMDevice for the given @object_path or %NULL if none is found. + * Returns: (transfer none): the #NMDevice for the given @object_path or %NULL if none is found. **/ NMDevice * nm_client_get_device_by_path (NMClient *client, const char *object_path) @@ -1060,7 +1084,9 @@ nm_client_get_device_by_path (NMClient *client, const char *object_path) } typedef struct { - NMClientActivateDeviceFn fn; + NMClient *client; + NMClientActivateDeviceFn act_fn; + NMClientAddActivateFn add_act_fn; gpointer user_data; } ActivateDeviceInfo; @@ -1072,8 +1098,8 @@ activate_cb (DBusGProxy *proxy, { ActivateDeviceInfo *info = (ActivateDeviceInfo *) user_data; - if (info->fn) - info->fn (info->user_data, path, error); + if (info->act_fn) + info->act_fn (info->client, path, error, info->user_data); else if (error) nm_warning ("Device activation failed: (%d) %s", error->code, error->message); @@ -1083,19 +1109,17 @@ activate_cb (DBusGProxy *proxy, /** * nm_client_activate_connection: * @client: a #NMClient - * @service_name: the connection's service name * @connection_path: the connection's DBus path * @device: the #NMDevice * @specific_object: the device specific object (currently used only for * activating wireless devices and should be the #NMAccessPoint's path. - * @callback: the function to call when the call is done + * @callback: (scope async): the function to call when the call is done * @user_data: user data to pass to the callback function * * Activates a connection with the given #NMDevice. **/ void nm_client_activate_connection (NMClient *client, - const char *service_name, const char *connection_path, NMDevice *device, const char *specific_object, @@ -1103,30 +1127,92 @@ nm_client_activate_connection (NMClient *client, gpointer user_data) { ActivateDeviceInfo *info; - char *internal_so = (char *) specific_object; g_return_if_fail (NM_IS_CLIENT (client)); g_return_if_fail (NM_IS_DEVICE (device)); - g_return_if_fail (service_name != NULL); g_return_if_fail (connection_path != NULL); - /* NULL specific object must be translated into "/" because D-Bus does - * not have any idea of NULL object paths. - */ - if (internal_so == NULL) - internal_so = "/"; - info = g_slice_new (ActivateDeviceInfo); - info->fn = callback; + info->act_fn = callback; info->user_data = user_data; + info->client = client; org_freedesktop_NetworkManager_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->client_proxy, - service_name, - connection_path, - nm_object_get_path (NM_OBJECT (device)), - internal_so, - activate_cb, - info); + connection_path, + nm_object_get_path (NM_OBJECT (device)), + specific_object ? specific_object : "/", + activate_cb, + info); +} + +static void +add_activate_cb (DBusGProxy *proxy, + char *connection_path, + char *active_path, + GError *error, + gpointer user_data) +{ + ActivateDeviceInfo *info = (ActivateDeviceInfo *) user_data; + + if (info->add_act_fn) + info->add_act_fn (info->client, connection_path, active_path, error, info->user_data); + else if (error) + nm_warning ("Connection add and activate failed: (%d) %s", error->code, error->message); + + g_slice_free (ActivateDeviceInfo, info); +} + +/** + * nm_client_add_and_activate_connection: + * @client: a #NMClient + * @partial: an #NMConnection to add; the connection may be partially filled + * and will be completed by NetworkManager using the given @device and + * @specific_object before being added + * @device: the #NMDevice + * @specific_object: (allow-none): the object path of a connection-type-specific + * object this activation should use. This parameter is currently ignored for + * wired and mobile broadband connections, and the value of NULL should be used + * (ie, no specific object). For WiFi connections, pass the object path of a + * specific AP from the card's scan list, which will be used to complete the + * details of the newly added connection. + * @callback: (scope async): the function to call when the call is done + * @user_data: (closure): user data to pass to the callback function + * + * Adds a new connection using the given details (if any) as a template + * (automatically filling in missing settings with the capabilities of the + * given device and specific object), then activate the new connection. + * Cannot be used for VPN connections at this time. + **/ +void +nm_client_add_and_activate_connection (NMClient *client, + NMConnection *partial, + NMDevice *device, + const char *specific_object, + NMClientAddActivateFn callback, + gpointer user_data) +{ + ActivateDeviceInfo *info; + GHashTable *hash = NULL; + + g_return_if_fail (NM_IS_CLIENT (client)); + g_return_if_fail (NM_IS_DEVICE (device)); + + info = g_slice_new (ActivateDeviceInfo); + info->add_act_fn = callback; + info->user_data = user_data; + info->client = client; + + if (partial) + hash = nm_connection_to_hash (partial, NM_SETTING_HASH_FLAG_ALL); + else + hash = g_hash_table_new (g_str_hash, g_str_equal); + org_freedesktop_NetworkManager_add_and_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->client_proxy, + hash, + nm_object_get_path (NM_OBJECT (device)), + specific_object ? specific_object : "/", + add_activate_cb, + info); + g_hash_table_unref (hash); } /** @@ -1161,7 +1247,8 @@ nm_client_deactivate_connection (NMClient *client, NMActiveConnection *active) * * Gets the active connections. * - * Returns: a #GPtrArray containing all the active #NMActiveConnections. + * Returns: (transfer none) (element-type NMClient.ActiveConnection): a #GPtrArray +* containing all the active #NMActiveConnections. * The returned array is owned by the client and should not be modified. **/ const GPtrArray * diff --git a/libnm-glib/nm-client.h b/libnm-glib/nm-client.h index 4153ebcadd..1885f8faba 100644 --- a/libnm-glib/nm-client.h +++ b/libnm-glib/nm-client.h @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2010 Red Hat, Inc. + * Copyright (C) 2007 - 2011 Red Hat, Inc. */ #ifndef NM_CLIENT_H @@ -58,10 +58,16 @@ typedef enum { NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK = 1, NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI = 2, NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN = 3, - NM_CLIENT_PERMISSION_USE_USER_CONNECTIONS = 4, - NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX = 5, + NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX = 4, + NM_CLIENT_PERMISSION_SLEEP_WAKE = 5, + NM_CLIENT_PERMISSION_NETWORK_CONTROL = 6, + NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED = 7, + NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN = 8, + NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM = 9, + NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN = 10, + NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME = 11, - NM_CLIENT_PERMISSION_LAST = NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX + NM_CLIENT_PERMISSION_LAST = NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME } NMClientPermission; typedef enum { @@ -82,6 +88,9 @@ typedef struct { /* Signals */ void (*device_added) (NMClient *client, NMDevice *device); void (*device_removed) (NMClient *client, NMDevice *device); + void (*permission_changed) (NMClient *client, + NMClientPermission permission, + NMClientPermissionResult result); /* Padding for future expansion */ void (*_reserved1) (void); @@ -99,15 +108,30 @@ NMClient *nm_client_new (void); const GPtrArray *nm_client_get_devices (NMClient *client); NMDevice *nm_client_get_device_by_path (NMClient *client, const char *object_path); -typedef void (*NMClientActivateDeviceFn) (gpointer user_data, const char *object_path, GError *error); +typedef void (*NMClientActivateDeviceFn) (NMClient *client, + const char *object_path, + GError *error, + gpointer user_data); void nm_client_activate_connection (NMClient *client, - const char *service_name, - const char *connection_path, - NMDevice *device, - const char *specific_object, - NMClientActivateDeviceFn callback, - gpointer user_data); + const char *connection_path, + NMDevice *device, + const char *specific_object, + NMClientActivateDeviceFn callback, + gpointer user_data); + +typedef void (*NMClientAddActivateFn) (NMClient *client, + const char *connection_path, + const char *active_path, + GError *error, + gpointer user_data); + +void nm_client_add_and_activate_connection (NMClient *client, + NMConnection *partial, + NMDevice *device, + const char *specific_object, + NMClientAddActivateFn callback, + gpointer user_data); void nm_client_deactivate_connection (NMClient *client, NMActiveConnection *active); diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c index 3d17023950..be5b987693 100644 --- a/libnm-glib/nm-device-wifi.c +++ b/libnm-glib/nm-device-wifi.c @@ -252,7 +252,7 @@ nm_device_wifi_get_capabilities (NMDeviceWifi *device) * * Gets the active #NMAccessPoint. * - * Returns: the access point or %NULL if none is active + * Returns: (transfer none): the access point or %NULL if none is active **/ NMAccessPoint * nm_device_wifi_get_active_access_point (NMDeviceWifi *device) @@ -302,7 +302,8 @@ nm_device_wifi_get_active_access_point (NMDeviceWifi *device) * * Gets all the scanned access points of the #NMDeviceWifi. * - * Returns: a #GPtrArray containing all the scanned #NMAccessPoints. + * Returns: (element-type NMClient.AccessPoint): a #GPtrArray containing all the + * scanned #NMAccessPoints. * The returned array is owned by the client and should not be modified. **/ const GPtrArray * @@ -342,7 +343,7 @@ nm_device_wifi_get_access_points (NMDeviceWifi *device) * * Gets a #NMAccessPoint by path. * - * Returns: the access point or %NULL if none is found. + * Returns: (transfer none): the access point or %NULL if none is found. **/ NMAccessPoint * nm_device_wifi_get_access_point_by_path (NMDeviceWifi *device, diff --git a/libnm-glib/nm-device-wimax.c b/libnm-glib/nm-device-wimax.c index bdab0eb743..4e7ebe8d84 100644 --- a/libnm-glib/nm-device-wimax.c +++ b/libnm-glib/nm-device-wimax.c @@ -108,12 +108,12 @@ nm_device_wimax_new (DBusGConnection *connection, const char *path) /** * nm_device_wimax_get_hw_address: - * @device: a #NMDeviceWimax + * @wimax: a #NMDeviceWimax * * Gets the hardware (MAC) address of the #NMDeviceWimax * * Returns: the hardware address. This is the internal string used by the - * device, and must not be modified. + * device, and must not be modified. **/ const char * nm_device_wimax_get_hw_address (NMDeviceWimax *wimax) @@ -138,7 +138,7 @@ nm_device_wimax_get_hw_address (NMDeviceWimax *wimax) * * Gets the active #NMWimaxNsp. * - * Returns: the access point or %NULL if none is active + * Returns: (transfer full): the access point or %NULL if none is active **/ NMWimaxNsp * nm_device_wimax_get_active_nsp (NMDeviceWimax *wimax) @@ -188,7 +188,8 @@ nm_device_wimax_get_active_nsp (NMDeviceWimax *wimax) * * Gets all the scanned NSPs of the #NMDeviceWimax. * - * Returns: a #GPtrArray containing all the scanned #NMWimaxNsps. + * Returns: (element-type NMClient.WimaxNsp): a #GPtrArray containing + * all the scanned #NMWimaxNsps. * The returned array is owned by the client and should not be modified. **/ const GPtrArray * @@ -228,7 +229,7 @@ nm_device_wimax_get_nsps (NMDeviceWimax *wimax) * * Gets a #NMWimaxNsp by path. * - * Returns: the access point or %NULL if none is found. + * Returns: (transfer none): the access point or %NULL if none is found. **/ NMWimaxNsp * nm_device_wimax_get_nsp_by_path (NMDeviceWimax *wimax, @@ -339,7 +340,7 @@ clean_up_nsps (NMDeviceWimax *self, gboolean notify) /** * nm_device_wimax_get_center_frequency: - * @device: a #NMDeviceWimax + * @self: a #NMDeviceWimax * * Gets the center frequency (in KHz) of the radio channel the device is using * to communicate with the network when connected. Has no meaning when the @@ -348,15 +349,15 @@ clean_up_nsps (NMDeviceWimax *self, gboolean notify) * Returns: the center frequency in KHz, or 0 **/ guint -nm_device_wimax_get_center_frequency (NMDeviceWimax *wimax) +nm_device_wimax_get_center_frequency (NMDeviceWimax *self) { NMDeviceWimaxPrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE_WIMAX (wimax), 0); + g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), 0); - priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax); + priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); if (!priv->center_freq) { - priv->center_freq = _nm_object_get_uint_property (NM_OBJECT (wimax), + priv->center_freq = _nm_object_get_uint_property (NM_OBJECT (self), NM_DBUS_INTERFACE_DEVICE_WIMAX, DBUS_PROP_CENTER_FREQUENCY); } @@ -365,7 +366,7 @@ nm_device_wimax_get_center_frequency (NMDeviceWimax *wimax) /** * nm_device_wimax_get_rssi: - * @device: a #NMDeviceWimax + * @self: a #NMDeviceWimax * * Gets the RSSI of the current radio link in dBm. This value indicates how * strong the raw received RF signal from the base station is, but does not @@ -375,15 +376,15 @@ nm_device_wimax_get_center_frequency (NMDeviceWimax *wimax) * Returns: the RSSI in dBm, or 0 **/ gint -nm_device_wimax_get_rssi (NMDeviceWimax *wimax) +nm_device_wimax_get_rssi (NMDeviceWimax *self) { NMDeviceWimaxPrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE_WIMAX (wimax), 0); + g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), 0); - priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax); + priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); if (!priv->rssi) { - priv->rssi = _nm_object_get_int_property (NM_OBJECT (wimax), + priv->rssi = _nm_object_get_int_property (NM_OBJECT (self), NM_DBUS_INTERFACE_DEVICE_WIMAX, DBUS_PROP_RSSI); } @@ -392,7 +393,7 @@ nm_device_wimax_get_rssi (NMDeviceWimax *wimax) /** * nm_device_wimax_get_cinr: - * @device: a #NMDeviceWimax + * @self: a #NMDeviceWimax * * Gets the CINR (Carrier to Interference + Noise Ratio) of the current radio * link in dB. CINR is a more accurate measure of radio link quality. Has no @@ -401,15 +402,15 @@ nm_device_wimax_get_rssi (NMDeviceWimax *wimax) * Returns: the CINR in dB, or 0 **/ gint -nm_device_wimax_get_cinr (NMDeviceWimax *wimax) +nm_device_wimax_get_cinr (NMDeviceWimax *self) { NMDeviceWimaxPrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE_WIMAX (wimax), 0); + g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), 0); - priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax); + priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); if (!priv->cinr) { - priv->cinr = _nm_object_get_int_property (NM_OBJECT (wimax), + priv->cinr = _nm_object_get_int_property (NM_OBJECT (self), NM_DBUS_INTERFACE_DEVICE_WIMAX, DBUS_PROP_CINR); } @@ -418,7 +419,7 @@ nm_device_wimax_get_cinr (NMDeviceWimax *wimax) /** * nm_device_wimax_get_tx_power: - * @device: a #NMDeviceWimax + * @self: a #NMDeviceWimax * * Average power of the last burst transmitted by the device, in units of * 0.5 dBm. i.e. a TxPower of -11 represents an actual device TX power of @@ -427,15 +428,15 @@ nm_device_wimax_get_cinr (NMDeviceWimax *wimax) * Returns: the TX power in dBm, or 0 **/ gint -nm_device_wimax_get_tx_power (NMDeviceWimax *wimax) +nm_device_wimax_get_tx_power (NMDeviceWimax *self) { NMDeviceWimaxPrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE_WIMAX (wimax), 0); + g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), 0); - priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax); + priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); if (!priv->tx_power) { - priv->tx_power = _nm_object_get_int_property (NM_OBJECT (wimax), + priv->tx_power = _nm_object_get_int_property (NM_OBJECT (self), NM_DBUS_INTERFACE_DEVICE_WIMAX, DBUS_PROP_TX_POWER); } @@ -444,22 +445,22 @@ nm_device_wimax_get_tx_power (NMDeviceWimax *wimax) /** * nm_device_wimax_get_bsid: - * @device: a #NMDeviceWimax + * @self: a #NMDeviceWimax * * Gets the ID of the serving Base Station when the device is connected. * * Returns: the ID of the serving Base Station, or NULL **/ const char * -nm_device_wimax_get_bsid (NMDeviceWimax *wimax) +nm_device_wimax_get_bsid (NMDeviceWimax *self) { NMDeviceWimaxPrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE_WIMAX (wimax), NULL); + g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), NULL); - priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax); + priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); if (!priv->bsid) { - priv->bsid = _nm_object_get_string_property (NM_OBJECT (wimax), + priv->bsid = _nm_object_get_string_property (NM_OBJECT (self), NM_DBUS_INTERFACE_DEVICE_WIMAX, DBUS_PROP_BSID); } diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c index b494749ada..6a39c77fdf 100644 --- a/libnm-glib/nm-device.c +++ b/libnm-glib/nm-device.c @@ -934,7 +934,7 @@ nm_device_get_firmware_missing (NMDevice *device) * * Gets the current #NMIP4Config associated with the #NMDevice. * - * Returns: the #NMIP4Config or %NULL if the device is not activated. + * Returns: (transfer none): the #NMIP4Config or %NULL if the device is not activated. **/ NMIP4Config * nm_device_get_ip4_config (NMDevice *device) @@ -968,7 +968,7 @@ nm_device_get_ip4_config (NMDevice *device) * * Gets the current #NMDHCP4Config associated with the #NMDevice. * - * Returns: the #NMDHCPConfig or %NULL if the device is not activated or not + * Returns: (transfer none): the #NMDHCPConfig or %NULL if the device is not activated or not * using DHCP. **/ NMDHCP4Config * @@ -1003,7 +1003,7 @@ nm_device_get_dhcp4_config (NMDevice *device) * * Gets the current #NMIP6Config associated with the #NMDevice. * - * Returns: the #NMIP6Config or %NULL if the device is not activated. + * Returns: (transfer none): the #NMIP6Config or %NULL if the device is not activated. **/ NMIP6Config * nm_device_get_ip6_config (NMDevice *device) @@ -1037,7 +1037,7 @@ nm_device_get_ip6_config (NMDevice *device) * * Gets the current #NMDHCP6Config associated with the #NMDevice. * - * Returns: the #NMDHCPConfig or %NULL if the device is not activated or not + * Returns: (transfer none): the #NMDHCPConfig or %NULL if the device is not activated or not * using DHCP. **/ NMDHCP6Config * @@ -1317,7 +1317,7 @@ deactivate_cb (DBusGProxy *proxy, /** * nm_device_disconnect: * @device: a #NMDevice - * @callback: callback to be called when disconnect operation completes + * @callback: (scope async): callback to be called when disconnect operation completes * @user_data: caller-specific data passed to @callback * * Disconnects the device if currently connected, and prevents the device from diff --git a/libnm-glib/nm-dhcp4-config.c b/libnm-glib/nm-dhcp4-config.c index 442d19d192..45d48345c0 100644 --- a/libnm-glib/nm-dhcp4-config.c +++ b/libnm-glib/nm-dhcp4-config.c @@ -203,7 +203,7 @@ nm_dhcp4_config_new (DBusGConnection *connection, const char *object_path) * * Gets all the options contained in the configuration. * - * Returns: the #GHashTable containing strings for keys and values. + * Returns: (transfer none) (element-type utf8 GObject.Value): the #GHashTable containing strings for keys and values. * This is the internal copy used by the configuration, and must not be modified. **/ GHashTable * diff --git a/libnm-glib/nm-dhcp6-config.c b/libnm-glib/nm-dhcp6-config.c index 3792867207..dbcf4c682e 100644 --- a/libnm-glib/nm-dhcp6-config.c +++ b/libnm-glib/nm-dhcp6-config.c @@ -203,7 +203,7 @@ nm_dhcp6_config_new (DBusGConnection *connection, const char *object_path) * * Gets all the options contained in the configuration. * - * Returns: the #GHashTable containing strings for keys and values. + * Returns: (transfer none) (element-type utf8 GObject.Value): the #GHashTable containing strings for keys and values. * This is the internal copy used by the configuration, and must not be modified. **/ GHashTable * diff --git a/libnm-glib/nm-exported-connection.c b/libnm-glib/nm-exported-connection.c deleted file mode 100644 index 3a8e51ce79..0000000000 --- a/libnm-glib/nm-exported-connection.c +++ /dev/null @@ -1,281 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * (C) Copyright 2008 Novell, Inc. - * (C) Copyright 2008 - 2009 Red Hat, Inc. - */ - -#include -#include -#include - -#include "nm-exported-connection.h" -#include "nm-settings-interface.h" -#include "nm-settings-connection-interface.h" - -static gboolean impl_exported_connection_get_settings (NMExportedConnection *connection, - GHashTable **settings, - GError **error); - -static void impl_exported_connection_update (NMExportedConnection *connection, - GHashTable *new_settings, - DBusGMethodInvocation *context); - -static void impl_exported_connection_delete (NMExportedConnection *connection, - DBusGMethodInvocation *context); - -static void impl_exported_connection_get_secrets (NMExportedConnection *connection, - const gchar *setting_name, - const gchar **hints, - gboolean request_new, - DBusGMethodInvocation *context); - -#include "nm-exported-connection-glue.h" - -static void settings_connection_interface_init (NMSettingsConnectionInterface *class); - -G_DEFINE_TYPE_EXTENDED (NMExportedConnection, nm_exported_connection, NM_TYPE_CONNECTION, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE, - settings_connection_interface_init)) - -#define NM_EXPORTED_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ - NM_TYPE_EXPORTED_CONNECTION, \ - NMExportedConnectionPrivate)) - -typedef struct { - gboolean foo; -} NMExportedConnectionPrivate; - - -/**************************************************************/ - -static GHashTable * -real_get_settings (NMExportedConnection *self, GError **error) -{ - NMConnection *no_secrets; - GHashTable *settings; - - /* Secrets should *never* be returned by the GetSettings method, they - * get returned by the GetSecrets method which can be better - * protected against leakage of secrets to unprivileged callers. - */ - no_secrets = nm_connection_duplicate (NM_CONNECTION (self)); - g_assert (no_secrets); - nm_connection_clear_secrets (no_secrets); - settings = nm_connection_to_hash (no_secrets); - g_assert (settings); - g_object_unref (no_secrets); - - return settings; -} - -/**************************************************************/ - -static gboolean -check_writable (NMConnection *connection, GError **error) -{ - NMSettingConnection *s_con; - - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - - s_con = (NMSettingConnection *) nm_connection_get_setting (connection, - NM_TYPE_SETTING_CONNECTION); - if (!s_con) { - g_set_error_literal (error, - NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION, - "Connection did not have required 'connection' setting"); - return FALSE; - } - - /* If the connection is read-only, that has to be changed at the source of - * the problem (ex a system settings plugin that can't write connections out) - * instead of over D-Bus. - */ - if (nm_setting_connection_get_read_only (s_con)) { - g_set_error_literal (error, - NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_READ_ONLY_CONNECTION, - "Connection is read-only"); - return FALSE; - } - - return TRUE; -} - -static gboolean -impl_exported_connection_get_settings (NMExportedConnection *self, - GHashTable **settings, - GError **error) -{ - /* Must always be implemented */ - g_assert (NM_EXPORTED_CONNECTION_GET_CLASS (self)->get_settings); - *settings = NM_EXPORTED_CONNECTION_GET_CLASS (self)->get_settings (self, error); - return *settings ? TRUE : FALSE; -} - -static gboolean -update (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceUpdateFunc callback, - gpointer user_data) -{ - g_object_ref (connection); - nm_settings_connection_interface_emit_updated (connection); - callback (connection, NULL, user_data); - g_object_unref (connection); - return TRUE; -} - -static void -impl_exported_connection_update (NMExportedConnection *self, - GHashTable *new_settings, - DBusGMethodInvocation *context) -{ - NMConnection *tmp; - GError *error = NULL; - - /* If the connection is read-only, that has to be changed at the source of - * the problem (ex a system settings plugin that can't write connections out) - * instead of over D-Bus. - */ - if (!check_writable (NM_CONNECTION (self), &error)) { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - /* Check if the settings are valid first */ - tmp = nm_connection_new_from_hash (new_settings, &error); - if (!tmp) { - g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - g_object_unref (tmp); - - if (NM_EXPORTED_CONNECTION_GET_CLASS (self)->update) - NM_EXPORTED_CONNECTION_GET_CLASS (self)->update (self, new_settings, context); - else { - error = g_error_new (NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, - "%s: %s:%d update() unimplemented", __func__, __FILE__, __LINE__); - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - -static gboolean -do_delete (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceDeleteFunc callback, - gpointer user_data) -{ - g_object_ref (connection); - g_signal_emit_by_name (connection, "removed"); - callback (connection, NULL, user_data); - g_object_unref (connection); - return TRUE; -} - -static void -impl_exported_connection_delete (NMExportedConnection *self, - DBusGMethodInvocation *context) -{ - GError *error = NULL; - - if (!check_writable (NM_CONNECTION (self), &error)) { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - if (NM_EXPORTED_CONNECTION_GET_CLASS (self)->delete) - NM_EXPORTED_CONNECTION_GET_CLASS (self)->delete (self, context); - else { - error = g_error_new (NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, - "%s: %s:%d delete() unimplemented", __func__, __FILE__, __LINE__); - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - -static void -impl_exported_connection_get_secrets (NMExportedConnection *self, - const gchar *setting_name, - const gchar **hints, - gboolean request_new, - DBusGMethodInvocation *context) -{ - GError *error = NULL; - - if (NM_EXPORTED_CONNECTION_GET_CLASS (self)->get_secrets) - NM_EXPORTED_CONNECTION_GET_CLASS (self)->get_secrets (self, setting_name, hints, request_new, context); - else { - error = g_error_new (NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, - "%s: %s:%d get_secrets() unimplemented", __func__, __FILE__, __LINE__); - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - -/**************************************************************/ - -static void -settings_connection_interface_init (NMSettingsConnectionInterface *iface) -{ - iface->update = update; - iface->delete = do_delete; -} - -/** - * nm_exported_connection_new: - * @scope: the Connection scope (either user or system) - * - * Creates a new object representing the remote connection. - * - * Returns: the new exported connection object on success, or %NULL on failure - **/ -NMExportedConnection * -nm_exported_connection_new (NMConnectionScope scope) -{ - g_return_val_if_fail (scope != NM_CONNECTION_SCOPE_UNKNOWN, NULL); - - return (NMExportedConnection *) g_object_new (NM_TYPE_EXPORTED_CONNECTION, - NM_CONNECTION_SCOPE, scope, - NULL); -} - -static void -nm_exported_connection_init (NMExportedConnection *self) -{ -} - -static void -nm_exported_connection_class_init (NMExportedConnectionClass *class) -{ - g_type_class_add_private (class, sizeof (NMExportedConnectionPrivate)); - - /* Virtual methods */ - class->get_settings = real_get_settings; - - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class), - &dbus_glib_nm_exported_connection_object_info); -} diff --git a/libnm-glib/nm-exported-connection.h b/libnm-glib/nm-exported-connection.h deleted file mode 100644 index 53dc3b024e..0000000000 --- a/libnm-glib/nm-exported-connection.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * (C) Copyright 2009 Red Hat, Inc. - */ - -#ifndef NM_EXPORTED_CONNECTION_H -#define NM_EXPORTED_CONNECTION_H - -#include -#include - -G_BEGIN_DECLS - -#define NM_TYPE_EXPORTED_CONNECTION (nm_exported_connection_get_type ()) -#define NM_EXPORTED_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_EXPORTED_CONNECTION, NMExportedConnection)) -#define NM_EXPORTED_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_EXPORTED_CONNECTION, NMExportedConnectionClass)) -#define NM_IS_EXPORTED_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_EXPORTED_CONNECTION)) -#define NM_IS_EXPORTED_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_EXPORTED_CONNECTION)) -#define NM_EXPORTED_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_EXPORTED_CONNECTION, NMExportedConnectionClass)) - -typedef struct { - NMConnection parent; -} NMExportedConnection; - -typedef struct { - NMConnectionClass parent; - - GHashTable * (*get_settings) (NMExportedConnection *self, - GError **error); - - void (*update) (NMExportedConnection *self, - GHashTable *new_settings, - DBusGMethodInvocation *context); - - void (*delete) (NMExportedConnection *self, - DBusGMethodInvocation *context); - - void (*get_secrets) (NMExportedConnection *self, - const gchar *setting_name, - const gchar **hints, - gboolean request_new, - DBusGMethodInvocation *context); - - /* Padding for future expansion */ - void (*_reserved1) (void); - void (*_reserved2) (void); - void (*_reserved3) (void); - void (*_reserved4) (void); - void (*_reserved5) (void); - void (*_reserved6) (void); -} NMExportedConnectionClass; - -GType nm_exported_connection_get_type (void); - -NMExportedConnection *nm_exported_connection_new (NMConnectionScope scope); - -G_END_DECLS - -#endif /* NM_EXPORTED_CONNECTION_H */ diff --git a/libnm-glib/nm-ip4-config.c b/libnm-glib/nm-ip4-config.c index 4bedc7a1a7..bc93a2c121 100644 --- a/libnm-glib/nm-ip4-config.c +++ b/libnm-glib/nm-ip4-config.c @@ -337,8 +337,8 @@ nm_ip4_config_new (DBusGConnection *connection, const char *object_path) * * Gets the IP4 addresses (containing the address, prefix, and gateway). * - * Returns: the #GSList containing #NMSettingIP4Addresses. This is the internal copy - * used by the configuration and must not be modified. + * Returns: (element-type NetworkManager.IP4Address): the #GSList containing #NMIP4Addresses. + * This is the internal copy used by the configuration and must not be modified. **/ const GSList * nm_ip4_config_get_addresses (NMIP4Config *config) @@ -366,7 +366,7 @@ nm_ip4_config_get_addresses (NMIP4Config *config) } /** - * nm_ip4_config_get_hostname: + * nm_ip4_config_get_hostname: (skip): * @config: a #NMIP4Config * * DEPRECATED. Don't use. @@ -385,7 +385,7 @@ nm_ip4_config_get_hostname (NMIP4Config *config) * * Gets the domain name servers (DNS). * - * Returns: the #GArray containing %guint32s. This is the internal copy used by the + * Returns: (element-type guint32): the #GArray containing %guint32s. This is the internal copy used by the * configuration and must not be modified. **/ const GArray * @@ -421,7 +421,7 @@ nm_ip4_config_get_nameservers (NMIP4Config *config) * * Gets the domain names. * - * Returns: the #GPtrArray containing domains as strings. This is the + * Returns: (element-type utf8): the #GPtrArray containing domains as strings. This is the * internal copy used by the configuration, and must not be modified. **/ const GPtrArray * @@ -460,8 +460,8 @@ nm_ip4_config_get_domains (NMIP4Config *config) * * Gets the Windows Internet Name Service servers (WINS). * - * Returns: the #GArray containing %guint32s. This is the internal copy used by the - * configuration and must not be modified. + * Returns: (element-type guint32): the #GArray containing %guint32s. + * This is the internal copy used by the configuration and must not be modified. **/ const GArray * nm_ip4_config_get_wins_servers (NMIP4Config *config) @@ -496,8 +496,9 @@ nm_ip4_config_get_wins_servers (NMIP4Config *config) * * Gets the routes. * - * Returns: the #GSList containing #NMSettingIP4Routes. This is the - * internal copy used by the configuration, and must not be modified. + * Returns: (element-type NetworkManager.IP4Route): the #GSList containing + * #NMIP4Routes. This is the internal copy used by the configuration, + * and must not be modified. **/ const GSList * nm_ip4_config_get_routes (NMIP4Config *config) diff --git a/libnm-glib/nm-ip6-config.c b/libnm-glib/nm-ip6-config.c index fe71c1b8d3..fce6430e47 100644 --- a/libnm-glib/nm-ip6-config.c +++ b/libnm-glib/nm-ip6-config.c @@ -146,8 +146,9 @@ register_for_property_changed (NMIP6Config *config) * * Gets the IP6 addresses (containing the address, prefix, and gateway). * - * Returns: the #GSList containing #NMSettingIP6Addresses. This is the internal copy - * used by the configuration and must not be modified. + * Returns: (element-type NetworkManager.IP6Address): the #GSList containing + * #NMIP6Addresses. This is the internal copy used by the configuration + * and must not be modified. **/ const GSList * nm_ip6_config_get_addresses (NMIP6Config *config) @@ -174,15 +175,16 @@ nm_ip6_config_get_addresses (NMIP6Config *config) return priv->addresses; } +/* FIXME: like in libnm_util, in6_addr is not introspectable, so skipping here */ /** - * nm_ip6_config_get_nameservers: + * nm_ip6_config_get_nameservers: (skip) * @config: a #NMIP6Config * * Gets the domain name servers (DNS). * - * Returns: a #GSList containing elements of type 'struct in6_addr' which contain - * the addresses of nameservers of the configuration. This is the internal copy - * used by the configuration and must not be modified. + * Returns: (element-type Posix.in6_addr): a #GSList containing elements of type + * 'struct in6_addr' which contain the addresses of nameservers of the configuration. + * This is the internal copy used by the configuration and must not be modified. **/ const GSList * nm_ip6_config_get_nameservers (NMIP6Config *config) @@ -217,8 +219,8 @@ nm_ip6_config_get_nameservers (NMIP6Config *config) * * Gets the domain names. * - * Returns: the #GPtrArray containing domains as strings. This is the - * internal copy used by the configuration, and must not be modified. + * Returns: (element-type utf8): the #GPtrArray containing domains as strings. + * This is the internal copy used by the configuration, and must not be modified. **/ const GPtrArray * nm_ip6_config_get_domains (NMIP6Config *config) @@ -251,8 +253,9 @@ nm_ip6_config_get_domains (NMIP6Config *config) * * Gets the routes. * - * Returns: the #GSList containing #NMSettingIP6Routes. This is the - * internal copy used by the configuration, and must not be modified. + * Returns: (element-type NetworkManager.IP6Route): the #GSList containing + * #NMIP6Routes. This is the internal copy used by the configuration, + * and must not be modified. **/ const GSList * nm_ip6_config_get_routes (NMIP6Config *config) diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c index 85cb6b78ab..78b46388a4 100644 --- a/libnm-glib/nm-object.c +++ b/libnm-glib/nm-object.c @@ -223,7 +223,7 @@ nm_object_class_init (NMObjectClass *nm_object_class) * * Gets the #NMObject's DBusGConnection. * - * Returns: the connection + * Returns: (transfer none): the connection **/ DBusGConnection * nm_object_get_connection (NMObject *object) diff --git a/libnm-glib/nm-remote-connection-private.h b/libnm-glib/nm-remote-connection-private.h index 22d84ae743..3df5760623 100644 --- a/libnm-glib/nm-remote-connection-private.h +++ b/libnm-glib/nm-remote-connection-private.h @@ -28,7 +28,8 @@ typedef enum { NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN = 0, NM_REMOTE_CONNECTION_INIT_RESULT_SUCCESS, - NM_REMOTE_CONNECTION_INIT_RESULT_ERROR + NM_REMOTE_CONNECTION_INIT_RESULT_ERROR, + NM_REMOTE_CONNECTION_INIT_RESULT_INVISIBLE, } NMRemoteConnectionInitResult; #endif /* __NM_REMOTE_CONNECTION_PRIVATE__ */ diff --git a/libnm-glib/nm-remote-connection.c b/libnm-glib/nm-remote-connection.c index 1039a7d188..09c7112596 100644 --- a/libnm-glib/nm-remote-connection.c +++ b/libnm-glib/nm-remote-connection.c @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2010 Red Hat, Inc. + * Copyright (C) 2007 - 2011 Red Hat, Inc. */ #include @@ -29,15 +29,11 @@ #include "nm-remote-connection.h" #include "nm-remote-connection-private.h" #include "nm-dbus-glib-types.h" -#include "nm-exported-connection-bindings.h" -#include "nm-settings-connection-interface.h" +#include "nm-settings-connection-bindings.h" #define NM_REMOTE_CONNECTION_BUS "bus" -static void settings_connection_interface_init (NMSettingsConnectionInterface *klass); - -G_DEFINE_TYPE_EXTENDED (NMRemoteConnection, nm_remote_connection, NM_TYPE_CONNECTION, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE, settings_connection_interface_init)) +G_DEFINE_TYPE (NMRemoteConnection, nm_remote_connection, NM_TYPE_CONNECTION) enum { PROP_0, @@ -47,10 +43,18 @@ enum { LAST_PROP }; +enum { + UPDATED, + REMOVED, + VISIBLE, + + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + typedef struct { NMRemoteConnection *self; - DBusGProxy *proxy; DBusGProxyCall *call; GFunc callback; gpointer user_data; @@ -59,10 +63,10 @@ typedef struct { typedef struct { DBusGConnection *bus; DBusGProxy *proxy; - DBusGProxy *secrets_proxy; GSList *calls; NMRemoteConnectionInitResult init_result; + gboolean visible; gboolean disposed; } NMRemoteConnectionPrivate; @@ -88,161 +92,184 @@ static void update_cb (DBusGProxy *proxy, GError *error, gpointer user_data) { RemoteCall *call = user_data; - NMSettingsConnectionInterfaceUpdateFunc func = (NMSettingsConnectionInterfaceUpdateFunc) call->callback; + NMRemoteConnectionCommitFunc func = (NMRemoteConnectionCommitFunc) call->callback; - (*func)(NM_SETTINGS_CONNECTION_INTERFACE (call->self), error, call->user_data); + (*func)(call->self, error, call->user_data); remote_call_complete (call->self, call); } -static gboolean -update (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceUpdateFunc callback, - gpointer user_data) +/** + * nm_remote_connection_commit_changes: + * @connection: the #NMRemoteConnection + * @callback: (scope async): a function to be called when the commit completes + * @user_data: caller-specific data to be passed to @callback + * + * Save any local changes to the settings and properties of this connection and + * save them in the settings service. + **/ +void +nm_remote_connection_commit_changes (NMRemoteConnection *self, + NMRemoteConnectionCommitFunc callback, + gpointer user_data) { - NMRemoteConnection *self = NM_REMOTE_CONNECTION (connection); - NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); + NMRemoteConnectionPrivate *priv; GHashTable *settings = NULL; RemoteCall *call; + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_REMOTE_CONNECTION (self)); + g_return_if_fail (callback != NULL); + + priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); + call = g_malloc0 (sizeof (RemoteCall)); call->self = self; call->callback = (GFunc) callback; call->user_data = user_data; - call->proxy = priv->proxy; - settings = nm_connection_to_hash (NM_CONNECTION (self)); + settings = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ALL); - call->call = org_freedesktop_NetworkManagerSettings_Connection_update_async (priv->proxy, - settings, - update_cb, - call); + call->call = org_freedesktop_NetworkManager_Settings_Connection_update_async (priv->proxy, + settings, + update_cb, + call); g_assert (call->call); priv->calls = g_slist_append (priv->calls, call); g_hash_table_destroy (settings); - - return TRUE; } static void delete_cb (DBusGProxy *proxy, GError *error, gpointer user_data) { RemoteCall *call = user_data; - NMSettingsConnectionInterfaceDeleteFunc func = (NMSettingsConnectionInterfaceDeleteFunc) call->callback; + NMRemoteConnectionDeleteFunc func = (NMRemoteConnectionDeleteFunc) call->callback; - (*func)(NM_SETTINGS_CONNECTION_INTERFACE (call->self), error, call->user_data); + (*func)(call->self, error, call->user_data); remote_call_complete (call->self, call); } -static gboolean -do_delete (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceDeleteFunc callback, - gpointer user_data) +/** + * nm_remote_connection_delete: + * @connection: the #NMRemoteConnection + * @callback: (scope async): a function to be called when the delete completes + * @user_data: caller-specific data to be passed to @callback + * + * Delete the connection. + **/ +void +nm_remote_connection_delete (NMRemoteConnection *self, + NMRemoteConnectionDeleteFunc callback, + gpointer user_data) { - NMRemoteConnection *self = NM_REMOTE_CONNECTION (connection); - NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); + NMRemoteConnectionPrivate *priv; RemoteCall *call; + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_REMOTE_CONNECTION (self)); + g_return_if_fail (callback != NULL); + + priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); + call = g_malloc0 (sizeof (RemoteCall)); call->self = self; call->callback = (GFunc) callback; call->user_data = user_data; - call->proxy = priv->proxy; - call->call = org_freedesktop_NetworkManagerSettings_Connection_delete_async (priv->proxy, - delete_cb, - call); + call->call = org_freedesktop_NetworkManager_Settings_Connection_delete_async (priv->proxy, + delete_cb, + call); g_assert (call->call); priv->calls = g_slist_append (priv->calls, call); - - return TRUE; } static void get_secrets_cb (DBusGProxy *proxy, GHashTable *secrets, GError *error, gpointer user_data) { RemoteCall *call = user_data; - NMSettingsConnectionInterfaceGetSecretsFunc func = (NMSettingsConnectionInterfaceGetSecretsFunc) call->callback; + NMRemoteConnectionGetSecretsFunc func = (NMRemoteConnectionGetSecretsFunc) call->callback; - (*func)(NM_SETTINGS_CONNECTION_INTERFACE (call->self), error ? NULL : secrets, error, call->user_data); + (*func)(call->self, error ? NULL : secrets, error, call->user_data); remote_call_complete (call->self, call); } -static gboolean -get_secrets (NMSettingsConnectionInterface *connection, - const char *setting_name, - const char **hints, - gboolean request_new, - NMSettingsConnectionInterfaceGetSecretsFunc callback, - gpointer user_data) +/** + * nm_remote_connection_get_secrets: + * @connection: the #NMRemoteConnection + * @setting_name: the #NMSetting object name to get secrets for + * @callback: (scope async): a function to be called when the update completes + * @user_data: caller-specific data to be passed to @callback + * + * Request the connection's secrets. + **/ +void +nm_remote_connection_get_secrets (NMRemoteConnection *self, + const char *setting_name, + NMRemoteConnectionGetSecretsFunc callback, + gpointer user_data) { - NMRemoteConnection *self = NM_REMOTE_CONNECTION (connection); - NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); + NMRemoteConnectionPrivate *priv; RemoteCall *call; + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_REMOTE_CONNECTION (self)); + g_return_if_fail (callback != NULL); + + priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); + call = g_malloc0 (sizeof (RemoteCall)); call->self = self; call->callback = (GFunc) callback; call->user_data = user_data; - call->proxy = priv->secrets_proxy; - call->call = org_freedesktop_NetworkManagerSettings_Connection_Secrets_get_secrets_async (priv->secrets_proxy, - setting_name, - hints, - request_new, - get_secrets_cb, - call); + call->call = org_freedesktop_NetworkManager_Settings_Connection_get_secrets_async (priv->proxy, + setting_name, + get_secrets_cb, + call); g_assert (call->call); priv->calls = g_slist_append (priv->calls, call); - - return TRUE; } /****************************************************************/ -static gboolean +static void replace_settings (NMRemoteConnection *self, GHashTable *new_settings) { GError *error = NULL; - if (!nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error)) { - g_warning ("%s: error updating %s connection %s settings: (%d) %s", + if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error)) + g_signal_emit (self, signals[UPDATED], 0, new_settings); + else { + g_warning ("%s: error updating connection %s settings: (%d) %s", __func__, - (nm_connection_get_scope (NM_CONNECTION (self)) == NM_CONNECTION_SCOPE_USER) ? "user" : "system", nm_connection_get_path (NM_CONNECTION (self)), error ? error->code : -1, (error && error->message) ? error->message : "(unknown)"); g_clear_error (&error); - return FALSE; - } - /* Emit update irregardless to let listeners figure out what to do with - * the connection; whether to delete / ignore it or not. - */ - nm_settings_connection_interface_emit_updated (NM_SETTINGS_CONNECTION_INTERFACE (self)); - return TRUE; + g_signal_emit (self, signals[REMOVED], 0); + } } static void -get_settings_cb (DBusGProxy *proxy, - GHashTable *new_settings, - GError *error, - gpointer user_data) +init_get_settings_cb (DBusGProxy *proxy, + GHashTable *new_settings, + GError *error, + gpointer user_data) { NMRemoteConnection *self = user_data; NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); if (error) { - g_warning ("%s: error getting %s connection %s settings: (%d) %s", - __func__, - (nm_connection_get_scope (NM_CONNECTION (self)) == NM_CONNECTION_SCOPE_USER) ? "user" : "system", - nm_connection_get_path (NM_CONNECTION (self)), - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); - g_error_free (error); - priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_ERROR; + /* Connection doesn't exist, or isn't visible to this user */ + if (dbus_g_error_has_name (error, "org.freedesktop.NetworkManager.Settings.PermissionDenied")) + priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_INVISIBLE; + else + priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_ERROR; + g_object_notify (G_OBJECT (self), NM_REMOTE_CONNECTION_INIT_RESULT); } else { + priv->visible = TRUE; replace_settings (self, new_settings); g_hash_table_destroy (new_settings); priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_SUCCESS; @@ -251,34 +278,64 @@ get_settings_cb (DBusGProxy *proxy, } static void -updated_cb (DBusGProxy *proxy, GHashTable *settings, gpointer user_data) +updated_get_settings_cb (DBusGProxy *proxy, + GHashTable *new_settings, + GError *error, + gpointer user_data) { - replace_settings (NM_REMOTE_CONNECTION (user_data), settings); + NMRemoteConnection *self = user_data; + NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); + + if (error) { + GHashTable *hash; + + /* Connection is no longer visible to this user. Let the settings + * service handle this via 'visible'. The settings service will emit + * the "removed" signal for us since it handles the lifetime of this + * object. + */ + hash = g_hash_table_new (g_str_hash, g_str_equal); + nm_connection_replace_settings (NM_CONNECTION (self), hash, NULL); + g_hash_table_destroy (hash); + + priv->visible = FALSE; + g_signal_emit (self, signals[VISIBLE], 0, FALSE); + } else { + replace_settings (self, new_settings); + g_hash_table_destroy (new_settings); + + /* Settings service will handle announcing the connection to clients */ + if (priv->visible == FALSE) { + priv->visible = TRUE; + g_signal_emit (self, signals[VISIBLE], 0, TRUE); + } + } +} + +static void +updated_cb (DBusGProxy *proxy, gpointer user_data) +{ + NMRemoteConnection *self = NM_REMOTE_CONNECTION (user_data); + NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); + + /* The connection got updated; request the replacement settings */ + org_freedesktop_NetworkManager_Settings_Connection_get_settings_async (priv->proxy, + updated_get_settings_cb, + self); } static void removed_cb (DBusGProxy *proxy, gpointer user_data) { - g_signal_emit_by_name (G_OBJECT (user_data), "removed"); + g_signal_emit (G_OBJECT (user_data), signals[REMOVED], 0); } /****************************************************************/ -static void -settings_connection_interface_init (NMSettingsConnectionInterface *klass) -{ - /* interface implementation */ - klass->update = update; - klass->delete = do_delete; - klass->get_secrets = get_secrets; -} - /** * nm_remote_connection_new: * @bus: a valid and connected D-Bus connection - * @scope: the Connection scope (either user or system) * @path: the D-Bus path of the connection as exported by the settings service - * indicated by @scope * * Creates a new object representing the remote connection. * @@ -286,7 +343,6 @@ settings_connection_interface_init (NMSettingsConnectionInterface *klass) **/ NMRemoteConnection * nm_remote_connection_new (DBusGConnection *bus, - NMConnectionScope scope, const char *path) { g_return_val_if_fail (bus != NULL, NULL); @@ -294,7 +350,6 @@ nm_remote_connection_new (DBusGConnection *bus, return (NMRemoteConnection *) g_object_new (NM_TYPE_REMOTE_CONNECTION, NM_REMOTE_CONNECTION_BUS, bus, - NM_CONNECTION_SCOPE, scope, NM_CONNECTION_PATH, path, NULL); } @@ -306,7 +361,6 @@ constructor (GType type, { GObject *object; NMRemoteConnectionPrivate *priv; - const char *service = NM_DBUS_SERVICE_USER_SETTINGS; object = G_OBJECT_CLASS (nm_remote_connection_parent_class)->constructor (type, n_construct_params, construct_params); if (!object) @@ -316,32 +370,22 @@ constructor (GType type, g_assert (priv->bus); g_assert (nm_connection_get_path (NM_CONNECTION (object))); - if (nm_connection_get_scope (NM_CONNECTION (object)) == NM_CONNECTION_SCOPE_SYSTEM) - service = NM_DBUS_SERVICE_SYSTEM_SETTINGS; - priv->proxy = dbus_g_proxy_new_for_name (priv->bus, - service, + NM_DBUS_SERVICE, nm_connection_get_path (NM_CONNECTION (object)), NM_DBUS_IFACE_SETTINGS_CONNECTION); g_assert (priv->proxy); dbus_g_proxy_set_default_timeout (priv->proxy, G_MAXINT); - priv->secrets_proxy = dbus_g_proxy_new_for_name (priv->bus, - service, - nm_connection_get_path (NM_CONNECTION (object)), - NM_DBUS_IFACE_SETTINGS_CONNECTION_SECRETS); - g_assert (priv->secrets_proxy); - dbus_g_proxy_set_default_timeout (priv->secrets_proxy, G_MAXINT); - - dbus_g_proxy_add_signal (priv->proxy, "Updated", DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->proxy, "Updated", G_TYPE_INVALID); dbus_g_proxy_connect_signal (priv->proxy, "Updated", G_CALLBACK (updated_cb), object, NULL); dbus_g_proxy_add_signal (priv->proxy, "Removed", G_TYPE_INVALID); dbus_g_proxy_connect_signal (priv->proxy, "Removed", G_CALLBACK (removed_cb), object, NULL); - org_freedesktop_NetworkManagerSettings_Connection_get_settings_async (priv->proxy, - get_settings_cb, - object); + org_freedesktop_NetworkManager_Settings_Connection_get_settings_async (priv->proxy, + init_get_settings_cb, + object); return object; } @@ -397,7 +441,6 @@ dispose (GObject *object) remote_call_complete (self, priv->calls->data); g_object_unref (priv->proxy); - g_object_unref (priv->secrets_proxy); dbus_g_connection_unref (priv->bus); } @@ -435,5 +478,31 @@ nm_remote_connection_class_init (NMRemoteConnectionClass *remote_class) NM_REMOTE_CONNECTION_INIT_RESULT_ERROR, NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN, G_PARAM_READABLE)); -} + /* Signals */ + signals[UPDATED] = + g_signal_new (NM_REMOTE_CONNECTION_UPDATED, + G_TYPE_FROM_CLASS (remote_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMRemoteConnectionClass, updated), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[REMOVED] = + g_signal_new (NM_REMOTE_CONNECTION_REMOVED, + G_TYPE_FROM_CLASS (remote_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMRemoteConnectionClass, removed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[VISIBLE] = + g_signal_new ("visible", + G_TYPE_FROM_CLASS (remote_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); +} diff --git a/libnm-glib/nm-remote-connection.h b/libnm-glib/nm-remote-connection.h index ef5452f99f..809927ea4c 100644 --- a/libnm-glib/nm-remote-connection.h +++ b/libnm-glib/nm-remote-connection.h @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2009 Red Hat, Inc. + * Copyright (C) 2007 - 2011 Red Hat, Inc. */ #ifndef __NM_REMOTE_CONNECTION_H__ @@ -38,6 +38,9 @@ G_BEGIN_DECLS #define NM_IS_REMOTE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_REMOTE_CONNECTION)) #define NM_REMOTE_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_REMOTE_CONNECTION, NMRemoteConnectionClass)) +#define NM_REMOTE_CONNECTION_UPDATED "updated" +#define NM_REMOTE_CONNECTION_REMOVED "removed" + typedef struct { NMConnection parent; } NMRemoteConnection; @@ -45,6 +48,12 @@ typedef struct { typedef struct { NMConnectionClass parent_class; + /* Signals */ + void (*updated) (NMRemoteConnection *connection, + GHashTable *new_settings); + + void (*removed) (NMRemoteConnection *connection); + /* Padding for future expansion */ void (*_reserved1) (void); void (*_reserved2) (void); @@ -54,11 +63,36 @@ typedef struct { void (*_reserved6) (void); } NMRemoteConnectionClass; +typedef void (*NMRemoteConnectionCommitFunc) (NMRemoteConnection *connection, + GError *error, + gpointer user_data); + +typedef void (*NMRemoteConnectionDeleteFunc) (NMRemoteConnection *connection, + GError *error, + gpointer user_data); + +typedef void (*NMRemoteConnectionGetSecretsFunc) (NMRemoteConnection *connection, + GHashTable *secrets, + GError *error, + gpointer user_data); + GType nm_remote_connection_get_type (void); NMRemoteConnection *nm_remote_connection_new (DBusGConnection *bus, - NMConnectionScope scope, const char *path); + +void nm_remote_connection_commit_changes (NMRemoteConnection *connection, + NMRemoteConnectionCommitFunc callback, + gpointer user_data); + +void nm_remote_connection_delete (NMRemoteConnection *connection, + NMRemoteConnectionDeleteFunc callback, + gpointer user_data); + +void nm_remote_connection_get_secrets (NMRemoteConnection *connection, + const char *setting_name, + NMRemoteConnectionGetSecretsFunc callback, + gpointer user_data); G_END_DECLS #endif /* __NM_REMOTE_CONNECTION__ */ diff --git a/libnm-glib/nm-remote-settings-system.c b/libnm-glib/nm-remote-settings-system.c deleted file mode 100644 index 95098c7e60..0000000000 --- a/libnm-glib/nm-remote-settings-system.c +++ /dev/null @@ -1,375 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * libnm_glib -- Access network status & information from glib applications - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2009 - 2010 Red Hat, Inc. - */ - -#include -#include -#include - -#include "nm-marshal.h" -#include "nm-dbus-glib-types.h" -#include "nm-remote-settings-system.h" -#include "nm-settings-system-bindings.h" -#include "nm-settings-system-interface.h" - -static void settings_system_interface_init (NMSettingsSystemInterface *klass); - -G_DEFINE_TYPE_EXTENDED (NMRemoteSettingsSystem, nm_remote_settings_system, NM_TYPE_REMOTE_SETTINGS, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_SYSTEM_INTERFACE, settings_system_interface_init)) - -#define NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_REMOTE_SETTINGS_SYSTEM, NMRemoteSettingsSystemPrivate)) - -typedef struct { - DBusGProxy *proxy; - DBusGProxy *props_proxy; - - char *hostname; - gboolean can_modify; - - NMSettingsSystemPermissions permissions; - gboolean have_permissions; - - gboolean disposed; -} NMRemoteSettingsSystemPrivate; - -static void -properties_changed_cb (DBusGProxy *proxy, - GHashTable *properties, - gpointer user_data) -{ - NMRemoteSettingsSystem *self = NM_REMOTE_SETTINGS_SYSTEM (user_data); - NMRemoteSettingsSystemPrivate *priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (self); - GHashTableIter iter; - gpointer key, tmp; - - g_hash_table_iter_init (&iter, properties); - while (g_hash_table_iter_next (&iter, &key, &tmp)) { - GValue *value = tmp; - - if (!strcmp ((const char *) key, "Hostname")) { - g_free (priv->hostname); - priv->hostname = g_value_dup_string (value); - g_object_notify (G_OBJECT (self), NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME); - } - - if (!strcmp ((const char *) key, "CanModify")) { - priv->can_modify = g_value_get_boolean (value); - g_object_notify (G_OBJECT (self), NM_SETTINGS_SYSTEM_INTERFACE_CAN_MODIFY); - } - } -} - -static void -get_all_cb (DBusGProxy *proxy, - DBusGProxyCall *call, - gpointer user_data) -{ - NMRemoteSettingsSystem *self = NM_REMOTE_SETTINGS_SYSTEM (user_data); - GHashTable *props = NULL; - GError *error = NULL; - - if (!dbus_g_proxy_end_call (proxy, call, &error, - DBUS_TYPE_G_MAP_OF_VARIANT, &props, - G_TYPE_INVALID)) { - /* Don't warn when the call times out because the settings service can't - * be activated or whatever. - */ - if (!(error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NO_REPLY)) { - g_warning ("%s: couldn't retrieve system settings properties: (%d) %s.", - __func__, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); - } - g_clear_error (&error); - return; - } - - properties_changed_cb (NULL, props, self); - g_hash_table_destroy (props); -} - -typedef struct { - NMSettingsSystemInterface *settings; - NMSettingsSystemSaveHostnameFunc callback; - gpointer callback_data; -} SaveHostnameInfo; - -static void -save_hostname_cb (DBusGProxy *proxy, - DBusGProxyCall *call, - gpointer user_data) -{ - SaveHostnameInfo *info = user_data; - GError *error = NULL; - - dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); - info->callback (info->settings, error, info->callback_data); - g_clear_error (&error); -} - -static gboolean -save_hostname (NMSettingsSystemInterface *settings, - const char *hostname, - NMSettingsSystemSaveHostnameFunc callback, - gpointer user_data) -{ - NMRemoteSettingsSystem *self = NM_REMOTE_SETTINGS_SYSTEM (settings); - NMRemoteSettingsSystemPrivate *priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (self); - SaveHostnameInfo *info; - - info = g_malloc0 (sizeof (SaveHostnameInfo)); - info->settings = settings; - info->callback = callback; - info->callback_data = user_data; - - dbus_g_proxy_begin_call (priv->proxy, "SaveHostname", - save_hostname_cb, - info, - g_free, - G_TYPE_STRING, hostname ? hostname : "", - G_TYPE_INVALID); - return TRUE; -} - -typedef struct { - NMSettingsSystemInterface *settings; - NMSettingsSystemGetPermissionsFunc callback; - gpointer callback_data; -} GetPermissionsInfo; - -static void -get_permissions_cb (DBusGProxy *proxy, - DBusGProxyCall *call, - gpointer user_data) -{ - GetPermissionsInfo *info = user_data; - NMRemoteSettingsSystem *self = NM_REMOTE_SETTINGS_SYSTEM (info->settings); - NMRemoteSettingsSystemPrivate *priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (self); - NMSettingsSystemPermissions permissions = NM_SETTINGS_SYSTEM_PERMISSION_NONE; - GError *error = NULL; - - dbus_g_proxy_end_call (proxy, call, &error, - G_TYPE_UINT, &permissions, - G_TYPE_INVALID); - priv->permissions = permissions; - priv->have_permissions = !error; - info->callback (info->settings, permissions, error, info->callback_data); - g_clear_error (&error); -} - -static gboolean -get_permissions (NMSettingsSystemInterface *settings, - NMSettingsSystemGetPermissionsFunc callback, - gpointer user_data) -{ - NMRemoteSettingsSystemPrivate *priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (settings); - GetPermissionsInfo *info; - - /* Skip D-Bus if we already have permissions */ - if (priv->have_permissions) { - callback (settings, priv->permissions, NULL, user_data); - return TRUE; - } - - /* Otherwise fetch them from NM */ - info = g_malloc0 (sizeof (GetPermissionsInfo)); - info->settings = settings; - info->callback = callback; - info->callback_data = user_data; - - dbus_g_proxy_begin_call (priv->proxy, "GetPermissions", - get_permissions_cb, - info, - g_free, - G_TYPE_INVALID); - return TRUE; -} - -static void -check_permissions_cb (DBusGProxy *proxy, gpointer user_data) -{ - NMRemoteSettingsSystem *self = NM_REMOTE_SETTINGS_SYSTEM (user_data); - NMRemoteSettingsSystemPrivate *priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (self); - - /* Permissions need to be re-fetched */ - priv->have_permissions = FALSE; - g_signal_emit_by_name (self, NM_SETTINGS_SYSTEM_INTERFACE_CHECK_PERMISSIONS); -} - -/****************************************************************/ - -static void -settings_system_interface_init (NMSettingsSystemInterface *klass) -{ - /* interface implementation */ - klass->save_hostname = save_hostname; - klass->get_permissions = get_permissions; -} - -/** - * nm_remote_settings_system_new: - * @bus: a valid and connected D-Bus connection - * - * Creates a new object representing the remote system settings service. - * - * Returns: the new remote system settings object on success, or %NULL on failure - **/ -NMRemoteSettingsSystem * -nm_remote_settings_system_new (DBusGConnection *bus) -{ - g_return_val_if_fail (bus != NULL, NULL); - - return (NMRemoteSettingsSystem *) g_object_new (NM_TYPE_REMOTE_SETTINGS_SYSTEM, - NM_REMOTE_SETTINGS_BUS, bus, - NM_REMOTE_SETTINGS_SCOPE, NM_CONNECTION_SCOPE_SYSTEM, - NULL); -} - -static void -nm_remote_settings_system_init (NMRemoteSettingsSystem *self) -{ -} - -static GObject * -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) -{ - GObject *object; - NMRemoteSettingsSystemPrivate *priv; - DBusGConnection *bus = NULL; - - object = G_OBJECT_CLASS (nm_remote_settings_system_parent_class)->constructor (type, n_construct_params, construct_params); - if (!object) - return NULL; - - priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (object); - - g_object_get (G_OBJECT (object), NM_REMOTE_SETTINGS_BUS, &bus, NULL); - g_assert (bus); - - /* D-Bus properties proxy */ - priv->props_proxy = dbus_g_proxy_new_for_name (bus, - NM_DBUS_SERVICE_SYSTEM_SETTINGS, - NM_DBUS_PATH_SETTINGS, - "org.freedesktop.DBus.Properties"); - g_assert (priv->props_proxy); - - /* System settings proxy */ - priv->proxy = dbus_g_proxy_new_for_name (bus, - NM_DBUS_SERVICE_SYSTEM_SETTINGS, - NM_DBUS_PATH_SETTINGS, - NM_DBUS_IFACE_SETTINGS_SYSTEM); - g_assert (priv->proxy); - dbus_g_proxy_set_default_timeout (priv->proxy, G_MAXINT); - - dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, - DBUS_TYPE_G_MAP_OF_VARIANT, - G_TYPE_INVALID); - dbus_g_proxy_add_signal (priv->proxy, "PropertiesChanged", - DBUS_TYPE_G_MAP_OF_VARIANT, - G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "PropertiesChanged", - G_CALLBACK (properties_changed_cb), - object, - NULL); - - /* Monitor for permissions changes */ - dbus_g_proxy_add_signal (priv->proxy, "CheckPermissions", G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "CheckPermissions", - G_CALLBACK (check_permissions_cb), - object, - NULL); - - /* Get properties */ - dbus_g_proxy_begin_call (priv->props_proxy, "GetAll", - get_all_cb, - object, - NULL, - G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS_SYSTEM, - G_TYPE_INVALID); - - dbus_g_connection_unref (bus); - - return object; -} - -static void -dispose (GObject *object) -{ - NMRemoteSettingsSystemPrivate *priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (object); - - if (priv->disposed) - return; - - priv->disposed = TRUE; - - g_free (priv->hostname); - - g_object_unref (priv->props_proxy); - g_object_unref (priv->proxy); - - G_OBJECT_CLASS (nm_remote_settings_system_parent_class)->dispose (object); -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMRemoteSettingsSystemPrivate *priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (object); - - switch (prop_id) { - case NM_SETTINGS_SYSTEM_INTERFACE_PROP_HOSTNAME: - g_value_set_string (value, priv->hostname); - break; - case NM_SETTINGS_SYSTEM_INTERFACE_PROP_CAN_MODIFY: - g_value_set_boolean (value, priv->can_modify); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -nm_remote_settings_system_class_init (NMRemoteSettingsSystemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NMRemoteSettingsSystemPrivate)); - - /* Virtual methods */ - object_class->constructor = constructor; - object_class->get_property = get_property; - object_class->dispose = dispose; - - /* Properties */ - g_object_class_override_property (object_class, - NM_SETTINGS_SYSTEM_INTERFACE_PROP_HOSTNAME, - NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME); - - g_object_class_override_property (object_class, - NM_SETTINGS_SYSTEM_INTERFACE_PROP_CAN_MODIFY, - NM_SETTINGS_SYSTEM_INTERFACE_CAN_MODIFY); -} - diff --git a/libnm-glib/nm-remote-settings-system.h b/libnm-glib/nm-remote-settings-system.h deleted file mode 100644 index b518227331..0000000000 --- a/libnm-glib/nm-remote-settings-system.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * libnm_glib -- Access network status & information from glib applications - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2009 Red Hat, Inc. - */ - -#ifndef NM_REMOTE_SETTINGS_SYSTEM_H -#define NM_REMOTE_SETTINGS_SYSTEM_H - -#include -#include - -#include "nm-remote-settings.h" -#include "nm-settings-system-interface.h" - -G_BEGIN_DECLS - -#define NM_TYPE_REMOTE_SETTINGS_SYSTEM (nm_remote_settings_system_get_type ()) -#define NM_REMOTE_SETTINGS_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_REMOTE_SETTINGS_SYSTEM, NMRemoteSettingsSystem)) -#define NM_REMOTE_SETTINGS_SYSTEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_REMOTE_SETTINGS_SYSTEM, NMRemoteSettingsSystemClass)) -#define NM_IS_REMOTE_SETTINGS_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_REMOTE_SETTINGS_SYSTEM)) -#define NM_IS_REMOTE_SETTINGS_SYSTEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_REMOTE_SETTINGS_SYSTEM)) -#define NM_REMOTE_SETTINGS_SYSTEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_REMOTE_SETTINGS_SYSTEM, NMRemoteSettingsSystemClass)) - -typedef struct { - NMRemoteSettings parent; -} NMRemoteSettingsSystem; - -typedef struct { - NMRemoteSettingsClass parent; - - /* Padding for future expansion */ - void (*_reserved1) (void); - void (*_reserved2) (void); - void (*_reserved3) (void); - void (*_reserved4) (void); - void (*_reserved5) (void); - void (*_reserved6) (void); -} NMRemoteSettingsSystemClass; - -GType nm_remote_settings_system_get_type (void); - -NMRemoteSettingsSystem *nm_remote_settings_system_new (DBusGConnection *bus); - -G_END_DECLS - -#endif /* NM_REMOTE_SETTINGS_SYSTEM_H */ diff --git a/libnm-glib/nm-remote-settings.c b/libnm-glib/nm-remote-settings.c index 6a9a1d71e9..8bfa0d924b 100644 --- a/libnm-glib/nm-remote-settings.c +++ b/libnm-glib/nm-remote-settings.c @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2011 Red Hat, Inc. */ #include @@ -26,26 +26,30 @@ #include #include "nm-marshal.h" +#include "nm-dbus-glib-types.h" #include "nm-remote-settings.h" #include "nm-settings-bindings.h" -#include "nm-settings-interface.h" #include "nm-remote-connection-private.h" -static void settings_interface_init (NMSettingsInterface *class); - -G_DEFINE_TYPE_EXTENDED (NMRemoteSettings, nm_remote_settings, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_INTERFACE, settings_interface_init)) +G_DEFINE_TYPE (NMRemoteSettings, nm_remote_settings, G_TYPE_OBJECT) #define NM_REMOTE_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_REMOTE_SETTINGS, NMRemoteSettingsPrivate)) typedef struct { DBusGConnection *bus; - NMConnectionScope scope; DBusGProxy *proxy; GHashTable *connections; GHashTable *pending; /* Connections we don't have settings for yet */ gboolean service_running; + guint32 init_left; + + /* AddConnectionInfo objects that are waiting for the connection to become initialized */ + GSList *add_list; + + DBusGProxy *props_proxy; + char *hostname; + gboolean can_modify; DBusGProxy *dbus_proxy; @@ -57,15 +61,124 @@ typedef struct { enum { PROP_0, PROP_BUS, - PROP_SCOPE, PROP_SERVICE_RUNNING, + PROP_HOSTNAME, + PROP_CAN_MODIFY, LAST_PROP }; -static NMSettingsConnectionInterface * -get_connection_by_path (NMSettingsInterface *settings, const char *path) +/* Signals */ +enum { + NEW_CONNECTION, + CONNECTIONS_READ, + + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +/**********************************************************************/ + +/** + * nm_remote_settings_error_quark: + * + * Registers an error quark for #NMRemoteSettings if necessary. + * + * Returns: the error quark used for #NMRemoteSettings errors. + **/ +GQuark +nm_remote_settings_error_quark (void) { + static GQuark quark; + + if (G_UNLIKELY (!quark)) + quark = g_quark_from_static_string ("nm-remote-settings-error-quark"); + return quark; +} + +/* This should really be standard. */ +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +nm_remote_settings_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + ENUM_ENTRY (NM_REMOTE_SETTINGS_ERROR_UNKNOWN, "UnknownError"), + ENUM_ENTRY (NM_REMOTE_SETTINGS_ERROR_CONNECTION_REMOVED, "ConnectionRemoved"), + ENUM_ENTRY (NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE, "ConnectionUnavailable"), + { 0, 0, 0 } + }; + etype = g_enum_register_static ("NMRemoteSettingsError", values); + } + return etype; +} + +/**********************************************************************/ + +typedef struct { + NMRemoteSettings *self; + NMRemoteSettingsAddConnectionFunc callback; + gpointer callback_data; + NMRemoteConnection *connection; +} AddConnectionInfo; + +static AddConnectionInfo * +add_connection_info_find (NMRemoteSettings *self, NMRemoteConnection *connection) +{ + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + for (iter = priv->add_list; iter; iter = g_slist_next (iter)) { + AddConnectionInfo *info = iter->data; + + if (info->connection == connection) + return info; + } + + return NULL; +} + +static void +add_connection_info_dispose (NMRemoteSettings *self, AddConnectionInfo *info) +{ + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + + priv->add_list = g_slist_remove (priv->add_list, info); + + g_free (info); +} + +static void +add_connection_info_complete (NMRemoteSettings *self, + AddConnectionInfo *info, + GError *error) +{ + g_return_if_fail (info != NULL); + + info->callback (info->self, error ? NULL : info->connection, error, info->callback_data); + add_connection_info_dispose (self, info); +} + +/** + * nm_remote_settings_get_connection_by_path: + * @settings: the %NMRemoteSettings + * @path: the D-Bus object path of the remote connection + * + * Returns the %NMRemoteConnection representing the connection at @path. + * + * Returns: (transfer none): the remote connection object on success, or NULL if the object was + * not known + **/ +NMRemoteConnection * +nm_remote_settings_get_connection_by_path (NMRemoteSettings *settings, const char *path) +{ + g_return_val_if_fail (settings != NULL, NULL); + g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL); + g_return_val_if_fail (path != NULL, NULL); + return g_hash_table_lookup (NM_REMOTE_SETTINGS_GET_PRIVATE (settings)->connections, path); } @@ -74,13 +187,67 @@ connection_removed_cb (NMRemoteConnection *remote, gpointer user_data) { NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + AddConnectionInfo *addinfo; + GError *add_error; const char *path; + /* Might have been removed while it was waiting to be initialized */ + addinfo = add_connection_info_find (self, remote); + if (addinfo) { + add_error = g_error_new_literal (NM_REMOTE_SETTINGS_ERROR, + NM_REMOTE_SETTINGS_ERROR_CONNECTION_REMOVED, + "Connection removed before it was initialized"); + add_connection_info_complete (self, addinfo, add_error); + g_error_free (add_error); + } + path = nm_connection_get_path (NM_CONNECTION (remote)); g_hash_table_remove (priv->connections, path); g_hash_table_remove (priv->pending, path); } +static void +connection_visible_cb (NMRemoteConnection *remote, + gboolean visible, + gpointer user_data) +{ + NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + const char *path; + + path = nm_connection_get_path (NM_CONNECTION (remote)); + g_assert (path); + + /* When a connection becomes invisible, we put it back in the pending + * hash until it becomes visible again. When it does, we move it back to + * the normal connections hash. + */ + if (visible) { + /* Connection visible to this user again */ + if (g_hash_table_lookup (priv->pending, path)) { + /* Move connection from pending to visible hash; emit for clients */ + g_hash_table_insert (priv->connections, g_strdup (path), g_object_ref (remote)); + g_hash_table_remove (priv->pending, path); + g_signal_emit (self, signals[NEW_CONNECTION], 0, remote); + } + } else { + /* Connection now invisible to this user */ + if (g_hash_table_lookup (priv->connections, path)) { + /* Move connection to pending hash and wait for it to become visible again */ + g_hash_table_insert (priv->pending, g_strdup (path), g_object_ref (remote)); + g_hash_table_remove (priv->connections, path); + + /* Signal to clients that the connection is gone; but we have to + * block our connection removed handler so we don't destroy + * the connection when the signal is emitted. + */ + g_signal_handlers_block_by_func (remote, connection_removed_cb, self); + g_signal_emit_by_name (remote, NM_REMOTE_CONNECTION_REMOVED); + g_signal_handlers_unblock_by_func (remote, connection_removed_cb, self); + } + } +} + static void connection_init_result_cb (NMRemoteConnection *remote, GParamSpec *pspec, @@ -89,7 +256,10 @@ connection_init_result_cb (NMRemoteConnection *remote, NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); guint32 init_result = NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN; + AddConnectionInfo *addinfo; const char *path; + GError *add_error = NULL; + gboolean remove_from_pending = TRUE; /* Disconnect from the init-result signal just to be safe */ g_signal_handlers_disconnect_matched (remote, @@ -106,6 +276,8 @@ connection_init_result_cb (NMRemoteConnection *remote, NM_REMOTE_CONNECTION_INIT_RESULT, &init_result, NULL); + addinfo = add_connection_info_find (self, remote); + switch (init_result) { case NM_REMOTE_CONNECTION_INIT_RESULT_SUCCESS: /* ref it when adding to ->connections, since removing it from ->pending @@ -113,36 +285,69 @@ connection_init_result_cb (NMRemoteConnection *remote, */ g_hash_table_insert (priv->connections, g_strdup (path), g_object_ref (remote)); + /* If there's a pending AddConnection request, complete that here before + * signaling new-connection. + */ + if (addinfo) + add_connection_info_complete (self, addinfo, NULL); + /* Finally, let users know of the new connection now that it has all * its settings and is valid. */ - g_signal_emit_by_name (self, "new-connection", remote); + g_signal_emit (self, signals[NEW_CONNECTION], 0, remote); break; + case NM_REMOTE_CONNECTION_INIT_RESULT_INVISIBLE: + remove_from_pending = FALSE; + /* fall through */ case NM_REMOTE_CONNECTION_INIT_RESULT_ERROR: + /* Complete pending AddConnection callbacks */ + if (addinfo) { + add_error = g_error_new_literal (NM_REMOTE_SETTINGS_ERROR, + NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE, + "Connection not visible or not available"); + add_connection_info_complete (self, addinfo, add_error); + g_error_free (add_error); + } + break; default: break; } - g_hash_table_remove (priv->pending, path); + if (remove_from_pending) + g_hash_table_remove (priv->pending, path); /* Let listeners know that all connections have been found */ - if (!g_hash_table_size (priv->pending)) - g_signal_emit_by_name (self, NM_SETTINGS_INTERFACE_CONNECTIONS_READ); + priv->init_left--; + if (priv->init_left == 0) + g_signal_emit (self, signals[CONNECTIONS_READ], 0); } -static void +static NMRemoteConnection * new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) { NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); - NMRemoteConnection *connection; + NMRemoteConnection *connection = NULL; - connection = nm_remote_connection_new (priv->bus, priv->scope, path); + /* Make double-sure we don't already have it */ + connection = g_hash_table_lookup (priv->pending, path); + if (connection) + return connection; + connection = g_hash_table_lookup (priv->connections, path); + if (connection) + return connection; + + /* Create a new connection object for it */ + connection = nm_remote_connection_new (priv->bus, path); if (connection) { - g_signal_connect (connection, "removed", + g_signal_connect (connection, NM_REMOTE_CONNECTION_REMOVED, G_CALLBACK (connection_removed_cb), self); + g_signal_connect (connection, "visible", + G_CALLBACK (connection_visible_cb), + self); + g_signal_connect (connection, "notify::" NM_REMOTE_CONNECTION_INIT_RESULT, G_CALLBACK (connection_init_result_cb), self); @@ -153,6 +358,7 @@ new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) */ g_hash_table_insert (priv->pending, g_strdup (path), connection); } + return connection; } static void @@ -162,45 +368,38 @@ fetch_connections_done (DBusGProxy *proxy, gpointer user_data) { NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); - NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); int i; if (error) { - gboolean is_spawn_error = FALSE; - - /* Don't warn if the user settings service wasn't running since that's - * just annoying when running headless. - */ - if ( g_error_matches (error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN) - || g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NAME_HAS_NO_OWNER)) - is_spawn_error = TRUE; - - if (!is_spawn_error || priv->scope == NM_CONNECTION_SCOPE_SYSTEM) { - g_warning ("%s: error fetching %s connections: (%d) %s.", - __func__, - priv->scope == NM_CONNECTION_SCOPE_USER ? "user" : "system", + /* Ignore settings service spawn errors */ + if ( !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN) + && !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NAME_HAS_NO_OWNER)) { + g_warning ("%s: error fetching connections: (%d) %s.", + __func__, error->code, error->message ? error->message : "(unknown)"); } g_clear_error (&error); /* We tried to read connections and failed */ - g_signal_emit_by_name (self, NM_SETTINGS_INTERFACE_CONNECTIONS_READ); + g_signal_emit (self, signals[CONNECTIONS_READ], 0); return; } /* Let listeners know we are done getting connections */ - if (connections->len == 0) { - g_signal_emit_by_name (self, NM_SETTINGS_INTERFACE_CONNECTIONS_READ); - return; + if (connections->len == 0) + g_signal_emit (self, signals[CONNECTIONS_READ], 0); + else { + priv->init_left = connections->len; + for (i = 0; i < connections->len; i++) { + char *path = g_ptr_array_index (connections, i); + + new_connection_cb (proxy, path, user_data); + g_free (path); + } } - for (i = 0; connections && (i < connections->len); i++) { - char *path = g_ptr_array_index (connections, i); - - new_connection_cb (proxy, path, user_data); - g_free (path); - } g_ptr_array_free (connections, TRUE); } @@ -212,20 +411,32 @@ fetch_connections (gpointer user_data) priv->fetch_id = 0; - org_freedesktop_NetworkManagerSettings_list_connections_async (priv->proxy, - fetch_connections_done, - self); + org_freedesktop_NetworkManager_Settings_list_connections_async (priv->proxy, + fetch_connections_done, + self); return FALSE; } -static GSList * -list_connections (NMSettingsInterface *settings) +/** + * nm_remote_settings_list_connections: + * @settings: the %NMRemoteSettings + * + * Returns: (transfer container) (element-type NMClient.RemoteConnection): all connections in the remote settings service, represented as + * %NMRemoteConnection instances + **/ +GSList * +nm_remote_settings_list_connections (NMRemoteSettings *settings) { - NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings); + NMRemoteSettingsPrivate *priv; GSList *list = NULL; GHashTableIter iter; gpointer value; + g_return_val_if_fail (settings != NULL, NULL); + g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL); + + priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings); + g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, NULL, &value)) list = g_slist_prepend (list, NM_REMOTE_CONNECTION (value)); @@ -233,53 +444,76 @@ list_connections (NMSettingsInterface *settings) return list; } -typedef struct { - NMSettingsInterface *self; - NMSettingsAddConnectionFunc callback; - gpointer callback_data; -} AddConnectionInfo; - static void add_connection_done (DBusGProxy *proxy, + char *path, GError *error, gpointer user_data) { AddConnectionInfo *info = user_data; - info->callback (info->self, error, info->callback_data); - g_free (info); + if (error) { + add_connection_info_complete (info->self, info, error); + } else { + info->connection = new_connection_cb (proxy, path, info->self); + g_assert (info->connection); + /* Wait until this connection is fully initialized before calling the callback */ + } + + g_free (path); } -static gboolean -add_connection (NMSettingsInterface *settings, - NMConnection *connection, - NMSettingsAddConnectionFunc callback, - gpointer user_data) +/** + * nm_remote_settings_add_connection: + * @settings: the %NMRemoteSettings + * @connection: the connection to add. Note that this object's settings will be + * added, not the object itself + * @callback: (scope async): callback to be called when the add operation completes + * @user_data: caller-specific data passed to @callback + * + * Requests that the remote settings service add the given settings to a new + * connection. + * + * Returns: TRUE if the request was successful, FALSE if it failed + **/ +gboolean +nm_remote_settings_add_connection (NMRemoteSettings *settings, + NMConnection *connection, + NMRemoteSettingsAddConnectionFunc callback, + gpointer user_data) { - NMRemoteSettings *self = NM_REMOTE_SETTINGS (settings); - NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + NMRemoteSettingsPrivate *priv; AddConnectionInfo *info; GHashTable *new_settings; + g_return_val_if_fail (settings != NULL, FALSE); + g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE); + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail (callback != NULL, FALSE); + + priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings); + info = g_malloc0 (sizeof (AddConnectionInfo)); info->self = settings; info->callback = callback; info->callback_data = user_data; - new_settings = nm_connection_to_hash (connection); - org_freedesktop_NetworkManagerSettings_add_connection_async (priv->proxy, - new_settings, - add_connection_done, - info); + new_settings = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL); + org_freedesktop_NetworkManager_Settings_add_connection_async (priv->proxy, + new_settings, + add_connection_done, + info); g_hash_table_destroy (new_settings); + + priv->add_list = g_slist_append (priv->add_list, info); + return TRUE; } -static gboolean -remove_connections (gpointer user_data) +static void +clear_one_hash (GHashTable *table) { - NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); - NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); GHashTableIter iter; gpointer value; GSList *list = NULL, *list_iter; @@ -289,18 +523,90 @@ remove_connections (gpointer user_data) * that explicitly removes the the connection from the hash table somewhere * else. */ - g_hash_table_iter_init (&iter, priv->connections); + g_hash_table_iter_init (&iter, table); while (g_hash_table_iter_next (&iter, NULL, &value)) list = g_slist_prepend (list, NM_REMOTE_CONNECTION (value)); for (list_iter = list; list_iter; list_iter = g_slist_next (list_iter)) - g_signal_emit_by_name (NM_REMOTE_CONNECTION (list_iter->data), "removed"); + g_signal_emit_by_name (NM_REMOTE_CONNECTION (list_iter->data), NM_REMOTE_CONNECTION_REMOVED); g_slist_free (list); - g_hash_table_remove_all (priv->connections); + g_hash_table_remove_all (table); +} + +static gboolean +remove_connections (gpointer user_data) +{ + NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + + clear_one_hash (priv->pending); + clear_one_hash (priv->connections); return FALSE; } +typedef struct { + NMRemoteSettings *settings; + NMRemoteSettingsSaveHostnameFunc callback; + gpointer callback_data; +} SaveHostnameInfo; + +static void +save_hostname_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) +{ + SaveHostnameInfo *info = user_data; + GError *error = NULL; + + dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); + info->callback (info->settings, error, info->callback_data); + g_clear_error (&error); +} + +/** + * nm_remote_settings_save_hostname: + * @settings: the %NMRemoteSettings + * @hostname: the new persistent hostname to set, or NULL to clear any existing + * persistent hostname + * @callback: (scope async): callback to be called when the hostname operation completes + * @user_data: caller-specific data passed to @callback + * + * Requests that the machine's persistent hostname be set to the specified value + * or cleared. + * + * Returns: TRUE if the request was successful, FALSE if it failed + **/ +gboolean +nm_remote_settings_save_hostname (NMRemoteSettings *settings, + const char *hostname, + NMRemoteSettingsSaveHostnameFunc callback, + gpointer user_data) +{ + NMRemoteSettingsPrivate *priv; + SaveHostnameInfo *info; + + g_return_val_if_fail (settings != NULL, FALSE); + g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE); + g_return_val_if_fail (hostname != NULL, FALSE); + g_return_val_if_fail (callback != NULL, FALSE); + + priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings); + + info = g_malloc0 (sizeof (SaveHostnameInfo)); + info->settings = settings; + info->callback = callback; + info->callback_data = user_data; + + dbus_g_proxy_begin_call (priv->proxy, "SaveHostname", + save_hostname_cb, + info, + g_free, + G_TYPE_STRING, hostname ? hostname : "", + G_TYPE_INVALID); + return TRUE; +} + static void name_owner_changed (DBusGProxy *proxy, const char *name, @@ -310,10 +616,7 @@ name_owner_changed (DBusGProxy *proxy, { NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); - const char *sname = NM_DBUS_SERVICE_USER_SETTINGS; - - if (priv->scope == NM_CONNECTION_SCOPE_SYSTEM) - sname = NM_DBUS_SERVICE_SYSTEM_SETTINGS; + const char *sname = NM_DBUS_SERVICE; if (!strcmp (name, sname)) { if (priv->fetch_id) @@ -330,35 +633,80 @@ name_owner_changed (DBusGProxy *proxy, } } -/****************************************************************/ +static void +properties_changed_cb (DBusGProxy *proxy, + GHashTable *properties, + gpointer user_data) +{ + NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + GHashTableIter iter; + gpointer key, tmp; + + g_hash_table_iter_init (&iter, properties); + while (g_hash_table_iter_next (&iter, &key, &tmp)) { + GValue *value = tmp; + + if (!strcmp ((const char *) key, "Hostname")) { + g_free (priv->hostname); + priv->hostname = g_value_dup_string (value); + g_object_notify (G_OBJECT (self), NM_REMOTE_SETTINGS_HOSTNAME); + } + + if (!strcmp ((const char *) key, "CanModify")) { + priv->can_modify = g_value_get_boolean (value); + g_object_notify (G_OBJECT (self), NM_REMOTE_SETTINGS_CAN_MODIFY); + } + } +} static void -settings_interface_init (NMSettingsInterface *iface) +get_all_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) { - /* interface implementation */ - iface->list_connections = list_connections; - iface->get_connection_by_path = get_connection_by_path; - iface->add_connection = add_connection; + NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); + GHashTable *props = NULL; + GError *error = NULL; + + if (!dbus_g_proxy_end_call (proxy, call, &error, + DBUS_TYPE_G_MAP_OF_VARIANT, &props, + G_TYPE_INVALID)) { + /* Don't warn when the call times out because the settings service can't + * be activated or whatever. + */ + if (!(error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NO_REPLY)) { + g_warning ("%s: couldn't retrieve system settings properties: (%d) %s.", + __func__, + error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); + } + g_clear_error (&error); + return; + } + + properties_changed_cb (NULL, props, self); + g_hash_table_destroy (props); } +/****************************************************************/ + /** * nm_remote_settings_new: - * @bus: a valid and connected D-Bus connection - * @scope: the settings service scope (either user or system) + * @bus: (allow-none): a valid and connected D-Bus connection * * Creates a new object representing the remote settings service. * * Returns: the new remote settings object on success, or %NULL on failure **/ NMRemoteSettings * -nm_remote_settings_new (DBusGConnection *bus, NMConnectionScope scope) +nm_remote_settings_new (DBusGConnection *bus) { - g_return_val_if_fail (bus != NULL, NULL); - g_return_val_if_fail (scope != NM_CONNECTION_SCOPE_UNKNOWN, NULL); + if (bus == NULL) + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); return (NMRemoteSettings *) g_object_new (NM_TYPE_REMOTE_SETTINGS, NM_REMOTE_SETTINGS_BUS, bus, - NM_REMOTE_SETTINGS_SCOPE, scope, NULL); } @@ -378,7 +726,6 @@ constructor (GType type, { GObject *object; NMRemoteSettingsPrivate *priv; - const char *service = NM_DBUS_SERVICE_USER_SETTINGS; GError *error = NULL; object = G_OBJECT_CLASS (nm_remote_settings_parent_class)->constructor (type, n_construct_params, construct_params); @@ -406,12 +753,8 @@ constructor (GType type, G_CALLBACK (name_owner_changed), object, NULL); - /* Settings service proxy */ - if (priv->scope == NM_CONNECTION_SCOPE_SYSTEM) - service = NM_DBUS_SERVICE_SYSTEM_SETTINGS; - if (!dbus_g_proxy_call (priv->dbus_proxy, "NameHasOwner", &error, - G_TYPE_STRING, service, + G_TYPE_STRING, NM_DBUS_SERVICE, G_TYPE_INVALID, G_TYPE_BOOLEAN, &priv->service_running, G_TYPE_INVALID)) { @@ -424,7 +767,7 @@ constructor (GType type, } priv->proxy = dbus_g_proxy_new_for_name (priv->bus, - service, + NM_DBUS_SERVICE, NM_DBUS_PATH_SETTINGS, NM_DBUS_IFACE_SETTINGS); g_assert (priv->proxy); @@ -440,13 +783,43 @@ constructor (GType type, priv->fetch_id = g_idle_add (fetch_connections, object); + + /* D-Bus properties proxy */ + priv->props_proxy = dbus_g_proxy_new_for_name (priv->bus, + NM_DBUS_SERVICE, + NM_DBUS_PATH_SETTINGS, + "org.freedesktop.DBus.Properties"); + g_assert (priv->props_proxy); + + /* Monitor properties */ + dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + DBUS_TYPE_G_MAP_OF_VARIANT, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->proxy, "PropertiesChanged", + DBUS_TYPE_G_MAP_OF_VARIANT, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "PropertiesChanged", + G_CALLBACK (properties_changed_cb), + object, + NULL); + + /* Get properties */ + dbus_g_proxy_begin_call (priv->props_proxy, "GetAll", + get_all_cb, + object, + NULL, + G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS, + G_TYPE_INVALID); + return object; } static void dispose (GObject *object) { - NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (object); + NMRemoteSettings *self = NM_REMOTE_SETTINGS (object); + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); if (priv->disposed) return; @@ -456,14 +829,20 @@ dispose (GObject *object) if (priv->fetch_id) g_source_remove (priv->fetch_id); + while (g_slist_length (priv->add_list)) + add_connection_info_dispose (self, (AddConnectionInfo *) priv->add_list->data); + if (priv->connections) g_hash_table_destroy (priv->connections); if (priv->pending) g_hash_table_destroy (priv->pending); + g_free (priv->hostname); + g_object_unref (priv->dbus_proxy); g_object_unref (priv->proxy); + g_object_unref (priv->props_proxy); dbus_g_connection_unref (priv->bus); G_OBJECT_CLASS (nm_remote_settings_parent_class)->dispose (object); @@ -480,9 +859,6 @@ set_property (GObject *object, guint prop_id, /* Construct only */ priv->bus = dbus_g_connection_ref ((DBusGConnection *) g_value_get_boxed (value)); break; - case PROP_SCOPE: - priv->scope = (NMConnectionScope) g_value_get_uint (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -499,12 +875,15 @@ get_property (GObject *object, guint prop_id, case PROP_BUS: g_value_set_boxed (value, priv->bus); break; - case PROP_SCOPE: - g_value_set_uint (value, priv->scope); - break; case PROP_SERVICE_RUNNING: g_value_set_boolean (value, priv->service_running); break; + case PROP_HOSTNAME: + g_value_set_string (value, priv->hostname); + break; + case PROP_CAN_MODIFY: + g_value_set_boolean (value, priv->can_modify); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -533,16 +912,6 @@ nm_remote_settings_class_init (NMRemoteSettingsClass *class) DBUS_TYPE_G_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property - (object_class, PROP_SCOPE, - g_param_spec_uint (NM_REMOTE_SETTINGS_SCOPE, - "Scope", - "NMConnection scope", - NM_CONNECTION_SCOPE_UNKNOWN, - NM_CONNECTION_SCOPE_USER, - NM_CONNECTION_SCOPE_USER, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, PROP_SERVICE_RUNNING, g_param_spec_boolean (NM_REMOTE_SETTINGS_SERVICE_RUNNING, @@ -550,5 +919,40 @@ nm_remote_settings_class_init (NMRemoteSettingsClass *class) "Is service running", FALSE, G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_HOSTNAME, + g_param_spec_string (NM_REMOTE_SETTINGS_HOSTNAME, + "Hostname", + "Persistent hostname", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_CAN_MODIFY, + g_param_spec_boolean (NM_REMOTE_SETTINGS_CAN_MODIFY, + "CanModify", + "Can modify anything (hostname, connections, etc)", + FALSE, + G_PARAM_READABLE)); + + /* Signals */ + signals[NEW_CONNECTION] = + g_signal_new (NM_REMOTE_SETTINGS_NEW_CONNECTION, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMRemoteSettingsClass, new_connection), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[CONNECTIONS_READ] = + g_signal_new (NM_REMOTE_SETTINGS_CONNECTIONS_READ, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMRemoteSettingsClass, connections_read), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } diff --git a/libnm-glib/nm-remote-settings.h b/libnm-glib/nm-remote-settings.h index d3085566ea..2bf748a6eb 100644 --- a/libnm-glib/nm-remote-settings.h +++ b/libnm-glib/nm-remote-settings.h @@ -38,17 +38,65 @@ G_BEGIN_DECLS #define NM_IS_REMOTE_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_REMOTE_SETTINGS)) #define NM_REMOTE_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_REMOTE_SETTINGS, NMRemoteSettingsClass)) -#define NM_REMOTE_SETTINGS_BUS "bus" -#define NM_REMOTE_SETTINGS_SCOPE "scope" +/** + * NMRemoteSettingsError: + * @NM_REMOTE_SETTINGS_ERROR_UNKNOWN: unknown or unclassified error + * @NM_REMOTE_SETTINGS_ERROR_CONNECTION_REMOVED: the #NMRemoteConnection object + * was removed before it was completely initialized + * @NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE: the #NMRemoteConnection object + * is not visible or otherwise unreadable + * + * Describes errors that may result from operations involving a #NMRemoteSettings. + * + **/ +typedef enum { + NM_REMOTE_SETTINGS_ERROR_UNKNOWN = 0, + NM_REMOTE_SETTINGS_ERROR_CONNECTION_REMOVED, + NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE, +} NMRemoteSettingsError; + +#define NM_TYPE_REMOTE_SETTINGS_ERROR (nm_remote_settings_error_get_type ()) +GType nm_remote_settings_error_get_type (void); + +#define NM_REMOTE_SETTINGS_ERROR nm_remote_settings_error_quark () +GQuark nm_remote_settings_error_quark (void); + + +#define NM_REMOTE_SETTINGS_BUS "bus" #define NM_REMOTE_SETTINGS_SERVICE_RUNNING "service-running" +#define NM_REMOTE_SETTINGS_HOSTNAME "hostname" +#define NM_REMOTE_SETTINGS_CAN_MODIFY "can-modify" -typedef struct { +#define NM_REMOTE_SETTINGS_NEW_CONNECTION "new-connection" +#define NM_REMOTE_SETTINGS_CONNECTIONS_READ "connections-read" + +typedef struct _NMRemoteSettings NMRemoteSettings; +typedef struct _NMRemoteSettingsClass NMRemoteSettingsClass; + + +typedef void (*NMRemoteSettingsAddConnectionFunc) (NMRemoteSettings *settings, + NMRemoteConnection *connection, + GError *error, + gpointer user_data); + +typedef void (*NMRemoteSettingsSaveHostnameFunc) (NMRemoteSettings *settings, + GError *error, + gpointer user_data); + + +struct _NMRemoteSettings { GObject parent; -} NMRemoteSettings; +}; -typedef struct { +struct _NMRemoteSettingsClass { GObjectClass parent; + /* Signals */ + void (*new_connection) (NMRemoteSettings *settings, + NMRemoteConnection *connection); + + void (*connections_read) (NMRemoteSettings *settings); + /* Padding for future expansion */ void (*_reserved1) (void); void (*_reserved2) (void); @@ -56,11 +104,26 @@ typedef struct { void (*_reserved4) (void); void (*_reserved5) (void); void (*_reserved6) (void); -} NMRemoteSettingsClass; +}; GType nm_remote_settings_get_type (void); -NMRemoteSettings *nm_remote_settings_new (DBusGConnection *bus, NMConnectionScope scope); +NMRemoteSettings *nm_remote_settings_new (DBusGConnection *bus); + +GSList * nm_remote_settings_list_connections (NMRemoteSettings *settings); + +NMRemoteConnection * nm_remote_settings_get_connection_by_path (NMRemoteSettings *settings, + const char *path); + +gboolean nm_remote_settings_add_connection (NMRemoteSettings *settings, + NMConnection *connection, + NMRemoteSettingsAddConnectionFunc callback, + gpointer user_data); + +gboolean nm_remote_settings_save_hostname (NMRemoteSettings *settings, + const char *hostname, + NMRemoteSettingsSaveHostnameFunc callback, + gpointer user_data); G_END_DECLS diff --git a/libnm-glib/nm-secret-agent.c b/libnm-glib/nm-secret-agent.c new file mode 100644 index 0000000000..72431e2dae --- /dev/null +++ b/libnm-glib/nm-secret-agent.c @@ -0,0 +1,862 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2010 - 2011 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include + +#include "nm-secret-agent.h" +#include "nm-marshal.h" +#include "NetworkManager.h" + +static void impl_secret_agent_get_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + const char *setting_name, + const char **hints, + guint32 flags, + DBusGMethodInvocation *context); + +static void impl_secret_agent_cancel_get_secrets (NMSecretAgent *self, + const char *connection_path, + const char *setting_name, + DBusGMethodInvocation *context); + +static void impl_secret_agent_save_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + DBusGMethodInvocation *context); + +static void impl_secret_agent_delete_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + DBusGMethodInvocation *context); + +#include "nm-secret-agent-glue.h" + +G_DEFINE_ABSTRACT_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) + +#define NM_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_SECRET_AGENT, \ + NMSecretAgentPrivate)) + +static gboolean auto_register_cb (gpointer user_data); + +typedef struct { + gboolean registered; + + DBusGConnection *bus; + DBusGProxy *dbus_proxy; + DBusGProxy *manager_proxy; + DBusGProxyCall *reg_call; + + char *nm_owner; + + char *identifier; + gboolean auto_register; + gboolean suppress_auto; + gboolean auto_register_id; + + gboolean disposed; +} NMSecretAgentPrivate; + +enum { + PROP_0, + PROP_IDENTIFIER, + PROP_AUTO_REGISTER, + + LAST_PROP +}; + +enum { + REGISTRATION_RESULT, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + + +/********************************************************************/ + +GQuark +nm_secret_agent_error_quark (void) +{ + static GQuark ret = 0; + + if (G_UNLIKELY (ret == 0)) + ret = g_quark_from_static_string ("nm-secret-agent-error"); + return ret; +} + +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +nm_secret_agent_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + /* Sender is not authorized to make this request */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, "NotAuthorized"), + /* Given connection details do not make a valid connection */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, "InvalidConnection"), + /* The request was canceled explicitly by the user */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_USER_CANCELED, "UserCanceled"), + /* The request was canceled, but not by the user */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_AGENT_CANCELED, "AgentCanceled"), + /* Some internal error prevented returning secrets */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_INTERNAL_ERROR, "InternalError"), + /* No secrets could be found to fulfill the request */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_NO_SECRETS, "NoSecrets"), + { 0, 0, 0 } + }; + etype = g_enum_register_static ("NMSecretAgentError", values); + } + return etype; +} + +/*************************************************************/ + +static const char * +get_nm_owner (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GError *error = NULL; + char *owner; + + if (!priv->nm_owner) { + if (!dbus_g_proxy_call_with_timeout (priv->dbus_proxy, + "GetNameOwner", 2000, &error, + G_TYPE_STRING, NM_DBUS_SERVICE, + G_TYPE_INVALID, + G_TYPE_STRING, &owner, + G_TYPE_INVALID)) + return NULL; + + priv->nm_owner = g_strdup (owner); + g_free (owner); + } + + return priv->nm_owner; +} + +static void +_internal_unregister (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + if (priv->registered) { + dbus_g_connection_unregister_g_object (priv->bus, G_OBJECT (self)); + priv->registered = FALSE; + } +} + +static void +name_owner_changed (DBusGProxy *proxy, + const char *name, + const char *old_owner, + const char *new_owner, + gpointer user_data) +{ + NMSecretAgent *self = NM_SECRET_AGENT (user_data); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + gboolean old_owner_good = (old_owner && strlen (old_owner)); + gboolean new_owner_good = (new_owner && strlen (new_owner)); + + if (strcmp (name, NM_DBUS_SERVICE) == 0) { + g_free (priv->nm_owner); + priv->nm_owner = g_strdup (new_owner); + + if (!old_owner_good && new_owner_good) { + /* NM appeared */ + auto_register_cb (self); + } else if (old_owner_good && !new_owner_good) { + /* NM disappeared */ + _internal_unregister (self); + } else if (old_owner_good && new_owner_good && strcmp (old_owner, new_owner)) { + /* Hmm, NM magically restarted */ + _internal_unregister (self); + auto_register_cb (self); + } + } +} + +static gboolean +verify_request (NMSecretAgent *self, + DBusGMethodInvocation *context, + GHashTable *connection_hash, + const char *connection_path, + NMConnection **out_connection, + GError **error) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + NMConnection *connection = NULL; + DBusConnection *bus; + char *sender; + const char *nm_owner; + DBusError dbus_error; + uid_t sender_uid = G_MAXUINT; + GError *local = NULL; + + g_return_val_if_fail (context != NULL, FALSE); + + /* Verify the sender's UID is 0, and that the sender is the same as + * NetworkManager's bus name owner. + */ + + nm_owner = get_nm_owner (self); + if (!nm_owner) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "NetworkManager bus name owner unknown."); + return FALSE; + } + + bus = dbus_g_connection_get_connection (priv->bus); + if (!bus) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Failed to get DBus connection."); + return FALSE; + } + + sender = dbus_g_method_get_sender (context); + if (!sender) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Failed to get request sender."); + return FALSE; + } + + /* Check that the sender matches the current NM bus name owner */ + if (strcmp (sender, nm_owner) != 0) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Request sender does not match NetworkManager bus name owner."); + goto out; + } + + dbus_error_init (&dbus_error); + sender_uid = dbus_bus_get_unix_user (bus, sender, &dbus_error); + if (dbus_error_is_set (&dbus_error)) { + g_set_error (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Failed to get request unix user: (%s) %s.", + dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + + if (0 != sender_uid) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Request sender is not root."); + goto out; + } + + /* And make sure the connection is actually valid */ + if (connection_hash) { + connection = nm_connection_new_from_hash (connection_hash, &local); + if (connection && connection_path) { + nm_connection_set_path (connection, connection_path); + } else { + g_set_error (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, + "Invalid connection: (%d) %s", + local ? local->code : -1, + (local && local->message) ? local->message : "(unknown)"); + g_clear_error (&local); + } + } + +out: + if (out_connection) + *out_connection = connection; + g_free (sender); + + return !!connection; +} + +static void +get_secrets_cb (NMSecretAgent *self, + NMConnection *connection, + GHashTable *secrets, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context, secrets); +} + +static void +impl_secret_agent_get_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + const char *setting_name, + const char **hints, + guint32 flags, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + NMConnection *connection = NULL; + + /* Make sure the request comes from NetworkManager and is valid */ + if (!verify_request (self, context, connection_hash, connection_path, &connection, &error)) { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + return; + } + + NM_SECRET_AGENT_GET_CLASS (self)->get_secrets (self, + connection, + connection_path, + setting_name, + hints, + flags, + get_secrets_cb, + context); + g_object_unref (connection); +} + +static void +impl_secret_agent_cancel_get_secrets (NMSecretAgent *self, + const char *connection_path, + const char *setting_name, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + + /* Make sure the request comes from NetworkManager and is valid */ + if (!verify_request (self, context, NULL, NULL, NULL, &error)) { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + } else { + NM_SECRET_AGENT_GET_CLASS (self)->cancel_get_secrets (self, connection_path, setting_name); + dbus_g_method_return (context); + } +} + +static void +save_secrets_cb (NMSecretAgent *self, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); +} + +static void +impl_secret_agent_save_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + NMConnection *connection = NULL; + + /* Make sure the request comes from NetworkManager and is valid */ + if (!verify_request (self, context, connection_hash, connection_path, &connection, &error)) { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + return; + } + + NM_SECRET_AGENT_GET_CLASS (self)->save_secrets (self, + connection, + connection_path, + save_secrets_cb, + context); + g_object_unref (connection); +} + +static void +delete_secrets_cb (NMSecretAgent *self, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); +} + +static void +impl_secret_agent_delete_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + NMConnection *connection = NULL; + + /* Make sure the request comes from NetworkManager and is valid */ + if (!verify_request (self, context, connection_hash, connection_path, &connection, &error)) { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + return; + } + + NM_SECRET_AGENT_GET_CLASS (self)->delete_secrets (self, + connection, + connection_path, + delete_secrets_cb, + context); + g_object_unref (connection); +} + +/**************************************************************/ + +static void +reg_request_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) +{ + NMSecretAgent *self = NM_SECRET_AGENT (user_data); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GError *error = NULL; + + priv->reg_call = NULL; + + if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) + priv->registered = TRUE; + else { + /* If registration failed we shouldn't expose ourselves on the bus */ + _internal_unregister (self); + } + + g_signal_emit (self, signals[REGISTRATION_RESULT], 0, error); + g_clear_error (&error); +} + +/** + * nm_secret_agent_register: + * + * Registers the #NMSecretAgent with the NetworkManager secret manager, + * indicating to NetworkManager that the agent is able to provide and save + * secrets for connections on behalf of its user. Registration is an + * asynchronous operation and its success or failure is indicated via the + * 'registration-result' signal. + * + * Returns: a new %TRUE if registration was successfully requested (this does + * not mean registration itself was successful), %FALSE if registration was not + * successfully requested. + **/ +gboolean +nm_secret_agent_register (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv; + NMSecretAgentClass *class; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE); + + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + g_return_val_if_fail (priv->registered == FALSE, FALSE); + g_return_val_if_fail (priv->reg_call == NULL, FALSE); + g_return_val_if_fail (priv->bus != NULL, FALSE); + g_return_val_if_fail (priv->manager_proxy != NULL, FALSE); + + /* Also make sure the subclass can actually respond to secrets requests */ + class = NM_SECRET_AGENT_GET_CLASS (self); + g_return_val_if_fail (class->get_secrets != NULL, FALSE); + g_return_val_if_fail (class->save_secrets != NULL, FALSE); + g_return_val_if_fail (class->delete_secrets != NULL, FALSE); + + priv->suppress_auto = FALSE; + + /* Export our secret agent interface before registering with the manager */ + dbus_g_connection_register_g_object (priv->bus, + NM_DBUS_PATH_SECRET_AGENT, + G_OBJECT (self)); + + priv->reg_call = dbus_g_proxy_begin_call_with_timeout (priv->manager_proxy, + "Register", + reg_request_cb, + self, + NULL, + 5000, + G_TYPE_STRING, priv->identifier, + G_TYPE_INVALID); + + return TRUE; +} + +/** + * nm_secret_agent_unregister: + * + * Unregisters the #NMSecretAgent with the NetworkManager secret manager, + * indicating to NetworkManager that the agent is will no longer provide or + * store secrets on behalf of this user. + * + * Returns: a new %TRUE if unregistration was successful, %FALSE if it was not. + **/ +gboolean +nm_secret_agent_unregister (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE); + + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + g_return_val_if_fail (priv->registered == TRUE, FALSE); + g_return_val_if_fail (priv->bus != NULL, FALSE); + g_return_val_if_fail (priv->manager_proxy != NULL, FALSE); + + dbus_g_proxy_call_no_reply (priv->manager_proxy, "Unregister", G_TYPE_INVALID); + + _internal_unregister (self); + priv->suppress_auto = TRUE; + + return TRUE; +} + +static gboolean +auto_register_cb (gpointer user_data) +{ + NMSecretAgent *self = NM_SECRET_AGENT (user_data); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + priv->auto_register_id = 0; + if (priv->auto_register && !priv->suppress_auto && (priv->reg_call == NULL)) + nm_secret_agent_register (self); + return FALSE; +} + +/**************************************************************/ + +void +nm_secret_agent_get_secrets (NMSecretAgent *self, + NMConnection *connection, + const char *setting_name, + const char **hints, + guint32 flags, + NMSecretAgentGetSecretsFunc callback, + gpointer callback_data) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_SECRET_AGENT (self)); + g_return_if_fail (connection != NULL); + g_return_if_fail (NM_IS_CONNECTION (connection)); + g_return_if_fail (nm_connection_get_path (connection)); + g_return_if_fail (setting_name != NULL); + g_return_if_fail (strlen (setting_name) > 0); + g_return_if_fail (callback != NULL); + + NM_SECRET_AGENT_GET_CLASS (self)->get_secrets (self, + connection, + nm_connection_get_path (connection), + setting_name, + hints, + flags, + callback, + callback_data); +} + +void +nm_secret_agent_save_secrets (NMSecretAgent *self, + NMConnection *connection, + NMSecretAgentSaveSecretsFunc callback, + gpointer callback_data) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_SECRET_AGENT (self)); + g_return_if_fail (connection != NULL); + g_return_if_fail (NM_IS_CONNECTION (connection)); + g_return_if_fail (nm_connection_get_path (connection)); + + NM_SECRET_AGENT_GET_CLASS (self)->save_secrets (self, + connection, + nm_connection_get_path (connection), + callback, + callback_data); +} + +void +nm_secret_agent_delete_secrets (NMSecretAgent *self, + NMConnection *connection, + NMSecretAgentDeleteSecretsFunc callback, + gpointer callback_data) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_SECRET_AGENT (self)); + g_return_if_fail (connection != NULL); + g_return_if_fail (NM_IS_CONNECTION (connection)); + g_return_if_fail (nm_connection_get_path (connection)); + + NM_SECRET_AGENT_GET_CLASS (self)->delete_secrets (self, + connection, + nm_connection_get_path (connection), + callback, + callback_data); +} + +/**************************************************************/ + +static gboolean +validate_identifier (const char *identifier) +{ + const char *p = identifier; + size_t id_len; + + /* Length between 3 and 255 characters inclusive */ + id_len = strlen (identifier); + if (id_len < 3 || id_len > 255) + return FALSE; + + if ((identifier[0] == '.') || (identifier[id_len - 1] == '.')) + return FALSE; + + /* FIXME: do complete validation here */ + while (p && *p) { + if (!isalnum (*p) && (*p != '_') && (*p != '-') && (*p != '.')) + return FALSE; + if ((*p == '.') && (*(p + 1) == '.')) + return FALSE; + p++; + } + + return TRUE; +} + +static void +nm_secret_agent_init (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GError *error = NULL; + + priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (!priv->bus) { + g_warning ("Couldn't connect to system bus: %s", error->message); + g_error_free (error); + return; + } + + priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + if (!priv->dbus_proxy) { + g_warning ("Couldn't create messagebus proxy."); + return; + } + + dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING, + G_TYPE_NONE, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->dbus_proxy, + "NameOwnerChanged", + G_CALLBACK (name_owner_changed), + self, NULL); + + priv->manager_proxy = dbus_g_proxy_new_for_name (priv->bus, + NM_DBUS_SERVICE, + NM_DBUS_PATH_AGENT_MANAGER, + NM_DBUS_INTERFACE_AGENT_MANAGER); + if (!priv->manager_proxy) { + g_warning ("Couldn't create NM agent manager proxy."); + return; + } + + priv->auto_register_id = g_idle_add (auto_register_cb, self); +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_IDENTIFIER: + g_value_set_string (value, priv->identifier); + break; + case PROP_AUTO_REGISTER: + g_value_set_boolean (value, priv->auto_register); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + const char *identifier; + + switch (prop_id) { + case PROP_IDENTIFIER: + identifier = g_value_get_string (value); + + g_return_if_fail (validate_identifier (identifier)); + + g_free (priv->identifier); + priv->identifier = g_strdup (identifier); + break; + case PROP_AUTO_REGISTER: + priv->auto_register = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMSecretAgent *self = NM_SECRET_AGENT (object); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + if (!priv->disposed) { + priv->disposed = TRUE; + + if (priv->registered) + nm_secret_agent_unregister (self); + + if (priv->auto_register_id) + g_source_remove (priv->auto_register_id); + + g_free (priv->identifier); + g_free (priv->nm_owner); + + if (priv->dbus_proxy) + g_object_unref (priv->dbus_proxy); + + if (priv->manager_proxy) + g_object_unref (priv->manager_proxy); + + if (priv->bus) + dbus_g_connection_unref (priv->bus); + } + + G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object); +} + +static void +nm_secret_agent_class_init (NMSecretAgentClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + g_type_class_add_private (class, sizeof (NMSecretAgentPrivate)); + + /* Virtual methods */ + object_class->dispose = dispose; + object_class->get_property = get_property; + object_class->set_property = set_property; + + /** + * NMSecretAgent:identifier: + * + * Identifies this agent; only one agent in each user session may use the + * same identifier. Identifier formatting follows the same rules as + * D-Bus bus names with the exception that the ':' character is not + * allowed. The valid set of characters is "[A-Z][a-z][0-9]_-." and the + * identifier is limited in length to 255 characters with a minimum + * of 3 characters. An example valid identifier is 'org.gnome.nm-applet' + * (without quotes). + **/ + g_object_class_install_property + (object_class, PROP_IDENTIFIER, + g_param_spec_string (NM_SECRET_AGENT_IDENTIFIER, + "Identifier", + "Identifier", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * NMSecretAgent:auto-register: + * + * If TRUE, the agent will attempt to automatically register itself after + * it is created (via an idle handler) and to re-register itself if + * NetworkManager restarts. If FALSE, the agent does not automatically + * register with NetworkManager, and nm_secret_agent_register() must be + * called. If 'auto-register' is TRUE, calling nm_secret_agent_unregister() + * will suppress auto-registration until nm_secret_agent_register() is + * called, which re-enables auto-registration. + **/ + g_object_class_install_property + (object_class, PROP_AUTO_REGISTER, + g_param_spec_boolean (NM_SECRET_AGENT_AUTO_REGISTER, + "Auto Register", + "Auto Register", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + /** + * NMSecretAgent::registration-result: + * @agent: the agent that received the signal + * @error: the error, if any, that occured while registering + * + * Indicates the result of a registration request; if @error is NULL the + * request was successful. + **/ + signals[REGISTRATION_RESULT] = + g_signal_new (NM_SECRET_AGENT_REGISTRATION_RESULT, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class), + &dbus_glib_nm_secret_agent_object_info); + + dbus_g_error_domain_register (NM_SECRET_AGENT_ERROR, + NM_DBUS_INTERFACE_SECRET_AGENT, + NM_TYPE_SECRET_AGENT_ERROR); +} + diff --git a/libnm-glib/nm-secret-agent.h b/libnm-glib/nm-secret-agent.h new file mode 100644 index 0000000000..60354d5638 --- /dev/null +++ b/libnm-glib/nm-secret-agent.h @@ -0,0 +1,171 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2010 - 2011 Red Hat, Inc. + */ + +#ifndef NM_SECRET_AGENT_H +#define NM_SECRET_AGENT_H + +#include + +G_BEGIN_DECLS + +#define NM_SECRET_AGENT_ERROR (nm_secret_agent_error_quark ()) +#define NM_TYPE_SECRET_AGENT_ERROR (nm_secret_agent_error_get_type ()) + +GQuark nm_secret_agent_error_quark (void); +GType nm_secret_agent_error_get_type (void); + +typedef enum { + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED = 0, + NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, + NM_SECRET_AGENT_ERROR_USER_CANCELED, + NM_SECRET_AGENT_ERROR_AGENT_CANCELED, + NM_SECRET_AGENT_ERROR_INTERNAL_ERROR, + NM_SECRET_AGENT_ERROR_NO_SECRETS, +} NMSecretAgentError; + +enum { + NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE = 0x0, + NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION = 0x1, + NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW = 0x2 +}; + +#define NM_TYPE_SECRET_AGENT (nm_secret_agent_get_type ()) +#define NM_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent)) +#define NM_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) +#define NM_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SECRET_AGENT)) +#define NM_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SECRET_AGENT)) +#define NM_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) + +#define NM_SECRET_AGENT_IDENTIFIER "identifier" +#define NM_SECRET_AGENT_AUTO_REGISTER "auto-register" + +#define NM_SECRET_AGENT_REGISTRATION_RESULT "registration-result" + +typedef struct { + GObject parent; +} NMSecretAgent; + +typedef void (*NMSecretAgentGetSecretsFunc) (NMSecretAgent *agent, + NMConnection *connection, + GHashTable *secrets, + GError *error, + gpointer user_data); + +typedef void (*NMSecretAgentSaveSecretsFunc) (NMSecretAgent *agent, + NMConnection *connection, + GError *error, + gpointer user_data); + +typedef void (*NMSecretAgentDeleteSecretsFunc) (NMSecretAgent *agent, + NMConnection *connection, + GError *error, + gpointer user_data); + +typedef struct { + GObjectClass parent; + + /* Virtual methods for subclasses */ + + /* Called when the subclass should retrieve and return secrets. Subclass + * must copy or reference any arguments it may require after returning from + * this method, as the arguments will freed (except for 'agent', 'callback', + * and 'callback_data' of course). If the request is canceled, the callback + * should still be called, but with the NM_SECRET_AGENT_ERROR_AGENT_CANCELED + * error. + */ + void (*get_secrets) (NMSecretAgent *agent, + NMConnection *connection, + const char *connection_path, + const char *setting_name, + const char **hints, + guint32 flags, + NMSecretAgentGetSecretsFunc callback, + gpointer callback_data); + + /* Called when the subclass should cancel an outstanding request to + * get secrets for a given connection. + */ + void (*cancel_get_secrets) (NMSecretAgent *agent, + const char *connection_path, + const char *setting_name); + + /* Called when the subclass should save the secrets contained in the + * connection to backing storage. Subclass must copy or reference any + * arguments it may require after returning from this method, as the + * arguments will freed (except for 'agent', 'callback', and 'callback_data' + * of course). + */ + void (*save_secrets) (NMSecretAgent *agent, + NMConnection *connection, + const char *connection_path, + NMSecretAgentSaveSecretsFunc callback, + gpointer callback_data); + + /* Called when the subclass should delete the secrets contained in the + * connection from backing storage. Subclass must copy or reference any + * arguments it may require after returning from this method, as the + * arguments will freed (except for 'agent', 'callback', and 'callback_data' + * of course). + */ + void (*delete_secrets) (NMSecretAgent *agent, + NMConnection *connection, + const char *connection_path, + NMSecretAgentDeleteSecretsFunc callback, + gpointer callback_data); + + /* Signals */ + void (*registration_result) (NMSecretAgent *agent, GError *error); + + /* Padding for future expansion */ + void (*_reserved1) (void); + void (*_reserved2) (void); + void (*_reserved3) (void); + void (*_reserved4) (void); + void (*_reserved5) (void); + void (*_reserved6) (void); +} NMSecretAgentClass; + +GType nm_secret_agent_get_type (void); + +gboolean nm_secret_agent_register (NMSecretAgent *self); + +gboolean nm_secret_agent_unregister (NMSecretAgent *self); + +void nm_secret_agent_get_secrets (NMSecretAgent *self, + NMConnection *connection, + const char *setting_name, + const char **hints, + guint32 flags, + NMSecretAgentGetSecretsFunc callback, + gpointer callback_data); + +void nm_secret_agent_save_secrets (NMSecretAgent *self, + NMConnection *connection, + NMSecretAgentSaveSecretsFunc callback, + gpointer callback_data); + +void nm_secret_agent_delete_secrets (NMSecretAgent *self, + NMConnection *connection, + NMSecretAgentDeleteSecretsFunc callback, + gpointer callback_data); + +G_END_DECLS + +#endif /* NM_SECRET_AGENT_H */ diff --git a/libnm-glib/nm-settings-connection-interface.c b/libnm-glib/nm-settings-connection-interface.c deleted file mode 100644 index 868ad047a7..0000000000 --- a/libnm-glib/nm-settings-connection-interface.c +++ /dev/null @@ -1,192 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2009 Red Hat, Inc. - */ - -#include "nm-settings-connection-interface.h" -#include "nm-dbus-glib-types.h" - -/** - * nm_settings_connection_interface_update: - * @connection: an object implementing #NMSettingsConnectionInterface - * @callback: a function to be called when the update completes - * @user_data: caller-specific data to be passed to @callback - * - * Update the connection with current settings and properties. - * - * Returns: TRUE on success, FALSE on failure - **/ -gboolean -nm_settings_connection_interface_update (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceUpdateFunc callback, - gpointer user_data) -{ - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection), FALSE); - g_return_val_if_fail (callback != NULL, FALSE); - - if (NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE (connection)->update) { - return NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE (connection)->update (connection, - callback, - user_data); - } - return FALSE; -} - -/** - * nm_settings_connection_interface_delete: - * @connection: a objecting implementing #NMSettingsConnectionInterface - * @callback: a function to be called when the delete completes - * @user_data: caller-specific data to be passed to @callback - * - * Delete the connection. - * - * Returns: TRUE on success, FALSE on failure - **/ -gboolean -nm_settings_connection_interface_delete (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceDeleteFunc callback, - gpointer user_data) -{ - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection), FALSE); - g_return_val_if_fail (callback != NULL, FALSE); - - if (NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE (connection)->delete) { - return NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE (connection)->delete (connection, - callback, - user_data); - } - return FALSE; -} - -/** - * nm_settings_connection_interface_get_secrets: - * @connection: a object implementing #NMSettingsConnectionInterface - * @setting_name: the #NMSetting object name to get secrets for - * @hints: #NMSetting key names to get secrets for (optional) - * @request_new: hint that new secrets (instead of cached or stored secrets) - * should be returned - * @callback: a function to be called when the update completes - * @user_data: caller-specific data to be passed to @callback - * - * Request the connection's secrets. - * - * Returns: TRUE on success, FALSE on failure - **/ -gboolean -nm_settings_connection_interface_get_secrets (NMSettingsConnectionInterface *connection, - const char *setting_name, - const char **hints, - gboolean request_new, - NMSettingsConnectionInterfaceGetSecretsFunc callback, - gpointer user_data) -{ - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection), FALSE); - g_return_val_if_fail (callback != NULL, FALSE); - - if (NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE (connection)->get_secrets) { - return NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE (connection)->get_secrets (connection, - setting_name, - hints, - request_new, - callback, - user_data); - } - return FALSE; -} - -void -nm_settings_connection_interface_emit_updated (NMSettingsConnectionInterface *connection) -{ - if (NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE (connection)->emit_updated) - NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE (connection)->emit_updated (connection); - else { - NMConnection *tmp; - GHashTable *settings; - - tmp = nm_connection_duplicate (NM_CONNECTION (connection)); - nm_connection_clear_secrets (tmp); - settings = nm_connection_to_hash (tmp); - g_object_unref (tmp); - - g_signal_emit_by_name (connection, NM_SETTINGS_CONNECTION_INTERFACE_UPDATED, settings); - g_hash_table_destroy (settings); - } -} - -static void -nm_settings_connection_interface_init (gpointer g_iface) -{ - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; - - if (initialized) - return; - - /* Signals */ - g_signal_new (NM_SETTINGS_CONNECTION_INTERFACE_UPDATED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsConnectionInterface, updated), - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT); - - g_signal_new (NM_SETTINGS_CONNECTION_INTERFACE_REMOVED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsConnectionInterface, removed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - initialized = TRUE; -} - -GType -nm_settings_connection_interface_get_type (void) -{ - static GType itype = 0; - - if (!itype) { - const GTypeInfo iinfo = { - sizeof (NMSettingsConnectionInterface), /* class_size */ - nm_settings_connection_interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - itype = g_type_register_static (G_TYPE_INTERFACE, - "NMSettingsConnectionInterface", - &iinfo, 0); - - g_type_interface_add_prerequisite (itype, NM_TYPE_CONNECTION); - } - - return itype; -} - diff --git a/libnm-glib/nm-settings-connection-interface.h b/libnm-glib/nm-settings-connection-interface.h deleted file mode 100644 index 7c7a198c78..0000000000 --- a/libnm-glib/nm-settings-connection-interface.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * libnm_glib -- Access network status & information from glib applications - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2009 Red Hat, Inc. - */ - -#ifndef __NM_SETTINGS_CONNECTION_INTERFACE_H__ -#define __NM_SETTINGS_CONNECTION_INTERFACE_H__ - -#include -#include - -#include - -G_BEGIN_DECLS - -#define NM_TYPE_SETTINGS_CONNECTION_INTERFACE (nm_settings_connection_interface_get_type ()) -#define NM_SETTINGS_CONNECTION_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_CONNECTION_INTERFACE, NMSettingsConnectionInterface)) -#define NM_IS_SETTINGS_CONNECTION_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS_CONNECTION_INTERFACE)) -#define NM_SETTINGS_CONNECTION_INTERFACE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_SETTINGS_CONNECTION_INTERFACE, NMSettingsConnectionInterface)) - -#define NM_SETTINGS_CONNECTION_INTERFACE_UPDATED "updated" -#define NM_SETTINGS_CONNECTION_INTERFACE_REMOVED "removed" - -typedef struct _NMSettingsConnectionInterface NMSettingsConnectionInterface; - -typedef void (*NMSettingsConnectionInterfaceUpdateFunc) (NMSettingsConnectionInterface *connection, - GError *error, - gpointer user_data); - -typedef void (*NMSettingsConnectionInterfaceDeleteFunc) (NMSettingsConnectionInterface *connection, - GError *error, - gpointer user_data); - -typedef void (*NMSettingsConnectionInterfaceGetSecretsFunc) (NMSettingsConnectionInterface *connection, - GHashTable *secrets, - GError *error, - gpointer user_data); - -struct _NMSettingsConnectionInterface { - GTypeInterface g_iface; - - /* Methods */ - gboolean (*update) (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceUpdateFunc callback, - gpointer user_data); - - gboolean (*delete) (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceDeleteFunc callback, - gpointer user_data); - - gboolean (*get_secrets) (NMSettingsConnectionInterface *connection, - const char *setting_name, - const char **hints, - gboolean request_new, - NMSettingsConnectionInterfaceGetSecretsFunc callback, - gpointer user_data); - - void (*emit_updated) (NMSettingsConnectionInterface *connection); - - /* Signals */ - /* 'new_settings' hash should *not* contain secrets */ - void (*updated) (NMSettingsConnectionInterface *connection, - GHashTable *new_settings); - - void (*removed) (NMSettingsConnectionInterface *connection); - - /* Padding for future expansion */ - void (*_reserved1) (void); - void (*_reserved2) (void); - void (*_reserved3) (void); - void (*_reserved4) (void); - void (*_reserved5) (void); - void (*_reserved6) (void); -}; - -GType nm_settings_connection_interface_get_type (void); - -gboolean nm_settings_connection_interface_update (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceUpdateFunc callback, - gpointer user_data); - -gboolean nm_settings_connection_interface_delete (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceDeleteFunc callback, - gpointer user_data); - -gboolean nm_settings_connection_interface_get_secrets (NMSettingsConnectionInterface *connection, - const char *setting_name, - const char **hints, - gboolean request_new, - NMSettingsConnectionInterfaceGetSecretsFunc callback, - gpointer user_data); - -void nm_settings_connection_interface_emit_updated (NMSettingsConnectionInterface *connection); - -G_END_DECLS - -#endif /* __NM_SETTINGS_CONNECTION_INTERFACE_H__ */ - diff --git a/libnm-glib/nm-settings-interface.c b/libnm-glib/nm-settings-interface.c deleted file mode 100644 index 3bd4037a1e..0000000000 --- a/libnm-glib/nm-settings-interface.c +++ /dev/null @@ -1,206 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2010 Red Hat, Inc. - */ - -#include "nm-settings-interface.h" - - -/** - * nm_settings_interface_error_quark: - * - * Setting error quark. - * - * Returns: the setting error quark - **/ -GQuark -nm_settings_interface_error_quark (void) -{ - static GQuark quark; - - if (G_UNLIKELY (!quark)) - quark = g_quark_from_static_string ("nm-settings-interface-error-quark"); - return quark; -} - -/* This should really be standard. */ -#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -GType -nm_settings_interface_error_get_type (void) -{ - static GType etype = 0; - - if (etype == 0) { - static const GEnumValue values[] = { - /* The connection was invalid. */ - ENUM_ENTRY (NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION, "InvalidConnection"), - /* The connection is read-only; modifications are not allowed. */ - ENUM_ENTRY (NM_SETTINGS_INTERFACE_ERROR_READ_ONLY_CONNECTION, "ReadOnlyConnection"), - /* A bug in the settings service caused the error. */ - ENUM_ENTRY (NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, "InternalError"), - /* Retrieval or request of secrets failed. */ - ENUM_ENTRY (NM_SETTINGS_INTERFACE_ERROR_SECRETS_UNAVAILABLE, "SecretsUnavailable"), - /* The request for secrets was canceled. */ - ENUM_ENTRY (NM_SETTINGS_INTERFACE_ERROR_SECRETS_REQUEST_CANCELED, "SecretsRequestCanceled"), - /* The request could not be completed because permission was denied. */ - ENUM_ENTRY (NM_SETTINGS_INTERFACE_ERROR_PERMISSION_DENIED, "PermissionDenied"), - /* The requested setting does not existing in this connection. */ - ENUM_ENTRY (NM_SETTINGS_INTERFACE_ERROR_INVALID_SETTING, "InvalidSetting"), - { 0, 0, 0 }, - }; - etype = g_enum_register_static ("NMSettingsInterfaceError", values); - } - return etype; -} - - -/** - * nm_settings_list_connections: - * @settings: a object implementing %NMSettingsInterface - * - * Returns: all connections known to the object. - **/ -GSList * -nm_settings_interface_list_connections (NMSettingsInterface *settings) -{ - g_return_val_if_fail (settings != NULL, NULL); - g_return_val_if_fail (NM_IS_SETTINGS_INTERFACE (settings), NULL); - - if (NM_SETTINGS_INTERFACE_GET_INTERFACE (settings)->list_connections) - return NM_SETTINGS_INTERFACE_GET_INTERFACE (settings)->list_connections (settings); - return NULL; -} - -/** - * nm_settings_get_connection_by_path: - * @settings: a object implementing %NMSettingsInterface - * @path: the D-Bus object path of the remote connection - * - * Returns the object implementing %NMSettingsConnectionInterface at @path. - * - * Returns: the remote connection object on success, or NULL if the object was - * not known - **/ -NMSettingsConnectionInterface * -nm_settings_interface_get_connection_by_path (NMSettingsInterface *settings, - const char *path) -{ - g_return_val_if_fail (settings != NULL, NULL); - g_return_val_if_fail (NM_IS_SETTINGS_INTERFACE (settings), NULL); - g_return_val_if_fail (path != NULL, NULL); - - if (NM_SETTINGS_INTERFACE_GET_INTERFACE (settings)->get_connection_by_path) - return NM_SETTINGS_INTERFACE_GET_INTERFACE (settings)->get_connection_by_path (settings, path); - return NULL; -} - -/** - * nm_settings_interface_add_connection: - * @settings: a object implementing %NMSettingsInterface - * @connection: the settings to add; note that this object's settings will be - * added, not the object itself - * @callback: callback to be called when the add operation completes - * @user_data: caller-specific data passed to @callback - * - * Requests that the settings service add the given settings to a new connection. - * - * Returns: TRUE if the request was successful, FALSE if it failed - **/ -gboolean -nm_settings_interface_add_connection (NMSettingsInterface *settings, - NMConnection *connection, - NMSettingsAddConnectionFunc callback, - gpointer user_data) -{ - g_return_val_if_fail (settings != NULL, FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_INTERFACE (settings), FALSE); - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - g_return_val_if_fail (callback != NULL, FALSE); - - if (NM_SETTINGS_INTERFACE_GET_INTERFACE (settings)->add_connection) { - return NM_SETTINGS_INTERFACE_GET_INTERFACE (settings)->add_connection (settings, - connection, - callback, - user_data); - } - return FALSE; -} - -/*****************************************************************/ - -static void -nm_settings_interface_init (gpointer g_iface) -{ - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; - - if (initialized) - return; - - /* Signals */ - g_signal_new (NM_SETTINGS_INTERFACE_NEW_CONNECTION, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsInterface, new_connection), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - g_signal_new (NM_SETTINGS_INTERFACE_CONNECTIONS_READ, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsInterface, connections_read), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - initialized = TRUE; -} - -GType -nm_settings_interface_get_type (void) -{ - static GType settings_interface_type = 0; - - if (!settings_interface_type) { - const GTypeInfo settings_interface_info = { - sizeof (NMSettingsInterface), /* class_size */ - nm_settings_interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - settings_interface_type = g_type_register_static (G_TYPE_INTERFACE, - "NMSettingsInterface", - &settings_interface_info, 0); - - g_type_interface_add_prerequisite (settings_interface_type, G_TYPE_OBJECT); - } - - return settings_interface_type; -} - diff --git a/libnm-glib/nm-settings-interface.h b/libnm-glib/nm-settings-interface.h deleted file mode 100644 index 5920bd8255..0000000000 --- a/libnm-glib/nm-settings-interface.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2010 Red Hat, Inc. - */ - -#ifndef NM_SETTINGS_INTERFACE_H -#define NM_SETTINGS_INTERFACE_H - -#include - -#include "NetworkManager.h" -#include "nm-settings-connection-interface.h" - -G_BEGIN_DECLS - -typedef enum { - NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION = 0, - NM_SETTINGS_INTERFACE_ERROR_READ_ONLY_CONNECTION, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, - NM_SETTINGS_INTERFACE_ERROR_SECRETS_UNAVAILABLE, - NM_SETTINGS_INTERFACE_ERROR_SECRETS_REQUEST_CANCELED, - NM_SETTINGS_INTERFACE_ERROR_PERMISSION_DENIED, - NM_SETTINGS_INTERFACE_ERROR_INVALID_SETTING, -} NMSettingsInterfaceError; - -#define NM_SETTINGS_INTERFACE_ERROR (nm_settings_interface_error_quark ()) -GQuark nm_settings_interface_error_quark (void); - -#define NM_TYPE_SETTINGS_INTERFACE_ERROR (nm_settings_interface_error_get_type ()) -GType nm_settings_interface_error_get_type (void); - - -#define NM_TYPE_SETTINGS_INTERFACE (nm_settings_interface_get_type ()) -#define NM_SETTINGS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_INTERFACE, NMSettingsInterface)) -#define NM_IS_SETTINGS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS_INTERFACE)) -#define NM_SETTINGS_INTERFACE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_SETTINGS_INTERFACE, NMSettingsInterface)) - -#define NM_SETTINGS_INTERFACE_NEW_CONNECTION "new-connection" -#define NM_SETTINGS_INTERFACE_CONNECTIONS_READ "connections-read" - -typedef struct _NMSettingsInterface NMSettingsInterface; - -typedef void (*NMSettingsAddConnectionFunc) (NMSettingsInterface *settings, - GError *error, - gpointer user_data); - -struct _NMSettingsInterface { - GTypeInterface g_iface; - - /* Methods */ - /* Returns a list of objects implementing NMSettingsConnectionInterface */ - GSList * (*list_connections) (NMSettingsInterface *settings); - - NMSettingsConnectionInterface * (*get_connection_by_path) (NMSettingsInterface *settings, - const char *path); - - gboolean (*add_connection) (NMSettingsInterface *settings, - NMConnection *connection, - NMSettingsAddConnectionFunc callback, - gpointer user_data); - - /* Signals */ - void (*new_connection) (NMSettingsInterface *settings, - NMSettingsConnectionInterface *connection); - - void (*connections_read) (NMSettingsInterface *settings); - - /* Padding for future expansion */ - void (*_reserved1) (void); - void (*_reserved2) (void); - void (*_reserved3) (void); - void (*_reserved4) (void); - void (*_reserved5) (void); - void (*_reserved6) (void); -}; - -GType nm_settings_interface_get_type (void); - -/* Returns a list of objects implementing NMSettingsConnectionInterface */ -GSList *nm_settings_interface_list_connections (NMSettingsInterface *settings); - -NMSettingsConnectionInterface *nm_settings_interface_get_connection_by_path (NMSettingsInterface *settings, - const char *path); - -gboolean nm_settings_interface_add_connection (NMSettingsInterface *settings, - NMConnection *connection, - NMSettingsAddConnectionFunc callback, - gpointer user_data); - -G_END_DECLS - -#endif /* NM_SETTINGS_INTERFACE_H */ diff --git a/libnm-glib/nm-settings-service.c b/libnm-glib/nm-settings-service.c deleted file mode 100644 index 6266d10dac..0000000000 --- a/libnm-glib/nm-settings-service.c +++ /dev/null @@ -1,372 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * (C) Copyright 2008 Novell, Inc. - * (C) Copyright 2008 - 2009 Red Hat, Inc. - */ - -#include -#include -#include - -#include "nm-settings-service.h" -#include "nm-settings-interface.h" -#include "nm-exported-connection.h" - -static gboolean impl_settings_list_connections (NMSettingsService *self, - GPtrArray **connections, - GError **error); - -static void impl_settings_add_connection (NMSettingsService *self, - GHashTable *settings, - DBusGMethodInvocation *context); - -#include "nm-settings-glue.h" - -static void settings_interface_init (NMSettingsInterface *class); - -G_DEFINE_TYPE_EXTENDED (NMSettingsService, nm_settings_service, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_INTERFACE, settings_interface_init)) - -#define NM_SETTINGS_SERVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ - NM_TYPE_SETTINGS_SERVICE, \ - NMSettingsServicePrivate)) - -typedef struct { - DBusGConnection *bus; - NMConnectionScope scope; - gboolean exported; - - gboolean disposed; -} NMSettingsServicePrivate; - -enum { - PROP_0, - PROP_BUS, - PROP_SCOPE, - - LAST_PROP -}; - - -/**************************************************************/ - -void -nm_settings_service_export (NMSettingsService *self) -{ - NMSettingsServicePrivate *priv; - - g_return_if_fail (self != NULL); - g_return_if_fail (NM_IS_SETTINGS_SERVICE (self)); - - priv = NM_SETTINGS_SERVICE_GET_PRIVATE (self); - - g_return_if_fail (priv->bus != NULL); - - /* Don't allow exporting twice */ - g_return_if_fail (priv->exported == FALSE); - - dbus_g_connection_register_g_object (priv->bus, - NM_DBUS_PATH_SETTINGS, - G_OBJECT (self)); - priv->exported = TRUE; -} - -/**************************************************************/ - -static GSList * -list_connections (NMSettingsInterface *settings) -{ - /* Must always be implemented */ - g_assert (NM_SETTINGS_SERVICE_GET_CLASS (settings)->list_connections); - return NM_SETTINGS_SERVICE_GET_CLASS (settings)->list_connections (NM_SETTINGS_SERVICE (settings)); -} - -static gboolean -impl_settings_list_connections (NMSettingsService *self, - GPtrArray **connections, - GError **error) -{ - GSList *list = NULL, *iter; - - list = list_connections (NM_SETTINGS_INTERFACE (self)); - *connections = g_ptr_array_sized_new (g_slist_length (list) + 1); - for (iter = list; iter; iter = g_slist_next (iter)) { - g_ptr_array_add (*connections, - g_strdup (nm_connection_get_path (NM_CONNECTION (iter->data)))); - } - g_slist_free (list); - return TRUE; -} - -static NMSettingsConnectionInterface * -get_connection_by_path (NMSettingsInterface *settings, const char *path) -{ - NMExportedConnection *connection = NULL; - GSList *list = NULL, *iter; - - list = list_connections (settings); - for (iter = list; iter; iter = g_slist_next (iter)) { - if (!strcmp (nm_connection_get_path (NM_CONNECTION (iter->data)), path)) { - connection = NM_EXPORTED_CONNECTION (iter->data); - break; - } - } - g_slist_free (list); - - return (NMSettingsConnectionInterface *) connection; -} - -NMExportedConnection * -nm_settings_service_get_connection_by_path (NMSettingsService *self, - const char *path) -{ - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (NM_IS_SETTINGS_SERVICE (self), NULL); - - return (NMExportedConnection *) get_connection_by_path (NM_SETTINGS_INTERFACE (self), path); -} - -static gboolean -add_connection (NMSettingsInterface *settings, - NMConnection *connection, - NMSettingsAddConnectionFunc callback, - gpointer user_data) -{ - NMSettingsService *self = NM_SETTINGS_SERVICE (settings); - GError *error = NULL; - gboolean success = FALSE; - - if (NM_SETTINGS_SERVICE_GET_CLASS (self)->add_connection) { - NM_SETTINGS_SERVICE_GET_CLASS (self)->add_connection (NM_SETTINGS_SERVICE (self), - connection, - NULL, - callback, - user_data); - success = TRUE; - } else { - error = g_error_new (NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, - "%s: %s:%d add_connection() not implemented", - __func__, __FILE__, __LINE__); - callback (settings, error, user_data); - g_error_free (error); - } - - return success; -} - -static void -dbus_add_connection_cb (NMSettingsInterface *settings, - GError *error, - gpointer user_data) -{ - DBusGMethodInvocation *context = user_data; - - if (error) - dbus_g_method_return_error (context, error); - else - dbus_g_method_return (context); -} - -static void -impl_settings_add_connection (NMSettingsService *self, - GHashTable *settings, - DBusGMethodInvocation *context) -{ - NMConnection *tmp; - GError *error = NULL; - - /* Check if the settings are valid first */ - tmp = nm_connection_new_from_hash (settings, &error); - if (!tmp) { - g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - if (NM_SETTINGS_SERVICE_GET_CLASS (self)->add_connection) { - NM_SETTINGS_SERVICE_GET_CLASS (self)->add_connection (NM_SETTINGS_SERVICE (self), - tmp, - context, - dbus_add_connection_cb, - context); - } else { - error = g_error_new (NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, - "%s: %s:%d add_connection() not implemented", - __func__, __FILE__, __LINE__); - dbus_g_method_return_error (context, error); - g_error_free (error); - } - - g_object_unref (tmp); -} - -void -nm_settings_service_export_connection (NMSettingsService *self, - NMSettingsConnectionInterface *connection) -{ - NMSettingsServicePrivate *priv = NM_SETTINGS_SERVICE_GET_PRIVATE (self); - static guint32 ec_counter = 0; - char *path; - - g_return_if_fail (connection != NULL); - g_return_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection)); - g_return_if_fail (priv->bus != NULL); - - /* Don't allow exporting twice */ - g_return_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); - - path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, ec_counter++); - nm_connection_set_path (NM_CONNECTION (connection), path); - nm_connection_set_scope (NM_CONNECTION (connection), priv->scope); - - dbus_g_connection_register_g_object (priv->bus, path, G_OBJECT (connection)); - g_free (path); -} - -/**************************************************************/ - -static void -settings_interface_init (NMSettingsInterface *iface) -{ - /* interface implementation */ - iface->list_connections = list_connections; - iface->get_connection_by_path = get_connection_by_path; - iface->add_connection = add_connection; - - dbus_g_object_type_install_info (G_TYPE_FROM_INTERFACE (iface), - &dbus_glib_nm_settings_object_info); -} - -static GObject * -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) -{ - GObject *object; - - object = G_OBJECT_CLASS (nm_settings_service_parent_class)->constructor (type, n_construct_params, construct_params); - if (object) { - g_assert (NM_SETTINGS_SERVICE_GET_PRIVATE (object)->scope != NM_CONNECTION_SCOPE_UNKNOWN); - } - return object; -} - -static void -nm_settings_service_init (NMSettingsService *self) -{ -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMSettingsServicePrivate *priv = NM_SETTINGS_SERVICE_GET_PRIVATE (object); - DBusGConnection *bus; - - switch (prop_id) { - case PROP_BUS: - /* Construct only */ - bus = g_value_get_boxed (value); - if (bus) - priv->bus = dbus_g_connection_ref (bus); - break; - case PROP_SCOPE: - /* Construct only */ - priv->scope = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMSettingsServicePrivate *priv = NM_SETTINGS_SERVICE_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_BUS: - g_value_set_boxed (value, priv->bus); - break; - case PROP_SCOPE: - g_value_set_uint (value, priv->scope); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -dispose (GObject *object) -{ - NMSettingsServicePrivate *priv = NM_SETTINGS_SERVICE_GET_PRIVATE (object); - - if (!priv->disposed) { - priv->disposed = TRUE; - if (priv->bus) - dbus_g_connection_unref (priv->bus); - } - - G_OBJECT_CLASS (nm_settings_service_parent_class)->dispose (object); -} - -static void -nm_settings_service_class_init (NMSettingsServiceClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - - g_type_class_add_private (class, sizeof (NMSettingsServicePrivate)); - - /* Virtual methods */ - object_class->dispose = dispose; - object_class->constructor = constructor; - object_class->get_property = get_property; - object_class->set_property = set_property; - - /** - * NMSettingsService:bus: - * - * The %DBusGConnection which this object is exported on - **/ - g_object_class_install_property (object_class, PROP_BUS, - g_param_spec_boxed (NM_SETTINGS_SERVICE_BUS, - "Bus", - "Bus", - DBUS_TYPE_G_CONNECTION, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - /** - * NMSettingsService:scope: - * - * The capabilities of the device. - **/ - g_object_class_install_property (object_class, PROP_SCOPE, - g_param_spec_uint (NM_SETTINGS_SERVICE_SCOPE, - "Scope", - "Scope", - NM_CONNECTION_SCOPE_SYSTEM, - NM_CONNECTION_SCOPE_USER, - NM_CONNECTION_SCOPE_USER, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} diff --git a/libnm-glib/nm-settings-service.h b/libnm-glib/nm-settings-service.h deleted file mode 100644 index 9f4b95fcc5..0000000000 --- a/libnm-glib/nm-settings-service.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * (C) Copyright 2009 Red Hat, Inc. - */ - -#ifndef NM_SETTINGS_SERVICE_H -#define NM_SETTINGS_SERVICE_H - -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define NM_TYPE_SETTINGS_SERVICE (nm_settings_service_get_type ()) -#define NM_SETTINGS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_SERVICE, NMSettingsService)) -#define NM_SETTINGS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTINGS_SERVICE, NMSettingsServiceClass)) -#define NM_IS_SETTINGS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS_SERVICE)) -#define NM_IS_SETTINGS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SETTINGS_SERVICE)) -#define NM_SETTINGS_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTINGS_SERVICE, NMSettingsServiceClass)) - -#define NM_SETTINGS_SERVICE_BUS "bus" -#define NM_SETTINGS_SERVICE_SCOPE "scope" - -typedef struct { - GObject parent; -} NMSettingsService; - -typedef struct { - GObjectClass parent; - - /* Returned list must contain all NMExportedConnection objects exported - * by the settings service. The list (but not the NMExportedConnection - * objects) will be freed by caller. - */ - GSList * (*list_connections) (NMSettingsService *self); - - void (*add_connection) (NMSettingsService *self, - NMConnection *connection, - DBusGMethodInvocation *context, /* Only present for D-Bus calls */ - NMSettingsAddConnectionFunc callback, - gpointer user_data); - - /* Padding for future expansion */ - void (*_reserved1) (void); - void (*_reserved2) (void); - void (*_reserved3) (void); - void (*_reserved4) (void); - void (*_reserved5) (void); - void (*_reserved6) (void); -} NMSettingsServiceClass; - -GType nm_settings_service_get_type (void); - -NMExportedConnection *nm_settings_service_get_connection_by_path (NMSettingsService *self, - const char *path); - -void nm_settings_service_export (NMSettingsService *self); - -void nm_settings_service_export_connection (NMSettingsService *self, - NMSettingsConnectionInterface *exported); - -G_END_DECLS - -#endif /* NM_SETTINGS_SERVICE_H */ diff --git a/libnm-glib/nm-settings-system-interface.c b/libnm-glib/nm-settings-system-interface.c deleted file mode 100644 index 0f59377a53..0000000000 --- a/libnm-glib/nm-settings-system-interface.c +++ /dev/null @@ -1,150 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2008 Red Hat, Inc. - */ - -#include "nm-settings-interface.h" -#include "nm-settings-system-interface.h" - - -/** - * nm_settings_system_interface_save_hostname: - * @settings: a object implementing %NMSettingsSystemInterface - * @hostname: the new persistent hostname to set, or NULL to clear any existing - * persistent hostname - * @callback: callback to be called when the hostname operation completes - * @user_data: caller-specific data passed to @callback - * - * Requests that the machine's persistent hostname be set to the specified value - * or cleared. - * - * Returns: TRUE if the request was successful, FALSE if it failed - **/ -gboolean -nm_settings_system_interface_save_hostname (NMSettingsSystemInterface *settings, - const char *hostname, - NMSettingsSystemSaveHostnameFunc callback, - gpointer user_data) -{ - g_return_val_if_fail (settings != NULL, FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_SYSTEM_INTERFACE (settings), FALSE); - g_return_val_if_fail (hostname != NULL, FALSE); - g_return_val_if_fail (callback != NULL, FALSE); - - if (NM_SETTINGS_SYSTEM_INTERFACE_GET_INTERFACE (settings)->save_hostname) { - return NM_SETTINGS_SYSTEM_INTERFACE_GET_INTERFACE (settings)->save_hostname (settings, - hostname, - callback, - user_data); - } - return FALSE; -} - -/** - * nm_settings_system_interface_get_permissions: - * @settings: a object implementing %NMSettingsSystemInterface - * @callback: callback to be called when the permissions operation completes - * @user_data: caller-specific data passed to @callback - * - * Requests an indication of the operations the caller is permitted to perform - * including those that may require authorization. - * - * Returns: TRUE if the request was successful, FALSE if it failed - **/ -gboolean -nm_settings_system_interface_get_permissions (NMSettingsSystemInterface *settings, - NMSettingsSystemGetPermissionsFunc callback, - gpointer user_data) -{ - g_return_val_if_fail (settings != NULL, FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_SYSTEM_INTERFACE (settings), FALSE); - g_return_val_if_fail (callback != NULL, FALSE); - - if (NM_SETTINGS_SYSTEM_INTERFACE_GET_INTERFACE (settings)->get_permissions) - return NM_SETTINGS_SYSTEM_INTERFACE_GET_INTERFACE (settings)->get_permissions (settings, callback, user_data); - return FALSE; -} - -static void -nm_settings_system_interface_init (gpointer g_iface) -{ - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; - - if (initialized) - return; - - /* Properties */ - g_object_interface_install_property - (g_iface, - g_param_spec_string (NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME, - "Hostname", - "Persistent hostname", - NULL, - G_PARAM_READABLE)); - - g_object_interface_install_property - (g_iface, - g_param_spec_boolean (NM_SETTINGS_SYSTEM_INTERFACE_CAN_MODIFY, - "CanModify", - "Can modify anything (hostname, connections, etc)", - FALSE, - G_PARAM_READABLE)); - - /* Signals */ - g_signal_new (NM_SETTINGS_SYSTEM_INTERFACE_CHECK_PERMISSIONS, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsSystemInterface, check_permissions), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - initialized = TRUE; -} - -GType -nm_settings_system_interface_get_type (void) -{ - static GType itype = 0; - - if (!itype) { - const GTypeInfo iinfo = { - sizeof (NMSettingsSystemInterface), /* class_size */ - nm_settings_system_interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - itype = g_type_register_static (G_TYPE_INTERFACE, - "NMSettingsSystemInterface", - &iinfo, 0); - - g_type_interface_add_prerequisite (itype, NM_TYPE_SETTINGS_INTERFACE); - } - - return itype; -} - diff --git a/libnm-glib/nm-settings-system-interface.h b/libnm-glib/nm-settings-system-interface.h deleted file mode 100644 index d016556123..0000000000 --- a/libnm-glib/nm-settings-system-interface.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2009 Red Hat, Inc. - */ - -#ifndef NM_SETTINGS_SYSTEM_INTERFACE_H -#define NM_SETTINGS_SYSTEM_INTERFACE_H - -#include - -#include "NetworkManager.h" - -G_BEGIN_DECLS - -typedef enum { - NM_SETTINGS_SYSTEM_PERMISSION_NONE = 0x0, - NM_SETTINGS_SYSTEM_PERMISSION_CONNECTION_MODIFY = 0x1, - NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_PROTECTED = 0x2, - NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_OPEN = 0x4, - NM_SETTINGS_SYSTEM_PERMISSION_HOSTNAME_MODIFY = 0x8 -} NMSettingsSystemPermissions; - -#define NM_TYPE_SETTINGS_SYSTEM_INTERFACE (nm_settings_system_interface_get_type ()) -#define NM_SETTINGS_SYSTEM_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_SYSTEM_INTERFACE, NMSettingsSystemInterface)) -#define NM_IS_SETTINGS_SYSTEM_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS_SYSTEM_INTERFACE)) -#define NM_SETTINGS_SYSTEM_INTERFACE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_SETTINGS_SYSTEM_INTERFACE, NMSettingsSystemInterface)) - -#define NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME "hostname" -#define NM_SETTINGS_SYSTEM_INTERFACE_CAN_MODIFY "can-modify" - -#define NM_SETTINGS_SYSTEM_INTERFACE_CHECK_PERMISSIONS "check-permissions" - -typedef enum { - NM_SETTINGS_SYSTEM_INTERFACE_PROP_FIRST = 0x1000, - - NM_SETTINGS_SYSTEM_INTERFACE_PROP_HOSTNAME = NM_SETTINGS_SYSTEM_INTERFACE_PROP_FIRST, - NM_SETTINGS_SYSTEM_INTERFACE_PROP_CAN_MODIFY -} NMSettingsSystemInterfaceProp; - - -typedef struct _NMSettingsSystemInterface NMSettingsSystemInterface; - - -typedef void (*NMSettingsSystemSaveHostnameFunc) (NMSettingsSystemInterface *settings, - GError *error, - gpointer user_data); - -typedef void (*NMSettingsSystemGetPermissionsFunc) (NMSettingsSystemInterface *settings, - NMSettingsSystemPermissions permissions, - GError *error, - gpointer user_data); - -struct _NMSettingsSystemInterface { - GTypeInterface g_iface; - - /* Methods */ - gboolean (*save_hostname) (NMSettingsSystemInterface *settings, - const char *hostname, - NMSettingsSystemSaveHostnameFunc callback, - gpointer user_data); - - gboolean (*get_permissions) (NMSettingsSystemInterface *settings, - NMSettingsSystemGetPermissionsFunc callback, - gpointer user_data); - - /* Signals */ - void (*check_permissions) (NMSettingsSystemInterface *settings); - - /* Padding for future expansion */ - void (*_reserved1) (void); - void (*_reserved2) (void); - void (*_reserved3) (void); - void (*_reserved4) (void); - void (*_reserved5) (void); - void (*_reserved6) (void); -}; - -GType nm_settings_system_interface_get_type (void); - -gboolean nm_settings_system_interface_save_hostname (NMSettingsSystemInterface *settings, - const char *hostname, - NMSettingsSystemSaveHostnameFunc callback, - gpointer user_data); - -gboolean nm_settings_system_interface_get_permissions (NMSettingsSystemInterface *settings, - NMSettingsSystemGetPermissionsFunc callback, - gpointer user_data); - -G_END_DECLS - -#endif /* NM_SETTINGS_SYSTEM_INTERFACE_H */ diff --git a/libnm-glib/nm-types.c b/libnm-glib/nm-types.c index cf9e084c77..923c436b18 100644 --- a/libnm-glib/nm-types.c +++ b/libnm-glib/nm-types.c @@ -52,7 +52,7 @@ nm_ssid_get_type (void) static GType our_type = 0; if (our_type == 0) - our_type = g_boxed_type_register_static (g_intern_static_string ("nm-ssid"), + our_type = g_boxed_type_register_static (g_intern_static_string ("NMSsid"), (GBoxedCopyFunc) nm_ssid_copy, (GBoxedFreeFunc) nm_ssid_free); return our_type; @@ -105,7 +105,7 @@ nm_uint_array_get_type (void) static GType our_type = 0; if (our_type == 0) - our_type = g_boxed_type_register_static (g_intern_static_string ("nm-uint-array"), + our_type = g_boxed_type_register_static (g_intern_static_string ("NMUintArray"), (GBoxedCopyFunc) nm_uint_array_copy, (GBoxedFreeFunc) nm_uint_array_free); return our_type; @@ -163,7 +163,7 @@ nm_string_array_get_type (void) static GType our_type = 0; if (our_type == 0) - our_type = g_boxed_type_register_static (g_intern_static_string ("nm-string-array"), + our_type = g_boxed_type_register_static (g_intern_static_string ("NMStringArray"), (GBoxedCopyFunc) nm_string_array_copy, (GBoxedFreeFunc) nm_string_array_free); return our_type; @@ -224,7 +224,7 @@ nm_object_array_get_type (void) static GType our_type = 0; if (our_type == 0) - our_type = g_boxed_type_register_static (g_intern_static_string ("nm-object-array"), + our_type = g_boxed_type_register_static (g_intern_static_string ("NMObjectArray"), (GBoxedCopyFunc) nm_object_array_copy, (GBoxedFreeFunc) nm_object_array_free); return our_type; @@ -306,7 +306,7 @@ nm_ip6_address_object_array_get_type (void) static GType our_type = 0; if (our_type == 0) - our_type = g_boxed_type_register_static (g_intern_static_string ("nm-ip6-address-object-array"), + our_type = g_boxed_type_register_static (g_intern_static_string ("NMIP6AddressObjectArray"), (GBoxedCopyFunc) nm_ip6_address_object_array_copy, (GBoxedFreeFunc) nm_ip6_address_object_array_free); return our_type; @@ -348,7 +348,7 @@ nm_ip6_address_array_get_type (void) static GType our_type = 0; if (our_type == 0) - our_type = g_boxed_type_register_static (g_intern_static_string ("nm-ip6-address-array"), + our_type = g_boxed_type_register_static (g_intern_static_string ("NMIP6AddressArray"), (GBoxedCopyFunc) nm_ip6_address_array_copy, (GBoxedFreeFunc) nm_ip6_address_array_free); return our_type; @@ -415,7 +415,7 @@ nm_ip6_route_object_array_get_type (void) static GType our_type = 0; if (our_type == 0) - our_type = g_boxed_type_register_static (g_intern_static_string ("nm-ip6-route-object-array"), + our_type = g_boxed_type_register_static (g_intern_static_string ("NMIP6RouteObjectArray"), (GBoxedCopyFunc) nm_ip6_route_object_array_copy, (GBoxedFreeFunc) nm_ip6_route_object_array_free); return our_type; diff --git a/libnm-glib/nm-vpn-plugin-utils.c b/libnm-glib/nm-vpn-plugin-utils.c new file mode 100644 index 0000000000..8234a91978 --- /dev/null +++ b/libnm-glib/nm-vpn-plugin-utils.c @@ -0,0 +1,188 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2011 Red Hat, Inc. + */ + +#include +#include +#include +#include + +#include "nm-vpn-plugin-utils.h" +#include "nm-setting-private.h" + +#define DATA_KEY_TAG "DATA_KEY=" +#define DATA_VAL_TAG "DATA_VAL=" +#define SECRET_KEY_TAG "SECRET_KEY=" +#define SECRET_VAL_TAG "SECRET_VAL=" + +static void +free_secret (gpointer data) +{ + char *secret = data; + + memset (secret, 0, strlen (secret)); + g_free (secret); +} + +/** + * nm_vpn_plugin_utils_read_vpn_details: + * @fd: file descriptor to read from, usually stdin (0) + * @out_data: (out) (transfer full): on successful return, a hash table + * (mapping char*:char*) containing the key/value pairs of VPN data items + * @out_secrets: (out) (transfer full): on successful return, a hash table + * (mapping char*:char*) containing the key/value pairsof VPN secrets + * + * Parses key/value pairs from a file descriptor (normally stdin) passed by + * an applet when the applet calls the authentication dialog of the VPN plugin. + * + * Returns: %TRUE if reading values was successful, %FALSE if not + **/ +gboolean +nm_vpn_plugin_utils_read_vpn_details (int fd, + GHashTable **out_data, + GHashTable **out_secrets) +{ + GHashTable *data, *secrets; + gboolean success = FALSE; + char *key = NULL, *val = NULL; + GString *line; + gchar c; + + if (out_data) + g_return_val_if_fail (*out_data == NULL, FALSE); + if (out_secrets) + g_return_val_if_fail (*out_secrets == NULL, FALSE); + + data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_secret); + + line = g_string_new (NULL); + + /* Read stdin for data and secret items until we get a DONE */ + while (1) { + ssize_t nr; + GHashTable *hash = NULL; + + errno = 0; + nr = read (fd, &c, 1); + if (nr == -1) { + if (errno == EAGAIN) { + g_usleep (100); + continue; + } + break; + } + + if (c != '\n') { + g_string_append_c (line, c); + continue; + } + + /* Check for the finish marker */ + if (strcmp (line->str, "DONE") == 0) + break; + + /* Otherwise it's a data/secret item */ + if (strncmp (line->str, DATA_KEY_TAG, strlen (DATA_KEY_TAG)) == 0) { + hash = data; + key = g_strdup (line->str + strlen (DATA_KEY_TAG)); + } else if (strncmp (line->str, DATA_VAL_TAG, strlen (DATA_VAL_TAG)) == 0) { + hash = data; + val = g_strdup (line->str + strlen (DATA_VAL_TAG)); + } else if (strncmp (line->str, SECRET_KEY_TAG, strlen (SECRET_KEY_TAG)) == 0) { + hash = secrets; + key = g_strdup (line->str + strlen (SECRET_KEY_TAG)); + } else if (strncmp (line->str, SECRET_VAL_TAG, strlen (SECRET_VAL_TAG)) == 0) { + hash = secrets; + val = g_strdup (line->str + strlen (SECRET_VAL_TAG)); + } + g_string_truncate (line, 0); + + if (key && val && hash) { + g_hash_table_insert (hash, key, val); + key = NULL; + val = NULL; + success = TRUE; /* Got at least one value */ + } + } + + if (success) { + if (out_data) + *out_data = data; + else + g_hash_table_destroy (data); + + if (out_secrets) + *out_secrets = secrets; + else + g_hash_table_destroy (secrets); + } else { + g_hash_table_destroy (data); + g_hash_table_destroy (secrets); + } + + g_string_free (line, TRUE); + return success; +} + +/** + * nm_vpn_plugin_utils_get_secret_flags: + * @data: hash table containing VPN key/value pair data items + * @secret_name: VPN secret key name for which to retrieve flags for + * @out_flags: (out): on success, the flags associated with @secret_name + * + * Given a VPN secret key name, attempts to find the corresponding flags data + * item in @data. If found, converts the flags data item to + * #NMSettingSecretFlags and returns it. + * + * Returns: %TRUE if the flag data item was found and successfully converted + * to flags, %FALSE if not + **/ +gboolean +nm_vpn_plugin_utils_get_secret_flags (GHashTable *data, + const char *secret_name, + NMSettingSecretFlags *out_flags) +{ + char *flag_name; + const char *val; + unsigned long tmp; + gboolean success = FALSE; + + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (secret_name != NULL, FALSE); + g_return_val_if_fail (out_flags != NULL, FALSE); + g_return_val_if_fail (*out_flags == NM_SETTING_SECRET_FLAG_NONE, FALSE); + + flag_name = g_strdup_printf ("%s-flags", secret_name); + + /* Try new flags value first */ + val = g_hash_table_lookup (data, flag_name); + if (val) { + errno = 0; + tmp = strtoul (val, NULL, 10); + if (errno == 0 && tmp <= NM_SETTING_SECRET_FLAGS_ALL) { + *out_flags = (NMSettingSecretFlags) tmp; + success = TRUE; + } + } + + g_free (flag_name); + return success; +} + diff --git a/libnm-glib/nm-vpn-plugin-utils.h b/libnm-glib/nm-vpn-plugin-utils.h new file mode 100644 index 0000000000..aab73c4e68 --- /dev/null +++ b/libnm-glib/nm-vpn-plugin-utils.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2011 Red Hat, Inc. + */ + +#ifndef NM_VPN_PLUGIN_UTILS_H +#define NM_VPN_PLUGIN_UTILS_H + +#include +#include + +G_BEGIN_DECLS + +gboolean nm_vpn_plugin_utils_read_vpn_details (int fd, + GHashTable **out_data, + GHashTable **out_secrets); + +gboolean nm_vpn_plugin_utils_get_secret_flags (GHashTable *data, + const char *secret_name, + NMSettingSecretFlags *out_flags); + +G_END_DECLS + +#endif /* NM_VPN_PLUGIN_UTILS_H */ diff --git a/libnm-glib/tests/Makefile.am b/libnm-glib/tests/Makefile.am new file mode 100644 index 0000000000..06aee71252 --- /dev/null +++ b/libnm-glib/tests/Makefile.am @@ -0,0 +1,35 @@ +INCLUDES = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/libnm-util \ + -I$(top_srcdir)/libnm-glib + +noinst_PROGRAMS = test-remote-settings-client + +####### remote settings client test ####### + +test_remote_settings_client_SOURCES = \ + test-remote-settings-client.c + +test_remote_settings_client_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) + +test_remote_settings_client_LDADD = \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(top_builddir)/libnm-glib/libnm-glib-test.la \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) + +########################################### + +TEST_RSS_BIN = test-remote-settings-service.py + +EXTRA_DIST = $(TEST_RSS_BIN) + +if WITH_TESTS + +check-local: test-remote-settings-client + $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN) + +endif + diff --git a/libnm-glib/tests/test-remote-settings-client.c b/libnm-glib/tests/test-remote-settings-client.c new file mode 100644 index 0000000000..ad62075d41 --- /dev/null +++ b/libnm-glib/tests/test-remote-settings-client.c @@ -0,0 +1,406 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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, 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 (C) 2010 - 2011 Red Hat, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "nm-remote-settings.h" + +static GPid spid = 0; +static NMRemoteSettings *settings = NULL; +DBusGConnection *bus = NULL; +NMRemoteConnection *remote = NULL; + +/*******************************************************************/ + +static void +cleanup (void) +{ + if (settings) + g_object_unref (settings); + kill (spid, SIGTERM); +} + +#define test_assert(condition) \ +do { \ + if (!G_LIKELY (condition)) \ + cleanup (); \ + g_assert (condition); \ +} while (0) + +/*******************************************************************/ + +static void +add_cb (NMRemoteSettings *s, + NMRemoteConnection *connection, + GError *error, + gpointer user_data) +{ + if (error) + g_warning ("Add error: %s", error->message); + + *((gboolean *) user_data) = TRUE; + remote = connection; +} + +#define TEST_CON_ID "blahblahblah" + +static void +test_add_connection (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + char *uuid; + gboolean success; + time_t start, now; + gboolean done = FALSE; + + connection = nm_connection_new (); + + s_con = (NMSettingConnection *) nm_setting_connection_new (); + uuid = nm_utils_uuid_generate (); + g_object_set (G_OBJECT (s_con), + NM_SETTING_CONNECTION_ID, TEST_CON_ID, + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NULL); + g_free (uuid); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + success = nm_remote_settings_add_connection (settings, + connection, + add_cb, + &done); + test_assert (success == TRUE); + + start = time (NULL); + do { + now = time (NULL); + g_main_context_iteration (NULL, FALSE); + } while ((done == FALSE) && (now - start < 5)); + test_assert (done == TRUE); + test_assert (remote != NULL); + + /* Make sure the connection is the same as what we added */ + test_assert (nm_connection_compare (connection, + NM_CONNECTION (remote), + NM_SETTING_COMPARE_FLAG_EXACT) == TRUE); +} + +/*******************************************************************/ + +static void +set_visible_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) +{ + GError *error = NULL; + gboolean success; + + success = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); + if (!success) + g_warning ("Failed to change connection visibility: %s", error->message); + test_assert (success == TRUE); + test_assert (error == NULL); +} + +static void +invis_removed_cb (NMRemoteConnection *connection, gboolean *done) +{ + *done = TRUE; +} + +static void +invis_has_settings_cb (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) +{ + *((gboolean *) user_data) = TRUE; +} + +static void +test_make_invisible (void) +{ + time_t start, now; + GSList *list, *iter; + DBusGProxy *proxy; + gboolean done = FALSE, has_settings = FALSE; + char *path; + + test_assert (remote != NULL); + + /* Listen for the remove event when the connection becomes invisible */ + g_signal_connect (remote, "removed", G_CALLBACK (invis_removed_cb), &done); + + path = g_strdup (nm_connection_get_path (NM_CONNECTION (remote))); + proxy = dbus_g_proxy_new_for_name (bus, + NM_DBUS_SERVICE, + path, + NM_DBUS_IFACE_SETTINGS_CONNECTION); + test_assert (proxy != NULL); + + /* Bypass the NMRemoteSettings object so we can test it independently */ + dbus_g_proxy_begin_call (proxy, "SetVisible", set_visible_cb, NULL, NULL, + G_TYPE_BOOLEAN, FALSE, G_TYPE_INVALID); + + /* Wait for the connection to be removed */ + start = time (NULL); + do { + now = time (NULL); + g_main_context_iteration (NULL, FALSE); + } while ((done == FALSE) && (now - start < 5)); + test_assert (done == TRUE); + + /* Ensure NMRemoteSettings no longer has the connection */ + list = nm_remote_settings_list_connections (settings); + for (iter = list; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = NM_CONNECTION (iter->data); + + test_assert ((gpointer) remote != (gpointer) candidate); + test_assert (strcmp (path, nm_connection_get_path (candidate)) != 0); + } + + /* And ensure the invisible connection no longer has any settings */ + nm_connection_for_each_setting_value (NM_CONNECTION (remote), + invis_has_settings_cb, + &has_settings); + test_assert (has_settings == FALSE); + + g_free (path); + g_object_unref (proxy); +} + +/*******************************************************************/ + +static void +vis_new_connection_cb (NMRemoteSettings *foo, + NMRemoteConnection *connection, + NMRemoteConnection **new) +{ + *new = connection; +} + +static void +test_make_visible (void) +{ + time_t start, now; + GSList *list, *iter; + DBusGProxy *proxy; + gboolean found = FALSE; + char *path; + NMRemoteConnection *new = NULL; + + test_assert (remote != NULL); + + /* Wait for the new-connection signal when the connection is visible again */ + g_signal_connect (settings, NM_REMOTE_SETTINGS_NEW_CONNECTION, + G_CALLBACK (vis_new_connection_cb), &new); + + path = g_strdup (nm_connection_get_path (NM_CONNECTION (remote))); + proxy = dbus_g_proxy_new_for_name (bus, + NM_DBUS_SERVICE, + path, + NM_DBUS_IFACE_SETTINGS_CONNECTION); + test_assert (proxy != NULL); + + /* Bypass the NMRemoteSettings object so we can test it independently */ + dbus_g_proxy_begin_call (proxy, "SetVisible", set_visible_cb, NULL, NULL, + G_TYPE_BOOLEAN, TRUE, G_TYPE_INVALID); + + + /* Wait for the settings service to announce the connection again */ + start = time (NULL); + do { + now = time (NULL); + g_main_context_iteration (NULL, FALSE); + } while ((new == NULL) && (now - start < 5)); + + /* Ensure the new connection is the same as the one we made visible again */ + test_assert (new == remote); + + /* Ensure NMRemoteSettings has the connection */ + list = nm_remote_settings_list_connections (settings); + for (iter = list; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = NM_CONNECTION (iter->data); + + if ((gpointer) remote == (gpointer) candidate) { + test_assert (strcmp (path, nm_connection_get_path (candidate)) == 0); + test_assert (strcmp (TEST_CON_ID, nm_connection_get_id (candidate)) == 0); + found = TRUE; + break; + } + } + test_assert (found == TRUE); + + g_free (path); + g_object_unref (proxy); +} + +/*******************************************************************/ + +static void +deleted_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) +{ + GError *error = NULL; + gboolean success; + + success = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); + if (!success) + g_warning ("Failed to delete connection: %s", error->message); + test_assert (success == TRUE); + test_assert (error == NULL); +} + +static void +removed_cb (NMRemoteConnection *connection, gboolean *done) +{ + *done = TRUE; +} + +static void +test_remove_connection (void) +{ + NMRemoteConnection *connection; + time_t start, now; + GSList *list, *iter; + DBusGProxy *proxy; + gboolean done = FALSE; + char *path; + + /* Find a connection to delete */ + list = nm_remote_settings_list_connections (settings); + test_assert (g_slist_length (list) > 0); + + connection = NM_REMOTE_CONNECTION (list->data); + path = g_strdup (nm_connection_get_path (NM_CONNECTION (connection))); + g_signal_connect (connection, "removed", G_CALLBACK (removed_cb), &done); + + proxy = dbus_g_proxy_new_for_name (bus, + NM_DBUS_SERVICE, + path, + NM_DBUS_IFACE_SETTINGS_CONNECTION); + test_assert (proxy != NULL); + + /* Bypass the NMRemoteSettings object so we can test it independently */ + dbus_g_proxy_begin_call (proxy, "Delete", deleted_cb, NULL, NULL, G_TYPE_INVALID); + + start = time (NULL); + do { + now = time (NULL); + g_main_context_iteration (NULL, FALSE); + } while ((done == FALSE) && (now - start < 5)); + test_assert (done == TRUE); + + /* Ensure NMRemoteSettings no longer has the connection */ + list = nm_remote_settings_list_connections (settings); + for (iter = list; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = NM_CONNECTION (iter->data); + + test_assert ((gpointer) connection != (gpointer) candidate); + test_assert (strcmp (path, nm_connection_get_path (candidate)) != 0); + } + + g_free (path); + g_object_unref (proxy); +} + +/*******************************************************************/ + +#if GLIB_CHECK_VERSION(2,25,12) +typedef GTestFixtureFunc TCFunc; +#else +typedef void (*TCFunc)(void); +#endif + +#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL) + +int main (int argc, char **argv) +{ + GTestSuite *suite; + char *service_argv[3] = { NULL, NULL, NULL }; + int ret; + GError *error = NULL; + int i = 100; + + g_assert (argc == 3); + + g_type_init (); + + g_test_init (&argc, &argv, NULL); + + bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (!bus) { + g_warning ("Error connecting to D-Bus: %s", error->message); + g_assert (error == NULL); + } + + service_argv[0] = g_strdup_printf ("%s/%s", argv[1], argv[2]); + if (!g_spawn_async (argv[1], service_argv, NULL, 0, NULL, NULL, &spid, &error)) { + g_warning ("Error spawning %s: %s", argv[2], error->message); + g_assert (error == NULL); + } + + /* Wait until the service is registered on the bus */ + while (i > 0) { + g_usleep (G_USEC_PER_SEC / 50); + if (dbus_bus_name_has_owner (dbus_g_connection_get_connection (bus), + "org.freedesktop.NetworkManager", + NULL)) + break; + i--; + } + test_assert (i > 0); + + settings = nm_remote_settings_new (bus); + test_assert (settings != NULL); + + suite = g_test_get_root (); + + g_test_suite_add (suite, TESTCASE (test_add_connection, NULL)); + g_test_suite_add (suite, TESTCASE (test_make_invisible, NULL)); + g_test_suite_add (suite, TESTCASE (test_make_visible, NULL)); + g_test_suite_add (suite, TESTCASE (test_remove_connection, NULL)); + + ret = g_test_run (); + + cleanup (); + + return ret; +} + diff --git a/libnm-glib/tests/test-remote-settings-service.py b/libnm-glib/tests/test-remote-settings-service.py new file mode 100755 index 0000000000..e6bd798f92 --- /dev/null +++ b/libnm-glib/tests/test-remote-settings-service.py @@ -0,0 +1,131 @@ +#!/bin/env python +# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +import glib +import gobject +import sys +import dbus +import dbus.service +import dbus.mainloop.glib + +IFACE_SETTINGS = 'org.freedesktop.NetworkManager.Settings' +IFACE_CONNECTION = 'org.freedesktop.NetworkManager.Settings.Connection' +IFACE_DBUS = 'org.freedesktop.DBus' + +class UnknownInterfaceException(dbus.DBusException): + _dbus_error_name = IFACE_DBUS + '.UnknownInterface' + +class UnknownPropertyException(dbus.DBusException): + _dbus_error_name = IFACE_DBUS + '.UnknownProperty' + +class PermissionDeniedException(dbus.DBusException): + _dbus_error_name = IFACE_SETTINGS + '.PermissionDenied' + +mainloop = gobject.MainLoop() + +class Connection(dbus.service.Object): + def __init__(self, bus, object_path, settings, remove_func): + dbus.service.Object.__init__(self, bus, object_path) + self.path = object_path + self.settings = settings + self.remove_func = remove_func + self.visible = True + + @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='a{sa{sv}}') + def GetSettings(self): + if not self.visible: + raise PermissionDeniedException() + return self.settings + + @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='b', out_signature='') + def SetVisible(self, vis): + self.visible = vis + self.Updated() + + @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='') + def Delete(self): + self.remove_func(self) + self.Removed() + + @dbus.service.signal(IFACE_CONNECTION, signature='') + def Removed(self): + pass + + @dbus.service.signal(IFACE_CONNECTION, signature='') + def Updated(self): + pass + +class Settings(dbus.service.Object): + def __init__(self, bus, object_path): + dbus.service.Object.__init__(self, bus, object_path) + self.connections = {} + self.bus = bus + self.counter = 1 + self.props = {} + self.props['Hostname'] = "foobar.baz" + self.props['CanModify'] = True + + @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='', out_signature='ao') + def ListConnections(self): + connections = [] + return self.connections.keys() + + @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='a{sa{sv}}', out_signature='o') + def AddConnection(self, settings): + path = "/org/freedesktop/NetworkManager/Settings/Connection/%d" % self.counter + self.counter = self.counter + 1 + self.connections[path] = Connection(self.bus, path, settings, self.delete_connection) + print "Added connection %s" % path + return path + + def delete_connection(self, connection): + del self.connections[connection.path] + + @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}') + def GetAll(self, iface): + if iface != IFACE_SETTINGS: + raise UnknownInterfaceException() + return self.props + + @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v') + def Get(self, iface, name): + if iface != IFACE_SETTINGS: + raise UnknownInterfaceException() + if not name in self.props.keys(): + raise UnknownPropertyException() + return self.props[name] + + @dbus.service.signal(IFACE_SETTINGS, signature='o') + def NewConnection(self, path): + pass + + @dbus.service.method(IFACE_SETTINGS, in_signature='', out_signature='') + def Quit(self): + mainloop.quit() + +def quit_cb(user_data): + mainloop.quit() + +def main(): + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + bus = dbus.SessionBus() + obj = Settings(bus, "/org/freedesktop/NetworkManager/Settings") + if not bus.request_name("org.freedesktop.NetworkManager"): + sys.exit(1) + + print "Service started" + + gobject.timeout_add_seconds(20, quit_cb, None) + + try: + mainloop.run() + except Exception, e: + pass + + print "Service stopped" + sys.exit(0) + +if __name__ == '__main__': + main() + diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index fdadc7517f..395775213a 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -31,12 +31,16 @@ libnm_util_include_HEADERS = \ nm-setting-vpn.h \ nm-utils.h -libnm_util_la_SOURCES= \ - crypto.c \ +libnm_util_la_private_headers = \ crypto.h \ + nm-param-spec-specialized.h \ + nm-utils-private.h \ + nm-setting-private.h + +libnm_util_la_csources = \ + crypto.c \ nm-connection.c \ nm-param-spec-specialized.c \ - nm-param-spec-specialized.h \ nm-setting.c \ nm-setting-8021x.c \ nm-setting-bluetooth.c \ @@ -54,14 +58,16 @@ libnm_util_la_SOURCES= \ nm-setting-wireless.c \ nm-setting-wireless-security.c \ nm-setting-vpn.c \ - nm-utils.c \ - nm-utils-private.h \ - $(libnm_util_include_HEADERS) + nm-utils.c + +libnm_util_la_SOURCES = \ + $(libnm_util_la_csources) \ + $(libnm_util_la_private_headers) libnm_util_la_LIBADD = $(GLIB_LIBS) $(DBUS_LIBS) $(UUID_LIBS) libnm_util_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-util.ver \ - -version-info "7:0:6" + -version-info "8:0:7" if WITH_GNUTLS libnm_util_la_SOURCES += crypto_gnutls.c @@ -104,12 +110,36 @@ libtest_crypto_la_CPPFLAGS += $(NSS_CFLAGS) libtest_crypto_la_LIBADD += $(NSS_LIBS) endif - - pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libnm-util.pc DISTCLEANFILES = libnm-util.pc +CLEANFILES = EXTRA_DIST = libnm-util.pc.in libnm-util.ver +-include $(INTROSPECTION_MAKEFILE) +INTROSPECTION_GIRS = +INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) +INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) + +if HAVE_INTROSPECTION +introspection_sources = $(libnm_util_include_HEADERS) $(libnm_util_la_csources) $(top_srcdir)/include/NetworkManager.h $(top_srcdir)/include/NetworkManagerVPN.h + +NetworkManager-1.0.gir: libnm-util.la +NetworkManager_1_0_gir_INCLUDES = GObject-2.0 DBusGLib-1.0 +NetworkManager_1_0_gir_PACKAGES = gobject-2.0 dbus-glib-1 +NetworkManager_1_0_gir_CFLAGS = $(INCLUDES) -I$(top_srcdir)/libnm-util +NetworkManager_1_0_gir_LIBS = libnm-util.la +NetworkManager_1_0_gir_FILES = $(introspection_sources) +NetworkManager_1_0_gir_SCANNERFLAGS = --warn-all --identifier-prefix=NM --symbol-prefix=nm_ +INTROSPECTION_GIRS += NetworkManager-1.0.gir + +girdir = $(datadir)/gir-1.0 +gir_DATA = $(INTROSPECTION_GIRS) + +typelibdir = $(libdir)/girepository-1.0 +typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) + +CLEANFILES += $(gir_DATA) $(typelib_DATA) +endif diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index 00629d750d..22bd5a140c 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -9,10 +9,11 @@ global: nm_connection_error_get_type; nm_connection_error_quark; nm_connection_for_each_setting_value; + nm_connection_get_id; nm_connection_get_path; - nm_connection_get_scope; nm_connection_get_setting; nm_connection_get_setting_by_name; + nm_connection_get_uuid; nm_connection_get_type; nm_connection_lookup_setting_type; nm_connection_lookup_setting_type_by_quark; @@ -22,7 +23,6 @@ global: nm_connection_remove_setting; nm_connection_replace_settings; nm_connection_set_path; - nm_connection_set_scope; nm_connection_to_hash; nm_connection_update_secrets; nm_connection_verify; @@ -48,6 +48,7 @@ global: nm_setting_802_1x_get_identity; nm_setting_802_1x_get_num_eap_methods; nm_setting_802_1x_get_password; + nm_setting_802_1x_get_password_flags; nm_setting_802_1x_get_phase1_fast_provisioning; nm_setting_802_1x_get_phase1_peaplabel; nm_setting_802_1x_get_phase1_peapver; @@ -71,6 +72,7 @@ global: nm_setting_802_1x_get_phase2_private_key_format; nm_setting_802_1x_set_phase2_private_key_from_file; nm_setting_802_1x_get_phase2_private_key_password; + nm_setting_802_1x_get_phase2_private_key_password_flags; nm_setting_802_1x_get_phase2_private_key_path; nm_setting_802_1x_get_phase2_private_key_scheme; nm_setting_802_1x_get_phase2_private_key_type; @@ -81,11 +83,11 @@ global: nm_setting_802_1x_get_private_key_format; nm_setting_802_1x_set_private_key_from_file; nm_setting_802_1x_get_private_key_password; + nm_setting_802_1x_get_private_key_password_flags; nm_setting_802_1x_get_private_key_path; nm_setting_802_1x_get_private_key_scheme; nm_setting_802_1x_get_private_key_type; nm_setting_802_1x_set_private_key; - nm_setting_802_1x_get_psk; nm_setting_802_1x_get_system_ca_certs; nm_setting_802_1x_get_type; nm_setting_802_1x_new; @@ -103,8 +105,10 @@ global: nm_setting_cdma_get_number; nm_setting_cdma_get_username; nm_setting_cdma_get_password; + nm_setting_cdma_get_password_flags; nm_setting_clear_secrets; nm_setting_compare; + nm_setting_connection_add_permission; nm_setting_connection_error_get_type; nm_setting_connection_error_quark; nm_setting_connection_get_type; @@ -115,6 +119,10 @@ global: nm_setting_connection_get_autoconnect; nm_setting_connection_get_timestamp; nm_setting_connection_get_read_only; + nm_setting_connection_get_num_permissions; + nm_setting_connection_get_permission; + nm_setting_connection_permissions_user_allowed; + nm_setting_connection_remove_permission; nm_setting_duplicate; nm_setting_enumerate_values; nm_setting_error_get_type; @@ -129,13 +137,13 @@ global: nm_setting_gsm_get_number; nm_setting_gsm_get_username; nm_setting_gsm_get_password; + nm_setting_gsm_get_password_flags; nm_setting_gsm_get_apn; nm_setting_gsm_get_network_id; nm_setting_gsm_get_network_type; nm_setting_gsm_get_allowed_bands; - nm_setting_gsm_get_band; nm_setting_gsm_get_pin; - nm_setting_gsm_get_puk; + nm_setting_gsm_get_pin_flags; nm_setting_gsm_get_home_only; nm_setting_ip4_config_error_get_type; nm_setting_ip4_config_error_quark; @@ -169,6 +177,7 @@ global: nm_setting_ip4_config_get_dhcp_send_hostname; nm_setting_ip4_config_get_never_default; nm_setting_ip4_config_get_may_fail; + nm_ip6_address_get_type; nm_ip6_address_new; nm_ip6_address_dup; nm_ip6_address_ref; @@ -180,6 +189,7 @@ global: nm_ip6_address_set_gateway; nm_ip6_address_get_prefix; nm_ip6_address_set_prefix; + nm_ip6_route_get_type; nm_ip6_route_new; nm_ip6_route_dup; nm_ip6_route_ref; @@ -252,6 +262,7 @@ global: nm_setting_pppoe_get_service; nm_setting_pppoe_get_username; nm_setting_pppoe_get_password; + nm_setting_pppoe_get_password_flags; nm_setting_serial_error_get_type; nm_setting_serial_error_quark; nm_setting_serial_get_type; @@ -261,23 +272,25 @@ global: nm_setting_serial_get_parity; nm_setting_serial_get_stopbits; nm_setting_serial_get_send_delay; + nm_setting_get_secret_flags; + nm_setting_set_secret_flags; nm_setting_to_hash; nm_setting_to_string; nm_setting_update_secrets; nm_setting_verify; + nm_setting_vpn_add_data_item; + nm_setting_vpn_add_secret; nm_setting_vpn_error_get_type; nm_setting_vpn_error_quark; - nm_setting_vpn_get_type; - nm_setting_vpn_new; - nm_setting_vpn_get_service_type; - nm_setting_vpn_get_user_name; - nm_setting_vpn_add_data_item; nm_setting_vpn_foreach_data_item; - nm_setting_vpn_get_data_item; - nm_setting_vpn_remove_data_item; - nm_setting_vpn_add_secret; nm_setting_vpn_foreach_secret; + nm_setting_vpn_get_data_item; nm_setting_vpn_get_secret; + nm_setting_vpn_get_service_type; + nm_setting_vpn_get_type; + nm_setting_vpn_get_user_name; + nm_setting_vpn_new; + nm_setting_vpn_remove_data_item; nm_setting_vpn_remove_secret; nm_setting_wimax_error_get_type; nm_setting_wimax_error_quark; @@ -335,14 +348,17 @@ global: nm_setting_wireless_security_get_key_mgmt; nm_setting_wireless_security_get_leap_username; nm_setting_wireless_security_get_leap_password; + nm_setting_wireless_security_get_leap_password_flags; nm_setting_wireless_security_get_num_groups; nm_setting_wireless_security_get_num_pairwise; nm_setting_wireless_security_get_num_protos; nm_setting_wireless_security_get_pairwise; nm_setting_wireless_security_get_proto; nm_setting_wireless_security_get_psk; + nm_setting_wireless_security_get_psk_flags; nm_setting_wireless_security_get_type; nm_setting_wireless_security_get_wep_key; + nm_setting_wireless_security_get_wep_key_flags; nm_setting_wireless_security_get_wep_key_type; nm_setting_wireless_security_get_wep_tx_keyidx; nm_setting_wireless_security_new; @@ -387,8 +403,9 @@ global: nm_ip4_address_compare; nm_ip4_address_dup; nm_ip4_address_get_address; - nm_ip4_address_get_prefix; nm_ip4_address_get_gateway; + nm_ip4_address_get_prefix; + nm_ip4_address_get_type; nm_ip4_address_new; nm_ip4_address_ref; nm_ip4_address_set_address; @@ -401,6 +418,7 @@ global: nm_ip4_route_get_prefix; nm_ip4_route_get_next_hop; nm_ip4_route_get_metric; + nm_ip4_route_get_type; nm_ip4_route_new; nm_ip4_route_ref; nm_ip4_route_unref; diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c index ad9ed813f7..ec3390720d 100644 --- a/libnm-util/nm-connection.c +++ b/libnm-util/nm-connection.c @@ -29,6 +29,7 @@ #include "nm-connection.h" #include "nm-utils.h" #include "nm-utils-private.h" +#include "nm-dbus-glib-types.h" #include "nm-setting-8021x.h" #include "nm-setting-bluetooth.h" @@ -66,12 +67,6 @@ * parameters (MTU, SSID, APN, channel, rate, etc) and IP-level parameters * (addresses, routes, addressing methods, etc). * - * Most connections also have a %NMConnectionScope; a connection will be - * provided over D-Bus either by the user settings service - * (org.freedesktop.NetworkManagerUserSettings) running in an active user - * session, or by the system-wide system settings service - * (org.freedesktop.NetworkManagerSystemSettings) which provides connections - * for all users. */ /** @@ -113,9 +108,6 @@ nm_connection_error_get_type (void) typedef struct { GHashTable *settings; - /* Type of the connection (system or user) */ - NMConnectionScope scope; - /* D-Bus path of the connection, if any */ char *path; } NMConnectionPrivate; @@ -126,7 +118,6 @@ G_DEFINE_TYPE (NMConnection, nm_connection, G_TYPE_OBJECT) enum { PROP_0, - PROP_SCOPE, PROP_PATH, LAST_PROP @@ -234,9 +225,9 @@ register_default_settings (void) 1); register_one_setting (NM_SETTING_BLUETOOTH_SETTING_NAME, - NM_TYPE_SETTING_BLUETOOTH, - NM_SETTING_BLUETOOTH_ERROR, - 1); + NM_TYPE_SETTING_BLUETOOTH, + NM_SETTING_BLUETOOTH_ERROR, + 1); register_one_setting (NM_SETTING_WIMAX_SETTING_NAME, NM_TYPE_SETTING_WIMAX, @@ -359,7 +350,7 @@ nm_connection_lookup_setting_type_by_quark (GQuark error_quark) * * Create a new #NMSetting object of the desired type, given a setting name. * - * Returns: the new setting object, or NULL if the setting name was unknown + * Returns: (transfer full): the new setting object, or NULL if the setting name was unknown **/ NMSetting * nm_connection_create_setting (const char *name) @@ -393,7 +384,7 @@ parse_one_setting (gpointer key, gpointer value, gpointer user_data) /** * nm_connection_add_setting: * @connection: a #NMConnection - * @setting: the #NMSetting to add to the connection object + * @setting: (transfer full): the #NMSetting to add to the connection object * * Adds a #NMSetting to the connection, replacing any previous #NMSetting of the * same name which has previously been added to the #NMConnection. The @@ -435,7 +426,7 @@ nm_connection_remove_setting (NMConnection *connection, GType setting_type) * Gets the #NMSetting with the given #GType, if one has been previously added * to the #NMConnection. * - * Returns: the #NMSetting, or NULL if no setting of that type was previously + * Returns: (transfer none): the #NMSetting, or NULL if no setting of that type was previously * added to the #NMConnection **/ NMSetting * @@ -456,7 +447,7 @@ nm_connection_get_setting (NMConnection *connection, GType setting_type) * Gets the #NMSetting with the given name, if one has been previously added * the the #NMConnection. * - * Returns: the #NMSetting, or NULL if no setting with that name was previously + * Returns: (transfer none): the #NMSetting, or NULL if no setting with that name was previously * added to the #NMConnection **/ NMSetting * @@ -472,10 +463,37 @@ nm_connection_get_setting_by_name (NMConnection *connection, const char *name) return type ? nm_connection_get_setting (connection, type) : NULL; } +static gboolean +validate_permissions_type (GHashTable *hash, GError **error) +{ + GHashTable *s_con; + GValue *permissions; + + /* Ensure the connection::permissions item (if present) is the correct + * type, otherwise the g_object_set() will throw a warning and ignore the + * error, leaving us with no permissions. + */ + s_con = g_hash_table_lookup (hash, NM_SETTING_CONNECTION_SETTING_NAME); + if (s_con) { + permissions = g_hash_table_lookup (s_con, NM_SETTING_CONNECTION_PERMISSIONS); + if (permissions) { + if ( !G_VALUE_HOLDS (permissions, G_TYPE_STRV) + && !G_VALUE_HOLDS (permissions, DBUS_TYPE_G_LIST_OF_STRING)) { + g_set_error_literal (error, + NM_SETTING_ERROR, + NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, + "Wrong permissions property type; should be a list of strings."); + return FALSE; + } + } + } + return TRUE; +} + /** * nm_connection_replace_settings: * @connection: a #NMConnection - * @new_settings: a #GHashTable of settings + * @new_settings: (element-type utf8 GLib.HashTable): a #GHashTable of settings * @error: location to store error, or %NULL * * Returns: %TRUE if the settings were valid and added to the connection, %FALSE @@ -492,6 +510,9 @@ nm_connection_replace_settings (NMConnection *connection, if (error) g_return_val_if_fail (*error == NULL, FALSE); + if (!validate_permissions_type (new_settings, error)) + return FALSE; + g_hash_table_remove_all (NM_CONNECTION_GET_PRIVATE (connection)->settings); g_hash_table_foreach (new_settings, parse_one_setting, connection); @@ -630,7 +651,7 @@ nm_connection_verify (NMConnection *connection, GError **error) * nm_connection_update_secrets: * @connection: the #NMConnection * @setting_name: the setting object name to which the secrets apply - * @secrets: a #GHashTable mapping string:#GValue of setting property names and + * @secrets: (element-type utf8 GObject.Value): a #GHashTable mapping string:#GValue of setting property names and * secrets * @error: location to store error, or %NULL * @@ -643,28 +664,39 @@ nm_connection_verify (NMConnection *connection, GError **error) gboolean nm_connection_update_secrets (NMConnection *connection, const char *setting_name, - GHashTable *secrets, + GHashTable *all_secrets, GError **error) { NMSetting *setting; gboolean success; + GHashTable *setting_secrets; g_return_val_if_fail (connection != NULL, FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); g_return_val_if_fail (setting_name != NULL, FALSE); - g_return_val_if_fail (secrets != NULL, FALSE); + g_return_val_if_fail (all_secrets != NULL, FALSE); if (error) g_return_val_if_fail (*error == NULL, FALSE); setting = nm_connection_get_setting (connection, nm_connection_lookup_setting_type (setting_name)); if (!setting) { - g_set_error (error, NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND, - "%s", setting_name); + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND, + setting_name); return FALSE; } - success = nm_setting_update_secrets (setting, secrets, error); + setting_secrets = g_hash_table_lookup (all_secrets, setting_name); + if (!setting_secrets) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND, + setting_name); + return FALSE; + } + + success = nm_setting_update_secrets (setting, setting_secrets, error); if (success) g_signal_emit (connection, signals[SECRETS_UPDATED], 0, setting_name); return success; @@ -777,26 +809,10 @@ nm_connection_clear_secrets (NMConnection *connection) g_hash_table_foreach (priv->settings, clear_setting_secrets, NULL); } -static void -add_one_setting_to_hash (gpointer key, gpointer data, gpointer user_data) -{ - NMSetting *setting = (NMSetting *) data; - GHashTable *connection_hash = (GHashTable *) user_data; - GHashTable *setting_hash; - - g_return_if_fail (setting != NULL); - g_return_if_fail (connection_hash != NULL); - - setting_hash = nm_setting_to_hash (setting); - if (setting_hash) - g_hash_table_insert (connection_hash, - g_strdup (nm_setting_get_name (setting)), - setting_hash); -} - /** * nm_connection_to_hash: * @connection: the #NMConnection + * @flags: hash flags, e.g. %NM_SETTING_HASH_FLAG_ALL * * Converts the #NMConnection into a #GHashTable describing the connection, * suitable for marshalling over D-Bus or serializing. The hash table mapping @@ -805,50 +821,50 @@ add_one_setting_to_hash (gpointer key, gpointer data, gpointer user_data) * are #GHashTables mapping string:GValue, each of which represents the * properties of the #NMSetting object. * - * Returns: a new #GHashTable describing the connection, its settings, and - * each setting's properties. The caller owns the hash table and must unref - * the hash table with g_hash_table_unref() when it is no longer needed. + * Returns: (transfer full) (element-type utf8 GLib.HashTable): a new + * #GHashTable describing the connection, its settings, and each setting's + * properties. The caller owns the hash table and must unref the hash table + * with g_hash_table_unref() when it is no longer needed. **/ GHashTable * -nm_connection_to_hash (NMConnection *connection) +nm_connection_to_hash (NMConnection *connection, NMSettingHashFlags flags) { NMConnectionPrivate *priv; - GHashTable *connection_hash; + GHashTableIter iter; + gpointer key, data; + GHashTable *ret, *setting_hash; + g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - connection_hash = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) g_hash_table_destroy); + ret = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_hash_table_destroy); priv = NM_CONNECTION_GET_PRIVATE (connection); - g_hash_table_foreach (priv->settings, add_one_setting_to_hash, connection_hash); - /* Don't send empty hashes */ - if (g_hash_table_size (connection_hash) < 1) { - g_hash_table_destroy (connection_hash); - connection_hash = NULL; + /* Add each setting's hash to the main hash */ + g_hash_table_iter_init (&iter, priv->settings); + while (g_hash_table_iter_next (&iter, &key, &data)) { + NMSetting *setting = NM_SETTING (data); + + setting_hash = nm_setting_to_hash (setting, flags); + if (setting_hash) + g_hash_table_insert (ret, g_strdup (nm_setting_get_name (setting)), setting_hash); } - return connection_hash; -} + /* Don't send empty hashes */ + if (g_hash_table_size (ret) < 1) { + g_hash_table_destroy (ret); + ret = NULL; + } -typedef struct ForEachValueInfo { - NMSettingValueIterFn func; - gpointer user_data; -} ForEachValueInfo; - -static void -for_each_setting (gpointer key, gpointer value, gpointer user_data) -{ - ForEachValueInfo *info = (ForEachValueInfo *) user_data; - - nm_setting_enumerate_values (NM_SETTING (value), info->func, info->user_data); + return ret; } /** * nm_connection_for_each_setting_value: * @connection: the #NMConnection - * @func: user-supplied function called for each setting's property + * @func: (scope call): user-supplied function called for each setting's property * @user_data: user data passed to @func at each invocation * * Iterates over the properties of each #NMSetting object in the #NMConnection, @@ -859,25 +875,15 @@ nm_connection_for_each_setting_value (NMConnection *connection, NMSettingValueIterFn func, gpointer user_data) { - NMConnectionPrivate *priv; - ForEachValueInfo *info; + GHashTableIter iter; + gpointer value; g_return_if_fail (NM_IS_CONNECTION (connection)); g_return_if_fail (func != NULL); - priv = NM_CONNECTION_GET_PRIVATE (connection); - - info = g_slice_new0 (ForEachValueInfo); - if (!info) { - g_warning ("Not enough memory to enumerate values."); - return; - } - info->func = func; - info->user_data = user_data; - - g_hash_table_foreach (priv->settings, for_each_setting, info); - - g_slice_free (ForEachValueInfo, info); + g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings); + while (g_hash_table_iter_next (&iter, NULL, &value)) + nm_setting_enumerate_values (NM_SETTING (value), func, user_data); } static void @@ -906,43 +912,6 @@ nm_connection_dump (NMConnection *connection) g_hash_table_foreach (NM_CONNECTION_GET_PRIVATE (connection)->settings, dump_setting, NULL); } -/** - * nm_connection_set_scope: - * @connection: the #NMConnection - * @scope: the scope of the connection - * - * Sets the scope of the connection. This property is not serialized, and is - * only for the reference of the caller. A connection may have no scope - * (internal, temporary connections), "system" scope (provided by the system - * settings service), or "user" scope, provided by a user settings service. The - * creator of the #NMConnection object is responsible for setting the - * connection's scope if needed. Sets the #NMConnection:scope property. - **/ -void -nm_connection_set_scope (NMConnection *connection, NMConnectionScope scope) -{ - g_return_if_fail (NM_IS_CONNECTION (connection)); - - NM_CONNECTION_GET_PRIVATE (connection)->scope = scope; -} - -/** - * nm_connection_get_scope: - * @connection: the #NMConnection - * - * Returns the connection scope. - * - * Returns: the scope of the connection, previously set by a call to - * nm_connection_set_scope(). - **/ -NMConnectionScope -nm_connection_get_scope (NMConnection *connection) -{ - g_return_val_if_fail (NM_IS_CONNECTION (connection), NM_CONNECTION_SCOPE_UNKNOWN); - - return NM_CONNECTION_GET_PRIVATE (connection)->scope; -} - /** * nm_connection_set_path: * @connection: the #NMConnection @@ -1010,7 +979,8 @@ nm_connection_new (void) /** * nm_connection_new_from_hash: - * @hash: the #GHashTable describing the connection + * @hash: (element-type utf8 GLib.HashTable): the #GHashTable describing + * the connection * @error: on unsuccessful return, an error * * Creates a new #NMConnection from a hash table describing the connection. See @@ -1027,6 +997,9 @@ nm_connection_new_from_hash (GHashTable *hash, GError **error) g_return_val_if_fail (hash != NULL, NULL); + if (!validate_permissions_type (hash, error)) + return FALSE; + connection = nm_connection_new (); g_hash_table_foreach (hash, parse_one_setting, connection); @@ -1050,7 +1023,7 @@ duplicate_cb (gpointer key, gpointer value, gpointer user_data) * * Duplicates a #NMConnection. * - * Returns: a new #NMConnection containing the same settings and properties + * Returns: (transfer full): a new #NMConnection containing the same settings and properties * as the source #NMConnection **/ NMConnection * @@ -1061,13 +1034,57 @@ nm_connection_duplicate (NMConnection *connection) g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); dup = nm_connection_new (); - nm_connection_set_scope (dup, nm_connection_get_scope (connection)); nm_connection_set_path (dup, nm_connection_get_path (connection)); g_hash_table_foreach (NM_CONNECTION_GET_PRIVATE (connection)->settings, duplicate_cb, dup); return dup; } +/** + * nm_connection_get_uuid: + * @connection: the #NMConnection + * + * A shortcut to return the UUID from the connections #NMSettingConnection. + * + * Returns: the UUID from the connection's 'connection' setting + **/ +const char * +nm_connection_get_uuid (NMConnection *connection) +{ + NMSettingConnection *s_con; + + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + g_return_val_if_fail (s_con != NULL, NULL); + + return nm_setting_connection_get_uuid (s_con); +} + +/** + * nm_connection_get_uuid: + * @connection: the #NMConnection + * + * A shortcut to return the UUID from the connections #NMSettingConnection. + * + * Returns: the UUID from the connection's 'connection' setting + **/ +const char *nm_connection_get_id (NMConnection *connection) +{ + NMSettingConnection *s_con; + + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + g_return_val_if_fail (s_con != NULL, NULL); + + return nm_setting_connection_get_id (s_con); +} + +/*************************************************************/ + static void nm_connection_init (NMConnection *connection) { @@ -1098,9 +1115,6 @@ set_property (GObject *object, guint prop_id, NMConnection *connection = NM_CONNECTION (object); switch (prop_id) { - case PROP_SCOPE: - nm_connection_set_scope (connection, g_value_get_uint (value)); - break; case PROP_PATH: nm_connection_set_path (connection, g_value_get_string (value)); break; @@ -1117,9 +1131,6 @@ get_property (GObject *object, guint prop_id, NMConnection *connection = NM_CONNECTION (object); switch (prop_id) { - case PROP_SCOPE: - g_value_set_uint (value, nm_connection_get_scope (connection)); - break; case PROP_PATH: g_value_set_string (value, nm_connection_get_path (connection)); break; @@ -1143,23 +1154,6 @@ nm_connection_class_init (NMConnectionClass *klass) /* Properties */ - /** - * NMConnection:scope: - * - * The connection's scope, used only by the calling process as a record - * of which settings service the connection is provided by. One of the - * NM_CONNECTION_SCOPE_* defines. - **/ - g_object_class_install_property - (object_class, PROP_SCOPE, - g_param_spec_uint (NM_CONNECTION_SCOPE, - "Scope", - "Scope", - NM_CONNECTION_SCOPE_UNKNOWN, - NM_CONNECTION_SCOPE_USER, - NM_CONNECTION_SCOPE_UNKNOWN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - /** * NMConnection:path: * diff --git a/libnm-util/nm-connection.h b/libnm-util/nm-connection.h index 576db04984..fce715ab18 100644 --- a/libnm-util/nm-connection.h +++ b/libnm-util/nm-connection.h @@ -39,23 +39,6 @@ G_BEGIN_DECLS #define NM_IS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CONNECTION)) #define NM_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTION, NMConnectionClass)) -/** - * NMConnectionScope: - * @NM_CONNECTION_SCOPE_UNKNOWN: scope not known or not yet set - * @NM_CONNECTION_SCOPE_SYSTEM: connection is provided by the system settings - * service - * @NM_CONNECTION_SCOPE_USER: connection is provided by a user settings service - * - * Connection scope indicated what settings service, if any, provides the - * connection. - * - **/ -typedef enum { - NM_CONNECTION_SCOPE_UNKNOWN = 0, - NM_CONNECTION_SCOPE_SYSTEM, - NM_CONNECTION_SCOPE_USER -} NMConnectionScope; - /** * NMConnectionError: @@ -79,7 +62,6 @@ GType nm_connection_error_get_type (void); #define NM_CONNECTION_ERROR nm_connection_error_quark () GQuark nm_connection_error_quark (void); -#define NM_CONNECTION_SCOPE "scope" #define NM_CONNECTION_PATH "path" /** @@ -107,8 +89,10 @@ NMConnection *nm_connection_new_from_hash (GHashTable *hash, GError **error); NMConnection *nm_connection_duplicate (NMConnection *connection); +NMSetting *nm_connection_create_setting (const char *name); + void nm_connection_add_setting (NMConnection *connection, - NMSetting *setting); + NMSetting *setting); void nm_connection_remove_setting (NMConnection *connection, GType setting_type); @@ -117,7 +101,7 @@ NMSetting *nm_connection_get_setting (NMConnection *connection, GType setting_type); NMSetting *nm_connection_get_setting_by_name (NMConnection *connection, - const char *name); + const char *name); gboolean nm_connection_replace_settings (NMConnection *connection, GHashTable *new_settings, @@ -139,28 +123,28 @@ gboolean nm_connection_update_secrets (NMConnection *connection, GHashTable *secrets, GError **error); -void nm_connection_set_scope (NMConnection *connection, - NMConnectionScope scope); +void nm_connection_set_path (NMConnection *connection, + const char *path); -NMConnectionScope nm_connection_get_scope (NMConnection *connection); - -void nm_connection_set_path (NMConnection *connection, - const char *path); - -const char * nm_connection_get_path (NMConnection *connection); +const char * nm_connection_get_path (NMConnection *connection); void nm_connection_for_each_setting_value (NMConnection *connection, - NMSettingValueIterFn func, - gpointer user_data); + NMSettingValueIterFn func, + gpointer user_data); + +GHashTable *nm_connection_to_hash (NMConnection *connection, + NMSettingHashFlags flags); -GHashTable *nm_connection_to_hash (NMConnection *connection); void nm_connection_dump (NMConnection *connection); -NMSetting *nm_connection_create_setting (const char *name); +GType nm_connection_lookup_setting_type (const char *name); -GType nm_connection_lookup_setting_type (const char *name); +GType nm_connection_lookup_setting_type_by_quark (GQuark error_quark); -GType nm_connection_lookup_setting_type_by_quark (GQuark error_quark); +/* Helpers */ +const char * nm_connection_get_uuid (NMConnection *connection); + +const char * nm_connection_get_id (NMConnection *connection); G_END_DECLS diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c index eea6ba5e7c..cb1c95116c 100644 --- a/libnm-util/nm-setting-8021x.c +++ b/libnm-util/nm-setting-8021x.c @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -32,6 +32,7 @@ #include "nm-dbus-glib-types.h" #include "crypto.h" #include "nm-utils-private.h" +#include "nm-setting-private.h" /** * SECTION:nm-setting-8021x @@ -125,12 +126,15 @@ typedef struct { char *phase2_ca_path; GByteArray *phase2_client_cert; char *password; + NMSettingSecretFlags password_flags; char *pin; - char *psk; + NMSettingSecretFlags pin_flags; GByteArray *private_key; char *private_key_password; + NMSettingSecretFlags private_key_password_flags; GByteArray *phase2_private_key; char *phase2_private_key_password; + NMSettingSecretFlags phase2_private_key_password_flags; gboolean system_ca_certs; } NMSetting8021xPrivate; @@ -151,12 +155,15 @@ enum { PROP_PHASE2_CA_PATH, PROP_PHASE2_CLIENT_CERT, PROP_PASSWORD, + PROP_PASSWORD_FLAGS, PROP_PRIVATE_KEY, PROP_PRIVATE_KEY_PASSWORD, + PROP_PRIVATE_KEY_PASSWORD_FLAGS, PROP_PHASE2_PRIVATE_KEY, PROP_PHASE2_PRIVATE_KEY_PASSWORD, + PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, PROP_PIN, - PROP_PSK, + PROP_PIN_FLAGS, PROP_SYSTEM_CA_CERTS, LAST_PROP @@ -423,29 +430,6 @@ nm_setting_802_1x_get_ca_cert_blob (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert; } -/** - * nm_setting_802_1x_get_ca_cert: - * @setting: the #NMSetting8021x - * - * Returns the CA certificate blob if the CA certificate is stored using the - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. Not all EAP methods use a - * CA certificate (LEAP for example), and those that can take advantage of the - * CA certificate allow it to be unset. Note that lack of a CA certificate - * reduces security by allowing man-in-the-middle attacks, because the identity - * of the network cannot be confirmed by the client. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_ca_cert_blob(). - * - * Returns: the CA certificate data - **/ -const GByteArray * -nm_setting_802_1x_get_ca_cert (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_ca_cert_blob (setting); -} - /** * nm_setting_802_1x_get_ca_cert_path: * @setting: the #NMSetting8021x @@ -560,61 +544,6 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *self, return priv->ca_cert != NULL; } -static NMSetting8021xCKType -ck_format_to_type (NMSetting8021xCKFormat format) -{ - switch (format) { - case NM_SETTING_802_1X_CK_FORMAT_X509: - return NM_SETTING_802_1X_CK_TYPE_X509; - case NM_SETTING_802_1X_CK_FORMAT_RAW_KEY: - return NM_SETTING_802_1X_CK_TYPE_RAW_KEY; - case NM_SETTING_802_1X_CK_FORMAT_PKCS12: - return NM_SETTING_802_1X_CK_TYPE_PKCS12; - default: - break; - } - return NM_SETTING_802_1X_CK_TYPE_UNKNOWN; -} - -/** - * nm_setting_802_1x_set_ca_cert_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the CA certificate file (PEM or DER format). Passing - * NULL clears the CA certificate. - * @out_ck_type: on successful return, the type of the certificate added - * @error: on unsuccessful return, an error - * - * Reads a certificate from disk and sets the #NMSetting8021x:ca-cert property - * with the raw certificate data using the %NM_SETTING_802_1X_CK_SCHEME_BLOB - * scheme. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_ca_cert() with the - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_ca_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_ca_cert (setting, - filename, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - /** * nm_setting_802_1x_get_client_cert_scheme: * @setting: the #NMSetting8021x @@ -656,26 +585,6 @@ nm_setting_802_1x_get_client_cert_blob (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert; } -/** - * nm_setting_802_1x_get_client_cert: - * @setting: the #NMSetting8021x - * - * Client certificates are used to identify the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_client_cert_blob(). - * - * Returns: the client certificate data - **/ -const GByteArray * -nm_setting_802_1x_get_client_cert (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_client_cert_blob (setting); -} - /** * nm_setting_802_1x_get_client_cert_path: * @setting: the #NMSetting8021x @@ -795,48 +704,6 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *self, return priv->client_cert != NULL; } -/** - * nm_setting_802_1x_set_client_cert_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the client certificate file (PEM, DER, or - * PKCS#12 format). Passing NULL clears the client certificate. - * @out_ck_type: on successful return, the type of the certificate added - * @error: on unsuccessful return, an error - * - * Reads a certificate from disk and sets the #NMSetting8021x:client-cert - * property with the raw certificate data. - * - * Client certificates are used to identify the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_client_cert() with the - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_client_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_client_cert (setting, - filename, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - /** * nm_setting_802_1x_get_phase1_peapver: * @setting: the #NMSetting8021x @@ -982,28 +849,6 @@ nm_setting_802_1x_get_phase2_ca_cert_blob (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert; } -/** - * nm_setting_802_1x_get_phase2_ca_cert: - * @setting: the #NMSetting8021x - * - * Returns the "phase 2" CA certificate blob. Not all EAP methods use - * a CA certificate (LEAP for example), and those that can take advantage of the - * CA certificate allow it to be unset. Note that lack of a CA certificate - * reduces security by allowing man-in-the-middle attacks, because the identity - * of the network cannot be confirmed by the client. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_phase2_ca_cert_blob(). - * - * Returns: the "phase 2" CA certificate data - **/ -const GByteArray * -nm_setting_802_1x_get_phase2_ca_cert (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_phase2_ca_cert_blob (setting); -} - /** * nm_setting_802_1x_get_phase2_ca_cert_path: * @setting: the #NMSetting8021x @@ -1118,44 +963,6 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self, return priv->phase2_ca_cert != NULL; } -/** - * nm_setting_802_1x_set_phase2_ca_cert_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the "phase2" CA certificate file (PEM or DER format). - * Passing NULL with any @scheme clears the "phase2" CA certificate. - * @out_ck_type: on successful return, the type of the certificate added - * @error: on unsuccessful return, an error - * - * Reads a certificate from disk and sets the #NMSetting8021x:phase2-ca-cert - * property with the raw certificate data. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_phase2_ca_cert(). - * with the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_phase2_ca_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_phase2_ca_cert (setting, - filename, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - /** * nm_setting_802_1x_get_phase2_client_cert_scheme: * @setting: the #NMSetting8021x @@ -1199,26 +1006,6 @@ nm_setting_802_1x_get_phase2_client_cert_blob (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert; } -/** - * nm_setting_802_1x_get_phase2_client_cert: - * @setting: the #NMSetting8021x - * - * Client certificates are used to identify the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_phase2_client_cert_blob(). - * - * Returns: the "phase 2" client certificate data - **/ -const GByteArray * -nm_setting_802_1x_get_phase2_client_cert (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_phase2_client_cert_blob (setting); -} - /** * nm_setting_802_1x_get_phase2_client_cert_path: * @setting: the #NMSetting8021x @@ -1338,48 +1125,6 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self, return priv->phase2_client_cert != NULL; } -/** - * nm_setting_802_1x_set_phase2_client_cert_from_file: - * @setting: the #NMSetting8021x - * @filename: pass the path of the "phase2" client certificate file (PEM, DER, - * or PKCS#12 format). Passing NULL clears the "phase2" client certificate. - * @out_ck_type: on successful return, the type of the certificate added - * @error: on unsuccessful return, an error - * - * Reads a certificate from disk and sets the #NMSetting8021x:phase2-client-cert - * property with the raw certificate data. - * - * Client certificates are used to identify the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_phase2_client_cert() with the. - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_phase2_client_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_phase2_client_cert (setting, - filename, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - /** * nm_setting_802_1x_get_password: * @setting: the #NMSetting8021x @@ -1395,6 +1140,20 @@ nm_setting_802_1x_get_password (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->password; } +/** + * nm_setting_802_1x_get_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the #NMSetting8021x:password + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->password_flags; +} + /** * nm_setting_802_1x_get_pin: * @setting: the #NMSetting8021x @@ -1411,18 +1170,18 @@ nm_setting_802_1x_get_pin (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_psk: + * nm_setting_802_1x_get_pin_flags: * @setting: the #NMSetting8021x * - * Returns: the Pre-Shared-Key used by the authentication method, if any, as - * specified by the #NMSetting8021x:psk property + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:pin **/ -const char * -nm_setting_802_1x_get_psk (NMSetting8021x *setting) +NMSettingSecretFlags +nm_setting_802_1x_get_pin_flags (NMSetting8021x *setting) { - g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); - return NM_SETTING_802_1X_GET_PRIVATE (setting)->psk; + return NM_SETTING_802_1X_GET_PRIVATE (setting)->pin_flags; } /** @@ -1453,6 +1212,10 @@ nm_setting_802_1x_get_private_key_scheme (NMSetting8021x *setting) * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x * authentication method. * + * WARNING: the private key property is not a "secret" property, and thus + * unencrypted private key data may be readable by unprivileged users. Private + * keys should always be encrypted with a private key password. + * * Returns: the private key data **/ const GByteArray * @@ -1468,26 +1231,6 @@ nm_setting_802_1x_get_private_key_blob (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key; } -/** - * nm_setting_802_1x_get_private_key: - * @setting: the #NMSetting8021x - * - * Private keys are used to authenticate the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_private_key_blob(). - * - * Returns: the private key data - **/ -const GByteArray * -nm_setting_802_1x_get_private_key (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_private_key_blob (setting); -} - /** * nm_setting_802_1x_get_private_key_path: * @setting: the #NMSetting8021x @@ -1533,6 +1276,11 @@ nm_setting_802_1x_get_private_key_path (NMSetting8021x *setting) * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x * authentication method. * + * WARNING: the private key property is not a "secret" property, and thus + * unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a private + * key password to prevent unauthorized access to unencrypted private key data. + * * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful **/ gboolean @@ -1659,51 +1407,6 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *self, return priv->private_key != NULL; } -/** - * nm_setting_802_1x_set_private_key_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the private key file (PEM, DER, or PKCS#12 format). - * Passing NULL clears the private key. - * @password: password used to decrypt the private key - * @out_ck_type: on successful return, the type of the private key added - * @error: on unsuccessful return, an error - * - * Reads a private key from disk and sets the #NMSetting8021x:private-key - * property with the raw private key data. - * - * Private keys are used to authenticate the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_private_key() with. - * the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_private_key_from_file (NMSetting8021x *setting, - const char *filename, - const char *password, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_private_key (setting, - filename, - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - /** * nm_setting_802_1x_get_private_key_password: * @setting: the #NMSetting8021x @@ -1721,6 +1424,21 @@ nm_setting_802_1x_get_private_key_password (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key_password; } +/** + * nm_setting_802_1x_get_private_key_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:private-key-password + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_private_key_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key_password_flags; +} + /** * nm_setting_802_1x_get_private_key_format: * @setting: the #NMSetting8021x @@ -1763,23 +1481,6 @@ nm_setting_802_1x_get_private_key_format (NMSetting8021x *setting) return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; } -/** - * nm_setting_802_1x_get_private_key_type: - * @setting: the #NMSetting8021x - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_private_key_format(). - * - * Returns: the data format of the private key data stored in the - * #NMSetting8021x:private-key property - **/ -NMSetting8021xCKType -nm_setting_802_1x_get_private_key_type (NMSetting8021x *setting) -{ - return ck_format_to_type (nm_setting_802_1x_get_private_key_format (setting)); -} - /** * nm_setting_802_1x_get_phase2_private_key_password: * @setting: the #NMSetting8021x @@ -1797,6 +1498,21 @@ nm_setting_802_1x_get_phase2_private_key_password (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key_password; } +/** + * nm_setting_802_1x_get_phase2_private_key_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:phase2-private-key-password + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_phase2_private_key_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key_password_flags; +} + /** * nm_setting_802_1x_get_phase2_private_key_scheme: * @setting: the #NMSetting8021x @@ -1825,6 +1541,10 @@ nm_setting_802_1x_get_phase2_private_key_scheme (NMSetting8021x *setting) * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x * authentication method. * + * WARNING: the phase2 private key property is not a "secret" property, and thus + * unencrypted private key data may be readable by unprivileged users. Private + * keys should always be encrypted with a private key password. + * * Returns: the "phase 2" private key data **/ const GByteArray * @@ -1840,26 +1560,6 @@ nm_setting_802_1x_get_phase2_private_key_blob (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key; } -/** - * nm_setting_802_1x_get_phase2_private_key: - * @setting: the #NMSetting8021x - * - * Private keys are used to authenticate the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_private_key_blob(). - * - * Returns: the "phase 2" private key data - **/ -const GByteArray * -nm_setting_802_1x_get_phase2_private_key (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_phase2_private_key_blob (setting); -} - /** * nm_setting_802_1x_get_phase2_private_key_path: * @setting: the #NMSetting8021x @@ -1905,6 +1605,11 @@ nm_setting_802_1x_get_phase2_private_key_path (NMSetting8021x *setting) * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x * authentication method. * + * WARNING: the phase2 private key property is not a "secret" property, and thus + * unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a private + * key password to prevent unauthorized access to unencrypted private key data. + * * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful **/ gboolean @@ -2031,51 +1736,6 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self, return priv->phase2_private_key != NULL; } -/** - * nm_setting_802_1x_set_phase2_private_key_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the "phase2" private key file (PEM, DER, or PKCS#12 - * format). Passing NULL clears the "phase2" private key. - * @password: password used to decrypt the private key - * @out_ck_type: on successful return, the type of the private key added - * @error: on unsuccessful return, an error - * - * Reads a "phase 2" private key from disk and sets the - * #NMSetting8021x:phase2-private-key property with the raw private key data. - * - * Private keys are used to authenticate the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_phase2_private_key() with - * the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_phase2_private_key_from_file (NMSetting8021x *setting, - const char *filename, - const char *password, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_phase2_private_key (setting, - filename, - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - /** * nm_setting_802_1x_get_phase2_private_key_format: * @setting: the #NMSetting8021x @@ -2118,23 +1778,6 @@ nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting) return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; } -/** - * nm_setting_802_1x_get_phase2_private_key_type: - * @setting: the #NMSetting8021x - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_phase2_private_key_format(). - * - * Returns: the data format of the private key data stored in the - * #NMSetting8021x:phase2-private-key property - **/ -NMSetting8021xCKType -nm_setting_802_1x_get_phase2_private_key_type (NMSetting8021x *setting) -{ - return ck_format_to_type (nm_setting_802_1x_get_phase2_private_key_format (setting)); -} - static void need_secrets_password (NMSetting8021x *self, GPtrArray *secrets, @@ -2204,11 +1847,6 @@ need_secrets_tls (NMSetting8021x *self, const char *path = NULL; if (phase2) { - if (!priv->phase2_private_key || !priv->phase2_private_key->len) { - g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); - return; - } - scheme = nm_setting_802_1x_get_phase2_private_key_scheme (self); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) path = nm_setting_802_1x_get_phase2_private_key_path (self); @@ -2223,11 +1861,6 @@ need_secrets_tls (NMSetting8021x *self, if (need_private_key_password (blob, path, priv->phase2_private_key_password)) g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD); } else { - if (!priv->private_key || !priv->private_key->len) { - g_ptr_array_add (secrets, NM_SETTING_802_1X_PRIVATE_KEY); - return; - } - scheme = nm_setting_802_1x_get_private_key_scheme (self); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) path = nm_setting_802_1x_get_private_key_path (self); @@ -2264,8 +1897,23 @@ verify_tls (NMSetting8021x *self, gboolean phase2, GError **error) return FALSE; } + /* Private key is required for TLS */ + if (!priv->phase2_private_key) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_MISSING_PROPERTY, + NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + return FALSE; + } else if (!priv->phase2_private_key->len) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_INVALID_PROPERTY, + NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + return FALSE; + } + /* If the private key is PKCS#12, check that it matches the client cert */ - if (priv->phase2_private_key && crypto_is_pkcs12_data (priv->phase2_private_key)) { + if (crypto_is_pkcs12_data (priv->phase2_private_key)) { if (priv->phase2_private_key->len != priv->phase2_client_cert->len) { g_set_error (error, NM_SETTING_802_1X_ERROR, @@ -2299,8 +1947,23 @@ verify_tls (NMSetting8021x *self, gboolean phase2, GError **error) return FALSE; } + /* Private key is required for TLS */ + if (!priv->private_key) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_MISSING_PROPERTY, + NM_SETTING_802_1X_PRIVATE_KEY); + return FALSE; + } else if (!priv->private_key->len) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_INVALID_PROPERTY, + NM_SETTING_802_1X_PRIVATE_KEY); + return FALSE; + } + /* If the private key is PKCS#12, check that it matches the client cert */ - if (priv->private_key && crypto_is_pkcs12_data (priv->private_key)) { + if (crypto_is_pkcs12_data (priv->private_key)) { if (priv->private_key->len != priv->client_cert->len) { g_set_error (error, NM_SETTING_802_1X_ERROR, @@ -2817,6 +2480,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->password); priv->password = g_value_dup_string (value); break; + case PROP_PASSWORD_FLAGS: + priv->password_flags = g_value_get_uint (value); + break; case PROP_PRIVATE_KEY: if (priv->private_key) { g_byte_array_free (priv->private_key, TRUE); @@ -2833,6 +2499,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->private_key_password); priv->private_key_password = g_value_dup_string (value); break; + case PROP_PRIVATE_KEY_PASSWORD_FLAGS: + priv->private_key_password_flags = g_value_get_uint (value); + break; case PROP_PHASE2_PRIVATE_KEY: if (priv->phase2_private_key) { g_byte_array_free (priv->phase2_private_key, TRUE); @@ -2849,6 +2518,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->phase2_private_key_password); priv->phase2_private_key_password = g_value_dup_string (value); break; + case PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS: + priv->phase2_private_key_password_flags = g_value_get_uint (value); + break; case PROP_SYSTEM_CA_CERTS: priv->system_ca_certs = g_value_get_boolean (value); break; @@ -2911,18 +2583,27 @@ get_property (GObject *object, guint prop_id, case PROP_PASSWORD: g_value_set_string (value, priv->password); break; + case PROP_PASSWORD_FLAGS: + g_value_set_uint (value, priv->password_flags); + break; case PROP_PRIVATE_KEY: g_value_set_boxed (value, priv->private_key); break; case PROP_PRIVATE_KEY_PASSWORD: g_value_set_string (value, priv->private_key_password); break; + case PROP_PRIVATE_KEY_PASSWORD_FLAGS: + g_value_set_uint (value, priv->private_key_password_flags); + break; case PROP_PHASE2_PRIVATE_KEY: g_value_set_boxed (value, priv->phase2_private_key); break; case PROP_PHASE2_PRIVATE_KEY_PASSWORD: g_value_set_string (value, priv->phase2_private_key_password); break; + case PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS: + g_value_set_uint (value, priv->phase2_private_key_password_flags); + break; case PROP_SYSTEM_CA_CERTS: g_value_set_boolean (value, priv->system_ca_certs); break; @@ -3285,12 +2966,32 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + /** + * NMSetting8021x:password-flags: + * + * Flags indicating how to handle #NMSetting8021x:password:. + **/ + g_object_class_install_property (object_class, PROP_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_802_1X_PASSWORD_FLAGS, + "Password Flags", + "Flags indicating how to handle the 802.1x password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSetting8021x:private-key: * * Contains the private key if the #NMSetting8021x:eap property is set to * 'tls'. Setting this property directly is discouraged; use the * nm_setting_802_1x_set_private_key() function instead. + * + * WARNING: #NMSetting8021x:private-key is not a "secret" property, and thus + * unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a + * private key password to prevent unauthorized access to unencrypted + * private key data. **/ g_object_class_install_property (object_class, PROP_PRIVATE_KEY, @@ -3301,12 +3002,17 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) "'scheme'; two are currently supported: blob and " "path. When using the blob scheme and X.509 private " "keys, this property should be set to the keys's " - "decrypted DER encoded data. When using X.509 " - "private keys with the path scheme, this property " - "should be set to the full UTF-8 encoded path of " - "the key, prefixed with the string 'file://' and " - "and ending with a terminating NULL byte. When " - "using PKCS#12 format private keys and the blob " + "PEM or DER encoded data; if using DER-encoded " + "data the private key must be decrypted as the " + "DER format is incomplete. Use of decrypted " + "DER-format private keys is not recommended as it " + "may allow unprivileged users access to the " + "decrypted data. When using X.509 private keys " + "with the path scheme, this property should be " + "set to the full UTF-8 encoded path of the key, " + "prefixed with the string 'file://' and ending " + "with a terminating NULL byte. When using " + "PKCS#12 format private keys and the blob " "scheme, this property should be set to the " "PKCS#12 data (which is encrypted) and the " "'private-key-password' property must be set to " @@ -3320,7 +3026,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) "be set to the password used to decode the PKCS#12 " "private key and certificate.", DBUS_TYPE_G_UCHAR_ARRAY, - G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); /** * NMSetting8021x:private-key-password: @@ -3343,6 +3049,21 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + /** + * NMSetting8021x:private-key-password-flags: + * + * Flags indicating how to handle #NMSetting8021x:private-key-password:. + **/ + g_object_class_install_property (object_class, PROP_PRIVATE_KEY_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, + "Private Key Password Flags", + "Flags indicating how to handle the 802.1x private " + "key password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSetting8021x:phase2-private-key: * @@ -3363,12 +3084,17 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) "'scheme'; two are currently supported: blob and " "path. When using the blob scheme and X.509 private " "keys, this property should be set to the keys's " - "decrypted DER encoded data. When using X.509 " - "private keys with the path scheme, this property " - "should be set to the full UTF-8 encoded path of " - "the key, prefixed with the string 'file://' and " - "and ending with a terminating NULL byte. When " - "using PKCS#12 format private keys and the blob " + "PEM or DER encoded data; if using DER-encoded " + "data the private key must be decrypted as the " + "DER format is incomplete. Use of decrypted " + "DER-format private keys is not recommended as it " + "may allow unprivileged users access to the " + "decrypted data. When using X.509 private keys " + "with the path scheme, this property should be " + "set to the full UTF-8 encoded path of the key, " + "prefixed with the string 'file://' and ending " + "with a terminating NULL byte. When using " + "PKCS#12 format private keys and the blob " "scheme, this property should be set to the " "PKCS#12 data (which is encrypted) and the " "'private-key-password' property must be set to " @@ -3382,7 +3108,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) "be set to the password used to decode the PKCS#12 " "private key and certificate.", DBUS_TYPE_G_UCHAR_ARRAY, - G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); /** * NMSetting8021x:phase2-private-key-password: @@ -3405,6 +3131,21 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + /** + * NMSetting8021x:phase2-private-key-password-flags: + * + * Flags indicating how to handle #NMSetting8021x:phase2-private-key-password:. + **/ + g_object_class_install_property (object_class, PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, + "Phase2 Private Key Password Flags", + "Flags indicating how to handle the 802.1x phase2 " + "private key password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSetting8021x:system-ca-certs: * diff --git a/libnm-util/nm-setting-8021x.h b/libnm-util/nm-setting-8021x.h index 7ee868a012..00cfedd043 100644 --- a/libnm-util/nm-setting-8021x.h +++ b/libnm-util/nm-setting-8021x.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2009 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -81,12 +81,15 @@ GQuark nm_setting_802_1x_error_quark (void); #define NM_SETTING_802_1X_PHASE2_CA_PATH "phase2-ca-path" #define NM_SETTING_802_1X_PHASE2_CLIENT_CERT "phase2-client-cert" #define NM_SETTING_802_1X_PASSWORD "password" +#define NM_SETTING_802_1X_PASSWORD_FLAGS "password-flags" #define NM_SETTING_802_1X_PRIVATE_KEY "private-key" #define NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD "private-key-password" +#define NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS "private-key-password-flags" #define NM_SETTING_802_1X_PHASE2_PRIVATE_KEY "phase2-private-key" #define NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD "phase2-private-key-password" +#define NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS "phase2-private-key-password-flags" #define NM_SETTING_802_1X_PIN "pin" -#define NM_SETTING_802_1X_PSK "psk" +#define NM_SETTING_802_1X_PIN_FLAGS "pin-flags" #define NM_SETTING_802_1X_SYSTEM_CA_CERTS "system-ca-certs" /* PRIVATE KEY NOTE: when setting PKCS#12 private keys directly via properties @@ -102,15 +105,17 @@ GQuark nm_setting_802_1x_error_quark (void); * * When setting OpenSSL-derived "traditional" format (ie S/MIME style, not * PKCS#8) RSA and DSA keys directly via properties with the "blob" scheme, they - * must passed to NetworkManager completely decrypted because the OpenSSL - * "traditional" format is non-standard and is not complete enough for all - * crypto libraries to use. Thus, for OpenSSL "traditional" format keys, the - * private key password is not passed to NetworkManager (because the data is - * already decrypted by the client), and the appropriate "client-cert" (or - * "phase2-client-cert") property of the NMSetting8021x object must be a valid - * client certificate. When using the "path" scheme, just set the private-key - * and client-cert properties to the paths to their respective objects, and - * set the private-key password correctly. + * should be passed to NetworkManager in PEM format with the "DEK-Info" and + * "Proc-Type" tags intact, or in decrypted binary DER format (not recommended, + * as this may allow unprivileged users to read the decrypted private key). + * When decryped keys are used (again, not recommended) the private key password + * should not be set. The recommended method for passing private keys to + * NetworkManager is via the "path" scheme with encrypted private keys, and a + * private key password. + * + * When using the "path" scheme, just set the private-key and client-cert + * properties to the paths to their respective objects, and set the private-key + * password correctly. */ typedef struct { @@ -192,10 +197,10 @@ gboolean nm_setting_802_1x_set_phase2_client_cert (NMSett GError **error); const char * nm_setting_802_1x_get_password (NMSetting8021x *setting); +NMSettingSecretFlags nm_setting_802_1x_get_password_flags (NMSetting8021x *setting); const char * nm_setting_802_1x_get_pin (NMSetting8021x *setting); - -const char * nm_setting_802_1x_get_psk (NMSetting8021x *setting); +NMSettingSecretFlags nm_setting_802_1x_get_pin_flags (NMSetting8021x *setting); NMSetting8021xCKScheme nm_setting_802_1x_get_private_key_scheme (NMSetting8021x *setting); const GByteArray * nm_setting_802_1x_get_private_key_blob (NMSetting8021x *setting); @@ -207,6 +212,7 @@ gboolean nm_setting_802_1x_set_private_key (NMSett NMSetting8021xCKFormat *out_format, GError **error); const char * nm_setting_802_1x_get_private_key_password (NMSetting8021x *setting); +NMSettingSecretFlags nm_setting_802_1x_get_private_key_password_flags (NMSetting8021x *setting); NMSetting8021xCKFormat nm_setting_802_1x_get_private_key_format (NMSetting8021x *setting); @@ -220,61 +226,11 @@ gboolean nm_setting_802_1x_set_phase2_private_key (NMSett NMSetting8021xCKFormat *out_format, GError **error); const char * nm_setting_802_1x_get_phase2_private_key_password (NMSetting8021x *setting); +NMSettingSecretFlags nm_setting_802_1x_get_phase2_private_key_password_flags (NMSetting8021x *setting); NMSetting8021xCKFormat nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting); -/***** DEPRECATED; anything below will be removed in version 0.9 *****/ - -typedef enum { - NM_SETTING_802_1X_CK_TYPE_UNKNOWN = 0, - NM_SETTING_802_1X_CK_TYPE_X509, - NM_SETTING_802_1X_CK_TYPE_RAW_KEY, - NM_SETTING_802_1X_CK_TYPE_PKCS12 -} NMSetting8021xCKType; - -const GByteArray *nm_setting_802_1x_get_ca_cert (NMSetting8021x *setting); -gboolean nm_setting_802_1x_set_ca_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error); - -const GByteArray *nm_setting_802_1x_get_client_cert (NMSetting8021x *setting); -gboolean nm_setting_802_1x_set_client_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error); - -const GByteArray *nm_setting_802_1x_get_phase2_ca_cert (NMSetting8021x *setting); -gboolean nm_setting_802_1x_set_phase2_ca_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error); - -const GByteArray *nm_setting_802_1x_get_phase2_client_cert (NMSetting8021x *setting); -gboolean nm_setting_802_1x_set_phase2_client_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error); - -const GByteArray *nm_setting_802_1x_get_private_key (NMSetting8021x *setting); -gboolean nm_setting_802_1x_set_private_key_from_file (NMSetting8021x *setting, - const char *filename, - const char *password, - NMSetting8021xCKType *out_ck_type, - GError **error); - -NMSetting8021xCKType nm_setting_802_1x_get_private_key_type (NMSetting8021x *setting); - -const GByteArray *nm_setting_802_1x_get_phase2_private_key (NMSetting8021x *setting); -gboolean nm_setting_802_1x_set_phase2_private_key_from_file (NMSetting8021x *setting, - const char *filename, - const char *password, - NMSetting8021xCKType *out_ck_type, - GError **error); - -NMSetting8021xCKType nm_setting_802_1x_get_phase2_private_key_type (NMSetting8021x *setting); - G_END_DECLS #endif /* NM_SETTING_8021X_H */ diff --git a/libnm-util/nm-setting-cdma.c b/libnm-util/nm-setting-cdma.c index 7255eb9159..86f2d7bd64 100644 --- a/libnm-util/nm-setting-cdma.c +++ b/libnm-util/nm-setting-cdma.c @@ -18,13 +18,14 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. */ #include #include "nm-setting-cdma.h" #include "nm-setting-serial.h" #include "nm-utils.h" +#include "nm-setting-private.h" /** * SECTION:nm-setting-cdma @@ -87,6 +88,7 @@ typedef struct { char *number; /* For dialing, duh */ char *username; char *password; + NMSettingSecretFlags password_flags; } NMSettingCdmaPrivate; enum { @@ -94,6 +96,7 @@ enum { PROP_NUMBER, PROP_USERNAME, PROP_PASSWORD, + PROP_PASSWORD_FLAGS, LAST_PROP }; @@ -153,6 +156,20 @@ nm_setting_cdma_get_password (NMSettingCdma *setting) return NM_SETTING_CDMA_GET_PRIVATE (setting)->password; } +/** + * nm_setting_cdma_get_password_flags: + * @setting: the #NMSettingCdma + * + * Returns: the #NMSettingSecretFlags pertaining to the #NMSettingCdma:password + **/ +NMSettingSecretFlags +nm_setting_cdma_get_password_flags (NMSettingCdma *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_CDMA (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_CDMA_GET_PRIVATE (setting)->password_flags; +} + static gint find_setting_by_name (gconstpointer a, gconstpointer b) { @@ -220,8 +237,10 @@ need_secrets (NMSetting *setting) return NULL; if (priv->username) { - secrets = g_ptr_array_sized_new (1); - g_ptr_array_add (secrets, NM_SETTING_CDMA_PASSWORD); + if (!(priv->password_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) { + secrets = g_ptr_array_sized_new (1); + g_ptr_array_add (secrets, NM_SETTING_CDMA_PASSWORD); + } } return secrets; @@ -264,6 +283,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->password); priv->password = g_value_dup_string (value); break; + case PROP_PASSWORD_FLAGS: + priv->password_flags = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -286,6 +308,9 @@ get_property (GObject *object, guint prop_id, case PROP_PASSWORD: g_value_set_string (value, nm_setting_cdma_get_password (setting)); break; + case PROP_PASSWORD_FLAGS: + g_value_set_uint (value, nm_setting_cdma_get_password_flags (setting)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -360,4 +385,18 @@ nm_setting_cdma_class_init (NMSettingCdmaClass *setting_class) "a password or accept any password.", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + + /** + * NMSettingCdma:password-flags: + * + * Flags indicating how to handle #NMSettingCdma:password:. + **/ + g_object_class_install_property (object_class, PROP_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_CDMA_PASSWORD_FLAGS, + "Password Flags", + "Flags indicating how to handle the CDMA password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); } diff --git a/libnm-util/nm-setting-cdma.h b/libnm-util/nm-setting-cdma.h index 8a6c4505b0..8abfce4abb 100644 --- a/libnm-util/nm-setting-cdma.h +++ b/libnm-util/nm-setting-cdma.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -53,9 +53,10 @@ GType nm_setting_cdma_error_get_type (void); #define NM_SETTING_CDMA_ERROR nm_setting_cdma_error_quark () GQuark nm_setting_cdma_error_quark (void); -#define NM_SETTING_CDMA_NUMBER "number" -#define NM_SETTING_CDMA_USERNAME "username" -#define NM_SETTING_CDMA_PASSWORD "password" +#define NM_SETTING_CDMA_NUMBER "number" +#define NM_SETTING_CDMA_USERNAME "username" +#define NM_SETTING_CDMA_PASSWORD "password" +#define NM_SETTING_CDMA_PASSWORD_FLAGS "password-flags" typedef struct { NMSetting parent; @@ -77,6 +78,7 @@ NMSetting *nm_setting_cdma_new (void); const char *nm_setting_cdma_get_number (NMSettingCdma *setting); const char *nm_setting_cdma_get_username (NMSettingCdma *setting); const char *nm_setting_cdma_get_password (NMSettingCdma *setting); +NMSettingSecretFlags nm_setting_cdma_get_password_flags (NMSettingCdma *setting); G_END_DECLS diff --git a/libnm-util/nm-setting-connection.c b/libnm-util/nm-setting-connection.c index 65f613eba9..27e7913a73 100644 --- a/libnm-util/nm-setting-connection.c +++ b/libnm-util/nm-setting-connection.c @@ -19,12 +19,15 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ #include #include +#include "nm-utils.h" +#include "nm-dbus-glib-types.h" +#include "nm-param-spec-specialized.h" #include "nm-setting-connection.h" /** @@ -81,10 +84,20 @@ G_DEFINE_TYPE (NMSettingConnection, nm_setting_connection, NM_TYPE_SETTING) #define NM_SETTING_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_CONNECTION, NMSettingConnectionPrivate)) +typedef enum { + PERM_TYPE_USER = 0, +} PermType; + +typedef struct { + guint8 ptype; + char *item; +} Permission; + typedef struct { char *id; char *uuid; char *type; + GSList *permissions; /* list of Permission structs */ gboolean autoconnect; guint64 timestamp; gboolean read_only; @@ -95,6 +108,7 @@ enum { PROP_ID, PROP_UUID, PROP_TYPE, + PROP_PERMISSIONS, PROP_AUTOCONNECT, PROP_TIMESTAMP, PROP_READ_ONLY, @@ -102,6 +116,86 @@ enum { LAST_PROP }; +/***********************************************************************/ + +#define PERM_USER_PREFIX "user:" + +static Permission * +permission_new_from_str (const char *str) +{ + Permission *p; + const char *last_colon; + size_t ulen = 0, i; + + g_return_val_if_fail (strncmp (str, PERM_USER_PREFIX, strlen (PERM_USER_PREFIX)) == 0, NULL); + str += strlen (PERM_USER_PREFIX); + + last_colon = strrchr (str, ':'); + if (last_colon) { + /* Ensure that somebody didn't pass "user::" */ + g_return_val_if_fail (last_colon > str, NULL); + + /* Make sure we don't include detail in the username */ + ulen = last_colon - str; + } else + ulen = strlen (str); + + /* Sanity check the length of the username */ + g_return_val_if_fail (ulen < 100, NULL); + + /* Make sure there's no ':' in the username */ + for (i = 0; i < ulen; i++) + g_return_val_if_fail (str[i] != ':', NULL); + + /* And the username must be valid UTF-8 */ + g_return_val_if_fail (g_utf8_validate (str, -1, NULL) == TRUE, NULL); + + /* Yay, valid... create the new permission */ + p = g_slice_new0 (Permission); + p->ptype = PERM_TYPE_USER; + if (last_colon) { + p->item = g_malloc (ulen + 1); + memcpy (p->item, str, ulen); + p->item[ulen] = '\0'; + } else + p->item = g_strdup (str); + + return p; +} + +static Permission * +permission_new (const char *uname) +{ + Permission *p; + + g_return_val_if_fail (uname, NULL); + g_return_val_if_fail (uname[0] != '\0', NULL); + g_return_val_if_fail (strchr (uname, ':') == NULL, NULL); + g_return_val_if_fail (g_utf8_validate (uname, -1, NULL) == TRUE, NULL); + + /* Yay, valid... create the new permission */ + p = g_slice_new0 (Permission); + p->ptype = PERM_TYPE_USER; + p->item = g_strdup (uname); + return p; +} + +static char * +permission_to_string (Permission *p) +{ + return g_strdup_printf (PERM_USER_PREFIX "%s:", p->item); +} + +static void +permission_free (Permission *p) +{ + g_free (p->item); + memset (p, 0, sizeof (*p)); + g_slice_free (Permission, p); +} + +/***********************************************************************/ + /** * nm_setting_connection_new: * @@ -162,6 +256,177 @@ nm_setting_connection_get_connection_type (NMSettingConnection *setting) return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->type; } + +/** + * nm_setting_connection_get_num_permissions: + * @setting: the #NMSettingConnection + * + * Returns the number of entires in the #NMSettingConnection:permissions + * property of this setting. + * + * Returns: the number of permissions entires + */ +guint32 +nm_setting_connection_get_num_permissions (NMSettingConnection *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), 0); + + return g_slist_length (NM_SETTING_CONNECTION_GET_PRIVATE (setting)->permissions); +} + +/** + * nm_setting_connection_get_permission: + * @setting: the #NMSettingConnection + * @idx: the zero-based index of the permissions entry + * @out_ptype: on return, the permission type (at this time, always "user") + * @out_pitem: on return, the permission item (formatted accoring to @ptype, see + * #NMSettingConnection:permissions for more detail + * @out_detail: on return, the permission detail (at this time, always NULL) + * + * Retrieve one of the entries of the #NMSettingConnection:permissions property + * of this setting. + * + * Returns: %TRUE if a permission was returned, %FALSE if @idx was invalid + */ +gboolean +nm_setting_connection_get_permission (NMSettingConnection *setting, + guint32 idx, + const char **out_ptype, + const char **out_pitem, + const char **out_detail) +{ + NMSettingConnectionPrivate *priv; + Permission *p; + + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + + g_return_val_if_fail (idx < g_slist_length (priv->permissions), FALSE); + + p = g_slist_nth_data (priv->permissions, idx); + if (out_ptype) + *out_ptype = "user"; + if (out_pitem) + *out_pitem = p->item; + if (out_detail) + *out_detail = NULL; + + return TRUE; +} + +/** + * nm_setting_connection_permissions_user_allowed: + * @setting: the #NMSettingConnection + * @uname: the user name to check permissions for + * + * Checks whether the given username is allowed to view/access this connection. + * + * Returns: %TRUE if the requested user is allowed to view this connection, + * %FALSE if the given user is not allowed to view this connection + */ +gboolean +nm_setting_connection_permissions_user_allowed (NMSettingConnection *setting, + const char *uname) +{ + NMSettingConnectionPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE); + g_return_val_if_fail (uname != NULL, FALSE); + g_return_val_if_fail (*uname != '\0', FALSE); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + + /* If no permissions, visible to all */ + if (priv->permissions == NULL) + return TRUE; + + /* Find the username in the permissions list */ + for (iter = priv->permissions; iter; iter = g_slist_next (iter)) { + Permission *p = iter->data; + + if (strcmp (uname, p->item) == 0) + return TRUE; + } + + return FALSE; +} + +/** + * nm_setting_connection_add_permission: + * @setting: the #NMSettingConnection + * @ptype: the permission type; at this time only "user" is supported + * @pitem: the permission item formatted as required for @ptype + * @detail: unused at this time; must be %NULL + * + * Adds a permission to the connection's permission list. At this time, only + * the "user" permission type is supported, and @pitem must be a username. See + * #NMSettingConnection:permissions: for more details. + * + * Returns: TRUE if the permission was unique and was successfully added to the + * list, FALSE if @ptype or @pitem was invalid or it the permission was already + * present in the list + */ +gboolean +nm_setting_connection_add_permission (NMSettingConnection *setting, + const char *ptype, + const char *pitem, + const char *detail) +{ + NMSettingConnectionPrivate *priv; + Permission *p; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE); + g_return_val_if_fail (ptype, FALSE); + g_return_val_if_fail (strlen (ptype) > 0, FALSE); + g_return_val_if_fail (detail == NULL, FALSE); + + /* Only "user" for now... */ + g_return_val_if_fail (strcmp (ptype, "user") == 0, FALSE); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + + /* No dupes */ + for (iter = priv->permissions; iter; iter = g_slist_next (iter)) { + p = iter->data; + if (strcmp (pitem, p->item) == 0) + return FALSE; + } + + p = permission_new (pitem); + g_return_val_if_fail (p != NULL, FALSE); + priv->permissions = g_slist_append (priv->permissions, p); + + return TRUE; +} + +/** + * nm_setting_connection_remove_permission: + * @setting: the #NMSettingConnection + * @idx: the zero-based index of the permission to remove + * + * Removes the permission at index @idx from the connection. + */ +void +nm_setting_connection_remove_permission (NMSettingConnection *setting, + guint32 idx) +{ + NMSettingConnectionPrivate *priv; + GSList *iter; + + g_return_if_fail (NM_IS_SETTING_CONNECTION (setting)); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + iter = g_slist_nth (priv->permissions, idx); + g_return_if_fail (iter != NULL); + + permission_free ((Permission *) iter->data); + priv->permissions = g_slist_delete_link (priv->permissions, iter); +} + + /** * nm_setting_connection_get_autoconnect: * @setting: the #NMSettingConnection @@ -308,13 +573,30 @@ finalize (GObject *object) g_free (priv->id); g_free (priv->uuid); g_free (priv->type); + nm_utils_slist_free (priv->permissions, (GDestroyNotify) permission_free); G_OBJECT_CLASS (nm_setting_connection_parent_class)->finalize (object); } +static GSList * +perm_stringlist_to_permlist (GSList *strlist) +{ + GSList *list = NULL, *iter; + + for (iter = strlist; iter; iter = g_slist_next (iter)) { + Permission *p; + + p = permission_new_from_str ((const char *) iter->data); + if (p) + list = g_slist_append (list, p); + } + + return list; +} + static void set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) + const GValue *value, GParamSpec *pspec) { NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (object); @@ -331,6 +613,10 @@ set_property (GObject *object, guint prop_id, g_free (priv->type); priv->type = g_value_dup_string (value); break; + case PROP_PERMISSIONS: + nm_utils_slist_free (priv->permissions, (GDestroyNotify) permission_free); + priv->permissions = perm_stringlist_to_permlist (g_value_get_boxed (value)); + break; case PROP_AUTOCONNECT: priv->autoconnect = g_value_get_boolean (value); break; @@ -346,11 +632,22 @@ set_property (GObject *object, guint prop_id, } } +static GSList * +perm_permlist_to_stringlist (GSList *permlist) +{ + GSList *list = NULL, *iter; + + for (iter = permlist; iter; iter = g_slist_next (iter)) + list = g_slist_append (list, permission_to_string ((Permission *) iter->data)); + return list; +} + static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMSettingConnection *setting = NM_SETTING_CONNECTION (object); + NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); switch (prop_id) { case PROP_ID: @@ -362,6 +659,9 @@ get_property (GObject *object, guint prop_id, case PROP_TYPE: g_value_set_string (value, nm_setting_connection_get_connection_type (setting)); break; + case PROP_PERMISSIONS: + g_value_take_boxed (value, perm_permlist_to_stringlist (priv->permissions)); + break; case PROP_AUTOCONNECT: g_value_set_boolean (value, nm_setting_connection_get_autoconnect (setting)); break; @@ -464,6 +764,45 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class) NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** + * NMSettingConnection:permissions: + * + * An array of strings defining what access a given user has to this + * connection. If this is NULL or empty, all users are allowed to access + * this connection. Otherwise a user is allowed to access this connection + * if and only if they are in this list. Each entry is of the form + * "[type]:[id]:[reserved]", for example: + * + * user:dcbw:blah + * + * At this time only the 'user' [type] is allowed. Any other values are + * ignored and reserved for future use. [id] is the username that this + * permission refers to, which may not contain the ':' character. Any + * [reserved] information present must be ignored and is reserved for + * future use. All of [type], [id], and [reserved] must be valid UTF-8. + */ + g_object_class_install_property + (object_class, PROP_PERMISSIONS, + _nm_param_spec_specialized (NM_SETTING_CONNECTION_PERMISSIONS, + "Permissions", + "An array of strings defining what access a given " + "user has to this connection. If this is NULL or " + "empty, all users are allowed to access this " + "connection. Otherwise a user is allowed to access " + "this connection if and only if they are in this " + "array. Each entry is of the form " + "\"[type]:[id]:[reserved]\", for example: " + "\"user:dcbw:blah\" At this time only the 'user' " + "[type] is allowed. Any other values are ignored and " + "reserved for future use. [id] is the username that " + "this permission refers to, which may not contain the " + "':' character. Any [reserved] information (if " + "present) must be ignored and is reserved for future " + "use. All of [type], [id], and [reserved] must be " + "valid UTF-8.", + DBUS_TYPE_G_LIST_OF_STRING, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSettingConnection:autoconnect: * diff --git a/libnm-util/nm-setting-connection.h b/libnm-util/nm-setting-connection.h index 6dedca220b..1ec5bf1204 100644 --- a/libnm-util/nm-setting-connection.h +++ b/libnm-util/nm-setting-connection.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2010 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -74,6 +74,7 @@ GQuark nm_setting_connection_error_quark (void); #define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect" #define NM_SETTING_CONNECTION_TIMESTAMP "timestamp" #define NM_SETTING_CONNECTION_READ_ONLY "read-only" +#define NM_SETTING_CONNECTION_PERMISSIONS "permissions" /** * NMSettingConnection: @@ -97,13 +98,27 @@ typedef struct { GType nm_setting_connection_get_type (void); -NMSetting * nm_setting_connection_new (void); -const char *nm_setting_connection_get_id (NMSettingConnection *setting); -const char *nm_setting_connection_get_uuid (NMSettingConnection *setting); -const char *nm_setting_connection_get_connection_type (NMSettingConnection *setting); -gboolean nm_setting_connection_get_autoconnect (NMSettingConnection *setting); -guint64 nm_setting_connection_get_timestamp (NMSettingConnection *setting); -gboolean nm_setting_connection_get_read_only (NMSettingConnection *setting); +NMSetting * nm_setting_connection_new (void); +const char *nm_setting_connection_get_id (NMSettingConnection *setting); +const char *nm_setting_connection_get_uuid (NMSettingConnection *setting); +const char *nm_setting_connection_get_connection_type (NMSettingConnection *setting); +gboolean nm_setting_connection_get_autoconnect (NMSettingConnection *setting); +guint64 nm_setting_connection_get_timestamp (NMSettingConnection *setting); +gboolean nm_setting_connection_get_read_only (NMSettingConnection *setting); + +guint32 nm_setting_connection_get_num_permissions (NMSettingConnection *setting); +gboolean nm_setting_connection_get_permission (NMSettingConnection *setting, + guint32 idx, + const char **out_ptype, + const char **out_pitem, + const char **out_detail); +gboolean nm_setting_connection_permissions_user_allowed (NMSettingConnection *setting, const char *uname); +gboolean nm_setting_connection_add_permission (NMSettingConnection *setting, + const char *ptype, + const char *pitem, + const char *detail); +void nm_setting_connection_remove_permission (NMSettingConnection *setting, + guint32 idx); G_END_DECLS diff --git a/libnm-util/nm-setting-gsm.c b/libnm-util/nm-setting-gsm.c index 9f24265d8c..aeac116448 100644 --- a/libnm-util/nm-setting-gsm.c +++ b/libnm-util/nm-setting-gsm.c @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2010 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -28,6 +28,7 @@ #include "nm-setting-gsm.h" #include "nm-setting-serial.h" #include "nm-utils.h" +#include "nm-setting-private.h" GQuark nm_setting_gsm_error_quark (void) @@ -73,6 +74,7 @@ typedef struct { char *number; /* For dialing, duh */ char *username; char *password; + NMSettingSecretFlags password_flags; char *apn; /* NULL for dynamic */ char *network_id; /* for manual registration or NULL for automatic */ @@ -80,6 +82,7 @@ typedef struct { guint32 allowed_bands; /* A bitfield of NM_SETTING_GSM_BAND_* */ char *pin; + NMSettingSecretFlags pin_flags; gboolean home_only; } NMSettingGsmPrivate; @@ -89,12 +92,12 @@ enum { PROP_NUMBER, PROP_USERNAME, PROP_PASSWORD, + PROP_PASSWORD_FLAGS, PROP_APN, PROP_NETWORK_ID, PROP_NETWORK_TYPE, - PROP_BAND, PROP_PIN, - PROP_PUK, + PROP_PIN_FLAGS, PROP_ALLOWED_BANDS, PROP_HOME_ONLY, @@ -140,6 +143,20 @@ nm_setting_gsm_get_password (NMSettingGsm *setting) return NM_SETTING_GSM_GET_PRIVATE (setting)->password; } +/** + * nm_setting_gsm_get_password_flags: + * @setting: the #NMSettingGsm + * + * Returns: the #NMSettingSecretFlags pertaining to the #NMSettingGsm:password + **/ +NMSettingSecretFlags +nm_setting_gsm_get_password_flags (NMSettingGsm *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_GSM (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_GSM_GET_PRIVATE (setting)->password_flags; +} + const char * nm_setting_gsm_get_apn (NMSettingGsm *setting) { @@ -164,13 +181,6 @@ nm_setting_gsm_get_network_type (NMSettingGsm *setting) return NM_SETTING_GSM_GET_PRIVATE (setting)->network_type; } -int -nm_setting_gsm_get_band (NMSettingGsm *setting) -{ - g_warning ("Tried to get deprecated property " NM_SETTING_GSM_SETTING_NAME "/" NM_SETTING_GSM_BAND); - return -1; -} - guint32 nm_setting_gsm_get_allowed_bands (NMSettingGsm *setting) { @@ -187,11 +197,18 @@ nm_setting_gsm_get_pin (NMSettingGsm *setting) return NM_SETTING_GSM_GET_PRIVATE (setting)->pin; } -const char * -nm_setting_gsm_get_puk (NMSettingGsm *setting) +/** + * nm_setting_gsm_get_pin_flags: + * @setting: the #NMSettingGsm + * + * Returns: the #NMSettingSecretFlags pertaining to the #NMSettingGsm:pin + **/ +NMSettingSecretFlags +nm_setting_gsm_get_pin_flags (NMSettingGsm *setting) { - g_warning ("Tried to get deprecated property " NM_SETTING_GSM_SETTING_NAME "/" NM_SETTING_GSM_PUK); - return NULL; + g_return_val_if_fail (NM_IS_SETTING_GSM (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_GSM_GET_PRIVATE (setting)->pin_flags; } gboolean @@ -310,8 +327,10 @@ need_secrets (NMSetting *setting) return NULL; if (priv->username) { - secrets = g_ptr_array_sized_new (1); - g_ptr_array_add (secrets, NM_SETTING_GSM_PASSWORD); + if (!(priv->password_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) { + secrets = g_ptr_array_sized_new (1); + g_ptr_array_add (secrets, NM_SETTING_GSM_PASSWORD); + } } return secrets; @@ -343,7 +362,6 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMSettingGsmPrivate *priv = NM_SETTING_GSM_GET_PRIVATE (object); - const char *str; char *tmp; switch (prop_id) { @@ -359,6 +377,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->password); priv->password = g_value_dup_string (value); break; + case PROP_PASSWORD_FLAGS: + priv->password_flags = g_value_get_uint (value); + break; case PROP_APN: g_free (priv->apn); priv->apn = NULL; @@ -376,10 +397,6 @@ set_property (GObject *object, guint prop_id, case PROP_NETWORK_TYPE: priv->network_type = g_value_get_int (value); break; - case PROP_BAND: - if (g_value_get_int (value) != -1) - g_warning ("Tried to set deprecated property " NM_SETTING_GSM_SETTING_NAME "/" NM_SETTING_GSM_BAND); - break; case PROP_ALLOWED_BANDS: priv->allowed_bands = g_value_get_uint (value); break; @@ -387,10 +404,8 @@ set_property (GObject *object, guint prop_id, g_free (priv->pin); priv->pin = g_value_dup_string (value); break; - case PROP_PUK: - str = g_value_get_string (value); - if (str && strlen (str)) - g_warning ("Tried to set deprecated property " NM_SETTING_GSM_SETTING_NAME "/" NM_SETTING_GSM_PUK); + case PROP_PIN_FLAGS: + priv->pin_flags = g_value_get_uint (value); break; case PROP_HOME_ONLY: priv->home_only = g_value_get_boolean (value); @@ -417,6 +432,9 @@ get_property (GObject *object, guint prop_id, case PROP_PASSWORD: g_value_set_string (value, nm_setting_gsm_get_password (setting)); break; + case PROP_PASSWORD_FLAGS: + g_value_set_uint (value, nm_setting_gsm_get_password_flags (setting)); + break; case PROP_APN: g_value_set_string (value, nm_setting_gsm_get_apn (setting)); break; @@ -432,13 +450,8 @@ get_property (GObject *object, guint prop_id, case PROP_PIN: g_value_set_string (value, nm_setting_gsm_get_pin (setting)); break; - case PROP_PUK: - /* deprecated */ - g_value_set_string (value, NULL); - break; - case PROP_BAND: - /* deprecated */ - g_value_set_int (value, -1); + case PROP_PIN_FLAGS: + g_value_set_uint (value, nm_setting_gsm_get_pin_flags (setting)); break; case PROP_HOME_ONLY: g_value_set_boolean (value, nm_setting_gsm_get_home_only (setting)); @@ -520,6 +533,20 @@ nm_setting_gsm_class_init (NMSettingGsmClass *setting_class) NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + /** + * NMSettingGsm:password-flags: + * + * Flags indicating how to handle #NMSettingGsm:password:. + **/ + g_object_class_install_property (object_class, PROP_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_GSM_PASSWORD_FLAGS, + "Password Flags", + "Flags indicating how to handle the GSM password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSettingGsm:apn: * @@ -639,6 +666,20 @@ nm_setting_gsm_class_init (NMSettingGsmClass *setting_class) NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + /** + * NMSettingGsm:pin-flags: + * + * Flags indicating how to handle #NMSettingGsm:pin:. + **/ + g_object_class_install_property (object_class, PROP_PIN_FLAGS, + g_param_spec_uint (NM_SETTING_GSM_PIN_FLAGS, + "PIN Flags", + "Flags indicating how to handle the GSM SIM PIN.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSettingGsm:home-only: * @@ -654,31 +695,4 @@ nm_setting_gsm_class_init (NMSettingGsmClass *setting_class) "not be made.", FALSE, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); - - /* Deprecated properties */ - /** - * NMSettingGsm:puk: - * - * DEPRECATED - **/ - g_object_class_install_property - (object_class, PROP_PUK, - g_param_spec_string (NM_SETTING_GSM_PUK, - "PUK (DEPRECATED and UNUSED)", - "PUK (DEPRECATED and UNUSED)", - NULL, - G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); - - /** - * NMSettingGsm:band: - * - * DEPRECATED - **/ - g_object_class_install_property - (object_class, PROP_BAND, - g_param_spec_int (NM_SETTING_GSM_BAND, - "Band (DEPRECATED and UNUSED)", - "Band (DEPRECATED and UNUSED)", - -1, 5, -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); } diff --git a/libnm-util/nm-setting-gsm.h b/libnm-util/nm-setting-gsm.h index 0ac7122462..855787c2d3 100644 --- a/libnm-util/nm-setting-gsm.h +++ b/libnm-util/nm-setting-gsm.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2010 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -53,26 +53,17 @@ GType nm_setting_gsm_error_get_type (void); #define NM_SETTING_GSM_ERROR nm_setting_gsm_error_quark () GQuark nm_setting_gsm_error_quark (void); -#define NM_SETTING_GSM_NUMBER "number" -#define NM_SETTING_GSM_USERNAME "username" -#define NM_SETTING_GSM_PASSWORD "password" -#define NM_SETTING_GSM_APN "apn" -#define NM_SETTING_GSM_NETWORK_ID "network-id" -#define NM_SETTING_GSM_NETWORK_TYPE "network-type" -#define NM_SETTING_GSM_ALLOWED_BANDS "allowed-bands" -#define NM_SETTING_GSM_PIN "pin" -#define NM_SETTING_GSM_HOME_ONLY "home-only" - -/* DEPRECATED & UNUSED */ -#define NM_SETTING_GSM_PUK "puk" -#define NM_SETTING_GSM_BAND "band" - -/* DEPRECATED, use NM_SETTING_NETWORK_TYPE_* instead */ -#define NM_GSM_NETWORK_ANY NM_SETTING_GSM_NETWORK_TYPE_ANY -#define NM_GSM_NETWORK_UMTS_HSPA NM_SETTING_GSM_NETWORK_TYPE_UMTS_HSPA -#define NM_GSM_NETWORK_GPRS_EDGE NM_SETTING_GSM_NETWORK_TYPE_GPRS_EDGE -#define NM_GSM_NETWORK_PREFER_UMTS_HSPA NM_SETTING_GSM_NETWORK_TYPE_PREFER_UMTS_HSPA -#define NM_GSM_NETWORK_PREFER_GPRS_EDGE NM_SETTING_GSM_NETWORK_TYPE_PREFER_GPRS_EDGE +#define NM_SETTING_GSM_NUMBER "number" +#define NM_SETTING_GSM_USERNAME "username" +#define NM_SETTING_GSM_PASSWORD "password" +#define NM_SETTING_GSM_PASSWORD_FLAGS "password-flags" +#define NM_SETTING_GSM_APN "apn" +#define NM_SETTING_GSM_NETWORK_ID "network-id" +#define NM_SETTING_GSM_NETWORK_TYPE "network-type" +#define NM_SETTING_GSM_ALLOWED_BANDS "allowed-bands" +#define NM_SETTING_GSM_PIN "pin" +#define NM_SETTING_GSM_PIN_FLAGS "pin-flags" +#define NM_SETTING_GSM_HOME_ONLY "home-only" typedef enum { NM_SETTING_GSM_NETWORK_TYPE_ANY = -1, @@ -126,9 +117,8 @@ guint32 nm_setting_gsm_get_allowed_bands (NMSettingGsm *setting); const char *nm_setting_gsm_get_pin (NMSettingGsm *setting); gboolean nm_setting_gsm_get_home_only (NMSettingGsm *setting); -/* DEPRECATED & UNUSED */ -const char *nm_setting_gsm_get_puk (NMSettingGsm *setting); -int nm_setting_gsm_get_band (NMSettingGsm *setting); +NMSettingSecretFlags nm_setting_gsm_get_pin_flags (NMSettingGsm *setting); +NMSettingSecretFlags nm_setting_gsm_get_password_flags (NMSettingGsm *setting); G_END_DECLS diff --git a/libnm-util/nm-setting-ip4-config.c b/libnm-util/nm-setting-ip4-config.c index ec8de7ce3b..21dae96ed7 100644 --- a/libnm-util/nm-setting-ip4-config.c +++ b/libnm-util/nm-setting-ip4-config.c @@ -66,6 +66,8 @@ nm_setting_ip4_config_error_get_type (void) return etype; } +G_DEFINE_BOXED_TYPE (NMIP4Address, nm_ip4_address, nm_ip4_address_dup, nm_ip4_address_unref) +G_DEFINE_BOXED_TYPE (NMIP4Route, nm_ip4_route, nm_ip4_route_dup, nm_ip4_route_unref) G_DEFINE_TYPE (NMSettingIP4Config, nm_setting_ip4_config, NM_TYPE_SETTING) diff --git a/libnm-util/nm-setting-ip4-config.h b/libnm-util/nm-setting-ip4-config.h index 80ddd4758e..91cf0ea6d7 100644 --- a/libnm-util/nm-setting-ip4-config.h +++ b/libnm-util/nm-setting-ip4-config.h @@ -74,6 +74,8 @@ GQuark nm_setting_ip4_config_error_quark (void); typedef struct NMIP4Address NMIP4Address; +GType nm_ip4_address_get_type (void); + NMIP4Address * nm_ip4_address_new (void); NMIP4Address * nm_ip4_address_dup (NMIP4Address *source); void nm_ip4_address_ref (NMIP4Address *address); @@ -95,6 +97,8 @@ void nm_ip4_address_set_gateway (NMIP4Address *address, typedef struct NMIP4Route NMIP4Route; +GType nm_ip4_route_get_type (void); + NMIP4Route * nm_ip4_route_new (void); NMIP4Route * nm_ip4_route_dup (NMIP4Route *route); void nm_ip4_route_ref (NMIP4Route *route); diff --git a/libnm-util/nm-setting-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index e8af058041..10fe3ccd6d 100644 --- a/libnm-util/nm-setting-ip6-config.c +++ b/libnm-util/nm-setting-ip6-config.c @@ -65,6 +65,8 @@ nm_setting_ip6_config_error_get_type (void) return etype; } +G_DEFINE_BOXED_TYPE (NMIP6Address, nm_ip6_address, nm_ip6_address_dup, nm_ip6_address_unref) +G_DEFINE_BOXED_TYPE (NMIP6Route, nm_ip6_route, nm_ip6_route_dup, nm_ip6_route_unref) G_DEFINE_TYPE (NMSettingIP6Config, nm_setting_ip6_config, NM_TYPE_SETTING) diff --git a/libnm-util/nm-setting-ip6-config.h b/libnm-util/nm-setting-ip6-config.h index e3e286e684..b9733b4ac1 100644 --- a/libnm-util/nm-setting-ip6-config.h +++ b/libnm-util/nm-setting-ip6-config.h @@ -74,6 +74,8 @@ GQuark nm_setting_ip6_config_error_quark (void); typedef struct NMIP6Address NMIP6Address; +GType nm_ip6_address_get_type (void); + NMIP6Address * nm_ip6_address_new (void); NMIP6Address * nm_ip6_address_dup (NMIP6Address *source); void nm_ip6_address_ref (NMIP6Address *address); @@ -95,6 +97,8 @@ void nm_ip6_address_set_gateway (NMIP6Address *address, typedef struct NMIP6Route NMIP6Route; +GType nm_ip6_route_get_type (void); + NMIP6Route * nm_ip6_route_new (void); NMIP6Route * nm_ip6_route_dup (NMIP6Route *route); void nm_ip6_route_ref (NMIP6Route *route); diff --git a/libnm-util/nm-setting-pppoe.c b/libnm-util/nm-setting-pppoe.c index d1aba43d30..18dd7983a4 100644 --- a/libnm-util/nm-setting-pppoe.c +++ b/libnm-util/nm-setting-pppoe.c @@ -19,13 +19,14 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2010 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ #include #include "nm-setting-pppoe.h" #include "nm-setting-ppp.h" +#include "nm-setting-private.h" GQuark nm_setting_pppoe_error_quark (void) @@ -71,6 +72,7 @@ typedef struct { char *service; char *username; char *password; + NMSettingSecretFlags password_flags; } NMSettingPPPOEPrivate; enum { @@ -78,6 +80,7 @@ enum { PROP_SERVICE, PROP_USERNAME, PROP_PASSWORD, + PROP_PASSWORD_FLAGS, LAST_PROP }; @@ -112,6 +115,20 @@ nm_setting_pppoe_get_password (NMSettingPPPOE *setting) return NM_SETTING_PPPOE_GET_PRIVATE (setting)->password; } +/** + * nm_setting_pppoe_get_password_flags: + * @setting: the #NMSettingPPPOE + * + * Returns: the #NMSettingSecretFlags pertaining to the #NMSettingPPPOE:password + **/ +NMSettingSecretFlags +nm_setting_pppoe_get_password_flags (NMSettingPPPOE *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_PPPOE (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_PPPOE_GET_PRIVATE (setting)->password_flags; +} + static gboolean verify (NMSetting *setting, GSList *all_settings, GError **error) { @@ -146,13 +163,15 @@ static GPtrArray * need_secrets (NMSetting *setting) { NMSettingPPPOEPrivate *priv = NM_SETTING_PPPOE_GET_PRIVATE (setting); - GPtrArray *secrets; + GPtrArray *secrets = NULL; if (priv->password) return NULL; - secrets = g_ptr_array_sized_new (1); - g_ptr_array_add (secrets, NM_SETTING_PPPOE_PASSWORD); + if (!(priv->password_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) { + secrets = g_ptr_array_sized_new (1); + g_ptr_array_add (secrets, NM_SETTING_PPPOE_PASSWORD); + } return secrets; } @@ -182,6 +201,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->password); priv->password = g_value_dup_string (value); break; + case PROP_PASSWORD_FLAGS: + priv->password_flags = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -204,6 +226,9 @@ get_property (GObject *object, guint prop_id, case PROP_PASSWORD: g_value_set_string (value, nm_setting_pppoe_get_password (setting)); break; + case PROP_PASSWORD_FLAGS: + g_value_set_uint (value, nm_setting_pppoe_get_password_flags (setting)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -271,4 +296,18 @@ nm_setting_pppoe_class_init (NMSettingPPPOEClass *setting_class) "Password used to authenticate with the PPPoE service.", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + + /** + * NMSettingPPPOE:password-flags: + * + * Flags indicating how to handle #NMSettingPPPOE:password:. + **/ + g_object_class_install_property (object_class, PROP_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_PPPOE_PASSWORD_FLAGS, + "Password Flags", + "Flags indicating how to handle the PPPoE password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); } diff --git a/libnm-util/nm-setting-pppoe.h b/libnm-util/nm-setting-pppoe.h index 83e95d4ee6..d163decb4c 100644 --- a/libnm-util/nm-setting-pppoe.h +++ b/libnm-util/nm-setting-pppoe.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -53,9 +53,10 @@ GType nm_setting_pppoe_error_get_type (void); #define NM_SETTING_PPPOE_ERROR nm_setting_pppoe_error_quark () GQuark nm_setting_pppoe_error_quark (void); -#define NM_SETTING_PPPOE_SERVICE "service" -#define NM_SETTING_PPPOE_USERNAME "username" -#define NM_SETTING_PPPOE_PASSWORD "password" +#define NM_SETTING_PPPOE_SERVICE "service" +#define NM_SETTING_PPPOE_USERNAME "username" +#define NM_SETTING_PPPOE_PASSWORD "password" +#define NM_SETTING_PPPOE_PASSWORD_FLAGS "password-flags" typedef struct { NMSetting parent; @@ -77,6 +78,7 @@ NMSetting *nm_setting_pppoe_new (void); const char *nm_setting_pppoe_get_service (NMSettingPPPOE *setting); const char *nm_setting_pppoe_get_username (NMSettingPPPOE *setting); const char *nm_setting_pppoe_get_password (NMSettingPPPOE *setting); +NMSettingSecretFlags nm_setting_pppoe_get_password_flags (NMSettingPPPOE *setting); G_END_DECLS diff --git a/libnm-util/nm-setting-private.h b/libnm-util/nm-setting-private.h new file mode 100644 index 0000000000..5c4e0a5ede --- /dev/null +++ b/libnm-util/nm-setting-private.h @@ -0,0 +1,31 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2011 Red Hat, Inc. + */ + +#ifndef NM_SETTING_PRIVATE_H +#define NM_SETTING_PRIVATE_H + +#define NM_SETTING_SECRET_FLAGS_ALL \ + (NM_SETTING_SECRET_FLAG_NONE | \ + NM_SETTING_SECRET_FLAG_AGENT_OWNED | \ + NM_SETTING_SECRET_FLAG_NOT_SAVED | \ + NM_SETTING_SECRET_FLAG_NOT_REQUIRED) + +#endif /* NM_SETTING_PRIVATE_H */ + diff --git a/libnm-util/nm-setting-vpn.c b/libnm-util/nm-setting-vpn.c index 53b609e2d8..53884f9db6 100644 --- a/libnm-util/nm-setting-vpn.c +++ b/libnm-util/nm-setting-vpn.c @@ -18,16 +18,19 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ #include +#include +#include #include #include "nm-setting-vpn.h" #include "nm-param-spec-specialized.h" #include "nm-utils.h" #include "nm-dbus-glib-types.h" +#include "nm-setting-private.h" GQuark nm_setting_vpn_error_quark (void) @@ -158,9 +161,17 @@ nm_setting_vpn_remove_data_item (NMSettingVPN *setting, const char *key) g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->data, key); } +/** + * nm_setting_vpn_foreach_data_item: + * @setting: a #NMSettingVPN + * @func: (scope call): an user provided function + * @user_data: + * + * Iterates all data items stored in this setting + */ void nm_setting_vpn_foreach_data_item (NMSettingVPN *setting, - VPNIterFunc func, + NMVPNIterFunc func, gpointer user_data) { g_return_if_fail (NM_IS_SETTING_VPN (setting)); @@ -200,9 +211,17 @@ nm_setting_vpn_remove_secret (NMSettingVPN *setting, const char *key) g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, key); } +/** + * nm_setting_vpn_foreach_secret: + * @setting: a #NMSettingVPN + * @func: (scope call): an user provided function + * @user_data: + * + * Iterates all secrets stored in this setting. + */ void nm_setting_vpn_foreach_secret (NMSettingVPN *setting, - VPNIterFunc func, + NMVPNIterFunc func, gpointer user_data) { g_return_if_fail (NM_IS_SETTING_VPN (setting)); @@ -245,34 +264,158 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) } static gboolean -update_one_secret (NMSetting *setting, const char *key, GValue *value, GError **error) +update_secret_string (NMSetting *setting, + const char *key, + const char *value, + GError **error) { NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting); - char *str; g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); - if (!G_VALUE_HOLDS_STRING (value)) { - g_set_error (error, NM_SETTING_ERROR, - NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, - "%s", key); - return FALSE; - } - - str = g_value_dup_string (value); - if (!str || !strlen (str)) { + if (!value || !strlen (value)) { g_set_error (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, "Secret %s was empty", key); - g_free (str); return FALSE; } - g_hash_table_insert (priv->secrets, g_strdup (key), str); + g_hash_table_insert (priv->secrets, g_strdup (key), g_strdup (value)); return TRUE; } +static gboolean +update_secret_hash (NMSetting *setting, + GHashTable *secrets, + GError **error) +{ + NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting); + GHashTableIter iter; + const char *name, *value; + + g_return_val_if_fail (secrets != NULL, FALSE); + + /* Make sure the items are valid */ + g_hash_table_iter_init (&iter, secrets); + while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &value)) { + if (!name || !strlen (name)) { + g_set_error_literal (error, NM_SETTING_ERROR, + NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, + "Secret name was empty"); + return FALSE; + } + + if (!value || !strlen (value)) { + g_set_error (error, NM_SETTING_ERROR, + NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, + "Secret %s value was empty", name); + return FALSE; + } + } + + /* Now add the items to the settings' secrets list */ + g_hash_table_iter_init (&iter, secrets); + while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &value)) { + if (value == NULL) { + g_warn_if_fail (value != NULL); + continue; + } + if (strlen (value) == 0) { + g_warn_if_fail (strlen (value) > 0); + continue; + } + + g_hash_table_insert (priv->secrets, g_strdup (name), g_strdup (value)); + } + + return TRUE; +} + +static gboolean +update_one_secret (NMSetting *setting, const char *key, GValue *value, GError **error) +{ + gboolean success = FALSE; + + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + if (G_VALUE_HOLDS_STRING (value)) { + /* Passing the string properties individually isn't correct, and won't + * produce the correct result, but for some reason that's how it used + * to be done. So even though it's not correct, keep the code around + * for compatibility's sake. + */ + success = update_secret_string (setting, key, g_value_get_string (value), error); + } else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) { + if (strcmp (key, NM_SETTING_VPN_SECRETS) != 0) { + g_set_error (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_NOT_SECRET, + "Property %s not a secret property", key); + } else + success = update_secret_hash (setting, g_value_get_boxed (value), error); + } else + g_set_error_literal (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, key); + + return success; +} + +static gboolean +get_secret_flags (NMSetting *setting, + const char *secret_name, + gboolean verify_secret, + NMSettingSecretFlags *out_flags, + GError **error) +{ + NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting); + gboolean success = FALSE; + char *flags_key; + gpointer val; + unsigned long tmp; + + flags_key = g_strdup_printf ("%s-flags", secret_name); + if (g_hash_table_lookup_extended (priv->data, flags_key, NULL, &val)) { + errno = 0; + tmp = strtoul ((const char *) val, NULL, 10); + if ((errno == 0) && (tmp <= NM_SETTING_SECRET_FLAGS_ALL)) { + *out_flags = (guint32) tmp; + success = TRUE; + } else { + g_set_error (error, + NM_SETTING_ERROR, + NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, + "Failed to convert '%s' value '%s' to uint", + flags_key, (const char *) val); + } + } else { + g_set_error (error, + NM_SETTING_ERROR, + NM_SETTING_ERROR_PROPERTY_NOT_FOUND, + "Secret flags property '%s' not found", flags_key); + } + g_free (flags_key); + return success; +} + +static gboolean +set_secret_flags (NMSetting *setting, + const char *secret_name, + gboolean verify_secret, + NMSettingSecretFlags flags, + GError **error) +{ + g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->data, + g_strdup_printf ("%s-flags", secret_name), + g_strdup_printf ("%u", flags)); + return TRUE; +} + +static GPtrArray * +need_secrets (NMSetting *setting) +{ + /* Assume that VPN connections need secrets since they almost always will */ + return g_ptr_array_sized_new (1); +} + static void destroy_one_secret (gpointer data) { @@ -309,6 +452,8 @@ finalize (GObject *object) static void copy_hash (gpointer key, gpointer value, gpointer user_data) { + g_return_if_fail (value != NULL); + g_return_if_fail (strlen (value)); g_hash_table_insert ((GHashTable *) user_data, g_strdup (key), g_strdup (value)); } @@ -386,8 +531,12 @@ nm_setting_vpn_class_init (NMSettingVPNClass *setting_class) object_class->set_property = set_property; object_class->get_property = get_property; object_class->finalize = finalize; - parent_class->verify = verify; + + parent_class->verify = verify; parent_class->update_one_secret = update_one_secret; + parent_class->get_secret_flags = get_secret_flags; + parent_class->set_secret_flags = set_secret_flags; + parent_class->need_secrets = need_secrets; /* Properties */ /** @@ -395,7 +544,7 @@ nm_setting_vpn_class_init (NMSettingVPNClass *setting_class) * * D-Bus service name of the VPN plugin that this setting uses to connect * to its network. i.e. org.freedesktop.NetworkManager.vpnc for the vpnc - * plugin. + * plugin. **/ g_object_class_install_property (object_class, PROP_SERVICE_TYPE, diff --git a/libnm-util/nm-setting-vpn.h b/libnm-util/nm-setting-vpn.h index 9c684bbf11..bb203560f9 100644 --- a/libnm-util/nm-setting-vpn.h +++ b/libnm-util/nm-setting-vpn.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -71,7 +71,9 @@ typedef struct { void (*_reserved4) (void); } NMSettingVPNClass; -typedef void (*VPNIterFunc) (const char *key, const char *value, gpointer user_data); +typedef void (*NMVPNIterFunc) (const char *key, const char *value, gpointer user_data); +/* For backward compatibility */ +typedef NMVPNIterFunc VPNIterFunc; GType nm_setting_vpn_get_type (void); @@ -87,7 +89,7 @@ const char * nm_setting_vpn_get_data_item (NMSettingVPN *setting, void nm_setting_vpn_remove_data_item (NMSettingVPN *setting, const char *key); void nm_setting_vpn_foreach_data_item (NMSettingVPN *setting, - VPNIterFunc func, + NMVPNIterFunc func, gpointer user_data); void nm_setting_vpn_add_secret (NMSettingVPN *setting, @@ -98,7 +100,7 @@ const char * nm_setting_vpn_get_secret (NMSettingVPN *setting, void nm_setting_vpn_remove_secret (NMSettingVPN *setting, const char *key); void nm_setting_vpn_foreach_secret (NMSettingVPN *setting, - VPNIterFunc func, + NMVPNIterFunc func, gpointer user_data); G_END_DECLS diff --git a/libnm-util/nm-setting-wimax.c b/libnm-util/nm-setting-wimax.c index 349a3ae8ea..c37af8cdc9 100644 --- a/libnm-util/nm-setting-wimax.c +++ b/libnm-util/nm-setting-wimax.c @@ -16,11 +16,14 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * + * (C) Copyright 2011 Red Hat, Inc. * (C) Copyright 2009 Novell, Inc. */ +#include #include #include + #include "nm-setting-wimax.h" #include "nm-param-spec-specialized.h" @@ -111,6 +114,15 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } + if (!strlen (priv->network_name)) { + g_set_error (error, + NM_SETTING_WIMAX_ERROR, + NM_SETTING_WIMAX_ERROR_INVALID_PROPERTY, + NM_SETTING_WIMAX_NETWORK_NAME); + + return FALSE; + } + if (priv->mac_address && priv->mac_address->len != ETH_ALEN) { g_set_error (error, NM_SETTING_WIMAX_ERROR, diff --git a/libnm-util/nm-setting-wireless-security.c b/libnm-util/nm-setting-wireless-security.c index ca789b422b..3b4eba6f7a 100644 --- a/libnm-util/nm-setting-wireless-security.c +++ b/libnm-util/nm-setting-wireless-security.c @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2010 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -33,6 +33,7 @@ #include "nm-utils.h" #include "nm-dbus-glib-types.h" #include "nm-utils-private.h" +#include "nm-setting-private.h" GQuark nm_setting_wireless_security_error_quark (void) @@ -82,19 +83,28 @@ G_DEFINE_TYPE (NMSettingWirelessSecurity, nm_setting_wireless_security, NM_TYPE_ typedef struct { char *key_mgmt; - guint32 wep_tx_keyidx; char *auth_alg; GSList *proto; /* GSList of strings */ GSList *pairwise; /* GSList of strings */ GSList *group; /* GSList of strings */ + + /* LEAP */ char *leap_username; + char *leap_password; + NMSettingSecretFlags leap_password_flags; + + /* WEP */ char *wep_key0; char *wep_key1; char *wep_key2; char *wep_key3; - char *psk; - char *leap_password; + NMSettingSecretFlags wep_key_flags; NMWepKeyType wep_key_type; + guint32 wep_tx_keyidx; + + /* WPA-PSK */ + char *psk; + NMSettingSecretFlags psk_flags; } NMSettingWirelessSecurityPrivate; enum { @@ -110,9 +120,12 @@ enum { PROP_WEP_KEY1, PROP_WEP_KEY2, PROP_WEP_KEY3, - PROP_PSK, - PROP_LEAP_PASSWORD, + PROP_WEP_KEY_FLAGS, PROP_WEP_KEY_TYPE, + PROP_PSK, + PROP_PSK_FLAGS, + PROP_LEAP_PASSWORD, + PROP_LEAP_PASSWORD_FLAGS, LAST_PROP }; @@ -343,6 +356,21 @@ nm_setting_wireless_security_get_psk (NMSettingWirelessSecurity *setting) return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->psk; } +/** + * nm_setting_wireless_security_get_psk_flags: + * @setting: the #NMSettingWirelessSecurity + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSettingWirelessSecurity:psk + **/ +NMSettingSecretFlags +nm_setting_wireless_security_get_psk_flags (NMSettingWirelessSecurity *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->psk_flags; +} + const char * nm_setting_wireless_security_get_leap_username (NMSettingWirelessSecurity *setting) { @@ -359,6 +387,21 @@ nm_setting_wireless_security_get_leap_password (NMSettingWirelessSecurity *setti return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->leap_password; } +/** + * nm_setting_wireless_security_get_leap_password_flags: + * @setting: the #NMSettingWirelessSecurity + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSettingWirelessSecurity:leap-password + **/ +NMSettingSecretFlags +nm_setting_wireless_security_get_leap_password_flags (NMSettingWirelessSecurity *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->leap_password_flags; +} + const char * nm_setting_wireless_security_get_wep_key (NMSettingWirelessSecurity *setting, guint32 idx) { @@ -428,6 +471,20 @@ nm_setting_wireless_security_get_auth_alg (NMSettingWirelessSecurity *setting) return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->auth_alg; } +/** + * nm_setting_wireless_security_get_wep_key_flags: + * @setting: the #NMSettingWirelessSecurity + * + * Returns: the #NMSettingSecretFlags pertaining to the all WEP keys + **/ +NMSettingSecretFlags +nm_setting_wireless_security_get_wep_key_flags (NMSettingWirelessSecurity *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->wep_key_flags; +} + NMWepKeyType nm_setting_wireless_security_get_wep_key_type (NMSettingWirelessSecurity *setting) { @@ -771,6 +828,58 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return TRUE; } +static gboolean +get_secret_flags (NMSetting *setting, + const char *secret_name, + gboolean verify_secret, + NMSettingSecretFlags *out_flags, + GError **error) +{ + NMSettingClass *setting_class; + gboolean verify_override = verify_secret; + + /* There's only one 'flags' property for WEP keys, so alias all the WEP key + * property names to that flags property. + */ + if ( !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0) + || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1) + || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2) + || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) { + secret_name = "wep-key"; + verify_override = FALSE; /* Already know it's a secret */ + } + + /* Chain up to superclass with modified key name */ + setting_class = NM_SETTING_CLASS (nm_setting_wireless_security_parent_class); + return setting_class->get_secret_flags (setting, secret_name, verify_override, out_flags, error); +} + +static gboolean +set_secret_flags (NMSetting *setting, + const char *secret_name, + gboolean verify_secret, + NMSettingSecretFlags flags, + GError **error) +{ + NMSettingClass *setting_class; + gboolean verify_override = verify_secret; + + /* There's only one 'flags' property for WEP keys, so alias all the WEP key + * property names to that flags property. + */ + if ( !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0) + || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1) + || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2) + || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) { + secret_name = "wep-key"; + verify_override = FALSE; /* Already know it's a secret */ + } + + /* Chain up to superclass with modified key name */ + setting_class = NM_SETTING_CLASS (nm_setting_wireless_security_parent_class); + return setting_class->set_secret_flags (setting, secret_name, verify_override, flags, error); +} + static void nm_setting_wireless_security_init (NMSettingWirelessSecurity *setting) { @@ -852,14 +961,23 @@ set_property (GObject *object, guint prop_id, case PROP_WEP_KEY3: nm_setting_wireless_security_set_wep_key (setting, 3, g_value_get_string (value)); break; + case PROP_WEP_KEY_FLAGS: + priv->wep_key_flags = g_value_get_uint (value); + break; case PROP_PSK: g_free (priv->psk); priv->psk = g_value_dup_string (value); break; + case PROP_PSK_FLAGS: + priv->psk_flags = g_value_get_uint (value); + break; case PROP_LEAP_PASSWORD: g_free (priv->leap_password); priv->leap_password = g_value_dup_string (value); break; + case PROP_LEAP_PASSWORD_FLAGS: + priv->leap_password_flags = g_value_get_uint (value); + break; case PROP_WEP_KEY_TYPE: priv->wep_key_type = g_value_get_uint (value); break; @@ -910,12 +1028,21 @@ get_property (GObject *object, guint prop_id, case PROP_WEP_KEY3: g_value_set_string (value, priv->wep_key3); break; + case PROP_WEP_KEY_FLAGS: + g_value_set_uint (value, priv->wep_key_flags); + break; case PROP_PSK: g_value_set_string (value, priv->psk); break; + case PROP_PSK_FLAGS: + g_value_set_uint (value, priv->psk_flags); + break; case PROP_LEAP_PASSWORD: g_value_set_string (value, priv->leap_password); break; + case PROP_LEAP_PASSWORD_FLAGS: + g_value_set_uint (value, priv->leap_password_flags); + break; case PROP_WEP_KEY_TYPE: g_value_set_uint (value, priv->wep_key_type); break; @@ -938,8 +1065,10 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *setting object_class->get_property = get_property; object_class->finalize = finalize; - parent_class->verify = verify; - parent_class->need_secrets = need_secrets; + parent_class->verify = verify; + parent_class->need_secrets = need_secrets; + parent_class->get_secret_flags = get_secret_flags; + parent_class->set_secret_flags = set_secret_flags; /* Properties */ /** @@ -1139,6 +1268,20 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *setting NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + /** + * NMSettingWirelessSecurity:wep-key-flags: + * + * Flags indicating how to handle #NMSettingWirelessSecurity WEP keys. + **/ + g_object_class_install_property (object_class, PROP_WEP_KEY_FLAGS, + g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, + "WEP Key Flags", + "Flags indicating how to handle the WEP keys.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSettingWirelessSecurity:psk: * @@ -1164,6 +1307,20 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *setting NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + /** + * NMSettingWirelessSecurity:psk-flags: + * + * Flags indicating how to handle #NMSettingWirelessSecurity:psk + **/ + g_object_class_install_property (object_class, PROP_PSK_FLAGS, + g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, + "PSK Flags", + "Flags indicating how to handle the WPA PSK key.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSettingWirelessSecurity:leap-password: * @@ -1179,6 +1336,20 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *setting NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + /** + * NMSettingWirelessSecurity:leap-password-flags: + * + * Flags indicating how to handle #NMSettingWirelessSecurity:leap-password. + **/ + g_object_class_install_property (object_class, PROP_LEAP_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, + "LEAP Password Flags", + "Flags indicating how to handle the LEAP password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSettingWirelessSecurity:wep-key-type: * diff --git a/libnm-util/nm-setting-wireless-security.h b/libnm-util/nm-setting-wireless-security.h index 90d971b235..743e161f02 100644 --- a/libnm-util/nm-setting-wireless-security.h +++ b/libnm-util/nm-setting-wireless-security.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -75,9 +75,12 @@ typedef enum { #define NM_SETTING_WIRELESS_SECURITY_WEP_KEY1 "wep-key1" #define NM_SETTING_WIRELESS_SECURITY_WEP_KEY2 "wep-key2" #define NM_SETTING_WIRELESS_SECURITY_WEP_KEY3 "wep-key3" -#define NM_SETTING_WIRELESS_SECURITY_PSK "psk" -#define NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD "leap-password" +#define NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS "wep-key-flags" #define NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE "wep-key-type" +#define NM_SETTING_WIRELESS_SECURITY_PSK "psk" +#define NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS "psk-flags" +#define NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD "leap-password" +#define NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS "leap-password-flags" typedef struct { NMSetting parent; @@ -118,14 +121,18 @@ void nm_setting_wireless_security_remove_group (NMSettingWirelessSec void nm_setting_wireless_security_clear_groups (NMSettingWirelessSecurity *setting); const char *nm_setting_wireless_security_get_psk (NMSettingWirelessSecurity *setting); +NMSettingSecretFlags nm_setting_wireless_security_get_psk_flags (NMSettingWirelessSecurity *setting); const char *nm_setting_wireless_security_get_leap_username (NMSettingWirelessSecurity *setting); const char *nm_setting_wireless_security_get_leap_password (NMSettingWirelessSecurity *setting); +NMSettingSecretFlags nm_setting_wireless_security_get_leap_password_flags (NMSettingWirelessSecurity *setting); const char *nm_setting_wireless_security_get_wep_key (NMSettingWirelessSecurity *setting, guint32 idx); void nm_setting_wireless_security_set_wep_key (NMSettingWirelessSecurity *setting, guint32 idx, const char *key); guint32 nm_setting_wireless_security_get_wep_tx_keyidx (NMSettingWirelessSecurity *setting); const char *nm_setting_wireless_security_get_auth_alg (NMSettingWirelessSecurity *setting); + +NMSettingSecretFlags nm_setting_wireless_security_get_wep_key_flags (NMSettingWirelessSecurity *setting); NMWepKeyType nm_setting_wireless_security_get_wep_key_type (NMSettingWirelessSecurity *setting); G_END_DECLS diff --git a/libnm-util/nm-setting-wireless.c b/libnm-util/nm-setting-wireless.c index ec7d53ad77..f645e9d8aa 100644 --- a/libnm-util/nm-setting-wireless.c +++ b/libnm-util/nm-setting-wireless.c @@ -446,7 +446,7 @@ static gboolean verify (NMSetting *setting, GSList *all_settings, GError **error) { NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting); - const char *valid_modes[] = { "infrastructure", "adhoc", NULL }; + const char *valid_modes[] = { NM_SETTING_WIRELESS_MODE_INFRA, NM_SETTING_WIRELESS_MODE_ADHOC, NULL }; const char *valid_bands[] = { "a", "bg", NULL }; GSList *iter; diff --git a/libnm-util/nm-setting-wireless.h b/libnm-util/nm-setting-wireless.h index 2216a246af..728a05e2ca 100644 --- a/libnm-util/nm-setting-wireless.h +++ b/libnm-util/nm-setting-wireless.h @@ -68,6 +68,9 @@ GQuark nm_setting_wireless_error_quark (void); #define NM_SETTING_WIRELESS_SEEN_BSSIDS "seen-bssids" #define NM_SETTING_WIRELESS_SEC "security" +#define NM_SETTING_WIRELESS_MODE_ADHOC "adhoc" +#define NM_SETTING_WIRELESS_MODE_INFRA "infrastructure" + typedef struct { NMSetting parent; } NMSettingWireless; diff --git a/libnm-util/nm-setting.c b/libnm-util/nm-setting.c index 190199c121..b5a8b71f64 100644 --- a/libnm-util/nm-setting.c +++ b/libnm-util/nm-setting.c @@ -19,13 +19,14 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ #include #include "nm-setting.h" +#include "nm-setting-private.h" #include "nm-setting-connection.h" #include "nm-utils.h" @@ -107,21 +108,23 @@ destroy_gvalue (gpointer data) /** * nm_setting_to_hash: * @setting: the #NMSetting + * @flags: hash flags, e.g. %NM_SETTING_HASH_FLAG_ALL * * Converts the #NMSetting into a #GHashTable mapping each setting property * name to a GValue describing that property, suitable for marshalling over * D-Bus or serializing. The mapping is string:GValue. * - * Returns: a new #GHashTable describing the setting's properties + * Returns: (transfer full) (element-type utf8 GObject.Value): a new #GHashTable describing the setting's properties **/ GHashTable * -nm_setting_to_hash (NMSetting *setting) +nm_setting_to_hash (NMSetting *setting, NMSettingHashFlags flags) { GHashTable *hash; GParamSpec **property_specs; guint n_property_specs; guint i; + g_return_val_if_fail (setting != NULL, NULL); g_return_val_if_fail (NM_IS_SETTING (setting), NULL); property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs); @@ -132,29 +135,41 @@ nm_setting_to_hash (NMSetting *setting) } hash = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - destroy_gvalue); + (GDestroyNotify) g_free, destroy_gvalue); for (i = 0; i < n_property_specs; i++) { GParamSpec *prop_spec = property_specs[i]; + GValue *value; - if (prop_spec->flags & NM_SETTING_PARAM_SERIALIZE) { - GValue *value; + if (!(prop_spec->flags & NM_SETTING_PARAM_SERIALIZE)) + continue; - value = g_slice_new0 (GValue); - g_value_init (value, prop_spec->value_type); - g_object_get_property (G_OBJECT (setting), prop_spec->name, value); + if ( (flags & NM_SETTING_HASH_FLAG_NO_SECRETS) + && (prop_spec->flags & NM_SETTING_PARAM_SECRET)) + continue; - /* Don't serialize values with default values */ - if (!g_param_value_defaults (prop_spec, value)) - g_hash_table_insert (hash, g_strdup (prop_spec->name), value); - else - destroy_gvalue (value); - } + if ( (flags & NM_SETTING_HASH_FLAG_ONLY_SECRETS) + && !(prop_spec->flags & NM_SETTING_PARAM_SECRET)) + continue; + + value = g_slice_new0 (GValue); + g_value_init (value, prop_spec->value_type); + g_object_get_property (G_OBJECT (setting), prop_spec->name, value); + + /* Don't serialize values with default values */ + if (!g_param_value_defaults (prop_spec, value)) + g_hash_table_insert (hash, g_strdup (prop_spec->name), value); + else + destroy_gvalue (value); } - g_free (property_specs); + /* Don't return empty hashes */ + if (g_hash_table_size (hash) < 1) { + g_hash_table_destroy (hash); + hash = NULL; + } + return hash; } @@ -254,7 +269,7 @@ duplicate_setting (NMSetting *setting, * * Duplicates a #NMSetting. * - * Returns: a new #NMSetting containing the same properties and values as the + * Returns: (transfer full): a new #NMSetting containing the same properties and values as the * source #NMSetting **/ NMSetting * @@ -390,7 +405,7 @@ nm_setting_compare (NMSetting *a, /** * nm_setting_enumerate_values: * @setting: the #NMSetting - * @func: user-supplied function called for each property of the setting + * @func: (scope call): user-supplied function called for each property of the setting * @user_data: user data passed to @func at each invocation * * Iterates over each property of the #NMSetting object, calling the supplied @@ -465,7 +480,7 @@ nm_setting_clear_secrets (NMSetting *setting) * guide to what secrets may be required, because in some circumstances, there * is no way to conclusively determine exactly which secrets are needed. * - * Returns: a #GPtrArray containing the property names of secrets of the + * Returns: (transfer full) (element-type utf8): a #GPtrArray containing the property names of secrets of the * #NMSetting which may be required; the caller owns the array * and must free the each array element with g_free(), as well as the array * itself with g_ptr_array_free() @@ -483,11 +498,6 @@ nm_setting_need_secrets (NMSetting *setting) return secrets; } -typedef struct { - NMSetting *setting; - GError **error; -} UpdateSecretsInfo; - static gboolean update_one_secret (NMSetting *setting, const char *key, GValue *value, GError **error) { @@ -504,13 +514,9 @@ update_one_secret (NMSetting *setting, const char *key, GValue *value, GError ** return FALSE; } - if (!(prop_spec->flags & NM_SETTING_PARAM_SECRET)) { - g_set_error (error, - NM_SETTING_ERROR, - NM_SETTING_ERROR_PROPERTY_NOT_SECRET, - "%s", key); - return FALSE; - } + /* Silently ignore non-secrets */ + if (!(prop_spec->flags & NM_SETTING_PARAM_SECRET)) + return TRUE; if (g_value_type_compatible (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (prop_spec))) { g_object_set_property (G_OBJECT (setting), prop_spec->name, value); @@ -528,17 +534,6 @@ update_one_secret (NMSetting *setting, const char *key, GValue *value, GError ** return success; } -static void -update_one_cb (gpointer key, gpointer val, gpointer user_data) -{ - UpdateSecretsInfo *info = user_data; - const char *secret_key = (const char *) key; - GValue *secret_value = (GValue *) val; - - if (*(info->error) == NULL) - NM_SETTING_GET_CLASS (info->setting)->update_one_secret (info->setting, secret_key, secret_value, info->error); -} - /** * nm_setting_update_secrets: * @setting: the #NMSetting @@ -555,8 +550,9 @@ update_one_cb (gpointer key, gpointer val, gpointer user_data) gboolean nm_setting_update_secrets (NMSetting *setting, GHashTable *secrets, GError **error) { - UpdateSecretsInfo *info; - gboolean success; + GHashTableIter iter; + gpointer key, data; + GError *tmp_error = NULL; g_return_val_if_fail (setting != NULL, FALSE); g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); @@ -564,14 +560,137 @@ nm_setting_update_secrets (NMSetting *setting, GHashTable *secrets, GError **err if (error) g_return_val_if_fail (*error == NULL, FALSE); - info = g_malloc0 (sizeof (UpdateSecretsInfo)); - info->setting = setting; - info->error = error; - g_hash_table_foreach (secrets, update_one_cb, info); - success = *(info->error) ? FALSE : TRUE; - g_free (info); + g_hash_table_iter_init (&iter, secrets); + while (g_hash_table_iter_next (&iter, &key, &data)) { + const char *secret_key = (const char *) key; + GValue *secret_value = (GValue *) data; - return success; + NM_SETTING_GET_CLASS (setting)->update_one_secret (setting, secret_key, secret_value, &tmp_error); + if (tmp_error) { + g_propagate_error (error, tmp_error); + break; + } + } + + return tmp_error ? FALSE : TRUE; +} + +static gboolean +is_secret_prop (NMSetting *setting, const char *secret_name, GError **error) +{ + GParamSpec *pspec; + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), secret_name); + if (!pspec) { + g_set_error (error, + NM_SETTING_ERROR, + NM_SETTING_ERROR_PROPERTY_NOT_FOUND, + "Secret %s not provided by this setting", secret_name); + return FALSE; + } + + if (!(pspec->flags & NM_SETTING_PARAM_SECRET)) { + g_set_error (error, + NM_SETTING_ERROR, + NM_SETTING_ERROR_PROPERTY_NOT_SECRET, + "Property %s is not a secret", secret_name); + return FALSE; + } + + return TRUE; +} + +static gboolean +get_secret_flags (NMSetting *setting, + const char *secret_name, + gboolean verify_secret, + NMSettingSecretFlags *out_flags, + GError **error) +{ + char *flags_prop; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + + if (verify_secret) + g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE); + + flags_prop = g_strdup_printf ("%s-flags", secret_name); + g_object_get (G_OBJECT (setting), flags_prop, &flags, NULL); + g_free (flags_prop); + + if (out_flags) + *out_flags = flags; + return TRUE; +} + +/** + * nm_setting_get_secret_flags: + * @setting: the #NMSetting + * @secret_name: the secret key name to get flags for + * @out_flags: on success, the #NMSettingSecretFlags for the secret + * @error: location to store error, or %NULL + * + * For a given secret, retrieves the #NMSettingSecretFlags describing how to + * handle that secret. + * + * Returns: TRUE on success (if the given secret name was a valid property of + * this setting, and if that property is secret), FALSE if not + **/ +gboolean +nm_setting_get_secret_flags (NMSetting *setting, + const char *secret_name, + NMSettingSecretFlags *out_flags, + GError **error) +{ + g_return_val_if_fail (setting != NULL, FALSE); + g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); + g_return_val_if_fail (secret_name != NULL, FALSE); + + return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, TRUE, out_flags, error); +} + +static gboolean +set_secret_flags (NMSetting *setting, + const char *secret_name, + gboolean verify_secret, + NMSettingSecretFlags flags, + GError **error) +{ + char *flags_prop; + + if (verify_secret) + g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE); + + flags_prop = g_strdup_printf ("%s-flags", secret_name); + g_object_set (G_OBJECT (setting), flags_prop, flags, NULL); + g_free (flags_prop); + return TRUE; +} + +/** + * nm_setting_set_secret_flags: + * @setting: the #NMSetting + * @secret_name: the secret key name to set flags for + * @flags: the #NMSettingSecretFlags for the secret + * @error: location to store error, or %NULL + * + * For a given secret, retrieves the #NMSettingSecretFlags describing how to + * handle that secret. + * + * Returns: TRUE on success (if the given secret name was a valid property of + * this setting, and if that property is secret), FALSE if not + **/ +gboolean +nm_setting_set_secret_flags (NMSetting *setting, + const char *secret_name, + NMSettingSecretFlags flags, + GError **error) +{ + g_return_val_if_fail (setting != NULL, FALSE); + g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); + g_return_val_if_fail (secret_name != NULL, FALSE); + g_return_val_if_fail (flags <= NM_SETTING_SECRET_FLAGS_ALL, FALSE); + + return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, TRUE, flags, error); } /** @@ -730,6 +849,8 @@ nm_setting_class_init (NMSettingClass *setting_class) object_class->finalize = finalize; setting_class->update_one_secret = update_one_secret; + setting_class->get_secret_flags = get_secret_flags; + setting_class->set_secret_flags = set_secret_flags; /* Properties */ diff --git a/libnm-util/nm-setting.h b/libnm-util/nm-setting.h index de5657eea4..067db14cbc 100644 --- a/libnm-util/nm-setting.h +++ b/libnm-util/nm-setting.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -83,6 +83,34 @@ GQuark nm_setting_error_quark (void); #define NM_SETTING_NAME "name" +/** + * NMSettingSecretFlags: + * @NM_SETTING_SECRET_FLAG_NONE: the system is responsible for providing and + * storing this secret (default) + * @NM_SETTING_SECRET_FLAG_AGENT_OWNED: a user secret agent is responsible + * for providing and storing this secret; when it is required agents will be + * asked to retrieve it + * @NM_SETTING_SECRET_FLAG_NOT_SAVED: this secret should not be saved, but + * should be requested from the user each time it is needed + * @NM_SETTING_SECRET_FLAG_NOT_REQUIRED: in situations where it cannot be + * automatically determined that the secret is required (some VPNs and PPP + * providers dont require all secrets) this flag indicates that the specific + * secret is not required + * + * These flags indicate specific behavior related to handling of a secret. Each + * secret has a corresponding set of these flags which indicate how the secret + * is to be stored and/or requested when it is needed. + * + **/ +typedef enum { + NM_SETTING_SECRET_FLAG_NONE = 0x00000000, + NM_SETTING_SECRET_FLAG_AGENT_OWNED = 0x00000001, + NM_SETTING_SECRET_FLAG_NOT_SAVED = 0x00000002, + NM_SETTING_SECRET_FLAG_NOT_REQUIRED = 0x00000004 + + /* NOTE: if adding flags, update nm-setting-private.h as well */ +} NMSettingSecretFlags; + /** * NMSetting: * @@ -108,6 +136,18 @@ typedef struct { GValue *value, GError **error); + gboolean (*get_secret_flags) (NMSetting *setting, + const char *secret_name, + gboolean verify_secret, + NMSettingSecretFlags *out_flags, + GError **error); + + gboolean (*set_secret_flags) (NMSetting *setting, + const char *secret_name, + gboolean verify_secret, + NMSettingSecretFlags flags, + GError **error); + /* Padding for future expansion */ void (*_reserved1) (void); void (*_reserved2) (void); @@ -124,7 +164,25 @@ typedef void (*NMSettingValueIterFn) (NMSetting *setting, GType nm_setting_get_type (void); -GHashTable *nm_setting_to_hash (NMSetting *setting); +/** + * NMSettingHashFlags: + * @NM_SETTING_HASH_FLAG_ALL: hash all properties (including secrets) + * @NM_SETTING_HASH_FLAG_NO_SECRETS: do not include secrets + * @NM_SETTING_HASH_FLAG_ONLY_SECRETS: only hash secrets + * + * These flags determine which properties are added to the resulting hash + * when calling nm_setting_to_hash(). + * + **/ +typedef enum { + NM_SETTING_HASH_FLAG_ALL = 0x00000000, + NM_SETTING_HASH_FLAG_NO_SECRETS = 0x00000001, + NM_SETTING_HASH_FLAG_ONLY_SECRETS = 0x00000002, +} NMSettingHashFlags; + +GHashTable *nm_setting_to_hash (NMSetting *setting, + NMSettingHashFlags flags); + NMSetting *nm_setting_new_from_hash (GType setting_type, GHashTable *hash); @@ -173,6 +231,16 @@ gboolean nm_setting_update_secrets (NMSetting *setting, GHashTable *secrets, GError **error); +gboolean nm_setting_get_secret_flags (NMSetting *setting, + const char *secret_name, + NMSettingSecretFlags *out_flags, + GError **error); + +gboolean nm_setting_set_secret_flags (NMSetting *setting, + const char *secret_name, + NMSettingSecretFlags flags, + GError **error); + G_END_DECLS #endif /* NM_SETTING_H */ diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c index 9c3662f47f..87c5d5f6e2 100644 --- a/libnm-util/nm-utils.c +++ b/libnm-util/nm-utils.c @@ -487,7 +487,7 @@ value_dup (gpointer key, gpointer val, gpointer user_data) * * Utility function to duplicate a hash table of GValues. * - * Returns: a newly allocated duplicated #GHashTable, caller must free the + * Returns: (transfer container) (element-type utf8 GObject.Value): a newly allocated duplicated #GHashTable, caller must free the * returned hash with g_hash_table_unref() or g_hash_table_destroy() **/ GHashTable * @@ -1359,7 +1359,7 @@ nm_utils_security_valid (NMUtilsSecurityType type, * this serialization is not guaranteed to be stable and the #GArray may be * extended in the future. * - * Returns: a newly allocated #GSList of #NMIP4Address objects + * Returns: (transfer full) (element-type NetworkManager.IP4Address): a newly allocated #GSList of #NMIP4Address objects **/ GSList * nm_utils_ip4_addresses_from_gvalue (const GValue *value) @@ -1441,7 +1441,7 @@ nm_utils_ip4_addresses_to_gvalue (GSList *list, GValue *value) * format of this serialization is not guaranteed to be stable and may be * extended in the future. * - * Returns: a newly allocated #GSList of #NMIP4Route objects + * Returns: (transfer full) (element-type NetworkManager.IP4Route): a newly allocated #GSList of #NMIP4Route objects **/ GSList * nm_utils_ip4_routes_from_gvalue (const GValue *value) @@ -1604,7 +1604,7 @@ nm_utils_ip4_get_default_prefix (guint32 ip) * this serialization is not guaranteed to be stable and the #GValueArray may be * extended in the future. * - * Returns: a newly allocated #GSList of #NMIP6Address objects + * Returns: (transfer full) (element-type NetworkManager.IP6Address): a newly allocated #GSList of #NMIP6Address objects **/ GSList * nm_utils_ip6_addresses_from_gvalue (const GValue *value) @@ -1747,7 +1747,7 @@ nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value) * into a GSList of #NMIP6Route objects. The specific format of this serialization * is not guaranteed to be stable and may be extended in the future. * - * Returns: a newly allocated #GSList of #NMIP6Route objects + * Returns: (transfer full) (element-type NetworkManager.IP6Route): a newly allocated #GSList of #NMIP6Route objects **/ GSList * nm_utils_ip6_routes_from_gvalue (const GValue *value) @@ -1863,6 +1863,18 @@ nm_utils_ip6_routes_to_gvalue (GSList *list, GValue *value) g_value_take_boxed (value, routes); } +/* FIXME: the Posix namespace does not exist, and thus neither does + the in6_addr struct. Marking (skip) for now */ +/** + * nm_utils_ip6_dns_from_gvalue: (skip): + * @value: a #GValue + * + * Converts a #GValue containing a #GPtrArray of IP6 DNS, represented as + * #GByteArrays into a #GSList of #in6_addrs. + * + * Returns: (transfer full) (element-type Posix.in6_addr): a #GSList of IP6 + * addresses. + */ GSList * nm_utils_ip6_dns_from_gvalue (const GValue *value) { @@ -2046,8 +2058,8 @@ utils_bin2hexstr (const char *bytes, int len, int final_len) /** * nm_utils_rsa_key_encrypt: * @data: RSA private key data to be encrypted - * @in_password: existing password to use, if any - * @out_password: if @in_password was NULL, a random password will be generated + * @in_password: (allow-none): existing password to use, if any + * @out_password: (out) (allow-none): if @in_password was NULL, a random password will be generated * and returned in this argument * @error: detailed error information on return, if an error occurred * @@ -2055,7 +2067,7 @@ utils_bin2hexstr (const char *bytes, int len, int final_len) * a password if no password was given) and converts the data to PEM format * suitable for writing to a file. * - * Returns: on success, PEM-formatted data suitable for writing to a PEM-formatted + * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted * certificate/private key file. **/ GByteArray * diff --git a/libnm-util/tests/test-general.c b/libnm-util/tests/test-general.c index e91e2b5ce2..a2c7b2dcbf 100644 --- a/libnm-util/tests/test-general.c +++ b/libnm-util/tests/test-general.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 - 2010 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. * */ @@ -29,6 +29,7 @@ #include "nm-setting-connection.h" #include "nm-setting-vpn.h" #include "nm-setting-gsm.h" +#include "nm-setting-wireless-security.h" #include "nm-setting-ip6-config.h" #include "nm-dbus-glib-types.h" @@ -130,6 +131,65 @@ test_setting_vpn_items (void) g_object_unref (s_vpn); } +static void +test_setting_vpn_update_secrets (void) +{ + NMConnection *connection; + NMSettingVPN *s_vpn; + GHashTable *settings, *vpn, *secrets; + GValue val = { 0 }; + gboolean success; + GError *error = NULL; + const char *tmp; + const char *key1 = "foobar"; + const char *key2 = "blahblah"; + const char *val1 = "value1"; + const char *val2 = "value2"; + + connection = nm_connection_new (); + ASSERT (connection != NULL, + "vpn-update-secrets", + "error creating connection"); + + s_vpn = (NMSettingVPN *) nm_setting_vpn_new (); + ASSERT (s_vpn != NULL, + "vpn-update-secrets", + "error creating vpn setting"); + nm_connection_add_setting (connection, NM_SETTING (s_vpn)); + + settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_hash_table_destroy); + vpn = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_value_unset); + g_hash_table_insert (settings, NM_SETTING_VPN_SETTING_NAME, vpn); + + secrets = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + g_value_init (&val, DBUS_TYPE_G_MAP_OF_STRING); + g_value_take_boxed (&val, secrets); + g_hash_table_insert (vpn, NM_SETTING_VPN_SECRETS, &val); + + /* Add some secrets */ + g_hash_table_insert (secrets, (char *) key1, (char *) val1); + g_hash_table_insert (secrets, (char *) key2, (char *) val2); + + success = nm_connection_update_secrets (connection, NM_SETTING_VPN_SETTING_NAME, settings, &error); + ASSERT (success == TRUE, + "vpn-update-secrets", "failed to update VPN secrets: %s", error->message); + + /* Read the secrets back out */ + tmp = nm_setting_vpn_get_secret (s_vpn, key1); + ASSERT (tmp != NULL, + "vpn-update-secrets", "unexpected failure getting key #1"); + ASSERT (strcmp (tmp, val1) == 0, + "vpn-update-secrets", "unexpected key #1 value"); + + tmp = nm_setting_vpn_get_secret (s_vpn, key2); + ASSERT (tmp != NULL, + "vpn-update-secrets", "unexpected failure getting key #2"); + ASSERT (strcmp (tmp, val2) == 0, + "vpn-update-secrets", "unexpected key #2 value"); + + g_object_unref (connection); +} + #define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID)) #define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS)) @@ -289,6 +349,319 @@ test_setting_gsm_apn_bad_chars (void) "gsm-apn-bad-chars", "unexpectedly valid GSM setting"); } +static NMSettingWirelessSecurity * +make_test_wsec_setting (const char *detail) +{ + NMSettingWirelessSecurity *s_wsec; + + s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); + ASSERT (s_wsec != NULL, detail, "error creating setting"); + + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, "foobarbaz", + NM_SETTING_WIRELESS_SECURITY_PSK, "random psk", + NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, "aaaaaaaaaa", + NULL); + + return s_wsec; +} + +static void +test_setting_to_hash_all (void) +{ + NMSettingWirelessSecurity *s_wsec; + GHashTable *hash; + + s_wsec = make_test_wsec_setting ("setting-to-hash-all"); + + hash = nm_setting_to_hash (NM_SETTING (s_wsec), NM_SETTING_HASH_FLAG_ALL); + + /* Make sure all keys are there */ + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT), + "setting-to-hash-all", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME), + "setting-to-hash-all", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME); + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_PSK), + "setting-to-hash-all", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_PSK); + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0), + "setting-to-hash-all", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_WEP_KEY0); + + g_hash_table_destroy (hash); + g_object_unref (s_wsec); +} + +static void +test_setting_to_hash_no_secrets (void) +{ + NMSettingWirelessSecurity *s_wsec; + GHashTable *hash; + + s_wsec = make_test_wsec_setting ("setting-to-hash-no-secrets"); + + hash = nm_setting_to_hash (NM_SETTING (s_wsec), NM_SETTING_HASH_FLAG_NO_SECRETS); + + /* Make sure non-secret keys are there */ + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT), + "setting-to-hash-no-secrets", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME), + "setting-to-hash-no-secrets", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME); + + /* Make sure secrets are not there */ + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_PSK) == NULL, + "setting-to-hash-no-secrets", "unexpectedly present " NM_SETTING_WIRELESS_SECURITY_PSK); + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0) == NULL, + "setting-to-hash-no-secrets", "unexpectedly present " NM_SETTING_WIRELESS_SECURITY_WEP_KEY0); + + g_hash_table_destroy (hash); + g_object_unref (s_wsec); +} + +static void +test_setting_to_hash_only_secrets (void) +{ + NMSettingWirelessSecurity *s_wsec; + GHashTable *hash; + + s_wsec = make_test_wsec_setting ("setting-to-hash-only-secrets"); + + hash = nm_setting_to_hash (NM_SETTING (s_wsec), NM_SETTING_HASH_FLAG_ONLY_SECRETS); + + /* Make sure non-secret keys are there */ + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT) == NULL, + "setting-to-hash-only-secrets", "unexpectedly present " NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME) == NULL, + "setting-to-hash-only-secrets", "unexpectedly present " NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME); + + /* Make sure secrets are not there */ + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_PSK), + "setting-to-hash-only-secrets", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_PSK); + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0), + "setting-to-hash-only-secrets", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_WEP_KEY0); + + g_hash_table_destroy (hash); + g_object_unref (s_wsec); +} + +static void +test_connection_to_hash_setting_name (void) +{ + NMConnection *connection; + NMSettingWirelessSecurity *s_wsec; + GHashTable *hash; + + connection = nm_connection_new (); + s_wsec = make_test_wsec_setting ("connection-to-hash-setting-name"); + nm_connection_add_setting (connection, NM_SETTING (s_wsec)); + + hash = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL); + + /* Make sure the keys of the first level hash are setting names, not + * the GType name of the setting objects. + */ + ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) != NULL, + "connection-to-hash-setting-name", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); + + g_hash_table_destroy (hash); + g_object_unref (connection); +} + +static void +check_permission (NMSettingConnection *s_con, + guint32 idx, + const char *expected_uname, + const char *tag) +{ + gboolean success; + const char *ptype = NULL, *pitem = NULL, *detail = NULL; + + success = nm_setting_connection_get_permission (s_con, 0, &ptype, &pitem, &detail); + ASSERT (success == TRUE, tag, "unexpected failure getting added permission"); + + /* Permission type */ + ASSERT (ptype != NULL, tag, "unexpected failure getting permission type"); + ASSERT (strcmp (ptype, "user") == 0, tag, "retrieved unexpected permission type"); + + /* Permission item */ + ASSERT (pitem != NULL, tag, "unexpected failure getting permission item"); + ASSERT (strcmp (pitem, expected_uname) == 0, tag, "retrieved unexpected permission item"); + + ASSERT (detail == NULL, tag, "unexpected success getting permission detail"); +} + +#define TEST_UNAME "asdfasfasdf" + +static void +test_setting_connection_permissions_helpers (void) +{ + NMSettingConnection *s_con; + gboolean success; + char buf[9] = { 0x61, 0x62, 0x63, 0xff, 0xfe, 0xfd, 0x23, 0x01, 0x00 }; + GSList *list = NULL; + const char *expected_perm = "user:" TEST_UNAME ":"; + + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + + /* Ensure a bad [type] is rejected */ + success = nm_setting_connection_add_permission (s_con, "foobar", "blah", NULL); + ASSERT (success == FALSE, + "setting-connection-permissions-helpers", "unexpected success adding bad permission type #1"); + + /* Ensure a bad [type] is rejected */ + success = nm_setting_connection_add_permission (s_con, NULL, "blah", NULL); + ASSERT (success == FALSE, + "setting-connection-permissions-helpers", "unexpected success adding bad permission type #2"); + + /* Ensure a bad [item] is rejected */ + success = nm_setting_connection_add_permission (s_con, "user", NULL, NULL); + ASSERT (success == FALSE, + "setting-connection-permissions-helpers", "unexpected success adding bad permission item #1"); + + /* Ensure a bad [item] is rejected */ + success = nm_setting_connection_add_permission (s_con, "user", "", NULL); + ASSERT (success == FALSE, + "setting-connection-permissions-helpers", "unexpected success adding bad permission item #2"); + + /* Ensure an [item] with ':' is rejected */ + success = nm_setting_connection_add_permission (s_con, "user", "ad:asdf", NULL); + ASSERT (success == FALSE, + "setting-connection-permissions-helpers", "unexpected success adding bad permission item #3"); + + /* Ensure a non-UTF-8 [item] is rejected */ + success = nm_setting_connection_add_permission (s_con, "user", buf, NULL); + ASSERT (success == FALSE, + "setting-connection-permissions-helpers", "unexpected success adding bad permission item #4"); + + /* Ensure a non-NULL [detail] is rejected */ + success = nm_setting_connection_add_permission (s_con, "user", "dafasdf", "asdf"); + ASSERT (success == FALSE, + "setting-connection-permissions-helpers", "unexpected success adding bad detail"); + + /* Ensure a valid call results in success */ + success = nm_setting_connection_add_permission (s_con, "user", TEST_UNAME, NULL); + ASSERT (success == TRUE, + "setting-connection-permissions-helpers", "unexpected failure adding valid user permisson"); + + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 1, + "setting-connection-permissions-helpers", "unexpected failure getting number of permissions"); + + check_permission (s_con, 0, TEST_UNAME, "setting-connection-permissions-helpers"); + + /* Check the actual GObject property just to be paranoid */ + g_object_get (G_OBJECT (s_con), NM_SETTING_CONNECTION_PERMISSIONS, &list, NULL); + ASSERT (list != NULL, + "setting-connection-permissions-helpers", "unexpected failure getting permissions list"); + ASSERT (g_slist_length (list) == 1, + "setting-connection-permissions-helpers", "unexpected failure getting number of permissions in list"); + ASSERT (strcmp (list->data, expected_perm) == 0, + "setting-connection-permissions-helpers", "unexpected permission property data"); + + /* Now remove that permission and ensure we have 0 permissions */ + nm_setting_connection_remove_permission (s_con, 0); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-helpers", "unexpected failure removing permission"); + + g_object_unref (s_con); +} + +static void +add_permission_property (NMSettingConnection *s_con, + const char *ptype, + const char *pitem, + int pitem_len, + const char *detail) +{ + GString *str; + GSList *list = NULL; + + str = g_string_sized_new (50); + if (ptype) + g_string_append (str, ptype); + g_string_append_c (str, ':'); + + if (pitem) { + if (pitem_len >= 0) + g_string_append_len (str, pitem, pitem_len); + else + g_string_append (str, pitem); + } + + g_string_append_c (str, ':'); + + if (detail) + g_string_append (str, detail); + + list = g_slist_append (list, str->str); + g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_PERMISSIONS, list, NULL); + + g_string_free (str, TRUE); + g_slist_free (list); +} + +static void +test_setting_connection_permissions_property (void) +{ + NMSettingConnection *s_con; + gboolean success; + char buf[9] = { 0x61, 0x62, 0x63, 0xff, 0xfe, 0xfd, 0x23, 0x01, 0x00 }; + + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + + /* Ensure a bad [type] is rejected */ + add_permission_property (s_con, "foobar", "blah", -1, NULL); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected success adding bad permission type #1"); + + /* Ensure a bad [type] is rejected */ + add_permission_property (s_con, NULL, "blah", -1, NULL); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected success adding bad permission type #2"); + + /* Ensure a bad [item] is rejected */ + add_permission_property (s_con, "user", NULL, -1, NULL); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected success adding bad permission item #1"); + + /* Ensure a bad [item] is rejected */ + add_permission_property (s_con, "user", "", -1, NULL); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected success adding bad permission item #2"); + + /* Ensure an [item] with ':' in the middle is rejected */ + add_permission_property (s_con, "user", "ad:asdf", -1, NULL); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected success adding bad permission item #3"); + + /* Ensure an [item] with ':' at the end is rejected */ + add_permission_property (s_con, "user", "adasdfaf:", -1, NULL); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected success adding bad permission item #4"); + + /* Ensure a non-UTF-8 [item] is rejected */ + add_permission_property (s_con, "user", buf, (int) sizeof (buf), NULL); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected success adding bad permission item #5"); + + /* Ensure a non-NULL [detail] is rejected */ + add_permission_property (s_con, "user", "dafasdf", -1, "asdf"); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected success adding bad detail"); + + /* Ensure a valid call results in success */ + success = nm_setting_connection_add_permission (s_con, "user", TEST_UNAME, NULL); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 1, + "setting-connection-permissions-property", "unexpected failure adding valid user permisson"); + + check_permission (s_con, 0, TEST_UNAME, "setting-connection-permissions-property"); + + /* Now remove that permission and ensure we have 0 permissions */ + nm_setting_connection_remove_permission (s_con, 0); + ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0, + "setting-connection-permissions-property", "unexpected failure removing permission"); + + g_object_unref (s_con); +} + int main (int argc, char **argv) { GError *error = NULL; @@ -303,9 +676,16 @@ int main (int argc, char **argv) /* The tests */ test_setting_vpn_items (); + test_setting_vpn_update_secrets (); test_setting_ip6_config_old_address_array (); test_setting_gsm_apn_spaces (); test_setting_gsm_apn_bad_chars (); + test_setting_to_hash_all (); + test_setting_to_hash_no_secrets (); + test_setting_to_hash_only_secrets (); + test_connection_to_hash_setting_name (); + test_setting_connection_permissions_helpers (); + test_setting_connection_permissions_property (); base = g_path_get_basename (argv[0]); fprintf (stdout, "%s: SUCCESS\n", base); diff --git a/libnm-util/tests/test-need-secrets.c b/libnm-util/tests/test-need-secrets.c index 517e2e01d7..0c2634ea5b 100644 --- a/libnm-util/tests/test-need-secrets.c +++ b/libnm-util/tests/test-need-secrets.c @@ -154,7 +154,6 @@ test_need_tls_secrets_path (void) NMConnection *connection; const char *setting_name; GPtrArray *hints = NULL; - NMSetting8021x *s_8021x; connection = make_tls_connection ("need-tls-secrets-path-key", NM_SETTING_802_1X_CK_SCHEME_PATH); ASSERT (connection != NULL, @@ -170,41 +169,9 @@ test_need_tls_secrets_path (void) "need-tls-secrets-path-key", "hints should be NULL since no secrets were required"); - /* Connection is good; clear secrets and ensure private key is then required */ + /* Connection is good; clear secrets and ensure private key password is then required */ nm_connection_clear_secrets (connection); - hints = NULL; - setting_name = nm_connection_need_secrets (connection, &hints); - ASSERT (setting_name != NULL, - "need-tls-secrets-path-key", - "unexpected secrets success"); - ASSERT (strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) == 0, - "need-tls-secrets-path-key", - "unexpected setting secrets required"); - - ASSERT (hints != NULL, - "need-tls-secrets-path-key", - "expected returned secrets hints"); - ASSERT (find_hints_item (hints, NM_SETTING_802_1X_PRIVATE_KEY), - "need-tls-secrets-path-key", - "expected to require private key, but it wasn't"); - - g_object_unref (connection); - - /*** Just clear the private key this time ***/ - - connection = make_tls_connection ("need-tls-secrets-path-key-password", NM_SETTING_802_1X_CK_SCHEME_PATH); - ASSERT (connection != NULL, - "need-tls-secrets-path-key-password", - "error creating test connection"); - - s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); - ASSERT (s_8021x != NULL, - "need-tls-secrets-path-key-password", - "error getting test 802.1x setting"); - - g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, NULL, NULL); - hints = NULL; setting_name = nm_connection_need_secrets (connection, &hints); ASSERT (setting_name != NULL, @@ -230,7 +197,6 @@ test_need_tls_secrets_blob (void) NMConnection *connection; const char *setting_name; GPtrArray *hints = NULL; - NMSetting8021x *s_8021x; connection = make_tls_connection ("need-tls-secrets-blob-key", NM_SETTING_802_1X_CK_SCHEME_BLOB); ASSERT (connection != NULL, @@ -246,42 +212,11 @@ test_need_tls_secrets_blob (void) "need-tls-secrets-blob-key", "hints should be NULL since no secrets were required"); - /* Connection is good; clear secrets and ensure private key is then required */ + /* Connection is good; clear secrets and ensure private key password is not + * required because our blob is decrypted. + */ nm_connection_clear_secrets (connection); - hints = NULL; - setting_name = nm_connection_need_secrets (connection, &hints); - ASSERT (setting_name != NULL, - "need-tls-secrets-blob-key", - "unexpected secrets success"); - ASSERT (strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) == 0, - "need-tls-secrets-blob-key", - "unexpected setting secrets required"); - - ASSERT (hints != NULL, - "need-tls-secrets-blob-key", - "expected returned secrets hints"); - ASSERT (find_hints_item (hints, NM_SETTING_802_1X_PRIVATE_KEY), - "need-tls-secrets-blob-key", - "expected to require private key, but it wasn't"); - - g_object_unref (connection); - - /*** Just clear the private key this time ***/ - - connection = make_tls_connection ("need-tls-secrets-blob-key-password", NM_SETTING_802_1X_CK_SCHEME_BLOB); - ASSERT (connection != NULL, - "need-tls-secrets-blob-key-password", - "error creating test connection"); - - s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); - ASSERT (s_8021x != NULL, - "need-tls-secrets-blob-key-password", - "error getting test 802.1x setting"); - - g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, NULL, NULL); - - /* Blobs are already decrypted and don't need a password */ hints = NULL; setting_name = nm_connection_need_secrets (connection, &hints); ASSERT (setting_name == NULL, @@ -396,7 +331,6 @@ test_need_tls_phase2_secrets_path (void) NMConnection *connection; const char *setting_name; GPtrArray *hints = NULL; - NMSetting8021x *s_8021x; connection = make_tls_phase2_connection ("need-tls-phase2-secrets-path-key", NM_SETTING_802_1X_CK_SCHEME_PATH); @@ -413,42 +347,9 @@ test_need_tls_phase2_secrets_path (void) "need-tls-phase2-secrets-path-key", "hints should be NULL since no secrets were required"); - /* Connection is good; clear secrets and ensure private key is then required */ + /* Connection is good; clear secrets and ensure private key password is then required */ nm_connection_clear_secrets (connection); - hints = NULL; - setting_name = nm_connection_need_secrets (connection, &hints); - ASSERT (setting_name != NULL, - "need-tls-phase2-secrets-path-key", - "unexpected secrets success"); - ASSERT (strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) == 0, - "need-tls-phase2-secrets-path-key", - "unexpected setting secrets required"); - - ASSERT (hints != NULL, - "need-tls-phase2-secrets-path-key", - "expected returned secrets hints"); - ASSERT (find_hints_item (hints, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY), - "need-tls-phase2-secrets-path-key", - "expected to require private key, but it wasn't"); - - g_object_unref (connection); - - /*** Just clear the private key this time ***/ - - connection = make_tls_phase2_connection ("need-tls-phase2-secrets-path-key-password", - NM_SETTING_802_1X_CK_SCHEME_PATH); - ASSERT (connection != NULL, - "need-tls-phase2-secrets-path-key-password", - "error creating test connection"); - - s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); - ASSERT (s_8021x != NULL, - "need-tls-phase2-secrets-path-key-password", - "error getting test 802.1x setting"); - - g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, NULL, NULL); - hints = NULL; setting_name = nm_connection_need_secrets (connection, &hints); ASSERT (setting_name != NULL, @@ -474,7 +375,6 @@ test_need_tls_phase2_secrets_blob (void) NMConnection *connection; const char *setting_name; GPtrArray *hints = NULL; - NMSetting8021x *s_8021x; connection = make_tls_phase2_connection ("need-tls-phase2-secrets-blob-key", NM_SETTING_802_1X_CK_SCHEME_BLOB); @@ -491,43 +391,11 @@ test_need_tls_phase2_secrets_blob (void) "need-tls-phase2-secrets-blob-key", "hints should be NULL since no secrets were required"); - /* Connection is good; clear secrets and ensure private key is then required */ + /* Connection is good; clear secrets and ensure private key password is not + * required because our blob is decrypted. + */ nm_connection_clear_secrets (connection); - hints = NULL; - setting_name = nm_connection_need_secrets (connection, &hints); - ASSERT (setting_name != NULL, - "need-tls-phase2-secrets-blob-key", - "unexpected secrets success"); - ASSERT (strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) == 0, - "need-tls-phase2-secrets-blob-key", - "unexpected setting secrets required"); - - ASSERT (hints != NULL, - "need-tls-phase2-secrets-blob-key", - "expected returned secrets hints"); - ASSERT (find_hints_item (hints, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY), - "need-tls-phase2-secrets-blob-key", - "expected to require private key, but it wasn't"); - - g_object_unref (connection); - - /*** Just clear the private key this time ***/ - - connection = make_tls_phase2_connection ("need-tls-phase2-secrets-blob-key-password", - NM_SETTING_802_1X_CK_SCHEME_BLOB); - ASSERT (connection != NULL, - "need-tls-phase2-secrets-blob-key-password", - "error creating test connection"); - - s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); - ASSERT (s_8021x != NULL, - "need-tls-phase2-secrets-blob-key-password", - "error getting test 802.1x setting"); - - g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, NULL, NULL); - - /* Blobs are already decrypted and don't need a password */ hints = NULL; setting_name = nm_connection_need_secrets (connection, &hints); ASSERT (setting_name == NULL, diff --git a/m4/introspection.m4 b/m4/introspection.m4 new file mode 100644 index 0000000000..589721c5a0 --- /dev/null +++ b/m4/introspection.m4 @@ -0,0 +1,94 @@ +dnl -*- mode: autoconf -*- +dnl Copyright 2009 Johan Dahlin +dnl +dnl This file is free software; the author(s) gives unlimited +dnl permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl + +# serial 1 + +m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], +[ + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([LT_INIT],[$0])dnl setup libtool first + + dnl enable/disable introspection + m4_if([$2], [require], + [dnl + enable_introspection=yes + ],[dnl + AC_ARG_ENABLE(introspection, + AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]], + [Enable introspection for this build]),, + [enable_introspection=auto]) + ])dnl + + AC_MSG_CHECKING([for gobject-introspection]) + + dnl presence/version checking + AS_CASE([$enable_introspection], + [no], [dnl + found_introspection="no (disabled, use --enable-introspection to enable)" + ],dnl + [yes],[dnl + PKG_CHECK_EXISTS([gobject-introspection-1.0],, + AC_MSG_ERROR([gobject-introspection-1.0 is not installed])) + PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], + found_introspection=yes, + AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME])) + ],dnl + [auto],[dnl + PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no) + ],dnl + [dnl + AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@]) + ])dnl + + AC_MSG_RESULT([$found_introspection]) + + INTROSPECTION_SCANNER= + INTROSPECTION_COMPILER= + INTROSPECTION_GENERATE= + INTROSPECTION_GIRDIR= + INTROSPECTION_TYPELIBDIR= + if test "x$found_introspection" = "xyes"; then + INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` + INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` + INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` + INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` + INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" + INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` + INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` + INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection + fi + AC_SUBST(INTROSPECTION_SCANNER) + AC_SUBST(INTROSPECTION_COMPILER) + AC_SUBST(INTROSPECTION_GENERATE) + AC_SUBST(INTROSPECTION_GIRDIR) + AC_SUBST(INTROSPECTION_TYPELIBDIR) + AC_SUBST(INTROSPECTION_CFLAGS) + AC_SUBST(INTROSPECTION_LIBS) + AC_SUBST(INTROSPECTION_MAKEFILE) + + AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes") +]) + + +dnl Usage: +dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version]) + +AC_DEFUN([GOBJECT_INTROSPECTION_CHECK], +[ + _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1]) +]) + +dnl Usage: +dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version]) + + +AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE], +[ + _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require]) +]) diff --git a/man/NetworkManager.conf.5.in b/man/NetworkManager.conf.5.in index 2d7a9e8873..d047f39391 100644 --- a/man/NetworkManager.conf.5.in +++ b/man/NetworkManager.conf.5.in @@ -162,11 +162,11 @@ warning messages. .B domains=\fI,, ...\fP The following log domains are available: [NONE, HW, RFKILL, ETHER, WIFI, BT, MB, DHCP4, DHCP6, PPP, WIFI_SCAN, IP4, IP6, AUTOIP4, DNS, VPN, SHARING, SUPPLICANT, -USER_SET, SYS_SET, SUSPEND, CORE, DEVICE, OLPC, WIMAX]. When "NONE" is given by -itself, logging is disabled. MB = Mobile Broadband, USER_SET = user settings -operations and communication, SYS_SET = system settings service operations, OLPC -= OLPC Mesh device operations, CORE = core daemon operations, DEVICE = activation -and general interface operations. +AGENTS, SETTINGS, SUSPEND, CORE, DEVICE, OLPC, WIMAX]. When "NONE" is given by +itself, logging is disabled. MB = Mobile Broadband, AGENTS = secret agents +operations and communication, SETTINGS = settings/config service operations, +OLPC = OLPC Mesh device operations, CORE = core daemon operations, DEVICE = +activation and general interface operations. .SH "SEE ALSO" .BR http://live.gnome.org/NetworkManager/SystemSettings .sp diff --git a/man/nmcli.1.in b/man/nmcli.1.in index 44e9558ad2..5afb802bc9 100644 --- a/man/nmcli.1.in +++ b/man/nmcli.1.in @@ -66,16 +66,18 @@ power users who prefer the command line. The use cases comprise: .IP \(em 4 Initscripts: ifup/ifdown can utilize NetworkManager via \fInmcli\fP instead of -having to manage connections itself and possible interfere with NetworkManager. +having to manage connections itself and possibly interfere with NetworkManager. .IP \(em 4 -Servers, headless machines: No GUI is available; then \fInmcli\fP is used to -talk directly to NetworkManager and control only system-wide connections. +Servers, headless machines: No GUI is available; then \fInmcli\fP can be used +to activate/deactivate connections. However, if a connection requires a secret +to activate and if that secret is not stored at the system level, \fInmcli\fP +will not be able to activate it; it is currently unable to supply the needed +secrets to NetworkManager. .IP \(em 4 -User sessions: For this case, \fInmcli\fP can talk to \fInm-applet\fP to find -user connections. It can still talk directly to NetworkManager for manipulating -these connections. As \fInmcli\fP doesn't have direct access to user -configuration data in GConf, \fInm-applet\fP handles that itself. That may, -for example, cause the applet to pop up keyring dialogs when secrets are needed. +User sessions: \fInmcli\fP can be used activate/deactivate connections from the +command line, but a full NetworkManager client (like \fInm-applet\fP) is used +for supplying secrets not stored at the system level. Keyring dialogs and +password prompts may appear if this happens. .SS \fIOPTIONS\fP .TP .B \-t, \-\-terse @@ -203,14 +205,12 @@ Get information about NetworkManager's connections. .sp .RS .TP -.B list [id | uuid | system | user] +.B list [id | uuid ] .br -List configured connections. Without a parameter, configured connection from -both system and user settings services are listed. \fIsystem\fP argument filters -only system-wide connections, \fIuser\fP prints user connections only. -In order to get connection details, \fIid\fP with connection's name or \fIuuid\fP -with connection's UUID shall be specified. -When no command is given to \fIcon\fP object, the default action is 'nmcli con list'. +List configured connections. Without a parameter, all connections +are listed. In order to get connection details, \fIid\fP with connection's +name or \fIuuid\fP with connection's UUID shall be specified. When no command +is given to the \fIcon\fP object, the default action is 'nmcli con list'. .br .nf \fBReference to D-Bus:\fP diff --git a/marshallers/nm-marshal.list b/marshallers/nm-marshal.list index 359fbed2d5..b152d9c1f2 100644 --- a/marshallers/nm-marshal.list +++ b/marshallers/nm-marshal.list @@ -26,4 +26,5 @@ BOOLEAN:VOID VOID:STRING,BOOLEAN VOID:STRING,OBJECT,POINTER VOID:BOOLEAN,UINT +UINT:STRING,STRING,POINTER,POINTER diff --git a/po/POTFILES.in b/po/POTFILES.in index d4988c43ca..65008b27f0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -11,16 +11,21 @@ libnm-util/crypto.c libnm-util/crypto_gnutls.c libnm-util/crypto_nss.c libnm-util/nm-utils.c -policy/org.freedesktop.network-manager-settings.system.policy.in policy/org.freedesktop.NetworkManager.policy.in -src/nm-netlink-monitor.c src/main.c src/dhcp-manager/nm-dhcp-dhclient.c src/dhcp-manager/nm-dhcp-dhclient-utils.c src/dhcp-manager/nm-dhcp-manager.c -src/logging/nm-logging.c src/dns-manager/nm-dns-manager.c -src/system-settings/nm-default-wired-connection.c +src/logging/nm-logging.c +src/modem-manager/nm-modem-cdma.c +src/modem-manager/nm-modem-gsm.c +src/nm-device-bt.c +src/nm-device-ethernet.c +src/nm-device-olpc-mesh.c +src/nm-manager.c +src/nm-netlink-monitor.c +src/settings/nm-default-wired-connection.c system-settings/plugins/ifcfg-rh/reader.c system-settings/plugins/ifnet/connection_parser.c diff --git a/po/as.po b/po/as.po index 46e41809b6..78a2cd3a90 100644 --- a/po/as.po +++ b/po/as.po @@ -1598,7 +1598,7 @@ msgstr "মন কৰিব: libc resolver ৰ দ্বাৰা ৩ তকৈ msgid "The nameservers listed below may not be recognized." msgstr "নিম্নলিখিত নাম-সেৱকসমূহ চিনাক্ত ন'হ'বও পাৰে ।" -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "স্বয়ংক্ৰিয় %s" diff --git a/po/bg.po b/po/bg.po index b916906017..cda45f19ed 100644 --- a/po/bg.po +++ b/po/bg.po @@ -1932,7 +1932,7 @@ msgstr "ЗАБЕЛЕЖКА: libc може да не поддържа повеч msgid "The nameservers listed below may not be recognized." msgstr "Следните сървъри за имена може да не бъдат разпознати." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Автоматично %s" diff --git a/po/bn_IN.po b/po/bn_IN.po index cf275dad69..372d7bb2a7 100644 --- a/po/bn_IN.po +++ b/po/bn_IN.po @@ -1597,7 +1597,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "নিম্নলিখিত নেম-সার্ভারগুলি সনাক্ত না হওয়ার সম্ভাবনা রয়েছে।" -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "স্বয়ংক্রিয় %s" diff --git a/po/cs.po b/po/cs.po index ccea6bdbe0..6c0d8630f3 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1748,7 +1748,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "Jmenné servery uvedené v následujícím seznamu nelze rozpoznat." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Automaticky %s" diff --git a/po/de.po b/po/de.po index 07a6a3b242..90de5c22ec 100644 --- a/po/de.po +++ b/po/de.po @@ -1809,7 +1809,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "Die nachfolgend gelisteten Nameserver werden eventuell nicht erkannt." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Auto %s" diff --git a/po/el.po b/po/el.po index cb9fa186b0..c6db6f79bf 100644 --- a/po/el.po +++ b/po/el.po @@ -1773,7 +1773,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "Οι κάτωθι εξυπηρετητές ονομάτων ίσως να μην αναγνωρίζονται." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Αυτόματο %s" diff --git a/po/en_GB.po b/po/en_GB.po index ef279f8fab..528f915c2f 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -326,7 +326,7 @@ msgstr "NOTE: the libc resolver may not support more than 3 nameservers." msgid "The nameservers listed below may not be recognized." msgstr "The nameservers listed below may not be recognised." -#: ../src/system-settings/nm-default-wired-connection.c:194 +#: ../src/settings/nm-default-wired-connection.c:194 #, c-format msgid "Auto %s" msgstr "Auto %s" diff --git a/po/es.po b/po/es.po index 74746f4a46..2ef45cbca2 100644 --- a/po/es.po +++ b/po/es.po @@ -1768,7 +1768,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "Puede que los servidores de nombres listados abajo no se reconozcan." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Auto %s" diff --git a/po/eu.po b/po/eu.po index 5a584ec367..68b8204a4b 100644 --- a/po/eu.po +++ b/po/eu.po @@ -1308,7 +1308,7 @@ msgstr "OHARRA: libc-en ebaztaileak ez du 3 izen-zerbitzari baino gehiago onartz msgid "The nameservers listed below may not be recognized." msgstr "Azpian zerrendatutako izen-zenbitzariak ez dira ezagutuko." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Auto %s" diff --git a/po/fr.po b/po/fr.po index 25b6c76b8b..6aa67c8c28 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1621,7 +1621,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "Les serveurs de noms listés ci-dessous peuvent ne pas être reconnus." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Auto %s" diff --git a/po/gl.po b/po/gl.po index 4adefda785..62dc71f3fe 100644 --- a/po/gl.po +++ b/po/gl.po @@ -1732,7 +1732,7 @@ msgstr "NOTE: o importador libc non permite máis de 3 nomes de servidores." msgid "The nameservers listed below may not be recognized." msgstr "Os nomes de servidores listados a seguir poden non ser recoñecidos" -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Auto %s" diff --git a/po/gu.po b/po/gu.po index 3fa8cf3333..68c97d7152 100644 --- a/po/gu.po +++ b/po/gu.po @@ -1596,7 +1596,7 @@ msgstr "નોંધ: libc સુધારનાર એ ૩ નામ સર્ msgid "The nameservers listed below may not be recognized." msgstr "નીચે યાદી થયેલ નામસર્વરો એ ઓળખી શકાતા નથી." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "%s સ્વયં કરો" diff --git a/po/hi.po b/po/hi.po index aab5c03467..59b00c4a87 100644 --- a/po/hi.po +++ b/po/hi.po @@ -1691,7 +1691,7 @@ msgstr "नोट: libc समाधानकर्ता 3 नेमसर् msgid "The nameservers listed below may not be recognized." msgstr "नीचे सूची में दिया गया नेमसर्वर पहचाना नहीं जा सकता है." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "स्वतः %s" diff --git a/po/hu.po b/po/hu.po index 79ee46a4f9..f76c564343 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1910,7 +1910,7 @@ msgid "The nameservers listed below may not be recognized." msgstr "" "Az alább felsorolt névkiszolgálók lehet, hogy nem kerülnek felismerésre." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Automatikus %s" diff --git a/po/id.po b/po/id.po index b88792905f..e8adc15101 100644 --- a/po/id.po +++ b/po/id.po @@ -1706,7 +1706,7 @@ msgstr "CATATAN: resolver libc mungkin tak mendukung lebih dari 3 nameserver." msgid "The nameservers listed below may not be recognized." msgstr "Nameserver yang terdaftar di bawah mungkin tak dikenali." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Otomatis %s" diff --git a/po/it.po b/po/it.po index dd24604d56..08de04994e 100644 --- a/po/it.po +++ b/po/it.po @@ -1610,7 +1610,7 @@ msgstr "NOTA: il risolutore libc non supporta più di 3 server di nomi." msgid "The nameservers listed below may not be recognized." msgstr "I server di nomi elencati sotto non possono essere riconosciuti." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "%s (automatica)" diff --git a/po/ja.po b/po/ja.po index 4b49f0089c..37f0e82965 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1598,7 +1598,7 @@ msgstr "注記: libc リゾルバは 3つ以上のネームサーバーをサ msgid "The nameservers listed below may not be recognized." msgstr "以下の一覧にあるネームサーバーは認識されないかも知れません。" -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "自動 %s" diff --git a/po/kn.po b/po/kn.po index 54769baa77..6d172a0d7f 100644 --- a/po/kn.po +++ b/po/kn.po @@ -1700,7 +1700,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "ಈ ಕೆಳಗೆ ಸೂಚಿಸಲಾದ ನಾಮಪರಿಚಾರಕಗಳನ್ನು ಗುರುತಿಸಲಾಗಿಲ್ಲ." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "ಸ್ವಯಂ %s" diff --git a/po/ko.po b/po/ko.po index e2cc426bca..20b749afd6 100644 --- a/po/ko.po +++ b/po/ko.po @@ -1598,7 +1598,7 @@ msgstr "주의: libc 주소 검색은 3개를 초과하는 네임서버를 지 msgid "The nameservers listed below may not be recognized." msgstr "아래 열거된 네임서버를 인식하지 못할 수 있습니다." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "자동 %s" diff --git a/po/lt.po b/po/lt.po index 2f58078c69..1d9eb95e65 100644 --- a/po/lt.po +++ b/po/lt.po @@ -1780,7 +1780,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "Žemiau pateikti vardų serveriai gali būti neatpažinti." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Automatinis %s" diff --git a/po/ml.po b/po/ml.po index 0d9796f9fe..59b0b0f262 100644 --- a/po/ml.po +++ b/po/ml.po @@ -1594,7 +1594,7 @@ msgstr "കുറിപ്പു്: libc റിസോള്‍വര്‍ 3 msgid "The nameservers listed below may not be recognized." msgstr "താഴെ പറഞ്ഞിരിക്കുന്ന നെയിംസര്‍വറുകള്‍ തിരിച്ചറിയപ്പെടുന്നവയല്ല." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "ഓട്ടോ %s" diff --git a/po/mr.po b/po/mr.po index 67335ad2e3..03f93b2724 100644 --- a/po/mr.po +++ b/po/mr.po @@ -1680,7 +1680,7 @@ msgstr "NOTE: libc रिजॉलव्हर 3 पेक्षा जास् msgid "The nameservers listed below may not be recognized." msgstr "खालिल यादीतील नेमसर्व्हर्स् अनोळखी राहतील." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "स्वयं %s" diff --git a/po/or.po b/po/or.po index bba0d598c7..32eb1aa11f 100644 --- a/po/or.po +++ b/po/or.po @@ -1696,7 +1696,7 @@ msgstr "ଟିପ୍ପଣୀ: libc resolver 3 ରୁ ଅଧିକ nameserverଗ msgid "The nameservers listed below may not be recognized." msgstr "ନିମ୍ନରେ ତାଲିକାଭୁକ୍ତ nameserverଗୁଡ଼ିକୁ ଚିହ୍ନି ହୋଇନପାରେ." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "ସ୍ୱୟଂ %s" diff --git a/po/pa.po b/po/pa.po index cf3777a70b..87092b0f3c 100644 --- a/po/pa.po +++ b/po/pa.po @@ -1755,7 +1755,7 @@ msgstr "ਨੋਟ: libc ਰਿਜ਼ੋਲਵਰ ੩ ਤੋਂ ਵੱਧ ਨੇ msgid "The nameservers listed below may not be recognized." msgstr "ਹੇਠਾਂ ਦਿੱਤੇ ਨੇਮ-ਸਰਵਰ ਪਛਾਣੇ ਨਹੀਂ ਜਾ ਸਕਦੇ।" -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "ਆਟੋ %s" diff --git a/po/pl.po b/po/pl.po index f1b0650d04..58ad3e7e55 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1780,7 +1780,7 @@ msgstr "UWAGA: obsługa nazw libc nie obsługuje więcej niż 3 serwery nazw." msgid "The nameservers listed below may not be recognized." msgstr "Poniższe serwery nazw nie mogą nie zostać rozpoznane." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Automatyczne %s" diff --git a/po/pt_BR.po b/po/pt_BR.po index 40919e8a6b..3b364b50b5 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -1321,7 +1321,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "Os servidores de nomes listados abaixo podem não ser reconhecidos." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Auto %s" diff --git a/po/ru.po b/po/ru.po index 2595ab3c6b..5dc18f3832 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1604,7 +1604,7 @@ msgstr "" msgid "The nameservers listed below may not be recognized." msgstr "Нижеперечисленные сервера могут быть пропущены." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Авто %s" diff --git a/po/sl.po b/po/sl.po index cb37ee828a..33af9c1e5b 100644 --- a/po/sl.po +++ b/po/sl.po @@ -1839,7 +1839,7 @@ msgstr "OPOMBA: razreševalnik libc morda ne podpira več kot 3 imenskih strežn msgid "The nameservers listed below may not be recognized." msgstr "Navedeni imenski strežniki morda ne bodo prepoznani." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Samodejno %s" diff --git a/po/sv.po b/po/sv.po index 56b73dc1e7..eb8da2eafb 100644 --- a/po/sv.po +++ b/po/sv.po @@ -1858,7 +1858,7 @@ msgstr "OBSERVERA: uppslag via glibc kanske inte har stöd för fler än 3 namns msgid "The nameservers listed below may not be recognized." msgstr "Namnservrarna listade nedan kanske inte kommer att kännas igen." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "Automatisk %s" diff --git a/po/ta.po b/po/ta.po index 8ab5caeb63..44125c38bb 100644 --- a/po/ta.po +++ b/po/ta.po @@ -1602,7 +1602,7 @@ msgstr "குறிப்பு: இந்த libc மறுதீர்வா msgid "The nameservers listed below may not be recognized." msgstr "கீழே பட்டியலிட்டப்படுள்ள பெயர்சேவையகங்கள் கண்டுபிடிக்கப்படவில்லை." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "தானியக்கி %s" diff --git a/po/te.po b/po/te.po index cf05561417..a8d55575c4 100644 --- a/po/te.po +++ b/po/te.po @@ -1689,7 +1689,7 @@ msgstr "గమనిక: libc రిజాల్వర్ 3 నామపు స msgid "The nameservers listed below may not be recognized." msgstr "క్రిందన జాబితాచేసివున్న నామపుసేవికలు గుర్తించబడక పోవచ్చును." -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "స్వయంచాలక %s" diff --git a/po/zh_CN.po b/po/zh_CN.po index 81e2e6b6a2..5f4b64f4c6 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1690,7 +1690,7 @@ msgstr "注意:libc 解析器可能不支持超过三个名字服务器。" msgid "The nameservers listed below may not be recognized." msgstr "以下列出的名字服务器可能无法被识别。" -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "自动 %s" diff --git a/po/zh_TW.po b/po/zh_TW.po index 25e81bbe1b..d6e530fdf3 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -1599,7 +1599,7 @@ msgstr "注意:libc 解析器不支援 3 個以上的名稱伺服器。" msgid "The nameservers listed below may not be recognized." msgstr "下面列出的名稱伺服器可能不會被辨識。" -#: ../src/system-settings/nm-default-wired-connection.c:157 +#: ../src/settings/nm-default-wired-connection.c:157 #, c-format msgid "Auto %s" msgstr "自動 %s" diff --git a/policy/Makefile.am b/policy/Makefile.am index 4778ce230a..289d220bdb 100644 --- a/policy/Makefile.am +++ b/policy/Makefile.am @@ -1,7 +1,6 @@ polkit_policydir = $(datadir)/polkit-1/actions dist_polkit_policy_in_files = \ - org.freedesktop.network-manager-settings.system.policy.in \ org.freedesktop.NetworkManager.policy.in dist_polkit_policy_DATA = $(dist_polkit_policy_in_files:.policy.in=.policy) diff --git a/policy/org.freedesktop.NetworkManager.policy.in b/policy/org.freedesktop.NetworkManager.policy.in index 185265885b..a7d5202fb9 100644 --- a/policy/org.freedesktop.NetworkManager.policy.in +++ b/policy/org.freedesktop.NetworkManager.policy.in @@ -54,15 +54,6 @@ - - <_description>Allow use of user-specific connections - <_message>System policy prevents use of user-specific connections - - yes - yes - - - <_description>Allow control of network connections <_message>System policy prevents control of network connections @@ -72,5 +63,50 @@ + + <_description>Connection sharing via a protected WiFi network + <_message>System policy prevents sharing connections via a protected WiFi network + + no + yes + + + + + <_description>Connection sharing via an open WiFi network + <_message>System policy prevents sharing connections via an open WiFi network + + no + yes + + + + + <_description>Modify personal network connections + <_message>System policy prevents modification of personal network settings + + no + yes + + + + + <_description>Modify network connections for all users + <_message>System policy prevents modification of network settings for all users + + no + yes + + + + + <_description>Modify persistent system hostname + <_message>System policy prevents modification of the persistent system hostname + + no + auth_admin_keep + + + diff --git a/policy/org.freedesktop.network-manager-settings.system.policy.in b/policy/org.freedesktop.network-manager-settings.system.policy.in deleted file mode 100644 index 620e3a6a58..0000000000 --- a/policy/org.freedesktop.network-manager-settings.system.policy.in +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - NetworkManager - http://www.gnome.org/projects/NetworkManager - nm-icon - - - <_description>Modify system connections - <_message>System policy prevents modification of system settings - - no - auth_admin_keep - - - - - <_description>Modify persistent system hostname - <_message>System policy prevents modification of the persistent system hostname - - no - auth_admin_keep - - - - - <_description>Connection sharing via a protected WiFi network - <_message>System policy prevents sharing connections via a protected WiFi network - - no - yes - - - - - <_description>Connection sharing via an open WiFi network - <_message>System policy prevents sharing connections via an open WiFi network - - no - yes - - - - diff --git a/src/Makefile.am b/src/Makefile.am index ec0fda557e..8a04d81152 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ SUBDIRS= \ dnsmasq-manager \ modem-manager \ bluez-manager \ - system-settings + settings if WITH_WIMAX SUBDIRS += wimax @@ -30,7 +30,7 @@ INCLUDES = -I${top_srcdir} \ -I${top_srcdir}/src/dnsmasq-manager \ -I${top_srcdir}/src/modem-manager \ -I$(top_srcdir)/src/bluez-manager \ - -I$(top_srcdir)/src/system-settings \ + -I$(top_srcdir)/src/settings \ -I${top_srcdir}/libnm-util \ -I${top_srcdir}/callouts @@ -38,13 +38,14 @@ if WITH_WIMAX INCLUDES += -I$(top_srcdir)/src/wimax endif -INCLUDES += -I${top_srcdir}/libnm-glib - ########################################### # Test libraries ########################################### -noinst_LTLIBRARIES = libtest-dhcp.la libtest-policy-hosts.la +noinst_LTLIBRARIES = \ + libtest-dhcp.la \ + libtest-policy-hosts.la \ + libtest-wifi-ap-utils.la ########################################### # DHCP test library @@ -85,6 +86,22 @@ libtest_policy_hosts_la_LIBADD = \ $(GLIB_LIBS) +########################################### +# Wifi ap utils +########################################### + +libtest_wifi_ap_utils_la_SOURCES = \ + nm-wifi-ap-utils.c \ + nm-wifi-ap-utils.h + +libtest_wifi_ap_utils_la_CPPFLAGS = \ + $(GLIB_CFLAGS) + +libtest_wifi_ap_utils_la_LIBADD = \ + ${top_builddir}/libnm-util/libnm-util.la \ + $(GLIB_LIBS) + + ########################################### # NetworkManager ########################################### @@ -115,6 +132,8 @@ NetworkManager_SOURCES = \ nm-device-gsm.h \ nm-wifi-ap.c \ nm-wifi-ap.h \ + nm-wifi-ap-utils.c \ + nm-wifi-ap-utils.h \ nm-dbus-manager.h \ nm-dbus-manager.c \ nm-udev-manager.c \ @@ -125,8 +144,6 @@ NetworkManager_SOURCES = \ nm-ip4-config.h \ nm-ip6-config.c \ nm-ip6-config.h \ - nm-secrets-provider-interface.c \ - nm-secrets-provider-interface.h \ nm-active-connection.h \ nm-active-connection.c \ main.c \ @@ -156,7 +173,9 @@ NetworkManager_SOURCES = \ nm-dhcp4-config.h \ nm-dhcp6-config.c \ nm-dhcp6-config.h \ - nm-rfkill.h + nm-rfkill.h \ + nm-session-monitor.c \ + nm-session-monitor.h nm-access-point-glue.h: $(top_srcdir)/introspection/nm-access-point.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_access_point --mode=glib-server --output=$@ $< @@ -252,8 +271,8 @@ NetworkManager_LDADD = \ ./ppp-manager/libppp-manager.la \ ./modem-manager/libmodem-manager.la \ ./bluez-manager/libbluez-manager.la \ + ./settings/libsettings.la \ $(WIMAX_LIBS) \ - ./system-settings/libsystem-settings.la \ ./backends/libnmbackend.la \ $(top_builddir)/libnm-util/libnm-util.la \ $(DBUS_LIBS) \ diff --git a/src/NetworkManager.conf b/src/NetworkManager.conf index 1f1ed49b46..b256a444e4 100644 --- a/src/NetworkManager.conf +++ b/src/NetworkManager.conf @@ -4,13 +4,12 @@ - - - + + @@ -57,6 +56,9 @@ + + @@ -75,10 +77,14 @@ - - + + + + - - 512 diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 10240960b0..38176b3de8 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -36,6 +36,9 @@ #include "nm-dbus-manager.h" #include "nm-dispatcher-action.h" #include "nm-dbus-glib-types.h" +#include "nm-setting-connection.h" +#include "nm-setting-ip4-config.h" +#include "nm-setting-ip6-config.h" #include #include @@ -402,21 +405,10 @@ nm_utils_call_dispatcher (const char *action, } if (connection) { - connection_hash = nm_connection_to_hash (connection); + connection_hash = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_NO_SECRETS); connection_props = value_hash_create (); - /* Service name */ - if (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_USER) { - value_hash_add_str (connection_props, - NMD_CONNECTION_PROPS_SERVICE_NAME, - NM_DBUS_SERVICE_USER_SETTINGS); - } else if (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM) { - value_hash_add_str (connection_props, - NMD_CONNECTION_PROPS_SERVICE_NAME, - NM_DBUS_SERVICE_SYSTEM_SETTINGS); - } - /* path */ value_hash_add_object_path (connection_props, NMD_CONNECTION_PROPS_PATH, @@ -719,3 +711,118 @@ nm_utils_get_proc_sys_net_value (const char *path, return success; } +static char * +get_new_connection_name (const GSList *existing, + const char *format, + const char *preferred) +{ + GSList *names = NULL; + const GSList *iter; + char *cname = NULL; + int i = 0; + gboolean preferred_found = FALSE; + + for (iter = existing; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = NM_CONNECTION (iter->data); + NMSettingConnection *s_con; + const char *id; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION)); + id = nm_setting_connection_get_id (s_con); + g_assert (id); + names = g_slist_append (names, (gpointer) id); + + if (preferred && !preferred_found && (strcmp (preferred, id) == 0)) + preferred_found = TRUE; + } + + /* Return the preferred name if it was unique */ + if (preferred && !preferred_found) { + g_slist_free (names); + return g_strdup (preferred); + } + + /* Otherwise find the next available unique connection name using the given + * connection name template. + */ + while (!cname && (i++ < 10000)) { + char *temp; + gboolean found = FALSE; + + temp = g_strdup_printf (format, i); + for (iter = names; iter; iter = g_slist_next (iter)) { + if (!strcmp (iter->data, temp)) { + found = TRUE; + break; + } + } + if (!found) + cname = temp; + else + g_free (temp); + } + + g_slist_free (names); + return cname; +} + +void +nm_utils_complete_generic (NMConnection *connection, + const char *ctype, + const GSList *existing, + const char *format, + const char *preferred) +{ + NMSettingConnection *s_con; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + const char *method; + char *id, *uuid; + + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + if (!s_con) { + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + } + g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_TYPE, ctype, NULL); + + if (!nm_setting_connection_get_uuid (s_con)) { + uuid = nm_utils_uuid_generate (); + g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_UUID, uuid, NULL); + g_free (uuid); + } + + /* Add a connection ID if absent */ + if (!nm_setting_connection_get_id (s_con)) { + id = get_new_connection_name (existing, format, preferred); + g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_ID, id, NULL); + g_free (id); + } + + /* Add an 'auto' IPv4 connection if present */ + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (!s_ip4) { + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + } + method = nm_setting_ip4_config_get_method (s_ip4); + if (!method) { + g_object_set (G_OBJECT (s_ip4), + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NULL); + } + + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + if (!s_ip6) { + s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + } + method = nm_setting_ip6_config_get_method (s_ip6); + if (!method) { + g_object_set (G_OBJECT (s_ip6), + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); + } +} + diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 72c0e532b8..1edd87746f 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -78,4 +78,10 @@ gboolean nm_utils_get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value); +void nm_utils_complete_generic (NMConnection *connection, + const char *ctype, + const GSList *existing, + const char *format, + const char *preferred); + #endif /* NETWORK_MANAGER_UTILS_H */ diff --git a/src/bluez-manager/nm-bluez-manager.c b/src/bluez-manager/nm-bluez-manager.c index 59849d3bd5..5381151ea8 100644 --- a/src/bluez-manager/nm-bluez-manager.c +++ b/src/bluez-manager/nm-bluez-manager.c @@ -317,12 +317,12 @@ nm_bluez_manager_init (NMBluezManager *self) g_assert (priv->dbus_mgr); g_signal_connect (priv->dbus_mgr, - "name-owner-changed", + NM_DBUS_MANAGER_NAME_OWNER_CHANGED, G_CALLBACK (name_owner_changed_cb), self); g_signal_connect (priv->dbus_mgr, - "dbus-connection-changed", + NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, G_CALLBACK (dbus_connection_changed_cb), self); diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c index 84cf16fb50..9e643cdfe7 100644 --- a/src/logging/nm-logging.c +++ b/src/logging/nm-logging.c @@ -41,8 +41,8 @@ static guint32 log_level = LOGL_INFO | LOGL_WARN | LOGL_ERR; static guint32 log_domains = \ LOGD_HW | LOGD_RFKILL | LOGD_ETHER | LOGD_WIFI | LOGD_BT | LOGD_MB | \ LOGD_DHCP4 | LOGD_DHCP6 | LOGD_PPP | LOGD_IP4 | LOGD_IP6 | LOGD_AUTOIP4 | \ - LOGD_DNS | LOGD_VPN | LOGD_SHARING | LOGD_SUPPLICANT | LOGD_USER_SET | \ - LOGD_SYS_SET | LOGD_SUSPEND | LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | \ + LOGD_DNS | LOGD_VPN | LOGD_SHARING | LOGD_SUPPLICANT | LOGD_AGENTS | \ + LOGD_SETTINGS | LOGD_SUSPEND | LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | \ LOGD_WIMAX; typedef struct { @@ -77,8 +77,8 @@ static const LogDesc domain_descs[] = { { LOGD_VPN, "VPN" }, { LOGD_SHARING, "SHARING" }, { LOGD_SUPPLICANT,"SUPPLICANT" }, - { LOGD_USER_SET, "USER_SET" }, - { LOGD_SYS_SET, "SYS_SET" }, + { LOGD_AGENTS, "AGENTS" }, + { LOGD_SETTINGS, "SETTINGS" }, { LOGD_SUSPEND, "SUSPEND" }, { LOGD_CORE, "CORE" }, { LOGD_DEVICE, "DEVICE" }, diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h index 4bfc8078a0..3e8ef696ef 100644 --- a/src/logging/nm-logging.h +++ b/src/logging/nm-logging.h @@ -45,8 +45,8 @@ enum { LOGD_VPN = 0x00004000, LOGD_SHARING = 0x00008000, /* Connection sharing/dnsmasq */ LOGD_SUPPLICANT = 0x00010000, /* WiFi and 802.1x */ - LOGD_USER_SET = 0x00020000, /* User settings */ - LOGD_SYS_SET = 0x00040000, /* System settings */ + LOGD_AGENTS = 0x00020000, /* Secret agents */ + LOGD_SETTINGS = 0x00040000, /* Settings */ LOGD_SUSPEND = 0x00080000, /* Suspend/Resume */ LOGD_CORE = 0x00100000, /* Core daemon and policy stuff */ LOGD_DEVICE = 0x00200000, /* Device state and activation */ diff --git a/src/main.c b/src/main.c index 211a5b983d..577f842d58 100644 --- a/src/main.c +++ b/src/main.c @@ -469,6 +469,7 @@ main (int argc, char *argv[]) NMDBusManager *dbus_mgr = NULL; NMSupplicantManager *sup_mgr = NULL; NMDHCPManager *dhcp_mgr = NULL; + NMSettings *settings = NULL; GError *error = NULL; gboolean wrote_pidfile = FALSE; char *cfg_log_level = NULL, *cfg_log_domains = NULL; @@ -688,7 +689,14 @@ main (int argc, char *argv[]) goto done; } - manager = nm_manager_get (config, + settings = nm_settings_new (config, plugins, &error); + if (!settings) { + nm_log_err (LOGD_CORE, "failed to initialize settings storage."); + goto done; + } + + manager = nm_manager_get (settings, + config, plugins, state_file, net_enabled, @@ -702,7 +710,7 @@ main (int argc, char *argv[]) goto done; } - policy = nm_policy_new (manager, vpn_manager); + policy = nm_policy_new (manager, vpn_manager, settings); if (policy == NULL) { nm_log_err (LOGD_CORE, "failed to initialize the policy."); goto done; @@ -753,6 +761,9 @@ done: if (manager) g_object_unref (manager); + if (settings) + g_object_unref (settings); + if (vpn_manager) g_object_unref (vpn_manager); diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c index c32c18222c..7000c5de82 100644 --- a/src/modem-manager/nm-modem-cdma.c +++ b/src/modem-manager/nm-modem-cdma.c @@ -15,19 +15,23 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2011 Red Hat, Inc. * Copyright (C) 2009 Novell, Inc. */ #include +#include #include "nm-dbus-glib-types.h" #include "nm-modem-cdma.h" #include "nm-modem-types.h" #include "nm-device.h" +#include "nm-device-private.h" #include "nm-dbus-manager.h" #include "nm-setting-connection.h" #include "nm-setting-cdma.h" +#include "nm-setting-serial.h" +#include "nm-setting-ppp.h" #include "NetworkManagerUtils.h" #include "nm-logging.h" @@ -269,6 +273,47 @@ real_check_connection_compatible (NMModem *modem, return TRUE; } +static gboolean +real_complete_connection (NMModem *modem, + NMConnection *connection, + const GSList *existing_connections, + GError **error) +{ + NMSettingCdma *s_cdma; + NMSettingSerial *s_serial; + NMSettingPPP *s_ppp; + + s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA); + s_serial = (NMSettingSerial *) nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL); + s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP); + + if (!s_cdma) { + s_cdma = (NMSettingCdma *) nm_setting_cdma_new (); + nm_connection_add_setting (connection, NM_SETTING (s_cdma)); + } + + if (!nm_setting_cdma_get_number (s_cdma)) + g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL); + + /* Need serial and PPP settings at least */ + if (!s_serial) { + s_serial = (NMSettingSerial *) nm_setting_serial_new (); + nm_connection_add_setting (connection, NM_SETTING (s_serial)); + } + if (!s_ppp) { + s_ppp = (NMSettingPPP *) nm_setting_ppp_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ppp)); + } + + nm_utils_complete_generic (connection, + NM_SETTING_CDMA_SETTING_NAME, + existing_connections, + _("CDMA connection %d"), + NULL); + + return TRUE; +} + static gboolean real_get_user_pass (NMModem *modem, NMConnection *connection, @@ -344,6 +389,7 @@ nm_modem_cdma_class_init (NMModemCdmaClass *klass) modem_class->get_setting_name = real_get_setting_name; modem_class->get_best_auto_connection = real_get_best_auto_connection; modem_class->check_connection_compatible = real_check_connection_compatible; + modem_class->complete_connection = real_complete_connection; modem_class->act_stage1_prepare = real_act_stage1_prepare; modem_class->deactivate_quickly = real_deactivate_quickly; diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c index abb96db1fd..525aa55b05 100644 --- a/src/modem-manager/nm-modem-gsm.c +++ b/src/modem-manager/nm-modem-gsm.c @@ -15,16 +15,21 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2011 Red Hat, Inc. * Copyright (C) 2009 Novell, Inc. */ #include +#include + #include "nm-dbus-glib-types.h" #include "nm-modem-gsm.h" #include "nm-device.h" +#include "nm-device-private.h" #include "nm-setting-connection.h" #include "nm-setting-gsm.h" +#include "nm-setting-serial.h" +#include "nm-setting-ppp.h" #include "nm-modem-types.h" #include "nm-logging.h" #include "NetworkManagerUtils.h" @@ -177,12 +182,10 @@ ask_for_pin (NMModemGsm *self, gboolean always_ask) if (!always_ask) tries = priv->pin_tries++; - g_signal_emit_by_name (self, NM_MODEM_NEED_AUTH, - NM_SETTING_GSM_SETTING_NAME, - (tries || always_ask) ? TRUE : FALSE, - SECRETS_CALLER_MOBILE_BROADBAND, - NM_SETTING_GSM_PIN, - NULL); + nm_modem_get_secrets (NM_MODEM (self), + NM_SETTING_GSM_SETTING_NAME, + (tries || always_ask) ? TRUE : FALSE, + NM_SETTING_GSM_PIN); } static void @@ -469,6 +472,51 @@ real_check_connection_compatible (NMModem *modem, return TRUE; } +static gboolean +real_complete_connection (NMModem *modem, + NMConnection *connection, + const GSList *existing_connections, + GError **error) +{ + NMSettingGsm *s_gsm; + NMSettingSerial *s_serial; + NMSettingPPP *s_ppp; + + s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM); + s_serial = (NMSettingSerial *) nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL); + s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP); + + if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) { + /* Need an APN at least */ + g_set_error_literal (error, + NM_SETTING_GSM_ERROR, + NM_SETTING_GSM_ERROR_MISSING_PROPERTY, + NM_SETTING_GSM_APN); + return FALSE; + } + + if (!nm_setting_gsm_get_number (s_gsm)) + g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL); + + /* Need serial and PPP settings at least */ + if (!s_serial) { + s_serial = (NMSettingSerial *) nm_setting_serial_new (); + nm_connection_add_setting (connection, NM_SETTING (s_serial)); + } + if (!s_ppp) { + s_ppp = (NMSettingPPP *) nm_setting_ppp_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ppp)); + } + + nm_utils_complete_generic (connection, + NM_SETTING_GSM_SETTING_NAME, + existing_connections, + _("GSM connection %d"), + NULL); + + return TRUE; +} + static gboolean real_get_user_pass (NMModem *modem, NMConnection *connection, @@ -547,6 +595,7 @@ nm_modem_gsm_class_init (NMModemGsmClass *klass) modem_class->get_setting_name = real_get_setting_name; modem_class->get_best_auto_connection = real_get_best_auto_connection; modem_class->check_connection_compatible = real_check_connection_compatible; + modem_class->complete_connection = real_complete_connection; modem_class->act_stage1_prepare = real_act_stage1_prepare; modem_class->deactivate_quickly = real_deactivate_quickly; diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c index 28f7b94d0c..f5ade50c09 100644 --- a/src/modem-manager/nm-modem-manager.c +++ b/src/modem-manager/nm-modem-manager.c @@ -371,7 +371,7 @@ nm_modem_manager_init (NMModemManager *self) priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); priv->dbus_mgr = nm_dbus_manager_get (); - g_signal_connect (priv->dbus_mgr, "name-owner-changed", + g_signal_connect (priv->dbus_mgr, NM_DBUS_MANAGER_NAME_OWNER_CHANGED, G_CALLBACK (nm_modem_manager_name_owner_changed), self); diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c index b3f7eaa1cb..44937eedcc 100644 --- a/src/modem-manager/nm-modem.c +++ b/src/modem-manager/nm-modem.c @@ -62,7 +62,9 @@ typedef struct { char *device; char *iface; + NMActRequest *act_request; guint32 secrets_tries; + guint32 secrets_id; DBusGProxyCall *call; @@ -78,7 +80,8 @@ enum { PPP_FAILED, PREPARE_RESULT, IP4_CONFIG_RESULT, - NEED_AUTH, + AUTH_REQUESTED, + AUTH_RESULT, LAST_SIGNAL }; @@ -475,67 +478,60 @@ nm_modem_stage4_get_ip4_config (NMModem *self, return ret; } -gboolean -nm_modem_connection_secrets_updated (NMModem *self, - NMActRequest *req, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller) +static void +cancel_get_secrets (NMModem *self) { - NMModemPrivate *priv; - gboolean found = FALSE; - const char *setting_name; - GSList *iter; + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (NM_IS_MODEM (self), FALSE); - g_return_val_if_fail (req != NULL, FALSE); - g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); - - priv = NM_MODEM_GET_PRIVATE (self); - - if (caller == SECRETS_CALLER_PPP) { - const char *user = NULL; - const char *pass = NULL; - - g_return_val_if_fail (priv->ppp_manager != NULL, FALSE); - - if (!NM_MODEM_GET_CLASS (self)->get_user_pass (self, connection, &user, &pass)) { - /* Shouldn't ever happen */ - nm_ppp_manager_update_secrets (priv->ppp_manager, - priv->iface, - NULL, - NULL, - "missing GSM/CDMA setting; no secrets could be found."); - } else { - nm_ppp_manager_update_secrets (priv->ppp_manager, - priv->iface, - user ? user : "", - pass ? pass : "", - NULL); - } - return TRUE; + if (priv->secrets_id) { + nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id); + priv->secrets_id = 0; } +} - g_return_val_if_fail (caller == SECRETS_CALLER_MOBILE_BROADBAND, FALSE); +static void +modem_secrets_cb (NMActRequest *req, + guint32 call_id, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + NMModem *self = NM_MODEM (user_data); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - g_assert (NM_MODEM_GET_CLASS (self)->get_setting_name); - setting_name = NM_MODEM_GET_CLASS (self)->get_setting_name (self); + g_return_if_fail (call_id == priv->secrets_id); - for (iter = updated_settings; iter; iter = g_slist_next (iter)) { - const char *candidate_setting_name = (const char *) iter->data; + priv->secrets_id = 0; - if (!strcmp (candidate_setting_name, setting_name)) - found = TRUE; - else { - nm_log_warn (LOGD_MB, "ignoring updated secrets for setting '%s'.", - candidate_setting_name); - } - } + if (error) + nm_log_warn (LOGD_MB, "%s", error->message); - return found; + g_signal_emit (self, signals[AUTH_RESULT], 0, error); +} + +gboolean +nm_modem_get_secrets (NMModem *self, + const char *setting_name, + gboolean request_new, + const char *hint) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + guint32 flags = NM_ACT_REQUEST_GET_SECRETS_FLAG_ALLOW_INTERACTION; + + cancel_get_secrets (self); + + if (request_new) + flags |= NM_ACT_REQUEST_GET_SECRETS_FLAG_REQUEST_NEW; + priv->secrets_id = nm_act_request_get_secrets (priv->act_request, + setting_name, + flags, + hint, + modem_secrets_cb, + self); + if (priv->secrets_id) + g_signal_emit (self, signals[AUTH_REQUESTED], 0); + + return !!(priv->secrets_id); } static NMActStageReturn @@ -558,6 +554,11 @@ nm_modem_act_stage1_prepare (NMModem *self, NMActStageReturn ret; GPtrArray *hints = NULL; const char *setting_name = NULL; + guint32 flags = NM_ACT_REQUEST_GET_SECRETS_FLAG_ALLOW_INTERACTION; + + if (priv->act_request) + g_object_unref (priv->act_request); + priv->act_request = g_object_ref (req); ret = NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, req, @@ -565,23 +566,22 @@ nm_modem_act_stage1_prepare (NMModem *self, &setting_name, reason); if ((ret == NM_ACT_STAGE_RETURN_POSTPONE) && setting_name) { - const char *hint1 = NULL, *hint2 = NULL; + if (priv->secrets_tries++) + flags |= NM_ACT_REQUEST_GET_SECRETS_FLAG_REQUEST_NEW; - /* Need some secrets */ - if (hints) { - if (hints->len > 0) - hint1 = g_ptr_array_index (hints, 0); - if (hints->len > 1) - hint2 = g_ptr_array_index (hints, 1); + priv->secrets_id = nm_act_request_get_secrets (req, + setting_name, + flags, + hints ? g_ptr_array_index (hints, 0) : NULL, + modem_secrets_cb, + self); + if (priv->secrets_id) + g_signal_emit (self, signals[AUTH_REQUESTED], 0); + else { + *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + ret = NM_ACT_STAGE_RETURN_FAILURE; } - g_signal_emit (self, signals[NEED_AUTH], 0, - setting_name, - priv->secrets_tries++ ? TRUE : FALSE, - SECRETS_CALLER_MOBILE_BROADBAND, - hint1, - hint2); - if (hints) g_ptr_array_free (hints, TRUE); } @@ -624,6 +624,17 @@ nm_modem_check_connection_compatible (NMModem *self, return FALSE; } +gboolean +nm_modem_complete_connection (NMModem *self, + NMConnection *connection, + const GSList *existing_connections, + GError **error) +{ + if (NM_MODEM_GET_CLASS (self)->complete_connection) + return NM_MODEM_GET_CLASS (self)->complete_connection (self, connection, existing_connections, error); + return FALSE; +} + static void real_deactivate_quickly (NMModem *self, NMDevice *device) { @@ -639,6 +650,12 @@ real_deactivate_quickly (NMModem *self, NMDevice *device) priv->secrets_tries = 0; + if (priv->act_request) { + cancel_get_secrets (self); + g_object_unref (priv->act_request); + priv->act_request = NULL; + } + if (priv->call) { dbus_g_proxy_cancel_call (priv->proxy, priv->call); priv->call = NULL; @@ -697,6 +714,7 @@ nm_modem_device_state_changed (NMModem *self, NMDeviceStateReason reason) { gboolean was_connected = FALSE; + NMModemPrivate *priv; g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_MODEM (self)); @@ -704,16 +722,26 @@ nm_modem_device_state_changed (NMModem *self, if (IS_ACTIVATING_STATE (old_state) || (old_state == NM_DEVICE_STATE_ACTIVATED)) was_connected = TRUE; + priv = NM_MODEM_GET_PRIVATE (self); + /* Make sure we don't leave the serial device open */ switch (new_state) { case NM_DEVICE_STATE_NEED_AUTH: - if (NM_MODEM_GET_PRIVATE (self)->ppp_manager) + if (priv->ppp_manager) break; /* else fall through */ case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: case NM_DEVICE_STATE_FAILED: case NM_DEVICE_STATE_DISCONNECTED: + if (new_state != NM_DEVICE_STATE_NEED_AUTH) { + if (priv->act_request) { + cancel_get_secrets (self); + g_object_unref (priv->act_request); + priv->act_request = NULL; + } + } + if (was_connected) { dbus_g_proxy_begin_call (nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM), "Disconnect", @@ -1022,6 +1050,9 @@ finalize (GObject *object) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); + if (priv->act_request) + g_object_unref (priv->act_request); + if (priv->proxy) g_object_unref (priv->proxy); @@ -1134,15 +1165,23 @@ nm_modem_class_init (NMModemClass *klass) _nm_marshal_VOID__BOOLEAN_UINT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_UINT); - signals[NEED_AUTH] = - g_signal_new (NM_MODEM_NEED_AUTH, + signals[AUTH_REQUESTED] = + g_signal_new (NM_MODEM_AUTH_REQUESTED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemClass, need_auth), + G_STRUCT_OFFSET (NMModemClass, auth_requested), NULL, NULL, - _nm_marshal_VOID__STRING_BOOLEAN_UINT_STRING_STRING, - G_TYPE_NONE, 5, - G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING); + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[AUTH_RESULT] = + g_signal_new (NM_MODEM_AUTH_RESULT, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, auth_result), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); } const DBusGObjectInfo * diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h index a2aed57e00..f4f7be7985 100644 --- a/src/modem-manager/nm-modem.h +++ b/src/modem-manager/nm-modem.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009 - 2010 Red Hat, Inc. * Copyright (C) 2009 Novell, Inc. */ @@ -46,7 +46,8 @@ G_BEGIN_DECLS #define NM_MODEM_PPP_FAILED "ppp-failed" #define NM_MODEM_PREPARE_RESULT "prepare-result" #define NM_MODEM_IP4_CONFIG_RESULT "ip4-config-result" -#define NM_MODEM_NEED_AUTH "need-auth" +#define NM_MODEM_AUTH_REQUESTED "auth-requested" +#define NM_MODEM_AUTH_RESULT "auth-result" typedef struct { GObject parent; @@ -66,6 +67,11 @@ typedef struct { NMConnection *connection, GError **error); + gboolean (*complete_connection) (NMModem *modem, + NMConnection *connection, + const GSList *existing_connections, + GError **error); + NMConnection * (*get_best_auto_connection) (NMModem *modem, GSList *connections, char **specific_object); @@ -85,12 +91,8 @@ typedef struct { void (*prepare_result) (NMModem *self, gboolean success, NMDeviceStateReason reason); void (*ip4_config_result) (NMModem *self, const char *iface, NMIP4Config *config, GError *error); - void (*need_auth) (NMModem *self, - const char *setting_name, - gboolean retry, - RequestSecretsCaller caller, - const char *hint1, - const char *hint2); + void (*auth_requested) (NMModem *self); + void (*auth_result) (NMModem *self, GError *error); } NMModemClass; GType nm_modem_get_type (void); @@ -110,6 +112,11 @@ gboolean nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection, GError **error); +gboolean nm_modem_complete_connection (NMModem *self, + NMConnection *connection, + const GSList *existing_connections, + GError **error); + NMActStageReturn nm_modem_act_stage1_prepare (NMModem *modem, NMActRequest *req, NMDeviceStateReason *reason); @@ -129,6 +136,11 @@ NMActStageReturn nm_modem_stage4_get_ip4_config (NMModem *modem, NMIP4Config **config, NMDeviceStateReason *reason); +gboolean nm_modem_get_secrets (NMModem *modem, + const char *setting_name, + gboolean request_new, + const char *hint); + void nm_modem_deactivate_quickly (NMModem *modem, NMDevice *device); void nm_modem_device_state_changed (NMModem *modem, @@ -140,12 +152,6 @@ gboolean nm_modem_hw_is_up (NMModem *modem, NMDevice *device); gboolean nm_modem_hw_bring_up (NMModem *modem, NMDevice *device, gboolean *no_firmware); -gboolean nm_modem_connection_secrets_updated (NMModem *modem, - NMActRequest *req, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller); - const DBusGObjectInfo *nm_modem_get_serial_dbus_info (void); gboolean nm_modem_get_mm_enabled (NMModem *self); diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 7d13140145..6a36975a83 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2010 Red Hat, Inc. + * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ @@ -36,24 +36,19 @@ #include "nm-active-connection.h" #include "nm-dbus-glib-types.h" #include "nm-active-connection-glue.h" +#include "nm-settings-connection.h" -static void secrets_provider_interface_init (NMSecretsProviderInterface *sp_interface_class); +G_DEFINE_TYPE (NMActRequest, nm_act_request, G_TYPE_OBJECT) -G_DEFINE_TYPE_EXTENDED (NMActRequest, nm_act_request, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SECRETS_PROVIDER_INTERFACE, - secrets_provider_interface_init)) - -#define NM_ACT_REQUEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ACT_REQUEST, NMActRequestPrivate)) +#define NM_ACT_REQUEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_ACT_REQUEST, \ + NMActRequestPrivate)) enum { - CONNECTION_SECRETS_UPDATED, - CONNECTION_SECRETS_FAILED, PROPERTIES_CHANGED, - LAST_SIGNAL }; - static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { @@ -65,11 +60,13 @@ typedef struct { gboolean disposed; NMConnection *connection; - guint32 secrets_call_id; + + GSList *secrets_calls; char *specific_object; NMDevice *device; gboolean user_requested; + gulong user_uid; NMActiveConnectionState state; gboolean is_default; @@ -84,7 +81,6 @@ typedef struct { enum { PROP_0, - PROP_SERVICE_NAME, PROP_CONNECTION, PROP_SPECIFIC_OBJECT, PROP_DEVICES, @@ -96,358 +92,101 @@ enum { LAST_PROP }; +/*******************************************************************/ + +typedef struct { + NMActRequest *self; + guint32 call_id; + NMActRequestSecretsFunc callback; + gpointer callback_data; +} GetSecretsInfo; static void -device_state_changed (NMDevice *device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) +get_secrets_cb (NMSettingsConnection *connection, + guint32 call_id, + const char *setting_name, + GError *error, + gpointer user_data) { - NMActRequest *self = NM_ACT_REQUEST (user_data); - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); - NMActiveConnectionState new_ac_state; - gboolean new_default = FALSE, new_default6 = FALSE; + GetSecretsInfo *info = user_data; + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (info->self); - /* Set NMActiveConnection state based on the device's state */ - switch (new_state) { - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_CONFIG: - case NM_DEVICE_STATE_NEED_AUTH: - case NM_DEVICE_STATE_IP_CONFIG: - new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATING; - break; - case NM_DEVICE_STATE_ACTIVATED: - new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED; - new_default = priv->is_default; - new_default6 = priv->is_default6; - break; - default: - new_ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; - break; - } + g_return_if_fail (info->call_id == call_id); + priv->secrets_calls = g_slist_remove (priv->secrets_calls, info); - if (new_ac_state != priv->state) { - priv->state = new_ac_state; - g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE); - } - - if (new_default != priv->is_default) { - priv->is_default = new_default; - g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT); - } - - if (new_default6 != priv->is_default6) { - priv->is_default6 = new_default6; - g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT6); - } + info->callback (info->self, call_id, NM_CONNECTION (connection), error, info->callback_data); + g_free (info); } -NMActRequest * -nm_act_request_new (NMConnection *connection, - const char *specific_object, - gboolean user_requested, - gboolean assumed, - gpointer *device) -{ - GObject *object; - NMActRequestPrivate *priv; - - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_DEVICE (device), NULL); - - object = g_object_new (NM_TYPE_ACT_REQUEST, NULL); - if (!object) - return NULL; - - priv = NM_ACT_REQUEST_GET_PRIVATE (object); - - priv->connection = g_object_ref (connection); - if (specific_object) - priv->specific_object = g_strdup (specific_object); - - priv->device = NM_DEVICE (device); - g_signal_connect (device, "state-changed", - G_CALLBACK (device_state_changed), - NM_ACT_REQUEST (object)); - - priv->user_requested = user_requested; - priv->assumed = assumed; - - return NM_ACT_REQUEST (object); -} - -static void -nm_act_request_init (NMActRequest *req) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req); - NMDBusManager *dbus_mgr; - - priv->ac_path = nm_active_connection_get_next_object_path (); - priv->state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; - - dbus_mgr = nm_dbus_manager_get (); - dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (dbus_mgr), - priv->ac_path, - G_OBJECT (req)); - g_object_unref (dbus_mgr); -} - -static void -dispose (GObject *object) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); - - if (priv->disposed) { - G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object); - return; - } - priv->disposed = TRUE; - - g_assert (priv->connection); - - g_signal_handlers_disconnect_by_func (G_OBJECT (priv->device), - G_CALLBACK (device_state_changed), - NM_ACT_REQUEST (object)); - - /* Clear any share rules */ - nm_act_request_set_shared (NM_ACT_REQUEST (object), FALSE); - - g_object_unref (priv->connection); - - G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object); -} - -static void -clear_share_rules (NMActRequest *req) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req); - GSList *iter; - - for (iter = priv->share_rules; iter; iter = g_slist_next (iter)) { - ShareRule *rule = (ShareRule *) iter->data; - - g_free (rule->table); - g_free (rule->rule); - g_free (rule); - } - - g_slist_free (priv->share_rules); - priv->share_rules = NULL; -} - -static void -finalize (GObject *object) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); - - g_free (priv->specific_object); - g_free (priv->ac_path); - - clear_share_rules (NM_ACT_REQUEST (object)); - - G_OBJECT_CLASS (nm_act_request_parent_class)->finalize (object); -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); - GPtrArray *devices; - - switch (prop_id) { - case PROP_SERVICE_NAME: - nm_active_connection_scope_to_value (priv->connection, value); - break; - case PROP_CONNECTION: - g_value_set_boxed (value, nm_connection_get_path (priv->connection)); - break; - case PROP_SPECIFIC_OBJECT: - if (priv->specific_object) - g_value_set_boxed (value, priv->specific_object); - else - g_value_set_boxed (value, "/"); - break; - case PROP_DEVICES: - devices = g_ptr_array_sized_new (1); - g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device))); - g_value_take_boxed (value, devices); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_DEFAULT: - g_value_set_boolean (value, priv->is_default); - break; - case PROP_DEFAULT6: - g_value_set_boolean (value, priv->is_default6); - break; - case PROP_VPN: - g_value_set_boolean (value, FALSE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -nm_act_request_class_init (NMActRequestClass *req_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (req_class); - - g_type_class_add_private (req_class, sizeof (NMActRequestPrivate)); - - /* virtual methods */ - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - /* properties */ - nm_active_connection_install_properties (object_class, - PROP_SERVICE_NAME, - PROP_CONNECTION, - PROP_SPECIFIC_OBJECT, - PROP_DEVICES, - PROP_STATE, - PROP_DEFAULT, - PROP_DEFAULT6, - PROP_VPN); - - /* Signals */ - signals[CONNECTION_SECRETS_UPDATED] = - g_signal_new ("connection-secrets-updated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMActRequestClass, secrets_updated), - NULL, NULL, - _nm_marshal_VOID__OBJECT_POINTER_UINT, - G_TYPE_NONE, 3, - G_TYPE_OBJECT, G_TYPE_POINTER, G_TYPE_UINT); - - signals[CONNECTION_SECRETS_FAILED] = - g_signal_new ("connection-secrets-failed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMActRequestClass, secrets_failed), - NULL, NULL, - _nm_marshal_VOID__OBJECT_STRING_UINT, - G_TYPE_NONE, 3, - G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_UINT); - - signals[PROPERTIES_CHANGED] = - nm_properties_changed_signal_new (object_class, - G_STRUCT_OFFSET (NMActRequestClass, properties_changed)); - - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (req_class), - &dbus_glib_nm_active_connection_object_info); -} - -static gboolean -secrets_update_setting (NMSecretsProviderInterface *interface, - const char *setting_name, - GHashTable *new) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (interface); - NMSetting *setting = NULL; - GError *error = NULL; - GType type; - - g_return_val_if_fail (priv->connection != NULL, FALSE); - - /* Check whether a complete & valid NMSetting object was returned. If - * yes, replace the setting object in the connection. If not, just try - * updating the secrets. - */ - type = nm_connection_lookup_setting_type (setting_name); - if (type == 0) - return FALSE; - - setting = nm_setting_new_from_hash (type, new); - if (setting) { - NMSetting *s_8021x = NULL; - GSList *all_settings = NULL; - - /* The wireless-security setting might need the 802.1x setting in - * the all_settings argument of the verify function. Ugh. - */ - s_8021x = nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_802_1X); - if (s_8021x) - all_settings = g_slist_append (all_settings, s_8021x); - - if (!nm_setting_verify (setting, all_settings, NULL)) { - /* Just try updating secrets */ - g_object_unref (setting); - setting = NULL; - } - - g_slist_free (all_settings); - } - - if (setting) - nm_connection_add_setting (priv->connection, setting); - else { - if (!nm_connection_update_secrets (priv->connection, setting_name, new, &error)) { - nm_log_warn (LOGD_DEVICE, "Failed to update connection secrets: %d %s", - error ? error->code : -1, - error && error->message ? error->message : "(none)"); - g_clear_error (&error); - } - } - - return TRUE; -} - -static void -secrets_result (NMSecretsProviderInterface *interface, - const char *setting_name, - RequestSecretsCaller caller, - const GSList *updated, - GError *error) -{ - NMActRequest *self = NM_ACT_REQUEST (interface); - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); - - g_return_if_fail (priv->connection != NULL); - - if (error) { - g_signal_emit (self, signals[CONNECTION_SECRETS_FAILED], 0, - priv->connection, setting_name, caller); - } else { - g_signal_emit (self, signals[CONNECTION_SECRETS_UPDATED], 0, - priv->connection, updated, caller); - } -} - -static void -secrets_provider_interface_init (NMSecretsProviderInterface *sp_interface_class) -{ - /* interface implementation */ - sp_interface_class->update_setting = secrets_update_setting; - sp_interface_class->result = secrets_result; -} - -gboolean +guint32 nm_act_request_get_secrets (NMActRequest *self, const char *setting_name, - gboolean request_new, - RequestSecretsCaller caller, - const char *hint1, - const char *hint2) + guint32 flags, + const char *hint, + NMActRequestSecretsFunc callback, + gpointer callback_data) { - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (NM_IS_ACT_REQUEST (self), FALSE); + NMActRequestPrivate *priv; + GetSecretsInfo *info; + guint32 call_id; - return nm_secrets_provider_interface_get_secrets (NM_SECRETS_PROVIDER_INTERFACE (self), - nm_act_request_get_connection (self), - setting_name, - request_new, - caller, - hint1, - hint2); + g_return_val_if_fail (self, 0); + g_return_val_if_fail (NM_IS_ACT_REQUEST (self), 0); + + priv = NM_ACT_REQUEST_GET_PRIVATE (self); + + info = g_malloc0 (sizeof (GetSecretsInfo)); + info->self = self; + info->callback = callback; + info->callback_data = callback_data; + + call_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (priv->connection), + priv->user_requested, + priv->user_uid, + setting_name, + flags, + hint, + get_secrets_cb, + info, + NULL); + if (call_id > 0) { + info->call_id = call_id; + priv->secrets_calls = g_slist_append (priv->secrets_calls, info); + } else + g_free (info); + + return call_id; } +void +nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id) +{ + NMActRequestPrivate *priv; + GSList *iter; + + g_return_if_fail (self); + g_return_if_fail (NM_IS_ACT_REQUEST (self)); + g_return_if_fail (call_id > 0); + + priv = NM_ACT_REQUEST_GET_PRIVATE (self); + + for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) { + GetSecretsInfo *info = iter->data; + + /* Remove the matching info */ + if (info->call_id == call_id) { + priv->secrets_calls = g_slist_remove_link (priv->secrets_calls, iter); + g_slist_free (iter); + + nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), call_id); + g_free (info); + break; + } + } +} + +/*******************************************************************/ + NMConnection * nm_act_request_get_connection (NMActRequest *req) { @@ -542,6 +281,42 @@ nm_act_request_get_default6 (NMActRequest *req) return NM_ACT_REQUEST_GET_PRIVATE (req)->is_default6; } +GObject * +nm_act_request_get_device (NMActRequest *req) +{ + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + + return G_OBJECT (NM_ACT_REQUEST_GET_PRIVATE (req)->device); +} + +gboolean +nm_act_request_get_assumed (NMActRequest *req) +{ + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + + return NM_ACT_REQUEST_GET_PRIVATE (req)->assumed; +} + +/********************************************************************/ + +static void +clear_share_rules (NMActRequest *req) +{ + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req); + GSList *iter; + + for (iter = priv->share_rules; iter; iter = g_slist_next (iter)) { + ShareRule *rule = (ShareRule *) iter->data; + + g_free (rule->table); + g_free (rule->rule); + g_free (rule); + } + + g_slist_free (priv->share_rules); + priv->share_rules = NULL; +} + static void share_child_setup (gpointer user_data G_GNUC_UNUSED) { @@ -628,26 +403,230 @@ nm_act_request_add_share_rule (NMActRequest *req, g_return_if_fail (NM_IS_ACT_REQUEST (req)); g_return_if_fail (table != NULL); g_return_if_fail (table_rule != NULL); - + rule = g_malloc0 (sizeof (ShareRule)); rule->table = g_strdup (table); rule->rule = g_strdup (table_rule); priv->share_rules = g_slist_append (priv->share_rules, rule); } -GObject * -nm_act_request_get_device (NMActRequest *req) -{ - g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); +/********************************************************************/ - return G_OBJECT (NM_ACT_REQUEST_GET_PRIVATE (req)->device); +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMActRequest *self = NM_ACT_REQUEST (user_data); + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); + NMActiveConnectionState new_ac_state; + gboolean new_default = FALSE, new_default6 = FALSE; + + /* Set NMActiveConnection state based on the device's state */ + switch (new_state) { + case NM_DEVICE_STATE_PREPARE: + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_NEED_AUTH: + case NM_DEVICE_STATE_IP_CONFIG: + new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATING; + break; + case NM_DEVICE_STATE_ACTIVATED: + new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED; + new_default = priv->is_default; + new_default6 = priv->is_default6; + break; + default: + new_ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; + break; + } + + if (new_ac_state != priv->state) { + priv->state = new_ac_state; + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE); + } + + if (new_default != priv->is_default) { + priv->is_default = new_default; + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT); + } + + if (new_default6 != priv->is_default6) { + priv->is_default6 = new_default6; + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT6); + } } -gboolean -nm_act_request_get_assumed (NMActRequest *req) -{ - g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); +/********************************************************************/ - return NM_ACT_REQUEST_GET_PRIVATE (req)->assumed; +NMActRequest * +nm_act_request_new (NMConnection *connection, + const char *specific_object, + gboolean user_requested, + gulong user_uid, + gboolean assumed, + gpointer *device) +{ + GObject *object; + NMActRequestPrivate *priv; + + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (NM_DEVICE (device), NULL); + + object = g_object_new (NM_TYPE_ACT_REQUEST, NULL); + if (!object) + return NULL; + + priv = NM_ACT_REQUEST_GET_PRIVATE (object); + + priv->connection = g_object_ref (connection); + if (specific_object) + priv->specific_object = g_strdup (specific_object); + + priv->device = NM_DEVICE (device); + g_signal_connect (device, "state-changed", + G_CALLBACK (device_state_changed), + NM_ACT_REQUEST (object)); + + priv->user_uid = user_uid; + priv->user_requested = user_requested; + priv->assumed = assumed; + + return NM_ACT_REQUEST (object); +} + +static void +nm_act_request_init (NMActRequest *req) +{ + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req); + NMDBusManager *dbus_mgr; + + priv->ac_path = nm_active_connection_get_next_object_path (); + priv->state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; + + dbus_mgr = nm_dbus_manager_get (); + dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (dbus_mgr), + priv->ac_path, + G_OBJECT (req)); + g_object_unref (dbus_mgr); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); + GPtrArray *devices; + + switch (prop_id) { + case PROP_CONNECTION: + g_value_set_boxed (value, nm_connection_get_path (priv->connection)); + break; + case PROP_SPECIFIC_OBJECT: + if (priv->specific_object) + g_value_set_boxed (value, priv->specific_object); + else + g_value_set_boxed (value, "/"); + break; + case PROP_DEVICES: + devices = g_ptr_array_sized_new (1); + g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device))); + g_value_take_boxed (value, devices); + break; + case PROP_STATE: + g_value_set_uint (value, priv->state); + break; + case PROP_DEFAULT: + g_value_set_boolean (value, priv->is_default); + break; + case PROP_DEFAULT6: + g_value_set_boolean (value, priv->is_default6); + break; + case PROP_VPN: + g_value_set_boolean (value, FALSE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); + GSList *iter; + + if (priv->disposed) { + G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object); + return; + } + priv->disposed = TRUE; + + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->device), + G_CALLBACK (device_state_changed), + NM_ACT_REQUEST (object)); + + /* Clear any share rules */ + nm_act_request_set_shared (NM_ACT_REQUEST (object), FALSE); + + /* Kill any in-progress secrets requests */ + g_assert (priv->connection); + for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) { + GetSecretsInfo *info = iter->data; + + nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), info->call_id); + g_free (info); + } + g_slist_free (priv->secrets_calls); + + g_object_unref (priv->connection); + + G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); + + g_free (priv->specific_object); + g_free (priv->ac_path); + + clear_share_rules (NM_ACT_REQUEST (object)); + + G_OBJECT_CLASS (nm_act_request_parent_class)->finalize (object); +} + +static void +nm_act_request_class_init (NMActRequestClass *req_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (req_class); + + g_type_class_add_private (req_class, sizeof (NMActRequestPrivate)); + + /* virtual methods */ + object_class->get_property = get_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + /* properties */ + nm_active_connection_install_properties (object_class, + PROP_CONNECTION, + PROP_SPECIFIC_OBJECT, + PROP_DEVICES, + PROP_STATE, + PROP_DEFAULT, + PROP_DEFAULT6, + PROP_VPN); + + /* Signals */ + signals[PROPERTIES_CHANGED] = + nm_properties_changed_signal_new (object_class, + G_STRUCT_OFFSET (NMActRequestClass, properties_changed)); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (req_class), + &dbus_glib_nm_active_connection_object_info); } diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index a243694521..61456cc655 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -25,7 +25,6 @@ #include #include "nm-connection.h" #include "nm-active-connection.h" -#include "nm-secrets-provider-interface.h" #define NM_TYPE_ACT_REQUEST (nm_act_request_get_type ()) #define NM_ACT_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACT_REQUEST, NMActRequest)) @@ -42,15 +41,6 @@ typedef struct { GObjectClass parent; /* Signals */ - void (*secrets_updated) (NMActRequest *req, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller); - void (*secrets_failed) (NMActRequest *req, - NMConnection *connection, - const char *setting, - RequestSecretsCaller caller); - void (*properties_changed) (NMActRequest *req, GHashTable *properties); } NMActRequestClass; @@ -59,6 +49,7 @@ GType nm_act_request_get_type (void); NMActRequest *nm_act_request_new (NMConnection *connection, const char *specific_object, gboolean user_requested, + gulong user_uid, gboolean assumed, gpointer *device); /* An NMDevice */ @@ -92,12 +83,31 @@ GObject * nm_act_request_get_device (NMActRequest *req); gboolean nm_act_request_get_assumed (NMActRequest *req); -gboolean nm_act_request_get_secrets (NMActRequest *req, - const char *setting_name, - gboolean request_new, - RequestSecretsCaller caller, - const char *hint1, - const char *hint2); +/* Secrets handling */ + +typedef void (*NMActRequestSecretsFunc) (NMActRequest *req, + guint32 call_id, + NMConnection *connection, + GError *error, + gpointer user_data); + +/* NOTE: these values should match the NM_SECRET_AGENT_GET_SECRETS_FLAGS in + * the nm-secret-agent.xml introspection file. + */ +enum { + NM_ACT_REQUEST_GET_SECRETS_FLAG_NONE = 0x0, + NM_ACT_REQUEST_GET_SECRETS_FLAG_ALLOW_INTERACTION = 0x1, + NM_ACT_REQUEST_GET_SECRETS_FLAG_REQUEST_NEW = 0x2 +}; + +guint32 nm_act_request_get_secrets (NMActRequest *req, + const char *setting_name, + guint32 flags, + const char *hint, + NMActRequestSecretsFunc callback, + gpointer callback_data); + +void nm_act_request_cancel_secrets (NMActRequest *req, guint32 call_id); #endif /* NM_ACTIVATION_REQUEST_H */ diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 90495bd2c1..859d2cde78 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -32,30 +32,8 @@ nm_active_connection_get_next_object_path (void) return g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++); } -void -nm_active_connection_scope_to_value (NMConnection *connection, GValue *value) -{ - if (!connection) { - g_value_set_string (value, ""); - return; - } - - switch (nm_connection_get_scope (connection)) { - case NM_CONNECTION_SCOPE_SYSTEM: - g_value_set_string (value, NM_DBUS_SERVICE_SYSTEM_SETTINGS); - break; - case NM_CONNECTION_SCOPE_USER: - g_value_set_string (value, NM_DBUS_SERVICE_USER_SETTINGS); - break; - default: - nm_log_err (LOGD_CORE, "unknown connection scope!"); - break; - } -} - void nm_active_connection_install_properties (GObjectClass *object_class, - guint prop_service_name, guint prop_connection, guint prop_specific_object, guint prop_devices, @@ -64,13 +42,6 @@ nm_active_connection_install_properties (GObjectClass *object_class, guint prop_default6, guint prop_vpn) { - g_object_class_install_property (object_class, prop_service_name, - g_param_spec_string (NM_ACTIVE_CONNECTION_SERVICE_NAME, - "Service name", - "Service name", - NULL, - G_PARAM_READABLE)); - g_object_class_install_property (object_class, prop_connection, g_param_spec_boxed (NM_ACTIVE_CONNECTION_CONNECTION, "Connection", diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 5dde308753..d39fcbd757 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -24,7 +24,6 @@ #include #include "nm-connection.h" -#define NM_ACTIVE_CONNECTION_SERVICE_NAME "service-name" #define NM_ACTIVE_CONNECTION_CONNECTION "connection" #define NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT "specific-object" #define NM_ACTIVE_CONNECTION_DEVICES "devices" @@ -35,10 +34,7 @@ char *nm_active_connection_get_next_object_path (void); -void nm_active_connection_scope_to_value (NMConnection *connection, GValue *value); - void nm_active_connection_install_properties (GObjectClass *object_class, - guint prop_service_name, guint prop_connection, guint prop_specific_object, guint prop_devices, diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c index 9b621b42ba..8552f559e9 100644 --- a/src/nm-dbus-manager.c +++ b/src/nm-dbus-manager.c @@ -105,7 +105,7 @@ nm_dbus_manager_class_init (NMDBusManagerClass *klass) object_class->dispose = nm_dbus_manager_dispose; signals[DBUS_CONNECTION_CHANGED] = - g_signal_new ("dbus-connection-changed", + g_signal_new (NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMDBusManagerClass, dbus_connection_changed), @@ -113,7 +113,7 @@ nm_dbus_manager_class_init (NMDBusManagerClass *klass) G_TYPE_NONE, 1, G_TYPE_POINTER); signals[NAME_OWNER_CHANGED] = - g_signal_new ("name-owner-changed", + g_signal_new (NM_DBUS_MANAGER_NAME_OWNER_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMDBusManagerClass, name_owner_changed), @@ -339,24 +339,6 @@ nm_dbus_manager_start_service (NMDBusManager *self) return FALSE; } - if (!dbus_g_proxy_call (priv->proxy, "RequestName", &err, - G_TYPE_STRING, NM_DBUS_SERVICE_SYSTEM_SETTINGS, - G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE, - G_TYPE_INVALID, - G_TYPE_UINT, &result, - G_TYPE_INVALID)) { - nm_log_warn (LOGD_CORE, "Could not acquire the NetworkManagerSystemSettings service.\n" - " Message: '%s'", err->message); - g_error_free (err); - return FALSE; - } - - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - nm_log_warn (LOGD_CORE, "Could not acquire the NetworkManagerSystemSettings service " - "as it is already taken."); - return FALSE; - } - priv->started = TRUE; return priv->started; } diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h index 275ae4e092..3c4d283d90 100644 --- a/src/nm-dbus-manager.h +++ b/src/nm-dbus-manager.h @@ -40,6 +40,9 @@ typedef gboolean (* NMDBusSignalHandlerFunc) (DBusConnection * connection, #define NM_IS_DBUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_DBUS_MANAGER)) #define NM_DBUS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_DBUS_MANAGER, NMDBusManagerClass)) +#define NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED "dbus-connection-changed" +#define NM_DBUS_MANAGER_NAME_OWNER_CHANGED "name-owner-changed" + typedef struct { GObject parent; } NMDBusManager; diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c index 3ef08de8b6..8c8545b4bd 100644 --- a/src/nm-device-bt.c +++ b/src/nm-device-bt.c @@ -15,12 +15,15 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2011 Red Hat, Inc. */ #include #include #include +#include + +#include #include "nm-glib-compat.h" #include "nm-bluez-common.h" @@ -36,6 +39,8 @@ #include "nm-setting-bluetooth.h" #include "nm-setting-cdma.h" #include "nm-setting-gsm.h" +#include "nm-setting-serial.h" +#include "nm-setting-ppp.h" #include "nm-device-bt-glue.h" #include "NetworkManagerUtils.h" @@ -46,6 +51,8 @@ G_DEFINE_TYPE (NMDeviceBt, nm_device_bt, NM_TYPE_DEVICE) #define NM_DEVICE_BT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_BT, NMDeviceBtPrivate)) +static gboolean modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason); + typedef struct { char *bdaddr; char *name; @@ -248,6 +255,156 @@ real_check_connection_compatible (NMDevice *device, return addr_match; } +static gboolean +real_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + NMSettingBluetooth *s_bt; + const GByteArray *setting_bdaddr; + struct ether_addr *devaddr = ether_aton (priv->bdaddr); + const char *ctype; + gboolean is_dun = FALSE, is_pan = FALSE; + NMSettingGsm *s_gsm; + NMSettingCdma *s_cdma; + NMSettingSerial *s_serial; + NMSettingPPP *s_ppp; + const char *format = NULL, *preferred = NULL; + + s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM); + s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA); + s_serial = (NMSettingSerial *) nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL); + s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP); + + s_bt = (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH); + if (!s_bt) { + s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new (); + nm_connection_add_setting (connection, NM_SETTING (s_bt)); + } + + ctype = nm_setting_bluetooth_get_connection_type (s_bt); + if (ctype) { + if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_DUN)) + is_dun = TRUE; + else if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_PANU)) + is_pan = TRUE; + } else { + if (s_gsm || s_cdma) + is_dun = TRUE; + else if (priv->capabilities & NM_BT_CAPABILITY_NAP) + is_pan = TRUE; + } + + if (is_pan) { + /* Make sure the device supports PAN */ + if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "PAN required but Bluetooth device does not support NAP"); + return FALSE; + } + + /* PAN can't use any DUN-related settings */ + if (s_gsm || s_cdma || s_serial) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "PAN incompatible with GSM, CDMA, or serial settings"); + return FALSE; + } + + g_object_set (G_OBJECT (s_bt), + NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU, + NULL); + + format = _("PAN connection %d"); + } else if (is_dun) { + /* Make sure the device supports PAN */ + if (!(priv->capabilities & NM_BT_CAPABILITY_DUN)) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "DUN required but Bluetooth device does not support DUN"); + return FALSE; + } + + /* Need at least a GSM or a CDMA setting */ + if (!s_gsm && !s_cdma) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "Setting requires DUN but no GSM or CDMA setting is present"); + return FALSE; + } + + g_object_set (G_OBJECT (s_bt), + NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_DUN, + NULL); + + if (s_gsm) { + format = _("GSM connection %d"); + if (!nm_setting_gsm_get_number (s_gsm)) + g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL); + } else if (s_cdma) { + format = _("CDMA connection %d"); + if (!nm_setting_cdma_get_number (s_cdma)) + g_object_set (G_OBJECT (s_cdma), NM_SETTING_GSM_NUMBER, "#777", NULL); + } else + format = _("DUN connection %d"); + + /* Need serial and PPP settings */ + if (!s_serial) { + s_serial = (NMSettingSerial *) nm_setting_serial_new (); + nm_connection_add_setting (connection, NM_SETTING (s_serial)); + } + if (!s_ppp) { + s_ppp = (NMSettingPPP *) nm_setting_ppp_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ppp)); + } + } else { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "Unknown/unhandled Bluetooth connection type"); + return FALSE; + } + + nm_utils_complete_generic (connection, + NM_SETTING_BLUETOOTH_SETTING_NAME, + existing_connections, + format, + preferred); + + setting_bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); + if (setting_bdaddr) { + /* Make sure the setting BT Address (if any) matches the device's */ + if (memcmp (setting_bdaddr->data, devaddr->ether_addr_octet, ETH_ALEN)) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + NM_SETTING_BLUETOOTH_BDADDR); + return FALSE; + } + } else { + GByteArray *bdaddr; + const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + /* Lock the connection to this device by default */ + if (memcmp (devaddr->ether_addr_octet, null_mac, ETH_ALEN)) { + bdaddr = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (bdaddr, devaddr->ether_addr_octet, ETH_ALEN); + g_object_set (G_OBJECT (s_bt), NM_SETTING_BLUETOOTH_BDADDR, bdaddr, NULL); + g_byte_array_free (bdaddr, TRUE); + } + } + + return TRUE; +} + static guint32 real_get_generic_capabilities (NMDevice *dev) { @@ -291,22 +448,30 @@ ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) } static void -modem_need_auth (NMModem *modem, - const char *setting_name, - gboolean retry, - RequestSecretsCaller caller, - const char *hint1, - const char *hint2, - gpointer user_data) +modem_auth_requested (NMModem *modem, gpointer user_data) { - NMDeviceBt *self = NM_DEVICE_BT (user_data); - NMActRequest *req; + nm_device_state_changed (NM_DEVICE (user_data), + NM_DEVICE_STATE_NEED_AUTH, + NM_DEVICE_STATE_REASON_NONE); +} - req = nm_device_get_act_request (NM_DEVICE (self)); - g_assert (req); +static void +modem_auth_result (NMModem *modem, GError *error, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); - nm_act_request_get_secrets (req, setting_name, retry, caller, hint1, hint2); + if (error) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + } else { + /* Otherwise, on success for GSM/CDMA secrets we need to schedule modem stage1 again */ + g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); + if (!modem_stage1 (NM_DEVICE_BT (device), priv->modem, &reason)) + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + } } static void @@ -412,41 +577,6 @@ modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason) return FALSE; } -static void -real_connection_secrets_updated (NMDevice *device, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller) -{ - NMDeviceBt *self = NM_DEVICE_BT (device); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - NMActRequest *req; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - - g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (device))); - - req = nm_device_get_act_request (device); - g_assert (req); - - if (!nm_modem_connection_secrets_updated (priv->modem, - req, - connection, - updated_settings, - caller)) { - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - /* PPP handles stuff itself... */ - if (caller == SECRETS_CALLER_PPP) - return; - - /* Otherwise, on success for GSM/CDMA secrets we need to schedule modem stage1 again */ - g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); - if (!modem_stage1 (self, priv->modem, &reason)) - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, reason); -} - /*****************************************************************************/ gboolean @@ -511,7 +641,8 @@ nm_device_bt_modem_added (NMDeviceBt *self, g_signal_connect (modem, NM_MODEM_PPP_FAILED, G_CALLBACK (ppp_failed), self); g_signal_connect (modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK (modem_prepare_result), self); g_signal_connect (modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK (modem_ip4_config_result), self); - g_signal_connect (modem, NM_MODEM_NEED_AUTH, G_CALLBACK (modem_need_auth), self); + g_signal_connect (modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self); + g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); /* Kick off the modem connection */ if (!modem_stage1 (self, modem, &reason)) @@ -1019,12 +1150,12 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) device_class->get_best_auto_connection = real_get_best_auto_connection; device_class->get_generic_capabilities = real_get_generic_capabilities; - device_class->connection_secrets_updated = real_connection_secrets_updated; device_class->deactivate_quickly = real_deactivate_quickly; device_class->act_stage2_config = real_act_stage2_config; device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start; device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; device_class->check_connection_compatible = real_check_connection_compatible; + device_class->complete_connection = real_complete_connection; /* Properties */ g_object_class_install_property diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index 0613c9edfb..079d9cf1fe 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2010 Red Hat, Inc. + * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -917,67 +917,6 @@ real_get_best_auto_connection (NMDevice *dev, return NULL; } -static void -real_connection_secrets_updated (NMDevice *dev, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (dev); - NMActRequest *req; - gboolean valid = FALSE; - GSList *iter; - - g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (dev))); - - /* PPPoE? */ - if (caller == SECRETS_CALLER_PPP) { - NMSettingPPPOE *s_pppoe; - - g_assert (priv->ppp_manager); - - s_pppoe = (NMSettingPPPOE *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE); - if (!s_pppoe) { - nm_ppp_manager_update_secrets (priv->ppp_manager, - nm_device_get_iface (dev), - NULL, - NULL, - "missing PPPoE setting; no secrets could be found."); - } else { - const char *pppoe_username = nm_setting_pppoe_get_username (s_pppoe); - const char *pppoe_password = nm_setting_pppoe_get_password (s_pppoe); - - nm_ppp_manager_update_secrets (priv->ppp_manager, - nm_device_get_iface (dev), - pppoe_username ? pppoe_username : "", - pppoe_password ? pppoe_password : "", - NULL); - } - return; - } - - /* Only caller could be ourselves for 802.1x */ - g_return_if_fail (caller == SECRETS_CALLER_ETHERNET); - g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH); - - for (iter = updated_settings; iter; iter = g_slist_next (iter)) { - const char *setting_name = (const char *) iter->data; - - if (!strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME)) { - valid = TRUE; - } else { - nm_log_warn (LOGD_DEVICE, "Ignoring updated secrets for setting '%s'.", - setting_name); - } - } - - req = nm_device_get_act_request (dev); - g_assert (req); - - g_return_if_fail (nm_act_request_get_connection (req) == connection); - nm_device_activate_schedule_stage1_device_prepare (dev); -} - /* FIXME: Move it to nm-device.c and then get rid of all foo_device_get_setting() all around. It's here now to keep the patch short. */ static NMSetting * @@ -1053,6 +992,28 @@ supplicant_interface_release (NMDeviceEthernet *self) } } +static void +wired_secrets_cb (NMActRequest *req, + guint32 call_id, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + NMDevice *dev = NM_DEVICE (user_data); + + g_return_if_fail (req == nm_device_get_act_request (dev)); + g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH); + g_return_if_fail (nm_act_request_get_connection (req) == connection); + + if (error) { + nm_log_warn (LOGD_ETHER, "%s", error->message); + nm_device_state_changed (dev, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + } else + nm_device_activate_schedule_stage1_device_prepare (dev); +} + static gboolean link_timeout_cb (gpointer user_data) { @@ -1095,10 +1056,10 @@ link_timeout_cb (gpointer user_data) nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); nm_act_request_get_secrets (req, setting_name, - TRUE, - SECRETS_CALLER_ETHERNET, + NM_ACT_REQUEST_GET_SECRETS_FLAG_REQUEST_NEW, NULL, - NULL); + wired_secrets_cb, + self); return FALSE; @@ -1276,18 +1237,14 @@ handle_auth_or_fail (NMDeviceEthernet *self, nm_connection_clear_secrets (connection); setting_name = nm_connection_need_secrets (connection, NULL); if (setting_name) { - gboolean get_new; + guint32 flags = NM_ACT_REQUEST_GET_SECRETS_FLAG_ALLOW_INTERACTION; /* If the caller doesn't necessarily want completely new secrets, * only ask for new secrets after the first failure. */ - get_new = new_secrets ? TRUE : (tries ? TRUE : FALSE); - nm_act_request_get_secrets (req, - setting_name, - get_new, - SECRETS_CALLER_ETHERNET, - NULL, - NULL); + if (new_secrets || tries) + flags |= NM_ACT_REQUEST_GET_SECRETS_FLAG_REQUEST_NEW; + nm_act_request_get_secrets (req, setting_name, flags, NULL, wired_secrets_cb, self); g_object_set_data (G_OBJECT (connection), WIRED_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); } else { @@ -1698,6 +1655,67 @@ real_check_connection_compatible (NMDevice *device, return TRUE; } +static gboolean +real_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); + NMSettingWired *s_wired; + NMSettingPPPOE *s_pppoe; + const GByteArray *setting_mac; + + s_pppoe = (NMSettingPPPOE *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE); + + /* We can't telepathically figure out the service name or username, so if + * those weren't given, we can't complete the connection. + */ + if (s_pppoe && !nm_setting_verify (NM_SETTING (s_pppoe), NULL, error)) + return FALSE; + + /* Default to an ethernet-only connection, but if a PPPoE setting was given + * then PPPoE should be our connection type. + */ + nm_utils_complete_generic (connection, + s_pppoe ? NM_SETTING_PPPOE_SETTING_NAME : NM_SETTING_CONNECTION_SETTING_NAME, + existing_connections, + s_pppoe ? _("PPPoE connection %d") : _("Wired connection %d"), + NULL); + + s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); + if (!s_wired) { + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + } + + setting_mac = nm_setting_wired_get_mac_address (s_wired); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (memcmp (setting_mac->data, priv->perm_hw_addr, ETH_ALEN)) { + g_set_error_literal (error, + NM_SETTING_WIRED_ERROR, + NM_SETTING_WIRED_ERROR_INVALID_PROPERTY, + NM_SETTING_WIRED_MAC_ADDRESS); + return FALSE; + } + } else { + GByteArray *mac; + const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + /* Lock the connection to this device by default */ + if (memcmp (priv->perm_hw_addr, null_mac, ETH_ALEN)) { + mac = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (mac, priv->perm_hw_addr, ETH_ALEN); + g_object_set (G_OBJECT (s_wired), NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL); + g_byte_array_free (mac, TRUE); + } + } + + return TRUE; +} + static gboolean spec_match_list (NMDevice *device, const GSList *specs) { @@ -2006,8 +2024,8 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) parent_class->update_initial_hw_address = real_update_initial_hw_address; parent_class->get_best_auto_connection = real_get_best_auto_connection; parent_class->is_available = real_is_available; - parent_class->connection_secrets_updated = real_connection_secrets_updated; parent_class->check_connection_compatible = real_check_connection_compatible; + parent_class->complete_connection = real_complete_connection; parent_class->act_stage1_prepare = real_act_stage1_prepare; parent_class->act_stage2_config = real_act_stage2_config; diff --git a/src/nm-device-modem.c b/src/nm-device-modem.c index 441f92cece..362ff8575c 100644 --- a/src/nm-device-modem.c +++ b/src/nm-device-modem.c @@ -107,22 +107,27 @@ modem_prepare_result (NMModem *modem, } static void -modem_need_auth (NMModem *modem, - const char *setting_name, - gboolean retry, - RequestSecretsCaller caller, - const char *hint1, - const char *hint2, - gpointer user_data) +modem_auth_requested (NMModem *modem, gpointer user_data) { - NMDeviceModem *self = NM_DEVICE_MODEM (user_data); - NMActRequest *req; + nm_device_state_changed (NM_DEVICE (user_data), + NM_DEVICE_STATE_NEED_AUTH, + NM_DEVICE_STATE_REASON_NONE); +} - req = nm_device_get_act_request (NM_DEVICE (self)); - g_assert (req); +static void +modem_auth_result (NMModem *modem, GError *error, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); - nm_act_request_get_secrets (req, setting_name, retry, caller, hint1, hint2); + if (error) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + } else { + /* Otherwise, on success for modem secrets we need to schedule stage1 again */ + g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); + nm_device_activate_schedule_stage1_device_prepare (device); + } } static void @@ -205,38 +210,6 @@ real_get_best_auto_connection (NMDevice *device, return nm_modem_get_best_auto_connection (priv->modem, connections, specific_object); } -static void -real_connection_secrets_updated (NMDevice *device, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); - NMActRequest *req; - - g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (device))); - - req = nm_device_get_act_request (device); - g_assert (req); - - if (!nm_modem_connection_secrets_updated (priv->modem, - req, - connection, - updated_settings, - caller)) { - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - /* PPP handles stuff itself... */ - if (caller == SECRETS_CALLER_PPP) - return; - - /* Otherwise, on success for modem secrets we need to schedule stage1 again */ - g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); - nm_device_activate_schedule_stage1_device_prepare (device); -} - static gboolean real_check_connection_compatible (NMDevice *device, NMConnection *connection, @@ -247,6 +220,18 @@ real_check_connection_compatible (NMDevice *device, return nm_modem_check_connection_compatible (priv->modem, connection, error); } +static gboolean +real_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + return nm_modem_complete_connection (priv->modem, connection, existing_connections, error); +} + static gboolean real_hw_is_up (NMDevice *device) { @@ -365,7 +350,8 @@ set_modem (NMDeviceModem *self, NMModem *modem) g_signal_connect (modem, NM_MODEM_PPP_FAILED, G_CALLBACK (ppp_failed), self); g_signal_connect (modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK (modem_prepare_result), self); g_signal_connect (modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK (modem_ip4_config_result), self); - g_signal_connect (modem, NM_MODEM_NEED_AUTH, G_CALLBACK (modem_need_auth), self); + g_signal_connect (modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self); + g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); g_signal_connect (modem, "notify::" NM_MODEM_ENABLED, G_CALLBACK (modem_enabled_cb), self); } @@ -426,8 +412,8 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) device_class->get_generic_capabilities = real_get_generic_capabilities; device_class->get_best_auto_connection = real_get_best_auto_connection; - device_class->connection_secrets_updated = real_connection_secrets_updated; device_class->check_connection_compatible = real_check_connection_compatible; + device_class->complete_connection = real_complete_connection; device_class->hw_is_up = real_hw_is_up; device_class->hw_bring_up = real_hw_bring_up; device_class->deactivate_quickly = real_deactivate_quickly; diff --git a/src/nm-device-modem.h b/src/nm-device-modem.h index c6ef4d2184..806676e5be 100644 --- a/src/nm-device-modem.h +++ b/src/nm-device-modem.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2011 Red Hat, Inc. */ #ifndef NM_DEVICE_MODEM_H diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c index 244780d6fa..36b056e8fe 100644 --- a/src/nm-device-olpc-mesh.c +++ b/src/nm-device-olpc-mesh.c @@ -19,7 +19,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2005 - 2010 Red Hat, Inc. + * (C) Copyright 2005 - 2011 Red Hat, Inc. * (C) Copyright 2008 Collabora Ltd. * (C) Copyright 2009 One Laptop per Child */ @@ -381,6 +381,50 @@ real_check_connection_compatible (NMDevice *device, return TRUE; } +#define DEFAULT_SSID "olpc-mesh" + +static gboolean +real_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingOlpcMesh *s_mesh; + GByteArray *tmp; + + s_mesh = (NMSettingOlpcMesh *) nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH); + if (!s_mesh) { + s_mesh = (NMSettingOlpcMesh *) nm_setting_olpc_mesh_new (); + nm_connection_add_setting (connection, NM_SETTING (s_mesh)); + } + + if (!nm_setting_olpc_mesh_get_ssid (s_mesh)) { + tmp = g_byte_array_sized_new (strlen (DEFAULT_SSID)); + g_byte_array_append (tmp, (const guint8 *) DEFAULT_SSID, strlen (DEFAULT_SSID)); + g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_SSID, tmp, NULL); + g_byte_array_free (tmp, TRUE); + } + + if (!nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh)) { + const guint8 anycast[ETH_ALEN] = { 0xC0, 0x27, 0xC0, 0x27, 0xC0, 0x27 }; + + tmp = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (tmp, anycast, sizeof (anycast)); + g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, tmp, NULL); + g_byte_array_free (tmp, TRUE); + + } + + nm_utils_complete_generic (connection, + NM_SETTING_OLPC_MESH_SETTING_NAME, + existing_connections, + _("Mesh %d"), + NULL); + + return TRUE; +} + /* * nm_device_olpc_mesh_get_address * @@ -652,7 +696,7 @@ dispose (GObject *object) device_cleanup (self); - manager = nm_manager_get (NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL); + manager = nm_manager_get (NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL); if (priv->device_added_id) g_signal_handler_disconnect (manager, priv->device_added_id); g_object_unref (manager); @@ -722,6 +766,7 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) parent_class->take_down = real_take_down; parent_class->update_hw_address = real_update_hw_address; parent_class->check_connection_compatible = real_check_connection_compatible; + parent_class->complete_connection = real_complete_connection; parent_class->act_stage1_prepare = real_act_stage1_prepare; parent_class->act_stage2_config = real_act_stage2_config; @@ -850,7 +895,7 @@ is_companion (NMDeviceOlpcMesh *self, NMDevice *other) priv->companion = other; /* When we've found the companion, stop listening for other devices */ - manager = nm_manager_get (NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL); + manager = nm_manager_get (NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL); if (priv->device_added_id) { g_signal_handler_disconnect (manager, priv->device_added_id); priv->device_added_id = 0; @@ -905,7 +950,7 @@ check_companion_cb (gpointer user_data) if (priv->device_added_id != 0) return FALSE; - manager = nm_manager_get (NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL); + manager = nm_manager_get (NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL); priv->device_added_id = g_signal_connect (manager, "device-added", G_CALLBACK (device_added_cb), self); diff --git a/src/nm-device-private.h b/src/nm-device-private.h index f4f968a949..a7d238b10b 100644 --- a/src/nm-device-private.h +++ b/src/nm-device-private.h @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2011 Red Hat, Inc. */ #ifndef NM_DEVICE_PRIVATE_H diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index efa46bfc76..f2ab7aff45 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2010 Red Hat, Inc. + * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -104,15 +104,6 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; -typedef enum { - NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS = 0, - NM_WIFI_ERROR_CONNECTION_INVALID, - NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, -} NMWifiError; - -#define NM_WIFI_ERROR (nm_wifi_error_quark ()) -#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ()) - #define SUP_SIG_ID_LEN 5 typedef struct Supplicant { @@ -201,6 +192,18 @@ static guint32 nm_device_wifi_get_bitrate (NMDeviceWifi *self); static void cull_scan_list (NMDeviceWifi *self); +/*****************************************************************/ + +typedef enum { + NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS = 0, + NM_WIFI_ERROR_CONNECTION_INVALID, + NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, + NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, +} NMWifiError; + +#define NM_WIFI_ERROR (nm_wifi_error_quark ()) +#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ()) + static GQuark nm_wifi_error_quark (void) { @@ -226,6 +229,8 @@ nm_wifi_error_get_type (void) ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INVALID, "ConnectionInvalid"), /* Connection does not apply to this device. */ ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"), + /* Given access point was not in this device's scan list. */ + ENUM_ENTRY (NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, "AccessPointNotFound"), { 0, 0, 0 } }; etype = g_enum_register_static ("NMWifiError", values); @@ -233,6 +238,8 @@ nm_wifi_error_get_type (void) return etype; } +/*****************************************************************/ + /* IPW rfkill handling (until 2.6.33) */ RfKillState nm_device_wifi_get_ipw_rfkill_state (NMDeviceWifi *self) @@ -291,6 +298,8 @@ ipw_rfkill_state_work (gpointer user_data) return TRUE; } +/*****************************************************************/ + /* * wireless_qual_to_percent * @@ -820,6 +829,20 @@ supplicant_interface_release (NMDeviceWifi *self) } } + +static NMAccessPoint * +get_ap_by_path (NMDeviceWifi *self, const char *path) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + GSList *iter; + + for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { + if (strcmp (path, nm_ap_get_dbus_path (NM_AP (iter->data))) == 0) + return NM_AP (iter->data); + } + return NULL; +} + static NMAccessPoint * get_active_ap (NMDeviceWifi *self, NMAccessPoint *ignore_ap, @@ -1319,6 +1342,169 @@ real_check_connection_compatible (NMDevice *device, return TRUE; } +/* + * List of manufacturer default SSIDs that are often unchanged by users. + * + * NOTE: this list should *not* contain networks that you would like to + * automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot". + */ +static const char * +manf_defaults[] = { + "linksys", + "linksys-a", + "linksys-g", + "default", + "belkin54g", + "NETGEAR", + "o2DSL", + "WLAN", + "ALICE-WLAN", +}; + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0])) + +static gboolean +is_manf_default_ssid (const GByteArray *ssid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE (manf_defaults); i++) { + if (ssid->len == strlen (manf_defaults[i])) { + if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0) + return TRUE; + } + } + return FALSE; +} + +static gboolean +real_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMDeviceWifi *self = NM_DEVICE_WIFI (device); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMSettingWireless *s_wifi; + NMSettingWirelessSecurity *s_wsec; + NMSetting8021x *s_8021x; + const GByteArray *setting_mac; + char *format, *str_ssid = NULL; + NMAccessPoint *ap = NULL; + const GByteArray *ssid = NULL; + GSList *iter; + + s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); + s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY); + s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); + + if (!specific_object) { + /* If not given a specific object, we need at minimum an SSID */ + if (!s_wifi) { + g_set_error_literal (error, + NM_WIFI_ERROR, + NM_WIFI_ERROR_CONNECTION_INVALID, + "A 'wireless' setting is required if no AP path was given."); + return FALSE; + } + + ssid = nm_setting_wireless_get_ssid (s_wifi); + if (!ssid || !ssid->len) { + g_set_error_literal (error, + NM_WIFI_ERROR, + NM_WIFI_ERROR_CONNECTION_INVALID, + "A 'wireless' setting with a valid SSID is required if no AP path was given."); + return FALSE; + } + + /* Find a compatible AP in the scan list */ + for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { + if (nm_ap_check_compatible (NM_AP (iter->data), connection)) { + ap = NM_AP (iter->data); + break; + } + } + + /* If we still don't have an AP, then the WiFI settings needs to be + * fully specified by the client. Might not be able to find an AP + * if the network isn't broadcasting the SSID for example. + */ + if (!ap) { + GSList *settings = NULL; + gboolean valid; + + settings = g_slist_prepend (settings, s_wifi); + settings = g_slist_prepend (settings, s_wsec); + settings = g_slist_prepend (settings, s_8021x); + valid = nm_setting_verify (NM_SETTING (s_wifi), settings, error); + g_slist_free (settings); + if (!valid) + return FALSE; + } + } else { + ap = get_ap_by_path (self, specific_object); + if (!ap) { + g_set_error (error, + NM_WIFI_ERROR, + NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, + "The access point %s was not in the scan list.", + specific_object); + return FALSE; + } + } + + if (ap) { + ssid = nm_ap_get_ssid (ap); + + /* If the SSID is a well-known SSID, lock the connection to the AP's + * specific BSSID so NM doesn't autoconnect to some random wifi net. + */ + if (!nm_ap_complete_connection (ap, + connection, + is_manf_default_ssid (ssid), + error)) + return FALSE; + } + + g_assert (ssid); + str_ssid = nm_utils_ssid_to_utf8 ((const char *) ssid, ssid->len); + format = g_strdup_printf ("%s %%d", str_ssid); + + nm_utils_complete_generic (connection, + NM_SETTING_WIRELESS_SETTING_NAME, + existing_connections, + format, + str_ssid); + g_free (str_ssid); + g_free (format); + + setting_mac = nm_setting_wireless_get_mac_address (s_wifi); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (memcmp (setting_mac->data, priv->perm_hw_addr, ETH_ALEN)) { + g_set_error (error, + NM_SETTING_WIRELESS_ERROR, + NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY, + NM_SETTING_WIRELESS_MAC_ADDRESS); + return FALSE; + } + } else { + GByteArray *mac; + const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + /* Lock the connection to this device by default */ + if (memcmp (priv->perm_hw_addr, null_mac, ETH_ALEN)) { + mac = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (mac, priv->perm_hw_addr, ETH_ALEN); + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MAC_ADDRESS, mac, NULL); + g_byte_array_free (mac, TRUE); + } + } + + return TRUE; +} + static gboolean real_is_available (NMDevice *dev) { @@ -2193,6 +2379,27 @@ cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect) nm_supplicant_interface_disconnect (priv->supplicant.iface); } +static void +wifi_secrets_cb (NMActRequest *req, + guint32 call_id, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + NMDevice *dev = NM_DEVICE (user_data); + + g_return_if_fail (req == nm_device_get_act_request (dev)); + g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH); + g_return_if_fail (nm_act_request_get_connection (req) == connection); + + if (error) { + nm_log_warn (LOGD_WIFI, "%s", error->message); + nm_device_state_changed (dev, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + } else + nm_device_activate_schedule_stage1_device_prepare (dev); +} static void remove_link_timeout (NMDeviceWifi *self) @@ -2289,10 +2496,10 @@ link_timeout_cb (gpointer user_data) nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); nm_act_request_get_secrets (req, setting_name, - TRUE, - SECRETS_CALLER_WIFI, + NM_ACT_REQUEST_GET_SECRETS_FLAG_REQUEST_NEW, NULL, - NULL); + wifi_secrets_cb, + self); return FALSE; } @@ -2504,6 +2711,7 @@ handle_auth_or_fail (NMDeviceWifi *self, guint32 tries; NMAccessPoint *ap; NMConnection *connection; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NM_ACT_STAGE_RETURN_FAILURE); @@ -2527,24 +2735,21 @@ handle_auth_or_fail (NMDeviceWifi *self, nm_connection_clear_secrets (connection); setting_name = nm_connection_need_secrets (connection, NULL); if (setting_name) { - gboolean get_new; + guint32 flags = NM_ACT_REQUEST_GET_SECRETS_FLAG_ALLOW_INTERACTION; /* If the caller doesn't necessarily want completely new secrets, * only ask for new secrets after the first failure. */ - get_new = new_secrets ? TRUE : (tries ? TRUE : FALSE); - nm_act_request_get_secrets (req, - setting_name, - get_new, - SECRETS_CALLER_WIFI, - NULL, - NULL); + if (new_secrets || tries) + flags |= NM_ACT_REQUEST_GET_SECRETS_FLAG_REQUEST_NEW; + nm_act_request_get_secrets (req, setting_name, flags, NULL, wifi_secrets_cb, self); g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); - } else { + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else nm_log_warn (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - } - return NM_ACT_STAGE_RETURN_POSTPONE; + + return ret; } /* @@ -2914,42 +3119,6 @@ done: return NM_ACT_STAGE_RETURN_SUCCESS; } - -static void -real_connection_secrets_updated (NMDevice *dev, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller) -{ - NMActRequest *req; - gboolean valid = FALSE; - GSList *iter; - - g_return_if_fail (caller == SECRETS_CALLER_WIFI); - - if (nm_device_get_state (dev) != NM_DEVICE_STATE_NEED_AUTH) - return; - - for (iter = updated_settings; iter; iter = g_slist_next (iter)) { - const char *setting_name = (const char *) iter->data; - - if ( !strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) - || !strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME)) { - valid = TRUE; - } else { - nm_log_warn (LOGD_DEVICE, "Ignoring updated secrets for setting '%s'.", - setting_name); - } - } - - req = nm_device_get_act_request (dev); - g_assert (req); - - g_return_if_fail (nm_act_request_get_connection (req) == connection); - - nm_device_activate_schedule_stage1_device_prepare (dev); -} - static NMActStageReturn real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) { @@ -3410,10 +3579,8 @@ device_state_changed (NMDevice *device, NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self) { - NMDeviceWifiPrivate *priv; NMActRequest *req; const char *ap_path; - GSList * elt; g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NULL); @@ -3422,18 +3589,8 @@ nm_device_wifi_get_activation_ap (NMDeviceWifi *self) return NULL; ap_path = nm_act_request_get_specific_object (req); - if (!ap_path) - return NULL; - /* Find the AP by it's object path */ - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - for (elt = priv->ap_list; elt; elt = g_slist_next (elt)) { - NMAccessPoint *ap = NM_AP (elt->data); - - if (!strcmp (ap_path, nm_ap_get_dbus_path (ap))) - return ap; - } - return NULL; + return ap_path ? get_ap_by_path (self, ap_path) : NULL; } static void @@ -3659,8 +3816,8 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->update_initial_hw_address = real_update_initial_hw_address; parent_class->get_best_auto_connection = real_get_best_auto_connection; parent_class->is_available = real_is_available; - parent_class->connection_secrets_updated = real_connection_secrets_updated; parent_class->check_connection_compatible = real_check_connection_compatible; + parent_class->complete_connection = real_complete_connection; parent_class->act_stage1_prepare = real_act_stage1_prepare; parent_class->act_stage2_config = real_act_stage2_config; diff --git a/src/nm-device.c b/src/nm-device.c index fa586eff51..36df712dcd 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2010 Red Hat, Inc. + * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -572,6 +572,38 @@ nm_device_get_best_auto_connection (NMDevice *dev, return NM_DEVICE_GET_CLASS (dev)->get_best_auto_connection (dev, connections, specific_object); } +gboolean +nm_device_complete_connection (NMDevice *self, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + gboolean success = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (connection != NULL, FALSE); + + if (!NM_DEVICE_GET_CLASS (self)->complete_connection) { + g_set_error (error, + NM_DEVICE_INTERFACE_ERROR, + NM_DEVICE_INTERFACE_ERROR_CONNECTION_INVALID, + "Device class %s had no complete_connection method", + G_OBJECT_TYPE_NAME (self)); + return FALSE; + } + + success = NM_DEVICE_GET_CLASS (self)->complete_connection (self, + connection, + specific_object, + existing_connections, + error); + if (success) + success = nm_connection_verify (connection, error); + + return success; +} + static void dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer user_data) { @@ -2883,31 +2915,6 @@ check_connection_compatible (NMDeviceInterface *dev_iface, return TRUE; } -static void -connection_secrets_updated_cb (NMActRequest *req, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller, - gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - - if (NM_DEVICE_GET_CLASS (self)->connection_secrets_updated) - NM_DEVICE_GET_CLASS (self)->connection_secrets_updated (self, connection, updated_settings, caller); -} - -static void -connection_secrets_failed_cb (NMActRequest *req, - NMConnection *connection, - const char *setting_name, - RequestSecretsCaller caller, - gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); -} - static gboolean device_activation_precheck (NMDevice *self, NMConnection *connection, GError **error) { @@ -2950,14 +2957,6 @@ nm_device_activate (NMDeviceInterface *device, } priv->act_request = g_object_ref (req); - priv->secrets_updated_id = g_signal_connect (req, - "connection-secrets-updated", - G_CALLBACK (connection_secrets_updated_cb), - device); - priv->secrets_failed_id = g_signal_connect (req, - "connection-secrets-failed", - G_CALLBACK (connection_secrets_failed_cb), - device); if (!nm_act_request_get_assumed (req)) { /* HACK: update the state a bit early to avoid a race between the @@ -3358,10 +3357,8 @@ dispose (GObject *object) NMSettingIP4Config *s_ip4 = NULL; const char *method = NULL; - /* Only system connections can be left up */ connection = nm_act_request_get_connection (priv->act_request); - if ( connection - && (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM)) { + if (connection) { /* Only static or DHCP IPv4 connections can be left up. * All IPv6 connections can be left up, so we don't have diff --git a/src/nm-device.h b/src/nm-device.h index bd400fd6bf..94c8510be3 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2010 Red Hat, Inc. + * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -84,15 +84,16 @@ typedef struct { GSList *connections, char **specific_object); - void (* connection_secrets_updated) (NMDevice *self, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller); - gboolean (* check_connection_compatible) (NMDevice *self, NMConnection *connection, GError **error); + gboolean (* complete_connection) (NMDevice *self, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error); + NMActStageReturn (* act_stage1_prepare) (NMDevice *self, NMDeviceStateReason *reason); NMActStageReturn (* act_stage2_config) (NMDevice *self, @@ -162,6 +163,12 @@ NMConnection * nm_device_get_best_auto_connection (NMDevice *dev, GSList *connections, char **specific_object); +gboolean nm_device_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connection, + GError **error); + void nm_device_activate_schedule_stage1_device_prepare (NMDevice *device); void nm_device_activate_schedule_stage2_device_config (NMDevice *device); void nm_device_activate_schedule_stage4_ip4_config_get (NMDevice *device); diff --git a/src/nm-manager-auth.c b/src/nm-manager-auth.c index 44c82c23e6..8515959ebf 100644 --- a/src/nm-manager-auth.c +++ b/src/nm-manager-auth.c @@ -18,11 +18,13 @@ * Copyright (C) 2010 Red Hat, Inc. */ +#include +#include + +#include #include "nm-manager-auth.h" #include "nm-logging.h" - -#include -#include +#include "nm-dbus-manager.h" struct NMAuthChain { guint32 refcount; @@ -78,12 +80,13 @@ _auth_chain_new (PolkitAuthority *authority, DBusGMethodInvocation *context, DBusGProxy *proxy, DBusMessage *message, + const char *dbus_sender, NMAuthChainResultFunc done_func, gpointer user_data) { NMAuthChain *self; - g_return_val_if_fail (context || proxy || message, NULL); + g_return_val_if_fail (context || proxy || message || dbus_sender, NULL); self = g_malloc0 (sizeof (NMAuthChain)); self->refcount = 1; @@ -100,6 +103,8 @@ _auth_chain_new (PolkitAuthority *authority, self->owner = dbus_g_method_get_sender (context); else if (message) self->owner = g_strdup (dbus_message_get_sender (message)); + else if (dbus_sender) + self->owner = g_strdup (dbus_sender); if (!self->owner) { /* Need an owner */ @@ -118,7 +123,7 @@ nm_auth_chain_new (PolkitAuthority *authority, NMAuthChainResultFunc done_func, gpointer user_data) { - return _auth_chain_new (authority, context, proxy, NULL, done_func, user_data); + return _auth_chain_new (authority, context, proxy, NULL, NULL, done_func, user_data); } NMAuthChain * @@ -127,7 +132,16 @@ nm_auth_chain_new_raw_message (PolkitAuthority *authority, NMAuthChainResultFunc done_func, gpointer user_data) { - return _auth_chain_new (authority, NULL, NULL, message, done_func, user_data); + return _auth_chain_new (authority, NULL, NULL, message, NULL, done_func, user_data); +} + +NMAuthChain * +nm_auth_chain_new_dbus_sender (PolkitAuthority *authority, + const char *dbus_sender, + NMAuthChainResultFunc done_func, + gpointer user_data) +{ + return _auth_chain_new (authority, NULL, NULL, NULL, dbus_sender, done_func, user_data); } gpointer @@ -164,6 +178,43 @@ nm_auth_chain_set_data (NMAuthChain *self, } } +gulong +nm_auth_chain_get_data_ulong (NMAuthChain *self, const char *tag) +{ + gulong *ptr; + + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (tag != NULL, 0); + + ptr = nm_auth_chain_get_data (self, tag); + return *ptr; +} + + +void +nm_auth_chain_set_data_ulong (NMAuthChain *self, + const char *tag, + gulong data) +{ + gulong *ptr; + + g_return_if_fail (self != NULL); + g_return_if_fail (tag != NULL); + + ptr = g_malloc (sizeof (*ptr)); + *ptr = data; + nm_auth_chain_set_data (self, tag, ptr, g_free); +} + +NMAuthCallResult +nm_auth_chain_get_result (NMAuthChain *self, const char *permission) +{ + g_return_val_if_fail (self != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); + g_return_val_if_fail (permission != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); + + return GPOINTER_TO_UINT (nm_auth_chain_get_data (self, permission)); +} + static void nm_auth_chain_check_done (NMAuthChain *self) { @@ -317,7 +368,7 @@ gboolean nm_auth_get_caller_uid (DBusGMethodInvocation *context, NMDBusManager *dbus_mgr, gulong *out_uid, - const char **out_error_desc) + char **out_error_desc) { DBusConnection *connection; char *sender = NULL; @@ -325,22 +376,27 @@ nm_auth_get_caller_uid (DBusGMethodInvocation *context, DBusError dbus_error; g_return_val_if_fail (context != NULL, FALSE); - g_return_val_if_fail (dbus_mgr != NULL, FALSE); g_return_val_if_fail (out_uid != NULL, FALSE); + if (!dbus_mgr) { + dbus_mgr = nm_dbus_manager_get (); + g_assert (dbus_mgr); + } else + g_object_ref (dbus_mgr); + *out_uid = G_MAXULONG; sender = dbus_g_method_get_sender (context); if (!sender) { if (out_error_desc) - *out_error_desc = "Could not determine D-Bus requestor"; + *out_error_desc = g_strdup ("Could not determine D-Bus requestor"); goto out; } connection = nm_dbus_manager_get_dbus_connection (dbus_mgr); if (!connection) { if (out_error_desc) - *out_error_desc = "Could not get the D-Bus system bus"; + *out_error_desc = g_strdup ("Could not get the D-Bus system bus"); goto out; } @@ -349,73 +405,55 @@ nm_auth_get_caller_uid (DBusGMethodInvocation *context, *out_uid = dbus_bus_get_unix_user (connection, sender, &dbus_error); if (dbus_error_is_set (&dbus_error)) { if (out_error_desc) - *out_error_desc = "Could not determine the user ID of the requestor"; + *out_error_desc = g_strdup_printf ("Could not determine the user ID of the requestor"); dbus_error_free (&dbus_error); *out_uid = G_MAXULONG; } else success = TRUE; out: + g_object_unref (dbus_mgr); g_free (sender); return success; } gboolean -nm_auth_uid_authorized (gulong uid, - NMDBusManager *dbus_mgr, - DBusGProxy *user_proxy, - const char **out_error_desc) +nm_auth_uid_in_acl (NMConnection *connection, + NMSessionMonitor *smon, + gulong uid, + char **out_error_desc) { - DBusConnection *connection; - DBusError dbus_error; - char *service_owner = NULL; - const char *service_name; - gulong service_uid = G_MAXULONG; + NMSettingConnection *s_con; + const char *user = NULL; + GError *local = NULL; - g_return_val_if_fail (dbus_mgr != NULL, FALSE); - g_return_val_if_fail (out_error_desc != NULL, FALSE); + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (smon != NULL, FALSE); - /* Ensure the request to activate the user connection came from the - * same session as the user settings service. FIXME: use ConsoleKit - * too. - */ + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + g_assert (s_con); - if (!user_proxy) { - *out_error_desc = "No user settings service available"; + /* Reject the request if the request comes from no session at all */ + if (!nm_session_monitor_uid_has_session (smon, uid, &user, &local)) { + if (out_error_desc) { + *out_error_desc = g_strdup_printf ("No session found for uid %lu (%s)", + uid, + local && local->message ? local->message : "unknown"); + } + g_clear_error (&local); return FALSE; } - service_name = dbus_g_proxy_get_bus_name (user_proxy); - if (!service_name) { - *out_error_desc = "Could not determine user settings service name"; + if (!user) { + if (out_error_desc) + *out_error_desc = g_strdup_printf ("Could not determine username for uid %lu", uid); return FALSE; } - connection = nm_dbus_manager_get_dbus_connection (dbus_mgr); - if (!connection) { - *out_error_desc = "Could not get the D-Bus system bus"; - return FALSE; - } - - service_owner = nm_dbus_manager_get_name_owner (dbus_mgr, service_name, NULL); - if (!service_owner) { - *out_error_desc = "Could not determine D-Bus owner of the user settings service"; - return FALSE; - } - - dbus_error_init (&dbus_error); - service_uid = dbus_bus_get_unix_user (connection, service_owner, &dbus_error); - g_free (service_owner); - - if (dbus_error_is_set (&dbus_error)) { - dbus_error_free (&dbus_error); - *out_error_desc = "Could not determine the Unix UID of the sender of the request"; - return FALSE; - } - - /* And finally, the actual UID check */ - if (uid != service_uid) { - *out_error_desc = "Requestor UID does not match the UID of the user settings service"; + /* Match the username returned by the session check to a user in the ACL */ + if (!nm_setting_connection_permissions_user_allowed (s_con, user)) { + if (out_error_desc) + *out_error_desc = g_strdup_printf ("uid %lu has no permission to perform this operation", uid); return FALSE; } diff --git a/src/nm-manager-auth.h b/src/nm-manager-auth.h index 35bf270f65..7e7ff7a12c 100644 --- a/src/nm-manager-auth.h +++ b/src/nm-manager-auth.h @@ -25,15 +25,21 @@ #include #include +#include #include "nm-dbus-manager.h" +#include "nm-session-monitor.h" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network" -#define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI "org.freedesktop.NetworkManager.enable-disable-wifi" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN "org.freedesktop.NetworkManager.enable-disable-wwan" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX "org.freedesktop.NetworkManager.enable-disable-wimax" -#define NM_AUTH_PERMISSION_USE_USER_CONNECTIONS "org.freedesktop.NetworkManager.use-user-connections" -#define NM_AUTH_PERMISSION_NETWORK_CONTROL "org.freedesktop.NetworkManager.network-control" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network" +#define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI "org.freedesktop.NetworkManager.enable-disable-wifi" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN "org.freedesktop.NetworkManager.enable-disable-wwan" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX "org.freedesktop.NetworkManager.enable-disable-wimax" +#define NM_AUTH_PERMISSION_NETWORK_CONTROL "org.freedesktop.NetworkManager.network-control" +#define NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED "org.freedesktop.NetworkManager.wifi.share.protected" +#define NM_AUTH_PERMISSION_WIFI_SHARE_OPEN "org.freedesktop.NetworkManager.wifi.share.open" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM "org.freedesktop.NetworkManager.settings.modify.system" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN "org.freedesktop.NetworkManager.settings.modify.own" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME "org.freedesktop.NetworkManager.settings.modify.hostname" typedef struct NMAuthChain NMAuthChain; @@ -67,6 +73,11 @@ NMAuthChain *nm_auth_chain_new_raw_message (PolkitAuthority *authority, NMAuthChainResultFunc done_func, gpointer user_data); +NMAuthChain *nm_auth_chain_new_dbus_sender (PolkitAuthority *authority, + const char *dbus_sender, + NMAuthChainResultFunc done_func, + gpointer user_data); + gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag); void nm_auth_chain_set_data (NMAuthChain *chain, @@ -74,6 +85,15 @@ void nm_auth_chain_set_data (NMAuthChain *chain, gpointer data, GDestroyNotify data_destroy); +void nm_auth_chain_set_data_ulong (NMAuthChain *chain, + const char *tag, + gulong data); + +gulong nm_auth_chain_get_data_ulong (NMAuthChain *chain, const char *tag); + +NMAuthCallResult nm_auth_chain_get_result (NMAuthChain *chain, + const char *permission); + gboolean nm_auth_chain_add_call (NMAuthChain *chain, const char *permission, gboolean allow_interaction); @@ -84,12 +104,13 @@ void nm_auth_chain_unref (NMAuthChain *chain); gboolean nm_auth_get_caller_uid (DBusGMethodInvocation *context, NMDBusManager *dbus_mgr, gulong *out_uid, - const char **out_error_desc); + char **out_error_desc); -gboolean nm_auth_uid_authorized (gulong uid, - NMDBusManager *dbus_mgr, - DBusGProxy *user_proxy, - const char **out_error_desc); +/* Caller must free returned error description */ +gboolean nm_auth_uid_in_acl (NMConnection *connection, + NMSessionMonitor *smon, + gulong uid, + char **out_error_desc); #endif /* NM_MANAGER_AUTH_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index e47ec37f41..4b2332b840 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "nm-glib-compat.h" #include "nm-manager.h" @@ -55,11 +56,10 @@ #include "nm-hostname-provider.h" #include "nm-bluez-manager.h" #include "nm-bluez-common.h" -#include "nm-sysconfig-settings.h" -#include "nm-secrets-provider-interface.h" -#include "nm-settings-interface.h" -#include "nm-settings-system-interface.h" +#include "nm-settings.h" +#include "nm-settings-connection.h" #include "nm-manager-auth.h" +#include "NetworkManagerUtils.h" #define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd" #define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd" @@ -68,12 +68,17 @@ static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err); static void impl_manager_activate_connection (NMManager *manager, - const char *service_name, const char *connection_path, const char *device_path, const char *specific_object_path, DBusGMethodInvocation *context); +static void impl_manager_add_and_activate_connection (NMManager *manager, + GHashTable *settings, + const char *device_path, + const char *specific_object_path, + DBusGMethodInvocation *context); + static void impl_manager_deactivate_connection (NMManager *manager, const char *connection_path, DBusGMethodInvocation *context); @@ -102,10 +107,6 @@ static gboolean impl_manager_legacy_state (NMManager *manager, guint32 *state, G #include "nm-manager-glue.h" -static void connection_added_default_handler (NMManager *manager, - NMConnection *connection, - NMConnectionScope scope); - static void udev_device_added_cb (NMUdevManager *udev_mgr, GUdevDevice *device, NMDeviceCreatorFn creator_fn, @@ -138,6 +139,7 @@ static const char *internal_activate_device (NMManager *manager, NMConnection *connection, const char *specific_object, gboolean user_requested, + gulong sender_uid, gboolean assumed, GError **error); @@ -179,14 +181,10 @@ struct PendingActivation { PendingActivationFunc callback; NMAuthChain *chain; - gboolean have_connection; - gboolean authorized; - - NMConnectionScope scope; char *connection_path; + NMConnection *connection; char *specific_object_path; char *device_path; - guint timeout_id; }; typedef struct { @@ -212,19 +210,9 @@ typedef struct { NMUdevManager *udev_mgr; NMBluezManager *bluez_mgr; - GHashTable *user_connections; - DBusGProxy *user_proxy; - NMAuthCallResult user_con_perm; - NMAuthCallResult user_net_perm; - - GHashTable *system_connections; - NMSysconfigSettings *sys_settings; + NMSettings *settings; char *hostname; - GSList *secrets_calls; - - GSList *pending_activations; - RadioState radio_states[RFKILL_TYPE_MAX]; gboolean sleeping; gboolean net_enabled; @@ -265,10 +253,6 @@ enum { STATE_CHANGED, STATE_CHANGE, /* DEPRECATED */ PROPERTIES_CHANGED, - CONNECTIONS_ADDED, - CONNECTION_ADDED, - CONNECTION_UPDATED, - CONNECTION_REMOVED, CHECK_PERMISSIONS, USER_PERMISSIONS_CHANGED, @@ -297,17 +281,19 @@ enum { LAST_PROP }; -typedef enum -{ + +/************************************************************************/ + +typedef enum { NM_MANAGER_ERROR_UNKNOWN_CONNECTION = 0, NM_MANAGER_ERROR_UNKNOWN_DEVICE, NM_MANAGER_ERROR_UNMANAGED_DEVICE, - NM_MANAGER_ERROR_INVALID_SERVICE, NM_MANAGER_ERROR_SYSTEM_CONNECTION, NM_MANAGER_ERROR_PERMISSION_DENIED, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, + NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, } NMManagerError; #define NM_MANAGER_ERROR (nm_manager_error_quark ()) @@ -338,10 +324,6 @@ nm_manager_error_get_type (void) ENUM_ENTRY (NM_MANAGER_ERROR_UNKNOWN_DEVICE, "UnknownDevice"), /* Unmanaged device. */ ENUM_ENTRY (NM_MANAGER_ERROR_UNMANAGED_DEVICE, "UnmanagedDevice"), - /* Invalid settings service (not a recognized system or user - * settings service name) - */ - ENUM_ENTRY (NM_MANAGER_ERROR_INVALID_SERVICE, "InvalidService"), /* Connection was superceded by a system connection. */ ENUM_ENTRY (NM_MANAGER_ERROR_SYSTEM_CONNECTION, "SystemConnection"), /* User does not have the permission to activate this connection. */ @@ -352,6 +334,8 @@ nm_manager_error_get_type (void) ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, "AlreadyAsleepOrAwake"), /* The manager is already in the requested enabled/disabled state */ ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, "AlreadyEnabledOrDisabled"), + /* The requested operation is unsupported for this type of connection */ + ENUM_ENTRY (NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, "UnsupportedConnectionType"), { 0, 0, 0 }, }; etype = g_enum_register_static ("NMManagerError", values); @@ -359,6 +343,32 @@ nm_manager_error_get_type (void) return etype; } +/************************************************************************/ + +static NMDevice * +nm_manager_get_device_by_udi (NMManager *manager, const char *udi) +{ + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { + if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi)) + return NM_DEVICE (iter->data); + } + return NULL; +} + +static NMDevice * +nm_manager_get_device_by_path (NMManager *manager, const char *path) +{ + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { + if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path)) + return NM_DEVICE (iter->data); + } + return NULL; +} + static gboolean manager_sleeping (NMManager *self) { @@ -469,7 +479,7 @@ nm_manager_update_state (NMManager *manager) } static void -ignore_cb (NMSettingsConnectionInterface *connection, GError *error, gpointer user_data) +ignore_cb (NMSettingsConnection *connection, GError *error, gpointer user_data) { } @@ -479,7 +489,6 @@ update_active_connection_timestamp (NMManager *manager, NMDevice *device) NMActRequest *req; NMConnection *connection; NMSettingConnection *s_con; - NMSettingsConnectionInterface *connection_interface; NMManagerPrivate *priv; g_return_if_fail (NM_IS_DEVICE (device)); @@ -492,19 +501,14 @@ update_active_connection_timestamp (NMManager *manager, NMDevice *device) connection = nm_act_request_get_connection (req); g_assert (connection); - if (nm_connection_get_scope (connection) != NM_CONNECTION_SCOPE_SYSTEM) - return; - - s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION)); + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); g_assert (s_con); g_object_set (s_con, NM_SETTING_CONNECTION_TIMESTAMP, (guint64) time (NULL), NULL); if (nm_setting_connection_get_read_only (s_con)) return; - connection_interface = nm_settings_interface_get_connection_by_path (NM_SETTINGS_INTERFACE (priv->sys_settings), - nm_connection_get_path (connection)); - nm_settings_connection_interface_update (connection_interface, ignore_cb, NULL); + nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (connection), ignore_cb, NULL); } static void @@ -560,7 +564,7 @@ remove_one_device (NMManager *manager, g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager); - nm_sysconfig_settings_device_removed (priv->sys_settings, device); + nm_settings_device_removed (priv->settings, device); g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device); g_object_unref (device); @@ -650,24 +654,43 @@ nm_manager_get_state (NMManager *manager) return NM_MANAGER_GET_PRIVATE (manager)->state; } -static void -emit_removed (gpointer key, gpointer value, gpointer user_data) +static gboolean +might_be_vpn (NMConnection *connection) { - NMManager *manager = NM_MANAGER (user_data); - NMConnection *connection = NM_CONNECTION (value); + NMSettingConnection *s_con; + const char *ctype = NULL; - g_signal_emit (manager, signals[CONNECTION_REMOVED], 0, - connection, - nm_connection_get_scope (connection)); + if (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN)) + return TRUE; + + /* Make sure it's not a VPN, which we can't autocomplete yet */ + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + if (s_con) + ctype = nm_setting_connection_get_connection_type (s_con); + + return (g_strcmp0 (ctype, NM_SETTING_VPN_SETTING_NAME) == 0); } -static void -nm_manager_pending_activation_remove (NMManager *self, - PendingActivation *pending) +static gboolean +try_complete_vpn (NMConnection *connection, GSList *existing, GError **error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + g_assert (might_be_vpn (connection) == TRUE); - priv->pending_activations = g_slist_remove (priv->pending_activations, pending); + if (!nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN)) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, + "VPN connections require a 'vpn' setting"); + return FALSE; + } + + nm_utils_complete_generic (connection, + NM_SETTING_VPN_SETTING_NAME, + existing, + _("VPN connection %d"), + NULL); + + return TRUE; } static PendingActivation * @@ -675,18 +698,58 @@ pending_activation_new (NMManager *manager, PolkitAuthority *authority, DBusGMethodInvocation *context, const char *device_path, - NMConnectionScope scope, const char *connection_path, + GHashTable *settings, const char *specific_object_path, - PendingActivationFunc callback) + PendingActivationFunc callback, + GError **error) { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); PendingActivation *pending; + NMDevice *device; + NMConnection *connection = NULL; + GSList *all_connections = NULL; + gboolean success; g_return_val_if_fail (manager != NULL, NULL); g_return_val_if_fail (authority != NULL, NULL); g_return_val_if_fail (context != NULL, NULL); g_return_val_if_fail (device_path != NULL, NULL); - g_return_val_if_fail (connection_path != NULL, NULL); + + /* Create the partial connection from the given settings */ + if (settings) { + device = nm_manager_get_device_by_path (manager, device_path); + if (!device) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Device not found"); + return NULL; + } + + connection = nm_connection_new (); + nm_connection_replace_settings (connection, settings, NULL); + + all_connections = nm_settings_get_connections (priv->settings); + + if (might_be_vpn (connection)) { + /* Try to fill the VPN's connection setting and name at least */ + success = try_complete_vpn (connection, all_connections, error); + } else { + /* Let each device subclass complete the connection */ + success = nm_device_complete_connection (device, + connection, + specific_object_path, + all_connections, + error); + } + g_slist_free (all_connections); + + if (success == FALSE) { + g_object_unref (connection); + return NULL; + } + } pending = g_slice_new0 (PendingActivation); pending->manager = manager; @@ -695,8 +758,8 @@ pending_activation_new (NMManager *manager, pending->callback = callback; pending->device_path = g_strdup (device_path); - pending->scope = scope; pending->connection_path = g_strdup (connection_path); + pending->connection = connection; /* "/" is special-cased to NULL to get through D-Bus */ if (specific_object_path && strcmp (specific_object_path, "/")) @@ -705,39 +768,6 @@ pending_activation_new (NMManager *manager, return pending; } -static void -pending_auth_user_done (NMAuthChain *chain, - GError *error, - DBusGMethodInvocation *context, - gpointer user_data) -{ - PendingActivation *pending = user_data; - NMAuthCallResult result; - - pending->chain = NULL; - - if (error) { - pending->callback (pending, error); - goto out; - } - - /* Caller has had a chance to obtain authorization, so we only need to - * check for 'yes' here. - */ - result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS)); - if (result != NM_AUTH_CALL_RESULT_YES) { - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Not authorized to use user connections."); - pending->callback (pending, error); - g_error_free (error); - } else - pending->callback (pending, NULL); - -out: - nm_auth_chain_unref (chain); -} - static void pending_auth_net_done (NMAuthChain *chain, GError *error, @@ -767,86 +797,33 @@ pending_auth_net_done (NMAuthChain *chain, goto out; } - if (pending->scope == NM_CONNECTION_SCOPE_SYSTEM) { - /* System connection and the user is authorized for that if they have - * the network-control permission. - */ - pending->callback (pending, NULL); - } else { - g_assert (pending->scope == NM_CONNECTION_SCOPE_USER); - - /* User connection, check the 'use-user-connections' permission */ - pending->chain = nm_auth_chain_new (pending->authority, - pending->context, - NULL, - pending_auth_user_done, - pending); - nm_auth_chain_add_call (pending->chain, - NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, - TRUE); - } + pending->callback (pending, NULL); out: nm_auth_chain_unref (chain); } -static gboolean -check_user_authorized (NMDBusManager *dbus_mgr, - DBusGProxy *user_proxy, - DBusGMethodInvocation *context, - NMConnectionScope scope, - gulong *out_sender_uid, - const char **out_error_desc) -{ - g_return_val_if_fail (dbus_mgr != NULL, FALSE); - g_return_val_if_fail (context != NULL, FALSE); - g_return_val_if_fail (out_sender_uid != NULL, FALSE); - g_return_val_if_fail (out_error_desc != NULL, FALSE); - - *out_sender_uid = G_MAXULONG; - - /* Get the UID */ - if (!nm_auth_get_caller_uid (context, dbus_mgr, out_sender_uid, out_error_desc)) - return FALSE; - - /* root gets to do anything */ - if (0 == *out_sender_uid) - return TRUE; - - /* Check whether the UID is authorized for user connections */ - if ( scope == NM_CONNECTION_SCOPE_USER - && !nm_auth_uid_authorized (*out_sender_uid, - dbus_mgr, - user_proxy, - out_error_desc)) - return FALSE; - - return TRUE; -} - static void pending_activation_check_authorized (PendingActivation *pending, - NMDBusManager *dbus_mgr, - DBusGProxy *user_proxy) + NMDBusManager *dbus_mgr) { - const char *error_desc = NULL; + char *error_desc = NULL; gulong sender_uid = G_MAXULONG; GError *error; g_return_if_fail (pending != NULL); g_return_if_fail (dbus_mgr != NULL); - if (!check_user_authorized (dbus_mgr, - user_proxy, - pending->context, - pending->scope, - &sender_uid, - &error_desc)) { + if (!nm_auth_get_caller_uid (pending->context, + dbus_mgr, + &sender_uid, + &error_desc)) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, error_desc); pending->callback (pending, error); g_error_free (error); + g_free (error_desc); return; } @@ -877,16 +854,22 @@ pending_activation_destroy (PendingActivation *pending, { g_return_if_fail (pending != NULL); - if (pending->timeout_id) - g_source_remove (pending->timeout_id); + if (error) + dbus_g_method_return_error (pending->context, error); + else if (ac_path) { + if (pending->connection) { + dbus_g_method_return (pending->context, + pending->connection_path, + ac_path); + } else + dbus_g_method_return (pending->context, ac_path); + } + g_free (pending->connection_path); g_free (pending->specific_object_path); g_free (pending->device_path); - - if (error) - dbus_g_method_return_error (pending->context, error); - else if (ac_path) - dbus_g_method_return (pending->context, ac_path); + if (pending->connection) + g_object_unref (pending->connection); if (pending->chain) nm_auth_chain_unref (pending->chain); @@ -928,577 +911,28 @@ get_active_connections (NMManager *manager, NMConnection *filter) return active; } -static void -remove_connection (NMManager *manager, - NMConnection *connection, - GHashTable *hash) -{ - /* Destroys the connection, then associated DBusGProxy due to the - * weak reference notify function placed on the connection when it - * was created. - */ - g_object_ref (connection); - g_hash_table_remove (hash, nm_connection_get_path (connection)); - g_signal_emit (manager, signals[CONNECTION_REMOVED], 0, - connection, - nm_connection_get_scope (connection)); - g_object_unref (connection); - - bluez_manager_resync_devices (manager); -} - /*******************************************************************/ -/* User settings stuff via D-Bus */ +/* Settings stuff via NMSettings */ /*******************************************************************/ static void -user_proxy_cleanup (NMManager *self, gboolean resync_bt) +connections_changed (NMSettings *settings, + NMSettingsConnection *connection, + NMManager *manager) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - - if (priv->user_connections) { - g_hash_table_foreach (priv->user_connections, emit_removed, self); - g_hash_table_remove_all (priv->user_connections); - } - - priv->user_net_perm = NM_AUTH_CALL_RESULT_UNKNOWN; - priv->user_con_perm = NM_AUTH_CALL_RESULT_UNKNOWN; - - if (priv->user_proxy) { - g_object_unref (priv->user_proxy); - priv->user_proxy = NULL; - } - - if (resync_bt) { - /* Resync BT devices since they are generated from connections */ - bluez_manager_resync_devices (self); - } -} - -typedef struct GetSettingsInfo { - NMManager *manager; - NMConnection *connection; - DBusGProxy *proxy; - guint32 *calls; -} GetSettingsInfo; - -static void -free_get_settings_info (gpointer data) -{ - GetSettingsInfo *info = (GetSettingsInfo *) data; - - /* If this was the last pending call for a batch of GetSettings calls, - * send out the connections-added signal. - */ - if (info->calls) { - (*info->calls)--; - if (*info->calls == 0) { - g_slice_free (guint32, (gpointer) info->calls); - g_signal_emit (info->manager, signals[CONNECTIONS_ADDED], 0, NM_CONNECTION_SCOPE_USER); - - /* Update the Bluetooth connections for all the new connections */ - bluez_manager_resync_devices (info->manager); - } - } - - if (info->manager) { - g_object_unref (info->manager); - info->manager = NULL; - } - if (info->connection) { - g_object_unref (info->connection); - info->connection = NULL; - } - if (info->proxy) { - g_object_unref (info->proxy); - info->proxy = NULL; - } - - g_slice_free (GetSettingsInfo, data); -} - -static void -user_connection_get_settings_cb (DBusGProxy *proxy, - DBusGProxyCall *call_id, - gpointer user_data) -{ - GetSettingsInfo *info = (GetSettingsInfo *) user_data; - GError *err = NULL; - GHashTable *settings = NULL; - NMConnection *connection; - NMManager *manager; - - g_return_if_fail (info != NULL); - - if (!dbus_g_proxy_end_call (proxy, call_id, &err, - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings, - G_TYPE_INVALID)) { - nm_log_info (LOGD_USER_SET, "couldn't retrieve connection settings: %s.", - err && err->message ? err->message : "(unknown)"); - g_error_free (err); - goto out; - } - - manager = info->manager; - connection = info->connection; - if (connection == NULL) { - const char *path = dbus_g_proxy_get_path (proxy); - NMManagerPrivate *priv; - GError *error = NULL; - NMConnection *existing = NULL; - - connection = nm_connection_new_from_hash (settings, &error); - if (connection == NULL) { - nm_log_warn (LOGD_USER_SET, "invalid connection: '%s' / '%s' invalid: %d", - g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)), - error->message, error->code); - g_error_free (error); - goto out; - } - - nm_connection_set_path (connection, path); - nm_connection_set_scope (connection, NM_CONNECTION_SCOPE_USER); - - /* Add the new connection to the internal hashes only if the same - * connection isn't already there. - */ - priv = NM_MANAGER_GET_PRIVATE (manager); - - existing = g_hash_table_lookup (priv->user_connections, path); - if (!existing || !nm_connection_compare (existing, connection, NM_SETTING_COMPARE_FLAG_EXACT)) { - g_hash_table_insert (priv->user_connections, - g_strdup (path), - connection); - existing = NULL; - - /* Attach the D-Bus proxy representing the remote NMConnection - * to the local NMConnection object to ensure it stays alive to - * continue delivering signals. It'll be destroyed once the - * NMConnection is destroyed. - */ - g_object_set_data_full (G_OBJECT (connection), - "proxy", - g_object_ref (info->proxy), - g_object_unref); - } else - g_object_unref (connection); - - /* If the connection-added signal is supposed to be batched, don't - * emit the single connection-added here. Also, don't emit the signal - * if the connection wasn't actually added to the system or user hashes. - */ - if (!info->calls && !existing) { - g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection, NM_CONNECTION_SCOPE_USER); - /* Update the Bluetooth connections for that single new connection */ - bluez_manager_resync_devices (manager); - } - } else { - // FIXME: merge settings? or just replace? - nm_log_dbg (LOGD_USER_SET, "implement merge settings"); - } - -out: - if (settings) - g_hash_table_destroy (settings); - - return; -} - -static void -user_connection_removed_cb (DBusGProxy *proxy, gpointer user_data) -{ - NMManager *manager = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - NMConnection *connection = NULL; - const char *path; - - path = dbus_g_proxy_get_path (proxy); - if (path) { - connection = g_hash_table_lookup (priv->user_connections, path); - if (connection) - remove_connection (manager, connection, priv->user_connections); - } -} - -static void -user_connection_updated_cb (DBusGProxy *proxy, - GHashTable *settings, - gpointer user_data) -{ - NMManager *manager = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - NMConnection *new_connection; - NMConnection *old_connection = NULL; - gboolean valid = FALSE; - GError *error = NULL; - const char *path; - - path = dbus_g_proxy_get_path (proxy); - if (path) - old_connection = g_hash_table_lookup (priv->user_connections, path); - - g_return_if_fail (old_connection != NULL); - - new_connection = nm_connection_new_from_hash (settings, &error); - if (!new_connection) { - /* New connection invalid, remove existing connection */ - nm_log_warn (LOGD_USER_SET, "invalid connection: '%s' / '%s' invalid: %d", - g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)), - error->message, error->code); - g_error_free (error); - remove_connection (manager, old_connection, priv->user_connections); - return; - } - g_object_unref (new_connection); - - valid = nm_connection_replace_settings (old_connection, settings, NULL); - if (valid) { - g_signal_emit (manager, signals[CONNECTION_UPDATED], 0, - old_connection, - nm_connection_get_scope (old_connection)); - - bluez_manager_resync_devices (manager); - } else { - remove_connection (manager, old_connection, priv->user_connections); - } -} - -static void -user_internal_new_connection_cb (NMManager *manager, - const char *path, - guint32 *counter) -{ - GetSettingsInfo *info; - DBusGProxy *con_proxy; - DBusGConnection *g_connection; - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - - g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr); - con_proxy = dbus_g_proxy_new_for_name (g_connection, - NM_DBUS_SERVICE_USER_SETTINGS, - path, - NM_DBUS_IFACE_SETTINGS_CONNECTION); - if (!con_proxy) { - nm_log_err (LOGD_USER_SET, "could not init user connection proxy"); - return; - } - - dbus_g_proxy_add_signal (con_proxy, "Updated", - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, - G_TYPE_INVALID); - dbus_g_proxy_connect_signal (con_proxy, "Updated", - G_CALLBACK (user_connection_updated_cb), - manager, - NULL); - - dbus_g_proxy_add_signal (con_proxy, "Removed", G_TYPE_INVALID, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (con_proxy, "Removed", - G_CALLBACK (user_connection_removed_cb), - manager, - NULL); - - info = g_slice_new0 (GetSettingsInfo); - info->manager = g_object_ref (manager); - info->proxy = con_proxy; - if (counter) { - info->calls = counter; - (*info->calls)++; - } - dbus_g_proxy_begin_call (con_proxy, "GetSettings", - user_connection_get_settings_cb, - info, - free_get_settings_info, - G_TYPE_INVALID); -} - -static void -user_list_connections_cb (DBusGProxy *proxy, - DBusGProxyCall *call_id, - gpointer user_data) -{ - NMManager *manager = NM_MANAGER (user_data); - GError *err = NULL; - GPtrArray *ops; - guint32 *counter = NULL; - int i; - - if (!dbus_g_proxy_end_call (proxy, call_id, &err, - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &ops, - G_TYPE_INVALID)) { - nm_log_warn (LOGD_USER_SET, "couldn't retrieve connections: %s", - err && err->message ? err->message : "(unknown)"); - g_clear_error (&err); - return; - } - - /* Keep track of all calls made here; don't want to emit connection-added for - * each one, but emit connections-added when they are all done. - */ - counter = g_slice_new0 (guint32); - for (i = 0; i < ops->len; i++) { - char *op = g_ptr_array_index (ops, i); - - user_internal_new_connection_cb (manager, op, counter); - g_free (op); - } - g_ptr_array_free (ops, TRUE); -} - -static void -user_proxy_destroyed_cb (DBusGProxy *proxy, NMManager *self) -{ - nm_log_dbg (LOGD_USER_SET, "Removing user connections..."); - - /* At this point the user proxy is already being disposed */ - NM_MANAGER_GET_PRIVATE (self)->user_proxy = NULL; - - /* User Settings service disappeared; throw away user connections */ - user_proxy_cleanup (self, TRUE); -} - -static void -user_new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) -{ - user_internal_new_connection_cb (NM_MANAGER (user_data), path, NULL); -} - -static gboolean -user_settings_authorized (NMManager *self, NMAuthChain *chain) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMAuthCallResult old_net_perm = priv->user_net_perm; - NMAuthCallResult old_con_perm = priv->user_con_perm; - - /* If the user could potentially get authorization to use networking and/or - * to use user connections, the user settings service is authorized. - */ - priv->user_net_perm = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL)); - priv->user_con_perm = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS)); - - nm_log_dbg (LOGD_USER_SET, "User connections permissions: net %d, con %d", - priv->user_net_perm, priv->user_con_perm); - - if (old_net_perm != priv->user_net_perm || old_con_perm != priv->user_con_perm) - g_signal_emit (self, signals[USER_PERMISSIONS_CHANGED], 0); - - /* If the user can't control the network they certainly aren't allowed - * to provide user connections. - */ - if ( priv->user_net_perm == NM_AUTH_CALL_RESULT_UNKNOWN - || priv->user_net_perm == NM_AUTH_CALL_RESULT_NO) - return FALSE; - - /* And of course if they aren't allowed to use user connections, they can't - * provide them either. - */ - if ( priv->user_con_perm == NM_AUTH_CALL_RESULT_UNKNOWN - || priv->user_con_perm == NM_AUTH_CALL_RESULT_NO) - return FALSE; - - return TRUE; -} - -static void -user_proxy_auth_done (NMAuthChain *chain, - GError *error, - DBusGMethodInvocation *context, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gboolean authorized = FALSE; - - priv->auth_chains = g_slist_remove (priv->auth_chains, chain); - - if (error) { - nm_log_warn (LOGD_USER_SET, "User connections unavailable: (%d) %s", - error->code, error->message ? error->message : "(unknown)"); - } else - authorized = user_settings_authorized (self, chain); - - if (authorized) { - /* If authorized, finish setting up the user settings service proxy */ - nm_log_dbg (LOGD_USER_SET, "Requesting user connections..."); - - authorized = TRUE; - - dbus_g_proxy_add_signal (priv->user_proxy, - "NewConnection", - DBUS_TYPE_G_OBJECT_PATH, - G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->user_proxy, "NewConnection", - G_CALLBACK (user_new_connection_cb), - self, - NULL); - - /* Clean up when the user settings proxy goes away */ - g_signal_connect (priv->user_proxy, "destroy", - G_CALLBACK (user_proxy_destroyed_cb), - self); - - /* Request user connections */ - dbus_g_proxy_begin_call (priv->user_proxy, "ListConnections", - user_list_connections_cb, - self, - NULL, - G_TYPE_INVALID); - } else { - /* Otherwise, we ignore the user settings service completely */ - user_proxy_cleanup (self, TRUE); - } - - nm_auth_chain_unref (chain); -} - -static void -user_proxy_init (NMManager *self) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - DBusGConnection *bus; - NMAuthChain *chain; - GError *error = NULL; - - g_return_if_fail (self != NULL); - g_return_if_fail (priv->user_proxy == NULL); - - /* Don't try to initialize the user settings proxy if the user - * settings service doesn't actually exist. - */ - if (!nm_dbus_manager_name_has_owner (priv->dbus_mgr, NM_DBUS_SERVICE_USER_SETTINGS)) - return; - - bus = nm_dbus_manager_get_connection (priv->dbus_mgr); - priv->user_proxy = dbus_g_proxy_new_for_name_owner (bus, - NM_DBUS_SERVICE_USER_SETTINGS, - NM_DBUS_PATH_SETTINGS, - NM_DBUS_IFACE_SETTINGS, - &error); - if (!priv->user_proxy) { - nm_log_err (LOGD_USER_SET, "could not init user settings proxy: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - return; - } - - /* Kick off some PolicyKit authorization requests to figure out what - * permissions this user settings service has. - */ - chain = nm_auth_chain_new (priv->authority, - NULL, - priv->user_proxy, - user_proxy_auth_done, - self); - priv->auth_chains = g_slist_prepend (priv->auth_chains, chain); - - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE); -} - -/*******************************************************************/ -/* System settings stuff via NMSysconfigSettings */ -/*******************************************************************/ - -static void -system_connection_updated_cb (NMSettingsConnectionInterface *connection, - gpointer unused, - NMManager *manager) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - const char *path; - NMSettingsConnectionInterface *existing; - GError *error = NULL; - - path = nm_connection_get_path (NM_CONNECTION (connection)); - - existing = g_hash_table_lookup (priv->system_connections, path); - if (!existing) - return; - if (existing != connection) { - nm_log_warn (LOGD_SYS_SET, "existing connection didn't matched updated."); - return; - } - - if (!nm_connection_verify (NM_CONNECTION (existing), &error)) { - /* Updated connection invalid, remove existing connection */ - nm_log_warn (LOGD_SYS_SET, "invalid connection: '%s' / '%s' invalid: %d", - g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)), - error->message, error->code); - g_error_free (error); - remove_connection (manager, NM_CONNECTION (existing), priv->system_connections); - return; - } - - g_signal_emit (manager, signals[CONNECTION_UPDATED], 0, - existing, NM_CONNECTION_SCOPE_SYSTEM); - bluez_manager_resync_devices (manager); } static void -system_connection_removed_cb (NMSettingsConnectionInterface *connection, - NMManager *manager) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - const char *path; - - path = nm_connection_get_path (NM_CONNECTION (connection)); - - connection = g_hash_table_lookup (priv->system_connections, path); - if (connection) - remove_connection (manager, NM_CONNECTION (connection), priv->system_connections); -} - -static void -system_internal_new_connection (NMManager *manager, - NMSettingsConnectionInterface *connection) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - const char *path; - - g_return_if_fail (connection != NULL); - - g_signal_connect (connection, NM_SETTINGS_CONNECTION_INTERFACE_UPDATED, - G_CALLBACK (system_connection_updated_cb), manager); - g_signal_connect (connection, NM_SETTINGS_CONNECTION_INTERFACE_REMOVED, - G_CALLBACK (system_connection_removed_cb), manager); - - path = nm_connection_get_path (NM_CONNECTION (connection)); - g_hash_table_insert (priv->system_connections, g_strdup (path), - g_object_ref (connection)); - g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection, NM_CONNECTION_SCOPE_SYSTEM); -} - -static void -system_new_connection_cb (NMSysconfigSettings *settings, - NMSettingsConnectionInterface *connection, - NMManager *manager) -{ - system_internal_new_connection (manager, connection); -} - -static void -system_query_connections (NMManager *manager) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *system_connections, *iter; - - system_connections = nm_settings_interface_list_connections (NM_SETTINGS_INTERFACE (priv->sys_settings)); - for (iter = system_connections; iter; iter = g_slist_next (iter)) - system_internal_new_connection (manager, NM_SETTINGS_CONNECTION_INTERFACE (iter->data)); - g_slist_free (system_connections); -} - -static void -system_unmanaged_devices_changed_cb (NMSysconfigSettings *sys_settings, +system_unmanaged_devices_changed_cb (NMSettings *settings, GParamSpec *pspec, gpointer user_data) { - NMManager *manager = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + NMManager *self = NM_MANAGER (user_data); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); const GSList *unmanaged_specs, *iter; - unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (sys_settings); + unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); for (iter = priv->devices; iter; iter = g_slist_next (iter)) { NMDevice *device = NM_DEVICE (iter->data); gboolean managed; @@ -1507,30 +941,28 @@ system_unmanaged_devices_changed_cb (NMSysconfigSettings *sys_settings, nm_device_set_managed (device, managed, managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED : - NM_DEVICE_STATE_REASON_NOW_UNMANAGED); + NM_DEVICE_STATE_REASON_NOW_UNMANAGED); } } static void -system_hostname_changed_cb (NMSysconfigSettings *sys_settings, +system_hostname_changed_cb (NMSettings *settings, GParamSpec *pspec, gpointer user_data) { - NMManager *manager = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + NMManager *self = NM_MANAGER (user_data); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); char *hostname; - hostname = nm_sysconfig_settings_get_hostname (sys_settings); - + hostname = nm_settings_get_hostname (priv->settings); if (!hostname && !priv->hostname) return; - if (hostname && priv->hostname && !strcmp (hostname, priv->hostname)) return; g_free (priv->hostname); priv->hostname = (hostname && strlen (hostname)) ? g_strdup (hostname) : NULL; - g_object_notify (G_OBJECT (manager), NM_MANAGER_HOSTNAME); + g_object_notify (G_OBJECT (self), NM_MANAGER_HOSTNAME); g_free (hostname); } @@ -1539,49 +971,6 @@ system_hostname_changed_cb (NMSysconfigSettings *sys_settings, /* General NMManager stuff */ /*******************************************************************/ -static NMDevice * -nm_manager_get_device_by_udi (NMManager *manager, const char *udi) -{ - GSList *iter; - - for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { - if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi)) - return NM_DEVICE (iter->data); - } - return NULL; -} - -static NMDevice * -nm_manager_get_device_by_path (NMManager *manager, const char *path) -{ - GSList *iter; - - for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { - if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path)) - return NM_DEVICE (iter->data); - } - return NULL; -} - -static void -nm_manager_name_owner_changed (NMDBusManager *mgr, - const char *name, - const char *old, - const char *new, - gpointer user_data) -{ - NMManager *manager = NM_MANAGER (user_data); - gboolean old_owner_good = (old && (strlen (old) > 0)); - gboolean new_owner_good = (new && (strlen (new) > 0)); - - if (strcmp (name, NM_DBUS_SERVICE_USER_SETTINGS) == 0) { - if (!old_owner_good && new_owner_good) - user_proxy_init (manager); - else - user_proxy_cleanup (manager, TRUE); - } -} - /* Store value into key-file; supported types: boolean, int, string */ static gboolean write_value_to_state_file (const char *filename, @@ -1683,6 +1072,7 @@ manager_hidden_ap_found (NMDeviceInterface *device, gpointer user_data) { NMManager *manager = NM_MANAGER (user_data); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); const struct ether_addr *ap_addr; const GByteArray *ap_ssid; GSList *iter; @@ -1698,8 +1088,7 @@ manager_hidden_ap_found (NMDeviceInterface *device, /* Look for this AP's BSSID in the seen-bssids list of a connection, * and if a match is found, copy over the SSID */ - connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM); - connections = g_slist_concat (connections, nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER)); + connections = nm_settings_get_connections (priv->settings); for (iter = connections; iter && !done; iter = g_slist_next (iter)) { NMConnection *connection = NM_CONNECTION (iter->data); @@ -1710,32 +1099,27 @@ manager_hidden_ap_found (NMDeviceInterface *device, s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); if (!s_wireless) - goto next; + continue; num_bssids = nm_setting_wireless_get_num_seen_bssids (s_wireless); if (num_bssids < 1) - goto next; + continue; ssid = nm_setting_wireless_get_ssid (s_wireless); g_assert (ssid); - for (i = 0; i < num_bssids; i++) { + for (i = 0; i < num_bssids && !done; i++) { const char *seen_bssid = nm_setting_wireless_get_seen_bssid (s_wireless, i); struct ether_addr seen_addr; - if (!ether_aton_r (seen_bssid, &seen_addr)) - continue; - - if (memcmp (ap_addr, &seen_addr, sizeof (struct ether_addr))) - continue; - - /* Copy the SSID from the connection to the AP */ - nm_ap_set_ssid (ap, ssid); - done = TRUE; + if (ether_aton_r (seen_bssid, &seen_addr)) { + if (memcmp (ap_addr, &seen_addr, sizeof (struct ether_addr))) { + /* Copy the SSID from the connection to the AP */ + nm_ap_set_ssid (ap, ssid); + done = TRUE; + } + } } - -next: - g_object_unref (connection); } g_slist_free (connections); } @@ -1902,90 +1286,40 @@ deactivate_disconnect_check_error (GError *auth_error, } else if (result != NM_AUTH_CALL_RESULT_YES) { return g_error_new (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - "Not authorized to %s user connections", + "Not authorized to %s connections", detail); } return NULL; } -static void -disconnect_user_auth_done_cb (NMAuthChain *chain, - GError *error, - DBusGMethodInvocation *context, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GError *ret_error = NULL; - NMAuthCallResult result; - NMDevice *device; - - priv->auth_chains = g_slist_remove (priv->auth_chains, chain); - - result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS)); - ret_error = deactivate_disconnect_check_error (error, result, "Disconnect"); - if (!ret_error) { - /* Everything authorized, deactivate the connection */ - device = nm_auth_chain_get_data (chain, "device"); - if (nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &ret_error)) - dbus_g_method_return (context); - } - - if (ret_error) - dbus_g_method_return_error (context, ret_error); - g_clear_error (&ret_error); - - nm_auth_chain_unref (chain); -} - static void disconnect_net_auth_done_cb (NMAuthChain *chain, - GError *error, + GError *auth_error, DBusGMethodInvocation *context, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GError *ret_error = NULL; + GError *error = NULL; NMAuthCallResult result; - NMConnectionScope scope; NMDevice *device; priv->auth_chains = g_slist_remove (priv->auth_chains, chain); result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL)); - ret_error = deactivate_disconnect_check_error (error, result, "Disconnect"); - if (ret_error) { - dbus_g_method_return_error (context, ret_error); - g_error_free (ret_error); - goto done; + error = deactivate_disconnect_check_error (auth_error, result, "Disconnect"); + if (!error) { + device = nm_auth_chain_get_data (chain, "device"); + if (!nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &error)) + g_assert (error); } - /* If it's a system connection, we're done */ - device = nm_auth_chain_get_data (chain, "device"); - scope = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "scope")); - if (scope == NM_CONNECTION_SCOPE_USER) { - NMAuthChain *user_chain; + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); - /* It's a user connection, so we need to ensure the caller is - * authorized to manipulate user connections. - */ - user_chain = nm_auth_chain_new (priv->authority, context, NULL, disconnect_user_auth_done_cb, self); - g_assert (user_chain); - priv->auth_chains = g_slist_append (priv->auth_chains, user_chain); - - nm_auth_chain_set_data (user_chain, "device", g_object_ref (device), g_object_unref); - nm_auth_chain_set_data (user_chain, "scope", GUINT_TO_POINTER (scope), NULL); - nm_auth_chain_add_call (user_chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, TRUE); - } else { - if (!nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &ret_error)) { - dbus_g_method_return_error (context, ret_error); - g_clear_error (&ret_error); - } else - dbus_g_method_return (context); - } - -done: + g_clear_error (&error); nm_auth_chain_unref (chain); } @@ -1996,11 +1330,9 @@ manager_device_disconnect_request (NMDevice *device, { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActRequest *req; - NMConnection *connection; GError *error = NULL; - NMConnectionScope scope; gulong sender_uid = G_MAXULONG; - const char *error_desc = NULL; + char *error_desc = NULL; req = nm_device_get_act_request (device); if (!req) { @@ -2012,24 +1344,19 @@ manager_device_disconnect_request (NMDevice *device, return; } - connection = nm_act_request_get_connection (req); - g_assert (connection); - /* Need to check the caller's permissions and stuff before we can * deactivate the connection. */ - scope = nm_connection_get_scope (connection); - if (!check_user_authorized (priv->dbus_mgr, - priv->user_proxy, - context, - scope, - &sender_uid, - &error_desc)) { + if (!nm_auth_get_caller_uid (context, + priv->dbus_mgr, + &sender_uid, + &error_desc)) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, error_desc); dbus_g_method_return_error (context, error); g_error_free (error); + g_free (error_desc); return; } @@ -2049,7 +1376,6 @@ manager_device_disconnect_request (NMDevice *device, priv->auth_chains = g_slist_append (priv->auth_chains, chain); nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref); - nm_auth_chain_set_data (chain, "scope", GUINT_TO_POINTER (scope), NULL); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); } } @@ -2063,8 +1389,6 @@ add_device (NMManager *self, NMDevice *device) static guint32 devcount = 0; const GSList *unmanaged_specs; NMConnection *existing = NULL; - GHashTableIter iter; - gpointer value; gboolean managed = FALSE, enabled = FALSE; iface = nm_device_get_ip_iface (device); @@ -2149,9 +1473,7 @@ add_device (NMManager *self, NMDevice *device) if (nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (device))) { GSList *connections = NULL; - g_hash_table_iter_init (&iter, priv->system_connections); - while (g_hash_table_iter_next (&iter, NULL, &value)) - connections = g_slist_append (connections, value); + connections = nm_settings_get_connections (priv->settings); existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device), (const GSList *) connections); g_slist_free (connections); @@ -2167,7 +1489,7 @@ add_device (NMManager *self, NMDevice *device) } /* Start the device if it's supposed to be managed */ - unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings); + unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); if ( !manager_sleeping (self) && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) { nm_device_set_managed (device, @@ -2177,7 +1499,7 @@ add_device (NMManager *self, NMDevice *device) managed = TRUE; } - nm_sysconfig_settings_device_added (priv->sys_settings, device); + nm_settings_device_added (priv->settings, device); g_signal_emit (self, signals[DEVICE_ADDED], 0, device); /* If the device has a connection it can assume, do that now */ @@ -2188,12 +1510,11 @@ add_device (NMManager *self, NMDevice *device) nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume existing connection", nm_device_get_iface (device)); - ac_path = internal_activate_device (self, device, existing, NULL, FALSE, TRUE, &error); + ac_path = internal_activate_device (self, device, existing, NULL, FALSE, 0, TRUE, &error); if (ac_path) g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); else { - nm_log_warn (LOGD_DEVICE, "assumed connection (%d) %s failed to activate: (%d) %s", - nm_connection_get_scope (existing), + nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s", nm_connection_get_path (existing), error ? error->code : -1, error && error->message ? error->message : "(unknown)"); @@ -2233,11 +1554,11 @@ bluez_manager_find_connection (NMManager *manager, const char *bdaddr, guint32 capabilities) { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); NMConnection *found = NULL; GSList *connections, *l; - connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM); - connections = g_slist_concat (connections, nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER)); + connections = nm_settings_get_connections (priv->settings); for (l = connections; l != NULL; l = l->next) { NMConnection *candidate = NM_CONNECTION (l->data); @@ -2517,302 +1838,13 @@ nm_manager_get_act_request_by_path (NMManager *manager, return NULL; } -typedef struct GetSecretsInfo { - NMManager *manager; - NMSecretsProviderInterface *provider; - - char *setting_name; - RequestSecretsCaller caller; - gboolean request_new; - - /* User connection bits */ - DBusGProxy *proxy; - DBusGProxyCall *call; - - /* System connection bits */ - guint32 idle_id; - char *hint1; - char *hint2; - char *connection_path; -} GetSecretsInfo; - -static void -free_get_secrets_info (gpointer data) -{ - GetSecretsInfo *info = data; - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (info->manager); - - g_object_weak_unref (G_OBJECT (info->provider), (GWeakNotify) free_get_secrets_info, info); - - priv->secrets_calls = g_slist_remove (priv->secrets_calls, info); - - if (info->proxy) { - if (info->call) - dbus_g_proxy_cancel_call (info->proxy, info->call); - g_object_unref (info->proxy); - } - - if (info->idle_id) - g_source_remove (info->idle_id); - - g_free (info->hint1); - g_free (info->hint2); - g_free (info->setting_name); - g_free (info->connection_path); - memset (info, 0, sizeof (GetSecretsInfo)); - g_free (info); -} - -static void -provider_cancel_secrets (NMSecretsProviderInterface *provider, gpointer user_data) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (user_data); - GSList *iter; - - for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) { - GetSecretsInfo *candidate = iter->data; - - if (candidate->provider == provider) { - free_get_secrets_info (candidate); - break; - } - } -} - -static void -user_get_secrets_cb (DBusGProxy *proxy, - DBusGProxyCall *call, - gpointer user_data) -{ - GetSecretsInfo *info = (GetSecretsInfo *) user_data; - GHashTable *settings = NULL; - GError *error = NULL; - GObject *provider; - - g_return_if_fail (info != NULL); - g_return_if_fail (info->provider); - g_return_if_fail (info->setting_name); - - provider = g_object_ref (info->provider); - - if (dbus_g_proxy_end_call (proxy, call, &error, - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings, - G_TYPE_INVALID)) { - nm_secrets_provider_interface_get_secrets_result (info->provider, - info->setting_name, - info->caller, - settings, - NULL); - g_hash_table_destroy (settings); - } else { - nm_secrets_provider_interface_get_secrets_result (info->provider, - info->setting_name, - info->caller, - NULL, - error); - g_clear_error (&error); - } - - info->call = NULL; - free_get_secrets_info (info); - - g_object_unref (provider); -} - -static GetSecretsInfo * -user_get_secrets (NMManager *self, - NMSecretsProviderInterface *provider, - NMConnection *connection, - const char *setting_name, - gboolean request_new, - RequestSecretsCaller caller_id, - const char *hint1, - const char *hint2) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - DBusGConnection *g_connection; - GetSecretsInfo *info = NULL; - GPtrArray *hints = NULL; - - info = g_malloc0 (sizeof (GetSecretsInfo)); - - g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr); - info->proxy = dbus_g_proxy_new_for_name (g_connection, - NM_DBUS_SERVICE_USER_SETTINGS, - nm_connection_get_path (connection), - NM_DBUS_IFACE_SETTINGS_CONNECTION_SECRETS); - if (!info->proxy) { - nm_log_warn (LOGD_USER_SET, "could not create user connection secrets proxy"); - g_free (info); - return NULL; - } - - info->manager = self; - info->provider = provider; - info->caller = caller_id; - info->setting_name = g_strdup (setting_name); - - g_object_weak_ref (G_OBJECT (provider), (GWeakNotify) free_get_secrets_info, info); - - hints = g_ptr_array_sized_new (2); - if (hint1) - g_ptr_array_add (hints, (char *) hint1); - if (hint2) - g_ptr_array_add (hints, (char *) hint2); - - info->call = dbus_g_proxy_begin_call_with_timeout (info->proxy, "GetSecrets", - user_get_secrets_cb, - info, - NULL, - G_MAXINT32, - G_TYPE_STRING, setting_name, - DBUS_TYPE_G_ARRAY_OF_STRING, hints, - G_TYPE_BOOLEAN, request_new, - G_TYPE_INVALID); - g_ptr_array_free (hints, TRUE); - return info; -} - -static void -system_get_secrets_reply_cb (NMSettingsConnectionInterface *connection, - GHashTable *secrets, - GError *error, - gpointer user_data) -{ - GetSecretsInfo *info = user_data; - GObject *provider; - - provider = g_object_ref (info->provider); - - nm_secrets_provider_interface_get_secrets_result (info->provider, - info->setting_name, - info->caller, - error ? NULL : secrets, - error); - free_get_secrets_info (info); - g_object_unref (provider); -} - -static gboolean -system_get_secrets_idle_cb (gpointer user_data) -{ - GetSecretsInfo *info = user_data; - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (info->manager); - NMSettingsConnectionInterface *connection; - GError *error = NULL; - const char *hints[3] = { NULL, NULL, NULL }; - - info->idle_id = 0; - - connection = nm_settings_interface_get_connection_by_path (NM_SETTINGS_INTERFACE (priv->sys_settings), - info->connection_path); - if (!connection) { - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "unknown connection (not exported by system settings)"); - nm_secrets_provider_interface_get_secrets_result (info->provider, - info->setting_name, - info->caller, - NULL, - error); - g_error_free (error); - free_get_secrets_info (info); - return FALSE; - } - - hints[0] = info->hint1; - hints[1] = info->hint2; - nm_settings_connection_interface_get_secrets (connection, - info->setting_name, - hints, - info->request_new, - system_get_secrets_reply_cb, - info); - return FALSE; -} - -static GetSecretsInfo * -system_get_secrets (NMManager *self, - NMSecretsProviderInterface *provider, - NMConnection *connection, - const char *setting_name, - gboolean request_new, - RequestSecretsCaller caller_id, - const char *hint1, - const char *hint2) -{ - GetSecretsInfo *info; - - info = g_malloc0 (sizeof (GetSecretsInfo)); - info->manager = self; - info->provider = provider; - info->caller = caller_id; - info->setting_name = g_strdup (setting_name); - info->hint1 = hint1 ? g_strdup (hint1) : NULL; - info->hint2 = hint2 ? g_strdup (hint2) : NULL; - info->connection_path = g_strdup (nm_connection_get_path (connection)); - info->request_new = request_new; - - g_object_weak_ref (G_OBJECT (provider), (GWeakNotify) free_get_secrets_info, info); - - info->idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, - system_get_secrets_idle_cb, - info, - NULL); - return info; -} - -static gboolean -provider_get_secrets (NMSecretsProviderInterface *provider, - NMConnection *connection, - const char *setting_name, - gboolean request_new, - RequestSecretsCaller caller_id, - const char *hint1, - const char *hint2, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GetSecretsInfo *info = NULL; - NMConnectionScope scope; - GSList *iter; - - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (setting_name != NULL, FALSE); - - /* Tear down any pending secrets requests for this secrets provider */ - for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) { - GetSecretsInfo *candidate = iter->data; - - if (provider == candidate->provider) { - free_get_secrets_info (candidate); - break; - } - } - - /* Build up the new secrets request */ - scope = nm_connection_get_scope (connection); - if (scope == NM_CONNECTION_SCOPE_SYSTEM) { - info = system_get_secrets (self, provider, connection, setting_name, - request_new, caller_id, hint1, hint2); - } else if (scope == NM_CONNECTION_SCOPE_USER) { - info = user_get_secrets (self, provider, connection, setting_name, - request_new, caller_id, hint1, hint2); - } - - if (info) - priv->secrets_calls = g_slist_append (priv->secrets_calls, info); - - return !!info; -} - static const char * internal_activate_device (NMManager *manager, NMDevice *device, NMConnection *connection, const char *specific_object, gboolean user_requested, + gulong sender_uid, gboolean assumed, GError **error) { @@ -2837,42 +1869,24 @@ internal_activate_device (NMManager *manager, NM_DEVICE_STATE_REASON_NONE); } - req = nm_act_request_new (connection, specific_object, user_requested, assumed, (gpointer) device); - g_signal_connect (req, "manager-get-secrets", G_CALLBACK (provider_get_secrets), manager); - g_signal_connect (req, "manager-cancel-secrets", G_CALLBACK (provider_cancel_secrets), manager); + req = nm_act_request_new (connection, + specific_object, + user_requested, + sender_uid, + assumed, + (gpointer) device); success = nm_device_interface_activate (dev_iface, req, error); g_object_unref (req); return success ? nm_act_request_get_active_connection_path (req) : NULL; } -static gboolean -wait_for_connection_expired (gpointer data) -{ - PendingActivation *pending = data; - GError *error = NULL; - - g_return_val_if_fail (pending != NULL, FALSE); - - nm_log_warn (LOGD_CORE, "connection %s (scope %d) failed to activate (timeout)", - pending->connection_path, pending->scope); - - nm_manager_pending_activation_remove (pending->manager, pending); - - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "Connection was not provided by any settings service"); - pending_activation_destroy (pending, error, NULL); - g_error_free (error); - return FALSE; -} - const char * nm_manager_activate_connection (NMManager *manager, NMConnection *connection, const char *specific_object, const char *device_path, - gboolean user_requested, + const char *dbus_sender, GError **error) { NMManagerPrivate *priv; @@ -2880,6 +1894,8 @@ nm_manager_activate_connection (NMManager *manager, NMSettingConnection *s_con; NMVPNConnection *vpn_connection; const char *path = NULL; + gulong sender_uid = 0; + DBusError dbus_error; g_return_val_if_fail (manager != NULL, NULL); g_return_val_if_fail (connection != NULL, NULL); @@ -2888,19 +1904,34 @@ nm_manager_activate_connection (NMManager *manager, priv = NM_MANAGER_GET_PRIVATE (manager); + /* Get the UID of the user that originated the request, if any */ + if (dbus_sender) { + dbus_error_init (&dbus_error); + sender_uid = dbus_bus_get_unix_user (nm_dbus_manager_get_dbus_connection (priv->dbus_mgr), + dbus_sender, + &dbus_error); + if (dbus_error_is_set (&dbus_error)) { + g_set_error_literal (error, + NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, + "Failed to get unix user for dbus sender"); + dbus_error_free (&dbus_error); + return NULL; + } + } + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); g_assert (s_con); if (!strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_VPN_SETTING_NAME)) { - NMActRequest *req = NULL; + NMActRequest *parent_req = NULL; NMVPNManager *vpn_manager; /* VPN connection */ if (specific_object) { /* Find the specifc connection the client requested we use */ - req = nm_manager_get_act_request_by_path (manager, specific_object, &device); - if (!req) { + parent_req = nm_manager_get_act_request_by_path (manager, specific_object, &device); + if (!parent_req) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "%s", "Base connection for VPN connection not active."); @@ -2917,13 +1948,13 @@ nm_manager_activate_connection (NMManager *manager, candidate_req = nm_device_get_act_request (candidate); if (candidate_req && nm_act_request_get_default (candidate_req)) { device = candidate; - req = candidate_req; + parent_req = candidate_req; break; } } } - if (!device || !req) { + if (!device || !parent_req) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "%s", "Could not find source connection, or the source connection had no active device."); @@ -2933,16 +1964,13 @@ nm_manager_activate_connection (NMManager *manager, vpn_manager = nm_vpn_manager_get (); vpn_connection = nm_vpn_manager_activate_connection (vpn_manager, connection, - req, + parent_req, device, + TRUE, + sender_uid, error); - if (vpn_connection) { - g_signal_connect (vpn_connection, "manager-get-secrets", - G_CALLBACK (provider_get_secrets), manager); - g_signal_connect (vpn_connection, "manager-cancel-secrets", - G_CALLBACK (provider_cancel_secrets), manager); + if (vpn_connection) path = nm_vpn_connection_get_active_connection_path (vpn_connection); - } g_object_unref (vpn_manager); } else { NMDeviceState state; @@ -2968,7 +1996,8 @@ nm_manager_activate_connection (NMManager *manager, device, connection, specific_object, - user_requested, + dbus_sender ? TRUE : FALSE, + dbus_sender ? sender_uid : 0, FALSE, error); } @@ -2976,40 +2005,24 @@ nm_manager_activate_connection (NMManager *manager, return path; } -static PendingActivation * -nm_manager_pending_activation_find (NMManager *self, - const char *path, - NMConnectionScope scope) +/* + * TODO this function was created and named in the era of user settings, where + * we could get activation requests for a connection before we got the settings + * data of that connection. Now that user settings are gone, flatten or rename + * it. + */ +static void +pending_activate (NMManager *self, PendingActivation *pending) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->pending_activations; iter; iter = g_slist_next (iter)) { - PendingActivation *pending = iter->data; - - if (!strcmp (pending->connection_path, path) && (pending->scope == scope)) - return pending; - } - return NULL; -} - -static void -check_pending_ready (NMManager *self, PendingActivation *pending) -{ - NMConnection *connection; + NMSettingsConnection *connection; const char *path = NULL; GError *error = NULL; + char *sender; - if (!pending->have_connection || !pending->authorized) - return; + /* Ok, we're authorized */ - /* Ok, we're authorized and the connection is available */ - - nm_manager_pending_activation_remove (self, pending); - - connection = nm_manager_get_connection_by_object_path (self, - pending->scope, - pending->connection_path); + connection = nm_settings_get_connection_by_path (priv->settings, pending->connection_path); if (!connection) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, @@ -3017,15 +2030,19 @@ check_pending_ready (NMManager *self, PendingActivation *pending) goto out; } + sender = dbus_g_method_get_sender (pending->context); + g_assert (sender); path = nm_manager_activate_connection (self, - connection, + NM_CONNECTION (connection), pending->specific_object_path, pending->device_path, - TRUE, + sender, &error); + g_free (sender); + if (!path) { - nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate: (%d) %s", - pending->scope, pending->connection_path, error->code, error->message); + nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s", + pending->connection_path, error->code, error->message); } else g_object_notify (G_OBJECT (pending->manager), NM_MANAGER_ACTIVE_CONNECTIONS); @@ -3034,70 +2051,26 @@ out: g_clear_error (&error); } -static void -connection_added_default_handler (NMManager *self, - NMConnection *connection, - NMConnectionScope scope) -{ - PendingActivation *pending; - - pending = nm_manager_pending_activation_find (self, - nm_connection_get_path (connection), - scope); - if (pending) { - pending->have_connection = TRUE; - check_pending_ready (self, pending); - } -} - static void activation_auth_done (PendingActivation *pending, GError *error) { - if (error) { - nm_manager_pending_activation_remove (pending->manager, pending); + if (error) pending_activation_destroy (pending, error, NULL); - return; - } else { - pending->authorized = TRUE; - - /* Now that we're authorized, if the connection hasn't shown up yet, - * start a timer and wait for it. - */ - if (!pending->have_connection && !pending->timeout_id) - pending->timeout_id = g_timeout_add_seconds (5, wait_for_connection_expired, pending); - - check_pending_ready (pending->manager, pending); - } + else + pending_activate (pending->manager, pending); } static void impl_manager_activate_connection (NMManager *self, - const char *service_name, const char *connection_path, const char *device_path, const char *specific_object_path, DBusGMethodInvocation *context) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMConnectionScope scope = NM_CONNECTION_SCOPE_UNKNOWN; PendingActivation *pending; GError *error = NULL; - if (!strcmp (service_name, NM_DBUS_SERVICE_USER_SETTINGS)) - scope = NM_CONNECTION_SCOPE_USER; - else if (!strcmp (service_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS)) - scope = NM_CONNECTION_SCOPE_SYSTEM; - else { - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_INVALID_SERVICE, - "Invalid settings service name"); - dbus_g_method_return_error (context, error); - nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate: (%d) %s", - scope, connection_path, error->code, error->message); - g_error_free (error); - return; - } - /* Need to check the caller's permissions and stuff before we can * activate the connection. */ @@ -3105,16 +2078,87 @@ impl_manager_activate_connection (NMManager *self, priv->authority, context, device_path, - scope, connection_path, + NULL, specific_object_path, - activation_auth_done); - priv->pending_activations = g_slist_prepend (priv->pending_activations, pending); + activation_auth_done, + &error); + if (pending) + pending_activation_check_authorized (pending, priv->dbus_mgr); + else { + g_assert (error); + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} - if (nm_manager_get_connection_by_object_path (self, scope, connection_path)) - pending->have_connection = TRUE; +static void +activation_add_done (NMSettings *self, + NMSettingsConnection *connection, + GError *error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + PendingActivation *pending = user_data; - pending_activation_check_authorized (pending, priv->dbus_mgr, priv->user_proxy); + if (error) + pending_activation_destroy (pending, error, NULL); + else { + /* Save the new connection's D-Bus path */ + pending->connection_path = g_strdup (nm_connection_get_path (NM_CONNECTION (connection))); + + /* And activate it */ + pending_activate (pending->manager, pending); + } +} + +static void +add_and_activate_auth_done (PendingActivation *pending, GError *error) +{ + if (error) + pending_activation_destroy (pending, error, NULL); + else { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager); + + /* Basic sender auth checks performed; try to add the connection */ + nm_settings_add_connection (priv->settings, + pending->connection, + pending->context, + activation_add_done, + pending); + } +} + +static void +impl_manager_add_and_activate_connection (NMManager *self, + GHashTable *settings, + const char *device_path, + const char *specific_object_path, + DBusGMethodInvocation *context) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + PendingActivation *pending; + GError *error = NULL; + + /* Need to check the caller's permissions and stuff before we can + * activate the connection. + */ + pending = pending_activation_new (self, + priv->authority, + context, + device_path, + NULL, + settings, + specific_object_path, + add_and_activate_auth_done, + &error); + if (pending) + pending_activation_check_authorized (pending, priv->dbus_mgr); + else { + g_assert (error); + dbus_g_method_return_error (context, error); + g_error_free (error); + } } gboolean @@ -3165,37 +2209,6 @@ done: return success; } -static void -deactivate_user_auth_done_cb (NMAuthChain *chain, - GError *error, - DBusGMethodInvocation *context, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GError *ret_error = NULL; - NMAuthCallResult result; - - priv->auth_chains = g_slist_remove (priv->auth_chains, chain); - - result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS)); - ret_error = deactivate_disconnect_check_error (error, result, "Deactivate"); - if (!ret_error) { - /* Everything authorized, deactivate the connection */ - if (nm_manager_deactivate_connection (self, - nm_auth_chain_get_data (chain, "path"), - NM_DEVICE_STATE_REASON_USER_REQUESTED, - &ret_error)) - dbus_g_method_return (context); - } - - if (ret_error) - dbus_g_method_return_error (context, ret_error); - g_clear_error (&ret_error); - - nm_auth_chain_unref (chain); -} - static void deactivate_net_auth_done_cb (NMAuthChain *chain, GError *error, @@ -3207,7 +2220,6 @@ deactivate_net_auth_done_cb (NMAuthChain *chain, GError *ret_error = NULL; NMAuthCallResult result; const char *active_path; - NMConnectionScope scope; priv->auth_chains = g_slist_remove (priv->auth_chains, chain); @@ -3219,32 +2231,15 @@ deactivate_net_auth_done_cb (NMAuthChain *chain, goto done; } - /* If it's a system connection, we're done */ active_path = nm_auth_chain_get_data (chain, "path"); - scope = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "scope")); - if (scope == NM_CONNECTION_SCOPE_USER) { - NMAuthChain *user_chain; - - /* It's a user connection, so we need to ensure the caller is - * authorized to manipulate user connections. - */ - user_chain = nm_auth_chain_new (priv->authority, context, NULL, deactivate_user_auth_done_cb, self); - g_assert (user_chain); - priv->auth_chains = g_slist_append (priv->auth_chains, user_chain); - - nm_auth_chain_set_data (user_chain, "path", g_strdup (active_path), g_free); - nm_auth_chain_set_data (user_chain, "scope", GUINT_TO_POINTER (scope), NULL); - nm_auth_chain_add_call (user_chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, TRUE); - } else { - if (!nm_manager_deactivate_connection (self, - active_path, - NM_DEVICE_STATE_REASON_USER_REQUESTED, - &ret_error)) { - dbus_g_method_return_error (context, ret_error); - g_clear_error (&ret_error); - } else - dbus_g_method_return (context); - } + if (!nm_manager_deactivate_connection (self, + active_path, + NM_DEVICE_STATE_REASON_USER_REQUESTED, + &ret_error)) { + dbus_g_method_return_error (context, ret_error); + g_clear_error (&ret_error); + } else + dbus_g_method_return (context); done: nm_auth_chain_unref (chain); @@ -3261,8 +2256,7 @@ impl_manager_deactivate_connection (NMManager *self, GSList *iter; NMAuthChain *chain; gulong sender_uid = G_MAXULONG; - NMConnectionScope scope; - const char *error_desc = NULL; + char *error_desc = NULL; /* Check for device connections first */ for (iter = priv->devices; iter; iter = g_slist_next (iter)) { @@ -3295,18 +2289,16 @@ impl_manager_deactivate_connection (NMManager *self, /* Need to check the caller's permissions and stuff before we can * deactivate the connection. */ - scope = nm_connection_get_scope (connection); - if (!check_user_authorized (priv->dbus_mgr, - priv->user_proxy, - context, - scope, - &sender_uid, - &error_desc)) { + if (!nm_auth_get_caller_uid (context, + priv->dbus_mgr, + &sender_uid, + &error_desc)) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, error_desc); dbus_g_method_return_error (context, error); g_error_free (error); + g_free (error_desc); return; } @@ -3330,7 +2322,6 @@ impl_manager_deactivate_connection (NMManager *self, priv->auth_chains = g_slist_append (priv->auth_chains, chain); nm_auth_chain_set_data (chain, "path", g_strdup (active_path), g_free); - nm_auth_chain_set_data (chain, "scope", GUINT_TO_POINTER (scope), NULL); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); } @@ -3354,7 +2345,7 @@ do_sleep_wake (NMManager *self) } else { nm_log_info (LOGD_SUSPEND, "waking up and re-enabling..."); - unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings); + unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); /* Ensure rfkill state is up-to-date since we don't respond to state * changes during sleep. @@ -3640,7 +2631,7 @@ impl_manager_enable (NMManager *self, NMAuthChain *chain; GError *error = NULL; gulong sender_uid = G_MAXULONG; - const char *error_desc = NULL; + char *error_desc = NULL; g_return_if_fail (NM_IS_MANAGER (self)); @@ -3661,6 +2652,7 @@ impl_manager_enable (NMManager *self, error_desc); dbus_g_method_return_error (context, error); g_error_free (error); + g_free (error_desc); return; } @@ -3684,61 +2676,9 @@ impl_manager_enable (NMManager *self, /* Permissions */ -static void -user_proxy_permissions_changed_done (NMAuthChain *chain, - GError *error, - DBusGMethodInvocation *context, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gboolean authorized = FALSE; - - priv->auth_chains = g_slist_remove (priv->auth_chains, chain); - - if (error) { - nm_log_warn (LOGD_USER_SET, "User connections unavailable: (%d) %s", - error->code, error->message ? error->message : "(unknown)"); - } else - authorized = user_settings_authorized (self, chain); - - if (authorized) { - /* User connections are authorized */ - if (!priv->user_proxy) - user_proxy_init (self); - } else - user_proxy_cleanup (self, TRUE); - - nm_auth_chain_unref (chain); -} - static void pk_authority_changed_cb (GObject *object, gpointer user_data) { - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMAuthChain *chain; - - /* If the user settings service wasn't previously authorized, we wouldn't - * care about it. But it might be authorized now, so lets check. - */ - if (!priv->user_proxy) - user_proxy_init (self); - else { - /* Otherwise the user settings permissions could have changed so we - * need to recheck them. - */ - chain = nm_auth_chain_new (priv->authority, - NULL, - priv->user_proxy, - user_proxy_permissions_changed_done, - self); - priv->auth_chains = g_slist_prepend (priv->auth_chains, chain); - - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE); - } - /* Let clients know they should re-check their authorization */ g_signal_emit (NM_MANAGER (user_data), signals[CHECK_PERMISSIONS], 0); } @@ -3787,8 +2727,12 @@ get_permissions_done_cb (NMAuthChain *chain, get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI); get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN); get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS); get_perm_add_result (chain, results, NM_AUTH_PERMISSION_NETWORK_CONTROL); + get_perm_add_result (chain, results, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); + get_perm_add_result (chain, results, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN); + get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM); + get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN); + get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME); dbus_g_method_return (context, results); g_hash_table_destroy (results); } @@ -3815,8 +2759,12 @@ impl_manager_get_permissions (NMManager *self, nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, FALSE); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, FALSE); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE); } /* Legacy 0.6 compatibility interface */ @@ -3861,94 +2809,6 @@ impl_manager_set_logging (NMManager *manager, return FALSE; } -/* Connections */ - -gboolean -nm_manager_auto_user_connections_allowed (NMManager *self) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - - return priv->user_net_perm == NM_AUTH_CALL_RESULT_YES - && priv->user_con_perm == NM_AUTH_CALL_RESULT_YES; -} - -static int -connection_sort (gconstpointer pa, gconstpointer pb) -{ - NMConnection *a = NM_CONNECTION (pa); - NMSettingConnection *con_a; - NMConnection *b = NM_CONNECTION (pb); - NMSettingConnection *con_b; - - con_a = (NMSettingConnection *) nm_connection_get_setting (a, NM_TYPE_SETTING_CONNECTION); - g_assert (con_a); - con_b = (NMSettingConnection *) nm_connection_get_setting (b, NM_TYPE_SETTING_CONNECTION); - g_assert (con_b); - - if (nm_setting_connection_get_autoconnect (con_a) != nm_setting_connection_get_autoconnect (con_b)) { - if (nm_setting_connection_get_autoconnect (con_a)) - return -1; - return 1; - } - - if (nm_setting_connection_get_timestamp (con_a) > nm_setting_connection_get_timestamp (con_b)) - return -1; - else if (nm_setting_connection_get_timestamp (con_a) == nm_setting_connection_get_timestamp (con_b)) - return 0; - return 1; -} - -static void -connections_to_slist (gpointer key, gpointer value, gpointer user_data) -{ - GSList **list = (GSList **) user_data; - - *list = g_slist_insert_sorted (*list, g_object_ref (value), connection_sort); -} - -/* Returns a GSList of referenced NMConnection objects, caller must - * unref the connections in the list and destroy the list. - */ -GSList * -nm_manager_get_connections (NMManager *manager, - NMConnectionScope scope) -{ - NMManagerPrivate *priv; - GSList *list = NULL; - - g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); - - priv = NM_MANAGER_GET_PRIVATE (manager); - if (scope == NM_CONNECTION_SCOPE_USER) - g_hash_table_foreach (priv->user_connections, connections_to_slist, &list); - else if (scope == NM_CONNECTION_SCOPE_SYSTEM) - g_hash_table_foreach (priv->system_connections, connections_to_slist, &list); - else - nm_log_err (LOGD_CORE, "unknown NMConnectionScope %d", scope); - return list; -} - -NMConnection * -nm_manager_get_connection_by_object_path (NMManager *manager, - NMConnectionScope scope, - const char *path) -{ - NMManagerPrivate *priv; - NMConnection *connection = NULL; - - g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); - g_return_val_if_fail (path != NULL, NULL); - - priv = NM_MANAGER_GET_PRIVATE (manager); - if (scope == NM_CONNECTION_SCOPE_USER) - connection = (NMConnection *) g_hash_table_lookup (priv->user_connections, path); - else if (scope == NM_CONNECTION_SCOPE_SYSTEM) - connection = (NMConnection *) g_hash_table_lookup (priv->system_connections, path); - else - nm_log_err (LOGD_CORE, "unknown NMConnectionScope %d", scope); - return connection; -} - GPtrArray * nm_manager_get_active_connections_by_connection (NMManager *manager, NMConnection *connection) @@ -3986,15 +2846,8 @@ nm_manager_start (NMManager *self) nm_log_info (LOGD_CORE, "Networking is %s by state file", priv->net_enabled ? "enabled" : "disabled"); - system_unmanaged_devices_changed_cb (priv->sys_settings, NULL, self); - system_hostname_changed_cb (priv->sys_settings, NULL, self); - system_query_connections (self); - - /* Get user connections if the user settings service is around, otherwise - * they will be queried when the user settings service shows up on the - * bus in nm_manager_name_owner_changed(). - */ - user_proxy_init (self); + system_unmanaged_devices_changed_cb (priv->settings, NULL, self); + system_hostname_changed_cb (priv->settings, NULL, self); nm_udev_manager_query_devices (priv->udev_mgr); bluez_manager_resync_devices (self); @@ -4218,13 +3071,14 @@ out: } NMManager * -nm_manager_get (const char *config_file, +nm_manager_get (NMSettings *settings, + const char *config_file, const char *plugins, const char *state_file, gboolean initial_net_enabled, gboolean initial_wifi_enabled, gboolean initial_wwan_enabled, - gboolean initial_wimax_enabled, + gboolean initial_wimax_enabled, GError **error) { static NMManager *singleton = NULL; @@ -4235,6 +3089,8 @@ nm_manager_get (const char *config_file, if (singleton) return g_object_ref (singleton); + g_assert (settings); + singleton = (NMManager *) g_object_new (NM_TYPE_MANAGER, NULL); g_assert (singleton); @@ -4251,15 +3107,9 @@ nm_manager_get (const char *config_file, return NULL; } - priv->sys_settings = nm_sysconfig_settings_new (config_file, plugins, bus, error); - if (!priv->sys_settings) { - g_object_unref (singleton); - return NULL; - } - nm_settings_service_export (NM_SETTINGS_SERVICE (priv->sys_settings)); + priv->settings = g_object_ref (settings); priv->config_file = g_strdup (config_file); - priv->state_file = g_strdup (state_file); priv->net_enabled = initial_net_enabled; @@ -4268,21 +3118,20 @@ nm_manager_get (const char *config_file, priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = initial_wwan_enabled; priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = initial_wimax_enabled; - g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS, + g_signal_connect (priv->settings, "notify::" NM_SETTINGS_UNMANAGED_SPECS, G_CALLBACK (system_unmanaged_devices_changed_cb), singleton); - g_signal_connect (priv->sys_settings, "notify::" NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME, + g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME, G_CALLBACK (system_hostname_changed_cb), singleton); - g_signal_connect (priv->sys_settings, "new-connection", - G_CALLBACK (system_new_connection_cb), singleton); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, + G_CALLBACK (connections_changed), singleton); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, + G_CALLBACK (connections_changed), singleton); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, + G_CALLBACK (connections_changed), singleton); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, + G_CALLBACK (connections_changed), singleton); - dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr), - NM_DBUS_PATH, - G_OBJECT (singleton)); - - g_signal_connect (priv->dbus_mgr, - "name-owner-changed", - G_CALLBACK (nm_manager_name_owner_changed), - singleton); + dbus_g_connection_register_g_object (bus, NM_DBUS_PATH, G_OBJECT (singleton)); priv->udev_mgr = nm_udev_manager_new (); g_signal_connect (priv->udev_mgr, @@ -4318,7 +3167,6 @@ dispose (GObject *object) { NMManager *manager = NM_MANAGER (object); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *iter; DBusGConnection *bus; DBusConnection *dbus_connection; @@ -4328,18 +3176,10 @@ dispose (GObject *object) } priv->disposed = TRUE; - for (iter = priv->pending_activations; iter; iter = g_slist_next (iter)) - pending_activation_destroy ((PendingActivation *) iter->data, NULL, NULL); - g_slist_free (priv->pending_activations); - priv->pending_activations = NULL; - g_slist_foreach (priv->auth_chains, (GFunc) nm_auth_chain_unref, NULL); g_slist_free (priv->auth_chains); g_object_unref (priv->authority); - while (g_slist_length (priv->secrets_calls)) - free_get_secrets_info ((GetSecretsInfo *) priv->secrets_calls->data); - while (g_slist_length (priv->devices)) { priv->devices = remove_one_device (manager, priv->devices, @@ -4347,22 +3187,10 @@ dispose (GObject *object) TRUE); } - user_proxy_cleanup (manager, FALSE); - g_hash_table_destroy (priv->user_connections); - priv->user_connections = NULL; - - g_hash_table_foreach (priv->system_connections, emit_removed, manager); - g_hash_table_remove_all (priv->system_connections); - g_hash_table_destroy (priv->system_connections); - priv->system_connections = NULL; - g_free (priv->hostname); g_free (priv->config_file); - if (priv->sys_settings) { - g_object_unref (priv->sys_settings); - priv->sys_settings = NULL; - } + g_object_unref (priv->settings); if (priv->vpn_manager_id) { g_source_remove (priv->vpn_manager_id); @@ -4603,16 +3431,6 @@ nm_manager_init (NMManager *manager) priv->dbus_mgr = nm_dbus_manager_get (); - priv->user_connections = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - - priv->system_connections = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - priv->modem_manager = nm_modem_manager_get (); priv->modem_added_id = g_signal_connect (priv->modem_manager, "modem-added", G_CALLBACK (modem_added), manager); @@ -4710,8 +3528,6 @@ nm_manager_class_init (NMManagerClass *manager_class) g_type_class_add_private (manager_class, sizeof (NMManagerPrivate)); /* virtual methods */ - manager_class->connection_added = connection_added_default_handler; - object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; @@ -4847,42 +3663,6 @@ nm_manager_class_init (NMManagerClass *manager_class) nm_properties_changed_signal_new (object_class, G_STRUCT_OFFSET (NMManagerClass, properties_changed)); - signals[CONNECTIONS_ADDED] = - g_signal_new ("connections-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMManagerClass, connections_added), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - signals[CONNECTION_ADDED] = - g_signal_new ("connection-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMManagerClass, connection_added), - NULL, NULL, - _nm_marshal_VOID__OBJECT_UINT, - G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT); - - signals[CONNECTION_UPDATED] = - g_signal_new ("connection-updated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMManagerClass, connection_updated), - NULL, NULL, - _nm_marshal_VOID__OBJECT_UINT, - G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT); - - signals[CONNECTION_REMOVED] = - g_signal_new ("connection-removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMManagerClass, connection_removed), - NULL, NULL, - _nm_marshal_VOID__OBJECT_UINT, - G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT); - signals[CHECK_PERMISSIONS] = g_signal_new ("check-permissions", G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/nm-manager.h b/src/nm-manager.h index 42472407d1..22bfca9e8b 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -20,13 +20,14 @@ */ #ifndef NM_MANAGER_H -#define NM_MANAGER_H 1 +#define NM_MANAGER_H #include #include #include #include "nm-device.h" #include "nm-device-interface.h" +#include "nm-settings.h" #define NM_TYPE_MANAGER (nm_manager_get_type ()) #define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MANAGER, NMManager)) @@ -62,25 +63,12 @@ typedef struct { void (*device_removed) (NMManager *manager, NMDevice *device); void (*state_changed) (NMManager *manager, guint state); void (*properties_changed) (NMManager *manager, GHashTable *properties); - - void (*connections_added) (NMManager *manager, NMConnectionScope scope); - - void (*connection_added) (NMManager *manager, - NMConnection *connection, - NMConnectionScope scope); - - void (*connection_updated) (NMManager *manager, - NMConnection *connection, - NMConnectionScope scope); - - void (*connection_removed) (NMManager *manager, - NMConnection *connection, - NMConnectionScope scope); } NMManagerClass; GType nm_manager_get_type (void); -NMManager *nm_manager_get (const char *config_file, +NMManager *nm_manager_get (NMSettings *settings, + const char *config_file, const char *plugins, const char *state_file, gboolean initial_net_enabled, @@ -99,7 +87,7 @@ const char * nm_manager_activate_connection (NMManager *manager, NMConnection *connection, const char *specific_object, const char *device_path, - gboolean user_requested, + const char *dbus_sender, /* NULL if automatic */ GError **error); gboolean nm_manager_deactivate_connection (NMManager *manager, @@ -111,16 +99,6 @@ gboolean nm_manager_deactivate_connection (NMManager *manager, NMState nm_manager_get_state (NMManager *manager); -/* Connections */ - -GSList *nm_manager_get_connections (NMManager *manager, NMConnectionScope scope); - -gboolean nm_manager_auto_user_connections_allowed (NMManager *manager); - -NMConnection * nm_manager_get_connection_by_object_path (NMManager *manager, - NMConnectionScope scope, - const char *path); - GPtrArray * nm_manager_get_active_connections_by_connection (NMManager *manager, NMConnection *connection); diff --git a/src/nm-policy.c b/src/nm-policy.c index 8650dfed40..06cdb24bb7 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -51,13 +51,16 @@ struct NMPolicy { NMManager *manager; guint update_state_id; GSList *pending_activation_checks; - GSList *signal_ids; - GSList *dev_signal_ids; + GSList *manager_ids; + GSList *settings_ids; + GSList *dev_ids; NMVPNManager *vpn_manager; gulong vpn_activated_id; gulong vpn_deactivated_id; + NMSettings *settings; + NMDevice *default_device4; NMDevice *default_device6; @@ -292,7 +295,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6) /* Hostname precedence order: * - * 1) a configured hostname (from system-settings) + * 1) a configured hostname (from settings) * 2) automatic hostname from the default device's config (DHCP, VPN, etc) * 3) the original hostname when NM started * 4) reverse-DNS of the best device's IPv4 address @@ -716,32 +719,35 @@ auto_activate_device (gpointer user_data) if (nm_device_get_act_request (data->device)) goto out; - /* System connections first, then user connections */ - connections = nm_manager_get_connections (policy->manager, NM_CONNECTION_SCOPE_SYSTEM); - if (nm_manager_auto_user_connections_allowed (policy->manager)) - connections = g_slist_concat (connections, nm_manager_get_connections (policy->manager, NM_CONNECTION_SCOPE_USER)); + iter = connections = nm_settings_get_connections (policy->settings); - /* Remove connections that have INVALID_TAG and shouldn't be retried any more. */ - iter = connections; + /* Remove connections that shouldn't be auto-activated */ while (iter) { - NMConnection *iter_connection = NM_CONNECTION (iter->data); - GSList *next = g_slist_next (iter); + NMConnection *candidate = NM_CONNECTION (iter->data); + gboolean ignore = FALSE; - if (g_object_get_data (G_OBJECT (iter_connection), INVALID_TAG)) { - guint retries = get_connection_auto_retries (iter_connection); + /* Ignore connecitons that were tried too many times */ + if (g_object_get_data (G_OBJECT (candidate), INVALID_TAG)) { + guint retries = get_connection_auto_retries (candidate); - if (retries == 0) { - connections = g_slist_remove_link (connections, iter); - g_object_unref (iter_connection); - g_slist_free (iter); - } else if (retries > 0) - set_connection_auto_retries (iter_connection, retries - 1); + if (retries == 0) + ignore = TRUE; + else if (retries > 0) + set_connection_auto_retries (candidate, retries - 1); } else { /* Set the initial # of retries for auto-connection */ - set_connection_auto_retries (iter_connection, RETRIES_DEFAULT); + set_connection_auto_retries (candidate, RETRIES_DEFAULT); } - iter = next; + /* Ignore connections that aren't visible to any logged-in users */ + if (ignore == FALSE) { + if (!nm_settings_connection_is_visible (NM_SETTINGS_CONNECTION (candidate))) + ignore = TRUE; + } + + iter = g_slist_next (iter); + if (ignore) + connections = g_slist_remove (connections, candidate); } best_connection = nm_device_get_best_auto_connection (data->device, connections, &specific_object); @@ -752,7 +758,7 @@ auto_activate_device (gpointer user_data) best_connection, specific_object, nm_device_get_path (data->device), - FALSE, + NULL, &error)) { NMSettingConnection *s_con; @@ -765,7 +771,6 @@ auto_activate_device (gpointer user_data) } } - g_slist_foreach (connections, (GFunc) g_object_unref, NULL); g_slist_free (connections); out: @@ -811,6 +816,7 @@ hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) static void sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) { + NMPolicy *policy = user_data; gboolean sleeping = FALSE, enabled = FALSE; GSList *connections, *iter; @@ -819,8 +825,7 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) /* Clear the invalid flag on all connections so they'll get retried on wakeup */ if (sleeping || !enabled) { - connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM); - connections = g_slist_concat (connections, nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER)); + connections = nm_settings_get_connections (policy->settings); for (iter = connections; iter; iter = g_slist_next (iter)) g_object_set_data (G_OBJECT (iter->data), INVALID_TAG, NULL); g_slist_free (connections); @@ -946,64 +951,36 @@ nsps_changed (NMDeviceWimax *device, NMWimaxNsp *nsp, gpointer user_data) typedef struct { gulong id; NMDevice *device; -} DeviceSignalID; +} DeviceSignalId; -static GSList * -add_device_signal_id (GSList *list, gulong id, NMDevice *device) +static void +_connect_device_signal (NMPolicy *policy, NMDevice *device, const char *name, gpointer callback) { - DeviceSignalID *data; + DeviceSignalId *data; - data = g_malloc0 (sizeof (DeviceSignalID)); - if (!data) - return list; - - data->id = id; + data = g_slice_new0 (DeviceSignalId); + g_assert (data); + data->id = g_signal_connect (device, name, callback, policy); data->device = device; - return g_slist_append (list, data); + policy->dev_ids = g_slist_prepend (policy->dev_ids, data); } static void device_added (NMManager *manager, NMDevice *device, gpointer user_data) { NMPolicy *policy = (NMPolicy *) user_data; - gulong id; - id = g_signal_connect (device, "state-changed", - G_CALLBACK (device_state_changed), - policy); - policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); - - id = g_signal_connect (device, "notify::" NM_DEVICE_INTERFACE_IP4_CONFIG, - G_CALLBACK (device_ip_config_changed), - policy); - policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); - - id = g_signal_connect (device, "notify::" NM_DEVICE_INTERFACE_IP6_CONFIG, - G_CALLBACK (device_ip_config_changed), - policy); - policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); + _connect_device_signal (policy, device, "state-changed", device_state_changed); + _connect_device_signal (policy, device, "notify::" NM_DEVICE_INTERFACE_IP4_CONFIG, device_ip_config_changed); + _connect_device_signal (policy, device, "notify::" NM_DEVICE_INTERFACE_IP6_CONFIG, device_ip_config_changed); if (NM_IS_DEVICE_WIFI (device)) { - id = g_signal_connect (device, "access-point-added", - G_CALLBACK (wireless_networks_changed), - policy); - policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); - - id = g_signal_connect (device, "access-point-removed", - G_CALLBACK (wireless_networks_changed), - policy); - policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); + _connect_device_signal (policy, device, "access-point-added", wireless_networks_changed); + _connect_device_signal (policy, device, "access-point-removed", wireless_networks_changed); #if WITH_WIMAX } else if (NM_IS_DEVICE_WIMAX (device)) { - id = g_signal_connect (device, "nsp-added", - G_CALLBACK (nsps_changed), - policy); - policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); - - id = g_signal_connect (device, "nsp-removed", - G_CALLBACK (nsps_changed), - policy); - policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); + _connect_device_signal (policy, device, "nsp-added", nsps_changed); + _connect_device_signal (policy, device, "nsp-removed", nsps_changed); #endif } } @@ -1030,15 +1007,15 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data) } /* Clear any signal handlers for this device */ - iter = policy->dev_signal_ids; + iter = policy->dev_ids; while (iter) { - DeviceSignalID *data = (DeviceSignalID *) iter->data; + DeviceSignalId *data = iter->data; GSList *next = g_slist_next (iter); if (data->device == device) { g_signal_handler_disconnect (data->device, data->id); - g_free (data); - policy->dev_signal_ids = g_slist_delete_link (policy->dev_signal_ids, iter); + g_slice_free (DeviceSignalId, data); + policy->dev_ids = g_slist_delete_link (policy->dev_ids, iter); } iter = next; } @@ -1057,26 +1034,23 @@ schedule_activate_all (NMPolicy *policy) } static void -connections_added (NMManager *manager, - NMConnectionScope scope, - gpointer user_data) -{ - schedule_activate_all ((NMPolicy *) user_data); -} - -static void -connection_added (NMManager *manager, +connection_added (NMSettings *settings, NMConnection *connection, - NMConnectionScope scope, gpointer user_data) { schedule_activate_all ((NMPolicy *) user_data); } static void -connection_updated (NMManager *manager, +connections_loaded (NMSettings *settings, + gpointer user_data) +{ + schedule_activate_all ((NMPolicy *) user_data); +} + +static void +connection_updated (NMSettings *settings, NMConnection *connection, - NMConnectionScope scope, gpointer user_data) { /* Clear the invalid tag on the connection if it got updated. */ @@ -1086,23 +1060,19 @@ connection_updated (NMManager *manager, } static void -connection_removed (NMManager *manager, - NMConnection *connection, - NMConnectionScope scope, - gpointer user_data) +_deactivate_if_active (NMManager *manager, NMConnection *connection) { NMSettingConnection *s_con; GPtrArray *list; int i; - s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); - if (!s_con) - return; - list = nm_manager_get_active_connections_by_connection (manager, connection); if (!list) return; + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + g_assert (s_con); + for (i = 0; i < list->len; i++) { char *path = g_ptr_array_index (list, i); GError *error = NULL; @@ -1118,13 +1088,50 @@ connection_removed (NMManager *manager, } static void -manager_user_permissions_changed (NMManager *manager, NMPolicy *policy) +connection_removed (NMSettings *settings, + NMConnection *connection, + gpointer user_data) { - schedule_activate_all (policy); + NMPolicy *policy = user_data; + + _deactivate_if_active (policy->manager, connection); +} + +static void +connection_visibility_changed (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data) +{ + NMPolicy *policy = user_data; + + if (nm_settings_connection_is_visible (connection)) + schedule_activate_all (policy); + else + _deactivate_if_active (policy->manager, NM_CONNECTION (connection)); +} + +static void +_connect_manager_signal (NMPolicy *policy, const char *name, gpointer callback) +{ + guint id; + + id = g_signal_connect (policy->manager, name, callback, policy); + policy->manager_ids = g_slist_prepend (policy->manager_ids, GUINT_TO_POINTER (id)); +} + +static void +_connect_settings_signal (NMPolicy *policy, const char *name, gpointer callback) +{ + guint id; + + id = g_signal_connect (policy->settings, name, callback, policy); + policy->settings_ids = g_slist_prepend (policy->settings_ids, GUINT_TO_POINTER (id)); } NMPolicy * -nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager) +nm_policy_new (NMManager *manager, + NMVPNManager *vpn_manager, + NMSettings *settings) { NMPolicy *policy; static gboolean initialized = FALSE; @@ -1136,6 +1143,7 @@ nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager) policy = g_malloc0 (sizeof (NMPolicy)); policy->manager = g_object_ref (manager); + policy->settings = g_object_ref (settings); policy->update_state_id = 0; /* Grab hostname on startup and use that if nothing provides one */ @@ -1154,54 +1162,21 @@ nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager) G_CALLBACK (vpn_connection_deactivated), policy); policy->vpn_deactivated_id = id; - id = g_signal_connect (manager, "state-changed", - G_CALLBACK (global_state_changed), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); + _connect_manager_signal (policy, "state-changed", global_state_changed); + _connect_manager_signal (policy, "notify::" NM_MANAGER_HOSTNAME, hostname_changed); + _connect_manager_signal (policy, "notify::" NM_MANAGER_SLEEPING, sleeping_changed); + _connect_manager_signal (policy, "notify::" NM_MANAGER_NETWORKING_ENABLED, sleeping_changed); + _connect_manager_signal (policy, "device-added", device_added); + _connect_manager_signal (policy, "device-removed", device_removed); - id = g_signal_connect (manager, "notify::" NM_MANAGER_HOSTNAME, - G_CALLBACK (hostname_changed), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - id = g_signal_connect (manager, "notify::" NM_MANAGER_SLEEPING, - G_CALLBACK (sleeping_changed), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - id = g_signal_connect (manager, "notify::" NM_MANAGER_NETWORKING_ENABLED, - G_CALLBACK (sleeping_changed), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - id = g_signal_connect (manager, "device-added", - G_CALLBACK (device_added), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - id = g_signal_connect (manager, "device-removed", - G_CALLBACK (device_removed), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - /* Large batch of connections added, manager doesn't want us to - * process each one individually. - */ - id = g_signal_connect (manager, "connections-added", - G_CALLBACK (connections_added), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - /* Single connection added */ - id = g_signal_connect (manager, "connection-added", - G_CALLBACK (connection_added), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - id = g_signal_connect (manager, "connection-updated", - G_CALLBACK (connection_updated), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - id = g_signal_connect (manager, "connection-removed", - G_CALLBACK (connection_removed), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); - - id = g_signal_connect (manager, "user-permissions-changed", - G_CALLBACK (manager_user_permissions_changed), policy); - policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); + _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTIONS_LOADED, connections_loaded); + _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, connection_added); + _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, connection_updated); + _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, connection_removed); + _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, + connection_visibility_changed); + initialized = TRUE; return policy; } @@ -1233,21 +1208,26 @@ nm_policy_destroy (NMPolicy *policy) g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_deactivated_id); g_object_unref (policy->vpn_manager); - for (iter = policy->signal_ids; iter; iter = g_slist_next (iter)) - g_signal_handler_disconnect (policy->manager, (gulong) iter->data); - g_slist_free (policy->signal_ids); + for (iter = policy->manager_ids; iter; iter = g_slist_next (iter)) + g_signal_handler_disconnect (policy->manager, GPOINTER_TO_UINT (iter->data)); + g_slist_free (policy->manager_ids); - for (iter = policy->dev_signal_ids; iter; iter = g_slist_next (iter)) { - DeviceSignalID *data = (DeviceSignalID *) iter->data; + for (iter = policy->settings_ids; iter; iter = g_slist_next (iter)) + g_signal_handler_disconnect (policy->settings, GPOINTER_TO_UINT (iter->data)); + g_slist_free (policy->settings_ids); + + for (iter = policy->dev_ids; iter; iter = g_slist_next (iter)) { + DeviceSignalId *data = iter->data; g_signal_handler_disconnect (data->device, data->id); - g_free (data); + g_slice_free (DeviceSignalId, data); } - g_slist_free (policy->dev_signal_ids); + g_slist_free (policy->dev_ids); g_free (policy->orig_hostname); g_free (policy->cur_hostname); + g_object_unref (policy->settings); g_object_unref (policy->manager); g_free (policy); } diff --git a/src/nm-policy.h b/src/nm-policy.h index 7d99613cc0..33796bcaab 100644 --- a/src/nm-policy.h +++ b/src/nm-policy.h @@ -15,22 +15,22 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2004 - 2008 Red Hat, Inc. + * Copyright (C) 2004 - 2010 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#ifndef NETWORK_MANAGER_POLICY_H -#define NETWORK_MANAGER_POLICY_H +#ifndef NM_POLICY_H +#define NM_POLICY_H -#include "NetworkManager.h" #include "nm-manager.h" #include "nm-vpn-manager.h" -#include "nm-device.h" -#include "nm-activation-request.h" +#include "nm-settings.h" typedef struct NMPolicy NMPolicy; -NMPolicy *nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager); +NMPolicy *nm_policy_new (NMManager *manager, + NMVPNManager *vpn_manager, + NMSettings *settings); void nm_policy_destroy (NMPolicy *policy); -#endif /* NETWORK_MANAGER_POLICY_H */ +#endif /* NM_POLICY_H */ diff --git a/src/nm-secrets-provider-interface.c b/src/nm-secrets-provider-interface.c deleted file mode 100644 index 47b8e57efa..0000000000 --- a/src/nm-secrets-provider-interface.c +++ /dev/null @@ -1,224 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * 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 (C) 2009 Red Hat, Inc. - */ - -#include - -#include "nm-marshal.h" -#include "nm-secrets-provider-interface.h" - -#include -#include -#include "nm-logging.h" - -static void -nm_secrets_provider_interface_init (gpointer g_iface) -{ - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; - - if (initialized) - return; - initialized = TRUE; - - /* Signals */ - g_signal_new ("manager-get-secrets", - iface_type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMSecretsProviderInterface, manager_get_secrets), - NULL, NULL, - _nm_marshal_BOOLEAN__POINTER_STRING_BOOLEAN_UINT_STRING_STRING, - G_TYPE_BOOLEAN, 6, - G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING); - - g_signal_new ("manager-cancel-secrets", - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSecretsProviderInterface, manager_cancel_secrets), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - - -GType -nm_secrets_provider_interface_get_type (void) -{ - static GType interface_type = 0; - - if (!interface_type) { - const GTypeInfo interface_info = { - sizeof (NMSecretsProviderInterface), /* class_size */ - nm_secrets_provider_interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - interface_type = g_type_register_static (G_TYPE_INTERFACE, - "NMSecretsProviderInterface", - &interface_info, 0); - - g_type_interface_add_prerequisite (interface_type, G_TYPE_OBJECT); - } - - return interface_type; -} - -gboolean -nm_secrets_provider_interface_get_secrets (NMSecretsProviderInterface *self, - NMConnection *connection, - const char *setting_name, - gboolean request_new, - RequestSecretsCaller caller, - const char *hint1, - const char *hint2) -{ - guint success = FALSE; - - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (NM_IS_SECRETS_PROVIDER_INTERFACE (self), FALSE); - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - g_return_val_if_fail (setting_name != NULL, FALSE); - - nm_secrets_provider_interface_cancel_get_secrets (self); - - g_signal_emit_by_name (self, "manager-get-secrets", - connection, setting_name, request_new, caller, hint1, hint2, - &success); - if (!success) { - nm_log_warn (LOGD_CORE, "failed to get connection secrets."); - return FALSE; - } - - return TRUE; -} - -void -nm_secrets_provider_interface_cancel_get_secrets (NMSecretsProviderInterface *self) -{ - g_return_if_fail (self != NULL); - g_return_if_fail (NM_IS_SECRETS_PROVIDER_INTERFACE (self)); - - g_signal_emit_by_name (self, "manager-cancel-secrets"); -} - - -static void -add_one_key_to_list (gpointer key, gpointer data, gpointer user_data) -{ - GSList **list = (GSList **) user_data; - - *list = g_slist_append (*list, key); -} - -static gint -settings_order_func (gconstpointer a, gconstpointer b) -{ - /* Just ensure the 802.1x setting gets processed _before_ the - * wireless-security one. - */ - - if ( !strcmp (a, NM_SETTING_802_1X_SETTING_NAME) - && !strcmp (b, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME)) - return -1; - - if ( !strcmp (a, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) - && !strcmp (b, NM_SETTING_802_1X_SETTING_NAME)) - return 1; - - return 0; -} - -void -nm_secrets_provider_interface_get_secrets_result (NMSecretsProviderInterface *self, - const char *setting_name, - RequestSecretsCaller caller, - GHashTable *settings, - GError *error) -{ - GSList *keys = NULL, *iter; - GSList *updated = NULL; - GError *tmp_error = NULL; - - g_return_if_fail (self != NULL); - g_return_if_fail (NM_IS_SECRETS_PROVIDER_INTERFACE (self)); - - if (error) { - NM_SECRETS_PROVIDER_INTERFACE_GET_INTERFACE (self)->result (self, - setting_name, - caller, - NULL, - error); - return; - } - - if (g_hash_table_size (settings) == 0) { - g_set_error (&tmp_error, 0, 0, "%s", "no secrets were received!"); - NM_SECRETS_PROVIDER_INTERFACE_GET_INTERFACE (self)->result (self, - setting_name, - caller, - NULL, - tmp_error); - g_clear_error (&tmp_error); - return; - } - - g_hash_table_foreach (settings, add_one_key_to_list, &keys); - keys = g_slist_sort (keys, settings_order_func); - for (iter = keys; iter; iter = g_slist_next (iter)) { - GHashTable *hash; - const char *name = (const char *) iter->data; - - hash = g_hash_table_lookup (settings, name); - if (!hash) { - nm_log_warn (LOGD_CORE, "couldn't get setting secrets for '%s'", name); - continue; - } - - if (NM_SECRETS_PROVIDER_INTERFACE_GET_INTERFACE (self)->update_setting (self, name, hash)) - updated = g_slist_append (updated, (gpointer) setting_name); - } - g_slist_free (keys); - - if (g_slist_length (updated)) { - NM_SECRETS_PROVIDER_INTERFACE_GET_INTERFACE (self)->result (self, - setting_name, - caller, - updated, - NULL); - } else { - g_set_error (&tmp_error, 0, 0, "%s", "no secrets updated because no valid " - "settings were received!"); - NM_SECRETS_PROVIDER_INTERFACE_GET_INTERFACE (self)->result (self, - setting_name, - caller, - NULL, - tmp_error); - g_clear_error (&tmp_error); - } - - g_slist_free (updated); -} - diff --git a/src/nm-secrets-provider-interface.h b/src/nm-secrets-provider-interface.h deleted file mode 100644 index 3d9e08b186..0000000000 --- a/src/nm-secrets-provider-interface.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * 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 (C) 2009 Red Hat, Inc. - */ - -#ifndef NM_SECRETS_PROVIDER_INTERFACE_H -#define NM_SECRETS_PROVIDER_INTERFACE_H - -#include -#include - -typedef enum { - SECRETS_CALLER_NONE = 0, - SECRETS_CALLER_ETHERNET, - SECRETS_CALLER_WIFI, - SECRETS_CALLER_MOBILE_BROADBAND, - SECRETS_CALLER_PPP, - SECRETS_CALLER_VPN -} RequestSecretsCaller; - -#define NM_TYPE_SECRETS_PROVIDER_INTERFACE (nm_secrets_provider_interface_get_type ()) -#define NM_SECRETS_PROVIDER_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SECRETS_PROVIDER_INTERFACE, NMSecretsProviderInterface)) -#define NM_IS_SECRETS_PROVIDER_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SECRETS_PROVIDER_INTERFACE)) -#define NM_SECRETS_PROVIDER_INTERFACE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_SECRETS_PROVIDER_INTERFACE, NMSecretsProviderInterface)) - -typedef struct _NMSecretsProviderInterface NMSecretsProviderInterface; - -struct _NMSecretsProviderInterface { - GTypeInterface g_iface; - - /* Methods */ - void (*result) (NMSecretsProviderInterface *self, - const char *setting_name, - RequestSecretsCaller caller, - const GSList *updated, - GError *error); - - gboolean (*update_setting) (NMSecretsProviderInterface *self, - const char *setting_name, - GHashTable *new); - - /* Signals */ - void (*manager_get_secrets) (NMSecretsProviderInterface *self, - NMConnection *connection, - const char *setting_name, - gboolean request_new, - RequestSecretsCaller caller, - const char *hint1, - const char *hint2); - - void (*manager_cancel_secrets) (NMSecretsProviderInterface *self); -}; - -GType nm_secrets_provider_interface_get_type (void); - -/* For callers */ -gboolean nm_secrets_provider_interface_get_secrets (NMSecretsProviderInterface *self, - NMConnection *connection, - const char *setting_name, - gboolean request_new, - RequestSecretsCaller caller, - const char *hint1, - const char *hint2); - -void nm_secrets_provider_interface_cancel_get_secrets (NMSecretsProviderInterface *self); - -/* For NMManager */ -void nm_secrets_provider_interface_get_secrets_result (NMSecretsProviderInterface *self, - const char *setting_name, - RequestSecretsCaller caller, - GHashTable *settings, - GError *error); - -#endif /* NM_SECRETS_PROVIDER_INTERFACE_H */ - diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c new file mode 100644 index 0000000000..4877b77032 --- /dev/null +++ b/src/nm-session-monitor.c @@ -0,0 +1,602 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2008 - 2010 Red Hat, Inc. + * Author: David Zeuthen + * Author: Dan Williams + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include "nm-logging.h" + +#include "nm-session-monitor.h" + +#define CKDB_PATH "/var/run/ConsoleKit/database" + +/* + * SECTION:nm-session-monitor + * @title: NMSessionMonitor + * @short_description: Monitor sessions + * + * The #NMSessionMonitor class is a utility class to track and monitor sessions. + */ + +struct _NMSessionMonitor { + GObject parent_instance; + + GKeyFile *database; + GFileMonitor *database_monitor; + time_t database_mtime; + GHashTable *sessions_by_uid; + GHashTable *sessions_by_user; +}; + +struct _NMSessionMonitorClass { + GObjectClass parent_class; + + void (*changed) (NMSessionMonitor *monitor); +}; + + +enum { + CHANGED, + LAST_SIGNAL, +}; +static guint signals[LAST_SIGNAL] = {0}; + +G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT); + +/********************************************************************/ + +#define NM_SESSION_MONITOR_ERROR (nm_session_monitor_error_quark ()) +GQuark nm_session_monitor_error_quark (void) G_GNUC_CONST; +GType nm_session_monitor_error_get_type (void) G_GNUC_CONST; + +typedef enum { + NM_SESSION_MONITOR_ERROR_IO_ERROR = 0, + NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE, + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, +} NMSessionMonitorError; + +GQuark +nm_session_monitor_error_quark (void) +{ + static GQuark ret = 0; + + if (G_UNLIKELY (ret == 0)) + ret = g_quark_from_static_string ("nm-session-monitor-error"); + return ret; +} + +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +nm_session_monitor_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + /* Some I/O operation on the CK database failed */ + ENUM_ENTRY (NM_SESSION_MONITOR_ERROR_IO_ERROR, "IOError"), + /* Error parsing the CK database */ + ENUM_ENTRY (NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE, "MalformedDatabase"), + /* Username or UID could could not be found */ + ENUM_ENTRY (NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, "UnknownUser"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("NMSessionMonitorError", values); + } + return etype; +} +/********************************************************************/ + +typedef struct { + char *user; + uid_t uid; + gboolean local; + gboolean active; +} Session; + +static void +session_free (Session *s) +{ + g_free (s->user); + memset (s, 0, sizeof (Session)); + g_free (s); +} + +static gboolean +check_key (GKeyFile *keyfile, const char *group, const char *key, GError **error) +{ + if (g_key_file_has_key (keyfile, group, key, error)) + return TRUE; + + if (!error) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE, + "ConsoleKit database " CKDB_PATH " group '%s' had no '%s' key", + group, key); + } + return FALSE; +} + +static Session * +session_new (GKeyFile *keyfile, const char *group, GError **error) +{ + GError *local = NULL; + Session *s; + struct passwd *pw; + + s = g_new0 (Session, 1); + g_assert (s); + + s->uid = G_MAXUINT; /* paranoia */ + if (!check_key (keyfile, group, "uid", &local)) + goto error; + s->uid = (uid_t) g_key_file_get_integer (keyfile, group, "uid", &local); + if (local) + goto error; + + if (!check_key (keyfile, group, "is_active", &local)) + goto error; + s->active = g_key_file_get_boolean (keyfile, group, "is_active", &local); + if (local) + goto error; + + if (!check_key (keyfile, group, "is_local", &local)) + goto error; + s->local = g_key_file_get_boolean (keyfile, group, "is_local", &local); + if (local) + goto error; + + pw = getpwuid (s->uid); + if (!pw) { + g_set_error (&local, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, + "Could not get username for UID %d", + s->uid); + goto error; + } + s->user = g_strdup (pw->pw_name); + + return s; + +error: + session_free (s); + g_propagate_error (error, local); + return NULL; +} + +/********************************************************************/ + +static void +free_database (NMSessionMonitor *self) +{ + if (self->database != NULL) { + g_key_file_free (self->database); + self->database = NULL; + } + + g_hash_table_remove_all (self->sessions_by_uid); + g_hash_table_remove_all (self->sessions_by_user); +} + +static gboolean +reload_database (NMSessionMonitor *self, GError **error) +{ + struct stat statbuf; + char **groups = NULL; + gsize len = 0, i; + Session *s; + + free_database (self); + + if (stat (CKDB_PATH, &statbuf) != 0) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_IO_ERROR, + "Error statting file " CKDB_PATH ": %s", + strerror (errno)); + goto error; + } + self->database_mtime = statbuf.st_mtime; + + self->database = g_key_file_new (); + if (!g_key_file_load_from_file (self->database, CKDB_PATH, G_KEY_FILE_NONE, error)) + goto error; + + groups = g_key_file_get_groups (self->database, &len); + if (!groups) { + g_set_error_literal (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_IO_ERROR, + "Could not load groups from " CKDB_PATH ""); + goto error; + } + + for (i = 0; i < len; i++) { + if (!g_str_has_prefix (groups[i], "Session ")) + continue; + + s = session_new (self->database, groups[i], error); + if (!s) + goto error; + g_hash_table_insert (self->sessions_by_user, (gpointer) s->user, s); + g_hash_table_insert (self->sessions_by_uid, GUINT_TO_POINTER (s->uid), s); + } + + g_strfreev (groups); + return TRUE; + +error: + if (groups) + g_strfreev (groups); + free_database (self); + return FALSE; +} + +static gboolean +ensure_database (NMSessionMonitor *self, GError **error) +{ + gboolean ret = FALSE; + +#if NO_CONSOLEKIT + return TRUE; +#endif + + if (self->database != NULL) { + struct stat statbuf; + + if (stat (CKDB_PATH, &statbuf) != 0) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_IO_ERROR, + "Error statting file " CKDB_PATH " to check timestamp: %s", + strerror (errno)); + goto out; + } + + if (statbuf.st_mtime == self->database_mtime) { + ret = TRUE; + goto out; + } + } + + ret = reload_database (self, error); + +out: + return ret; +} + +static void +on_file_monitor_changed (GFileMonitor * file_monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + NMSessionMonitor *self = NM_SESSION_MONITOR (user_data); + + /* throw away cache */ + free_database (self); + + g_signal_emit (self, signals[CHANGED], 0); +} + +static void +nm_session_monitor_init (NMSessionMonitor *self) +{ + GError *error = NULL; + GFile *file; + +#if NO_CONSOLEKIT + return; +#endif + + /* Sessions-by-user is responsible for destroying the Session objects */ + self->sessions_by_user = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, (GDestroyNotify) session_free); + self->sessions_by_uid = g_hash_table_new (g_direct_hash, g_direct_equal); + + + error = NULL; + if (!ensure_database (self, &error)) { + nm_log_err (LOGD_CORE, "Error loading " CKDB_PATH ": %s", error->message); + g_error_free (error); + } + + error = NULL; + file = g_file_new_for_path (CKDB_PATH); + self->database_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error); + g_object_unref (file); + if (self->database_monitor == NULL) { + nm_log_err (LOGD_CORE, "Error monitoring " CKDB_PATH ": %s", error->message); + g_error_free (error); + } else { + g_signal_connect (self->database_monitor, + "changed", + G_CALLBACK (on_file_monitor_changed), + self); + } +} + +static void +finalize (GObject *object) +{ + NMSessionMonitor *self = NM_SESSION_MONITOR (object); + + if (self->database_monitor != NULL) + g_object_unref (self->database_monitor); + + free_database (self); + + if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL) + G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object); +} + +static void +nm_session_monitor_class_init (NMSessionMonitorClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = finalize; + + /** + * NMSessionMonitor::changed: + * @monitor: A #NMSessionMonitor + * + * Emitted when something changes. + */ + signals[CHANGED] = g_signal_new (NM_SESSION_MONITOR_CHANGED, + NM_TYPE_SESSION_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMSessionMonitorClass, changed), + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +NMSessionMonitor * +nm_session_monitor_get (void) +{ + static NMSessionMonitor *singleton = NULL; + + if (singleton) + return NM_SESSION_MONITOR (g_object_ref (singleton)); + + return NM_SESSION_MONITOR (g_object_new (NM_TYPE_SESSION_MONITOR, NULL)); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +#if NO_CONSOLEKIT +static gboolean +uid_to_user (uid_t uid, const char **out_user, GError **error) +{ + struct passwd *pw; + + pw = getpwuid (uid); + if (!pw) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, + "Could not get username for UID %d", + uid); + return FALSE; + } + + /* Ugly, but hey, use ConsoleKit */ + if (out_user) + *out_user = pw->pw_name; + return TRUE; +} + +static gboolean +user_to_uid (const char *user, uid_t *out_uid, GError **error) +{ + struct passwd *pw; + + pw = getpwnam (user); + if (!pw) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, + "Could not get UID for username '%s'", + user); + return FALSE; + } + + /* Ugly, but hey, use ConsoleKit */ + if (out_uid) + *out_uid = pw->pw_uid; + return TRUE; +} +#endif + +/** + * nm_session_monitor_user_has_session: + * @monitor: A #NMSessionMonitor. + * @username: A username. + * @error: Return location for error. + * + * Checks whether the given @username is logged into a session or not. + * + * Returns: %FALSE if @error is set otherwise %TRUE if the given @username is + * currently logged into a session. + */ +gboolean +nm_session_monitor_user_has_session (NMSessionMonitor *monitor, + const char *username, + uid_t *out_uid, + GError **error) +{ + Session *s; + +#if NO_CONSOLEKIT + if (!user_to_uid (username, out_uid, error)) + return FALSE; + return TRUE; +#endif + + if (!ensure_database (monitor, error)) + return FALSE; + + s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username); + if (!s) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, + "No session found for user '%s'", + username); + return FALSE; + } + + if (out_uid) + *out_uid = s->uid; + return TRUE; +} + +/** + * nm_session_monitor_uid_has_session: + * @monitor: A #NMSessionMonitor. + * @uid: A user ID. + * @error: Return location for error. + * + * Checks whether the given @uid is logged into a session or not. + * + * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is + * currently logged into a session. + */ +gboolean +nm_session_monitor_uid_has_session (NMSessionMonitor *monitor, + uid_t uid, + const char **out_user, + GError **error) +{ + Session *s; + +#if NO_CONSOLEKIT + if (!uid_to_user (uid, out_user, error)) + return FALSE; + return TRUE; +#endif + + if (!ensure_database (monitor, error)) + return FALSE; + + s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid)); + if (!s) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, + "No session found for uid %d", + uid); + return FALSE; + } + + if (out_user) + *out_user = s->user; + return TRUE; +} + +/** + * nm_session_monitor_user_active: + * @monitor: A #NMSessionMonitor. + * @username: A username. + * @error: Return location for error. + * + * Checks whether the given @username is logged into a active session or not. + * + * Returns: %FALSE if @error is set otherwise %TRUE if the given @username is + * logged into an active session. + */ +gboolean +nm_session_monitor_user_active (NMSessionMonitor *monitor, + const char *username, + GError **error) +{ + Session *s; + +#if NO_CONSOLEKIT + return TRUE; +#endif + + if (!ensure_database (monitor, error)) + return FALSE; + + s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username); + if (!s) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, + "No session found for user '%s'", + username); + return FALSE; + } + + return s->active; +} + +/** + * nm_session_monitor_uid_active: + * @monitor: A #NMSessionMonitor. + * @uid: A user ID. + * @error: Return location for error. + * + * Checks whether the given @uid is logged into a active session or not. + * + * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is + * logged into an active session. + */ +gboolean +nm_session_monitor_uid_active (NMSessionMonitor *monitor, + uid_t uid, + GError **error) +{ + Session *s; + +#if NO_CONSOLEKIT + return TRUE; +#endif + + if (!ensure_database (monitor, error)) + return FALSE; + + s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid)); + if (!s) { + g_set_error (error, + NM_SESSION_MONITOR_ERROR, + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, + "No session found for uid '%d'", + uid); + return FALSE; + } + + return s->active; +} + diff --git a/src/nm-session-monitor.h b/src/nm-session-monitor.h new file mode 100644 index 0000000000..77ea9a0364 --- /dev/null +++ b/src/nm-session-monitor.h @@ -0,0 +1,64 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2008 - 2010 Red Hat, Inc. + * Author: David Zeuthen + * Author: Dan Williams + */ + +#ifndef NM_SESSION_MONITOR_H +#define NM_SESSION_MONITOR_H + +#include + +G_BEGIN_DECLS + +#define NM_TYPE_SESSION_MONITOR (nm_session_monitor_get_type ()) +#define NM_SESSION_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_SESSION_MONITOR, NMSessionMonitor)) +#define NM_SESSION_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), NM_TYPE_SESSION_MONITOR, NMSessionMonitorClass)) +#define NM_SESSION_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_SESSION_MONITOR, NMSessionMonitorClass)) +#define NM_IS_SESSION_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NM_TYPE_SESSION_MONITOR)) +#define NM_IS_SESSION_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_SESSION_MONITOR)) + +#define NM_SESSION_MONITOR_CHANGED "changed" + +typedef struct _NMSessionMonitor NMSessionMonitor; +typedef struct _NMSessionMonitorClass NMSessionMonitorClass; + +GType nm_session_monitor_get_type (void) G_GNUC_CONST; +NMSessionMonitor *nm_session_monitor_get (void); + +gboolean nm_session_monitor_user_has_session (NMSessionMonitor *monitor, + const char *username, + uid_t *out_uid, + GError **error); + +gboolean nm_session_monitor_uid_has_session (NMSessionMonitor *monitor, + uid_t uid, + const char **out_user, + GError **error); + +gboolean nm_session_monitor_user_active (NMSessionMonitor *monitor, + const char *username, + GError **error); + +gboolean nm_session_monitor_uid_active (NMSessionMonitor *monitor, + uid_t uid, + GError **error); + +G_END_DECLS + +#endif /* NM_SESSION_MONITOR_H */ + diff --git a/src/nm-wifi-ap-utils.c b/src/nm-wifi-ap-utils.c new file mode 100644 index 0000000000..15e176a125 --- /dev/null +++ b/src/nm-wifi-ap-utils.c @@ -0,0 +1,708 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2011 Red Hat, Inc. + */ + +#include + +#include "nm-wifi-ap-utils.h" + +static gboolean +verify_no_wep (NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error) +{ + if ( nm_setting_wireless_security_get_wep_key (s_wsec, 0) + || nm_setting_wireless_security_get_wep_key (s_wsec, 1) + || nm_setting_wireless_security_get_wep_key (s_wsec, 2) + || nm_setting_wireless_security_get_wep_key (s_wsec, 3) + || nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec) + || nm_setting_wireless_security_get_wep_key_type (s_wsec)) { + /* Dynamic WEP cannot have any WEP keys set */ + g_set_error (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "%s is incompatible with static WEP keys", tag); + return FALSE; + } + + return TRUE; +} + +static gboolean +verify_leap (NMSettingWirelessSecurity *s_wsec, + NMSetting8021x *s_8021x, + gboolean adhoc, + GError **error) +{ + const char *key_mgmt, *auth_alg, *leap_username; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); + auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); + leap_username = nm_setting_wireless_security_get_leap_username (s_wsec); + + /* One (or both) of two things indicates we want LEAP: + * 1) auth_alg == 'leap' + * 2) valid leap_username + * + * LEAP always requires a LEAP username. + */ + + if (auth_alg) { + if (!strcmp (auth_alg, "leap")) { + /* LEAP authentication requires at least a LEAP username */ + if (!leap_username) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME, + "LEAP requires a LEAP username"); + return FALSE; + } + } else if (leap_username) { + /* Leap username requires 'leap' auth */ + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "LEAP requires 'leap' authentication"); + return FALSE; + } + } + + if (leap_username) { + if (key_mgmt && strcmp (key_mgmt, "ieee8021x")) { + /* LEAP requires ieee8021x key management */ + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_802_1X, + "LEAP requires IEEE 802.1x key management"); + return FALSE; + } + } + + /* At this point if auth_alg is set it must be 'leap', and if key_mgmt + * is set it must be 'ieee8021x'. + */ + if (leap_username) { + if (auth_alg) + g_assert (strcmp (auth_alg, "leap") == 0); + if (key_mgmt) + g_assert (strcmp (key_mgmt, "ieee8021x") == 0); + + if (adhoc) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "LEAP incompatible with Ad-Hoc mode"); + return FALSE; + } + + if (!verify_no_wep (s_wsec, "LEAP", error)) + return FALSE; + + if (s_8021x) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME, + "LEAP incompatible with 802.1x setting"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +verify_no_wpa (NMSettingWirelessSecurity *s_wsec, + const char *tag, + GError **error) +{ + const char *key_mgmt; + int n, i; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); + if (key_mgmt && !strncmp (key_mgmt, "wpa", 3)) { + g_set_error (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "%s incompatible with any WPA key management", tag); + return FALSE; + } + + if (nm_setting_wireless_security_get_num_protos (s_wsec)) { + g_set_error (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "%s incompatible with any 'proto' setting", tag); + return FALSE; + } + + n = nm_setting_wireless_security_get_num_pairwise (s_wsec); + for (i = 0; i < n; i++) { + const char *pw; + + pw = nm_setting_wireless_security_get_pairwise (s_wsec, i); + if (strcmp (pw, "wep40") && strcmp (pw, "wep104")) { + g_set_error (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "%s is incompatible with WPA pairwise ciphers", tag); + return FALSE; + } + } + + n = nm_setting_wireless_security_get_num_groups (s_wsec); + for (i = 0; i < n; i++) { + const char *gr; + + gr = nm_setting_wireless_security_get_group (s_wsec, i); + if (strcmp (gr, "wep40") && strcmp (gr, "wep104")) { + g_set_error (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "%s is incompatible with WPA group ciphers", tag); + return FALSE; + } + } + + if (nm_setting_wireless_security_get_psk (s_wsec)) { + g_set_error (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "%s is incompatible with a WPA Pre-Shared Key", tag); + return FALSE; + } + + return TRUE; +} + +static gboolean +verify_dynamic_wep (NMSettingWirelessSecurity *s_wsec, + NMSetting8021x *s_8021x, + gboolean adhoc, + GError **error) +{ + const char *key_mgmt, *auth_alg, *leap_username; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); + auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); + leap_username = nm_setting_wireless_security_get_leap_username (s_wsec); + + g_return_val_if_fail (leap_username == NULL, TRUE); + + if (key_mgmt) { + if (!strcmp (key_mgmt, "ieee8021x")) { + if (!s_8021x) { + /* 802.1x key management requires an 802.1x setting */ + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Dynamic WEP requires an 802.1x setting"); + return FALSE; + } + + if (auth_alg && strcmp (auth_alg, "open")) { + /* 802.1x key management must use "open" authentication */ + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Dynamic WEP requires 'open' authentication"); + return FALSE; + } + + /* Dynamic WEP incompatible with anything static WEP related */ + if (!verify_no_wep (s_wsec, "Dynamic WEP", error)) + return FALSE; + } else if (!strcmp (key_mgmt, "none")) { + if (s_8021x) { + /* 802.1x setting requires 802.1x key management */ + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Dynamic WEP requires 'ieee8021x' key management"); + return FALSE; + } + } + } else if (s_8021x) { + /* 802.1x setting incompatible with anything but 'open' auth */ + if (auth_alg && strcmp (auth_alg, "open")) { + /* 802.1x key management must use "open" authentication */ + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Dynamic WEP requires 'open' authentication"); + return FALSE; + } + + /* Dynamic WEP incompatible with anything static WEP related */ + if (!verify_no_wep (s_wsec, "Dynamic WEP", error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +verify_wpa_psk (NMSettingWirelessSecurity *s_wsec, + NMSetting8021x *s_8021x, + gboolean adhoc, + guint32 wpa_flags, + guint32 rsn_flags, + GError **error) +{ + const char *key_mgmt, *auth_alg, *tmp; + int n; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); + auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); + + if (key_mgmt) { + if (!strcmp (key_mgmt, "wpa-psk") || !strcmp (key_mgmt, "wpa-none")) { + if (s_8021x) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA-PSK incompatible with 802.1x"); + return FALSE; + } + + if (auth_alg && strcmp (auth_alg, "open")) { + /* WPA must use "open" authentication */ + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA-PSK requires 'open' authentication"); + return FALSE; + } + } + + if (!strcmp (key_mgmt, "wpa-none")) { + if (!adhoc) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA Ad-Hoc requires an Ad-Hoc mode AP"); + return FALSE; + } + + /* Ad-Hoc WPA requires 'wpa' proto, 'none' pairwise, and 'tkip' group */ + n = nm_setting_wireless_security_get_num_protos (s_wsec); + tmp = (n > 0) ? nm_setting_wireless_security_get_proto (s_wsec, 0) : NULL; + if (n > 1 || strcmp (tmp, "wpa")) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA Ad-Hoc requires 'wpa' proto"); + return FALSE; + } + + n = nm_setting_wireless_security_get_num_pairwise (s_wsec); + tmp = (n > 0) ? nm_setting_wireless_security_get_pairwise (s_wsec, 0) : NULL; + if (n > 1 || strcmp (tmp, "none")) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA Ad-Hoc requires 'none' pairwise cipher"); + return FALSE; + } + + n = nm_setting_wireless_security_get_num_groups (s_wsec); + tmp = (n > 0) ? nm_setting_wireless_security_get_group (s_wsec, 0) : NULL; + if (n > 1 || strcmp (tmp, "tkip")) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA Ad-Hoc requires 'tkip' group cipher"); + return FALSE; + } + } + + if (!strcmp (key_mgmt, "wpa-psk")) { + /* Make sure the AP's capabilities support WPA-PSK */ + if ( !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "AP does not support PSK but setting requires it"); + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +verify_wpa_eap (NMSettingWirelessSecurity *s_wsec, + NMSetting8021x *s_8021x, + guint32 wpa_flags, + guint32 rsn_flags, + GError **error) +{ + const char *key_mgmt, *auth_alg; + gboolean is_wpa_eap = FALSE; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); + auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); + + if (key_mgmt) { + if (!strcmp (key_mgmt, "wpa-eap")) { + if (!s_8021x) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA-EAP requires an 802.1x setting"); + return FALSE; + } + + if (auth_alg && strcmp (auth_alg, "open")) { + /* WPA must use "open" authentication */ + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA-EAP requires 'open' authentication"); + return FALSE; + } + + is_wpa_eap = TRUE; + } else if (s_8021x) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Setting requires 802.1x but does not use 'wpa-eap' key management"); + return FALSE; + } + } + + if (is_wpa_eap || s_8021x) { + /* Make sure the AP's capabilities support WPA-EAP */ + if ( !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) + && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "AP does not support 802.1x but setting requires it"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +verify_adhoc (NMSettingWirelessSecurity *s_wsec, + NMSetting8021x *s_8021x, + gboolean adhoc, + GError **error) +{ + const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL; + + if (s_wsec) { + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); + auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); + leap_username = nm_setting_wireless_security_get_leap_username (s_wsec); + } + + if (adhoc) { + if (key_mgmt && strcmp (key_mgmt, "wpa-none") && strcmp (key_mgmt, "none")) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "AP mode is Ad-Hoc but setting requires Infrastructure security"); + return FALSE; + } + + if (s_8021x) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Ad-Hoc mode incompatible with 802.1x security"); + return FALSE; + } + + if (leap_username) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Ad-Hoc mode incompatible with LEAP security"); + return FALSE; + } + + if (auth_alg && strcmp (auth_alg, "open")) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Ad-Hoc mode requires 'open' authentication"); + return FALSE; + } + } else { + if (key_mgmt && !strcmp (key_mgmt, "wpa-none")) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "AP mode is Infrastructure but setting requires Ad-Hoc security"); + return FALSE; + } + } + + return TRUE; +} + +gboolean +nm_ap_utils_complete_connection (const GByteArray *ap_ssid, + const guint8 ap_bssid[ETH_ALEN], + NM80211Mode ap_mode, + guint32 ap_flags, + guint32 ap_wpa_flags, + guint32 ap_rsn_flags, + NMConnection *connection, + gboolean lock_bssid, + GError **error) +{ + NMSettingWireless *s_wifi; + NMSettingWirelessSecurity *s_wsec; + NMSetting8021x *s_8021x; + const GByteArray *ssid; + const char *mode, *key_mgmt, *auth_alg, *leap_username; + gboolean adhoc = FALSE; + + s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); + s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY); + s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); + + if (!s_wifi) { + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + } + + /* Fill in missing SSID */ + ssid = nm_setting_wireless_get_ssid (s_wifi); + if (!ssid) + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid, NULL); + else if ( ssid->len != ap_ssid->len + || memcmp (ssid->data, ap_ssid->data, ssid->len)) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_ERROR, + NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY, + "Setting SSID did not match AP SSID"); + return FALSE; + } + + if (lock_bssid && !nm_setting_wireless_get_bssid (s_wifi)) { + GByteArray *bssid; + + bssid = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (bssid, ap_bssid, ETH_ALEN); + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL); + g_byte_array_free (bssid, TRUE); + } + + /* And mode */ + mode = nm_setting_wireless_get_mode (s_wifi); + if (mode) { + gboolean valid = FALSE; + + /* Make sure the supplied mode matches the AP's */ + if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_INFRA)) { + if (ap_mode == NM_802_11_MODE_INFRA) + valid = TRUE; + } else if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) { + if (ap_mode == NM_802_11_MODE_ADHOC) + valid = TRUE; + adhoc = TRUE; + } + + if (valid == FALSE) { + g_set_error (error, + NM_SETTING_WIRELESS_ERROR, + NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY, + NM_SETTING_WIRELESS_MODE); + return FALSE; + } + } else { + mode = NM_SETTING_WIRELESS_MODE_INFRA; + if (ap_mode == NM_802_11_MODE_ADHOC) { + mode = NM_SETTING_WIRELESS_MODE_ADHOC; + adhoc = TRUE; + } + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, mode, NULL); + } + + /* Security */ + + /* Open */ + if ( !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY) + && (ap_wpa_flags == NM_802_11_AP_SEC_NONE) + && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) { + /* Make sure the connection doesn't specify security */ + if (nm_setting_wireless_get_security (s_wifi) || s_wsec || s_8021x) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "AP is unencrypted but setting specifies security"); + return FALSE; + } + return TRUE; + } + + /* Everything else requires security */ + g_object_set (G_OBJECT (s_wifi), + NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + NULL); + if (!s_wsec) { + s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wsec)); + } + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); + auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); + leap_username = nm_setting_wireless_security_get_leap_username (s_wsec); + + /* Ad-Hoc checks */ + if (!verify_adhoc (s_wsec, s_8021x, adhoc, error)) + return FALSE; + + /* Static WEP, Dynamic WEP, or LEAP */ + if ( (ap_flags & NM_802_11_AP_FLAGS_PRIVACY) + && (ap_wpa_flags == NM_802_11_AP_SEC_NONE) + && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) { + const char *tag = "WEP"; + gboolean is_dynamic_wep = FALSE; + + if (!verify_leap (s_wsec, s_8021x, adhoc, error)) + return FALSE; + + if (leap_username) { + tag = "LEAP"; + } else { + /* Static or Dynamic WEP */ + if (!verify_dynamic_wep (s_wsec, s_8021x, adhoc, error)) + return FALSE; + + if (s_8021x || (key_mgmt && !strcmp (key_mgmt, "ieee8021x"))) { + is_dynamic_wep = TRUE; + tag = "Dynamic WEP"; + } + } + + /* Nothing WPA-related can be set */ + if (!verify_no_wpa (s_wsec, tag, error)) + return FALSE; + + if (leap_username) { + /* LEAP */ + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", + NULL); + } else if (is_dynamic_wep) { + /* Dynamic WEP */ + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NULL); + nm_setting_wireless_security_add_pairwise (s_wsec, "wep40"); + nm_setting_wireless_security_add_pairwise (s_wsec, "wep104"); + nm_setting_wireless_security_add_group (s_wsec, "wep40"); + nm_setting_wireless_security_add_group (s_wsec, "wep104"); + + if (s_8021x) { + /* Dynamic WEP requires a valid 802.1x setting since we can't + * autocomplete 802.1x. + */ + if (!nm_setting_verify (NM_SETTING (s_8021x), NULL, error)) + return FALSE; + } + } else { + /* Static WEP */ + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", + NULL); + } + + return TRUE; + } + + /* WPA/RSN */ + g_assert (ap_wpa_flags || ap_rsn_flags); + + /* Ensure key management is valid for WPA */ + if ((key_mgmt && !strcmp (key_mgmt, "ieee8021x")) || leap_username) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA incompatible with non-EAP (original) LEAP or Dynamic WEP"); + return FALSE; + } + + /* 'shared' auth incompatible with any type of WPA */ + if (auth_alg && strcmp (auth_alg, "open")) { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "WPA incompatible with Shared Key authentication"); + return FALSE; + } + + if (!verify_no_wep (s_wsec, "WPA", error)) + return FALSE; + + if (!verify_wpa_psk (s_wsec, s_8021x, adhoc, ap_wpa_flags, ap_rsn_flags, error)) + return FALSE; + + if (!adhoc && !verify_wpa_eap (s_wsec, s_8021x, ap_wpa_flags, ap_rsn_flags, error)) + return FALSE; + + if (adhoc) { + g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL); + /* Ad-Hoc does not support RSN/WPA2 */ + nm_setting_wireless_security_add_proto (s_wsec, "wpa"); + nm_setting_wireless_security_add_pairwise (s_wsec, "none"); + nm_setting_wireless_security_add_group (s_wsec, "tkip"); + } else if (s_8021x) { + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NULL); + /* Leave proto/pairwise/group as client set them; if they are unset the + * supplicant will figure out the best combination at connect time. + */ + + /* 802.1x also requires the client to completely fill in the 8021x + * setting. Since there's so much configuration required for it, there's + * no way it can be automatically completed. + */ + } else if ( (key_mgmt && !strcmp (key_mgmt, "wpa-psk")) + || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NULL); + /* Leave proto/pairwise/group as client set them; if they are unset the + * supplicant will figure out the best combination at connect time. + */ + } else { + g_set_error_literal (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + "Failed to determine AP security information"); + return FALSE; + } + + return TRUE; +} + diff --git a/src/nm-wifi-ap-utils.h b/src/nm-wifi-ap-utils.h new file mode 100644 index 0000000000..a464867b96 --- /dev/null +++ b/src/nm-wifi-ap-utils.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2011 Red Hat, Inc. + */ + +#ifndef NM_WIFI_AP_UTILS_H +#define NM_WIFI_AP_UTILS_H + +#include + +#include +#include +#include +#include +#include + +gboolean nm_ap_utils_complete_connection (const GByteArray *ssid, + const guint8 bssid[ETH_ALEN], + NM80211Mode mode, + guint32 flags, + guint32 wpa_flags, + guint32 rsn_flags, + NMConnection *connection, + gboolean lock_bssid, + GError **error); + +#endif /* NM_WIFI_AP_UTILS_H */ + diff --git a/src/nm-wifi-ap.c b/src/nm-wifi-ap.c index 4438118729..d216ea6a90 100644 --- a/src/nm-wifi-ap.c +++ b/src/nm-wifi-ap.c @@ -25,6 +25,7 @@ #include #include "nm-wifi-ap.h" +#include "nm-wifi-ap-utils.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-logging.h" @@ -1314,6 +1315,27 @@ nm_ap_check_compatible (NMAccessPoint *self, nm_ap_get_mode (self)); } +gboolean +nm_ap_complete_connection (NMAccessPoint *self, + NMConnection *connection, + gboolean lock_bssid, + GError **error) +{ + NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (self); + + g_return_val_if_fail (connection != NULL, FALSE); + + return nm_ap_utils_complete_connection (priv->ssid, + priv->address.ether_addr_octet, + priv->mode, + priv->flags, + priv->wpa_flags, + priv->rsn_flags, + connection, + lock_bssid, + error); +} + static gboolean capabilities_compatible (guint32 a_flags, guint32 b_flags) { diff --git a/src/nm-wifi-ap.h b/src/nm-wifi-ap.h index 09c87d970a..2a10d3505d 100644 --- a/src/nm-wifi-ap.h +++ b/src/nm-wifi-ap.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2004 - 2010 Red Hat, Inc. + * Copyright (C) 2004 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -113,6 +113,11 @@ void nm_ap_set_user_addresses (NMAccessPoint *ap, GSList *list); gboolean nm_ap_check_compatible (NMAccessPoint *self, NMConnection *connection); +gboolean nm_ap_complete_connection (NMAccessPoint *self, + NMConnection *connection, + gboolean lock_bssid, + GError **error); + NMAccessPoint * nm_ap_match_in_list (NMAccessPoint *find_ap, GSList *ap_list, gboolean strict_match); diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c index efa660b03f..62faaad720 100644 --- a/src/ppp-manager/nm-ppp-manager.c +++ b/src/ppp-manager/nm-ppp-manager.c @@ -78,6 +78,7 @@ typedef struct { NMActRequest *act_req; DBusGMethodInvocation *pending_secrets_context; + guint32 secrets_id; guint32 ppp_watch_id; guint32 ppp_timeout_handler; @@ -334,19 +335,29 @@ remove_timeout_handler (NMPPPManager *manager) } static void -impl_ppp_manager_need_secrets (NMPPPManager *manager, - DBusGMethodInvocation *context) +cancel_get_secrets (NMPPPManager *self) { - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - NMConnection *connection; - NMSettingConnection *s_con; - const char *connection_type; - const char *setting_name; - guint32 tries; - GPtrArray *hints = NULL; - const char *hint1 = NULL, *hint2 = NULL; + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); - connection = nm_act_request_get_connection (priv->act_req); + if (priv->secrets_id) { + nm_act_request_cancel_secrets (priv->act_req, priv->secrets_id); + priv->secrets_id = 0; + } +} + +static gboolean +extract_details_from_connection (NMConnection *connection, + const char **username, + const char **password, + GError **error) +{ + NMSettingConnection *s_con; + NMSetting *setting; + const char *connection_type; + + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (username != NULL, FALSE); + g_return_val_if_fail (password != NULL, FALSE); s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); g_assert (s_con); @@ -354,67 +365,117 @@ impl_ppp_manager_need_secrets (NMPPPManager *manager, connection_type = nm_setting_connection_get_connection_type (s_con); g_assert (connection_type); + setting = nm_connection_get_setting_by_name (connection, connection_type); + if (!setting) { + g_set_error_literal (error, NM_PPP_MANAGER_ERROR, NM_PPP_MANAGER_ERROR_UNKOWN, + "Missing type-specific setting; no secrets could be found."); + return FALSE; + } + + /* FIXME: push this down to the settings and keep PPP manager generic */ + if (NM_IS_SETTING_PPPOE (setting)) { + *username = nm_setting_pppoe_get_username (NM_SETTING_PPPOE (setting)); + *password = nm_setting_pppoe_get_password (NM_SETTING_PPPOE (setting)); + } else if (NM_IS_SETTING_GSM (setting)) { + *username = nm_setting_gsm_get_username (NM_SETTING_GSM (setting)); + *password = nm_setting_gsm_get_password (NM_SETTING_GSM (setting)); + } else if (NM_IS_SETTING_CDMA (setting)) { + *username = nm_setting_cdma_get_username (NM_SETTING_CDMA (setting)); + *password = nm_setting_cdma_get_password (NM_SETTING_CDMA (setting)); + } + + return TRUE; +} + +static void +ppp_secrets_cb (NMActRequest *req, + guint32 call_id, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + NMPPPManager *self = NM_PPP_MANAGER (user_data); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); + const char *username = NULL; + const char *password = NULL; + GError *local = NULL; + + g_return_if_fail (priv->pending_secrets_context != NULL); + g_return_if_fail (req == priv->act_req); + g_return_if_fail (call_id == priv->secrets_id); + + if (error) { + nm_log_warn (LOGD_PPP, "%s", error->message); + dbus_g_method_return_error (priv->pending_secrets_context, error); + goto out; + } + + if (!extract_details_from_connection (connection, &username, &password, &local)) { + nm_log_warn (LOGD_PPP, "%s", local->message); + dbus_g_method_return_error (priv->pending_secrets_context, local); + g_clear_error (&local); + goto out; + } + + /* This is sort of a hack but... + * pppd plugin only ever needs username and password. Passing the full + * connection there would mean some bloat: the plugin would need to link + * against libnm-util just to parse this. So instead, let's just send what + * it needs. + */ + dbus_g_method_return (priv->pending_secrets_context, username, password); + +out: + priv->pending_secrets_context = NULL; + priv->secrets_id = 0; +} + +static void +impl_ppp_manager_need_secrets (NMPPPManager *manager, + DBusGMethodInvocation *context) +{ + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMConnection *connection; + const char *setting_name; + const char *username = NULL; + const char *password = NULL; + guint32 tries; + GPtrArray *hints = NULL; + GError *error = NULL; + guint32 flags = NM_ACT_REQUEST_GET_SECRETS_FLAG_ALLOW_INTERACTION; + + connection = nm_act_request_get_connection (priv->act_req); + nm_connection_clear_secrets (connection); setting_name = nm_connection_need_secrets (connection, &hints); if (!setting_name) { - NMSetting *setting; - - setting = nm_connection_get_setting_by_name (connection, connection_type); - if (setting) { - const char *username = NULL; - const char *password = NULL; - - /* FIXME: push this down to the settings and keep PPP manager generic */ - if (NM_IS_SETTING_PPPOE (setting)) { - username = nm_setting_pppoe_get_username (NM_SETTING_PPPOE (setting)); - password = nm_setting_pppoe_get_password (NM_SETTING_PPPOE (setting)); - } else if (NM_IS_SETTING_GSM (setting)) { - username = nm_setting_gsm_get_username (NM_SETTING_GSM (setting)); - password = nm_setting_gsm_get_password (NM_SETTING_GSM (setting)); - } else if (NM_IS_SETTING_CDMA (setting)) { - username = nm_setting_cdma_get_username (NM_SETTING_CDMA (setting)); - password = nm_setting_cdma_get_password (NM_SETTING_CDMA (setting)); - } - - /* If secrets are not required, send the existing username and password - * back to the PPP plugin immediately. - */ + /* Use existing secrets from the connection */ + if (extract_details_from_connection (connection, &username, &password, &error)) { + /* Send existing secrets to the PPP plugin */ priv->pending_secrets_context = context; - nm_ppp_manager_update_secrets (manager, - priv->parent_iface, - username ? username : "", - password ? password : "", - NULL); + ppp_secrets_cb (priv->act_req, priv->secrets_id, connection, NULL, manager); } else { - GError *err = NULL; - - g_set_error (&err, NM_PPP_MANAGER_ERROR, NM_PPP_MANAGER_ERROR_UNKOWN, - "Missing type-specific setting; no secrets could be found."); - nm_log_warn (LOGD_PPP, "%s", err->message); - dbus_g_method_return_error (context, err); + nm_log_warn (LOGD_PPP, "%s", error->message); + dbus_g_method_return_error (priv->pending_secrets_context, error); + g_clear_error (&error); } return; } - /* Extract hints */ - if (hints) { - if (hints->len > 0) - hint1 = g_ptr_array_index (hints, 0); - if (hints->len > 1) - hint2 = g_ptr_array_index (hints, 1); - } - - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES)); - /* Only ask for completely new secrets after retrying them once; some PPP - * servers (T-Mobile USA) appear to ask a few times when they actually don't - * even care what you pass back. + /* Only ask for completely new secrets after retrying them once; some devices + * appear to ask a few times when they actually don't even care what you + * pass back. */ - nm_act_request_get_secrets (priv->act_req, - setting_name, - tries > 1 ? TRUE : FALSE, - SECRETS_CALLER_PPP, - hint1, - hint2); + tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES)); + if (tries > 1) + flags |= NM_ACT_REQUEST_GET_SECRETS_FLAG_REQUEST_NEW; + + priv->secrets_id = nm_act_request_get_secrets (priv->act_req, + setting_name, + flags, + hints ? g_ptr_array_index (hints, 0) : NULL, + ppp_secrets_cb, + manager); g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, GUINT_TO_POINTER (++tries)); priv->pending_secrets_context = context; @@ -955,46 +1016,6 @@ nm_ppp_manager_start (NMPPPManager *manager, return priv->pid > 0; } -void -nm_ppp_manager_update_secrets (NMPPPManager *manager, - const char *device, - const char *username, - const char *password, - const char *error_message) -{ - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - - g_return_if_fail (NM_IS_PPP_MANAGER (manager)); - g_return_if_fail (device != NULL); - g_return_if_fail (priv->pending_secrets_context != NULL); - - if (error_message) { - g_return_if_fail (username == NULL); - g_return_if_fail (password == NULL); - } else { - g_return_if_fail (username != NULL); - g_return_if_fail (password != NULL); - } - - if (error_message) { - GError *err = NULL; - - g_set_error (&err, NM_PPP_MANAGER_ERROR, NM_PPP_MANAGER_ERROR_UNKOWN, "%s", error_message); - nm_log_warn (LOGD_PPP, "%s", error_message); - dbus_g_method_return_error (priv->pending_secrets_context, err); - g_error_free (err); - } else { - /* This is sort of a hack but... - pppd plugin only ever needs username and password. - Passing the full connection there would mean some bloat: - the plugin would need to link against libnm-util just to parse this. - So instead, let's just send what it needs */ - - dbus_g_method_return (priv->pending_secrets_context, username, password); - } - priv->pending_secrets_context = NULL; -} - static gboolean ensure_killed (gpointer data) { @@ -1020,6 +1041,8 @@ nm_ppp_manager_stop (NMPPPManager *manager) priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + cancel_get_secrets (manager); + if (priv->monitor_id) { g_source_remove (priv->monitor_id); priv->monitor_id = 0; diff --git a/src/ppp-manager/nm-ppp-manager.h b/src/ppp-manager/nm-ppp-manager.h index a0200973f1..5a8c73e4c9 100644 --- a/src/ppp-manager/nm-ppp-manager.h +++ b/src/ppp-manager/nm-ppp-manager.h @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2010 Red Hat, Inc. */ #ifndef NM_PPP_MANAGER_H @@ -63,12 +63,6 @@ gboolean nm_ppp_manager_start (NMPPPManager *manager, guint32 timeout_secs, GError **err); -void nm_ppp_manager_update_secrets (NMPPPManager *manager, - const char *device, - const char *username, - const char *password, - const char *error_message); - void nm_ppp_manager_stop (NMPPPManager *manager); diff --git a/src/settings/Makefile.am b/src/settings/Makefile.am new file mode 100644 index 0000000000..b6a241310e --- /dev/null +++ b/src/settings/Makefile.am @@ -0,0 +1,72 @@ +INCLUDES = -I${top_srcdir} \ + -I${top_srcdir}/include \ + -I${top_srcdir}/libnm-util \ + -I${top_srcdir}/src/logging \ + -I${top_srcdir}/src \ + -I${top_builddir}/marshallers + +noinst_LTLIBRARIES = libsettings.la + +BUILT_SOURCES = \ + nm-settings-glue.h \ + nm-settings-connection-glue.h \ + nm-agent-manager-glue.h + +libsettings_la_SOURCES = \ + nm-settings.c \ + nm-settings.h \ + nm-inotify-helper.c \ + nm-inotify-helper.h \ + nm-polkit-helpers.h \ + nm-settings-error.c \ + nm-settings-error.h \ + nm-system-config-interface.c \ + nm-system-config-interface.h \ + nm-settings-connection.c \ + nm-settings-connection.h \ + nm-default-wired-connection.c \ + nm-default-wired-connection.h \ + nm-agent-manager.c \ + nm-agent-manager.h \ + nm-secret-agent.c \ + nm-secret-agent.h + +libsettings_la_CPPFLAGS = \ + $(DBUS_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GMODULE_CFLAGS) \ + $(POLKIT_CFLAGS) \ + -DG_DISABLE_DEPRECATED \ + -DBINDIR=\"$(bindir)\" \ + -DSBINDIR=\"$(sbindir)\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DLOCALSTATEDIR=\"$(localstatedir)\" \ + -DGNOMELOCALEDIR=\"$(datadir)/locale\" \ + -DPLUGINDIR=\"$(pkglibdir)\" + +libsettings_la_LIBADD = \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(top_builddir)/marshallers/libmarshallers.la \ + $(top_builddir)/src/logging/libnm-logging.la \ + $(top_builddir)/system-settings/plugins/keyfile/libnm-settings-plugin-keyfile.la \ + $(DBUS_LIBS) \ + $(GLIB_LIBS) \ + $(GMODULE_LIBS) \ + $(POLKIT_LIBS) + +libsettings_la_LDFLAGS = -rdynamic + +nm-settings-glue.h: $(top_srcdir)/introspection/nm-settings.xml + $(AM_V_GEN) dbus-binding-tool --prefix=nm_settings --mode=glib-server --output=$@ $< + +nm-settings-connection-glue.h: $(top_srcdir)/introspection/nm-settings-connection.xml + $(AM_V_GEN) dbus-binding-tool --prefix=nm_settings_connection --mode=glib-server --output=$@ $< + +nm-agent-manager-glue.h: $(top_srcdir)/introspection/nm-agent-manager.xml + $(AM_V_GEN) dbus-binding-tool --prefix=nm_agent_manager --mode=glib-server --output=$@ $< + +CLEANFILES = \ + $(BUILT_SOURCES) + diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c new file mode 100644 index 0000000000..0ffcfd454e --- /dev/null +++ b/src/settings/nm-agent-manager.c @@ -0,0 +1,1346 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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 (C) 2010 - 2011 Red Hat, Inc. + */ + +#include +#include +#include + +#include +#include +#include + +#include "NetworkManager.h" +#include "nm-logging.h" +#include "nm-agent-manager.h" +#include "nm-secret-agent.h" +#include "nm-manager-auth.h" +#include "nm-dbus-glib-types.h" +#include "nm-polkit-helpers.h" +#include "nm-manager-auth.h" +#include "nm-setting-vpn.h" +#include "nm-setting-connection.h" + +G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, G_TYPE_OBJECT) + +#define NM_AGENT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_AGENT_MANAGER, \ + NMAgentManagerPrivate)) + +typedef struct { + gboolean disposed; + + NMDBusManager *dbus_mgr; + NMSessionMonitor *session_monitor; + PolkitAuthority *authority; + + /* Hashed by owner name, not identifier, since two agents in different + * sessions can use the same identifier. + */ + GHashTable *agents; + + GHashTable *requests; +} NMAgentManagerPrivate; + +typedef struct _Request Request; + +static void request_add_agent (Request *req, + NMSecretAgent *agent, + NMSessionMonitor *session_monitor); + +static void request_remove_agent (Request *req, NMSecretAgent *agent); + +static void impl_agent_manager_register (NMAgentManager *self, + const char *identifier, + DBusGMethodInvocation *context); + +static void impl_agent_manager_unregister (NMAgentManager *self, + DBusGMethodInvocation *context); + +#include "nm-agent-manager-glue.h" + +/********************************************************************/ + +#define NM_AGENT_MANAGER_ERROR (nm_agent_manager_error_quark ()) +#define NM_TYPE_AGENT_MANAGER_ERROR (nm_agent_manager_error_get_type ()) + +typedef enum { + NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN = 0, + NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, + NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND, + NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, + NM_AGENT_MANAGER_ERROR_NOT_REGISTERED, + NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR, + NM_AGENT_MANAGER_ERROR_NO_SECRETS +} NMAgentManagerError; + +static GQuark +nm_agent_manager_error_quark (void) +{ + static GQuark ret = 0; + + if (G_UNLIKELY (ret == 0)) + ret = g_quark_from_static_string ("nm-agent-manager-error"); + return ret; +} + +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +static GType +nm_agent_manager_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + /* Unable to determine caller's sender or UID */ + ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, "SenderUnknown"), + /* Permission for some operation was denied */ + ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, "PermissionDenied"), + /* The caller's session could not be determined */ + ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND, "SessionNotFound"), + /* The identifier was invalid */ + ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, "InvalidIdentifier"), + /* Request was not from a registered agent */ + ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_NOT_REGISTERED, "NotRegistered"), + /* Some internal error occurred */ + ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR, "InternalError"), + /* No secrets were available */ + ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_NO_SECRETS, "NoSecrets"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("NMAgentManagerError", values); + } + return etype; +} + +/*************************************************************/ + +static gboolean +remove_agent (NMAgentManager *self, const char *owner) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + NMSecretAgent *agent; + GHashTableIter iter; + gpointer data; + + g_return_val_if_fail (owner != NULL, FALSE); + + /* Make sure this agent has already registered */ + agent = g_hash_table_lookup (priv->agents, owner); + if (!agent) + return FALSE; + + nm_log_dbg (LOGD_AGENTS, "(%s) agent unregistered", + nm_secret_agent_get_description (agent)); + + /* Remove this agent to any in-progress secrets requests */ + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, NULL, &data)) + request_remove_agent ((Request *) data, agent); + + /* And dispose of the agent */ + g_hash_table_remove (priv->agents, owner); + return TRUE; +} + +/*************************************************************/ + +static gboolean +validate_identifier (const char *identifier, GError **error) +{ + const char *p = identifier; + size_t id_len; + + if (!identifier) { + g_set_error_literal (error, + NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, + "No identifier was given"); + return FALSE; + } + + /* Length between 3 and 255 characters inclusive */ + id_len = strlen (identifier); + if (id_len < 3 || id_len > 255) { + g_set_error_literal (error, + NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, + "Identifier length not between 3 and 255 characters (inclusive)"); + return FALSE; + } + + if ((identifier[0] == '.') || (identifier[id_len - 1] == '.')) { + g_set_error_literal (error, + NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, + "Identifier must not start or end with '.'"); + return FALSE; + } + + /* FIXME: do complete validation here */ + while (p && *p) { + if (!isalnum (*p) && (*p != '_') && (*p != '-') && (*p != '.')) { + g_set_error (error, + NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, + "Identifier contains invalid character '%c'", *p); + return FALSE; + } + + if ((*p == '.') && (*(p + 1) == '.')) { + g_set_error_literal (error, + NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, + "Identifier contains two '.' characters in sequence"); + return FALSE; + } + p++; + } + + return TRUE; +} + +static void +impl_agent_manager_register (NMAgentManager *self, + const char *identifier, + DBusGMethodInvocation *context) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + char *error_desc = NULL, *sender = NULL; + gulong sender_uid = G_MAXULONG; + GError *error = NULL, *local = NULL; + NMSecretAgent *agent; + GHashTableIter iter; + gpointer data; + + if (!nm_auth_get_caller_uid (context, + priv->dbus_mgr, + &sender_uid, + &error_desc)) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, + error_desc); + g_free (error_desc); + goto done; + } + + if (!nm_session_monitor_uid_has_session (priv->session_monitor, + sender_uid, + NULL, + &local)) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND, + local && local->message ? local->message : "Session not found"); + goto done; + } + + sender = dbus_g_method_get_sender (context); + if (!sender) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, + "Failed to get D-Bus request sender"); + goto done; + } + + /* Validate the identifier */ + if (!validate_identifier (identifier, &error)) + goto done; + + /* Success, add the new agent */ + agent = nm_secret_agent_new (priv->dbus_mgr, sender, identifier, sender_uid); + if (!agent) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR, + "Failed to initialize the agent"); + goto done; + } + + g_hash_table_insert (priv->agents, g_strdup (sender), agent); + nm_log_dbg (LOGD_AGENTS, "(%s) agent registered", + nm_secret_agent_get_description (agent)); + dbus_g_method_return (context); + + /* Add this agent to any in-progress secrets requests */ + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, NULL, &data)) + request_add_agent ((Request *) data, agent, priv->session_monitor); + +done: + if (error) + dbus_g_method_return_error (context, error); + g_clear_error (&error); + g_clear_error (&local); + g_free (sender); +} + +static void +impl_agent_manager_unregister (NMAgentManager *self, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + char *sender = NULL; + + sender = dbus_g_method_get_sender (context); + if (!sender) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, + "Failed to get D-Bus request sender"); + goto done; + } + + /* Found the agent, unregister and remove it */ + if (!remove_agent (self, sender)) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_NOT_REGISTERED, + "Caller is not registered as an Agent"); + goto done; + } + + dbus_g_method_return (context); + +done: + if (error) + dbus_g_method_return_error (context, error); + g_clear_error (&error); + g_free (sender); +} + +/*************************************************************/ + +typedef void (*RequestCompleteFunc) (Request *req, + GHashTable *secrets, + const char *agent_dbus_owner, + gboolean agent_has_modify, + GError *error, + gpointer user_data); +typedef void (*RequestNextFunc) (Request *req); +typedef void (*RequestCancelFunc) (Request *req); + +struct _Request { + guint32 reqid; + PolkitAuthority *authority; + NMAuthChain *chain; + + NMConnection *connection; + gboolean filter_by_uid; + gulong uid_filter; + char *setting_name; + guint32 flags; + char *hint; + + /* Current agent being asked for secrets */ + NMSecretAgent *current; + gconstpointer current_call_id; + gboolean current_has_modify; + + /* Stores the sorted list of NMSecretAgents which will be asked for secrets */ + GSList *pending; + + /* Stores the list of NMSecretAgent hashes that we've already + * asked for secrets, so that we don't ask the same agent twice + * if it quits and re-registers during this secrets request. + */ + GSList *asked; + + guint32 idle_id; + + GHashTable *existing_secrets; + + NMAgentSecretsResultFunc callback; + gpointer callback_data; + gpointer other_data2; + gpointer other_data3; + + RequestCancelFunc cancel_callback; + RequestNextFunc next_callback; + RequestCompleteFunc complete_callback; + gpointer complete_callback_data; +}; + +static guint32 next_req_id = 1; + +static Request * +request_new_get (NMConnection *connection, + PolkitAuthority *authority, + gboolean filter_by_uid, + gulong uid_filter, + GHashTable *existing_secrets, + const char *setting_name, + guint32 flags, + const char *hint, + NMAgentSecretsResultFunc callback, + gpointer callback_data, + gpointer other_data2, + gpointer other_data3, + RequestCompleteFunc complete_callback, + gpointer complete_callback_data, + RequestNextFunc next_callback, + RequestCancelFunc cancel_callback) +{ + Request *req; + + req = g_malloc0 (sizeof (Request)); + req->reqid = next_req_id++; + req->connection = g_object_ref (connection); + req->authority = g_object_ref (authority); + req->filter_by_uid = filter_by_uid; + req->uid_filter = uid_filter; + if (existing_secrets) + req->existing_secrets = g_hash_table_ref (existing_secrets); + req->setting_name = g_strdup (setting_name); + req->flags = flags; + req->hint = g_strdup (hint); + req->callback = callback; + req->callback_data = callback_data; + req->other_data2 = other_data2; + req->other_data3 = other_data3; + req->complete_callback = complete_callback; + req->complete_callback_data = complete_callback_data; + req->next_callback = next_callback; + req->cancel_callback = cancel_callback; + + return req; +} + +static Request * +request_new_other (NMConnection *connection, + gboolean filter_by_uid, + gulong uid_filter, + RequestCompleteFunc complete_callback, + gpointer complete_callback_data, + RequestNextFunc next_callback) +{ + Request *req; + + req = g_malloc0 (sizeof (Request)); + req->reqid = next_req_id++; + req->connection = g_object_ref (connection); + req->filter_by_uid = filter_by_uid; + req->uid_filter = uid_filter; + req->complete_callback = complete_callback; + req->complete_callback_data = complete_callback_data; + req->next_callback = next_callback; + + return req; +} + +static void +request_free (Request *req) +{ + if (req->idle_id) + g_source_remove (req->idle_id); + + req->cancel_callback (req); + + g_slist_free (req->pending); + g_slist_free (req->asked); + g_object_unref (req->connection); + g_free (req->setting_name); + g_free (req->hint); + if (req->existing_secrets) + g_hash_table_unref (req->existing_secrets); + if (req->chain) + nm_auth_chain_unref (req->chain); + g_object_unref (req->authority); + memset (req, 0, sizeof (Request)); + g_free (req); +} + +static gint +agent_compare_func (NMSecretAgent *a, NMSecretAgent *b, gpointer user_data) +{ + NMSessionMonitor *session_monitor = NM_SESSION_MONITOR (user_data); + gboolean a_active, b_active; + + if (a && !b) + return -1; + else if (a == b) + return 0; + else if (!a && b) + return 1; + + /* Prefer agents in active sessions */ + a_active = nm_session_monitor_uid_active (session_monitor, + nm_secret_agent_get_owner_uid (a), + NULL); + b_active = nm_session_monitor_uid_active (session_monitor, + nm_secret_agent_get_owner_uid (b), + NULL); + if (a_active && !b_active) + return -1; + else if (a_active == b_active) + return 0; + else if (!a_active && b_active) + return 1; + + return 0; +} + +static void +request_add_agent (Request *req, + NMSecretAgent *agent, + NMSessionMonitor *session_monitor) +{ + uid_t agent_uid; + + g_return_if_fail (req != NULL); + g_return_if_fail (agent != NULL); + + if (g_slist_find (req->asked, GUINT_TO_POINTER (nm_secret_agent_get_hash (agent)))) + return; + + /* Ensure the caller's username exists in the connection's permissions, + * or that the permissions is empty (ie, visible by everyone). + */ + agent_uid = nm_secret_agent_get_owner_uid (agent); + if (0 != agent_uid) { + if (!nm_auth_uid_in_acl (req->connection, session_monitor, agent_uid, NULL)) { + nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s (not in ACL)", + nm_secret_agent_get_description (agent), + req, req->setting_name); + /* Connection not visible to this agent's user */ + return; + } + /* Caller is allowed to manipulate this connection */ + } + + /* If the request should filter agents by UID, do that now */ + if (req->filter_by_uid && (agent_uid != req->uid_filter)) { + nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s " + "(uid %ld not required %ld)", + nm_secret_agent_get_description (agent), + req, req->setting_name, agent_uid, req->uid_filter); + return; + } + + nm_log_dbg (LOGD_AGENTS, "(%s) agent allowed for secrets request %p/%s", + nm_secret_agent_get_description (agent), + req, req->setting_name); + + /* Add this agent to the list, preferring active sessions */ + req->pending = g_slist_insert_sorted_with_data (req->pending, + agent, + (GCompareDataFunc) agent_compare_func, + session_monitor); +} + +static void +request_add_agents (NMAgentManager *self, Request *req) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + GHashTableIter iter; + gpointer data; + + g_hash_table_iter_init (&iter, priv->agents); + while (g_hash_table_iter_next (&iter, NULL, &data)) + request_add_agent (req, NM_SECRET_AGENT (data), priv->session_monitor); +} + +static void +request_remove_agent (Request *req, NMSecretAgent *agent) +{ + gboolean try_next = FALSE; + const char *detail = ""; + + g_return_if_fail (req != NULL); + g_return_if_fail (agent != NULL); + + /* If this agent is being asked right now, cancel the request */ + if (agent == req->current) { + req->cancel_callback (req); + req->current_has_modify = FALSE; + req->current = NULL; + req->current_call_id = NULL; + try_next = TRUE; + detail = " current"; + } + + nm_log_dbg (LOGD_AGENTS, "(%s)%s agent removed from secrets request %p/%s", + nm_secret_agent_get_description (agent), + detail, req, req->setting_name); + + req->pending = g_slist_remove (req->pending, agent); + + if (try_next) { + /* If the agent serving the in-progress secrets request went away then + * we need to send the request to the next agent. + */ + req->next_callback (req); + } +} + +static gboolean +next_generic (Request *req, const char *detail) +{ + GError *error = NULL; + gboolean success = FALSE; + + if (req->pending == NULL) { + /* No more secret agents are available to fulfill this secrets request */ + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_NO_SECRETS, + "No agents were available for this request."); + req->complete_callback (req, NULL, NULL, FALSE, error, req->complete_callback_data); + g_error_free (error); + } else { + /* Send a secrets request to the next agent */ + req->current_has_modify = FALSE; + req->current = req->pending->data; + req->pending = g_slist_remove (req->pending, req->current); + + nm_log_dbg (LOGD_AGENTS, "(%s) agent %s secrets for request %p/%s", + nm_secret_agent_get_description (req->current), + detail, req, req->setting_name); + success = TRUE; + } + + return success; +} + +static gboolean +start_generic (gpointer user_data) +{ + Request *req = user_data; + + req->idle_id = 0; + req->next_callback (req); + return FALSE; +} + + +/*************************************************************/ + +static void +get_done_cb (NMSecretAgent *agent, + gconstpointer call_id, + GHashTable *secrets, + GError *error, + gpointer user_data) +{ + Request *req = user_data; + GHashTable *setting_secrets; + const char *agent_dbus_owner; + gboolean agent_has_modify; + + g_return_if_fail (call_id == req->current_call_id); + + agent_has_modify = req->current_has_modify; + req->current_has_modify = FALSE; + req->current = NULL; + req->current_call_id = NULL; + + if (error) { + nm_log_dbg (LOGD_AGENTS, "(%s) agent failed secrets request %p/%s: (%d) %s", + nm_secret_agent_get_description (agent), + req, req->setting_name, + error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); + + /* Try the next agent */ + req->next_callback (req); + return; + } + + /* Ensure the setting we wanted secrets for got returned and has something in it */ + setting_secrets = g_hash_table_lookup (secrets, req->setting_name); + if (!setting_secrets || !g_hash_table_size (setting_secrets)) { + nm_log_dbg (LOGD_AGENTS, "(%s) agent returned no secrets for request %p/%s", + nm_secret_agent_get_description (agent), + req, req->setting_name); + + /* Try the next agent */ + req->next_callback (req); + return; + } + + nm_log_dbg (LOGD_AGENTS, "(%s) agent returned secrets for request %p/%s", + nm_secret_agent_get_description (agent), + req, req->setting_name); + + agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent); + req->complete_callback (req, secrets, agent_dbus_owner, agent_has_modify, NULL, req->complete_callback_data); +} + +static void +set_secrets_not_required (NMConnection *connection, GHashTable *hash) +{ + GHashTableIter iter, setting_iter; + const char *setting_name = NULL; + GHashTable *setting_hash = NULL; + + /* Iterate through the settings hashes */ + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, + (gpointer *) &setting_name, + (gpointer *) &setting_hash)) { + const char *key_name = NULL; + NMSetting *setting; + GValue *val; + + setting = nm_connection_get_setting_by_name (connection, setting_name); + if (setting) { + /* Now through each secret in the setting and mark it as not required */ + g_hash_table_iter_init (&setting_iter, setting_hash); + while (g_hash_table_iter_next (&setting_iter, (gpointer *) &key_name, (gpointer *) &val)) { + /* For each secret, set the flag that it's not required; VPN + * secrets need slightly different treatment here since the + * "secrets" property is actually a hash table of secrets. + */ + if ( strcmp (setting_name, NM_SETTING_VPN_SETTING_NAME) == 0 + && strcmp (key_name, NM_SETTING_VPN_SECRETS) == 0 + && G_VALUE_HOLDS (val, DBUS_TYPE_G_MAP_OF_STRING)) { + GHashTableIter vpn_secret_iter; + const char *secret_name; + + g_hash_table_iter_init (&vpn_secret_iter, g_value_get_boxed (val)); + while (g_hash_table_iter_next (&vpn_secret_iter, (gpointer *) &secret_name, NULL)) + nm_setting_set_secret_flags (setting, secret_name, NM_SETTING_SECRET_FLAG_NOT_REQUIRED, NULL); + } else + nm_setting_set_secret_flags (setting, key_name, NM_SETTING_SECRET_FLAG_NOT_REQUIRED, NULL); + } + } + } +} + +static void +get_agent_request_secrets (Request *req, gboolean include_system_secrets) +{ + NMConnection *tmp; + + tmp = nm_connection_duplicate (req->connection); + nm_connection_clear_secrets (tmp); + if (include_system_secrets) + nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, NULL); + else { + /* Update secret flags in the temporary connection to indicate that + * the system secrets we're not sending to the agent aren't required, + * so the agent can properly validate UI controls and such. + */ + if (req->existing_secrets) + set_secrets_not_required (tmp, req->existing_secrets); + } + + req->current_call_id = nm_secret_agent_get_secrets (NM_SECRET_AGENT (req->current), + tmp, + req->setting_name, + req->hint, + req->flags, + get_done_cb, + req); + if (req->current_call_id == NULL) { + /* Shouldn't hit this, but handle it anyway */ + g_warn_if_fail (req->current_call_id != NULL); + req->current_has_modify = FALSE; + req->current = NULL; + req->next_callback (req); + } + + g_object_unref (tmp); +} + +static void +get_agent_modify_auth_cb (NMAuthChain *chain, + GError *error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + Request *req = user_data; + NMAuthCallResult result; + const char *perm; + + req->chain = NULL; + + if (error) { + nm_log_dbg (LOGD_AGENTS, "(%p/%s) agent MODIFY check error: (%d) %s", + req, req->setting_name, + error->code, error->message ? error->message : "(unknown)"); + + /* Try the next agent */ + req->next_callback (req); + } else { + /* If the agent obtained the 'modify' permission, we send all system secrets + * to it. If it didn't, we still ask it for secrets, but we don't send + * any system secrets. + */ + perm = nm_auth_chain_get_data (chain, "perm"); + g_assert (perm); + result = nm_auth_chain_get_result (chain, perm); + if (result == NM_AUTH_CALL_RESULT_YES) + req->current_has_modify = TRUE; + + nm_log_dbg (LOGD_AGENTS, "(%p/%s) agent MODIFY check result %d", + req, req->setting_name, result); + + get_agent_request_secrets (req, req->current_has_modify); + } + nm_auth_chain_unref (chain); +} + +static void +check_system_secrets_cb (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) +{ + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + gboolean *has_system = user_data; + + if (!(flags & NM_SETTING_PARAM_SECRET)) + return; + + /* Clear out system-owned or always-ask secrets */ + if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) { + GHashTableIter iter; + const char *secret_name = NULL; + + /* VPNs are special; need to handle each secret separately */ + g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value)); + while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) { + if (nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { + if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) + *has_system = TRUE; + } + } + } else { + nm_setting_get_secret_flags (setting, key, &secret_flags, NULL); + if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) + *has_system = TRUE; + } +} + +static gboolean +has_system_secrets (NMConnection *connection) +{ + gboolean has_system = FALSE; + + nm_connection_for_each_setting_value (connection, check_system_secrets_cb, &has_system); + return has_system; +} + +static void +get_next_cb (Request *req) +{ + NMSettingConnection *s_con; + const char *agent_dbus_owner, *perm; + + if (!next_generic (req, "getting")) + return; + + agent_dbus_owner = nm_secret_agent_get_dbus_owner (NM_SECRET_AGENT (req->current)); + + /* If the request flags allow user interaction, and there are existing + * system secrets (or blank secrets that are supposed to be system-owned), + * check whether the agent has the 'modify' permission before sending those + * secrets to the agent. We shouldn't leak system-owned secrets to + * unprivileged users. + */ + if ((req->flags != 0) && (req->existing_secrets || has_system_secrets (req->connection))) { + nm_log_dbg (LOGD_AGENTS, "(%p/%s) request has system secrets; checking agent %s for MODIFY", + req, req->setting_name, agent_dbus_owner); + + req->chain = nm_auth_chain_new_dbus_sender (req->authority, + agent_dbus_owner, + get_agent_modify_auth_cb, + req); + g_assert (req->chain); + + /* If the caller is the only user in the connection's permissions, then + * we use the 'modify.own' permission instead of 'modify.system'. If the + * request affects more than just the caller, require 'modify.system'. + */ + s_con = (NMSettingConnection *) nm_connection_get_setting (req->connection, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (nm_setting_connection_get_num_permissions (s_con) == 1) + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; + else + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; + nm_auth_chain_set_data (req->chain, "perm", (gpointer) perm, NULL); + + nm_auth_chain_add_call (req->chain, perm, TRUE); + } else { + nm_log_dbg (LOGD_AGENTS, "(%p/%s) requesting user-owned secrets from agent %s", + req, req->setting_name, agent_dbus_owner); + + get_agent_request_secrets (req, FALSE); + } +} + +static gboolean +get_start (gpointer user_data) +{ + Request *req = user_data; + GHashTable *setting_secrets = NULL; + + req->idle_id = 0; + + /* Check if there are any existing secrets */ + if (req->existing_secrets) + setting_secrets = g_hash_table_lookup (req->existing_secrets, req->setting_name); + + if (setting_secrets && g_hash_table_size (setting_secrets)) { + NMConnection *tmp; + GError *error = NULL; + + /* The connection already had secrets; check if any more are required. + * If no more are required, we're done. If secrets are still needed, + * ask a secret agent for more. This allows admins to provide generic + * secrets but allow additional user-specific ones as well. + */ + tmp = nm_connection_duplicate (req->connection); + g_assert (tmp); + + if (!nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, &error)) { + req->complete_callback (req, NULL, NULL, FALSE, error, req->complete_callback_data); + g_clear_error (&error); + } else { + /* Do we have everything we need? */ + /* FIXME: handle second check for VPN connections */ + if (nm_connection_need_secrets (tmp, NULL) == NULL) { + nm_log_dbg (LOGD_AGENTS, "(%p/%s) system settings secrets sufficient", + req, req->setting_name); + + /* Got everything, we're done */ + req->complete_callback (req, req->existing_secrets, NULL, FALSE, NULL, req->complete_callback_data); + } else { + nm_log_dbg (LOGD_AGENTS, "(%p/%s) system settings secrets insufficient, asking agents", + req, req->setting_name); + + /* We don't, so ask some agents for additional secrets */ + req->next_callback (req); + } + } + g_object_unref (tmp); + } else { + /* Couldn't get secrets from system settings, so now we ask the + * agents for secrets. Let the Agent Manager handle which agents + * we'll ask and in which order. + */ + req->next_callback (req); + } + + return FALSE; +} + +static void +get_complete_cb (Request *req, + GHashTable *secrets, + const char *agent_dbus_owner, + gboolean agent_has_modify, + GError *error, + gpointer user_data) +{ + NMAgentManager *self = NM_AGENT_MANAGER (user_data); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + + /* Send secrets back to the requesting object */ + req->callback (self, + req->reqid, + agent_dbus_owner, + agent_has_modify, + req->setting_name, + req->flags, + error ? NULL : secrets, + error, + req->callback_data, + req->other_data2, + req->other_data3); + + g_hash_table_remove (priv->requests, GUINT_TO_POINTER (req->reqid)); +} + +static void +get_cancel_cb (Request *req) +{ + if (req->current && req->current_call_id) + nm_secret_agent_cancel_secrets (req->current, req->current_call_id); +} + +guint32 +nm_agent_manager_get_secrets (NMAgentManager *self, + NMConnection *connection, + gboolean filter_by_uid, + gulong uid_filter, + GHashTable *existing_secrets, + const char *setting_name, + guint32 flags, + const char *hint, + NMAgentSecretsResultFunc callback, + gpointer callback_data, + gpointer other_data2, + gpointer other_data3) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + Request *req; + + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (connection != NULL, 0); + g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); + g_return_val_if_fail (callback != NULL, 0); + + nm_log_dbg (LOGD_SETTINGS, + "Secrets requested for connection %s (%s)", + nm_connection_get_path (connection), + setting_name); + + /* NOTE: a few things in the Request handling depend on existing_secrets + * being NULL if there aren't any system-owned secrets for this connection. + * This in turn depends on nm_connection_to_hash() and nm_setting_to_hash() + * both returning NULL if they didn't hash anything. + */ + + req = request_new_get (connection, + priv->authority, + filter_by_uid, + uid_filter, + existing_secrets, + setting_name, + flags, + hint, + callback, + callback_data, + other_data2, + other_data3, + get_complete_cb, + self, + get_next_cb, + get_cancel_cb); + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (req->reqid), req); + + /* Kick off the request */ + request_add_agents (self, req); + req->idle_id = g_idle_add (get_start, req); + + return req->reqid; +} + +void +nm_agent_manager_cancel_secrets (NMAgentManager *self, + guint32 request_id) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (request_id > 0); + + g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, + GUINT_TO_POINTER (request_id)); +} + +/*************************************************************/ + +static void +save_done_cb (NMSecretAgent *agent, + gconstpointer call_id, + GHashTable *secrets, + GError *error, + gpointer user_data) +{ + Request *req = user_data; + const char *agent_dbus_owner; + + g_return_if_fail (call_id == req->current_call_id); + + req->current = NULL; + req->current_call_id = NULL; + + if (error) { + nm_log_dbg (LOGD_AGENTS, "(%s) agent failed save secrets request %p/%s: (%d) %s", + nm_secret_agent_get_description (agent), + req, req->setting_name, + error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); + + /* Try the next agent */ + req->next_callback (req); + return; + } + + nm_log_dbg (LOGD_AGENTS, "(%s) agent saved secrets for request %p/%s", + nm_secret_agent_get_description (agent), + req, req->setting_name); + + agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent); + req->complete_callback (req, NULL, agent_dbus_owner, FALSE, NULL, req->complete_callback_data); +} + +static void +save_next_cb (Request *req) +{ + if (!next_generic (req, "saving")) + return; + + req->current_call_id = nm_secret_agent_save_secrets (NM_SECRET_AGENT (req->current), + req->connection, + save_done_cb, + req); + if (req->current_call_id == NULL) { + /* Shouldn't hit this, but handle it anyway */ + g_warn_if_fail (req->current_call_id != NULL); + req->current = NULL; + req->next_callback (req); + } +} + +static void +save_complete_cb (Request *req, + GHashTable *secrets, + const char *agent_dbus_owner, + gboolean agent_has_modify, + GError *error, + gpointer user_data) +{ + NMAgentManager *self = NM_AGENT_MANAGER (user_data); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + + g_hash_table_remove (priv->requests, GUINT_TO_POINTER (req->reqid)); +} + +guint32 +nm_agent_manager_save_secrets (NMAgentManager *self, + NMConnection *connection, + gboolean filter_by_uid, + gulong uid_filter) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + Request *req; + + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (connection != NULL, 0); + g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); + + nm_log_dbg (LOGD_SETTINGS, + "Saving secrets for connection %s", + nm_connection_get_path (connection)); + + req = request_new_other (connection, + filter_by_uid, + uid_filter, + save_complete_cb, + self, + save_next_cb); + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (req->reqid), req); + + /* Kick off the request */ + request_add_agents (self, req); + req->idle_id = g_idle_add (start_generic, req); + + return req->reqid; +} + +/*************************************************************/ + +static void +delete_done_cb (NMSecretAgent *agent, + gconstpointer call_id, + GHashTable *secrets, + GError *error, + gpointer user_data) +{ + Request *req = user_data; + + g_return_if_fail (call_id == req->current_call_id); + + req->current = NULL; + req->current_call_id = NULL; + + if (error) { + nm_log_dbg (LOGD_AGENTS, "(%s) agent failed delete secrets request %p/%s: (%d) %s", + nm_secret_agent_get_description (agent), + req, req->setting_name, + error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); + } else { + nm_log_dbg (LOGD_AGENTS, "(%s) agent deleted secrets for request %p/%s", + nm_secret_agent_get_description (agent), + req, req->setting_name); + } + + /* Tell the next agent to delete secrets */ + req->next_callback (req); +} + +static void +delete_next_cb (Request *req) +{ + if (!next_generic (req, "deleting")) + return; + + req->current_call_id = nm_secret_agent_delete_secrets (NM_SECRET_AGENT (req->current), + req->connection, + delete_done_cb, + req); + if (req->current_call_id == NULL) { + /* Shouldn't hit this, but handle it anyway */ + g_warn_if_fail (req->current_call_id != NULL); + req->current = NULL; + req->next_callback (req); + } +} + +static void +delete_complete_cb (Request *req, + GHashTable *secrets, + const char *agent_dbus_owner, + gboolean agent_has_modify, + GError *error, + gpointer user_data) +{ + NMAgentManager *self = NM_AGENT_MANAGER (user_data); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + + g_hash_table_remove (priv->requests, GUINT_TO_POINTER (req->reqid)); +} + +guint32 +nm_agent_manager_delete_secrets (NMAgentManager *self, + NMConnection *connection, + gboolean filter_by_uid, + gulong uid_filter) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + Request *req; + + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (connection != NULL, 0); + g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); + + nm_log_dbg (LOGD_SETTINGS, + "Deleting secrets for connection %s", + nm_connection_get_path (connection)); + + req = request_new_other (connection, + filter_by_uid, + uid_filter, + delete_complete_cb, + self, + delete_next_cb); + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (req->reqid), req); + + /* Kick off the request */ + request_add_agents (self, req); + req->idle_id = g_idle_add (start_generic, req); + + return req->reqid; +} + +/*************************************************************/ + +static void +name_owner_changed_cb (NMDBusManager *dbus_mgr, + const char *name, + const char *old_owner, + const char *new_owner, + gpointer user_data) +{ + if (old_owner) { + /* The agent quit, so remove it and let interested clients know */ + remove_agent (NM_AGENT_MANAGER (user_data), old_owner); + } +} + +/*************************************************************/ + +NMAgentManager * +nm_agent_manager_get (void) +{ + static NMAgentManager *singleton = NULL; + NMAgentManagerPrivate *priv; + DBusGConnection *connection; + + if (singleton) + return g_object_ref (singleton); + + singleton = (NMAgentManager *) g_object_new (NM_TYPE_AGENT_MANAGER, NULL); + g_assert (singleton); + + priv = NM_AGENT_MANAGER_GET_PRIVATE (singleton); + priv->session_monitor = nm_session_monitor_get (); + priv->dbus_mgr = nm_dbus_manager_get (); + + connection = nm_dbus_manager_get_connection (priv->dbus_mgr); + dbus_g_connection_register_g_object (connection, + NM_DBUS_PATH_AGENT_MANAGER, + G_OBJECT (singleton)); + + g_signal_connect (priv->dbus_mgr, + NM_DBUS_MANAGER_NAME_OWNER_CHANGED, + G_CALLBACK (name_owner_changed_cb), + singleton); + + return singleton; +} + +static void +nm_agent_manager_init (NMAgentManager *self) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + GError *error = NULL; + + priv->authority = polkit_authority_get_sync (NULL, &error); + if (!priv->authority) { + nm_log_warn (LOGD_SETTINGS, "failed to create PolicyKit authority: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } + + priv->agents = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->requests = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) request_free); +} + +static void +dispose (GObject *object) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (object); + + if (!priv->disposed) { + priv->disposed = TRUE; + + g_hash_table_destroy (priv->agents); + g_hash_table_destroy (priv->requests); + + g_object_unref (priv->session_monitor); + g_object_unref (priv->dbus_mgr); + g_object_unref (priv->authority); + } + + G_OBJECT_CLASS (nm_agent_manager_parent_class)->dispose (object); +} + +static void +nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (agent_manager_class); + + g_type_class_add_private (agent_manager_class, sizeof (NMAgentManagerPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (agent_manager_class), + &dbus_glib_nm_agent_manager_object_info); + + dbus_g_error_domain_register (NM_AGENT_MANAGER_ERROR, + NM_DBUS_INTERFACE_AGENT_MANAGER, + NM_TYPE_AGENT_MANAGER_ERROR); +} diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h new file mode 100644 index 0000000000..5e5dca42f6 --- /dev/null +++ b/src/settings/nm-agent-manager.h @@ -0,0 +1,86 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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 (C) 2010 - 2011 Red Hat, Inc. + */ + +#ifndef NM_AGENT_MANAGER_H +#define NM_AGENT_MANAGER_H + +#include +#include +#include + +#define NM_TYPE_AGENT_MANAGER (nm_agent_manager_get_type ()) +#define NM_AGENT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManager)) +#define NM_AGENT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass)) +#define NM_IS_AGENT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AGENT_MANAGER)) +#define NM_IS_AGENT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_AGENT_MANAGER)) +#define NM_AGENT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass)) + +typedef struct { + GObject parent; +} NMAgentManager; + +typedef struct { + GObjectClass parent; +} NMAgentManagerClass; + +GType nm_agent_manager_get_type (void); + +NMAgentManager *nm_agent_manager_get (void); + +/* If no agent fulfilled the secrets request, agent_dbus_owner will be NULL */ +typedef void (*NMAgentSecretsResultFunc) (NMAgentManager *manager, + guint32 call_id, + const char *agent_dbus_owner, + gboolean agent_has_modify, + const char *setting_name, + guint32 flags, + GHashTable *secrets, + GError *error, + gpointer user_data, + gpointer other_data2, + gpointer other_data3); + +guint32 nm_agent_manager_get_secrets (NMAgentManager *manager, + NMConnection *connection, + gboolean filter_by_uid, + gulong uid, + GHashTable *existing_secrets, + const char *setting_name, + guint32 flags, + const char *hint, + NMAgentSecretsResultFunc callback, + gpointer callback_data, + gpointer other_data2, + gpointer other_data3); + +void nm_agent_manager_cancel_secrets (NMAgentManager *manager, + guint32 request_id); + +guint32 nm_agent_manager_save_secrets (NMAgentManager *manager, + NMConnection *connection, + gboolean filter_by_uid, + gulong uid_filter); + +guint32 nm_agent_manager_delete_secrets (NMAgentManager *manager, + NMConnection *connection, + gboolean filter_by_uid, + gulong uid_filter); + +#endif /* NM_AGENT_MANAGER_H */ diff --git a/src/system-settings/nm-default-wired-connection.c b/src/settings/nm-default-wired-connection.c similarity index 88% rename from src/system-settings/nm-default-wired-connection.c rename to src/settings/nm-default-wired-connection.c index 0d19dea014..e8b9a1554a 100644 --- a/src/system-settings/nm-default-wired-connection.c +++ b/src/settings/nm-default-wired-connection.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * (C) Copyright 2008 Novell, Inc. - * (C) Copyright 2009 Red Hat, Inc. + * (C) Copyright 2009 - 2011 Red Hat, Inc. */ #include @@ -31,15 +31,8 @@ #include "nm-dbus-glib-types.h" #include "nm-marshal.h" #include "nm-default-wired-connection.h" -#include "nm-settings-connection-interface.h" -static NMSettingsConnectionInterface *parent_settings_connection_iface; - -static void settings_connection_interface_init (NMSettingsConnectionInterface *iface); - -G_DEFINE_TYPE_EXTENDED (NMDefaultWiredConnection, nm_default_wired_connection, NM_TYPE_SYSCONFIG_CONNECTION, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE, - settings_connection_interface_init)) +G_DEFINE_TYPE (NMDefaultWiredConnection, nm_default_wired_connection, NM_TYPE_SETTINGS_CONNECTION) #define NM_DEFAULT_WIRED_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEFAULT_WIRED_CONNECTION, NMDefaultWiredConnectionPrivate)) @@ -91,10 +84,10 @@ nm_default_wired_connection_get_device (NMDefaultWiredConnection *wired) return NM_DEFAULT_WIRED_CONNECTION_GET_PRIVATE (wired)->device; } -static gboolean -update (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceUpdateFunc callback, - gpointer user_data) +static void +commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitFunc callback, + gpointer user_data) { NMDefaultWiredConnection *self = NM_DEFAULT_WIRED_CONNECTION (connection); @@ -105,31 +98,24 @@ update (NMSettingsConnectionInterface *connection, g_signal_emit (self, signals[TRY_UPDATE], 0); callback (connection, NULL, user_data); g_object_unref (connection); - return TRUE; } -static gboolean -do_delete (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceDeleteFunc callback, +static void +do_delete (NMSettingsConnection *connection, + NMSettingsConnectionDeleteFunc callback, gpointer user_data) { NMDefaultWiredConnection *self = NM_DEFAULT_WIRED_CONNECTION (connection); NMDefaultWiredConnectionPrivate *priv = NM_DEFAULT_WIRED_CONNECTION_GET_PRIVATE (connection); g_signal_emit (self, signals[DELETED], 0, priv->mac); - return parent_settings_connection_iface->delete (connection, callback, user_data); + NM_SETTINGS_CONNECTION_CLASS (nm_default_wired_connection_parent_class)->delete (connection, + callback, + user_data); } /****************************************************************/ -static void -settings_connection_interface_init (NMSettingsConnectionInterface *iface) -{ - parent_settings_connection_iface = g_type_interface_peek_parent (iface); - iface->update = update; - iface->delete = do_delete; -} - static void nm_default_wired_connection_init (NMDefaultWiredConnection *self) { @@ -251,6 +237,7 @@ static void nm_default_wired_connection_class_init (NMDefaultWiredConnectionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (klass); g_type_class_add_private (klass, sizeof (NMDefaultWiredConnectionPrivate)); @@ -259,6 +246,8 @@ nm_default_wired_connection_class_init (NMDefaultWiredConnectionClass *klass) object_class->set_property = set_property; object_class->get_property = get_property; object_class->finalize = finalize; + settings_class->commit_changes = commit_changes; + settings_class->delete = do_delete; /* Properties */ g_object_class_install_property diff --git a/src/system-settings/nm-default-wired-connection.h b/src/settings/nm-default-wired-connection.h similarity index 94% rename from src/system-settings/nm-default-wired-connection.h rename to src/settings/nm-default-wired-connection.h index de89b67567..9a3bafd027 100644 --- a/src/system-settings/nm-default-wired-connection.h +++ b/src/settings/nm-default-wired-connection.h @@ -16,13 +16,13 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * (C) Copyright 2008 Novell, Inc. - * (C) Copyright 2009 Red Hat, Inc. + * (C) Copyright 2009 - 2011 Red Hat, Inc. */ #ifndef NM_DEFAULT_WIRED_CONNECTION_H #define NM_DEFAULT_WIRED_CONNECTION_H -#include "nm-sysconfig-connection.h" +#include "nm-settings-connection.h" #include "nm-device.h" G_BEGIN_DECLS @@ -39,11 +39,11 @@ G_BEGIN_DECLS #define NM_DEFAULT_WIRED_CONNECTION_READ_ONLY "read-only" typedef struct { - NMSysconfigConnection parent; + NMSettingsConnection parent; } NMDefaultWiredConnection; typedef struct { - NMSysconfigConnectionClass parent; + NMSettingsConnectionClass parent; } NMDefaultWiredConnectionClass; GType nm_default_wired_connection_get_type (void); diff --git a/src/system-settings/nm-inotify-helper.c b/src/settings/nm-inotify-helper.c similarity index 97% rename from src/system-settings/nm-inotify-helper.c rename to src/settings/nm-inotify-helper.c index 0ee168e542..f44fee8232 100644 --- a/src/system-settings/nm-inotify-helper.c +++ b/src/settings/nm-inotify-helper.c @@ -123,14 +123,14 @@ init_inotify (NMInotifyHelper *self) priv->ifd = inotify_init (); if (priv->ifd == -1) { - nm_log_warn (LOGD_SYS_SET, "couldn't initialize inotify"); + nm_log_warn (LOGD_SETTINGS, "couldn't initialize inotify"); return FALSE; } /* Watch the inotify descriptor for file/directory change events */ channel = g_io_channel_unix_new (priv->ifd); if (!channel) { - nm_log_warn (LOGD_SYS_SET, "couldn't create new GIOChannel"); + nm_log_warn (LOGD_SETTINGS, "couldn't create new GIOChannel"); close (priv->ifd); priv->ifd = -1; return FALSE; diff --git a/src/system-settings/nm-inotify-helper.h b/src/settings/nm-inotify-helper.h similarity index 100% rename from src/system-settings/nm-inotify-helper.h rename to src/settings/nm-inotify-helper.h diff --git a/src/system-settings/nm-polkit-helpers.h b/src/settings/nm-polkit-helpers.h similarity index 74% rename from src/system-settings/nm-polkit-helpers.h rename to src/settings/nm-polkit-helpers.h index a37c2eebaa..dfe9ecefc3 100644 --- a/src/system-settings/nm-polkit-helpers.h +++ b/src/settings/nm-polkit-helpers.h @@ -25,11 +25,6 @@ #include #include -#define NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY "org.freedesktop.network-manager-settings.system.modify" -#define NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_PROTECTED "org.freedesktop.network-manager-settings.system.wifi.share.protected" -#define NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_OPEN "org.freedesktop.network-manager-settings.system.wifi.share.open" -#define NM_SYSCONFIG_POLICY_ACTION_HOSTNAME_MODIFY "org.freedesktop.network-manager-settings.system.hostname.modify" - /* Fix for polkit 0.97 and later */ #if !HAVE_POLKIT_AUTHORITY_GET_SYNC static inline PolkitAuthority * diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c new file mode 100644 index 0000000000..67aea821c3 --- /dev/null +++ b/src/settings/nm-secret-agent.c @@ -0,0 +1,398 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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 (C) 2010 - 2011 Red Hat, Inc. + */ + +#include + +#include +#include +#include + +#include "NetworkManager.h" +#include "nm-secret-agent.h" +#include "nm-dbus-glib-types.h" + +G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) + +#define NM_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_SECRET_AGENT, \ + NMSecretAgentPrivate)) + +typedef struct { + gboolean disposed; + + char *description; + char *owner; + char *identifier; + uid_t owner_uid; + guint32 hash; + + NMDBusManager *dbus_mgr; + DBusGProxy *proxy; + + GHashTable *requests; +} NMSecretAgentPrivate; + +/*************************************************************/ + +typedef struct { + NMSecretAgent *agent; + DBusGProxyCall *call; + char *path; + char *setting_name; + NMSecretAgentCallback callback; + gpointer callback_data; +} Request; + +static Request * +request_new (NMSecretAgent *agent, + const char *path, + const char *setting_name, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + Request *r; + + r = g_slice_new0 (Request); + r->agent = agent; + r->path = g_strdup (path); + r->setting_name = g_strdup (setting_name); + r->callback = callback; + r->callback_data = callback_data; + return r; +} + +static void +request_free (Request *r) +{ + g_free (r->path); + g_free (r->setting_name); + g_slice_free (Request, r); +} + +/*************************************************************/ + +const char * +nm_secret_agent_get_description (NMSecretAgent *agent) +{ + NMSecretAgentPrivate *priv; + + g_return_val_if_fail (agent != NULL, NULL); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); + + priv = NM_SECRET_AGENT_GET_PRIVATE (agent); + if (!priv->description) { + priv->description = g_strdup_printf ("%s/%s/%u", + priv->owner, + priv->identifier, + priv->owner_uid); + } + + return priv->description; +} + +const char * +nm_secret_agent_get_dbus_owner (NMSecretAgent *agent) +{ + g_return_val_if_fail (agent != NULL, NULL); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner; +} + +const char * +nm_secret_agent_get_identifier (NMSecretAgent *agent) +{ + g_return_val_if_fail (agent != NULL, NULL); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->identifier; +} + +uid_t +nm_secret_agent_get_owner_uid (NMSecretAgent *agent) +{ + g_return_val_if_fail (agent != NULL, G_MAXUINT); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXUINT); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner_uid; +} + +guint32 +nm_secret_agent_get_hash (NMSecretAgent *agent) +{ + g_return_val_if_fail (agent != NULL, 0); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), 0); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash; +} + +/*************************************************************/ + +static void +get_callback (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + Request *r = user_data; + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + GError *error = NULL; + GHashTable *secrets = NULL; + + g_return_if_fail (call == r->call); + + dbus_g_proxy_end_call (proxy, call, &error, + DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &secrets, + G_TYPE_INVALID); + r->callback (r->agent, r->call, secrets, error, r->callback_data); + if (secrets) + g_hash_table_unref (secrets); + g_clear_error (&error); + g_hash_table_remove (priv->requests, call); +} + +gconstpointer +nm_secret_agent_get_secrets (NMSecretAgent *self, + NMConnection *connection, + const char *setting_name, + const char *hint, + guint32 flags, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + NMSecretAgentPrivate *priv; + GHashTable *hash; + const char *hints[2] = { hint, NULL }; + Request *r; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (setting_name != NULL, NULL); + + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + hash = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL); + + r = request_new (self, nm_connection_get_path (connection), setting_name, callback, callback_data); + r->call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, + "GetSecrets", + get_callback, + r, + NULL, + 120000, /* 120 seconds */ + DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash, + DBUS_TYPE_G_OBJECT_PATH, nm_connection_get_path (connection), + G_TYPE_STRING, setting_name, + G_TYPE_STRV, hints, + G_TYPE_UINT, flags, + G_TYPE_INVALID); + g_hash_table_insert (priv->requests, r->call, r); + + g_hash_table_destroy (hash); + return r->call; +} + +void +nm_secret_agent_cancel_secrets (NMSecretAgent *self, gconstpointer call) +{ + NMSecretAgentPrivate *priv; + Request *r; + + g_return_if_fail (self != NULL); + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + r = g_hash_table_lookup (priv->requests, call); + g_return_if_fail (r != NULL); + + dbus_g_proxy_cancel_call (NM_SECRET_AGENT_GET_PRIVATE (self)->proxy, (gpointer) call); + + dbus_g_proxy_call_no_reply (priv->proxy, + "CancelGetSecrets", + G_TYPE_STRING, r->path, + G_TYPE_STRING, r->setting_name, + G_TYPE_INVALID); + g_hash_table_remove (priv->requests, call); +} + +/*************************************************************/ + +static void +agent_save_delete_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + Request *r = user_data; + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + GError *error = NULL; + + g_return_if_fail (call == r->call); + + dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); + r->callback (r->agent, r->call, NULL, error, r->callback_data); + g_clear_error (&error); + g_hash_table_remove (priv->requests, call); +} + +static gpointer +agent_new_save_delete (NMSecretAgent *self, + NMConnection *connection, + NMSettingHashFlags hash_flags, + const char *method, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GHashTable *hash; + Request *r; + const char *cpath = nm_connection_get_path (connection); + + hash = nm_connection_to_hash (connection, hash_flags); + + r = request_new (self, cpath, NULL, callback, callback_data); + r->call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, + method, + agent_save_delete_cb, + r, + NULL, + 10000, /* 10 seconds */ + DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash, + DBUS_TYPE_G_OBJECT_PATH, cpath, + G_TYPE_INVALID); + g_hash_table_insert (priv->requests, r->call, r); + + g_hash_table_destroy (hash); + return r->call; +} + +gconstpointer +nm_secret_agent_save_secrets (NMSecretAgent *self, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + /* Caller should have ensured that only agent-owned secrets exist in 'connection' */ + return agent_new_save_delete (self, + connection, + NM_SETTING_HASH_FLAG_ALL, + "SaveSecrets", + callback, + callback_data); +} + +gconstpointer +nm_secret_agent_delete_secrets (NMSecretAgent *self, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + /* No secrets sent; agents must be smart enough to track secrets using the UUID or something */ + return agent_new_save_delete (self, + connection, + NM_SETTING_HASH_FLAG_NO_SECRETS, + "DeleteSecrets", + callback, + callback_data); +} + +/*************************************************************/ + +NMSecretAgent * +nm_secret_agent_new (NMDBusManager *dbus_mgr, + const char *owner, + const char *identifier, + uid_t owner_uid) +{ + NMSecretAgent *self; + NMSecretAgentPrivate *priv; + DBusGConnection *bus; + char *hash_str; + + g_return_val_if_fail (owner != NULL, NULL); + g_return_val_if_fail (identifier != NULL, NULL); + + self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL); + if (self) { + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + priv->owner = g_strdup (owner); + priv->identifier = g_strdup (identifier); + priv->owner_uid = owner_uid; + + hash_str = g_strdup_printf ("%08u%s", owner_uid, identifier); + priv->hash = g_str_hash (hash_str); + g_free (hash_str); + + priv->dbus_mgr = g_object_ref (dbus_mgr); + bus = nm_dbus_manager_get_connection (priv->dbus_mgr); + priv->proxy = dbus_g_proxy_new_for_name (bus, + owner, + NM_DBUS_PATH_SECRET_AGENT, + NM_DBUS_INTERFACE_SECRET_AGENT); + g_assert (priv->proxy); + } + + return self; +} + +static void +nm_secret_agent_init (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + priv->requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) request_free); +} + +static void +dispose (GObject *object) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + + if (!priv->disposed) { + priv->disposed = TRUE; + + g_free (priv->description); + g_free (priv->owner); + g_free (priv->identifier); + + g_hash_table_destroy (priv->requests); + g_object_unref (priv->proxy); + g_object_unref (priv->dbus_mgr); + } + + G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object); +} + +static void +nm_secret_agent_class_init (NMSecretAgentClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + g_type_class_add_private (config_class, sizeof (NMSecretAgentPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; +} + diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h new file mode 100644 index 0000000000..676a370b66 --- /dev/null +++ b/src/settings/nm-secret-agent.h @@ -0,0 +1,91 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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 (C) 2010 - 2011 Red Hat, Inc. + */ + +#ifndef NM_SECRET_AGENT_H +#define NM_SECRET_AGENT_H + +#include +#include +#include +#include + +#include +#include "nm-dbus-manager.h" + +#define NM_TYPE_SECRET_AGENT (nm_secret_agent_get_type ()) +#define NM_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent)) +#define NM_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) +#define NM_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SECRET_AGENT)) +#define NM_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SECRET_AGENT)) +#define NM_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) + +typedef struct { + GObject parent; +} NMSecretAgent; + +typedef struct { + GObjectClass parent; +} NMSecretAgentClass; + +GType nm_secret_agent_get_type (void); + +NMSecretAgent *nm_secret_agent_new (NMDBusManager *dbus_mgr, + const char *owner, + const char *identifier, + uid_t owner_uid); + +const char *nm_secret_agent_get_description (NMSecretAgent *agent); + +const char *nm_secret_agent_get_dbus_owner (NMSecretAgent *agent); + +const char *nm_secret_agent_get_identifier (NMSecretAgent *agent); + +uid_t nm_secret_agent_get_owner_uid (NMSecretAgent *agent); + +guint32 nm_secret_agent_get_hash (NMSecretAgent *agent); + +typedef void (*NMSecretAgentCallback) (NMSecretAgent *agent, + gconstpointer call, + GHashTable *new_secrets, /* NULL for save & delete */ + GError *error, + gpointer user_data); + +gconstpointer nm_secret_agent_get_secrets (NMSecretAgent *agent, + NMConnection *connection, + const char *setting_name, + const char *hint, + guint32 flags, + NMSecretAgentCallback callback, + gpointer callback_data); + +void nm_secret_agent_cancel_secrets (NMSecretAgent *agent, + gconstpointer call_id); + +gconstpointer nm_secret_agent_save_secrets (NMSecretAgent *agent, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); + +gconstpointer nm_secret_agent_delete_secrets (NMSecretAgent *agent, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); + +#endif /* NM_SECRET_AGENT_H */ diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c new file mode 100644 index 0000000000..4c059df862 --- /dev/null +++ b/src/settings/nm-settings-connection.c @@ -0,0 +1,1344 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2008 Novell, Inc. + * (C) Copyright 2008 - 2011 Red Hat, Inc. + */ + +#include + +#include +#include +#include +#include +#include + +#include "nm-settings-connection.h" +#include "nm-session-monitor.h" +#include "nm-dbus-manager.h" +#include "nm-settings-error.h" +#include "nm-dbus-glib-types.h" +#include "nm-polkit-helpers.h" +#include "nm-logging.h" +#include "nm-manager-auth.h" +#include "nm-marshal.h" +#include "nm-agent-manager.h" + +static void impl_settings_connection_get_settings (NMSettingsConnection *connection, + DBusGMethodInvocation *context); + +static void impl_settings_connection_update (NMSettingsConnection *connection, + GHashTable *new_settings, + DBusGMethodInvocation *context); + +static void impl_settings_connection_delete (NMSettingsConnection *connection, + DBusGMethodInvocation *context); + +static void impl_settings_connection_get_secrets (NMSettingsConnection *connection, + const gchar *setting_name, + DBusGMethodInvocation *context); + +#include "nm-settings-connection-glue.h" + +G_DEFINE_TYPE (NMSettingsConnection, nm_settings_connection, NM_TYPE_CONNECTION) + +#define NM_SETTINGS_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_SETTINGS_CONNECTION, \ + NMSettingsConnectionPrivate)) + +enum { + PROP_0 = 0, + PROP_VISIBLE, +}; + +enum { + UPDATED, + REMOVED, + UNREGISTER, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + gboolean disposed; + + NMDBusManager *dbus_mgr; + NMAgentManager *agent_mgr; + + PolkitAuthority *authority; + GSList *pending_auths; /* List of pending authentication requests */ + NMConnection *secrets; + gboolean visible; /* Is this connection is visible by some session? */ + + GSList *reqs; /* in-progress secrets requests */ + + NMSessionMonitor *session_monitor; + guint session_changed_id; +} NMSettingsConnectionPrivate; + +/**************************************************************/ + +static void +set_visible (NMSettingsConnection *self, gboolean new_visible) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + if (new_visible == priv->visible) + return; + priv->visible = new_visible; + g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_VISIBLE); +} + +gboolean +nm_settings_connection_is_visible (NMSettingsConnection *self) +{ + g_return_val_if_fail (NM_SETTINGS_CONNECTION (self), FALSE); + + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->visible; +} + +void +nm_settings_connection_recheck_visibility (NMSettingsConnection *self) +{ + NMSettingsConnectionPrivate *priv; + NMSettingConnection *s_con; + guint32 num, i; + + g_return_if_fail (NM_SETTINGS_CONNECTION (self)); + + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + + /* Check every user in the ACL for a session */ + num = nm_setting_connection_get_num_permissions (s_con); + if (num == 0) { + /* Visible to all */ + set_visible (self, TRUE); + return; + } + + for (i = 0; i < num; i++) { + const char *puser; + + if (nm_setting_connection_get_permission (s_con, i, NULL, &puser, NULL)) { + if (nm_session_monitor_user_has_session (priv->session_monitor, puser, NULL, NULL)) { + set_visible (self, TRUE); + return; + } + } + } + + set_visible (self, FALSE); +} + +static void +session_changed_cb (NMSessionMonitor *self, gpointer user_data) +{ + nm_settings_connection_recheck_visibility (NM_SETTINGS_CONNECTION (user_data)); +} + +/**************************************************************/ + +static void +only_system_secrets_cb (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) +{ + if (flags & NM_SETTING_PARAM_SECRET) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + /* VPNs are special; need to handle each secret separately */ + if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) { + GHashTableIter iter; + const char *secret_name = NULL; + + g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value)); + while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) { + if (nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { + if (secret_flags != NM_SETTING_SECRET_FLAG_NONE) + nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name); + } + } + } else { + nm_setting_get_secret_flags (setting, key, &secret_flags, NULL); + if (secret_flags != NM_SETTING_SECRET_FLAG_NONE) + g_object_set (G_OBJECT (setting), key, NULL, NULL); + } + } +} + +static void +update_secrets_cache (NMSettingsConnection *self) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + if (priv->secrets) + g_object_unref (priv->secrets); + priv->secrets = nm_connection_duplicate (NM_CONNECTION (self)); + + /* Clear out non-system-owned and not-saved secrets */ + nm_connection_for_each_setting_value (priv->secrets, only_system_secrets_cb, NULL); +} + +/* Update the settings of this connection to match that of 'new', taking care to + * make a private copy of secrets. */ +gboolean +nm_settings_connection_replace_settings (NMSettingsConnection *self, + NMConnection *new, + GError **error) +{ + NMSettingsConnectionPrivate *priv; + GHashTable *new_settings; + gboolean success = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); + g_return_val_if_fail (new != NULL, FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (new), FALSE); + + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + new_settings = nm_connection_to_hash (new, NM_SETTING_HASH_FLAG_ALL); + g_assert (new_settings); + if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, error)) { + /* Copy the connection to keep its secrets around even if NM + * calls nm_connection_clear_secrets(). + */ + update_secrets_cache (self); + + nm_settings_connection_recheck_visibility (self); + success = TRUE; + } + g_hash_table_destroy (new_settings); + return success; +} + +static void +ignore_cb (NMSettingsConnection *connection, + GError *error, + gpointer user_data) +{ +} + +/* Replaces the settings in this connection with those in 'new'. If any changes + * are made, commits them to permanent storage and to any other subsystems + * watching this connection. Before returning, 'callback' is run with the given + * 'user_data' along with any errors encountered. + */ +void +nm_settings_connection_replace_and_commit (NMSettingsConnection *self, + NMConnection *new, + NMSettingsConnectionCommitFunc callback, + gpointer user_data) +{ + GError *error = NULL; + + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); + g_return_if_fail (new != NULL); + g_return_if_fail (NM_IS_CONNECTION (new)); + + if (!callback) + callback = ignore_cb; + + /* Do nothing if there's nothing to update */ + if (nm_connection_compare (NM_CONNECTION (self), + NM_CONNECTION (new), + NM_SETTING_COMPARE_FLAG_EXACT)) { + callback (self, NULL, user_data); + return; + } + + if (nm_settings_connection_replace_settings (self, new, &error)) { + nm_settings_connection_commit_changes (self, callback, user_data); + } else { + callback (self, error, user_data); + g_clear_error (&error); + } +} + +void +nm_settings_connection_commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitFunc callback, + gpointer user_data) +{ + g_return_if_fail (connection != NULL); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); + g_return_if_fail (callback != NULL); + + if (NM_SETTINGS_CONNECTION_GET_CLASS (connection)->commit_changes) { + NM_SETTINGS_CONNECTION_GET_CLASS (connection)->commit_changes (connection, + callback, + user_data); + } else { + GError *error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INTERNAL_ERROR, + "%s: %s:%d commit_changes() unimplemented", __func__, __FILE__, __LINE__); + callback (connection, error, user_data); + g_error_free (error); + } +} + +void +nm_settings_connection_delete (NMSettingsConnection *connection, + NMSettingsConnectionDeleteFunc callback, + gpointer user_data) +{ + g_return_if_fail (connection != NULL); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); + g_return_if_fail (callback != NULL); + + if (NM_SETTINGS_CONNECTION_GET_CLASS (connection)->delete) { + NM_SETTINGS_CONNECTION_GET_CLASS (connection)->delete (connection, + callback, + user_data); + } else { + GError *error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INTERNAL_ERROR, + "%s: %s:%d delete() unimplemented", __func__, __FILE__, __LINE__); + callback (connection, error, user_data); + g_error_free (error); + } +} + +static void +commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitFunc callback, + gpointer user_data) +{ + g_object_ref (connection); + g_signal_emit (connection, signals[UPDATED], 0); + callback (connection, NULL, user_data); + g_object_unref (connection); +} + +static void +do_delete (NMSettingsConnection *connection, + NMSettingsConnectionDeleteFunc callback, + gpointer user_data) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection); + NMConnection *for_agents; + + g_object_ref (connection); + set_visible (connection, FALSE); + + /* Tell agents to remove secrets for this connection */ + for_agents = nm_connection_duplicate (NM_CONNECTION (connection)); + nm_connection_clear_secrets (for_agents); + nm_agent_manager_delete_secrets (priv->agent_mgr, for_agents, FALSE, 0); + + /* Signal the connection is removed and deleted */ + g_signal_emit (connection, signals[REMOVED], 0); + callback (connection, NULL, user_data); + g_object_unref (connection); +} + +/**************************************************************/ + +static gboolean +supports_secrets (NMSettingsConnection *connection, const char *setting_name) +{ + /* All secrets supported */ + return TRUE; +} + +/* Return TRUE to continue, FALSE to stop */ +typedef gboolean (*ForEachSecretFunc) (GHashTableIter *iter, + NMSettingSecretFlags flags, + gpointer user_data); + +static gboolean +clear_nonagent_secrets (GHashTableIter *iter, + NMSettingSecretFlags flags, + gpointer user_data) +{ + if (flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED) + g_hash_table_iter_remove (iter); + return TRUE; +} + +static gboolean +clear_unsaved_secrets (GHashTableIter *iter, + NMSettingSecretFlags flags, + gpointer user_data) +{ + if (flags & (NM_SETTING_SECRET_FLAG_NOT_SAVED | NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) + g_hash_table_iter_remove (iter); + return TRUE; +} + +static gboolean +has_system_owned_secrets (GHashTableIter *iter, + NMSettingSecretFlags flags, + gpointer user_data) +{ + gboolean *has_system_owned = user_data; + + if (!(flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)) { + *has_system_owned = TRUE; + return FALSE; + } + return TRUE; +} + +static void +for_each_secret (NMConnection *connection, + GHashTable *secrets, + ForEachSecretFunc callback, + gpointer callback_data) +{ + GHashTableIter iter; + const char *setting_name; + GHashTable *setting_hash; + + /* Walk through the list of setting hashes */ + g_hash_table_iter_init (&iter, secrets); + while (g_hash_table_iter_next (&iter, + (gpointer *) &setting_name, + (gpointer *) &setting_hash)) { + GHashTableIter setting_iter; + const char *secret_name; + + /* Walk through the list of keys in each setting hash */ + g_hash_table_iter_init (&setting_iter, setting_hash); + while (g_hash_table_iter_next (&setting_iter, (gpointer *) &secret_name, NULL)) { + NMSetting *setting; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + + /* Get the actual NMSetting from the connection so we can get secret flags */ + setting = nm_connection_get_setting_by_name (connection, setting_name); + if (setting && nm_setting_get_secret_flags (setting, secret_name, &flags, NULL)) { + if (callback (&setting_iter, flags, callback_data) == FALSE) + return; + } + } + } +} + +static void +new_secrets_commit_cb (NMSettingsConnection *connection, + GError *error, + gpointer user_data) +{ + if (error) { + nm_log_warn (LOGD_SETTINGS, "Error saving new secrets to backing storage: (%d) %s", + error->code, error->message ? error->message : "(unknown)"); + } +} + +static void +agent_secrets_done_cb (NMAgentManager *manager, + guint32 call_id, + const char *agent_dbus_owner, + gboolean agent_has_modify, + const char *setting_name, + guint32 flags, + GHashTable *secrets, + GError *error, + gpointer user_data, + gpointer other_data2, + gpointer other_data3) +{ + NMSettingsConnection *self = NM_SETTINGS_CONNECTION (user_data); + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMSettingsConnectionSecretsFunc callback = other_data2; + gpointer callback_data = other_data3; + GError *local = NULL; + GHashTable *hash; + + if (error) { + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets request error: (%d) %s", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id, + error->code, + error->message ? error->message : "(unknown)"); + + callback (self, call_id, setting_name, error, callback_data); + return; + } + + if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { + local = g_error_new (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_SETTING, + "%s.%d - Connection didn't have requested setting '%s'.", + __FILE__, __LINE__, setting_name); + callback (self, call_id, setting_name, local, callback_data); + g_clear_error (&local); + return; + } + + g_assert (secrets); + if (agent_dbus_owner) { + gboolean has_system = FALSE; + + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets returned from agent %s", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id, + agent_dbus_owner); + + /* If the agent returned any system-owned secrets (initial connect and no + * secrets given when the connection was created, or something like that) + * make sure the agent's UID has the 'modify' permission before we use or + * save those system-owned secrets. If not, discard them and use the + * existing secrets, or fail the connection. + */ + for_each_secret (NM_CONNECTION (self), secrets, has_system_owned_secrets, &has_system); + if (has_system) { + if (flags == 0) { /* ie SECRETS_FLAG_NONE */ + /* No user interaction was allowed when requesting secrets; the + * agent is being bad. Remove system-owned secrets. + */ + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) interaction forbidden but agent %s returned system secrets", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id, + agent_dbus_owner); + + for_each_secret (NM_CONNECTION (self), secrets, clear_nonagent_secrets, NULL); + } else if (agent_has_modify == FALSE) { + /* Agent didn't successfully authenticate; clear system-owned secrets + * from the secrets the agent returned. + */ + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) agent failed to authenticate but provided system secrets", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id); + + for_each_secret (NM_CONNECTION (self), secrets, clear_nonagent_secrets, NULL); + } + } + } else { + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) existing secrets returned", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id); + } + + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets request completed", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id); + + /* If no user interaction was allowed, make sure that no "unsaved" secrets + * came back. Unsaved secrets by definition require user interaction. + */ + if (flags == 0) /* ie SECRETS_FLAG_NONE */ + for_each_secret (NM_CONNECTION (self), secrets, clear_unsaved_secrets, NULL); + + /* Update the connection with our existing secrets from backing storage */ + nm_connection_clear_secrets (NM_CONNECTION (self)); + hash = nm_connection_to_hash (priv->secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS); + if (!hash || nm_connection_update_secrets (NM_CONNECTION (self), setting_name, hash, &local)) { + /* Update the connection with the agent's secrets; by this point if any + * system-owned secrets exist in 'secrets' the agent that provided them + * will have been authenticated, so those secrets can replace the existing + * system secrets. + */ + if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, secrets, &local)) { + /* Now that all secrets are updated, copy and cache new secrets, + * then save them to backing storage. + */ + update_secrets_cache (self); + + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) saving new secrets to backing storage", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id); + + nm_settings_connection_commit_changes (self, new_secrets_commit_cb, NULL); + } else { + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) failed to update with agent secrets: (%d) %s", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id, + local ? local->code : -1, + (local && local->message) ? local->message : "(unknown)"); + } + } else { + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) failed to update with existing secrets: (%d) %s", + nm_connection_get_uuid (NM_CONNECTION (self)), + setting_name, + call_id, + local ? local->code : -1, + (local && local->message) ? local->message : "(unknown)"); + } + + callback (self, call_id, setting_name, local, callback_data); + g_clear_error (&local); + if (hash) + g_hash_table_destroy (hash); +} + +/** + * nm_settings_connection_get_secrets: + * @connection: the #NMSettingsConnection + * @filter_by_uid: if TRUE, only request secrets from agents registered by the + * same UID as @uid. + * @uid: when @filter_by_uid is TRUE, only request secrets from agents belonging + * to this UID + * @setting_name: the setting to return secrets for + * @flags: flags to modify the secrets request + * @hint: the name of a key in @setting_name for which a secret may be required + * @callback: the function to call with returned secrets + * @callback_data: user data to pass to @callback + * + * Retrieves secrets from persistent storage and queries any secret agents for + * additional secrets. + * + * Returns: a call ID which may be used to cancel the ongoing secrets request + **/ +guint32 +nm_settings_connection_get_secrets (NMSettingsConnection *self, + gboolean filter_by_uid, + gulong uid, + const char *setting_name, + guint32 flags, + const char *hint, + NMSettingsConnectionSecretsFunc callback, + gpointer callback_data, + GError **error) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMSettingConnection *s_con; + GHashTable *existing_secrets; + guint32 call_id = 0; + + /* Use priv->secrets to work around the fact that nm_connection_clear_secrets() + * will clear secrets on this object's settings. priv->secrets should be + * a complete copy of this object and kept in sync by + * nm_settings_connection_replace_settings(). + */ + if (!priv->secrets) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "%s.%d - Internal error; secrets cache invalid.", + __FILE__, __LINE__); + return 0; + } + + /* Make sure the request actually requests something we can return */ + if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_SETTING, + "%s.%d - Connection didn't have requested setting '%s'.", + __FILE__, __LINE__, setting_name); + return 0; + } + + existing_secrets = nm_connection_to_hash (priv->secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS); + call_id = nm_agent_manager_get_secrets (priv->agent_mgr, + NM_CONNECTION (self), + filter_by_uid, + uid, + existing_secrets, + setting_name, + flags, + hint, + agent_secrets_done_cb, + self, + callback, + callback_data); + if (existing_secrets) + g_hash_table_unref (existing_secrets); + + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION); + nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets requested flags 0x%X hint '%s'", + nm_setting_connection_get_uuid (s_con), + setting_name, + call_id, + flags, + hint); + + return call_id; +} + +void +nm_settings_connection_cancel_secrets (NMSettingsConnection *self, + guint32 call_id) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMSettingConnection *s_con; + + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION); + nm_log_dbg (LOGD_SETTINGS, "(%s:%u) secrets canceled", + nm_setting_connection_get_uuid (s_con), + call_id); + + priv->reqs = g_slist_remove (priv->reqs, GUINT_TO_POINTER (call_id)); + nm_agent_manager_cancel_secrets (priv->agent_mgr, call_id); +} + +/**** User authorization **************************************/ + +typedef void (*AuthCallback) (NMSettingsConnection *connection, + DBusGMethodInvocation *context, + gulong sender_uid, + GError *error, + gpointer data); + +static void +pk_auth_cb (NMAuthChain *chain, + GError *chain_error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + NMSettingsConnection *self = NM_SETTINGS_CONNECTION (user_data); + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + GError *error = NULL; + NMAuthCallResult result; + const char *perm; + AuthCallback callback; + gpointer callback_data; + gulong sender_uid; + + priv->pending_auths = g_slist_remove (priv->pending_auths, chain); + + /* If our NMSettingsConnection is already gone, do nothing */ + if (chain_error) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_GENERAL, + "Error checking authorization: %s", + chain_error->message ? chain_error->message : "(unknown)"); + } else { + perm = nm_auth_chain_get_data (chain, "perm"); + g_assert (perm); + result = nm_auth_chain_get_result (chain, perm); + + /* Caller didn't successfully authenticate */ + if (result != NM_AUTH_CALL_RESULT_YES) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_NOT_PRIVILEGED, + "Insufficient privileges."); + } + } + + callback = nm_auth_chain_get_data (chain, "callback"); + callback_data = nm_auth_chain_get_data (chain, "callback-data"); + sender_uid = nm_auth_chain_get_data_ulong (chain, "sender-uid"); + callback (self, context, sender_uid, error, callback_data); + + g_clear_error (&error); + nm_auth_chain_unref (chain); +} + +static gboolean +check_user_in_acl (NMConnection *connection, + DBusGMethodInvocation *context, + NMDBusManager *dbus_mgr, + NMSessionMonitor *session_monitor, + gulong *out_sender_uid, + GError **error) +{ + gulong sender_uid = G_MAXULONG; + char *error_desc = NULL; + + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (context != NULL, FALSE); + g_return_val_if_fail (session_monitor != NULL, FALSE); + + /* Get the caller's UID */ + if (!nm_auth_get_caller_uid (context, dbus_mgr, &sender_uid, &error_desc)) { + g_set_error_literal (error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); + return FALSE; + } + + /* Make sure the UID can view this connection */ + if (0 != sender_uid) { + if (!nm_auth_uid_in_acl (connection, session_monitor, sender_uid, &error_desc)) { + g_set_error_literal (error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); + return FALSE; + } + } + + if (out_sender_uid) + *out_sender_uid = sender_uid; + return TRUE; +} + +static void +auth_start (NMSettingsConnection *self, + DBusGMethodInvocation *context, + const char *check_permission, + AuthCallback callback, + gpointer callback_data) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMAuthChain *chain; + gulong sender_uid = G_MAXULONG; + GError *error = NULL; + + if (!check_user_in_acl (NM_CONNECTION (self), + context, + priv->dbus_mgr, + priv->session_monitor, + &sender_uid, + &error)) { + callback (self, context, G_MAXULONG, error, callback_data); + g_clear_error (&error); + return; + } + + if (check_permission) { + chain = nm_auth_chain_new (priv->authority, context, NULL, pk_auth_cb, self); + g_assert (chain); + nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL); + nm_auth_chain_set_data (chain, "callback", callback, NULL); + nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL); + nm_auth_chain_set_data_ulong (chain, "sender-uid", sender_uid); + + nm_auth_chain_add_call (chain, check_permission, TRUE); + priv->pending_auths = g_slist_append (priv->pending_auths, chain); + } else { + /* Don't need polkit auth, automatic success */ + callback (self, context, sender_uid, NULL, callback_data); + } +} + +/**** DBus method handlers ************************************/ + +static gboolean +check_writable (NMConnection *connection, GError **error) +{ + NMSettingConnection *s_con; + + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + if (!s_con) { + g_set_error_literal (error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Connection did not have required 'connection' setting"); + return FALSE; + } + + /* If the connection is read-only, that has to be changed at the source of + * the problem (ex a system settings plugin that can't write connections out) + * instead of over D-Bus. + */ + if (nm_setting_connection_get_read_only (s_con)) { + g_set_error_literal (error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_READ_ONLY_CONNECTION, + "Connection is read-only"); + return FALSE; + } + + return TRUE; +} + +static void +get_settings_auth_cb (NMSettingsConnection *self, + DBusGMethodInvocation *context, + gulong sender_uid, + GError *error, + gpointer data) +{ + if (error) + dbus_g_method_return_error (context, error); + else { + GHashTable *settings; + + /* Secrets should *never* be returned by the GetSettings method, they + * get returned by the GetSecrets method which can be better + * protected against leakage of secrets to unprivileged callers. + */ + settings = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_NO_SECRETS); + g_assert (settings); + dbus_g_method_return (context, settings); + g_hash_table_destroy (settings); + } +} + +static void +impl_settings_connection_get_settings (NMSettingsConnection *self, + DBusGMethodInvocation *context) +{ + auth_start (self, context, NULL, get_settings_auth_cb, NULL); +} + +static void +con_update_cb (NMSettingsConnection *connection, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); +} + +static void +only_agent_secrets_cb (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) +{ + if (flags & NM_SETTING_PARAM_SECRET) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + /* Clear out system-owned or always-ask secrets */ + if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) { + GHashTableIter iter; + const char *secret_name = NULL; + + /* VPNs are special; need to handle each secret separately */ + g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value)); + while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) { + if (nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { + if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED) + nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name); + } + } + } else { + nm_setting_get_secret_flags (setting, key, &secret_flags, NULL); + if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED) + g_object_set (G_OBJECT (setting), key, NULL, NULL); + } + } +} + +static void +update_auth_cb (NMSettingsConnection *self, + DBusGMethodInvocation *context, + gulong sender_uid, + GError *error, + gpointer data) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMConnection *new_settings = data; + NMConnection *for_agent; + + if (error) + dbus_g_method_return_error (context, error); + else { + /* Update and commit our settings. */ + nm_settings_connection_replace_and_commit (self, + new_settings, + con_update_cb, + context); + + /* Dupe the connection and clear out non-agent-owned secrets so we can + * send the agent-owned ones to agents to be saved. Only send them to + * agents of the same UID as the Update() request sender. + */ + for_agent = nm_connection_duplicate (NM_CONNECTION (self)); + nm_connection_for_each_setting_value (for_agent, only_agent_secrets_cb, NULL); + nm_agent_manager_save_secrets (priv->agent_mgr, for_agent, TRUE, sender_uid); + g_object_unref (for_agent); + } + + g_object_unref (new_settings); +} + +static const char * +get_modify_permission_update (NMConnection *old, NMConnection *new) +{ + NMSettingConnection *s_con; + guint32 orig_num = 0, new_num = 0; + + s_con = (NMSettingConnection *) nm_connection_get_setting (old, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + orig_num = nm_setting_connection_get_num_permissions (s_con); + + s_con = (NMSettingConnection *) nm_connection_get_setting (new, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + new_num = nm_setting_connection_get_num_permissions (s_con); + + /* If the caller is the only user in either connection's permissions, then + * we use the 'modify.own' permission instead of 'modify.system'. + */ + if (orig_num == 1 && new_num == 1) + return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; + + /* If the update request affects more than just the caller (ie if the old + * settings were system-wide, or the new ones are), require 'modify.system'. + */ + return NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; +} + +static void +impl_settings_connection_update (NMSettingsConnection *self, + GHashTable *new_settings, + DBusGMethodInvocation *context) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMConnection *tmp; + GError *error = NULL; + + /* If the connection is read-only, that has to be changed at the source of + * the problem (ex a system settings plugin that can't write connections out) + * instead of over D-Bus. + */ + if (!check_writable (NM_CONNECTION (self), &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } + + /* Check if the settings are valid first */ + tmp = nm_connection_new_from_hash (new_settings, &error); + if (!tmp) { + g_assert (error); + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } + + /* And that the new connection settings will be visible to the user + * that's sending the update request. You can't make a connection + * invisible to yourself. + */ + if (!check_user_in_acl (tmp, + context, + priv->dbus_mgr, + priv->session_monitor, + NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + g_object_unref (tmp); + return; + } + + auth_start (self, + context, + get_modify_permission_update (NM_CONNECTION (self), tmp), + update_auth_cb, + tmp); +} + +static void +con_delete_cb (NMSettingsConnection *connection, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); +} + +static void +delete_auth_cb (NMSettingsConnection *self, + DBusGMethodInvocation *context, + gulong sender_uid, + GError *error, + gpointer data) +{ + if (error) { + dbus_g_method_return_error (context, error); + return; + } + + nm_settings_connection_delete (self, con_delete_cb, context); +} + +static const char * +get_modify_permission_basic (NMSettingsConnection *connection) +{ + NMSettingConnection *s_con; + + /* If the caller is the only user in the connection's permissions, then + * we use the 'modify.own' permission instead of 'modify.system'. If the + * request affects more than just the caller, require 'modify.system'. + */ + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (nm_setting_connection_get_num_permissions (s_con) == 1) + return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; + + return NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; +} + +static void +impl_settings_connection_delete (NMSettingsConnection *self, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + + if (!check_writable (NM_CONNECTION (self), &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } + + auth_start (self, context, get_modify_permission_basic (self), delete_auth_cb, NULL); +} + +/**************************************************************/ + +static void +dbus_get_agent_secrets_cb (NMSettingsConnection *self, + guint32 call_id, + const char *setting_name, + GError *error, + gpointer user_data) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + DBusGMethodInvocation *context = user_data; + GHashTable *hash; + + priv->reqs = g_slist_remove (priv->reqs, GUINT_TO_POINTER (call_id)); + + if (error) + dbus_g_method_return_error (context, error); + else { + /* The connection's secrets will have been updated by the agent manager, + * so we want to refresh the secrets cache. Note that we will never save + * new secrets to backing storage here because D-Bus initated requests will + * never ask for completely new secrets from agents. Thus system-owned + * secrets should not have changed from backing storage. We also don't + * send agent-owned secrets back out to be saved since we assume the agent + * that provided the secrets saved them itself. + */ + update_secrets_cache (self); + + hash = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS); + dbus_g_method_return (context, hash); + g_hash_table_destroy (hash); + } +} + +static void +dbus_secrets_auth_cb (NMSettingsConnection *self, + DBusGMethodInvocation *context, + gulong sender_uid, + GError *error, + gpointer user_data) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + char *setting_name = user_data; + guint32 call_id = 0; + GError *local = NULL; + + if (!error) { + call_id = nm_settings_connection_get_secrets (self, + TRUE, + sender_uid, + setting_name, + 0, /* GET_SECRETS_FLAG_NONE */ + NULL, + dbus_get_agent_secrets_cb, + context, + &local); + if (call_id > 0) { + /* track the request and wait for the callback */ + priv->reqs = g_slist_append (priv->reqs, GUINT_TO_POINTER (call_id)); + } + } + + if (error || local) { + dbus_g_method_return_error (context, error ? error : local); + g_clear_error (&local); + } + + g_free (setting_name); +} + +static void +impl_settings_connection_get_secrets (NMSettingsConnection *self, + const gchar *setting_name, + DBusGMethodInvocation *context) +{ + auth_start (self, + context, + get_modify_permission_basic (self), + dbus_secrets_auth_cb, + g_strdup (setting_name)); +} + +/**************************************************************/ + +void +nm_settings_connection_signal_remove (NMSettingsConnection *self) +{ + /* Emit removed first */ + g_signal_emit_by_name (self, NM_SETTINGS_CONNECTION_REMOVED); + + /* And unregistered last to ensure the removed signal goes out before + * we take the connection off the bus. + */ + g_signal_emit_by_name (self, "unregister"); +} + +/**************************************************************/ + +static void +nm_settings_connection_init (NMSettingsConnection *self) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + static guint32 dbus_counter = 0; + char *dbus_path; + GError *error = NULL; + + priv->dbus_mgr = nm_dbus_manager_get (); + + priv->authority = polkit_authority_get_sync (NULL, &error); + if (!priv->authority) { + nm_log_warn (LOGD_SETTINGS, "failed to create PolicyKit authority: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } + + dbus_path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, dbus_counter++); + nm_connection_set_path (NM_CONNECTION (self), dbus_path); + g_free (dbus_path); + priv->visible = FALSE; + + priv->session_monitor = nm_session_monitor_get (); + priv->session_changed_id = g_signal_connect (priv->session_monitor, + NM_SESSION_MONITOR_CHANGED, + G_CALLBACK (session_changed_cb), + self); + + priv->agent_mgr = nm_agent_manager_get (); +} + +static void +dispose (GObject *object) +{ + NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + GSList *iter; + + if (priv->disposed) + goto out; + priv->disposed = TRUE; + + if (priv->secrets) + g_object_unref (priv->secrets); + + /* Cancel PolicyKit requests */ + for (iter = priv->pending_auths; iter; iter = g_slist_next (iter)) + nm_auth_chain_unref ((NMAuthChain *) iter->data); + g_slist_free (priv->pending_auths); + priv->pending_auths = NULL; + + /* Cancel in-progress secrets requests */ + for (iter = priv->reqs; iter; iter = g_slist_next (iter)) + nm_agent_manager_cancel_secrets (priv->agent_mgr, GPOINTER_TO_UINT (iter->data)); + g_slist_free (priv->reqs); + + set_visible (self, FALSE); + + g_object_unref (priv->session_monitor); + g_object_unref (priv->agent_mgr); + g_object_unref (priv->dbus_mgr); + g_object_unref (priv->authority); + +out: + G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_VISIBLE: + g_value_set_boolean (value, NM_SETTINGS_CONNECTION_GET_PRIVATE (object)->visible); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +} + +static void +nm_settings_connection_class_init (NMSettingsConnectionClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + g_type_class_add_private (class, sizeof (NMSettingsConnectionPrivate)); + + /* Virtual methods */ + object_class->dispose = dispose; + object_class->get_property = get_property; + object_class->set_property = set_property; + + class->commit_changes = commit_changes; + class->delete = do_delete; + class->supports_secrets = supports_secrets; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_VISIBLE, + g_param_spec_boolean (NM_SETTINGS_CONNECTION_VISIBLE, + "Visible", + "Visible", + FALSE, + G_PARAM_READABLE)); + + /* Signals */ + signals[UPDATED] = + g_signal_new (NM_SETTINGS_CONNECTION_UPDATED, + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[REMOVED] = + g_signal_new (NM_SETTINGS_CONNECTION_REMOVED, + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /* Not exported */ + signals[UNREGISTER] = + g_signal_new ("unregister", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class), + &dbus_glib_nm_settings_connection_object_info); +} diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h new file mode 100644 index 0000000000..190923c9fb --- /dev/null +++ b/src/settings/nm-settings-connection.h @@ -0,0 +1,121 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2008 Novell, Inc. + * (C) Copyright 2008 - 2011 Red Hat, Inc. + */ + +#ifndef NM_SETTINGS_CONNECTION_H +#define NM_SETTINGS_CONNECTION_H + +#include + +G_BEGIN_DECLS + +#define NM_TYPE_SETTINGS_CONNECTION (nm_settings_connection_get_type ()) +#define NM_SETTINGS_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnection)) +#define NM_SETTINGS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionClass)) +#define NM_IS_SETTINGS_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS_CONNECTION)) +#define NM_IS_SETTINGS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SETTINGS_CONNECTION)) +#define NM_SETTINGS_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionClass)) + +#define NM_SETTINGS_CONNECTION_UPDATED "updated" +#define NM_SETTINGS_CONNECTION_REMOVED "removed" +#define NM_SETTINGS_CONNECTION_GET_SECRETS "get-secrets" +#define NM_SETTINGS_CONNECTION_CANCEL_SECRETS "cancel-secrets" + +#define NM_SETTINGS_CONNECTION_VISIBLE "visible" + +typedef struct _NMSettingsConnection NMSettingsConnection; + +typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass; + +typedef void (*NMSettingsConnectionCommitFunc) (NMSettingsConnection *connection, + GError *error, + gpointer user_data); + +typedef void (*NMSettingsConnectionDeleteFunc) (NMSettingsConnection *connection, + GError *error, + gpointer user_data); + +struct _NMSettingsConnection { + NMConnection parent; +}; + +struct _NMSettingsConnectionClass { + NMConnectionClass parent; + + /* virtual methods */ + void (*commit_changes) (NMSettingsConnection *connection, + NMSettingsConnectionCommitFunc callback, + gpointer user_data); + + void (*delete) (NMSettingsConnection *connection, + NMSettingsConnectionDeleteFunc callback, + gpointer user_data); + + gboolean (*supports_secrets) (NMSettingsConnection *connection, + const char *setting_name); +}; + +GType nm_settings_connection_get_type (void); + +void nm_settings_connection_commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitFunc callback, + gpointer user_data); + +gboolean nm_settings_connection_replace_settings (NMSettingsConnection *self, + NMConnection *new_settings, + GError **error); + +void nm_settings_connection_replace_and_commit (NMSettingsConnection *self, + NMConnection *new_settings, + NMSettingsConnectionCommitFunc callback, + gpointer user_data); + +void nm_settings_connection_delete (NMSettingsConnection *connection, + NMSettingsConnectionDeleteFunc callback, + gpointer user_data); + +typedef void (*NMSettingsConnectionSecretsFunc) (NMSettingsConnection *connection, + guint32 call_id, + const char *setting_name, + GError *error, + gpointer user_data); + +guint32 nm_settings_connection_get_secrets (NMSettingsConnection *connection, + gboolean filter_by_uid, + gulong uid, + const char *setting_name, + guint32 flags, + const char *hint, + NMSettingsConnectionSecretsFunc callback, + gpointer callback_data, + GError **error); + +void nm_settings_connection_cancel_secrets (NMSettingsConnection *connection, + guint32 call_id); + +gboolean nm_settings_connection_is_visible (NMSettingsConnection *self); + +void nm_settings_connection_recheck_visibility (NMSettingsConnection *self); + +void nm_settings_connection_signal_remove (NMSettingsConnection *self); + +G_END_DECLS + +#endif /* NM_SETTINGS_CONNECTION_H */ diff --git a/src/settings/nm-settings-error.c b/src/settings/nm-settings-error.c new file mode 100644 index 0000000000..7e24fb71ff --- /dev/null +++ b/src/settings/nm-settings-error.c @@ -0,0 +1,83 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * 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 (C) 2008 Novell, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. + */ + +#include "nm-settings-error.h" + +GQuark +nm_settings_error_quark (void) +{ + static GQuark ret = 0; + + if (ret == 0) + ret = g_quark_from_static_string ("nm-settings-error"); + + return ret; +} + +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +nm_settings_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + ENUM_ENTRY (NM_SETTINGS_ERROR_GENERAL, "GeneralError"), + + /* The connection was invalid. */ + ENUM_ENTRY (NM_SETTINGS_ERROR_INVALID_CONNECTION, "InvalidConnection"), + /* The connection is read-only; modifications are not allowed. */ + ENUM_ENTRY (NM_SETTINGS_ERROR_READ_ONLY_CONNECTION, "ReadOnlyConnection"), + /* A bug in the settings service caused the error. */ + ENUM_ENTRY (NM_SETTINGS_ERROR_INTERNAL_ERROR, "InternalError"), + /* Retrieval or request of secrets failed. */ + ENUM_ENTRY (NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE, "SecretsUnavailable"), + /* The request for secrets was canceled. */ + ENUM_ENTRY (NM_SETTINGS_ERROR_SECRETS_REQUEST_CANCELED, "SecretsRequestCanceled"), + /* The request could not be completed because permission was denied. */ + ENUM_ENTRY (NM_SETTINGS_ERROR_PERMISSION_DENIED, "PermissionDenied"), + /* The requested setting does not existing in this connection. */ + ENUM_ENTRY (NM_SETTINGS_ERROR_INVALID_SETTING, "InvalidSetting"), + /* The caller does not have permission to perform this operation */ + ENUM_ENTRY (NM_SETTINGS_ERROR_NOT_PRIVILEGED, "NotPrivileged"), + /* No plugin supports adding new connections */ + ENUM_ENTRY (NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED, "AddNotSupported"), + /* The plugin providing this connection does not support updating it */ + ENUM_ENTRY (NM_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED, "UpdateNotSupported"), + /* The plugin providing this connection does not support deleting it */ + ENUM_ENTRY (NM_SETTINGS_ERROR_DELETE_NOT_SUPPORTED, "DeleteNotSupported"), + /* Failed to add the connection */ + ENUM_ENTRY (NM_SETTINGS_ERROR_ADD_FAILED, "AddFailed"), + /* No plugin supports modifying the system hostname */ + ENUM_ENTRY (NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, "SaveHostnameNotSupported"), + /* Saving the system hostname failed */ + ENUM_ENTRY (NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, "SaveHostnameFailed"), + /* A connection with this UUID already exists */ + ENUM_ENTRY (NM_SETTINGS_ERROR_UUID_EXISTS, "UuidExists"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("NMSettingsError", values); + } + + return etype; +} diff --git a/src/settings/nm-settings-error.h b/src/settings/nm-settings-error.h new file mode 100644 index 0000000000..b782a7791c --- /dev/null +++ b/src/settings/nm-settings-error.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * 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 (C) 2008 Novell, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. + */ + +#ifndef NM_SETTINGS_ERROR_H +#define NM_SETTINGS_ERROR_H + +#include +#include + +enum { + NM_SETTINGS_ERROR_GENERAL = 0, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + NM_SETTINGS_ERROR_READ_ONLY_CONNECTION, + NM_SETTINGS_ERROR_INTERNAL_ERROR, + NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE, + NM_SETTINGS_ERROR_SECRETS_REQUEST_CANCELED, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + NM_SETTINGS_ERROR_INVALID_SETTING, + NM_SETTINGS_ERROR_NOT_PRIVILEGED, + NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED, + NM_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED, + NM_SETTINGS_ERROR_DELETE_NOT_SUPPORTED, + NM_SETTINGS_ERROR_ADD_FAILED, + NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, + NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, + NM_SETTINGS_ERROR_UUID_EXISTS, +}; + +#define NM_SETTINGS_ERROR (nm_settings_error_quark ()) +GQuark nm_settings_error_quark (void); + +#define NM_TYPE_SETTINGS_ERROR (nm_settings_error_get_type ()) +GType nm_settings_error_get_type (void); + +#endif /* NM_SETTINGS_ERROR_H */ diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c new file mode 100644 index 0000000000..169936c392 --- /dev/null +++ b/src/settings/nm-settings.c @@ -0,0 +1,1660 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * Søren Sandmann + * Dan Williams + * Tambet Ingo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2007 - 2010 Red Hat, Inc. + * (C) Copyright 2008 Novell, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../nm-device-ethernet.h" +#include "nm-dbus-glib-types.h" +#include "nm-settings.h" +#include "nm-settings-connection.h" +#include "nm-polkit-helpers.h" +#include "nm-settings-error.h" +#include "nm-default-wired-connection.h" +#include "nm-logging.h" +#include "nm-dbus-manager.h" +#include "nm-manager-auth.h" +#include "nm-session-monitor.h" +#include "system-settings/plugins/keyfile/plugin.h" +#include "nm-agent-manager.h" + +#define CONFIG_KEY_NO_AUTO_DEFAULT "no-auto-default" + +/* LINKER CRACKROCK */ +#define EXPORT(sym) void * __export_##sym = &sym; + +#include "nm-inotify-helper.h" +EXPORT(nm_inotify_helper_get_type) +EXPORT(nm_inotify_helper_get) +EXPORT(nm_inotify_helper_add_watch) +EXPORT(nm_inotify_helper_remove_watch) + +EXPORT(nm_settings_connection_get_type) +EXPORT(nm_settings_connection_replace_settings) +EXPORT(nm_settings_connection_replace_and_commit) +/* END LINKER CRACKROCK */ + +static void claim_connection (NMSettings *self, + NMSettingsConnection *connection, + gboolean do_export); + +static gboolean impl_settings_list_connections (NMSettings *self, + GPtrArray **connections, + GError **error); + +static void impl_settings_add_connection (NMSettings *self, + GHashTable *settings, + DBusGMethodInvocation *context); + +static void impl_settings_save_hostname (NMSettings *self, + const char *hostname, + DBusGMethodInvocation *context); + +#include "nm-settings-glue.h" + +static void unmanaged_specs_changed (NMSystemConfigInterface *config, gpointer user_data); + +typedef struct { + NMDBusManager *dbus_mgr; + DBusGConnection *bus; + + NMAgentManager *agent_mgr; + + PolkitAuthority *authority; + guint auth_changed_id; + char *config_file; + + NMSessionMonitor *session_monitor; + GSList *auths; + + GSList *plugins; + gboolean connections_loaded; + GHashTable *connections; + GSList *unmanaged_specs; +} NMSettingsPrivate; + +G_DEFINE_TYPE (NMSettings, nm_settings, G_TYPE_OBJECT) + +#define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate)) + +enum { + PROPERTIES_CHANGED, + CONNECTION_ADDED, + CONNECTION_UPDATED, + CONNECTION_REMOVED, + CONNECTION_VISIBILITY_CHANGED, + CONNECTIONS_LOADED, + + NEW_CONNECTION, /* exported, not used internally */ + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +enum { + PROP_0, + PROP_UNMANAGED_SPECS, + PROP_HOSTNAME, + PROP_CAN_MODIFY, + + LAST_PROP +}; + +static void +load_connections (NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + if (priv->connections_loaded) + return; + + for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { + NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + GSList *plugin_connections; + GSList *elt; + + plugin_connections = nm_system_config_interface_get_connections (plugin); + + // FIXME: ensure connections from plugins loaded with a lower priority + // get rejected when they conflict with connections from a higher + // priority plugin. + + for (elt = plugin_connections; elt; elt = g_slist_next (elt)) + claim_connection (self, NM_SETTINGS_CONNECTION (elt->data), TRUE); + + g_slist_free (plugin_connections); + } + + priv->connections_loaded = TRUE; + + /* FIXME: Bad hack */ + unmanaged_specs_changed (NULL, self); + + g_signal_emit (self, signals[CONNECTIONS_LOADED], 0); +} + +void +nm_settings_for_each_connection (NMSettings *self, + NMSettingsForEachFunc for_each_func, + gpointer user_data) +{ + NMSettingsPrivate *priv; + GHashTableIter iter; + gpointer data; + + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_SETTINGS (self)); + g_return_if_fail (for_each_func != NULL); + + priv = NM_SETTINGS_GET_PRIVATE (self); + + load_connections (self); + + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, &data)) + for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data); +} + +static gboolean +impl_settings_list_connections (NMSettings *self, + GPtrArray **connections, + GError **error) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GHashTableIter iter; + gpointer key; + + load_connections (self); + + *connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, &key, NULL)) + g_ptr_array_add (*connections, g_strdup ((const char *) key)); + return TRUE; +} + +static int +connection_sort (gconstpointer pa, gconstpointer pb) +{ + NMConnection *a = NM_CONNECTION (pa); + NMSettingConnection *con_a; + NMConnection *b = NM_CONNECTION (pb); + NMSettingConnection *con_b; + + con_a = (NMSettingConnection *) nm_connection_get_setting (a, NM_TYPE_SETTING_CONNECTION); + g_assert (con_a); + con_b = (NMSettingConnection *) nm_connection_get_setting (b, NM_TYPE_SETTING_CONNECTION); + g_assert (con_b); + + if (nm_setting_connection_get_autoconnect (con_a) != nm_setting_connection_get_autoconnect (con_b)) { + if (nm_setting_connection_get_autoconnect (con_a)) + return -1; + return 1; + } + + if (nm_setting_connection_get_timestamp (con_a) > nm_setting_connection_get_timestamp (con_b)) + return -1; + else if (nm_setting_connection_get_timestamp (con_a) == nm_setting_connection_get_timestamp (con_b)) + return 0; + return 1; +} + +/* Returns a list of NMSettingsConnections. Caller must free the list with + * g_slist_free(). + */ +GSList * +nm_settings_get_connections (NMSettings *self) +{ + GHashTableIter iter; + gpointer data = NULL; + GSList *list = NULL; + + g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); + + g_hash_table_iter_init (&iter, NM_SETTINGS_GET_PRIVATE (self)->connections); + while (g_hash_table_iter_next (&iter, NULL, &data)) + list = g_slist_insert_sorted (list, data, connection_sort); + return list; +} + +NMSettingsConnection * +nm_settings_get_connection_by_path (NMSettings *self, const char *path) +{ + NMSettingsPrivate *priv; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); + g_return_val_if_fail (path != NULL, NULL); + + priv = NM_SETTINGS_GET_PRIVATE (self); + + load_connections (self); + + return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path); +} + +static void +clear_unmanaged_specs (NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + + g_slist_foreach (priv->unmanaged_specs, (GFunc) g_free, NULL); + g_slist_free (priv->unmanaged_specs); + priv->unmanaged_specs = NULL; +} + +static char* +uscore_to_wincaps (const char *uscore) +{ + const char *p; + GString *str; + gboolean last_was_uscore; + + last_was_uscore = TRUE; + + str = g_string_new (NULL); + p = uscore; + while (p && *p) { + if (*p == '-' || *p == '_') + last_was_uscore = TRUE; + else { + if (last_was_uscore) { + g_string_append_c (str, g_ascii_toupper (*p)); + last_was_uscore = FALSE; + } else + g_string_append_c (str, *p); + } + ++p; + } + + return g_string_free (str, FALSE); +} + +static void +notify (GObject *object, GParamSpec *pspec) +{ + GValue *value; + GHashTable *hash; + + value = g_slice_new0 (GValue); + hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); + + g_value_init (value, pspec->value_type); + g_object_get_property (object, pspec->name, value); + g_hash_table_insert (hash, uscore_to_wincaps (pspec->name), value); + g_signal_emit (object, signals[PROPERTIES_CHANGED], 0, hash); + g_hash_table_destroy (hash); + g_value_unset (value); + g_slice_free (GValue, value); +} + +const GSList * +nm_settings_get_unmanaged_specs (NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + + load_connections (self); + return priv->unmanaged_specs; +} + +static NMSystemConfigInterface * +get_plugin (NMSettings *self, guint32 capability) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + g_return_val_if_fail (self != NULL, NULL); + + /* Do any of the plugins support setting the hostname? */ + for (iter = priv->plugins; iter; iter = iter->next) { + NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; + + g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); + if (caps & capability) + return NM_SYSTEM_CONFIG_INTERFACE (iter->data); + } + + return NULL; +} + +/* Returns an allocated string which the caller owns and must eventually free */ +char * +nm_settings_get_hostname (NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSList *iter; + char *hostname = NULL; + + /* Hostname returned is the hostname returned from the first plugin + * that provides one. + */ + for (iter = priv->plugins; iter; iter = iter->next) { + NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; + + g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); + if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { + g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, &hostname, NULL); + if (hostname && strlen (hostname)) + return hostname; + g_free (hostname); + } + } + + return NULL; +} + +static void +plugin_connection_added (NMSystemConfigInterface *config, + NMSettingsConnection *connection, + gpointer user_data) +{ + claim_connection (NM_SETTINGS (user_data), connection, TRUE); +} + +static gboolean +find_unmanaged_device (NMSettings *self, const char *needle) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + for (iter = priv->unmanaged_specs; iter; iter = g_slist_next (iter)) { + if (!strcmp ((const char *) iter->data, needle)) + return TRUE; + } + return FALSE; +} + +static void +unmanaged_specs_changed (NMSystemConfigInterface *config, + gpointer user_data) +{ + NMSettings *self = NM_SETTINGS (user_data); + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + clear_unmanaged_specs (self); + + /* Ask all the plugins for their unmanaged specs */ + for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { + GSList *specs, *specs_iter; + + specs = nm_system_config_interface_get_unmanaged_specs (NM_SYSTEM_CONFIG_INTERFACE (iter->data)); + for (specs_iter = specs; specs_iter; specs_iter = specs_iter->next) { + if (!find_unmanaged_device (self, (const char *) specs_iter->data)) { + priv->unmanaged_specs = g_slist_prepend (priv->unmanaged_specs, specs_iter->data); + } else + g_free (specs_iter->data); + } + + g_slist_free (specs); + } + + g_object_notify (G_OBJECT (self), NM_SETTINGS_UNMANAGED_SPECS); +} + +static void +hostname_changed (NMSystemConfigInterface *config, + GParamSpec *pspec, + gpointer user_data) +{ + g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME); +} + +static void +add_plugin (NMSettings *self, NMSystemConfigInterface *plugin) +{ + NMSettingsPrivate *priv; + char *pname = NULL; + char *pinfo = NULL; + + g_return_if_fail (NM_IS_SETTINGS (self)); + g_return_if_fail (NM_IS_SYSTEM_CONFIG_INTERFACE (plugin)); + + priv = NM_SETTINGS_GET_PRIVATE (self); + + priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin)); + + g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, + G_CALLBACK (plugin_connection_added), self); + g_signal_connect (plugin, "notify::hostname", G_CALLBACK (hostname_changed), self); + + nm_system_config_interface_init (plugin, NULL); + + g_object_get (G_OBJECT (plugin), + NM_SYSTEM_CONFIG_INTERFACE_NAME, &pname, + NM_SYSTEM_CONFIG_INTERFACE_INFO, &pinfo, + NULL); + + g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED, + G_CALLBACK (unmanaged_specs_changed), self); + + nm_log_info (LOGD_SETTINGS, "Loaded plugin %s: %s", pname, pinfo); + g_free (pname); + g_free (pinfo); +} + +static GObject * +find_plugin (GSList *list, const char *pname) +{ + GSList *iter; + GObject *obj = NULL; + + g_return_val_if_fail (pname != NULL, FALSE); + + for (iter = list; iter && !obj; iter = g_slist_next (iter)) { + NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + char *list_pname = NULL; + + g_object_get (G_OBJECT (plugin), + NM_SYSTEM_CONFIG_INTERFACE_NAME, + &list_pname, + NULL); + if (list_pname && !strcmp (pname, list_pname)) + obj = G_OBJECT (plugin); + + g_free (list_pname); + } + + return obj; +} + +static gboolean +load_plugins (NMSettings *self, const char *plugins, GError **error) +{ + GSList *list = NULL; + char **plist; + char **iter; + gboolean success = TRUE; + + plist = g_strsplit (plugins, ",", 0); + if (!plist) + return FALSE; + + for (iter = plist; *iter; iter++) { + GModule *plugin; + char *full_name, *path; + const char *pname = g_strstrip (*iter); + GObject *obj; + GObject * (*factory_func) (void); + + /* keyfile plugin built in now */ + if (!strcmp (pname, "keyfile")) + continue; + + /* ifcfg-fedora was renamed ifcfg-rh; handle old configs here */ + if (!strcmp (pname, "ifcfg-fedora")) + pname = "ifcfg-rh"; + + obj = find_plugin (list, pname); + if (obj) + continue; + + full_name = g_strdup_printf ("nm-settings-plugin-%s", pname); + path = g_module_build_path (PLUGINDIR, full_name); + + plugin = g_module_open (path, G_MODULE_BIND_LOCAL); + if (!plugin) { + g_set_error (error, 0, 0, + "Could not load plugin '%s': %s", + pname, g_module_error ()); + g_free (full_name); + g_free (path); + success = FALSE; + break; + } + + g_free (full_name); + g_free (path); + + if (!g_module_symbol (plugin, "nm_system_config_factory", (gpointer) (&factory_func))) { + g_set_error (error, 0, 0, + "Could not find plugin '%s' factory function.", + pname); + success = FALSE; + break; + } + + obj = (*factory_func) (); + if (!obj || !NM_IS_SYSTEM_CONFIG_INTERFACE (obj)) { + g_set_error (error, 0, 0, + "Plugin '%s' returned invalid system config object.", + pname); + success = FALSE; + break; + } + + g_module_make_resident (plugin); + g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin); + add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (obj)); + list = g_slist_append (list, obj); + } + + g_strfreev (plist); + + g_slist_foreach (list, (GFunc) g_object_unref, NULL); + g_slist_free (list); + + return success; +} + +#define REMOVED_ID_TAG "removed-id-tag" +#define UPDATED_ID_TAG "updated-id-tag" +#define VISIBLE_ID_TAG "visible-id-tag" +#define UNREG_ID_TAG "unreg-id-tag" + +static void +connection_removed (NMSettingsConnection *obj, gpointer user_data) +{ + GObject *connection = G_OBJECT (obj); + guint id; + + g_object_ref (connection); + + /* Disconnect signal handlers, as plugins might still keep references + * to the connection (and thus the signal handlers would still be live) + * even after NMSettings has dropped all its references. + */ + + id = GPOINTER_TO_UINT (g_object_get_data (connection, REMOVED_ID_TAG)); + if (id) + g_signal_handler_disconnect (connection, id); + + id = GPOINTER_TO_UINT (g_object_get_data (connection, UPDATED_ID_TAG)); + if (id) + g_signal_handler_disconnect (connection, id); + + id = GPOINTER_TO_UINT (g_object_get_data (connection, VISIBLE_ID_TAG)); + if (id) + g_signal_handler_disconnect (connection, id); + + /* Forget about the connection internall */ + g_hash_table_remove (NM_SETTINGS_GET_PRIVATE (user_data)->connections, + (gpointer) nm_connection_get_path (NM_CONNECTION (connection))); + + /* Re-emit for listeners like NMPolicy */ + g_signal_emit (NM_SETTINGS (user_data), signals[CONNECTION_REMOVED], 0, connection); + + g_object_unref (connection); +} + +static void +connection_unregister (NMSettingsConnection *obj, gpointer user_data) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (user_data); + GObject *connection = G_OBJECT (obj); + guint id; + + /* Make sure it's unregistered from the bus now that's removed */ + dbus_g_connection_unregister_g_object (priv->bus, connection); + + id = GPOINTER_TO_UINT (g_object_get_data (connection, UNREG_ID_TAG)); + if (id) + g_signal_handler_disconnect (connection, id); +} + +static void +connection_updated (NMSettingsConnection *connection, gpointer user_data) +{ + /* Re-emit for listeners like NMPolicy */ + g_signal_emit (NM_SETTINGS (user_data), + signals[CONNECTION_UPDATED], + 0, + connection); +} + +static void +connection_visibility_changed (NMSettingsConnection *connection, + GParamSpec *pspec, + gpointer user_data) +{ + /* Re-emit for listeners like NMPolicy */ + g_signal_emit (NM_SETTINGS (user_data), + signals[CONNECTION_VISIBILITY_CHANGED], + 0, + connection); +} + +static void +claim_connection (NMSettings *self, + NMSettingsConnection *connection, + gboolean do_export) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + static guint32 ec_counter = 0; + GError *error = NULL; + GHashTableIter iter; + gpointer data; + char *path; + guint id; + + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); + g_return_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); + + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, &data)) { + /* prevent duplicates */ + if (data == connection) + return; + } + + if (!nm_connection_verify (NM_CONNECTION (connection), &error)) { + nm_log_warn (LOGD_SETTINGS, "plugin provided invalid connection: '%s' / '%s' invalid: %d", + g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)), + error->message, error->code); + g_error_free (error); + return; + } + + /* Ensure it's initial visibility is up-to-date */ + nm_settings_connection_recheck_visibility (connection); + + id = g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, + G_CALLBACK (connection_removed), + self); + g_object_set_data (G_OBJECT (connection), REMOVED_ID_TAG, GUINT_TO_POINTER (id)); + + id = g_signal_connect (connection, "unregister", + G_CALLBACK (connection_unregister), + self); + g_object_set_data (G_OBJECT (connection), UNREG_ID_TAG, GUINT_TO_POINTER (id)); + + id = g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED, + G_CALLBACK (connection_updated), + self); + g_object_set_data (G_OBJECT (connection), UPDATED_ID_TAG, GUINT_TO_POINTER (id)); + + id = g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_VISIBLE, + G_CALLBACK (connection_visibility_changed), + self); + g_object_set_data (G_OBJECT (connection), VISIBLE_ID_TAG, GUINT_TO_POINTER (id)); + + /* Export the connection over D-Bus */ + g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); + path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, ec_counter++); + nm_connection_set_path (NM_CONNECTION (connection), path); + dbus_g_connection_register_g_object (priv->bus, path, G_OBJECT (connection)); + g_free (path); + + g_hash_table_insert (priv->connections, + (gpointer) nm_connection_get_path (NM_CONNECTION (connection)), + g_object_ref (connection)); + + /* Only emit the individual connection-added signal after connections + * have been initially loaded. While getting the first list of connections + * we suppress it, then send the connections-loaded signal after we're all + * done to minimize processing. + */ + if (priv->connections_loaded) { + /* Internal added signal */ + g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection); + + /* Exported D-Bus signal */ + g_signal_emit (self, signals[NEW_CONNECTION], 0, connection); + } +} + +// TODO it seems that this is only ever used to remove a +// NMDefaultWiredConnection, and it probably needs to stay that way. So this +// *needs* a better name! +static void +remove_default_wired_connection (NMSettings *self, + NMSettingsConnection *connection, + gboolean do_signal) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + const char *path = nm_connection_get_path (NM_CONNECTION (connection)); + + if (g_hash_table_lookup (priv->connections, path)) { + g_signal_emit_by_name (G_OBJECT (connection), NM_SETTINGS_SIGNAL_CONNECTION_REMOVED); + g_hash_table_remove (priv->connections, path); + } +} + +static NMSettingsConnection * +add_new_connection (NMSettings *self, + NMConnection *connection, + GError **error) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSList *iter; + NMSettingsConnection *added = NULL; + GHashTableIter citer; + NMConnection *candidate = NULL; + + /* Make sure a connection with this UUID doesn't already exist */ + g_hash_table_iter_init (&citer, priv->connections); + while (g_hash_table_iter_next (&citer, NULL, (gpointer *) &candidate)) { + if (g_strcmp0 (nm_connection_get_uuid (connection), + nm_connection_get_uuid (candidate)) == 0) { + g_set_error_literal (error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_UUID_EXISTS, + "A connection with this UUID already exists."); + return NULL; + } + } + + /* 1) plugin writes the NMConnection to disk + * 2) plugin creates a new NMSettingsConnection subclass with the settings + * from the NMConnection and returns it to the settings service + * 3) settings service exports the new NMSettingsConnection subclass + * 4) plugin notices that something on the filesystem has changed + * 5) plugin reads the changes and ignores them because they will + * contain the same data as the connection it already knows about + */ + for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { + NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + GError *add_error = NULL; + + g_clear_error (error); + added = nm_system_config_interface_add_connection (plugin, connection, &add_error); + if (added) { + claim_connection (self, added, TRUE); + return added; + } + g_propagate_error (error, add_error); + } + return NULL; +} + +static void +pk_add_cb (NMAuthChain *chain, + GError *chain_error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + NMSettings *self = NM_SETTINGS (user_data); + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMAuthCallResult result; + GError *error = NULL, *add_error = NULL; + NMConnection *connection; + NMSettingsConnection *added = NULL; + NMSettingsAddCallback callback; + gpointer callback_data; + const char *perm; + + priv->auths = g_slist_remove (priv->auths, chain); + + if (chain_error) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_GENERAL, + "Error checking authorization: %s", + chain_error->message ? chain_error->message : "(unknown)"); + goto done; + } + + perm = nm_auth_chain_get_data (chain, "perm"); + g_assert (perm); + result = nm_auth_chain_get_result (chain, perm); + + /* Caller didn't successfully authenticate */ + if (result != NM_AUTH_CALL_RESULT_YES) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_NOT_PRIVILEGED, + "Insufficient privileges."); + goto done; + } + + connection = nm_auth_chain_get_data (chain, "connection"); + g_assert (connection); + added = add_new_connection (self, connection, &add_error); + if (!added) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_ADD_FAILED, + "Saving connection failed: (%d) %s", + add_error ? add_error->code : -1, + (add_error && add_error->message) ? add_error->message : "(unknown)"); + g_error_free (add_error); + } + +done: + callback = nm_auth_chain_get_data (chain, "callback"); + callback_data = nm_auth_chain_get_data (chain, "callback-data"); + + callback (self, added, error, context, callback_data); + + g_clear_error (&error); + nm_auth_chain_unref (chain); +} + +static void +add_cb (NMSettings *self, + NMSettingsConnection *connection, + GError *error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection))); +} + +void +nm_settings_add_connection (NMSettings *self, + NMConnection *connection, + DBusGMethodInvocation *context, + NMSettingsAddCallback callback, + gpointer user_data) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMSettingConnection *s_con; + NMAuthChain *chain; + GError *error = NULL, *tmp_error = NULL; + gulong caller_uid = G_MAXULONG; + char *error_desc = NULL; + const char *perm; + + /* Connection must be valid, of course */ + if (!nm_connection_verify (connection, &tmp_error)) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "The connection was invalid: %s", + tmp_error ? tmp_error->message : "(unknown)"); + g_error_free (tmp_error); + callback (self, NULL, error, context, user_data); + g_error_free (error); + return; + } + + /* Do any of the plugins support adding? */ + if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED, + "None of the registered plugins support add."); + callback (self, NULL, error, context, user_data); + g_error_free (error); + return; + } + + /* Get the caller's UID */ + if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, &caller_uid, &error_desc)) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_NOT_PRIVILEGED, + "Unable to determine UID of request: %s.", + error_desc ? error_desc : "(unknown)"); + g_free (error_desc); + callback (self, NULL, error, context, user_data); + g_error_free (error); + return; + } + + /* Ensure the caller's username exists in the connection's permissions, + * or that the permissions is empty (ie, visible by everyone). + */ + if (0 != caller_uid) { + if (!nm_auth_uid_in_acl (connection, priv->session_monitor, caller_uid, &error_desc)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_NOT_PRIVILEGED, + error_desc); + g_free (error_desc); + callback (self, NULL, error, context, user_data); + g_error_free (error); + return; + } + + /* Caller is allowed to add this connection */ + } + + /* If the caller is the only user in the connection's permissions, then + * we use the 'modify.own' permission instead of 'modify.system'. If the + * request affects more than just the caller, require 'modify.system'. + */ + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (nm_setting_connection_get_num_permissions (s_con) == 1) + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; + else + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; + + /* Otherwise validate the user request */ + chain = nm_auth_chain_new (priv->authority, context, NULL, pk_add_cb, self); + g_assert (chain); + priv->auths = g_slist_append (priv->auths, chain); + nm_auth_chain_add_call (chain, perm, TRUE); + nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL); + nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref); + nm_auth_chain_set_data (chain, "callback", callback, NULL); + nm_auth_chain_set_data (chain, "callback-data", user_data, NULL); +} + +static void +impl_settings_add_connection (NMSettings *self, + GHashTable *settings, + DBusGMethodInvocation *context) +{ + NMConnection *connection; + GError *error = NULL; + + connection = nm_connection_new_from_hash (settings, &error); + if (connection) { + nm_settings_add_connection (self, connection, context, add_cb, NULL); + g_object_unref (connection); + } else { + g_assert (error); + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +static void +pk_hostname_cb (NMAuthChain *chain, + GError *chain_error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + NMSettings *self = NM_SETTINGS (user_data); + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMAuthCallResult result; + gboolean success = FALSE; + GError *error = NULL; + GSList *iter; + const char *hostname; + + priv->auths = g_slist_remove (priv->auths, chain); + + /* If our NMSettingsConnection is already gone, do nothing */ + if (chain_error) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_GENERAL, + "Error checking authorization: %s", + chain_error->message ? chain_error->message : "(unknown)"); + goto done; + } + + result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME); + + /* Caller didn't successfully authenticate */ + if (result != NM_AUTH_CALL_RESULT_YES) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_NOT_PRIVILEGED, + "Insufficient privileges."); + goto done; + } + + /* Set the hostname in all plugins */ + hostname = nm_auth_chain_get_data (chain, "hostname"); + for (iter = priv->plugins; iter; iter = iter->next) { + NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; + + g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); + if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { + g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, hostname, NULL); + success = TRUE; + } + } + + if (!success) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, + "Saving the hostname failed."); + } + +done: + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); + + g_clear_error (&error); + nm_auth_chain_unref (chain); +} + +static void +impl_settings_save_hostname (NMSettings *self, + const char *hostname, + DBusGMethodInvocation *context) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMAuthChain *chain; + GError *error = NULL; + + /* Do any of the plugins support setting the hostname? */ + if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, + "None of the registered plugins support setting the hostname."); + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } + + /* Otherwise validate the user request */ + chain = nm_auth_chain_new (priv->authority, context, NULL, pk_hostname_cb, self); + g_assert (chain); + priv->auths = g_slist_append (priv->auths, chain); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE); + nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free); +} + +static gboolean +have_connection_for_device (NMSettings *self, GByteArray *mac) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GHashTableIter iter; + gpointer data; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + const GByteArray *setting_mac; + gboolean ret = FALSE; + + g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); + g_return_val_if_fail (mac != NULL, FALSE); + + /* Find a wired connection locked to the given MAC address, if any */ + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, &data)) { + NMConnection *connection = NM_CONNECTION (data); + const char *connection_type; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + connection_type = nm_setting_connection_get_connection_type (s_con); + + if ( strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME) + && strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) + continue; + + s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); + + /* No wired setting; therefore the PPPoE connection applies to any device */ + if (!s_wired && !strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) { + ret = TRUE; + break; + } + + setting_mac = nm_setting_wired_get_mac_address (s_wired); + if (setting_mac) { + /* A connection mac-locked to this device */ + if (!memcmp (setting_mac->data, mac->data, ETH_ALEN)) { + ret = TRUE; + break; + } + } else { + /* A connection that applies to any wired device */ + ret = TRUE; + break; + } + } + + return ret; +} + +/* Search through the list of blacklisted MAC addresses in the config file. */ +static gboolean +is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GKeyFile *config; + char **list, **iter; + gboolean found = FALSE; + + g_return_val_if_fail (mac != NULL, FALSE); + + if (!priv->config_file) + return FALSE; + + config = g_key_file_new (); + if (!config) { + nm_log_warn (LOGD_SETTINGS, "not enough memory to load config file."); + return FALSE; + } + + g_key_file_set_list_separator (config, ','); + if (!g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_NONE, NULL)) + goto out; + + list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, NULL, NULL); + for (iter = list; iter && *iter; iter++) { + struct ether_addr *candidate; + + if (strcmp(g_strstrip(*iter), "*") == 0) { + found = TRUE; + break; + } + + candidate = ether_aton (*iter); + if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) { + found = TRUE; + break; + } + } + + if (list) + g_strfreev (list); + +out: + g_key_file_free (config); + return found; +} + +#define DEFAULT_WIRED_TAG "default-wired" + +static void +default_wired_deleted (NMDefaultWiredConnection *wired, + const GByteArray *mac, + NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMSettingConnection *s_con; + char *tmp; + GKeyFile *config; + char **list, **iter, **updated; + gboolean found = FALSE; + gsize len = 0, i; + char *data; + + /* If there was no config file specified, there's nothing to do */ + if (!priv->config_file) + goto cleanup; + + /* When the default wired connection is removed (either deleted or saved + * to a new persistent connection by a plugin), write the MAC address of + * the wired device to the config file and don't create a new default wired + * connection for that device again. + */ + + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (wired), + NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + + /* Ignore removals of read-only connections, since they couldn't have + * been removed by the user. + */ + if (nm_setting_connection_get_read_only (s_con)) + goto cleanup; + + config = g_key_file_new (); + if (!config) + goto cleanup; + + g_key_file_set_list_separator (config, ','); + g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_KEEP_COMMENTS, NULL); + + list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, &len, NULL); + for (iter = list; iter && *iter; iter++) { + struct ether_addr *candidate; + + if (strcmp(g_strstrip(*iter), "*") == 0) { + found = TRUE; + break; + } + + candidate = ether_aton (*iter); + if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) { + found = TRUE; + break; + } + } + + /* Add this device's MAC to the list */ + if (!found) { + tmp = g_strdup_printf ("%02x:%02x:%02x:%02x:%02x:%02x", + mac->data[0], mac->data[1], mac->data[2], + mac->data[3], mac->data[4], mac->data[5]); + + /* New list; size + 1 for the new element, + 1 again for ending NULL */ + updated = g_malloc0 (sizeof (char*) * (len + 2)); + + /* Copy original list and add new MAC */ + for (i = 0; list && list[i]; i++) + updated[i] = list[i]; + updated[i++] = tmp; + updated[i] = NULL; + + g_key_file_set_string_list (config, + "main", CONFIG_KEY_NO_AUTO_DEFAULT, + (const char **) updated, + len + 2); + /* g_free() not g_strfreev() since 'updated' isn't a deep-copy */ + g_free (updated); + g_free (tmp); + + data = g_key_file_to_data (config, &len, NULL); + if (data) { + g_file_set_contents (priv->config_file, data, len, NULL); + g_free (data); + } + } + + if (list) + g_strfreev (list); + g_key_file_free (config); + +cleanup: + g_object_set_data (G_OBJECT (nm_default_wired_connection_get_device (wired)), + DEFAULT_WIRED_TAG, + NULL); +} + +static void +delete_cb (NMSettingsConnection *connection, GError *error, gpointer user_data) +{ +} + +static gboolean +default_wired_try_update (NMDefaultWiredConnection *wired, + NMSettings *self) +{ + GError *error = NULL; + NMSettingConnection *s_con; + const char *id; + NMSettingsConnection *added; + + /* Try to move this default wired conneciton to a plugin so that it has + * persistent storage. + */ + + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (wired), + NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + id = nm_setting_connection_get_id (s_con); + g_assert (id); + + remove_default_wired_connection (self, NM_SETTINGS_CONNECTION (wired), FALSE); + added = add_new_connection (self, NM_CONNECTION (wired), &error); + if (added) { + nm_settings_connection_delete (NM_SETTINGS_CONNECTION (wired), delete_cb, NULL); + + g_object_set_data (G_OBJECT (nm_default_wired_connection_get_device (wired)), + DEFAULT_WIRED_TAG, + NULL); + nm_log_info (LOGD_SETTINGS, "Saved default wired connection '%s' to persistent storage", id); + return FALSE; + } + + nm_log_warn (LOGD_SETTINGS, "couldn't save default wired connection '%s': %d / %s", + id, + error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); + g_clear_error (&error); + + /* If there was an error, don't destroy the default wired connection, + * but add it back to the system settings service. Connection is already + * exported on the bus, don't export it again, thus do_export == FALSE. + */ + claim_connection (self, NM_SETTINGS_CONNECTION (wired), FALSE); + return TRUE; +} + +void +nm_settings_device_added (NMSettings *self, NMDevice *device) +{ + GByteArray *mac = NULL; + struct ether_addr tmp; + NMDefaultWiredConnection *wired; + NMSettingConnection *s_con; + gboolean read_only = TRUE; + const char *id; + + if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET) + return; + + /* If the device isn't managed or it already has a default wired connection, + * ignore it. + */ + if ( !nm_device_get_managed (device) + || g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG)) + return; + + nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (device), &tmp); + + mac = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (mac, tmp.ether_addr_octet, ETH_ALEN); + + if ( have_connection_for_device (self, mac) + || is_mac_auto_wired_blacklisted (self, mac)) + goto ignore; + + if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) + read_only = FALSE; + + wired = nm_default_wired_connection_new (mac, device, read_only); + if (!wired) + goto ignore; + + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (wired), + NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + id = nm_setting_connection_get_id (s_con); + g_assert (id); + + nm_log_info (LOGD_SETTINGS, "Added default wired connection '%s' for %s", + id, nm_device_get_udi (device)); + + g_signal_connect (wired, "try-update", (GCallback) default_wired_try_update, self); + g_signal_connect (wired, "deleted", (GCallback) default_wired_deleted, self); + claim_connection (self, NM_SETTINGS_CONNECTION (wired), TRUE); + g_object_unref (wired); + + g_object_set_data (G_OBJECT (device), DEFAULT_WIRED_TAG, wired); + +ignore: + g_byte_array_free (mac, TRUE); +} + +void +nm_settings_device_removed (NMSettings *self, NMDevice *device) +{ + NMDefaultWiredConnection *connection; + + if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET) + return; + + connection = (NMDefaultWiredConnection *) g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG); + if (connection) + remove_default_wired_connection (self, NM_SETTINGS_CONNECTION (connection), TRUE); +} + +/***************************************************************/ + +NMSettings * +nm_settings_new (const char *config_file, + const char *plugins, + GError **error) +{ + NMSettings *self; + NMSettingsPrivate *priv; + GObject *keyfile_plugin; + + self = g_object_new (NM_TYPE_SETTINGS, NULL); + if (!self) + return NULL; + + priv = NM_SETTINGS_GET_PRIVATE (self); + + priv->config_file = g_strdup (config_file); + priv->dbus_mgr = nm_dbus_manager_get (); + priv->bus = nm_dbus_manager_get_connection (priv->dbus_mgr); + + if (plugins) { + /* Load the plugins; fail if a plugin is not found. */ + if (!load_plugins (self, plugins, error)) { + g_object_unref (self); + return NULL; + } + } + + /* Add the keyfile plugin last */ + keyfile_plugin = nm_settings_keyfile_plugin_new (); + g_assert (keyfile_plugin); + add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (keyfile_plugin)); + + unmanaged_specs_changed (NULL, self); + + dbus_g_connection_register_g_object (priv->bus, NM_DBUS_PATH_SETTINGS, G_OBJECT (self)); + return self; +} + +static void +nm_settings_init (NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GError *error = NULL; + + priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + priv->authority = polkit_authority_get_sync (NULL, &error); + if (!priv->authority) { + nm_log_warn (LOGD_SETTINGS, "failed to create PolicyKit authority: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } + + priv->session_monitor = nm_session_monitor_get (); + + /* Hold a reference to the agent manager so it stays alive; the only + * other holders are NMSettingsConnection objects which are often + * transient, and we don't want the agent manager to get destroyed and + * recreated often. + */ + priv->agent_mgr = nm_agent_manager_get (); +} + +static void +dispose (GObject *object) +{ + NMSettings *self = NM_SETTINGS (object); + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + if (priv->auth_changed_id) { + g_signal_handler_disconnect (priv->authority, priv->auth_changed_id); + priv->auth_changed_id = 0; + } + + for (iter = priv->auths; iter; iter = g_slist_next (iter)) + nm_auth_chain_unref ((NMAuthChain *) iter->data); + g_slist_free (priv->auths); + + g_object_unref (priv->dbus_mgr); + + g_object_unref (priv->session_monitor); + g_object_unref (priv->agent_mgr); + + G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMSettings *self = NM_SETTINGS (object); + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + + g_hash_table_destroy (priv->connections); + + clear_unmanaged_specs (self); + + g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL); + g_slist_free (priv->plugins); + + g_free (priv->config_file); + + G_OBJECT_CLASS (nm_settings_parent_class)->finalize (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettings *self = NM_SETTINGS (object); + const GSList *specs, *iter; + GSList *copy = NULL; + + switch (prop_id) { + case PROP_UNMANAGED_SPECS: + specs = nm_settings_get_unmanaged_specs (self); + for (iter = specs; iter; iter = g_slist_next (iter)) + copy = g_slist_append (copy, g_strdup (iter->data)); + g_value_take_boxed (value, copy); + break; + case PROP_HOSTNAME: + g_value_take_string (value, nm_settings_get_hostname (self)); + + /* Don't ever pass NULL through D-Bus */ + if (!g_value_get_string (value)) + g_value_set_static_string (value, ""); + break; + case PROP_CAN_MODIFY: + g_value_set_boolean (value, !!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_settings_class_init (NMSettingsClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + g_type_class_add_private (class, sizeof (NMSettingsPrivate)); + + /* virtual methods */ + object_class->notify = notify; + object_class->get_property = get_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + /* properties */ + + g_object_class_install_property + (object_class, PROP_UNMANAGED_SPECS, + g_param_spec_boxed (NM_SETTINGS_UNMANAGED_SPECS, + "Unamanged device specs", + "Unmanaged device specs", + DBUS_TYPE_G_LIST_OF_STRING, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_HOSTNAME, + g_param_spec_string (NM_SETTINGS_HOSTNAME, + "Hostname", + "Persistent hostname", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_CAN_MODIFY, + g_param_spec_boolean (NM_SETTINGS_CAN_MODIFY, + "CanModify", + "Can modify anything (hostname, connections, etc)", + FALSE, + G_PARAM_READABLE)); + + /* signals */ + signals[PROPERTIES_CHANGED] = + g_signal_new ("properties-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsClass, properties_changed), + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT); + signals[CONNECTION_ADDED] = + g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_ADDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsClass, connection_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[CONNECTION_UPDATED] = + g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsClass, connection_updated), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[CONNECTION_REMOVED] = + g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsClass, connection_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[CONNECTION_VISIBILITY_CHANGED] = + g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsClass, connection_visibility_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[CONNECTIONS_LOADED] = + g_signal_new (NM_SETTINGS_SIGNAL_CONNECTIONS_LOADED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsClass, connections_loaded), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[NEW_CONNECTION] = + g_signal_new ("new-connection", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + dbus_g_error_domain_register (NM_SETTINGS_ERROR, + NM_DBUS_IFACE_SETTINGS, + NM_TYPE_SETTINGS_ERROR); + + /* And register all the settings errors with D-Bus */ + dbus_g_error_domain_register (NM_CONNECTION_ERROR, NULL, NM_TYPE_CONNECTION_ERROR); + dbus_g_error_domain_register (NM_SETTING_802_1X_ERROR, NULL, NM_TYPE_SETTING_802_1X_ERROR); + dbus_g_error_domain_register (NM_SETTING_BLUETOOTH_ERROR, NULL, NM_TYPE_SETTING_BLUETOOTH_ERROR); + dbus_g_error_domain_register (NM_SETTING_CDMA_ERROR, NULL, NM_TYPE_SETTING_CDMA_ERROR); + dbus_g_error_domain_register (NM_SETTING_CONNECTION_ERROR, NULL, NM_TYPE_SETTING_CONNECTION_ERROR); + dbus_g_error_domain_register (NM_SETTING_GSM_ERROR, NULL, NM_TYPE_SETTING_GSM_ERROR); + dbus_g_error_domain_register (NM_SETTING_IP4_CONFIG_ERROR, NULL, NM_TYPE_SETTING_IP4_CONFIG_ERROR); + dbus_g_error_domain_register (NM_SETTING_IP6_CONFIG_ERROR, NULL, NM_TYPE_SETTING_IP6_CONFIG_ERROR); + dbus_g_error_domain_register (NM_SETTING_OLPC_MESH_ERROR, NULL, NM_TYPE_SETTING_OLPC_MESH_ERROR); + dbus_g_error_domain_register (NM_SETTING_PPP_ERROR, NULL, NM_TYPE_SETTING_PPP_ERROR); + dbus_g_error_domain_register (NM_SETTING_PPPOE_ERROR, NULL, NM_TYPE_SETTING_PPPOE_ERROR); + dbus_g_error_domain_register (NM_SETTING_SERIAL_ERROR, NULL, NM_TYPE_SETTING_SERIAL_ERROR); + dbus_g_error_domain_register (NM_SETTING_VPN_ERROR, NULL, NM_TYPE_SETTING_VPN_ERROR); + dbus_g_error_domain_register (NM_SETTING_WIRED_ERROR, NULL, NM_TYPE_SETTING_WIRED_ERROR); + dbus_g_error_domain_register (NM_SETTING_WIRELESS_SECURITY_ERROR, NULL, NM_TYPE_SETTING_WIRELESS_SECURITY_ERROR); + dbus_g_error_domain_register (NM_SETTING_WIRELESS_ERROR, NULL, NM_TYPE_SETTING_WIRELESS_ERROR); + dbus_g_error_domain_register (NM_SETTING_ERROR, NULL, NM_TYPE_SETTING_ERROR); + + dbus_g_object_type_install_info (NM_TYPE_SETTINGS, &dbus_glib_nm_settings_object_info); + +} + diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h new file mode 100644 index 0000000000..a5cb4d7c88 --- /dev/null +++ b/src/settings/nm-settings.h @@ -0,0 +1,115 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * Søren Sandmann + * Dan Williams + * Tambet Ingo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2007 - 2010 Red Hat, Inc. + * (C) Copyright 2008 Novell, Inc. + */ + +#ifndef __NM_SETTINGS_H__ +#define __NM_SETTINGS_H__ + +#include + +#include "nm-settings-connection.h" +#include "nm-system-config-interface.h" +#include "nm-device.h" + +#define NM_TYPE_SETTINGS (nm_settings_get_type ()) +#define NM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS, NMSettings)) +#define NM_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTINGS, NMSettingsClass)) +#define NM_IS_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS)) +#define NM_IS_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTINGS)) +#define NM_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTINGS, NMSettingsClass)) + +#define NM_SETTINGS_UNMANAGED_SPECS "unmanaged-specs" +#define NM_SETTINGS_HOSTNAME "hostname" +#define NM_SETTINGS_CAN_MODIFY "can-modify" + +#define NM_SETTINGS_SIGNAL_CONNECTION_ADDED "connection-added" +#define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED "connection-updated" +#define NM_SETTINGS_SIGNAL_CONNECTION_REMOVED "connection-removed" +#define NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED "connection-visibility-changed" +#define NM_SETTINGS_SIGNAL_CONNECTIONS_LOADED "connections-loaded" + +typedef struct { + GObject parent_instance; +} NMSettings; + +typedef struct { + GObjectClass parent_class; + + /* Signals */ + void (*properties_changed) (NMSettings *self, GHashTable *properties); + + void (*connection_added) (NMSettings *self, NMSettingsConnection *connection); + + void (*connection_updated) (NMSettings *self, NMSettingsConnection *connection); + + void (*connection_removed) (NMSettings *self, NMSettingsConnection *connection); + + void (*connection_visibility_changed) (NMSettings *self, NMSettingsConnection *connection); + + void (*connections_loaded) (NMSettings *self); +} NMSettingsClass; + +GType nm_settings_get_type (void); + +NMSettings *nm_settings_new (const char *config_file, + const char *plugins, + GError **error); + +typedef void (*NMSettingsForEachFunc) (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data); + +void nm_settings_for_each_connection (NMSettings *settings, + NMSettingsForEachFunc for_each_func, + gpointer user_data); + +typedef void (*NMSettingsAddCallback) (NMSettings *settings, + NMSettingsConnection *connection, + GError *error, + DBusGMethodInvocation *context, + gpointer user_data); + +void nm_settings_add_connection (NMSettings *self, + NMConnection *connection, + DBusGMethodInvocation *context, + NMSettingsAddCallback callback, + gpointer user_data); + +/* Returns a list of NMSettingsConnections. Caller must free the list with + * g_slist_free(). + */ +GSList *nm_settings_get_connections (NMSettings *settings); + +NMSettingsConnection *nm_settings_get_connection_by_path (NMSettings *settings, + const char *path); + +const GSList *nm_settings_get_unmanaged_specs (NMSettings *self); + +char *nm_settings_get_hostname (NMSettings *self); + +void nm_settings_device_added (NMSettings *self, NMDevice *device); + +void nm_settings_device_removed (NMSettings *self, NMDevice *device); + +#endif /* __NM_SETTINGS_H__ */ diff --git a/src/system-settings/nm-system-config-interface.c b/src/settings/nm-system-config-interface.c similarity index 93% rename from src/system-settings/nm-system-config-interface.c rename to src/settings/nm-system-config-interface.c index 90fd93ba3d..0533ff33c0 100644 --- a/src/system-settings/nm-system-config-interface.c +++ b/src/settings/nm-system-config-interface.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2011 Red Hat, Inc. * Copyright (C) 2008 Novell, Inc. */ @@ -53,7 +53,8 @@ interface_init (gpointer g_iface) "Capabilities", "Plugin capabilties", NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE, - NM_SYSTEM_CONFIG_INTERFACE_CAP_LAST - 1, + ( NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS + | NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME), NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE, G_PARAM_READABLE)); @@ -73,7 +74,7 @@ interface_init (gpointer g_iface) NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, - NM_TYPE_SETTINGS_CONNECTION_INTERFACE); + NM_TYPE_SETTINGS_CONNECTION); g_signal_new (NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED, iface_type, @@ -146,18 +147,16 @@ nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config) return NULL; } -gboolean +NMSettingsConnection * nm_system_config_interface_add_connection (NMSystemConfigInterface *config, NMConnection *connection, GError **error) { - gboolean success = FALSE; - g_return_val_if_fail (config != NULL, FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection) - success = NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection, error); + return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection, error); - return success; + return NULL; } diff --git a/src/system-settings/nm-system-config-interface.h b/src/settings/nm-system-config-interface.h similarity index 77% rename from src/system-settings/nm-system-config-interface.h rename to src/settings/nm-system-config-interface.h index 3daceb89bd..96a640619e 100644 --- a/src/system-settings/nm-system-config-interface.h +++ b/src/settings/nm-system-config-interface.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2010 Red Hat, Inc. + * Copyright (C) 2007 - 2011 Red Hat, Inc. * Copyright (C) 2008 Novell, Inc. */ @@ -25,7 +25,7 @@ #include #include #include -#include +#include G_BEGIN_DECLS @@ -41,15 +41,6 @@ G_BEGIN_DECLS */ GObject * nm_system_config_factory (void); -/* NOTE: - * When passing NMConnection objects to NetworkManager, any properties - * of that NMConnection's NMSetting objects that are secrets must be set as - * GObject data items on the NMSetting object, _not_ inside the NMSetting - * object itself. This is to ensure that the secrets are only given to - * NetworkManager itself and not exposed to clients like nm-applet that need - * connection details, but not secrets. - */ - #define NM_TYPE_SYSTEM_CONFIG_INTERFACE (nm_system_config_interface_get_type ()) #define NM_SYSTEM_CONFIG_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SYSTEM_CONFIG_INTERFACE, NMSystemConfigInterface)) #define NM_IS_SYSTEM_CONFIG_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SYSTEM_CONFIG_INTERFACE)) @@ -67,9 +58,11 @@ GObject * nm_system_config_factory (void); typedef enum { NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE = 0x00000000, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS = 0x00000001, - NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME = 0x00000002, + NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME = 0x00000002 - NM_SYSTEM_CONFIG_INTERFACE_CAP_LAST = NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME + /* When adding more capabilities, be sure to update the "Capabilities" + * property max value in nm-system-config-interface.c. + */ } NMSystemConfigInterfaceCapabilities; typedef enum { @@ -90,9 +83,9 @@ struct _NMSystemConfigInterface { /* Called when the plugin is loaded to initialize it */ void (*init) (NMSystemConfigInterface *config); - /* Returns a GSList of objects that implement NMSettingsConnectionInterface - * that represent connections the plugin knows about. The returned list - * is freed by the system settings service. + /* Returns a GSList of NMSettingsConnection objects that represent + * connections the plugin knows about. The returned list is freed by the + * system settings service. */ GSList * (*get_connections) (NMSystemConfigInterface *config); @@ -117,17 +110,19 @@ struct _NMSystemConfigInterface { GSList * (*get_unmanaged_specs) (NMSystemConfigInterface *config); /* - * Add a new connection. + * Save the given connection to backing storage, and return a new + * NMSettingsConnection subclass that contains the same settings as the + * original connection. */ - gboolean (*add_connection) (NMSystemConfigInterface *config, - NMConnection *connection, - GError **error); + NMSettingsConnection * (*add_connection) (NMSystemConfigInterface *config, + NMConnection *connection, + GError **error); /* Signals */ /* Emitted when a new connection has been found by the plugin */ void (*connection_added) (NMSystemConfigInterface *config, - NMSettingsConnectionInterface *connection); + NMSettingsConnection *connection); /* Emitted when the list of unmanaged device specifications changes */ void (*unmanaged_specs_changed) (NMSystemConfigInterface *config); @@ -142,9 +137,9 @@ GSList *nm_system_config_interface_get_connections (NMSystemConfigInterface *con GSList *nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config); -gboolean nm_system_config_interface_add_connection (NMSystemConfigInterface *config, - NMConnection *connection, - GError **error); +NMSettingsConnection *nm_system_config_interface_add_connection (NMSystemConfigInterface *config, + NMConnection *connection, + GError **error); G_END_DECLS diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c index 19ee5730f9..8209da21d2 100644 --- a/src/supplicant-manager/nm-supplicant-manager.c +++ b/src/supplicant-manager/nm-supplicant-manager.c @@ -234,7 +234,7 @@ nm_supplicant_manager_init (NMSupplicantManager * self) priv->dbus_mgr = nm_dbus_manager_get (); priv->name_owner_id = g_signal_connect (priv->dbus_mgr, - "name-owner-changed", + NM_DBUS_MANAGER_NAME_OWNER_CHANGED, G_CALLBACK (name_owner_changed), self); priv->running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, WPAS_DBUS_SERVICE); diff --git a/src/system-settings/Makefile.am b/src/system-settings/Makefile.am deleted file mode 100644 index 0b92228f57..0000000000 --- a/src/system-settings/Makefile.am +++ /dev/null @@ -1,61 +0,0 @@ -INCLUDES = -I${top_srcdir} \ - -I${top_srcdir}/include \ - -I${top_srcdir}/libnm-util \ - -I${top_srcdir}/libnm-glib \ - -I${top_srcdir}/src/logging \ - -I${top_srcdir}/src \ - -I${top_builddir}/marshallers - -noinst_LTLIBRARIES = libsystem-settings.la - -BUILT_SOURCES = \ - nm-settings-system-glue.h - -libsystem_settings_la_SOURCES = \ - nm-sysconfig-settings.c \ - nm-sysconfig-settings.h \ - nm-inotify-helper.c \ - nm-inotify-helper.h \ - nm-polkit-helpers.h \ - nm-system-config-error.c \ - nm-system-config-error.h \ - nm-system-config-interface.c \ - nm-system-config-interface.h \ - nm-sysconfig-connection.c \ - nm-sysconfig-connection.h \ - nm-default-wired-connection.c \ - nm-default-wired-connection.h - -libsystem_settings_la_CPPFLAGS = \ - $(DBUS_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GMODULE_CFLAGS) \ - $(POLKIT_CFLAGS) \ - -DG_DISABLE_DEPRECATED \ - -DBINDIR=\"$(bindir)\" \ - -DSBINDIR=\"$(sbindir)\" \ - -DLIBEXECDIR=\"$(libexecdir)\" \ - -DDATADIR=\"$(datadir)\" \ - -DSYSCONFDIR=\"$(sysconfdir)\" \ - -DLOCALSTATEDIR=\"$(localstatedir)\" \ - -DGNOMELOCALEDIR=\"$(datadir)/locale\" \ - -DPLUGINDIR=\"$(pkglibdir)\" - -libsystem_settings_la_LIBADD = \ - $(top_builddir)/libnm-util/libnm-util.la \ - $(top_builddir)/libnm-glib/libnm-glib.la \ - $(top_builddir)/marshallers/libmarshallers.la \ - $(top_builddir)/src/logging/libnm-logging.la \ - $(DBUS_LIBS) \ - $(GLIB_LIBS) \ - $(GMODULE_LIBS) \ - $(POLKIT_LIBS) - -libsystem_settings_la_LDFLAGS = -rdynamic - -nm-settings-system-glue.h: $(top_srcdir)/introspection/nm-settings-system.xml - $(AM_V_GEN) dbus-binding-tool --prefix=nm_settings_system --mode=glib-server --output=$@ $< - -CLEANFILES = \ - $(BUILT_SOURCES) - diff --git a/src/system-settings/nm-sysconfig-connection.c b/src/system-settings/nm-sysconfig-connection.c deleted file mode 100644 index 73906d20a7..0000000000 --- a/src/system-settings/nm-sysconfig-connection.c +++ /dev/null @@ -1,662 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * (C) Copyright 2008 Novell, Inc. - * (C) Copyright 2008 - 2010 Red Hat, Inc. - */ - -#include -#include - -#include "nm-sysconfig-connection.h" -#include "nm-system-config-error.h" -#include "nm-dbus-glib-types.h" -#include "nm-settings-connection-interface.h" -#include "nm-settings-interface.h" -#include "nm-polkit-helpers.h" -#include "nm-logging.h" - - -static void settings_connection_interface_init (NMSettingsConnectionInterface *klass); - -G_DEFINE_TYPE_EXTENDED (NMSysconfigConnection, nm_sysconfig_connection, NM_TYPE_EXPORTED_CONNECTION, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE, - settings_connection_interface_init)) - -#define NM_SYSCONFIG_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ - NM_TYPE_SYSCONFIG_CONNECTION, \ - NMSysconfigConnectionPrivate)) - -typedef struct { - PolkitAuthority *authority; - GSList *pk_calls; - NMConnection *secrets; -} NMSysconfigConnectionPrivate; - -/**************************************************************/ - -static void -ignore_cb (NMSettingsConnectionInterface *connection, - GError *error, - gpointer user_data) -{ -} - -gboolean -nm_sysconfig_connection_update (NMSysconfigConnection *self, - NMConnection *new, - gboolean signal_update, - GError **error) -{ - NMSysconfigConnectionPrivate *priv; - GHashTable *new_settings; - gboolean success = FALSE; - - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (NM_IS_SYSCONFIG_CONNECTION (self), FALSE); - g_return_val_if_fail (new != NULL, FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (new), FALSE); - - priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - - /* Do nothing if there's nothing to update */ - if (nm_connection_compare (NM_CONNECTION (self), - NM_CONNECTION (new), - NM_SETTING_COMPARE_FLAG_EXACT)) - return TRUE; - - new_settings = nm_connection_to_hash (new); - g_assert (new_settings); - if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, error)) { - /* Copy the connection to keep its secrets around even if NM - * calls nm_connection_clear_secrets(). - */ - if (priv->secrets) - g_object_unref (priv->secrets); - priv->secrets = nm_connection_duplicate (NM_CONNECTION (self)); - - if (signal_update) { - nm_settings_connection_interface_update (NM_SETTINGS_CONNECTION_INTERFACE (self), - ignore_cb, - NULL); - } - success = TRUE; - } - g_hash_table_destroy (new_settings); - return success; -} - -/**************************************************************/ - -static GValue * -string_to_gvalue (const char *str) -{ - GValue *val = g_slice_new0 (GValue); - - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, str); - return val; -} - -static GValue * -byte_array_to_gvalue (const GByteArray *array) -{ - GValue *val; - - val = g_slice_new0 (GValue); - g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY); - g_value_set_boxed (val, array); - - return val; -} - -static void -copy_one_secret (gpointer key, gpointer value, gpointer user_data) -{ - const char *value_str = (const char *) value; - - if (value_str) { - g_hash_table_insert ((GHashTable *) user_data, - g_strdup ((char *) key), - string_to_gvalue (value_str)); - } -} - -static void -add_secrets (NMSetting *setting, - const char *key, - const GValue *value, - GParamFlags flags, - gpointer user_data) -{ - GHashTable *secrets = user_data; - - if (!(flags & NM_SETTING_PARAM_SECRET)) - return; - - /* Copy secrets into the returned hash table */ - if (G_VALUE_HOLDS_STRING (value)) { - const char *tmp; - - tmp = g_value_get_string (value); - if (tmp) - g_hash_table_insert (secrets, g_strdup (key), string_to_gvalue (tmp)); - } else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) { - /* Flatten the string hash by pulling its keys/values out */ - g_hash_table_foreach (g_value_get_boxed (value), copy_one_secret, secrets); - } else if (G_VALUE_TYPE (value) == DBUS_TYPE_G_UCHAR_ARRAY) { - GByteArray *array; - - array = g_value_get_boxed (value); - if (array) - g_hash_table_insert (secrets, g_strdup (key), byte_array_to_gvalue (array)); - } -} - -static void -destroy_gvalue (gpointer data) -{ - GValue *value = (GValue *) data; - - g_value_unset (value); - g_slice_free (GValue, value); -} - -static gboolean -get_secrets (NMSettingsConnectionInterface *connection, - const char *setting_name, - const char **hints, - gboolean request_new, - NMSettingsConnectionInterfaceGetSecretsFunc callback, - gpointer user_data) -{ - NMSysconfigConnection *self = NM_SYSCONFIG_CONNECTION (connection); - NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - GHashTable *settings = NULL; - GHashTable *secrets = NULL; - NMSetting *setting; - GError *error = NULL; - - /* Use priv->secrets to work around the fact that nm_connection_clear_secrets() - * will clear secrets on this object's settings. priv->secrets should be - * a complete copy of this object and kept in sync by - * nm_sysconfig_connection_update(). - */ - if (!priv->secrets) { - error = g_error_new (NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION, - "%s.%d - Internal error; secrets cache invalid.", - __FILE__, __LINE__); - (*callback) (connection, NULL, error, user_data); - g_error_free (error); - return TRUE; - } - - setting = nm_connection_get_setting_by_name (priv->secrets, setting_name); - if (!setting) { - error = g_error_new (NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INVALID_SETTING, - "%s.%d - Connection didn't have requested setting '%s'.", - __FILE__, __LINE__, setting_name); - (*callback) (connection, NULL, error, user_data); - g_error_free (error); - return TRUE; - } - - /* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that - * will contain all the individual settings hashes. - */ - settings = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) g_hash_table_destroy); - - /* Add the secrets from this setting to the inner secrets hash for this setting */ - secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue); - nm_setting_enumerate_values (setting, add_secrets, secrets); - - g_hash_table_insert (settings, g_strdup (setting_name), secrets); - callback (connection, settings, NULL, user_data); - g_hash_table_destroy (settings); - return TRUE; -} - -/**************************************************************/ - -typedef struct { - NMSysconfigConnection *self; - DBusGMethodInvocation *context; - PolkitSubject *subject; - GCancellable *cancellable; - gboolean disposed; - - /* Update */ - NMConnection *connection; - - /* Secrets */ - char *setting_name; - char **hints; - gboolean request_new; -} PolkitCall; - -static PolkitCall * -polkit_call_new (NMSysconfigConnection *self, - DBusGMethodInvocation *context, - NMConnection *connection, - const char *setting_name, - const char **hints, - gboolean request_new) -{ - PolkitCall *call; - char *sender; - - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (context != NULL, NULL); - - call = g_malloc0 (sizeof (PolkitCall)); - call->self = self; - call->context = context; - call->cancellable = g_cancellable_new (); - call->connection = connection; - call->setting_name = g_strdup (setting_name); - if (hints) - call->hints = g_strdupv ((char **) hints); - call->request_new = request_new; - - sender = dbus_g_method_get_sender (context); - call->subject = polkit_system_bus_name_new (sender); - g_free (sender); - - return call; -} - -static void -polkit_call_free (PolkitCall *call) -{ - if (call->connection) - g_object_unref (call->connection); - g_free (call->setting_name); - if (call->hints) - g_strfreev (call->hints); - - g_object_unref (call->subject); - g_object_unref (call->cancellable); - g_free (call); -} - -static void -con_update_cb (NMSettingsConnectionInterface *connection, - GError *error, - gpointer user_data) -{ - PolkitCall *call = user_data; - - if (error) - dbus_g_method_return_error (call->context, error); - else - dbus_g_method_return (call->context); - - polkit_call_free (call); -} - -static void -pk_update_cb (GObject *object, GAsyncResult *result, gpointer user_data) -{ - PolkitCall *call = user_data; - NMSysconfigConnection *self = call->self; - NMSysconfigConnectionPrivate *priv; - PolkitAuthorizationResult *pk_result; - GError *error = NULL; - - /* If our NMSysconfigConnection is already gone, do nothing */ - if (call->disposed) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_GENERAL, - "Request was canceled."); - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - return; - } - - priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - - priv->pk_calls = g_slist_remove (priv->pk_calls, call); - - pk_result = polkit_authority_check_authorization_finish (priv->authority, - result, - &error); - /* Some random error happened */ - if (error) { - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - return; - } - - /* Caller didn't successfully authenticate */ - if (!polkit_authorization_result_get_is_authorized (pk_result)) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_NOT_PRIVILEGED, - "Insufficient privileges."); - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - goto out; - } - - /* Update our settings internally so the update() call will save the new - * ones. We don't let nm_sysconfig_connection_update() handle the update - * signal since we need our own callback after the update is done. - */ - if (!nm_sysconfig_connection_update (self, call->connection, FALSE, &error)) { - /* Shouldn't really happen since we've already validated the settings */ - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - goto out; - } - - /* Caller is authenticated, now we can finally try to commit the update */ - nm_settings_connection_interface_update (NM_SETTINGS_CONNECTION_INTERFACE (self), - con_update_cb, - call); - -out: - g_object_unref (pk_result); -} - -static void -dbus_update (NMExportedConnection *exported, - GHashTable *new_settings, - DBusGMethodInvocation *context) -{ - NMSysconfigConnection *self = NM_SYSCONFIG_CONNECTION (exported); - NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - PolkitCall *call; - NMConnection *tmp; - GError *error = NULL; - - /* Check if the settings are valid first */ - tmp = nm_connection_new_from_hash (new_settings, &error); - if (!tmp) { - g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - call = polkit_call_new (self, context, tmp, NULL, NULL, FALSE); - g_assert (call); - polkit_authority_check_authorization (priv->authority, - call->subject, - NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY, - NULL, - POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, - call->cancellable, - pk_update_cb, - call); - priv->pk_calls = g_slist_prepend (priv->pk_calls, call); -} - -static void -con_delete_cb (NMSettingsConnectionInterface *connection, - GError *error, - gpointer user_data) -{ - PolkitCall *call = user_data; - - if (error) - dbus_g_method_return_error (call->context, error); - else - dbus_g_method_return (call->context); - - polkit_call_free (call); -} - -static void -pk_delete_cb (GObject *object, GAsyncResult *result, gpointer user_data) -{ - PolkitCall *call = user_data; - NMSysconfigConnection *self = call->self; - NMSysconfigConnectionPrivate *priv; - PolkitAuthorizationResult *pk_result; - GError *error = NULL; - - /* If our NMSysconfigConnection is already gone, do nothing */ - if (call->disposed) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_GENERAL, - "Request was canceled."); - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - return; - } - - priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - - priv->pk_calls = g_slist_remove (priv->pk_calls, call); - - pk_result = polkit_authority_check_authorization_finish (priv->authority, - result, - &error); - /* Some random error happened */ - if (error) { - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - return; - } - - /* Caller didn't successfully authenticate */ - if (!polkit_authorization_result_get_is_authorized (pk_result)) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_NOT_PRIVILEGED, - "Insufficient privileges."); - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - goto out; - } - - /* Caller is authenticated, now we can finally try to delete */ - nm_settings_connection_interface_delete (NM_SETTINGS_CONNECTION_INTERFACE (self), - con_delete_cb, - call); - -out: - g_object_unref (pk_result); -} - -static void -dbus_delete (NMExportedConnection *exported, - DBusGMethodInvocation *context) -{ - NMSysconfigConnection *self = NM_SYSCONFIG_CONNECTION (exported); - NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - PolkitCall *call; - - call = polkit_call_new (self, context, NULL, NULL, NULL, FALSE); - g_assert (call); - polkit_authority_check_authorization (priv->authority, - call->subject, - NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY, - NULL, - POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, - call->cancellable, - pk_delete_cb, - call); - priv->pk_calls = g_slist_prepend (priv->pk_calls, call); -} - -static void -con_secrets_cb (NMSettingsConnectionInterface *connection, - GHashTable *secrets, - GError *error, - gpointer user_data) -{ - PolkitCall *call = user_data; - - if (error) - dbus_g_method_return_error (call->context, error); - else - dbus_g_method_return (call->context, secrets); - - polkit_call_free (call); -} - -static void -pk_secrets_cb (GObject *object, GAsyncResult *result, gpointer user_data) -{ - PolkitCall *call = user_data; - NMSysconfigConnection *self = call->self; - NMSysconfigConnectionPrivate *priv; - PolkitAuthorizationResult *pk_result; - GError *error = NULL; - - /* If our NMSysconfigConnection is already gone, do nothing */ - if (call->disposed) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_GENERAL, - "Request was canceled."); - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - return; - } - - priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - - priv->pk_calls = g_slist_remove (priv->pk_calls, call); - - pk_result = polkit_authority_check_authorization_finish (priv->authority, - result, - &error); - /* Some random error happened */ - if (error) { - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - return; - } - - /* Caller didn't successfully authenticate */ - if (!polkit_authorization_result_get_is_authorized (pk_result)) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_NOT_PRIVILEGED, - "Insufficient privileges."); - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - goto out; - } - - /* Caller is authenticated, now we can finally try to update */ - nm_settings_connection_interface_get_secrets (NM_SETTINGS_CONNECTION_INTERFACE (self), - call->setting_name, - (const char **) call->hints, - call->request_new, - con_secrets_cb, - call); - -out: - g_object_unref (pk_result); -} - -static void -dbus_get_secrets (NMExportedConnection *exported, - const gchar *setting_name, - const gchar **hints, - gboolean request_new, - DBusGMethodInvocation *context) -{ - NMSysconfigConnection *self = NM_SYSCONFIG_CONNECTION (exported); - NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - PolkitCall *call; - - call = polkit_call_new (self, context, NULL, setting_name, hints, request_new); - g_assert (call); - polkit_authority_check_authorization (priv->authority, - call->subject, - NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY, - NULL, - POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, - call->cancellable, - pk_secrets_cb, - call); - priv->pk_calls = g_slist_prepend (priv->pk_calls, call); -} - -/**************************************************************/ - -static void -settings_connection_interface_init (NMSettingsConnectionInterface *iface) -{ - iface->get_secrets = get_secrets; -} - -static void -nm_sysconfig_connection_init (NMSysconfigConnection *self) -{ - NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - GError *error = NULL; - - priv->authority = polkit_authority_get_sync (NULL, NULL); - if (!priv->authority) { - nm_log_warn (LOGD_SYS_SET, "failed to create PolicyKit authority: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } -} - -static void -dispose (GObject *object) -{ - NMSysconfigConnection *self = NM_SYSCONFIG_CONNECTION (object); - NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self); - GSList *iter; - - if (priv->secrets) - g_object_unref (priv->secrets); - - /* Cancel PolicyKit requests */ - for (iter = priv->pk_calls; iter; iter = g_slist_next (iter)) { - PolkitCall *call = iter->data; - - call->disposed = TRUE; - g_cancellable_cancel (call->cancellable); - } - g_slist_free (priv->pk_calls); - priv->pk_calls = NULL; - - G_OBJECT_CLASS (nm_sysconfig_connection_parent_class)->dispose (object); -} - -static void -nm_sysconfig_connection_class_init (NMSysconfigConnectionClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - NMExportedConnectionClass *ec_class = NM_EXPORTED_CONNECTION_CLASS (class); - - g_type_class_add_private (class, sizeof (NMSysconfigConnectionPrivate)); - - /* Virtual methods */ - object_class->dispose = dispose; - ec_class->update = dbus_update; - ec_class->delete = dbus_delete; - ec_class->get_secrets = dbus_get_secrets; -} diff --git a/src/system-settings/nm-sysconfig-connection.h b/src/system-settings/nm-sysconfig-connection.h deleted file mode 100644 index 0431dc95c2..0000000000 --- a/src/system-settings/nm-sysconfig-connection.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * (C) Copyright 2008 Novell, Inc. - */ - -#ifndef NM_SYSCONFIG_CONNECTION_H -#define NM_SYSCONFIG_CONNECTION_H - -#include -#include - -G_BEGIN_DECLS - -#define NM_TYPE_SYSCONFIG_CONNECTION (nm_sysconfig_connection_get_type ()) -#define NM_SYSCONFIG_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SYSCONFIG_CONNECTION, NMSysconfigConnection)) -#define NM_SYSCONFIG_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SYSCONFIG_CONNECTION, NMSysconfigConnectionClass)) -#define NM_IS_SYSCONFIG_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SYSCONFIG_CONNECTION)) -#define NM_IS_SYSCONFIG_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SYSCONFIG_CONNECTION)) -#define NM_SYSCONFIG_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SYSCONFIG_CONNECTION, NMSysconfigConnectionClass)) - -typedef struct { - NMExportedConnection parent; -} NMSysconfigConnection; - -typedef struct { - NMExportedConnectionClass parent; -} NMSysconfigConnectionClass; - -GType nm_sysconfig_connection_get_type (void); - -/* Called by a system-settings plugin to update a connection is out of sync - * with it's backing storage. - */ -gboolean nm_sysconfig_connection_update (NMSysconfigConnection *self, - NMConnection *new_settings, - gboolean signal_update, - GError **error); - -G_END_DECLS - -#endif /* NM_SYSCONFIG_CONNECTION_H */ diff --git a/src/system-settings/nm-sysconfig-settings.c b/src/system-settings/nm-sysconfig-settings.c deleted file mode 100644 index d929813f1b..0000000000 --- a/src/system-settings/nm-sysconfig-settings.c +++ /dev/null @@ -1,1537 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * Søren Sandmann - * Dan Williams - * Tambet Ingo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * (C) Copyright 2007 - 2010 Red Hat, Inc. - * (C) Copyright 2008 Novell, Inc. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../nm-device-ethernet.h" -#include "nm-dbus-glib-types.h" -#include "nm-sysconfig-settings.h" -#include "nm-sysconfig-connection.h" -#include "nm-polkit-helpers.h" -#include "nm-system-config-error.h" -#include "nm-default-wired-connection.h" -#include "nm-logging.h" - -#define CONFIG_KEY_NO_AUTO_DEFAULT "no-auto-default" - -/* LINKER CRACKROCK */ -#define EXPORT(sym) void * __export_##sym = &sym; - -#include "nm-inotify-helper.h" -EXPORT(nm_inotify_helper_get_type) -EXPORT(nm_inotify_helper_get) -EXPORT(nm_inotify_helper_add_watch) -EXPORT(nm_inotify_helper_remove_watch) - -EXPORT(nm_sysconfig_connection_get_type) -EXPORT(nm_sysconfig_connection_update) -/* END LINKER CRACKROCK */ - -static void claim_connection (NMSysconfigSettings *self, - NMSettingsConnectionInterface *connection, - gboolean do_export); - -static void impl_settings_save_hostname (NMSysconfigSettings *self, - const char *hostname, - DBusGMethodInvocation *context); - -static void impl_settings_get_permissions (NMSysconfigSettings *self, - DBusGMethodInvocation *context); - -#include "nm-settings-system-glue.h" - -static void unmanaged_specs_changed (NMSystemConfigInterface *config, gpointer user_data); - -typedef struct { - PolkitAuthority *authority; - guint auth_changed_id; - char *config_file; - - GSList *pk_calls; - GSList *permissions_calls; - - GSList *plugins; - gboolean connections_loaded; - GHashTable *connections; - GSList *unmanaged_specs; -} NMSysconfigSettingsPrivate; - -static void settings_system_interface_init (NMSettingsSystemInterface *klass); - -G_DEFINE_TYPE_WITH_CODE (NMSysconfigSettings, nm_sysconfig_settings, NM_TYPE_SETTINGS_SERVICE, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_SYSTEM_INTERFACE, - settings_system_interface_init)) - -#define NM_SYSCONFIG_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettingsPrivate)) - -enum { - PROPERTIES_CHANGED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -enum { - PROP_0, - PROP_UNMANAGED_SPECS, - - LAST_PROP -}; - -static void -load_connections (NMSysconfigSettings *self) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GSList *iter; - - if (priv->connections_loaded) - return; - - for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); - GSList *plugin_connections; - GSList *elt; - - plugin_connections = nm_system_config_interface_get_connections (plugin); - - // FIXME: ensure connections from plugins loaded with a lower priority - // get rejected when they conflict with connections from a higher - // priority plugin. - - for (elt = plugin_connections; elt; elt = g_slist_next (elt)) - claim_connection (self, NM_SETTINGS_CONNECTION_INTERFACE (elt->data), TRUE); - - g_slist_free (plugin_connections); - } - - priv->connections_loaded = TRUE; - - /* FIXME: Bad hack */ - unmanaged_specs_changed (NULL, self); -} - -static GSList * -list_connections (NMSettingsService *settings) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (settings); - GHashTableIter iter; - gpointer key; - GSList *list = NULL; - - load_connections (NM_SYSCONFIG_SETTINGS (settings)); - - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, &key, NULL)) - list = g_slist_prepend (list, NM_EXPORTED_CONNECTION (key)); - return g_slist_reverse (list); -} - -static void -clear_unmanaged_specs (NMSysconfigSettings *self) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - g_slist_foreach (priv->unmanaged_specs, (GFunc) g_free, NULL); - g_slist_free (priv->unmanaged_specs); - priv->unmanaged_specs = NULL; -} - -static char* -uscore_to_wincaps (const char *uscore) -{ - const char *p; - GString *str; - gboolean last_was_uscore; - - last_was_uscore = TRUE; - - str = g_string_new (NULL); - p = uscore; - while (p && *p) { - if (*p == '-' || *p == '_') - last_was_uscore = TRUE; - else { - if (last_was_uscore) { - g_string_append_c (str, g_ascii_toupper (*p)); - last_was_uscore = FALSE; - } else - g_string_append_c (str, *p); - } - ++p; - } - - return g_string_free (str, FALSE); -} - -static void -notify (GObject *object, GParamSpec *pspec) -{ - GValue *value; - GHashTable *hash; - - value = g_slice_new0 (GValue); - hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); - - g_value_init (value, pspec->value_type); - g_object_get_property (object, pspec->name, value); - g_hash_table_insert (hash, uscore_to_wincaps (pspec->name), value); - g_signal_emit (object, signals[PROPERTIES_CHANGED], 0, hash); - g_hash_table_destroy (hash); - g_value_unset (value); - g_slice_free (GValue, value); -} - -const GSList * -nm_sysconfig_settings_get_unmanaged_specs (NMSysconfigSettings *self) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - load_connections (self); - return priv->unmanaged_specs; -} - -static NMSystemConfigInterface * -get_plugin (NMSysconfigSettings *self, guint32 capability) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GSList *iter; - - g_return_val_if_fail (self != NULL, NULL); - - /* Do any of the plugins support setting the hostname? */ - for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - if (caps & capability) - return NM_SYSTEM_CONFIG_INTERFACE (iter->data); - } - - return NULL; -} - -/* Returns an allocated string which the caller owns and must eventually free */ -char * -nm_sysconfig_settings_get_hostname (NMSysconfigSettings *self) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GSList *iter; - char *hostname = NULL; - - /* Hostname returned is the hostname returned from the first plugin - * that provides one. - */ - for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, &hostname, NULL); - if (hostname && strlen (hostname)) - return hostname; - g_free (hostname); - } - } - - return NULL; -} - -static void -plugin_connection_added (NMSystemConfigInterface *config, - NMSettingsConnectionInterface *connection, - gpointer user_data) -{ - claim_connection (NM_SYSCONFIG_SETTINGS (user_data), connection, TRUE); -} - -static gboolean -find_unmanaged_device (NMSysconfigSettings *self, const char *needle) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->unmanaged_specs; iter; iter = g_slist_next (iter)) { - if (!strcmp ((const char *) iter->data, needle)) - return TRUE; - } - return FALSE; -} - -static void -unmanaged_specs_changed (NMSystemConfigInterface *config, - gpointer user_data) -{ - NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (user_data); - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GSList *iter; - - clear_unmanaged_specs (self); - - /* Ask all the plugins for their unmanaged specs */ - for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - GSList *specs, *specs_iter; - - specs = nm_system_config_interface_get_unmanaged_specs (NM_SYSTEM_CONFIG_INTERFACE (iter->data)); - for (specs_iter = specs; specs_iter; specs_iter = specs_iter->next) { - if (!find_unmanaged_device (self, (const char *) specs_iter->data)) { - priv->unmanaged_specs = g_slist_prepend (priv->unmanaged_specs, specs_iter->data); - } else - g_free (specs_iter->data); - } - - g_slist_free (specs); - } - - g_object_notify (G_OBJECT (self), NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS); -} - -static void -hostname_changed (NMSystemConfigInterface *config, - GParamSpec *pspec, - gpointer user_data) -{ - g_object_notify (G_OBJECT (user_data), NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME); -} - -static void -add_plugin (NMSysconfigSettings *self, NMSystemConfigInterface *plugin) -{ - NMSysconfigSettingsPrivate *priv; - char *pname = NULL; - char *pinfo = NULL; - - g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); - g_return_if_fail (NM_IS_SYSTEM_CONFIG_INTERFACE (plugin)); - - priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin)); - - g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, - G_CALLBACK (plugin_connection_added), self); - g_signal_connect (plugin, "notify::hostname", G_CALLBACK (hostname_changed), self); - - nm_system_config_interface_init (plugin, NULL); - - g_object_get (G_OBJECT (plugin), - NM_SYSTEM_CONFIG_INTERFACE_NAME, &pname, - NM_SYSTEM_CONFIG_INTERFACE_INFO, &pinfo, - NULL); - - g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED, - G_CALLBACK (unmanaged_specs_changed), self); - - nm_log_info (LOGD_SYS_SET, "Loaded plugin %s: %s", pname, pinfo); - g_free (pname); - g_free (pinfo); -} - -static GObject * -find_plugin (GSList *list, const char *pname) -{ - GSList *iter; - GObject *obj = NULL; - - g_return_val_if_fail (pname != NULL, FALSE); - - for (iter = list; iter && !obj; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); - char *list_pname = NULL; - - g_object_get (G_OBJECT (plugin), - NM_SYSTEM_CONFIG_INTERFACE_NAME, - &list_pname, - NULL); - if (list_pname && !strcmp (pname, list_pname)) - obj = G_OBJECT (plugin); - - g_free (list_pname); - } - - return obj; -} - -static gboolean -load_plugins (NMSysconfigSettings *self, const char *plugins, GError **error) -{ - GSList *list = NULL; - char **plist; - char **iter; - gboolean success = TRUE; - - plist = g_strsplit (plugins, ",", 0); - if (!plist) - return FALSE; - - for (iter = plist; *iter; iter++) { - GModule *plugin; - char *full_name, *path; - const char *pname = g_strstrip (*iter); - GObject *obj; - GObject * (*factory_func) (void); - - /* ifcfg-fedora was renamed ifcfg-rh; handle old configs here */ - if (!strcmp (pname, "ifcfg-fedora")) - pname = "ifcfg-rh"; - - obj = find_plugin (list, pname); - if (obj) - continue; - - full_name = g_strdup_printf ("nm-settings-plugin-%s", pname); - path = g_module_build_path (PLUGINDIR, full_name); - - plugin = g_module_open (path, G_MODULE_BIND_LOCAL); - if (!plugin) { - g_set_error (error, 0, 0, - "Could not load plugin '%s': %s", - pname, g_module_error ()); - g_free (full_name); - g_free (path); - success = FALSE; - break; - } - - g_free (full_name); - g_free (path); - - if (!g_module_symbol (plugin, "nm_system_config_factory", (gpointer) (&factory_func))) { - g_set_error (error, 0, 0, - "Could not find plugin '%s' factory function.", - pname); - success = FALSE; - break; - } - - obj = (*factory_func) (); - if (!obj || !NM_IS_SYSTEM_CONFIG_INTERFACE (obj)) { - g_set_error (error, 0, 0, - "Plugin '%s' returned invalid system config object.", - pname); - success = FALSE; - break; - } - - g_module_make_resident (plugin); - g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin); - add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (obj)); - list = g_slist_append (list, obj); - } - - g_strfreev (plist); - - g_slist_foreach (list, (GFunc) g_object_unref, NULL); - g_slist_free (list); - - return success; -} - -static void -connection_removed (NMSettingsConnectionInterface *connection, - gpointer user_data) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data); - - g_hash_table_remove (priv->connections, connection); -} - -static void -claim_connection (NMSysconfigSettings *self, - NMSettingsConnectionInterface *connection, - gboolean do_export) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); - g_return_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection)); - - if (g_hash_table_lookup (priv->connections, connection)) - /* A plugin is lying to us. */ - return; - - g_hash_table_insert (priv->connections, g_object_ref (connection), GINT_TO_POINTER (1)); - g_signal_connect (connection, - NM_SETTINGS_CONNECTION_INTERFACE_REMOVED, - G_CALLBACK (connection_removed), - self); - - if (do_export) { - nm_settings_service_export_connection (NM_SETTINGS_SERVICE (self), connection); - g_signal_emit_by_name (self, NM_SETTINGS_INTERFACE_NEW_CONNECTION, connection); - } -} - -static void -remove_connection (NMSysconfigSettings *self, - NMSettingsConnectionInterface *connection, - gboolean do_signal) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); - g_return_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection)); - - if (g_hash_table_lookup (priv->connections, connection)) { - g_signal_emit_by_name (G_OBJECT (connection), NM_SETTINGS_CONNECTION_INTERFACE_REMOVED); - g_hash_table_remove (priv->connections, connection); - } -} - -typedef struct { - NMSysconfigSettings *self; - DBusGMethodInvocation *context; - PolkitSubject *subject; - GCancellable *cancellable; - gboolean disposed; - - NMConnection *connection; - NMSettingsAddConnectionFunc callback; - gpointer callback_data; - - char *hostname; - - NMSettingsSystemPermissions permissions; - guint32 permissions_calls; -} PolkitCall; - -#include "nm-dbus-manager.h" - -static PolkitCall * -polkit_call_new (NMSysconfigSettings *self, - DBusGMethodInvocation *context, - NMConnection *connection, - NMSettingsAddConnectionFunc callback, - gpointer callback_data, - const char *hostname) -{ - PolkitCall *call; - char *sender; - - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (context != NULL, NULL); - - call = g_malloc0 (sizeof (PolkitCall)); - call->self = self; - call->cancellable = g_cancellable_new (); - call->context = context; - if (connection) - call->connection = g_object_ref (connection); - if (callback) { - call->callback = callback; - call->callback_data = callback_data; - } - if (hostname) - call->hostname = g_strdup (hostname); - - sender = dbus_g_method_get_sender (context); - call->subject = polkit_system_bus_name_new (sender); - g_free (sender); - - return call; -} - -static void -polkit_call_free (PolkitCall *call) -{ - if (call->connection) - g_object_unref (call->connection); - g_object_unref (call->cancellable); - g_free (call->hostname); - g_object_unref (call->subject); - g_free (call); -} - -static gboolean -add_new_connection (NMSysconfigSettings *self, - NMConnection *connection, - GError **error) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GError *tmp_error = NULL, *last_error = NULL; - GSList *iter; - gboolean success = FALSE; - - /* Here's how it works: - 1) plugin writes a connection. - 2) plugin notices that a new connection is available for reading. - 3) plugin reads the new connection (the one it wrote in 1) and emits 'connection-added' signal. - 4) NMSysconfigSettings receives the signal and adds it to it's connection list. - */ - - for (iter = priv->plugins; iter && !success; iter = iter->next) { - success = nm_system_config_interface_add_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), - connection, - &tmp_error); - g_clear_error (&last_error); - if (!success) { - last_error = tmp_error; - tmp_error = NULL; - } - } - - if (!success) - *error = last_error; - return success; -} - -static void -pk_add_cb (GObject *object, GAsyncResult *result, gpointer user_data) -{ - PolkitCall *call = user_data; - NMSysconfigSettings *self = call->self; - NMSysconfigSettingsPrivate *priv; - PolkitAuthorizationResult *pk_result; - GError *error = NULL, *add_error = NULL; - - /* If NMSysconfigSettings is already gone, do nothing */ - if (call->disposed) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_GENERAL, - "Request was canceled."); - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - return; - } - - priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - priv->pk_calls = g_slist_remove (priv->pk_calls, call); - - pk_result = polkit_authority_check_authorization_finish (priv->authority, - result, - &error); - /* Some random error happened */ - if (error) { - call->callback (NM_SETTINGS_INTERFACE (self), error, call->callback_data); - goto out; - } - - /* Caller didn't successfully authenticate */ - if (!polkit_authorization_result_get_is_authorized (pk_result)) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_NOT_PRIVILEGED, - "Insufficient privileges."); - call->callback (NM_SETTINGS_INTERFACE (self), error, call->callback_data); - goto out; - } - - if (add_new_connection (self, call->connection, &add_error)) - call->callback (NM_SETTINGS_INTERFACE (self), NULL, call->callback_data); - else { - error = g_error_new (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_ADD_FAILED, - "Saving connection failed: (%d) %s", - add_error ? add_error->code : -1, - (add_error && add_error->message) ? add_error->message : "(unknown)"); - g_error_free (add_error); - call->callback (NM_SETTINGS_INTERFACE (self), error, call->callback_data); - } - -out: - g_clear_error (&error); - polkit_call_free (call); - if (pk_result) - g_object_unref (pk_result); -} - -static void -add_connection (NMSettingsService *service, - NMConnection *connection, - DBusGMethodInvocation *context, /* Only present for D-Bus calls */ - NMSettingsAddConnectionFunc callback, - gpointer user_data) -{ - NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (service); - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - PolkitCall *call; - GError *error = NULL; - - /* Do any of the plugins support adding? */ - if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_ADD_NOT_SUPPORTED, - "None of the registered plugins support add."); - callback (NM_SETTINGS_INTERFACE (service), error, user_data); - g_error_free (error); - return; - } - - call = polkit_call_new (self, context, connection, callback, user_data, NULL); - g_assert (call); - polkit_authority_check_authorization (priv->authority, - call->subject, - NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY, - NULL, - POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, - call->cancellable, - pk_add_cb, - call); - priv->pk_calls = g_slist_append (priv->pk_calls, call); -} - -static void -pk_hostname_cb (GObject *object, GAsyncResult *result, gpointer user_data) -{ - PolkitCall *call = user_data; - NMSysconfigSettings *self = call->self; - NMSysconfigSettingsPrivate *priv; - PolkitAuthorizationResult *pk_result; - GError *error = NULL; - GSList *iter; - gboolean success = FALSE; - - /* If our NMSysconfigConnection is already gone, do nothing */ - if (call->disposed) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_GENERAL, - "Request was canceled."); - dbus_g_method_return_error (call->context, error); - g_error_free (error); - polkit_call_free (call); - return; - } - - priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - priv->pk_calls = g_slist_remove (priv->pk_calls, call); - - pk_result = polkit_authority_check_authorization_finish (priv->authority, - result, - &error); - /* Some random error happened */ - if (error) { - dbus_g_method_return_error (call->context, error); - goto out; - } - - /* Caller didn't successfully authenticate */ - if (!polkit_authorization_result_get_is_authorized (pk_result)) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_NOT_PRIVILEGED, - "Insufficient privileges."); - dbus_g_method_return_error (call->context, error); - goto out; - } - - /* Set the hostname in all plugins */ - for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { - g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, call->hostname, NULL); - success = TRUE; - } - } - - if (success) { - dbus_g_method_return (call->context); - } else { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, - "Saving the hostname failed."); - dbus_g_method_return_error (call->context, error); - } - -out: - g_clear_error (&error); - polkit_call_free (call); - if (pk_result) - g_object_unref (pk_result); -} - -static void -impl_settings_save_hostname (NMSysconfigSettings *self, - const char *hostname, - DBusGMethodInvocation *context) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - PolkitCall *call; - GError *error = NULL; - - /* Do any of the plugins support setting the hostname? */ - if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, - "None of the registered plugins support setting the hostname."); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - call = polkit_call_new (self, context, NULL, NULL, NULL, hostname); - g_assert (call); - polkit_authority_check_authorization (priv->authority, - call->subject, - NM_SYSCONFIG_POLICY_ACTION_HOSTNAME_MODIFY, - NULL, - POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, - call->cancellable, - pk_hostname_cb, - call); - priv->pk_calls = g_slist_append (priv->pk_calls, call); -} - -static void -pk_authority_changed_cb (GObject *object, gpointer user_data) -{ - /* Let clients know they should re-check their authorization */ - g_signal_emit_by_name (NM_SYSCONFIG_SETTINGS (user_data), - NM_SETTINGS_SYSTEM_INTERFACE_CHECK_PERMISSIONS); -} - -typedef struct { - PolkitCall *pk_call; - const char *pk_action; - GCancellable *cancellable; - NMSettingsSystemPermissions permission; - gboolean disposed; -} PermissionsCall; - -static void -permission_call_done (GObject *object, GAsyncResult *result, gpointer user_data) -{ - PermissionsCall *call = user_data; - PolkitCall *pk_call = call->pk_call; - NMSysconfigSettings *self = pk_call->self; - NMSysconfigSettingsPrivate *priv; - PolkitAuthorizationResult *pk_result; - GError *error = NULL; - - /* If NMSysconfigSettings is gone, just skip to the end */ - if (call->disposed) - goto done; - - priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - priv->permissions_calls = g_slist_remove (priv->permissions_calls, call); - - pk_result = polkit_authority_check_authorization_finish (priv->authority, - result, - &error); - /* Some random error happened */ - if (error) { - nm_log_err (LOGD_SYS_SET, "error checking '%s' permission: (%d) %s", - __FILE__, __LINE__, __func__, - call->pk_action, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - if (error) - g_error_free (error); - } else { - /* If the caller is authorized, or the caller could authorize via a - * challenge, then authorization is possible. Otherwise, caller is out of - * luck. - */ - if ( polkit_authorization_result_get_is_authorized (pk_result) - || polkit_authorization_result_get_is_challenge (pk_result)) - pk_call->permissions |= call->permission; - } - - g_object_unref (pk_result); - -done: - pk_call->permissions_calls--; - if (pk_call->permissions_calls == 0) { - if (call->disposed) { - error = g_error_new_literal (NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_GENERAL, - "Request was canceled."); - dbus_g_method_return_error (pk_call->context, error); - g_error_free (error); - } else { - /* All the permissions calls are done, return the full permissions - * bitfield back to the user. - */ - dbus_g_method_return (pk_call->context, pk_call->permissions); - } - - polkit_call_free (pk_call); - } - memset (call, 0, sizeof (PermissionsCall)); - g_free (call); -} - -static void -start_permission_check (NMSysconfigSettings *self, - PolkitCall *pk_call, - const char *pk_action, - NMSettingsSystemPermissions permission) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - PermissionsCall *call; - - g_return_if_fail (pk_call != NULL); - g_return_if_fail (pk_action != NULL); - g_return_if_fail (permission != NM_SETTINGS_SYSTEM_PERMISSION_NONE); - - call = g_malloc0 (sizeof (PermissionsCall)); - call->pk_call = pk_call; - call->pk_action = pk_action; - call->permission = permission; - call->cancellable = g_cancellable_new (); - - pk_call->permissions_calls++; - - polkit_authority_check_authorization (priv->authority, - pk_call->subject, - pk_action, - NULL, - 0, - call->cancellable, - permission_call_done, - call); - priv->permissions_calls = g_slist_append (priv->permissions_calls, call); -} - -static void -impl_settings_get_permissions (NMSysconfigSettings *self, - DBusGMethodInvocation *context) -{ - PolkitCall *call; - - call = polkit_call_new (self, context, NULL, NULL, NULL, FALSE); - g_assert (call); - - /* Start checks for the various permissions */ - - /* Only check for connection-modify if one of our plugins supports it. */ - if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) { - start_permission_check (self, call, - NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY, - NM_SETTINGS_SYSTEM_PERMISSION_CONNECTION_MODIFY); - } - - /* Only check for hostname-modify if one of our plugins supports it. */ - if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) { - start_permission_check (self, call, - NM_SYSCONFIG_POLICY_ACTION_HOSTNAME_MODIFY, - NM_SETTINGS_SYSTEM_PERMISSION_HOSTNAME_MODIFY); - } - - // FIXME: hook these into plugin permissions like the modify permissions */ - start_permission_check (self, call, - NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_OPEN, - NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_OPEN); - start_permission_check (self, call, - NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_PROTECTED, - NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_PROTECTED); -} - -static gboolean -get_permissions (NMSettingsSystemInterface *settings, - NMSettingsSystemGetPermissionsFunc callback, - gpointer user_data) -{ - NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (settings); - NMSettingsSystemPermissions permissions = NM_SETTINGS_SYSTEM_PERMISSION_NONE; - - /* Local caller (ie, NM) gets full permissions by default because it doesn't - * need authorization. However, permissions are still subject to plugin's - * restrictions. i.e. if no plugins support connection-modify, then even - * the local caller won't get that permission. - */ - - /* Only check for connection-modify if one of our plugins supports it. */ - if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) - permissions |= NM_SETTINGS_SYSTEM_PERMISSION_CONNECTION_MODIFY; - - /* Only check for hostname-modify if one of our plugins supports it. */ - if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) - permissions |= NM_SETTINGS_SYSTEM_PERMISSION_HOSTNAME_MODIFY; - - // FIXME: hook these into plugin permissions like the modify permissions */ - permissions |= NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_OPEN; - permissions |= NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_PROTECTED; - - callback (settings, permissions, NULL, user_data); - return TRUE; -} - -static gboolean -have_connection_for_device (NMSysconfigSettings *self, GByteArray *mac) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GHashTableIter iter; - gpointer key; - NMSettingConnection *s_con; - NMSettingWired *s_wired; - const GByteArray *setting_mac; - gboolean ret = FALSE; - - g_return_val_if_fail (NM_IS_SYSCONFIG_SETTINGS (self), FALSE); - g_return_val_if_fail (mac != NULL, FALSE); - - /* Find a wired connection locked to the given MAC address, if any */ - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, &key, NULL)) { - NMConnection *connection = NM_CONNECTION (key); - const char *connection_type; - - s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); - connection_type = nm_setting_connection_get_connection_type (s_con); - - if ( strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME) - && strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) - continue; - - s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); - - /* No wired setting; therefore the PPPoE connection applies to any device */ - if (!s_wired && !strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) { - ret = TRUE; - break; - } - - setting_mac = nm_setting_wired_get_mac_address (s_wired); - if (setting_mac) { - /* A connection mac-locked to this device */ - if (!memcmp (setting_mac->data, mac->data, ETH_ALEN)) { - ret = TRUE; - break; - } - } else { - /* A connection that applies to any wired device */ - ret = TRUE; - break; - } - } - - return ret; -} - -/* Search through the list of blacklisted MAC addresses in the config file. */ -static gboolean -is_mac_auto_wired_blacklisted (NMSysconfigSettings *self, const GByteArray *mac) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GKeyFile *config; - char **list, **iter; - gboolean found = FALSE; - - g_return_val_if_fail (mac != NULL, FALSE); - - if (!priv->config_file) - return FALSE; - - config = g_key_file_new (); - if (!config) { - nm_log_warn (LOGD_SYS_SET, "not enough memory to load config file."); - return FALSE; - } - - g_key_file_set_list_separator (config, ','); - if (!g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_NONE, NULL)) - goto out; - - list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, NULL, NULL); - for (iter = list; iter && *iter; iter++) { - struct ether_addr *candidate; - - if (strcmp(g_strstrip(*iter), "*") == 0) { - found = TRUE; - break; - } - - candidate = ether_aton (*iter); - if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) { - found = TRUE; - break; - } - } - - if (list) - g_strfreev (list); - -out: - g_key_file_free (config); - return found; -} - -#define DEFAULT_WIRED_TAG "default-wired" - -static void -default_wired_deleted (NMDefaultWiredConnection *wired, - const GByteArray *mac, - NMSysconfigSettings *self) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - NMSettingConnection *s_con; - char *tmp; - GKeyFile *config; - char **list, **iter, **updated; - gboolean found = FALSE; - gsize len = 0, i; - char *data; - - /* If there was no config file specified, there's nothing to do */ - if (!priv->config_file) - goto cleanup; - - /* When the default wired connection is removed (either deleted or saved - * to a new persistent connection by a plugin), write the MAC address of - * the wired device to the config file and don't create a new default wired - * connection for that device again. - */ - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (wired), - NM_TYPE_SETTING_CONNECTION); - g_assert (s_con); - - /* Ignore removals of read-only connections, since they couldn't have - * been removed by the user. - */ - if (nm_setting_connection_get_read_only (s_con)) - goto cleanup; - - config = g_key_file_new (); - if (!config) - goto cleanup; - - g_key_file_set_list_separator (config, ','); - g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_KEEP_COMMENTS, NULL); - - list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, &len, NULL); - for (iter = list; iter && *iter; iter++) { - struct ether_addr *candidate; - - if (strcmp(g_strstrip(*iter), "*") == 0) { - found = TRUE; - break; - } - - candidate = ether_aton (*iter); - if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) { - found = TRUE; - break; - } - } - - /* Add this device's MAC to the list */ - if (!found) { - tmp = g_strdup_printf ("%02x:%02x:%02x:%02x:%02x:%02x", - mac->data[0], mac->data[1], mac->data[2], - mac->data[3], mac->data[4], mac->data[5]); - - /* New list; size + 1 for the new element, + 1 again for ending NULL */ - updated = g_malloc0 (sizeof (char*) * (len + 2)); - - /* Copy original list and add new MAC */ - for (i = 0; list && list[i]; i++) - updated[i] = list[i]; - updated[i++] = tmp; - updated[i] = NULL; - - g_key_file_set_string_list (config, - "main", CONFIG_KEY_NO_AUTO_DEFAULT, - (const char **) updated, - len + 2); - /* g_free() not g_strfreev() since 'updated' isn't a deep-copy */ - g_free (updated); - g_free (tmp); - - data = g_key_file_to_data (config, &len, NULL); - if (data) { - g_file_set_contents (priv->config_file, data, len, NULL); - g_free (data); - } - } - - if (list) - g_strfreev (list); - g_key_file_free (config); - -cleanup: - g_object_set_data (G_OBJECT (nm_default_wired_connection_get_device (wired)), - DEFAULT_WIRED_TAG, - NULL); -} - -static void -delete_cb (NMSettingsConnectionInterface *connection, GError *error, gpointer user_data) -{ -} - -static gboolean -default_wired_try_update (NMDefaultWiredConnection *wired, - NMSysconfigSettings *self) -{ - GError *error = NULL; - NMSettingConnection *s_con; - const char *id; - - /* Try to move this default wired conneciton to a plugin so that it has - * persistent storage. - */ - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (wired), - NM_TYPE_SETTING_CONNECTION); - g_assert (s_con); - id = nm_setting_connection_get_id (s_con); - g_assert (id); - - remove_connection (self, NM_SETTINGS_CONNECTION_INTERFACE (wired), FALSE); - if (add_new_connection (self, NM_CONNECTION (wired), &error)) { - nm_settings_connection_interface_delete (NM_SETTINGS_CONNECTION_INTERFACE (wired), - delete_cb, - NULL); - - g_object_set_data (G_OBJECT (nm_default_wired_connection_get_device (wired)), - DEFAULT_WIRED_TAG, - NULL); - nm_log_info (LOGD_SYS_SET, "Saved default wired connection '%s' to persistent storage", id); - return FALSE; - } - - nm_log_warn (LOGD_SYS_SET, "couldn't save default wired connection '%s': %d / %s", - id, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); - - /* If there was an error, don't destroy the default wired connection, - * but add it back to the system settings service. Connection is already - * exported on the bus, don't export it again, thus do_export == FALSE. - */ - claim_connection (self, NM_SETTINGS_CONNECTION_INTERFACE (wired), FALSE); - return TRUE; -} - -void -nm_sysconfig_settings_device_added (NMSysconfigSettings *self, NMDevice *device) -{ - GByteArray *mac = NULL; - struct ether_addr tmp; - NMDefaultWiredConnection *wired; - NMSettingConnection *s_con; - gboolean read_only = TRUE; - const char *id; - - if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET) - return; - - /* If the device isn't managed or it already has a default wired connection, - * ignore it. - */ - if ( !nm_device_get_managed (device) - || g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG)) - return; - - nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (device), &tmp); - - mac = g_byte_array_sized_new (ETH_ALEN); - g_byte_array_append (mac, tmp.ether_addr_octet, ETH_ALEN); - - if ( have_connection_for_device (self, mac) - || is_mac_auto_wired_blacklisted (self, mac)) - goto ignore; - - if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) - read_only = FALSE; - - wired = nm_default_wired_connection_new (mac, device, read_only); - if (!wired) - goto ignore; - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (wired), - NM_TYPE_SETTING_CONNECTION); - g_assert (s_con); - id = nm_setting_connection_get_id (s_con); - g_assert (id); - - nm_log_info (LOGD_SYS_SET, "Added default wired connection '%s' for %s", - id, nm_device_get_udi (device)); - - g_signal_connect (wired, "try-update", (GCallback) default_wired_try_update, self); - g_signal_connect (wired, "deleted", (GCallback) default_wired_deleted, self); - claim_connection (self, NM_SETTINGS_CONNECTION_INTERFACE (wired), TRUE); - g_object_unref (wired); - - g_object_set_data (G_OBJECT (device), DEFAULT_WIRED_TAG, wired); - -ignore: - g_byte_array_free (mac, TRUE); -} - -void -nm_sysconfig_settings_device_removed (NMSysconfigSettings *self, NMDevice *device) -{ - NMDefaultWiredConnection *connection; - - if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET) - return; - - connection = (NMDefaultWiredConnection *) g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG); - if (connection) - remove_connection (self, NM_SETTINGS_CONNECTION_INTERFACE (connection), TRUE); -} - -NMSysconfigSettings * -nm_sysconfig_settings_new (const char *config_file, - const char *plugins, - DBusGConnection *bus, - GError **error) -{ - NMSysconfigSettings *self; - NMSysconfigSettingsPrivate *priv; - - self = g_object_new (NM_TYPE_SYSCONFIG_SETTINGS, - NM_SETTINGS_SERVICE_BUS, bus, - NM_SETTINGS_SERVICE_SCOPE, NM_CONNECTION_SCOPE_SYSTEM, - NULL); - if (!self) - return NULL; - - priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - priv->config_file = g_strdup (config_file); - - if (plugins) { - /* Load the plugins; fail if a plugin is not found. */ - if (!load_plugins (self, plugins, error)) { - g_object_unref (self); - return NULL; - } - unmanaged_specs_changed (NULL, self); - } - - return self; -} - -/***************************************************************/ - -static void -dispose (GObject *object) -{ - NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (object); - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GSList *iter; - - if (priv->auth_changed_id) { - g_signal_handler_disconnect (priv->authority, priv->auth_changed_id); - priv->auth_changed_id = 0; - } - - /* Cancel PolicyKit requests */ - for (iter = priv->pk_calls; iter; iter = g_slist_next (iter)) { - PolkitCall *call = iter->data; - - call->disposed = TRUE; - g_cancellable_cancel (call->cancellable); - } - g_slist_free (priv->pk_calls); - priv->pk_calls = NULL; - - /* Cancel PolicyKit permissions requests */ - for (iter = priv->permissions_calls; iter; iter = g_slist_next (iter)) { - PermissionsCall *call = iter->data; - - call->disposed = TRUE; - g_cancellable_cancel (call->cancellable); - } - g_slist_free (priv->permissions_calls); - priv->permissions_calls = NULL; - - G_OBJECT_CLASS (nm_sysconfig_settings_parent_class)->dispose (object); -} - -static void -finalize (GObject *object) -{ - NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (object); - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - - g_hash_table_destroy (priv->connections); - - clear_unmanaged_specs (self); - - g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL); - g_slist_free (priv->plugins); - - g_free (priv->config_file); - - G_OBJECT_CLASS (nm_sysconfig_settings_parent_class)->finalize (object); -} - -static void -settings_system_interface_init (NMSettingsSystemInterface *iface) -{ - iface->get_permissions = get_permissions; - - dbus_g_object_type_install_info (G_TYPE_FROM_INTERFACE (iface), - &dbus_glib_nm_settings_system_object_info); -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (object); - const GSList *specs, *iter; - GSList *copy = NULL; - - switch (prop_id) { - case PROP_UNMANAGED_SPECS: - specs = nm_sysconfig_settings_get_unmanaged_specs (self); - for (iter = specs; iter; iter = g_slist_next (iter)) - copy = g_slist_append (copy, g_strdup (iter->data)); - g_value_take_boxed (value, copy); - break; - case NM_SETTINGS_SYSTEM_INTERFACE_PROP_HOSTNAME: - g_value_take_string (value, nm_sysconfig_settings_get_hostname (self)); - - /* Don't ever pass NULL through D-Bus */ - if (!g_value_get_string (value)) - g_value_set_static_string (value, ""); - break; - case NM_SETTINGS_SYSTEM_INTERFACE_PROP_CAN_MODIFY: - g_value_set_boolean (value, !!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -nm_sysconfig_settings_class_init (NMSysconfigSettingsClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - NMSettingsServiceClass *ss_class = NM_SETTINGS_SERVICE_CLASS (class); - - g_type_class_add_private (class, sizeof (NMSysconfigSettingsPrivate)); - - /* virtual methods */ - object_class->notify = notify; - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - ss_class->list_connections = list_connections; - ss_class->add_connection = add_connection; - - /* properties */ - g_object_class_install_property - (object_class, PROP_UNMANAGED_SPECS, - g_param_spec_boxed (NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS, - "Unamanged device specs", - "Unmanaged device specs", - DBUS_TYPE_G_LIST_OF_STRING, - G_PARAM_READABLE)); - - g_object_class_override_property (object_class, - NM_SETTINGS_SYSTEM_INTERFACE_PROP_HOSTNAME, - NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME); - - g_object_class_override_property (object_class, - NM_SETTINGS_SYSTEM_INTERFACE_PROP_CAN_MODIFY, - NM_SETTINGS_SYSTEM_INTERFACE_CAN_MODIFY); - - /* signals */ - signals[PROPERTIES_CHANGED] = - g_signal_new ("properties-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSysconfigSettingsClass, properties_changed), - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT); - - dbus_g_error_domain_register (NM_SYSCONFIG_SETTINGS_ERROR, - NM_DBUS_IFACE_SETTINGS_SYSTEM, - NM_TYPE_SYSCONFIG_SETTINGS_ERROR); - - dbus_g_error_domain_register (NM_SETTINGS_INTERFACE_ERROR, - NM_DBUS_IFACE_SETTINGS, - NM_TYPE_SETTINGS_INTERFACE_ERROR); - - /* And register all the settings errors with D-Bus */ - dbus_g_error_domain_register (NM_CONNECTION_ERROR, NULL, NM_TYPE_CONNECTION_ERROR); - dbus_g_error_domain_register (NM_SETTING_802_1X_ERROR, NULL, NM_TYPE_SETTING_802_1X_ERROR); - dbus_g_error_domain_register (NM_SETTING_BLUETOOTH_ERROR, NULL, NM_TYPE_SETTING_BLUETOOTH_ERROR); - dbus_g_error_domain_register (NM_SETTING_CDMA_ERROR, NULL, NM_TYPE_SETTING_CDMA_ERROR); - dbus_g_error_domain_register (NM_SETTING_CONNECTION_ERROR, NULL, NM_TYPE_SETTING_CONNECTION_ERROR); - dbus_g_error_domain_register (NM_SETTING_GSM_ERROR, NULL, NM_TYPE_SETTING_GSM_ERROR); - dbus_g_error_domain_register (NM_SETTING_IP4_CONFIG_ERROR, NULL, NM_TYPE_SETTING_IP4_CONFIG_ERROR); - dbus_g_error_domain_register (NM_SETTING_IP6_CONFIG_ERROR, NULL, NM_TYPE_SETTING_IP6_CONFIG_ERROR); - dbus_g_error_domain_register (NM_SETTING_OLPC_MESH_ERROR, NULL, NM_TYPE_SETTING_OLPC_MESH_ERROR); - dbus_g_error_domain_register (NM_SETTING_PPP_ERROR, NULL, NM_TYPE_SETTING_PPP_ERROR); - dbus_g_error_domain_register (NM_SETTING_PPPOE_ERROR, NULL, NM_TYPE_SETTING_PPPOE_ERROR); - dbus_g_error_domain_register (NM_SETTING_SERIAL_ERROR, NULL, NM_TYPE_SETTING_SERIAL_ERROR); - dbus_g_error_domain_register (NM_SETTING_VPN_ERROR, NULL, NM_TYPE_SETTING_VPN_ERROR); - dbus_g_error_domain_register (NM_SETTING_WIRED_ERROR, NULL, NM_TYPE_SETTING_WIRED_ERROR); - dbus_g_error_domain_register (NM_SETTING_WIRELESS_SECURITY_ERROR, NULL, NM_TYPE_SETTING_WIRELESS_SECURITY_ERROR); - dbus_g_error_domain_register (NM_SETTING_WIRELESS_ERROR, NULL, NM_TYPE_SETTING_WIRELESS_ERROR); - dbus_g_error_domain_register (NM_SETTING_ERROR, NULL, NM_TYPE_SETTING_ERROR); -} - -static void -nm_sysconfig_settings_init (NMSysconfigSettings *self) -{ - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - GError *error = NULL; - - priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); - - priv->authority = polkit_authority_get_sync (NULL, &error); - if (priv->authority) { - priv->auth_changed_id = g_signal_connect (priv->authority, - "changed", - G_CALLBACK (pk_authority_changed_cb), - self); - } else { - nm_log_warn (LOGD_SYS_SET, "failed to create PolicyKit authority: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } -} - diff --git a/src/system-settings/nm-sysconfig-settings.h b/src/system-settings/nm-sysconfig-settings.h deleted file mode 100644 index ae2ba68329..0000000000 --- a/src/system-settings/nm-sysconfig-settings.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * Søren Sandmann - * Dan Williams - * Tambet Ingo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * (C) Copyright 2007 - 2009 Red Hat, Inc. - * (C) Copyright 2008 Novell, Inc. - */ - -#ifndef __NM_SYSCONFIG_SETTINGS_H__ -#define __NM_SYSCONFIG_SETTINGS_H__ - -#include -#include - -#include "nm-sysconfig-connection.h" -#include "nm-system-config-interface.h" -#include "nm-device.h" - -#define NM_TYPE_SYSCONFIG_SETTINGS (nm_sysconfig_settings_get_type ()) -#define NM_SYSCONFIG_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettings)) -#define NM_SYSCONFIG_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettingsClass)) -#define NM_IS_SYSCONFIG_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SYSCONFIG_SETTINGS)) -#define NM_IS_SYSCONFIG_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SYSCONFIG_SETTINGS)) -#define NM_SYSCONFIG_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettingsClass)) - -#define NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS "unmanaged-specs" - -typedef struct { - NMSettingsService parent_instance; -} NMSysconfigSettings; - -typedef struct { - NMSettingsServiceClass parent_class; - - /* Signals */ - void (*properties_changed) (NMSysconfigSettings *self, GHashTable *properties); -} NMSysconfigSettingsClass; - -GType nm_sysconfig_settings_get_type (void); - -NMSysconfigSettings *nm_sysconfig_settings_new (const char *config_file, - const char *plugins, - DBusGConnection *bus, - GError **error); - -const GSList *nm_sysconfig_settings_get_unmanaged_specs (NMSysconfigSettings *self); - -char *nm_sysconfig_settings_get_hostname (NMSysconfigSettings *self); - -void nm_sysconfig_settings_device_added (NMSysconfigSettings *self, NMDevice *device); - -void nm_sysconfig_settings_device_removed (NMSysconfigSettings *self, NMDevice *device); - -#endif /* __NM_SYSCONFIG_SETTINGS_H__ */ diff --git a/src/system-settings/nm-system-config-error.c b/src/system-settings/nm-system-config-error.c deleted file mode 100644 index 13d47462f9..0000000000 --- a/src/system-settings/nm-system-config-error.c +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * 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 (C) 2008 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. - */ - -#include "nm-system-config-error.h" - -GQuark -nm_sysconfig_settings_error_quark (void) -{ - static GQuark ret = 0; - - if (ret == 0) - ret = g_quark_from_static_string ("nm_sysconfig_settings_error"); - - return ret; -} - -#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -GType -nm_sysconfig_settings_error_get_type (void) -{ - static GType etype = 0; - - if (etype == 0) { - static const GEnumValue values[] = { - ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_GENERAL, "GeneralError"), - ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_NOT_PRIVILEGED, "NotPrivileged"), - ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_ADD_NOT_SUPPORTED, "AddNotSupported"), - ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED, "UpdateNotSupported"), - ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_DELETE_NOT_SUPPORTED, "DeleteNotSupported"), - ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_ADD_FAILED, "AddFailed"), - ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, "SaveHostnameNotSupported"), - ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, "SaveHostnameFailed"), - { 0, 0, 0 } - }; - - etype = g_enum_register_static ("NMSysconfigSettingsError", values); - } - - return etype; -} diff --git a/src/system-settings/nm-system-config-error.h b/src/system-settings/nm-system-config-error.h deleted file mode 100644 index 63896fcd09..0000000000 --- a/src/system-settings/nm-system-config-error.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * 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 (C) 2008 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. - */ - -#ifndef NM_SYSTEM_CONFIG_ERROR_H -#define NM_SYSTEM_CONFIG_ERROR_H - -#include -#include - -enum { - NM_SYSCONFIG_SETTINGS_ERROR_GENERAL = 0, - NM_SYSCONFIG_SETTINGS_ERROR_NOT_PRIVILEGED, - NM_SYSCONFIG_SETTINGS_ERROR_ADD_NOT_SUPPORTED, - NM_SYSCONFIG_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED, - NM_SYSCONFIG_SETTINGS_ERROR_DELETE_NOT_SUPPORTED, - NM_SYSCONFIG_SETTINGS_ERROR_ADD_FAILED, - NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, - NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, -}; - -#define NM_SYSCONFIG_SETTINGS_ERROR (nm_sysconfig_settings_error_quark ()) -#define NM_TYPE_SYSCONFIG_SETTINGS_ERROR (nm_sysconfig_settings_error_get_type ()) - -GQuark nm_sysconfig_settings_error_quark (void); -GType nm_sysconfig_settings_error_get_type (void); - -#endif /* NM_SYSTEM_CONFIG_ERROR_H */ diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 62612a0e15..33a7bb15a1 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -6,7 +6,10 @@ INCLUDES = \ -I$(top_srcdir)/src \ -I$(top_builddir)/src -noinst_PROGRAMS = test-dhcp-options test-policy-hosts +noinst_PROGRAMS = \ + test-dhcp-options \ + test-policy-hosts \ + test-wifi-ap-utils ####### DHCP options test ####### @@ -39,11 +42,33 @@ test_policy_hosts_LDADD = \ $(top_builddir)/src/libtest-policy-hosts.la \ $(GLIB_LIBS) +####### wifi ap utils test ####### + +test_wifi_ap_utils_SOURCES = \ + test-wifi-ap-utils.c + +test_wifi_ap_utils_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) + +test_wifi_ap_utils_LDADD = \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(top_builddir)/src/libtest-wifi-ap-utils.la \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) + +####### secret agent interface test ####### + +EXTRA_DIST = test-secret-agent.py + +########################################### + if WITH_TESTS -check-local: test-dhcp-options +check-local: test-dhcp-options test-policy-hosts $(abs_builddir)/test-dhcp-options $(abs_builddir)/test-policy-hosts + $(abs_builddir)/test-wifi-ap-utils endif diff --git a/src/tests/test-secret-agent.py b/src/tests/test-secret-agent.py new file mode 100755 index 0000000000..6b9e676b3d --- /dev/null +++ b/src/tests/test-secret-agent.py @@ -0,0 +1,74 @@ +#!/bin/env python +# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +import glib +import gobject +import sys +import dbus +import dbus.service +import dbus.mainloop.glib + +IFACE_SECRET_AGENT = 'org.freedesktop.NetworkManager.SecretAgent' +IFACE_AGENT_MANAGER = 'org.freedesktop.NetworkManager.AgentManager' + +class NotAuthorizedException(dbus.DBusException): + _dbus_error_name = IFACE_SECRET_AGENT + '.NotAuthorized' + +class Agent(dbus.service.Object): + def __init__(self, bus, object_path): + self.agents = {} + self.bus = bus + dbus.service.Object.__init__(self, bus, object_path) + + @dbus.service.method(IFACE_SECRET_AGENT, + in_signature='a{sa{sv}}osasb', + out_signature='a{sa{sv}}', + sender_keyword='sender') + def GetSecrets(self, connection_hash, connection_path, setting_name, hints, request_new, sender=None): + if not sender: + raise NotAuthorizedException("Internal error: couldn't get sender") + uid = self.bus.get_unix_user(sender) + if uid != 0: + raise NotAuthorizedException("UID %d not authorized" % uid) + + print "Secrets requested path '%s' setting '%s' hints '%s' new %d" % (connection_path, setting_name, str(hints), request_new) + + # return some random GSM secrets + s_gsm = dbus.Dictionary({'password': 'asdfadfasdfaf'}) + con = dbus.Dictionary({'gsm': s_gsm}) + return con + +def register(proxy): + proxy.Register("test.agent.id", dbus_interface=IFACE_AGENT_MANAGER) + print "Registered!" + return False + +def unregister(proxy, loop): + proxy.Unregister(dbus_interface=IFACE_AGENT_MANAGER) + loop.quit() + return False + +def main(): + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + bus = dbus.SystemBus() + obj = Agent(bus, "/org/freedesktop/NetworkManager/SecretAgent") + proxy = bus.get_object("org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager/AgentManager") + + mainloop = gobject.MainLoop() + + gobject.idle_add(register, proxy) + print "Running test secret agent" + + try: + mainloop.run() + except KeyboardInterrupt, e: + pass + + print "Unregistering..." + unregister(proxy, mainloop); + +if __name__ == '__main__': + main() + diff --git a/src/tests/test-wifi-ap-utils.c b/src/tests/test-wifi-ap-utils.c new file mode 100644 index 0000000000..da46b8cd6f --- /dev/null +++ b/src/tests/test-wifi-ap-utils.c @@ -0,0 +1,1344 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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, 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 (C) 2011 Red Hat, Inc. + * + */ + +#include +#include + +#include "nm-wifi-ap-utils.h" +#include "nm-dbus-glib-types.h" + +#include "nm-setting-connection.h" +#include "nm-setting-wireless.h" +#include "nm-setting-wireless-security.h" +#include "nm-setting-8021x.h" + +#define DEBUG 1 + +/*******************************************/ + +#define COMPARE(src, expected, success, error, edomain, ecode) \ +{ \ + if (expected) { \ + if (!success) { \ + g_assert (error != NULL); \ + g_warning ("Failed to complete connection: (%d) %s", error->code, error->message); \ + } \ + g_assert (success == TRUE); \ + g_assert (error == NULL); \ +\ + success = nm_connection_compare (src, expected, NM_SETTING_COMPARE_FLAG_EXACT); \ + if (success == FALSE && DEBUG) { \ + g_message ("\n- COMPLETED ---------------------------------\n"); \ + nm_connection_dump (src); \ + g_message ("+ EXPECTED ++++++++++++++++++++++++++++++++++++\n"); \ + nm_connection_dump (expected); \ + g_message ("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); \ + } \ + g_assert (success == TRUE); \ + } else { \ + if (success) { \ + g_message ("\n- COMPLETED ---------------------------------\n"); \ + nm_connection_dump (src); \ + } \ + g_assert (success == FALSE); \ + g_assert_error (error, edomain, ecode); \ + } \ + \ + g_clear_error (&error); \ +} + +static gboolean +complete_connection (const char *ssid, + const guint8 bssid[ETH_ALEN], + NM80211Mode mode, + guint32 flags, + guint32 wpa_flags, + guint32 rsn_flags, + gboolean lock_bssid, + NMConnection *src, + GError **error) +{ + GByteArray *tmp; + gboolean success; + + tmp = g_byte_array_sized_new (strlen (ssid)); + g_byte_array_append (tmp, (const guint8 *) ssid, strlen (ssid)); + + success = nm_ap_utils_complete_connection (tmp, + bssid, + mode, + flags, + wpa_flags, + rsn_flags, + src, + lock_bssid, + error); + g_byte_array_free (tmp, TRUE); + return success; +} + +typedef struct { + const char *key; + const char *str; + guint32 uint; +} KeyData; + +static void +set_items (NMSetting *setting, const KeyData *items) +{ + const KeyData *item; + GParamSpec *pspec; + GByteArray *tmp; + + for (item = items; item && item->key; item++) { + g_assert (item->key); + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), item->key); + g_assert (pspec); + + if (pspec->value_type == G_TYPE_STRING) { + g_assert (item->uint == 0); + if (item->str) + g_object_set (G_OBJECT (setting), item->key, item->str, NULL); + } else if (pspec->value_type == G_TYPE_UINT) { + g_assert (item->str == NULL); + g_object_set (G_OBJECT (setting), item->key, item->uint, NULL); + } else if (pspec->value_type == G_TYPE_INT) { + gint foo = (gint) item->uint; + + g_assert (item->str == NULL); + g_object_set (G_OBJECT (setting), item->key, foo, NULL); + } else if (pspec->value_type == G_TYPE_BOOLEAN) { + gboolean foo = !! (item->uint); + + g_assert (item->str == NULL); + g_object_set (G_OBJECT (setting), item->key, foo, NULL); + } else if (pspec->value_type == DBUS_TYPE_G_UCHAR_ARRAY) { + g_assert (item->str); + tmp = g_byte_array_sized_new (strlen (item->str)); + g_byte_array_append (tmp, (const guint8 *) item->str, strlen (item->str)); + g_object_set (G_OBJECT (setting), item->key, tmp, NULL); + g_byte_array_free (tmp, TRUE); + } else { + /* Special types, check based on property name */ + if (!strcmp (item->key, NM_SETTING_WIRELESS_SECURITY_PROTO)) + nm_setting_wireless_security_add_proto (NM_SETTING_WIRELESS_SECURITY (setting), item->str); + else if (!strcmp (item->key, NM_SETTING_WIRELESS_SECURITY_PAIRWISE)) + nm_setting_wireless_security_add_pairwise (NM_SETTING_WIRELESS_SECURITY (setting), item->str); + else if (!strcmp (item->key, NM_SETTING_WIRELESS_SECURITY_GROUP)) + nm_setting_wireless_security_add_group (NM_SETTING_WIRELESS_SECURITY (setting), item->str); + else if (!strcmp (item->key, NM_SETTING_802_1X_EAP)) + nm_setting_802_1x_add_eap_method (NM_SETTING_802_1X (setting), item->str); + } + } +} + +static NMSettingWireless * +fill_wifi_empty (NMConnection *connection) +{ + NMSettingWireless *s_wifi; + + s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); + if (!s_wifi) { + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + } + return s_wifi; +} + +static NMSettingWireless * +fill_wifi (NMConnection *connection, const KeyData items[]) +{ + NMSettingWireless *s_wifi; + + s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); + if (!s_wifi) { + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + } + + set_items (NM_SETTING (s_wifi), items); + return s_wifi; +} + +static NMSettingWirelessSecurity * +fill_wsec (NMConnection *connection, const KeyData items[]) +{ + NMSettingWirelessSecurity *s_wsec; + + s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY); + if (!s_wsec) { + s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wsec)); + } + + set_items (NM_SETTING (s_wsec), items); + return s_wsec; +} + +static NMSetting8021x * +fill_8021x (NMConnection *connection, const KeyData items[]) +{ + NMSetting8021x *s_8021x; + + s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); + if (!s_8021x) { + s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); + nm_connection_add_setting (connection, NM_SETTING (s_8021x)); + } + + set_items (NM_SETTING (s_8021x), items); + return s_8021x; +} + +static NMConnection * +create_basic (const char *ssid, + const guint8 *bssid, + NM80211Mode mode, + gboolean set_security) +{ + NMConnection *connection; + NMSettingWireless *s_wifi = NULL; + GByteArray *tmp; + + connection = nm_connection_new (); + + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + /* SSID */ + tmp = g_byte_array_sized_new (strlen (ssid)); + g_byte_array_append (tmp, (const guint8 *) ssid, strlen (ssid)); + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, tmp, NULL); + g_byte_array_free (tmp, TRUE); + + /* BSSID */ + if (bssid) { + tmp = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (tmp, bssid, ETH_ALEN); + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, tmp, NULL); + g_byte_array_free (tmp, TRUE); + } + + if (mode == NM_802_11_MODE_INFRA) + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, "infrastructure", NULL); + else if (mode == NM_802_11_MODE_ADHOC) + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, "adhoc", NULL); + else + g_assert_not_reached (); + + if (set_security) + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NULL); + + return connection; +} + +/*******************************************/ + +static void +test_lock_bssid (void) +{ + NMConnection *src, *expected; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const char *ssid = "blahblah"; + gboolean success; + GError *error = NULL; + + src = nm_connection_new (); + success = complete_connection (ssid, bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + TRUE, + src, &error); + expected = create_basic (ssid, bssid, NM_802_11_MODE_INFRA, FALSE); + COMPARE (src, expected, success, error, 0, 0); + + g_object_unref (src); + g_object_unref (expected); +} + +/*******************************************/ + +static void +test_open_ap_empty_connection (void) +{ + NMConnection *src, *expected; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const char *ssid = "blahblah"; + gboolean success; + GError *error = NULL; + + /* Test that an empty source connection is correctly filled with the + * SSID and Infra modes of the given AP details. + */ + + src = nm_connection_new (); + success = complete_connection (ssid, bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + expected = create_basic (ssid, NULL, NM_802_11_MODE_INFRA, FALSE); + COMPARE (src, expected, success, error, 0, 0); + + g_object_unref (src); + g_object_unref (expected); +} + +/*******************************************/ + +static void +test_open_ap_leap_connection_1 (gboolean add_wifi) +{ + NMConnection *src; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { { NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, "Bill Smith", 0 }, { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that a basic connection filled with a LEAP username is + * rejected when completion is attempted with an open AP. LEAP requires + * the AP to have the Privacy bit set. + */ + + src = nm_connection_new (); + if (add_wifi) + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + + success = complete_connection ("blahblah", bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + /* We expect failure */ + COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_open_ap_leap_connection_2 (void) +{ + NMConnection *src; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that a basic connection specifying IEEE8021x security (ie, Dynamic + * WEP or LEAP) is rejected when completion is attempted with an open AP. + */ + + src = nm_connection_new (); + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + + success = complete_connection ("blahblah", bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + /* We expect failure */ + COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_open_ap_wep_connection (gboolean add_wifi) +{ + NMConnection *src; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, "11111111111111111111111111", 0 }, + { NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, NULL, 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that a static WEP connection is rejected when completion is + * attempted with an open AP. + */ + + src = nm_connection_new (); + if (add_wifi) + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + success = complete_connection ("blahblah", bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + /* We expect failure */ + COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_ap_wpa_psk_connection_base (const char *key_mgmt, + const char *auth_alg, + guint32 flags, + guint32 wpa_flags, + guint32 rsn_flags, + gboolean add_wifi, + NMConnection *expected) +{ + NMConnection *src; + const char *ssid = "blahblah"; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData exp_wifi[] = { + { NM_SETTING_WIRELESS_SSID, ssid, 0 }, + { NM_SETTING_WIRELESS_MODE, "infrastructure", 0 }, + { NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, 0 }, + { NULL } }; + const KeyData both_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, 0 }, + { NM_SETTING_WIRELESS_SECURITY_PSK, "asdfasdfasdfasdfasdfafs", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + src = nm_connection_new (); + if (add_wifi) + fill_wifi_empty (src); + fill_wsec (src, both_wsec); + success = complete_connection (ssid, bssid, NM_802_11_MODE_INFRA, + flags, wpa_flags, rsn_flags, + FALSE, src, &error); + if (expected) { + fill_wifi (expected, exp_wifi); + fill_wsec (expected, both_wsec); + } + COMPARE (src, expected, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY); + + g_object_unref (src); +} + +static void +test_open_ap_wpa_psk_connection_1 (void) +{ + /* Test that a WPA-PSK connection filling only the PSK itself and *not* + * filling the wifi setting is rejected when completion is attempted with + * an open AP. + */ + test_ap_wpa_psk_connection_base (NULL, NULL, + NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + FALSE, NULL); +} + +static void +test_open_ap_wpa_psk_connection_2 (void) +{ + /* Test that a WPA-PSK connection filling only the PSK itself and also + * filling the wifi setting is rejected when completion is attempted with + * an open AP. + */ + test_ap_wpa_psk_connection_base (NULL, NULL, + NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + TRUE, NULL); +} + +static void +test_open_ap_wpa_psk_connection_3 (void) +{ + /* Test that a WPA-PSK connection filling the PSK and setting the auth alg + * to 'open' is rejected when completion is attempted with an open AP. + */ + test_ap_wpa_psk_connection_base (NULL, "open", + NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + FALSE, NULL); +} + +static void +test_open_ap_wpa_psk_connection_4 (void) +{ + /* Test that a WPA-PSK connection filling the PSK and setting the auth alg + * to 'shared' is rejected when completion is attempted with an open AP. + * Shared auth cannot be used with WPA. + */ + test_ap_wpa_psk_connection_base (NULL, "shared", + NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + FALSE, NULL); +} + +static void +test_open_ap_wpa_psk_connection_5 (void) +{ + /* Test that a WPA-PSK connection filling the PSK, the auth algorithm, and + * key management is rejected when completion is attempted with an open AP. + */ + test_ap_wpa_psk_connection_base ("wpa-psk", "open", + NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + FALSE, NULL); +} + +/*******************************************/ + +static void +test_ap_wpa_eap_connection_base (const char *key_mgmt, + const char *auth_alg, + guint32 flags, + guint32 wpa_flags, + guint32 rsn_flags, + gboolean add_wifi, + guint error_domain, + guint error_code) +{ + NMConnection *src; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_empty[] = { { NULL } }; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + src = nm_connection_new (); + if (add_wifi) + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + fill_8021x (src, src_empty); + success = complete_connection ("blahblah", bssid, NM_802_11_MODE_INFRA, + flags, wpa_flags, rsn_flags, + FALSE, src, &error); + /* Failure expected */ + COMPARE (src, NULL, success, error, error_domain, error_code); + + g_object_unref (src); +} + +enum { + IDX_NONE = 0, + IDX_OPEN, + IDX_PRIV, + IDX_WPA_PSK, + IDX_RSN_PSK, + IDX_WPA_8021X, + IDX_RSN_8021X +}; + +static guint32 +flags_for_idx (guint32 idx) +{ + if (idx == IDX_OPEN) + return NM_802_11_AP_FLAGS_NONE; + else if (idx == IDX_PRIV || idx == IDX_WPA_PSK || idx == IDX_RSN_PSK + || idx == IDX_WPA_8021X || idx == IDX_RSN_8021X) + return NM_802_11_AP_FLAGS_PRIVACY; + else + g_assert_not_reached (); +} + +static guint32 +wpa_flags_for_idx (guint32 idx) +{ + if (idx == IDX_OPEN || idx == IDX_PRIV || idx == IDX_RSN_PSK || idx == IDX_RSN_8021X) + return NM_802_11_AP_SEC_NONE; + else if (idx == IDX_WPA_PSK) + return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_KEY_MGMT_PSK; + else if (idx == IDX_WPA_8021X) + return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_KEY_MGMT_802_1X; + else + g_assert_not_reached (); +} + +static guint32 +rsn_flags_for_idx (guint32 idx) +{ + if (idx == IDX_OPEN || idx == IDX_PRIV || idx == IDX_WPA_PSK || idx == IDX_WPA_8021X) + return NM_802_11_AP_SEC_NONE; + else if (idx == IDX_RSN_PSK) + return NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_CCMP | NM_802_11_AP_SEC_KEY_MGMT_PSK; + else if (idx == IDX_RSN_8021X) + return NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_CCMP | NM_802_11_AP_SEC_KEY_MGMT_802_1X; + else + g_assert_not_reached (); +} + +static guint32 +error_domain_for_idx (guint32 idx, guint num) +{ + if (idx == IDX_OPEN) + return NM_SETTING_WIRELESS_SECURITY_ERROR; + else if (idx == IDX_PRIV) { + if (num <= 3) + return NM_SETTING_802_1X_ERROR; + else + return NM_SETTING_WIRELESS_SECURITY_ERROR; + } else if (idx == IDX_WPA_PSK || idx == IDX_RSN_PSK) + return NM_SETTING_WIRELESS_SECURITY_ERROR; + else + g_assert_not_reached (); +} + +static guint32 +error_code_for_idx (guint32 idx, guint num) +{ + if (idx == IDX_OPEN) + return NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY; + else if (idx == IDX_PRIV) { + if (num <= 3) + return NM_SETTING_802_1X_ERROR_MISSING_PROPERTY; + else + return NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY; + } else if (idx == IDX_WPA_PSK || idx == IDX_RSN_PSK) { + return NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY; + } else + g_assert_not_reached (); +} + +static void +test_ap_wpa_eap_connection_1 (guint32 idx) +{ + test_ap_wpa_eap_connection_base (NULL, NULL, + flags_for_idx (idx), + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, + error_domain_for_idx (idx, 1), + error_code_for_idx (idx, 1)); +} + +static void +test_ap_wpa_eap_connection_2 (guint idx) +{ + test_ap_wpa_eap_connection_base (NULL, NULL, + flags_for_idx (idx), + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + TRUE, + error_domain_for_idx (idx, 2), + error_code_for_idx (idx, 2)); +} + +static void +test_ap_wpa_eap_connection_3 (guint idx) +{ + test_ap_wpa_eap_connection_base (NULL, "open", + flags_for_idx (idx), + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, + error_domain_for_idx (idx, 3), + error_code_for_idx (idx, 3)); +} + +static void +test_ap_wpa_eap_connection_4 (guint idx) +{ + test_ap_wpa_eap_connection_base (NULL, "shared", + flags_for_idx (idx), + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, + error_domain_for_idx (idx, 4), + error_code_for_idx (idx, 4)); +} + +static void +test_ap_wpa_eap_connection_5 (guint idx) +{ + test_ap_wpa_eap_connection_base ("wpa-eap", "open", + flags_for_idx (idx), + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, + error_domain_for_idx (idx, 5), + error_code_for_idx (idx, 5)); +} + +/*******************************************/ + +static void +test_priv_ap_empty_connection (void) +{ + NMConnection *src, *expected; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const char *ssid = "blahblah"; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that an empty connection is completed to a valid Static WEP + * connection when completed with an AP with the Privacy bit set. + */ + + src = nm_connection_new (); + success = complete_connection (ssid, bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + + /* Static WEP connection expected */ + expected = create_basic (ssid, NULL, NM_802_11_MODE_INFRA, TRUE); + fill_wsec (expected, exp_wsec); + COMPARE (src, expected, success, error, 0, 0); + + g_object_unref (src); + g_object_unref (expected); +} + +/*******************************************/ + +static void +test_priv_ap_leap_connection_1 (gboolean add_wifi) +{ + NMConnection *src, *expected; + const char *ssid = "blahblah"; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const char *leap_username = "Bill Smith"; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0 }, + { NULL } }; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0 }, + { NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that an minimal LEAP connection specifying only key management and + * the LEAP username is completed to a full LEAP connection when completed + * with an AP with the Privacy bit set. + */ + + src = nm_connection_new (); + if (add_wifi) + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + success = complete_connection (ssid, bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + /* We expect success here; since LEAP APs just set the 'privacy' flag + * there's no way to determine from the AP's beacon whether it's static WEP, + * dynamic WEP, or LEAP. + */ + expected = create_basic (ssid, NULL, NM_802_11_MODE_INFRA, TRUE); + fill_wsec (expected, exp_wsec); + COMPARE (src, expected, success, error, 0, 0); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_priv_ap_leap_connection_2 (void) +{ + NMConnection *src; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that an minimal LEAP connection specifying only key management and + * the LEAP auth alg is completed to a full LEAP connection when completed + * with an AP with the Privacy bit set. + */ + + src = nm_connection_new (); + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + success = complete_connection ("blahblah", bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + /* We expect failure here, we need a LEAP username */ + COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_priv_ap_dynamic_wep_1 (void) +{ + NMConnection *src, *expected; + const char *ssid = "blahblah"; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NULL } }; + const KeyData both_8021x[] = { + { NM_SETTING_802_1X_EAP, "peap", 0 }, + { NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0 }, + { NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0 }, + { NULL } }; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NM_SETTING_WIRELESS_SECURITY_PAIRWISE, "wep40", 0 }, + { NM_SETTING_WIRELESS_SECURITY_PAIRWISE, "wep104", 0 }, + { NM_SETTING_WIRELESS_SECURITY_GROUP, "wep40", 0 }, + { NM_SETTING_WIRELESS_SECURITY_GROUP, "wep104", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that an minimal Dynamic WEP connection specifying key management, + * the auth algorithm, and valid 802.1x setting is completed to a valid + * Dynamic WEP connection when completed with an AP with the Privacy bit set. + */ + + src = nm_connection_new (); + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + fill_8021x (src, both_8021x); + success = complete_connection (ssid, bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + + /* We expect a completed Dynamic WEP connection */ + expected = create_basic (ssid, NULL, NM_802_11_MODE_INFRA, TRUE); + fill_wsec (expected, exp_wsec); + fill_8021x (expected, both_8021x); + COMPARE (src, expected, success, error, 0, 0); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_priv_ap_dynamic_wep_2 (void) +{ + NMConnection *src, *expected; + const char *ssid = "blahblah"; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NULL } }; + const KeyData both_8021x[] = { + { NM_SETTING_802_1X_EAP, "peap", 0 }, + { NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0 }, + { NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0 }, + { NULL } }; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NM_SETTING_WIRELESS_SECURITY_PAIRWISE, "wep40", 0 }, + { NM_SETTING_WIRELESS_SECURITY_PAIRWISE, "wep104", 0 }, + { NM_SETTING_WIRELESS_SECURITY_GROUP, "wep40", 0 }, + { NM_SETTING_WIRELESS_SECURITY_GROUP, "wep104", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that an minimal Dynamic WEP connection specifying only the auth + * algorithm and a valid 802.1x setting is completed to a valid Dynamic + * WEP connection when completed with an AP with the Privacy bit set. + */ + + src = nm_connection_new (); + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + fill_8021x (src, both_8021x); + success = complete_connection (ssid, bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + + /* We expect a completed Dynamic WEP connection */ + expected = create_basic (ssid, NULL, NM_802_11_MODE_INFRA, TRUE); + fill_wsec (expected, exp_wsec); + fill_8021x (expected, both_8021x); + COMPARE (src, expected, success, error, 0, 0); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_priv_ap_dynamic_wep_3 (void) +{ + NMConnection *src; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", 0 }, + { NULL } }; + const KeyData src_8021x[] = { + { NM_SETTING_802_1X_EAP, "peap", 0 }, + { NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0 }, + { NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Ensure that a basic connection specifying 'shared' auth and an 802.1x + * setting is rejected, as 802.1x is incompatible with 'shared' auth. + */ + + src = nm_connection_new (); + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + fill_8021x (src, src_8021x); + success = complete_connection ("blahblah", bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, + FALSE, + src, &error); + /* Expect failure; shared is not compatible with dynamic WEP */ + COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_priv_ap_wpa_psk_connection_1 (void) +{ + /* Test that a basic WPA-PSK connection is rejected when completion is + * attempted with an AP with just the Privacy bit set. Lack of WPA/RSN + * flags means the AP provides Static/Dynamic WEP or LEAP, not WPA. + */ + test_ap_wpa_psk_connection_base (NULL, NULL, + NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + FALSE, NULL); +} + +static void +test_priv_ap_wpa_psk_connection_2 (void) +{ + /* Test that a basic WPA-PSK connection is rejected when completion is + * attempted with an AP with just the Privacy bit set. Lack of WPA/RSN + * flags means the AP provides Static/Dynamic WEP or LEAP, not WPA. + */ + test_ap_wpa_psk_connection_base (NULL, NULL, + NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + TRUE, NULL); +} + +static void +test_priv_ap_wpa_psk_connection_3 (void) +{ + /* Test that a basic WPA-PSK connection specifying only the auth algorithm + * is rejected when completion is attempted with an AP with just the Privacy + * bit set. Lack of WPA/RSN flags means the AP provides Static/Dynamic WEP + * or LEAP, not WPA. + */ + test_ap_wpa_psk_connection_base (NULL, "open", + NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + FALSE, NULL); +} + +static void +test_priv_ap_wpa_psk_connection_4 (void) +{ + /* Test that a basic WPA-PSK connection specifying only the auth algorithm + * is rejected when completion is attempted with an AP with just the Privacy + * bit set. Lack of WPA/RSN flags means the AP provides Static/Dynamic WEP + * or LEAP, not WPA. Second, 'shared' auth is incompatible with WPA. + */ + test_ap_wpa_psk_connection_base (NULL, "shared", + NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + FALSE, NULL); +} + +static void +test_priv_ap_wpa_psk_connection_5 (void) +{ + /* Test that a WPA-PSK connection specifying both the key management and + * auth algorithm is rejected when completion is attempted with an AP with + * just the Privacy bit set. Lack of WPA/RSN flags means the AP provides + * Static/Dynamic WEP or LEAP, not WPA. + */ + test_ap_wpa_psk_connection_base ("wpa-psk", "open", + NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_SEC_NONE, + NM_802_11_AP_SEC_NONE, + FALSE, NULL); +} + +/*******************************************/ + +static void +test_wpa_ap_empty_connection (guint idx) +{ + NMConnection *src, *expected; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const char *ssid = "blahblah"; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that a basic WPA-PSK connection specifying just key management and + * the auth algorithm is completed successfully when given an AP with WPA + * or RSN flags. + */ + + src = nm_connection_new (); + success = complete_connection (ssid, bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, src, &error); + + /* WPA connection expected */ + expected = create_basic (ssid, NULL, NM_802_11_MODE_INFRA, TRUE); + fill_wsec (expected, exp_wsec); + COMPARE (src, expected, success, error, 0, 0); + + g_object_unref (src); + g_object_unref (expected); +} + +/*******************************************/ + +static void +test_wpa_ap_leap_connection_1 (guint idx) +{ + NMConnection *src; + const char *ssid = "blahblah"; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const char *leap_username = "Bill Smith"; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that completion of a LEAP connection with a WPA-enabled AP is + * rejected since WPA APs (usually) do not support LEAP. + */ + + src = nm_connection_new (); + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + success = complete_connection (ssid, bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, + src, &error); + /* Expect failure here; WPA APs don't support old-school LEAP */ + COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_wpa_ap_leap_connection_2 (guint idx) +{ + NMConnection *src; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that completion of a LEAP connection with a WPA-enabled AP is + * rejected since WPA APs (usually) do not support LEAP. + */ + + src = nm_connection_new (); + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + success = complete_connection ("blahblah", bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, + src, &error); + /* We expect failure here, we need a LEAP username */ + COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_wpa_ap_dynamic_wep_connection (guint idx) +{ + NMConnection *src; + const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + const KeyData src_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0 }, + { NULL } }; + gboolean success; + GError *error = NULL; + + /* Test that completion of a Dynamic WEP connection with a WPA-enabled AP is + * rejected since WPA APs (usually) do not support Dynamic WEP. + */ + + src = nm_connection_new (); + fill_wifi_empty (src); + fill_wsec (src, src_wsec); + success = complete_connection ("blahblah", bssid, + NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, + src, &error); + /* We expect failure here since Dynamic WEP is incompatible with WPA */ + COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY); + + g_object_unref (src); +} + +/*******************************************/ + +static void +test_wpa_ap_wpa_psk_connection_1 (guint idx) +{ + NMConnection *expected; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NULL } }; + + expected = nm_connection_new (); + fill_wsec (expected, exp_wsec); + test_ap_wpa_psk_connection_base (NULL, NULL, + NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, expected); + g_object_unref (expected); +} + +static void +test_wpa_ap_wpa_psk_connection_2 (guint idx) +{ + NMConnection *expected; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NULL } }; + + expected = nm_connection_new (); + fill_wsec (expected, exp_wsec); + test_ap_wpa_psk_connection_base (NULL, NULL, + NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + TRUE, expected); + g_object_unref (expected); +} + +static void +test_wpa_ap_wpa_psk_connection_3 (guint idx) +{ + NMConnection *expected; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NULL } }; + + expected = nm_connection_new (); + fill_wsec (expected, exp_wsec); + test_ap_wpa_psk_connection_base (NULL, "open", + NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, expected); + g_object_unref (expected); +} + +static void +test_wpa_ap_wpa_psk_connection_4 (guint idx) +{ + test_ap_wpa_psk_connection_base (NULL, "shared", + NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, NULL); +} + +static void +test_wpa_ap_wpa_psk_connection_5 (guint idx) +{ + NMConnection *expected; + const KeyData exp_wsec[] = { + { NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0 }, + { NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0 }, + { NULL } }; + + expected = nm_connection_new (); + fill_wsec (expected, exp_wsec); + test_ap_wpa_psk_connection_base ("wpa-psk", "open", + NM_802_11_AP_FLAGS_PRIVACY, + wpa_flags_for_idx (idx), + rsn_flags_for_idx (idx), + FALSE, expected); + g_object_unref (expected); +} + +/*******************************************/ + +#if GLIB_CHECK_VERSION(2,25,12) +typedef GTestFixtureFunc TCFunc; +#else +typedef void (*TCFunc)(void); +#endif + +#define TESTCASE(t, d) g_test_create_case (#t, 0, (gconstpointer) d, NULL, (TCFunc) t, NULL) + +int main (int argc, char **argv) +{ + GTestSuite *suite; + + g_type_init (); + g_test_init (&argc, &argv, NULL); + + suite = g_test_get_root (); + + g_test_suite_add (suite, TESTCASE (test_lock_bssid, NULL)); + + /* Open AP tests; make sure that connections to be completed that have + * various security-related settings already set cause the completion + * to fail. + */ + g_test_suite_add (suite, TESTCASE (test_open_ap_empty_connection, NULL)); + g_test_suite_add (suite, TESTCASE (test_open_ap_leap_connection_1, TRUE)); + g_test_suite_add (suite, TESTCASE (test_open_ap_leap_connection_1, FALSE)); + g_test_suite_add (suite, TESTCASE (test_open_ap_leap_connection_2, NULL)); + g_test_suite_add (suite, TESTCASE (test_open_ap_wep_connection, TRUE)); + g_test_suite_add (suite, TESTCASE (test_open_ap_wep_connection, FALSE)); + + g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_1, NULL)); + g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_2, NULL)); + g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_3, NULL)); + g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_4, NULL)); + g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_5, NULL)); + + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_1, IDX_OPEN)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_2, IDX_OPEN)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_3, IDX_OPEN)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_4, IDX_OPEN)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_5, IDX_OPEN)); + + /* WEP AP tests */ + g_test_suite_add (suite, TESTCASE (test_priv_ap_empty_connection, NULL)); + g_test_suite_add (suite, TESTCASE (test_priv_ap_leap_connection_1, FALSE)); + g_test_suite_add (suite, TESTCASE (test_priv_ap_leap_connection_2, FALSE)); + + g_test_suite_add (suite, TESTCASE (test_priv_ap_dynamic_wep_1, NULL)); + g_test_suite_add (suite, TESTCASE (test_priv_ap_dynamic_wep_2, NULL)); + g_test_suite_add (suite, TESTCASE (test_priv_ap_dynamic_wep_3, NULL)); + + g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_1, NULL)); + g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_2, NULL)); + g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_3, NULL)); + g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_4, NULL)); + g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_5, NULL)); + + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_1, IDX_PRIV)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_2, IDX_PRIV)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_3, IDX_PRIV)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_4, IDX_PRIV)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_5, IDX_PRIV)); + + /* WPA-PSK tests */ + g_test_suite_add (suite, TESTCASE (test_wpa_ap_empty_connection, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_leap_connection_1, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_leap_connection_2, IDX_WPA_PSK)); + + g_test_suite_add (suite, TESTCASE (test_wpa_ap_dynamic_wep_connection, IDX_WPA_PSK)); + + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_1, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_2, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_3, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_4, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_5, IDX_WPA_PSK)); + + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_1, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_2, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_3, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_4, IDX_WPA_PSK)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_5, IDX_WPA_PSK)); + + /* RSN-PSK tests */ + g_test_suite_add (suite, TESTCASE (test_wpa_ap_empty_connection, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_leap_connection_1, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_leap_connection_2, IDX_RSN_PSK)); + + g_test_suite_add (suite, TESTCASE (test_wpa_ap_dynamic_wep_connection, IDX_RSN_PSK)); + + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_1, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_2, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_3, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_4, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_wpa_ap_wpa_psk_connection_5, IDX_RSN_PSK)); + + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_1, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_2, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_3, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_4, IDX_RSN_PSK)); + g_test_suite_add (suite, TESTCASE (test_ap_wpa_eap_connection_5, IDX_RSN_PSK)); + + return g_test_run (); +} + diff --git a/src/vpn-manager/nm-vpn-connection-base.c b/src/vpn-manager/nm-vpn-connection-base.c index 8a6fb2bebf..7fde5db066 100644 --- a/src/vpn-manager/nm-vpn-connection-base.c +++ b/src/vpn-manager/nm-vpn-connection-base.c @@ -43,7 +43,6 @@ typedef struct { enum { PROP_0, - PROP_SERVICE_NAME, PROP_CONNECTION, PROP_SPECIFIC_OBJECT, PROP_DEVICES, @@ -141,9 +140,6 @@ get_property (GObject *object, guint prop_id, NMVpnConnectionBasePrivate *priv = NM_VPN_CONNECTION_BASE_GET_PRIVATE (object); switch (prop_id) { - case PROP_SERVICE_NAME: - nm_active_connection_scope_to_value (priv->connection, value); - break; case PROP_CONNECTION: g_value_set_boxed (value, nm_connection_get_path (priv->connection)); break; @@ -184,7 +180,6 @@ nm_vpn_connection_base_class_init (NMVpnConnectionBaseClass *vpn_class) /* properties */ nm_active_connection_install_properties (object_class, - PROP_SERVICE_NAME, PROP_CONNECTION, PROP_SPECIFIC_OBJECT, PROP_DEVICES, diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 4a07712403..e84c353207 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -30,11 +30,11 @@ #include "NetworkManager.h" #include "NetworkManagerVPN.h" #include "nm-vpn-connection.h" +#include "nm-device-interface.h" #include "nm-setting-connection.h" #include "nm-setting-vpn.h" #include "nm-setting-ip4-config.h" #include "nm-dbus-manager.h" -#include "nm-manager.h" #include "nm-system.h" #include "nm-logging.h" #include "nm-utils.h" @@ -47,21 +47,21 @@ #include "nm-dns-manager.h" #include "nm-netlink-monitor.h" #include "nm-glib-compat.h" +#include "settings/nm-settings-connection.h" #include "nm-vpn-connection-glue.h" -static void secrets_provider_interface_init (NMSecretsProviderInterface *sp_interface_class); - -G_DEFINE_TYPE_EXTENDED (NMVPNConnection, nm_vpn_connection, NM_TYPE_VPN_CONNECTION_BASE, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SECRETS_PROVIDER_INTERFACE, - secrets_provider_interface_init)) +G_DEFINE_TYPE (NMVPNConnection, nm_vpn_connection, NM_TYPE_VPN_CONNECTION_BASE) typedef struct { gboolean disposed; NMConnection *connection; + gboolean user_requested; + gulong user_uid; NMActRequest *act_request; + guint32 secrets_id; NMDevice *parent_dev; gulong device_monitor; @@ -201,7 +201,9 @@ device_ip4_config_changed (NMDevice *device, NMVPNConnection * nm_vpn_connection_new (NMConnection *connection, NMActRequest *act_request, - NMDevice *parent_device) + NMDevice *parent_device, + gboolean user_requested, + gulong user_uid) { NMVPNConnection *self; NMVPNConnectionPrivate *priv; @@ -216,6 +218,8 @@ nm_vpn_connection_new (NMConnection *connection, priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + priv->user_requested = user_requested; + priv->user_uid = user_uid; priv->connection = g_object_ref (connection); priv->parent_dev = g_object_ref (parent_device); priv->act_request = g_object_ref (act_request); @@ -594,6 +598,7 @@ static void really_activate (NMVPNConnection *connection) { NMVPNConnectionPrivate *priv; + GHashTable *hash; g_return_if_fail (NM_IS_VPN_CONNECTION (connection)); g_return_if_fail (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_NEED_AUTH); @@ -610,10 +615,12 @@ really_activate (NMVPNConnection *connection) G_CALLBACK (nm_vpn_connection_ip4_config_get), connection, NULL); + hash = nm_connection_to_hash (priv->connection, NM_SETTING_HASH_FLAG_ALL); org_freedesktop_NetworkManager_VPN_Plugin_connect_async (priv->proxy, - nm_connection_to_hash (priv->connection), - nm_vpn_connection_connect_cb, - connection); + hash, + nm_vpn_connection_connect_cb, + connection); + g_hash_table_destroy (hash); nm_vpn_connection_set_vpn_state (connection, NM_VPN_CONNECTION_STATE_CONNECT, @@ -756,42 +763,31 @@ nm_vpn_connection_disconnect (NMVPNConnection *connection, /******************************************************************************/ -static gboolean -secrets_update_setting (NMSecretsProviderInterface *interface, - const char *setting_name, - GHashTable *new) +static void +cancel_get_secrets (NMVPNConnection *self) { - NMVPNConnection *self = NM_VPN_CONNECTION (interface); NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - GError *error = NULL; - g_return_val_if_fail (priv->connection != NULL, FALSE); - - if (strcmp (setting_name, NM_SETTING_VPN_SETTING_NAME)) - return FALSE; - - if (!nm_connection_update_secrets (priv->connection, NM_SETTING_VPN_SETTING_NAME, new, &error)) { - nm_log_warn (LOGD_VPN, "Failed to update VPN secrets: %d %s", - error ? error->code : -1, - error && error->message ? error->message : "(none)"); - g_clear_error (&error); - return FALSE; + if (priv->secrets_id) { + nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), priv->secrets_id); + priv->secrets_id = 0; } - return TRUE; } static void -secrets_result (NMSecretsProviderInterface *interface, - const char *setting_name, - RequestSecretsCaller caller, - const GSList *updated, - GError *error) +vpn_secrets_cb (NMSettingsConnection *connection, + guint32 call_id, + const char *setting_name, + GError *error, + gpointer user_data) { - NMVPNConnection *self = NM_VPN_CONNECTION (interface); + NMVPNConnection *self = NM_VPN_CONNECTION (user_data); NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (priv->connection != NULL); - g_return_if_fail (caller == SECRETS_CALLER_VPN); + g_return_if_fail (NM_CONNECTION (connection) == priv->connection); + g_return_if_fail (call_id == priv->secrets_id); + + priv->secrets_id = 0; if (error) nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS); @@ -799,14 +795,6 @@ secrets_result (NMSecretsProviderInterface *interface, really_activate (self); } -static void -secrets_provider_interface_init (NMSecretsProviderInterface *sp_interface_class) -{ - /* interface implementation */ - sp_interface_class->update_setting = secrets_update_setting; - sp_interface_class->result = secrets_result; -} - static void connection_need_secrets_cb (DBusGProxy *proxy, char *setting_name, @@ -815,6 +803,7 @@ connection_need_secrets_cb (DBusGProxy *proxy, { NMVPNConnection *self = NM_VPN_CONNECTION (user_data); NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + GError *local = NULL; if (error) { nm_log_err (LOGD_VPN, "NeedSecrets failed: %s %s", @@ -825,35 +814,102 @@ connection_need_secrets_cb (DBusGProxy *proxy, } if (!setting_name || !strlen (setting_name)) { + nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated no additional secrets required", + nm_connection_get_uuid (priv->connection), + nm_connection_get_id (priv->connection)); + /* No secrets required */ really_activate (self); return; } - /* Get the secrets the VPN plugin wants */ - if (!nm_secrets_provider_interface_get_secrets (NM_SECRETS_PROVIDER_INTERFACE (self), - priv->connection, - setting_name, - FALSE, - SECRETS_CALLER_VPN, - NULL, - NULL)) + nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated additional '%s' secrets required", + nm_connection_get_uuid (priv->connection), + nm_connection_get_id (priv->connection), + setting_name); + + priv->secrets_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (priv->connection), + priv->user_requested, + priv->user_uid, + setting_name, + NM_ACT_REQUEST_GET_SECRETS_FLAG_ALLOW_INTERACTION, + NULL, + vpn_secrets_cb, + self, + &local); + if (!priv->secrets_id) { + if (local) + nm_log_err (LOGD_VPN, "failed to get secrets: (%d) %s", local->code, local->message); nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS); + g_clear_error (&local); + } } static void -call_need_secrets (NMVPNConnection *vpn_connection) +existing_secrets_cb (NMSettingsConnection *connection, + guint32 call_id, + const char *setting_name, + GError *error, + gpointer user_data) { - NMVPNConnectionPrivate *priv; - GHashTable *settings; + NMVPNConnection *self = NM_VPN_CONNECTION (user_data); + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + GHashTable *hash; - priv = NM_VPN_CONNECTION_GET_PRIVATE (vpn_connection); - settings = nm_connection_to_hash (priv->connection); - org_freedesktop_NetworkManager_VPN_Plugin_need_secrets_async (priv->proxy, - settings, - connection_need_secrets_cb, - vpn_connection); - g_hash_table_destroy (settings); + g_return_if_fail (NM_CONNECTION (connection) == priv->connection); + g_return_if_fail (call_id == priv->secrets_id); + + priv->secrets_id = 0; + + if (error) { + nm_log_err (LOGD_VPN, "Failed to request existing VPN secrets #2: (%s) %s", + g_quark_to_string (error->domain), + error->message); + nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS); + } else { + nm_log_dbg (LOGD_VPN, "(%s/%s) asking service if additional secrets are required", + nm_connection_get_uuid (priv->connection), + nm_connection_get_id (priv->connection)); + + /* Ask the VPN service if more secrets are required */ + hash = nm_connection_to_hash (priv->connection, NM_SETTING_HASH_FLAG_ALL); + org_freedesktop_NetworkManager_VPN_Plugin_need_secrets_async (priv->proxy, + hash, + connection_need_secrets_cb, + self); + g_hash_table_destroy (hash); + } +} + +static void +get_existing_secrets (NMVPNConnection *self) +{ + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + GError *error = NULL; + + nm_log_dbg (LOGD_VPN, "(%s/%s) requesting existing VPN secrets", + nm_connection_get_uuid (priv->connection), + nm_connection_get_id (priv->connection)); + + /* Just get existing secrets if any so we can ask the VPN service if + * any more are required. + */ + priv->secrets_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (priv->connection), + priv->user_requested, + priv->user_uid, + NM_SETTING_VPN_SETTING_NAME, + NM_ACT_REQUEST_GET_SECRETS_FLAG_NONE, + NULL, + existing_secrets_cb, + self, + &error); + if (priv->secrets_id == 0) { + nm_log_err (LOGD_VPN, "Failed to request existing VPN secrets #1: (%s) %s", + g_quark_to_string (error->domain), + error->message); + g_error_free (error); + nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS); + } } static void @@ -916,17 +972,21 @@ vpn_cleanup (NMVPNConnection *connection) } static void -connection_state_changed (NMVPNConnection *connection, +connection_state_changed (NMVPNConnection *self, NMVPNConnectionState state, NMVPNConnectionStateReason reason) { - NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - nm_secrets_provider_interface_cancel_get_secrets (NM_SECRETS_PROVIDER_INTERFACE (priv->act_request)); + cancel_get_secrets (self); switch (state) { case NM_VPN_CONNECTION_STATE_NEED_AUTH: - call_need_secrets (connection); + get_existing_secrets (self); + break; + case NM_VPN_CONNECTION_STATE_ACTIVATED: + /* Secrets no longer needed now that we're connected */ + nm_connection_clear_secrets (priv->connection); break; case NM_VPN_CONNECTION_STATE_DISCONNECTED: case NM_VPN_CONNECTION_STATE_FAILED: @@ -942,7 +1002,7 @@ connection_state_changed (NMVPNConnection *connection, g_object_unref (priv->proxy); priv->proxy = NULL; } - vpn_cleanup (connection); + vpn_cleanup (self); break; default: break; @@ -986,6 +1046,9 @@ dispose (GObject *object) if (priv->proxy) g_object_unref (priv->proxy); + if (priv->secrets_id) + nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id); + g_object_unref (priv->act_request); g_object_unref (priv->connection); diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index ab880b17f5..fd5ee24e19 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2008 Red Hat, Inc. + * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -27,7 +27,6 @@ #include "NetworkManagerVPN.h" #include "nm-device.h" #include "nm-activation-request.h" -#include "nm-secrets-provider-interface.h" #include "nm-vpn-connection-base.h" #define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ()) @@ -59,7 +58,9 @@ GType nm_vpn_connection_get_type (void); NMVPNConnection * nm_vpn_connection_new (NMConnection *connection, NMActRequest *act_request, - NMDevice *parent_device); + NMDevice *parent_device, + gboolean user_requested, + gulong user_uid); void nm_vpn_connection_activate (NMVPNConnection *connection); NMConnection * nm_vpn_connection_get_connection (NMVPNConnection *connection); diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index 4b58be0d48..aec6f9121b 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -159,6 +159,8 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager, NMConnection *connection, NMActRequest *act_request, NMDevice *device, + gboolean user_requested, + gulong user_uid, GError **error) { NMSettingVPN *vpn_setting; @@ -205,7 +207,7 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager, return NULL; } - vpn = nm_vpn_service_activate (service, connection, act_request, device, error); + vpn = nm_vpn_service_activate (service, connection, act_request, device, user_requested, user_uid, error); if (vpn) { g_signal_connect (vpn, "vpn-state-changed", G_CALLBACK (connection_vpn_state_changed), diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h index f14844a9d4..6159bb86f5 100644 --- a/src/vpn-manager/nm-vpn-manager.h +++ b/src/vpn-manager/nm-vpn-manager.h @@ -71,6 +71,8 @@ NMVPNConnection *nm_vpn_manager_activate_connection (NMVPNManager *manager, NMConnection *connection, NMActRequest *act_request, NMDevice *device, + gboolean user_requested, + gulong user_uid, GError **error); gboolean nm_vpn_manager_deactivate_connection (NMVPNManager *manager, diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c index 3d44d9004b..3b4e2b4817 100644 --- a/src/vpn-manager/nm-vpn-service.c +++ b/src/vpn-manager/nm-vpn-service.c @@ -325,6 +325,8 @@ nm_vpn_service_activate (NMVPNService *service, NMConnection *connection, NMActRequest *act_request, NMDevice *device, + gboolean user_requested, + gulong user_uid, GError **error) { NMVPNConnection *vpn; @@ -341,7 +343,7 @@ nm_vpn_service_activate (NMVPNService *service, clear_quit_timeout (service); - vpn = nm_vpn_connection_new (connection, act_request, device); + vpn = nm_vpn_connection_new (connection, act_request, device, user_requested, user_uid); g_signal_connect (vpn, "vpn-state-changed", G_CALLBACK (connection_vpn_state_changed), service); @@ -415,7 +417,8 @@ nm_vpn_service_init (NMVPNService *self) NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self); priv->dbus_mgr = nm_dbus_manager_get (); - priv->name_owner_id = g_signal_connect (priv->dbus_mgr, "name-owner-changed", + priv->name_owner_id = g_signal_connect (priv->dbus_mgr, + NM_DBUS_MANAGER_NAME_OWNER_CHANGED, G_CALLBACK (nm_vpn_service_name_owner_changed), self); } diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h index c7c1b0366a..0c2445e26d 100644 --- a/src/vpn-manager/nm-vpn-service.h +++ b/src/vpn-manager/nm-vpn-service.h @@ -59,6 +59,8 @@ NMVPNConnection * nm_vpn_service_activate (NMVPNService *service, NMConnection *connection, NMActRequest *act_request, NMDevice *device, + gboolean user_requested, + gulong user_uid, GError **error); GSList * nm_vpn_service_get_active_connections (NMVPNService *service); diff --git a/src/wimax/nm-device-wimax.c b/src/wimax/nm-device-wimax.c index fba108f5be..4b35a1cf45 100644 --- a/src/wimax/nm-device-wimax.c +++ b/src/wimax/nm-device-wimax.c @@ -114,6 +114,7 @@ typedef enum NM_WIMAX_ERROR_CONNECTION_NOT_WIMAX = 0, NM_WIMAX_ERROR_CONNECTION_INVALID, NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE, + NM_WIMAX_ERROR_NSP_NOT_FOUND, } NMWimaxError; #define NM_WIMAX_ERROR (nm_wimax_error_quark ()) @@ -144,6 +145,8 @@ nm_wimax_error_get_type (void) ENUM_ENTRY (NM_WIMAX_ERROR_CONNECTION_INVALID, "ConnectionInvalid"), /* Connection does not apply to this device. */ ENUM_ENTRY (NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"), + /* NSP not found in the scan list. */ + ENUM_ENTRY (NM_WIMAX_ERROR_NSP_NOT_FOUND, "NspNotFound"), { 0, 0, 0 } }; etype = g_enum_register_static ("NMWimaxError", values); @@ -479,6 +482,117 @@ real_check_connection_compatible (NMDevice *device, return TRUE; } +static gboolean +real_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMDeviceWimax *self = NM_DEVICE_WIMAX (device); + NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); + NMSettingWimax *s_wimax; + const GByteArray *setting_mac; + char *format; + const char *nsp_name = NULL; + NMWimaxNsp *nsp = NULL; + GSList *iter; + + s_wimax = (NMSettingWimax *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIMAX); + + if (!specific_object) { + /* If not given a specific object, we need at minimum an NSP name */ + if (!s_wimax) { + g_set_error_literal (error, + NM_WIMAX_ERROR, + NM_WIMAX_ERROR_CONNECTION_INVALID, + "A 'wimax' setting is required if no NSP path was given."); + return FALSE; + } + + nsp_name = nm_setting_wimax_get_network_name (s_wimax); + if (!nsp_name || !strlen (nsp_name)) { + g_set_error_literal (error, + NM_WIMAX_ERROR, + NM_WIMAX_ERROR_CONNECTION_INVALID, + "A 'wimax' setting with a valid network name is required if no NSP path was given."); + return FALSE; + } + + /* Find a compatible NSP in the list */ + nsp = get_nsp_by_name (self, nsp_name); + + /* If we still don't have an NSP, then the WiMAX settings needs to be + * fully specified by the client. Might not be able to find the NSP + * if the scan didn't find the NSP yet. + */ + if (!nsp) { + if (!nm_setting_verify (NM_SETTING (s_wimax), NULL, error)) + return FALSE; + } + } else { + /* Find a compatible NSP in the list */ + for (iter = priv->nsp_list; iter; iter = g_slist_next (iter)) { + if (!strcmp (specific_object, nm_wimax_nsp_get_dbus_path (NM_WIMAX_NSP (iter->data)))) { + nsp = NM_WIMAX_NSP (iter->data); + break; + } + } + + if (!nsp) { + g_set_error (error, + NM_WIMAX_ERROR, + NM_WIMAX_ERROR_NSP_NOT_FOUND, + "The NSP %s was not in the scan list.", + specific_object); + return FALSE; + } + + nsp_name = nm_wimax_nsp_get_name (nsp); + } + + /* Add a WiMAX setting if one doesn't exist */ + if (!s_wimax) { + s_wimax = (NMSettingWimax *) nm_setting_wimax_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wimax)); + } + + g_assert (nsp_name); + format = g_strdup_printf ("%s %%d", nsp_name); + nm_utils_complete_generic (connection, + NM_SETTING_WIMAX_SETTING_NAME, + existing_connections, + format, + nsp_name); + g_free (format); + g_object_set (G_OBJECT (s_wimax), NM_SETTING_WIMAX_NETWORK_NAME, nsp_name, NULL); + + setting_mac = nm_setting_wimax_get_mac_address (s_wimax); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (memcmp (setting_mac->data, &priv->hw_addr.ether_addr_octet, ETH_ALEN)) { + g_set_error (error, + NM_SETTING_WIMAX_ERROR, + NM_SETTING_WIMAX_ERROR_INVALID_PROPERTY, + NM_SETTING_WIMAX_MAC_ADDRESS); + return FALSE; + } + } else { + GByteArray *mac; + const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + /* Lock the connection to this device by default */ + if (memcmp (&priv->hw_addr.ether_addr_octet, null_mac, ETH_ALEN)) { + mac = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (mac, priv->hw_addr.ether_addr_octet, ETH_ALEN); + g_object_set (G_OBJECT (s_wimax), NM_SETTING_WIMAX_MAC_ADDRESS, mac, NULL); + g_byte_array_free (mac, TRUE); + } + } + + return TRUE; +} + static NMConnection * real_get_best_auto_connection (NMDevice *device, GSList *connections, @@ -1349,6 +1463,7 @@ nm_device_wimax_class_init (NMDeviceWimaxClass *klass) device_class->hw_take_down = real_hw_take_down; device_class->update_hw_address = real_update_hw_address; device_class->check_connection_compatible = real_check_connection_compatible; + device_class->complete_connection = real_complete_connection; device_class->get_best_auto_connection = real_get_best_auto_connection; device_class->get_generic_capabilities = real_get_generic_capabilities; device_class->is_available = real_is_available; diff --git a/system-settings/plugins/ifcfg-rh/Makefile.am b/system-settings/plugins/ifcfg-rh/Makefile.am index 54d686bb48..9874d352ba 100644 --- a/system-settings/plugins/ifcfg-rh/Makefile.am +++ b/system-settings/plugins/ifcfg-rh/Makefile.am @@ -23,7 +23,7 @@ libifcfg_rh_io_la_SOURCES = \ utils.h INCLUDES = \ - -I$(top_srcdir)/src/system-settings \ + -I$(top_srcdir)/src/settings \ -I$(top_srcdir)/include \ -I$(top_srcdir)/libnm-glib \ -I$(top_srcdir)/libnm-util \ diff --git a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c index 52ce6e152d..52c172dae4 100644 --- a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c +++ b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 - 2009 Red Hat, Inc. + * Copyright (C) 2008 - 2010 Red Hat, Inc. */ #include @@ -33,7 +33,6 @@ #include #include #include -#include #include "common.h" #include "nm-ifcfg-connection.h" @@ -41,20 +40,14 @@ #include "writer.h" #include "nm-inotify-helper.h" -static NMSettingsConnectionInterface *parent_settings_connection_iface; - -static void settings_connection_interface_init (NMSettingsConnectionInterface *klass); - -G_DEFINE_TYPE_EXTENDED (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_SYSCONFIG_CONNECTION, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE, - settings_connection_interface_init)) +G_DEFINE_TYPE (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_SETTINGS_CONNECTION) #define NM_IFCFG_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionPrivate)) typedef struct { gulong ih_event_id; - char *filename; + char *path; int file_wd; char *keyfile; @@ -66,16 +59,12 @@ typedef struct { char *route6file; int route6file_wd; - char *udi; char *unmanaged; } NMIfcfgConnectionPrivate; enum { PROP_0, - PROP_FILENAME, PROP_UNMANAGED, - PROP_UDI, - LAST_PROP }; @@ -96,7 +85,10 @@ files_changed_cb (NMInotifyHelper *ih, NMIfcfgConnection *self = NM_IFCFG_CONNECTION (user_data); NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); - if ((evt->wd != priv->file_wd) && (evt->wd != priv->keyfile_wd) && (evt->wd != priv->routefile_wd) && (evt->wd != priv->route6file_wd)) + if ( (evt->wd != priv->file_wd) + && (evt->wd != priv->keyfile_wd) + && (evt->wd != priv->routefile_wd) + && (evt->wd != priv->route6file_wd)) return; /* push the event up to the plugin */ @@ -104,7 +96,8 @@ files_changed_cb (NMInotifyHelper *ih, } NMIfcfgConnection * -nm_ifcfg_connection_new (const char *filename, +nm_ifcfg_connection_new (const char *full_path, + NMConnection *source, GError **error, gboolean *ignore_error) { @@ -117,31 +110,43 @@ nm_ifcfg_connection_new (const char *filename, char *route6file = NULL; NMInotifyHelper *ih; - g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (full_path != NULL, NULL); - tmp = connection_from_file (filename, NULL, NULL, NULL, &unmanaged, &keyfile, &routefile, &route6file, error, ignore_error); - if (!tmp) - return NULL; - - object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION, - NM_IFCFG_CONNECTION_FILENAME, filename, - NM_IFCFG_CONNECTION_UNMANAGED, unmanaged, - NULL); - if (!object) { - g_object_unref (tmp); - return NULL; + /* If we're given a connection already, prefer that instead of re-reading */ + if (source) + tmp = g_object_ref (source); + else { + tmp = connection_from_file (full_path, NULL, NULL, NULL, + &unmanaged, + &keyfile, + &routefile, + &route6file, + error, + ignore_error); + if (!tmp) + return NULL; } + object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION, + NM_IFCFG_CONNECTION_UNMANAGED, unmanaged, + NULL); + if (!object) + goto out; + /* Update our settings with what was read from the file */ - nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (object), tmp, FALSE, NULL); - g_object_unref (tmp); + if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, error)) { + g_object_unref (object); + object = NULL; + goto out; + } priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object); + priv->path = g_strdup (full_path); ih = nm_inotify_helper_get (); priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (files_changed_cb), object); - priv->file_wd = nm_inotify_helper_add_watch (ih, filename); + priv->file_wd = nm_inotify_helper_add_watch (ih, full_path); priv->keyfile = keyfile; priv->keyfile_wd = nm_inotify_helper_add_watch (ih, keyfile); @@ -152,15 +157,17 @@ nm_ifcfg_connection_new (const char *filename, priv->route6file = route6file; priv->route6file_wd = nm_inotify_helper_add_watch (ih, route6file); - return NM_IFCFG_CONNECTION (object); +out: + g_object_unref (tmp); + return (NMIfcfgConnection *) object; } const char * -nm_ifcfg_connection_get_filename (NMIfcfgConnection *self) +nm_ifcfg_connection_get_path (NMIfcfgConnection *self) { g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL); - return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->filename; + return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->path; } const char * @@ -171,10 +178,10 @@ nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self) return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unmanaged; } -static gboolean -update (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceUpdateFunc callback, - gpointer user_data) +static void +commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitFunc callback, + gpointer user_data) { NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection); GError *error = NULL; @@ -185,7 +192,7 @@ update (NMSettingsConnectionInterface *connection, * processes on-disk, read the existing connection back in and only rewrite * it if it's really changed. */ - reread = connection_from_file (priv->filename, NULL, NULL, NULL, + reread = connection_from_file (priv->path, NULL, NULL, NULL, &unmanaged, &keyfile, &routefile, &route6file, NULL, NULL); g_free (unmanaged); @@ -200,28 +207,28 @@ update (NMSettingsConnectionInterface *connection, if (!writer_update_connection (NM_CONNECTION (connection), IFCFG_DIR, - priv->filename, + priv->path, priv->keyfile, &error)) { callback (connection, error, user_data); g_error_free (error); - return FALSE; + return; } out: if (reread) g_object_unref (reread); - return parent_settings_connection_iface->update (connection, callback, user_data); + NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data); } -static gboolean -do_delete (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceDeleteFunc callback, +static void +do_delete (NMSettingsConnection *connection, + NMSettingsConnectionDeleteFunc callback, gpointer user_data) { NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection); - g_unlink (priv->filename); + g_unlink (priv->path); if (priv->keyfile) g_unlink (priv->keyfile); if (priv->routefile) @@ -230,19 +237,11 @@ do_delete (NMSettingsConnectionInterface *connection, if (priv->route6file) g_unlink (priv->route6file); - return parent_settings_connection_iface->delete (connection, callback, user_data); + NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->delete (connection, callback, user_data); } /* GObject */ -static void -settings_connection_interface_init (NMSettingsConnectionInterface *iface) -{ - parent_settings_connection_iface = g_type_interface_peek_parent (iface); - iface->update = update; - iface->delete = do_delete; -} - static void nm_ifcfg_connection_init (NMIfcfgConnection *connection) { @@ -254,15 +253,14 @@ finalize (GObject *object) NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object); NMInotifyHelper *ih; - g_free (priv->udi); - nm_connection_clear_secrets (NM_CONNECTION (object)); ih = nm_inotify_helper_get (); - g_signal_handler_disconnect (ih, priv->ih_event_id); + if (priv->ih_event_id) + g_signal_handler_disconnect (ih, priv->ih_event_id); - g_free (priv->filename); + g_free (priv->path); if (priv->file_wd >= 0) nm_inotify_helper_remove_watch (ih, priv->file_wd); @@ -288,17 +286,9 @@ set_property (GObject *object, guint prop_id, NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object); switch (prop_id) { - case PROP_FILENAME: - /* Construct only */ - priv->filename = g_value_dup_string (value); - break; case PROP_UNMANAGED: priv->unmanaged = g_value_dup_string (value); break; - case PROP_UDI: - /* Construct only */ - priv->udi = g_value_dup_string (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -312,15 +302,9 @@ get_property (GObject *object, guint prop_id, NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object); switch (prop_id) { - case PROP_FILENAME: - g_value_set_string (value, priv->filename); - break; case PROP_UNMANAGED: g_value_set_string (value, priv->unmanaged); break; - case PROP_UDI: - g_value_set_string (value, priv->udi); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -331,6 +315,7 @@ static void nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class) { GObjectClass *object_class = G_OBJECT_CLASS (ifcfg_connection_class); + NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (ifcfg_connection_class); g_type_class_add_private (ifcfg_connection_class, sizeof (NMIfcfgConnectionPrivate)); @@ -338,16 +323,10 @@ nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class) object_class->set_property = set_property; object_class->get_property = get_property; object_class->finalize = finalize; + settings_class->delete = do_delete; + settings_class->commit_changes = commit_changes; /* Properties */ - g_object_class_install_property - (object_class, PROP_FILENAME, - g_param_spec_string (NM_IFCFG_CONNECTION_FILENAME, - "FileName", - "File name", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, PROP_UNMANAGED, g_param_spec_string (NM_IFCFG_CONNECTION_UNMANAGED, @@ -356,14 +335,6 @@ nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class) NULL, G_PARAM_READWRITE)); - g_object_class_install_property - (object_class, PROP_UDI, - g_param_spec_string (NM_IFCFG_CONNECTION_UDI, - "UDI", - "UDI", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - signals[IFCFG_CHANGED] = g_signal_new ("ifcfg-changed", G_OBJECT_CLASS_TYPE (object_class), diff --git a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.h b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.h index 5cac5d9c8a..731aa598c3 100644 --- a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.h +++ b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. */ #ifndef NM_IFCFG_CONNECTION_H @@ -24,7 +24,7 @@ G_BEGIN_DECLS #include -#include +#include #define NM_TYPE_IFCFG_CONNECTION (nm_ifcfg_connection_get_type ()) #define NM_IFCFG_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnection)) @@ -33,25 +33,24 @@ G_BEGIN_DECLS #define NM_IS_IFCFG_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_IFCFG_CONNECTION)) #define NM_IFCFG_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionClass)) -#define NM_IFCFG_CONNECTION_FILENAME "filename" #define NM_IFCFG_CONNECTION_UNMANAGED "unmanaged" -#define NM_IFCFG_CONNECTION_UDI "udi" typedef struct { - NMSysconfigConnection parent; + NMSettingsConnection parent; } NMIfcfgConnection; typedef struct { - NMSysconfigConnectionClass parent; + NMSettingsConnectionClass parent; } NMIfcfgConnectionClass; GType nm_ifcfg_connection_get_type (void); NMIfcfgConnection *nm_ifcfg_connection_new (const char *filename, + NMConnection *source, GError **error, gboolean *ignore_error); -const char *nm_ifcfg_connection_get_filename (NMIfcfgConnection *self); +const char *nm_ifcfg_connection_get_path (NMIfcfgConnection *self); const char *nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self); diff --git a/system-settings/plugins/ifcfg-rh/plugin.c b/system-settings/plugins/ifcfg-rh/plugin.c index 8dce0334a5..3e2e034628 100644 --- a/system-settings/plugins/ifcfg-rh/plugin.c +++ b/system-settings/plugins/ifcfg-rh/plugin.c @@ -18,7 +18,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2011 Red Hat, Inc. */ #include @@ -38,12 +38,13 @@ #include #include -#include #include "common.h" #include "nm-dbus-glib-types.h" #include "plugin.h" #include "nm-system-config-interface.h" +#include "nm-settings-error.h" + #include "nm-ifcfg-connection.h" #include "nm-inotify-helper.h" #include "shvar.h" @@ -61,20 +62,12 @@ static gboolean impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, #include "nm-ifcfg-rh-glue.h" +static void connection_new_or_changed (SCPluginIfcfg *plugin, + const char *path, + NMIfcfgConnection *existing); + static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); -static void connection_changed_handler (SCPluginIfcfg *plugin, - const char *path, - NMIfcfgConnection *connection, - gboolean *do_remove, - gboolean *do_new); - -static void handle_connection_remove_or_new (SCPluginIfcfg *plugin, - const char *path, - NMIfcfgConnection *connection, - gboolean do_remove, - gboolean do_new); - G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, system_config_interface_init)) @@ -108,64 +101,66 @@ static void connection_ifcfg_changed (NMIfcfgConnection *connection, gpointer user_data) { SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); - gboolean do_remove = FALSE, do_new = FALSE; const char *path; - path = nm_ifcfg_connection_get_filename (connection); + path = nm_ifcfg_connection_get_path (connection); g_return_if_fail (path != NULL); - connection_changed_handler (plugin, path, connection, &do_remove, &do_new); - handle_connection_remove_or_new (plugin, path, connection, do_remove, do_new); + connection_new_or_changed (plugin, path, connection); } static NMIfcfgConnection * -read_one_connection (SCPluginIfcfg *plugin, const char *filename) +_internal_new_connection (SCPluginIfcfg *self, + const char *path, + NMConnection *source, + GError **error) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); NMIfcfgConnection *connection; - GError *error = NULL; + NMSettingConnection *s_con; + const char *cid; + GError *local = NULL; gboolean ignore_error = FALSE; - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "parsing %s ... ", filename); + if (!source) { + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "parsing %s ... ", path); + } - connection = nm_ifcfg_connection_new (filename, &error, &ignore_error); - if (connection) { - NMSettingConnection *s_con; - const char *cid; - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); - g_assert (s_con); - - cid = nm_setting_connection_get_id (s_con); - g_assert (cid); - - g_hash_table_insert (priv->connections, - (gpointer) nm_ifcfg_connection_get_filename (connection), - g_object_ref (connection)); - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " read connection '%s'", cid); - - if (nm_ifcfg_connection_get_unmanaged_spec (connection)) { - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its " - "device due to NM_CONTROLLED/BRIDGE/VLAN.", cid); - } else { - /* Wait for the connection to become unmanaged once it knows the - * UDI of it's device, if/when the device gets plugged in. - */ - g_signal_connect (G_OBJECT (connection), "notify::unmanaged", - G_CALLBACK (connection_unmanaged_changed), plugin); - } - - /* watch changes of ifcfg hardlinks */ - g_signal_connect (G_OBJECT (connection), "ifcfg-changed", - G_CALLBACK (connection_ifcfg_changed), plugin); - } else { + connection = nm_ifcfg_connection_new (path, source, &local, &ignore_error); + if (!connection) { if (!ignore_error) { PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " error: %s", - (error && error->message) ? error->message : "(unknown)"); + (local && local->message) ? local->message : "(unknown)"); } - g_clear_error (&error); + g_propagate_error (error, local); + return NULL; } + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + cid = nm_setting_connection_get_id (s_con); + g_assert (cid); + + g_hash_table_insert (priv->connections, + (gpointer) nm_ifcfg_connection_get_path (connection), + connection); + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " read connection '%s'", cid); + + if (nm_ifcfg_connection_get_unmanaged_spec (connection)) { + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its " + "device due to NM_CONTROLLED/BRIDGE/VLAN.", cid); + } else { + /* Wait for the connection to become unmanaged once it knows the + * hardware IDs of its device, if/when the device gets plugged in. + */ + g_signal_connect (G_OBJECT (connection), "notify::" NM_IFCFG_CONNECTION_UNMANAGED, + G_CALLBACK (connection_unmanaged_changed), self); + } + + /* watch changes of ifcfg hardlinks */ + g_signal_connect (G_OBJECT (connection), "ifcfg-changed", + G_CALLBACK (connection_ifcfg_changed), self); + return connection; } @@ -186,7 +181,8 @@ read_connections (SCPluginIfcfg *plugin) continue; full_path = g_build_filename (IFCFG_DIR, item, NULL); - read_one_connection (plugin, full_path); + if (utils_get_ifcfg_name (full_path, TRUE)) + _internal_new_connection (plugin, full_path, NULL, NULL); g_free (full_path); } @@ -199,25 +195,71 @@ read_connections (SCPluginIfcfg *plugin) /* Monitoring */ +/* Callback for nm_settings_connection_replace_and_commit. Report any errors + * encountered when commiting connection settings updates. */ static void -connection_changed_handler (SCPluginIfcfg *plugin, - const char *path, - NMIfcfgConnection *connection, - gboolean *do_remove, - gboolean *do_new) +commit_cb (NMSettingsConnection *connection, GError *error, gpointer unused) +{ + if (error) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error updating: %s", + (error && error->message) ? error->message : "(unknown)"); + } +} + +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 void +connection_new_or_changed (SCPluginIfcfg *self, + const char *path, + NMIfcfgConnection *existing) { NMIfcfgConnection *new; GError *error = NULL; gboolean ignore_error = FALSE; const char *new_unmanaged = NULL, *old_unmanaged = NULL; - g_return_if_fail (plugin != NULL); + g_return_if_fail (self != NULL); g_return_if_fail (path != NULL); - g_return_if_fail (connection != NULL); - g_return_if_fail (do_remove != NULL); - g_return_if_fail (do_new != NULL); - new = (NMIfcfgConnection *) nm_ifcfg_connection_new (path, &error, &ignore_error); + if (!existing) { + /* Completely new connection */ + new = _internal_new_connection (self, path, NULL, NULL); + if (new) { + if (nm_ifcfg_connection_get_unmanaged_spec (new)) { + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + } else { + /* Only managed connections are announced to the settings service */ + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new); + } + } + return; + } + + /* Existing connection that got changed */ + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "updating %s", path); + + new = (NMIfcfgConnection *) nm_ifcfg_connection_new (path, NULL, &error, &ignore_error); if (!new) { /* errors reading connection; remove it */ if (!ignore_error) { @@ -227,15 +269,14 @@ connection_changed_handler (SCPluginIfcfg *plugin, g_clear_error (&error); PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", path); - *do_remove = TRUE; + remove_connection (self, existing); return; } - /* Successfully read connection changes */ /* When the connections are the same, nothing is done */ - if (nm_connection_compare (NM_CONNECTION (connection), + if (nm_connection_compare (NM_CONNECTION (existing), NM_CONNECTION (new), NM_SETTING_COMPARE_FLAG_EXACT)) { g_object_unref (new); @@ -244,13 +285,17 @@ connection_changed_handler (SCPluginIfcfg *plugin, PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "updating %s", path); - old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (connection)); + old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (existing)); new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (new)); if (new_unmanaged) { if (!old_unmanaged) { - /* Unexport the connection by destroying it, then re-creating it as unmanaged */ - *do_remove = *do_new = TRUE; + /* Unexport the connection by telling the settings service it's + * been removed, and notify the settings service by signalling that + * unmanaged specs have changed. + */ + nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (existing)); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); } } else { if (old_unmanaged) { /* now managed */ @@ -259,67 +304,25 @@ connection_changed_handler (SCPluginIfcfg *plugin, s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (new), NM_TYPE_SETTING_CONNECTION); g_assert (s_con); - cid = nm_setting_connection_get_id (s_con); g_assert (cid); PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Managing connection '%s' and its " "device because NM_CONTROLLED was true.", cid); - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, existing); } - if (!nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (connection), - NM_CONNECTION (new), - TRUE, - &error)) { - PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error updating: %s", - (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - } + nm_settings_connection_replace_and_commit (NM_SETTINGS_CONNECTION (existing), + NM_CONNECTION (new), + commit_cb, NULL); /* Update unmanaged status */ - g_object_set (connection, "unmanaged", new_unmanaged, NULL); - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_object_set (existing, NM_IFCFG_CONNECTION_UNMANAGED, new_unmanaged, NULL); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); } g_object_unref (new); } -static void -handle_connection_remove_or_new (SCPluginIfcfg *plugin, - const char *path, - NMIfcfgConnection *connection, - gboolean do_remove, - gboolean do_new) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); - - g_return_if_fail (plugin != NULL); - g_return_if_fail (path != NULL); - - if (do_remove) { - const char *unmanaged; - - g_return_if_fail (connection != NULL); - - unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection); - g_hash_table_remove (priv->connections, path); - g_signal_emit_by_name (connection, "removed"); - - /* Emit unmanaged changes _after_ removing the connection */ - if (unmanaged) - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); - } - - if (do_new) { - connection = read_one_connection (plugin, path); - if (connection) { - if (nm_ifcfg_connection_get_unmanaged_spec (connection)) - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); - else - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection); - } - } -} static void dir_changed (GFileMonitor *monitor, GFile *file, @@ -331,7 +334,6 @@ dir_changed (GFileMonitor *monitor, SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); char *path, *name; NMIfcfgConnection *connection; - gboolean do_remove = FALSE, do_new = FALSE; path = g_file_get_path (file); if (utils_should_ignore_file (path, FALSE)) { @@ -342,29 +344,24 @@ dir_changed (GFileMonitor *monitor, /* Given any ifcfg, keys, or routes file, get the ifcfg file path */ name = utils_get_ifcfg_path (path); g_free (path); - - connection = g_hash_table_lookup (priv->connections, name); - switch (event_type) { - case G_FILE_MONITOR_EVENT_DELETED: - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", name); - if (connection) - handle_connection_remove_or_new (plugin, name, connection, TRUE, FALSE); - break; - case G_FILE_MONITOR_EVENT_CREATED: - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - /* Update */ - if (!connection) - do_new = TRUE; - else - connection_changed_handler (plugin, name, connection, &do_remove, &do_new); - - handle_connection_remove_or_new (plugin, name, connection, do_remove, do_new); - break; - default: - break; + if (name) { + connection = g_hash_table_lookup (priv->connections, name); + switch (event_type) { + case G_FILE_MONITOR_EVENT_DELETED: + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", name); + if (connection) + remove_connection (plugin, connection); + break; + case G_FILE_MONITOR_EVENT_CREATED: + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + /* Update or new */ + connection_new_or_changed (plugin, name, connection); + break; + default: + break; + } + g_free (name); } - - g_free (name); } static void @@ -448,12 +445,21 @@ get_unmanaged_specs (NMSystemConfigInterface *config) return list; } -static gboolean +static NMSettingsConnection * add_connection (NMSystemConfigInterface *config, NMConnection *connection, GError **error) { - return writer_new_connection (connection, IFCFG_DIR, NULL, error); + SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config); + NMIfcfgConnection *added = NULL; + char *path = NULL; + + /* Write it out first, then add the connection to our internal list */ + if (writer_new_connection (connection, IFCFG_DIR, &path, error)) { + added = _internal_new_connection (self, path, connection, error); + g_free (path); + } + return (NMSettingsConnection *) added; } #define SC_NETWORK_FILE SYSCONFDIR"/sysconfig/network" @@ -547,8 +553,8 @@ impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, if (!g_path_is_absolute (in_ifcfg)) { g_set_error (error, - NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, "ifcfg path '%s' is not absolute", in_ifcfg); return FALSE; } @@ -556,8 +562,8 @@ impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, connection = g_hash_table_lookup (priv->connections, in_ifcfg); if (!connection || nm_ifcfg_connection_get_unmanaged_spec (connection)) { g_set_error (error, - NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, "ifcfg file '%s' unknown", in_ifcfg); return FALSE; } @@ -565,8 +571,8 @@ impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); if (!s_con) { g_set_error (error, - NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INTERNAL_ERROR, "unable to retrieve the connection setting"); return FALSE; } @@ -574,8 +580,8 @@ impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, uuid = nm_setting_connection_get_uuid (s_con); if (!uuid) { g_set_error (error, - NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INTERNAL_ERROR, "unable to get the UUID"); return FALSE; } @@ -583,8 +589,8 @@ impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, path = nm_connection_get_path (NM_CONNECTION (connection)); if (!path) { g_set_error (error, - NM_SETTINGS_INTERFACE_ERROR, - NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INTERNAL_ERROR, "unable to get the connection D-Bus path"); return FALSE; } diff --git a/system-settings/plugins/ifcfg-rh/reader.c b/system-settings/plugins/ifcfg-rh/reader.c index f1a170f50c..7ac5e0c945 100644 --- a/system-settings/plugins/ifcfg-rh/reader.c +++ b/system-settings/plugins/ifcfg-rh/reader.c @@ -182,6 +182,20 @@ make_connection_setting (const char *file, g_free (value); } + value = svGetValue (ifcfg, "USERS", FALSE); + if (value) { + char **items, **iter; + + items = g_strsplit_set (value, " ", -1); + for (iter = items; iter && *iter; iter++) { + if (strlen (*iter)) { + if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL)) + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid USERS item '%s'", *iter); + } + } + g_free (value); + } + return NM_SETTING (s_con); } @@ -1729,6 +1743,7 @@ make_wep_setting (shvarFile *ifcfg, char *value; shvarFile *keys_ifcfg = NULL; int default_key_idx = 0; + gboolean has_default_key = FALSE; s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL); @@ -1739,6 +1754,7 @@ make_wep_setting (shvarFile *ifcfg, success = get_int (value, &default_key_idx); if (success && (default_key_idx >= 1) && (default_key_idx <= 4)) { + has_default_key = TRUE; default_key_idx--; /* convert to [0...3] */ g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, default_key_idx, NULL); } else { @@ -1765,21 +1781,6 @@ make_wep_setting (shvarFile *ifcfg, g_assert (error == NULL || *error == NULL); } - /* If there's a default key, ensure that key exists */ - if ((default_key_idx == 1) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)) { - g_set_error (error, IFCFG_PLUGIN_ERROR, 0, - "Default WEP key index was 2, but no valid KEY2 exists."); - goto error; - } else if ((default_key_idx == 2) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2)) { - g_set_error (error, IFCFG_PLUGIN_ERROR, 0, - "Default WEP key index was 3, but no valid KEY3 exists."); - goto error; - } else if ((default_key_idx == 3) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3)) { - g_set_error (error, IFCFG_PLUGIN_ERROR, 0, - "Default WEP key index was 4, but no valid KEY4 exists."); - goto error; - } - value = svGetValue (ifcfg, "SECURITYMODE", FALSE); if (value) { char *lcase; @@ -1805,7 +1806,7 @@ make_wep_setting (shvarFile *ifcfg, && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3) - && !nm_setting_wireless_security_get_wep_tx_keyidx (s_wireless_sec)) { + && (has_default_key == FALSE)) { const char *auth_alg; auth_alg = nm_setting_wireless_security_get_auth_alg (s_wireless_sec); @@ -1923,11 +1924,8 @@ parse_wpa_psk (shvarFile *ifcfg, if (!psk) psk = svGetValue (ifcfg, "WPA_PSK", TRUE); - if (!psk) { - g_set_error (error, IFCFG_PLUGIN_ERROR, 0, - "Missing WPA_PSK for WPA-PSK key management"); + if (!psk) return NULL; - } p = psk; @@ -2544,10 +2542,10 @@ make_wpa_setting (shvarFile *ifcfg, if (!strcmp (value, "WPA-PSK")) { psk = parse_wpa_psk (ifcfg, file, ssid, error); - if (!psk) - goto error; - g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL); - g_free (psk); + if (psk) { + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL); + g_free (psk); + } if (adhoc) g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL); diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am index 28cfb98f3f..a2caf8793e 100644 --- a/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am @@ -69,7 +69,9 @@ EXTRA_DIST = \ ifcfg-test-wired-qeth-static \ ifcfg-test-bridge-main \ ifcfg-test-bridge-component \ - ifcfg-test-vlan-interface + ifcfg-test-vlan-interface \ + ifcfg-test-wifi-wep-no-keys \ + ifcfg-test-permissions check-local: @for f in $(EXTRA_DIST); do \ diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-permissions b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-permissions new file mode 100644 index 0000000000..5b413aa977 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-permissions @@ -0,0 +1,8 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=dhcp +ONBOOT=yes +USERS="dcbw ssmith johnny5" + diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wep-no-keys b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wep-no-keys new file mode 100644 index 0000000000..cb4da43f77 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wep-no-keys @@ -0,0 +1,18 @@ +ESSID="foobar" +MODE=Managed +TYPE=Wireless +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=yes +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +UUID=9c4637bd-7600-40cc-9c24-13819c5bf5dd +ONBOOT=yes +HWADDR=00:16:BB:AA:CC:DD +DEFAULTKEY=1 +PEERDNS=yes +PEERROUTES=yes +IPV6_PEERDNS=yes +IPV6_PEERROUTES=yes diff --git a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 1945fb99cd..49a07c2338 100644 --- a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -5621,6 +5621,199 @@ test_read_wired_qeth_static (void) g_object_unref (connection); } +#define TEST_IFCFG_WIFI_WEP_NO_KEYS TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-wep-no-keys" + +static void +test_read_wifi_wep_no_keys (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWireless *s_wireless; + NMSettingWirelessSecurity *s_wsec; + char *unmanaged = NULL; + char *keyfile = NULL; + char *routefile = NULL; + char *route6file = NULL; + gboolean ignore_error = FALSE; + GError *error = NULL; + const char *tmp; + const char *expected_id = "System foobar (test-wifi-wep-no-keys)"; + NMWepKeyType key_type; + + connection = connection_from_file (TEST_IFCFG_WIFI_WEP_NO_KEYS, + NULL, + TYPE_WIRELESS, + NULL, + &unmanaged, + &keyfile, + &routefile, + &route6file, + &error, + &ignore_error); + ASSERT (connection != NULL, + "wifi-wep-no-keys-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WEP_NO_KEYS, error->message); + + ASSERT (nm_connection_verify (connection, &error), + "wifi-wep-no-keys-verify", "failed to verify %s: %s", TEST_IFCFG_WIFI_WEP_NO_KEYS, error->message); + + /* ===== CONNECTION SETTING ===== */ + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + ASSERT (s_con != NULL, + "wifi-wep-no-keys-verify-connection", "failed to verify %s: missing %s setting", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_CONNECTION_SETTING_NAME); + + /* ID */ + tmp = nm_setting_connection_get_id (s_con); + ASSERT (tmp != NULL, + "wifi-wep-no-keys-verify-connection", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + ASSERT (strcmp (tmp, expected_id) == 0, + "wifi-wep-no-keys-verify-connection", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + + /* UUID can't be tested if the ifcfg does not contain the UUID key, because + * the UUID is generated on the full path of the ifcfg file, which can change + * depending on where the tests are run. + */ + + /* ===== WIRELESS SETTING ===== */ + + s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS)); + ASSERT (s_wireless != NULL, + "wifi-wep-no-keys-verify-wireless", "failed to verify %s: missing %s setting", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_WIRELESS_SETTING_NAME); + + /* Security */ + tmp = nm_setting_wireless_get_security (s_wireless); + ASSERT (tmp != NULL, + "wifi-wep-no-keys-verify-wireless", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_SEC); + ASSERT (strcmp (tmp, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0, + "wifi-wep-no-keys-verify-wireless", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_SEC); + + + /* ===== WIRELESS SECURITY SETTING ===== */ + + s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY)); + ASSERT (s_wsec != NULL, + "wifi-wep-no-keys-verify-wireless", "failed to verify %s: missing %s setting", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); + + /* Key management */ + ASSERT (strcmp (nm_setting_wireless_security_get_key_mgmt (s_wsec), "none") == 0, + "wifi-wep-no-keys-verify-wireless", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); + + /* WEP key index */ + ASSERT (nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec) == 0, + "wifi-wep-no-keys-verify-wireless", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX); + + /* WEP key type */ + key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec); + ASSERT (key_type == NM_WEP_KEY_TYPE_UNKNOWN || key_type == NM_WEP_KEY_TYPE_KEY, + "wifi-wep-no-keys-verify-wireless", "failed to verify %s: unexpected WEP key type %d", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + key_type); + + /* WEP key index 0; we don't expect it to be filled */ + tmp = nm_setting_wireless_security_get_wep_key (s_wsec, 0); + ASSERT (tmp == NULL, + "wifi-wep-no-keys-verify-wireless", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_WIFI_WEP_NO_KEYS, + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY0); + + g_object_unref (connection); +} + +#define TEST_IFCFG_PERMISSIONS TEST_IFCFG_DIR"/network-scripts/ifcfg-test-permissions" + +static void +test_read_permissions (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + char *unmanaged = NULL; + char *keyfile = NULL; + char *routefile = NULL; + char *route6file = NULL; + gboolean ignore_error = FALSE, success; + GError *error = NULL; + guint32 num; + const char *tmp; + + connection = connection_from_file (TEST_IFCFG_PERMISSIONS, + NULL, + TYPE_ETHERNET, + NULL, + &unmanaged, + &keyfile, + &routefile, + &route6file, + &error, + &ignore_error); + ASSERT (connection != NULL, + "permissions-read", "failed to read %s: %s", TEST_IFCFG_PERMISSIONS, error->message); + + ASSERT (nm_connection_verify (connection, &error), + "permissions-verify", "failed to verify %s: %s", TEST_IFCFG_PERMISSIONS, error->message); + + /* ===== CONNECTION SETTING ===== */ + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + ASSERT (s_con != NULL, + "permissions-verify-connection", "failed to verify %s: missing %s setting", + TEST_IFCFG_PERMISSIONS, + NM_SETTING_CONNECTION_SETTING_NAME); + + num = nm_setting_connection_get_num_permissions (s_con); + ASSERT (num == 3, + "permissions-verify-permissions", "unexpected number of permissions (%d, expected 3)", + num); + + /* verify each permission */ + tmp = NULL; + success = nm_setting_connection_get_permission (s_con, 0, NULL, &tmp, NULL); + ASSERT (success == TRUE, + "permissions-verify-permissions", "unexpected failure getting permission #1"); + ASSERT (strcmp (tmp, "dcbw") == 0, + "permissions-verify-permissions", "unexpected permission #1"); + + tmp = NULL; + success = nm_setting_connection_get_permission (s_con, 1, NULL, &tmp, NULL); + ASSERT (success == TRUE, + "permissions-verify-permissions", "unexpected failure getting permission #2"); + ASSERT (strcmp (tmp, "ssmith") == 0, + "permissions-verify-permissions", "unexpected permission #2"); + + tmp = NULL; + success = nm_setting_connection_get_permission (s_con, 2, NULL, &tmp, NULL); + ASSERT (success == TRUE, + "permissions-verify-permissions", "unexpected failure getting permission #3"); + ASSERT (strcmp (tmp, "johnny5") == 0, + "permissions-verify-permissions", "unexpected permission #3"); + + g_object_unref (connection); +} + static void test_write_wired_static (void) { @@ -9123,6 +9316,128 @@ test_write_wired_qeth_dhcp (void) g_object_unref (reread); } +static void +test_write_permissions (void) +{ + NMConnection *connection; + NMConnection *reread; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + char *uuid; + gboolean success; + GError *error = NULL; + char *testfile = NULL; + char *unmanaged = NULL; + char *keyfile = NULL; + char *routefile = NULL; + char *route6file = NULL; + gboolean ignore_error = FALSE; + + connection = nm_connection_new (); + ASSERT (connection != NULL, + "permissions-write", "failed to allocate new connection"); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + ASSERT (s_con != NULL, + "permissions-write", "failed to allocate new %s setting", + NM_SETTING_CONNECTION_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Write Permissions", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NULL); + g_free (uuid); + + nm_setting_connection_add_permission (s_con, "user", "blahblah", NULL); + nm_setting_connection_add_permission (s_con, "user", "foobar", NULL); + nm_setting_connection_add_permission (s_con, "user", "asdfasdf", NULL); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + ASSERT (s_wired != NULL, + "permissions-write", "failed to allocate new %s setting", + NM_SETTING_WIRED_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + /* IP4 setting */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + ASSERT (s_ip4 != NULL, + "permissions-write", "failed to allocate new %s setting", + NM_SETTING_IP4_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NULL); + + /* IP6 setting */ + s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); + ASSERT (s_ip6 != NULL, + "wired-qeth-dhcp-write", "failed to allocate new %s setting", + NM_SETTING_IP6_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NULL); + + /* Verify */ + ASSERT (nm_connection_verify (connection, &error) == TRUE, + "permissions-write", "failed to verify connection: %s", + (error && error->message) ? error->message : "(unknown)"); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + ASSERT (success == TRUE, + "permissions-write", "failed to write connection to disk: %s", + (error && error->message) ? error->message : "(unknown)"); + + ASSERT (testfile != NULL, + "permissions-write", "didn't get ifcfg file path back after writing connection"); + + /* re-read the connection for comparison */ + reread = connection_from_file (testfile, + NULL, + TYPE_ETHERNET, + NULL, + &unmanaged, + &keyfile, + &routefile, + &route6file, + &error, + &ignore_error); + unlink (testfile); + + ASSERT (reread != NULL, + "permissions-write-reread", "failed to read %s: %s", testfile, error->message); + + ASSERT (nm_connection_verify (reread, &error), + "permissions-write-reread-verify", "failed to verify %s: %s", testfile, error->message); + + ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, + "permissions-write", "written and re-read connection weren't the same."); + + if (route6file) + unlink (route6file); + + g_free (testfile); + g_free (keyfile); + g_free (routefile); + g_free (route6file); + g_object_unref (connection); + g_object_unref (reread); +} + static void test_write_wired_pppoe (void) { @@ -9537,6 +9852,8 @@ int main (int argc, char **argv) test_read_wifi_wpa_eap_ttls_tls (); test_read_wifi_wep_eap_ttls_chap (); test_read_wired_qeth_static (); + test_read_wifi_wep_no_keys (); + test_read_permissions (); test_write_wired_static (); test_write_wired_static_ip6_only (); @@ -9587,6 +9904,7 @@ int main (int argc, char **argv) test_write_wifi_wpa_eap_ttls_tls (); test_write_wifi_wpa_eap_ttls_mschapv2 (); test_write_wired_qeth_dhcp (); + test_write_permissions (); /* iSCSI / ibft */ test_read_ibft_dhcp (); diff --git a/system-settings/plugins/ifcfg-rh/writer.c b/system-settings/plugins/ifcfg-rh/writer.c index 71f8958210..068173d4f2 100644 --- a/system-settings/plugins/ifcfg-rh/writer.c +++ b/system-settings/plugins/ifcfg-rh/writer.c @@ -49,7 +49,11 @@ { g_warning (" " pname ": " fmt, ##args); } static void -set_secret (shvarFile *ifcfg, const char *key, const char *value, gboolean verbatim) +set_secret (shvarFile *ifcfg, + const char *key, + const char *value, + NMSettingSecretFlags flags, + gboolean verbatim) { shvarFile *keyfile; @@ -60,10 +64,14 @@ set_secret (shvarFile *ifcfg, const char *key, const char *value, gboolean verba goto error; } - /* Clear the secret from the actual ifcfg */ + /* Clear the secret from the ifcfg and the associated "keys" file */ svSetValue (ifcfg, key, NULL, FALSE); + svSetValue (keyfile, key, NULL, FALSE); + + /* Only write the secret if it's system owned and supposed to be saved */ + if (flags == NM_SETTING_SECRET_FLAG_NONE) + svSetValue (keyfile, key, value, verbatim); - svSetValue (keyfile, key, value, verbatim); if (svWriteFile (keyfile, 0600)) { PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: could not update key file '%s'", keyfile->fileName); @@ -341,6 +349,7 @@ write_8021x_certs (NMSetting8021x *s_8021x, gboolean success = FALSE, is_pkcs12 = FALSE; const ObjectType *otype = NULL; const GByteArray *blob = NULL; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; /* CA certificate */ if (phase2) @@ -358,12 +367,14 @@ write_8021x_certs (NMSetting8021x *s_8021x, is_pkcs12 = TRUE; } password = nm_setting_802_1x_get_phase2_private_key_password (s_8021x); + flags = nm_setting_802_1x_get_phase2_private_key_password_flags (s_8021x); } else { if (nm_setting_802_1x_get_private_key_scheme (s_8021x) != NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { if (nm_setting_802_1x_get_private_key_format (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) is_pkcs12 = TRUE; } password = nm_setting_802_1x_get_private_key_password (s_8021x); + flags = nm_setting_802_1x_get_private_key_password_flags (s_8021x); } if (is_pkcs12) @@ -384,8 +395,10 @@ write_8021x_certs (NMSetting8021x *s_8021x, if (!enc_key) goto out; - if (generated_pw) + if (generated_pw) { password = generated_pw; + flags = NM_SETTING_SECRET_FLAG_NONE; + } } /* Save the private key */ @@ -394,9 +407,9 @@ write_8021x_certs (NMSetting8021x *s_8021x, /* Private key password */ if (phase2) - set_secret (ifcfg, "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD", password, FALSE); + set_secret (ifcfg, "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD", password, flags, FALSE); else - set_secret (ifcfg, "IEEE_8021X_PRIVATE_KEY_PASSWORD", password, FALSE); + set_secret (ifcfg, "IEEE_8021X_PRIVATE_KEY_PASSWORD", password, flags, FALSE); /* Client certificate */ if (is_pkcs12) { @@ -469,7 +482,11 @@ write_8021x_setting (NMConnection *connection, nm_setting_802_1x_get_anonymous_identity (s_8021x), FALSE); - set_secret (ifcfg, "IEEE_8021X_PASSWORD", nm_setting_802_1x_get_password (s_8021x), FALSE); + set_secret (ifcfg, + "IEEE_8021X_PASSWORD", + nm_setting_802_1x_get_password (s_8021x), + nm_setting_802_1x_get_password_flags (s_8021x), + FALSE); /* PEAP version */ value = nm_setting_802_1x_get_phase1_peapver (s_8021x); @@ -574,6 +591,7 @@ write_wireless_security_setting (NMConnection *connection, FALSE); set_secret (ifcfg, "IEEE_8021X_PASSWORD", nm_setting_wireless_security_get_leap_password (s_wsec), + nm_setting_wireless_security_get_leap_password_flags (s_wsec), FALSE); *no_8021x = TRUE; } @@ -581,15 +599,17 @@ write_wireless_security_setting (NMConnection *connection, /* WEP keys */ + /* Clear any default key */ + set_secret (ifcfg, "KEY", NULL, NM_SETTING_SECRET_FLAG_NONE, FALSE); + /* Clear existing keys */ - set_secret (ifcfg, "KEY", NULL, FALSE); /* Clear any default key */ for (i = 0; i < 4; i++) { tmp = g_strdup_printf ("KEY_PASSPHRASE%d", i + 1); - set_secret (ifcfg, tmp, NULL, FALSE); + set_secret (ifcfg, tmp, NULL, NM_SETTING_SECRET_FLAG_NONE, FALSE); g_free (tmp); tmp = g_strdup_printf ("KEY%d", i + 1); - set_secret (ifcfg, tmp, NULL, FALSE); + set_secret (ifcfg, tmp, NULL, NM_SETTING_SECRET_FLAG_NONE, FALSE); g_free (tmp); } @@ -624,7 +644,7 @@ write_wireless_security_setting (NMConnection *connection, } } - set_secret (ifcfg, tmp, key, FALSE); + set_secret (ifcfg, tmp, key, nm_setting_wireless_security_get_wep_key_flags (s_wsec), FALSE); g_free (tmp); g_free (ascii_key); } @@ -687,11 +707,15 @@ write_wireless_security_setting (NMConnection *connection, g_string_append (quoted, psk); g_string_append_c (quoted, '"'); } - set_secret (ifcfg, "WPA_PSK", quoted ? quoted->str : psk, TRUE); + set_secret (ifcfg, + "WPA_PSK", + quoted ? quoted->str : psk, + nm_setting_wireless_security_get_psk_flags (s_wsec), + TRUE); if (quoted) g_string_free (quoted, TRUE); } else - set_secret (ifcfg, "WPA_PSK", NULL, FALSE); + set_secret (ifcfg, "WPA_PSK", NULL, NM_SETTING_SECRET_FLAG_NONE, FALSE); return TRUE; } @@ -826,6 +850,13 @@ write_wireless_setting (NMConnection *connection, g_free (tmp); } + /* Ensure DEFAULTKEY and SECURITYMODE are cleared unless there's security; + * otherwise there's no way to detect WEP vs. open when WEP keys aren't + * saved. + */ + svSetValue (ifcfg, "DEFAULTKEY", NULL, FALSE); + svSetValue (ifcfg, "SECURITYMODE", NULL, FALSE); + if (nm_setting_wireless_get_security (s_wireless)) { if (!write_wireless_security_setting (connection, ifcfg, adhoc, no_8021x, error)) return FALSE; @@ -938,6 +969,8 @@ static void write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) { char *tmp; + guint32 n, i; + GString *str; svSetValue (ifcfg, "NAME", nm_setting_connection_get_id (s_con), FALSE); svSetValue (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con), FALSE); @@ -951,6 +984,28 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) svSetValue (ifcfg, "LAST_CONNECT", tmp, FALSE); g_free (tmp); } + + /* Permissions */ + svSetValue (ifcfg, "USERS", NULL, FALSE); + n = nm_setting_connection_get_num_permissions (s_con); + if (n > 0) { + str = g_string_sized_new (n * 20); + + for (i = 0; i < n; i++) { + const char *puser = NULL; + + /* Items separated by space for consistency with eg + * IPV6ADDR_SECONDARIES and DOMAIN. + */ + if (str->len) + g_string_append_c (str, ' '); + + if (nm_setting_connection_get_permission (s_con, i, NULL, &puser, NULL)) + g_string_append (str, puser); + } + svSetValue (ifcfg, "USERS", str->str, FALSE); + g_string_free (str, TRUE); + } } static gboolean @@ -1556,8 +1611,33 @@ write_connection (NMConnection *connection, escaped = escape_id (nm_setting_connection_get_id (s_con)); ifcfg_name = g_strdup_printf ("%s/ifcfg-%s", ifcfg_dir, escaped); - ifcfg = svCreateFile (ifcfg_name); + + /* If a file with this path already exists then we need another name. + * Multiple connections can have the same ID (ie if two connections with + * the same ID are visible to different users) but of course can't have + * the same path. + */ + if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS)) { + guint32 idx = 0; + + g_free (ifcfg_name); + while (idx++ < 500) { + ifcfg_name = g_strdup_printf ("%s/ifcfg-%s %u", ifcfg_dir, escaped, idx); + if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS) == FALSE) + break; + g_free (ifcfg_name); + ifcfg_name = NULL; + } + } g_free (escaped); + + if (ifcfg_name == NULL) { + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, + "Failed to find usable ifcfg file name"); + return FALSE; + } + + ifcfg = svCreateFile (ifcfg_name); } if (!ifcfg) { diff --git a/system-settings/plugins/ifcfg-suse/Makefile.am b/system-settings/plugins/ifcfg-suse/Makefile.am index f28f57f791..3db8ed31d4 100644 --- a/system-settings/plugins/ifcfg-suse/Makefile.am +++ b/system-settings/plugins/ifcfg-suse/Makefile.am @@ -10,7 +10,7 @@ libnm_settings_plugin_ifcfg_suse_la_CPPFLAGS = \ $(GMODULE_CFLAGS) \ $(DBUS_CFLAGS) \ -DG_DISABLE_DEPRECATED \ - -I${top_srcdir}/src/system-settings \ + -I${top_srcdir}/src/settings \ -I$(top_srcdir)/include \ -I$(top_srcdir)/libnm-util \ -I$(top_srcdir)/libnm-glib \ diff --git a/system-settings/plugins/ifnet/Makefile.am b/system-settings/plugins/ifnet/Makefile.am index 86d5ea2514..9bf8a79a18 100644 --- a/system-settings/plugins/ifnet/Makefile.am +++ b/system-settings/plugins/ifnet/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS = . tests INCLUDES = \ - -I$(top_srcdir)/src/system-settings \ + -I$(top_srcdir)/src/settings \ -I$(top_srcdir)/include \ -I$(top_srcdir)/libnm-glib \ -I$(top_srcdir)/libnm-util diff --git a/system-settings/plugins/ifnet/connection_parser.c b/system-settings/plugins/ifnet/connection_parser.c index f9fae51f35..8779577297 100644 --- a/system-settings/plugins/ifnet/connection_parser.c +++ b/system-settings/plugins/ifnet/connection_parser.c @@ -50,7 +50,7 @@ get_prefix (void) } static void -update_connection_id (NMConnection * connection, gchar * conn_name) +update_connection_id (NMConnection *connection, const char *conn_name) { gchar *idstr = NULL; gchar *uuid_base = NULL; @@ -73,30 +73,37 @@ update_connection_id (NMConnection * connection, gchar * conn_name) g_free (idstr); } -static gboolean -eap_simple_reader (const char *eap_method, - gchar * ssid, - NMSetting8021x * s_8021x, gboolean phase2, GError ** error); +static gboolean eap_simple_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error); + static gboolean eap_tls_reader (const char *eap_method, - gchar * ssid, - NMSetting8021x * s_8021x, - gboolean phase2, GError ** error); + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error); static gboolean eap_peap_reader (const char *eap_method, - gchar * ssid, - NMSetting8021x * s_8021x, - gboolean phase2, GError ** error); + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error); static gboolean eap_ttls_reader (const char *eap_method, - gchar * ssid, - NMSetting8021x * s_8021x, - gboolean phase2, GError ** error); + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error); typedef struct { const char *method; - gboolean (*reader) (const char *eap_method, gchar * ssid, - NMSetting8021x * s_8021x, - gboolean phase2, GError ** error); + gboolean (*reader) (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error); gboolean wifi_phase2_only; } EAPReader; @@ -116,10 +123,12 @@ static EAPReader eap_readers[] = { /* reading identity and password */ static gboolean eap_simple_reader (const char *eap_method, - gchar * ssid, - NMSetting8021x * s_8021x, gboolean phase2, GError ** error) + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error) { - char *value; + const char *value; /* identity */ value = wpa_get_value (ssid, "identity"); @@ -147,17 +156,18 @@ eap_simple_reader (const char *eap_method, static gboolean eap_tls_reader (const char *eap_method, - gchar * ssid, - NMSetting8021x * s_8021x, gboolean phase2, GError ** error) + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error) { - char *value; - char *ca_cert = NULL; - char *client_cert = NULL; - char *privkey = NULL; - char *privkey_password = NULL; + const char *value; + const char *ca_cert = NULL; + const char *client_cert = NULL; + const char *privkey = NULL; + const char *privkey_password = NULL; gboolean success = FALSE; - NMSetting8021xCKFormat privkey_format = - NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; /* identity */ value = wpa_get_value (ssid, "identity"); @@ -275,14 +285,15 @@ eap_tls_reader (const char *eap_method, static gboolean eap_peap_reader (const char *eap_method, - gchar * ssid, - NMSetting8021x * s_8021x, gboolean phase2, GError ** error) + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error) { - char *ca_cert = NULL; - char *inner_auth = NULL; - char *peapver = NULL; - char *lower; - char **list = NULL, **iter; + const char *ca_cert = NULL; + const char *inner_auth = NULL; + const char *peapver = NULL; + char **list = NULL, **iter, *lower; gboolean success = FALSE; ca_cert = wpa_get_value (ssid, "ca_cert"); @@ -375,15 +386,16 @@ eap_peap_reader (const char *eap_method, static gboolean eap_ttls_reader (const char *eap_method, - gchar * ssid, - NMSetting8021x * s_8021x, gboolean phase2, GError ** error) + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error) { gboolean success = FALSE; - char *anon_ident = NULL; - char *ca_cert = NULL; - char *tmp; - char **list = NULL, **iter; - char *inner_auth = NULL; + const char *anon_ident = NULL; + const char *ca_cert = NULL; + const char *tmp; + char **list = NULL, **iter, *inner_auth = NULL; /* ca cert */ ca_cert = wpa_get_value (ssid, "ca_cert"); @@ -464,37 +476,35 @@ eap_ttls_reader (const char *eap_method, /* type is already decided by net_parser, this function is just used to * doing tansformation*/ static const gchar * -guess_connection_type (gchar * conn_name) +guess_connection_type (const char *conn_name) { const gchar *type = ifnet_get_data (conn_name, "type"); - const gchar *name = conn_name; const gchar *ret_type = NULL; - if (name && !strcmp ("ppp", type)) + if (!g_strcmp0 (type, "ppp")) ret_type = NM_SETTING_PPPOE_SETTING_NAME; - if (name && !strcmp ("wireless", type)) + if (!g_strcmp0 (type, "wireless")) ret_type = NM_SETTING_WIRELESS_SETTING_NAME; if (!ret_type) ret_type = NM_SETTING_WIRED_SETTING_NAME; PLUGIN_PRINT (IFNET_PLUGIN_NAME, - "guessed connection type (%s) = %s", name, ret_type); + "guessed connection type (%s) = %s", conn_name, ret_type); return ret_type; } /* Reading mac address for setting connection option. * Unmanaged device mac address is required by NetworkManager*/ static gboolean -read_mac_address (gchar * conn_name, GByteArray ** array, GError ** error) +read_mac_address (const char *conn_name, GByteArray **array, GError **error) { - gchar *value = ifnet_get_data (conn_name, "mac"); + const char *value = ifnet_get_data (conn_name, "mac"); struct ether_addr *mac; - if (!value || !strlen (value)) { + if (!value || !strlen (value)) return TRUE; - } mac = ether_aton (value); if (!mac) { @@ -504,18 +514,18 @@ read_mac_address (gchar * conn_name, GByteArray ** array, GError ** error) } *array = g_byte_array_sized_new (ETH_ALEN); - g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, - ETH_ALEN); + g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN); return TRUE; } static void -make_wired_connection_setting (NMConnection * connection, gchar * conn_name, - GError ** error) +make_wired_connection_setting (NMConnection *connection, + const char *conn_name, + GError **error) { GByteArray *mac = NULL; NMSettingWired *s_wired = NULL; - gchar *value = NULL; + const char *value = NULL; s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); @@ -552,12 +562,14 @@ make_wired_connection_setting (NMConnection * connection, gchar * conn_name, /* add NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, * NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID in future*/ static void -make_ip4_setting (NMConnection * connection, gchar * conn_name, GError ** error) +make_ip4_setting (NMConnection *connection, + const char *conn_name, + GError **error) { NMSettingIP4Config *ip4_setting = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ()); - gchar *value; + const char *value; gboolean is_static_block = is_static_ip4 (conn_name); ip_block *iblock = NULL; @@ -618,10 +630,9 @@ make_ip4_setting (NMConnection * connection, gchar * conn_name, GError ** error) } g_object_set (ip4_setting, - NM_SETTING_IP4_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, - !has_default_ip4_route (conn_name), NULL); + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, !has_default_ip4_route (conn_name), + NULL); } /* add dhcp hostname and client id */ @@ -651,13 +662,14 @@ make_ip4_setting (NMConnection * connection, gchar * conn_name, GError ** error) set_ip4_dns_servers (ip4_setting, conn_name); /* DNS searches */ - value = (gchar *) ifnet_get_data (conn_name, "dns_search"); + value = ifnet_get_data (conn_name, "dns_search"); if (value) { + char *stripped = g_strdup (value); char **searches = NULL; - strip_string (value, '"'); + strip_string (stripped, '"'); - searches = g_strsplit (value, " ", 0); + searches = g_strsplit (stripped, " ", 0); if (searches) { char **item; @@ -678,7 +690,8 @@ make_ip4_setting (NMConnection * connection, gchar * conn_name, GError ** error) iblock = convert_ip4_routes_block (conn_name); while (iblock) { ip_block *current_iblock = iblock; - gchar *metric_str; + const char *metric_str; + char *stripped; long int metric; NMIP4Route *route = nm_ip4_route_new (); @@ -693,10 +706,12 @@ make_ip4_setting (NMConnection * connection, gchar * conn_name, GError ** error) } else { metric_str = ifnet_get_global_data ("metric"); if (metric_str) { + stripped = g_strdup (metric_str); + strip_string (stripped, '"'); metric = strtol (metric_str, NULL, 10); nm_ip4_route_set_metric (route, (guint32) metric); - g_free (metric_str); + g_free (stripped); } } @@ -718,7 +733,9 @@ make_ip4_setting (NMConnection * connection, gchar * conn_name, GError ** error) } static void -make_ip6_setting (NMConnection * connection, gchar * conn_name, GError ** error) +make_ip6_setting (NMConnection *connection, + const char *conn_name, + GError **error) { NMSettingIP6Config *s_ip6 = NULL; gboolean is_static_block = is_static_ip6 (conn_name); @@ -726,7 +743,7 @@ make_ip6_setting (NMConnection * connection, gchar * conn_name, GError ** error) // used to disable IPv6 gboolean ipv6_enabled = FALSE; gchar *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; - gchar *value; + const char *value; ip6_block *iblock; gboolean never_default = !has_default_ip6_route (conn_name); @@ -816,7 +833,8 @@ make_ip6_setting (NMConnection * connection, gchar * conn_name, GError ** error) /* Add all IPv6 routes */ while (iblock) { ip6_block *current_iblock = iblock; - gchar *metric_str; + const char *metric_str; + char *stripped; long int metric = 1; NMIP6Route *route = nm_ip6_route_new (); @@ -831,10 +849,12 @@ make_ip6_setting (NMConnection * connection, gchar * conn_name, GError ** error) } else { metric_str = ifnet_get_global_data ("metric"); if (metric_str) { + stripped = g_strdup (metric_str); + strip_string (stripped, '"'); metric = strtol (metric_str, NULL, 10); nm_ip6_route_set_metric (route, (guint32) metric); - g_free (metric_str); + g_free (stripped); } else nm_ip6_route_set_metric (route, (guint32) 1); } @@ -862,16 +882,17 @@ make_ip6_setting (NMConnection * connection, gchar * conn_name, GError ** error) } static NMSetting * -make_wireless_connection_setting (gchar * conn_name, - NMSetting8021x ** s_8021x, GError ** error) +make_wireless_connection_setting (const char *conn_name, + NMSetting8021x **s_8021x, + GError **error) { GByteArray *array, *mac = NULL; NMSettingWireless *wireless_setting = NULL; gboolean adhoc = FALSE; - gchar *value; - gchar *type; + const char *value; + const char *type; - /* PPP over WIFI is not supported */ + /* PPP over WIFI is not supported yet */ g_return_val_if_fail (conn_name != NULL && strcmp (ifnet_get_data (conn_name, "type"), "ppp") != 0, NULL); @@ -899,8 +920,8 @@ make_wireless_connection_setting (gchar * conn_name, /* handle ssid (hex and ascii) */ if (conn_name) { gsize ssid_len = 0, value_len = strlen (conn_name); - char *p = conn_name, *tmp; - char buf[33]; + const char *p; + char *tmp, *converted = NULL; ssid_len = value_len; if ((value_len > 2) && (g_str_has_prefix (conn_name, "0x"))) { @@ -923,11 +944,11 @@ make_wireless_connection_setting (gchar * conn_name, goto error; } - tmp = utils_hexstr2bin (conn_name + 2, value_len - 2); + tmp = utils_hexstr2bin (p, value_len - 2); ssid_len = (value_len - 2) / 2; - memcpy (buf, tmp, ssid_len); + converted = g_malloc0 (ssid_len + 1); + memcpy (converted, tmp, ssid_len); g_free (tmp); - p = &buf[0]; } if (ssid_len > 32 || ssid_len == 0) { @@ -937,10 +958,10 @@ make_wireless_connection_setting (gchar * conn_name, goto error; } array = g_byte_array_sized_new (ssid_len); - g_byte_array_append (array, (const guint8 *) p, ssid_len); - g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, array, - NULL); + g_byte_array_append (array, (const guint8 *) (converted ? converted : conn_name), ssid_len); + g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, array, NULL); g_byte_array_free (array, TRUE); + g_free (converted); } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing SSID"); @@ -1010,10 +1031,10 @@ make_wireless_connection_setting (gchar * conn_name, } static NMSettingWirelessSecurity * -make_leap_setting (gchar * ssid, GError ** error) +make_leap_setting (const char *ssid, GError **error) { NMSettingWirelessSecurity *wsec; - char *value; + const char *value; wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); @@ -1052,31 +1073,34 @@ make_leap_setting (gchar * ssid, GError ** error) } static gboolean -add_one_wep_key (gchar * ssid, gchar * key, int key_idx, - NMSettingWirelessSecurity * s_wsec, GError ** error) +add_one_wep_key (const char *ssid, + const char *key, + int key_idx, + NMSettingWirelessSecurity *s_wsec, + GError **error) { - gchar *value; + const char *value; + char *converted = NULL; gboolean success = FALSE; g_return_val_if_fail (ssid != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (key_idx >= 0 && key_idx <= 3, FALSE); g_return_val_if_fail (s_wsec != NULL, FALSE); + value = wpa_get_value (ssid, key); if (!value) return TRUE; - key = NULL; + /* Validate keys */ if (strlen (value) == 10 || strlen (value) == 26) { /* Hexadecimal WEP key */ - char *p = value; - - if (!is_hex (p)) { + if (!is_hex (value)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid hexadecimal WEP key."); goto out; } - key = g_strdup (value); + converted = g_strdup (value); } else if (value[0] == '"' && (strlen (value) == 7 || strlen (value) == 15)) { /* ASCII passphrase */ @@ -1091,7 +1115,7 @@ add_one_wep_key (gchar * ssid, gchar * key, int key_idx, } - key = utils_bin2hexstr (tmp, strlen (tmp), strlen (tmp) * 2); + converted = utils_bin2hexstr (tmp, strlen (tmp), strlen (tmp) * 2); g_free (tmp); } else { g_set_error (error, ifnet_plugin_error_quark (), 0, @@ -1099,19 +1123,20 @@ add_one_wep_key (gchar * ssid, gchar * key, int key_idx, goto out; } - if (key) { - nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); - g_free (key); + if (converted) { + nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, converted); + g_free (converted); success = TRUE; } - out: +out: return success; - } static gboolean -add_wep_keys (gchar * ssid, NMSettingWirelessSecurity * s_wsec, GError ** error) +add_wep_keys (const char *ssid, + NMSettingWirelessSecurity *s_wsec, + GError **error) { if (!add_one_wep_key (ssid, "wep_key0", 0, s_wsec, error)) return FALSE; @@ -1126,11 +1151,10 @@ add_wep_keys (gchar * ssid, NMSettingWirelessSecurity * s_wsec, GError ** error) } static NMSettingWirelessSecurity * -make_wep_setting (gchar * ssid, GError ** error) +make_wep_setting (const char *ssid, GError **error) { - gchar *auth_alg; + const char *auth_alg, *value; int default_key_idx = 0; - gchar *value; NMSettingWirelessSecurity *s_wireless_sec; s_wireless_sec = @@ -1226,9 +1250,10 @@ make_wep_setting (gchar * ssid, GError ** error) } static char * -parse_wpa_psk (gchar * psk, GError ** error) +parse_wpa_psk (const char *psk, GError **error) { - gchar *p, *hashed = NULL; + const char *p = psk; + char *hashed = NULL; gboolean quoted = FALSE; if (!psk) { @@ -1243,12 +1268,11 @@ parse_wpa_psk (gchar * psk, GError ** error) * the passphrase contains spaces. */ - p = psk; - if (p[0] == '"' && psk[strlen (psk) - 1] == '"') + if (psk[0] == '"' && psk[strlen (psk) - 1] == '"') quoted = TRUE; if (!quoted && (strlen (psk) == 64)) { /* Verify the hex PSK; 64 digits */ - if (!is_hex (p)) { + if (!is_hex (psk)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid WPA_PSK (contains non-hexadecimal characters)"); @@ -1256,17 +1280,21 @@ parse_wpa_psk (gchar * psk, GError ** error) } hashed = g_strdup (psk); } else { - strip_string (p, '"'); + char *stripped = g_strdup (psk); + + strip_string (stripped, '"'); /* Length check */ if (strlen (p) < 8 || strlen (p) > 63) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid WPA_PSK (passphrases must be between " "8 and 63 characters long (inclusive))"); + g_free (stripped); goto out; } - hashed = g_strdup (p); + hashed = g_strdup (stripped); + g_free (stripped); } if (!hashed) { @@ -1275,24 +1303,25 @@ parse_wpa_psk (gchar * psk, GError ** error) goto out; } - out: +out: return hashed; } static gboolean -fill_wpa_ciphers (gchar * ssid, - NMSettingWirelessSecurity * wsec, - gboolean group, gboolean adhoc) +fill_wpa_ciphers (const char *ssid, + NMSettingWirelessSecurity *wsec, + gboolean group, + gboolean adhoc) { - char *value = NULL, *p; + const char *value; char **list = NULL, **iter; int i = 0; - p = value = wpa_get_value (ssid, group ? "group" : "pairwise"); + value = wpa_get_value (ssid, group ? "group" : "pairwise"); if (!value) return TRUE; - list = g_strsplit_set (p, " ", 0); + list = g_strsplit_set (value, " ", 0); for (iter = list; iter && *iter; iter++, i++) { /* Ad-Hoc configurations cannot have pairwise ciphers, and can only * have one group cipher. Ignore any additional group ciphers and @@ -1344,10 +1373,13 @@ fill_wpa_ciphers (gchar * ssid, } static NMSetting8021x * -fill_8021x (gchar * ssid, gchar * key_mgmt, gboolean wifi, GError ** error) +fill_8021x (const char *ssid, + const char *key_mgmt, + gboolean wifi, + GError **error) { NMSetting8021x *s_8021x; - char *value; + const char *value; char **list, **iter; value = wpa_get_value (ssid, "eap"); @@ -1420,10 +1452,13 @@ fill_8021x (gchar * ssid, gchar * key_mgmt, gboolean wifi, GError ** error) } static NMSettingWirelessSecurity * -make_wpa_setting (gchar * ssid, NMSetting8021x ** s_8021x, GError ** error) +make_wpa_setting (const char *ssid, + NMSetting8021x **s_8021x, + GError **error) { NMSettingWirelessSecurity *wsec; - char *value, *lower; + const char *value; + char *lower; gboolean adhoc = FALSE; if (!exist_ssid (ssid)) { @@ -1462,7 +1497,7 @@ make_wpa_setting (gchar * ssid, NMSetting8021x ** s_8021x, GError ** error) } if (!strcmp (value, "WPA-PSK")) { - gchar *psk = parse_wpa_psk (wpa_get_value (ssid, "psk"), error); + char *psk = parse_wpa_psk (wpa_get_value (ssid, "psk"), error); if (!psk) goto error; @@ -1506,14 +1541,14 @@ make_wpa_setting (gchar * ssid, NMSetting8021x ** s_8021x, GError ** error) } static NMSettingWirelessSecurity * -make_wireless_security_setting (gchar * - conn_name, - NMSetting8021x ** s_8021x, GError ** error) +make_wireless_security_setting (const char *conn_name, + NMSetting8021x **s_8021x, + GError ** error) { NMSettingWirelessSecurity *wsec = NULL; - gchar *ssid; + const char *ssid; gboolean adhoc = FALSE; - gchar *value; + const char *value; g_return_val_if_fail (conn_name != NULL && strcmp (ifnet_get_data (conn_name, "type"), @@ -1557,12 +1592,13 @@ make_wireless_security_setting (gchar * /* Currently only support username and password */ static void -make_pppoe_connection_setting (NMConnection * connection, - gchar * conn_name, GError ** error) +make_pppoe_connection_setting (NMConnection *connection, + const char *conn_name, + GError **error) { NMSettingPPPOE *s_pppoe; NMSettingPPP *s_ppp; - gchar *value; + const char *value; s_pppoe = NM_SETTING_PPPOE (nm_setting_pppoe_new ()); @@ -1590,7 +1626,7 @@ make_pppoe_connection_setting (NMConnection * connection, } NMConnection * -ifnet_update_connection_from_config_block (gchar * conn_name, GError ** error) +ifnet_update_connection_from_config_block (const char *conn_name, GError **error) { const gchar *type = NULL; NMConnection *connection = NULL; @@ -1598,7 +1634,7 @@ ifnet_update_connection_from_config_block (gchar * conn_name, GError ** error) NMSetting8021x *s_8021x = NULL; NMSettingWirelessSecurity *wsec = NULL; gboolean auto_conn = TRUE; - gchar *value = NULL; + const char *value = NULL; gboolean success = FALSE; connection = nm_connection_new (); @@ -1642,14 +1678,11 @@ ifnet_update_connection_from_config_block (gchar * conn_name, GError ** error) } } else if (!strcmp (NM_SETTING_WIRELESS_SETTING_NAME, type)) { /* wireless setting */ - NMSetting *wireless_setting = - make_wireless_connection_setting (conn_name, - &s_8021x, - error); + NMSetting *wireless_setting; - if (!wireless_setting) { + wireless_setting = make_wireless_connection_setting (conn_name, &s_8021x, error); + if (!wireless_setting) goto error; - } nm_connection_add_setting (connection, wireless_setting); if (error && *error) { @@ -1659,8 +1692,7 @@ ifnet_update_connection_from_config_block (gchar * conn_name, GError ** error) } /* wireless security setting */ - wsec = - make_wireless_security_setting (conn_name, &s_8021x, error); + wsec = make_wireless_security_setting (conn_name, &s_8021x, error); if (wsec) { nm_connection_add_setting (connection, NM_SETTING (wsec)); @@ -1698,12 +1730,12 @@ ifnet_update_connection_from_config_block (gchar * conn_name, GError ** error) if (error && *error) PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message); - PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Connection verified %s:%d", conn_name, - success); + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Connection verified %s:%d", conn_name, success); if (!success) goto error; return connection; - error: + +error: g_object_unref (setting); g_object_unref (connection); return NULL; @@ -1795,10 +1827,11 @@ static const ObjectType phase2_p12_type = { }; static gboolean -write_object (NMSetting8021x * s_8021x, - gchar * conn_name, - const GByteArray * override_data, - const ObjectType * objtype, GError ** error) +write_object (NMSetting8021x *s_8021x, + const char *conn_name, + const GByteArray *override_data, + const ObjectType *objtype, + GError **error) { NMSetting8021xCKScheme scheme; const char *path = NULL; @@ -1844,8 +1877,10 @@ write_object (NMSetting8021x * s_8021x, } static gboolean -write_8021x_certs (NMSetting8021x * s_8021x, - gboolean phase2, gchar * conn_name, GError ** error) +write_8021x_certs (NMSetting8021x *s_8021x, + gboolean phase2, + const char *conn_name, + GError **error) { char *password = NULL; const ObjectType *otype = NULL; @@ -1948,8 +1983,10 @@ write_8021x_certs (NMSetting8021x * s_8021x, } static gboolean -write_8021x_setting (NMConnection * connection, - gchar * conn_name, gboolean wired, GError ** error) +write_8021x_setting (NMConnection *connection, + const char *conn_name, + gboolean wired, + GError **error) { NMSetting8021x *s_8021x; const char *value; @@ -2192,20 +2229,24 @@ write_wireless_security_setting (NMConnection * connection, /* remove old ssid and add new one*/ static void -update_wireless_ssid (NMConnection * connection, gchar * conn_name, - gchar * ssid, gboolean hex) +update_wireless_ssid (NMConnection *connection, + const char *conn_name, + const char *ssid, + gboolean hex) { ifnet_delete_network (conn_name); - ifnet_add_connection (ssid, "wireless"); - wpa_delete_security (conn_name); + + ifnet_add_connection (ssid, "wireless"); wpa_add_security (ssid); } static gboolean -write_wireless_setting (NMConnection * connection, - gchar ** conn_name_ptr, gboolean * no_8021x, - GError ** error) +write_wireless_setting (NMConnection *connection, + const char *conn_name, + gboolean *no_8021x, + const char **out_new_name, + GError **error) { NMSettingWireless *s_wireless; const GByteArray *ssid, *mac, *bssid; @@ -2214,11 +2255,8 @@ write_wireless_setting (NMConnection * connection, guint32 mtu, i; gboolean adhoc = FALSE, hex_ssid = FALSE; gchar *ssid_str, *tmp; - gchar *conn_name = *conn_name_ptr; - s_wireless = - (NMSettingWireless *) nm_connection_get_setting (connection, - NM_TYPE_SETTING_WIRELESS); + s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); if (!s_wireless) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing '%s' setting", @@ -2258,10 +2296,8 @@ write_wireless_setting (NMConnection * connection, g_string_append (str, "0x"); for (i = 0; i < ssid->len; i++) g_string_append_printf (str, "%02X", ssid->data[i]); - update_wireless_ssid (connection, conn_name, str->str, - hex_ssid); - ssid_str = g_strdup (str->str); - g_string_free (str, TRUE); + update_wireless_ssid (connection, conn_name, str->str, hex_ssid); + ssid_str = g_string_free (str, FALSE); } else { /* Printable SSIDs get quoted */ memset (buf, 0, sizeof (buf)); @@ -2321,14 +2357,17 @@ write_wireless_setting (NMConnection * connection, return FALSE; } else wpa_delete_security (ssid_str); - *conn_name_ptr = ifnet_get_data (ssid_str, "name"); + + if (out_new_name) + *out_new_name = ifnet_get_data (ssid_str, "name"); g_free (ssid_str); return TRUE; } static gboolean -write_wired_setting (NMConnection * connection, gchar * conn_name, - GError ** error) +write_wired_setting (NMConnection *connection, + const char *conn_name, + GError **error) { NMSettingWired *s_wired; const GByteArray *mac; @@ -2370,7 +2409,7 @@ write_wired_setting (NMConnection * connection, gchar * conn_name, } static void -write_connection_setting (NMSettingConnection * s_con, gchar * conn_name) +write_connection_setting (NMSettingConnection *s_con, const char *conn_name) { ifnet_set_data (conn_name, "auto", nm_setting_connection_get_autoconnect (s_con) ? "true" : @@ -2378,8 +2417,7 @@ write_connection_setting (NMSettingConnection * s_con, gchar * conn_name) } static gboolean -write_ip4_setting (NMConnection * connection, gchar * conn_name, - GError ** error) +write_ip4_setting (NMConnection *connection, const char *conn_name, GError **error) { NMSettingIP4Config *s_ip4; const char *value; @@ -2537,8 +2575,7 @@ write_ip4_setting (NMConnection * connection, gchar * conn_name, } static gboolean -write_route6_file (NMSettingIP6Config * s_ip6, gchar * conn_name, - GError ** error) +write_route6_file (NMSettingIP6Config *s_ip6, const char *conn_name, GError **error) { char dest[INET6_ADDRSTRLEN + 1]; char next_hop[INET6_ADDRSTRLEN + 1]; @@ -2547,7 +2584,7 @@ write_route6_file (NMSettingIP6Config * s_ip6, gchar * conn_name, guint32 prefix; guint32 i, num; GString *routes_string; - gchar *old_routes; + const char *old_routes; g_return_val_if_fail (s_ip6 != NULL, FALSE); num = nm_setting_ip6_config_get_num_routes (s_ip6); @@ -2585,8 +2622,7 @@ write_route6_file (NMSettingIP6Config * s_ip6, gchar * conn_name, } static gboolean -write_ip6_setting (NMConnection * connection, gchar * conn_name, - GError ** error) +write_ip6_setting (NMConnection *connection, const char *conn_name, GError **error) { NMSettingIP6Config *s_ip6; const char *value; @@ -2616,7 +2652,7 @@ write_ip6_setting (NMConnection * connection, gchar * conn_name, /* nothing to do now */ } else { // if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - gchar *config = ifnet_get_data (conn_name, "config"); + const char *config = ifnet_get_data (conn_name, "config"); gchar *tmp; if (!config) @@ -2635,7 +2671,7 @@ write_ip6_setting (NMConnection * connection, gchar * conn_name, ifnet_set_data (conn_name, "enable_ipv6", "true"); if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { - gchar *config = ifnet_get_data (conn_name, "config"); + const char *config = ifnet_get_data (conn_name, "config"); gchar *tmp; GString *ip_str; @@ -2667,7 +2703,7 @@ write_ip6_setting (NMConnection * connection, gchar * conn_name, /* DNS Servers */ num = nm_setting_ip6_config_get_num_dns (s_ip6); if (num > 0) { - gchar *dns_servers = ifnet_get_data (conn_name, "dns_servers"); + const char *dns_servers = ifnet_get_data (conn_name, "dns_servers"); gchar *tmp; GString *dns_string = g_string_new (NULL); @@ -2691,7 +2727,7 @@ write_ip6_setting (NMConnection * connection, gchar * conn_name, /* DNS Searches */ num = nm_setting_ip6_config_get_num_dns_searches (s_ip6); if (num > 0) { - char *ip4_domains; + const char *ip4_domains; ip4_domains = ifnet_get_data (conn_name, "dns_search"); if (!ip4_domains) @@ -2719,7 +2755,7 @@ write_ip6_setting (NMConnection * connection, gchar * conn_name, } static gboolean -write_pppoe_setting (gchar * conn_name, NMSettingPPPOE * s_pppoe) +write_pppoe_setting (const char *conn_name, NMSettingPPPOE * s_pppoe) { const gchar *value; @@ -2738,11 +2774,12 @@ write_pppoe_setting (gchar * conn_name, NMSettingPPPOE * s_pppoe) } gboolean -ifnet_update_parsers_by_connection (NMConnection * connection, - gchar * conn_name, - gchar ** nm_conn_name, - gchar * config_file, - gchar * wpa_file, GError ** error) +ifnet_update_parsers_by_connection (NMConnection *connection, + const char *conn_name, + const char *config_file, + const char *wpa_file, + const char **out_new_name, + GError **error) { NMSettingConnection *s_con; NMSettingIP6Config *s_ip6; @@ -2750,6 +2787,7 @@ ifnet_update_parsers_by_connection (NMConnection * connection, const char *type; gboolean no_8021x = FALSE; gboolean wired = FALSE, pppoe = TRUE; + const char *new_name = NULL; s_con = NM_SETTING_CONNECTION (nm_connection_get_setting @@ -2776,16 +2814,14 @@ ifnet_update_parsers_by_connection (NMConnection * connection, no_8021x = TRUE; } else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) { /* Writing wireless setting */ - if (!write_wireless_setting - (connection, &conn_name, &no_8021x, error)) + if (!write_wireless_setting (connection, conn_name, &no_8021x, &new_name, error)) goto out; } else if (!strcmp (type, NM_SETTING_PPPOE_SETTING_NAME)) { + NMSettingPPPOE *s_pppoe; + /* Writing pppoe setting */ - if (! - (write_pppoe_setting - (conn_name, - NM_SETTING_PPPOE (nm_connection_get_setting - (connection, NM_TYPE_SETTING_PPPOE))))) + s_pppoe = NM_SETTING_PPPOE (nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE)); + if (!write_pppoe_setting (conn_name, s_pppoe)) goto out; pppoe = TRUE; wired = TRUE; @@ -2796,6 +2832,12 @@ ifnet_update_parsers_by_connection (NMConnection * connection, goto out; } + /* connection name may have been updated; use it when writing out + * the rest of the settings. + */ + if (new_name) + conn_name = new_name; + //FIXME wired connection doesn't support 8021x now if (!no_8021x) { if (!write_8021x_setting (connection, conn_name, wired, error)) @@ -2806,9 +2848,7 @@ ifnet_update_parsers_by_connection (NMConnection * connection, if (!write_ip4_setting (connection, conn_name, error)) goto out; - s_ip6 = - (NMSettingIP6Config *) nm_connection_get_setting (connection, - NM_TYPE_SETTING_IP6_CONFIG); + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); if (s_ip6) { /* IPv6 Setting */ if (!write_ip6_setting (connection, conn_name, error)) @@ -2821,19 +2861,21 @@ ifnet_update_parsers_by_connection (NMConnection * connection, /* connection id will be displayed in nm-applet */ update_connection_id (connection, conn_name); - if (nm_conn_name) - *nm_conn_name = g_strdup (conn_name); success = ifnet_flush_to_file (config_file); if (success) wpa_flush_to_file (wpa_file); - out: + if (out_new_name) + *out_new_name = new_name; + +out: return success; } gboolean -ifnet_delete_connection_in_parsers (gchar * conn_name, - gchar * config_file, gchar * wpa_file) +ifnet_delete_connection_in_parsers (const char *conn_name, + const char *config_file, + const char *wpa_file) { gboolean result = FALSE; @@ -2931,32 +2973,22 @@ get_wireless_name (NMConnection * connection) return result; } -gboolean -ifnet_add_new_connection (NMConnection * connection, - gchar * config_file, gchar * wpa_file, - GError ** error) +char * +ifnet_add_new_connection (NMConnection *connection, + const char *config_file, + const char *wpa_file, + GError **error) { NMSettingConnection *s_con; gboolean success = FALSE; const char *type; gchar *new_type, *new_name = NULL; - s_con = - NM_SETTING_CONNECTION (nm_connection_get_setting - (connection, NM_TYPE_SETTING_CONNECTION)); - if (!s_con) { - g_set_error (error, ifnet_plugin_error_quark (), 0, - "Missing '%s' setting", - NM_SETTING_CONNECTION_SETTING_NAME); - return FALSE; - } - + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + g_assert (s_con); type = nm_setting_connection_get_connection_type (s_con); - if (!type) { - g_set_error (error, ifnet_plugin_error_quark (), 0, - "Missing connection type!"); - goto out; - } + g_assert (type); + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Adding %s connection", type); /* get name and type @@ -2982,16 +3014,20 @@ ifnet_add_new_connection (NMConnection * connection, goto out; } - if (ifnet_add_connection (new_name, new_type)) - success = - ifnet_update_parsers_by_connection (connection, new_name, - NULL, config_file, - wpa_file, error); - PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Added new connection: %s, result: %s", - new_name, success ? "success" : "fail"); + if (ifnet_add_connection (new_name, new_type)) { + success = ifnet_update_parsers_by_connection (connection, + new_name, + config_file, + wpa_file, + NULL, + error); + } - out: - if (new_name) + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Added new connection: %s, result: %s", + new_name, success ? "success" : "fail"); + +out: + if (!success) g_free (new_name); - return success; + return success ? new_name : NULL; } diff --git a/system-settings/plugins/ifnet/connection_parser.h b/system-settings/plugins/ifnet/connection_parser.h index b006954cc8..2154f56e64 100644 --- a/system-settings/plugins/ifnet/connection_parser.h +++ b/system-settings/plugins/ifnet/connection_parser.h @@ -24,20 +24,23 @@ #include #include "net_parser.h" -NMConnection *ifnet_update_connection_from_config_block (gchar * conn_name, - GError ** error); +NMConnection *ifnet_update_connection_from_config_block (const char *conn_name, + GError **error); /* nm_conn_name is used to update nm_ifnet_connection's priv data */ -gboolean ifnet_update_parsers_by_connection (NMConnection * connection, - gchar * conn_name, - gchar ** nm_conn_name, - gchar * config_file, - gchar * wpa_file, GError ** error); +gboolean ifnet_update_parsers_by_connection (NMConnection *connection, + const char *conn_name, + const char *config_file, + const char *wpa_file, + const char **out_new_name, + GError **error); -gboolean ifnet_delete_connection_in_parsers (gchar * conn_name, - gchar * config_file, - gchar * wpa_file); -gboolean ifnet_add_new_connection (NMConnection * connection, - gchar * config_file, gchar * wpa_file, - GError ** error); +gboolean ifnet_delete_connection_in_parsers (const char *conn_name, + const char *config_file, + const char *wpa_file); + +char * ifnet_add_new_connection (NMConnection *connection, + const char *config_file, + const char *wpa_file, + GError ** error); #endif diff --git a/system-settings/plugins/ifnet/net_parser.c b/system-settings/plugins/ifnet/net_parser.c index b4a381dee8..98cfc2f1bd 100644 --- a/system-settings/plugins/ifnet/net_parser.c +++ b/system-settings/plugins/ifnet/net_parser.c @@ -58,24 +58,24 @@ add_new_connection_config (const gchar * type, const gchar * name) } gboolean -ifnet_add_connection (gchar * name, gchar * type) +ifnet_add_connection (const char *name, const char *type) { if (add_new_connection_config (type, name)) { PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Adding network for %s", name); net_parser_data_changed = TRUE; return TRUE; - } else - return FALSE; + } + return FALSE; } gboolean -ifnet_has_connection (gchar * conn_name) +ifnet_has_connection (const char *conn_name) { return g_hash_table_lookup (conn_table, conn_name) != NULL; } static GHashTable * -get_connection_config (gchar * name) +get_connection_config (const char *name) { return g_hash_table_lookup (conn_table, name); } @@ -87,7 +87,7 @@ static gchar *ignore_name[] = { }; static gboolean -ignore_connection_name (gchar * name) +ignore_connection_name (const char *name) { gboolean result = FALSE; guint i = 0; @@ -194,8 +194,8 @@ destroy_connection_config (GHashTable * conn) } // read settings from /etc/NetworkManager/nm-system-settings.conf -gchar * -ifnet_get_global_setting (gchar * group, gchar * key) +const char * +ifnet_get_global_setting (const char *group, const char *key) { GError *error = NULL; GKeyFile *keyfile = g_key_file_new (); @@ -362,8 +362,8 @@ ifnet_init (gchar * config_file) return TRUE; } -gchar * -ifnet_get_data (gchar * conn_name, const gchar * key) +const char * +ifnet_get_data (const char *conn_name, const char *key) { GHashTable *conn = g_hash_table_lookup (conn_table, conn_name); @@ -373,7 +373,7 @@ ifnet_get_data (gchar * conn_name, const gchar * key) } void -ifnet_set_data (gchar * conn_name, gchar * key, gchar * value) +ifnet_set_data (const char *conn_name, const char *key, const char *value) { gpointer orin_key = NULL, orin_value = NULL; GHashTable *conn = g_hash_table_lookup (conn_table, conn_name); @@ -396,32 +396,26 @@ ifnet_set_data (gchar * conn_name, gchar * key, gchar * value) } // Remember to free return value -gchar * +const char * ifnet_get_global_data (const gchar * key) { - gchar *result = g_hash_table_lookup (global_settings_table, key); - - if (result) - result = g_strdup (result); - else - return NULL; - strip_string (result, '"'); - return result; + return g_hash_table_lookup (global_settings_table, key); } // Return names of legal connections GList * -ifnet_get_connection_names () +ifnet_get_connection_names (void) { GList *names = g_hash_table_get_keys (conn_table); GList *result = NULL; while (names) { if (!ignore_connection_name (names->data)) - result = g_list_append (result, names->data); + result = g_list_prepend (result, names->data); names = names->next; } - return result; + g_list_free (names); + return g_list_reverse (result); } /* format IP and route for writing */ @@ -455,7 +449,7 @@ format_ips (gchar * value, gchar ** out_line, gchar * key, gchar * name) } gboolean -ifnet_flush_to_file (gchar * config_file) +ifnet_flush_to_file (const char *config_file) { GIOChannel *channel; GError **error = NULL; @@ -584,7 +578,7 @@ ifnet_flush_to_file (gchar * config_file) } gboolean -ifnet_delete_network (gchar * conn_name) +ifnet_delete_network (const char *conn_name) { GHashTable *network = NULL; diff --git a/system-settings/plugins/ifnet/net_parser.h b/system-settings/plugins/ifnet/net_parser.h index 73a44c857d..5b9fadaecc 100644 --- a/system-settings/plugins/ifnet/net_parser.h +++ b/system-settings/plugins/ifnet/net_parser.h @@ -33,14 +33,14 @@ void ifnet_destroy (void); /* Reader functions */ GList *ifnet_get_connection_names (void); -gchar *ifnet_get_data (gchar * conn_name, const gchar * key); -gchar *ifnet_get_global_data (const gchar * key); -gchar *ifnet_get_global_setting (gchar * group, gchar * key); -gboolean ifnet_has_connection (gchar * conn_name); +const char *ifnet_get_data (const char *conn_name, const char *key); +const char *ifnet_get_global_data (const char *key); +const char *ifnet_get_global_setting (const char *group, const char *key); +gboolean ifnet_has_connection (const char *conn_name); /* Writer functions */ -gboolean ifnet_flush_to_file (gchar * config_file); -void ifnet_set_data (gchar * conn_name, gchar * key, gchar * value); -gboolean ifnet_add_connection (gchar * name, gchar * type); -gboolean ifnet_delete_network (gchar * conn_name); +gboolean ifnet_flush_to_file (const char *config_file); +void ifnet_set_data (const char *conn_name, const char *key, const char *value); +gboolean ifnet_add_connection (const char *name, const char *type); +gboolean ifnet_delete_network (const char *conn_name); #endif diff --git a/system-settings/plugins/ifnet/net_utils.c b/system-settings/plugins/ifnet/net_utils.c index 2dc253c546..338ead25dd 100644 --- a/system-settings/plugins/ifnet/net_utils.c +++ b/system-settings/plugins/ifnet/net_utils.c @@ -59,40 +59,34 @@ strip_string (gchar * str, gchar t) } gboolean -is_hex (gchar * value) +is_hex (const char *value) { - gchar *p; + const char *p = value; - if (!value) + if (!p) return FALSE; - p = value; while (*p) { - if (!isxdigit (*p)) { + if (!isxdigit (*p++)) return FALSE; - } - p++; } return TRUE; } gboolean -is_ascii (gchar * value) +is_ascii (const char *value) { - gchar *p; + const char *p = value; - p = value; while (*p) { - if (!isascii (*p)) { + if (!isascii (*p++)) return FALSE; - } - p++; } return TRUE; } gboolean -is_true (char *str) +is_true (const char *str) { if (!g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "true")) @@ -220,7 +214,7 @@ find_gateway_str (char *str) } gboolean -reload_parsers () +reload_parsers (void) { ifnet_destroy (); wpa_parser_destroy (); @@ -231,7 +225,7 @@ reload_parsers () } gchar * -read_hostname (gchar * path) +read_hostname (const char *path) { gchar *contents = NULL, *result = NULL, *tmp; gchar **all_lines = NULL; @@ -260,21 +254,23 @@ read_hostname (gchar * path) } gboolean -write_hostname (const gchar * hostname, gchar * path) +write_hostname (const gchar *hostname, const char *path) { - gchar *contents = g_strdup_printf ("#Generated by NetworkManager\n" - "hostname=\"%s\"\n", hostname); - gboolean result = g_file_set_contents (path, contents, -1, NULL); + gboolean result; + char *contents; + contents = g_strdup_printf ("#Generated by NetworkManager\n" + "hostname=\"%s\"\n", hostname); + result = g_file_set_contents (path, contents, -1, NULL); g_free (contents); return result; } gboolean -is_static_ip4 (gchar * conn_name) +is_static_ip4 (const char *conn_name) { - gchar *data = ifnet_get_data (conn_name, "config"); - gchar *dhcp6; + const char *data = ifnet_get_data (conn_name, "config"); + const char *dhcp6; if (!data) return FALSE; @@ -295,9 +291,9 @@ is_static_ip4 (gchar * conn_name) } gboolean -is_static_ip6 (gchar * conn_name) +is_static_ip6 (const char *conn_name) { - gchar *data = ifnet_get_data (conn_name, "config"); + const char *data = ifnet_get_data (conn_name, "config"); if (!data) return TRUE; @@ -305,9 +301,9 @@ is_static_ip6 (gchar * conn_name) } gboolean -is_ip4_address (gchar * in_address) +is_ip4_address (const char *in_address) { - gchar *pattern = + const char *pattern = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.((\\{\\d{1,3}\\.\\.\\d{1,3}\\})|\\d{1,3})$"; gchar *address = g_strdup (in_address); gboolean result = FALSE; @@ -333,17 +329,15 @@ is_ip4_address (gchar * in_address) } gboolean -is_ip6_address (gchar * in_address) +is_ip6_address (const char *in_address) { struct in6_addr tmp_ip6_addr; - gchar *tmp; - gchar *address = g_strdup (in_address); + gchar *tmp, *address; gboolean result = FALSE; - if (!address) { - g_free (address); + if (!in_address) return FALSE; - } + address = g_strdup (in_address); g_strstrip (address); if ((tmp = strchr (address, '/')) != NULL) *tmp = '\0'; @@ -355,7 +349,7 @@ is_ip6_address (gchar * in_address) } gboolean -has_ip6_address (gchar * conn_name) +has_ip6_address (const char *conn_name) { gchar **ipset; guint length; @@ -378,29 +372,27 @@ has_ip6_address (gchar * conn_name) } gboolean -has_default_route (gchar * conn_name, gboolean (*check_fn) (gchar *)) +has_default_route (const char *conn_name, gboolean (*check_fn) (const char *)) { - gchar *routes = NULL, *tmp, *end; + char *routes = NULL, *end, *tmp; + gboolean success = FALSE; g_return_val_if_fail (conn_name != NULL, FALSE); - tmp = ifnet_get_data (conn_name, "routes"); - if (!tmp) + + routes = g_strdup (ifnet_get_data (conn_name, "routes")); + if (!routes) return FALSE; - routes = g_strdup (tmp); tmp = find_default_gateway_str (routes); - if (!tmp) { - goto error; + if (tmp) { + g_strstrip (tmp); + if ((end = strstr (tmp, "\"")) != NULL) + *end = '\0'; + if (check_fn (tmp)) + success = TRUE; } - g_strstrip (tmp); - if ((end = strstr (tmp, "\"")) != NULL) - *end = '\0'; - if (check_fn (tmp)) { - g_free (routes); - return TRUE; - } - error: + g_free (routes); - return FALSE; + return success; } static ip_block * @@ -563,28 +555,28 @@ get_ip6_next_hop (gchar * next_hop) } ip_block * -convert_ip4_config_block (gchar * conn_name) +convert_ip4_config_block (const char *conn_name) { gchar **ipset; guint length; guint i; gchar *ip; - guint32 def_gateway; - gchar *routes; + guint32 def_gateway = 0; + const char *routes; gchar *pos; ip_block *start = NULL, *current = NULL, *iblock = NULL; - gchar *pattern = + const char *pattern = "((\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.)\\{(\\d{1,3})\\.\\.(\\d{1,3})\\}(/\\d{1,2}))"; - GRegex *regex = g_regex_new (pattern, 0, 0, NULL); g_return_val_if_fail (conn_name != NULL, NULL); + ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0); length = g_strv_length (ipset); + routes = ifnet_get_data (conn_name, "routes"); if (routes) def_gateway = get_ip4_gateway (strstr (routes, "default")); - else - def_gateway = 0; + for (i = 0; i < length; i++) { ip = ipset[i]; ip = strip_string (ip, '"'); @@ -593,9 +585,13 @@ convert_ip4_config_block (gchar * conn_name) gchar *ip_start, *ip_prefix; gchar *begin_str, *end_str; int begin, end, j; + GRegex *regex; GMatchInfo *match_info; + regex = g_regex_new (pattern, 0, 0, NULL); g_regex_match (regex, ip, 0, &match_info); + g_regex_unref (regex); + if (!g_match_info_matches (match_info)) { g_match_info_free (match_info); continue; @@ -654,12 +650,11 @@ convert_ip4_config_block (gchar * conn_name) } } g_strfreev (ipset); - g_regex_unref (regex); return start; } ip6_block * -convert_ip6_config_block (gchar * conn_name) +convert_ip6_config_block (const char *conn_name) { gchar **ipset; guint length; @@ -688,16 +683,17 @@ convert_ip6_config_block (gchar * conn_name) } ip_block * -convert_ip4_routes_block (gchar * conn_name) +convert_ip4_routes_block (const char *conn_name) { gchar **ipset; guint length; guint i; gchar *ip; - gchar *routes; + const char *routes; ip_block *start = NULL, *current = NULL, *iblock = NULL; g_return_val_if_fail (conn_name != NULL, NULL); + routes = ifnet_get_data (conn_name, "routes"); if (!routes) return NULL; @@ -725,13 +721,13 @@ convert_ip4_routes_block (gchar * conn_name) } ip6_block * -convert_ip6_routes_block (gchar * conn_name) +convert_ip6_routes_block (const char *conn_name) { gchar **ipset; guint length; guint i; gchar *ip, *tmp_addr; - gchar *routes; + const char *routes; ip6_block *start = NULL, *current = NULL, *iblock = NULL; struct in6_addr *tmp_ip6_addr; @@ -798,18 +794,22 @@ destroy_ip6_block (ip6_block * iblock) } void -set_ip4_dns_servers (NMSettingIP4Config * s_ip4, gchar * conn_name) +set_ip4_dns_servers (NMSettingIP4Config *s_ip4, const char *conn_name) { - gchar *dns_servers = ifnet_get_data (conn_name, "dns_servers"); - gchar **server_list; + const char *dns_servers; + gchar **server_list, *stripped; guint length, i; struct in_addr tmp_ip4_addr; guint32 new_dns; + dns_servers = ifnet_get_data (conn_name, "dns_servers"); if (!dns_servers) return; - strip_string (dns_servers, '"'); - server_list = g_strsplit (dns_servers, " ", 0); + stripped = g_strdup (dns_servers); + strip_string (stripped, '"'); + server_list = g_strsplit (stripped, " ", 0); + g_free (stripped); + length = g_strv_length (server_list); if (length) g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, @@ -835,17 +835,22 @@ set_ip4_dns_servers (NMSettingIP4Config * s_ip4, gchar * conn_name) } void -set_ip6_dns_servers (NMSettingIP6Config * s_ip6, gchar * conn_name) +set_ip6_dns_servers (NMSettingIP6Config *s_ip6, const char *conn_name) { - gchar *dns_servers = ifnet_get_data (conn_name, "dns_servers"); - gchar **server_list; + const char *dns_servers; + gchar **server_list, *stripped; guint length, i; struct in6_addr tmp_ip6_addr; + dns_servers = ifnet_get_data (conn_name, "dns_servers"); if (!dns_servers) return; - strip_string (dns_servers, '"'); - server_list = g_strsplit (dns_servers, " ", 0); + + stripped = g_strdup (dns_servers); + strip_string (stripped, '"'); + server_list = g_strsplit (stripped, " ", 0); + g_free (stripped); + length = g_strv_length (server_list); if (length) g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, @@ -871,7 +876,7 @@ set_ip6_dns_servers (NMSettingIP6Config * s_ip6, gchar * conn_name) } gboolean -is_managed (gchar * conn_name) +is_managed (const char *conn_name) { gchar *config; @@ -887,7 +892,7 @@ is_managed (gchar * conn_name) void get_dhcp_hostname_and_client_id (char **hostname, char **client_id) { - gchar *dhcp_client = NULL; + const char *dhcp_client; const gchar *dhcpcd_conf = "/etc/dhcpcd.conf"; const gchar *dhclient_conf = "/etc/dhcp/dhclient.conf"; gchar *line = NULL, *tmp = NULL, *contents = NULL; @@ -904,7 +909,6 @@ get_dhcp_hostname_and_client_id (char **hostname, char **client_id) else if (!strcmp (dhcp_client, "dhcpcd")) g_file_get_contents (dhcpcd_conf, &contents, NULL, NULL); - g_free (dhcp_client); } else { if (g_file_test (dhclient_conf, G_FILE_TEST_IS_REGULAR)) g_file_get_contents (dhclient_conf, &contents, NULL, diff --git a/system-settings/plugins/ifnet/net_utils.h b/system-settings/plugins/ifnet/net_utils.h index ba7af39c27..42f8d67257 100644 --- a/system-settings/plugins/ifnet/net_utils.h +++ b/system-settings/plugins/ifnet/net_utils.h @@ -27,8 +27,8 @@ #include #include #include "net_parser.h" -#define has_default_ip4_route(conn_name) has_default_route((conn_name),&is_ip4_address) -#define has_default_ip6_route(conn_name) has_default_route((conn_name),&is_ip6_address) +#define has_default_ip4_route(conn_name) has_default_route((conn_name), &is_ip4_address) +#define has_default_ip6_route(conn_name) has_default_route((conn_name), &is_ip6_address) typedef struct _ip_block { guint32 ip; @@ -44,36 +44,36 @@ typedef struct _ip6_block { struct _ip6_block *next; } ip6_block; -gchar *read_hostname (gchar * path); -gboolean write_hostname (const gchar * hostname, gchar * path); -gboolean is_static_ip4 (gchar * conn_name); -gboolean is_static_ip6 (gchar * conn_name); -gboolean is_ip4_address (gchar * in_address); -gboolean is_ip6_address (gchar * in_address); -gboolean has_ip6_address (gchar * conn_name); -gboolean has_default_route (gchar * conn_name, gboolean (*check_fn) (gchar *)); +gchar *read_hostname (const char *path); +gboolean write_hostname (const char *hostname, const char *path); +gboolean is_static_ip4 (const char *conn_name); +gboolean is_static_ip6 (const char *conn_name); +gboolean is_ip4_address (const char *in_address); +gboolean is_ip6_address (const char *in_address); +gboolean has_ip6_address (const char *conn_name); +gboolean has_default_route (const char *conn_name, gboolean (*check_fn) (const char *)); gboolean reload_parsers (void); -ip_block *convert_ip4_config_block (gchar * conn_name); -ip6_block *convert_ip6_config_block (gchar * conn_name); -ip_block *convert_ip4_routes_block (gchar * conn_name); -ip6_block *convert_ip6_routes_block (gchar * conn_name); +ip_block *convert_ip4_config_block (const char *conn_name); +ip6_block *convert_ip6_config_block (const char *conn_name); +ip_block *convert_ip4_routes_block (const char *conn_name); +ip6_block *convert_ip6_routes_block (const char *conn_name); void destroy_ip_block (ip_block * iblock); void destroy_ip6_block (ip6_block * iblock); -void set_ip4_dns_servers (NMSettingIP4Config * s_ip4, gchar * conn_name); -void set_ip6_dns_servers (NMSettingIP6Config * s_ip6, gchar * conn_name); +void set_ip4_dns_servers (NMSettingIP4Config * s_ip4, const char *conn_name); +void set_ip6_dns_servers (NMSettingIP6Config * s_ip6, const char *conn_name); -gchar *strip_string (gchar * str, gchar t); -gboolean is_managed (gchar * conn_name); +gchar *strip_string (gchar *str, gchar t); +gboolean is_managed (const char *conn_name); GQuark ifnet_plugin_error_quark (void); gchar *utils_hexstr2bin (const gchar * hex, size_t len); gchar *utils_bin2hexstr (const gchar * bytes, int len, int final_len); -gboolean is_hex (gchar * value); -gboolean is_ascii (gchar * value); -gboolean is_true (gchar * str); +gboolean is_hex (const char *value); +gboolean is_ascii (const char *value); +gboolean is_true (const char *str); void get_dhcp_hostname_and_client_id (char **hostname, char **client_id); diff --git a/system-settings/plugins/ifnet/nm-ifnet-connection.c b/system-settings/plugins/ifnet/nm-ifnet-connection.c index e47495cfbe..16a21bafa2 100644 --- a/system-settings/plugins/ifnet/nm-ifnet-connection.c +++ b/system-settings/plugins/ifnet/nm-ifnet-connection.c @@ -24,9 +24,9 @@ #include #include #include -#include +#include #include -#include +#include #include "nm-ifnet-connection.h" #include "connection_parser.h" #include "net_parser.h" @@ -34,18 +34,8 @@ #include "wpa_parser.h" #include "plugin.h" -static NMSettingsConnectionInterface *parent_settings_connection_iface; +G_DEFINE_TYPE (NMIfnetConnection, nm_ifnet_connection, NM_TYPE_SETTINGS_CONNECTION) -static void settings_connection_interface_init (NMSettingsConnectionInterface * - klass); - -G_DEFINE_TYPE_EXTENDED (NMIfnetConnection, nm_ifnet_connection, - NM_TYPE_SYSCONFIG_CONNECTION, 0, - G_IMPLEMENT_INTERFACE - (NM_TYPE_SETTINGS_CONNECTION_INTERFACE, - settings_connection_interface_init)) -// G_DEFINE_TYPE(NMIfnetConnection, nm_ifnet_connection, -// NM_TYPE_SYSCONFIG_CONNECTION) #define NM_IFNET_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionPrivate)) enum { PROP_ZERO, @@ -67,26 +57,32 @@ typedef struct { } NMIfnetConnectionPrivate; NMIfnetConnection * -nm_ifnet_connection_new (gchar * conn_name) +nm_ifnet_connection_new (const char *conn_name, NMConnection *source) { NMConnection *tmp; GObject *object; GError **error = NULL; g_return_val_if_fail (conn_name != NULL, NULL); - tmp = ifnet_update_connection_from_config_block (conn_name, error); - if (!tmp) - return NULL; - object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION, - NM_IFNET_CONNECTION_CONN_NAME, - conn_name, NULL); + + if (source) + tmp = g_object_ref (source); + else { + tmp = ifnet_update_connection_from_config_block (conn_name, error); + if (!tmp) + return NULL; + } + + object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION, NULL); if (!object) { g_object_unref (tmp); return NULL; } - nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (object), tmp, - FALSE, NULL); + + NM_IFNET_CONNECTION_GET_PRIVATE (object)->conn_name = g_strdup (conn_name); + nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, NULL); g_object_unref (tmp); + return NM_IFNET_CONNECTION (object); } @@ -95,50 +91,47 @@ nm_ifnet_connection_init (NMIfnetConnection * connection) { } -static gboolean -update (NMSettingsConnectionInterface * connection, - NMSettingsConnectionInterfaceUpdateFunc callback, gpointer user_data) +static void +commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitFunc callback, + gpointer user_data) { GError *error = NULL; - gchar *new_conn_name = NULL; - gboolean result; - NMIfnetConnectionPrivate *priv = - NM_IFNET_CONNECTION_GET_PRIVATE (connection); + NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE (connection); + const char *new_name = NULL; + g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); - if (!ifnet_update_parsers_by_connection - (NM_CONNECTION (connection), priv->conn_name, &new_conn_name, - CONF_NET_FILE, WPA_SUPPLICANT_CONF, &error)) { - if (new_conn_name) - g_free (new_conn_name); - PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Failed to update %s", - priv->conn_name); + if (!ifnet_update_parsers_by_connection (NM_CONNECTION (connection), + priv->conn_name, + CONF_NET_FILE, + WPA_SUPPLICANT_CONF, + &new_name, + &error)) { + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Failed to update %s", priv->conn_name); reload_parsers (); callback (connection, error, user_data); g_error_free (error); g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); - return FALSE; + return; } g_free (priv->conn_name); - priv->conn_name = new_conn_name; - result = - parent_settings_connection_iface->update (connection, callback, - user_data); - if (result) - PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Successfully updated %s", - priv->conn_name); + priv->conn_name = g_strdup (new_name); + + NM_SETTINGS_CONNECTION_CLASS (nm_ifnet_connection_parent_class)->commit_changes (connection, callback, user_data); + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Successfully updated %s", priv->conn_name); + g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); - return result; } -static gboolean -do_delete (NMSettingsConnectionInterface * connection, - NMSettingsConnectionInterfaceDeleteFunc callback, gpointer user_data) +static void +do_delete (NMSettingsConnection *connection, + NMSettingsConnectionDeleteFunc callback, + gpointer user_data) { GError *error = NULL; - gboolean result; - NMIfnetConnectionPrivate *priv = - NM_IFNET_CONNECTION_GET_PRIVATE (connection); + NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE (connection); + g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); if (!ifnet_delete_connection_in_parsers (priv->conn_name, CONF_NET_FILE, WPA_SUPPLICANT_CONF)) { @@ -148,62 +141,14 @@ do_delete (NMSettingsConnectionInterface * connection, callback (connection, error, user_data); g_error_free (error); g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); - return FALSE; + return; } - result = - parent_settings_connection_iface->delete (connection, callback, - user_data); - if (result) - PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Successfully deleted %s", - priv->conn_name); + + NM_SETTINGS_CONNECTION_CLASS (nm_ifnet_connection_parent_class)->delete (connection, callback, user_data); + + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Successfully deleted %s", + priv->conn_name); g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); - return result; -} - -static void -settings_connection_interface_init (NMSettingsConnectionInterface * iface) -{ - parent_settings_connection_iface = g_type_interface_peek_parent (iface); - iface->update = update; - iface->delete = do_delete; -} - -static void -set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - NMIfnetConnectionPrivate *priv = - NM_IFNET_CONNECTION_GET_PRIVATE (object); - g_return_if_fail (priv); - - switch (prop_id) { - case PROP_CONN_NAME: - if (priv->conn_name) - g_free (priv->conn_name); - priv->conn_name = g_strdup (g_value_get_pointer (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - NMIfnetConnectionPrivate *priv = - NM_IFNET_CONNECTION_GET_PRIVATE (object); - g_return_if_fail (priv); - - switch (prop_id) { - case PROP_CONN_NAME: - g_value_set_pointer (value, priv->conn_name); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } } static void @@ -222,21 +167,15 @@ static void nm_ifnet_connection_class_init (NMIfnetConnectionClass * ifnet_connection_class) { GObjectClass *object_class = G_OBJECT_CLASS (ifnet_connection_class); + NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (ifnet_connection_class); g_type_class_add_private (ifnet_connection_class, sizeof (NMIfnetConnectionPrivate)); - object_class->set_property = set_property; - object_class->get_property = get_property; object_class->finalize = finalize; + settings_class->delete = do_delete; + settings_class->commit_changes = commit_changes; - /* Properties */ - g_object_class_install_property - (object_class, PROP_CONN_NAME, - g_param_spec_pointer (NM_IFNET_CONNECTION_CONN_NAME, - "config_block", - "", - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); signals[IFNET_SETUP_MONITORS] = g_signal_new ("ifnet_setup_monitors", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, diff --git a/system-settings/plugins/ifnet/nm-ifnet-connection.h b/system-settings/plugins/ifnet/nm-ifnet-connection.h index 8b3d495f0b..9423f20d71 100644 --- a/system-settings/plugins/ifnet/nm-ifnet-connection.h +++ b/system-settings/plugins/ifnet/nm-ifnet-connection.h @@ -22,28 +22,30 @@ #ifndef NM_IFNET_CONNECTION_H #define NM_IFNET_CONNECTION_H -#include +#include #include "net_parser.h" G_BEGIN_DECLS + #define NM_TYPE_IFNET_CONNECTION (nm_ifnet_connection_get_type ()) #define NM_IFNET_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnection)) #define NM_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass)) #define NM_IS_IFNET_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IFNET_CONNECTION)) #define NM_IS_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_IFNET_CONNECTION)) #define NM_IFNET_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass)) -#define NM_IFNET_CONNECTION_CONN_NAME "connection_name" - typedef struct { - NMSysconfigConnection parent; + +typedef struct { + NMSettingsConnection parent; } NMIfnetConnection; typedef struct { - NMSysconfigConnectionClass parent; + NMSettingsConnectionClass parent; } NMIfnetConnectionClass; GType nm_ifnet_connection_get_type (void); -NMIfnetConnection *nm_ifnet_connection_new (gchar * conn_name); +NMIfnetConnection *nm_ifnet_connection_new (const char *conn_name, + NMConnection *source); G_END_DECLS #endif /* NM_IFNET_CONNECTION_H */ diff --git a/system-settings/plugins/ifnet/plugin.c b/system-settings/plugins/ifnet/plugin.c index 94f9e791f5..f71acf6cf1 100644 --- a/system-settings/plugins/ifnet/plugin.c +++ b/system-settings/plugins/ifnet/plugin.c @@ -63,15 +63,12 @@ typedef struct { gpointer user_data; } FileMonitorInfo; -static void system_config_interface_init (NMSystemConfigInterface * - system_config_interface_class); +static void system_config_interface_init (NMSystemConfigInterface *class); -static void - reload_connections (gpointer config); +static void reload_connections (gpointer config); G_DEFINE_TYPE_EXTENDED (SCPluginIfnet, sc_plugin_ifnet, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, - system_config_interface_init)) + G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, system_config_interface_init)) #define SC_PLUGIN_IFNET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFNET, SCPluginIfnetPrivate)) /* static void @@ -126,20 +123,11 @@ write_system_hostname (NMSystemConfigInterface * config, static gboolean is_managed_plugin () { - gchar *result = NULL; + const char *result = NULL; - result = - ifnet_get_global_setting (IFNET_KEY_FILE_GROUP, - IFNET_KEY_FILE_KEY_MANAGED); - if (result) { - if (is_true (result)) { - g_free (result); - return TRUE; - } else { - g_free (result); - return FALSE; - } - } + result = ifnet_get_global_setting (IFNET_KEY_FILE_GROUP, IFNET_KEY_FILE_KEY_MANAGED); + if (result) + return is_true (result); return IFNET_MANAGE_WELL_KNOWN_DEFAULT; } @@ -194,24 +182,23 @@ monitor_file_changes (const char *filename, return monitor; } +/* Callback for nm_settings_connection_replace_and_commit. Report any errors + * encountered when commiting connection settings updates. */ static void -update_old_connection (gchar * conn_name, - NMIfnetConnection * old_conn, - NMIfnetConnection * new_conn, - SCPluginIfnetPrivate * priv) +commit_cb (NMSettingsConnection *connection, GError *error, gpointer unused) { - GError **error = NULL; + if (error) { + PLUGIN_WARN (IFNET_PLUGIN_NAME, " error updating: %s", + (error && error->message) ? error->message : "(unknown)"); + } else { + NMSettingConnection *s_con; - if (!nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (old_conn), - NM_CONNECTION (new_conn), TRUE, - error)) { - PLUGIN_WARN (IFNET_PLUGIN_NAME, "error updating: %s", - (error - && (*error)) ? (*error)->message : "(unknown)"); - } else + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), + NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Connection %s updated", - conn_name); - g_object_unref (new_conn); + nm_setting_connection_get_id (s_con)); + } } static void @@ -268,92 +255,85 @@ reload_connections (gpointer config) if (!reload_parsers ()) return; + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Loading connections"); + conn_names = ifnet_get_connection_names (); - new_conn_names = - g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + new_conn_names = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); for (n_iter = conn_names; n_iter; n_iter = g_list_next (n_iter)) { - NMIfnetConnection *exported; + NMIfnetConnection *new; NMIfnetConnection *old; - gchar *conn_name = g_strdup (n_iter->data); + const char *conn_name = n_iter->data; - /* add the new connection */ - exported = nm_ifnet_connection_new (conn_name); - if (!exported) { - g_free (conn_name); + /* read the new connection */ + new = nm_ifnet_connection_new (conn_name, NULL); + if (!new) continue; - } - g_signal_connect (G_OBJECT (exported), "ifnet_setup_monitors", - G_CALLBACK (setup_monitors), config); - g_signal_connect (G_OBJECT (exported), "ifnet_cancel_monitors", - G_CALLBACK (cancel_monitors), config); - old = g_hash_table_lookup (priv->config_connections, conn_name); - if (old && exported) { - gchar *auto_refresh = - ifnet_get_global_setting (IFNET_KEY_FILE_GROUP, - "auto_refresh"); + g_signal_connect (G_OBJECT (new), "ifnet_setup_monitors", + G_CALLBACK (setup_monitors), config); + g_signal_connect (G_OBJECT (new), "ifnet_cancel_monitors", + G_CALLBACK (cancel_monitors), config); + + old = g_hash_table_lookup (priv->config_connections, conn_name); + if (old && new) { + const char *auto_refresh; + + auto_refresh = ifnet_get_global_setting (IFNET_KEY_FILE_GROUP, "auto_refresh"); if (auto_refresh && is_true (auto_refresh)) { if (!nm_connection_compare (NM_CONNECTION (old), - NM_CONNECTION - (exported), - NM_SETTING_COMPARE_FLAG_EXACT)) - { - PLUGIN_PRINT (IFNET_PLUGIN_NAME, - "Auto refreshing %s", - conn_name); - g_signal_emit_by_name (old, - NM_SETTINGS_CONNECTION_INTERFACE_REMOVED); - g_hash_table_remove - (priv->config_connections, - conn_name); - g_hash_table_insert - (priv->config_connections, - g_strdup (conn_name), exported); + NM_CONNECTION (new), + NM_SETTING_COMPARE_FLAG_EXACT)) { + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Auto refreshing %s", conn_name); + + /* Remove and re-add to disconnect and reconnect with new settings */ + nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (old)); + g_hash_table_remove (priv->config_connections, conn_name); + g_hash_table_insert (priv->config_connections, g_strdup (conn_name), new); if (is_managed (conn_name)) - g_signal_emit_by_name (self, - NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, - exported); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new); } - } else - update_old_connection (conn_name, old, - exported, priv); - g_signal_emit_by_name (self, - NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); - } else if (exported) { - g_hash_table_insert (priv->config_connections, - g_strdup (conn_name), exported); + } else { + /* Update existing connection with new settings */ + nm_settings_connection_replace_and_commit (NM_SETTINGS_CONNECTION (old), + NM_CONNECTION (new), + commit_cb, NULL); + g_object_unref (new); + } + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + } else if (new) { + g_hash_table_insert (priv->config_connections, g_strdup (conn_name), new); if (is_managed (conn_name)) - g_signal_emit_by_name (self, - NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, - exported); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new); } - g_hash_table_insert (new_conn_names, conn_name, conn_name); + g_hash_table_insert (new_conn_names, (gpointer) conn_name, (gpointer) conn_name); } + /* remove unused connections */ g_hash_table_iter_init (&iter, priv->config_connections); while (g_hash_table_iter_next (&iter, &key, &value)) { if (!g_hash_table_lookup (new_conn_names, key)) { - g_signal_emit_by_name (value, - NM_SETTINGS_CONNECTION_INTERFACE_REMOVED); + nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (value)); g_hash_table_remove (priv->config_connections, key); } } - g_hash_table_remove_all (new_conn_names); g_hash_table_destroy (new_conn_names); g_list_free (conn_names); } -static gboolean -add_connection (NMSystemConfigInterface * config, - NMConnection * connection, GError ** error) +static NMSettingsConnection * +add_connection (NMSystemConfigInterface *config, + NMConnection *source, + GError **error) { - gboolean result; + NMIfnetConnection *connection = NULL; + char *conn_name; - result = ifnet_add_new_connection (connection, CONF_NET_FILE, - WPA_SUPPLICANT_CONF, error); + conn_name = ifnet_add_new_connection (source, CONF_NET_FILE, WPA_SUPPLICANT_CONF, error); + if (conn_name) + connection = nm_ifnet_connection_new (conn_name, source); reload_connections (config); - return result; + return connection ? NM_SETTINGS_CONNECTION (connection) : NULL; } static void @@ -423,7 +403,7 @@ SCPluginIfnet_init (NMSystemConfigInterface * config) g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, - NM_EXPORTED_CONNECTION (value)); + NM_CONNECTION (value)); } } /* Read hostname */ @@ -433,7 +413,7 @@ SCPluginIfnet_init (NMSystemConfigInterface * config) } static GSList * -SCPluginIfnet_get_connections (NMSystemConfigInterface * config) +get_connections (NMSystemConfigInterface * config) { SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config); GSList *connections = NULL; @@ -459,15 +439,12 @@ SCPluginIfnet_get_connections (NMSystemConfigInterface * config) } static void -system_config_interface_init (NMSystemConfigInterface * - system_config_interface_class) +system_config_interface_init (NMSystemConfigInterface *class) { - system_config_interface_class->init = SCPluginIfnet_init; - system_config_interface_class->get_connections = - SCPluginIfnet_get_connections; - system_config_interface_class->get_unmanaged_specs = - get_unmanaged_specs; - system_config_interface_class->add_connection = add_connection; + class->init = SCPluginIfnet_init; + class->get_connections = get_connections; + class->get_unmanaged_specs = get_unmanaged_specs; + class->add_connection = add_connection; } static void diff --git a/system-settings/plugins/ifnet/tests/Makefile.am b/system-settings/plugins/ifnet/tests/Makefile.am index 17a081f54a..a351f31ce5 100644 --- a/system-settings/plugins/ifnet/tests/Makefile.am +++ b/system-settings/plugins/ifnet/tests/Makefile.am @@ -2,7 +2,7 @@ INCLUDES=-I$(top_srcdir)/system-settings/plugins/ifnet\ -I$(top_srcdir)/libnm-glib \ -I$(top_srcdir)/libnm-util \ -I$(top_srcdir)/include \ - -I$(top_srcdir)/src/system-settings + -I$(top_srcdir)/src/settings TESTS = check_ifnet check_PROGRAMS = check_ifnet check_ifnet_SOURCES = test_all.c diff --git a/system-settings/plugins/ifnet/tests/test_all.c b/system-settings/plugins/ifnet/tests/test_all.c index eff76af284..2e9de7a21a 100644 --- a/system-settings/plugins/ifnet/tests/test_all.c +++ b/system-settings/plugins/ifnet/tests/test_all.c @@ -205,7 +205,7 @@ test_convert_ipv4_routes_block () static void test_wpa_parser () { - gchar *value; + const char *value; ASSERT (exist_ssid ("example"), "get wsec", "ssid myxjtu2 is not found"); @@ -279,25 +279,31 @@ test_update_connection () { GError **error = NULL; NMConnection *connection; + gboolean success; connection = ifnet_update_connection_from_config_block ("eth0", error); ASSERT (connection != NULL, "get connection", "get connection failed: %s", error == NULL ? "None" : (*error)->message); - ASSERT (ifnet_update_parsers_by_connection - (connection, "eth0", NULL, "net.generate", - "wpa_supplicant.conf.generate", error), - "update connection", "update connection failed %s", "eth0"); + + success = ifnet_update_parsers_by_connection (connection, "eth0", + "net.generate", + "wpa_supplicant.conf.generate", + NULL, + error); + ASSERT (success, "update connection", "update connection failed %s", "eth0"); g_object_unref (connection); - connection = - ifnet_update_connection_from_config_block ("0xab3ace", error); - ASSERT (connection != NULL, "get connection", - "get connection failed: %s", + + connection = ifnet_update_connection_from_config_block ("0xab3ace", error); + ASSERT (connection != NULL, "get connection", "get connection failed: %s", error == NULL ? "None" : (*error)->message); - ASSERT (ifnet_update_parsers_by_connection - (connection, "0xab3ace", NULL, "net.generate", - "wpa_supplicant.conf.generate", error), - "update connection", "update connection failed %s", "0xab3ace"); + + success = ifnet_update_parsers_by_connection (connection, "0xab3ace", + "net.generate", + "wpa_supplicant.conf.generate", + NULL, + error); + ASSERT (success, "update connection", "update connection failed %s", "0xab3ace"); g_object_unref (connection); } diff --git a/system-settings/plugins/ifnet/wpa_parser.c b/system-settings/plugins/ifnet/wpa_parser.c index 5e94108e98..a3ca5225aa 100644 --- a/system-settings/plugins/ifnet/wpa_parser.c +++ b/system-settings/plugins/ifnet/wpa_parser.c @@ -35,7 +35,7 @@ static GHashTable *wsec_global_table = NULL; static gboolean wpa_parser_data_changed = FALSE; static long -wpa_get_long (GHashTable * table, gchar * key) +wpa_get_long (GHashTable *table, const char *key) { return atol (g_hash_table_lookup (table, key)); } @@ -57,14 +57,15 @@ destroy_security (GHashTable * network) } static GHashTable * -add_security (GHashTable * security) +add_security (GHashTable *security) { GHashTable *oldsecurity; - gchar *ssid = g_hash_table_lookup (security, "ssid"), *ssid_key; - gchar *value; + const char *ssid, *value; + char *ssid_key; gboolean is_hex_ssid; /* Every security information should have a ssid */ + ssid = g_hash_table_lookup (security, "ssid"); if (!ssid) { destroy_security (security); return NULL; @@ -181,7 +182,7 @@ add_keys_from_net () while (iter) { gchar *conn_name = iter->data; GHashTable *table; - gchar *key_str; + const char *key_str; if ((key_str = ifnet_get_data (conn_name, "key")) == NULL) { iter = g_list_next (iter); @@ -247,7 +248,7 @@ add_global_data (gchar * line) } void -wpa_parser_init (gchar * wpa_supplicant_conf) +wpa_parser_init (const char *wpa_supplicant_conf) { GIOChannel *channel = NULL; gchar *line; @@ -315,8 +316,8 @@ wpa_parser_init (gchar * wpa_supplicant_conf) add_keys_from_net (); } -gchar * -wpa_get_value (gchar * ssid, gchar * key) +const char * +wpa_get_value (const char *ssid, const char *key) { GHashTable *target = g_hash_table_lookup (wsec_table, ssid); @@ -326,13 +327,13 @@ wpa_get_value (gchar * ssid, gchar * key) } gboolean -exist_ssid (gchar * ssid) +exist_ssid (const char *ssid) { return g_hash_table_lookup (wsec_table, ssid) != NULL; } GHashTable * -_get_hash_table (gchar * ssid) +_get_hash_table (const char *ssid) { return g_hash_table_lookup (wsec_table, ssid); } @@ -355,7 +356,7 @@ need_quote (gchar * key) } gboolean -wpa_flush_to_file (gchar * config_file) +wpa_flush_to_file (const char *config_file) { GIOChannel *channel; GError **error = NULL; @@ -446,7 +447,7 @@ wpa_flush_to_file (gchar * config_file) /* If value is NULL, this method will delete old key value pair */ void -wpa_set_data (gchar * ssid, gchar * key, gchar * value) +wpa_set_data (const char *ssid, const char *key, const char *value) { gpointer orig_key = NULL, orig_value = NULL; GHashTable *security = g_hash_table_lookup (wsec_table, ssid); @@ -474,13 +475,13 @@ wpa_set_data (gchar * ssid, gchar * key, gchar * value) } gboolean -wpa_has_security (gchar * ssid) +wpa_has_security (const char *ssid) { return g_hash_table_lookup (wsec_table, ssid) != NULL; } gboolean -wpa_add_security (gchar * ssid) +wpa_add_security (const char *ssid) { if (wpa_has_security (ssid)) return FALSE; @@ -508,7 +509,7 @@ wpa_add_security (gchar * ssid) } gboolean -wpa_delete_security (gchar * ssid) +wpa_delete_security (const char *ssid) { gpointer orig_key, orig_value; diff --git a/system-settings/plugins/ifnet/wpa_parser.h b/system-settings/plugins/ifnet/wpa_parser.h index 55b0ec0c60..7fd77a0560 100644 --- a/system-settings/plugins/ifnet/wpa_parser.h +++ b/system-settings/plugins/ifnet/wpa_parser.h @@ -23,18 +23,18 @@ #define _WPA_PARSER_H #define WPA_SUPPLICANT_CONF "/etc/wpa_supplicant/wpa_supplicant.conf" #include -void wpa_parser_init (gchar * wpa_supplicant_conf); +void wpa_parser_init (const char *wpa_supplicant_conf); void wpa_parser_destroy (void); /* reader functions */ -gchar *wpa_get_value (gchar * ssid, gchar * key); -gboolean exist_ssid (gchar * ssid); -GHashTable *_get_hash_table (gchar * ssid); -gboolean wpa_has_security (gchar * ssid); +const char *wpa_get_value (const char *ssid, const char *key); +gboolean exist_ssid (const char *ssid); +GHashTable *_get_hash_table (const char *ssid); +gboolean wpa_has_security (const char *ssid); /* writer functions */ -gboolean wpa_flush_to_file (gchar * config_file); -void wpa_set_data (gchar * ssid, gchar * key, gchar * value); -gboolean wpa_add_security (gchar * ssid); -gboolean wpa_delete_security (gchar * ssid); +gboolean wpa_flush_to_file (const char *config_file); +void wpa_set_data (const char *ssid, const char *key, const char *value); +gboolean wpa_add_security (const char *ssid); +gboolean wpa_delete_security (const char *ssid); #endif diff --git a/system-settings/plugins/ifupdown/Makefile.am b/system-settings/plugins/ifupdown/Makefile.am index 652e545fce..1bbcc19282 100644 --- a/system-settings/plugins/ifupdown/Makefile.am +++ b/system-settings/plugins/ifupdown/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS=. tests INCLUDES = \ - -I$(top_srcdir)/src/system-settings \ + -I$(top_srcdir)/src/settings \ -I$(top_srcdir)/include \ -I$(top_srcdir)/libnm-glib \ -I$(top_srcdir)/libnm-util diff --git a/system-settings/plugins/ifupdown/nm-ifupdown-connection.c b/system-settings/plugins/ifupdown/nm-ifupdown-connection.c index ad9a479a6a..0cc73b34f6 100644 --- a/system-settings/plugins/ifupdown/nm-ifupdown-connection.c +++ b/system-settings/plugins/ifupdown/nm-ifupdown-connection.c @@ -26,13 +26,13 @@ #include #include #include -#include +#include #include -#include +#include #include "nm-ifupdown-connection.h" #include "parser.h" -G_DEFINE_TYPE (NMIfupdownConnection, nm_ifupdown_connection, NM_TYPE_SYSCONFIG_CONNECTION) +G_DEFINE_TYPE (NMIfupdownConnection, nm_ifupdown_connection, NM_TYPE_SETTINGS_CONNECTION) #define NM_IFUPDOWN_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IFUPDOWN_CONNECTION, NMIfupdownConnectionPrivate)) @@ -57,31 +57,12 @@ nm_ifupdown_connection_new (if_block *block) NULL); } -static void -get_secrets (NMExportedConnection *exported, - const gchar *setting_name, - const gchar **hints, - gboolean request_new, - DBusGMethodInvocation *context) +static gboolean +supports_secrets (NMSettingsConnection *connection, const char *setting_name) { - GError *error = NULL; + PLUGIN_PRINT ("SCPlugin-Ifupdown", "supports_secrets() for setting_name: '%s'", setting_name); - PLUGIN_PRINT ("SCPlugin-Ifupdown", "get_secrets() for setting_name:'%s'", setting_name); - - /* FIXME: Only wifi secrets are supported for now */ - if (strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME)) { - g_set_error (&error, - NM_SYSCONFIG_SETTINGS_ERROR, - NM_SYSCONFIG_SETTINGS_ERROR_GENERAL, - "%s.%d - security setting name not supported '%s'.", - __FILE__, __LINE__, setting_name); - PLUGIN_PRINT ("SCPlugin-Ifupdown", "%s", error->message); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - NM_EXPORTED_CONNECTION_CLASS (nm_ifupdown_connection_parent_class)->get_secrets (exported, setting_name, hints, request_new, context); + return (strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0); } static void @@ -165,7 +146,7 @@ static void nm_ifupdown_connection_class_init (NMIfupdownConnectionClass *ifupdown_connection_class) { GObjectClass *object_class = G_OBJECT_CLASS (ifupdown_connection_class); - NMExportedConnectionClass *connection_class = NM_EXPORTED_CONNECTION_CLASS (ifupdown_connection_class); + NMSettingsConnectionClass *connection_class = NM_SETTINGS_CONNECTION_CLASS (ifupdown_connection_class); g_type_class_add_private (ifupdown_connection_class, sizeof (NMIfupdownConnectionPrivate)); @@ -174,7 +155,7 @@ nm_ifupdown_connection_class_init (NMIfupdownConnectionClass *ifupdown_connectio object_class->set_property = set_property; object_class->get_property = get_property; - connection_class->get_secrets = get_secrets; + connection_class->supports_secrets = supports_secrets; /* Properties */ g_object_class_install_property diff --git a/system-settings/plugins/ifupdown/nm-ifupdown-connection.h b/system-settings/plugins/ifupdown/nm-ifupdown-connection.h index 2aa74df6b7..510a4d56ab 100644 --- a/system-settings/plugins/ifupdown/nm-ifupdown-connection.h +++ b/system-settings/plugins/ifupdown/nm-ifupdown-connection.h @@ -24,7 +24,7 @@ #ifndef NM_IFUPDOWN_CONNECTION_H #define NM_IFUPDOWN_CONNECTION_H -#include +#include #include "interface_parser.h" G_BEGIN_DECLS @@ -39,11 +39,11 @@ G_BEGIN_DECLS #define NM_IFUPDOWN_CONNECTION_IFBLOCK "ifblock" typedef struct { - NMSysconfigConnection parent; + NMSettingsConnection parent; } NMIfupdownConnection; typedef struct { - NMSysconfigConnectionClass parent; + NMSettingsConnectionClass parent; } NMIfupdownConnectionClass; GType nm_ifupdown_connection_get_type (void); diff --git a/system-settings/plugins/ifupdown/plugin.c b/system-settings/plugins/ifupdown/plugin.c index 8cfbedcd64..9944546cb5 100644 --- a/system-settings/plugins/ifupdown/plugin.c +++ b/system-settings/plugins/ifupdown/plugin.c @@ -179,7 +179,7 @@ sc_plugin_ifupdown_class_init (SCPluginIfupdownClass *req_class) } static void -ignore_cb (NMSettingsConnectionInterface *connection, +ignore_cb (NMSettingsConnection *connection, GError *error, gpointer user_data) { @@ -229,9 +229,7 @@ bind_device_to_connection (SCPluginIfupdown *self, } g_byte_array_free (mac_address, TRUE); - nm_settings_connection_interface_update (NM_SETTINGS_CONNECTION_INTERFACE (exported), - ignore_cb, - NULL); + nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), ignore_cb, NULL); } static void @@ -411,9 +409,7 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config) exported = g_hash_table_lookup (priv->iface_connections, block->name); if (exported) { PLUGIN_PRINT("SCPlugin-Ifupdown", "deleting %s from iface_connections", block->name); - nm_settings_connection_interface_delete (NM_SETTINGS_CONNECTION_INTERFACE (exported), - ignore_cb, - NULL); + nm_settings_connection_delete (NM_SETTINGS_CONNECTION (exported), ignore_cb, NULL); g_hash_table_remove (priv->iface_connections, block->name); } @@ -446,9 +442,7 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config) setting = NM_SETTING (nm_connection_get_setting (NM_CONNECTION (exported), NM_TYPE_SETTING_CONNECTION)); g_object_set (setting, NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NULL); - nm_settings_connection_interface_update (NM_SETTINGS_CONNECTION_INTERFACE (exported), - ignore_cb, - NULL); + nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), ignore_cb, NULL); PLUGIN_PRINT("SCPlugin-Ifupdown", "autoconnect"); } @@ -507,7 +501,7 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config) for (cl_iter = con_list; cl_iter; cl_iter = g_list_next (cl_iter)) { g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, - NM_EXPORTED_CONNECTION (cl_iter->data)); + NM_SETTINGS_CONNECTION (cl_iter->data)); } g_list_free (con_list); } diff --git a/system-settings/plugins/keyfile/Makefile.am b/system-settings/plugins/keyfile/Makefile.am index 128775ee97..3b24214220 100644 --- a/system-settings/plugins/keyfile/Makefile.am +++ b/system-settings/plugins/keyfile/Makefile.am @@ -1,14 +1,15 @@ SUBDIRS=. tests INCLUDES = \ - -I$(top_srcdir)/src/system-settings \ + -I$(top_srcdir)/src/settings \ -I$(top_srcdir)/include \ - -I$(top_srcdir)/libnm-util \ - -I$(top_srcdir)/libnm-glib + -I$(top_srcdir)/libnm-util -pkglib_LTLIBRARIES = libnm-settings-plugin-keyfile.la +noinst_LTLIBRARIES = \ + libkeyfile-io.la \ + libnm-settings-plugin-keyfile.la -noinst_LTLIBRARIES = libkeyfile-io.la +##### I/O library for testcases ##### libkeyfile_io_la_SOURCES = \ reader.c \ @@ -28,6 +29,8 @@ libkeyfile_io_la_CPPFLAGS = \ libkeyfile_io_la_LIBADD = $(GLIB_LIBS) +##################################### + libnm_settings_plugin_keyfile_la_SOURCES = \ nm-keyfile-connection.c \ nm-keyfile-connection.h \ @@ -41,16 +44,16 @@ libnm_settings_plugin_keyfile_la_CPPFLAGS = \ -DSYSCONFDIR=\"$(sysconfdir)\" \ -DG_DISABLE_DEPRECATED -libnm_settings_plugin_keyfile_la_LDFLAGS = -module -avoid-version libnm_settings_plugin_keyfile_la_LIBADD = \ $(top_builddir)/libnm-util/libnm-util.la \ - $(top_builddir)/libnm-glib/libnm-glib.la \ libkeyfile-io.la \ $(GLIB_LIBS) \ $(GMODULE_LIBS) \ $(DBUS_LIBS) \ $(GIO_LIBS) +libnm_settings_plugin_keyfile_la_LDFLAGS = -rdynamic + keyfiledir=$(sysconfdir)/NetworkManager/system-connections install-data-hook: diff --git a/system-settings/plugins/keyfile/nm-keyfile-connection.c b/system-settings/plugins/keyfile/nm-keyfile-connection.c index 3c27a54c79..23618f7c2b 100644 --- a/system-settings/plugins/keyfile/nm-keyfile-connection.c +++ b/system-settings/plugins/keyfile/nm-keyfile-connection.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 - 2010 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. */ #include @@ -24,7 +24,6 @@ #include #include #include -#include #include "nm-system-config-interface.h" #include "nm-dbus-glib-types.h" @@ -33,134 +32,115 @@ #include "writer.h" #include "common.h" -static NMSettingsConnectionInterface *parent_settings_connection_iface; - -static void settings_connection_interface_init (NMSettingsConnectionInterface *klass); - -G_DEFINE_TYPE_EXTENDED (NMKeyfileConnection, nm_keyfile_connection, NM_TYPE_SYSCONFIG_CONNECTION, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE, - settings_connection_interface_init)) +G_DEFINE_TYPE (NMKeyfileConnection, nm_keyfile_connection, NM_TYPE_SETTINGS_CONNECTION) #define NM_KEYFILE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_KEYFILE_CONNECTION, NMKeyfileConnectionPrivate)) typedef struct { - char *filename; + char *path; } NMKeyfileConnectionPrivate; -enum { - PROP_0, - PROP_FILENAME, - - LAST_PROP -}; - NMKeyfileConnection * -nm_keyfile_connection_new (const char *filename, GError **error) +nm_keyfile_connection_new (const char *full_path, + NMConnection *source, + GError **error) { GObject *object; NMKeyfileConnectionPrivate *priv; - NMSettingConnection *s_con; NMConnection *tmp; + const char *uuid; - g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (full_path != NULL, NULL); - tmp = connection_from_file (filename, error); - if (!tmp) - return NULL; - - object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION, - NM_KEYFILE_CONNECTION_FILENAME, filename, - NULL); - if (!object) { - g_object_unref (tmp); - return NULL; + /* If we're given a connection already, prefer that instead of re-reading */ + if (source) + tmp = g_object_ref (source); + else { + tmp = nm_keyfile_plugin_connection_from_file (full_path, error); + if (!tmp) + return NULL; } + object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION, NULL); + if (!object) + goto out; + priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (object); - g_assert (priv->filename); + priv->path = g_strdup (full_path); /* Update our settings with what was read from the file */ - nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (object), tmp, FALSE, NULL); - g_object_unref (tmp); - - /* if for some reason the connection didn't have a UUID, add one */ - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (object), NM_TYPE_SETTING_CONNECTION); - if (s_con && !nm_setting_connection_get_uuid (s_con)) { - GError *write_error = NULL; - char *uuid; - - uuid = nm_utils_uuid_generate (); - g_object_set (s_con, NM_SETTING_CONNECTION_UUID, uuid, NULL); - g_free (uuid); - - if (!write_connection (NM_CONNECTION (object), KEYFILE_DIR, 0, 0, NULL, &write_error)) { - PLUGIN_WARN (KEYFILE_PLUGIN_NAME, - "Couldn't update connection %s with a UUID: (%d) %s", - nm_setting_connection_get_id (s_con), - write_error ? write_error->code : -1, - (write_error && write_error->message) ? write_error->message : "(unknown)"); - g_propagate_error (error, write_error); - } + if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, error)) { + g_object_unref (object); + object = NULL; + goto out; } - return NM_KEYFILE_CONNECTION (object); + uuid = nm_connection_get_uuid (NM_CONNECTION (object)); + if (!uuid) { + g_set_error (error, KEYFILE_PLUGIN_ERROR, 0, + "Connection in file %s had no UUID", full_path); + g_object_unref (object); + object = NULL; + } + +out: + g_object_unref (tmp); + return (NMKeyfileConnection *) object; } const char * -nm_keyfile_connection_get_filename (NMKeyfileConnection *self) +nm_keyfile_connection_get_path (NMKeyfileConnection *self) { g_return_val_if_fail (NM_IS_KEYFILE_CONNECTION (self), NULL); - return NM_KEYFILE_CONNECTION_GET_PRIVATE (self)->filename; + return NM_KEYFILE_CONNECTION_GET_PRIVATE (self)->path; } -static gboolean -update (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceUpdateFunc callback, - gpointer user_data) +static void +commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitFunc callback, + gpointer user_data) { NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (connection); - char *filename = NULL; + char *path = NULL; GError *error = NULL; - if (!write_connection (NM_CONNECTION (connection), KEYFILE_DIR, 0, 0, &filename, &error)) { + if (!nm_keyfile_plugin_write_connection (NM_CONNECTION (connection), + priv->path, + &path, + &error)) { callback (connection, error, user_data); g_clear_error (&error); - return FALSE; + return; } - if (g_strcmp0 (priv->filename, filename)) { - /* Update the filename if it changed */ - g_free (priv->filename); - priv->filename = filename; - } else - g_free (filename); + /* Update the filename if it changed */ + if (path) { + g_free (priv->path); + priv->path = path; + } - return parent_settings_connection_iface->update (connection, callback, user_data); + NM_SETTINGS_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->commit_changes (connection, + callback, + user_data); } -static gboolean -do_delete (NMSettingsConnectionInterface *connection, - NMSettingsConnectionInterfaceDeleteFunc callback, - gpointer user_data) +static void +do_delete (NMSettingsConnection *connection, + NMSettingsConnectionDeleteFunc callback, + gpointer user_data) { NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (connection); - g_unlink (priv->filename); + g_unlink (priv->path); - return parent_settings_connection_iface->delete (connection, callback, user_data); + NM_SETTINGS_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->delete (connection, + callback, + user_data); } /* GObject */ -static void -settings_connection_interface_init (NMSettingsConnectionInterface *iface) -{ - parent_settings_connection_iface = g_type_interface_peek_parent (iface); - iface->update = update; - iface->delete = do_delete; -} - static void nm_keyfile_connection_init (NMKeyfileConnection *connection) { @@ -173,62 +153,21 @@ finalize (GObject *object) nm_connection_clear_secrets (NM_CONNECTION (object)); - g_free (priv->filename); + g_free (priv->path); G_OBJECT_CLASS (nm_keyfile_connection_parent_class)->finalize (object); } -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_FILENAME: - /* Construct only */ - priv->filename = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_FILENAME: - g_value_set_string (value, priv->filename); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void nm_keyfile_connection_class_init (NMKeyfileConnectionClass *keyfile_connection_class) { GObjectClass *object_class = G_OBJECT_CLASS (keyfile_connection_class); + NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (keyfile_connection_class); g_type_class_add_private (keyfile_connection_class, sizeof (NMKeyfileConnectionPrivate)); /* Virtual methods */ - object_class->set_property = set_property; - object_class->get_property = get_property; object_class->finalize = finalize; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_FILENAME, - g_param_spec_string (NM_KEYFILE_CONNECTION_FILENAME, - "FileName", - "File name", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + settings_class->commit_changes = commit_changes; + settings_class->delete = do_delete; } diff --git a/system-settings/plugins/keyfile/nm-keyfile-connection.h b/system-settings/plugins/keyfile/nm-keyfile-connection.h index 68e795a6ce..bf64e69a3a 100644 --- a/system-settings/plugins/keyfile/nm-keyfile-connection.h +++ b/system-settings/plugins/keyfile/nm-keyfile-connection.h @@ -16,13 +16,13 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. */ #ifndef NM_KEYFILE_CONNECTION_H #define NM_KEYFILE_CONNECTION_H -#include +#include G_BEGIN_DECLS @@ -33,21 +33,21 @@ G_BEGIN_DECLS #define NM_IS_KEYFILE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_KEYFILE_CONNECTION)) #define NM_KEYFILE_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_KEYFILE_CONNECTION, NMKeyfileConnectionClass)) -#define NM_KEYFILE_CONNECTION_FILENAME "filename" - typedef struct { - NMSysconfigConnection parent; + NMSettingsConnection parent; } NMKeyfileConnection; typedef struct { - NMSysconfigConnectionClass parent; + NMSettingsConnectionClass parent; } NMKeyfileConnectionClass; GType nm_keyfile_connection_get_type (void); -NMKeyfileConnection *nm_keyfile_connection_new (const char *filename, GError **error); +NMKeyfileConnection *nm_keyfile_connection_new (const char *filename, + NMConnection *source, + GError **error); -const char *nm_keyfile_connection_get_filename (NMKeyfileConnection *self); +const char *nm_keyfile_connection_get_path (NMKeyfileConnection *self); G_END_DECLS diff --git a/system-settings/plugins/keyfile/plugin.c b/system-settings/plugins/keyfile/plugin.c index da6456d983..68f51dc4ae 100644 --- a/system-settings/plugins/keyfile/plugin.c +++ b/system-settings/plugins/keyfile/plugin.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 - 2010 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. */ #include @@ -69,10 +69,31 @@ typedef struct { gboolean disposed; } SCPluginKeyfilePrivate; +static NMSettingsConnection * +_internal_new_connection (SCPluginKeyfile *self, + const char *full_path, + NMConnection *source, + GError **error) +{ + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + NMKeyfileConnection *connection; + + g_return_val_if_fail (full_path != NULL, NULL); + + connection = nm_keyfile_connection_new (full_path, source, error); + if (connection) { + g_hash_table_insert (priv->hash, + (gpointer) nm_keyfile_connection_get_path (connection), + connection); + } + + return (NMSettingsConnection *) connection; +} + static void read_connections (NMSystemConfigInterface *config) { - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); + SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); GDir *dir; GError *error = NULL; const char *item; @@ -88,82 +109,51 @@ read_connections (NMSystemConfigInterface *config) } while ((item = g_dir_read_name (dir))) { - NMKeyfileConnection *connection; + NMSettingsConnection *connection; char *full_path; - if (utils_should_ignore_file (item)) + if (nm_keyfile_plugin_utils_should_ignore_file (item)) continue; full_path = g_build_filename (KEYFILE_DIR, item, NULL); PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "parsing %s ... ", item); - connection = nm_keyfile_connection_new (full_path, &error); + + connection = _internal_new_connection (self, full_path, NULL, &error); if (connection) { - NMSettingConnection *s_con; - const char *cid; - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); - g_assert (s_con); - - cid = nm_setting_connection_get_id (s_con); - g_assert (cid); - - g_hash_table_insert (priv->hash, - (gpointer) nm_keyfile_connection_get_filename (connection), - connection); - - PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " read connection '%s'", cid); + PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " read connection '%s'", + nm_connection_get_id (NM_CONNECTION (connection))); } else { PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error: %s", (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); } + g_clear_error (&error); g_free (full_path); } g_dir_close (dir); } -typedef struct { - const char *uuid; - NMKeyfileConnection *found; -} FindByUUIDInfo; - static void -find_by_uuid (gpointer key, gpointer data, gpointer user_data) +update_connection_settings_commit_cb (NMSettingsConnection *orig, GError *error, gpointer user_data) { - NMKeyfileConnection *keyfile = NM_KEYFILE_CONNECTION (data); - FindByUUIDInfo *info = user_data; - NMSettingConnection *s_con; - const char *uuid; + 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); - if (info->found) - return; - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (keyfile), NM_TYPE_SETTING_CONNECTION); - - uuid = s_con ? nm_setting_connection_get_uuid (s_con) : NULL; - if (uuid && !strcmp (info->uuid, uuid)) - info->found = keyfile; + nm_settings_connection_signal_remove (orig); + } } static void update_connection_settings (NMKeyfileConnection *orig, NMKeyfileConnection *new) { - GError *error = NULL; - - if (!nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (orig), - NM_CONNECTION (new), - TRUE, - &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); - - g_signal_emit_by_name (orig, "removed"); - } + nm_settings_connection_replace_and_commit (NM_SETTINGS_CONNECTION (orig), + NM_CONNECTION (new), + update_connection_settings_commit_cb, NULL); } /* Monitoring */ @@ -179,10 +169,29 @@ remove_connection (SCPluginKeyfile *self, /* Removing from the hash table should drop the last reference */ g_object_ref (connection); g_hash_table_remove (SC_PLUGIN_KEYFILE_GET_PRIVATE (self)->hash, name); - g_signal_emit_by_name (connection, "removed"); + nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection)); g_object_unref (connection); } +static NMKeyfileConnection * +find_by_uuid (SCPluginKeyfile *self, const char *uuid) +{ + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + GHashTableIter iter; + gpointer data = NULL; + + g_return_val_if_fail (uuid != NULL, NULL); + + g_hash_table_iter_init (&iter, priv->hash); + while (g_hash_table_iter_next (&iter, NULL, &data)) { + NMConnection *candidate = NM_CONNECTION (data); + + if (strcmp (uuid, nm_connection_get_uuid (candidate)) == 0) + return NM_KEYFILE_CONNECTION (candidate); + } + return NULL; +} + static void dir_changed (GFileMonitor *monitor, GFile *file, @@ -191,24 +200,25 @@ dir_changed (GFileMonitor *monitor, gpointer user_data) { NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data); - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); - char *name; + SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + char *full_path; NMKeyfileConnection *connection; GError *error = NULL; - name = g_file_get_path (file); - if (utils_should_ignore_file (name)) { - g_free (name); + full_path = g_file_get_path (file); + if (nm_keyfile_plugin_utils_should_ignore_file (full_path)) { + g_free (full_path); return; } - connection = g_hash_table_lookup (priv->hash, name); + connection = g_hash_table_lookup (priv->hash, full_path); switch (event_type) { case G_FILE_MONITOR_EVENT_DELETED: if (connection) { - PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "removed %s.", name); - remove_connection (SC_PLUGIN_KEYFILE (config), connection, name); + PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "removed %s.", full_path); + remove_connection (SC_PLUGIN_KEYFILE (config), connection, full_path); } break; case G_FILE_MONITOR_EVENT_CREATED: @@ -217,12 +227,12 @@ dir_changed (GFileMonitor *monitor, /* Update */ NMKeyfileConnection *tmp; - tmp = nm_keyfile_connection_new (name, &error); + tmp = nm_keyfile_connection_new (full_path, NULL, &error); if (tmp) { if (!nm_connection_compare (NM_CONNECTION (connection), NM_CONNECTION (tmp), NM_SETTING_COMPARE_FLAG_EXACT)) { - PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", name); + PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", full_path); update_connection_settings (connection, tmp); } g_object_unref (tmp); @@ -231,42 +241,35 @@ dir_changed (GFileMonitor *monitor, PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error: %s", (error && error->message) ? error->message : "(unknown)"); g_clear_error (&error); - remove_connection (SC_PLUGIN_KEYFILE (config), connection, name); + remove_connection (SC_PLUGIN_KEYFILE (config), connection, full_path); } } else { - PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", name); + PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", full_path); /* New */ - connection = nm_keyfile_connection_new (name, &error); + connection = nm_keyfile_connection_new (full_path, NULL, &error); if (connection) { - NMSettingConnection *s_con; - const char *connection_uuid; NMKeyfileConnection *found = NULL; + NMSettingConnection *s_con; /* Connection renames will show up as different files but with * the same UUID. Try to find the original connection. */ s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); - connection_uuid = s_con ? nm_setting_connection_get_uuid (s_con) : NULL; - - if (connection_uuid) { - FindByUUIDInfo info = { .found = NULL, .uuid = connection_uuid }; - - g_hash_table_foreach (priv->hash, find_by_uuid, &info); - found = info.found; - } + g_assert (s_con); /* A connection rename is treated just like an update except * there's a bit more housekeeping with the hash table. */ + found = find_by_uuid (self, nm_setting_connection_get_uuid (s_con)); if (found) { - const char *old_filename = nm_keyfile_connection_get_filename (connection); + const char *old_path = nm_keyfile_connection_get_path (connection); /* Removing from the hash table should drop the last reference, * but of course we want to keep the connection around. */ g_object_ref (found); - g_hash_table_remove (priv->hash, old_filename); + g_hash_table_remove (priv->hash, old_path); /* Updating settings should update the NMKeyfileConnection's * filename property too. @@ -275,14 +278,14 @@ dir_changed (GFileMonitor *monitor, /* Re-insert the connection back into the hash with the new filename */ g_hash_table_insert (priv->hash, - (gpointer) nm_keyfile_connection_get_filename (found), + (gpointer) nm_keyfile_connection_get_path (found), found); /* Get rid of the temporary connection */ g_object_unref (connection); } else { g_hash_table_insert (priv->hash, - (gpointer) nm_keyfile_connection_get_filename (connection), + (gpointer) nm_keyfile_connection_get_path (connection), connection); g_signal_emit_by_name (config, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection); } @@ -297,7 +300,7 @@ dir_changed (GFileMonitor *monitor, break; } - g_free (name); + g_free (full_path); } static void @@ -365,38 +368,42 @@ setup_monitoring (NMSystemConfigInterface *config) } } -static void -hash_to_slist (gpointer key, gpointer value, gpointer user_data) -{ - GSList **list = (GSList **) user_data; - - *list = g_slist_prepend (*list, value); -} - /* Plugin */ static GSList * get_connections (NMSystemConfigInterface *config) { SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); - GSList *connections = NULL; + GHashTableIter iter; + gpointer data = NULL; + GSList *list = NULL; if (!priv->hash) { setup_monitoring (config); read_connections (config); } - g_hash_table_foreach (priv->hash, hash_to_slist, &connections); - - return connections; + g_hash_table_iter_init (&iter, priv->hash); + while (g_hash_table_iter_next (&iter, NULL, &data)) + list = g_slist_prepend (list, data); + return list; } -static gboolean +static NMSettingsConnection * add_connection (NMSystemConfigInterface *config, NMConnection *connection, GError **error) { - return write_connection (connection, KEYFILE_DIR, 0, 0, NULL, error); + SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); + NMSettingsConnection *added = NULL; + char *path = NULL; + + /* Write it out first, then add the connection to our internal list */ + if (nm_keyfile_plugin_write_connection (connection, NULL, &path, error)) { + added = _internal_new_connection (self, path, connection, error); + g_free (path); + } + return added; } static GSList * @@ -638,8 +645,8 @@ system_config_interface_init (NMSystemConfigInterface *system_config_interface_c system_config_interface_class->get_unmanaged_specs = get_unmanaged_specs; } -G_MODULE_EXPORT GObject * -nm_system_config_factory (void) +GObject * +nm_settings_keyfile_plugin_new (void) { static SCPluginKeyfile *singleton = NULL; diff --git a/system-settings/plugins/keyfile/plugin.h b/system-settings/plugins/keyfile/plugin.h index 71496c074b..af5147ef13 100644 --- a/system-settings/plugins/keyfile/plugin.h +++ b/system-settings/plugins/keyfile/plugin.h @@ -43,4 +43,6 @@ GType sc_plugin_keyfile_get_type (void); GQuark keyfile_plugin_error_quark (void); +GObject *nm_settings_keyfile_plugin_new (void); + #endif /* _PLUGIN_H_ */ diff --git a/system-settings/plugins/keyfile/reader.c b/system-settings/plugins/keyfile/reader.c index 841315d9c6..9533e906a0 100644 --- a/system-settings/plugins/keyfile/reader.c +++ b/system-settings/plugins/keyfile/reader.c @@ -1054,7 +1054,7 @@ read_vpn_secrets (GKeyFile *file, NMSettingVPN *s_vpn) } NMConnection * -connection_from_file (const char *filename, GError **error) +nm_keyfile_plugin_connection_from_file (const char *filename, GError **error) { GKeyFile *key_file; struct stat statbuf; diff --git a/system-settings/plugins/keyfile/reader.h b/system-settings/plugins/keyfile/reader.h index 3572715495..55819630eb 100644 --- a/system-settings/plugins/keyfile/reader.h +++ b/system-settings/plugins/keyfile/reader.h @@ -25,6 +25,6 @@ #include #include -NMConnection *connection_from_file (const char *filename, GError **error); +NMConnection *nm_keyfile_plugin_connection_from_file (const char *filename, GError **error); #endif /* _KEYFILE_PLUGIN_READER_H */ diff --git a/system-settings/plugins/keyfile/tests/test-keyfile.c b/system-settings/plugins/keyfile/tests/test-keyfile.c index 05131c8fe8..1aed7a0e68 100644 --- a/system-settings/plugins/keyfile/tests/test-keyfile.c +++ b/system-settings/plugins/keyfile/tests/test-keyfile.c @@ -83,7 +83,7 @@ test_read_valid_wired_connection (void) NMIP6Address *ip6_addr; NMIP6Route *ip6_route; - connection = connection_from_file (TEST_WIRED_FILE, NULL); + connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_FILE, NULL); ASSERT (connection != NULL, "connection-read", "failed to read %s", TEST_WIRED_FILE); @@ -693,7 +693,7 @@ test_write_wired_connection (void) /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); - success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); + success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); ASSERT (success == TRUE, "connection-write", "failed to allocate write keyfile: %s", error ? error->message : "(none)"); @@ -702,7 +702,7 @@ test_write_wired_connection (void) "connection-write", "didn't get keyfile name back after writing connection"); /* Read the connection back in and compare it to the one we just wrote out */ - reread = connection_from_file (testfile, NULL); + reread = nm_keyfile_plugin_connection_from_file (testfile, NULL); ASSERT (reread != NULL, "connection-write", "failed to re-read test connection"); ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, @@ -735,7 +735,7 @@ test_read_ip6_wired_connection (void) const char *expected6_gw1 = "abcd:1234:ffff::cdd1"; NMIP6Address *ip6_addr; - connection = connection_from_file (TEST_WIRED_IP6_FILE, NULL); + connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_IP6_FILE, NULL); ASSERT (connection != NULL, "connection-read", "failed to read %s", TEST_WIRED_IP6_FILE); @@ -953,7 +953,7 @@ test_write_ip6_wired_connection (void) /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); - success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); + success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); ASSERT (success == TRUE, "connection-write", "failed to allocate write keyfile: %s", error ? error->message : "(none)"); @@ -962,7 +962,7 @@ test_write_ip6_wired_connection (void) "connection-write", "didn't get keyfile name back after writing connection"); /* Read the connection back in and compare it to the one we just wrote out */ - reread = connection_from_file (testfile, NULL); + reread = nm_keyfile_plugin_connection_from_file (testfile, NULL); ASSERT (reread != NULL, "connection-write", "failed to re-read test connection"); ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, @@ -991,7 +991,7 @@ test_read_wired_mac_case (void) const char *expected_id = "Test Wired Connection MAC Case"; const char *expected_uuid = "4e80a56d-c99f-4aad-a6dd-b449bc398c57"; - connection = connection_from_file (TEST_WIRED_MAC_CASE_FILE, NULL); + connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_MAC_CASE_FILE, NULL); ASSERT (connection != NULL, "connection-read", "failed to read %s", TEST_WIRED_MAC_CASE_FILE); @@ -1077,7 +1077,7 @@ test_read_valid_wireless_connection (void) const guint64 expected_timestamp = 1226604314; guint64 timestamp; - connection = connection_from_file (TEST_WIRELESS_FILE, NULL); + connection = nm_keyfile_plugin_connection_from_file (TEST_WIRELESS_FILE, NULL); ASSERT (connection != NULL, "connection-read", "failed to read %s", TEST_WIRELESS_FILE); @@ -1271,7 +1271,7 @@ test_write_wireless_connection (void) /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); - success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); + success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); ASSERT (success == TRUE, "connection-write", "failed to allocate write keyfile: %s", error ? error->message : "(none)"); @@ -1280,7 +1280,7 @@ test_write_wireless_connection (void) "connection-write", "didn't get keyfile name back after writing connection"); /* Read the connection back in and compare it to the one we just wrote out */ - reread = connection_from_file (testfile, NULL); + reread = nm_keyfile_plugin_connection_from_file (testfile, NULL); ASSERT (reread != NULL, "connection-write", "failed to re-read test connection"); ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, @@ -1305,7 +1305,7 @@ test_read_string_ssid (void) const GByteArray *array; const char *expected_ssid = "blah blah ssid 1234"; - connection = connection_from_file (TEST_STRING_SSID_FILE, NULL); + connection = nm_keyfile_plugin_connection_from_file (TEST_STRING_SSID_FILE, NULL); ASSERT (connection != NULL, "connection-read", "failed to read %s", TEST_STRING_SSID_FILE); @@ -1401,7 +1401,7 @@ test_write_string_ssid (void) /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); - success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); + success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); ASSERT (success == TRUE, "connection-write", "failed to allocate write keyfile: %s", error ? error->message : "(none)"); @@ -1423,7 +1423,7 @@ test_write_string_ssid (void) g_key_file_free (keyfile); /* Read the connection back in and compare it to the one we just wrote out */ - reread = connection_from_file (testfile, NULL); + reread = nm_keyfile_plugin_connection_from_file (testfile, NULL); ASSERT (reread != NULL, "connection-write", "failed to re-read test connection"); ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, @@ -1458,7 +1458,7 @@ test_read_bt_dun_connection (void) const char *expected_username = "ISP@CINGULARGPRS.COM"; const char *expected_password = "CINGULAR1"; - connection = connection_from_file (TEST_BT_DUN_FILE, NULL); + connection = nm_keyfile_plugin_connection_from_file (TEST_BT_DUN_FILE, NULL); ASSERT (connection != NULL, "connection-read", "failed to read %s", TEST_BT_DUN_FILE); @@ -1699,7 +1699,7 @@ test_write_bt_dun_connection (void) /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); - success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); + success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); ASSERT (success == TRUE, "connection-write", "failed to allocate write keyfile: %s", error ? error->message : "(none)"); @@ -1708,7 +1708,7 @@ test_write_bt_dun_connection (void) "connection-write", "didn't get keyfile name back after writing connection"); /* Read the connection back in and compare it to the one we just wrote out */ - reread = connection_from_file (testfile, NULL); + reread = nm_keyfile_plugin_connection_from_file (testfile, NULL); ASSERT (reread != NULL, "connection-write", "failed to re-read test connection"); ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, @@ -1742,7 +1742,7 @@ test_read_gsm_connection (void) const char *expected_network_id = "24005"; const char *expected_pin = "2345"; - connection = connection_from_file (TEST_GSM_FILE, NULL); + connection = nm_keyfile_plugin_connection_from_file (TEST_GSM_FILE, NULL); ASSERT (connection != NULL, "connection-read", "failed to read %s", TEST_GSM_FILE); @@ -1961,7 +1961,7 @@ test_write_gsm_connection (void) /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); - success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); + success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); ASSERT (success == TRUE, "connection-write", "failed to allocate write keyfile: %s", error ? error->message : "(none)"); @@ -1970,7 +1970,7 @@ test_write_gsm_connection (void) "connection-write", "didn't get keyfile name back after writing connection"); /* Read the connection back in and compare it to the one we just wrote out */ - reread = connection_from_file (testfile, NULL); + reread = nm_keyfile_plugin_connection_from_file (testfile, NULL); ASSERT (reread != NULL, "connection-write", "failed to re-read test connection"); ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, diff --git a/system-settings/plugins/keyfile/utils.c b/system-settings/plugins/keyfile/utils.c index de64f7913b..c7cdc63108 100644 --- a/system-settings/plugins/keyfile/utils.c +++ b/system-settings/plugins/keyfile/utils.c @@ -75,7 +75,7 @@ check_suffix (const char *base, const char *tag) } gboolean -utils_should_ignore_file (const char *filename) +nm_keyfile_plugin_utils_should_ignore_file (const char *filename) { char *base; gboolean ignore = FALSE; diff --git a/system-settings/plugins/keyfile/utils.h b/system-settings/plugins/keyfile/utils.h index 3c1a6104bd..68e6e56f21 100644 --- a/system-settings/plugins/keyfile/utils.h +++ b/system-settings/plugins/keyfile/utils.h @@ -24,7 +24,7 @@ #include #include "common.h" -gboolean utils_should_ignore_file (const char *filename); +gboolean nm_keyfile_plugin_utils_should_ignore_file (const char *filename); #endif /* _UTILS_H_ */ diff --git a/system-settings/plugins/keyfile/writer.c b/system-settings/plugins/keyfile/writer.c index ffac35cff5..0887730a3e 100644 --- a/system-settings/plugins/keyfile/writer.c +++ b/system-settings/plugins/keyfile/writer.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 - 2010 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. */ #include @@ -415,43 +415,37 @@ mac_address_writer (GKeyFile *file, g_key_file_set_string (file, setting_name, key, mac); } -typedef struct { - GKeyFile *file; - const char *setting_name; -} WriteStringHashInfo; - -static void -write_hash_of_string_helper (gpointer key, gpointer data, gpointer user_data) -{ - WriteStringHashInfo *info = (WriteStringHashInfo *) user_data; - const char *property = (const char *) key; - const char *value = (const char *) data; - - g_key_file_set_string (info->file, - info->setting_name, - property, - value); -} - static void write_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key, const GValue *value) { - GHashTable *hash = g_value_get_boxed (value); - WriteStringHashInfo info; - - info.file = file; + GHashTableIter iter; + const char *property = NULL, *data = NULL; + const char *group_name = nm_setting_get_name (setting); + gboolean vpn_secrets = FALSE; /* Write VPN secrets out to a different group to keep them separate */ - if ( (G_OBJECT_TYPE (setting) == NM_TYPE_SETTING_VPN) - && !strcmp (key, NM_SETTING_VPN_SECRETS)) { - info.setting_name = VPN_SECRETS_GROUP; - } else - info.setting_name = nm_setting_get_name (setting); + if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) { + group_name = VPN_SECRETS_GROUP; + vpn_secrets = TRUE; + } - g_hash_table_foreach (hash, write_hash_of_string_helper, &info); + g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value)); + while (g_hash_table_iter_next (&iter, (gpointer *) &property, (gpointer *) &data)) { + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + + /* Handle VPN secrets specially; they are nested in the property's hash; + * we don't want to write them if the secret is not saved or not required. + */ + if (vpn_secrets && nm_setting_get_secret_flags (setting, property, &flags, NULL)) { + if (flags & (NM_SETTING_SECRET_FLAG_NOT_SAVED | NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) + continue; + } + + g_key_file_set_string (file, group_name, property, data); + } } static void @@ -564,6 +558,7 @@ write_setting_value (NMSetting *setting, GType type = G_VALUE_TYPE (value); KeyWriter *writer = &key_writers[0]; GParamSpec *pspec; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; /* Setting name gets picked up from the keyfile's section name instead */ if (!strcmp (key, NM_SETTING_NAME)) @@ -585,6 +580,14 @@ write_setting_value (NMSetting *setting, } } + /* Don't write secrets that are owned by user secret agents or aren't + * supposed to be saved. + */ + if ( (pspec->flags & NM_SETTING_PARAM_SECRET) + && nm_setting_get_secret_flags (setting, key, &flags, NULL) + && (flags != NM_SETTING_SECRET_FLAG_NONE)) + return; + /* Look through the list of handlers for non-standard format key values */ while (writer->setting_name) { if (!strcmp (writer->setting_name, setting_name) && !strcmp (writer->key, key)) { @@ -658,8 +661,8 @@ write_setting_value (NMSetting *setting, } } -char * -writer_id_to_filename (const char *id) +static char * +_writer_id_to_filename (const char *id) { char *filename, *f; const char *i = id; @@ -678,28 +681,31 @@ writer_id_to_filename (const char *id) return filename; } -gboolean -write_connection (NMConnection *connection, - const char *keyfile_dir, - uid_t owner_uid, - pid_t owner_grp, - char **out_path, - GError **error) +static gboolean +_internal_write_connection (NMConnection *connection, + const char *keyfile_dir, + uid_t owner_uid, + pid_t owner_grp, + const char *existing_path, + char **out_path, + GError **error) { - NMSettingConnection *s_con; GKeyFile *key_file; char *data; gsize len; gboolean success = FALSE; - char *filename, *path; - int err; + char *filename = NULL, *path; + const char *id; if (out_path) g_return_val_if_fail (*out_path == NULL, FALSE); - s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); - if (!s_con) - return success; + id = nm_connection_get_id (connection); + if (!id) { + g_set_error (error, KEYFILE_PLUGIN_ERROR, 0, + "%s.%d: connection had no ID", __FILE__, __LINE__); + return FALSE; + } key_file = g_key_file_new (); nm_connection_for_each_setting_value (connection, write_setting_value, key_file); @@ -707,9 +713,30 @@ write_connection (NMConnection *connection, if (!data) goto out; - filename = writer_id_to_filename (nm_setting_connection_get_id (s_con)); + filename = _writer_id_to_filename (id); path = g_build_filename (keyfile_dir, filename, NULL); - g_free (filename); + + /* If a file with this path already exists (but isn't the existing path + * of the connection) then we need another name. Multiple connections + * can have the same ID (ie if two connections with the same ID are visible + * to different users) but of course can't have the same path. Yeah, + * there's a race here, but there's not a lot we can do about it, and + * we shouldn't get more than one connection with the same UUID either. + */ + if (g_file_test (path, G_FILE_TEST_EXISTS) && (g_strcmp0 (path, existing_path) != 0)) { + /* A keyfile with this connection's ID already exists. Pick another name. */ + g_free (path); + + path = g_strdup_printf ("%s/%s-%s", keyfile_dir, filename, nm_connection_get_uuid (connection)); + if (g_file_test (path, G_FILE_TEST_EXISTS)) { + /* Hmm, this is odd. Give up. */ + g_set_error (error, KEYFILE_PLUGIN_ERROR, 0, + "%s.%d: could not find suitable keyfile file name (%s already used)", + __FILE__, __LINE__, path); + g_free (path); + goto out; + } + } g_file_set_contents (path, data, len, error); if (chown (path, owner_uid, owner_grp) < 0) { @@ -718,22 +745,55 @@ write_connection (NMConnection *connection, path, errno); unlink (path); } else { - err = chmod (path, S_IRUSR | S_IWUSR); - if (err) { + if (chmod (path, S_IRUSR | S_IWUSR) < 0) { g_set_error (error, KEYFILE_PLUGIN_ERROR, 0, "%s.%d: error setting permissions on '%s': %d", __FILE__, __LINE__, path, errno); unlink (path); } else { - if (out_path) - *out_path = g_strdup (path); + if (out_path && g_strcmp0 (existing_path, path)) { + *out_path = path; /* pass path out to caller */ + path = NULL; + } success = TRUE; } } g_free (path); out: + g_free (filename); g_free (data); g_key_file_free (key_file); return success; } + +gboolean +nm_keyfile_plugin_write_connection (NMConnection *connection, + const char *existing_path, + char **out_path, + GError **error) +{ + return _internal_write_connection (connection, + KEYFILE_DIR, + 0, 0, + existing_path, + out_path, + error); +} + +gboolean +nm_keyfile_plugin_write_test_connection (NMConnection *connection, + const char *keyfile_dir, + uid_t owner_uid, + pid_t owner_grp, + char **out_path, + GError **error) +{ + return _internal_write_connection (connection, + keyfile_dir, + owner_uid, owner_grp, + NULL, + out_path, + error); +} + diff --git a/system-settings/plugins/keyfile/writer.h b/system-settings/plugins/keyfile/writer.h index fa04deef98..a602f2f4a3 100644 --- a/system-settings/plugins/keyfile/writer.h +++ b/system-settings/plugins/keyfile/writer.h @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. */ #ifndef _KEYFILE_PLUGIN_WRITER_H @@ -26,13 +26,16 @@ #include #include -gboolean write_connection (NMConnection *connection, - const char *keyfile_dir, - uid_t owner_uid, - pid_t owner_grp, - char **out_path, - GError **error); +gboolean nm_keyfile_plugin_write_connection (NMConnection *connection, + const char *existing_path, + char **out_path, + GError **error); -char *writer_id_to_filename (const char *id); +gboolean nm_keyfile_plugin_write_test_connection (NMConnection *connection, + const char *keyfile_dir, + uid_t owner_uid, + pid_t owner_grp, + char **out_path, + GError **error); #endif /* _KEYFILE_PLUGIN_WRITER_H */ diff --git a/test/add-connection.py b/test/add-connection.py new file mode 100755 index 0000000000..817d6914c8 --- /dev/null +++ b/test/add-connection.py @@ -0,0 +1,59 @@ +#!/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 (C) 2010 Red Hat, Inc. +# + +import dbus +import sys + +s_wired = dbus.Dictionary({'duplex': 'full'}) +s_con = dbus.Dictionary({ + 'type': '802-3-ethernet', + 'uuid': '7371bb78-c1f7-42a3-a9db-5b9566e8ca07', + 'id': sys.argv[1]}) + +if len(sys.argv) > 2: + s_con['permissions'] = ["user:%s:" % sys.argv[2]] + +addr1 = dbus.Array([dbus.UInt32(50462986L), dbus.UInt32(8L), dbus.UInt32(16908554L)], signature=dbus.Signature('u')) +s_ip4 = dbus.Dictionary({ + 'addresses': dbus.Array([addr1], signature=dbus.Signature('au')), + 'method': 'manual'}) + +s_ip6 = dbus.Dictionary({'method': 'ignore'}) + +con = dbus.Dictionary({ + '802-3-ethernet': s_wired, + 'connection': s_con, + 'ipv4': s_ip4, + 'ipv6': s_ip6}) + + +bus = dbus.SystemBus() + +proxy = bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/Settings") +settings = dbus.Interface(proxy, "org.freedesktop.NetworkManager.Settings") + +new_con_path = settings.AddConnection(con) + +con_proxy = bus.get_object("org.freedesktop.NetworkManager", new_con_path) +con = dbus.Interface(con_proxy, "org.freedesktop.NetworkManager.Settings.Connection") + +print "New connection object path: %s" % new_con_path +print con.GetSettings() + + diff --git a/test/nm-tool.c b/test/nm-tool.c index 121d9d1762..ea3ef13b6c 100644 --- a/test/nm-tool.c +++ b/test/nm-tool.c @@ -56,8 +56,7 @@ #define DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT)) #define DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH)) -static GHashTable *user_connections = NULL; -static GHashTable *system_connections = NULL; +static GHashTable *connections = NULL; static gboolean get_nm_state (NMClient *client) @@ -307,7 +306,6 @@ get_dev_state_string (NMDeviceState state) static NMConnection * get_connection_for_active (NMActiveConnection *active) { - NMConnectionScope scope; const char *path; g_return_val_if_fail (active != NULL, NULL); @@ -315,14 +313,7 @@ get_connection_for_active (NMActiveConnection *active) path = nm_active_connection_get_connection (active); g_return_val_if_fail (path != NULL, NULL); - scope = nm_active_connection_get_scope (active); - if (scope == NM_CONNECTION_SCOPE_USER) - return (NMConnection *) g_hash_table_lookup (user_connections, path); - else if (scope == NM_CONNECTION_SCOPE_SYSTEM) - return (NMConnection *) g_hash_table_lookup (system_connections, path); - - g_warning ("error: unknown connection scope"); - return NULL; + return (NMConnection *) g_hash_table_lookup (connections, path); } struct cb_info { @@ -683,12 +674,10 @@ detail_vpn (gpointer data, gpointer user_data) static void get_one_connection (DBusGConnection *bus, const char *path, - NMConnectionScope scope, GHashTable *table) { DBusGProxy *proxy; NMConnection *connection = NULL; - const char *service; GError *error = NULL; GHashTable *settings = NULL; @@ -696,10 +685,8 @@ get_one_connection (DBusGConnection *bus, g_return_if_fail (path != NULL); g_return_if_fail (table != NULL); - service = (scope == NM_CONNECTION_SCOPE_SYSTEM) ? - NM_DBUS_SERVICE_SYSTEM_SETTINGS : NM_DBUS_SERVICE_USER_SETTINGS; - - proxy = dbus_g_proxy_new_for_name (bus, service, path, NM_DBUS_IFACE_SETTINGS_CONNECTION); + proxy = dbus_g_proxy_new_for_name (bus, NM_DBUS_SERVICE, + path, NM_DBUS_IFACE_SETTINGS_CONNECTION); if (!proxy) return; @@ -722,7 +709,6 @@ get_one_connection (DBusGConnection *bus, goto out; } - nm_connection_set_scope (connection, scope); nm_connection_set_path (connection, path); g_hash_table_insert (table, g_strdup (path), g_object_ref (connection)); @@ -733,27 +719,29 @@ out: g_object_unref (proxy); } -static void -get_connections_for_service (DBusGConnection *bus, - NMConnectionScope scope, - GHashTable *table) +static gboolean +get_all_connections (void) { GError *error = NULL; - DBusGProxy *proxy; + DBusGConnection *bus; + DBusGProxy *proxy = NULL; GPtrArray *paths = NULL; int i; - const char *service; + gboolean sucess = FALSE; - service = (scope == NM_CONNECTION_SCOPE_SYSTEM) ? - NM_DBUS_SERVICE_SYSTEM_SETTINGS : NM_DBUS_SERVICE_USER_SETTINGS; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (error || !bus) { + g_warning ("error: could not connect to dbus"); + goto out; + } proxy = dbus_g_proxy_new_for_name (bus, - service, + NM_DBUS_SERVICE, NM_DBUS_PATH_SETTINGS, NM_DBUS_IFACE_SETTINGS); if (!proxy) { - g_warning ("error: failed to create DBus proxy for %s", service); - return; + g_warning ("error: failed to create DBus proxy for settings service"); + goto out; } if (!dbus_g_proxy_call (proxy, "ListConnections", &error, @@ -765,33 +753,20 @@ get_connections_for_service (DBusGConnection *bus, goto out; } + connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + for (i = 0; paths && (i < paths->len); i++) - get_one_connection (bus, g_ptr_array_index (paths, i), scope, table); + get_one_connection (bus, g_ptr_array_index (paths, i), connections); + + sucess = TRUE; out: - g_object_unref (proxy); -} + if (bus) + dbus_g_connection_unref (bus); + if (proxy) + g_object_unref (proxy); -static gboolean -get_all_connections (void) -{ - DBusGConnection *bus; - GError *error = NULL; - - bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); - if (error || !bus) { - g_warning ("error: could not connect to dbus"); - return FALSE; - } - - user_connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - get_connections_for_service (bus, NM_CONNECTION_SCOPE_USER, user_connections); - - system_connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - get_connections_for_service (bus, NM_CONNECTION_SCOPE_SYSTEM, system_connections); - - dbus_g_connection_unref (bus); - return TRUE; + return sucess; } int @@ -830,8 +805,7 @@ main (int argc, char *argv[]) g_ptr_array_foreach ((GPtrArray *) info.active, detail_vpn, &info); g_object_unref (client); - g_hash_table_unref (user_connections); - g_hash_table_unref (system_connections); + g_hash_table_unref (connections); return 0; } diff --git a/test/set-hostname.py b/test/set-hostname.py new file mode 100755 index 0000000000..4c8995d255 --- /dev/null +++ b/test/set-hostname.py @@ -0,0 +1,27 @@ +#!/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 (C) 2010 Red Hat, Inc. +# + +import dbus +import sys + +bus = dbus.SystemBus() +proxy = bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/Settings") +settings = dbus.Interface(proxy, "org.freedesktop.NetworkManager.Settings") +settings.SaveHostname(sys.argv[1]) +