/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* * Mu Qiao * * 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) 1999-2010 Gentoo Foundation, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "net_utils.h" #include "wpa_parser.h" #include "connection_parser.h" #include "nm-ifnet-connection.h" static const char * get_prefix (void) { return _("System"); } static void update_connection_id (NMConnection * connection, gchar * conn_name) { gchar *idstr = NULL; gchar *uuid_base = NULL; gchar *uuid = NULL; NMSettingConnection *setting; idstr = g_strdup_printf ("%s (%s)", get_prefix (), conn_name); uuid_base = idstr; uuid = nm_utils_uuid_generate_from_string (uuid_base); setting = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); g_object_set (setting, NM_SETTING_CONNECTION_ID, idstr, NM_SETTING_CONNECTION_UUID, uuid, NULL); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "update_connection_setting_from_config_block: name:%s, id:%s, uuid: %s", conn_name, idstr, uuid); g_free (uuid); g_free (idstr); } static gboolean eap_simple_reader (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error); static gboolean eap_tls_reader (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error); static gboolean eap_peap_reader (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error); static gboolean eap_ttls_reader (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error); typedef struct { const char *method; gboolean (*reader) (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error); gboolean wifi_phase2_only; } EAPReader; static EAPReader eap_readers[] = { {"md5", eap_simple_reader, TRUE}, {"pap", eap_simple_reader, TRUE}, {"chap", eap_simple_reader, TRUE}, {"mschap", eap_simple_reader, TRUE}, {"mschapv2", eap_simple_reader, TRUE}, {"leap", eap_simple_reader, TRUE}, {"tls", eap_tls_reader, FALSE}, {"peap", eap_peap_reader, FALSE}, {"ttls", eap_ttls_reader, FALSE}, {NULL, NULL} }; /* reading identity and password */ static gboolean eap_simple_reader (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error) { char *value; /* identity */ value = wpa_get_value (ssid, "identity"); if (!value) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing IEEE_8021X_IDENTITY for EAP method '%s'.", eap_method); return FALSE; } g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL); /* password */ value = wpa_get_value (ssid, "password"); if (!value) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing IEEE_8021X_PASSWORD for EAP method '%s'.", eap_method); return FALSE; } g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL); return TRUE; } static gboolean eap_tls_reader (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error) { char *value; char *ca_cert = NULL; char *client_cert = NULL; char *privkey = NULL; char *privkey_password = NULL; gboolean success = FALSE; NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; /* identity */ value = wpa_get_value (ssid, "identity"); if (!value) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing IEEE_8021X_IDENTITY for EAP method '%s'.", eap_method); return FALSE; } g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL); /* ca cert */ ca_cert = wpa_get_value (ssid, phase2 ? "ca_cert2" : "ca_cert"); if (ca_cert) { if (phase2) { if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, ca_cert, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, error)) goto done; } else { if (!nm_setting_802_1x_set_ca_cert (s_8021x, ca_cert, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, error)) goto done; } } else { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: missing %s for EAP" " method '%s'; this is insecure!", phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT", eap_method); } /* Private key password */ privkey_password = wpa_get_value (ssid, phase2 ? "private_key_passwd2" : "private_key_passwd"); if (!privkey_password) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing %s for EAP method '%s'.", phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD" : "IEEE_8021X_PRIVATE_KEY_PASSWORD", eap_method); goto done; } /* The private key itself */ privkey = wpa_get_value (ssid, phase2 ? "private_key2" : "private_key"); if (!privkey) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing %s for EAP method '%s'.", phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY", eap_method); goto done; } if (phase2) { if (!nm_setting_802_1x_set_phase2_private_key (s_8021x, privkey, privkey_password, NM_SETTING_802_1X_CK_SCHEME_PATH, &privkey_format, error)) goto done; } else { if (!nm_setting_802_1x_set_private_key (s_8021x, privkey, privkey_password, NM_SETTING_802_1X_CK_SCHEME_PATH, &privkey_format, error)) goto done; } /* Only set the client certificate if the private key is not PKCS#12 format, * as NM (due to supplicant restrictions) requires. If the key was PKCS#12, * then nm_setting_802_1x_set_private_key() already set the client certificate * to the same value as the private key. */ if (privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) { client_cert = wpa_get_value (ssid, phase2 ? "client_cert2" : "client_cert"); if (!client_cert) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing %s for EAP method '%s'.", phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT", eap_method); goto done; } if (phase2) { if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, client_cert, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, error)) goto done; } else { if (!nm_setting_802_1x_set_client_cert (s_8021x, client_cert, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, error)) goto done; } } success = TRUE; done: return success; } static gboolean eap_peap_reader (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error) { char *ca_cert = NULL; char *inner_auth = NULL; char *peapver = NULL; char *lower; char **list = NULL, **iter; gboolean success = FALSE; ca_cert = wpa_get_value (ssid, "ca_cert"); if (ca_cert) { if (!nm_setting_802_1x_set_ca_cert (s_8021x, ca_cert, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, error)) goto done; } else { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: missing " "IEEE_8021X_CA_CERT for EAP method '%s'; this is" " insecure!", eap_method); } peapver = wpa_get_value (ssid, "phase1"); /* peap version, default is automatic */ if (peapver && strstr (peapver, "peapver")) { if (strstr (peapver, "peapver=0")) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL); else if (strstr (peapver, "peapver=1")) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL); else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Unknown IEEE_8021X_PEAP_VERSION value '%s'", peapver); goto done; } } /* peaplabel */ if (peapver && strstr (peapver, "peaplabel=1")) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL); inner_auth = wpa_get_value (ssid, "phase2"); if (!inner_auth) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing IEEE_8021X_INNER_AUTH_METHODS."); goto done; } /* Handle options for the inner auth method */ list = g_strsplit (inner_auth, " ", 0); for (iter = list; iter && *iter; iter++) { gchar *pos = NULL; if (!strlen (*iter)) continue; if (!(pos = strstr (*iter, "MSCHAPV2")) || !(pos = strstr (*iter, "MD5")) || !(pos = strstr (*iter, "GTC"))) { if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, error)) goto done; } else if (!(pos = strstr (*iter, "TLS"))) { if (!eap_tls_reader (pos, ssid, s_8021x, TRUE, error)) goto done; } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", *iter); goto done; } pos = strchr (*iter, '='); pos++; lower = g_ascii_strdown (pos, -1); g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL); g_free (lower); break; } if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "No valid IEEE_8021X_INNER_AUTH_METHODS found."); goto done; } success = TRUE; done: if (list) g_strfreev (list); return success; } static gboolean eap_ttls_reader (const char *eap_method, gchar * ssid, NMSetting8021x * s_8021x, gboolean phase2, GError ** error) { gboolean success = FALSE; char *anon_ident = NULL; char *ca_cert = NULL; char *tmp; char **list = NULL, **iter; char *inner_auth = NULL; /* ca cert */ ca_cert = wpa_get_value (ssid, "ca_cert"); if (ca_cert) { if (!nm_setting_802_1x_set_ca_cert (s_8021x, ca_cert, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, error)) goto done; } else { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: missing " "IEEE_8021X_CA_CERT for EAP method '%s'; this is" " insecure!", eap_method); } /* anonymous indentity for tls */ anon_ident = wpa_get_value (ssid, "anonymous_identity"); if (anon_ident && strlen (anon_ident)) g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL); tmp = wpa_get_value (ssid, "phase2"); if (!tmp) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing IEEE_8021X_INNER_AUTH_METHODS."); goto done; } /* Handle options for the inner auth method */ inner_auth = g_ascii_strdown (tmp, -1); list = g_strsplit (inner_auth, " ", 0); for (iter = list; iter && *iter; iter++) { gchar *pos = NULL; if (!strlen (*iter)) continue; if ((pos = strstr (*iter, "mschapv2")) != NULL || (pos = strstr (*iter, "mschap")) != NULL || (pos = strstr (*iter, "pap")) != NULL || (pos = strstr (*iter, "chap")) != NULL) { if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, error)) goto done; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, pos, NULL); } else if ((pos = strstr (*iter, "tls")) != NULL) { if (!eap_tls_reader (pos, ssid, s_8021x, TRUE, error)) goto done; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL); } else if ((pos = strstr (*iter, "mschapv2")) != NULL || (pos = strstr (*iter, "md5")) != NULL) { if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, error)) { PLUGIN_WARN (IFNET_PLUGIN_NAME, "SIMPLE ERROR"); goto done; } g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, pos, NULL); } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", *iter); goto done; } break; } success = TRUE; done: if (list) g_strfreev (list); if (inner_auth) g_free (inner_auth); return success; } /* type is already decided by net_parser, this function is just used to * doing tansformation*/ static const gchar * guess_connection_type (gchar * conn_name) { const gchar *type = ifnet_get_data (conn_name, "type"); const gchar *name = conn_name; const gchar *ret_type = NULL; if (name && !strcmp ("ppp", type)) ret_type = NM_SETTING_PPPOE_SETTING_NAME; if (name && !strcmp ("wireless", type)) ret_type = NM_SETTING_WIRELESS_SETTING_NAME; if (!ret_type) ret_type = NM_SETTING_WIRED_SETTING_NAME; PLUGIN_PRINT (IFNET_PLUGIN_NAME, "guessed connection type (%s) = %s", name, ret_type); return ret_type; } /* Reading mac address for setting connection option. * Unmanaged device mac address is required by NetworkManager*/ static gboolean read_mac_address (gchar * conn_name, GByteArray ** array, GError ** error) { gchar *value = ifnet_get_data (conn_name, "mac"); struct ether_addr *mac; if (!value || !strlen (value)) { return TRUE; } mac = ether_aton (value); if (!mac) { g_set_error (error, ifnet_plugin_error_quark (), 0, "The MAC address '%s' was invalid.", value); return FALSE; } *array = g_byte_array_sized_new (ETH_ALEN); g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN); return TRUE; } static void make_wired_connection_setting (NMConnection * connection, gchar * conn_name, GError ** error) { GByteArray *mac = NULL; NMSettingWired *s_wired = NULL; gchar *value = NULL; s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); /* mtu_xxx */ value = ifnet_get_data (conn_name, "mtu"); if (value) { long int mtu; errno = 0; mtu = strtol (value, NULL, 10); if (errno || mtu < 0 || mtu > 65535) { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: invalid MTU '%s' for %s", value, conn_name); } else g_object_set (s_wired, NM_SETTING_WIRED_MTU, (guint32) mtu, NULL); } if (read_mac_address (conn_name, &mac, error)) { if (mac) { g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL); g_byte_array_free (mac, TRUE); } } else { g_object_unref (s_wired); s_wired = NULL; } if (s_wired) nm_connection_add_setting (connection, NM_SETTING (s_wired)); } /* add NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, * NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID in future*/ static void make_ip4_setting (NMConnection * connection, gchar * conn_name, GError ** error) { NMSettingIP4Config *ip4_setting = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ()); gchar *value; gboolean is_static_block = is_static_ip4 (conn_name); ip_block *iblock = NULL; /* set dhcp options (dhcp_xxx) */ value = ifnet_get_data (conn_name, "dhcp"); g_object_set (ip4_setting, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, value && strstr (value, "nodns") ? TRUE : FALSE, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, value && strstr (value, "nogateway") ? TRUE : FALSE, NULL); if (!is_static_block) { g_object_set (ip4_setting, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, FALSE, NULL); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Using DHCP for %s", conn_name); } else { iblock = convert_ip4_config_block (conn_name); if (!iblock) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Ifnet plugin: can't aquire ip configuration for %s", conn_name); g_object_unref (ip4_setting); return; } /************** add all ip settings to the connection**********/ while (iblock) { ip_block *current_iblock; NMIP4Address *ip4_addr = nm_ip4_address_new (); nm_ip4_address_set_address (ip4_addr, iblock->ip); nm_ip4_address_set_prefix (ip4_addr, nm_utils_ip4_netmask_to_prefix (iblock->netmask)); /* currently all the IPs has the same gateway */ nm_ip4_address_set_gateway (ip4_addr, iblock->gateway); if (iblock->gateway) g_object_set (ip4_setting, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, TRUE, NULL); if (nm_setting_ip4_config_add_address (ip4_setting, ip4_addr)) { PLUGIN_PRINT (IFNET_PLUGIN_NAME, "new address: %d", iblock->ip); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "ipv4 addresses count: %d", nm_setting_ip4_config_get_num_addresses (ip4_setting)); } else { PLUGIN_WARN (IFNET_PLUGIN_NAME, "ignoring duplicate IP4 address"); } nm_ip4_address_unref (ip4_addr); current_iblock = iblock; iblock = iblock->next; destroy_ip_block (current_iblock); } g_object_set (ip4_setting, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, !has_default_ip4_route (conn_name), NULL); } /* add dhcp hostname and client id */ if (!is_static_block) { gchar *dhcp_hostname, *client_id; get_dhcp_hostname_and_client_id (&dhcp_hostname, &client_id); if (dhcp_hostname) { g_object_set (ip4_setting, NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, dhcp_hostname, NULL); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "DHCP hostname: %s", dhcp_hostname); g_free (dhcp_hostname); } if (client_id) { g_object_set (ip4_setting, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, client_id, NULL); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "DHCP client id: %s", client_id); g_free (client_id); } } /* add all IPv4 dns servers, IPv6 servers will be ignored */ set_ip4_dns_servers (ip4_setting, conn_name); /* DNS searches */ value = (gchar *) ifnet_get_data (conn_name, "dns_search"); if (value) { char **searches = NULL; strip_string (value, '"'); searches = g_strsplit (value, " ", 0); if (searches) { char **item; for (item = searches; *item; item++) { if (strlen (*item)) { if (!nm_setting_ip4_config_add_dns_search (ip4_setting, *item)) PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: duplicate DNS domain '%s'", *item); } } g_strfreev (searches); } } /* static routes */ iblock = convert_ip4_routes_block (conn_name); while (iblock) { ip_block *current_iblock = iblock; gchar *metric_str; long int metric; NMIP4Route *route = nm_ip4_route_new (); nm_ip4_route_set_dest (route, iblock->ip); nm_ip4_route_set_next_hop (route, iblock->gateway); nm_ip4_route_set_prefix (route, nm_utils_ip4_netmask_to_prefix (iblock->netmask)); if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL) { metric = strtol (metric_str, NULL, 10); nm_ip4_route_set_metric (route, (guint32) metric); } else { metric_str = ifnet_get_global_data ("metric"); if (metric_str) { metric = strtol (metric_str, NULL, 10); nm_ip4_route_set_metric (route, (guint32) metric); g_free (metric_str); } } if (!nm_setting_ip4_config_add_route (ip4_setting, route)) PLUGIN_WARN (IFNET_PLUGIN_NAME, "warning: duplicate IP4 route"); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "new IP4 route:%d\n", iblock->ip); nm_ip4_route_unref (route); current_iblock = iblock; iblock = iblock->next; destroy_ip_block (current_iblock); } /* Finally add setting to connection */ nm_connection_add_setting (connection, NM_SETTING (ip4_setting)); } static void make_ip6_setting (NMConnection * connection, gchar * conn_name, GError ** error) { NMSettingIP6Config *s_ip6 = NULL; gboolean is_static_block = is_static_ip6 (conn_name); // used to disable IPv6 gboolean ipv6_enabled = FALSE; gchar *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; gchar *value; ip6_block *iblock; gboolean never_default = !has_default_ip6_route (conn_name); s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); if (!s_ip6) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Could not allocate IP6 setting"); return; } value = ifnet_get_data (conn_name, "enable_ipv6"); if (value && is_true (value)) ipv6_enabled = TRUE; //FIXME Handle other methods that NM supports in future // Currently only Manual and DHCP are supported if (!ipv6_enabled) { g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); goto done; } else if (!is_static_block) { // config_eth* contains "dhcp6" method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; never_default = FALSE; } // else if (!has_ip6_address(conn_name)) // doesn't have "dhcp6" && doesn't have any ipv6 address // method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; else // doesn't have "dhcp6" && has at least one ipv6 address method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; PLUGIN_PRINT (IFNET_PLUGIN_NAME, "IPv6 for %s enabled, using %s", conn_name, method); g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, method, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, FALSE, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, FALSE, NM_SETTING_IP6_CONFIG_NEVER_DEFAULT, never_default, NULL); /* Make manual settings */ if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { ip6_block *current_iblock; iblock = convert_ip6_config_block (conn_name); if (!iblock) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Ifnet plugin: can't aquire ip6 configuration for %s", conn_name); goto error; } /* add all IPv6 addresses */ while (iblock) { NMIP6Address *ip6_addr = nm_ip6_address_new (); nm_ip6_address_set_address (ip6_addr, iblock->ip); nm_ip6_address_set_prefix (ip6_addr, iblock->prefix); if (nm_setting_ip6_config_add_address (s_ip6, ip6_addr)) { PLUGIN_PRINT (IFNET_PLUGIN_NAME, "ipv6 addresses count: %d", nm_setting_ip6_config_get_num_addresses (s_ip6)); } else { PLUGIN_WARN (IFNET_PLUGIN_NAME, "ignoring duplicate IP4 address"); } nm_ip6_address_unref (ip6_addr); current_iblock = iblock; iblock = iblock->next; destroy_ip6_block (current_iblock); } } else if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { /* - autoconf or DHCPv6 stuff goes here */ } // DNS Servers, set NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS TRUE here set_ip6_dns_servers (s_ip6, conn_name); /* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIP4Config */ // Add routes iblock = convert_ip6_routes_block (conn_name); if (iblock) g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, TRUE, NULL); /* Add all IPv6 routes */ while (iblock) { ip6_block *current_iblock = iblock; gchar *metric_str; long int metric = 1; NMIP6Route *route = nm_ip6_route_new (); nm_ip6_route_set_dest (route, iblock->ip); nm_ip6_route_set_next_hop (route, iblock->next_hop); nm_ip6_route_set_prefix (route, iblock->prefix); /* metric is not per routes configuration right now * global metric is also supported (metric="x") */ if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL) { metric = strtol (metric_str, NULL, 10); nm_ip6_route_set_metric (route, (guint32) metric); } else { metric_str = ifnet_get_global_data ("metric"); if (metric_str) { metric = strtol (metric_str, NULL, 10); nm_ip6_route_set_metric (route, (guint32) metric); g_free (metric_str); } else nm_ip6_route_set_metric (route, (guint32) 1); } if (!nm_setting_ip6_config_add_route (s_ip6, route)) PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: duplicate IP6 route"); PLUGIN_PRINT (IFNET_PLUGIN_NAME, " info: new IP6 route"); nm_ip6_route_unref (route); current_iblock = iblock; iblock = iblock->next; destroy_ip6_block (current_iblock); } done: nm_connection_add_setting (connection, NM_SETTING (s_ip6)); return; error: g_object_unref (s_ip6); PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: Ignore IPv6 for %s", conn_name); return; } static NMSetting * make_wireless_connection_setting (gchar * conn_name, NMSetting8021x ** s_8021x, GError ** error) { GByteArray *array, *mac = NULL; NMSettingWireless *wireless_setting = NULL; gboolean adhoc = FALSE; gchar *value; gchar *type; /* PPP over WIFI is not supported */ g_return_val_if_fail (conn_name != NULL && strcmp (ifnet_get_data (conn_name, "type"), "ppp") != 0, NULL); type = ifnet_get_data (conn_name, "type"); if (strcmp (type, "ppp") == 0) { PLUGIN_WARN (IFNET_PLUGIN_NAME, "PPP over WIFI is not supported yet"); return NULL; } wireless_setting = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); if (read_mac_address (conn_name, &mac, error)) { if (mac) { g_object_set (wireless_setting, NM_SETTING_WIRELESS_MAC_ADDRESS, mac, NULL); g_byte_array_free (mac, TRUE); } } else { g_object_unref (wireless_setting); return NULL; } /* handle ssid (hex and ascii) */ if (conn_name) { gsize ssid_len = 0, value_len = strlen (conn_name); char *p = conn_name, *tmp; char buf[33]; ssid_len = value_len; if ((value_len > 2) && (g_str_has_prefix (conn_name, "0x"))) { /* Hex representation */ if (value_len % 2) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid SSID '%s' size (looks like hex but length not multiple of 2)", conn_name); goto error; } // ignore "0x" p = conn_name + 2; if (!is_hex (p)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid SSID '%s' character (looks like hex SSID but '%c' isn't a hex digit)", conn_name, *p); goto error; } tmp = utils_hexstr2bin (conn_name + 2, value_len - 2); ssid_len = (value_len - 2) / 2; memcpy (buf, tmp, ssid_len); g_free (tmp); p = &buf[0]; } if (ssid_len > 32 || ssid_len == 0) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)", conn_name, ssid_len); goto error; } array = g_byte_array_sized_new (ssid_len); g_byte_array_append (array, (const guint8 *) p, ssid_len); g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, array, NULL); g_byte_array_free (array, TRUE); } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing SSID"); goto error; } /* mode=0: infrastructure * mode=1: adhoc */ value = wpa_get_value (conn_name, "mode"); if (value) adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE; if (exist_ssid (conn_name)) { const char *mode = adhoc ? "adhoc" : "infrastructure"; g_object_set (wireless_setting, NM_SETTING_WIRELESS_MODE, mode, NULL); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Using mode: %s", mode); } /* BSSID setting */ value = wpa_get_value (conn_name, "bssid"); if (value) { struct ether_addr *eth; GByteArray *bssid; eth = ether_aton (value); if (!eth) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid BSSID '%s'", value); goto error; } bssid = g_byte_array_sized_new (ETH_ALEN); g_byte_array_append (bssid, eth->ether_addr_octet, ETH_ALEN); g_object_set (wireless_setting, NM_SETTING_WIRELESS_BSSID, bssid, NULL); g_byte_array_free (bssid, TRUE); } /* mtu_ssid="xx" */ value = ifnet_get_data (conn_name, "mtu"); if (value) { long int mtu; errno = 0; mtu = strtol (value, NULL, 10); if (errno || mtu < 0 || mtu > 50000) { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: invalid MTU '%s' for %s", value, conn_name); } else g_object_set (wireless_setting, NM_SETTING_WIRELESS_MTU, (guint32) mtu, NULL); } PLUGIN_PRINT (IFNET_PLUGIN_NAME, "wireless_setting added for %s", conn_name); return NM_SETTING (wireless_setting); error: if (wireless_setting) g_object_unref (wireless_setting); return NULL; } static NMSettingWirelessSecurity * make_leap_setting (gchar * ssid, GError ** error) { NMSettingWirelessSecurity *wsec; char *value; wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); value = wpa_get_value (ssid, "key_mgmt"); if (!value || strcmp (value, "IEEE8021X")) goto error; /* Not LEAP */ value = wpa_get_value (ssid, "eap"); if (!value || strcasecmp (value, "LEAP")) goto error; /* Not LEAP */ value = wpa_get_value (ssid, "password"); if (value && strlen (value)) g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, value, NULL); value = wpa_get_value (ssid, "identity"); if (!value || !strlen (value)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing LEAP identity"); goto error; } g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value, NULL); g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", NULL); return wsec; error: if (wsec) g_object_unref (wsec); return NULL; } static gboolean add_one_wep_key (gchar * ssid, gchar * key, int key_idx, NMSettingWirelessSecurity * s_wsec, GError ** error) { gchar *value; gboolean success = FALSE; g_return_val_if_fail (ssid != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (key_idx >= 0 && key_idx <= 3, FALSE); g_return_val_if_fail (s_wsec != NULL, FALSE); value = wpa_get_value (ssid, key); if (!value) return TRUE; key = NULL; /* Validate keys */ if (strlen (value) == 10 || strlen (value) == 26) { /* Hexadecimal WEP key */ char *p = value; if (!is_hex (p)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid hexadecimal WEP key."); goto out; } key = g_strdup (value); } else if (value[0] == '"' && (strlen (value) == 7 || strlen (value) == 15)) { /* ASCII passphrase */ char *tmp = g_strdup (value); char *p = strip_string (tmp, '"'); if (!is_ascii (p)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid ASCII WEP passphrase."); g_free (tmp); goto out; } key = utils_bin2hexstr (tmp, strlen (tmp), strlen (tmp) * 2); g_free (tmp); } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid WEP key length. Key: %s", value); goto out; } if (key) { nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); g_free (key); success = TRUE; } out: return success; } static gboolean add_wep_keys (gchar * ssid, NMSettingWirelessSecurity * s_wsec, GError ** error) { if (!add_one_wep_key (ssid, "wep_key0", 0, s_wsec, error)) return FALSE; if (!add_one_wep_key (ssid, "wep_key1", 1, s_wsec, error)) return FALSE; if (!add_one_wep_key (ssid, "wep_key2", 2, s_wsec, error)) return FALSE; if (!add_one_wep_key (ssid, "wep_key3", 3, s_wsec, error)) return FALSE; return TRUE; } static NMSettingWirelessSecurity * make_wep_setting (gchar * ssid, GError ** error) { gchar *auth_alg; int default_key_idx = 0; gchar *value; NMSettingWirelessSecurity *s_wireless_sec; s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL); /* default key index */ value = wpa_get_value (ssid, "wep_tx_keyidx"); if (value) { default_key_idx = atoi (value); if (default_key_idx >= 0 && default_key_idx <= 3) { g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, default_key_idx, NULL); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Default key index: %d", default_key_idx); } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid default WEP key '%s'", value); goto error; } } if (!add_wep_keys (ssid, s_wireless_sec, error)) goto error; /* If there's a default key, ensure that key exists */ if ((default_key_idx == 1) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Default WEP key index was 2, but no valid KEY2 exists."); goto error; } else if ((default_key_idx == 2) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Default WEP key index was 3, but no valid KEY3 exists."); goto error; } else if ((default_key_idx == 3) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Default WEP key index was 4, but no valid KEY4 exists."); goto error; } /* authentication algorithms */ auth_alg = wpa_get_value (ssid, "auth_alg"); if (auth_alg) { if (strcmp (auth_alg, "OPEN") == 0) { g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "WEP: Use open system authentication"); } else if (strcmp (auth_alg, "SHARED") == 0) { g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "WEP: Use shared system authentication"); } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid WEP authentication algorithm '%s'", auth_alg); goto error; } } if (!nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2) && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3) && !nm_setting_wireless_security_get_wep_tx_keyidx (s_wireless_sec)) { if (auth_alg && !strcmp (auth_alg, "shared")) { g_set_error (error, ifnet_plugin_error_quark (), 0, "WEP Shared Key authentication is invalid for " "unencrypted connections."); goto error; } /* Unencrypted */ g_object_unref (s_wireless_sec); s_wireless_sec = NULL; } return s_wireless_sec; error: if (s_wireless_sec) g_object_unref (s_wireless_sec); return NULL; } static char * parse_wpa_psk (gchar * psk, GError ** error) { gchar *p, *hashed = NULL; gboolean quoted = FALSE; if (!psk) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing WPA_PSK for WPA-PSK key management"); return NULL; } /* Passphrase must be between 10 and 66 characters in length becuase WPA * hex keys are exactly 64 characters (no quoting), and WPA passphrases * are between 8 and 63 characters (inclusive), plus optional quoting if * the passphrase contains spaces. */ p = psk; if (p[0] == '"' && psk[strlen (psk) - 1] == '"') quoted = TRUE; if (!quoted && (strlen (psk) == 64)) { /* Verify the hex PSK; 64 digits */ if (!is_hex (p)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid WPA_PSK (contains non-hexadecimal characters)"); goto out; } hashed = g_strdup (psk); } else { strip_string (p, '"'); /* Length check */ if (strlen (p) < 8 || strlen (p) > 63) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid WPA_PSK (passphrases must be between " "8 and 63 characters long (inclusive))"); goto out; } hashed = g_strdup (p); } if (!hashed) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid WPA_PSK (doesn't look like a passphrase or hex key)"); goto out; } out: return hashed; } static gboolean fill_wpa_ciphers (gchar * ssid, NMSettingWirelessSecurity * wsec, gboolean group, gboolean adhoc) { char *value = NULL, *p; char **list = NULL, **iter; int i = 0; p = value = wpa_get_value (ssid, group ? "group" : "pairwise"); if (!value) return TRUE; list = g_strsplit_set (p, " ", 0); for (iter = list; iter && *iter; iter++, i++) { /* Ad-Hoc configurations cannot have pairwise ciphers, and can only * have one group cipher. Ignore any additional group ciphers and * any pairwise ciphers specified. */ if (adhoc) { if (group && (i > 0)) { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: ignoring group cipher '%s' (only one group cipher allowed in Ad-Hoc mode)", *iter); continue; } else if (!group) { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: ignoring pairwise cipher '%s' (pairwise not used in Ad-Hoc mode)", *iter); continue; } } if (!strcmp (*iter, "CCMP")) { if (group) nm_setting_wireless_security_add_group (wsec, "ccmp"); else nm_setting_wireless_security_add_pairwise (wsec, "ccmp"); } else if (!strcmp (*iter, "TKIP")) { if (group) nm_setting_wireless_security_add_group (wsec, "tkip"); else nm_setting_wireless_security_add_pairwise (wsec, "tkip"); } else if (group && !strcmp (*iter, "WEP104")) nm_setting_wireless_security_add_group (wsec, "wep104"); else if (group && !strcmp (*iter, "WEP40")) nm_setting_wireless_security_add_group (wsec, "wep40"); else { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: ignoring invalid %s cipher '%s'", group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", *iter); } } if (list) g_strfreev (list); return TRUE; } static NMSetting8021x * fill_8021x (gchar * ssid, gchar * key_mgmt, gboolean wifi, GError ** error) { NMSetting8021x *s_8021x; char *value; char **list, **iter; value = wpa_get_value (ssid, "eap"); if (!value) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing IEEE_8021X_EAP_METHODS for key management '%s'", key_mgmt); return NULL; } list = g_strsplit (value, " ", 0); s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); /* Validate and handle each EAP method */ for (iter = list; iter && *iter; iter++) { EAPReader *eap = &eap_readers[0]; gboolean found = FALSE; char *lower = NULL; lower = g_ascii_strdown (*iter, -1); while (eap->method && !found) { if (strcmp (eap->method, lower)) goto next; /* Some EAP methods don't provide keying material, thus they * cannot be used with WiFi unless they are an inner method * used with TTLS or PEAP or whatever. */ if (wifi && eap->wifi_phase2_only) { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: ignored invalid " "IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.", lower); goto next; } /* Parse EAP method specific options */ if (!(*eap->reader) (lower, ssid, s_8021x, FALSE, error)) { g_free (lower); goto error; } nm_setting_802_1x_add_eap_method (s_8021x, lower); found = TRUE; next: eap++; } if (!found) { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: ignored unknown" "IEEE_8021X_EAP_METHOD '%s'.", lower); } g_free (lower); } g_strfreev (list); if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) { g_set_error (error, ifnet_plugin_error_quark (), 0, "No valid EAP methods found in IEEE_8021X_EAP_METHODS."); goto error; } return s_8021x; error: g_object_unref (s_8021x); return NULL; } static NMSettingWirelessSecurity * make_wpa_setting (gchar * ssid, NMSetting8021x ** s_8021x, GError ** error) { NMSettingWirelessSecurity *wsec; char *value, *lower; gboolean adhoc = FALSE; if (!exist_ssid (ssid)) { g_set_error (error, ifnet_plugin_error_quark (), 0, "No security info found for ssid: %s", ssid); return NULL; } wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); /* mode=1: adhoc * mode=0: infrastructure */ value = wpa_get_value (ssid, "mode"); if (value) adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE; value = wpa_get_value (ssid, "key_mgmt"); /* Not WPA or Dynamic WEP */ if (!value) goto error; if (strcmp (value, "WPA-PSK") && strcmp (value, "WPA-EAP")) goto error; /* Pairwise and Group ciphers */ fill_wpa_ciphers (ssid, wsec, FALSE, adhoc); fill_wpa_ciphers (ssid, wsec, TRUE, adhoc); /* WPA and/or RSN */ if (adhoc) { /* Ad-Hoc mode only supports WPA proto for now */ nm_setting_wireless_security_add_proto (wsec, "wpa"); } else { nm_setting_wireless_security_add_proto (wsec, "wpa"); nm_setting_wireless_security_add_proto (wsec, "rsn"); } if (!strcmp (value, "WPA-PSK")) { gchar *psk = parse_wpa_psk (wpa_get_value (ssid, "psk"), error); if (!psk) goto error; g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL); g_free (psk); if (adhoc) g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL); else g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL); } else if (!strcmp (value, "WPA-EAP") || !strcmp (value, "IEEE8021X")) { if (adhoc) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'", value); goto error; } *s_8021x = fill_8021x (ssid, value, TRUE, error); if (!*s_8021x) goto error; lower = g_ascii_strdown (value, -1); g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL); g_free (lower); } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Unknown wireless KEY_MGMT type '%s'", value); goto error; } return wsec; error: if (wsec) g_object_unref (wsec); return NULL; } static NMSettingWirelessSecurity * make_wireless_security_setting (gchar * conn_name, NMSetting8021x ** s_8021x, GError ** error) { NMSettingWirelessSecurity *wsec = NULL; gchar *ssid; gboolean adhoc = FALSE; gchar *value; g_return_val_if_fail (conn_name != NULL && strcmp (ifnet_get_data (conn_name, "type"), "ppp") != 0, NULL); if (!wpa_get_value (conn_name, "ssid")) return NULL; PLUGIN_PRINT (IFNET_PLUGIN_NAME, "updating wireless security settings (%s).", conn_name); ssid = conn_name; value = wpa_get_value (ssid, "mode"); if (value) adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE; if (!adhoc) { wsec = make_leap_setting (ssid, error); if (error && *error) goto error; } if (!wsec) { wsec = make_wpa_setting (ssid, s_8021x, error); if (error && *error) goto error; } if (!wsec) { wsec = make_wep_setting (ssid, error); if (error && *error) goto error; } if (!wsec) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Can't handle security information for ssid: %s", conn_name); } return wsec; error: return NULL; } /* Currently only support username and password */ static void make_pppoe_connection_setting (NMConnection * connection, gchar * conn_name, GError ** error) { NMSettingPPPOE *s_pppoe; NMSettingPPP *s_ppp; gchar *value; s_pppoe = NM_SETTING_PPPOE (nm_setting_pppoe_new ()); /* username */ value = ifnet_get_data (conn_name, "username"); if (!value) { g_set_error (error, ifnet_plugin_error_quark (), 0, "ppp requires at lease a username"); return; } g_object_set (s_pppoe, NM_SETTING_PPPOE_USERNAME, value, NULL); /* password */ value = ifnet_get_data (conn_name, "password"); if (!value) { value = ""; } g_object_set (s_pppoe, NM_SETTING_PPPOE_PASSWORD, value, NULL); nm_connection_add_setting (connection, NM_SETTING (s_pppoe)); /* PPP setting */ s_ppp = (NMSettingPPP *) nm_setting_ppp_new (); nm_connection_add_setting (connection, NM_SETTING (s_ppp)); } NMConnection * ifnet_update_connection_from_config_block (gchar * conn_name, GError ** error) { const gchar *type = NULL; NMConnection *connection = NULL; NMSettingConnection *setting = NULL; NMSetting8021x *s_8021x = NULL; NMSettingWirelessSecurity *wsec = NULL; gboolean auto_conn = TRUE; gchar *value = NULL; gboolean success = FALSE; connection = nm_connection_new (); if (!connection) return NULL; setting = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); if (!setting) { setting = NM_SETTING_CONNECTION (nm_setting_connection_new ()); g_assert (setting); nm_connection_add_setting (connection, NM_SETTING (setting)); } type = guess_connection_type (conn_name); value = ifnet_get_data (conn_name, "auto"); if (value && !strcmp (value, "false")) auto_conn = FALSE; update_connection_id (connection, conn_name); g_object_set (setting, NM_SETTING_CONNECTION_TYPE, type, NM_SETTING_CONNECTION_READ_ONLY, FALSE, NM_SETTING_CONNECTION_AUTOCONNECT, auto_conn, NULL); if (!strcmp (NM_SETTING_WIRED_SETTING_NAME, type) || !strcmp (NM_SETTING_PPPOE_SETTING_NAME, type)) { /* wired setting */ make_wired_connection_setting (connection, conn_name, error); if (error && *error) { PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message); goto error; } /* pppoe setting */ if (!strcmp (NM_SETTING_PPPOE_SETTING_NAME, type)) make_pppoe_connection_setting (connection, conn_name, error); if (error && *error) { PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message); goto error; } } else if (!strcmp (NM_SETTING_WIRELESS_SETTING_NAME, type)) { /* wireless setting */ NMSetting *wireless_setting = make_wireless_connection_setting (conn_name, &s_8021x, error); if (!wireless_setting) { goto error; } nm_connection_add_setting (connection, wireless_setting); if (error && *error) { PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message); goto error; } /* wireless security setting */ wsec = make_wireless_security_setting (conn_name, &s_8021x, error); if (wsec) { nm_connection_add_setting (connection, NM_SETTING (wsec)); if (s_8021x) nm_connection_add_setting (connection, NM_SETTING (s_8021x)); g_object_set (wireless_setting, NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NULL); } if (error && *error) { PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message); goto error; } } else goto error; /* IPv4 setting */ make_ip4_setting (connection, conn_name, error); if (error && *error) PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message); /* IPv6 setting */ make_ip6_setting (connection, conn_name, error); if (error && *error) PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message); success = nm_connection_verify (connection, error); if (error && *error) PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Connection verified %s:%d", conn_name, success); if (!success) goto error; return connection; error: g_object_unref (setting); g_object_unref (connection); return NULL; } typedef NMSetting8021xCKScheme (*SchemeFunc) (NMSetting8021x * setting); typedef const char *(*PathFunc) (NMSetting8021x * setting); typedef const GByteArray *(*BlobFunc) (NMSetting8021x * setting); typedef struct ObjectType { const char *setting_key; SchemeFunc scheme_func; PathFunc path_func; BlobFunc blob_func; const char *conn_name_key; const char *suffix; } ObjectType; static const ObjectType ca_type = { NM_SETTING_802_1X_CA_CERT, nm_setting_802_1x_get_ca_cert_scheme, nm_setting_802_1x_get_ca_cert_path, nm_setting_802_1x_get_ca_cert_blob, "ca_cert", "ca-cert.der" }; static const ObjectType phase2_ca_type = { NM_SETTING_802_1X_PHASE2_CA_CERT, nm_setting_802_1x_get_phase2_ca_cert_scheme, nm_setting_802_1x_get_phase2_ca_cert_path, nm_setting_802_1x_get_phase2_ca_cert_blob, "ca_cert2", "inner-ca-cert.der" }; static const ObjectType client_type = { NM_SETTING_802_1X_CLIENT_CERT, nm_setting_802_1x_get_client_cert_scheme, nm_setting_802_1x_get_client_cert_path, nm_setting_802_1x_get_client_cert_blob, "client_cert", "client-cert.der" }; static const ObjectType phase2_client_type = { NM_SETTING_802_1X_PHASE2_CLIENT_CERT, nm_setting_802_1x_get_phase2_client_cert_scheme, nm_setting_802_1x_get_phase2_client_cert_path, nm_setting_802_1x_get_phase2_client_cert_blob, "client_cert2", "inner-client-cert.der" }; static const ObjectType pk_type = { NM_SETTING_802_1X_PRIVATE_KEY, nm_setting_802_1x_get_private_key_scheme, nm_setting_802_1x_get_private_key_path, nm_setting_802_1x_get_private_key_blob, "private_key", "private-key.pem" }; static const ObjectType phase2_pk_type = { NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, nm_setting_802_1x_get_phase2_private_key_scheme, nm_setting_802_1x_get_phase2_private_key_path, nm_setting_802_1x_get_phase2_private_key_blob, "private_key2", "inner-private-key.pem" }; static const ObjectType p12_type = { NM_SETTING_802_1X_PRIVATE_KEY, nm_setting_802_1x_get_private_key_scheme, nm_setting_802_1x_get_private_key_path, nm_setting_802_1x_get_private_key_blob, "private_key", "private-key.p12" }; static const ObjectType phase2_p12_type = { NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, nm_setting_802_1x_get_phase2_private_key_scheme, nm_setting_802_1x_get_phase2_private_key_path, nm_setting_802_1x_get_phase2_private_key_blob, "private_key2", "inner-private-key.p12" }; static gboolean write_object (NMSetting8021x * s_8021x, gchar * conn_name, const GByteArray * override_data, const ObjectType * objtype, GError ** error) { NMSetting8021xCKScheme scheme; const char *path = NULL; const GByteArray *blob = NULL; g_return_val_if_fail (conn_name != NULL, FALSE); g_return_val_if_fail (objtype != NULL, FALSE); if (override_data) /* if given explicit data to save, always use that instead of asking * the setting what to do. */ blob = override_data; else { scheme = (*(objtype->scheme_func)) (s_8021x); switch (scheme) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: blob = (*(objtype->blob_func)) (s_8021x); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = (*(objtype->path_func)) (s_8021x); break; default: break; } } /* If the object path was specified, prefer that over any raw cert data that * may have been sent. */ if (path) { wpa_set_data (conn_name, (gchar *) objtype->conn_name_key, (gchar *) path); return TRUE; } /* does not support writing encryption data now */ if (blob) { PLUGIN_WARN (IFNET_PLUGIN_NAME, " warning: Currently we do not support certs writing."); } return TRUE; } static gboolean write_8021x_certs (NMSetting8021x * s_8021x, gboolean phase2, gchar * conn_name, GError ** error) { char *password = NULL; const ObjectType *otype = NULL; gboolean is_pkcs12 = FALSE, success = FALSE; const GByteArray *blob = NULL; GByteArray *enc_key = NULL; gchar *generated_pw = NULL; /* CA certificate */ if (phase2) otype = &phase2_ca_type; else otype = &ca_type; if (!write_object (s_8021x, conn_name, NULL, otype, error)) return FALSE; /* Private key */ if (phase2) { if (nm_setting_802_1x_get_phase2_private_key_scheme (s_8021x) != NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { if (nm_setting_802_1x_get_phase2_private_key_format (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) is_pkcs12 = TRUE; } password = (char *) nm_setting_802_1x_get_phase2_private_key_password (s_8021x); } else { if (nm_setting_802_1x_get_private_key_scheme (s_8021x) != NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { if (nm_setting_802_1x_get_private_key_format (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) is_pkcs12 = TRUE; } password = (char *) nm_setting_802_1x_get_private_key_password (s_8021x); } if (is_pkcs12) otype = phase2 ? &phase2_p12_type : &p12_type; else otype = phase2 ? &phase2_pk_type : &pk_type; if ((*(otype->scheme_func)) (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB) blob = (*(otype->blob_func)) (s_8021x); /* Only do the private key re-encrypt dance if we got the raw key data, which * by definition will be unencrypted. If we're given a direct path to the * private key file, it'll be encrypted, so we don't need to re-encrypt. */ if (blob && !is_pkcs12) { /* Encrypt the unencrypted private key with the fake password */ enc_key = nm_utils_rsa_key_encrypt (blob, password, &generated_pw, error); if (!enc_key) goto out; if (generated_pw) password = generated_pw; } /* Save the private key */ if (!write_object (s_8021x, conn_name, enc_key ? enc_key : blob, otype, error)) goto out; if (phase2) wpa_set_data (conn_name, "private_key_passwd2", password); else wpa_set_data (conn_name, "private_key_passwd", password); /* Client certificate */ if (is_pkcs12) { wpa_set_data (conn_name, phase2 ? "client_cert2" : "client_cert", NULL); } else { if (phase2) otype = &phase2_client_type; else otype = &client_type; /* Save the client certificate */ if (!write_object (s_8021x, conn_name, NULL, otype, error)) goto out; } success = TRUE; out: if (generated_pw) { memset (generated_pw, 0, strlen (generated_pw)); g_free (generated_pw); } if (enc_key) { memset (enc_key->data, 0, enc_key->len); g_byte_array_free (enc_key, TRUE); } return success; } static gboolean write_8021x_setting (NMConnection * connection, gchar * conn_name, gboolean wired, GError ** error) { NMSetting8021x *s_8021x; const char *value; char *tmp = NULL; gboolean success = FALSE; GString *phase2_auth; GString *phase1; s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); if (!s_8021x) { return TRUE; } PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Adding 8021x setting for %s", conn_name); /* If wired, write KEY_MGMT */ if (wired) wpa_set_data (conn_name, "key_mgmt", "IEEE8021X"); /* EAP method */ if (nm_setting_802_1x_get_num_eap_methods (s_8021x)) { value = nm_setting_802_1x_get_eap_method (s_8021x, 0); if (value) tmp = g_ascii_strup (value, -1); } wpa_set_data (conn_name, "eap", tmp ? tmp : NULL); g_free (tmp); wpa_set_data (conn_name, "identity", (gchar *) nm_setting_802_1x_get_identity (s_8021x)); wpa_set_data (conn_name, "anonymous_identity", (gchar *) nm_setting_802_1x_get_anonymous_identity (s_8021x)); wpa_set_data (conn_name, "password", (gchar *) nm_setting_802_1x_get_password (s_8021x)); phase1 = g_string_new (NULL); /* PEAP version */ wpa_set_data (conn_name, "phase1", NULL); value = nm_setting_802_1x_get_phase1_peapver (s_8021x); if (value && (!strcmp (value, "0") || !strcmp (value, "1"))) g_string_append_printf (phase1, "peapver=%s ", value); /* PEAP label */ value = nm_setting_802_1x_get_phase1_peaplabel (s_8021x); if (value && !strcmp (value, "1")) g_string_append_printf (phase1, "peaplabel=%s ", value); if (phase1->len) { tmp = g_strstrip (g_strdup (phase1->str)); wpa_set_data (conn_name, "phase1", tmp); g_free (tmp); } /* Phase2 auth methods */ wpa_set_data (conn_name, "phase2", NULL); phase2_auth = g_string_new (NULL); value = nm_setting_802_1x_get_phase2_auth (s_8021x); if (value) { tmp = g_ascii_strup (value, -1); g_string_append_printf (phase2_auth, "auth=%s ", tmp); g_free (tmp); } /* Phase2 auth heap */ value = nm_setting_802_1x_get_phase2_autheap (s_8021x); if (value) { tmp = g_ascii_strup (value, -1); g_string_append_printf (phase2_auth, "autheap=%s ", tmp); g_free (tmp); } tmp = g_strstrip (g_strdup (phase2_auth->str)); wpa_set_data (conn_name, "phase2", phase2_auth->len ? tmp : NULL); g_free (tmp); g_string_free (phase2_auth, TRUE); g_string_free (phase1, TRUE); success = write_8021x_certs (s_8021x, FALSE, conn_name, error); if (success) { /* phase2/inner certs */ success = write_8021x_certs (s_8021x, TRUE, conn_name, error); } return success; } static gboolean write_wireless_security_setting (NMConnection * connection, gchar * conn_name, gboolean adhoc, gboolean * no_8021x, GError ** error) { NMSettingWirelessSecurity *s_wsec; const char *key_mgmt, *auth_alg, *key, *cipher, *psk; gboolean wep = FALSE, wpa = FALSE; char *tmp; guint32 i, num; GString *str; s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY); if (!s_wsec) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing '%s' setting", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); return FALSE; } key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); g_assert (key_mgmt); auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); if (!strcmp (key_mgmt, "none")) { wpa_set_data (conn_name, "key_mgmt", "NONE"); wep = TRUE; *no_8021x = TRUE; } else if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) { wpa_set_data (conn_name, "key_mgmt", "WPA-PSK"); wpa = TRUE; *no_8021x = TRUE; } else if (!strcmp (key_mgmt, "ieee8021x")) { wpa_set_data (conn_name, "key_mgmt", "IEEE8021X"); } else if (!strcmp (key_mgmt, "wpa-eap")) { wpa_set_data (conn_name, "key_mgmt", "WPA-EAP"); wpa = TRUE; } if (auth_alg) { if (!strcmp (auth_alg, "shared")) wpa_set_data (conn_name, "auth_alg", "SHARED"); else if (!strcmp (auth_alg, "open")) wpa_set_data (conn_name, "auth_alg", "OPEN"); else if (!strcmp (auth_alg, "leap")) { wpa_set_data (conn_name, "auth_alg", "LEAP"); wpa_set_data (conn_name, "eap", "LEAP"); wpa_set_data (conn_name, "identity", (gchar *) nm_setting_wireless_security_get_leap_username (s_wsec)); wpa_set_data (conn_name, "password", (gchar *) nm_setting_wireless_security_get_leap_password (s_wsec)); *no_8021x = TRUE; } } else wpa_set_data (conn_name, "auth_alg", NULL); /* Default WEP TX key index */ wpa_set_data (conn_name, "wep_tx_keyidx", NULL); if (wep) { tmp = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec)); wpa_set_data (conn_name, "wep_tx_keyidx", tmp); g_free (tmp); } /* WEP keys */ for (i = 0; i < 4; i++) { int length; key = nm_setting_wireless_security_get_wep_key (s_wsec, i); if (!key) continue; tmp = g_strdup_printf ("wep_key%d", i); length = strlen (key); if (length == 10 || length == 26 || length == 58) wpa_set_data (conn_name, tmp, (gchar *) key); else { gchar *tmp_key = g_strdup_printf ("\"%s\"", key); wpa_set_data (conn_name, tmp, tmp_key); g_free (tmp_key); } g_free (tmp); } /* WPA Pairwise ciphers */ wpa_set_data (conn_name, "pairwise", NULL); str = g_string_new (NULL); num = nm_setting_wireless_security_get_num_pairwise (s_wsec); for (i = 0; i < num; i++) { if (i > 0) g_string_append_c (str, ' '); cipher = nm_setting_wireless_security_get_pairwise (s_wsec, i); tmp = g_ascii_strup (cipher, -1); g_string_append (str, tmp); g_free (tmp); } if (strlen (str->str)) wpa_set_data (conn_name, "pairwise", str->str); g_string_free (str, TRUE); /* WPA Group ciphers */ wpa_set_data (conn_name, "group", NULL); str = g_string_new (NULL); num = nm_setting_wireless_security_get_num_groups (s_wsec); for (i = 0; i < num; i++) { if (i > 0) g_string_append_c (str, ' '); cipher = nm_setting_wireless_security_get_group (s_wsec, i); tmp = g_ascii_strup (cipher, -1); g_string_append (str, tmp); g_free (tmp); } if (strlen (str->str)) wpa_set_data (conn_name, "group", str->str); g_string_free (str, TRUE); /* WPA Passphrase */ if (wpa) { GString *quoted = NULL; psk = nm_setting_wireless_security_get_psk (s_wsec); if (psk && (strlen (psk) != 64)) { quoted = g_string_sized_new (strlen (psk) + 2); g_string_append_c (quoted, '"'); g_string_append (quoted, psk); g_string_append_c (quoted, '"'); } wpa_set_data (conn_name, "psk", quoted ? quoted->str : (gchar *) psk); if (quoted) g_string_free (quoted, TRUE); } else wpa_set_data (conn_name, "psk", NULL); return TRUE; } /* remove old ssid and add new one*/ static void update_wireless_ssid (NMConnection * connection, gchar * conn_name, gchar * ssid, gboolean hex) { ifnet_delete_network (conn_name); ifnet_add_connection (ssid, "wireless"); wpa_delete_security (conn_name); wpa_add_security (ssid); } static gboolean write_wireless_setting (NMConnection * connection, gchar ** conn_name_ptr, gboolean * no_8021x, GError ** error) { NMSettingWireless *s_wireless; const GByteArray *ssid, *mac, *bssid; const char *mode; char buf[33]; guint32 mtu, i; gboolean adhoc = FALSE, hex_ssid = FALSE; gchar *ssid_str, *tmp; gchar *conn_name = *conn_name_ptr; s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); if (!s_wireless) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME); return FALSE; } ssid = nm_setting_wireless_get_ssid (s_wireless); if (!ssid) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME); return FALSE; } if (!ssid->len || ssid->len > 32) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Invalid SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME); return FALSE; } /* If the SSID contains any non-printable characters, we need to use the * hex notation of the SSID instead. */ for (i = 0; i < ssid->len; i++) { if (!isprint (ssid->data[i])) { hex_ssid = TRUE; break; } } if (hex_ssid) { GString *str; /* Hex SSIDs don't get quoted */ str = g_string_sized_new (ssid->len * 2 + 3); g_string_append (str, "0x"); for (i = 0; i < ssid->len; i++) g_string_append_printf (str, "%02X", ssid->data[i]); update_wireless_ssid (connection, conn_name, str->str, hex_ssid); ssid_str = g_strdup (str->str); g_string_free (str, TRUE); } else { /* Printable SSIDs get quoted */ memset (buf, 0, sizeof (buf)); memcpy (buf, ssid->data, ssid->len); g_strstrip (buf); update_wireless_ssid (connection, conn_name, buf, hex_ssid); ssid_str = g_strdup (buf); } ifnet_set_data (ssid_str, "mac", NULL); mac = nm_setting_wireless_get_mac_address (s_wireless); if (mac) { tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); ifnet_set_data (ssid_str, "mac", tmp); g_free (tmp); } ifnet_set_data (ssid_str, "mtu", NULL); mtu = nm_setting_wireless_get_mtu (s_wireless); if (mtu) { tmp = g_strdup_printf ("%u", mtu); ifnet_set_data (ssid_str, "mtu", tmp); g_free (tmp); } ifnet_set_data (ssid_str, "mode", NULL); mode = nm_setting_wireless_get_mode (s_wireless); if (!mode || !strcmp (mode, "infrastructure")) { wpa_set_data (ssid_str, "mode", "0"); } else if (!strcmp (mode, "adhoc")) { wpa_set_data (ssid_str, "mode", "1"); adhoc = TRUE; } else { PLUGIN_WARN (IFNET_PLUGIN_NAME, "Invalid mode '%s' in '%s' setting", mode, NM_SETTING_WIRELESS_SETTING_NAME); return FALSE; } wpa_set_data (ssid_str, "bssid", NULL); bssid = nm_setting_wireless_get_bssid (s_wireless); if (bssid) { tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", bssid->data[0], bssid->data[1], bssid->data[2], bssid->data[3], bssid->data[4], bssid->data[5]); wpa_set_data (ssid_str, "bssid", tmp); g_free (tmp); } if (nm_setting_wireless_get_security (s_wireless)) { if (!write_wireless_security_setting (connection, ssid_str, adhoc, no_8021x, error)) return FALSE; } else wpa_delete_security (ssid_str); *conn_name_ptr = ifnet_get_data (ssid_str, "name"); g_free (ssid_str); return TRUE; } static gboolean write_wired_setting (NMConnection * connection, gchar * conn_name, GError ** error) { NMSettingWired *s_wired; const GByteArray *mac; char *tmp; guint32 mtu; s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); if (!s_wired) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing '%s' setting", NM_SETTING_WIRED_SETTING_NAME); return FALSE; } ifnet_set_data (conn_name, "mac", NULL); mac = nm_setting_wired_get_mac_address (s_wired); if (mac) { tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); ifnet_set_data (conn_name, "mac", tmp); g_free (tmp); } ifnet_set_data (conn_name, "mtu", NULL); mtu = nm_setting_wired_get_mtu (s_wired); if (mtu) { tmp = g_strdup_printf ("%u", mtu); ifnet_set_data (conn_name, "mtu", tmp); g_free (tmp); } //FIXME may add connection type in future //ifnet_set_data (conn_name, "TYPE", TYPE_ETHERNET); return TRUE; } static void write_connection_setting (NMSettingConnection * s_con, gchar * conn_name) { ifnet_set_data (conn_name, "auto", nm_setting_connection_get_autoconnect (s_con) ? "true" : "false"); } static gboolean write_ip4_setting (NMConnection * connection, gchar * conn_name, GError ** error) { NMSettingIP4Config *s_ip4; const char *value; char *tmp; guint32 i, num; GString *searches; GString *ips; GString *routes; GString *dns; gboolean has_def_route = FALSE; gboolean success = FALSE; s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); if (!s_ip4) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing '%s' setting", NM_SETTING_IP4_CONFIG_SETTING_NAME); return FALSE; } routes = g_string_new (NULL); value = nm_setting_ip4_config_get_method (s_ip4); g_assert (value); if (!strcmp (value, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { num = nm_setting_ip4_config_get_num_addresses (s_ip4); ips = g_string_new (NULL); /* IPv4 addresses */ for (i = 0; i < num; i++) { char buf[INET_ADDRSTRLEN + 1]; NMIP4Address *addr; guint32 ip; addr = nm_setting_ip4_config_get_address (s_ip4, i); memset (buf, 0, sizeof (buf)); ip = nm_ip4_address_get_address (addr); inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf)); g_string_append_printf (ips, "\"%s", &buf[0]); tmp = g_strdup_printf ("%u", nm_ip4_address_get_prefix (addr)); g_string_append_printf (ips, "/%s\" ", tmp); g_free (tmp); /* only the first gateway will be written */ if (!has_def_route && nm_ip4_address_get_gateway (addr)) { memset (buf, 0, sizeof (buf)); ip = nm_ip4_address_get_gateway (addr); inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf)); g_string_append_printf (routes, "\"default via %s\" ", &buf[0]); has_def_route = TRUE; } } ifnet_set_data (conn_name, "config", ips->str); g_string_free (ips, TRUE); } else ifnet_set_data (conn_name, "config", "dhcp"); /* DNS Servers */ ifnet_set_data (conn_name, "dns_servers", NULL); num = nm_setting_ip4_config_get_num_dns (s_ip4); if (num > 0) { dns = g_string_new (NULL); for (i = 0; i < num; i++) { char buf[INET_ADDRSTRLEN + 1]; guint32 ip; ip = nm_setting_ip4_config_get_dns (s_ip4, i); memset (buf, 0, sizeof (buf)); inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf)); g_string_append_printf (dns, " %s", buf); } ifnet_set_data (conn_name, "dns_servers", dns->str); g_string_free (dns, TRUE); } else ifnet_set_data (conn_name, "dns_servers", NULL); /* DNS Searches */ num = nm_setting_ip4_config_get_num_dns_searches (s_ip4); if (num > 0) { searches = g_string_new (NULL); for (i = 0; i < num; i++) { if (i > 0) g_string_append_c (searches, ' '); g_string_append (searches, nm_setting_ip4_config_get_dns_search (s_ip4, i)); } ifnet_set_data (conn_name, "dns_search", searches->str); g_string_free (searches, TRUE); } else ifnet_set_data (conn_name, "dns_search", NULL); /* FIXME Will be implemented when configuration supports it if (!strcmp(value, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { value = nm_setting_ip4_config_get_dhcp_hostname(s_ip4); if (value) ifnet_set_data(conn_name, "DHCP_HOSTNAME", value, FALSE); value = nm_setting_ip4_config_get_dhcp_client_id(s_ip4); if (value) ifnet_set_data(conn_name, "DHCP_CLIENT_ID", value, FALSE); } */ /* Static routes */ num = nm_setting_ip4_config_get_num_routes (s_ip4); if (num > 0) { for (i = 0; i < num; i++) { char buf[INET_ADDRSTRLEN + 1]; NMIP4Route *route; guint32 ip; route = nm_setting_ip4_config_get_route (s_ip4, i); memset (buf, 0, sizeof (buf)); ip = nm_ip4_route_get_dest (route); inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf)); g_string_append_printf (routes, "\"%s", buf); tmp = g_strdup_printf ("%u", nm_ip4_route_get_prefix (route)); g_string_append_printf (routes, "/%s via ", tmp); g_free (tmp); memset (buf, 0, sizeof (buf)); ip = nm_ip4_route_get_next_hop (route); inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf)); g_string_append_printf (routes, "%s\" ", buf); } } if (routes->len > 0) ifnet_set_data (conn_name, "routes", routes->str); else ifnet_set_data (conn_name, "routes", NULL); g_string_free (routes, TRUE); success = TRUE; return success; } static gboolean write_route6_file (NMSettingIP6Config * s_ip6, gchar * conn_name, GError ** error) { char dest[INET6_ADDRSTRLEN + 1]; char next_hop[INET6_ADDRSTRLEN + 1]; NMIP6Route *route; const struct in6_addr *ip; guint32 prefix; guint32 i, num; GString *routes_string; gchar *old_routes; g_return_val_if_fail (s_ip6 != NULL, FALSE); num = nm_setting_ip6_config_get_num_routes (s_ip6); if (num == 0) { return TRUE; } old_routes = ifnet_get_data (conn_name, "routes"); routes_string = g_string_new (old_routes); if (old_routes) g_string_append (routes_string, "\" "); for (i = 0; i < num; i++) { route = nm_setting_ip6_config_get_route (s_ip6, i); memset (dest, 0, sizeof (dest)); ip = nm_ip6_route_get_dest (route); inet_ntop (AF_INET6, (const void *) ip, &dest[0], sizeof (dest)); prefix = nm_ip6_route_get_prefix (route); memset (next_hop, 0, sizeof (next_hop)); ip = nm_ip6_route_get_next_hop (route); inet_ntop (AF_INET6, (const void *) ip, &next_hop[0], sizeof (next_hop)); g_string_append_printf (routes_string, "\"%s/%u via %s\" ", dest, prefix, next_hop); } if (num > 0) ifnet_set_data (conn_name, "routes", routes_string->str); g_string_free (routes_string, TRUE); return TRUE; } static gboolean write_ip6_setting (NMConnection * connection, gchar * conn_name, GError ** error) { NMSettingIP6Config *s_ip6; const char *value; char *prefix; guint32 i, num; GString *searches; char buf[INET6_ADDRSTRLEN + 1]; NMIP6Address *addr; const struct in6_addr *ip; s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); if (!s_ip6) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing '%s' setting", NM_SETTING_IP6_CONFIG_SETTING_NAME); return FALSE; } value = nm_setting_ip6_config_get_method (s_ip6); g_assert (value); if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { ifnet_set_data (conn_name, "enable_ipv6", "false"); return TRUE; } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { /* nothing to do now */ } else { // if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { gchar *config = ifnet_get_data (conn_name, "config"); gchar *tmp; if (!config) tmp = g_strdup_printf ("dhcp6"); else tmp = g_strdup_printf ("%s\" \"dhcp6\"", config); ifnet_set_data (conn_name, "config", tmp); g_free (tmp); } /* else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { } else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { } else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { } */ /* Remember to set IPv6 enabled */ ifnet_set_data (conn_name, "enable_ipv6", "true"); if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { gchar *config = ifnet_get_data (conn_name, "config"); gchar *tmp; GString *ip_str; if (!config) config = ""; num = nm_setting_ip6_config_get_num_addresses (s_ip6); /* IPv6 addresses */ ip_str = g_string_new (NULL); for (i = 0; i < num; i++) { addr = nm_setting_ip6_config_get_address (s_ip6, i); ip = nm_ip6_address_get_address (addr); prefix = g_strdup_printf ("%u", nm_ip6_address_get_prefix (addr)); memset (buf, 0, sizeof (buf)); inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf)); g_string_append_printf (ip_str, "\"%s/", buf); g_string_append_printf (ip_str, "%s\" ", prefix); g_free (prefix); } tmp = g_strdup_printf ("%s\" %s", config, ip_str->str); ifnet_set_data (conn_name, "config", tmp); g_free (tmp); g_string_free (ip_str, TRUE); } /* DNS Servers */ num = nm_setting_ip6_config_get_num_dns (s_ip6); if (num > 0) { gchar *dns_servers = ifnet_get_data (conn_name, "dns_servers"); gchar *tmp; GString *dns_string = g_string_new (NULL); if (!dns_servers) dns_servers = ""; for (i = 0; i < num; i++) { ip = nm_setting_ip6_config_get_dns (s_ip6, i); memset (buf, 0, sizeof (buf)); inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf)); if (!strstr (dns_servers, buf)) g_string_append_printf (dns_string, "%s ", buf); } tmp = g_strdup_printf ("%s %s", dns_servers, dns_string->str); ifnet_set_data (conn_name, "dns_servers", tmp); g_free (tmp); g_string_free (dns_string, TRUE); } else /* DNS Searches */ num = nm_setting_ip6_config_get_num_dns_searches (s_ip6); if (num > 0) { char *ip4_domains; ip4_domains = ifnet_get_data (conn_name, "dns_search"); if (!ip4_domains) ip4_domains = ""; searches = g_string_new (ip4_domains); for (i = 0; i < num; i++) { const gchar *search = NULL; search = nm_setting_ip6_config_get_dns_search (s_ip6, i); if (search && !strstr (searches->str, search)) { if (searches->len > 0) g_string_append_c (searches, ' '); g_string_append (searches, search); } } ifnet_set_data (conn_name, "dns_search", searches->str); g_string_free (searches, TRUE); } write_route6_file (s_ip6, conn_name, error); if (error && *error) return FALSE; return TRUE; } static gboolean write_pppoe_setting (gchar * conn_name, NMSettingPPPOE * s_pppoe) { const gchar *value; value = nm_setting_pppoe_get_username (s_pppoe); if (!value) { return FALSE; } ifnet_set_data (conn_name, "username", (gchar *) value); value = nm_setting_pppoe_get_password (s_pppoe); /* password could be NULL here */ if (value) { ifnet_set_data (conn_name, "password", (gchar *) value); } return TRUE; } gboolean ifnet_update_parsers_by_connection (NMConnection * connection, gchar * conn_name, gchar ** nm_conn_name, gchar * config_file, gchar * wpa_file, GError ** error) { NMSettingConnection *s_con; NMSettingIP6Config *s_ip6; gboolean success = FALSE; const char *type; gboolean no_8021x = FALSE; gboolean wired = FALSE, pppoe = TRUE; s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); if (!s_con) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing '%s' setting", NM_SETTING_CONNECTION_SETTING_NAME); return FALSE; } type = nm_setting_connection_get_connection_type (s_con); if (!type) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing connection type!"); goto out; } if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) { /* Writing wired setting */ if (!write_wired_setting (connection, conn_name, error)) goto out; wired = TRUE; no_8021x = TRUE; } else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) { /* Writing wireless setting */ if (!write_wireless_setting (connection, &conn_name, &no_8021x, error)) goto out; } else if (!strcmp (type, NM_SETTING_PPPOE_SETTING_NAME)) { /* Writing pppoe setting */ if (! (write_pppoe_setting (conn_name, NM_SETTING_PPPOE (nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE))))) goto out; pppoe = TRUE; wired = TRUE; no_8021x = TRUE; } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Can't write connection type '%s'", type); goto out; } //FIXME wired connection doesn't support 8021x now if (!no_8021x) { if (!write_8021x_setting (connection, conn_name, wired, error)) goto out; } /* IPv4 Setting */ if (!write_ip4_setting (connection, conn_name, error)) goto out; s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); if (s_ip6) { /* IPv6 Setting */ if (!write_ip6_setting (connection, conn_name, error)) goto out; } /* Connection Setting */ write_connection_setting (s_con, conn_name); /* connection id will be displayed in nm-applet */ update_connection_id (connection, conn_name); if (nm_conn_name) *nm_conn_name = g_strdup (conn_name); success = ifnet_flush_to_file (config_file); if (success) wpa_flush_to_file (wpa_file); out: return success; } gboolean ifnet_delete_connection_in_parsers (gchar * conn_name, gchar * config_file, gchar * wpa_file) { gboolean result = FALSE; ifnet_delete_network (conn_name); result = ifnet_flush_to_file (config_file); if (result) { /* connection may not have security information * so simply ignore the return value*/ wpa_delete_security (conn_name); wpa_flush_to_file (wpa_file); } return result; } /* get the available wired name(eth*). */ static gchar * get_wired_name () { int i = 0; for (; i < 256; i++) { gchar *conn_name = g_strdup_printf ("eth%d", i); if (!ifnet_has_connection (conn_name)) { return conn_name; } else g_free (conn_name); } return NULL; } /* get the available pppoe name(ppp*). */ static gchar * get_ppp_name () { int i = 0; for (; i < 256; i++) { gchar *conn_name = g_strdup_printf ("ppp%d", i); if (!ifnet_has_connection (conn_name)) { return conn_name; } else g_free (conn_name); } return NULL; } /* get wireless ssid */ static gchar * get_wireless_name (NMConnection * connection) { NMSettingWireless *s_wireless; const GByteArray *ssid; gboolean hex_ssid = FALSE; gchar *result = NULL; char buf[33]; int i = 0; s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); if (!s_wireless) return NULL; ssid = nm_setting_wireless_get_ssid (s_wireless); if (!ssid->len || ssid->len > 32) { return NULL; } for (i = 0; i < ssid->len; i++) { if (!isprint (ssid->data[i])) { hex_ssid = TRUE; break; } } if (hex_ssid) { GString *str; str = g_string_sized_new (ssid->len * 2 + 3); g_string_append (str, "0x"); for (i = 0; i < ssid->len; i++) g_string_append_printf (str, "%02X", ssid->data[i]); result = g_strdup (str->str); g_string_free (str, TRUE); } else { memset (buf, 0, sizeof (buf)); memcpy (buf, ssid->data, ssid->len); result = g_strdup_printf ("%s", buf); g_strstrip (result); } return result; } gboolean ifnet_add_new_connection (NMConnection * connection, gchar * config_file, gchar * wpa_file, GError ** error) { NMSettingConnection *s_con; gboolean success = FALSE; const char *type; gchar *new_type, *new_name = NULL; s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); if (!s_con) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing '%s' setting", NM_SETTING_CONNECTION_SETTING_NAME); return FALSE; } type = nm_setting_connection_get_connection_type (s_con); if (!type) { g_set_error (error, ifnet_plugin_error_quark (), 0, "Missing connection type!"); goto out; } PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Adding %s connection", type); /* get name and type * Wireless type: wireless * Wired type: wired * PPPoE type: ppp*/ if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) { new_name = get_wired_name (); if (!new_name) goto out; new_type = "wired"; } else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) { new_name = get_wireless_name (connection); new_type = "wireless"; } else if (!strcmp (type, NM_SETTING_PPPOE_SETTING_NAME)) { new_name = get_ppp_name (); if (!new_name) goto out; new_type = "ppp"; } else { g_set_error (error, ifnet_plugin_error_quark (), 0, "Can't write connection type '%s'", type); goto out; } if (ifnet_add_connection (new_name, new_type)) success = ifnet_update_parsers_by_connection (connection, new_name, NULL, config_file, wpa_file, error); PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Added new connection: %s, result: %s", new_name, success ? "success" : "fail"); out: if (new_name) g_free (new_name); return success; }