commit f3c9887472ef6d773aeabd0bb7fcf102cf725398 Author: Dan Williams <dcbw@redhat.com> Date: Sat May 9 22:34:35 2009 -0400 wifi: handle WEP & WPA passphrases (bgo #513820) (rh #441070) Instead of requiring applets to hash passphrases, just do it in NM instead. This should fix confusion where people don't understand that they are seeing their hashed passphrase. diff --git a/configure.in b/configure.in index 1766c49..47a7f61 100644 --- a/configure.in +++ b/configure.in @@ -464,6 +464,7 @@ src/named-manager/Makefile src/vpn-manager/Makefile src/dhcp-manager/Makefile src/supplicant-manager/Makefile +src/supplicant-manager/tests/Makefile src/ppp-manager/Makefile src/dnsmasq-manager/Makefile src/backends/Makefile diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index bc86e08..9fdc235 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -239,6 +239,7 @@ global: nm_setting_wireless_security_get_psk; nm_setting_wireless_security_get_type; nm_setting_wireless_security_get_wep_key; + nm_setting_wireless_security_get_wep_key_type; nm_setting_wireless_security_get_wep_tx_keyidx; nm_setting_wireless_security_new; nm_setting_wireless_security_remove_group; diff --git a/libnm-util/nm-setting-wireless-security.c b/libnm-util/nm-setting-wireless-security.c index e5304f7..926e3af 100644 --- a/libnm-util/nm-setting-wireless-security.c +++ b/libnm-util/nm-setting-wireless-security.c @@ -93,6 +93,7 @@ typedef struct { char *wep_key3; char *psk; char *leap_password; + NMWepKeyType wep_key_type; } NMSettingWirelessSecurityPrivate; enum { @@ -110,6 +111,7 @@ enum { PROP_WEP_KEY3, PROP_PSK, PROP_LEAP_PASSWORD, + PROP_WEP_KEY_TYPE, LAST_PROP }; @@ -425,8 +427,16 @@ nm_setting_wireless_security_get_auth_alg (NMSettingWirelessSecurity *setting) return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->auth_alg; } +NMWepKeyType +nm_setting_wireless_security_get_wep_key_type (NMSettingWirelessSecurity *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (setting), 0); + + return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->wep_key_type; +} + static gboolean -verify_wep_key (const char *key) +verify_wep_key (const char *key, NMWepKeyType wep_type) { int keylen, i; @@ -434,11 +444,24 @@ verify_wep_key (const char *key) return FALSE; keylen = strlen (key); - if (keylen != 10 && keylen != 26) - return FALSE; + if (wep_type == NM_WEP_KEY_TYPE_KEY || NM_WEP_KEY_TYPE_UNKNOWN) { + if (keylen == 10 || keylen == 26) { + /* Hex key */ + for (i = 0; i < keylen; i++) { + if (!isxdigit (key[i])) + return FALSE; + } + } else if (keylen == 5 || keylen == 13) { + /* ASCII key */ + for (i = 0; i < keylen; i++) { + if (!isascii (key[i])) + return FALSE; + } + } else + return FALSE; - for (i = 0; i < keylen; i++) { - if (!isxdigit (key[i])) + } else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) { + if (!keylen || keylen > 64) return FALSE; } @@ -454,12 +477,15 @@ verify_wpa_psk (const char *psk) return FALSE; psklen = strlen (psk); - if (psklen != 64) + if (psklen < 8 || psklen > 64) return FALSE; - for (i = 0; i < psklen; i++) { - if (!isxdigit (psk[i])) - return FALSE; + if (psklen == 64) { + /* Hex PSK */ + for (i = 0; i < psklen; i++) { + if (!isxdigit (psk[i])) + return FALSE; + } } return TRUE; @@ -483,19 +509,19 @@ need_secrets (NMSetting *setting) /* Static WEP */ if (strcmp (priv->key_mgmt, "none") == 0) { - if ((priv->wep_tx_keyidx == 0) && !verify_wep_key (priv->wep_key0)) { + if ((priv->wep_tx_keyidx == 0) && !verify_wep_key (priv->wep_key0, priv->wep_key_type)) { g_ptr_array_add (secrets, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0); return secrets; } - if ((priv->wep_tx_keyidx == 1) && !verify_wep_key (priv->wep_key1)) { + if ((priv->wep_tx_keyidx == 1) && !verify_wep_key (priv->wep_key1, priv->wep_key_type)) { g_ptr_array_add (secrets, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1); return secrets; } - if ((priv->wep_tx_keyidx == 2) && !verify_wep_key (priv->wep_key2)) { + if ((priv->wep_tx_keyidx == 2) && !verify_wep_key (priv->wep_key2, priv->wep_key_type)) { g_ptr_array_add (secrets, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2); return secrets; } - if ((priv->wep_tx_keyidx == 3) && !verify_wep_key (priv->wep_key3)) { + if ((priv->wep_tx_keyidx == 3) && !verify_wep_key (priv->wep_key3, priv->wep_key_type)) { g_ptr_array_add (secrets, NM_SETTING_WIRELESS_SECURITY_WEP_KEY3); return secrets; } @@ -627,28 +653,36 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } - if (priv->wep_key0 && !strlen (priv->wep_key0)) { + if (priv->wep_key_type > NM_WEP_KEY_TYPE_LAST) { + g_set_error (error, + NM_SETTING_WIRELESS_SECURITY_ERROR, + NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE); + return FALSE; + } + + if (priv->wep_key0 && !verify_wep_key (priv->wep_key0, priv->wep_key_type)) { g_set_error (error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0); return FALSE; } - if (priv->wep_key1 && !strlen (priv->wep_key1)) { + if (priv->wep_key1 && !verify_wep_key (priv->wep_key1, priv->wep_key_type)) { g_set_error (error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1); return FALSE; } - if (priv->wep_key2 && !strlen (priv->wep_key2)) { + if (priv->wep_key2 && !verify_wep_key (priv->wep_key2, priv->wep_key_type)) { g_set_error (error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2); return FALSE; } - if (priv->wep_key3 && !strlen (priv->wep_key3)) { + if (priv->wep_key3 && !verify_wep_key (priv->wep_key3, priv->wep_key_type)) { g_set_error (error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY, @@ -825,6 +859,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->leap_password); priv->leap_password = g_value_dup_string (value); break; + case PROP_WEP_KEY_TYPE: + priv->wep_key_type = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -878,6 +915,9 @@ get_property (GObject *object, guint prop_id, case PROP_LEAP_PASSWORD: g_value_set_string (value, priv->leap_password); break; + case PROP_WEP_KEY_TYPE: + g_value_set_uint (value, priv->wep_key_type); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1004,4 +1044,14 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *setting "LEAP Password", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + + g_object_class_install_property + (object_class, PROP_WEP_KEY_TYPE, + g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, + "WEP Key Type", + "WEP Key Type", + NM_WEP_KEY_TYPE_UNKNOWN, + NM_WEP_KEY_TYPE_LAST, + NM_WEP_KEY_TYPE_UNKNOWN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); } diff --git a/libnm-util/nm-setting-wireless-security.h b/libnm-util/nm-setting-wireless-security.h index d72c9bf..772a2d6 100644 --- a/libnm-util/nm-setting-wireless-security.h +++ b/libnm-util/nm-setting-wireless-security.h @@ -56,6 +56,14 @@ GType nm_setting_wireless_security_error_get_type (void); #define NM_SETTING_WIRELESS_SECURITY_ERROR nm_setting_wireless_security_error_quark () GQuark nm_setting_wireless_security_error_quark (void); +typedef enum { + NM_WEP_KEY_TYPE_UNKNOWN = 0, + NM_WEP_KEY_TYPE_KEY = 1, /* Hex or ASCII */ + NM_WEP_KEY_TYPE_PASSPHRASE = 2, /* 104/128-bit Passphrase */ + + NM_WEP_KEY_TYPE_LAST = NM_WEP_KEY_TYPE_PASSPHRASE +} NMWepKeyType; + #define NM_SETTING_WIRELESS_SECURITY_KEY_MGMT "key-mgmt" #define NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX "wep-tx-keyidx" #define NM_SETTING_WIRELESS_SECURITY_AUTH_ALG "auth-alg" @@ -69,6 +77,7 @@ GQuark nm_setting_wireless_security_error_quark (void); #define NM_SETTING_WIRELESS_SECURITY_WEP_KEY3 "wep-key3" #define NM_SETTING_WIRELESS_SECURITY_PSK "psk" #define NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD "leap-password" +#define NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE "wep-key-type" typedef struct { NMSetting parent; @@ -111,6 +120,7 @@ const char *nm_setting_wireless_security_get_wep_key (NMSettingWirelessSec void nm_setting_wireless_security_set_wep_key (NMSettingWirelessSecurity *setting, guint32 idx, const char *key); guint32 nm_setting_wireless_security_get_wep_tx_keyidx (NMSettingWirelessSecurity *setting); const char *nm_setting_wireless_security_get_auth_alg (NMSettingWirelessSecurity *setting); +NMWepKeyType nm_setting_wireless_security_get_wep_key_type (NMSettingWirelessSecurity *setting); G_END_DECLS diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 519e57d..26a4010 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -182,61 +182,6 @@ nm_utils_ip4_prefix_to_netmask (guint32 prefix) return (guint32) htonl (netmask); } - -/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */ - -static int hex2num (char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - return -1; -} - -static int hex2byte (const char *hex) -{ - int a, b; - a = hex2num(*hex++); - if (a < 0) - return -1; - b = hex2num(*hex++); - if (b < 0) - return -1; - return (a << 4) | b; -} - -char * -nm_utils_hexstr2bin (const char *hex, - size_t len) -{ - size_t i; - int a; - const char * ipos = hex; - char * buf = NULL; - char * opos; - - /* Length must be a multiple of 2 */ - if ((len % 2) != 0) - return NULL; - - opos = buf = g_malloc0 ((len / 2) + 1); - for (i = 0; i < len; i += 2) { - a = hex2byte (ipos); - if (a < 0) { - g_free (buf); - return NULL; - } - *opos++ = a; - ipos += 2; - } - return buf; -} - -/* End from hostap */ - char * nm_ether_ntop (const struct ether_addr *mac) { diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 147a972..c412c46 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -37,8 +37,6 @@ int nm_spawn_process (const char *args); struct nl_addr *nm_utils_ip4_addr_to_nl_addr (guint32 ip4_addr); -char *nm_utils_hexstr2bin (const char *hex, size_t len); - char *nm_ether_ntop (const struct ether_addr *mac); void nm_utils_merge_ip4_config (NMIP4Config *ip4_config, NMSettingIP4Config *setting); diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index 2d6e023..7806c91 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -2803,10 +2803,8 @@ build_supplicant_config (NMDeviceWifi *self, goto error; } } else { - /* Unencrypted, wpa_supplicant needs key_mgmt=NONE here */ - if (!nm_supplicant_config_add_option (config, "key_mgmt", "NONE", -1, FALSE)) { - nm_warning ("Couldn't add 802-11-wireless (no security) setting to" - " supplicant config."); + if (!nm_supplicant_config_add_no_security (config)) { + nm_warning ("Couldn't add unsecured option to supplicant config."); goto error; } } diff --git a/src/supplicant-manager/Makefile.am b/src/supplicant-manager/Makefile.am index df27d5c..d613e83 100644 --- a/src/supplicant-manager/Makefile.am +++ b/src/supplicant-manager/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS=. tests + INCLUDES = \ -I${top_srcdir}/src \ -I${top_srcdir}/include \ @@ -16,7 +18,9 @@ libsupplicant_manager_la_SOURCES = \ nm-supplicant-interface.c \ nm-supplicant-interface.h \ nm-supplicant-settings-verify.h \ - nm-supplicant-settings-verify.c + nm-supplicant-settings-verify.c \ + gnome-keyring-md5.h \ + gnome-keyring-md5.c libsupplicant_manager_la_CPPFLAGS = \ $(DBUS_CFLAGS) \ diff --git a/src/supplicant-manager/gnome-keyring-md5.c b/src/supplicant-manager/gnome-keyring-md5.c new file mode 100644 index 0000000..0a3dd71 --- /dev/null +++ b/src/supplicant-manager/gnome-keyring-md5.c @@ -0,0 +1,291 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * GnomeKeyringMD5Context structure, pass it to gnome_keyring_md5_init, call + * gnome_keyring_md5_update as needed on buffers full of bytes, and then call + * gnome_keyring_md5_final, which will fill a supplied 32-byte array with the + * digest in ascii form. + * + */ + +#include "gnome-keyring-md5.h" +#include <string.h> + +static void gnome_keyring_md5_transform (guint32 buf[4], + guint32 const in[16]); + +void +gnome_keyring_md5_string (const char *string, unsigned char digest[16]) +{ + struct GnomeKeyringMD5Context md5_context; + + gnome_keyring_md5_init (&md5_context); + gnome_keyring_md5_update (&md5_context, (const unsigned char *)string, strlen (string)); + gnome_keyring_md5_final (digest, &md5_context); +} + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else + +/* + * Note: this code is harmless on little-endian machines. + */ +static void +byteReverse(unsigned char *buf, unsigned longs) +{ + guint32 t; + do { + t = (guint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(guint32 *) buf = t; + buf += 4; + } while (--longs); +} + +#endif + +char * +gnome_keyring_md5_digest_to_ascii (unsigned char digest[16]) +{ + static char hex_digits[] = "0123456789abcdef"; + char *res; + int i; + + res = g_malloc (33); + + for (i = 0; i < 16; i++) { + res[2*i] = hex_digits[digest[i] >> 4]; + res[2*i+1] = hex_digits[digest[i] & 0xf]; + } + + res[32] = 0; + + return res; +} + + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +gnome_keyring_md5_init (struct GnomeKeyringMD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +gnome_keyring_md5_update (struct GnomeKeyringMD5Context *ctx, + unsigned char const *buf, + unsigned len) +{ + guint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((guint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy (p, buf, len); + return; + } + memcpy (p, buf, t); + byteReverse (ctx->in, 16); + gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy (ctx->in, buf, 64); + byteReverse (ctx->in, 16); + gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +gnome_keyring_md5_final (unsigned char digest[16], struct GnomeKeyringMD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset (p, 0, count); + byteReverse (ctx->in, 16); + gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((guint32 *) ctx->in)[14] = ctx->bits[0]; + ((guint32 *) ctx->in)[15] = ctx->bits[1]; + + gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in); + byteReverse ((unsigned char *) ctx->buf, 4); + memcpy (digest, ctx->buf, 16); + memset (ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + + +/* The four core functions - F1 is optimized somewhat */ + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1 (z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define gnome_keyring_md5_step(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. GnomeKeyringMD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +gnome_keyring_md5_transform (guint32 buf[4], guint32 const in[16]) +{ + register guint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + gnome_keyring_md5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + gnome_keyring_md5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + gnome_keyring_md5_step(F1, c, d, a, b, in[2] + 0x242070db, 17); + gnome_keyring_md5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + gnome_keyring_md5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + gnome_keyring_md5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + gnome_keyring_md5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17); + gnome_keyring_md5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22); + gnome_keyring_md5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7); + gnome_keyring_md5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + gnome_keyring_md5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + gnome_keyring_md5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + gnome_keyring_md5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7); + gnome_keyring_md5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12); + gnome_keyring_md5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17); + gnome_keyring_md5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + gnome_keyring_md5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + gnome_keyring_md5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9); + gnome_keyring_md5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + gnome_keyring_md5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + gnome_keyring_md5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + gnome_keyring_md5_step(F2, d, a, b, c, in[10] + 0x02441453, 9); + gnome_keyring_md5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + gnome_keyring_md5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + gnome_keyring_md5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + gnome_keyring_md5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + gnome_keyring_md5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + gnome_keyring_md5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + gnome_keyring_md5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + gnome_keyring_md5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + gnome_keyring_md5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + gnome_keyring_md5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + gnome_keyring_md5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + gnome_keyring_md5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11); + gnome_keyring_md5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + gnome_keyring_md5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + gnome_keyring_md5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + gnome_keyring_md5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + gnome_keyring_md5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + gnome_keyring_md5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + gnome_keyring_md5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + gnome_keyring_md5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + gnome_keyring_md5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + gnome_keyring_md5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23); + gnome_keyring_md5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + gnome_keyring_md5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + gnome_keyring_md5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + gnome_keyring_md5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + gnome_keyring_md5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6); + gnome_keyring_md5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10); + gnome_keyring_md5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + gnome_keyring_md5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + gnome_keyring_md5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + gnome_keyring_md5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + gnome_keyring_md5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + gnome_keyring_md5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + gnome_keyring_md5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + gnome_keyring_md5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + gnome_keyring_md5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15); + gnome_keyring_md5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + gnome_keyring_md5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + gnome_keyring_md5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + gnome_keyring_md5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + gnome_keyring_md5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + diff --git a/src/supplicant-manager/gnome-keyring-md5.h b/src/supplicant-manager/gnome-keyring-md5.h new file mode 100644 index 0000000..3dff998 --- /dev/null +++ b/src/supplicant-manager/gnome-keyring-md5.h @@ -0,0 +1,41 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * GnomeKeyringMD5Context structure, pass it to gnome_keyring_md5_init, call + * gnome_keyring_md5_update as needed on buffers full of bytes, and then call + * gnome_keyring_md5_final, which will fill a supplied 32-byte array with the + * digest in ascii form. + * + */ + +#ifndef GNOME_KEYRING_MD5_H +#define GNOME_KEYRING_MD5_H + +#include <glib.h> + +struct GnomeKeyringMD5Context { + guint32 buf[4]; + guint32 bits[2]; + unsigned char in[64]; +}; + +char *gnome_keyring_md5_digest_to_ascii (unsigned char digest[16]); +void gnome_keyring_md5_string (const char *string, + unsigned char digest[16]); +void gnome_keyring_md5_init (struct GnomeKeyringMD5Context *ctx); +void gnome_keyring_md5_update (struct GnomeKeyringMD5Context *ctx, + unsigned char const *buf, + unsigned len); +void gnome_keyring_md5_final (unsigned char digest[16], + struct GnomeKeyringMD5Context *ctx); + +#endif /* GNOME_KEYRING_MD5_H */ diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c index e2208ec..4fb6a1e 100644 --- a/src/supplicant-manager/nm-supplicant-config.c +++ b/src/supplicant-manager/nm-supplicant-config.c @@ -35,6 +35,10 @@ #include "nm-setting.h" #include "NetworkManagerUtils.h" +#include "gnome-keyring-md5.h" + +static char *hexstr2bin (const char *hex, size_t len); + #define NM_SUPPLICANT_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ NM_TYPE_SUPPLICANT_CONFIG, \ NMSupplicantConfigPrivate)) @@ -44,7 +48,7 @@ G_DEFINE_TYPE (NMSupplicantConfig, nm_supplicant_config, G_TYPE_OBJECT) typedef struct { char *value; guint32 len; - enum OptType type; + OptType type; } ConfigOption; typedef struct @@ -80,8 +84,8 @@ nm_supplicant_config_init (NMSupplicantConfig * self) NMSupplicantConfigPrivate *priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); priv->config = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) config_option_free); + (GDestroyNotify) g_free, + (GDestroyNotify) config_option_free); priv->blobs = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, @@ -91,12 +95,13 @@ nm_supplicant_config_init (NMSupplicantConfig * self) priv->dispose_has_run = FALSE; } -gboolean -nm_supplicant_config_add_option (NMSupplicantConfig *self, - const char * key, - const char * value, - gint32 len, - gboolean secret) +static gboolean +nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self, + const char *key, + const char *value, + gint32 len, + OptType opt_type, + gboolean secret) { NMSupplicantConfigPrivate *priv; ConfigOption *old_opt; @@ -112,13 +117,17 @@ nm_supplicant_config_add_option (NMSupplicantConfig *self, if (len < 0) len = strlen (value); - type = nm_supplicant_settings_verify_setting (key, value, len); - if (type == TYPE_INVALID) { - char buf[255]; - memset (&buf[0], 0, sizeof (buf)); - memcpy (&buf[0], value, len > 254 ? 254 : len); - nm_debug ("Key '%s' and/or value '%s' invalid.", key, buf); - return FALSE; + if (opt_type != TYPE_INVALID) + type = opt_type; + else { + type = nm_supplicant_settings_verify_setting (key, value, len); + if (type == TYPE_INVALID) { + char buf[255]; + memset (&buf[0], 0, sizeof (buf)); + memcpy (&buf[0], value, len > 254 ? 254 : len); + nm_debug ("Key '%s' and/or value '%s' invalid.", key, buf); + return FALSE; + } } old_opt = (ConfigOption *) g_hash_table_lookup (priv->config, key); @@ -155,6 +164,15 @@ nm_info ("Config: added '%s' value '%s'", key, secret ? "<omitted>" : &buf[0]); return TRUE; } +static gboolean +nm_supplicant_config_add_option (NMSupplicantConfig *self, + const char *key, + const char *value, + gint32 len, + gboolean secret) +{ + return nm_supplicant_config_add_option_with_type (self, key, value, len, TYPE_INVALID, secret); +} static gboolean nm_supplicant_config_add_blob (NMSupplicantConfig *self, @@ -283,6 +301,7 @@ get_hash_cb (gpointer key, gpointer value, gpointer user_data) g_byte_array_free (array, TRUE); break; case TYPE_KEYWORD: + case TYPE_STRING: g_value_init (variant, G_TYPE_STRING); g_value_set_string (variant, opt->value); break; @@ -306,17 +325,17 @@ destroy_hash_value (gpointer data) GHashTable * nm_supplicant_config_get_hash (NMSupplicantConfig * self) { + NMSupplicantConfigPrivate *priv; GHashTable *hash; g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), NULL); hash = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - destroy_hash_value); - - g_hash_table_foreach (NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->config, - get_hash_cb, hash); + (GDestroyNotify) g_free, + destroy_hash_value); + priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); + g_hash_table_foreach (priv->config, get_hash_cb, hash); return hash; } @@ -412,23 +431,26 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, return TRUE; } -#define ADD_STRING_VAL(field, name, ucase, unhexify, secret) \ - if (field) { \ - int len = -1; \ - if (ucase) \ - value = g_ascii_strup (field, -1); \ - else if (unhexify) { \ - value = nm_utils_hexstr2bin (field, strlen (field)); \ - len = strlen (field) / 2; \ - } else \ - value = g_strdup (field); \ - success = nm_supplicant_config_add_option (self, name, value, len, secret); \ - g_free (value); \ - if (!success) { \ - nm_warning ("Error adding %s to supplicant config.", name); \ - return FALSE; \ - } \ - } +static gboolean +add_string_val (NMSupplicantConfig *self, + const char *field, + const char *name, + gboolean ucase, + gboolean secret) +{ + gboolean success; + char *value; + + if (!field) + return TRUE; + + value = ucase ? g_ascii_strup (field, -1) : g_strdup (field); + success = nm_supplicant_config_add_option (self, name, value, strlen (field), secret); + if (!success) + nm_warning ("Error adding %s to supplicant config.", name); + g_free (value); + return success; +} #define ADD_STRING_LIST_VAL(setting, setting_name, field, field_plural, name, ucase, secret) \ if (nm_setting_##setting_name##_get_num_##field_plural (setting)) { \ @@ -444,7 +466,7 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, } \ } \ if (ucase) \ - g_string_ascii_up (str); \ + g_string_ascii_up (str); \ if (str->len) \ success = nm_supplicant_config_add_option (self, name, str->str, -1, secret); \ else \ @@ -479,6 +501,75 @@ get_blob_id (const char *name, const char *seed_uid) } \ } + +static unsigned char * +wep128_passphrase_hash (const char *input, size_t input_len, size_t *out_len) +{ + char md5_data[65]; + unsigned char *digest; + int i; + + *out_len = 16; + digest = g_malloc0 (*out_len); + + /* Get at least 64 bytes */ + for (i = 0; i < 64; i++) + md5_data[i] = input[i % input_len]; + + /* Null terminate md5 seed data and hash it */ + md5_data[64] = 0; + gnome_keyring_md5_string (md5_data, digest); + return digest; +} + +static gboolean +add_wep_key (NMSupplicantConfig *self, + const char *key, + const char *name, + NMWepKeyType wep_type) +{ + char *value; + gboolean success; + size_t key_len = key ? strlen (key) : 0; + + if (!key || !key_len) + return TRUE; + + if ( (wep_type == NM_WEP_KEY_TYPE_UNKNOWN) + || (wep_type == NM_WEP_KEY_TYPE_KEY)) { + if ((key_len == 10) || (key_len == 26)) { + value = hexstr2bin (key, strlen (key)); + success = nm_supplicant_config_add_option (self, name, value, key_len / 2, TRUE); + g_free (value); + if (!success) { + nm_warning ("Error adding %s to supplicant config.", name); + return FALSE; + } + } else if ((key_len == 5) || (key_len == 13)) { + if (!nm_supplicant_config_add_option (self, name, key, key_len, TRUE)) { + nm_warning ("Error adding %s to supplicant config.", name); + return FALSE; + } + } else { + nm_warning ("Invalid WEP key '%s'", name); + return FALSE; + } + } else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) { + char *digest; + size_t digest_len; + + digest = (char *) wep128_passphrase_hash (key, key_len, &digest_len); + success = nm_supplicant_config_add_option (self, name, digest, 13, TRUE); + g_free (digest); + if (!success) { + nm_warning ("Error adding %s to supplicant config.", name); + return FALSE; + } + } + + return TRUE; +} + gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, NMSettingWirelessSecurity *setting, @@ -489,6 +580,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, char *value; gboolean success; const char *key_mgmt, *auth_alg; + const char *psk; g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE); g_return_val_if_fail (setting != NULL, FALSE); @@ -497,12 +589,42 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting); - ADD_STRING_VAL (key_mgmt, "key_mgmt", TRUE, FALSE, FALSE); + if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE)) + return FALSE; auth_alg = nm_setting_wireless_security_get_auth_alg (setting); - ADD_STRING_VAL (auth_alg, "auth_alg", TRUE, FALSE, FALSE); + if (!add_string_val (self, auth_alg, "auth_alg", TRUE, FALSE)) + return FALSE; + + psk = nm_setting_wireless_security_get_psk (setting); + if (psk) { + size_t psk_len = strlen (psk); - ADD_STRING_VAL (nm_setting_wireless_security_get_psk (setting), "psk", FALSE, TRUE, TRUE); + if (psk_len == 64) { + /* Hex PSK */ + value = hexstr2bin (psk, psk_len); + success = nm_supplicant_config_add_option (self, "psk", value, psk_len / 2, TRUE); + g_free (value); + if (!success) { + nm_warning ("Error adding 'psk' to supplicant config."); + return FALSE; + } + } else if (psk_len >= 8 && psk_len < 63) { + /* Use TYPE_STRING here so that it gets pushed to the + * supplicant as a string, and therefore gets quoted, + * and therefore the supplicant will interpret it as a + * passphrase and not a hex key. + */ + if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, TRUE)) { + nm_warning ("Error adding 'psk' to supplicant config."); + return FALSE; + } + } else { + /* Invalid PSK */ + nm_warning ("Invalid PSK length %d: not between 8 and 63 characters inclusive.", psk_len); + return FALSE; + } + } /* Only WPA-specific things when using WPA */ if ( !strcmp (key_mgmt, "wpa-none") @@ -515,15 +637,20 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, /* WEP keys if required */ if (!strcmp (key_mgmt, "none")) { + NMWepKeyType wep_type = nm_setting_wireless_security_get_wep_key_type (setting); const char *wep0 = nm_setting_wireless_security_get_wep_key (setting, 0); const char *wep1 = nm_setting_wireless_security_get_wep_key (setting, 1); const char *wep2 = nm_setting_wireless_security_get_wep_key (setting, 2); const char *wep3 = nm_setting_wireless_security_get_wep_key (setting, 3); - ADD_STRING_VAL (wep0, "wep_key0", FALSE, TRUE, TRUE); - ADD_STRING_VAL (wep1, "wep_key1", FALSE, TRUE, TRUE); - ADD_STRING_VAL (wep2, "wep_key2", FALSE, TRUE, TRUE); - ADD_STRING_VAL (wep3, "wep_key3", FALSE, TRUE, TRUE); + if (!add_wep_key (self, wep0, "wep_key0", wep_type)) + return FALSE; + if (!add_wep_key (self, wep1, "wep_key1", wep_type)) + return FALSE; + if (!add_wep_key (self, wep2, "wep_key2", wep_type)) + return FALSE; + if (!add_wep_key (self, wep3, "wep_key3", wep_type)) + return FALSE; if (wep0 || wep1 || wep2 || wep3) { value = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (setting)); @@ -539,9 +666,18 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, if (auth_alg && !strcmp (auth_alg, "leap")) { /* LEAP */ if (!strcmp (key_mgmt, "ieee8021x")) { - ADD_STRING_VAL (nm_setting_wireless_security_get_leap_username (setting), "identity", FALSE, FALSE, FALSE); - ADD_STRING_VAL (nm_setting_wireless_security_get_leap_password (setting), "password", FALSE, FALSE, TRUE); - ADD_STRING_VAL ("leap", "eap", TRUE, FALSE, FALSE); + const char *tmp; + + tmp = nm_setting_wireless_security_get_leap_username (setting); + if (!add_string_val (self, tmp, "identity", FALSE, FALSE)) + return FALSE; + + tmp = nm_setting_wireless_security_get_leap_password (setting); + if (!add_string_val (self, tmp, "password", FALSE, TRUE)) + return FALSE; + + if (!add_string_val (self, "leap", "eap", TRUE, FALSE)) + return FALSE; } else { return FALSE; } @@ -565,7 +701,8 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, gboolean wired) { NMSupplicantConfigPrivate *priv; - char *value, *tmp; + char *tmp; + const char *value; gboolean success; GString *phase1, *phase2; const GByteArray *array; @@ -577,13 +713,19 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); - ADD_STRING_VAL (nm_setting_802_1x_get_password (setting), "password", FALSE, FALSE, TRUE); - ADD_STRING_VAL (nm_setting_802_1x_get_pin (setting), "pin", FALSE, FALSE, TRUE); + value = nm_setting_802_1x_get_password (setting); + if (!add_string_val (self, value, "password", FALSE, TRUE)) + return FALSE; + value = nm_setting_802_1x_get_pin (setting); + if (!add_string_val (self, value, "pin", FALSE, TRUE)) + return FALSE; if (wired) { - ADD_STRING_VAL ("IEEE8021X", "key_mgmt", TRUE, FALSE, FALSE); + if (!add_string_val (self, "IEEE8021X", "key_mgmt", FALSE, FALSE)) + return FALSE; /* Wired 802.1x must always use eapol_flags=0 */ - ADD_STRING_VAL ("0", "eapol_flags", FALSE, FALSE, FALSE); + if (!add_string_val (self, "0", "eapol_flags", FALSE, FALSE)) + return FALSE; } ADD_STRING_LIST_VAL (setting, 802_1x, eap_method, eap_methods, "eap", TRUE, FALSE); @@ -607,8 +749,12 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, g_string_append_printf (phase1, "peaplabel=%s", nm_setting_802_1x_get_phase1_peaplabel (setting)); } - if (phase1->len) - ADD_STRING_VAL (phase1->str, "phase1", FALSE, FALSE, FALSE); + if (phase1->len) { + if (!add_string_val (self, phase1->str, "phase1", FALSE, FALSE)) { + g_string_free (phase1, TRUE); + return FALSE; + } + } g_string_free (phase1, TRUE); phase2 = g_string_new (NULL); @@ -626,12 +772,17 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, g_free (tmp); } - if (phase2->len) - ADD_STRING_VAL (phase2->str, "phase2", FALSE, FALSE, FALSE); + if (phase2->len) { + if (!add_string_val (self, phase2->str, "phase2", FALSE, FALSE)) { + g_string_free (phase2, TRUE); + return FALSE; + } + } g_string_free (phase2, TRUE); if (nm_setting_802_1x_get_system_ca_certs (setting)) { - ADD_STRING_VAL (SYSTEM_CA_PATH, "ca_path", FALSE, FALSE, FALSE); + if (!add_string_val (self, SYSTEM_CA_PATH, "ca_path", FALSE, FALSE)) + return FALSE; } else { ADD_BLOB_VAL (nm_setting_802_1x_get_ca_cert (setting), "ca_cert", connection_uid); } @@ -643,7 +794,9 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, switch (nm_setting_802_1x_get_private_key_type (setting)) { case NM_SETTING_802_1X_CK_TYPE_PKCS12: /* Only add the private key password for PKCS#12 keys */ - ADD_STRING_VAL (nm_setting_802_1x_get_private_key_password (setting), "private_key_passwd", FALSE, FALSE, TRUE); + value = nm_setting_802_1x_get_private_key_password (setting); + if (!add_string_val (self, value, "private_key_passwd", FALSE, TRUE)) + return FALSE; break; default: /* Only add the client cert if the private key is not PKCS#12 */ @@ -653,7 +806,8 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, } if (nm_setting_802_1x_get_system_ca_certs (setting)) { - ADD_STRING_VAL (SYSTEM_CA_PATH, "ca_path2", FALSE, FALSE, FALSE); + if (!add_string_val (self, SYSTEM_CA_PATH, "ca_path2", FALSE, FALSE)) + return FALSE; } else { ADD_BLOB_VAL (nm_setting_802_1x_get_phase2_ca_cert (setting), "ca_cert2", connection_uid); } @@ -665,7 +819,9 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, switch (nm_setting_802_1x_get_phase2_private_key_type (setting)) { case NM_SETTING_802_1X_CK_TYPE_PKCS12: /* Only add the private key password for PKCS#12 keys */ - ADD_STRING_VAL (nm_setting_802_1x_get_phase2_private_key_password (setting), "private_key2_passwd", FALSE, FALSE, TRUE); + value = nm_setting_802_1x_get_phase2_private_key_password (setting); + if (!add_string_val (self, value, "private_key2_passwd", FALSE, TRUE)) + return FALSE; break; default: /* Only add the client cert if the private key is not PKCS#12 */ @@ -674,9 +830,72 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, } } - ADD_STRING_VAL (nm_setting_802_1x_get_identity (setting), "identity", FALSE, FALSE, FALSE); - ADD_STRING_VAL (nm_setting_802_1x_get_anonymous_identity (setting), "anonymous_identity", FALSE, FALSE, FALSE); + value = nm_setting_802_1x_get_identity (setting); + if (!add_string_val (self, value, "identity", FALSE, FALSE)) + return FALSE; + value = nm_setting_802_1x_get_anonymous_identity (setting); + if (!add_string_val (self, value, "anonymous_identity", FALSE, FALSE)) + return FALSE; return TRUE; } +gboolean +nm_supplicant_config_add_no_security (NMSupplicantConfig *self) +{ + return nm_supplicant_config_add_option (self, "key_mgmt", "NONE", -1, FALSE); +} + +/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */ + +static int hex2num (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static int hex2byte (const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) + return -1; + b = hex2num(*hex++); + if (b < 0) + return -1; + return (a << 4) | b; +} + +static char * +hexstr2bin (const char *hex, size_t len) +{ + size_t i; + int a; + const char * ipos = hex; + char * buf = NULL; + char * opos; + + /* Length must be a multiple of 2 */ + if ((len % 2) != 0) + return NULL; + + opos = buf = g_malloc0 ((len / 2) + 1); + for (i = 0; i < len; i += 2) { + a = hex2byte (ipos); + if (a < 0) { + g_free (buf); + return NULL; + } + *opos++ = a; + ipos += 2; + } + return buf; +} + +/* End from hostap */ + diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h index 9fc8d71..dad23e2 100644 --- a/src/supplicant-manager/nm-supplicant-config.h +++ b/src/supplicant-manager/nm-supplicant-config.h @@ -50,25 +50,19 @@ typedef struct GType nm_supplicant_config_get_type (void); -NMSupplicantConfig * nm_supplicant_config_new (void); +NMSupplicantConfig *nm_supplicant_config_new (void); -guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig * self); +guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self); -void nm_supplicant_config_set_ap_scan (NMSupplicantConfig * self, +void nm_supplicant_config_set_ap_scan (NMSupplicantConfig *self, guint32 ap_scan); -gboolean nm_supplicant_config_add_option (NMSupplicantConfig *self, - const char * key, - const char * value, - gint32 len, - gboolean secret); +GHashTable *nm_supplicant_config_get_hash (NMSupplicantConfig *self); -GHashTable *nm_supplicant_config_get_hash (NMSupplicantConfig * self); +GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig *self); -GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig * self); - -gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, - NMSettingWireless * setting, +gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self, + NMSettingWireless *setting, gboolean is_broadcast, guint32 adhoc_freq, gboolean has_scan_capa_ssid, @@ -78,6 +72,8 @@ gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig NMSetting8021x *setting_8021x, const char *connection_uid); +gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self); + gboolean nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, NMSetting8021x *setting, const char *connection_uid, diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.h b/src/supplicant-manager/nm-supplicant-settings-verify.h index 8752b43..0939ebd 100644 --- a/src/supplicant-manager/nm-supplicant-settings-verify.h +++ b/src/supplicant-manager/nm-supplicant-settings-verify.h @@ -25,7 +25,8 @@ typedef enum OptType { TYPE_INVALID = 0, TYPE_INT, TYPE_BYTES, - TYPE_KEYWORD + TYPE_KEYWORD, + TYPE_STRING } OptType; OptType nm_supplicant_settings_verify_setting (const char * key, diff --git a/src/supplicant-manager/tests/Makefile.am b/src/supplicant-manager/tests/Makefile.am new file mode 100644 index 0000000..757f654 --- /dev/null +++ b/src/supplicant-manager/tests/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/libnm-util \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/supplicant-manager + +noinst_PROGRAMS = test-supplicant-config + +test_supplicant_config_SOURCES = \ + test-supplicant-config.c \ + nm-test-helpers.h + +test_supplicant_config_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) + +test_supplicant_config_LDADD = \ + $(DBUS_LIBS) \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(top_builddir)/src/supplicant-manager/libsupplicant-manager.la + +check-local: test-supplicant-config + $(abs_builddir)/test-supplicant-config + diff --git a/src/supplicant-manager/tests/nm-test-helpers.h b/src/supplicant-manager/tests/nm-test-helpers.h new file mode 100644 index 0000000..d0868b5 --- /dev/null +++ b/src/supplicant-manager/tests/nm-test-helpers.h @@ -0,0 +1,48 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams <dcbw@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2008 Red Hat, Inc. + */ + +#ifndef NM_TEST_HELPERS_H +#define NM_TEST_HELPERS_H + +#include <stdio.h> +#include <unistd.h> + +static void +FAIL(const char *test_name, const char *fmt, ...) +{ + va_list args; + char buf[500]; + + snprintf (buf, 500, "FAIL: (%s) %s\n", test_name, fmt); + + va_start (args, fmt); + vfprintf (stderr, buf, args); + va_end (args); + _exit (1); +} + +#define ASSERT(x, test_name, fmt, ...) \ + if (!(x)) { \ + FAIL (test_name, fmt, ## __VA_ARGS__); \ + } + +#endif /* NM_TEST_HELPERS_H */ + diff --git a/src/supplicant-manager/tests/test-supplicant-config.c b/src/supplicant-manager/tests/test-supplicant-config.c new file mode 100644 index 0000000..d0868b5 --- /dev/null +++ b/src/supplicant-manager/tests/test-supplicant-config.c @@ -0,0 +1,518 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2008 - 2009 Red Hat, Inc. + */ + +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <netinet/ether.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <dbus/dbus-glib.h> + +#include <nm-utils.h> +#include <nm-setting-connection.h> +#include <nm-setting-wired.h> +#include <nm-setting-wireless.h> +#include <nm-setting-wireless-security.h> +#include <nm-setting-ip4-config.h> +#include <nm-setting-8021x.h> + +#include "nm-test-helpers.h" + +#include "nm-supplicant-config.h" +#include "nm-supplicant-settings-verify.h" + +static gboolean +validate_opt (const char *detail, + GHashTable *hash, + const char *key, + OptType val_type, + gconstpointer expected, + size_t expected_len) +{ + GValue *value; + gint int_val; + GByteArray *array; + const char *s; + const unsigned char *expected_array = expected; + int result; + + ASSERT (hash != NULL, detail, "hash was NULL"); + + value = g_hash_table_lookup (hash, key); + ASSERT (value != NULL, + detail, "option '%s' expected but not found in config hash."); + + switch (val_type) { + case TYPE_INT: + ASSERT (G_VALUE_HOLDS_INT (value), + detail, "config hash item '%s' was not TYPE_INT.", key); + int_val = g_value_get_int (value); + ASSERT (int_val == GPOINTER_TO_INT (expected), + detail, "unexpected config hash item '%s' value %d (expected %d)", + key, int_val, GPOINTER_TO_INT (expected)); + break; + case TYPE_BYTES: + ASSERT (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY), + detail, "config hash item '%s' was not TYPE_BYTES.", key); + array = g_value_get_boxed (value); + ASSERT (array->len == expected_len, + detail, "unexpected config hash item '%s' length %d (expected %d)", + key, array->len, expected_len); + result = memcmp (array->data, expected_array, expected_len); + ASSERT (result == 0, detail, "unexpected config hash item '%s' value", key); + break; + case TYPE_KEYWORD: + case TYPE_STRING: + ASSERT (G_VALUE_HOLDS_STRING (value), + detail, "config hash item '%s' was not TYPE_STRING or TYPE_KEYWORD.", key); + if (expected_len == -1) + expected_len = strlen ((const char *) expected); + s = g_value_get_string (value); + ASSERT (s != NULL, detail, "unexpected NULL config hash string item '%s'.", key); + ASSERT (strlen (s) == expected_len, + detail, "unexpected config hash string item '%s' length %d (expected %d)", + key, strlen (s), expected_len); + result = strcmp (s, (const char *) expected); + ASSERT (result == 0, + detail, "unexpected config hash string item '%s' value '%s' (expected '%s')", + key, s, (const char *) expected); + break; + default: + g_warning ("unknown supplicant config hash item '%s' option type %d", + key, val_type); + return FALSE; + } + + return TRUE; +} + +static void +test_wifi_open (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + NMSettingIP4Config *s_ip4; + NMSupplicantConfig *config; + GHashTable *hash; + char *uuid; + gboolean success; + GError *error = NULL; + GByteArray *ssid; + const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 }; + GByteArray *bssid; + const unsigned char bssid_data[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + const char *bssid_str = "11:22:33:44:55:66"; + + connection = nm_connection_new (); + ASSERT (connection != NULL, + "wifi-open", "failed to allocate new connection"); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + ASSERT (s_con != NULL, + "wifi-open", "failed to allocate new %s setting", + NM_SETTING_CONNECTION_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Wifi Open", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + g_free (uuid); + + /* Wifi setting */ + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + ASSERT (s_wifi != NULL, + "wifi-open", "failed to allocate new %s setting", + NM_SETTING_WIRELESS_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + ssid = g_byte_array_sized_new (sizeof (ssid_data)); + g_byte_array_append (ssid, ssid_data, sizeof (ssid_data)); + bssid = g_byte_array_sized_new (sizeof (bssid_data)); + g_byte_array_append (bssid, bssid_data, sizeof (bssid_data)); + + g_object_set (s_wifi, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_BSSID, bssid, + NM_SETTING_WIRELESS_MODE, "infrastructure", + NM_SETTING_WIRELESS_BAND, "bg", + NULL); + + g_byte_array_free (ssid, TRUE); + g_byte_array_free (bssid, TRUE); + + /* IP4 setting */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + ASSERT (s_ip4 != NULL, + "wifi-open", "failed to allocate new %s setting", + NM_SETTING_IP4_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + + ASSERT (nm_connection_verify (connection, &error) == TRUE, + "wifi-open", "failed to verify connection: %s", + (error && error->message) ? error->message : "(unknown)"); + + config = nm_supplicant_config_new (); + ASSERT (config != NULL, + "wifi-open", "failed to create new supplicant config"); + + success = nm_supplicant_config_add_setting_wireless (config, s_wifi, TRUE, 0, TRUE, FALSE); + ASSERT (success == TRUE, + "wifi-open", "failed to add wireless setting to supplicant config."); + + success = nm_supplicant_config_add_no_security (config); + ASSERT (success == TRUE, + "wifi-open", "failed to add wireless security to supplicant config."); + + hash = nm_supplicant_config_get_hash (config); + ASSERT (hash != NULL, + "wifi-open", "failed to hash supplicant config options."); + + validate_opt ("wifi-open", hash, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1); + validate_opt ("wifi-open", hash, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data)); + validate_opt ("wifi-open", hash, "bssid", TYPE_KEYWORD, bssid_str, -1); + validate_opt ("wifi-open", hash, "key_mgmt", TYPE_KEYWORD, "NONE", -1); + + g_object_unref (connection); +} + +static void +test_wifi_wep_key (const char *detail, + NMWepKeyType wep_type, + const char *key_data, + const unsigned char *expected, + size_t expected_size) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + NMSettingWirelessSecurity *s_wsec; + NMSettingIP4Config *s_ip4; + NMSupplicantConfig *config; + GHashTable *hash; + char *uuid; + gboolean success; + GError *error = NULL; + GByteArray *ssid; + const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 }; + GByteArray *bssid; + const unsigned char bssid_data[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + const char *bssid_str = "11:22:33:44:55:66"; + + connection = nm_connection_new (); + ASSERT (connection != NULL, + detail, "failed to allocate new connection"); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + ASSERT (s_con != NULL, + detail, "failed to allocate new %s setting", + NM_SETTING_CONNECTION_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Wifi WEP Key", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + g_free (uuid); + + /* Wifi setting */ + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + ASSERT (s_wifi != NULL, + detail, "failed to allocate new %s setting", + NM_SETTING_WIRELESS_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + ssid = g_byte_array_sized_new (sizeof (ssid_data)); + g_byte_array_append (ssid, ssid_data, sizeof (ssid_data)); + bssid = g_byte_array_sized_new (sizeof (bssid_data)); + g_byte_array_append (bssid, bssid_data, sizeof (bssid_data)); + + g_object_set (s_wifi, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_BSSID, bssid, + NM_SETTING_WIRELESS_MODE, "infrastructure", + NM_SETTING_WIRELESS_BAND, "bg", + NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + NULL); + + g_byte_array_free (ssid, TRUE); + g_byte_array_free (bssid, TRUE); + + /* Wifi Security setting */ + s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); + ASSERT (s_wsec != NULL, + detail, "failed to allocate new %s setting", + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_wsec)); + + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, wep_type, + NULL); + nm_setting_wireless_security_set_wep_key (s_wsec, 0, key_data); + + /* IP4 setting */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + ASSERT (s_ip4 != NULL, + detail, "failed to allocate new %s setting", + NM_SETTING_IP4_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + + ASSERT (nm_connection_verify (connection, &error) == TRUE, + detail, "failed to verify connection: %s", + (error && error->message) ? error->message : "(unknown)"); + + config = nm_supplicant_config_new (); + ASSERT (config != NULL, + detail, "failed to create new supplicant config"); + + success = nm_supplicant_config_add_setting_wireless (config, s_wifi, TRUE, 0, TRUE, FALSE); + ASSERT (success == TRUE, + detail, "failed to add wireless setting to supplicant config."); + + success = nm_supplicant_config_add_setting_wireless_security (config, + s_wsec, + NULL, + "376aced7-b28c-46be-9a62-fcdf072571da"); + ASSERT (success == TRUE, + detail, "failed to add wireless security to supplicant config."); + + hash = nm_supplicant_config_get_hash (config); + ASSERT (hash != NULL, + detail, "failed to hash supplicant config options."); + + validate_opt (detail, hash, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1); + validate_opt (detail, hash, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data)); + validate_opt (detail, hash, "bssid", TYPE_KEYWORD, bssid_str, -1); + validate_opt (detail, hash, "key_mgmt", TYPE_KEYWORD, "NONE", -1); + validate_opt (detail, hash, "wep_tx_keyidx", TYPE_INT, GINT_TO_POINTER (0), -1); + validate_opt (detail, hash, "wep_key0", TYPE_BYTES, expected, expected_size); + + g_object_unref (connection); +} + +static void +test_wifi_wep (void) +{ + const char *key1 = "12345"; + const unsigned char key1_expected[] = { 0x31, 0x32, 0x33, 0x34, 0x35 }; + const char *key2 = "ascii test$$$"; + const unsigned char key2_expected[] = { 0x61, 0x73, 0x63, 0x69, 0x69, 0x20, 0x74, 0x65, 0x73, 0x74, 0x24, 0x24, 0x24 }; + const char *key3 = "abcdef1234"; + const unsigned char key3_expected[] = { 0xab, 0xcd, 0xef, 0x12, 0x34 }; + const char *key4 = "96aec785c6392675f87f592972"; + const unsigned char key4_expected[] = { 0x96, 0xae, 0xc7, 0x85, 0xc6, 0x39, 0x26, 0x75, 0xf8, 0x7f, 0x59, 0x29, 0x72 }; + const char *key5 = "r34lly l33t w3p p4ssphr4s3 for t3st1ng"; + const unsigned char key5_expected[] = { 0xce, 0x68, 0x8b, 0x35, 0xf6, 0x0a, 0x2b, 0xbf, 0xc9, 0x8f, 0xed, 0x10, 0xda }; + + test_wifi_wep_key ("wifi-wep-ascii-40", NM_WEP_KEY_TYPE_KEY, key1, key1_expected, sizeof (key1_expected)); + test_wifi_wep_key ("wifi-wep-ascii-104", NM_WEP_KEY_TYPE_KEY, key2, key2_expected, sizeof (key2_expected)); + test_wifi_wep_key ("wifi-wep-hex-40", NM_WEP_KEY_TYPE_KEY, key3, key3_expected, sizeof (key3_expected)); + test_wifi_wep_key ("wifi-wep-hex-104", NM_WEP_KEY_TYPE_KEY, key4, key4_expected, sizeof (key4_expected)); + test_wifi_wep_key ("wifi-wep-passphrase-104", NM_WEP_KEY_TYPE_PASSPHRASE, key5, key5_expected, sizeof (key5_expected)); + + test_wifi_wep_key ("wifi-wep-old-hex-104", NM_WEP_KEY_TYPE_UNKNOWN, key4, key4_expected, sizeof (key4_expected)); +} + +static void +test_wifi_wpa_psk (const char *detail, + OptType key_type, + const char *key_data, + const unsigned char *expected, + size_t expected_size) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + NMSettingWirelessSecurity *s_wsec; + NMSettingIP4Config *s_ip4; + NMSupplicantConfig *config; + GHashTable *hash; + char *uuid; + gboolean success; + GError *error = NULL; + GByteArray *ssid; + const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 }; + GByteArray *bssid; + const unsigned char bssid_data[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + const char *bssid_str = "11:22:33:44:55:66"; + + connection = nm_connection_new (); + ASSERT (connection != NULL, + detail, "failed to allocate new connection"); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + ASSERT (s_con != NULL, + detail, "failed to allocate new %s setting", + NM_SETTING_CONNECTION_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Wifi WEP Key", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + g_free (uuid); + + /* Wifi setting */ + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + ASSERT (s_wifi != NULL, + detail, "failed to allocate new %s setting", + NM_SETTING_WIRELESS_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + ssid = g_byte_array_sized_new (sizeof (ssid_data)); + g_byte_array_append (ssid, ssid_data, sizeof (ssid_data)); + bssid = g_byte_array_sized_new (sizeof (bssid_data)); + g_byte_array_append (bssid, bssid_data, sizeof (bssid_data)); + + g_object_set (s_wifi, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_BSSID, bssid, + NM_SETTING_WIRELESS_MODE, "infrastructure", + NM_SETTING_WIRELESS_BAND, "bg", + NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + NULL); + + g_byte_array_free (ssid, TRUE); + g_byte_array_free (bssid, TRUE); + + /* Wifi Security setting */ + s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); + ASSERT (s_wsec != NULL, + detail, "failed to allocate new %s setting", + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_wsec)); + + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_PSK, key_data, + NULL); + + nm_setting_wireless_security_add_proto (s_wsec, "wpa"); + nm_setting_wireless_security_add_proto (s_wsec, "rsn"); + nm_setting_wireless_security_add_pairwise (s_wsec, "tkip"); + nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp"); + nm_setting_wireless_security_add_group (s_wsec, "tkip"); + nm_setting_wireless_security_add_group (s_wsec, "ccmp"); + + /* IP4 setting */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + ASSERT (s_ip4 != NULL, + detail, "failed to allocate new %s setting", + NM_SETTING_IP4_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + + ASSERT (nm_connection_verify (connection, &error) == TRUE, + detail, "failed to verify connection: %s", + (error && error->message) ? error->message : "(unknown)"); + + config = nm_supplicant_config_new (); + ASSERT (config != NULL, + detail, "failed to create new supplicant config"); + + success = nm_supplicant_config_add_setting_wireless (config, s_wifi, TRUE, 0, TRUE, FALSE); + ASSERT (success == TRUE, + detail, "failed to add wireless setting to supplicant config."); + + success = nm_supplicant_config_add_setting_wireless_security (config, + s_wsec, + NULL, + "376aced7-b28c-46be-9a62-fcdf072571da"); + ASSERT (success == TRUE, + detail, "failed to add wireless security to supplicant config."); + + hash = nm_supplicant_config_get_hash (config); + ASSERT (hash != NULL, + detail, "failed to hash supplicant config options."); + + validate_opt (detail, hash, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1); + validate_opt (detail, hash, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data)); + validate_opt (detail, hash, "bssid", TYPE_KEYWORD, bssid_str, -1); + validate_opt (detail, hash, "key_mgmt", TYPE_KEYWORD, "WPA-PSK", -1); + validate_opt (detail, hash, "proto", TYPE_KEYWORD, "WPA RSN", -1); + validate_opt (detail, hash, "pairwise", TYPE_KEYWORD, "TKIP CCMP", -1); + validate_opt (detail, hash, "group", TYPE_KEYWORD, "TKIP CCMP", -1); + validate_opt (detail, hash, "psk", key_type, expected, expected_size); + + g_object_unref (connection); +} + +static void +test_wifi_wpa_psk_types (void) +{ + const char *key1 = "d4721e911461d3cdef9793858e977fcda091779243abb7316c2f11605a160893"; + const unsigned char key1_expected[] = { 0xd4, 0x72, 0x1e, 0x91, 0x14, 0x61, 0xd3, 0xcd, + 0xef, 0x97, 0x93, 0x85, 0x8e, 0x97, 0x7f, 0xcd, + 0xa0, 0x91, 0x77, 0x92, 0x43, 0xab, 0xb7, 0x31, + 0x6c, 0x2f, 0x11, 0x60, 0x5a, 0x16, 0x08, 0x93 }; + const char *key2 = "r34lly l33t wp4 p4ssphr4s3 for t3st1ng"; + + test_wifi_wpa_psk ("wifi-wpa-psk-hex", TYPE_BYTES, key1, key1_expected, sizeof (key1_expected)); + test_wifi_wpa_psk ("wifi-wep-psk-passphrase", TYPE_STRING, key2, (gconstpointer) key2, strlen (key2)); +} + +int main (int argc, char **argv) +{ + GError *error = NULL; + DBusGConnection *bus; + char *base; + + g_type_init (); + bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); + + if (!nm_utils_init (&error)) + FAIL ("nm-utils-init", "failed to initialize libnm-util: %s", error->message); + + /* The tests */ + test_wifi_open (); + test_wifi_wep (); + test_wifi_wpa_psk_types (); + + base = g_path_get_basename (argv[0]); + fprintf (stdout, "%s: SUCCESS\n", base); + g_free (base); + return 0; +} +