NetworkManager/libnm-util/nm-connection.c
Dan Williams 937d1add73 2007-09-11 Dan Williams <dcbw@redhat.com>
* libnm-util/nm-setting.c
	  libnm-util/nm-setting.h
		- (nm_setting_update_secrets): new function; add a virtual function that
			subclasses can implement to update their secrets
		- (setting_wireless_security_update_secrets): implement that function
			for the 802-11-wireless-security subclass

	* libnm-util/nm-connection.c
	  libnm-util/nm-connection.h
		- (nm_connection_update_secrets): update secrets for a Setting and
			emit a signal on success

	* src/nm-manager.c
	  src/nm-manager.h
	  src/nm-marshal.list
		- (connection_get_settings_cb): enable system settings bits
		- (nm_manager_get_connection_secrets, get_secrets_cb): add function
			to request secrets from the settings dbus service and to
			push those secrets to the NMConnection itself

	* src/nm-activation-request.c
	  src/nm-activation-request.h
		- Attach to the 'secrets-updated' signal of the NMConnection that's
			currently being activated, and proxy that signal to other listeners.
			Goes through the activation request because the activation request
			is the thing that manages the lifetime of the NMConnection that's
			being activated.

	* src/nm-device-802-11-wireless.c
		- (real_connection_secrets_updated): implement the connection secrets
			updated notification and restart activation when secrets are
			received
		- (real_act_stage2_config): request secrets from the settings dbus
			service if secrets are needed

	* src/nm-device.c
	  src/nm-device.h
		- (clear_act_request, nm_device_activation_cancel,
		   nm_device_deactivate_quickly, nm_device_dispose): consolidate places
			where the activation request is cleared
		- (nm_device_activate, connection_secrets_updated_cb): attach to the
			updated secrets signal of activation request and add a function
			that subclasses can override to handle it easily



git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2782 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-09-11 18:02:27 +00:00

484 lines
12 KiB
C

