diff options
Diffstat (limited to 'src/settings')
26 files changed, 1386 insertions, 197 deletions
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 8a5ea106..5ccbdc67 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -49,6 +49,9 @@ typedef struct { NMDBusManager *dbus_mgr; NMSessionMonitor *session_monitor; + /* Auth chains for checking agent permissions */ + GSList *chains; + /* Hashed by owner name, not identifier, since two agents in different * sessions can use the same identifier. */ @@ -57,6 +60,14 @@ typedef struct { GHashTable *requests; } NMAgentManagerPrivate; +enum { + AGENT_REGISTERED, + + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + + typedef struct _Request Request; static void request_add_agent (Request *req, @@ -218,6 +229,59 @@ validate_identifier (const char *identifier, GError **error) } static void +agent_register_permissions_done (NMAuthChain *chain, + GError *error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + NMAgentManager *self = NM_AGENT_MANAGER (user_data); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + NMSecretAgent *agent; + const char *sender; + GError *local = NULL; + NMAuthCallResult result; + GHashTableIter iter; + Request *req; + + priv->chains = g_slist_remove (priv->chains, chain); + + if (error) { + local = g_error_new (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, + "Failed to request agent permissions: (%d) %s", + error->code, error->message); + dbus_g_method_return_error (context, local); + g_error_free (local); + } else { + agent = nm_auth_chain_steal_data (chain, "agent"); + + result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); + if (result == NM_AUTH_CALL_RESULT_YES) + nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, TRUE); + + result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN); + if (result == NM_AUTH_CALL_RESULT_YES) + nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, TRUE); + + sender = nm_secret_agent_get_dbus_owner (agent); + 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); + + /* Signal an agent was registered */ + g_signal_emit (self, signals[AGENT_REGISTERED], 0, agent); + + /* 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, (gpointer) &req)) + request_add_agent (req, agent, priv->session_monitor); + } + + nm_auth_chain_unref (chain); +} + +static void impl_agent_manager_register (NMAgentManager *self, const char *identifier, DBusGMethodInvocation *context) @@ -227,8 +291,7 @@ impl_agent_manager_register (NMAgentManager *self, gulong sender_uid = G_MAXULONG; GError *error = NULL, *local = NULL; NMSecretAgent *agent; - GHashTableIter iter; - gpointer data; + NMAuthChain *chain; if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, @@ -272,15 +335,16 @@ impl_agent_manager_register (NMAgentManager *self, goto done; } - g_hash_table_insert (priv->agents, g_strdup (sender), agent); - nm_log_dbg (LOGD_AGENTS, "(%s) agent registered", + nm_log_dbg (LOGD_AGENTS, "(%s) requesting permissions", 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); + /* Kick off permissions requests for this agent */ + chain = nm_auth_chain_new (context, NULL, agent_register_permissions_done, self); + nm_auth_chain_set_data (chain, "agent", agent, g_object_unref); + 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); + + priv->chains = g_slist_append (priv->chains, chain); done: if (error) @@ -945,8 +1009,8 @@ get_start (gpointer user_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) && (request_new == FALSE)) { + if ( (req->flags & NM_SETTINGS_GET_SECRETS_FLAG_ONLY_SYSTEM) + || ((nm_connection_need_secrets (tmp, NULL) == NULL) && (request_new == FALSE))) { nm_log_dbg (LOGD_AGENTS, "(%p/%s) system settings secrets sufficient", req, req->setting_name); @@ -1059,7 +1123,8 @@ nm_agent_manager_get_secrets (NMAgentManager *self, g_hash_table_insert (priv->requests, GUINT_TO_POINTER (req->reqid), req); /* Kick off the request */ - request_add_agents (self, req); + if (!(req->flags & NM_SETTINGS_GET_SECRETS_FLAG_ONLY_SYSTEM)) + request_add_agents (self, req); req->idle_id = g_idle_add (get_start, req); return req->reqid; @@ -1277,6 +1342,24 @@ nm_agent_manager_delete_secrets (NMAgentManager *self, /*************************************************************/ +NMSecretAgent * +nm_agent_manager_get_agent_by_user (NMAgentManager *self, const char *username) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + GHashTableIter iter; + NMSecretAgent *agent; + + g_hash_table_iter_init (&iter, priv->agents); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { + if (g_strcmp0 (nm_secret_agent_get_owner_username (agent), username) == 0) + return agent; + } + + return NULL; +} + +/*************************************************************/ + static void name_owner_changed_cb (NMDBusManager *dbus_mgr, const char *name, @@ -1290,6 +1373,73 @@ name_owner_changed_cb (NMDBusManager *dbus_mgr, } } +static void +agent_permissions_changed_done (NMAuthChain *chain, + GError *error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + NMAgentManager *self = NM_AGENT_MANAGER (user_data); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + NMSecretAgent *agent; + NMAuthCallResult result; + + priv->chains = g_slist_remove (priv->chains, chain); + + agent = nm_auth_chain_get_data (chain, "agent"); + + if (error) { + nm_log_dbg (LOGD_AGENTS, "(%s) failed to request updated agent permissions", + nm_secret_agent_get_description (agent)); + nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); + nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); + } else { + nm_log_dbg (LOGD_AGENTS, "(%s) updated agent permissions", + nm_secret_agent_get_description (agent)); + + result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); + nm_secret_agent_add_permission (agent, + NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, + (result == NM_AUTH_CALL_RESULT_YES)); + + result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN); + nm_secret_agent_add_permission (agent, + NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, + (result == NM_AUTH_CALL_RESULT_YES)); + } + + nm_auth_chain_unref (chain); +} + +static void +authority_changed_cb (gpointer user_data) +{ + NMAgentManager *self = NM_AGENT_MANAGER (user_data); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + GHashTableIter iter; + NMSecretAgent *agent; + + /* Recheck the permissions of all secret agents */ + g_hash_table_iter_init (&iter, priv->agents); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { + NMAuthChain *chain; + const char *sender; + + /* Kick off permissions requests for this agent */ + sender = nm_secret_agent_get_dbus_owner (agent); + chain = nm_auth_chain_new_dbus_sender (sender, agent_permissions_changed_done, self); + + /* Make sure if the agent quits while the permissions call is in progress + * that the object sticks around until our callback. + */ + nm_auth_chain_set_data (chain, "agent", g_object_ref (agent), g_object_unref); + 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); + + priv->chains = g_slist_append (priv->chains, chain); + } +} + /*************************************************************/ NMAgentManager * @@ -1319,6 +1469,8 @@ nm_agent_manager_get (void) G_CALLBACK (name_owner_changed_cb), singleton); + nm_auth_changed_func_register (authority_changed_cb, singleton); + return singleton; } @@ -1342,6 +1494,10 @@ dispose (GObject *object) if (!priv->disposed) { priv->disposed = TRUE; + nm_auth_changed_func_unregister (authority_changed_cb, NM_AGENT_MANAGER (object)); + + g_slist_foreach (priv->chains, (GFunc) nm_auth_chain_unref, NULL); + g_hash_table_destroy (priv->agents); g_hash_table_destroy (priv->requests); @@ -1362,6 +1518,17 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) /* virtual methods */ object_class->dispose = dispose; + /* Signals */ + signals[AGENT_REGISTERED] = + g_signal_new ("agent-registered", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMAgentManagerClass, agent_registered), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (agent_manager_class), &dbus_glib_nm_agent_manager_object_info); diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index 788a9175..e49f579d 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -25,6 +25,7 @@ #include <glib-object.h> #include <nm-connection.h> #include "nm-settings-flags.h" +#include "nm-secret-agent.h" #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)) @@ -39,6 +40,9 @@ typedef struct { typedef struct { GObjectClass parent; + + /* Signals */ + void (*agent_registered) (NMAgentManager *agent_mgr, NMSecretAgent *agent); } NMAgentManagerClass; GType nm_agent_manager_get_type (void); @@ -85,4 +89,7 @@ guint32 nm_agent_manager_delete_secrets (NMAgentManager *manager, gboolean filter_by_uid, gulong uid_filter); +NMSecretAgent *nm_agent_manager_get_agent_by_user (NMAgentManager *manager, + const char *username); + #endif /* NM_AGENT_MANAGER_H */ diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index 2b1156cb..94f046e5 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -20,6 +20,9 @@ #include <config.h> +#include <sys/types.h> +#include <pwd.h> + #include <glib.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> @@ -41,8 +44,11 @@ typedef struct { char *owner; char *identifier; uid_t owner_uid; + char *owner_username; guint32 hash; + GSList *permissions; + NMDBusManager *dbus_mgr; DBusGProxy *proxy; @@ -134,6 +140,15 @@ nm_secret_agent_get_owner_uid (NMSecretAgent *agent) return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner_uid; } +const char * +nm_secret_agent_get_owner_username(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_username; +} + guint32 nm_secret_agent_get_hash (NMSecretAgent *agent) { @@ -143,6 +158,76 @@ nm_secret_agent_get_hash (NMSecretAgent *agent) return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash; } +/** + * nm_secret_agent_add_permission: + * @agent: A #NMSecretAgent. + * @permission: The name of the permission + * + * Records whether or not the agent has a given permission. + */ +void +nm_secret_agent_add_permission (NMSecretAgent *agent, + const char *permission, + gboolean allowed) +{ + NMSecretAgentPrivate *priv; + GSList *iter; + + g_return_if_fail (agent != NULL); + g_return_if_fail (permission != NULL); + + priv = NM_SECRET_AGENT_GET_PRIVATE (agent); + + /* Check if the permission is already in the list */ + for (iter = priv->permissions; iter; iter = g_slist_next (iter)) { + if (g_strcmp0 (permission, iter->data) == 0) { + /* If the permission is no longer allowed, remove it from the + * list. If it is now allowed, do nothing since it's already + * in the list. + */ + if (allowed == FALSE) { + g_free (iter->data); + priv->permissions = g_slist_delete_link (priv->permissions, iter); + } + return; + } + } + + /* New permission that's allowed */ + if (allowed) + priv->permissions = g_slist_prepend (priv->permissions, g_strdup (permission)); +} + +/** + * nm_secret_agent_has_permission: + * @agent: A #NMSecretAgent. + * @permission: The name of the permission to check for + * + * Returns whether or not the agent has the given permission. + * + * Returns: %TRUE if the agent has the given permission, %FALSE if it does not + * or if the permission was not previous recorded with + * nm_secret_agent_add_permission(). + */ +gboolean +nm_secret_agent_has_permission (NMSecretAgent *agent, const char *permission) +{ + NMSecretAgentPrivate *priv; + GSList *iter; + + g_return_val_if_fail (agent != NULL, FALSE); + g_return_val_if_fail (permission != NULL, FALSE); + + priv = NM_SECRET_AGENT_GET_PRIVATE (agent); + + /* Check if the permission is already in the list */ + for (iter = priv->permissions; iter; iter = g_slist_next (iter)) { + if (g_strcmp0 (permission, iter->data) == 0) + return TRUE; + } + return FALSE; +} + /*************************************************************/ static void @@ -189,6 +274,9 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, hash = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL); + /* Mask off the private ONLY_SYSTEM flag if present */ + flags &= ~NM_SETTINGS_GET_SECRETS_FLAG_ONLY_SYSTEM; + 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", @@ -327,11 +415,17 @@ nm_secret_agent_new (NMDBusManager *dbus_mgr, NMSecretAgent *self; NMSecretAgentPrivate *priv; DBusGConnection *bus; - char *hash_str; + char *hash_str, *username; + struct passwd *pw; g_return_val_if_fail (owner != NULL, NULL); g_return_val_if_fail (identifier != NULL, NULL); + pw = getpwuid (owner_uid); + g_return_val_if_fail (pw != NULL, NULL); + g_return_val_if_fail (pw->pw_name[0] != '\0', NULL); + username = g_strdup (pw->pw_name); + self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL); if (self) { priv = NM_SECRET_AGENT_GET_PRIVATE (self); @@ -339,6 +433,7 @@ nm_secret_agent_new (NMDBusManager *dbus_mgr, priv->owner = g_strdup (owner); priv->identifier = g_strdup (identifier); priv->owner_uid = owner_uid; + priv->owner_username = g_strdup (username); hash_str = g_strdup_printf ("%08u%s", owner_uid, identifier); priv->hash = g_str_hash (hash_str); @@ -353,6 +448,7 @@ nm_secret_agent_new (NMDBusManager *dbus_mgr, g_assert (priv->proxy); } + g_free (username); return self; } @@ -376,6 +472,10 @@ dispose (GObject *object) g_free (priv->description); g_free (priv->owner); g_free (priv->identifier); + g_free (priv->owner_username); + + g_slist_foreach (priv->permissions, (GFunc) g_free, NULL); + g_slist_free (priv->permissions); g_hash_table_destroy (priv->requests); g_object_unref (priv->proxy); diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h index 597940b4..29b02be1 100644 --- a/src/settings/nm-secret-agent.h +++ b/src/settings/nm-secret-agent.h @@ -60,8 +60,17 @@ const char *nm_secret_agent_get_identifier (NMSecretAgent *agent); uid_t nm_secret_agent_get_owner_uid (NMSecretAgent *agent); +const char *nm_secret_agent_get_owner_username (NMSecretAgent *agent); + guint32 nm_secret_agent_get_hash (NMSecretAgent *agent); +void nm_secret_agent_add_permission (NMSecretAgent *agent, + const char *permission, + gboolean allowed); + +gboolean nm_secret_agent_has_permission (NMSecretAgent *agent, + const char *permission); + typedef void (*NMSecretAgentCallback) (NMSecretAgent *agent, gconstpointer call, GHashTable *new_secrets, /* NULL for save & delete */ diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 60de6b06..4b3a56cd 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -22,6 +22,7 @@ #include "config.h" #include <string.h> +#include <netinet/ether.h> #include <NetworkManager.h> #include <dbus/dbus-glib-lowlevel.h> @@ -38,8 +39,10 @@ #include "nm-manager-auth.h" #include "nm-marshal.h" #include "nm-agent-manager.h" +#include "NetworkManagerUtils.h" #define SETTINGS_TIMESTAMPS_FILE LOCALSTATEDIR"/lib/NetworkManager/timestamps" +#define SETTINGS_SEEN_BSSIDS_FILE LOCALSTATEDIR"/lib/NetworkManager/seen-bssids" static void impl_settings_connection_get_settings (NMSettingsConnection *connection, DBusGMethodInvocation *context); @@ -91,7 +94,8 @@ typedef struct { NMSessionMonitor *session_monitor; guint session_changed_id; - guint64 timestamp; /* Up-to-date timestamp of connection use */ + guint64 timestamp; /* Up-to-date timestamp of connection use */ + GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */ } NMSettingsConnectionPrivate; /**************************************************************/ @@ -238,6 +242,58 @@ session_changed_cb (NMSessionMonitor *self, gpointer user_data) /**************************************************************/ +/* Return TRUE if any active user in the connection's ACL has the given + * permission without having to authorize for it via PolicyKit. Connections + * visible to everyone automatically pass the check. + */ +gboolean +nm_settings_connection_check_permission (NMSettingsConnection *self, + const char *permission) +{ + NMSettingsConnectionPrivate *priv; + NMSettingConnection *s_con; + guint32 num, i; + const char *puser; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); + + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + if (priv->visible == FALSE) + return FALSE; + + s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); + 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 so it's OK to auto-activate */ + return TRUE; + } + + for (i = 0; i < num; i++) { + /* For each user get their secret agent and check if that agent has the + * required permission. + * + * FIXME: what if the user isn't running an agent? PolKit needs a bus + * name or a PID but if the user isn't running an agent they won't have + * either. + */ + if (nm_setting_connection_get_permission (s_con, i, NULL, &puser, NULL)) { + NMSecretAgent *agent = nm_agent_manager_get_agent_by_user (priv->agent_mgr, puser); + + if (agent && nm_secret_agent_has_permission (agent, permission)) + return TRUE; + } + } + + return FALSE; +} + +/**************************************************************/ + static void only_system_secrets_cb (NMSetting *setting, const char *key, @@ -326,25 +382,14 @@ nm_settings_connection_replace_settings (NMSettingsConnection *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)) { - GHashTableIter iter; - NMSetting *setting; - const char *setting_name; - GHashTable *setting_hash; - /* Copy the connection to keep its secrets around even if NM * calls nm_connection_clear_secrets(). */ update_secrets_cache (self); /* And add the transient secrets back */ - if (transient_secrets) { - g_hash_table_iter_init (&iter, transient_secrets); - while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) { - setting = nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name); - if (setting) - nm_setting_update_secrets (setting, setting_hash, NULL); - } - } + if (transient_secrets) + nm_connection_update_secrets (NM_CONNECTION (self), NULL, transient_secrets, NULL); nm_settings_connection_recheck_visibility (self); success = TRUE; @@ -455,12 +500,20 @@ commit_changes (NMSettingsConnection *connection, } static void -remove_timestamp_from_db (NMSettingsConnection *connection) +remove_entry_from_db (NMSettingsConnection *connection, const char* db_name) { - GKeyFile *timestamps_file; + GKeyFile *key_file; + const char *db_file; - timestamps_file = g_key_file_new (); - if (g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL)) { + if (strcmp (db_name, "timestamps") == 0) + db_file = SETTINGS_TIMESTAMPS_FILE; + else if (strcmp (db_name, "seen-bssids") == 0) + db_file = SETTINGS_SEEN_BSSIDS_FILE; + else + return; + + key_file = g_key_file_new (); + if (g_key_file_load_from_file (key_file, db_file, G_KEY_FILE_KEEP_COMMENTS, NULL)) { const char *connection_uuid; char *data; gsize len; @@ -468,18 +521,18 @@ remove_timestamp_from_db (NMSettingsConnection *connection) connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection)); - g_key_file_remove_key (timestamps_file, "timestamps", connection_uuid, NULL); - data = g_key_file_to_data (timestamps_file, &len, &error); + g_key_file_remove_key (key_file, db_name, connection_uuid, NULL); + data = g_key_file_to_data (key_file, &len, &error); if (data) { - g_file_set_contents (SETTINGS_TIMESTAMPS_FILE, data, len, &error); + g_file_set_contents (db_file, data, len, &error); g_free (data); } if (error) { - nm_log_warn (LOGD_SETTINGS, "error writing timestamps file '%s': %s", SETTINGS_TIMESTAMPS_FILE, error->message); + nm_log_warn (LOGD_SETTINGS, "error writing %s file '%s': %s", db_name, db_file, error->message); g_error_free (error); } } - g_key_file_free (timestamps_file); + g_key_file_free (key_file); } static void @@ -499,7 +552,10 @@ do_delete (NMSettingsConnection *connection, nm_agent_manager_delete_secrets (priv->agent_mgr, for_agents, FALSE, 0); /* Remove timestamp from timestamps database file */ - remove_timestamp_from_db (connection); + remove_entry_from_db (connection, "timestamps"); + + /* Remove connection from seen-bssids database file */ + remove_entry_from_db (connection, "seen-bssids"); /* Signal the connection is removed and deleted */ g_signal_emit (connection, signals[REMOVED], 0); @@ -980,21 +1036,21 @@ check_writable (NMConnection *connection, GError **error) static void get_settings_auth_cb (NMSettingsConnection *self, - DBusGMethodInvocation *context, - gulong sender_uid, - GError *error, - gpointer data) + DBusGMethodInvocation *context, + gulong sender_uid, + GError *error, + gpointer data) { if (error) dbus_g_method_return_error (context, error); else { GHashTable *settings; - NMConnection *dupl_con; + NMConnection *dupl_con; NMSettingConnection *s_con; guint64 timestamp; - dupl_con = nm_connection_duplicate (NM_CONNECTION (self)); - g_assert (dupl_con); + dupl_con = nm_connection_duplicate (NM_CONNECTION (self)); + g_assert (dupl_con); /* Timestamp is not updated in connection's 'timestamp' property, * because it would force updating the connection and in turn @@ -1004,7 +1060,7 @@ get_settings_auth_cb (NMSettingsConnection *self, */ timestamp = nm_settings_connection_get_timestamp (self); if (timestamp) { - s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (NM_CONNECTION (dupl_con), NM_TYPE_SETTING_CONNECTION)); + s_con = nm_connection_get_setting_connection (NM_CONNECTION (dupl_con)); g_assert (s_con); g_object_set (s_con, NM_SETTING_CONNECTION_TIMESTAMP, timestamp, NULL); } @@ -1017,7 +1073,7 @@ get_settings_auth_cb (NMSettingsConnection *self, g_assert (settings); dbus_g_method_return (context, settings); g_hash_table_destroy (settings); - g_object_unref (dupl_con); + g_object_unref (dupl_con); } } @@ -1042,31 +1098,30 @@ con_update_cb (NMSettingsConnection *connection, } static void -only_agent_secrets_cb (NMSetting *setting, - const char *key, - const GValue *value, - GParamFlags flags, - gpointer user_data) +secrets_filter_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; + NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data); + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + const char *secret_name = NULL; + GHashTableIter iter; - /* Clear out system-owned or always-ask secrets */ + if (flags & NM_SETTING_PARAM_SECRET) { 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)) { + while (g_hash_table_iter_next (&iter, (gpointer) &secret_name, NULL)) { secret_flags = NM_SETTING_SECRET_FLAG_NONE; nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL); - if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED) + if (!(secret_flags & filter_flags)) 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) + if (!(secret_flags & filter_flags)) g_object_set (G_OBJECT (setting), key, NULL, NULL); } } @@ -1081,23 +1136,52 @@ update_auth_cb (NMSettingsConnection *self, { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMConnection *new_settings = data; - NMConnection *for_agent; + NMConnection *for_agent, *dup; + NMSettingSecretFlags filter_flags; + GHashTable *hash; + GError *local = NULL; if (error) dbus_g_method_return_error (context, error); else { + /* Cache the new secrets since they may get overwritten by the replace + * when transient secrets are copied back. + */ + dup = nm_connection_duplicate (new_settings); + /* Update and commit our settings. */ nm_settings_connection_replace_and_commit (self, new_settings, con_update_cb, context); + /* Copy new agent secrets back to the connection */ + filter_flags = NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED; + nm_connection_for_each_setting_value (dup, + secrets_filter_cb, + GUINT_TO_POINTER (filter_flags)); + hash = nm_connection_to_hash (dup, NM_SETTING_HASH_FLAG_ONLY_SECRETS); + g_object_unref (dup); + + if (hash) { + if (!nm_connection_update_secrets (NM_CONNECTION (self), NULL, hash, &local)) { + nm_log_warn (LOGD_SETTINGS, "Failed to update connection secrets: (%d) %s", + local ? local->code : -1, + local && local->message ? local->message : "(unknown)"); + g_clear_error (&local); + } + g_hash_table_destroy (hash); + } + /* 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); + filter_flags = NM_SETTING_SECRET_FLAG_AGENT_OWNED; + nm_connection_for_each_setting_value (for_agent, + secrets_filter_cb, + GUINT_TO_POINTER (filter_flags)); nm_agent_manager_save_secrets (priv->agent_mgr, for_agent, TRUE, sender_uid); g_object_unref (for_agent); } @@ -1272,6 +1356,8 @@ dbus_get_agent_secrets_cb (NMSettingsConnection *self, update_secrets_cache (self); hash = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS); + if (!hash) + hash = g_hash_table_new (NULL, NULL); dbus_g_method_return (context, hash); g_hash_table_destroy (hash); } @@ -1440,6 +1526,181 @@ nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *connection g_key_file_free (timestamps_file); } +static guint +mac_hash (gconstpointer v) +{ + const guint8 *p = v; + guint32 i, h = 5381; + + for (i = 0; i < ETH_ALEN; i++) + h = (h << 5) + h + p[i]; + return h; +} + +static gboolean +mac_equal (gconstpointer a, gconstpointer b) +{ + return memcmp (a, b, ETH_ALEN) == 0; +} + +static guint8 * +mac_dup (const struct ether_addr *old) +{ + guint8 *new; + + g_return_val_if_fail (old != NULL, NULL); + + new = g_malloc0 (ETH_ALEN); + memcpy (new, old, ETH_ALEN); + return new; +} + +/** + * nm_settings_connection_has_seen_bssid: + * @connection: the #NMSettingsConnection + * @bssid: the BSSID to check the seen BSSID list for + * + * Returns: TRUE if the given @bssid is in the seen BSSIDs list + **/ +gboolean +nm_settings_connection_has_seen_bssid (NMSettingsConnection *connection, + const struct ether_addr *bssid) +{ + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), FALSE); + g_return_val_if_fail (bssid != NULL, FALSE); + + return !!g_hash_table_lookup (NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->seen_bssids, bssid); +} + +/** + * nm_settings_connection_add_seen_bssid: + * @connection: the #NMSettingsConnection + * @seen_bssid: BSSID to set into the connection and to store into + * the seen-bssids database + * + * Updates the connection and seen-bssids database with the provided BSSID. + **/ +void +nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection, + const struct ether_addr *seen_bssid) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection); + const char *connection_uuid; + GKeyFile *seen_bssids_file; + char *data, *bssid_str; + const char **list; + gsize len; + GError *error = NULL; + GHashTableIter iter; + guint n; + + g_return_if_fail (seen_bssid != NULL); + + if (g_hash_table_lookup (priv->seen_bssids, seen_bssid)) + return; /* Already in the list */ + + /* Add the new BSSID; let the hash take ownership of the allocated BSSID string */ + bssid_str = nm_ether_ntop (seen_bssid); + g_return_if_fail (bssid_str != NULL); + g_hash_table_insert (priv->seen_bssids, mac_dup (seen_bssid), bssid_str); + + /* Build up a list of all the BSSIDs in string form */ + n = 0; + list = g_malloc0 (g_hash_table_size (priv->seen_bssids) * sizeof (char *)); + g_hash_table_iter_init (&iter, priv->seen_bssids); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &bssid_str)) + list[n++] = bssid_str; + + /* Save BSSID to seen-bssids file */ + seen_bssids_file = g_key_file_new (); + g_key_file_set_list_separator (seen_bssids_file, ','); + if (!g_key_file_load_from_file (seen_bssids_file, SETTINGS_SEEN_BSSIDS_FILE, G_KEY_FILE_KEEP_COMMENTS, &error)) { + if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { + nm_log_warn (LOGD_SETTINGS, "error parsing seen-bssids file '%s': %s", + SETTINGS_SEEN_BSSIDS_FILE, error->message); + } + g_clear_error (&error); + } + + connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection)); + g_key_file_set_string_list (seen_bssids_file, "seen-bssids", connection_uuid, list, n); + g_free (list); + + data = g_key_file_to_data (seen_bssids_file, &len, &error); + if (data) { + g_file_set_contents (SETTINGS_SEEN_BSSIDS_FILE, data, len, &error); + g_free (data); + } + g_key_file_free (seen_bssids_file); + + if (error) { + nm_log_warn (LOGD_SETTINGS, "error saving seen-bssids to file '%s': %s", + SETTINGS_SEEN_BSSIDS_FILE, error->message); + g_error_free (error); + } +} + +static void +add_seen_bssid_string (NMSettingsConnection *self, const char *bssid) +{ + struct ether_addr mac; + + g_return_if_fail (bssid != NULL); + if (ether_aton_r (bssid, &mac)) { + g_hash_table_insert (NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->seen_bssids, + mac_dup (&mac), + g_strdup (bssid)); + } +} + +/** + * nm_settings_connection_read_and_fill_seen_bssids: + * @connection: the #NMSettingsConnection + * + * Retrieves seen BSSIDs of the connection from database file and stores then into the + * connection private data. + **/ +void +nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *connection) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection); + const char *connection_uuid; + GKeyFile *seen_bssids_file; + char **tmp_strv = NULL; + gsize i, len = 0; + NMSettingWireless *s_wifi; + + /* Get seen BSSIDs from database file */ + seen_bssids_file = g_key_file_new (); + g_key_file_set_list_separator (seen_bssids_file, ','); + if (g_key_file_load_from_file (seen_bssids_file, SETTINGS_SEEN_BSSIDS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL)) { + connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection)); + tmp_strv = g_key_file_get_string_list (seen_bssids_file, "seen-bssids", connection_uuid, &len, NULL); + } + g_key_file_free (seen_bssids_file); + + /* Update connection's seen-bssids */ + if (tmp_strv) { + g_hash_table_remove_all (priv->seen_bssids); + for (i = 0; i < len; i++) + add_seen_bssid_string (connection, tmp_strv[i]); + g_strfreev (tmp_strv); + } else { + /* If this connection didn't have an entry in the seen-bssids database, + * maybe this is the first time we've read it in, so populate the + * seen-bssids list from the deprecated seen-bssids property of the + * wifi setting. + */ + s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (connection)); + if (s_wifi) { + len = nm_setting_wireless_get_num_seen_bssids (s_wifi); + for (i = 0; i < len; i++) + add_seen_bssid_string (connection, nm_setting_wireless_get_seen_bssid (s_wifi, i)); + } + } +} + /**************************************************************/ static void @@ -1463,6 +1724,8 @@ nm_settings_connection_init (NMSettingsConnection *self) self); priv->agent_mgr = nm_agent_manager_get (); + + priv->seen_bssids = g_hash_table_new_full (mac_hash, mac_equal, g_free, g_free); } static void @@ -1490,6 +1753,8 @@ dispose (GObject *object) nm_agent_manager_cancel_secrets (priv->agent_mgr, GPOINTER_TO_UINT (iter->data)); g_slist_free (priv->reqs); + g_hash_table_destroy (priv->seen_bssids); + set_visible (self, FALSE); if (priv->session_changed_id) diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index 116bfdcc..bc9e3c47 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -24,6 +24,7 @@ #include <nm-connection.h> #include "nm-settings-flags.h" +#include <net/ethernet.h> G_BEGIN_DECLS @@ -116,6 +117,9 @@ gboolean nm_settings_connection_is_visible (NMSettingsConnection *self); void nm_settings_connection_recheck_visibility (NMSettingsConnection *self); +gboolean nm_settings_connection_check_permission (NMSettingsConnection *self, + const char *permission); + void nm_settings_connection_signal_remove (NMSettingsConnection *self); guint64 nm_settings_connection_get_timestamp (NMSettingsConnection *connection); @@ -124,6 +128,14 @@ void nm_settings_connection_update_timestamp (NMSettingsConnection *connection, void nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *connection); +gboolean nm_settings_connection_has_seen_bssid (NMSettingsConnection *connection, + const struct ether_addr *bssid); + +void nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection, + const struct ether_addr *seen_bssid); + +void nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *connection); + G_END_DECLS #endif /* NM_SETTINGS_CONNECTION_H */ diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index e23e8d13..733e9145 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -135,6 +135,7 @@ enum { CONNECTION_REMOVED, CONNECTION_VISIBILITY_CHANGED, CONNECTIONS_LOADED, + AGENT_REGISTERED, NEW_CONNECTION, /* exported, not used internally */ LAST_SIGNAL @@ -699,6 +700,18 @@ connection_visibility_changed (NMSettingsConnection *connection, connection); } +static void +secret_agent_registered (NMAgentManager *agent_mgr, + NMSecretAgent *agent, + gpointer user_data) +{ + /* Re-emit for listeners like NMPolicy */ + g_signal_emit (NM_SETTINGS (user_data), + signals[AGENT_REGISTERED], + 0, + agent); +} + #define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" #define NM_OPENCONNECT_KEY_GATEWAY "gateway" #define NM_OPENCONNECT_KEY_COOKIE "cookie" @@ -773,6 +786,9 @@ claim_connection (NMSettings *self, /* Read timestamp from look-aside file and put it into the connection's data */ nm_settings_connection_read_and_fill_timestamp (connection); + /* Read seen-bssids from look-aside file and put it into the connection's data */ + nm_settings_connection_read_and_fill_seen_bssids (connection); + /* Ensure it's initial visibility is up-to-date */ nm_settings_connection_recheck_visibility (connection); @@ -1527,6 +1543,8 @@ nm_settings_init (NMSettings *self) * recreated often. */ priv->agent_mgr = nm_agent_manager_get (); + + g_signal_connect (priv->agent_mgr, "agent-registered", G_CALLBACK (secret_agent_registered), self); } static void @@ -1690,6 +1708,16 @@ nm_settings_class_init (NMSettingsClass *class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + signals[AGENT_REGISTERED] = + g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsClass, agent_registered), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[NEW_CONNECTION] = g_signal_new ("new-connection", G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index a5cb4d7c..66d41cce 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -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 2007 - 2010 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2008 Novell, Inc. */ @@ -31,6 +31,7 @@ #include "nm-settings-connection.h" #include "nm-system-config-interface.h" #include "nm-device.h" +#include "nm-secret-agent.h" #define NM_TYPE_SETTINGS (nm_settings_get_type ()) #define NM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS, NMSettings)) @@ -48,6 +49,7 @@ #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" +#define NM_SETTINGS_SIGNAL_AGENT_REGISTERED "agent-registered" typedef struct { GObject parent_instance; @@ -68,6 +70,8 @@ typedef struct { void (*connection_visibility_changed) (NMSettings *self, NMSettingsConnection *connection); void (*connections_loaded) (NMSettings *self); + + void (*agent_registered) (NMSettings *self, NMSecretAgent *agent); } NMSettingsClass; GType nm_settings_get_type (void); diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c index 433f933b..04d3d3e4 100644 --- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c +++ b/src/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 - 2010 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. */ #include <string.h> @@ -181,12 +181,13 @@ nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self) static void commit_changes (NMSettingsConnection *connection, NMSettingsConnectionCommitFunc callback, - gpointer user_data) + gpointer user_data) { NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection); GError *error = NULL; NMConnection *reread; char *unmanaged = NULL, *keyfile = NULL, *routefile = NULL, *route6file = NULL; + gboolean same = FALSE; /* To ensure we don't rewrite files that are only changed from other * processes on-disk, read the existing connection back in and only rewrite @@ -200,28 +201,36 @@ commit_changes (NMSettingsConnection *connection, g_free (routefile); g_free (route6file); - if (reread && nm_connection_compare (NM_CONNECTION (connection), - reread, - NM_SETTING_COMPARE_FLAG_EXACT)) - goto out; + if (reread) { + same = nm_connection_compare (NM_CONNECTION (connection), + reread, + NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | + NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS); + g_object_unref (reread); - if (!writer_update_connection (NM_CONNECTION (connection), - IFCFG_DIR, - priv->path, - priv->keyfile, - &error)) { + /* Don't bother writing anything out if in-memory and on-disk data are the same */ + if (same) { + /* But chain up to parent to handle success - emits updated signal */ + NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data); + return; + } + } + + if (writer_update_connection (NM_CONNECTION (connection), + IFCFG_DIR, + priv->path, + priv->keyfile, + &error)) { + /* Chain up to parent to handle success */ + NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data); + } else { + /* Otherwise immediate error */ callback (connection, error, user_data); g_error_free (error); - return; } - -out: - if (reread) - g_object_unref (reread); - NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data); } -static void +static void do_delete (NMSettingsConnection *connection, NMSettingsConnectionDeleteFunc callback, gpointer user_data) diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c index 7915c467..ed0dceca 100644 --- a/src/settings/plugins/ifcfg-rh/plugin.c +++ b/src/settings/plugins/ifcfg-rh/plugin.c @@ -269,19 +269,24 @@ connection_new_or_changed (SCPluginIfcfg *self, /* Successfully read connection changes */ - /* When the connections are the same, nothing is done */ - if (nm_connection_compare (NM_CONNECTION (existing), - NM_CONNECTION (new), - NM_SETTING_COMPARE_FLAG_EXACT)) { + old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (existing)); + new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (new)); + + /* When interface is unmanaged or the connections and unmanaged specs are the same + * there's nothing to do */ + if ( (g_strcmp0 (old_unmanaged, new_unmanaged) == 0 && new_unmanaged != NULL) + || ( nm_connection_compare (NM_CONNECTION (existing), + NM_CONNECTION (new), + NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | + NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS) + && g_strcmp0 (old_unmanaged, new_unmanaged) == 0)) { + g_object_unref (new); return; } PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "updating %s", path); - 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 telling the settings service it's @@ -289,6 +294,11 @@ connection_new_or_changed (SCPluginIfcfg *self, * unmanaged specs have changed. */ nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (existing)); + /* Remove the path so that claim_connection() doesn't complain later when + * interface gets managed and connection is re-added. */ + nm_connection_set_path (NM_CONNECTION (existing), NULL); + + g_object_set (existing, NM_IFCFG_CONNECTION_UNMANAGED, new_unmanaged, NULL); g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); } } else { diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index a6f9ca85..cdf5889e 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -176,9 +176,9 @@ read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError mac = ether_aton (value); if (!mac) { - g_free (value); g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "%s: the MAC address '%s' was invalid.", key, value); + g_free (value); return FALSE; } @@ -574,7 +574,8 @@ read_full_ip4_address (shvarFile *ifcfg, if (!nm_ip4_address_get_prefix (addr)) { if (!read_ip4_address (ifcfg, netmask_tag, &tmp, error)) goto error; - nm_ip4_address_set_prefix (addr, nm_utils_ip4_netmask_to_prefix (tmp)); + if (tmp) + nm_ip4_address_set_prefix (addr, nm_utils_ip4_netmask_to_prefix (tmp)); } /* Try to autodetermine the prefix for the address' class */ @@ -661,7 +662,8 @@ read_one_ip4_route (shvarFile *ifcfg, /* Prefix */ if (!read_ip4_address (ifcfg, netmask_tag, &tmp, error)) goto out; - nm_ip4_route_set_prefix (route, nm_utils_ip4_netmask_to_prefix (tmp)); + if (tmp) + nm_ip4_route_set_prefix (route, nm_utils_ip4_netmask_to_prefix (tmp)); /* Validate the prefix */ if ( !nm_ip4_route_get_prefix (route) @@ -788,7 +790,7 @@ read_route_file_legacy (const char *filename, NMSettingIP4Config *s_ip4, GError if (prefix) { errno = 0; prefix_int = strtol (prefix, NULL, 10); - if (errno || prefix_int < 0 || prefix_int > 32) { + if (errno || prefix_int <= 0 || prefix_int > 32) { g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid IP4 route destination prefix '%s'", prefix); g_free (prefix); @@ -973,9 +975,9 @@ read_route6_file (const char *filename, NMSettingIP6Config *s_ip6, GError **erro const char *pattern_empty = "^\\s*(\\#.*)?$"; const char *pattern_to1 = "^\\s*(" IPV6_ADDR_REGEX "|default)" /* IPv6 or 'default' keyword */ - "(?:/(\\d{1,2}))?"; /* optional prefix */ + "(?:/(\\d{1,3}))?"; /* optional prefix */ const char *pattern_to2 = "to\\s+(" IPV6_ADDR_REGEX "|default)" /* IPv6 or 'default' keyword */ - "(?:/(\\d{1,2}))?"; /* optional prefix */ + "(?:/(\\d{1,3}))?"; /* optional prefix */ const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")"; /* IPv6 of gateway */ const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */ @@ -1041,7 +1043,7 @@ read_route6_file (const char *filename, NMSettingIP6Config *s_ip6, GError **erro if (prefix) { errno = 0; prefix_int = strtol (prefix, NULL, 10); - if (errno || prefix_int < 0 || prefix_int > 128) { + if (errno || prefix_int <= 0 || prefix_int > 128) { g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid IP6 route destination prefix '%s'", prefix); g_free (prefix); @@ -1228,15 +1230,11 @@ make_ip4_setting (shvarFile *ifcfg, && !tmp_ip4_0 && !tmp_prefix_0 && !tmp_netmask_0 && !tmp_ip4_1 && !tmp_prefix_1 && !tmp_netmask_1 && !tmp_ip4_2 && !tmp_prefix_2 && !tmp_netmask_2) { - if (valid_ip6_config) { + if (valid_ip6_config) /* Nope, no IPv4 */ - g_object_set (s_ip4, - NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - return NM_SETTING (s_ip4); - } - - method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + else + method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; } g_free (tmp_ip4); g_free (tmp_prefix); @@ -1260,6 +1258,9 @@ make_ip4_setting (shvarFile *ifcfg, NM_SETTING_IP4_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", TRUE), NULL); + if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) + return NM_SETTING (s_ip4); + /* Handle manual settings */ if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { NMIP4Address *addr; @@ -1418,7 +1419,7 @@ make_ip6_setting (shvarFile *ifcfg, char *value = NULL; char *str_value; char *route6_path = NULL; - gboolean bool_value, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE; + gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; guint32 i; shvarFile *network_ifcfg; @@ -1431,26 +1432,6 @@ make_ip6_setting (shvarFile *ifcfg, return NULL; } - /* Is IPV6 enabled? Set method to "ignored", when not enabled */ - str_value = svGetValue (ifcfg, "IPV6INIT", FALSE); - bool_value = svTrueValue (ifcfg, "IPV6INIT", FALSE); - if (!str_value) { - network_ifcfg = svNewFile (network_file); - if (network_ifcfg) { - bool_value = svTrueValue (network_ifcfg, "IPV6INIT", FALSE); - svCloseFile (network_ifcfg); - } - } - g_free (str_value); - - if (!bool_value) { - /* IPv6 is disabled */ - g_object_set (s_ip6, - NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NULL); - return NM_SETTING (s_ip6); - } - /* First check if IPV6_DEFROUTE is set for this device; IPV6_DEFROUTE has the * opposite meaning from never-default. The default if IPV6_DEFROUTE is not * specified is IPV6_DEFROUTE=yes which means that this connection can be used @@ -1493,23 +1474,39 @@ make_ip6_setting (shvarFile *ifcfg, } /* Find out method property */ - ipv6forwarding = svTrueValue (ifcfg, "IPV6FORWARDING", FALSE); - ipv6_autoconf = svTrueValue (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding); - dhcp6 = svTrueValue (ifcfg, "DHCPV6C", FALSE); - - if (ipv6_autoconf) - method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; - else if (dhcp6) - method = NM_SETTING_IP6_CONFIG_METHOD_DHCP; + /* Is IPV6 enabled? Set method to "ignored", when not enabled */ + str_value = svGetValue (ifcfg, "IPV6INIT", FALSE); + ipv6init = svTrueValue (ifcfg, "IPV6INIT", FALSE); + if (!str_value) { + network_ifcfg = svNewFile (network_file); + if (network_ifcfg) { + ipv6init = svTrueValue (network_ifcfg, "IPV6INIT", FALSE); + svCloseFile (network_ifcfg); + } + } + g_free (str_value); + + if (!ipv6init) + method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */ else { - /* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */ - str_value = svGetValue (ifcfg, "IPV6ADDR", FALSE); - if (!str_value) - str_value = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE); + ipv6forwarding = svTrueValue (ifcfg, "IPV6FORWARDING", FALSE); + ipv6_autoconf = svTrueValue (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding); + dhcp6 = svTrueValue (ifcfg, "DHCPV6C", FALSE); + + if (ipv6_autoconf) + method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; + else if (dhcp6) + method = NM_SETTING_IP6_CONFIG_METHOD_DHCP; + else { + /* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */ + str_value = svGetValue (ifcfg, "IPV6ADDR", FALSE); + if (!str_value) + str_value = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE); - if (!str_value) - method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; - g_free (str_value); + if (!str_value) + method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; + g_free (str_value); + } } /* TODO - handle other methods */ @@ -1521,6 +1518,10 @@ make_ip6_setting (shvarFile *ifcfg, NM_SETTING_IP6_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE), NULL); + /* Don't bother to read IP, DNS and routes when IPv6 is disabled */ + if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) + return NM_SETTING (s_ip6); + if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { NMIP6Address *addr; char *val; @@ -2234,6 +2235,7 @@ eap_peap_reader (const char *eap_method, gboolean phase2, GError **error) { + char *anon_ident = NULL; char *ca_cert = NULL; char *real_cert_path = NULL; char *inner_auth = NULL; @@ -2275,6 +2277,10 @@ eap_peap_reader (const char *eap_method, if (svTrueValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE)) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL); + anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE); + if (anon_ident && strlen (anon_ident)) + g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL); + inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE); if (!inner_auth) { g_set_error (error, IFCFG_PLUGIN_ERROR, 0, @@ -2324,6 +2330,7 @@ done: g_free (peapver); g_free (real_cert_path); g_free (ca_cert); + g_free (anon_ident); return success; } @@ -2737,6 +2744,7 @@ make_wireless_setting (shvarFile *ifcfg, { NMSettingWireless *s_wireless; GByteArray *array = NULL; + GSList *macaddr_blacklist = NULL; char *value; s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); @@ -2770,6 +2778,33 @@ make_wireless_setting (shvarFile *ifcfg, g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, array, NULL); g_byte_array_free (array, TRUE); } + } else { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: %s", (*error)->message); + g_clear_error (error); + } + + value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE); + if (value) { + char **list = NULL, **iter; + struct ether_addr addr; + + list = g_strsplit_set (value, " \t", 0); + for (iter = list; iter && *iter; iter++) { + if (**iter == '\0') + continue; + if (!ether_aton_r (*iter, &addr)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid MAC in HWADDR_BLACKLIST '%s'", *iter); + continue; + } + macaddr_blacklist = g_slist_prepend (macaddr_blacklist, *iter); + } + if (macaddr_blacklist) { + macaddr_blacklist = g_slist_reverse (macaddr_blacklist); + g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, macaddr_blacklist, NULL); + g_slist_free (macaddr_blacklist); + } + g_free (value); + g_strfreev (list); } value = svGetValue (ifcfg, "ESSID", TRUE); @@ -3030,6 +3065,7 @@ make_wired_setting (shvarFile *ifcfg, char *value = NULL; int mtu; GByteArray *mac = NULL; + GSList *macaddr_blacklist = NULL; char *nettype; s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); @@ -3162,6 +3198,33 @@ make_wired_setting (shvarFile *ifcfg, g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, mac, NULL); g_byte_array_free (mac, TRUE); } + } else { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: %s", (*error)->message); + g_clear_error (error); + } + + value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE); + if (value) { + char **list = NULL, **iter; + struct ether_addr addr; + + list = g_strsplit_set (value, " \t", 0); + for (iter = list; iter && *iter; iter++) { + if (**iter == '\0') + continue; + if (!ether_aton_r (*iter, &addr)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid MAC in HWADDR_BLACKLIST '%s'", *iter); + continue; + } + macaddr_blacklist = g_slist_prepend (macaddr_blacklist, *iter); + } + if (macaddr_blacklist) { + macaddr_blacklist = g_slist_reverse (macaddr_blacklist); + g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, macaddr_blacklist, NULL); + g_slist_free (macaddr_blacklist); + } + g_free (value); + g_strfreev (list); } value = svGetValue (ifcfg, "KEY_MGMT", FALSE); @@ -3246,7 +3309,7 @@ is_wireless_device (const char *iface) g_return_val_if_fail (iface != NULL, FALSE); fd = socket(AF_INET, SOCK_DGRAM, 0); - if (!fd) + if (fd == -1) return FALSE; memset (&wrq, 0, sizeof (struct iwreq)); diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-8021x-peap-mschapv2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-8021x-peap-mschapv2 index 6d68eca1..27bcbbf9 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-8021x-peap-mschapv2 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-8021x-peap-mschapv2 @@ -12,4 +12,4 @@ IEEE_8021X_CA_CERT=test_ca_cert.pem IEEE_8021X_PEAP_VERSION=1 IEEE_8021X_PEAP_FORCE_NEW_LABEL=yes IEEE_8021X_INNER_AUTH_METHODS=MSCHAPV2 - +IEEE_8021X_ANON_IDENTITY=somebody diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index e6013f8d..d1f08aa9 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -2707,6 +2707,7 @@ test_read_wired_8021x_peap_mschapv2 (void) GError *error = NULL; const char *tmp; const char *expected_identity = "David Smith"; + const char *expected_anon_identity = "somebody"; const char *expected_password = "foobar baz"; gboolean success = FALSE; const char *expected_ca_cert_path; @@ -2793,6 +2794,19 @@ test_read_wired_8021x_peap_mschapv2 (void) NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_IDENTITY); + /* Anonymous Identity */ + tmp = nm_setting_802_1x_get_anonymous_identity (s_8021x); + ASSERT (tmp != NULL, + "wired-8021x-peap-mschapv2-verify-8021x", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2, + NM_SETTING_802_1X_SETTING_NAME, + NM_SETTING_802_1X_ANONYMOUS_IDENTITY); + ASSERT (strcmp (tmp, expected_anon_identity) == 0, + "wired-8021x-peap-mschapv2-verify-8021x", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2, + NM_SETTING_802_1X_SETTING_NAME, + NM_SETTING_802_1X_ANONYMOUS_IDENTITY); + /* Password */ tmp = nm_setting_802_1x_get_password (s_8021x); ASSERT (tmp != NULL, @@ -6491,7 +6505,7 @@ test_write_wired_static (void) struct in6_addr ip6, ip6_1, ip6_2; struct in6_addr route1_dest, route2_dest, route1_nexthop, route2_nexthop; struct in6_addr dns6_1, dns6_2; - const guint32 route1_prefix = 64, route2_prefix = 0; + const guint32 route1_prefix = 64, route2_prefix = 128; const guint32 route1_metric = 99, route2_metric = 1; NMIP4Address *addr; NMIP6Address *addr6; @@ -6774,6 +6788,7 @@ test_write_wired_dhcp (void) g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, NULL); /* Save the ifcfg */ @@ -7234,7 +7249,10 @@ test_write_wired_static_routes (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wired-static-routes-write", "failed to verify connection: %s", @@ -7350,7 +7368,10 @@ test_write_wired_dhcp_8021x_peap_mschapv2 (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); /* 802.1x setting */ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); @@ -7361,6 +7382,7 @@ test_write_wired_dhcp_8021x_peap_mschapv2 (void) g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, "Bob Saget", + NM_SETTING_802_1X_ANONYMOUS_IDENTITY, "barney", NM_SETTING_802_1X_PASSWORD, "Kids, it was back in October 2008...", NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", @@ -7508,7 +7530,10 @@ test_write_wired_8021x_tls (NMSetting8021xCKScheme scheme, /* IP6 setting */ s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); g_assert (s_ip6); - g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); nm_connection_add_setting (connection, NM_SETTING (s_ip6)); /* 802.1x setting */ @@ -7753,7 +7778,10 @@ test_write_wifi_open (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-open-write", "failed to verify connection: %s", @@ -7892,7 +7920,10 @@ test_write_wifi_open_hex_ssid (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-open-hex-ssid-write", "failed to verify connection: %s", @@ -8035,7 +8066,10 @@ test_write_wifi_wep (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wep-write", "failed to verify connection: %s", @@ -8198,7 +8232,10 @@ test_write_wifi_wep_adhoc (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wep-adhoc-write", "failed to verify connection: %s", @@ -8351,7 +8388,10 @@ test_write_wifi_wep_passphrase (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wep-passphrase-write", "failed to verify connection: %s", @@ -8506,7 +8546,10 @@ test_write_wifi_wep_40_ascii (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wep-40-ascii-write", "failed to verify connection: %s", @@ -8661,7 +8704,10 @@ test_write_wifi_wep_104_ascii (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wep-104-ascii-write", "failed to verify connection: %s", @@ -8813,7 +8859,10 @@ test_write_wifi_leap (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-leap-write", "failed to verify connection: %s", @@ -8949,7 +8998,11 @@ test_write_wifi_leap_secret_flags (NMSettingSecretFlags flags) s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); g_assert (s_ip6); 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); + + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); success = nm_connection_verify (connection, &error); g_assert_no_error (error); @@ -9114,7 +9167,10 @@ test_write_wifi_wpa_psk (const char *name, 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, test_name, "failed to verify connection: %s", @@ -9277,7 +9333,10 @@ test_write_wifi_wpa_psk_adhoc (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wpa-psk-adhoc-write", "failed to verify connection: %s", @@ -9458,7 +9517,10 @@ test_write_wifi_wpa_eap_tls (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wpa-eap-tls-write", "failed to verify connection: %s", @@ -9657,7 +9719,10 @@ test_write_wifi_wpa_eap_ttls_tls (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wpa-eap-ttls-tls-write", "failed to verify connection: %s", @@ -9828,7 +9893,10 @@ test_write_wifi_wpa_eap_ttls_mschapv2 (void) 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); ASSERT (nm_connection_verify (connection, &error) == TRUE, "wifi-wpa-eap-ttls-mschapv2-write", "failed to verify connection: %s", @@ -9970,7 +10038,10 @@ test_write_wifi_wpa_then_open (void) g_assert (s_ip6); 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); + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); success = nm_connection_verify (connection, &error); g_assert_no_error (error); @@ -10154,9 +10225,13 @@ test_write_wifi_dynamic_wep_leap (void) /* IP6 setting */ s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); g_assert (s_ip6); - g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); 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, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); + success = nm_connection_verify (connection, &error); g_assert_no_error (error); g_assert (success); @@ -10688,6 +10763,7 @@ test_write_wired_qeth_dhcp (void) g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, NULL); /* Verify */ @@ -10804,7 +10880,11 @@ test_write_wired_ctc_dhcp (void) s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); g_assert (s_ip6); 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); + + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); /* Verify */ success = nm_connection_verify (connection, &error); @@ -10939,6 +11019,7 @@ test_write_permissions (void) g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, NULL); /* Verify */ @@ -11040,7 +11121,11 @@ test_write_wifi_wep_agent_keys (void) s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); g_assert (s_ip6); 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); + + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); /* Wifi setting */ s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index 6b66b232..192226ac 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -758,6 +758,7 @@ write_wireless_setting (NMConnection *connection, char buf[33]; guint32 mtu, chan, i; gboolean adhoc = FALSE, hex_ssid = FALSE; + const GSList *macaddr_blacklist; s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); if (!s_wireless) { @@ -786,6 +787,23 @@ write_wireless_setting (NMConnection *connection, g_free (tmp); } + svSetValue (ifcfg, "HWADDR_BLACKLIST", NULL, FALSE); + macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); + if (macaddr_blacklist) { + const GSList *iter; + GString *blacklist_str = g_string_new (NULL); + + for (iter = macaddr_blacklist; iter; iter = g_slist_next (iter)) { + g_string_append (blacklist_str, iter->data); + g_string_append_c (blacklist_str, ' '); + + } + if (blacklist_str->len > 0) + g_string_truncate (blacklist_str, blacklist_str->len - 1); + svSetValue (ifcfg, "HWADDR_BLACKLIST", blacklist_str->str, FALSE); + g_string_free (blacklist_str, TRUE); + } + svSetValue (ifcfg, "MTU", NULL, FALSE); mtu = nm_setting_wireless_get_mtu (s_wireless); if (mtu) { @@ -934,6 +952,7 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) guint32 mtu, num_opts, i; const GPtrArray *s390_subchannels; GString *str; + const GSList *macaddr_blacklist; s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); if (!s_wired) { @@ -961,6 +980,23 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) g_free (tmp); } + svSetValue (ifcfg, "HWADDR_BLACKLIST", NULL, FALSE); + macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); + if (macaddr_blacklist) { + const GSList *iter; + GString *blacklist_str = g_string_new (NULL); + + for (iter = macaddr_blacklist; iter; iter = g_slist_next (iter)) { + g_string_append (blacklist_str, iter->data); + g_string_append_c (blacklist_str, ' '); + + } + if (blacklist_str->len > 0) + g_string_truncate (blacklist_str, blacklist_str->len - 1); + svSetValue (ifcfg, "HWADDR_BLACKLIST", blacklist_str->str, FALSE); + g_string_free (blacklist_str, TRUE); + } + svSetValue (ifcfg, "MTU", NULL, FALSE); mtu = nm_setting_wired_get_mtu (s_wired); if (mtu) { @@ -1316,13 +1352,14 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (utils_has_route_file_new_syntax (route_path)) { shvarFile *routefile; - g_free (route_path); routefile = utils_get_route_ifcfg (ifcfg->fileName, TRUE); if (!routefile) { g_set_error (error, IFCFG_PLUGIN_ERROR, 0, - "Could not create route file '%s'", routefile->fileName); + "Could not create route file '%s'", route_path); + g_free (route_path); goto out; } + g_free (route_path); num = nm_setting_ip4_config_get_num_routes (s_ip4); for (i = 0; i < 256; i++) { diff --git a/src/settings/plugins/ifnet/plugin.c b/src/settings/plugins/ifnet/plugin.c index 69b7bc80..59083688 100644 --- a/src/settings/plugins/ifnet/plugin.c +++ b/src/settings/plugins/ifnet/plugin.c @@ -278,7 +278,8 @@ reload_connections (gpointer config) if (auto_refresh && is_true (auto_refresh)) { if (!nm_connection_compare (NM_CONNECTION (old), NM_CONNECTION (new), - NM_SETTING_COMPARE_FLAG_EXACT)) { + NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | + NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) { PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Auto refreshing %s", conn_name); /* Remove and re-add to disconnect and reconnect with new settings */ diff --git a/src/settings/plugins/keyfile/common.h b/src/settings/plugins/keyfile/common.h index 6c8f9ceb..7d94a705 100644 --- a/src/settings/plugins/keyfile/common.h +++ b/src/settings/plugins/keyfile/common.h @@ -23,9 +23,6 @@ #include <glib.h> -#define SWP_TAG ".swp" -#define SWPX_TAG ".swpx" - #define KEYFILE_PLUGIN_NAME "keyfile" #define KEYFILE_PLUGIN_INFO "(c) 2007 - 2010 Red Hat, Inc. To report bugs please use the NetworkManager mailing list." diff --git a/src/settings/plugins/keyfile/plugin.c b/src/settings/plugins/keyfile/plugin.c index ffc614bc..af69c200 100644 --- a/src/settings/plugins/keyfile/plugin.c +++ b/src/settings/plugins/keyfile/plugin.c @@ -231,7 +231,8 @@ dir_changed (GFileMonitor *monitor, if (tmp) { if (!nm_connection_compare (NM_CONNECTION (connection), NM_CONNECTION (tmp), - NM_SETTING_COMPARE_FLAG_EXACT)) { + NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | + NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) { PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", full_path); update_connection_settings (connection, tmp); } diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c index a8eaaa8e..c4136e05 100644 --- a/src/settings/plugins/keyfile/reader.c +++ b/src/settings/plugins/keyfile/reader.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2008 - 2010 Red Hat, Inc. + * Copyright (C) 2008 - 2011 Red Hat, Inc. */ #include <errno.h> @@ -40,6 +40,7 @@ #include <ctype.h> #include "nm-dbus-glib-types.h" +#include "nm-system-config-interface.h" #include "reader.h" #include "common.h" @@ -735,29 +736,27 @@ get_uchar_array (GKeyFile *keyfile, const char *key) { GByteArray *array = NULL; - char *p, *tmp_string; + char *tmp_string; gint *tmp_list; gsize length; int i; - /* New format: just a string. We try parsing the new format if there are - * no ';' in the string or it's not just numbers. + /* New format: just a string + * Old format: integer list; e.g. 11;25;38 */ - p = tmp_string = g_key_file_get_string (keyfile, setting_name, key, NULL); + tmp_string = g_key_file_get_string (keyfile, setting_name, key, NULL); if (tmp_string) { gboolean new_format = FALSE; + GRegex *regex; + GMatchInfo *match_info; + const char *pattern = "^[[:space:]]*[[:digit:]]{1,3}[[:space:]]*(;[[:space:]]*[[:digit:]]{1,3}[[:space:]]*)*(;[[:space:]]*)?$"; - if (strchr (p, ';') == NULL) - new_format = TRUE; - else { + regex = g_regex_new (pattern, 0, 0, NULL); + g_regex_match (regex, tmp_string, 0, &match_info); + if (!g_match_info_matches (match_info)) new_format = TRUE; - while (p && *p) { - if (!isdigit (*p++)) { - new_format = FALSE; - break; - } - } - } + g_match_info_free (match_info); + g_regex_unref (regex); if (new_format) { array = g_byte_array_sized_new (strlen (tmp_string)); @@ -835,6 +834,24 @@ get_cert_path (const char *keyfile_path, GByteArray *cert_path) #define SCHEME_PATH "file://" +static const char *certext[] = { ".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key" }; + +static gboolean +has_cert_ext (GByteArray *array) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (certext); i++) { + guint32 extlen = strlen (certext[i]); + + if (array->len <= extlen) + continue; + if (memcmp (&array->data[array->len - extlen], certext[i], extlen) == 0) + return TRUE; + } + return FALSE; +} + static void cert_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) { @@ -859,17 +876,31 @@ cert_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char && g_utf8_validate ((const char *) array->data, array->len, NULL)) { GByteArray *val; char *path; + gboolean exists; + + /* Might be a bare path without the file:// prefix; in that case + * if it's an absolute path, use that, otherwise treat it as a + * relative path to the current directory. + */ path = get_cert_path (keyfile_path, array); - if (g_file_test (path, G_FILE_TEST_EXISTS)) { + exists = g_file_test (path, G_FILE_TEST_EXISTS); + if ( exists + || memchr (array->data, '/', array->len) + || has_cert_ext (array)) { /* Construct the proper value as required for the PATH scheme */ val = g_byte_array_sized_new (strlen (SCHEME_PATH) + array->len + 1); g_byte_array_append (val, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); - g_byte_array_append (val, array->data, array->len); + g_byte_array_append (val, (const guint8 *) path, strlen (path)); g_byte_array_append (val, (const guint8 *) "\0", 1); g_object_set (setting, key, val, NULL); g_byte_array_free (val, TRUE); success = TRUE; + + /* Warn if the certificate didn't exist */ + if (exists == FALSE) { + PLUGIN_WARN (KEYFILE_PLUGIN_NAME, " certificate or key %s does not exist", path); + } } g_free (path); } @@ -881,7 +912,7 @@ cert_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char g_byte_array_free (array, TRUE); } else { - g_warning ("%s: ignoring invalid SSID for %s / %s", + g_warning ("%s: ignoring invalid key/cert value for %s / %s", __func__, setting_name, key); } } diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am index 0ce03209..302db866 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am +++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am @@ -7,8 +7,11 @@ KEYFILES = \ ATT_Data_Connect_BT \ ATT_Data_Connect_Plain \ Test_String_SSID \ + Test_Intlist_SSID \ Test_Wired_TLS_Old \ - Test_Wired_TLS_New + Test_Wired_TLS_New \ + Test_Wired_TLS_Blob \ + Test_Wired_TLS_Path_Missing CERTS = \ test-ca-cert.pem \ diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in index 2c3c1630..083615b0 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in +++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in @@ -277,8 +277,11 @@ KEYFILES = \ ATT_Data_Connect_BT \ ATT_Data_Connect_Plain \ Test_String_SSID \ + Test_Intlist_SSID \ Test_Wired_TLS_Old \ - Test_Wired_TLS_New + Test_Wired_TLS_New \ + Test_Wired_TLS_Blob \ + Test_Wired_TLS_Path_Missing CERTS = \ test-ca-cert.pem \ diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlist_SSID b/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlist_SSID new file mode 100644 index 00000000..6d2bc0fa --- /dev/null +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlist_SSID @@ -0,0 +1,11 @@ +[connection] +id=Test +uuid=2f962388-e5f3-45af-a62c-ac220b8f7baa +type=802-11-wireless + +[802-11-wireless] +ssid=98;108;97;104;49;50;51;52; + +[ipv4] +method=auto + diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_TLS_Blob b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_TLS_Blob new file mode 100644 index 00000000..9f4ef62f --- /dev/null +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_TLS_Blob @@ -0,0 +1,22 @@ + +[connection] +id=Wired TLS +uuid=5ee46013-9469-4c6a-a60a-0c7a1e1c7488 +type=802-3-ethernet + +[802-1x] +eap=tls; +identity=Bill Smith +ca-cert=48;130;2;52;48;130;1;161;2;16;2;173;102;126;78;69;254;94;87;111;60;152;25;94;221;192;48;13;6;9;42;134;72;134;247;13;1;1;2;5;0;48;95;49;11;48;9;6;3;85;4;6;19;2;85;83;49;32;48;30;6;3;85;4;10;19;23;82;83;65;32;68;97;116;97;32;83;101;99;117;114;105;116;121;44;32;73;110;99;46;49;46;48;44;6;3;85;4;11;19;37;83;101;99;117;114;101;32;83;101;114;118;101;114;32;67;101;114;116;105;102;105;99;97;116;105;111;110;32;65;117;116;104;111;114;105;116;121;48;30;23;13;57;52;49;49;48;57;48;48;48;48;48;48;90;23;13;49;48;48;49;48;55;50;51;53;57;53;57;90;48;95;49;11;48;9;6;3;85;4;6;19;2;85;83;49;32;48;30;6;3;85;4;10;19;23;82;83;65;32;68;97;116;97;32;83;101;99;117;114;105;116;121;44;32;73;110;99;46;49;46;48;44;6;3;85;4;11;19;37;83;101;99;117;114;101;32;83;101;114;118;101;114;32;67;101;114;116;105;102;105;99;97;116;105;111;110;32;65;117;116;104;111;114;105;116;121;48;129;155;48;13;6;9;42;134;72;134;247;13;1;1;1;5;0;3;129;137;0;48;129;133;2;126;0;146;206;122;193;174;131;62;90;170;137;131;87;172;37;1;118;12;173;174;142;44;55;206;235;53;120;100;84;3;229;132;64;81;201;191;143;8;226;138;130;8;210;22;134;55;85;233;177;33;2;173;118;104;129;154;5;162;75;201;75;37;102;34;86;108;136;7;143;247;129;89;109;132;7;101;112;19;113;118;62;155;119;76;227;80;137;86;152;72;185;29;167;41;26;19;46;74;17;89;156;30;21;213;73;84;44;115;58;105;130;177;151;57;156;109;112;103;72;229;221;45;214;200;30;123;2;3;1;0;1;48;13;6;9;42;134;72;134;247;13;1;1;2;5;0;3;126;0;101;221;126;225;178;236;176;226;58;224;236;113;70;154;25;17;184;211;199;160;180;3;64;38;2;62;9;156;225;18;179;209;90;246;55;165;183;97;3;182;91;22;105;59;198;68;8;12;136;83;12;107;151;73;199;62;53;220;108;185;187;170;223;92;187;58;47;147;96;182;169;75;77;242;32;247;205;95;127;100;123;142;220;0;92;215;250;119;202;57;22;89;111;14;234;211;181;131;127;77;77;66;86;118;180;201;95;4;248;56;248;235;210;95;117;95;205;123;252;229;142;128;124;252;80; +client-cert=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0; +private-key=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0; +private-key-password=12345testing + +[ipv4] +method=auto + +[802-3-ethernet] +duplex=full + +[ipv6] +method=ignore diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_TLS_Path_Missing b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_TLS_Path_Missing new file mode 100644 index 00000000..2b39538e --- /dev/null +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_TLS_Path_Missing @@ -0,0 +1,22 @@ + +[connection] +id=Wired TLS +uuid=5ee46013-9469-4c6a-a60a-0c7a1e1c7488 +type=802-3-ethernet + +[802-1x] +eap=tls; +identity=Bill Smith +ca-cert=/some/random/cert/path.pem +client-cert=test-key-and-cert.pem +private-key=test-key-and-cert.pem +private-key-password=12345testing + +[ipv4] +method=auto + +[802-3-ethernet] +duplex=full + +[ipv6] +method=ignore diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index bfe5aa43..3bbaaaec 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -1438,6 +1438,131 @@ test_write_string_ssid (void) g_object_unref (connection); } +#define TEST_INTLIST_SSID_FILE TEST_KEYFILES_DIR"/Test_Intlist_SSID" + +static void +test_read_intlist_ssid (void) +{ + NMConnection *connection; + NMSettingWireless *s_wifi; + GError *error = NULL; + gboolean success; + const GByteArray *array; + const char *expected_ssid = "blah1234"; + + connection = nm_keyfile_plugin_connection_from_file (TEST_INTLIST_SSID_FILE, &error); + g_assert_no_error (error); + g_assert (connection); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + /* SSID */ + s_wifi = nm_connection_get_setting_wireless (connection); + g_assert (s_wifi); + + array = nm_setting_wireless_get_ssid (s_wifi); + g_assert (array != NULL); + g_assert_cmpint (array->len, ==, strlen (expected_ssid)); + g_assert_cmpint (memcmp (array->data, expected_ssid, strlen (expected_ssid)), ==, 0); + + g_object_unref (connection); +} + +static void +test_write_intlist_ssid (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + NMSettingIP4Config *s_ip4; + char *uuid, *testfile = NULL; + GByteArray *ssid; + unsigned char tmpssid[] = { 65, 49, 50, 51, 0, 50, 50 }; + gboolean success; + NMConnection *reread; + GError *error = NULL; + pid_t owner_grp; + uid_t owner_uid; + GKeyFile *keyfile; + gint *intlist; + gsize len = 0, i; + + connection = nm_connection_new (); + g_assert (connection); + + /* Connection setting */ + + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + g_assert (s_con); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Intlist SSID Test", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + g_free (uuid); + + /* Wireless setting */ + s_wifi = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); + g_assert (s_wifi); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + ssid = g_byte_array_sized_new (sizeof (tmpssid)); + g_byte_array_append (ssid, &tmpssid[0], sizeof (tmpssid)); + g_object_set (s_wifi, NM_SETTING_WIRELESS_SSID, ssid, NULL); + g_byte_array_free (ssid, TRUE); + + /* IP4 setting */ + s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ()); + g_assert (s_ip4); + 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); + + /* Write out the connection */ + owner_uid = geteuid (); + owner_grp = getegid (); + success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); + g_assert_no_error (error); + g_assert (success); + g_assert (testfile != NULL); + + /* Ensure the SSID was written out as an int list */ + keyfile = g_key_file_new (); + success = g_key_file_load_from_file (keyfile, testfile, 0, &error); + g_assert_no_error (error); + g_assert (success); + + intlist = g_key_file_get_integer_list (keyfile, NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SSID, &len, &error); + g_assert_no_error (error); + g_assert (intlist); + g_assert_cmpint (len, ==, sizeof (tmpssid)); + + for (i = 0; i < len; i++) + g_assert_cmpint (intlist[i], ==, tmpssid[i]); + g_free (intlist); + + g_key_file_free (keyfile); + + /* Read the connection back in and compare it to the one we just wrote out */ + reread = nm_keyfile_plugin_connection_from_file (testfile, &error); + g_assert_no_error (error); + g_assert (reread); + + success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT); + g_assert (success); + + g_clear_error (&error); + unlink (testfile); + g_free (testfile); + + g_object_unref (reread); + g_object_unref (connection); +} + #define TEST_BT_DUN_FILE TEST_KEYFILES_DIR"/ATT_Data_Connect_BT" static void @@ -1953,6 +2078,133 @@ test_write_gsm_connection (void) g_object_unref (connection); } +#define TEST_WIRED_TLS_BLOB_FILE TEST_KEYFILES_DIR"/Test_Wired_TLS_Blob" + +static void +test_read_wired_8021x_tls_blob_connection (void) +{ + NMConnection *connection; + NMSetting *s_wired; + NMSetting8021x *s_8021x; + GError *error = NULL; + const char *tmp; + gboolean success; + const GByteArray *array; + + connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_TLS_BLOB_FILE, &error); + if (connection == NULL) { + g_assert (error); + g_warning ("Failed to read %s: %s", TEST_WIRED_TLS_BLOB_FILE, error->message); + g_assert (connection); + } + + success = nm_connection_verify (connection, &error); + if (!success) { + g_assert (error); + g_warning ("Failed to verify %s: %s", TEST_WIRED_TLS_BLOB_FILE, error->message); + g_assert (success); + } + + /* ===== Wired Setting ===== */ + s_wired = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); + g_assert (s_wired != NULL); + + /* ===== 802.1x Setting ===== */ + s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); + g_assert (s_8021x != NULL); + + g_assert (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 1); + tmp = nm_setting_802_1x_get_eap_method (s_8021x, 0); + g_assert (g_strcmp0 (tmp, "tls") == 0); + + tmp = nm_setting_802_1x_get_identity (s_8021x); + g_assert (g_strcmp0 (tmp, "Bill Smith") == 0); + + tmp = nm_setting_802_1x_get_private_key_password (s_8021x); + g_assert (g_strcmp0 (tmp, "12345testing") == 0); + + g_assert_cmpint (nm_setting_802_1x_get_ca_cert_scheme (s_8021x), ==, NM_SETTING_802_1X_CK_SCHEME_BLOB); + + /* Make sure it's not a path, since it's a blob */ + tmp = nm_setting_802_1x_get_ca_cert_path (s_8021x); + g_assert (tmp == NULL); + + /* Validate the path */ + array = nm_setting_802_1x_get_ca_cert_blob (s_8021x); + g_assert (array != NULL); + g_assert_cmpint (array->len, ==, 568); + + tmp = nm_setting_802_1x_get_client_cert_path (s_8021x); + g_assert_cmpstr (tmp, ==, "/home/dcbw/Desktop/certinfra/client.pem"); + + tmp = nm_setting_802_1x_get_private_key_path (s_8021x); + g_assert_cmpstr (tmp, ==, "/home/dcbw/Desktop/certinfra/client.pem"); + + g_object_unref (connection); +} + +#define TEST_WIRED_TLS_PATH_MISSING_FILE TEST_KEYFILES_DIR"/Test_Wired_TLS_Path_Missing" + +static void +test_read_wired_8021x_tls_bad_path_connection (void) +{ + NMConnection *connection; + NMSetting *s_wired; + NMSetting8021x *s_8021x; + GError *error = NULL; + const char *tmp; + char *tmp2; + gboolean success; + + connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_TLS_PATH_MISSING_FILE, &error); + if (connection == NULL) { + g_assert (error); + g_warning ("Failed to read %s: %s", TEST_WIRED_TLS_PATH_MISSING_FILE, error->message); + g_assert (connection); + } + + success = nm_connection_verify (connection, &error); + if (!success) { + g_assert (error); + g_warning ("Failed to verify %s: %s", TEST_WIRED_TLS_BLOB_FILE, error->message); + g_assert (success); + } + + /* ===== Wired Setting ===== */ + s_wired = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); + g_assert (s_wired != NULL); + + /* ===== 802.1x Setting ===== */ + s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); + g_assert (s_8021x != NULL); + + g_assert (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 1); + tmp = nm_setting_802_1x_get_eap_method (s_8021x, 0); + g_assert (g_strcmp0 (tmp, "tls") == 0); + + tmp = nm_setting_802_1x_get_identity (s_8021x); + g_assert (g_strcmp0 (tmp, "Bill Smith") == 0); + + tmp = nm_setting_802_1x_get_private_key_password (s_8021x); + g_assert (g_strcmp0 (tmp, "12345testing") == 0); + + g_assert_cmpint (nm_setting_802_1x_get_ca_cert_scheme (s_8021x), ==, NM_SETTING_802_1X_CK_SCHEME_PATH); + + tmp = nm_setting_802_1x_get_ca_cert_path (s_8021x); + g_assert_cmpstr (tmp, ==, "/some/random/cert/path.pem"); + + tmp2 = g_strdup_printf (TEST_KEYFILES_DIR "/test-key-and-cert.pem"); + + tmp = nm_setting_802_1x_get_client_cert_path (s_8021x); + g_assert_cmpstr (tmp, ==, tmp2); + + tmp = nm_setting_802_1x_get_private_key_path (s_8021x); + g_assert_cmpstr (tmp, ==, tmp2); + + g_free (tmp2); + g_object_unref (connection); +} + #define TEST_WIRED_TLS_OLD_FILE TEST_KEYFILES_DIR"/Test_Wired_TLS_Old" static void @@ -2019,6 +2271,7 @@ test_read_wired_8021x_tls_new_connection (void) NMSetting8021x *s_8021x; GError *error = NULL; const char *tmp; + char *tmp2; gboolean success; connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_TLS_NEW_FILE, &error); @@ -2053,15 +2306,20 @@ test_read_wired_8021x_tls_new_connection (void) tmp = nm_setting_802_1x_get_private_key_password (s_8021x); g_assert (g_strcmp0 (tmp, "12345testing") == 0); + tmp2 = g_strdup_printf (TEST_KEYFILES_DIR "/test-ca-cert.pem"); tmp = nm_setting_802_1x_get_ca_cert_path (s_8021x); - g_assert (g_strcmp0 (tmp, "test-ca-cert.pem") == 0); + g_assert_cmpstr (tmp, ==, tmp2); + g_free (tmp2); + + tmp2 = g_strdup_printf (TEST_KEYFILES_DIR "/test-key-and-cert.pem"); tmp = nm_setting_802_1x_get_client_cert_path (s_8021x); - g_assert (g_strcmp0 (tmp, "test-key-and-cert.pem") == 0); + g_assert_cmpstr (tmp, ==, tmp2); tmp = nm_setting_802_1x_get_private_key_path (s_8021x); - g_assert (g_strcmp0 (tmp, "test-key-and-cert.pem") == 0); + g_assert_cmpstr (tmp, ==, tmp2); + g_free (tmp2); g_object_unref (connection); } @@ -2153,16 +2411,23 @@ create_wired_tls_connection (NMSetting8021xCKScheme scheme) return connection; } +static char * +get_path (const char *file, gboolean relative) +{ + return relative ? g_path_get_basename (file) : g_strdup (file); +} + static void test_write_wired_8021x_tls_connection_path (void) { NMConnection *connection; - char *tmp; + char *tmp, *tmp2; gboolean success; NMConnection *reread; char *testfile = NULL; GError *error = NULL; GKeyFile *keyfile; + gboolean relative = FALSE; connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_PATH); g_assert (connection != NULL); @@ -2200,12 +2465,22 @@ test_write_wired_8021x_tls_connection_path (void) g_assert (success); } + /* Depending on whether this test is being run from 'make check' or + * 'make distcheck' we might be using relative paths (check) or + * absolute ones (distcheck). + */ + tmp2 = g_path_get_dirname (testfile); + if (g_strcmp0 (tmp2, TEST_KEYFILES_DIR) == 0) + relative = TRUE; + /* CA cert */ tmp = g_key_file_get_string (keyfile, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT, NULL); - g_assert (g_strcmp0 (tmp, TEST_WIRED_TLS_CA_CERT) == 0); + tmp2 = get_path (TEST_WIRED_TLS_CA_CERT, relative); + g_assert_cmpstr (tmp, ==, tmp2); + g_free (tmp2); g_free (tmp); /* Client cert */ @@ -2213,7 +2488,9 @@ test_write_wired_8021x_tls_connection_path (void) NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT, NULL); - g_assert (g_strcmp0 (tmp, TEST_WIRED_TLS_CLIENT_CERT) == 0); + tmp2 = get_path (TEST_WIRED_TLS_CLIENT_CERT, relative); + g_assert_cmpstr (tmp, ==, tmp2); + g_free (tmp2); g_free (tmp); /* Private key */ @@ -2221,7 +2498,9 @@ test_write_wired_8021x_tls_connection_path (void) NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY, NULL); - g_assert (g_strcmp0 (tmp, TEST_WIRED_TLS_PRIVKEY) == 0); + tmp2 = get_path (TEST_WIRED_TLS_PRIVKEY, relative); + g_assert_cmpstr (tmp, ==, tmp2); + g_free (tmp2); g_free (tmp); g_key_file_free (keyfile); @@ -2334,12 +2613,18 @@ int main (int argc, char **argv) test_read_string_ssid (); test_write_string_ssid (); + test_read_intlist_ssid (); + test_write_intlist_ssid (); + test_read_bt_dun_connection (); test_write_bt_dun_connection (); test_read_gsm_connection (); test_write_gsm_connection (); + test_read_wired_8021x_tls_blob_connection (); + test_read_wired_8021x_tls_bad_path_connection (); + test_read_wired_8021x_tls_old_connection (); test_read_wired_8021x_tls_new_connection (); test_write_wired_8021x_tls_connection_path (); diff --git a/src/settings/plugins/keyfile/utils.c b/src/settings/plugins/keyfile/utils.c index 7b93a245..f3531172 100644 --- a/src/settings/plugins/keyfile/utils.c +++ b/src/settings/plugins/keyfile/utils.c @@ -74,6 +74,11 @@ check_suffix (const char *base, const char *tag) return FALSE; } +#define SWP_TAG ".swp" +#define SWPX_TAG ".swpx" +#define PEM_TAG ".pem" +#define DER_TAG ".der" + gboolean nm_keyfile_plugin_utils_should_ignore_file (const char *filename) { @@ -88,6 +93,8 @@ nm_keyfile_plugin_utils_should_ignore_file (const char *filename) /* Ignore files with certain patterns */ if ( (check_prefix (base, ".") && check_suffix (base, SWP_TAG)) /* vim temporary files: .filename.swp */ || (check_prefix (base, ".") && check_suffix (base, SWPX_TAG)) /* vim temporary files: .filename.swpx */ + || check_suffix (base, PEM_TAG) /* 802.1x certificates and keys */ + || check_suffix (base, DER_TAG) /* 802.1x certificates and keys */ || check_mkstemp_suffix (base) /* temporary files created by mkstemp() */ || base[strlen (base) - 1] == '~') ignore = TRUE; diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c index eeb14556..060093ce 100644 --- a/src/settings/plugins/keyfile/writer.c +++ b/src/settings/plugins/keyfile/writer.c @@ -668,6 +668,16 @@ cert_writer (GKeyFile *file, if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { path = objtype->path_func (NM_SETTING_802_1X (setting)); g_assert (path); + + /* If the path is rooted in the keyfile directory, just use a + * relative path instead of an absolute one. + */ + if (g_str_has_prefix (path, keyfile_dir)) { + path += strlen (keyfile_dir); + while (*path == '/') + path++; + } + g_key_file_set_string (file, setting_name, key, path); } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { const GByteArray *blob; |