PageRenderTime 90ms CodeModel.GetById 3ms app.highlight 73ms RepoModel.GetById 1ms app.codeStats 1ms

/src/settings/plugins/ifnet/connection_parser.c

https://bitbucket.org/advaitraut/networkmanager
C | 3065 lines | 2568 code | 311 blank | 186 comment | 438 complexity | 54d6293ebe5a56028711311388915d1f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
   2/*
   3 * Mu Qiao <qiaomuf@gmail.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License along
  16 * with this program; if not, write to the Free Software Foundation, Inc.,
  17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18 *
  19 * Copyright (C) 1999-2010 Gentoo Foundation, Inc.
  20 */
  21
  22#include "config.h"
  23
  24#include <string.h>
  25#include <arpa/inet.h>
  26#include <stdlib.h>
  27#include <netinet/ether.h>
  28#include <errno.h>
  29#include <glib/gi18n.h>
  30
  31#include <nm-setting-connection.h>
  32#include <nm-setting-ip4-config.h>
  33#include <nm-setting-ip6-config.h>
  34#include <nm-setting-ppp.h>
  35#include <nm-setting-pppoe.h>
  36#include <nm-setting-wired.h>
  37#include <nm-setting-wireless.h>
  38#include <nm-setting-8021x.h>
  39#include <nm-system-config-interface.h>
  40#include <nm-utils.h>
  41
  42#include "net_utils.h"
  43#include "wpa_parser.h"
  44#include "connection_parser.h"
  45#include "nm-ifnet-connection.h"
  46
  47static void
  48update_connection_id (NMConnection *connection, const char *conn_name)
  49{
  50	gchar *idstr = NULL;
  51	gchar *uuid_base = NULL;
  52	gchar *uuid = NULL;
  53	int name_len;
  54	NMSettingConnection *setting;
  55
  56	name_len = strlen (conn_name);
  57	if ((name_len > 2) && (g_str_has_prefix (conn_name, "0x"))) {
  58		idstr = utils_hexstr2bin (conn_name + 2, name_len - 2);
  59	} else
  60		idstr = g_strdup_printf ("%s", conn_name);
  61	uuid_base = idstr;
  62	uuid = nm_utils_uuid_generate_from_string (uuid_base);
  63	setting = nm_connection_get_setting_connection (connection);
  64	g_object_set (setting, NM_SETTING_CONNECTION_ID, idstr,
  65		      NM_SETTING_CONNECTION_UUID, uuid, NULL);
  66	PLUGIN_PRINT (IFNET_PLUGIN_NAME,
  67		      "update_connection_setting_from_config_block: name:%s, id:%s, uuid: %s",
  68		      conn_name, idstr, uuid);
  69
  70	g_free (uuid);
  71	g_free (idstr);
  72}
  73
  74static gboolean eap_simple_reader (const char *eap_method,
  75                                   const char *ssid,
  76                                   NMSetting8021x *s_8021x,
  77                                   gboolean phase2,
  78                                   const char *basepath,
  79                                   GError **error);
  80
  81static gboolean eap_tls_reader (const char *eap_method,
  82                                const char *ssid,
  83                                NMSetting8021x *s_8021x,
  84                                gboolean phase2,
  85                                const char *basepath,
  86                                GError **error);
  87
  88static gboolean eap_peap_reader (const char *eap_method,
  89                                 const char *ssid,
  90                                 NMSetting8021x *s_8021x,
  91                                 gboolean phase2,
  92                                 const char *basepath,
  93                                 GError **error);
  94
  95static gboolean eap_ttls_reader (const char *eap_method,
  96                                 const char *ssid,
  97                                 NMSetting8021x *s_8021x,
  98                                 gboolean phase2,
  99                                 const char *basepath,
 100                                 GError **error);
 101
 102typedef struct {
 103	const char *method;
 104	 gboolean (*reader) (const char *eap_method,
 105	                     const char *ssid,
 106	                     NMSetting8021x *s_8021x,
 107	                     gboolean phase2,
 108	                     const char *basepath,
 109	                     GError **error);
 110	gboolean wifi_phase2_only;
 111} EAPReader;
 112
 113static EAPReader eap_readers[] = {
 114	{"md5", eap_simple_reader, TRUE},
 115	{"pap", eap_simple_reader, TRUE},
 116	{"chap", eap_simple_reader, TRUE},
 117	{"mschap", eap_simple_reader, TRUE},
 118	{"mschapv2", eap_simple_reader, TRUE},
 119	{"leap", eap_simple_reader, TRUE},
 120	{"tls", eap_tls_reader, FALSE},
 121	{"peap", eap_peap_reader, FALSE},
 122	{"ttls", eap_ttls_reader, FALSE},
 123	{NULL, NULL}
 124};
 125
 126/* reading identity and password */
 127static gboolean
 128eap_simple_reader (const char *eap_method,
 129                   const char *ssid,
 130                   NMSetting8021x *s_8021x,
 131                   gboolean phase2,
 132                   const char *basepath,
 133                   GError **error)
 134{
 135	const char *value;
 136
 137	/* identity */
 138	value = wpa_get_value (ssid, "identity");
 139	if (!value) {
 140		g_set_error (error, ifnet_plugin_error_quark (), 0,
 141			     "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
 142			     eap_method);
 143		return FALSE;
 144	}
 145	g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
 146
 147	/* password */
 148	value = wpa_get_value (ssid, "password");
 149	if (!value) {
 150		g_set_error (error, ifnet_plugin_error_quark (), 0,
 151			     "Missing IEEE_8021X_PASSWORD for EAP method '%s'.",
 152			     eap_method);
 153		return FALSE;
 154	}
 155
 156	g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL);
 157
 158	return TRUE;
 159}
 160
 161static char *
 162get_cert (const char *ssid, const char *key, const char *basepath)
 163{
 164	const char *orig;
 165
 166	/* If it's a relative path, convert to absolute using 'basepath' */
 167	orig = wpa_get_value (ssid, key);
 168	if (g_path_is_absolute (orig))
 169		return g_strdup (orig);
 170	return g_strdup_printf ("%s/%s", basepath, orig);
 171}
 172
 173static gboolean
 174eap_tls_reader (const char *eap_method,
 175                const char *ssid,
 176                NMSetting8021x *s_8021x,
 177                gboolean phase2,
 178                const char *basepath,
 179                GError **error)
 180{
 181	const char *value;
 182	char *ca_cert = NULL;
 183	char *client_cert = NULL;
 184	char *privkey = NULL;
 185	const char *privkey_password = NULL;
 186	gboolean success = FALSE;
 187	NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
 188
 189	/* identity */
 190	value = wpa_get_value (ssid, "identity");
 191	if (!value) {
 192		g_set_error (error, ifnet_plugin_error_quark (), 0,
 193			     "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
 194			     eap_method);
 195		return FALSE;
 196	}
 197	g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
 198
 199	/* ca cert */
 200	ca_cert = get_cert (ssid, phase2 ? "ca_cert2" : "ca_cert", basepath);
 201	if (ca_cert) {
 202		if (phase2) {
 203			if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
 204								   ca_cert,
 205								   NM_SETTING_802_1X_CK_SCHEME_PATH,
 206								   NULL, error))
 207				goto done;
 208		} else {
 209			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
 210							    ca_cert,
 211							    NM_SETTING_802_1X_CK_SCHEME_PATH,
 212							    NULL, error))
 213				goto done;
 214		}
 215	} else {
 216		PLUGIN_WARN (IFNET_PLUGIN_NAME,
 217			     "    warning: missing %s for EAP"
 218			     " method '%s'; this is insecure!",
 219			     phase2 ? "IEEE_8021X_INNER_CA_CERT" :
 220			     "IEEE_8021X_CA_CERT", eap_method);
 221	}
 222
 223	/* Private key password */
 224	privkey_password = wpa_get_value (ssid,
 225					  phase2 ? "private_key_passwd2" :
 226					  "private_key_passwd");
 227
 228	if (!privkey_password) {
 229		g_set_error (error, ifnet_plugin_error_quark (), 0,
 230			     "Missing %s for EAP method '%s'.",
 231			     phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD" :
 232			     "IEEE_8021X_PRIVATE_KEY_PASSWORD", eap_method);
 233		goto done;
 234	}
 235
 236	/* The private key itself */
 237	privkey = get_cert (ssid, phase2 ? "private_key2" : "private_key", basepath);
 238	if (!privkey) {
 239		g_set_error (error, ifnet_plugin_error_quark (), 0,
 240			     "Missing %s for EAP method '%s'.",
 241			     phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" :
 242			     "IEEE_8021X_PRIVATE_KEY", eap_method);
 243		goto done;
 244	}
 245
 246	if (phase2) {
 247		if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
 248							       privkey,
 249							       privkey_password,
 250							       NM_SETTING_802_1X_CK_SCHEME_PATH,
 251							       &privkey_format,
 252							       error))
 253			goto done;
 254	} else {
 255		if (!nm_setting_802_1x_set_private_key (s_8021x,
 256							privkey,
 257							privkey_password,
 258							NM_SETTING_802_1X_CK_SCHEME_PATH,
 259							&privkey_format, error))
 260			goto done;
 261	}
 262
 263	/* Only set the client certificate if the private key is not PKCS#12 format,
 264	 * as NM (due to supplicant restrictions) requires.  If the key was PKCS#12,
 265	 * then nm_setting_802_1x_set_private_key() already set the client certificate
 266	 * to the same value as the private key.
 267	 */
 268	if (privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY
 269	    || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) {
 270		client_cert = get_cert (ssid, phase2 ? "client_cert2" : "client_cert", basepath);
 271		if (!client_cert) {
 272			g_set_error (error, ifnet_plugin_error_quark (), 0,
 273				     "Missing %s for EAP method '%s'.",
 274				     phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" :
 275				     "IEEE_8021X_CLIENT_CERT", eap_method);
 276			goto done;
 277		}
 278
 279		if (phase2) {
 280			if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
 281								       client_cert,
 282								       NM_SETTING_802_1X_CK_SCHEME_PATH,
 283								       NULL,
 284								       error))
 285				goto done;
 286		} else {
 287			if (!nm_setting_802_1x_set_client_cert (s_8021x,
 288								client_cert,
 289								NM_SETTING_802_1X_CK_SCHEME_PATH,
 290								NULL, error))
 291				goto done;
 292		}
 293	}
 294
 295	success = TRUE;
 296
 297done:
 298	g_free (ca_cert);
 299	g_free (client_cert);
 300	g_free (privkey);
 301	return success;
 302}
 303
 304static gboolean
 305eap_peap_reader (const char *eap_method,
 306                 const char *ssid,
 307                 NMSetting8021x *s_8021x,
 308                 gboolean phase2,
 309                 const char *basepath,
 310                 GError **error)
 311{
 312	char *ca_cert = NULL;
 313	const char *inner_auth = NULL;
 314	const char *peapver = NULL;
 315	char **list = NULL, **iter, *lower;
 316	gboolean success = FALSE;
 317
 318	ca_cert = get_cert (ssid, "ca_cert", basepath);
 319	if (ca_cert) {
 320		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
 321						    ca_cert,
 322						    NM_SETTING_802_1X_CK_SCHEME_PATH,
 323						    NULL, error))
 324			goto done;
 325	} else {
 326		PLUGIN_WARN (IFNET_PLUGIN_NAME, "    warning: missing "
 327			     "IEEE_8021X_CA_CERT for EAP method '%s'; this is"
 328			     " insecure!", eap_method);
 329	}
 330
 331	peapver = wpa_get_value (ssid, "phase1");
 332	/* peap version, default is automatic */
 333	if (peapver && strstr (peapver, "peapver")) {
 334		if (strstr (peapver, "peapver=0"))
 335			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER,
 336				      "0", NULL);
 337		else if (strstr (peapver, "peapver=1"))
 338			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER,
 339				      "1", NULL);
 340		else {
 341			g_set_error (error, ifnet_plugin_error_quark (), 0,
 342				     "Unknown IEEE_8021X_PEAP_VERSION value '%s'",
 343				     peapver);
 344			goto done;
 345		}
 346	}
 347
 348	/* peaplabel */
 349	if (peapver && strstr (peapver, "peaplabel=1"))
 350		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1",
 351			      NULL);
 352
 353	inner_auth = wpa_get_value (ssid, "phase2");
 354	if (!inner_auth) {
 355		g_set_error (error, ifnet_plugin_error_quark (), 0,
 356			     "Missing IEEE_8021X_INNER_AUTH_METHODS.");
 357		goto done;
 358	}
 359	/* Handle options for the inner auth method */
 360	list = g_strsplit (inner_auth, " ", 0);
 361	for (iter = list; iter && *iter; iter++) {
 362		gchar *pos = NULL;
 363
 364		if (!strlen (*iter))
 365			continue;
 366
 367		if (!(pos = strstr (*iter, "MSCHAPV2"))
 368		    || !(pos = strstr (*iter, "MD5"))
 369		    || !(pos = strstr (*iter, "GTC"))) {
 370			if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error))
 371				goto done;
 372		} else if (!(pos = strstr (*iter, "TLS"))) {
 373			if (!eap_tls_reader (pos, ssid, s_8021x, TRUE, basepath, error))
 374				goto done;
 375		} else {
 376			g_set_error (error, ifnet_plugin_error_quark (), 0,
 377				     "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
 378				     *iter);
 379			goto done;
 380		}
 381
 382		pos = strchr (*iter, '=');
 383		pos++;
 384		lower = g_ascii_strdown (pos, -1);
 385		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower,
 386			      NULL);
 387		g_free (lower);
 388		break;
 389	}
 390
 391	if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
 392		g_set_error (error, ifnet_plugin_error_quark (), 0,
 393			     "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
 394		goto done;
 395	}
 396
 397	success = TRUE;
 398
 399done:
 400	g_free (ca_cert);
 401	if (list)
 402		g_strfreev (list);
 403	return success;
 404}
 405
 406static gboolean
 407eap_ttls_reader (const char *eap_method,
 408                 const char *ssid,
 409                 NMSetting8021x *s_8021x,
 410                 gboolean phase2,
 411                 const char *basepath,
 412                 GError **error)
 413{
 414	gboolean success = FALSE;
 415	const char *anon_ident = NULL;
 416	char *ca_cert = NULL;
 417	const char *tmp;
 418	char **list = NULL, **iter, *inner_auth = NULL;
 419
 420	/* ca cert */
 421	ca_cert = get_cert (ssid, "ca_cert", basepath);
 422	if (ca_cert) {
 423		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
 424						    ca_cert,
 425						    NM_SETTING_802_1X_CK_SCHEME_PATH,
 426						    NULL, error))
 427			goto done;
 428	} else {
 429		PLUGIN_WARN (IFNET_PLUGIN_NAME, "    warning: missing "
 430			     "IEEE_8021X_CA_CERT for EAP method '%s'; this is"
 431			     " insecure!", eap_method);
 432	}
 433
 434	/* anonymous indentity for tls */
 435	anon_ident = wpa_get_value (ssid, "anonymous_identity");
 436	if (anon_ident && strlen (anon_ident))
 437		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY,
 438			      anon_ident, NULL);
 439
 440	tmp = wpa_get_value (ssid, "phase2");
 441	if (!tmp) {
 442		g_set_error (error, ifnet_plugin_error_quark (), 0,
 443			     "Missing IEEE_8021X_INNER_AUTH_METHODS.");
 444		goto done;
 445	}
 446
 447	/* Handle options for the inner auth method */
 448	inner_auth = g_ascii_strdown (tmp, -1);
 449	list = g_strsplit (inner_auth, " ", 0);
 450	for (iter = list; iter && *iter; iter++) {
 451		gchar *pos = NULL;
 452
 453		if (!strlen (*iter))
 454			continue;
 455		if ((pos = strstr (*iter, "mschapv2")) != NULL
 456		    || (pos = strstr (*iter, "mschap")) != NULL
 457		    || (pos = strstr (*iter, "pap")) != NULL
 458		    || (pos = strstr (*iter, "chap")) != NULL) {
 459			if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error))
 460				goto done;
 461			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH,
 462				      pos, NULL);
 463		} else if ((pos = strstr (*iter, "tls")) != NULL) {
 464			if (!eap_tls_reader (pos, ssid, s_8021x, TRUE, basepath, error))
 465				goto done;
 466			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP,
 467				      "tls", NULL);
 468		} else if ((pos = strstr (*iter, "mschapv2")) != NULL
 469			   || (pos = strstr (*iter, "md5")) != NULL) {
 470			if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error)) {
 471				PLUGIN_WARN (IFNET_PLUGIN_NAME, "SIMPLE ERROR");
 472				goto done;
 473			}
 474			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP,
 475				      pos, NULL);
 476		} else {
 477			g_set_error (error, ifnet_plugin_error_quark (), 0,
 478				     "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
 479				     *iter);
 480			goto done;
 481		}
 482		break;
 483	}
 484
 485	success = TRUE;
 486done:
 487	g_free (ca_cert);
 488	if (list)
 489		g_strfreev (list);
 490	g_free (inner_auth);
 491	return success;
 492}
 493
 494/* type is already decided by net_parser, this function is just used to
 495 * doing tansformation*/
 496static const gchar *
 497guess_connection_type (const char *conn_name)
 498{
 499	const gchar *type = ifnet_get_data (conn_name, "type");
 500	const gchar *ret_type = NULL;
 501
 502	if (!g_strcmp0 (type, "ppp"))
 503		ret_type = NM_SETTING_PPPOE_SETTING_NAME;
 504
 505	if (!g_strcmp0 (type, "wireless"))
 506		ret_type = NM_SETTING_WIRELESS_SETTING_NAME;
 507
 508	if (!ret_type)
 509		ret_type = NM_SETTING_WIRED_SETTING_NAME;
 510
 511	PLUGIN_PRINT (IFNET_PLUGIN_NAME,
 512		      "guessed connection type (%s) = %s", conn_name, ret_type);
 513	return ret_type;
 514}
 515
 516/* Reading mac address for setting connection option.
 517 * Unmanaged device mac address is required by NetworkManager*/
 518static gboolean
 519read_mac_address (const char *conn_name, GByteArray **array, GError **error)
 520{
 521	const char *value = ifnet_get_data (conn_name, "mac");
 522
 523	if (!value || !strlen (value))
 524		return TRUE;
 525
 526	*array = nm_utils_hwaddr_atoba (value, ARPHRD_ETHER);
 527	if (!*array) {
 528		g_set_error (error, ifnet_plugin_error_quark (), 0,
 529					 "The MAC address '%s' was invalid.", value);
 530		return FALSE;
 531	}
 532
 533	return TRUE;
 534}
 535
 536static void
 537make_wired_connection_setting (NMConnection *connection,
 538                               const char *conn_name,
 539                               GError **error)
 540{
 541	GByteArray *mac = NULL;
 542	NMSettingWired *s_wired = NULL;
 543	const char *value = NULL;
 544
 545	s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
 546
 547	/* mtu_xxx */
 548	value = ifnet_get_data (conn_name, "mtu");
 549	if (value) {
 550		long int mtu;
 551
 552		errno = 0;
 553		mtu = strtol (value, NULL, 10);
 554		if (errno || mtu < 0 || mtu > 65535) {
 555			PLUGIN_WARN (IFNET_PLUGIN_NAME,
 556				     "    warning: invalid MTU '%s' for %s",
 557				     value, conn_name);
 558		} else
 559			g_object_set (s_wired, NM_SETTING_WIRED_MTU,
 560				      (guint32) mtu, NULL);
 561	}
 562
 563	if (read_mac_address (conn_name, &mac, error)) {
 564		if (mac) {
 565			g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS,
 566				      mac, NULL);
 567			g_byte_array_free (mac, TRUE);
 568		}
 569	} else {
 570		g_object_unref (s_wired);
 571		s_wired = NULL;
 572	}
 573	if (s_wired)
 574		nm_connection_add_setting (connection, NM_SETTING (s_wired));
 575}
 576
 577/* add NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME,
 578 * NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID in future*/
 579static void
 580make_ip4_setting (NMConnection *connection,
 581                  const char *conn_name,
 582                  GError **error)
 583{
 584
 585	NMSettingIP4Config *ip4_setting =
 586	    NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
 587	const char *value, *method;
 588	gboolean is_static_block = is_static_ip4 (conn_name);
 589	ip_block *iblock = NULL;
 590
 591	/* set dhcp options (dhcp_xxx) */
 592	value = ifnet_get_data (conn_name, "dhcp");
 593	g_object_set (ip4_setting, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, value
 594		      && strstr (value, "nodns") ? TRUE : FALSE,
 595		      NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, value
 596		      && strstr (value, "nogateway") ? TRUE : FALSE, NULL);
 597
 598	if (!is_static_block) {
 599		method = ifnet_get_data (conn_name, "config");
 600		if (!method){
 601			g_set_error (error, ifnet_plugin_error_quark (), 0,
 602						 "Unknown config for %s", conn_name);
 603			g_object_unref (ip4_setting);
 604			return;
 605		}
 606		if (strstr (method, "dhcp"))
 607			g_object_set (ip4_setting,
 608						  NM_SETTING_IP4_CONFIG_METHOD,
 609						  NM_SETTING_IP4_CONFIG_METHOD_AUTO,
 610						  NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, FALSE, NULL);
 611		else if (strstr (method, "autoip")) {
 612			g_object_set (ip4_setting,
 613						  NM_SETTING_IP4_CONFIG_METHOD,
 614						  NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
 615						  NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, FALSE, NULL);
 616			nm_connection_add_setting (connection, NM_SETTING (ip4_setting));
 617			return;
 618		} else if (strstr (method, "shared")) {
 619			g_object_set (ip4_setting,
 620						  NM_SETTING_IP4_CONFIG_METHOD,
 621						  NM_SETTING_IP4_CONFIG_METHOD_SHARED,
 622						  NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, FALSE, NULL);
 623			nm_connection_add_setting (connection, NM_SETTING (ip4_setting));
 624			return;
 625		} else {
 626			g_set_error (error, ifnet_plugin_error_quark (), 0,
 627						 "Unknown config for %s", conn_name);
 628			g_object_unref (ip4_setting);
 629			return;
 630		}
 631		PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Using %s method for %s",
 632					  method, conn_name);
 633	}else {
 634		iblock = convert_ip4_config_block (conn_name);
 635		if (!iblock) {
 636			g_set_error (error, ifnet_plugin_error_quark (), 0,
 637				     "Ifnet plugin: can't aquire ip configuration for %s",
 638				     conn_name);
 639			g_object_unref (ip4_setting);
 640			return;
 641		}
 642		/************** add all ip settings to the connection**********/
 643		while (iblock) {
 644			ip_block *current_iblock;
 645			NMIP4Address *ip4_addr = nm_ip4_address_new ();
 646
 647			nm_ip4_address_set_address (ip4_addr, iblock->ip);
 648			nm_ip4_address_set_prefix (ip4_addr,
 649						   nm_utils_ip4_netmask_to_prefix
 650						   (iblock->netmask));
 651			/* currently all the IPs has the same gateway */
 652			nm_ip4_address_set_gateway (ip4_addr, iblock->gateway);
 653			if (iblock->gateway)
 654				g_object_set (ip4_setting,
 655					      NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES,
 656					      TRUE, NULL);
 657			if (!nm_setting_ip4_config_add_address (ip4_setting, ip4_addr))
 658				PLUGIN_WARN (IFNET_PLUGIN_NAME,
 659					     "ignoring duplicate IP4 address");
 660			nm_ip4_address_unref (ip4_addr);
 661			current_iblock = iblock;
 662			iblock = iblock->next;
 663			destroy_ip_block (current_iblock);
 664
 665		}
 666		g_object_set (ip4_setting,
 667		              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
 668		              NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, !has_default_ip4_route (conn_name),
 669		              NULL);
 670	}
 671
 672	/* add dhcp hostname and client id */
 673	if (!is_static_block && strstr (method, "dhcp")) {
 674		gchar *dhcp_hostname, *client_id;
 675
 676		get_dhcp_hostname_and_client_id (&dhcp_hostname, &client_id);
 677		if (dhcp_hostname) {
 678			g_object_set (ip4_setting,
 679				      NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME,
 680				      dhcp_hostname, NULL);
 681			PLUGIN_PRINT (IFNET_PLUGIN_NAME, "DHCP hostname: %s",
 682				      dhcp_hostname);
 683			g_free (dhcp_hostname);
 684		}
 685		if (client_id) {
 686			g_object_set (ip4_setting,
 687				      NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID,
 688				      client_id, NULL);
 689			PLUGIN_PRINT (IFNET_PLUGIN_NAME, "DHCP client id: %s",
 690				      client_id);
 691			g_free (client_id);
 692		}
 693	}
 694
 695	/* add all IPv4 dns servers, IPv6 servers will be ignored */
 696	set_ip4_dns_servers (ip4_setting, conn_name);
 697
 698	/* DNS searches */
 699	value = ifnet_get_data (conn_name, "dns_search");
 700	if (value) {
 701		char *stripped = g_strdup (value);
 702		char **searches = NULL;
 703
 704		strip_string (stripped, '"');
 705
 706		searches = g_strsplit (stripped, " ", 0);
 707		if (searches) {
 708			char **item;
 709
 710			for (item = searches; *item; item++) {
 711				if (strlen (*item)) {
 712					if (!nm_setting_ip4_config_add_dns_search (ip4_setting, *item))
 713						PLUGIN_WARN
 714						    (IFNET_PLUGIN_NAME,
 715						     "    warning: duplicate DNS domain '%s'",
 716						     *item);
 717				}
 718			}
 719			g_strfreev (searches);
 720		}
 721	}
 722
 723	/* static routes */
 724	iblock = convert_ip4_routes_block (conn_name);
 725	while (iblock) {
 726		ip_block *current_iblock = iblock;
 727		const char *metric_str;
 728		char *stripped;
 729		long int metric;
 730		NMIP4Route *route = nm_ip4_route_new ();
 731
 732		nm_ip4_route_set_dest (route, iblock->ip);
 733		nm_ip4_route_set_next_hop (route, iblock->gateway);
 734		nm_ip4_route_set_prefix (route,
 735					 nm_utils_ip4_netmask_to_prefix
 736					 (iblock->netmask));
 737		if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL) {
 738			metric = strtol (metric_str, NULL, 10);
 739			nm_ip4_route_set_metric (route, (guint32) metric);
 740		} else {
 741			metric_str = ifnet_get_global_data ("metric");
 742			if (metric_str) {
 743				stripped = g_strdup (metric_str);
 744				strip_string (stripped, '"');
 745				metric = strtol (metric_str, NULL, 10);
 746				nm_ip4_route_set_metric (route,
 747							 (guint32) metric);
 748				g_free (stripped);
 749			}
 750		}
 751
 752		if (!nm_setting_ip4_config_add_route (ip4_setting, route))
 753			PLUGIN_WARN (IFNET_PLUGIN_NAME,
 754				     "warning: duplicate IP4 route");
 755		PLUGIN_PRINT (IFNET_PLUGIN_NAME,
 756			      "new IP4 route:%d\n", iblock->ip);
 757
 758		nm_ip4_route_unref (route);
 759
 760		current_iblock = iblock;
 761		iblock = iblock->next;
 762		destroy_ip_block (current_iblock);
 763	}
 764
 765	/* Finally add setting to connection */
 766	nm_connection_add_setting (connection, NM_SETTING (ip4_setting));
 767}
 768
 769static void
 770make_ip6_setting (NMConnection *connection,
 771                  const char *conn_name,
 772                  GError **error)
 773{
 774	NMSettingIP6Config *s_ip6 = NULL;
 775	gboolean is_static_block = is_static_ip6 (conn_name);
 776
 777	// used to disable IPv6
 778	gboolean ipv6_enabled = FALSE;
 779	gchar *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
 780	const char *value;
 781	ip6_block *iblock;
 782	gboolean never_default = !has_default_ip6_route (conn_name);
 783
 784	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
 785	if (!s_ip6) {
 786		g_set_error (error, ifnet_plugin_error_quark (), 0,
 787			     "Could not allocate IP6 setting");
 788		return;
 789	}
 790
 791	value = ifnet_get_data (conn_name, "enable_ipv6");
 792	if (value && is_true (value))
 793		ipv6_enabled = TRUE;
 794
 795	//FIXME Handle other methods that NM supports in future
 796	// Currently only Manual and DHCP are supported
 797	if (!ipv6_enabled) {
 798		g_object_set (s_ip6,
 799			      NM_SETTING_IP6_CONFIG_METHOD,
 800			      NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);
 801		goto done;
 802	} else if (!is_static_block) {
 803		// config_eth* contains "dhcp6"
 804		method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
 805		never_default = FALSE;
 806	}
 807	// else if (!has_ip6_address(conn_name))
 808	// doesn't have "dhcp6" && doesn't have any ipv6 address
 809	// method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
 810	else
 811		// doesn't have "dhcp6" && has at least one ipv6 address
 812		method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
 813	PLUGIN_PRINT (IFNET_PLUGIN_NAME, "IPv6 for %s enabled, using %s",
 814		      conn_name, method);
 815
 816	g_object_set (s_ip6,
 817		      NM_SETTING_IP6_CONFIG_METHOD, method,
 818		      NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, FALSE,
 819		      NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, FALSE,
 820		      NM_SETTING_IP6_CONFIG_NEVER_DEFAULT, never_default, NULL);
 821
 822	/* Make manual settings */
 823	if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
 824		ip6_block *current_iblock;
 825
 826		iblock = convert_ip6_config_block (conn_name);
 827		if (!iblock) {
 828			g_set_error (error, ifnet_plugin_error_quark (), 0,
 829				     "Ifnet plugin: can't aquire ip6 configuration for %s",
 830				     conn_name);
 831			goto error;
 832		}
 833		/* add all IPv6 addresses */
 834		while (iblock) {
 835			NMIP6Address *ip6_addr = nm_ip6_address_new ();
 836
 837			nm_ip6_address_set_address (ip6_addr, iblock->ip);
 838			nm_ip6_address_set_prefix (ip6_addr, iblock->prefix);
 839			if (nm_setting_ip6_config_add_address (s_ip6, ip6_addr)) {
 840				PLUGIN_PRINT (IFNET_PLUGIN_NAME,
 841					      "ipv6 addresses count: %d",
 842					      nm_setting_ip6_config_get_num_addresses
 843					      (s_ip6));
 844			} else {
 845				PLUGIN_WARN (IFNET_PLUGIN_NAME,
 846					     "ignoring duplicate IP4 address");
 847			}
 848			nm_ip6_address_unref (ip6_addr);
 849			current_iblock = iblock;
 850			iblock = iblock->next;
 851			destroy_ip6_block (current_iblock);
 852		}
 853
 854	} else if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
 855		/* - autoconf or DHCPv6 stuff goes here */
 856	}
 857	// DNS Servers, set NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS TRUE here
 858	set_ip6_dns_servers (s_ip6, conn_name);
 859
 860	/* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIP4Config */
 861
 862	// Add routes
 863	iblock = convert_ip6_routes_block (conn_name);
 864	if (iblock)
 865		g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES,
 866			      TRUE, NULL);
 867	/* Add all IPv6 routes */
 868	while (iblock) {
 869		ip6_block *current_iblock = iblock;
 870		const char *metric_str;
 871		char *stripped;
 872		long int metric = 1;
 873		NMIP6Route *route = nm_ip6_route_new ();
 874
 875		nm_ip6_route_set_dest (route, iblock->ip);
 876		nm_ip6_route_set_next_hop (route, iblock->next_hop);
 877		nm_ip6_route_set_prefix (route, iblock->prefix);
 878		/* metric is not per routes configuration right now
 879		 * global metric is also supported (metric="x") */
 880		if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL) {
 881			metric = strtol (metric_str, NULL, 10);
 882			nm_ip6_route_set_metric (route, (guint32) metric);
 883		} else {
 884			metric_str = ifnet_get_global_data ("metric");
 885			if (metric_str) {
 886				stripped = g_strdup (metric_str);
 887				strip_string (stripped, '"');
 888				metric = strtol (metric_str, NULL, 10);
 889				nm_ip6_route_set_metric (route,
 890							 (guint32) metric);
 891				g_free (stripped);
 892			} else
 893				nm_ip6_route_set_metric (route, (guint32) 1);
 894		}
 895
 896		if (!nm_setting_ip6_config_add_route (s_ip6, route))
 897			PLUGIN_WARN (IFNET_PLUGIN_NAME,
 898				     "    warning: duplicate IP6 route");
 899		PLUGIN_PRINT (IFNET_PLUGIN_NAME, "    info: new IP6 route");
 900		nm_ip6_route_unref (route);
 901
 902		current_iblock = iblock;
 903		iblock = iblock->next;
 904		destroy_ip6_block (current_iblock);
 905	}
 906
 907done:
 908	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
 909	return;
 910
 911error:
 912	g_object_unref (s_ip6);
 913	PLUGIN_WARN (IFNET_PLUGIN_NAME, "    warning: Ignore IPv6 for %s",
 914		     conn_name);
 915	return;
 916}
 917
 918static NMSetting *
 919make_wireless_connection_setting (const char *conn_name,
 920                                  NMSetting8021x **s_8021x,
 921                                  GError **error)
 922{
 923	GByteArray *array, *mac = NULL;
 924	NMSettingWireless *wireless_setting = NULL;
 925	gboolean adhoc = FALSE;
 926	const char *value;
 927	const char *type;
 928
 929	/* PPP over WIFI is not supported yet */
 930	g_return_val_if_fail (conn_name != NULL
 931			      && strcmp (ifnet_get_data (conn_name, "type"),
 932					 "ppp") != 0, NULL);
 933	type = ifnet_get_data (conn_name, "type");
 934	if (strcmp (type, "ppp") == 0) {
 935		PLUGIN_WARN (IFNET_PLUGIN_NAME,
 936			     "PPP over WIFI is not supported yet");
 937		return NULL;
 938	}
 939
 940	wireless_setting = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
 941	if (read_mac_address (conn_name, &mac, error)) {
 942		if (mac) {
 943			g_object_set (wireless_setting,
 944				      NM_SETTING_WIRELESS_MAC_ADDRESS, mac,
 945				      NULL);
 946			g_byte_array_free (mac, TRUE);
 947
 948		}
 949	} else {
 950		g_object_unref (wireless_setting);
 951		return NULL;
 952	}
 953
 954	/* handle ssid (hex and ascii) */
 955	if (conn_name) {
 956		gsize ssid_len = 0, value_len = strlen (conn_name);
 957		const char *p;
 958		char *tmp, *converted = NULL;
 959
 960		ssid_len = value_len;
 961		if ((value_len > 2) && (g_str_has_prefix (conn_name, "0x"))) {
 962			/* Hex representation */
 963			if (value_len % 2) {
 964				g_set_error (error, ifnet_plugin_error_quark (),
 965					     0,
 966					     "Invalid SSID '%s' size (looks like hex but length not multiple of 2)",
 967					     conn_name);
 968				goto error;
 969			}
 970			// ignore "0x"
 971			p = conn_name + 2;
 972			if (!is_hex (p)) {
 973				g_set_error (error,
 974					     ifnet_plugin_error_quark (),
 975					     0,
 976					     "Invalid SSID '%s' character (looks like hex SSID but '%c' isn't a hex digit)",
 977					     conn_name, *p);
 978				goto error;
 979
 980			}
 981			tmp = utils_hexstr2bin (p, value_len - 2);
 982			ssid_len = (value_len - 2) / 2;
 983			converted = g_malloc0 (ssid_len + 1);
 984			memcpy (converted, tmp, ssid_len);
 985			g_free (tmp);
 986		}
 987
 988		if (ssid_len > 32 || ssid_len == 0) {
 989			g_set_error (error, ifnet_plugin_error_quark (), 0,
 990				     "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
 991				     conn_name, ssid_len);
 992			goto error;
 993		}
 994		array = g_byte_array_sized_new (ssid_len);
 995		g_byte_array_append (array, (const guint8 *) (converted ? converted : conn_name), ssid_len);
 996		g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, array, NULL);
 997		g_byte_array_free (array, TRUE);
 998		g_free (converted);
 999	} else {
1000		g_set_error (error, ifnet_plugin_error_quark (), 0,
1001			     "Missing SSID");
1002		goto error;
1003	}
1004
1005	/* mode=0: infrastructure
1006	 * mode=1: adhoc */
1007	value = wpa_get_value (conn_name, "mode");
1008	if (value)
1009		adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE;
1010
1011	if (exist_ssid (conn_name)) {
1012		const char *mode = adhoc ? "adhoc" : "infrastructure";
1013
1014		g_object_set (wireless_setting, NM_SETTING_WIRELESS_MODE, mode,
1015			      NULL);
1016		PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Using mode: %s", mode);
1017	}
1018
1019	/* BSSID setting */
1020	value = wpa_get_value (conn_name, "bssid");
1021	if (value) {
1022		GByteArray *bssid;
1023
1024		bssid = nm_utils_hwaddr_atoba (value, ARPHRD_ETHER);
1025		if (!bssid) {
1026			g_set_error (error, ifnet_plugin_error_quark (), 0,
1027						 "Invalid BSSID '%s'", value);
1028			goto error;
1029		}
1030
1031		g_object_set (wireless_setting, NM_SETTING_WIRELESS_BSSID,
1032			      bssid, NULL);
1033		g_byte_array_free (bssid, TRUE);
1034
1035	}
1036
1037	/* mtu_ssid="xx" */
1038	value = ifnet_get_data (conn_name, "mtu");
1039	if (value) {
1040		long int mtu;
1041
1042		errno = 0;
1043		mtu = strtol (value, NULL, 10);
1044		if (errno || mtu < 0 || mtu > 50000) {
1045			PLUGIN_WARN (IFNET_PLUGIN_NAME,
1046				     "    warning: invalid MTU '%s' for %s",
1047				     value, conn_name);
1048		} else
1049			g_object_set (wireless_setting, NM_SETTING_WIRELESS_MTU,
1050				      (guint32) mtu, NULL);
1051
1052	}
1053
1054	PLUGIN_PRINT (IFNET_PLUGIN_NAME, "wireless_setting added for %s",
1055		      conn_name);
1056	return NM_SETTING (wireless_setting);
1057error:
1058	if (wireless_setting)
1059		g_object_unref (wireless_setting);
1060	return NULL;
1061
1062}
1063
1064static NMSettingWirelessSecurity *
1065make_leap_setting (const char *ssid, GError **error)
1066{
1067	NMSettingWirelessSecurity *wsec;
1068	const char *value;
1069
1070	wsec =
1071	    NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
1072
1073	value = wpa_get_value (ssid, "key_mgmt");
1074	if (!value || strcmp (value, "IEEE8021X"))
1075		goto error;	/* Not LEAP */
1076
1077	value = wpa_get_value (ssid, "eap");
1078	if (!value || strcasecmp (value, "LEAP"))
1079		goto error;	/* Not LEAP */
1080
1081	value = wpa_get_value (ssid, "password");
1082	if (value && strlen (value))
1083		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
1084			      value, NULL);
1085
1086	value = wpa_get_value (ssid, "identity");
1087	if (!value || !strlen (value)) {
1088		g_set_error (error, ifnet_plugin_error_quark (), 0,
1089			     "Missing LEAP identity");
1090		goto error;
1091	}
1092	g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value,
1093		      NULL);
1094
1095	g_object_set (wsec,
1096		      NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
1097		      NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", NULL);
1098
1099	return wsec;
1100error:
1101	if (wsec)
1102		g_object_unref (wsec);
1103	return NULL;
1104}
1105
1106static gboolean
1107add_one_wep_key (const char *ssid,
1108                 const char *key,
1109                 int key_idx,
1110                 NMSettingWirelessSecurity *s_wsec,
1111                 GError **error)
1112{
1113	const char *value;
1114	char *converted = NULL;
1115	gboolean success = FALSE;
1116
1117	g_return_val_if_fail (ssid != NULL, FALSE);
1118	g_return_val_if_fail (key != NULL, FALSE);
1119	g_return_val_if_fail (key_idx >= 0 && key_idx <= 3, FALSE);
1120	g_return_val_if_fail (s_wsec != NULL, FALSE);
1121
1122	value = wpa_get_value (ssid, key);
1123	if (!value)
1124		return TRUE;
1125
1126	/* Validate keys */
1127	if (strlen (value) == 10 || strlen (value) == 26) {
1128		/* Hexadecimal WEP key */
1129		if (!is_hex (value)) {
1130			g_set_error (error, ifnet_plugin_error_quark (),
1131				     0, "Invalid hexadecimal WEP key.");
1132			goto out;
1133		}
1134		converted = g_strdup (value);
1135	} else if (value[0] == '"'
1136		   && (strlen (value) == 7 || strlen (value) == 15)) {
1137		/* ASCII passphrase */
1138		char *tmp = g_strdup (value);
1139		char *p = strip_string (tmp, '"');
1140
1141		if (!is_ascii (p)) {
1142			g_set_error (error, ifnet_plugin_error_quark (),
1143				     0, "Invalid ASCII WEP passphrase.");
1144			g_free (tmp);
1145			goto out;
1146
1147		}
1148
1149		converted = utils_bin2hexstr (tmp, strlen (tmp), strlen (tmp) * 2);
1150		g_free (tmp);
1151	} else {
1152		g_set_error (error, ifnet_plugin_error_quark (), 0,
1153			     "Invalid WEP key length. Key: %s", value);
1154		goto out;
1155	}
1156
1157	if (converted) {
1158		nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, converted);
1159		g_free (converted);
1160		success = TRUE;
1161	}
1162
1163out:
1164	return success;
1165}
1166
1167static gboolean
1168add_wep_keys (const char *ssid,
1169              NMSettingWirelessSecurity *s_wsec,
1170              GError **error)
1171{
1172	if (!add_one_wep_key (ssid, "wep_key0", 0, s_wsec, error))
1173		return FALSE;
1174	if (!add_one_wep_key (ssid, "wep_key1", 1, s_wsec, error))
1175		return FALSE;
1176	if (!add_one_wep_key (ssid, "wep_key2", 2, s_wsec, error))
1177		return FALSE;
1178	if (!add_one_wep_key (ssid, "wep_key3", 3, s_wsec, error))
1179		return FALSE;
1180	return TRUE;
1181
1182}
1183
1184static NMSettingWirelessSecurity *
1185make_wep_setting (const char *ssid, GError **error)
1186{
1187	const char *auth_alg, *value;
1188	int default_key_idx = 0;
1189	NMSettingWirelessSecurity *s_wireless_sec;
1190
1191	s_wireless_sec =
1192	    NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
1193	g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
1194		      "none", NULL);
1195
1196	/* default key index */
1197	value = wpa_get_value (ssid, "wep_tx_keyidx");
1198	if (value) {
1199		default_key_idx = atoi (value);
1200		if (default_key_idx >= 0 && default_key_idx <= 3) {
1201			g_object_set (s_wireless_sec,
1202				      NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX,
1203				      default_key_idx, NULL);
1204			PLUGIN_PRINT (IFNET_PLUGIN_NAME,
1205				      "Default key index: %d", default_key_idx);
1206		} else {
1207			g_set_error (error, ifnet_plugin_error_quark (), 0,
1208				     "Invalid default WEP key '%s'", value);
1209			goto error;
1210		}
1211	}
1212
1213	if (!add_wep_keys (ssid, s_wireless_sec, error))
1214		goto error;
1215
1216	/* If there's a default key, ensure that key exists */
1217	if ((default_key_idx == 1)
1218	    && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)) {
1219		g_set_error (error, ifnet_plugin_error_quark (), 0,
1220			     "Default WEP key index was 2, but no valid KEY2 exists.");
1221		goto error;
1222	} else if ((default_key_idx == 2)
1223		   && !nm_setting_wireless_security_get_wep_key (s_wireless_sec,
1224								 2)) {
1225		g_set_error (error, ifnet_plugin_error_quark (), 0,
1226			     "Default WEP key index was 3, but no valid KEY3 exists.");
1227		goto error;
1228	} else if ((default_key_idx == 3)
1229		   && !nm_setting_wireless_security_get_wep_key (s_wireless_sec,
1230								 3)) {
1231		g_set_error (error, ifnet_plugin_error_quark (), 0,
1232			     "Default WEP key index was 4, but no valid KEY4 exists.");
1233		goto error;
1234	}
1235
1236	/* authentication algorithms */
1237	auth_alg = wpa_get_value (ssid, "auth_alg");
1238	if (auth_alg) {
1239		if (strcmp (auth_alg, "OPEN") == 0) {
1240			g_object_set (s_wireless_sec,
1241				      NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
1242				      "open", NULL);
1243			PLUGIN_PRINT (IFNET_PLUGIN_NAME,
1244				      "WEP: Use open system authentication");
1245		} else if (strcmp (auth_alg, "SHARED") == 0) {
1246			g_object_set (s_wireless_sec,
1247				      NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
1248				      "shared", NULL);
1249			PLUGIN_PRINT (IFNET_PLUGIN_NAME,
1250				      "WEP: Use shared system authentication");
1251		} else {
1252			g_set_error (error, ifnet_plugin_error_quark (), 0,
1253				     "Invalid WEP authentication algorithm '%s'",
1254				     auth_alg);
1255			goto error;
1256		}
1257
1258	}
1259
1260	if (!nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0)
1261	    && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)
1262	    && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2)
1263	    && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3)
1264	    && !nm_setting_wireless_security_get_wep_tx_keyidx (s_wireless_sec)) {
1265		if (auth_alg && !strcmp (auth_alg, "shared")) {
1266			g_set_error (error, ifnet_plugin_error_quark (), 0,
1267				     "WEP Shared Key authentication is invalid for "
1268				     "unencrypted connections.");
1269			goto error;
1270		}
1271		/* Unencrypted */
1272		g_object_unref (s_wireless_sec);
1273		s_wireless_sec = NULL;
1274	}
1275	return s_wireless_sec;
1276
1277error:
1278	if (s_wireless_sec)
1279		g_object_unref (s_wireless_sec);
1280	return NULL;
1281}
1282
1283static char *
1284parse_wpa_psk (const char *psk, GError **error)
1285{
1286	char *hashed = NULL;
1287	gboolean quoted = FALSE;
1288
1289	if (!psk) {
1290		g_set_error (error, ifnet_plugin_error_quark (), 0,
1291			     "Missing WPA_PSK for WPA-PSK key management");
1292		return NULL;
1293	}
1294
1295	/* Passphrase must be between 10 and 66 characters in length becuase WPA
1296	 * hex keys are exactly 64 characters (no quoting), and WPA passphrases
1297	 * are between 8 and 63 characters (inclusive), plus optional quoting if
1298	 * the passphrase contains spaces.
1299	 */
1300
1301	if (psk[0] == '"' && psk[strlen (psk) - 1] == '"')
1302		quoted = TRUE;
1303	if (!quoted && (strlen (psk) == 64)) {
1304		/* Verify the hex PSK; 64 digits */
1305		if (!is_hex (psk)) {
1306			g_set_error (error, ifnet_plugin_error_quark (),
1307				     0,
1308				     "Invalid WPA_PSK (contains non-hexadecimal characters)");
1309			goto out;
1310		}
1311		hashed = g_strdup (psk);
1312	} else {
1313		char *stripped = g_strdup (psk);
1314
1315		strip_string (stripped, '"');
1316
1317		/* Length check */
1318		if (strlen (stripped) < 8 || strlen (stripped) > 63) {
1319			g_set_error (error, ifnet_plugin_error_quark (), 0,
1320				     "Invalid WPA_PSK (passphrases must be between "
1321				     "8 and 63 characters long (inclusive))");
1322			g_free (stripped);
1323			goto out;
1324		}
1325
1326		hashed = g_strdup (stripped);
1327		g_free (stripped);
1328	}
1329
1330	if (!hashed) {
1331		g_set_error (error, ifnet_plugin_error_quark (), 0,
1332			     "Invalid WPA_PSK (doesn't look like a passphrase or hex key)");
1333		goto out;
1334	}
1335
1336out:
1337	return hashed;
1338}
1339
1340static gboolean
1341fill_wpa_ciphers (const char *ssid,
1342                  NMSettingWirelessSecurity *wsec,
1343                  gboolean group,
1344                  gboolean adhoc)
1345{
1346	const char *value;
1347	char **list = NULL, **iter;
1348	int i = 0;
1349
1350	value = wpa_get_value (ssid, group ? "group" : "pairwise");
1351	if (!value)
1352		return TRUE;
1353
1354	list = g_strsplit_set (value, " ", 0);
1355	for (iter = list; iter && *iter; iter++, i++) {
1356		/* Ad-Hoc configurations cannot have pairwise ciphers, and can only
1357		 * have one group cipher.  Ignore any additional group ciphers and
1358		 * any pairwise ciphers specified.
1359		 */
1360		if (adhoc) {
1361			if (group && (i > 0)) {
1362				PLUGIN_WARN (IFNET_PLUGIN_NAME,
1363					     "    warning: ignoring group cipher '%s' (only one group cipher allowed in Ad-Hoc mode)",
1364					     *iter);
1365				continue;
1366			} else if (!group) {
1367				PLUGIN_WARN (IFNET_PLUGIN_NAME,
1368					     "    warning: ignoring pairwise cipher '%s' (pairwise not used in Ad-Hoc mode)",
1369					     *iter);
1370				continue;
1371			}
1372		}
1373
1374		if (!strcmp (*iter, "CCMP")) {
1375			if (group)
1376				nm_setting_wireless_security_add_group (wsec,
1377									"ccmp");
1378			else
1379				nm_setting_wireless_security_add_pairwise (wsec,
1380									   "ccmp");
1381		} else if (!strcmp (*iter, "TKIP")) {
1382			if (group)
1383				nm_setting_wireless_security_add_group (wsec,
1384									"tkip");
1385			else
1386				nm_setting_wireless_security_add_pairwise (wsec,
1387									   "tkip");
1388		} else if (group && !strcmp (*iter, "WEP104"))
1389			nm_setting_wireless_security_add_group (wsec, "wep104");
1390		else if (group && !strcmp (*iter, "WEP40"))
1391			nm_setting_wireless_security_add_group (wsec, "wep40");
1392		else {
1393			PLUGIN_WARN (IFNET_PLUGIN_NAME,
1394				     "    warning: ignoring invalid %s cipher '%s'",
1395				     group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE",
1396				     *iter);
1397		}
1398	}
1399
1400	if (list)
1401		g_strfreev (list);
1402	return TRUE;
1403}
1404
1405static NMSetting8021x *
1406fill_8021x (const char *ssid,
1407            const char *key_mgmt,
1408            gboolean wifi,
1409            const char *basepath,
1410            GError **error)
1411{
1412	NMSetting8021x *s_8021x;
1413	const char *value;
1414	char **list, **iter;
1415
1416	value = wpa_get_value (ssid, "eap");
1417	if (!value) {
1418		g_set_error (error, ifnet_plugin_error_quark (), 0,
1419			     "Missing IEEE_8021X_EAP_METHODS for key management '%s'",
1420			     key_mgmt);
1421		return NULL;
1422	}
1423
1424	list = g_strsplit (value, " ", 0);
1425
1426	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
1427	/* Validate and handle each EAP method */
1428	for (iter = list; iter && *iter; iter++) {
1429		EAPReader *eap = &eap_readers[0];
1430		gboolean found = FALSE;
1431		char *lower = NULL;
1432
1433		lower = g_ascii_strdown (*iter, -1);
1434		while (eap->method && !found) {
1435			if (strcmp (eap->method, lower))
1436				goto next;
1437
1438			/* Some EAP methods don't provide keying material, thus they
1439			 * cannot be used with WiFi unless they are an inner method
1440			 * used with TTLS or PEAP or whatever.
1441			 */
1442			if (wifi && eap->wifi_phase2_only) {
1443				PLUGIN_WARN (IFNET_PLUGIN_NAME,
1444					     "    warning: ignored invalid "
1445					     "IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
1446					     lower);
1447				goto next;
1448			}
1449
1450			/* Parse EAP method specific options */
1451			if (!(*eap->reader) (lower, ssid, s_8021x, FALSE, basepath, error)) {
1452				g_free (lower);
1453				goto error;
1454			}
1455			nm_setting_802_1x_add_eap_method (s_8021x, lower);
1456			found = TRUE;
1457
1458		next:
1459			eap++;
1460		}
1461
1462		if (!found) {
1463			PLUGIN_WARN (IFNET_PLUGIN_NAME,
1464				     "    warning: ignored unknown"
1465				     "IEEE_8021X_EAP_METHOD '%s'.", lower);
1466		}
1467		g_free (lower);
1468	}
1469	g_strfreev (list);
1470
1471	if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) {
1472		g_set_error (error, ifnet_plugin_error_quark (), 0,
1473			     "No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
1474		goto error;
1475	}
1476
1477	return s_8021x;
1478
1479error:
1480	g_object_unref (s_8021x);
1481	return NULL;
1482}
1483
1484static NMSettingWirelessSecurity *
1485make_wpa_setting (const char *ssid,
1486                  const char *basepath,
1487                  NMSetting8021x **s_8021x,
1488                  GError **error)
1489{
1490	NMSettingWirelessSecurity *wsec;
1491	const char *value;
1492	char *lower;
1493	gboolean adhoc = FALSE;
1494
1495	if (!exist_ssid (ssid)) {
1496		g_set_error (error, ifnet_plugin_error_quark (), 0,
1497			     "No security info found for ssid: %s", ssid);
1498		return NULL;
1499	}
1500
1501	wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
1502
1503	/* mode=1: adhoc
1504	 * mode=0: infrastructure */
1505	value = wpa_get_value (ssid, "mode");
1506	if (value)
1507		adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE;
1508
1509	value = wpa_get_value (ssid, "key_mgmt");
1510	/* Not WPA or Dynamic WEP */
1511	if (!value)
1512		goto error;
1513	if (strcmp (value, "WPA-PSK") && strcmp (value, "WPA-EAP"))
1514		goto error;
1515	/* Pairwise and Group ciphers */
1516	fill_wpa_ciphers (ssid, wsec, FALSE, adhoc);
1517	fill_wpa_ciphers (ssid, wsec, TRUE, adhoc);
1518
1519	/* WPA and/or RSN */
1520	if (adhoc) {
1521		/* Ad-Hoc mode only supports WPA proto for now */
1522		nm_setting_wireless_security_add_proto (wsec, "wpa");
1523	} else {
1524		nm_setting_wireless_security_add_proto (wsec, "wpa");
1525		nm_setting_wireless_security_add_proto (wsec, "rsn");
1526
1527	}
1528
1529	if (!strcmp (value, "WPA-PSK")) {
1530		char *psk = parse_wpa_psk (wpa_get_value (ssid, "psk"), error);
1531
1532		if (!psk)
1533			goto error;
1534		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk,
1535			      NULL);
1536		g_free (psk);
1537
1538		if (adhoc)
1539			g_object_set (wsec,
1540				      NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
1541				      "wpa-none", NULL);
1542		else
1543			g_object_set (wsec,
1544				      NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
1545				      "wpa-psk", NULL);
1546	} else if (!strcmp (value, "WPA-EAP") || !strcmp (value, "IEEE8021X")) {
1547		if (adhoc) {
1548			g_set_error (error, ifnet_plugin_error_quark (), 0,
1549				     "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'",
1550				     value);
1551			goto error;
1552		}
1553		*s_8021x = fill_8021x (ssid, value, TRUE, basepath, error);
1554		if (!*s_8021x)
1555			goto error;
1556
1557		lower = g_ascii_strdown (value, -1);
1558		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
1559			      lower, NULL);
1560		g_free (lower);
1561	} else {
1562		g_set_error (error, ifnet_plugin_error_quark (), 0,
1563			     "Unknown wireless KEY_MGMT type '%s'", value);
1564		goto error;
1565	}
1566	return wsec;
1567error:
1568	if (wsec)
1569		g_object_unref (wsec);
1570	return NULL;
1571}
1572
1573static NMSettingWirelessSecurity *
1574make_wireless_security_setting (const char *conn_name,
1575                                const char *basepath,
1576                                NMSetting8021x **s_8021x,
1577                                GError ** error)
1578{
1579	NMSettingWirelessSecurity *wsec = NULL;
1580	const char *ssid;
1581	gboolean adhoc = FALSE;
1582	const char *value;
1583
1584	g_return_val_if_fail (conn_name != NULL
1585			      && strcmp (ifnet_get_data (conn_name, "type"),
1586					 "ppp") != 0, NULL);
1587	if (!wpa_get_value (conn_name, "ssid"))
1588		return NULL;
1589	PLUGIN_PRINT (IFNET_PLUGIN_NAME,
1590		      "updating wireless security settings (%s).", conn_name);
1591
1592	ssid = conn_name;
1593	value = wpa_get_value (ssid, "mode");
1594	if (value)
1595		adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE;
1596
1597	if (!adhoc) {
1598		wsec = make_leap_setting (ssid, error);
1599		if (error && *error)
1600			goto error;
1601	}
1602	if (!wsec) {
1603		wsec = make_wpa_setting (ssid, basepath, s_8021x, error);
1604		if (error && *error)
1605			goto error;
1606	}
1607	if (!wsec) {
1608		wsec = make_wep_setting (ssid, error);
1609		if (error && *error)
1610			goto error;
1611	}
1612
1613	if (!wsec) {
1614		g_set_error (error, ifnet_plugin_error_quark (), 0,
1615			     "Can't handle security information for ssid: %s",
1616			     conn_name);
1617	}
1618
1619	return wsec;
1620error:
1621	return NULL;
1622}
1623
1624/* Currently only support username and password */
1625static void
1626make_pppoe_connection_setting (NMConnection *connection,
1627                               const char *conn_name,
1628                               GError **error)
1629{
1630	NMSettingPPPOE *s_pppoe;
1631	NMSettingPPP *s_ppp;
1632	const char *value;
1633
1634	s_pppoe = NM_SETTING_PPPOE (nm_setting_pppoe_new ());
1635
1636	/* username */
1637	value = ifnet_get_data (conn_name, "username");
1638	if (!value) {
1639		g_set_error (error, ifnet_plugin_error_quark (), 0,
1640			     "ppp requires at lease a username");
1641		return;
1642	}
1643	g_object_set (s_pppoe, NM_SETTING_PPPOE_USERNAME, value, NULL);
1644
1645	/* password */
1646	value = ifnet_get_data (conn_name, "password");
1647	if (!value) {
1648		value = "";
1649	}
1650
1651	g_object_set (s_pppoe, NM_SETTING_PPPOE_PASSWORD, value, NULL);
1652	nm_connection_add_setting (connection, NM_SETTING (s_pppoe));
1653
1654	/* PPP setting */
1655	s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
1656	nm_connection_add_setting (connection, NM_SETTING (s_ppp));
1657}
1658
1659NMConnection *
1660ifnet_update_connection_from_config_block (const char *conn_name,
1661                                           const char *basepath,
1662                                           GError **error)
1663{
1664	const gchar *type = NULL;
1665	NMConnection *connection = NULL;
1666	NMSettingConnection *setting = NULL;
1667	NMSetting8021x *s_8021x = NULL;
1668	NMSettingWirelessSecurity *wsec = NULL;
1669	gboolean auto_conn = TRUE;
1670	const char *value = NULL;
1671	gboolean success = FALSE;
1672
1673	connection = nm_connection_new ();
1674	if (!connection)
1675		return NULL;
1676	setting = nm_connection_get_setting_connection (connection);
1677	if (!setting) {
1678		setting = NM_SETTING_CONNECTION (nm_setting_connection_new ());
1679		g_assert (setting);
1680		nm_connection_add_setting (connection, NM_SETTING (setting));
1681	}
1682
1683	type = guess_connection_type (conn_name);
1684	value = ifnet_get_data (conn_name, "auto");
1685	if (value && !strcmp (value, "false"))
1686		auto_conn = FALSE;
1687	update_connection_id (connection, conn_name);
1688	g_object_set (setting, NM_SETTING_CONNECTION_TYPE, type,
1689		      NM_SETTING_CONNECTION_READ_ONLY, FALSE,
1690		      NM_SETTING_CONNECTION_AUTOCONNECT, auto_conn, NULL);
1691
1692	if (!strcmp (NM_SETTING_WIRED_SETTING_NAME, type)
1693	    || !strcmp (NM_SETTING_PPPOE_SETTING_NAME, type)) {
1694		/* wired setting */
1695		make_wired_connection_setting (connection, conn_name, error);
1696		if (error && *error) {
1697			PLUGIN_WARN (IFNET_PLUGIN_NAME,
1698				     "Found error: %s", (*error)->message);
1699			goto error;
1700		}
1701		/* pppoe setting */
1702		if (!strcmp (NM_SETTING_PPPOE_SETTING_NAME, type))
1703			make_pppoe_connection_setting (connection, conn_name,
1704						       error);
1705		if (error && *error) {
1706			PLUGIN_WARN (IFNET_PLUGIN_NAME,
1707				     "Found error: %s", (*error)->message);
1708			goto error;
1709		}
1710	} else if (!strcmp (NM_SETTING_WIRELESS_SETTING_NAME, type)) {
1711		/* wireless setting */
1712		NMSetting *wireless_setting;
1713
1714		wireless_setting = make_wireless_connection_setting (conn_name, &s_8021x, error);
1715		if (!wireless_setting)
1716			goto error;
1717		nm_connection_add_setting (connection, wireless_setting);
1718
1719		if (error && *error) {
1720			PLUGIN_WARN (IFNET_PLUGIN_NAME,
1721				     "Found error: …

Large files files are truncated, but you can click here to view the full file