#include <glib-object.h>
#include <dbus/dbus-glib.h>
#include <string.h>
#include "nm-connection.h"
typedef struct {
GHashTable *settings;
} NMConnectionPrivate;
#define NM_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CONNECTION, NMConnectionPrivate))
G_DEFINE_TYPE (NMConnection, nm_connection, G_TYPE_OBJECT)
enum {
SECRETS_UPDATED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static GHashTable *registered_setting_creators = NULL;
static void
register_default_creators (void)
{
int i;
const struct {
const char *name;
NMSettingCreateFn fn;
} default_map[] = {
{ "connection", nm_setting_connection_new_from_hash },
{ "802-3-ethernet", nm_setting_wired_new_from_hash },
{ "802-11-wireless", nm_setting_wireless_new_from_hash },
{ "ipv4", nm_setting_ip4_config_new_from_hash },
{ "802-11-wireless-security", nm_setting_wireless_security_new_from_hash },
{ "ppp", nm_setting_ppp_new_from_hash },
{ NULL, NULL}
};
for (i = 0; default_map[i].name; i++)
nm_setting_parser_register (default_map[i].name, default_map[i].fn);
}
void
nm_setting_parser_register (const char *name, NMSettingCreateFn creator)
{
g_return_if_fail (name != NULL);
g_return_if_fail (creator != NULL);
if (!registered_setting_creators)
registered_setting_creators = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free, NULL);
if (g_hash_table_lookup (registered_setting_creators, name))
g_warning ("Already have a creator function for '%s', overriding", name);
g_hash_table_insert (registered_setting_creators, g_strdup (name), creator);
}
void
nm_setting_parser_unregister (const char *name)
{
if (registered_setting_creators)
g_hash_table_remove (registered_setting_creators, name);
}
static void
parse_one_setting (gpointer key, gpointer value, gpointer user_data)
{
NMConnection *connection = (NMConnection *) user_data;
NMSettingCreateFn fn;
NMSetting *setting;
fn = (NMSettingCreateFn) g_hash_table_lookup (registered_setting_creators, key);
if (fn) {
setting = fn ((GHashTable *) value);
if (setting)
nm_connection_add_setting (connection, setting);
} else
g_warning ("Unknown setting '%s'", (char *) key);
}
void
nm_connection_add_setting (NMConnection *connection, NMSetting *setting)
{
NMConnectionPrivate *priv;
g_return_if_fail (NM_IS_CONNECTION (connection));
g_return_if_fail (setting != NULL);
priv = NM_CONNECTION_GET_PRIVATE (connection);
g_hash_table_insert (priv->settings, setting->name, setting);
}
NMSetting *
nm_connection_get_setting (NMConnection *connection, const char *setting_name)
{
NMConnectionPrivate *priv;
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (setting_name != NULL, NULL);
priv = NM_CONNECTION_GET_PRIVATE (connection);
return (NMSetting *) g_hash_table_lookup (priv->settings, setting_name);
}
gboolean
nm_connection_compare (NMConnection *connection, NMConnection *other)
{
if (!connection && !other)
return TRUE;
if (!connection || !other)
return FALSE;
/* FIXME: Implement */
return FALSE;
}
static GPtrArray *
wireless_sec_need_secrets (NMSettingWirelessSecurity *sec)
{
GPtrArray * secrets;
secrets = g_ptr_array_sized_new (4);
if (!secrets) {
g_warning ("Not enough memory to create required secrets array.");
return NULL;
}
/* Static WEP */
if (strcmp (sec->key_mgmt, "none") == 0) {
if (!sec->wep_key0) {
g_ptr_array_add (secrets, "wep_key0");
return secrets;
}
if (sec->wep_tx_keyidx == 1 && !sec->wep_key1) {
g_ptr_array_add (secrets, "wep_key1");
return secrets;
}
if (sec->wep_tx_keyidx == 2 && !sec->wep_key2) {
g_ptr_array_add (secrets, "wep_key2");
return secrets;
}
if (sec->wep_tx_keyidx == 3 && !sec->wep_key3) {
g_ptr_array_add (secrets, "wep_key3");
return secrets;
}
goto no_secrets;
}
if ( (strcmp (sec->key_mgmt, "wpa-none") == 0)
|| (strcmp (sec->key_mgmt, "wpa-psk") == 0)) {
if (!sec->psk) {
g_ptr_array_add (secrets, "psk");
return secrets;
}
goto no_secrets;
}
if (strcmp (sec->key_mgmt, "wpa-eap") == 0) {
// FIXME: implement
goto no_secrets;
}
no_secrets:
if (secrets)
g_ptr_array_free (secrets, TRUE);
return NULL;
}
void
nm_connection_update_secrets (NMConnection *connection,
const char *setting_name,
GHashTable *secrets)
{
NMSetting *setting;
g_return_if_fail (NM_IS_CONNECTION (connection));
g_return_if_fail (setting_name != NULL);
g_return_if_fail (secrets != NULL);
setting = nm_connection_get_setting (connection, setting_name);
if (!setting) {
g_warning ("Unhandled settings object for secrets update.");
return;
}
if (!nm_setting_update_secrets (setting, secrets)) {
g_warning ("Error updating secrets for setting '%s'", setting_name);
return;
}
g_signal_emit (connection, signals[SECRETS_UPDATED], 0, setting_name);
}
const char *
nm_connection_need_secrets (NMConnection *connection)
{
NMSettingConnection *s_connection;
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
s_connection = (NMSettingConnection *) nm_connection_get_setting (connection, "connection");
if (!s_connection)
return NULL;
/* Wireless */
if (strcmp (s_connection->devtype, "802-11-wireless") == 0) {
NMSettingWireless *s_wireless;
NMSettingWirelessSecurity *s_wireless_sec;
GPtrArray * secrets = NULL;
s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, "802-11-wireless");
if (!s_wireless || !s_wireless->security)
return NULL;
s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, "802-11-wireless-security");
if (!s_wireless_sec)
return NULL;
secrets = wireless_sec_need_secrets (s_wireless_sec);
if (secrets) {
// FIXME: modify NeedSecrets message to include the actual secrets
// required rather than just requesting all secrets for the setting
g_ptr_array_free (secrets, TRUE);
return "802-11-wireless-security";
}
}
return NULL;
}
static void
add_one_setting_to_hash (gpointer key, gpointer data, gpointer user_data)
{
NMSetting *setting = (NMSetting *) data;
GHashTable *connection_hash = (GHashTable *) user_data;
GHashTable *setting_hash;
setting_hash = nm_setting_to_hash (setting);
if (setting_hash)
g_hash_table_insert (connection_hash,
g_strdup (setting->name),
setting_hash);
}
GHashTable *
nm_connection_to_hash (NMConnection *connection)
{
NMConnectionPrivate *priv;
GHashTable *connection_hash;
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
connection_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_hash_table_destroy);
priv = NM_CONNECTION_GET_PRIVATE (connection);
g_hash_table_foreach (priv->settings, add_one_setting_to_hash, connection_hash);
/* Don't send empty hashes */
if (g_hash_table_size (connection_hash) < 1) {
g_hash_table_destroy (connection_hash);
connection_hash = NULL;
}
return connection_hash;
}
static char *
garray_to_string (GArray *array)
{
GString *str;
int i;
char c;
g_return_val_if_fail (array != NULL, NULL);
str = g_string_sized_new (array->len);
for (i = 0; i < array->len; i++) {
c = array->data[i];
/* Convert NULLs to spaces to increase the readability. */
if (c == '\0')
c = ' ';
str = g_string_append_c (str, c);
}
str = g_string_append_c (str, '\0');
return g_string_free (str, FALSE);
}
static char *
gvalue_to_string (GValue *val)
{
char *ret;
GType type;
GString *str;
gboolean need_comma = FALSE;
type = G_VALUE_TYPE (val);
switch (type) {
case G_TYPE_STRING:
ret = g_strdup (g_value_get_string (val));
break;
case G_TYPE_INT:
ret = g_strdup_printf ("%d", g_value_get_int (val));
break;
case G_TYPE_UINT:
ret = g_strdup_printf ("%u", g_value_get_uint (val));
break;
case G_TYPE_BOOLEAN:
ret = g_strdup_printf ("%s", g_value_get_boolean (val) ? "True" : "False");
break;
case G_TYPE_UCHAR:
ret = g_strdup_printf ("%d", g_value_get_uchar (val));
break;
default:
/* These return dynamic values and thus can't be 'case's */
if (type == DBUS_TYPE_G_UCHAR_ARRAY)
ret = garray_to_string ((GArray *) g_value_get_boxed (val));
else if (type == dbus_g_type_get_collection ("GSList", G_TYPE_STRING)) {
GSList *iter;
str = g_string_new ("[");
for (iter = g_value_get_boxed (val); iter; iter = iter->next) {
if (need_comma)
g_string_append (str, ", ");
else
need_comma = TRUE;
g_string_append (str, (char *) iter->data);
}
g_string_append (str, "]");
ret = g_string_free (str, FALSE);
} else if (type == dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_UCHAR_ARRAY)) {
/* Array of arrays of chars, like wireless seen-bssids for example */
int i;
GPtrArray *ptr_array;
str = g_string_new ("[");
ptr_array = (GPtrArray *) g_value_get_boxed (val);
for (i = 0; i < ptr_array->len; i++) {
ret = garray_to_string ((GArray *) g_ptr_array_index (ptr_array, i));
if (need_comma)
g_string_append (str, ", ");
else
need_comma = TRUE;
g_string_append (str, ret);
g_free (ret);
}
g_string_append (str, "]");
ret = g_string_free (str, FALSE);
} else
ret = g_strdup_printf ("Value with type %s", g_type_name (type));
}
return ret;
}
static void
dump_setting_member (gpointer key, gpointer value, gpointer user_data)
{
char *val_as_str;
val_as_str = gvalue_to_string ((GValue *) value);
g_message ("\t%s : '%s'", (char *) key, val_as_str ? val_as_str : "(null)");
g_free (val_as_str);
}
static void
dump_setting (gpointer key, gpointer value, gpointer user_data)
{
g_message ("Setting '%s'", (char *) key);
g_hash_table_foreach ((GHashTable *) value, dump_setting_member, NULL);
g_message ("-------------------");
}
void
nm_connection_dump (NMConnection *connection)
{
GHashTable *hash;
g_return_if_fail (NM_IS_CONNECTION (connection));
/* Convert the connection to hash so that we can introspect it */
hash = nm_connection_to_hash (connection);
g_hash_table_foreach (hash, dump_setting, NULL);
g_hash_table_destroy (hash);
}
NMConnection *
nm_connection_new (void)
{
GObject *object;
if (!registered_setting_creators)
register_default_creators ();
object = g_object_new (NM_TYPE_CONNECTION, NULL);
return NM_CONNECTION (object);
}
NMConnection *
nm_connection_new_from_hash (GHashTable *hash)
{
NMConnection *connection;
NMConnectionPrivate *priv;
g_return_val_if_fail (hash != NULL, NULL);
connection = nm_connection_new ();
g_hash_table_foreach (hash, parse_one_setting, connection);
nm_connection_dump (connection);
priv = NM_CONNECTION_GET_PRIVATE (connection);
if (g_hash_table_size (priv->settings) < 1) {
g_warning ("No settings found.");
g_object_unref (connection);
return NULL;
}
if (!nm_settings_verify (priv->settings)) {
g_object_unref (connection);
return NULL;
}
return connection;
}
static void
nm_connection_init (NMConnection *connection)
{
NMConnectionPrivate *priv = NM_CONNECTION_GET_PRIVATE (connection);
priv->settings = g_hash_table_new (g_str_hash, g_str_equal);
}
static void
finalize (GObject *object)
{
NMConnection *connection = NM_CONNECTION (object);
NMConnectionPrivate *priv = NM_CONNECTION_GET_PRIVATE (connection);
g_hash_table_destroy (priv->settings);
priv->settings = NULL;
G_OBJECT_CLASS (nm_connection_parent_class)->finalize (object);
}
static void
nm_connection_class_init (NMConnectionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (NMConnectionPrivate));
/* virtual methods */
object_class->finalize = finalize;
/* Signals */
signals[SECRETS_UPDATED] =
g_signal_new ("secrets-updated",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMConnectionClass, secrets_updated),
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
}