From 8928b8dbe7b7b5c609ad65df3852d977f9286be8 Mon Sep 17 00:00:00 2001 From: Tambet Ingo Date: Thu, 8 May 2008 07:20:02 +0000 Subject: [PATCH] 2008-05-08 Tambet Ingo Rewrite the suse system settings plugin. * system-settings/plugins/ifcfg-suse/plugin.c: Rewrite. * system-settings/plugins/ifcfg-suse/parser.c: Rewrite. * system-settings/plugins/ifcfg-suse/nm-suse-connection.[ch]: Implement. * system-settings/plugins/ifcfg-suse/Makefile.am: Add new files to build. * system-settings/src/dbus-settings.c: Fix connection reference counting. * system-settings/src/main.c (load_plugins): Improve error reporting. * system-settings/src/sha1.[ch] Add. * system-settings/src/Makefile.am: Add sha1[ch] to build. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3644 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 20 + .../plugins/ifcfg-suse/Makefile.am | 4 +- .../plugins/ifcfg-suse/nm-suse-connection.c | 144 ++++ .../plugins/ifcfg-suse/nm-suse-connection.h | 33 + system-settings/plugins/ifcfg-suse/parser.c | 732 ++++++++---------- system-settings/plugins/ifcfg-suse/parser.h | 6 +- system-settings/plugins/ifcfg-suse/plugin.c | 437 +++++------ system-settings/src/Makefile.am | 4 +- system-settings/src/dbus-settings.c | 8 +- system-settings/src/main.c | 4 +- system-settings/src/sha1.c | 692 +++++++++++++++++ system-settings/src/sha1.h | 34 + 12 files changed, 1468 insertions(+), 650 deletions(-) create mode 100644 system-settings/plugins/ifcfg-suse/nm-suse-connection.c create mode 100644 system-settings/plugins/ifcfg-suse/nm-suse-connection.h create mode 100644 system-settings/src/sha1.c create mode 100644 system-settings/src/sha1.h diff --git a/ChangeLog b/ChangeLog index 21da44ff23..4836c33568 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2008-05-08 Tambet Ingo + + Rewrite the suse system settings plugin. + + * system-settings/plugins/ifcfg-suse/plugin.c: Rewrite. + + * system-settings/plugins/ifcfg-suse/parser.c: Rewrite. + + * system-settings/plugins/ifcfg-suse/nm-suse-connection.[ch]: Implement. + + * system-settings/plugins/ifcfg-suse/Makefile.am: Add new files to build. + + * system-settings/src/dbus-settings.c: Fix connection reference counting. + + * system-settings/src/main.c (load_plugins): Improve error reporting. + + * system-settings/src/sha1.[ch] Add. + + * system-settings/src/Makefile.am: Add sha1[ch] to build. + 2008-05-07 Dan Williams * system-settings/plugins/keyfile/reader.c diff --git a/system-settings/plugins/ifcfg-suse/Makefile.am b/system-settings/plugins/ifcfg-suse/Makefile.am index 74f2f0285d..067cf72ea1 100644 --- a/system-settings/plugins/ifcfg-suse/Makefile.am +++ b/system-settings/plugins/ifcfg-suse/Makefile.am @@ -2,6 +2,8 @@ pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-suse.la libnm_settings_plugin_ifcfg_suse_la_SOURCES = \ + nm-suse-connection.c \ + nm-suse-connection.h \ shvar.c \ shvar.h \ parser.c \ @@ -17,7 +19,7 @@ libnm_settings_plugin_ifcfg_suse_la_CPPFLAGS = \ -I${top_srcdir}/system-settings/src \ -I$(top_srcdir)/include \ -I$(top_srcdir)/libnm-util \ - -I${top_srcdir}/libnm-glib \ + -I$(top_srcdir)/libnm-glib \ -DSYSCONFDIR=\"$(sysconfdir)\" libnm_settings_plugin_ifcfg_suse_la_LDFLAGS = -module -avoid-version diff --git a/system-settings/plugins/ifcfg-suse/nm-suse-connection.c b/system-settings/plugins/ifcfg-suse/nm-suse-connection.c new file mode 100644 index 0000000000..2f31e6e3bb --- /dev/null +++ b/system-settings/plugins/ifcfg-suse/nm-suse-connection.c @@ -0,0 +1,144 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#include +#include +#include +#include +#include "nm-suse-connection.h" +#include "parser.h" + +G_DEFINE_TYPE (NMSuseConnection, nm_suse_connection, NM_TYPE_EXPORTED_CONNECTION) + +#define NM_SUSE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SUSE_CONNECTION, NMSuseConnectionPrivate)) + +typedef struct { + GFileMonitor *monitor; + guint monitor_id; + + const char *iface; + NMDeviceType dev_type; + char *filename; +} NMSuseConnectionPrivate; + +static void +file_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + NMExportedConnection *exported = NM_EXPORTED_CONNECTION (user_data); + NMSuseConnectionPrivate *priv = NM_SUSE_CONNECTION_GET_PRIVATE (exported); + NMConnection *new_connection; + GHashTable *new_settings; + + switch (event_type) { + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + new_connection = parse_ifcfg (priv->iface, priv->dev_type); + if (new_connection) { + new_settings = nm_connection_to_hash (new_connection); + nm_exported_connection_update (exported, new_settings); + g_hash_table_destroy (new_settings); + g_object_unref (new_connection); + } else + nm_exported_connection_delete (exported); + break; + case G_FILE_MONITOR_EVENT_DELETED: + nm_exported_connection_delete (exported); + break; + default: + break; + } +} + +NMSuseConnection * +nm_suse_connection_new (const char *iface, NMDeviceType dev_type) +{ + NMConnection *connection; + GFile *file; + GFileMonitor *monitor; + NMSuseConnection *exported; + NMSuseConnectionPrivate *priv; + + g_return_val_if_fail (iface != NULL, NULL); + + connection = parse_ifcfg (iface, dev_type); + if (!connection) + return NULL; + + exported = (NMSuseConnection *) g_object_new (NM_TYPE_SUSE_CONNECTION, + NM_EXPORTED_CONNECTION_CONNECTION, connection, + NULL); + g_object_unref (connection); + if (!exported) + return NULL; + + priv = NM_SUSE_CONNECTION_GET_PRIVATE (exported); + + priv->iface = g_strdup (iface); + priv->dev_type = dev_type; + priv->filename = g_strdup_printf (SYSCONFDIR "/sysconfig/network/ifcfg-%s", iface); + + file = g_file_new_for_path (priv->filename); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + + if (monitor) { + priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), exported); + priv->monitor = monitor; + } + + return exported; +} + +static GHashTable * +get_settings (NMExportedConnection *exported) +{ + return nm_connection_to_hash (nm_exported_connection_get_connection (exported)); +} + +static const char * +get_id (NMExportedConnection *exported) +{ + return NM_SUSE_CONNECTION_GET_PRIVATE (exported)->filename; +} + +/* GObject */ + +static void +nm_suse_connection_init (NMSuseConnection *connection) +{ +} + +static void +finalize (GObject *object) +{ + NMSuseConnectionPrivate *priv = NM_SUSE_CONNECTION_GET_PRIVATE (object); + + if (priv->monitor) { + if (priv->monitor_id) + g_signal_handler_disconnect (priv->monitor, priv->monitor_id); + + g_file_monitor_cancel (priv->monitor); + g_object_unref (priv->monitor); + } + + g_free (priv->filename); + + G_OBJECT_CLASS (nm_suse_connection_parent_class)->finalize (object); +} + +static void +nm_suse_connection_class_init (NMSuseConnectionClass *suse_connection_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (suse_connection_class); + NMExportedConnectionClass *connection_class = NM_EXPORTED_CONNECTION_CLASS (suse_connection_class); + + g_type_class_add_private (suse_connection_class, sizeof (NMSuseConnectionPrivate)); + + /* Virtual methods */ + object_class->finalize = finalize; + + connection_class->get_settings = get_settings; + connection_class->get_id = get_id; +} diff --git a/system-settings/plugins/ifcfg-suse/nm-suse-connection.h b/system-settings/plugins/ifcfg-suse/nm-suse-connection.h new file mode 100644 index 0000000000..571ead62ba --- /dev/null +++ b/system-settings/plugins/ifcfg-suse/nm-suse-connection.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#ifndef NM_SUSE_CONNECTION_H +#define NM_SUSE_CONNECTION_H + +#include +#include + +G_BEGIN_DECLS + +#define NM_TYPE_SUSE_CONNECTION (nm_suse_connection_get_type ()) +#define NM_SUSE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUSE_CONNECTION, NMSuseConnection)) +#define NM_SUSE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SUSE_CONNECTION, NMSuseConnectionClass)) +#define NM_IS_SUSE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SUSE_CONNECTION)) +#define NM_IS_SUSE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SUSE_CONNECTION)) +#define NM_SUSE_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUSE_CONNECTION, NMSuseConnectionClass)) + +typedef struct { + NMExportedConnection parent; +} NMSuseConnection; + +typedef struct { + NMExportedConnectionClass parent; +} NMSuseConnectionClass; + +GType nm_suse_connection_get_type (void); + +NMSuseConnection *nm_suse_connection_new (const char *iface, + NMDeviceType dev_type); + +G_END_DECLS + +#endif /* NM_SUSE_CONNECTION_H */ diff --git a/system-settings/plugins/ifcfg-suse/parser.c b/system-settings/plugins/ifcfg-suse/parser.c index 5ef4ee2cad..0b0aef8183 100644 --- a/system-settings/plugins/ifcfg-suse/parser.c +++ b/system-settings/plugins/ifcfg-suse/parser.c @@ -38,12 +38,17 @@ #include #include #include +#include #include #include "shvar.h" #include "parser.h" #include "plugin.h" +#include "sha1.h" +#define WPA_PMK_LEN 32 + +/* Common */ static gboolean get_int (const char *str, int *value) @@ -57,81 +62,37 @@ get_int (const char *str, int *value) return TRUE; } -#if 0 -static gboolean -read_startmode (shvarFile *file) -{ - char *value; - gboolean automatic = TRUE; - - value = svGetValue (file, "STARTMODE"); - if (value) { - if (!g_ascii_strcasecmp (value, "manual")) - automatic = FALSE; - else if (!g_ascii_strcasecmp (value, "off")) { - // FIXME: actually ignore the device, not the connection - g_message ("Ignoring connection '%s' because NM_CONTROLLED was false", file); - automatic = FALSE; - } - - g_free (value); - } - - return automatic; -} -#endif - static NMSetting * -make_connection_setting (const char *file, - shvarFile *ifcfg, +make_connection_setting (shvarFile *file, + const char *iface, const char *type, const char *suggested) { NMSettingConnection *s_con; - char *basename = NULL; - int len; - char *ifcfg_name; - - basename = g_path_get_basename (file); - if (!basename) - goto error; - len = strlen (basename); - - if (len < strlen (IFCFG_TAG) + 1) - goto error; - - if (strncmp (basename, IFCFG_TAG, strlen (IFCFG_TAG))) - goto error; - - /* ignore .bak files */ - if ((len > 4) && !strcmp (basename + len - 4, BAK_TAG)) - goto error; + char *str; s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); - - ifcfg_name = (char *) (basename + strlen (IFCFG_TAG)); - if (suggested) { /* For cosmetic reasons, if the suggested name is the same as * the ifcfg files name, don't use it. */ - if (strcmp (ifcfg_name, suggested)) { - s_con->id = g_strdup_printf ("System %s (%s)", suggested, ifcfg_name); - ifcfg_name = NULL; - } + if (strcmp (iface, suggested)) + s_con->id = g_strdup_printf ("System %s (%s)", suggested, iface); } - if (ifcfg_name) - s_con->id = g_strdup_printf ("System %s", ifcfg_name); + if (!s_con->id) + s_con->id = g_strdup_printf ("System %s", iface); s_con->type = g_strdup (type); - s_con->autoconnect = TRUE; + + str = svGetValue (file, "STARTMODE"); + if (str && !g_ascii_strcasecmp (str, "manual")) + s_con->autoconnect = FALSE; + else + s_con->autoconnect = TRUE; + g_free (str); return (NMSetting *) s_con; - -error: - g_free (basename); - return NULL; } static guint32 @@ -150,70 +111,73 @@ ip4_prefix_to_netmask (int prefix) } static NMSetting * -make_ip4_setting (shvarFile *ifcfg, GError **error) +make_ip4_setting (shvarFile *ifcfg) { - NMSettingIP4Config *s_ip4 = NULL; - char *value = NULL; + NMSettingIP4Config *s_ip4; + char *str; NMSettingIP4Address tmp = { 0, 0, 0 }; - char *method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; - value = svGetValue (ifcfg, "BOOTPROTO"); - if (!value) - return NULL; + s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ()); - if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) { - method = NM_SETTING_IP4_CONFIG_METHOD_DHCP; - return NULL; + str = svGetValue (ifcfg, "BOOTPROTO"); + if (str) { + if (!g_ascii_strcasecmp (str, "bootp") || !g_ascii_strcasecmp (str, "dhcp")) + s_ip4->method = g_strdup (NM_SETTING_IP4_CONFIG_METHOD_DHCP); + else if (!g_ascii_strcasecmp (str, "static")) + s_ip4->method = g_strdup (NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + else if (!g_ascii_strcasecmp (str, "autoip")) + s_ip4->method = g_strdup (NM_SETTING_IP4_CONFIG_METHOD_AUTOIP); + + g_free (str); } - value = svGetValue (ifcfg, "IPADDR"); - if (value) { + if (!s_ip4->method) + s_ip4->method = g_strdup (NM_SETTING_IP4_CONFIG_METHOD_DHCP); + + str = svGetValue (ifcfg, "IPADDR"); + if (str) { char **pieces; struct in_addr ip4_addr; - pieces = g_strsplit (value, "/", 2); + pieces = g_strsplit (str, "/", 2); - if (inet_pton (AF_INET, pieces[0], &ip4_addr)) + if (inet_pton (AF_INET, pieces[0], &ip4_addr)) { tmp.address = ip4_addr.s_addr; - else { - g_strfreev (pieces); - g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid IP4 address '%s'", value); - goto error; - } - if (g_strv_length (pieces) == 2) - tmp.netmask = ip4_prefix_to_netmask (atoi (pieces[1])); + if (g_strv_length (pieces) == 2) + tmp.netmask = ip4_prefix_to_netmask (atoi (pieces[1])); + } else + g_warning ("Ignoring invalid IP4 address '%s'", str); g_strfreev (pieces); - g_free (value); + g_free (str); } - if (tmp.netmask == 0) { - value = svGetValue (ifcfg, "PREFIXLEN"); - if (value) { - tmp.netmask = ip4_prefix_to_netmask (atoi (value)); - g_free (value); + if (tmp.address && tmp.netmask == 0) { + str = svGetValue (ifcfg, "PREFIXLEN"); + if (str) { + tmp.netmask = ip4_prefix_to_netmask (atoi (str)); + g_free (str); } } - if (tmp.netmask == 0) { - value = svGetValue (ifcfg, "NETMASK"); - if (value) { + if (tmp.address && tmp.netmask == 0) { + str = svGetValue (ifcfg, "NETMASK"); + if (str) { struct in_addr mask_addr; - if (inet_pton (AF_INET, value, &mask_addr)) + if (inet_pton (AF_INET, str, &mask_addr)) tmp.netmask = mask_addr.s_addr; else { - g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid IP4 netmask '%s'", value); - goto error; + g_warning ("Ignoring invalid IP4 addres: invalid netmask: '%s'", str); + tmp.address = 0; + tmp.netmask = 0; } - g_free (value); + g_free (str); } } - s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); - s_ip4->method = g_strdup (method); - if (tmp.address || tmp.netmask || tmp.gateway) { + if (tmp.address || tmp.netmask) { NMSettingIP4Address *addr; addr = g_new0 (NMSettingIP4Address, 1); memcpy (addr, &tmp, sizeof (NMSettingIP4Address)); @@ -221,48 +185,51 @@ make_ip4_setting (shvarFile *ifcfg, GError **error) } return NM_SETTING (s_ip4); - -error: - g_free (value); - if (s_ip4) - g_object_unref (s_ip4); - return NULL; } -#if 0 -/* - * utils_bin2hexstr - * - * Convert a byte-array into a hexadecimal string. - * - * Code originally by Alex Larsson and - * copyright Red Hat, Inc. under terms of the LGPL. - * - */ -static char * -utils_bin2hexstr (const char *bytes, int len, int final_len) +/* Ethernet */ + +static NMSetting * +make_wired_setting (shvarFile *ifcfg) { - static char hex_digits[] = "0123456789abcdef"; - char * result; - int i; + NMSettingWired *s_wired; + char *str; + int mtu; - g_return_val_if_fail (bytes != NULL, NULL); - g_return_val_if_fail (len > 0, NULL); - g_return_val_if_fail (len < 256, NULL); /* Arbitrary limit */ + s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); - result = g_malloc0 (len * 2 + 1); - for (i = 0; i < len; i++) - { - result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf]; - result[2*i+1] = hex_digits[bytes[i] & 0xf]; + str = svGetValue (ifcfg, "MTU"); + if (str) { + if (strlen (str) < 1) + /* Ignore empty MTU */ + ; + else if (get_int (str, &mtu)) { + if (mtu >= 0 && mtu < G_MAXINT) + s_wired->mtu = mtu; + } else + g_warning ("Ignoring invalid MTU: '%s'", str); + g_free (str); } - /* Cut converted key off at the correct length for this cipher type */ - if (final_len > -1) - result[final_len] = '\0'; - return result; + return (NMSetting *) s_wired; } -#endif + +static void +parse_ethernet (NMConnection *connection, shvarFile *file, const char *iface) +{ + NMSetting *setting; + + setting = make_connection_setting (file, iface, NM_SETTING_WIRED_SETTING_NAME, NULL); + nm_connection_add_setting (connection, setting); + + setting = make_wired_setting (file); + nm_connection_add_setting (connection, setting); + + setting = make_ip4_setting (file); + nm_connection_add_setting (connection, setting); +} + +/* Wireless */ static char * get_one_wep_key (shvarFile *ifcfg, guint8 idx, GError **err) @@ -342,23 +309,23 @@ get_one_wep_key (shvarFile *ifcfg, guint8 idx, GError **err) #define READ_WEP_KEY(idx) \ { \ - char *key = get_one_wep_key (ifcfg, idx, err); \ - if (*err) \ + char *key = get_one_wep_key (ifcfg, idx, &err); \ + if (err) \ goto error; \ if (key) { \ - g_object_set_data_full (G_OBJECT (security), \ - NM_SETTING_WIRELESS_SECURITY_WEP_KEY##idx, \ - key, \ - g_free); \ + g_object_set (G_OBJECT (security), \ + NM_SETTING_WIRELESS_SECURITY_WEP_KEY##idx, \ + key, \ + NULL); \ have_key = TRUE; \ } \ } - static void -read_wep_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security, GError **err) +read_wep_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security) { char *value; + GError *err = NULL; gboolean have_key = FALSE; READ_WEP_KEY(0) @@ -378,13 +345,16 @@ read_wep_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security, GError if (success && (key_idx >= 0) && (key_idx <= 3)) security->wep_tx_keyidx = key_idx; else - g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid defualt WEP key '%s'", value); + g_warning ("Invalid default WEP key: '%s'", value); g_free (value); } error: - return; + if (err) { + g_warning ("%s", err->message); + g_error_free (err); + } } /* Copied from applet/src/wireless-secuirty/wireless-security.c */ @@ -406,384 +376,320 @@ ws_wpa_fill_default_ciphers (NMSettingWirelessSecurity *s_wireless_sec) s_wireless_sec->group = g_slist_append (s_wireless_sec->group, g_strdup ("ccmp")); } +/* + * utils_bin2hexstr + * + * Convert a byte-array into a hexadecimal string. + * + * Code originally by Alex Larsson and + * copyright Red Hat, Inc. under terms of the LGPL. + * + */ +static char * +utils_bin2hexstr (const char *bytes, int len, int final_len) +{ + static char hex_digits[] = "0123456789abcdef"; + char * result; + int i; + + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (len > 0, NULL); + g_return_val_if_fail (len < 256, NULL); /* Arbitrary limit */ + + result = g_malloc0 (len * 2 + 1); + for (i = 0; i < len; i++) + { + result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf]; + result[2*i+1] = hex_digits[bytes[i] & 0xf]; + } + /* Cut converted key off at the correct length for this cipher type */ + if (final_len > -1) + result[final_len] = '\0'; + + return result; +} + static void -read_wpa_psk_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security, GError **err) +read_wpa_psk_settings (shvarFile *ifcfg, + NMSettingWirelessSecurity *security, + NMSettingWireless *s_wireless) { char *value; value = svGetValue (ifcfg, "WIRELESS_WPA_PSK"); if (value) { if (strlen (value) == 64) { - /* HEX key */ - security->psk = value; + /* Hex PSK */ + security->psk = g_strdup (value); } else { /* passphrase */ - - /* FIXME: */ -/* unsigned char *buf = g_malloc0 (WPA_PMK_LEN * 2); */ -/* pbkdf2_sha1 (value, (char *) s_wireless->ssid->data, s_wireless->ssid->len, 4096, buf, WPA_PMK_LEN); */ -/* security->psk = utils_bin2hexstr ((const char *) buf, WPA_PMK_LEN, WPA_PMK_LEN * 2); */ -/* g_free (buf); */ - g_free (value); + unsigned char *buf = g_malloc0 (WPA_PMK_LEN * 2); + pbkdf2_sha1 (value, (char *) s_wireless->ssid->data, s_wireless->ssid->len, 4096, buf, WPA_PMK_LEN); + security->psk = utils_bin2hexstr ((const char *) buf, WPA_PMK_LEN, WPA_PMK_LEN * 2); + g_free (buf); } + g_free (value); + ws_wpa_fill_default_ciphers (security); } else - g_set_error (err, ifcfg_plugin_error_quark (), 0, "Missing WPA-PSK key."); + g_warning ("Missing WPA-PSK key"); } #if 0 + static void -read_wpa_eap_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security, GError **err) +read_wpa_eap_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security) { - char *value; + char *str; - value = svGetValue (ifcfg, "WIRELESS_EAP_AUTH"); - if (value) { - /* valid values are TLS PEAP TTLS */ - security->eap = g_slist_append (NULL, value); + str = svGetValue (ifcfg, "WIRELESS_EAP_MODE"); + if (str) { + char **pieces; + int i; + + pieces = g_strsplit (str, " ", 0); + for (i = 0; pieces[i]; i++) + s_8021x->eap = g_slist_append (s_8021x->eap, pieces[i]); + + g_free (pieces); + g_free (str); } - value = svGetValue (ifcfg, "WIRELESS_WPA_PROTO"); - if (value) { - /* valid values are WPA RSN (WPA2) */ - security->proto = g_slist_append (NULL, value); - } + s_802_1x->anonymous_identity = svGetValue (ifcfg, "WIRELESS_WPA_ANONID"); - security->identity = svGetValue (ifcfg, "WIRELESS_WPA_IDENTITY"); + char *ca_path; - /* FIXME: This should be in get_secrets? */ - value = svGetValue (ifcfg, "WIRELESS_WPA_PASSWORD"); - if (value) { - g_free (value); - } + GByteArray *ca_cert; + "WIRELESS_CA_CERT"; - security->anonymous_identity = svGetValue (ifcfg, "WIRELESS_WPA_ANONID"); + GByteArray *client_cert; + "WIRELESS_CLIENT_CERT"; - value = svGetValue (ifcfg, "WIRELESS_CA_CERT"); - if (value) { - g_free (value); - } + GByteArray *private_key; + "WIRELESS_CLIENT_KEY"; - value = svGetValue (ifcfg, "WIRELESS_CLIENT_CERT"); - if (value) { - g_free (value); - } + private_key_passwd + "WIRELESS_CLIENT_KEY_PASSWORD"; - /* FIXME: This should be in get_secrets? */ - value = svGetValue (ifcfg, "WIRELESS_CLIENT_KEY"); - if (value) { - g_free (value); - } - /* FIXME: This should be in get_secrets? */ - value = svGetValue (ifcfg, "WIRELESS_CLIENT_KEY_PASSWORD"); - if (value) { - g_free (value); - } - - ws_wpa_fill_default_ciphers (security); + s_802_1x->phase1_peapver = svGetValue (ifcfg, "WIRELESS_PEAP_VERSION"); + s_802_1x->phase2_auth = svGetValue (ifcfg, "WIRELESS_EAP_AUTH"); + s_802_1x->identity = svGetValue (ifcfg, "WIRELESS_WPA_IDENTITY"); + s_802_1x->password = svGetValue (ifcfg, "WIRELESS_WPA_PASSWORD"); } #endif static NMSetting * -make_wireless_security_setting (shvarFile *ifcfg, GError **err) +make_wireless_security_setting (shvarFile *ifcfg, NMSettingWireless *s_wireless) { - NMSettingWirelessSecurity *s_wireless_sec = NULL; - char *value; + NMSettingWirelessSecurity *security; + char *str; - value = svGetValue (ifcfg, "WIRELESS_AUTH_MODE"); - if (!value) - return NULL; - - if (!g_ascii_strcasecmp (value, "no-encryption")) { - g_free (value); + str = svGetValue (ifcfg, "WIRELESS_AUTH_MODE"); + if (!str || !g_ascii_strcasecmp (str, "no-encryption")) { + g_free (str); return NULL; } - s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); + security = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); - if (!g_ascii_strcasecmp (value, "open")) { - s_wireless_sec->auth_alg = g_strdup ("open"); - read_wep_settings (ifcfg, s_wireless_sec, err); - } else if (!g_ascii_strcasecmp (value, "sharedkey")) { - s_wireless_sec->auth_alg = g_strdup ("shared"); - read_wep_settings (ifcfg, s_wireless_sec, err); + if (!g_ascii_strcasecmp (str, "open")) { + security->auth_alg = g_strdup ("open"); + read_wep_settings (ifcfg, security); + } else if (!g_ascii_strcasecmp (str, "sharedkey")) { + security->auth_alg = g_strdup ("shared"); + read_wep_settings (ifcfg, security); } - else if (!g_ascii_strcasecmp (value, "psk")) { - s_wireless_sec->key_mgmt = g_strdup ("wpa-psk"); - read_wpa_psk_settings (ifcfg, s_wireless_sec, err); - } else if (!g_ascii_strcasecmp (value, "eap")) { - s_wireless_sec->key_mgmt = g_strdup ("wps-eap"); - /* read_wpa_eap_settings (ifcfg, s_wireless_sec, err); */ + else if (!g_ascii_strcasecmp (str, "psk")) { + security->key_mgmt = g_strdup ("wpa-psk"); + read_wpa_psk_settings (ifcfg, security, s_wireless); + } else if (!g_ascii_strcasecmp (str, "eap")) { + /* FIXME */ +/* security->key_mgmt = g_strdup ("wps-eap"); */ +/* read_wpa_eap_settings (ifcfg, security); */ + g_warning ("WPA-EAP is currently not supported."); + g_object_unref (security); + security = NULL; } else - g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid authentication algoritm '%s'", value); + g_warning ("Invalid authentication algorithm: '%s'", str); - g_free (value); + g_free (str); - if (*err == NULL) - return NM_SETTING (s_wireless_sec); - - if (s_wireless_sec) - g_object_unref (s_wireless_sec); - return NULL; + return (NMSetting *) security; } static NMSetting * -make_wireless_setting (shvarFile *ifcfg, - NMSetting *security, - GError **err) +make_wireless_setting (shvarFile *ifcfg) { NMSettingWireless *s_wireless; - char *value; + char *str; s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); - value = svGetValue (ifcfg, "WIRELESS_ESSID"); - if (value) { - gsize len = strlen (value); + str = svGetValue (ifcfg, "WIRELESS_ESSID"); + if (str) { + gsize len = strlen (str); - if (len > 32 || len == 0) { - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)", - value, len); - goto error; - } + if (len > 0 && len <= 32) { + s_wireless->ssid = g_byte_array_sized_new (len); + g_byte_array_append (s_wireless->ssid, (const guint8 *) str, len); + } else + g_warning ("Ignoring invalid ESSID '%s', (size %zu not between 1 and 32 inclusive)", str, len); - s_wireless->ssid = g_byte_array_sized_new (strlen (value)); - g_byte_array_append (s_wireless->ssid, (const guint8 *) value, len); - g_free (value); + g_free (str); } - value = svGetValue (ifcfg, "WIRLESS_MODE"); - if (value) { - if (!g_ascii_strcasecmp (value, "ad-hoc")) { + str = svGetValue (ifcfg, "WIRLESS_MODE"); + if (str) { + if (!g_ascii_strcasecmp (str, "ad-hoc")) s_wireless->mode = g_strdup ("adhoc"); - } else if (!g_ascii_strcasecmp (value, "managed")) { + else if (!g_ascii_strcasecmp (str, "managed")) s_wireless->mode = g_strdup ("infrastructure"); - } else { - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Invalid mode '%s' (not ad-hoc or managed)", value); - g_free (value); - goto error; - } - g_free (value); - } - if (security) - s_wireless->security = g_strdup (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); + g_free (str); + } // FIXME: channel/freq, other L2 parameters like RTS return NM_SETTING (s_wireless); - -error: - if (s_wireless) - g_object_unref (s_wireless); - return NULL; } -static NMConnection * -wireless_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **err) +static char * +get_printable_ssid (NMSetting *setting) { - NMConnection *connection = NULL; - NMSetting *con_setting = NULL; - NMSetting *wireless_setting = NULL; - NMSettingWireless *tmp; - NMSetting *security_setting = NULL; + NMSettingWireless *s_wireless = NM_SETTING_WIRELESS (setting); char *printable_ssid = NULL; - connection = nm_connection_new (); - if (!connection) { - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Failed to allocate new connection for %s.", file); - return NULL; + if (s_wireless->ssid) + printable_ssid = nm_utils_ssid_to_utf8 ((const char *) s_wireless->ssid->data, + (guint32) s_wireless->ssid->len); + + return printable_ssid; +} + +static void +parse_wireless (NMConnection *connection, shvarFile *file, const char *iface) +{ + NMSetting *setting; + NMSetting *security; + char *printable_ssid; + + setting = make_wireless_setting (file); + nm_connection_add_setting (connection, setting); + + security = make_wireless_security_setting (file, NM_SETTING_WIRELESS (setting)); + if (security) { + const char *security_str; + + if (NM_IS_SETTING_802_1X (security)) + security_str = NM_SETTING_802_1X_SETTING_NAME; + else if (NM_IS_SETTING_WIRELESS_SECURITY (security)) + security_str = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; + else { + security_str = NULL; + g_warning ("Invalid security type: '%s'", G_OBJECT_TYPE_NAME (security)); + } + + g_object_set (G_OBJECT (setting), NM_SETTING_WIRELESS_SEC, security_str, NULL); + nm_connection_add_setting (connection, security); } - /* Wireless security */ - security_setting = make_wireless_security_setting (ifcfg, err); - if (*err) - goto error; - if (security_setting) - nm_connection_add_setting (connection, security_setting); - - /* Wireless */ - wireless_setting = make_wireless_setting (ifcfg, security_setting, err); - if (!wireless_setting) - goto error; - - nm_connection_add_setting (connection, wireless_setting); - - tmp = NM_SETTING_WIRELESS (wireless_setting); - printable_ssid = nm_utils_ssid_to_utf8 ((const char *) tmp->ssid->data, - (guint32) tmp->ssid->len); - - con_setting = make_connection_setting (file, ifcfg, - NM_SETTING_WIRELESS_SETTING_NAME, - printable_ssid); + printable_ssid = get_printable_ssid (setting); + setting = make_connection_setting (file, iface, NM_SETTING_WIRELESS_SETTING_NAME, printable_ssid); + nm_connection_add_setting (connection, setting); g_free (printable_ssid); - if (!con_setting) { - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Failed to create connection setting."); - goto error; - } - nm_connection_add_setting (connection, con_setting); - - if (!nm_connection_verify (connection)) { - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Connection from %s was invalid.", file); - goto error; - } - - return connection; - -error: - g_object_unref (connection); - if (con_setting) - g_object_unref (con_setting); - if (wireless_setting) - g_object_unref (wireless_setting); - return NULL; + setting = make_ip4_setting (file); + nm_connection_add_setting (connection, setting); } -static NMSetting * -make_wired_setting (shvarFile *ifcfg, GError **err) +static shvarFile * +parser_get_ifcfg_for_iface (const char *iface) { - NMSettingWired *s_wired; - char *value; - int mtu; + char *filename; + shvarFile *file = NULL; - s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); + filename = g_strdup_printf (SYSCONFDIR "/sysconfig/network/ifcfg-%s", iface); + if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + file = svNewFile (filename); - value = svGetValue (ifcfg, "MTU"); - if (value) { - if (strlen (value) < 1) - /* Ignore empty MTU */ - ; - else if (get_int (value, &mtu)) { - if (mtu >= 0 && mtu < 65536) - s_wired->mtu = mtu; - } else { - g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid MTU '%s'", value); - g_object_unref (s_wired); - s_wired = NULL; - } - g_free (value); - } + g_free (filename); - return (NMSetting *) s_wired; + return file; } -static NMConnection * -wired_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **err) +NMConnection * +parse_ifcfg (const char *iface, NMDeviceType type) { - NMConnection *connection = NULL; - NMSetting *con_setting = NULL; - NMSetting *wired_setting = NULL; + shvarFile *file; + NMConnection *connection; + + g_return_val_if_fail (iface != NULL, NULL); + + file = parser_get_ifcfg_for_iface (iface); + if (!file) + return NULL; connection = nm_connection_new (); - con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL); - if (!con_setting) { - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Failed to create connection setting."); - goto error; + + switch (type) { + case DEVICE_TYPE_802_3_ETHERNET: + parse_ethernet (connection, file, iface); + break; + case DEVICE_TYPE_802_11_WIRELESS: + parse_wireless (connection, file, iface); + break; + default: + break; } - nm_connection_add_setting (connection, con_setting); - wired_setting = make_wired_setting (ifcfg, err); - if (!wired_setting) - goto error; - - nm_connection_add_setting (connection, wired_setting); + svCloseFile (file); if (!nm_connection_verify (connection)) { - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Connection from %s was invalid.", file); - goto error; + g_object_unref (connection); + connection = NULL; } return connection; - -error: - g_object_unref (connection); - if (con_setting) - g_object_unref (con_setting); - if (wired_setting) - g_object_unref (wired_setting); - return NULL; } - -NMConnection * -parser_parse_ifcfg (const char *file, GError **err) + +gboolean +parser_ignore_device (const char *iface) { - NMConnection *connection = NULL; - shvarFile *parsed; - char *type; - char *nmc = NULL; - NMSetting *s_ip4; + shvarFile *file; + gboolean ignore = FALSE; - g_return_val_if_fail (file != NULL, NULL); + file = parser_get_ifcfg_for_iface (iface); + if (file) { + char *str; - parsed = svNewFile (file); - if (!parsed) { - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Couldn't parse file '%s'", file); - return NULL; + if (!svTrueValue (file, "NM_CONTROLLED", 1)) + ignore = TRUE; + + str = svGetValue (file, "STARTMODE"); + if (str && !g_ascii_strcasecmp (str, "off")) + ignore = TRUE; + g_free (str); + + svCloseFile (file); } - nmc = svGetValue (parsed, "NM_CONTROLLED"); - if (nmc) { - if (!svTrueValue (parsed, nmc, 1)) { - g_free (nmc); - // FIXME: actually ignore the device, not the connection - g_message ("Ignoring connection '%s' because NM_CONTROLLED was false", file); - goto done; - } - g_free (nmc); - } - - type = svGetValue (parsed, "WIRELESS_ESSID"); - if (type) { - g_free (type); - connection = wireless_connection_from_ifcfg (file, parsed, err); - } else - connection = wired_connection_from_ifcfg (file, parsed, err); - - if (!connection) - goto done; - - s_ip4 = make_ip4_setting (parsed, err); - if (*err) { - g_object_unref (connection); - connection = NULL; - goto done; - } else if (s_ip4) { - nm_connection_add_setting (connection, s_ip4); - } - - if (!nm_connection_verify (connection)) { - g_object_unref (connection); - connection = NULL; - g_set_error (err, ifcfg_plugin_error_quark (), 0, - "Connection was invalid"); - } - -done: - svCloseFile (parsed); - return connection; + return ignore; } guint32 -parser_parse_routes (const char *file, GError **err) +parser_parse_routes (const char *filename) { FILE *f; char *buf; char buffer[512]; guint route = 0; - if ((f = fopen (SYSCONFDIR"/sysconfig/network/routes", "r"))) { + g_return_val_if_fail (filename != NULL, 0); + + if ((f = fopen (filename, "r"))) { while (fgets (buffer, 512, f) && !feof (f)) { buf = strtok (buffer, " "); if (strcmp (buf, "default") == 0) { diff --git a/system-settings/plugins/ifcfg-suse/parser.h b/system-settings/plugins/ifcfg-suse/parser.h index 45e04dba40..1ec0c448f3 100644 --- a/system-settings/plugins/ifcfg-suse/parser.h +++ b/system-settings/plugins/ifcfg-suse/parser.h @@ -23,13 +23,15 @@ #define _PARSER_H_ #include +#include #include #define IFCFG_TAG "ifcfg-" #define BAK_TAG ".bak" -NMConnection * parser_parse_ifcfg (const char *file, GError **error); -guint32 parser_parse_routes (const char *file, GError **err); +NMConnection *parse_ifcfg (const char *iface, NMDeviceType type); +gboolean parser_ignore_device (const char *iface); +guint32 parser_parse_routes (const char *filename); #endif /* _PARSER_H_ */ diff --git a/system-settings/plugins/ifcfg-suse/plugin.c b/system-settings/plugins/ifcfg-suse/plugin.c index fa278ba243..86fe719445 100644 --- a/system-settings/plugins/ifcfg-suse/plugin.c +++ b/system-settings/plugins/ifcfg-suse/plugin.c @@ -34,6 +34,7 @@ #include "plugin.h" #include "parser.h" +#include "nm-suse-connection.h" #include "nm-system-config-interface.h" #define IFCFG_PLUGIN_NAME "ifcfg-suse" @@ -52,14 +53,18 @@ G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0, #define IFCFG_FILE_PATH_TAG "ifcfg-file-path" typedef struct { + DBusGConnection *dbus_connection; + NMSystemConfigHalManager *hal_manager; + gboolean initialized; - GSList *connections; + GHashTable *connections; + GHashTable *unmanaged_devices; - GFileMonitor *monitor; - guint monitor_id; + guint32 default_gw; + GFileMonitor *default_gw_monitor; + guint default_gw_monitor_id; } SCPluginIfcfgPrivate; - GQuark ifcfg_plugin_error_quark (void) { @@ -71,118 +76,74 @@ ifcfg_plugin_error_quark (void) return error_quark; } -struct FindInfo { - const char *path; - gboolean found; -}; - -static gboolean -is_ifcfg_file (const char *file) -{ - return g_str_has_prefix (file, IFCFG_TAG) && strcmp (file, IFCFG_TAG "lo"); -} - -static NMConnection * -build_one_connection (const char *ifcfg_file) -{ - NMConnection *connection; - GError *err = NULL; - - PLUGIN_PRINT (PLUGIN_NAME, "parsing %s ... ", ifcfg_file); - - connection = parser_parse_ifcfg (ifcfg_file, &err); - if (connection) { - NMSettingConnection *s_con; - - s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); - g_assert (s_con); - g_assert (s_con->id); - PLUGIN_PRINT (PLUGIN_NAME, " found connection '%s'", s_con->id); - } else - PLUGIN_PRINT (PLUGIN_NAME, " error: %s", err->message ? err->message : "(unknown)"); - - return connection; -} - -typedef struct { - SCPluginIfcfg *plugin; - NMConnection *connection; - GFileMonitor *monitor; - guint monitor_id; -} ConnectionMonitor; - static void -connection_monitor_destroy (gpointer data) +update_one_connection (gpointer key, gpointer val, gpointer user_data) { - ConnectionMonitor *monitor = (ConnectionMonitor *) data; + NMExportedConnection *exported = NM_EXPORTED_CONNECTION (val); + NMConnection *connection; + NMSettingIP4Config *ip4_config; - g_signal_handler_disconnect (monitor->monitor, monitor->monitor_id); - g_file_monitor_cancel (monitor->monitor); - g_object_unref (monitor->monitor); + connection = nm_exported_connection_get_connection (exported); + ip4_config = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (!ip4_config) + return; - g_free (monitor); + if (ip4_config->addresses) { + /* suse only has one address per device */ + NMSettingIP4Address *ip4_address = (NMSettingIP4Address *) ip4_config->addresses->data; + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (user_data); + GHashTable *settings; + + if (ip4_address->gateway != priv->default_gw) { + ip4_address->gateway = priv->default_gw; + settings = nm_connection_to_hash (connection); + nm_exported_connection_signal_updated (exported, settings); + g_hash_table_destroy (settings); + } + } } static void -connection_file_changed (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) +update_connections (SCPluginIfcfg *self) { - ConnectionMonitor *cm = (ConnectionMonitor *) user_data; - gboolean remove_connection = FALSE; + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + + g_hash_table_foreach (priv->connections, update_one_connection, self); +} + +static void +routes_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + SCPluginIfcfg *self = SC_PLUGIN_IFCFG (user_data); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + char *filename; + guint32 new_gw; switch (event_type) { - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: { - NMConnection *new_connection; - GHashTable *new_settings; - char *filename; - char *ifcfg_file; - - /* In case anything goes wrong */ - remove_connection = TRUE; - - filename = g_file_get_basename (file); - ifcfg_file = g_build_filename (IFCFG_DIR, filename, NULL); + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + case G_FILE_MONITOR_EVENT_DELETED: + filename = g_file_get_path (file); + new_gw = parser_parse_routes (filename); g_free (filename); - new_connection = build_one_connection (ifcfg_file); - g_free (ifcfg_file); - - if (new_connection) { - new_settings = nm_connection_to_hash (new_connection); - if (nm_connection_replace_settings (cm->connection, new_settings)) { - /* Nothing went wrong */ - remove_connection = FALSE; - g_signal_emit_by_name (cm->plugin, "connection-updated", cm->connection); - } - - g_object_unref (new_connection); + if (priv->default_gw != new_gw) { + priv->default_gw = new_gw; + update_connections (self); } - - break; - } - case G_FILE_MONITOR_EVENT_DELETED: - remove_connection = TRUE; break; default: break; } - - if (remove_connection) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (cm->plugin); - - priv->connections = g_slist_remove (priv->connections, cm->connection); - g_signal_emit_by_name (cm->plugin, "connection-removed", cm->connection); - g_object_unref (cm->connection); - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " removed connection"); - } } static void -monitor_connection (NMSystemConfigInterface *config, NMConnection *connection, const char *filename) +monitor_routes (SCPluginIfcfg *self, const char *filename) { + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); GFile *file; GFileMonitor *monitor; @@ -191,170 +152,190 @@ monitor_connection (NMSystemConfigInterface *config, NMConnection *connection, c g_object_unref (file); if (monitor) { - ConnectionMonitor *cm; - - cm = g_new (ConnectionMonitor, 1); - cm->plugin = SC_PLUGIN_IFCFG (config); - cm->connection = connection; - cm->monitor = monitor; - cm->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (connection_file_changed), cm); - g_object_set_data_full (G_OBJECT (connection), "file-monitor", cm, connection_monitor_destroy); + priv->default_gw_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (routes_changed), self); + priv->default_gw_monitor = monitor; } } -static void -add_one_connection (NMSystemConfigInterface *config, const char *filename, gboolean emit_added) +static char * +get_iface_by_udi (SCPluginIfcfg *self, const char *udi) { - char *ifcfg_file; - NMConnection *connection; + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + DBusGProxy *proxy; + char *iface = NULL; - if (!is_ifcfg_file (filename)) - return; - - ifcfg_file = g_build_filename (IFCFG_DIR, filename, NULL); - connection = build_one_connection (ifcfg_file); - if (connection) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config); + proxy = dbus_g_proxy_new_for_name (priv->dbus_connection, + "org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device"); - monitor_connection (config, connection, ifcfg_file); - priv->connections = g_slist_append (priv->connections, connection); + dbus_g_proxy_call_with_timeout (proxy, "GetPropertyString", 10000, NULL, + G_TYPE_STRING, "net.interface", G_TYPE_INVALID, + G_TYPE_STRING, &iface, G_TYPE_INVALID); + g_object_unref (proxy); - if (emit_added) - g_signal_emit_by_name (config, "connection-added", connection); - } - - g_free (ifcfg_file); + return iface; } static void -update_default_routes (NMSystemConfigInterface *config, gboolean emit_updated) +read_connection (SCPluginIfcfg *self, const char *udi, NMDeviceType dev_type) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config); - GSList *iter; - NMConnection *connection; - NMSettingIP4Config *ip4_setting; - gboolean got_manual = FALSE; - guint32 default_route; + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + char *iface; - /* First, make sure we have any non-DHCP connections */ - for (iter = priv->connections; iter; iter = iter->next) { - connection = NM_CONNECTION (iter->data); - ip4_setting = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); - if (ip4_setting && !strcmp (ip4_setting->method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { - got_manual = TRUE; - break; - } - } + iface = get_iface_by_udi (self, udi); + if (iface) { + if (parser_ignore_device (iface)) { + g_hash_table_insert (priv->unmanaged_devices, g_strdup (udi), GINT_TO_POINTER (1)); + g_signal_emit_by_name (self, "unmanaged-devices-changed"); + } else { + NMSuseConnection *connection; - if (!got_manual) - return; - - default_route = parser_parse_routes (IFCFG_DIR "/routes", NULL); - if (!default_route) - return; - - for (iter = priv->connections; iter; iter = iter->next) { - connection = NM_CONNECTION (iter->data); - ip4_setting = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); - if (ip4_setting && !strcmp (ip4_setting->method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { - GSList *address_iter; - - for (address_iter = ip4_setting->addresses; address_iter; address_iter = address_iter->next) { - NMSettingIP4Address *addr = (NMSettingIP4Address *) address_iter->data; - - addr->gateway = default_route; - if (emit_updated) - g_signal_emit_by_name (config, "connection-updated", connection); + connection = nm_suse_connection_new (iface, dev_type); + if (connection) { + g_hash_table_insert (priv->connections, g_strdup (udi), connection); + g_signal_emit_by_name (self, "connection-added", connection); } } } -} -static GSList * -get_connections (NMSystemConfigInterface *config) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config); - - if (!priv->initialized) { - GDir *dir; - const char *item; - GError *err = NULL; - - dir = g_dir_open (IFCFG_DIR, 0, &err); - if (!dir) { - PLUGIN_WARN (PLUGIN_NAME, "couldn't access network directory '%s': %s.", IFCFG_DIR, err->message); - g_error_free (err); - return NULL; - } - - while ((item = g_dir_read_name (dir))) - add_one_connection (config, item, FALSE); - - g_dir_close (dir); - priv->initialized = TRUE; - } - - if (!priv->connections) - /* No need to do any futher work, we have nothing. */ - return priv->connections; - - update_default_routes (config, FALSE); - - return priv->connections; + g_free (iface); } static void -ifcfg_dir_changed (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) +read_connections_by_type (SCPluginIfcfg *self, NMDeviceType dev_type) { - NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data); - char *name; + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + GSList *list; + GSList *iter; - name = g_file_get_basename (file); - - if (event_type == G_FILE_MONITOR_EVENT_CREATED) { - add_one_connection (config, name, TRUE); + list = nm_system_config_hal_manager_get_devices_of_type (priv->hal_manager, dev_type); + for (iter = list; iter; iter = iter->next) { + read_connection (self, (char *) iter->data, dev_type); + g_free (iter->data); } - if (!strcmp (name, "routes")) - update_default_routes (config, TRUE); + g_slist_free (list); +} - g_free (name); +static void +device_added_cb (NMSystemConfigHalManager *hal_mgr, + const char *udi, + NMDeviceType dev_type, + gpointer user_data) +{ + SCPluginIfcfg *self = SC_PLUGIN_IFCFG (user_data); + + if (dev_type != DEVICE_TYPE_802_3_ETHERNET && dev_type != DEVICE_TYPE_802_11_WIRELESS) + return; + + read_connection (self, udi, dev_type); +} + +static void +device_removed_cb (NMSystemConfigHalManager *hal_mgr, + const char *udi, + NMDeviceType dev_type, + gpointer user_data) +{ + SCPluginIfcfg *self = SC_PLUGIN_IFCFG (user_data); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + NMExportedConnection *exported; + + if (dev_type != DEVICE_TYPE_802_3_ETHERNET && dev_type != DEVICE_TYPE_802_11_WIRELESS) + return; + + if (g_hash_table_remove (priv->unmanaged_devices, udi)) + g_signal_emit_by_name (self, "unmanaged-devices-changed"); + + exported = (NMExportedConnection *) g_hash_table_lookup (priv->connections, udi); + if (exported) { + nm_exported_connection_signal_removed (exported); + g_hash_table_remove (priv->connections, udi); + } } static void init (NMSystemConfigInterface *config, NMSystemConfigHalManager *hal_manager) { - GFile *file; - GFileMonitor *monitor; - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config); + SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); - file = g_file_new_for_path (IFCFG_DIR); - monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); + priv->hal_manager = g_object_ref (hal_manager); - if (monitor) { - priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (ifcfg_dir_changed), config); - priv->monitor = monitor; + g_signal_connect (priv->hal_manager, "device-added", G_CALLBACK (device_added_cb), self); + g_signal_connect (priv->hal_manager, "device-removed", G_CALLBACK (device_removed_cb), self); +} + +static void +get_connections_cb (gpointer key, gpointer val, gpointer user_data) +{ + GSList **list = (GSList **) user_data; + + *list = g_slist_prepend (*list, val); +} + +static GSList * +get_connections (NMSystemConfigInterface *config) +{ + SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + GSList *list = NULL; + + if (!priv->initialized) { + const char *filename; + + read_connections_by_type (self, DEVICE_TYPE_802_3_ETHERNET); + read_connections_by_type (self, DEVICE_TYPE_802_11_WIRELESS); + + filename = SYSCONFDIR"/sysconfig/network/routes"; + monitor_routes (self, filename); + priv->default_gw = parser_parse_routes (filename); + if (priv->default_gw) + update_connections (self); + + priv->initialized = TRUE; } + + g_hash_table_foreach (priv->connections, get_connections_cb, &list); + + return list; } static void -release_one_connection (gpointer item, gpointer user_data) +get_unamanged_devices_cb (gpointer key, gpointer val, gpointer user_data) { - NMConnection *connection = NM_CONNECTION (item); - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); + GSList **list = (GSList **) key; - g_signal_emit_by_name (plugin, "connection-removed", connection); - g_object_unref (connection); + *list = g_slist_prepend (*list, g_strdup ((char *) val)); +} + +static GSList * +get_unmanaged_devices (NMSystemConfigInterface *config) +{ + GSList *list = NULL; + + g_hash_table_foreach (SC_PLUGIN_IFCFG_GET_PRIVATE (config)->unmanaged_devices, + get_unamanged_devices_cb, &list); + + return list; } static void -sc_plugin_ifcfg_init (SCPluginIfcfg *plugin) +sc_plugin_ifcfg_init (SCPluginIfcfg *self) { + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + GError *err = NULL; + + priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->unmanaged_devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err); + if (!priv->dbus_connection) { + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " dbus-glib error: %s", + err->message ? err->message : "(unknown)"); + g_error_free (err); + } } static void @@ -362,18 +343,21 @@ dispose (GObject *object) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object); - if (priv->connections) { - g_slist_foreach (priv->connections, release_one_connection, object); - g_slist_free (priv->connections); + g_hash_table_destroy (priv->connections); + g_hash_table_destroy (priv->unmanaged_devices); + + if (priv->default_gw_monitor) { + if (priv->default_gw_monitor_id) + g_signal_handler_disconnect (priv->default_gw_monitor, priv->default_gw_monitor_id); + + g_file_monitor_cancel (priv->default_gw_monitor); + g_object_unref (priv->default_gw_monitor); } - if (priv->monitor) { - if (priv->monitor_id) - g_signal_handler_disconnect (priv->monitor, priv->monitor_id); + if (priv->hal_manager) + g_object_unref (priv->hal_manager); - g_file_monitor_cancel (priv->monitor); - g_object_unref (priv->monitor); - } + dbus_g_connection_unref (priv->dbus_connection); G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object); } @@ -419,6 +403,7 @@ system_config_interface_init (NMSystemConfigInterface *system_config_interface_c { /* interface implementation */ system_config_interface_class->get_connections = get_connections; + system_config_interface_class->get_unmanaged_devices = get_unmanaged_devices; system_config_interface_class->init = init; } diff --git a/system-settings/src/Makefile.am b/system-settings/src/Makefile.am index c80a54ae2a..24e1b9ded8 100644 --- a/system-settings/src/Makefile.am +++ b/system-settings/src/Makefile.am @@ -17,7 +17,9 @@ nm_system_settings_SOURCES = \ nm-system-config-interface.h \ nm-system-config-hal-manager.c \ nm-system-config-hal-manager.h \ - nm-system-config-hal-manager-private.h + nm-system-config-hal-manager-private.h \ + sha1.c \ + sha1.h nm_system_settings_CPPFLAGS = \ $(DBUS_CFLAGS) \ diff --git a/system-settings/src/dbus-settings.c b/system-settings/src/dbus-settings.c index 24cf0df61a..6e741feb4f 100644 --- a/system-settings/src/dbus-settings.c +++ b/system-settings/src/dbus-settings.c @@ -363,13 +363,11 @@ nm_sysconfig_settings_add_connection (NMSysconfigSettings *self, g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); g_return_if_fail (NM_IS_EXPORTED_CONNECTION (connection)); - if (g_hash_table_lookup (priv->connections, connection)) { - /* A plugin is lying to us */ - g_message ("Connection is already added, ignoring"); + if (g_hash_table_lookup (priv->connections, connection)) + /* A plugin is lying to us. */ return; - } - g_hash_table_insert (priv->connections, connection, GINT_TO_POINTER (1)); + g_hash_table_insert (priv->connections, g_object_ref (connection), GINT_TO_POINTER (1)); g_signal_connect (connection, "removed", G_CALLBACK (connection_removed), self); nm_exported_connection_register_object (connection, NM_CONNECTION_SCOPE_SYSTEM, priv->g_connection); diff --git a/system-settings/src/main.c b/system-settings/src/main.c index f007593dfb..4c7856d942 100644 --- a/system-settings/src/main.c +++ b/system-settings/src/main.c @@ -130,8 +130,8 @@ load_plugins (Application *app, const char *plugins, GError **error) plugin = g_module_open (path, G_MODULE_BIND_LOCAL); if (!plugin) { g_set_error (error, plugins_error_quark (), 0, - "Could not find plugin '%s' as %s!", - *pname, path); + "Could not load plugin '%s': %s", + *pname, g_module_error ()); g_free (full_name); g_free (path); break; diff --git a/system-settings/src/sha1.c b/system-settings/src/sha1.c new file mode 100644 index 0000000000..f7ceaa60df --- /dev/null +++ b/system-settings/src/sha1.c @@ -0,0 +1,692 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include +#include + +#include "config.h" +#include "sha1.h" + + +/* Define types for stupid code. Userspace should + * be using u_*_t rather than kernel-space u* types. + */ +typedef u_int8_t u8; +typedef u_int16_t u16; +typedef u_int32_t u32; +typedef u_int64_t u64; + +void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); +void sha1_transform(u8 *state, const u8 data[64]); + +void sha1_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + const u8 *addr[3]; + size_t len[3]; + addr[0] = key; + len[0] = key_len; + addr[1] = data; + len[1] = data_len; + addr[2] = key; + len[2] = key_len; + sha1_vector(3, addr, len, mac); +} + + +/* HMAC code is based on RFC 2104 */ +void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ + unsigned char tk[20]; + const u8 *_addr[6]; + size_t _len[6], i; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return; + } + + /* if key is longer than 64 bytes reset it to key = SHA1(key) */ + if (key_len > 64) { + sha1_vector(1, &key, &key_len, tk); + key = tk; + key_len = 20; + } + + /* the HMAC_SHA1 transform looks like: + * + * SHA1(K XOR opad, SHA1(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + memset(k_pad, 0, sizeof(k_pad)); + memcpy(k_pad, key, key_len); + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner SHA1 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + sha1_vector(1 + num_elem, _addr, _len, mac); + + memset(k_pad, 0, sizeof(k_pad)); + memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer SHA1 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = SHA1_MAC_LEN; + sha1_vector(2, _addr, _len, mac); +} + + +void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); +} + + +void sha1_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len) +{ + u8 zero = 0, counter = 0; + size_t pos, plen; + u8 hash[SHA1_MAC_LEN]; + size_t label_len = strlen(label); + const unsigned char *addr[4]; + size_t len[4]; + + addr[0] = (u8 *) label; + len[0] = label_len; + addr[1] = &zero; + len[1] = 1; + addr[2] = data; + len[2] = data_len; + addr[3] = &counter; + len[3] = 1; + + pos = 0; + while (pos < buf_len) { + plen = buf_len - pos; + if (plen >= SHA1_MAC_LEN) { + hmac_sha1_vector(key, key_len, 4, addr, len, + &buf[pos]); + pos += SHA1_MAC_LEN; + } else { + hmac_sha1_vector(key, key_len, 4, addr, len, + hash); + memcpy(&buf[pos], hash, plen); + break; + } + counter++; + } +} + + +static void pbkdf2_sha1_f(const char *passphrase, const char *ssid, + size_t ssid_len, int iterations, int count, + u8 *digest) +{ + unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; + int i, j; + unsigned char count_buf[4]; + const u8 *addr[2]; + size_t len[2]; + size_t passphrase_len = strlen(passphrase); + + addr[0] = (u8 *) ssid; + len[0] = ssid_len; + addr[1] = count_buf; + len[1] = 4; + + /* F(P, S, c, i) = U1 xor U2 xor ... Uc + * U1 = PRF(P, S || i) + * U2 = PRF(P, U1) + * Uc = PRF(P, Uc-1) + */ + + count_buf[0] = (count >> 24) & 0xff; + count_buf[1] = (count >> 16) & 0xff; + count_buf[2] = (count >> 8) & 0xff; + count_buf[3] = count & 0xff; + hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, tmp); + memcpy(digest, tmp, SHA1_MAC_LEN); + + for (i = 1; i < iterations; i++) { + hmac_sha1((u8 *) passphrase, passphrase_len, tmp, SHA1_MAC_LEN, + tmp2); + memcpy(tmp, tmp2, SHA1_MAC_LEN); + for (j = 0; j < SHA1_MAC_LEN; j++) + digest[j] ^= tmp2[j]; + } +} + + +void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + int count = 0; + unsigned char *pos = buf; + size_t left = buflen; + size_t plen; + unsigned char digest[SHA1_MAC_LEN]; + + while (left > 0) { + count++; + pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count, + digest); + plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; + memcpy(pos, digest, plen); + pos += plen; + left -= plen; + } +} + + +#ifndef EAP_TLS_FUNCS + +typedef struct { + u32 state[5]; + u32 count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +static void SHA1Init(SHA1_CTX *context); +static void SHA1Update(SHA1_CTX *context, const void *data, u32 len); +static void SHA1Final(unsigned char digest[20], SHA1_CTX* context); +static void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + + +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + */ +void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + SHA1_CTX ctx; + size_t i; + + SHA1Init(&ctx); + for (i = 0; i < num_elem; i++) + SHA1Update(&ctx, addr[i], len[i]); + SHA1Final(mac, &ctx); +} + + +/** + * sha1_transform - Perform one SHA-1 transform step + * @state: SHA-1 state + * @data: Input data for the SHA-1 transform + * + * This function is used to implement random number generation specified in + * NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is + * similar to SHA-1, but has different message padding and as such, access to + * just part of the SHA-1 is needed. + */ +void sha1_transform(u8 *state, const u8 data[64]) +{ + SHA1Transform((u32 *) state, data); +} + + +/* ===== start - public domain SHA1 implementation ===== */ + +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 4/01 +By Jouni Malinen +Minor changes to match the coding style used in Dynamics. + +Modified September 24, 2004 +By Jouni Malinen +Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. + +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#define SHA1HANDSOFF + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifndef WORDS_BIGENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ + (rol(block->l[i], 8) & 0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v,w,x,y,z,i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w=rol(w, 30); + + +#ifdef VERBOSE /* SAK */ +void SHAPrintContext(SHA1_CTX *context, char *msg) +{ + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); +} +#endif + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(u32 state[5], const unsigned char buffer[64]) +{ + u32 a, b, c, d, e; + typedef union { + unsigned char c[64]; + u32 l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; +#ifdef SHA1HANDSOFF + u32 workspace[16]; + block = (CHAR64LONG16 *) workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, 0, 64); +#endif +} + + +/* SHA1Init - Initialize new context */ + +static void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len) +{ + u32 i, j; + const unsigned char *data = _data; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ + +static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ + u32 i; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char) + ((context->count[(i >= 4 ? 0 : 1)] >> + ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *) "\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *) "\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() + */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & + 255); + } + /* Wipe variables */ + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); +} + +/* ===== end - public domain SHA1 implementation ===== */ + +#endif /* EAP_TLS_FUNCS */ + + +#ifdef TEST_MAIN + +static u8 key0[] = +{ + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b +}; +static u8 data0[] = "Hi There"; +static u8 prf0[] = +{ + 0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84, + 0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54, + 0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06, + 0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee, + 0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88, + 0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb, + 0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e, + 0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a +}; + +static u8 key1[] = "Jefe"; +static u8 data1[] = "what do ya want for nothing?"; +static u8 prf1[] = +{ + 0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad, + 0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4, + 0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58, + 0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09, + 0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa, + 0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02, + 0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7, + 0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc +}; + + +static u8 key2[] = +{ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa +}; +static u8 data2[] = +{ + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd +}; +static u8 prf2[] = +{ + 0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f, + 0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1, + 0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1, + 0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce, + 0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc, + 0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae, + 0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6, + 0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07 +}; + + +struct passphrase_test { + char *passphrase; + char *ssid; + char psk[32]; +}; + +static struct passphrase_test passphrase_tests[] = +{ + { + "password", + "IEEE", + { + 0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef, + 0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90, + 0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2, + 0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e + } + }, + { + "ThisIsAPassword", + "ThisIsASSID", + { + 0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6, + 0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3, + 0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08, + 0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf + } + }, + { + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", + { + 0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83, + 0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c, + 0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48, + 0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62 + } + }, +}; + +#define NUM_PASSPHRASE_TESTS \ +(sizeof(passphrase_tests) / sizeof(passphrase_tests[0])) + + +int main(int argc, char *argv[]) +{ + u8 res[512]; + int ret = 0, i; + + printf("PRF-SHA1 test cases:\n"); + + sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1, + res, sizeof(prf0)); + if (memcmp(res, prf0, sizeof(prf0)) == 0) + printf("Test case 0 - OK\n"); + else { + printf("Test case 0 - FAILED!\n"); + ret++; + } + + sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1, + res, sizeof(prf1)); + if (memcmp(res, prf1, sizeof(prf1)) == 0) + printf("Test case 1 - OK\n"); + else { + printf("Test case 1 - FAILED!\n"); + ret++; + } + + sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2), + res, sizeof(prf2)); + if (memcmp(res, prf2, sizeof(prf2)) == 0) + printf("Test case 2 - OK\n"); + else { + printf("Test case 2 - FAILED!\n"); + ret++; + } + + ret += test_eap_fast(); + + printf("PBKDF2-SHA1 Passphrase test cases:\n"); + for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) { + u8 psk[32]; + struct passphrase_test *test = &passphrase_tests[i]; + pbkdf2_sha1(test->passphrase, + test->ssid, strlen(test->ssid), + 4096, psk, 32); + if (memcmp(psk, test->psk, 32) == 0) + printf("Test case %d - OK\n", i); + else { + printf("Test case %d - FAILED!\n", i); + ret++; + } + } + + return ret; +} +#endif /* TEST_MAIN */ diff --git a/system-settings/src/sha1.h b/system-settings/src/sha1.h new file mode 100644 index 0000000000..40863c860f --- /dev/null +++ b/system-settings/src/sha1.h @@ -0,0 +1,34 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA1_H +#define SHA1_H + +#include + + +#define SHA1_MAC_LEN 20 + +void sha1_mac(const u_int8_t *key, size_t key_len, const u_int8_t *data, size_t data_len, + u_int8_t *mac); +void hmac_sha1_vector(const u_int8_t *key, size_t key_len, size_t num_elem, + const u_int8_t *addr[], const size_t *len, u_int8_t *mac); +void hmac_sha1(const u_int8_t *key, size_t key_len, const u_int8_t *data, size_t data_len, + u_int8_t *mac); +void sha1_prf(const u_int8_t *key, size_t key_len, const char *label, + const u_int8_t *data, size_t data_len, u_int8_t *buf, size_t buf_len); +void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u_int8_t *buf, size_t buflen); + +#endif /* SHA1_H */