NetworkManager/src/settings/plugins/ifcfg-rh/reader.c

5110 lines
147 KiB
C
Raw Normal View History

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* 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 2008 - 2015 Red Hat, Inc.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/inotify.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <nm-connection.h>
#include <nm-dbus-interface.h>
#include <nm-setting-connection.h>
#include <nm-setting-ip4-config.h>
#include <nm-setting-vlan.h>
#include <nm-setting-ip6-config.h>
#include <nm-setting-wired.h>
#include <nm-setting-wireless.h>
#include <nm-setting-8021x.h>
#include <nm-setting-bond.h>
#include <nm-setting-team.h>
#include <nm-setting-team-port.h>
#include <nm-setting-bridge.h>
#include <nm-setting-bridge-port.h>
#include <nm-setting-dcb.h>
#include <nm-setting-generic.h>
#include "nm-default.h"
#include "nm-core-internal.h"
#include <nm-utils.h>
#include "nm-platform.h"
#include "NetworkManagerUtils.h"
#include "common.h"
#include "shvar.h"
#include "utils.h"
2008-02-07 Dan Williams <dcbw@redhat.com> * system-settings/src/dbus-settings.c system-settings/src/dbus-settings.h - (add_one_secret_to_hash): copy secrets out of the plugin-returned hash table of secrets - (connection_settings_get_secrets): consolidate error returns into one place; use the new get_secrets() plugin interface function to get secrets from the plugin itself rather than using GObject data magic * system-settings/src/main.c - (connection_added_cb, connection_removed_cb, free_plugin_connections, load_connections): keep a private list of the plugin-returned connections, don't use the plugin's GSList * system-settings/plugins/ifcfg-fedora/plugin.c - (watch_path): watch the path, not the filename (duh) - (reload_all_connections): use the direct hash/equal functions; the ones for int aren't appropriate here - (get_secrets, system_config_interface_init): implement the get_secrets() function - (build_one_connection, find_connection_by_path): ifcfg file path is now in the connection's ConnectionData instead of being a GObject data property - (handle_profile_item_changed): ifcfg file path is now in the connection's ConnectionData instead of being a GObject data property; be sure to copy secrets over from the new connection to the existing connection when updating the connection's settings - (init): sc_plugin_inotify_init() returns success/fail, not the inotify file descriptor * system-settings/plugins/ifcfg-fedora/parser.c system-settings/plugins/ifcfg-fedora/parser.h - (connection_data_get, copy_one_cdata_secret, clear_one_cdata_secret, connection_data_copy_secrets, connection_data_free, connection_data_add): new functions; connection data manipulation - (make_wireless_security_setting): stuff secrets into the connection data, not as GObject data items; make sure to close the keys ifcfg file - (wireless_connection_from_ifcfg, wired_connection_from_ifcfg): add connection data to the connection git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3299 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-02-07 20:11:31 +00:00
#include "reader.h"
#define PARSE_WARNING(msg...) nm_log_warn (LOGD_SETTINGS, " " msg)
2008-02-07 Dan Williams <dcbw@redhat.com> * system-settings/src/dbus-settings.c system-settings/src/dbus-settings.h - (add_one_secret_to_hash): copy secrets out of the plugin-returned hash table of secrets - (connection_settings_get_secrets): consolidate error returns into one place; use the new get_secrets() plugin interface function to get secrets from the plugin itself rather than using GObject data magic * system-settings/src/main.c - (connection_added_cb, connection_removed_cb, free_plugin_connections, load_connections): keep a private list of the plugin-returned connections, don't use the plugin's GSList * system-settings/plugins/ifcfg-fedora/plugin.c - (watch_path): watch the path, not the filename (duh) - (reload_all_connections): use the direct hash/equal functions; the ones for int aren't appropriate here - (get_secrets, system_config_interface_init): implement the get_secrets() function - (build_one_connection, find_connection_by_path): ifcfg file path is now in the connection's ConnectionData instead of being a GObject data property - (handle_profile_item_changed): ifcfg file path is now in the connection's ConnectionData instead of being a GObject data property; be sure to copy secrets over from the new connection to the existing connection when updating the connection's settings - (init): sc_plugin_inotify_init() returns success/fail, not the inotify file descriptor * system-settings/plugins/ifcfg-fedora/parser.c system-settings/plugins/ifcfg-fedora/parser.h - (connection_data_get, copy_one_cdata_secret, clear_one_cdata_secret, connection_data_copy_secrets, connection_data_free, connection_data_add): new functions; connection data manipulation - (make_wireless_security_setting): stuff secrets into the connection data, not as GObject data items; make sure to close the keys ifcfg file - (wireless_connection_from_ifcfg, wired_connection_from_ifcfg): add connection data to the connection git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3299 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-02-07 20:11:31 +00:00
static gboolean
get_int (const char *str, int *value)
{
char *e;
long int tmp;
errno = 0;
tmp = strtol (str, &e, 0);
if (errno || *e != '\0' || tmp > G_MAXINT || tmp < G_MININT)
return FALSE;
*value = (int) tmp;
return TRUE;
}
static gboolean
get_uint (const char *str, guint32 *value)
{
char *e;
long unsigned int tmp;
errno = 0;
tmp = strtoul (str, &e, 0);
if (errno || *e != '\0')
return FALSE;
*value = (guint32) tmp;
return TRUE;
}
static char *
make_connection_name (shvarFile *ifcfg,
const char *ifcfg_name,
const char *suggested,
const char *prefix)
{
char *full_name = NULL, *name;
/* If the ifcfg file already has a NAME, always use that */
name = svGetValue (ifcfg, "NAME", FALSE);
if (name && strlen (name))
return name;
/* Otherwise construct a new NAME */
g_free (name);
if (!prefix)
prefix = _("System");
/* For cosmetic reasons, if the suggested name is the same as
* the ifcfg files name, don't use it. Mainly for wifi so that
* the SSID is shown in the connection ID instead of just "wlan0".
*/
if (suggested && strcmp (ifcfg_name, suggested))
full_name = g_strdup_printf ("%s %s (%s)", prefix, suggested, ifcfg_name);
else
full_name = g_strdup_printf ("%s %s", prefix, ifcfg_name);
return full_name;
}
static NMSetting *
make_connection_setting (const char *file,
shvarFile *ifcfg,
const char *type,
const char *suggested,
const char *prefix)
{
NMSettingConnection *s_con;
NMSettingConnectionLldp lldp;
const char *ifcfg_name = NULL;
char *new_id, *uuid = NULL, *zone = NULL, *value;
ifcfg_name = utils_get_ifcfg_name (file, TRUE);
if (!ifcfg_name)
return NULL;
s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
new_id = make_connection_name (ifcfg, ifcfg_name, suggested, prefix);
g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
g_free (new_id);
/* Try for a UUID key before falling back to hashing the file name */
uuid = svGetValue (ifcfg, "UUID", FALSE);
if (!uuid || !strlen (uuid)) {
g_free (uuid);
uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
}
g_object_set (s_con,
NM_SETTING_CONNECTION_TYPE, type,
NM_SETTING_CONNECTION_UUID, uuid,
NULL);
g_free (uuid);
value = svGetValue (ifcfg, "DEVICE", FALSE);
if (value) {
if (nm_utils_iface_valid_name (value)) {
g_object_set (s_con,
NM_SETTING_CONNECTION_INTERFACE_NAME, value,
NULL);
} else
PARSE_WARNING ("invalid DEVICE name '%s'", value);
g_free (value);
}
value = svGetValue (ifcfg, "LLDP", FALSE);
if (!g_strcmp0 (value, "rx"))
lldp = NM_SETTING_CONNECTION_LLDP_ENABLE_RX;
else
lldp = svParseBoolean (value, NM_SETTING_CONNECTION_LLDP_DEFAULT);
g_free (value);
/* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */
g_object_set (s_con,
NM_SETTING_CONNECTION_AUTOCONNECT,
svGetValueBoolean (ifcfg, "ONBOOT", TRUE),
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY,
(gint) svGetValueInt64 (ifcfg, "AUTOCONNECT_PRIORITY", 10,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT),
NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES,
svGetValueBoolean (ifcfg, "AUTOCONNECT_SLAVES", NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT),
NM_SETTING_CONNECTION_LLDP, lldp,
NULL);
value = svGetValue (ifcfg, "USERS", FALSE);
if (value) {
char **items, **iter;
items = g_strsplit_set (value, " ", -1);
for (iter = items; iter && *iter; iter++) {
if (strlen (*iter)) {
if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL))
PARSE_WARNING ("invalid USERS item '%s'", *iter);
}
}
g_free (value);
g_strfreev (items);
}
zone = svGetValue(ifcfg, "ZONE", FALSE);
if (!zone || !strlen (zone)) {
g_free (zone);
zone = NULL;
}
g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL);
g_free (zone);
value = svGetValue (ifcfg, "SECONDARY_UUIDS", FALSE);
if (value) {
char **items, **iter;
items = g_strsplit_set (value, " \t", -1);
for (iter = items; iter && *iter; iter++) {
if (strlen (*iter)) {
if (!nm_setting_connection_add_secondary (s_con, *iter))
PARSE_WARNING ("secondary connection UUID '%s' already added", *iter);
}
}
g_free (value);
g_strfreev (items);
}
value = svGetValue (ifcfg, "BRIDGE", FALSE);
if (value) {
const char *old_value;
if ((old_value = nm_setting_connection_get_master (s_con))) {
PARSE_WARNING ("Already configured as slave of %s. Ignoring BRIDGE=\"%s\"",
old_value, value);
} else {
g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE,
NM_SETTING_BRIDGE_SETTING_NAME, NULL);
}
g_free (value);
}
value = svGetValue (ifcfg, "GATEWAY_PING_TIMEOUT", FALSE);
if (value) {
long int tmp;
guint32 timeout;
errno = 0;
tmp = strtol (value, NULL, 10);
if (errno == 0 && tmp >= 0 && tmp < G_MAXINT32) {
timeout = (guint32) tmp;
g_object_set (s_con, NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, timeout, NULL);
} else
PARSE_WARNING ("invalid GATEWAY_PING_TIMEOUT time");
g_free (value);
}
switch (svGetValueBoolean (ifcfg, "CONNECTION_METERED", -1)) {
case TRUE:
g_object_set (s_con, NM_SETTING_CONNECTION_METERED, NM_METERED_YES, NULL);
break;
case FALSE:
g_object_set (s_con, NM_SETTING_CONNECTION_METERED, NM_METERED_NO, NULL);
break;
}
return NM_SETTING (s_con);
}
/* Returns TRUE on missing address or valid address */
static gboolean
read_ip4_address (shvarFile *ifcfg,
const char *tag,
char **out_addr,
GError **error)
{
char *value = NULL;
g_return_val_if_fail (ifcfg != NULL, FALSE);
g_return_val_if_fail (tag != NULL, FALSE);
g_return_val_if_fail (out_addr != NULL, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
*out_addr = NULL;
value = svGetValue (ifcfg, tag, FALSE);
if (!value)
return TRUE;
if (nm_utils_ipaddr_valid (AF_INET, value)) {
*out_addr = value;
return TRUE;
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid %s IP4 address '%s'", tag, value);
g_free (value);
return FALSE;
}
}
static char *
get_numbered_tag (char *tag_name, int which)
{
if (which == -1)
return g_strdup (tag_name);
return g_strdup_printf ("%s%u", tag_name, which);
}
static gboolean
is_any_ip4_address_defined (shvarFile *ifcfg, int *idx)
{
int i, ignore, *ret_idx;;
ret_idx = idx ? idx : &ignore;
for (i = -1; i <= 2; i++) {
char *tag;
char *value;
tag = get_numbered_tag ("IPADDR", i);
value = svGetValue (ifcfg, tag, FALSE);
g_free (tag);
if (value) {
g_free (value);
*ret_idx = i;
return TRUE;
}
tag = get_numbered_tag ("PREFIX", i);
value = svGetValue (ifcfg, tag, FALSE);
g_free(tag);
if (value) {
g_free (value);
*ret_idx = i;
return TRUE;
}
tag = get_numbered_tag ("NETMASK", i);
value = svGetValue (ifcfg, tag, FALSE);
g_free(tag);
if (value) {
g_free (value);
*ret_idx = i;
return TRUE;
}
}
return FALSE;
}
/* Returns TRUE on missing address or valid address */
static gboolean
read_full_ip4_address (shvarFile *ifcfg,
gint32 which,
NMIPAddress *base_addr,
NMIPAddress **out_address,
char **out_gateway,
GError **error)
{
char *ip_tag, *prefix_tag, *netmask_tag, *gw_tag;
char *ip = NULL;
long prefix = 0;
gboolean success = FALSE;
char *value;
guint32 tmp;
g_return_val_if_fail (which >= -1, FALSE);
g_return_val_if_fail (ifcfg != NULL, FALSE);
g_return_val_if_fail (out_address != NULL, FALSE);
g_return_val_if_fail (*out_address == NULL, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
ip_tag = get_numbered_tag ("IPADDR", which);
prefix_tag = get_numbered_tag ("PREFIX", which);
netmask_tag = get_numbered_tag ("NETMASK", which);
gw_tag = get_numbered_tag ("GATEWAY", which);
/* IP address */
if (!read_ip4_address (ifcfg, ip_tag, &ip, error))
goto done;
if (!ip) {
if (base_addr)
ip = g_strdup (nm_ip_address_get_address (base_addr));
else {
success = TRUE;
goto done;
}
}
/* Gateway */
if (out_gateway && !*out_gateway) {
if (!read_ip4_address (ifcfg, gw_tag, out_gateway, error))
goto done;
}
/* Prefix */
value = svGetValue (ifcfg, prefix_tag, FALSE);
if (value) {
errno = 0;
prefix = strtol (value, NULL, 10);
if (errno || prefix < 0) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP4 prefix '%s'", value);
g_free (value);
goto done;
}
g_free (value);
}
/* Fall back to NETMASK if no PREFIX was specified */
if (prefix == 0) {
if (!read_ip4_address (ifcfg, netmask_tag, &value, error))
goto done;
if (value) {
inet_pton (AF_INET, value, &tmp);
prefix = nm_utils_ip4_netmask_to_prefix (tmp);
g_free (value);
}
}
if (prefix == 0 && base_addr)
prefix = nm_ip_address_get_prefix (base_addr);
/* Try to autodetermine the prefix for the address' class */
if (prefix == 0) {
if (inet_pton (AF_INET, ip, &tmp) == 1) {
prefix = nm_utils_ip4_get_default_prefix (tmp);
PARSE_WARNING ("missing %s, assuming %s/%ld", prefix_tag, ip, prefix);
}
}
/* Validate the prefix */
if (prefix == 0) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IP4 prefix");
goto done;
}
*out_address = nm_ip_address_new (AF_INET, ip, prefix, error);
if (*out_address)
success = TRUE;
done:
g_free (ip);
g_free (ip_tag);
g_free (prefix_tag);
g_free (netmask_tag);
g_free (gw_tag);
return success;
}
/* Returns TRUE on missing route or valid route */
static gboolean
read_one_ip4_route (shvarFile *ifcfg,
guint32 which,
NMIPRoute **out_route,
GError **error)
{
char *ip_tag, *netmask_tag, *gw_tag, *metric_tag, *value;
char *dest = NULL, *next_hop = NULL;
gint64 prefix, metric;
gboolean success = FALSE;
g_return_val_if_fail (ifcfg != NULL, FALSE);
g_return_val_if_fail (out_route != NULL, FALSE);
g_return_val_if_fail (*out_route == NULL, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
ip_tag = g_strdup_printf ("ADDRESS%u", which);
netmask_tag = g_strdup_printf ("NETMASK%u", which);
gw_tag = g_strdup_printf ("GATEWAY%u", which);
metric_tag = g_strdup_printf ("METRIC%u", which);
/* Destination */
if (!read_ip4_address (ifcfg, ip_tag, &dest, error))
goto out;
if (!dest) {
/* Check whether IP is missing or 0.0.0.0 */
char *val;
val = svGetValue (ifcfg, ip_tag, FALSE);
if (!val) {
*out_route = NULL;
success = TRUE; /* missing route = success */
goto out;
}
g_free (val);
}
/* Next hop */
if (!read_ip4_address (ifcfg, gw_tag, &next_hop, error))
goto out;
/* We don't make distinction between missing GATEWAY IP and 0.0.0.0 */
/* Prefix */
if (!read_ip4_address (ifcfg, netmask_tag, &value, error))
goto out;
if (value) {
guint32 netmask;
inet_pton (AF_INET, value, &netmask);
prefix = nm_utils_ip4_netmask_to_prefix (netmask);
g_free (value);
if (prefix == 0 || netmask != nm_utils_ip4_prefix_to_netmask (prefix)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, NULL));
goto out;
}
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IP4 route element '%s'", netmask_tag);
goto out;
}
/* Metric */
value = svGetValue (ifcfg, metric_tag, FALSE);
if (value) {
metric = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1);
if (metric < 0) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP4 route metric '%s'", value);
g_free (value);
goto out;
}
g_free (value);
} else
metric = -1;
*out_route = nm_ip_route_new (AF_INET, dest, prefix, next_hop, metric, error);
if (*out_route)
success = TRUE;
out:
g_free (dest);
g_free (next_hop);
g_free (ip_tag);
g_free (netmask_tag);
g_free (gw_tag);
g_free (metric_tag);
return success;
}
static gboolean
read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error)
{
char *contents = NULL;
gsize len = 0;
char **lines = NULL, **iter;
GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
GMatchInfo *match_info;
gint64 prefix_int, metric_int;
gboolean success = FALSE;
const char *pattern_empty = "^\\s*(\\#.*)?$";
const char *pattern_to1 = "^\\s*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */
"(?:/(\\d{1,2}))?"; /* optional prefix */
const char *pattern_to2 = "to\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */
"(?:/(\\d{1,2}))?"; /* optional prefix */
const char *pattern_via = "via\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})"; /* IP of gateway */
const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (s_ip4 != NULL, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
/* Read the route file */
if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) {
g_free (contents);
return TRUE; /* missing/empty = success */
}
/* Create regexes for pieces to be matched */
regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
regex_via = g_regex_new (pattern_via, 0, 0, NULL);
regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
/* Iterate through file lines */
lines = g_strsplit_set (contents, "\n\r", -1);
for (iter = lines; iter && *iter; iter++) {
2015-02-07 16:54:01 +01:00
gs_free char *next_hop = NULL, *dest = NULL;
char *prefix, *metric;
NMIPRoute *route;
/* Skip empty lines */
if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
continue;
/* Destination */
g_regex_match (regex_to1, *iter, 0, &match_info);
if (!g_match_info_matches (match_info)) {
g_match_info_free (match_info);
g_regex_match (regex_to2, *iter, 0, &match_info);
if (!g_match_info_matches (match_info)) {
g_match_info_free (match_info);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IP4 route destination address in record: '%s'", *iter);
goto error;
}
}
dest = g_match_info_fetch (match_info, 1);
if (!strcmp (dest, "default"))
2015-02-07 16:54:01 +01:00
strcpy (dest, "0.0.0.0");
if (!nm_utils_ipaddr_valid (AF_INET, dest)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP4 route destination address '%s'", dest);
g_match_info_free (match_info);
goto error;
}
/* Prefix - is optional; 32 if missing */
prefix = g_match_info_fetch (match_info, 2);
g_match_info_free (match_info);
prefix_int = 32;
if (prefix) {
errno = 0;
prefix_int = strtol (prefix, NULL, 10);
if (errno || prefix_int <= 0 || prefix_int > 32) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP4 route destination prefix '%s'", prefix);
g_free (prefix);
goto error;
}
}
g_free (prefix);
/* Next hop */
g_regex_match (regex_via, *iter, 0, &match_info);
if (g_match_info_matches (match_info)) {
next_hop = g_match_info_fetch (match_info, 1);
if (!nm_utils_ipaddr_valid (AF_INET, next_hop)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP4 route gateway address '%s'",
next_hop);
g_match_info_free (match_info);
goto error;
}
} else {
/* we don't make distinction between missing GATEWAY IP and 0.0.0.0 */
}
g_match_info_free (match_info);
/* Metric */
g_regex_match (regex_metric, *iter, 0, &match_info);
metric_int = -1;
if (g_match_info_matches (match_info)) {
metric = g_match_info_fetch (match_info, 1);
errno = 0;
metric_int = strtol (metric, NULL, 10);
if (errno || metric_int < 0) {
g_match_info_free (match_info);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP4 route metric '%s'", metric);
g_free (metric);
goto error;
}
g_free (metric);
}
g_match_info_free (match_info);
route = nm_ip_route_new (AF_INET, dest, prefix_int, next_hop, metric_int, error);
2015-02-07 16:54:01 +01:00
if (!route)
goto error;
if (!nm_setting_ip_config_add_route (s_ip4, route))
PARSE_WARNING ("duplicate IP4 route");
2015-02-07 16:54:01 +01:00
nm_ip_route_unref (route);
}
success = TRUE;
error:
g_free (contents);
g_strfreev (lines);
g_regex_unref (regex_to1);
g_regex_unref (regex_to2);
g_regex_unref (regex_via);
g_regex_unref (regex_metric);
return success;
}
2015-03-26 14:56:00 +01:00
static void
parse_dns_options (NMSettingIPConfig *ip_config, char *value)
{
char **options = NULL;
g_return_if_fail (ip_config);
if (!value)
return;
if (!nm_setting_ip_config_has_dns_options (ip_config))
nm_setting_ip_config_clear_dns_options (ip_config, TRUE);
2015-03-26 14:56:00 +01:00
options = g_strsplit (value, " ", 0);
if (options) {
char **item;
for (item = options; *item; item++) {
if (strlen (*item)) {
if (!nm_setting_ip_config_add_dns_option (ip_config, *item))
PARSE_WARNING ("can't add DNS option '%s'", *item);
}
}
g_strfreev (options);
}
}
static gboolean
parse_full_ip6_address (shvarFile *ifcfg,
const char *addr_str,
int i,
NMIPAddress **out_address,
GError **error)
{
char **list;
char *ip_val, *prefix_val;
long prefix;
gboolean success = FALSE;
g_return_val_if_fail (addr_str != NULL, FALSE);
g_return_val_if_fail (out_address != NULL, FALSE);
g_return_val_if_fail (*out_address == NULL, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
/* Split the address and prefix */
list = g_strsplit_set (addr_str, "/", 2);
if (g_strv_length (list) < 1) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP6 address '%s'", addr_str);
goto error;
}
ip_val = list[0];
prefix_val = list[1];
if (prefix_val) {
errno = 0;
prefix = strtol (prefix_val, NULL, 10);
if (errno || prefix <= 0 || prefix > 128) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP6 prefix '%s'", prefix_val);
goto error;
}
} else {
/* Missing prefix is treated as prefix of 64 */
prefix = 64;
}
*out_address = nm_ip_address_new (AF_INET6, ip_val, prefix, error);
if (*out_address)
success = TRUE;
error:
g_strfreev (list);
return success;
}
/* IPv6 address is very complex to describe completely by a regular expression,
* so don't try to, rather use looser syntax to comprise all possibilities
* NOTE: The regexes below don't describe all variants allowed by 'ip route add',
* namely destination IP without 'to' keyword is recognized just at line start.
*/
#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
static gboolean
read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error)
{
char *contents = NULL;
gsize len = 0;
char **lines = NULL, **iter;
GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
GMatchInfo *match_info;
char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
gint64 prefix_int, metric_int;
gboolean success = FALSE;
const char *pattern_empty = "^\\s*(\\#.*)?$";
const char *pattern_to1 = "^\\s*(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */
"(?:/(\\d{1,3}))?"; /* optional prefix */
const char *pattern_to2 = "to\\s+(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */
"(?:/(\\d{1,3}))?"; /* optional prefix */
const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")"; /* IPv6 of gateway */
const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (s_ip6 != NULL, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
/* Read the route file */
if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) {
g_free (contents);
return TRUE; /* missing/empty = success */
}
/* Create regexes for pieces to be matched */
regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
regex_via = g_regex_new (pattern_via, 0, 0, NULL);
regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
/* Iterate through file lines */
lines = g_strsplit_set (contents, "\n\r", -1);
for (iter = lines; iter && *iter; iter++) {
2015-02-07 16:54:01 +01:00
NMIPRoute *route;
/* Skip empty lines */
if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
continue;
/* Destination */
g_regex_match (regex_to1, *iter, 0, &match_info);
if (!g_match_info_matches (match_info)) {
g_match_info_free (match_info);
g_regex_match (regex_to2, *iter, 0, &match_info);
if (!g_match_info_matches (match_info)) {
g_match_info_free (match_info);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IP6 route destination address in record: '%s'", *iter);
goto error;
}
}
dest = g_match_info_fetch (match_info, 1);
if (!g_strcmp0 (dest, "default")) {
/* Ignore default route - NM handles it internally */
g_clear_pointer (&dest, g_free);
g_match_info_free (match_info);
PARSE_WARNING ("ignoring manual default route: '%s' (%s)", *iter, filename);
continue;
}
/* Prefix - is optional; 128 if missing */
prefix = g_match_info_fetch (match_info, 2);
g_match_info_free (match_info);
prefix_int = 128;
if (prefix) {
errno = 0;
prefix_int = strtol (prefix, NULL, 10);
if (errno || prefix_int <= 0 || prefix_int > 128) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP6 route destination prefix '%s'", prefix);
g_free (dest);
g_free (prefix);
goto error;
}
}
g_free (prefix);
/* Next hop */
g_regex_match (regex_via, *iter, 0, &match_info);
if (g_match_info_matches (match_info)) {
next_hop = g_match_info_fetch (match_info, 1);
if (!nm_utils_ipaddr_valid (AF_INET6, next_hop)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IPv6 route nexthop address '%s'",
next_hop);
g_match_info_free (match_info);
g_free (dest);
g_free (next_hop);
goto error;
}
} else {
/* Missing "via" is taken as :: */
next_hop = NULL;
}
g_match_info_free (match_info);
/* Metric */
g_regex_match (regex_metric, *iter, 0, &match_info);
metric_int = -1;
if (g_match_info_matches (match_info)) {
metric = g_match_info_fetch (match_info, 1);
errno = 0;
metric_int = strtol (metric, NULL, 10);
if (errno || metric_int < 0 || metric_int > G_MAXUINT32) {
g_match_info_free (match_info);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP6 route metric '%s'", metric);
g_free (dest);
g_free (next_hop);
g_free (metric);
goto error;
}
g_free (metric);
}
g_match_info_free (match_info);
route = nm_ip_route_new (AF_INET6, dest, prefix_int, next_hop, metric_int, error);
g_free (dest);
g_free (next_hop);
if (!route)
goto error;
if (!nm_setting_ip_config_add_route (s_ip6, route))
PARSE_WARNING ("duplicate IP6 route");
2015-02-07 16:54:01 +01:00
nm_ip_route_unref (route);
}
success = TRUE;
error:
g_free (contents);
g_strfreev (lines);
g_regex_unref (regex_to1);
g_regex_unref (regex_to2);
g_regex_unref (regex_via);
g_regex_unref (regex_metric);
return success;
}
static NMSetting *
make_ip4_setting (shvarFile *ifcfg,
const char *network_file,
GError **error)
{
NMSettingIPConfig *s_ip4 = NULL;
char *value = NULL;
char *route_path = NULL;
char *method;
2015-03-26 14:56:00 +01:00
char *dns_options = NULL;
gs_free char *gateway = NULL;
gint32 i;
shvarFile *network_ifcfg;
shvarFile *route_ifcfg;
gboolean never_default = FALSE;
s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
/* First check if DEFROUTE is set for this device; DEFROUTE has the
* opposite meaning from never-default. The default if DEFROUTE is not
* specified is DEFROUTE=yes which means that this connection can be used
* as a default route
*/
never_default = !svGetValueBoolean (ifcfg, "DEFROUTE", TRUE);
/* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */
network_ifcfg = svOpenFile (network_file, NULL);
if (network_ifcfg) {
char *gatewaydev;
/* Get the connection ifcfg device name and the global gateway device */
value = svGetValue (ifcfg, "DEVICE", FALSE);
gatewaydev = svGetValue (network_ifcfg, "GATEWAYDEV", FALSE);
dns_options = svGetValueFull (network_ifcfg, "RES_OPTIONS", FALSE);
/* If there was a global gateway device specified, then only connections
* for that device can be the default connection.
*/
if (gatewaydev && value)
never_default = !!strcmp (value, gatewaydev);
g_free (gatewaydev);
g_free (value);
svCloseFile (network_ifcfg);
}
value = svGetValue (ifcfg, "BOOTPROTO", FALSE);
if (!value || !*value || !g_ascii_strcasecmp (value, "none")) {
if (is_any_ip4_address_defined (ifcfg, NULL))
method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
else
method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
} else if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) {
method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
} else if (!g_ascii_strcasecmp (value, "static")) {
if (is_any_ip4_address_defined (ifcfg, NULL))
method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
else
method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
} else if (!g_ascii_strcasecmp (value, "autoip")) {
g_free (value);
g_object_set (s_ip4,
NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
NULL);
return NM_SETTING (s_ip4);
} else if (!g_ascii_strcasecmp (value, "shared")) {
int idx;
g_free (value);
g_object_set (s_ip4,
NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED,
NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
NULL);
/* 1 IP address is allowed for shared connections. Read it. */
if (is_any_ip4_address_defined (ifcfg, &idx)) {
NMIPAddress *addr = NULL;
if (!read_full_ip4_address (ifcfg, idx, NULL, &addr, NULL, error))
goto done;
if (!read_ip4_address (ifcfg, "GATEWAY", &gateway, error))
goto done;
(void) nm_setting_ip_config_add_address (s_ip4, addr);
nm_ip_address_unref (addr);
g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
}
return NM_SETTING (s_ip4);
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown BOOTPROTO '%s'", value);
g_free (value);
goto done;
}
g_free (value);
g_object_set (s_ip4,
NM_SETTING_IP_CONFIG_METHOD, method,
NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svGetValueBoolean (ifcfg, "PEERDNS", TRUE),
NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svGetValueBoolean (ifcfg, "PEERROUTES", TRUE),
NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV4_FAILURE_FATAL", FALSE),
NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV4_ROUTE_METRIC", 10,
-1, G_MAXUINT32, -1),
NULL);
if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
return NM_SETTING (s_ip4);
/* Handle DHCP settings */
if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
if (value && strlen (value))
g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL);
g_free (value);
g_object_set (s_ip4,
NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCP_SEND_HOSTNAME", TRUE),
NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT, svGetValueInt64 (ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXUINT32, 0),
NULL);
2009-03-27 10:30:06 -04:00
value = svGetValue (ifcfg, "DHCP_CLIENT_ID", FALSE);
if (value && strlen (value))
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, value, NULL);
g_free (value);
}
/* Read static IP addresses.
* Read them even for AUTO method - in this case the addresses are
* added to the automatic ones. Note that this is not currently supported by
* the legacy 'network' service (ifup-eth).
*/
for (i = -1; i < 256; i++) {
NMIPAddress *addr = NULL;
/* gateway will only be set if still unset. Hence, we don't leak gateway
* here by calling read_full_ip4_address() repeatedly */
if (!read_full_ip4_address (ifcfg, i, NULL, &addr, &gateway, error))
goto done;
if (!addr) {
/* The first mandatory variable is 2-indexed (IPADDR2)
* Variables IPADDR, IPADDR0 and IPADDR1 are optional */
if (i > 1)
break;
continue;
}
if (!nm_setting_ip_config_add_address (s_ip4, addr))
PARSE_WARNING ("duplicate IP4 address");
nm_ip_address_unref (addr);
}
/* Gateway */
if (!gateway) {
network_ifcfg = svOpenFile (network_file, NULL);
if (network_ifcfg) {
gboolean read_success;
read_success = read_ip4_address (network_ifcfg, "GATEWAY", &gateway, error);
svCloseFile (network_ifcfg);
if (!read_success)
goto done;
if (gateway && nm_setting_ip_config_get_num_addresses (s_ip4) == 0) {
gs_free char *f = g_path_get_basename (ifcfg->fileName);
PARSE_WARNING ("ignoring GATEWAY (/etc/sysconfig/network) for %s "
"because the connection has no static addresses", f);
g_clear_pointer (&gateway, g_free);
}
}
}
g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
/* DNS servers
* Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
*/
for (i = 1; i <= 10; i++) {
char *tag;
tag = g_strdup_printf ("DNS%u", i);
value = svGetValue (ifcfg, tag, FALSE);
if (value) {
if (nm_utils_ipaddr_valid (AF_INET, value)) {
if (!nm_setting_ip_config_add_dns (s_ip4, value))
PARSE_WARNING ("duplicate DNS server %s", tag);
} else if (nm_utils_ipaddr_valid (AF_INET6, value)) {
/* Ignore IPv6 addresses */
} else {
PARSE_WARNING ("invalid DNS server address %s", value);
g_free (tag);
g_free (value);
goto done;
}
g_free (value);
}
g_free (tag);
}
/* DNS searches */
value = svGetValue (ifcfg, "DOMAIN", FALSE);
if (value) {
char **searches = NULL;
searches = g_strsplit (value, " ", 0);
if (searches) {
char **item;
for (item = searches; *item; item++) {
if (strlen (*item)) {
if (!nm_setting_ip_config_add_dns_search (s_ip4, *item))
PARSE_WARNING ("duplicate DNS domain '%s'", *item);
}
}
g_strfreev (searches);
}
g_free (value);
}
2015-03-26 14:56:00 +01:00
/* DNS options */
value = svGetValueFull (ifcfg, "RES_OPTIONS", FALSE);
2015-03-26 14:56:00 +01:00
parse_dns_options (s_ip4, value);
parse_dns_options (s_ip4, dns_options);
g_free (value);
g_free (dns_options);
dns_options = NULL;
/* Static routes - route-<name> file */
route_path = utils_get_route_path (ifcfg->fileName);
if (utils_has_complex_routes (route_path)) {
PARSE_WARNING ("'rule-' or 'rule6-' file is present; you will need to use a dispatcher script to apply these routes");
} else if (utils_has_route_file_new_syntax (route_path)) {
/* Parse route file in new syntax */
route_ifcfg = utils_get_route_ifcfg (ifcfg->fileName, FALSE);
if (route_ifcfg) {
for (i = 0; i < 256; i++) {
NMIPRoute *route = NULL;
if (!read_one_ip4_route (route_ifcfg, i, &route, error)) {
svCloseFile (route_ifcfg);
goto done;
}
if (!route)
break;
if (!nm_setting_ip_config_add_route (s_ip4, route))
PARSE_WARNING ("duplicate IP4 route");
nm_ip_route_unref (route);
}
svCloseFile (route_ifcfg);
}
} else {
if (!read_route_file_legacy (route_path, s_ip4, error))
goto done;
}
g_free (route_path);
/* Legacy value NM used for a while but is incorrect (rh #459370) */
if (!nm_setting_ip_config_get_num_dns_searches (s_ip4)) {
value = svGetValue (ifcfg, "SEARCH", FALSE);
if (value) {
char **searches = NULL;
searches = g_strsplit (value, " ", 0);
if (searches) {
char **item;
for (item = searches; *item; item++) {
if (strlen (*item)) {
if (!nm_setting_ip_config_add_dns_search (s_ip4, *item))
PARSE_WARNING ("duplicate DNS search '%s'", *item);
}
}
g_strfreev (searches);
}
g_free (value);
}
}
return NM_SETTING (s_ip4);
done:
2015-03-26 14:56:00 +01:00
g_free (dns_options);
g_free (route_path);
g_object_unref (s_ip4);
return NULL;
}
static void
read_aliases (NMSettingIPConfig *s_ip4, const char *filename)
{
GDir *dir;
char *dirname, *base;
shvarFile *parsed;
NMIPAddress *base_addr = NULL;
GError *err = NULL;
g_return_if_fail (s_ip4 != NULL);
g_return_if_fail (filename != NULL);
if (nm_setting_ip_config_get_num_addresses (s_ip4) > 0)
base_addr = nm_setting_ip_config_get_address (s_ip4, 0);
dirname = g_path_get_dirname (filename);
g_return_if_fail (dirname != NULL);
base = g_path_get_basename (filename);
g_return_if_fail (base != NULL);
dir = g_dir_open (dirname, 0, &err);
if (dir) {
const char *item;
NMIPAddress *addr;
gboolean ok;
while ((item = g_dir_read_name (dir))) {
char *full_path, *device;
const char *p;
if (!utils_is_ifcfg_alias_file (item, base))
continue;
full_path = g_build_filename (dirname, item, NULL);
p = strchr (item, ':');
g_assert (p != NULL); /* we know this is true from utils_is_ifcfg_alias_file() */
for (p++; *p; p++) {
if (!g_ascii_isalnum (*p) && *p != '_')
break;
}
if (*p) {
PARSE_WARNING ("ignoring alias file '%s' with invalid name", full_path);
g_free (full_path);
continue;
}
parsed = svOpenFile (full_path, &err);
if (!parsed) {
PARSE_WARNING ("couldn't parse alias file '%s': %s", full_path, err->message);
g_free (full_path);
g_clear_error (&err);
continue;
}
device = svGetValue (parsed, "DEVICE", FALSE);
if (!device) {
PARSE_WARNING ("alias file '%s' has no DEVICE", full_path);
svCloseFile (parsed);
g_free (full_path);
continue;
}
/* We know that item starts with IFCFG_TAG from utils_is_ifcfg_alias_file() */
if (strcmp (device, item + strlen (IFCFG_TAG)) != 0) {
PARSE_WARNING ("alias file '%s' has invalid DEVICE (%s) for filename",
full_path, device);
g_free (device);
svCloseFile (parsed);
g_free (full_path);
continue;
}
addr = NULL;
ok = read_full_ip4_address (parsed, -1, base_addr, &addr, NULL, &err);
svCloseFile (parsed);
if (ok) {
nm_ip_address_set_attribute (addr, "label", g_variant_new_string (device));
if (!nm_setting_ip_config_add_address (s_ip4, addr))
PARSE_WARNING ("duplicate IP4 address in alias file %s", item);
} else {
PARSE_WARNING ("error reading IP4 address from alias file '%s': %s",
full_path, err ? err->message : "no address");
g_clear_error (&err);
}
nm_ip_address_unref (addr);
g_free (device);
g_free (full_path);
}
g_dir_close (dir);
} else {
PARSE_WARNING ("can not read directory '%s': %s", dirname, err->message);
g_error_free (err);
}
g_free (base);
g_free (dirname);
}
static NMSetting *
make_ip6_setting (shvarFile *ifcfg,
const char *network_file,
GError **error)
{
NMSettingIPConfig *s_ip6 = NULL;
char *value = NULL;
char *str_value;
char *route6_path = NULL;
2015-03-26 14:56:00 +01:00
char *dns_options = NULL;
gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE;
char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
char *ipv6addr, *ipv6addr_secondaries;
char **list = NULL, **iter;
guint32 i;
shvarFile *network_ifcfg;
gboolean never_default = FALSE;
gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip;
NMSettingIP6ConfigPrivacy ip6_privacy_val;
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
char *tmp;
s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
/* First check if IPV6_DEFROUTE is set for this device; IPV6_DEFROUTE has the
* opposite meaning from never-default. The default if IPV6_DEFROUTE is not
* specified is IPV6_DEFROUTE=yes which means that this connection can be used
* as a default route
*/
never_default = !svGetValueBoolean (ifcfg, "IPV6_DEFROUTE", TRUE);
/* Then check if IPV6_DEFAULTGW or IPV6_DEFAULTDEV is specified;
* they are global and override IPV6_DEFROUTE
* When both are set, the device specified in IPV6_DEFAULTGW takes preference.
*/
network_ifcfg = svOpenFile (network_file, NULL);
if (network_ifcfg) {
char *ipv6_defaultgw, *ipv6_defaultdev;
char *default_dev = NULL;
/* Get the connection ifcfg device name and the global default route device */
value = svGetValue (ifcfg, "DEVICE", FALSE);
ipv6_defaultgw = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
ipv6_defaultdev = svGetValue (network_ifcfg, "IPV6_DEFAULTDEV", FALSE);
dns_options = svGetValueFull (network_ifcfg, "RES_OPTIONS", FALSE);
if (ipv6_defaultgw) {
default_dev = strchr (ipv6_defaultgw, '%');
if (default_dev)
default_dev++;
}
if (!default_dev)
default_dev = ipv6_defaultdev;
/* If there was a global default route device specified, then only connections
* for that device can be the default connection.
*/
if (default_dev && value)
never_default = !!strcmp (value, default_dev);
g_free (ipv6_defaultgw);
g_free (ipv6_defaultdev);
g_free (value);
svCloseFile (network_ifcfg);
}
/* Find out method property */
/* Is IPV6 enabled? Set method to "ignored", when not enabled */
str_value = svGetValue (ifcfg, "IPV6INIT", FALSE);
ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE);
if (!str_value) {
network_ifcfg = svOpenFile (network_file, NULL);
if (network_ifcfg) {
ipv6init = svGetValueBoolean (network_ifcfg, "IPV6INIT", FALSE);
svCloseFile (network_ifcfg);
}
}
g_free (str_value);
if (!ipv6init)
method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */
else {
ipv6forwarding = svGetValueBoolean (ifcfg, "IPV6FORWARDING", FALSE);
ipv6_autoconf = svGetValueBoolean (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding);
dhcp6 = svGetValueBoolean (ifcfg, "DHCPV6C", FALSE);
if (ipv6_autoconf)
method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
else if (dhcp6)
method = NM_SETTING_IP6_CONFIG_METHOD_DHCP;
else {
/* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */
str_value = svGetValue (ifcfg, "IPV6ADDR", FALSE);
if (!str_value)
str_value = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
if (!str_value)
method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
g_free (str_value);
}
}
/* TODO - handle other methods */
/* Read IPv6 Privacy Extensions configuration */
tmp = svGetValue (ifcfg, "IPV6_PRIVACY", FALSE);
if (tmp) {
ip6_privacy = svGetValueBoolean (ifcfg, "IPV6_PRIVACY", FALSE);
if (!ip6_privacy)
ip6_privacy = g_strcmp0 (tmp, "rfc4941") == 0 ||
g_strcmp0 (tmp, "rfc3041") == 0;
}
ip6_privacy_prefer_public_ip = svGetValueBoolean (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE);
ip6_privacy_val = tmp ?
(ip6_privacy ?
(ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) :
NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) :
NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
g_free (tmp);
g_object_set (s_ip6,
NM_SETTING_IP_CONFIG_METHOD, method,
NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svGetValueBoolean (ifcfg, "IPV6_PEERDNS", TRUE),
NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svGetValueBoolean (ifcfg, "IPV6_PEERROUTES", TRUE),
NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV6_FAILURE_FATAL", FALSE),
NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV6_ROUTE_METRIC", 10,
-1, G_MAXUINT32, -1),
NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val,
NULL);
/* Don't bother to read IP, DNS and routes when IPv6 is disabled */
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0)
return NM_SETTING (s_ip6);
if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
|| !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
/* METHOD_AUTO may trigger DHCPv6, so save the hostname to send to DHCP */
value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
if (value && value[0])
g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL);
g_free (value);
}
/* Read static IP addresses.
* Read them even for AUTO and DHCP methods - in this case the addresses are
* added to the automatic ones. Note that this is not currently supported by
* the legacy 'network' service (ifup-eth).
*/
ipv6addr = svGetValue (ifcfg, "IPV6ADDR", FALSE);
ipv6addr_secondaries = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL,
ipv6addr ? ipv6addr : "",
ipv6addr_secondaries ? ipv6addr_secondaries : "",
NULL);
g_free (ipv6addr);
g_free (ipv6addr_secondaries);
list = g_strsplit_set (value, " ", 0);
g_free (value);
for (iter = list, i = 0; iter && *iter; iter++, i++) {
NMIPAddress *addr = NULL;
if (!parse_full_ip6_address (ifcfg, *iter, i, &addr, error)) {
g_strfreev (list);
goto error;
}
if (!nm_setting_ip_config_add_address (s_ip6, addr))
PARSE_WARNING ("duplicate IP6 address");
nm_ip_address_unref (addr);
}
g_strfreev (list);
/* Gateway */
if (nm_setting_ip_config_get_num_addresses (s_ip6)) {
value = svGetValue (ifcfg, "IPV6_DEFAULTGW", FALSE);
if (!value) {
/* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */
network_ifcfg = svOpenFile (network_file, NULL);
if (network_ifcfg) {
value = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
svCloseFile (network_ifcfg);
}
}
if (value) {
char *ptr;
if ((ptr = strchr (value, '%')) != NULL)
*ptr = '\0'; /* remove %interface prefix if present */
if (!nm_utils_ipaddr_valid (AF_INET6, value)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid IP6 address '%s'", value);
g_free (value);
goto error;
}
g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, value, NULL);
g_free (value);
}
}
/* IPv6 addressing mode configuration */
tmp = svGetValue (ifcfg, "IPV6_ADDR_GEN_MODE", FALSE);
if (tmp) {
if (nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), tmp,
(int *) &addr_gen_mode, NULL))
g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, addr_gen_mode, NULL);
else
PARSE_WARNING ("Invalid IPV6_ADDR_GEN_MODE");
g_free (tmp);
} else {
g_object_set (s_ip6,
NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
NULL);
}
/* DNS servers
* Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting())
*/
for (i = 1; i <= 10; i++) {
char *tag;
tag = g_strdup_printf ("DNS%u", i);
value = svGetValue (ifcfg, tag, FALSE);
if (!value) {
g_free (tag);
break; /* all done */
}
if (nm_utils_ipaddr_valid (AF_INET6, value)) {
if (!nm_setting_ip_config_add_dns (s_ip6, value))
PARSE_WARNING ("duplicate DNS server %s", tag);
} else if (nm_utils_ipaddr_valid (AF_INET, value)) {
/* Ignore IPv4 addresses */
} else {
PARSE_WARNING ("invalid DNS server address %s", value);
g_free (tag);
g_free (value);
goto error;
}
g_free (tag);
g_free (value);
}
/* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */
if (!utils_has_complex_routes (ifcfg->fileName)) {
/* Read static routes from route6-<interface> file */
route6_path = utils_get_route6_path (ifcfg->fileName);
if (!read_route6_file (route6_path, s_ip6, error))
goto error;
g_free (route6_path);
}
2015-03-26 14:56:00 +01:00
/* DNS options */
value = svGetValueFull (ifcfg, "RES_OPTIONS", FALSE);
2015-03-26 14:56:00 +01:00
parse_dns_options (s_ip6, value);
parse_dns_options (s_ip6, dns_options);
g_free (value);
g_free (dns_options);
return NM_SETTING (s_ip6);
error:
2015-03-26 14:56:00 +01:00
g_free (dns_options);
g_free (route6_path);
g_object_unref (s_ip6);
return NULL;
}
static void
check_if_bond_slave (shvarFile *ifcfg,
NMSettingConnection *s_con)
{
char *value;
value = svGetValue (ifcfg, "MASTER", FALSE);
if (value) {
g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
g_object_set (s_con,
NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
NULL);
g_free (value);
}
/* We should be checking for SLAVE=yes as well, but NM used to not set that,
* so for backward-compatibility, we don't check.
*/
}
static void
check_if_team_slave (shvarFile *ifcfg,
NMSettingConnection *s_con)
{
char *value;
value = svGetValue (ifcfg, "DEVICETYPE", FALSE);
if (!value)
return;
if (strcasecmp (value, TYPE_TEAM_PORT)) {
g_free (value);
return;
}
g_free (value);
value = svGetValue (ifcfg, "TEAM_MASTER", FALSE);
if (!value)
return;
g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL);
g_free (value);
}
typedef struct {
const char *enable_key;
const char *advertise_key;
const char *willing_key;
const char *flags_prop;
} DcbFlagsProperty;
enum {
DCB_APP_FCOE_FLAGS = 0,
DCB_APP_ISCSI_FLAGS = 1,
DCB_APP_FIP_FLAGS = 2,
DCB_PFC_FLAGS = 3,
DCB_PG_FLAGS = 4,
};
static DcbFlagsProperty dcb_flags_props[] = {
{ KEY_DCB_APP_FCOE_ENABLE, KEY_DCB_APP_FCOE_ADVERTISE, KEY_DCB_APP_FCOE_WILLING, NM_SETTING_DCB_APP_FCOE_FLAGS },
{ KEY_DCB_APP_ISCSI_ENABLE, KEY_DCB_APP_ISCSI_ADVERTISE, KEY_DCB_APP_ISCSI_WILLING, NM_SETTING_DCB_APP_ISCSI_FLAGS },
{ KEY_DCB_APP_FIP_ENABLE, KEY_DCB_APP_FIP_ADVERTISE, KEY_DCB_APP_FIP_WILLING, NM_SETTING_DCB_APP_FIP_FLAGS },
{ KEY_DCB_PFC_ENABLE, KEY_DCB_PFC_ADVERTISE, KEY_DCB_PFC_WILLING, NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS },
{ KEY_DCB_PG_ENABLE, KEY_DCB_PG_ADVERTISE, KEY_DCB_PG_WILLING, NM_SETTING_DCB_PRIORITY_GROUP_FLAGS },
{ NULL },
};
static NMSettingDcbFlags
read_dcb_flags (shvarFile *ifcfg, DcbFlagsProperty *property)
{
NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
if (svGetValueBoolean (ifcfg, property->enable_key, FALSE))
flags |= NM_SETTING_DCB_FLAG_ENABLE;
if (svGetValueBoolean (ifcfg, property->advertise_key, FALSE))
flags |= NM_SETTING_DCB_FLAG_ADVERTISE;
if (svGetValueBoolean (ifcfg, property->willing_key, FALSE))
flags |= NM_SETTING_DCB_FLAG_WILLING;
return flags;
}
static gboolean
read_dcb_app (shvarFile *ifcfg,
NMSettingDcb *s_dcb,
const char *app,
DcbFlagsProperty *flags_prop,
const char *priority_prop,
GError **error)
{
NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
char *tmp, *val;
gboolean success = TRUE;
int priority = -1;
flags = read_dcb_flags (ifcfg, flags_prop);
/* Priority */
tmp = g_strdup_printf ("DCB_APP_%s_PRIORITY", app);
val = svGetValue (ifcfg, tmp, FALSE);
if (val) {
success = get_int (val, &priority);
if (success)
success = (priority >= 0 && priority <= 7);
if (!success) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid %s value '%s' (expected 0 - 7)",
tmp, val);
}
g_free (val);
if (!(flags & NM_SETTING_DCB_FLAG_ENABLE))
PARSE_WARNING ("ignoring DCB %s priority; app not enabled", app);
}
g_free (tmp);
if (success) {
g_object_set (G_OBJECT (s_dcb),
flags_prop->flags_prop, flags,
priority_prop, (guint) priority,
NULL);
}
return success;
}
typedef void (*DcbSetBoolFunc) (NMSettingDcb *, guint, gboolean);
static gboolean
read_dcb_bool_array (shvarFile *ifcfg,
NMSettingDcb *s_dcb,
NMSettingDcbFlags flags,
const char *prop,
const char *desc,
DcbSetBoolFunc set_func,
GError **error)
{
char *val;
gboolean success = FALSE;
guint i;
val = svGetValue (ifcfg, prop, FALSE);
if (!val)
return TRUE;
if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
success = TRUE;
goto out;
}
val = g_strstrip (val);
if (strlen (val) != 8) {
PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val);
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"boolean array must be 8 characters");
goto out;
}
/* All characters must be either 0 or 1 */
for (i = 0; i < 8; i++) {
if (val[i] != '0' && val[i] != '1') {
PARSE_WARNING ("invalid %s value '%s': not all 0s and 1s", prop, val);
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"invalid boolean digit");
goto out;
}
set_func (s_dcb, i, (val[i] == '1'));
}
success = TRUE;
out:
g_free (val);
return success;
}
typedef void (*DcbSetUintFunc) (NMSettingDcb *, guint, guint);
static gboolean
read_dcb_uint_array (shvarFile *ifcfg,
NMSettingDcb *s_dcb,
NMSettingDcbFlags flags,
const char *prop,
const char *desc,
gboolean f_allowed,
DcbSetUintFunc set_func,
GError **error)
{
char *val;
gboolean success = FALSE;
guint i;
val = svGetValue (ifcfg, prop, FALSE);
if (!val)
return TRUE;
if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
success = TRUE;
goto out;
}
val = g_strstrip (val);
if (strlen (val) != 8) {
PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val);
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"uint array must be 8 characters");
goto out;
}
/* All characters must be either 0 - 7 or (optionally) f */
for (i = 0; i < 8; i++) {
if (val[i] >= '0' && val[i] <= '7')
set_func (s_dcb, i, val[i] - '0');
else if (f_allowed && (val[i] == 'f' || val[i] == 'F'))
set_func (s_dcb, i, 15);
else {
PARSE_WARNING ("invalid %s value '%s': not 0 - 7%s",
prop, val, f_allowed ? " or 'f'" : "");
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"invalid uint digit");
goto out;
}
}
success = TRUE;
out:
g_free (val);
return success;
}
static gboolean
read_dcb_percent_array (shvarFile *ifcfg,
NMSettingDcb *s_dcb,
NMSettingDcbFlags flags,
const char *prop,
const char *desc,
gboolean sum_pct,
DcbSetUintFunc set_func,
GError **error)
{
char *val;
gboolean success = FALSE;
char **split = NULL, **iter;
int tmp;
guint i, sum = 0;
val = svGetValue (ifcfg, prop, FALSE);
if (!val)
return TRUE;
if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
success = TRUE;
goto out;
}
val = g_strstrip (val);
split = g_strsplit_set (val, ",", 0);
if (!split || (g_strv_length (split) != 8)) {
PARSE_WARNING ("invalid %s percentage list value '%s'", prop, val);
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"percent array must be 8 elements");
goto out;
}
for (iter = split, i = 0; iter && *iter; iter++, i++) {
if (!get_int (*iter, &tmp) || tmp < 0 || tmp > 100) {
PARSE_WARNING ("invalid %s percentage value '%s'", prop, *iter);
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"invalid percent element");
goto out;
}
set_func (s_dcb, i, (guint) tmp);
sum += (guint) tmp;
}
if (sum_pct && (sum != 100)) {
PARSE_WARNING ("%s percentages do not equal 100%%", prop);
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"invalid percentage sum");
goto out;
}
success = TRUE;
out:
if (split)
g_strfreev (split);
g_free (val);
return success;
}
static gboolean
make_dcb_setting (shvarFile *ifcfg,
const char *network_file,
NMSetting **out_setting,
GError **error)
{
NMSettingDcb *s_dcb = NULL;
gboolean dcb_on;
NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
char *val;
g_return_val_if_fail (out_setting != NULL, FALSE);
dcb_on = !!svGetValueBoolean (ifcfg, "DCB", FALSE);
if (!dcb_on)
return TRUE;
s_dcb = (NMSettingDcb *) nm_setting_dcb_new ();
g_assert (s_dcb);
/* FCOE */
if (!read_dcb_app (ifcfg, s_dcb, "FCOE",
&dcb_flags_props[DCB_APP_FCOE_FLAGS],
NM_SETTING_DCB_APP_FCOE_PRIORITY,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) {
val = svGetValue (ifcfg, KEY_DCB_APP_FCOE_MODE, FALSE);
if (val) {
if (strcmp (val, NM_SETTING_DCB_FCOE_MODE_FABRIC) == 0 ||
strcmp (val, NM_SETTING_DCB_FCOE_MODE_VN2VN) == 0)
g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_FCOE_MODE, val, NULL);
else {
PARSE_WARNING ("invalid FCoE mode '%s'", val);
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"invalid FCoE mode");
g_free (val);
g_object_unref (s_dcb);
return FALSE;
}
g_free (val);
}
}
/* iSCSI */
if (!read_dcb_app (ifcfg, s_dcb, "ISCSI",
&dcb_flags_props[DCB_APP_ISCSI_FLAGS],
NM_SETTING_DCB_APP_ISCSI_PRIORITY,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
/* FIP */
if (!read_dcb_app (ifcfg, s_dcb, "FIP",
&dcb_flags_props[DCB_APP_FIP_FLAGS],
NM_SETTING_DCB_APP_FIP_PRIORITY,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
/* Priority Flow Control */
flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PFC_FLAGS]);
g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, flags, NULL);
if (!read_dcb_bool_array (ifcfg,
s_dcb,
flags,
KEY_DCB_PFC_UP,
"PFC",
nm_setting_dcb_set_priority_flow_control,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
/* Priority Groups */
flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PG_FLAGS]);
g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, flags, NULL);
if (!read_dcb_uint_array (ifcfg,
s_dcb,
flags,
KEY_DCB_PG_ID,
"PGID",
TRUE,
nm_setting_dcb_set_priority_group_id,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
/* Group bandwidth */
if (!read_dcb_percent_array (ifcfg,
s_dcb,
flags,
KEY_DCB_PG_PCT,
"PGPCT",
TRUE,
nm_setting_dcb_set_priority_group_bandwidth,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
/* Priority bandwidth */
if (!read_dcb_percent_array (ifcfg,
s_dcb,
flags,
KEY_DCB_PG_UPPCT,
"UPPCT",
FALSE,
nm_setting_dcb_set_priority_bandwidth,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
/* Strict Bandwidth */
if (!read_dcb_bool_array (ifcfg,
s_dcb,
flags,
KEY_DCB_PG_STRICT,
"STRICT",
nm_setting_dcb_set_priority_strict_bandwidth,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
if (!read_dcb_uint_array (ifcfg,
s_dcb,
flags,
KEY_DCB_PG_UP2TC,
"UP2TC",
FALSE,
nm_setting_dcb_set_priority_traffic_class,
error)) {
g_object_unref (s_dcb);
return FALSE;
}
*out_setting = NM_SETTING (s_dcb);
return TRUE;
}
static gboolean
add_one_wep_key (shvarFile *ifcfg,
const char *shvar_key,
guint8 key_idx,
gboolean passphrase,
NMSettingWirelessSecurity *s_wsec,
GError **error)
{
char *key = NULL;
char *value = NULL;
gboolean success = FALSE;
g_return_val_if_fail (ifcfg != NULL, FALSE);
g_return_val_if_fail (shvar_key != NULL, FALSE);
g_return_val_if_fail (key_idx <= 3, FALSE);
g_return_val_if_fail (s_wsec != NULL, FALSE);
value = svGetValue (ifcfg, shvar_key, FALSE);
if (!value || !strlen (value)) {
g_free (value);
return TRUE;
}
/* Validate keys */
if (passphrase) {
if (strlen (value) && strlen (value) < 64) {
key = g_strdup (value);
g_object_set (G_OBJECT (s_wsec),
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
NM_WEP_KEY_TYPE_PASSPHRASE,
NULL);
}
} else {
if (strlen (value) == 10 || strlen (value) == 26) {
/* Hexadecimal WEP key */
char *p = value;
while (*p) {
if (!g_ascii_isxdigit (*p)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid hexadecimal WEP key.");
goto out;
}
p++;
}
key = g_strdup (value);
} else if ( !strncmp (value, "s:", 2)
&& (strlen (value) == 7 || strlen (value) == 15)) {
/* ASCII key */
char *p = value + 2;
while (*p) {
if (!g_ascii_isprint ((int) (*p))) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid ASCII WEP key.");
goto out;
}
p++;
}
/* Remove 's:' prefix.
* Don't convert to hex string. wpa_supplicant takes 'wep_key0' option over D-Bus as byte array
* and converts it to hex string itself. Even though we convert hex string keys into a bin string
* before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly,
* ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users.
*/
key = g_strdup (value + 2);
}
}
if (key) {
nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key);
g_free (key);
success = TRUE;
} else
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid WEP key length.");
out:
g_free (value);
return success;
}
static gboolean
read_wep_keys (shvarFile *ifcfg,
guint8 def_idx,
NMSettingWirelessSecurity *s_wsec,
GError **error)
{
/* Try hex/ascii keys first */
if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error))
return FALSE;
if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error))
return FALSE;
if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error))
return FALSE;
if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error))
return FALSE;
if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error))
return FALSE;
/* And then passphrases */
if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error))
return FALSE;
if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error))
return FALSE;
if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error))
return FALSE;
if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error))
return FALSE;
return TRUE;
}
static NMSettingSecretFlags
read_secret_flags (shvarFile *ifcfg, const char *flags_key)
{
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
char *val;
g_return_val_if_fail (flags_key != NULL, NM_SETTING_SECRET_FLAG_NONE);
g_return_val_if_fail (flags_key[0] != '\0', NM_SETTING_SECRET_FLAG_NONE);
g_return_val_if_fail (g_str_has_suffix (flags_key, "_FLAGS"), NM_SETTING_SECRET_FLAG_NONE);
val = svGetValue (ifcfg, flags_key, FALSE);
if (val) {
if (strstr (val, SECRET_FLAG_AGENT))
flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
if (strstr (val, SECRET_FLAG_NOT_SAVED))
flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED;
if (strstr (val, SECRET_FLAG_NOT_REQUIRED))
flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED;
g_free (val);
}
return flags;
}
static NMSetting *
make_wep_setting (shvarFile *ifcfg,
const char *file,
GError **error)
{
2011-02-28 17:47:29 -06:00
NMSettingWirelessSecurity *s_wsec;
char *value;
2008-02-07 Dan Williams <dcbw@redhat.com> * system-settings/src/dbus-settings.c system-settings/src/dbus-settings.h - (add_one_secret_to_hash): copy secrets out of the plugin-returned hash table of secrets - (connection_settings_get_secrets): consolidate error returns into one place; use the new get_secrets() plugin interface function to get secrets from the plugin itself rather than using GObject data magic * system-settings/src/main.c - (connection_added_cb, connection_removed_cb, free_plugin_connections, load_connections): keep a private list of the plugin-returned connections, don't use the plugin's GSList * system-settings/plugins/ifcfg-fedora/plugin.c - (watch_path): watch the path, not the filename (duh) - (reload_all_connections): use the direct hash/equal functions; the ones for int aren't appropriate here - (get_secrets, system_config_interface_init): implement the get_secrets() function - (build_one_connection, find_connection_by_path): ifcfg file path is now in the connection's ConnectionData instead of being a GObject data property - (handle_profile_item_changed): ifcfg file path is now in the connection's ConnectionData instead of being a GObject data property; be sure to copy secrets over from the new connection to the existing connection when updating the connection's settings - (init): sc_plugin_inotify_init() returns success/fail, not the inotify file descriptor * system-settings/plugins/ifcfg-fedora/parser.c system-settings/plugins/ifcfg-fedora/parser.h - (connection_data_get, copy_one_cdata_secret, clear_one_cdata_secret, connection_data_copy_secrets, connection_data_free, connection_data_add): new functions; connection data manipulation - (make_wireless_security_setting): stuff secrets into the connection data, not as GObject data items; make sure to close the keys ifcfg file - (wireless_connection_from_ifcfg, wired_connection_from_ifcfg): add connection data to the connection git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3299 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-02-07 20:11:31 +00:00
shvarFile *keys_ifcfg = NULL;
int default_key_idx = 0;
gboolean has_default_key = FALSE, success;
NMSettingSecretFlags key_flags;
2011-02-28 17:47:29 -06:00
s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL);
value = svGetValue (ifcfg, "DEFAULTKEY", FALSE);
if (value) {
success = get_int (value, &default_key_idx);
if (success && (default_key_idx >= 1) && (default_key_idx <= 4)) {
has_default_key = TRUE;
default_key_idx--; /* convert to [0...3] */
2011-02-28 17:47:29 -06:00
g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, default_key_idx, NULL);
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid default WEP key '%s'", value);
g_free (value);
goto error;
}
g_free (value);
}
/* Read WEP key flags */
key_flags = read_secret_flags (ifcfg, "WEP_KEY_FLAGS");
g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, key_flags, NULL);
/* Read keys in the ifcfg file if they are system-owned */
if (key_flags == NM_SETTING_SECRET_FLAG_NONE) {
if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error))
goto error;
/* Try to get keys from the "shadow" key file */
keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
if (keys_ifcfg) {
if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) {
svCloseFile (keys_ifcfg);
goto error;
}
svCloseFile (keys_ifcfg);
g_assert (error == NULL || *error == NULL);
}
}
value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
if (value) {
char *lcase;
lcase = g_ascii_strdown (value, -1);
g_free (value);
if (!strcmp (lcase, "open")) {
2011-02-28 17:47:29 -06:00
g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL);
} else if (!strcmp (lcase, "restricted")) {
2011-02-28 17:47:29 -06:00
g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL);
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid WEP authentication algorithm '%s'",
lcase);
g_free (lcase);
goto error;
}
g_free (lcase);
}
/* If no WEP keys were given, and the keys are not agent-owned, and no
* default WEP key index was given, then the connection is unencrypted.
*/
2011-02-28 17:47:29 -06:00
if ( !nm_setting_wireless_security_get_wep_key (s_wsec, 0)
&& !nm_setting_wireless_security_get_wep_key (s_wsec, 1)
&& !nm_setting_wireless_security_get_wep_key (s_wsec, 2)
&& !nm_setting_wireless_security_get_wep_key (s_wsec, 3)
&& (has_default_key == FALSE)
&& (key_flags == NM_SETTING_SECRET_FLAG_NONE)) {
const char *auth_alg;
2011-02-28 17:47:29 -06:00
auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
if (auth_alg && !strcmp (auth_alg, "shared")) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"WEP Shared Key authentication is invalid for "
"unencrypted connections.");
goto error;
}
/* Unencrypted */
2011-02-28 17:47:29 -06:00
g_object_unref (s_wsec);
s_wsec = NULL;
}
2008-02-07 Dan Williams <dcbw@redhat.com> * system-settings/src/dbus-settings.c system-settings/src/dbus-settings.h - (add_one_secret_to_hash): copy secrets out of the plugin-returned hash table of secrets - (connection_settings_get_secrets): consolidate error returns into one place; use the new get_secrets() plugin interface function to get secrets from the plugin itself rather than using GObject data magic * system-settings/src/main.c - (connection_added_cb, connection_removed_cb, free_plugin_connections, load_connections): keep a private list of the plugin-returned connections, don't use the plugin's GSList * system-settings/plugins/ifcfg-fedora/plugin.c - (watch_path): watch the path, not the filename (duh) - (reload_all_connections): use the direct hash/equal functions; the ones for int aren't appropriate here - (get_secrets, system_config_interface_init): implement the get_secrets() function - (build_one_connection, find_connection_by_path): ifcfg file path is now in the connection's ConnectionData instead of being a GObject data property - (handle_profile_item_changed): ifcfg file path is now in the connection's ConnectionData instead of being a GObject data property; be sure to copy secrets over from the new connection to the existing connection when updating the connection's settings - (init): sc_plugin_inotify_init() returns success/fail, not the inotify file descriptor * system-settings/plugins/ifcfg-fedora/parser.c system-settings/plugins/ifcfg-fedora/parser.h - (connection_data_get, copy_one_cdata_secret, clear_one_cdata_secret, connection_data_copy_secrets, connection_data_free, connection_data_add): new functions; connection data manipulation - (make_wireless_security_setting): stuff secrets into the connection data, not as GObject data items; make sure to close the keys ifcfg file - (wireless_connection_from_ifcfg, wired_connection_from_ifcfg): add connection data to the connection git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3299 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-02-07 20:11:31 +00:00
2011-02-28 17:47:29 -06:00
return (NMSetting *) s_wsec;
error:
2011-02-28 17:47:29 -06:00
if (s_wsec)
g_object_unref (s_wsec);
return NULL;
}
static gboolean
fill_wpa_ciphers (shvarFile *ifcfg,
NMSettingWirelessSecurity *wsec,
gboolean group,
gboolean adhoc)
{
char *value = NULL, *p;
char **list = NULL, **iter;
int i = 0;
p = value = svGetValue (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", TRUE);
if (!value)
return TRUE;
/* Strip quotes */
if (p[0] == '"')
p++;
if (p[strlen (p) - 1] == '"')
p[strlen (p) - 1] = '\0';
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)) {
PARSE_WARNING ("ignoring group cipher '%s' (only one group cipher allowed "
"in Ad-Hoc mode)", *iter);
continue;
} else if (!group) {
PARSE_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 {
PARSE_WARNING ("ignoring invalid %s cipher '%s'",
group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE",
*iter);
}
}
if (list)
g_strfreev (list);
g_free (value);
return TRUE;
}
#define WPA_PMK_LEN 32
static char *
parse_wpa_psk (shvarFile *ifcfg,
const char *file,
GBytes *ssid,
GError **error)
{
shvarFile *keys_ifcfg;
char *psk = NULL, *p, *hashed = NULL;
size_t plen;
gboolean quoted = FALSE;
/* Passphrase must be between 10 and 66 characters in length because 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.
*/
/* Try to get keys from the "shadow" key file */
keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
if (keys_ifcfg) {
psk = svGetValue (keys_ifcfg, "WPA_PSK", TRUE);
svCloseFile (keys_ifcfg);
}
/* Fall back to the original ifcfg */
if (!psk)
psk = svGetValue (ifcfg, "WPA_PSK", TRUE);
if (!psk)
return NULL;
p = psk;
plen = strlen (p);
if ( (plen >= 2 && (p[0] == '"' || p[0] == '\'') && p[0] == p[plen - 1])
|| (plen >= 3 && p[0] == '$' && p[1] == '\'' && p[1] == p[plen - 1]))
quoted = TRUE;
if (!quoted && (strlen (psk) == 64)) {
/* Verify the hex PSK; 64 digits */
while (*p) {
if (!g_ascii_isxdigit (*p++)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid WPA_PSK (contains non-hexadecimal characters)");
goto out;
}
}
hashed = g_strdup (psk);
} else {
/* Prior to 4f6eef9e77265484555663cf666cde4fa8323469 and
* 28e2e446868b94b92edc4a82aa0bf1e3eda8ec54 the writer may not have
* properly quoted passphrases, so just handle anything that's unquoted
* and between 8 and 63 characters as a passphrase.
*/
/* Get rid of the quotes */
hashed = utils_single_unquote_string (p);
/* Length check */
if (strlen (hashed) < 8 || strlen (hashed) > 63) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid WPA_PSK (passphrases must be between "
"8 and 63 characters long (inclusive))");
g_free (hashed);
hashed = NULL;
goto out;
}
}
if (!hashed) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid WPA_PSK (doesn't look like a passphrase or hex key)");
goto out;
}
out:
g_free (psk);
return hashed;
}
2009-03-09 10:51:07 -04:00
static gboolean
eap_simple_reader (const char *eap_method,
shvarFile *ifcfg,
shvarFile *keys,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
2009-03-09 10:51:07 -04:00
{
NMSettingSecretFlags flags;
char *value;
2009-03-09 10:51:07 -04:00
value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
if (!value) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
eap_method);
return FALSE;
}
g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
g_free (value);
flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_FLAGS, flags, NULL);
2009-03-09 10:51:07 -04:00
/* Only read the password if it's system-owned */
if (flags == NM_SETTING_SECRET_FLAG_NONE) {
value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
if (!value && keys) {
/* Try the lookaside keys file */
value = svGetValue (keys, "IEEE_8021X_PASSWORD", FALSE);
}
if (!value) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IEEE_8021X_PASSWORD for EAP method '%s'.",
eap_method);
return FALSE;
}
g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL);
g_free (value);
}
return TRUE;
}
static char *
get_full_file_path (const char *ifcfg_path, const char *file_path)
{
const char *base = file_path;
char *p, *ret, *dirname;
g_return_val_if_fail (ifcfg_path != NULL, NULL);
g_return_val_if_fail (file_path != NULL, NULL);
if (file_path[0] == '/')
return g_strdup (file_path);
p = strrchr (file_path, '/');
if (p)
2009-04-21 18:12:41 -04:00
base = p + 1;
dirname = g_path_get_dirname (ifcfg_path);
2009-04-21 18:12:41 -04:00
ret = g_build_path ("/", dirname, base, NULL);
g_free (dirname);
return ret;
}
static gboolean
eap_tls_reader (const char *eap_method,
shvarFile *ifcfg,
shvarFile *keys,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
{
char *value;
char *ca_cert = NULL;
char *real_path = 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;
2011-02-28 17:50:32 -06:00
const char *ca_cert_key = phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT";
const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD";
const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY";
const char *cli_cert_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT";
const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS": "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS";
const char *pk_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS;
NMSettingSecretFlags flags;
value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
if (!value) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
eap_method);
return FALSE;
}
g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
g_free (value);
2011-02-28 17:50:32 -06:00
ca_cert = svGetValue (ifcfg, ca_cert_key, FALSE);
if (ca_cert) {
real_path = get_full_file_path (ifcfg->fileName, ca_cert);
if (phase2) {
if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
real_path,
NM_SETTING_802_1X_CK_SCHEME_PATH,
NULL,
error))
goto done;
} else {
if (!nm_setting_802_1x_set_ca_cert (s_8021x,
real_path,
NM_SETTING_802_1X_CK_SCHEME_PATH,
NULL,
error))
goto done;
}
g_free (real_path);
real_path = NULL;
} else {
PARSE_WARNING ("missing %s for EAP method '%s'; this is insecure!",
ca_cert_key, eap_method);
}
/* Read and set private key password flags */
flags = read_secret_flags (ifcfg, pk_pw_flags_key);
g_object_set (s_8021x, pk_pw_flags_prop, flags, NULL);
/* Read the private key password if it's system-owned */
if (flags == NM_SETTING_SECRET_FLAG_NONE) {
/* Private key password */
privkey_password = svGetValue (ifcfg, pk_pw_key, FALSE);
if (!privkey_password && keys) {
/* Try the lookaside keys file */
privkey_password = svGetValue (keys, pk_pw_key, FALSE);
}
if (!privkey_password) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing %s for EAP method '%s'.",
pk_pw_key,
eap_method);
goto done;
}
}
/* The private key itself */
2011-02-28 17:50:32 -06:00
privkey = svGetValue (ifcfg, pk_key, FALSE);
if (!privkey) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing %s for EAP method '%s'.",
2011-02-28 17:50:32 -06:00
pk_key,
eap_method);
goto done;
}
real_path = get_full_file_path (ifcfg->fileName, privkey);
if (phase2) {
if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
real_path,
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,
real_path,
privkey_password,
NM_SETTING_802_1X_CK_SCHEME_PATH,
&privkey_format,
error))
goto done;
}
g_free (real_path);
real_path = NULL;
/* 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) {
2011-02-28 17:50:32 -06:00
client_cert = svGetValue (ifcfg, cli_cert_key, FALSE);
if (!client_cert) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing %s for EAP method '%s'.",
2011-02-28 17:50:32 -06:00
cli_cert_key,
eap_method);
goto done;
2009-03-09 10:51:07 -04:00
}
real_path = get_full_file_path (ifcfg->fileName, client_cert);
if (phase2) {
if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
real_path,
NM_SETTING_802_1X_CK_SCHEME_PATH,
NULL,
error))
goto done;
} else {
if (!nm_setting_802_1x_set_client_cert (s_8021x,
real_path,
NM_SETTING_802_1X_CK_SCHEME_PATH,
NULL,
error))
goto done;
2009-03-09 10:51:07 -04:00
}
g_free (real_path);
real_path = NULL;
}
2009-03-09 10:51:07 -04:00
success = TRUE;
done:
g_free (real_path);
g_free (ca_cert);
g_free (client_cert);
g_free (privkey);
g_free (privkey_password);
return success;
}
static gboolean
eap_peap_reader (const char *eap_method,
shvarFile *ifcfg,
shvarFile *keys,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
{
char *anon_ident = NULL;
char *ca_cert = NULL;
char *real_cert_path = NULL;
char *inner_auth = NULL;
char *peapver = NULL;
char *lower;
char **list = NULL, **iter;
gboolean success = FALSE;
ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
if (ca_cert) {
real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
if (!nm_setting_802_1x_set_ca_cert (s_8021x,
real_cert_path,
NM_SETTING_802_1X_CK_SCHEME_PATH,
NULL,
error))
goto done;
} else {
PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
eap_method);
}
peapver = svGetValue (ifcfg, "IEEE_8021X_PEAP_VERSION", FALSE);
if (peapver) {
if (!strcmp (peapver, "0"))
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
else if (!strcmp (peapver, "1"))
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL);
else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown IEEE_8021X_PEAP_VERSION value '%s'",
peapver);
goto done;
2009-03-09 10:51:07 -04:00
}
}
if (svGetValueBoolean (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE))
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL);
anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
if (anon_ident && strlen (anon_ident))
g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
if (!inner_auth) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"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++) {
if (!strlen (*iter))
continue;
if ( !strcmp (*iter, "MSCHAPV2")
|| !strcmp (*iter, "MD5")
|| !strcmp (*iter, "GTC")) {
if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
goto done;
} else if (!strcmp (*iter, "TLS")) {
if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
goto done;
2009-03-10 09:46:40 -04:00
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2009-03-10 09:46:40 -04:00
"Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
*iter);
goto done;
}
2009-03-10 09:46:40 -04:00
lower = g_ascii_strdown (*iter, -1);
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
g_free (lower);
break;
2009-03-09 10:51:07 -04:00
}
if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"No valid IEEE_8021X_INNER_AUTH_METHODS found.");
goto done;
}
success = TRUE;
done:
if (list)
g_strfreev (list);
g_free (inner_auth);
g_free (peapver);
g_free (real_cert_path);
g_free (ca_cert);
g_free (anon_ident);
return success;
}
static gboolean
eap_ttls_reader (const char *eap_method,
shvarFile *ifcfg,
shvarFile *keys,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
{
2009-03-10 09:46:40 -04:00
gboolean success = FALSE;
char *anon_ident = NULL;
char *ca_cert = NULL;
char *real_cert_path = NULL;
2009-03-10 09:46:40 -04:00
char *inner_auth = NULL;
char *tmp;
2009-03-10 09:46:40 -04:00
char **list = NULL, **iter;
ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
if (ca_cert) {
real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
if (!nm_setting_802_1x_set_ca_cert (s_8021x,
real_cert_path,
NM_SETTING_802_1X_CK_SCHEME_PATH,
NULL,
error))
2009-03-10 09:46:40 -04:00
goto done;
} else {
PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
eap_method);
2009-03-10 09:46:40 -04:00
}
anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
if (anon_ident && strlen (anon_ident))
g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
tmp = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
if (!tmp) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2009-03-10 09:46:40 -04:00
"Missing IEEE_8021X_INNER_AUTH_METHODS.");
goto done;
}
inner_auth = g_ascii_strdown (tmp, -1);
g_free (tmp);
2009-03-10 09:46:40 -04:00
/* Handle options for the inner auth method */
list = g_strsplit (inner_auth, " ", 0);
for (iter = list; iter && *iter; iter++) {
if (!strlen (*iter))
continue;
if ( !strcmp (*iter, "mschapv2")
|| !strcmp (*iter, "mschap")
|| !strcmp (*iter, "pap")
|| !strcmp (*iter, "chap")) {
2009-03-10 09:46:40 -04:00
if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
goto done;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
} else if (!strcmp (*iter, "eap-tls")) {
2009-03-10 09:46:40 -04:00
if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
goto done;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
} else if ( !strcmp (*iter, "eap-mschapv2")
|| !strcmp (*iter, "eap-md5")
|| !strcmp (*iter, "eap-gtc")) {
2009-03-10 09:46:40 -04:00
if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
goto done;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + STRLEN ("eap-")), NULL);
2009-03-10 09:46:40 -04:00
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2009-03-10 09:46:40 -04:00
"Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
*iter);
goto done;
}
break;
}
success = TRUE;
done:
if (list)
g_strfreev (list);
g_free (inner_auth);
g_free (real_cert_path);
2009-03-10 09:46:40 -04:00
g_free (ca_cert);
g_free (anon_ident);
return success;
2009-03-09 10:51:07 -04:00
}
static gboolean
eap_fast_reader (const char *eap_method,
shvarFile *ifcfg,
shvarFile *keys,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
{
char *anon_ident = NULL;
char *pac_file = NULL;
char *real_pac_path = NULL;
char *inner_auth = NULL;
char *fast_provisioning = NULL;
char *lower;
char **list = NULL, **iter;
const char* pac_prov_str;
gboolean allow_unauth = FALSE, allow_auth = FALSE;
gboolean success = FALSE;
pac_file = svGetValue (ifcfg, "IEEE_8021X_PAC_FILE", FALSE);
if (pac_file) {
real_pac_path = get_full_file_path (ifcfg->fileName, pac_file);
g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL);
}
fast_provisioning = svGetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", FALSE);
if (fast_provisioning) {
list = g_strsplit_set (fast_provisioning, " \t", 0);
for (iter = list; iter && *iter; iter++) {
if (**iter == '\0')
continue;
if (strcmp (*iter, "allow-unauth") == 0)
allow_unauth = TRUE;
else if (strcmp (*iter, "allow-auth") == 0)
allow_auth = TRUE;
else {
PARSE_WARNING ("invalid IEEE_8021X_FAST_PROVISIONING '%s' "
"(space-separated list of these values [allow-auth, allow-unauth] expected)",
*iter);
}
}
g_strfreev (list);
list = NULL;
}
pac_prov_str = allow_unauth ? (allow_auth ? "3" : "1") : (allow_auth ? "2" : "0");
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, pac_prov_str, NULL);
if (!pac_file && !(allow_unauth || allow_auth)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled.");
goto done;
}
anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
if (anon_ident && strlen (anon_ident))
g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
if (!inner_auth) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"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++) {
if (!strlen (*iter))
continue;
if ( !strcmp (*iter, "MSCHAPV2")
|| !strcmp (*iter, "GTC")) {
if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
goto done;
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
*iter);
goto done;
}
lower = g_ascii_strdown (*iter, -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, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"No valid IEEE_8021X_INNER_AUTH_METHODS found.");
goto done;
}
success = TRUE;
done:
g_strfreev (list);
g_free (inner_auth);
g_free (fast_provisioning);
g_free (real_pac_path);
g_free (pac_file);
g_free (anon_ident);
return success;
}
typedef struct {
const char *method;
gboolean (*reader)(const char *eap_method,
shvarFile *ifcfg,
shvarFile *keys,
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, FALSE },
{ "pwd", eap_simple_reader, FALSE },
{ "tls", eap_tls_reader, FALSE },
{ "peap", eap_peap_reader, FALSE },
{ "ttls", eap_ttls_reader, FALSE },
{ "fast", eap_fast_reader, FALSE },
{ NULL, NULL }
};
static void
read_8021x_list_value (shvarFile *ifcfg,
const char *ifcfg_var_name,
NMSetting8021x *setting,
const char *prop_name)
{
char *value;
char **strv;
g_return_if_fail (ifcfg != NULL);
g_return_if_fail (ifcfg_var_name != NULL);
g_return_if_fail (prop_name != NULL);
value = svGetValue (ifcfg, ifcfg_var_name, FALSE);
if (!value)
return;
strv = g_strsplit_set (value, " \t", 0);
if (strv && strv[0])
g_object_set (setting, prop_name, strv, NULL);
g_strfreev (strv);
g_free (value);
}
static NMSetting8021x *
fill_8021x (shvarFile *ifcfg,
const char *file,
const char *key_mgmt,
2009-03-09 10:51:07 -04:00
gboolean wifi,
GError **error)
{
2009-03-09 10:51:07 -04:00
NMSetting8021x *s_8021x;
shvarFile *keys = NULL;
2009-03-09 10:51:07 -04:00
char *value;
char **list = NULL, **iter;
2009-03-09 10:51:07 -04:00
value = svGetValue (ifcfg, "IEEE_8021X_EAP_METHODS", FALSE);
if (!value) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2009-03-09 10:51:07 -04:00
"Missing IEEE_8021X_EAP_METHODS for key management '%s'",
key_mgmt);
return NULL;
}
list = g_strsplit (value, " ", 0);
g_free (value);
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
/* Read in the lookaside keys file, if present */
keys = utils_get_keys_ifcfg (file, FALSE);
/* 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) {
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) {
PARSE_WARNING ("ignored invalid IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
lower);
goto next;
}
/* Parse EAP method specific options */
if (!(*eap->reader)(lower, ifcfg, keys, s_8021x, FALSE, error)) {
g_free (lower);
goto error;
}
nm_setting_802_1x_add_eap_method (s_8021x, lower);
found = TRUE;
break;
next:
eap++;
}
if (!found)
PARSE_WARNING ("ignored unknown IEEE_8021X_EAP_METHOD '%s'.", lower);
g_free (lower);
2009-03-09 10:51:07 -04:00
}
if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
goto error;
}
2009-03-09 10:51:07 -04:00
value = svGetValue (ifcfg, "IEEE_8021X_SUBJECT_MATCH", FALSE);
g_object_set (s_8021x, NM_SETTING_802_1X_SUBJECT_MATCH, value, NULL);
g_free (value);
value = svGetValue (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH", FALSE);
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, value, NULL);
g_free (value);
read_8021x_list_value (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES",
s_8021x, NM_SETTING_802_1X_ALTSUBJECT_MATCHES);
read_8021x_list_value (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES",
s_8021x, NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES);
if (list)
g_strfreev (list);
if (keys)
svCloseFile (keys);
2009-03-09 10:51:07 -04:00
return s_8021x;
error:
if (list)
g_strfreev (list);
if (keys)
svCloseFile (keys);
2009-03-09 10:51:07 -04:00
g_object_unref (s_8021x);
return NULL;
}
static NMSetting *
make_wpa_setting (shvarFile *ifcfg,
const char *file,
GBytes *ssid,
gboolean adhoc,
NMSetting8021x **s_8021x,
GError **error)
{
NMSettingWirelessSecurity *wsec;
char *value, *psk, *lower;
gboolean wpa_psk = FALSE, wpa_eap = FALSE, ieee8021x = FALSE;
wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
wpa_psk = !g_strcmp0 (value, "WPA-PSK");
wpa_eap = !g_strcmp0 (value, "WPA-EAP");
ieee8021x = !g_strcmp0 (value, "IEEE8021X");
if (!wpa_psk && !wpa_eap && !ieee8021x)
goto error; /* Not WPA or Dynamic WEP */
/* Pairwise and Group ciphers (only relevant for WPA/RSN) */
if (wpa_psk || wpa_eap) {
fill_wpa_ciphers (ifcfg, wsec, FALSE, adhoc);
fill_wpa_ciphers (ifcfg, 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 {
char *allow_wpa, *allow_rsn;
allow_wpa = svGetValue (ifcfg, "WPA_ALLOW_WPA", FALSE);
allow_rsn = svGetValue (ifcfg, "WPA_ALLOW_WPA2", FALSE);
if (allow_wpa && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA", TRUE))
nm_setting_wireless_security_add_proto (wsec, "wpa");
if (allow_rsn && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA2", TRUE))
nm_setting_wireless_security_add_proto (wsec, "rsn");
/* If neither WPA_ALLOW_WPA or WPA_ALLOW_WPA2 were present, default
* to both WPA and RSN allowed.
*/
if (!allow_wpa && !allow_rsn && !ieee8021x) {
nm_setting_wireless_security_add_proto (wsec, "wpa");
nm_setting_wireless_security_add_proto (wsec, "rsn");
}
g_free (allow_wpa);
g_free (allow_rsn);
}
/* coverity[dereference] */
if (!strcmp (value, "WPA-PSK")) {
NMSettingSecretFlags psk_flags;
psk_flags = read_secret_flags (ifcfg, "WPA_PSK_FLAGS");
g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, psk_flags, NULL);
/* Read PSK if it's system-owned */
if (psk_flags == NM_SETTING_SECRET_FLAG_NONE) {
psk = parse_wpa_psk (ifcfg, file, ssid, error);
if (psk) {
g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL);
g_free (psk);
} else if (error)
goto error;
}
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")) {
/* Adhoc mode is mutually exclusive with any 802.1x-based authentication */
if (adhoc) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Ad-Hoc mode cannot be used with KEY_MGMT type '%s'", value);
goto error;
}
2009-03-09 10:51:07 -04:00
*s_8021x = fill_8021x (ifcfg, file, 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, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown wireless KEY_MGMT type '%s'", value);
goto error;
}
g_free (value);
return (NMSetting *) wsec;
error:
g_free (value);
if (wsec)
g_object_unref (wsec);
return NULL;
}
static NMSetting *
make_leap_setting (shvarFile *ifcfg,
const char *file,
GError **error)
{
NMSettingWirelessSecurity *wsec;
shvarFile *keys_ifcfg;
char *value;
NMSettingSecretFlags flags;
wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
if (!value || strcmp (value, "IEEE8021X"))
goto error; /* Not LEAP */
g_free (value);
value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
if (!value || strcasecmp (value, "leap"))
goto error; /* Not LEAP */
g_free (value);
flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, flags, NULL);
/* Read LEAP password if it's system-owned */
if (flags == NM_SETTING_SECRET_FLAG_NONE) {
value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
if (!value) {
/* Try to get keys from the "shadow" key file */
keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
if (keys_ifcfg) {
value = svGetValue (keys_ifcfg, "IEEE_8021X_PASSWORD", FALSE);
svCloseFile (keys_ifcfg);
}
}
if (value && strlen (value))
g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, value, NULL);
g_free (value);
}
value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
if (!value || !strlen (value)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing LEAP identity");
goto error;
}
g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value, NULL);
g_free (value);
g_object_set (wsec,
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
NULL);
return (NMSetting *) wsec;
error:
g_free (value);
if (wsec)
g_object_unref (wsec);
return NULL;
}
static NMSetting *
make_wireless_security_setting (shvarFile *ifcfg,
const char *file,
GBytes *ssid,
gboolean adhoc,
NMSetting8021x **s_8021x,
GError **error)
{
NMSetting *wsec;
ifcfg-rh: fix wireless_connection_from_ifcfg() to accept missing @error argument wireless_connection_from_ifcfg() did not support being called without error argument. #0 0x00007fe4fa2204e9 in g_logv (log_domain=0x7fe4f0597060 "NetworkManager-ifcfg-rh", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff1c7aaf00) at gmessages.c:989 #1 0x00007fe4fa22063f in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at gmessages.c:1025 #2 0x00007fe4f057eec3 in wireless_connection_from_ifcfg (file=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", ifcfg=0x7fe4fec6f730, error=0x0) at reader.c:3431 #3 0x00007fe4f057e2b6 in connection_from_file_full (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", network_file=0x7fe4f05976aa "/etc/sysconfig/network", test_type=0x0, out_unhandled=0x7fff1c7ab1f8, error=0x0, out_ignore_error=0x7fff1c7ab174) at reader.c:4750 #4 0x00007fe4f057db80 in connection_from_file (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", out_unhandled=0x7fff1c7ab1f8, error=0x0) at reader.c:4834 #5 0x00007fe4f057b4a6 in nm_ifcfg_connection_new (source=0x0, full_path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", error=0x0) at nm-ifcfg-connection.c:119 #6 0x00007fe4f0579c1d in _internal_new_connection (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", source=0x0, error=0x0) at plugin.c:136 #7 0x00007fe4f0579256 in connection_new_or_changed (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", existing=0x0, out_old_path=0x7fff1c7ab458) at plugin.c:265 #8 0x00007fe4f0578f61 in read_connections (plugin=0x7fe4fec6cd00) at plugin.c:462 #9 0x00007fe4f0578839 in get_connections (config=0x7fe4fec6cd00) at plugin.c:497 #10 0x00007fe4fdc9affb in nm_system_config_interface_get_connections (config=0x7fe4fec6cd00) at settings/nm-system-config-interface.c:143 #11 0x00007fe4fdc9764f in load_connections (self=0x7fe4fec6ca40) at settings/nm-settings.c:201 #12 0x00007fe4fdc96d74 in nm_settings_new (error=0x7fff1c7abb18) at settings/nm-settings.c:1802 #13 0x00007fe4fdc37146 in main (argc=1, argv=0x7fff1c7abcd8) at main.c:415 Fixes: 356849f70c72f920d1600ab98611f9f7ed10214c Fixes: 12bfaf5a8da788ae5ed50c0c93c203250a6ecf8b
2014-12-30 21:43:10 +01:00
g_return_val_if_fail (error && !*error, NULL);
if (!adhoc) {
wsec = make_leap_setting (ifcfg, file, error);
if (wsec)
return wsec;
else if (*error)
return NULL;
}
wsec = make_wpa_setting (ifcfg, file, ssid, adhoc, s_8021x, error);
if (wsec)
return wsec;
else if (*error)
return NULL;
wsec = make_wep_setting (ifcfg, file, error);
if (wsec)
return wsec;
else if (*error)
return NULL;
return NULL; /* unencrypted */
}
static char **
transform_hwaddr_blacklist (const char *blacklist)
{
char **strv, **iter;
int shift = 0;
strv = _nm_utils_strsplit_set (blacklist, " \t", 0);
for (iter = strv; iter && *iter; iter++) {
if (shift) {
*(iter - shift) = *iter;
*iter = NULL;
}
if (!nm_utils_hwaddr_valid (*(iter - shift), ETH_ALEN)) {
PARSE_WARNING ("invalid MAC in HWADDR_BLACKLIST '%s'", *(iter - shift));
g_free (*(iter - shift));
*(iter - shift) = NULL;
shift++;
}
}
return strv;
}
static NMSetting *
make_wireless_setting (shvarFile *ifcfg,
GError **error)
{
NMSettingWireless *s_wireless;
char *value = NULL;
gint64 chan = 0;
s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
value = svGetValue (ifcfg, "HWADDR", FALSE);
if (value) {
value = g_strstrip (value);
g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, value, NULL);
g_free (value);
}
value = svGetValue (ifcfg, "MACADDR", FALSE);
if (value) {
value = g_strstrip (value);
g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, value, NULL);
g_free (value);
}
value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
if (value) {
char **strv;
strv = transform_hwaddr_blacklist (value);
g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, strv, NULL);
g_strfreev (strv);
g_free (value);
}
value = svGetValue (ifcfg, "ESSID", TRUE);
if (value) {
GBytes *bytes = NULL;
gsize ssid_len = 0;
gsize value_len = strlen (value);
if ( (value_len >= 2)
&& (value[0] == '"')
&& (value[value_len - 1] == '"')) {
/* Strip the quotes and unescape */
char *p = value + 1;
value[value_len - 1] = '\0';
svUnescape (p);
bytes = g_bytes_new (p, strlen (p));
} else if ((value_len > 2) && (strncmp (value, "0x", 2) == 0)) {
/* Hex representation */
if (value_len % 2) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid SSID '%s' size (looks like hex but length not multiple of 2)",
value);
g_free (value);
goto error;
}
bytes = nm_utils_hexstr2bin (value);
if (!bytes) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid SSID '%s' (looks like hex SSID but isn't)",
value);
g_free (value);
goto error;
}
} else
bytes = g_bytes_new (value, value_len);
ssid_len = g_bytes_get_size (bytes);
if (ssid_len > 32 || ssid_len == 0) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
value, ssid_len);
g_bytes_unref (bytes);
g_free (value);
goto error;
}
g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, bytes, NULL);
g_bytes_unref (bytes);
g_free (value);
}
value = svGetValue (ifcfg, "MODE", FALSE);
if (value) {
char *lcase;
const char *mode = NULL;
lcase = g_ascii_strdown (value, -1);
g_free (value);
if (!strcmp (lcase, "ad-hoc")) {
mode = "adhoc";
} else if (!strcmp (lcase, "ap")) {
mode = "ap";
} else if (!strcmp (lcase, "managed") || !strcmp (lcase, "auto")) {
mode = "infrastructure";
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid mode '%s' (not 'Ad-Hoc', 'Ap', 'Managed', or 'Auto')",
lcase);
g_free (lcase);
goto error;
}
g_free (lcase);
g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, mode, NULL);
}
value = svGetValue (ifcfg, "BSSID", FALSE);
if (value) {
value = g_strstrip (value);
g_object_set (s_wireless, NM_SETTING_WIRELESS_BSSID, value, NULL);
g_free (value);
}
value = svGetValue (ifcfg, "CHANNEL", FALSE);
if (value) {
errno = 0;
chan = _nm_utils_ascii_str_to_int64 (value, 10, 1, 196, 0);
if (errno || (chan == 0)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid wireless channel '%s'", value);
g_free (value);
goto error;
}
g_object_set (s_wireless, NM_SETTING_WIRELESS_CHANNEL, (guint32) chan, NULL);
g_free (value);
}
value = svGetValue (ifcfg, "BAND", FALSE);
if (value) {
if (!strcmp (value, "a")) {
if (chan && chan <= 14) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2014-10-09 13:20:06 -05:00
"Band '%s' invalid for channel %u", value, (guint32) chan);
g_free (value);
goto error;
}
} else if (!strcmp (value, "bg")) {
if (chan && chan > 14) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2014-10-09 13:20:06 -05:00
"Band '%s' invalid for channel %u", value, (guint32) chan);
g_free (value);
goto error;
}
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid wireless band '%s'", value);
g_free (value);
goto error;
}
g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, value, NULL);
g_free (value);
} else if (chan > 0) {
if (chan > 14)
g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "a", NULL);
else
g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "bg", NULL);
}
value = svGetValue (ifcfg, "MTU", FALSE);
if (value) {
long int mtu;
errno = 0;
mtu = strtol (value, NULL, 10);
if (errno || mtu < 0 || mtu > 50000) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid wireless MTU '%s'", value);
g_free (value);
goto error;
}
g_object_set (s_wireless, NM_SETTING_WIRELESS_MTU, (guint32) mtu, NULL);
g_free (value);
}
g_object_set (s_wireless,
NM_SETTING_WIRELESS_HIDDEN,
svGetValueBoolean (ifcfg, "SSID_HIDDEN", FALSE),
NULL);
2015-01-21 14:29:42 -06:00
g_object_set (s_wireless,
NM_SETTING_WIRELESS_POWERSAVE,
svGetValueBoolean (ifcfg, "POWERSAVE", FALSE) ? 1 : 0,
2015-01-21 14:29:42 -06:00
NULL);
return NM_SETTING (s_wireless);
error:
if (s_wireless)
g_object_unref (s_wireless);
return NULL;
}
static NMConnection *
wireless_connection_from_ifcfg (const char *file,
shvarFile *ifcfg,
GError **error)
{
NMConnection *connection = NULL;
NMSetting *con_setting = NULL;
NMSetting *wireless_setting = NULL;
NMSetting8021x *s_8021x = NULL;
GBytes *ssid;
NMSetting *security_setting = NULL;
char *printable_ssid = NULL;
const char *mode;
gboolean adhoc = FALSE;
ifcfg-rh: fix wireless_connection_from_ifcfg() to accept missing @error argument wireless_connection_from_ifcfg() did not support being called without error argument. #0 0x00007fe4fa2204e9 in g_logv (log_domain=0x7fe4f0597060 "NetworkManager-ifcfg-rh", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff1c7aaf00) at gmessages.c:989 #1 0x00007fe4fa22063f in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at gmessages.c:1025 #2 0x00007fe4f057eec3 in wireless_connection_from_ifcfg (file=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", ifcfg=0x7fe4fec6f730, error=0x0) at reader.c:3431 #3 0x00007fe4f057e2b6 in connection_from_file_full (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", network_file=0x7fe4f05976aa "/etc/sysconfig/network", test_type=0x0, out_unhandled=0x7fff1c7ab1f8, error=0x0, out_ignore_error=0x7fff1c7ab174) at reader.c:4750 #4 0x00007fe4f057db80 in connection_from_file (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", out_unhandled=0x7fff1c7ab1f8, error=0x0) at reader.c:4834 #5 0x00007fe4f057b4a6 in nm_ifcfg_connection_new (source=0x0, full_path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", error=0x0) at nm-ifcfg-connection.c:119 #6 0x00007fe4f0579c1d in _internal_new_connection (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", source=0x0, error=0x0) at plugin.c:136 #7 0x00007fe4f0579256 in connection_new_or_changed (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", existing=0x0, out_old_path=0x7fff1c7ab458) at plugin.c:265 #8 0x00007fe4f0578f61 in read_connections (plugin=0x7fe4fec6cd00) at plugin.c:462 #9 0x00007fe4f0578839 in get_connections (config=0x7fe4fec6cd00) at plugin.c:497 #10 0x00007fe4fdc9affb in nm_system_config_interface_get_connections (config=0x7fe4fec6cd00) at settings/nm-system-config-interface.c:143 #11 0x00007fe4fdc9764f in load_connections (self=0x7fe4fec6ca40) at settings/nm-settings.c:201 #12 0x00007fe4fdc96d74 in nm_settings_new (error=0x7fff1c7abb18) at settings/nm-settings.c:1802 #13 0x00007fe4fdc37146 in main (argc=1, argv=0x7fff1c7abcd8) at main.c:415 Fixes: 356849f70c72f920d1600ab98611f9f7ed10214c Fixes: 12bfaf5a8da788ae5ed50c0c93c203250a6ecf8b
2014-12-30 21:43:10 +01:00
GError *local = NULL;
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (ifcfg != NULL, NULL);
ifcfg-rh: fix wireless_connection_from_ifcfg() to accept missing @error argument wireless_connection_from_ifcfg() did not support being called without error argument. #0 0x00007fe4fa2204e9 in g_logv (log_domain=0x7fe4f0597060 "NetworkManager-ifcfg-rh", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff1c7aaf00) at gmessages.c:989 #1 0x00007fe4fa22063f in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at gmessages.c:1025 #2 0x00007fe4f057eec3 in wireless_connection_from_ifcfg (file=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", ifcfg=0x7fe4fec6f730, error=0x0) at reader.c:3431 #3 0x00007fe4f057e2b6 in connection_from_file_full (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", network_file=0x7fe4f05976aa "/etc/sysconfig/network", test_type=0x0, out_unhandled=0x7fff1c7ab1f8, error=0x0, out_ignore_error=0x7fff1c7ab174) at reader.c:4750 #4 0x00007fe4f057db80 in connection_from_file (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", out_unhandled=0x7fff1c7ab1f8, error=0x0) at reader.c:4834 #5 0x00007fe4f057b4a6 in nm_ifcfg_connection_new (source=0x0, full_path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", error=0x0) at nm-ifcfg-connection.c:119 #6 0x00007fe4f0579c1d in _internal_new_connection (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", source=0x0, error=0x0) at plugin.c:136 #7 0x00007fe4f0579256 in connection_new_or_changed (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", existing=0x0, out_old_path=0x7fff1c7ab458) at plugin.c:265 #8 0x00007fe4f0578f61 in read_connections (plugin=0x7fe4fec6cd00) at plugin.c:462 #9 0x00007fe4f0578839 in get_connections (config=0x7fe4fec6cd00) at plugin.c:497 #10 0x00007fe4fdc9affb in nm_system_config_interface_get_connections (config=0x7fe4fec6cd00) at settings/nm-system-config-interface.c:143 #11 0x00007fe4fdc9764f in load_connections (self=0x7fe4fec6ca40) at settings/nm-settings.c:201 #12 0x00007fe4fdc96d74 in nm_settings_new (error=0x7fff1c7abb18) at settings/nm-settings.c:1802 #13 0x00007fe4fdc37146 in main (argc=1, argv=0x7fff1c7abcd8) at main.c:415 Fixes: 356849f70c72f920d1600ab98611f9f7ed10214c Fixes: 12bfaf5a8da788ae5ed50c0c93c203250a6ecf8b
2014-12-30 21:43:10 +01:00
g_return_val_if_fail (!error || !*error, NULL);
connection = nm_simple_connection_new ();
/* Wireless */
wireless_setting = make_wireless_setting (ifcfg, error);
if (!wireless_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, wireless_setting);
ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (wireless_setting));
if (ssid) {
printable_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL),
g_bytes_get_size (ssid));
} else
printable_ssid = g_strdup_printf ("unmanaged");
mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (wireless_setting));
if (mode && !strcmp (mode, "adhoc"))
adhoc = TRUE;
/* Wireless security */
ifcfg-rh: fix wireless_connection_from_ifcfg() to accept missing @error argument wireless_connection_from_ifcfg() did not support being called without error argument. #0 0x00007fe4fa2204e9 in g_logv (log_domain=0x7fe4f0597060 "NetworkManager-ifcfg-rh", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff1c7aaf00) at gmessages.c:989 #1 0x00007fe4fa22063f in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at gmessages.c:1025 #2 0x00007fe4f057eec3 in wireless_connection_from_ifcfg (file=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", ifcfg=0x7fe4fec6f730, error=0x0) at reader.c:3431 #3 0x00007fe4f057e2b6 in connection_from_file_full (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", network_file=0x7fe4f05976aa "/etc/sysconfig/network", test_type=0x0, out_unhandled=0x7fff1c7ab1f8, error=0x0, out_ignore_error=0x7fff1c7ab174) at reader.c:4750 #4 0x00007fe4f057db80 in connection_from_file (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", out_unhandled=0x7fff1c7ab1f8, error=0x0) at reader.c:4834 #5 0x00007fe4f057b4a6 in nm_ifcfg_connection_new (source=0x0, full_path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", error=0x0) at nm-ifcfg-connection.c:119 #6 0x00007fe4f0579c1d in _internal_new_connection (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", source=0x0, error=0x0) at plugin.c:136 #7 0x00007fe4f0579256 in connection_new_or_changed (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", existing=0x0, out_old_path=0x7fff1c7ab458) at plugin.c:265 #8 0x00007fe4f0578f61 in read_connections (plugin=0x7fe4fec6cd00) at plugin.c:462 #9 0x00007fe4f0578839 in get_connections (config=0x7fe4fec6cd00) at plugin.c:497 #10 0x00007fe4fdc9affb in nm_system_config_interface_get_connections (config=0x7fe4fec6cd00) at settings/nm-system-config-interface.c:143 #11 0x00007fe4fdc9764f in load_connections (self=0x7fe4fec6ca40) at settings/nm-settings.c:201 #12 0x00007fe4fdc96d74 in nm_settings_new (error=0x7fff1c7abb18) at settings/nm-settings.c:1802 #13 0x00007fe4fdc37146 in main (argc=1, argv=0x7fff1c7abcd8) at main.c:415 Fixes: 356849f70c72f920d1600ab98611f9f7ed10214c Fixes: 12bfaf5a8da788ae5ed50c0c93c203250a6ecf8b
2014-12-30 21:43:10 +01:00
security_setting = make_wireless_security_setting (ifcfg, file, ssid, adhoc, &s_8021x, &local);
if (local) {
g_free (printable_ssid);
g_object_unref (connection);
ifcfg-rh: fix wireless_connection_from_ifcfg() to accept missing @error argument wireless_connection_from_ifcfg() did not support being called without error argument. #0 0x00007fe4fa2204e9 in g_logv (log_domain=0x7fe4f0597060 "NetworkManager-ifcfg-rh", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff1c7aaf00) at gmessages.c:989 #1 0x00007fe4fa22063f in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at gmessages.c:1025 #2 0x00007fe4f057eec3 in wireless_connection_from_ifcfg (file=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", ifcfg=0x7fe4fec6f730, error=0x0) at reader.c:3431 #3 0x00007fe4f057e2b6 in connection_from_file_full (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", network_file=0x7fe4f05976aa "/etc/sysconfig/network", test_type=0x0, out_unhandled=0x7fff1c7ab1f8, error=0x0, out_ignore_error=0x7fff1c7ab174) at reader.c:4750 #4 0x00007fe4f057db80 in connection_from_file (filename=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", out_unhandled=0x7fff1c7ab1f8, error=0x0) at reader.c:4834 #5 0x00007fe4f057b4a6 in nm_ifcfg_connection_new (source=0x0, full_path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", error=0x0) at nm-ifcfg-connection.c:119 #6 0x00007fe4f0579c1d in _internal_new_connection (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", source=0x0, error=0x0) at plugin.c:136 #7 0x00007fe4f0579256 in connection_new_or_changed (self=0x7fe4fec6cd00, path=0x7fe4fec7c800 "/etc/sysconfig/network-scripts/ifcfg-Wi-Fi-1", existing=0x0, out_old_path=0x7fff1c7ab458) at plugin.c:265 #8 0x00007fe4f0578f61 in read_connections (plugin=0x7fe4fec6cd00) at plugin.c:462 #9 0x00007fe4f0578839 in get_connections (config=0x7fe4fec6cd00) at plugin.c:497 #10 0x00007fe4fdc9affb in nm_system_config_interface_get_connections (config=0x7fe4fec6cd00) at settings/nm-system-config-interface.c:143 #11 0x00007fe4fdc9764f in load_connections (self=0x7fe4fec6ca40) at settings/nm-settings.c:201 #12 0x00007fe4fdc96d74 in nm_settings_new (error=0x7fff1c7abb18) at settings/nm-settings.c:1802 #13 0x00007fe4fdc37146 in main (argc=1, argv=0x7fff1c7abcd8) at main.c:415 Fixes: 356849f70c72f920d1600ab98611f9f7ed10214c Fixes: 12bfaf5a8da788ae5ed50c0c93c203250a6ecf8b
2014-12-30 21:43:10 +01:00
g_propagate_error (error, local);
return NULL;
}
if (security_setting) {
nm_connection_add_setting (connection, security_setting);
if (s_8021x)
nm_connection_add_setting (connection, NM_SETTING (s_8021x));
}
/* Connection */
con_setting = make_connection_setting (file, ifcfg,
NM_SETTING_WIRELESS_SETTING_NAME,
printable_ssid, NULL);
g_free (printable_ssid);
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, con_setting);
return connection;
}
static void
parse_ethtool_option (const char *value, NMSettingWiredWakeOnLan *out_flags, char **out_password)
{
gs_strfreev char **words = NULL;
const char **iter = NULL, *flag;
if (!value || !value[0])
return;
words = g_strsplit_set (value, "\t ", 0);
iter = (const char **) words;
while (iter[0]) {
gboolean is_wol;
if (g_str_equal (iter[0], "wol"))
is_wol = TRUE;
else if (g_str_equal (iter[0], "sopass"))
is_wol = FALSE;
else {
/* Silently skip unknown options */
iter++;
continue;
}
iter++;
/* g_strsplit_set() returns empty tokens, meaning that we must skip over repeated
* space characters like to parse "wol d". */
while (iter[0] && !*iter[0])
iter++;
if (is_wol) {
NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE;
if (!iter[0]) {
PARSE_WARNING ("Wake-on-LAN options missing");
break;
}
for (flag = iter[0]; *flag; flag++) {
switch (*flag) {
case 'p':
wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_PHY;
break;
case 'u':
wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST;
break;
case 'm':
wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST;
break;
case 'b':
wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST;
break;
case 'a':
wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_ARP;
break;
case 'g':
wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC;
break;
case 's':
break;
case 'd':
wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE;
break;
default:
PARSE_WARNING ("unrecognized Wake-on-LAN option '%c'", *flag);
}
}
*out_flags = wol_flags;
} else {
if (!iter[0]) {
PARSE_WARNING ("Wake-on-LAN password missing");
break;
}
g_clear_pointer (out_password, g_free);
if (nm_utils_hwaddr_valid (iter[0], ETH_ALEN))
*out_password = g_strdup (iter[0]);
else
PARSE_WARNING ("Wake-on-LAN password '%s' is invalid", iter[0]);
}
iter++;
}
}
static void
parse_ethtool_options (shvarFile *ifcfg, NMSettingWired *s_wired, const char *value)
{
NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT;
gs_free char *wol_password = NULL;
gboolean ignore_wol_password = FALSE;
if (value) {
gs_strfreev char **opts = NULL;
const char **iter;
wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE;
opts = g_strsplit_set (value, ";", 0);
for (iter = (const char **) opts; iter[0]; iter++) {
/* in case of repeated wol_passwords, parse_ethtool_option()
* will do the right thing and clear wol_password before resetting. */
parse_ethtool_option (iter[0], &wol_flags, &wol_password);
}
}
if ( wol_password
&& !NM_FLAGS_HAS (wol_flags, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) {
PARSE_WARNING ("Wake-on-LAN password not expected");
ignore_wol_password = TRUE;
}
g_object_set (s_wired,
NM_SETTING_WIRED_WAKE_ON_LAN, wol_flags,
NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, ignore_wol_password ? NULL : wol_password,
NULL);
}
static NMSetting *
make_wired_setting (shvarFile *ifcfg,
const char *file,
NMSetting8021x **s_8021x,
GError **error)
{
NMSettingWired *s_wired;
char *value = NULL;
int mtu;
char *nettype;
s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
value = svGetValue (ifcfg, "MTU", FALSE);
if (value) {
if (get_int (value, &mtu)) {
if (mtu >= 0 && mtu < 65536)
g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu, NULL);
} else {
/* Shouldn't be fatal... */
PARSE_WARNING ("invalid MTU '%s'", value);
}
g_free (value);
}
value = svGetValue (ifcfg, "HWADDR", FALSE);
if (value) {
value = g_strstrip (value);
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, value, NULL);
g_free (value);
}
value = svGetValue (ifcfg, "SUBCHANNELS", FALSE);
if (value) {
const char *p = value;
gboolean success = TRUE;
char **chans = NULL;
/* basic sanity checks */
while (*p) {
if (!g_ascii_isxdigit (*p) && (*p != ',') && (*p != '.')) {
PARSE_WARNING ("invalid SUBCHANNELS '%s'", value);
success = FALSE;
break;
}
p++;
}
if (success) {
guint32 num_chans;
chans = g_strsplit_set (value, ",", 0);
num_chans = g_strv_length (chans);
if (num_chans < 2 || num_chans > 3) {
PARSE_WARNING ("invalid SUBCHANNELS '%s' (%d channels, 2 or 3 expected)",
value, g_strv_length (chans));
} else
g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, chans, NULL);
g_strfreev (chans);
}
g_free (value);
}
value = svGetValue (ifcfg, "PORTNAME", FALSE);
if (value && strlen (value)) {
nm_setting_wired_add_s390_option (s_wired, "portname", value);
}
g_free (value);
value = svGetValue (ifcfg, "CTCPROT", FALSE);
if (value && strlen (value))
nm_setting_wired_add_s390_option (s_wired, "ctcprot", value);
g_free (value);
nettype = svGetValue (ifcfg, "NETTYPE", FALSE);
if (nettype && strlen (nettype)) {
if (!strcmp (nettype, "qeth") || !strcmp (nettype, "lcs") || !strcmp (nettype, "ctc"))
g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, nettype, NULL);
else
PARSE_WARNING ("unknown s390 NETTYPE '%s'", nettype);
}
g_free (nettype);
value = svGetValue (ifcfg, "OPTIONS", FALSE);
if (value && strlen (value)) {
char **options, **iter;
iter = options = g_strsplit_set (value, " ", 0);
while (iter && *iter) {
char *equals = strchr (*iter, '=');
gboolean valid = FALSE;
if (equals) {
*equals = '\0';
valid = nm_setting_wired_add_s390_option (s_wired, *iter, equals + 1);
}
if (!valid)
PARSE_WARNING ("invalid s390 OPTION '%s'", *iter);
iter++;
}
g_strfreev (options);
}
g_free (value);
value = svGetValue (ifcfg, "MACADDR", FALSE);
if (value) {
value = g_strstrip (value);
g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, value, NULL);
g_free (value);
}
value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
if (value) {
char **strv;
strv = transform_hwaddr_blacklist (value);
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, strv, NULL);
g_strfreev (strv);
g_free (value);
}
value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
if (value) {
if (!strcmp (value, "IEEE8021X")) {
*s_8021x = fill_8021x (ifcfg, file, value, FALSE, error);
if (!*s_8021x)
goto error;
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown wired KEY_MGMT type '%s'", value);
goto error;
}
g_free (value);
}
value = svGetValueFull (ifcfg, "ETHTOOL_OPTS", FALSE);
parse_ethtool_options (ifcfg, s_wired, value);
g_free (value);
return (NMSetting *) s_wired;
error:
g_free (value);
g_object_unref (s_wired);
return NULL;
}
static NMConnection *
wired_connection_from_ifcfg (const char *file,
shvarFile *ifcfg,
GError **error)
{
NMConnection *connection = NULL;
NMSetting *con_setting = NULL;
NMSetting *wired_setting = NULL;
NMSetting8021x *s_8021x = NULL;
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (ifcfg != NULL, NULL);
connection = nm_simple_connection_new ();
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL, NULL);
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
g_object_unref (connection);
return NULL;
}
check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
nm_connection_add_setting (connection, con_setting);
wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
if (!wired_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, wired_setting);
if (s_8021x)
nm_connection_add_setting (connection, NM_SETTING (s_8021x));
return connection;
}
static gboolean
parse_infiniband_p_key (shvarFile *ifcfg,
int *out_p_key,
char **out_parent,
GError **error)
{
char *device = NULL, *physdev = NULL, *pkey_id = NULL, *end;
char *ifname = NULL;
guint32 id = G_MAXUINT32;
gboolean ret = FALSE;
device = svGetValue (ifcfg, "DEVICE", FALSE);
if (!device) {
PARSE_WARNING ("InfiniBand connection specified PKEY but not DEVICE");
goto done;
}
physdev = svGetValue (ifcfg, "PHYSDEV", FALSE);
if (!physdev) {
PARSE_WARNING ("InfiniBand connection specified PKEY but not PHYSDEV");
goto done;
}
pkey_id = svGetValue (ifcfg, "PKEY_ID", FALSE);
if (!pkey_id) {
PARSE_WARNING ("InfiniBand connection specified PKEY but not PKEY_ID");
goto done;
}
if (g_str_has_prefix (pkey_id, "0x"))
id = strtoul (pkey_id, &end, 16);
else if (!g_str_has_prefix (pkey_id, "0"))
id = strtoul (pkey_id, &end, 10);
else
end = pkey_id;
if (end == pkey_id || *end || id > 0xFFFF) {
PARSE_WARNING ("invalid InfiniBand PKEY_ID '%s'", pkey_id);
goto done;
}
id = (id | 0x8000);
ifname = g_strdup_printf ("%s.%04x", physdev, id);
if (strcmp (device, ifname) != 0) {
PARSE_WARNING ("InfiniBand DEVICE (%s) does not match PHYSDEV+PKEY_ID (%s)",
device, ifname);
goto done;
}
*out_p_key = id;
*out_parent = g_strdup (physdev);
ret = TRUE;
done:
g_free (device);
g_free (physdev);
g_free (pkey_id);
g_free (ifname);
if (!ret) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create InfiniBand setting.");
}
return ret;
}
2011-10-21 09:34:30 -04:00
static NMSetting *
make_infiniband_setting (shvarFile *ifcfg,
const char *file,
GError **error)
{
NMSettingInfiniband *s_infiniband;
char *value = NULL;
int mtu;
s_infiniband = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ());
value = svGetValue (ifcfg, "MTU", FALSE);
if (value) {
if (get_int (value, &mtu)) {
if (mtu >= 0 && mtu < 65536)
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MTU, mtu, NULL);
} else {
/* Shouldn't be fatal... */
PARSE_WARNING ("invalid MTU '%s'", value);
2011-10-21 09:34:30 -04:00
}
g_free (value);
}
value = svGetValue (ifcfg, "HWADDR", FALSE);
if (value) {
value = g_strstrip (value);
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, value, NULL);
g_free (value);
2011-10-21 09:34:30 -04:00
}
if (svGetValueBoolean (ifcfg, "CONNECTED_MODE", FALSE))
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL);
else
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);
if (svGetValueBoolean (ifcfg, "PKEY", FALSE)) {
int p_key;
char *parent;
if (!parse_infiniband_p_key (ifcfg, &p_key, &parent, error)) {
g_object_unref (s_infiniband);
return NULL;
}
g_object_set (s_infiniband,
NM_SETTING_INFINIBAND_P_KEY, p_key,
NM_SETTING_INFINIBAND_PARENT, parent,
NULL);
}
2011-10-21 09:34:30 -04:00
return (NMSetting *) s_infiniband;
}
static NMConnection *
infiniband_connection_from_ifcfg (const char *file,
shvarFile *ifcfg,
GError **error)
{
NMConnection *connection = NULL;
NMSetting *con_setting = NULL;
NMSetting *infiniband_setting = NULL;
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (ifcfg != NULL, NULL);
connection = nm_simple_connection_new ();
2011-10-21 09:34:30 -04:00
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL);
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2011-10-21 09:34:30 -04:00
"Failed to create connection setting.");
g_object_unref (connection);
return NULL;
}
check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
2011-10-21 09:34:30 -04:00
nm_connection_add_setting (connection, con_setting);
infiniband_setting = make_infiniband_setting (ifcfg, file, error);
2011-10-21 09:34:30 -04:00
if (!infiniband_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, infiniband_setting);
return connection;
}
static void
handle_bond_option (NMSettingBond *s_bond,
const char *key,
const char *value)
{
char *sanitized = NULL, *j;
const char *p = value;
/* Remove any quotes or +/- from arp_ip_target */
if (!g_strcmp0 (key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET) && value && value[0]) {
if (*p == '\'' || *p == '"')
p++;
j = sanitized = g_malloc0 (strlen (p) + 1);
while (*p) {
if (*p != '+' && *p != '-' && *p != '\'' && *p != '"')
*j++ = *p;
p++;
}
}
if (!nm_setting_bond_add_option (s_bond, key, sanitized ? sanitized : value))
PARSE_WARNING ("invalid bonding option '%s' = %s",
key, sanitized ? sanitized : value);
g_free (sanitized);
}
static NMSetting *
make_bond_setting (shvarFile *ifcfg,
const char *file,
GError **error)
{
NMSettingBond *s_bond;
char *value;
s_bond = NM_SETTING_BOND (nm_setting_bond_new ());
value = svGetValue (ifcfg, "DEVICE", FALSE);
if (!value || !strlen (value)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"mandatory DEVICE keyword missing");
goto error;
}
g_free (value);
value = svGetValue (ifcfg, "BONDING_OPTS", FALSE);
if (value) {
char **items, **iter;
items = g_strsplit_set (value, " ", -1);
for (iter = items; iter && *iter; iter++) {
if (strlen (*iter)) {
char **keys, *key, *val;
keys = g_strsplit_set (*iter, "=", 2);
if (keys && *keys) {
key = *keys;
val = *(keys + 1);
if (val && strlen(key) && strlen(val))
handle_bond_option (s_bond, key, val);
}
g_strfreev (keys);
}
}
g_free (value);
g_strfreev (items);
}
return (NMSetting *) s_bond;
error:
g_object_unref (s_bond);
return NULL;
}
static NMConnection *
bond_connection_from_ifcfg (const char *file,
shvarFile *ifcfg,
GError **error)
{
NMConnection *connection = NULL;
NMSetting *con_setting = NULL;
NMSetting *bond_setting = NULL;
NMSetting *wired_setting = NULL;
NMSetting8021x *s_8021x = NULL;
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (ifcfg != NULL, NULL);
connection = nm_simple_connection_new ();
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BOND_SETTING_NAME, NULL, _("Bond"));
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, con_setting);
bond_setting = make_bond_setting (ifcfg, file, error);
if (!bond_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, bond_setting);
wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
if (!wired_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, wired_setting);
if (s_8021x)
nm_connection_add_setting (connection, NM_SETTING (s_8021x));
return connection;
}
/* Check 'error' for errors. Missing config (NULL return value) is a valid case. */
static char *
read_team_config (shvarFile *ifcfg, const char *key, GError **error)
{
char *value;
size_t l;
/* FIXME: validate the JSON at some point */
value = svGetValue (ifcfg, key, TRUE);
if (!value)
return NULL;
/* No reason Team config should be over 20k. The config is read
* verbatim, length-checked, then unescaped. svUnescape() does not
* deal well with extremely long strings.
*/
l = strlen (value);
if (l > 20000) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"%s too long (size %zd)", key, l);
g_free (value);
return NULL;
}
svUnescape (value);
return value;
}
static NMSetting *
make_team_setting (shvarFile *ifcfg,
const char *file,
GError **error)
{
NMSettingTeam *s_team;
char *value;
GError *local_err = NULL;
s_team = NM_SETTING_TEAM (nm_setting_team_new ());
value = svGetValue (ifcfg, "DEVICE", FALSE);
if (!value || !strlen (value)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"mandatory DEVICE keyword missing");
goto error;
}
g_free (value);
value = read_team_config (ifcfg, "TEAM_CONFIG", &local_err);
if (local_err) {
g_propagate_error (error, local_err);
goto error;
}
g_object_set (s_team, NM_SETTING_TEAM_CONFIG, value, NULL);
g_free (value);
return (NMSetting *) s_team;
error:
g_object_unref (s_team);
return NULL;
}
static NMConnection *
team_connection_from_ifcfg (const char *file,
shvarFile *ifcfg,
GError **error)
{
NMConnection *connection = NULL;
NMSetting *con_setting = NULL;
NMSetting *team_setting = NULL;
NMSetting *wired_setting = NULL;
NMSetting8021x *s_8021x = NULL;
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (ifcfg != NULL, NULL);
connection = nm_simple_connection_new ();
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_TEAM_SETTING_NAME, NULL, _("Team"));
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, con_setting);
team_setting = make_team_setting (ifcfg, file, error);
if (!team_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, team_setting);
wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
if (!wired_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, wired_setting);
if (s_8021x)
nm_connection_add_setting (connection, NM_SETTING (s_8021x));
return connection;
}
typedef void (*BridgeOptFunc) (NMSetting *setting,
gboolean stp,
const char *key,
const char *value);
static void
handle_bridge_option (NMSetting *setting,
gboolean stp,
const char *key,
const char *value)
{
guint32 u = 0;
if (!strcmp (key, "priority")) {
if (stp == FALSE) {
PARSE_WARNING ("'priority' invalid when STP is disabled");
} else if (get_uint (value, &u))
g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL);
else
PARSE_WARNING ("invalid priority value '%s'", value);
} else if (!strcmp (key, "hello_time")) {
if (stp == FALSE) {
PARSE_WARNING ("'hello_time' invalid when STP is disabled");
} else if (get_uint (value, &u))
g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL);
else
PARSE_WARNING ("invalid hello_time value '%s'", value);
} else if (!strcmp (key, "max_age")) {
if (stp == FALSE) {
PARSE_WARNING ("'max_age' invalid when STP is disabled");
} else if (get_uint (value, &u))
g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL);
else
PARSE_WARNING ("invalid max_age value '%s'", value);
} else if (!strcmp (key, "ageing_time")) {
if (get_uint (value, &u))
g_object_set (setting, NM_SETTING_BRIDGE_AGEING_TIME, u, NULL);
else
PARSE_WARNING ("invalid ageing_time value '%s'", value);
} else if (!strcmp (key, "multicast_snooping")) {
if (get_uint (value, &u))
g_object_set (setting, NM_SETTING_BRIDGE_MULTICAST_SNOOPING,
(gboolean) u, NULL);
else
PARSE_WARNING ("invalid multicast_snooping value '%s'", value);
} else
PARSE_WARNING ("unhandled bridge option '%s'", key);
}
static void
handle_bridging_opts (NMSetting *setting,
gboolean stp,
const char *value,
BridgeOptFunc func)
{
char **items, **iter;
items = g_strsplit_set (value, " ", -1);
for (iter = items; iter && *iter; iter++) {
if (strlen (*iter)) {
char **keys, *key, *val;
keys = g_strsplit_set (*iter, "=", 2);
if (keys && *keys) {
key = *keys;
val = *(keys + 1);
if (val && strlen(key) && strlen(val))
func (setting, stp, key, val);
}
g_strfreev (keys);
}
}
g_strfreev (items);
}
static NMSetting *
make_bridge_setting (shvarFile *ifcfg,
const char *file,
GError **error)
{
NMSettingBridge *s_bridge;
char *value;
guint32 u;
gboolean stp = FALSE;
gboolean stp_set = FALSE;
s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ());
value = svGetValue (ifcfg, "DEVICE", FALSE);
if (!value || !strlen (value)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"mandatory DEVICE keyword missing");
goto error;
}
g_free (value);
value = svGetValue (ifcfg, "MACADDR", FALSE);
if (value) {
value = g_strstrip (value);
g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, value, NULL);
g_free (value);
}
value = svGetValue (ifcfg, "STP", FALSE);
if (value) {
if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) {
g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL);
stp = TRUE;
stp_set = TRUE;
} else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) {
g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
stp_set = TRUE;
} else
PARSE_WARNING ("invalid STP value '%s'", value);
g_free (value);
}
if (!stp_set) {
/* Missing or invalid STP property means "no" */
g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
}
value = svGetValue (ifcfg, "DELAY", FALSE);
if (value) {
if (stp) {
if (get_uint (value, &u))
g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, u, NULL);
else
PARSE_WARNING ("invalid forward delay value '%s'", value);
} else
PARSE_WARNING ("DELAY invalid when STP is disabled");
g_free (value);
}
value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE);
if (value) {
handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option);
g_free (value);
}
return (NMSetting *) s_bridge;
error:
g_object_unref (s_bridge);
return NULL;
}
static NMConnection *
bridge_connection_from_ifcfg (const char *file,
shvarFile *ifcfg,
GError **error)
{
NMConnection *connection = NULL;
NMSetting *con_setting = NULL;
NMSetting *bridge_setting = NULL;
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (ifcfg != NULL, NULL);
connection = nm_simple_connection_new ();
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BRIDGE_SETTING_NAME, NULL, _("Bridge"));
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, con_setting);
bridge_setting = make_bridge_setting (ifcfg, file, error);
if (!bridge_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, bridge_setting);
return connection;
}
static void
handle_bridge_port_option (NMSetting *setting,
gboolean stp,
const char *key,
const char *value)
{
guint32 u = 0;
if (!strcmp (key, "priority")) {
if (get_uint (value, &u))
g_object_set (setting, NM_SETTING_BRIDGE_PORT_PRIORITY, u, NULL);
else
PARSE_WARNING ("invalid priority value '%s'", value);
} else if (!strcmp (key, "path_cost")) {
if (get_uint (value, &u))
g_object_set (setting, NM_SETTING_BRIDGE_PORT_PATH_COST, u, NULL);
else
PARSE_WARNING ("invalid path_cost value '%s'", value);
} else if (!strcmp (key, "hairpin_mode")) {
if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1"))
g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, TRUE, NULL);
else if (!strcasecmp (value, "off") || !strcasecmp (value, "no"))
g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, FALSE, NULL);
else
PARSE_WARNING ("invalid hairpin_mode value '%s'", value);
} else
PARSE_WARNING ("unhandled bridge port option '%s'", key);
}
static NMSetting *
make_bridge_port_setting (shvarFile *ifcfg)
{
NMSetting *s_port = NULL;
char *value;
g_return_val_if_fail (ifcfg != NULL, FALSE);
value = svGetValue (ifcfg, "BRIDGE", FALSE);
if (value) {
g_free (value);
s_port = nm_setting_bridge_port_new ();
value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE);
if (value)
handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option);
g_free (value);
}
return s_port;
}
static NMSetting *
make_team_port_setting (shvarFile *ifcfg)
{
NMSetting *s_port = NULL;
char *value;
GError *error = NULL;
value = read_team_config (ifcfg, "TEAM_PORT_CONFIG", &error);
if (value) {
s_port = nm_setting_team_port_new ();
g_object_set (s_port, NM_SETTING_TEAM_PORT_CONFIG, value, NULL);
g_free (value);
} else if (error) {
PARSE_WARNING ("%s", error->message);
g_error_free (error);
}
return s_port;
}
static gboolean
is_bond_device (const char *name, shvarFile *parsed)
{
g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (parsed != NULL, FALSE);
if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE))
return TRUE;
/* XXX: Check for "bond[\d]+"? */
return FALSE;
}
static gboolean
is_vlan_device (const char *name, shvarFile *parsed)
{
g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (parsed != NULL, FALSE);
if (svGetValueBoolean (parsed, "VLAN", FALSE))
return TRUE;
return FALSE;
}
static gboolean
is_wifi_device (const char *name, shvarFile *parsed)
{
int ifindex;
g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (parsed != NULL, FALSE);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, name);
if (ifindex == 0)
return FALSE;
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) == NM_LINK_TYPE_WIFI;
}
static void
parse_prio_map_list (NMSettingVlan *s_vlan,
shvarFile *ifcfg,
const char *key,
NMVlanPriorityMap map)
{
char *value;
gchar **list = NULL, **iter;
value = svGetValue (ifcfg, key, FALSE);
if (!value)
return;
list = g_strsplit_set (value, ",", -1);
g_free (value);
for (iter = list; iter && *iter; iter++) {
if (!*iter || !strchr (*iter, ':'))
continue;
if (!nm_setting_vlan_add_priority_str (s_vlan, map, *iter))
PARSE_WARNING ("invalid %s priority map item '%s'", key, *iter);
}
g_strfreev (list);
}
static NMSetting *
make_vlan_setting (shvarFile *ifcfg,
const char *file,
GError **error)
{
NMSettingVlan *s_vlan = NULL;
char *value = NULL;
char *iface_name = NULL;
char *parent = NULL;
const char *p = NULL;
char *end = NULL;
gint vlan_id = -1;
guint32 vlan_flags = 0;
gint gvrp;
value = svGetValue (ifcfg, "VLAN_ID", FALSE);
if (value) {
errno = 0;
vlan_id = (gint) g_ascii_strtoll (value, NULL, 10);
if (vlan_id < 0 || vlan_id > 4096 || errno) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid VLAN_ID '%s'", value);
g_free (value);
return NULL;
}
g_free (value);
}
/* Need DEVICE if we don't have a separate VLAN_ID property */
iface_name = svGetValue (ifcfg, "DEVICE", FALSE);
if (!iface_name && vlan_id < 0) {
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing DEVICE property; cannot determine VLAN ID.");
return NULL;
}
s_vlan = NM_SETTING_VLAN (nm_setting_vlan_new ());
/* Parent interface from PHYSDEV takes precedence if it exists */
parent = svGetValue (ifcfg, "PHYSDEV", FALSE);
if (iface_name) {
p = strchr (iface_name, '.');
if (p) {
/* eth0.43; PHYSDEV is assumed from it if unknown */
if (!parent) {
parent = g_strndup (iface_name, p - iface_name);
if (g_str_has_prefix (parent, "vlan")) {
/* Like initscripts, if no PHYSDEV and we get an obviously
* invalid parent interface from DEVICE, fail.
*/
g_free (parent);
parent = NULL;
}
}
p++;
} else {
/* format like vlan43; PHYSDEV must be set */
if (g_str_has_prefix (iface_name, "vlan"))
p = iface_name + 4;
}
if (p) {
/* Grab VLAN ID from interface name; this takes precedence over the
* separate VLAN_ID property for backwards compat.
*/
gint device_vlan_id = (gint) g_ascii_strtoll (p, &end, 10);
if (device_vlan_id >= 0 && device_vlan_id <= 4095 && end != p && !*end)
vlan_id = device_vlan_id;
}
}
if (vlan_id < 0) {
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to determine VLAN ID from DEVICE or VLAN_ID.");
goto error;
}
g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
if (parent == NULL) {
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to determine VLAN parent from DEVICE or PHYSDEV");
goto error;
}
g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
2015-02-07 16:54:01 +01:00
g_clear_pointer (&parent, g_free);
if (svGetValueBoolean (ifcfg, "REORDER_HDR", FALSE))
vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS;
gvrp = svGetValueBoolean (ifcfg, "GVRP", -1);
if (gvrp > 0)
vlan_flags |= NM_VLAN_FLAG_GVRP;
value = svGetValue (ifcfg, "VLAN_FLAGS", FALSE);
if (value) {
/* Prefer GVRP variable; only take VLAN_FLAG=GVRP when GVRP is not specified */
if (g_strstr_len (value, -1, "GVRP") && gvrp == -1)
vlan_flags |= NM_VLAN_FLAG_GVRP;
if (g_strstr_len (value, -1, "LOOSE_BINDING"))
vlan_flags |= NM_VLAN_FLAG_LOOSE_BINDING;
}
if (svGetValueBoolean (ifcfg, "MVRP", FALSE))
vlan_flags |= NM_VLAN_FLAG_MVRP;
g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, vlan_flags, NULL);
g_free (value);
parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP);
parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP);
2015-02-07 16:54:01 +01:00
g_free (iface_name);
return (NMSetting *) s_vlan;
error:
g_free (parent);
g_free (iface_name);
g_object_unref (s_vlan);
return NULL;
}
static NMConnection *
vlan_connection_from_ifcfg (const char *file,
shvarFile *ifcfg,
GError **error)
{
NMConnection *connection = NULL;
NMSetting *con_setting = NULL;
NMSetting *wired_setting = NULL;
NMSetting *vlan_setting = NULL;
NMSetting8021x *s_8021x = NULL;
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (ifcfg != NULL, NULL);
connection = nm_simple_connection_new ();
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_VLAN_SETTING_NAME, NULL, "Vlan");
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
g_object_unref (connection);
return NULL;
}
check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
nm_connection_add_setting (connection, con_setting);
vlan_setting = make_vlan_setting (ifcfg, file, error);
if (!vlan_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, vlan_setting);
wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
if (!wired_setting) {
g_object_unref (connection);
return NULL;
}
nm_connection_add_setting (connection, wired_setting);
if (s_8021x)
nm_connection_add_setting (connection, NM_SETTING (s_8021x));
return connection;
}
static NMConnection *
create_unhandled_connection (const char *filename, shvarFile *ifcfg,
const char *type, char **out_spec)
{
NMConnection *connection;
NMSetting *s_con;
char *value;
g_assert (out_spec != NULL);
connection = nm_simple_connection_new ();
/* Get NAME, UUID, etc. We need to set a connection type (generic) and add
* an empty type-specific setting as well, to make sure it passes
* nm_connection_verify() later.
*/
s_con = make_connection_setting (filename, ifcfg, NM_SETTING_GENERIC_SETTING_NAME,
NULL, NULL);
nm_connection_add_setting (connection, s_con);
nm_connection_add_setting (connection, nm_setting_generic_new ());
/* Get a spec */
value = svGetValue (ifcfg, "HWADDR", FALSE);
if (value) {
char *lower = g_ascii_strdown (value, -1);
*out_spec = g_strdup_printf ("%s:mac:%s", type, lower);
g_free (lower);
g_free (value);
return connection;
}
value = svGetValue (ifcfg, "SUBCHANNELS", FALSE);
if (value) {
*out_spec = g_strdup_printf ("%s:s390-subchannels:%s", type, value);
g_free (value);
return connection;
}
value = svGetValue (ifcfg, "DEVICE", FALSE);
if (value) {
*out_spec = g_strdup_printf ("%s:interface-name:%s", type, value);
g_free (value);
return connection;
}
g_object_unref (connection);
return NULL;
}
char *
uuid_from_file (const char *filename)
{
const char *ifcfg_name = NULL;
shvarFile *ifcfg;
char *uuid;
g_return_val_if_fail (filename != NULL, NULL);
ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
if (!ifcfg_name)
return NULL;
ifcfg = svOpenFile (filename, NULL);
if (!ifcfg)
return NULL;
/* Try for a UUID key before falling back to hashing the file name */
uuid = svGetValue (ifcfg, "UUID", FALSE);
if (!uuid || !strlen (uuid)) {
g_free (uuid);
uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
}
svCloseFile (ifcfg);
return uuid;
}
static void
check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6)
{
if (!s_ip6)
return;
/* If there is no IPv4 config or it doesn't contain DNS searches,
* read DOMAIN and put the domains into IPv6.
*/
if (!s_ip4 || nm_setting_ip_config_get_num_dns_searches (NM_SETTING_IP_CONFIG (s_ip4)) == 0) {
/* DNS searches */
char *value = svGetValue (ifcfg, "DOMAIN", FALSE);
if (value) {
char **searches = g_strsplit (value, " ", 0);
if (searches) {
char **item;
for (item = searches; *item; item++) {
if (strlen (*item)) {
if (!nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (s_ip6), *item))
PARSE_WARNING ("duplicate DNS domain '%s'", *item);
}
}
g_strfreev (searches);
}
g_free (value);
}
}
}
static NMConnection *
connection_from_file_full (const char *filename,
const char *network_file, /* for unit tests only */
const char *test_type, /* for unit tests only */
char **out_unhandled,
GError **error,
gboolean *out_ignore_error)
{
NMConnection *connection = NULL;
shvarFile *parsed;
2015-02-07 16:54:01 +01:00
gs_free char *type = NULL;
char *devtype, *bootproto;
NMSetting *s_ip4, *s_ip6, *s_port, *s_dcb = NULL;
const char *ifcfg_name = NULL;
g_return_val_if_fail (filename != NULL, NULL);
if (out_unhandled)
g_return_val_if_fail (*out_unhandled == NULL, NULL);
/* Non-NULL only for unit tests; normally use /etc/sysconfig/network */
if (!network_file)
network_file = SYSCONFDIR "/sysconfig/network";
ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
if (!ifcfg_name) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Ignoring connection '%s' because it's not an ifcfg file.", filename);
return NULL;
}
parsed = svOpenFile (filename, error);
if (!parsed)
return NULL;
if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) {
g_assert (out_unhandled != NULL);
connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled);
if (!connection)
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
"NM_CONTROLLED was false but device was not uniquely identified; device will be managed");
goto done;
}
/* iBFT is handled by the iBFT settings plugin */
bootproto = svGetValue (parsed, "BOOTPROTO", FALSE);
if (bootproto && !g_ascii_strcasecmp (bootproto, "ibft")) {
if (out_ignore_error)
*out_ignore_error = TRUE;
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Ignoring iBFT configuration");
g_free (bootproto);
goto done;
}
g_free (bootproto);
devtype = svGetValue (parsed, "DEVICETYPE", FALSE);
if (devtype) {
if (!strcasecmp (devtype, TYPE_TEAM))
type = g_strdup (TYPE_TEAM);
else if (!strcasecmp (devtype, TYPE_TEAM_PORT))
type = g_strdup (TYPE_ETHERNET);
g_free (devtype);
}
if (!type)
type = svGetValue (parsed, "TYPE", FALSE);
if (!type) {
char *device;
device = svGetValue (parsed, "DEVICE", FALSE);
if (!device) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"File '%s' had neither TYPE nor DEVICE keys.", filename);
goto done;
}
if (!strcmp (device, "lo")) {
if (out_ignore_error)
*out_ignore_error = TRUE;
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Ignoring loopback device config.");
g_free (device);
goto done;
}
if (!test_type) {
if (is_bond_device (device, parsed))
type = g_strdup (TYPE_BOND);
else if (is_vlan_device (device, parsed))
type = g_strdup (TYPE_VLAN);
else if (is_wifi_device (device, parsed))
type = g_strdup (TYPE_WIRELESS);
else
type = g_strdup (TYPE_ETHERNET);
} else {
/* For the unit tests, there won't necessarily be any
* adapters of the connection's type in the system so the
* type can't be tested with ioctls.
*/
type = g_strdup (test_type);
}
g_free (device);
} else {
/* Check for IBM s390 CTC devices and call them Ethernet */
if (g_strcmp0 (type, "CTC") == 0) {
g_free (type);
type = g_strdup (TYPE_ETHERNET);
}
}
if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE) &&
strcasecmp (type, TYPE_BOND)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"BONDING_MASTER=yes key only allowed in TYPE=bond connections");
goto done;
}
/* Construct the connection */
if (!strcasecmp (type, TYPE_ETHERNET))
connection = wired_connection_from_ifcfg (filename, parsed, error);
else if (!strcasecmp (type, TYPE_WIRELESS))
connection = wireless_connection_from_ifcfg (filename, parsed, error);
2011-10-21 09:34:30 -04:00
else if (!strcasecmp (type, TYPE_INFINIBAND))
connection = infiniband_connection_from_ifcfg (filename, parsed, error);
else if (!strcasecmp (type, TYPE_BOND))
connection = bond_connection_from_ifcfg (filename, parsed, error);
else if (!strcasecmp (type, TYPE_TEAM))
connection = team_connection_from_ifcfg (filename, parsed, error);
else if (!strcasecmp (type, TYPE_VLAN))
connection = vlan_connection_from_ifcfg (filename, parsed, error);
else if (!strcasecmp (type, TYPE_BRIDGE))
connection = bridge_connection_from_ifcfg (filename, parsed, error);
else {
g_assert (out_unhandled != NULL);
connection = create_unhandled_connection (filename, parsed, "unrecognized", out_unhandled);
if (!connection)
PARSE_WARNING ("connection type was unrecognized but device was not uniquely identified; device may be managed");
goto done;
}
if (!connection)
goto done;
s_ip6 = make_ip6_setting (parsed, network_file, error);
if (!s_ip6) {
g_object_unref (connection);
connection = NULL;
goto done;
} else
nm_connection_add_setting (connection, s_ip6);
s_ip4 = make_ip4_setting (parsed, network_file, error);
if (!s_ip4) {
g_object_unref (connection);
connection = NULL;
goto done;
} else {
read_aliases (NM_SETTING_IP_CONFIG (s_ip4), filename);
nm_connection_add_setting (connection, s_ip4);
}
/* There is only one DOMAIN variable and it is read and put to IPv4 config
* But if IPv4 is disabled or the config fails for some reason, we read
* DOMAIN and put the values into IPv6 config instead.
*/
check_dns_search_domains (parsed, s_ip4, s_ip6);
/* Bridge port? */
s_port = make_bridge_port_setting (parsed);
if (s_port)
nm_connection_add_setting (connection, s_port);
/* Team port? */
s_port = make_team_port_setting (parsed);
if (s_port)
nm_connection_add_setting (connection, s_port);
if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) {
g_object_unref (connection);
connection = NULL;
goto done;
}
if (s_dcb)
nm_connection_add_setting (connection, s_dcb);
if (!nm_connection_normalize (connection, NULL, NULL, error)) {
g_object_unref (connection);
connection = NULL;
}
done:
svCloseFile (parsed);
return connection;
}
NMConnection *
connection_from_file (const char *filename,
char **out_unhandled,
GError **error,
gboolean *out_ignore_error)
{
return connection_from_file_full (filename, NULL, NULL,
out_unhandled,
error,
out_ignore_error);
}
NMConnection *
connection_from_file_test (const char *filename,
const char *network_file,
const char *test_type,
char **out_unhandled,
GError **error)
{
return connection_from_file_full (filename,
network_file,
test_type,
out_unhandled,
error,
NULL);
}
guint
devtimeout_from_file (const char *filename)
{
shvarFile *ifcfg;
char *devtimeout_str;
guint devtimeout;
g_return_val_if_fail (filename != NULL, 0);
ifcfg = svOpenFile (filename, NULL);
if (!ifcfg)
return 0;
devtimeout_str = svGetValue (ifcfg, "DEVTIMEOUT", FALSE);
if (devtimeout_str) {
devtimeout = _nm_utils_ascii_str_to_int64 (devtimeout_str, 10, 0, G_MAXUINT, 0);
g_free (devtimeout_str);
} else
devtimeout = 0;
svCloseFile (ifcfg);
return devtimeout;
}