1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager system settings service
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Copyright 2008 - 2014 Red Hat, Inc.
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <arpa/inet.h>
29 #include <sys/inotify.h>
31 #include <sys/ioctl.h>
35 #include <glib/gi18n.h>
36 #include <nm-connection.h>
37 #include <nm-dbus-interface.h>
38 #include <nm-setting-connection.h>
39 #include <nm-setting-ip4-config.h>
40 #include <nm-setting-vlan.h>
41 #include <nm-setting-ip6-config.h>
42 #include <nm-setting-wired.h>
43 #include <nm-setting-wireless.h>
44 #include <nm-setting-8021x.h>
45 #include <nm-setting-bond.h>
46 #include <nm-setting-team.h>
47 #include <nm-setting-team-port.h>
48 #include <nm-setting-bridge.h>
49 #include <nm-setting-bridge-port.h>
50 #include <nm-setting-dcb.h>
51 #include <nm-setting-generic.h>
52 #include "nm-core-internal.h"
55 #include "nm-platform.h"
56 #include "nm-posix-signals.h"
57 #include "NetworkManagerUtils.h"
58 #include "nm-logging.h"
66 #define PARSE_WARNING(msg...) nm_log_warn (LOGD_SETTINGS, " " msg)
69 get_int (const char *str, int *value)
75 tmp = strtol (str, &e, 0);
76 if (errno || *e != '\0' || tmp > G_MAXINT || tmp < G_MININT)
83 get_uint (const char *str, guint32 *value)
86 long unsigned int tmp;
89 tmp = strtoul (str, &e, 0);
90 if (errno || *e != '\0')
92 *value = (guint32) tmp;
97 make_connection_name (shvarFile *ifcfg,
98 const char *ifcfg_name,
99 const char *suggested,
102 char *full_name = NULL, *name;
104 /* If the ifcfg file already has a NAME, always use that */
105 name = svGetValue (ifcfg, "NAME", FALSE);
106 if (name && strlen (name))
109 /* Otherwise construct a new NAME */
112 prefix = _("System");
114 /* For cosmetic reasons, if the suggested name is the same as
115 * the ifcfg files name, don't use it. Mainly for wifi so that
116 * the SSID is shown in the connection ID instead of just "wlan0".
118 if (suggested && strcmp (ifcfg_name, suggested))
119 full_name = g_strdup_printf ("%s %s (%s)", prefix, suggested, ifcfg_name);
121 full_name = g_strdup_printf ("%s %s", prefix, ifcfg_name);
127 make_connection_setting (const char *file,
130 const char *suggested,
133 NMSettingConnection *s_con;
134 const char *ifcfg_name = NULL;
135 char *new_id, *uuid = NULL, *zone = NULL, *value;
137 ifcfg_name = utils_get_ifcfg_name (file, TRUE);
141 s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
143 new_id = make_connection_name (ifcfg, ifcfg_name, suggested, prefix);
144 g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
147 /* Try for a UUID key before falling back to hashing the file name */
148 uuid = svGetValue (ifcfg, "UUID", FALSE);
149 if (!uuid || !strlen (uuid)) {
151 uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
155 NM_SETTING_CONNECTION_TYPE, type,
156 NM_SETTING_CONNECTION_UUID, uuid,
160 value = svGetValue (ifcfg, "DEVICE", FALSE);
162 if (nm_utils_iface_valid_name (value)) {
164 NM_SETTING_CONNECTION_INTERFACE_NAME, value,
167 PARSE_WARNING ("invalid DEVICE name '%s'", value);
171 /* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */
173 NM_SETTING_CONNECTION_AUTOCONNECT,
174 svTrueValue (ifcfg, "ONBOOT", TRUE),
175 NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY,
176 (gint) svGetValueInt64 (ifcfg, "AUTOCONNECT_PRIORITY", 10,
177 NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN,
178 NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX,
179 NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT),
182 value = svGetValue (ifcfg, "USERS", FALSE);
184 char **items, **iter;
186 items = g_strsplit_set (value, " ", -1);
187 for (iter = items; iter && *iter; iter++) {
188 if (strlen (*iter)) {
189 if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL))
190 PARSE_WARNING ("invalid USERS item '%s'", *iter);
198 zone = svGetValue(ifcfg, "ZONE", FALSE);
199 if (!zone || !strlen (zone)) {
203 g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL);
206 value = svGetValue (ifcfg, "SECONDARY_UUIDS", FALSE);
208 char **items, **iter;
210 items = g_strsplit_set (value, " \t", -1);
211 for (iter = items; iter && *iter; iter++) {
212 if (strlen (*iter)) {
213 if (!nm_setting_connection_add_secondary (s_con, *iter))
214 PARSE_WARNING ("secondary connection UUID '%s' already added", *iter);
221 value = svGetValue (ifcfg, "BRIDGE", FALSE);
223 const char *old_value;
225 if ((old_value = nm_setting_connection_get_master (s_con))) {
226 PARSE_WARNING ("Already configured as slave of %s. Ignoring BRIDGE=\"%s\"",
229 g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
230 g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE,
231 NM_SETTING_BRIDGE_SETTING_NAME, NULL);
236 value = svGetValue (ifcfg, "GATEWAY_PING_TIMEOUT", FALSE);
242 tmp = strtol (value, NULL, 10);
243 if (errno == 0 && tmp >= 0 && tmp < G_MAXINT32) {
244 timeout = (guint32) tmp;
245 g_object_set (s_con, NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, timeout, NULL);
247 PARSE_WARNING ("invalid GATEWAY_PING_TIMEOUT time");
251 return NM_SETTING (s_con);
254 /* Returns TRUE on missing address or valid address */
256 read_ip4_address (shvarFile *ifcfg,
263 g_return_val_if_fail (ifcfg != NULL, FALSE);
264 g_return_val_if_fail (tag != NULL, FALSE);
265 g_return_val_if_fail (out_addr != NULL, FALSE);
266 g_return_val_if_fail (!error || !*error, FALSE);
270 value = svGetValue (ifcfg, tag, FALSE);
274 if (nm_utils_ipaddr_valid (AF_INET, value)) {
278 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
279 "Invalid %s IP4 address '%s'", tag, value);
286 get_numbered_tag (char *tag_name, int which)
289 return g_strdup (tag_name);
290 return g_strdup_printf ("%s%u", tag_name, which);
294 is_any_ip4_address_defined (shvarFile *ifcfg)
298 for (i = -1; i <= 2; i++) {
302 tag = get_numbered_tag ("IPADDR", i);
303 value = svGetValue (ifcfg, tag, FALSE);
310 tag = get_numbered_tag ("PREFIX", i);
311 value = svGetValue (ifcfg, tag, FALSE);
318 tag = get_numbered_tag ("NETMASK", i);
319 value = svGetValue (ifcfg, tag, FALSE);
329 /* Returns TRUE on missing address or valid address */
331 read_full_ip4_address (shvarFile *ifcfg,
332 const char *network_file,
334 NMIPAddress *base_addr,
335 NMIPAddress **out_address,
339 char *ip_tag, *prefix_tag, *netmask_tag, *gw_tag;
342 gboolean success = FALSE;
346 g_return_val_if_fail (which >= -1, FALSE);
347 g_return_val_if_fail (ifcfg != NULL, FALSE);
348 g_return_val_if_fail (network_file != NULL, FALSE);
349 g_return_val_if_fail (out_address != NULL, FALSE);
350 g_return_val_if_fail (*out_address == NULL, FALSE);
351 g_return_val_if_fail (!error || !*error, FALSE);
353 ip_tag = get_numbered_tag ("IPADDR", which);
354 prefix_tag = get_numbered_tag ("PREFIX", which);
355 netmask_tag = get_numbered_tag ("NETMASK", which);
356 gw_tag = get_numbered_tag ("GATEWAY", which);
359 if (!read_ip4_address (ifcfg, ip_tag, &ip, error))
363 ip = g_strdup (nm_ip_address_get_address (base_addr));
371 if (out_gateway && !*out_gateway) {
372 if (!read_ip4_address (ifcfg, gw_tag, out_gateway, error))
377 value = svGetValue (ifcfg, prefix_tag, FALSE);
380 prefix = strtol (value, NULL, 10);
381 if (errno || prefix < 0) {
382 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
383 "Invalid IP4 prefix '%s'", value);
390 /* Fall back to NETMASK if no PREFIX was specified */
392 if (!read_ip4_address (ifcfg, netmask_tag, &value, error))
395 inet_pton (AF_INET, value, &tmp);
396 prefix = nm_utils_ip4_netmask_to_prefix (tmp);
401 if (prefix == 0 && base_addr)
402 prefix = nm_ip_address_get_prefix (base_addr);
404 /* Try to autodetermine the prefix for the address' class */
406 if (inet_pton (AF_INET, ip, &tmp) == 1) {
407 prefix = nm_utils_ip4_get_default_prefix (tmp);
409 PARSE_WARNING ("missing %s, assuming %s/%ld", prefix_tag, ip, prefix);
413 /* Validate the prefix */
415 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
416 "Missing IP4 prefix");
420 *out_address = nm_ip_address_new (AF_INET, ip, prefix, error);
428 g_free (netmask_tag);
434 /* Returns TRUE on missing route or valid route */
436 read_one_ip4_route (shvarFile *ifcfg,
437 const char *network_file,
439 NMIPRoute **out_route,
442 char *ip_tag, *netmask_tag, *gw_tag, *metric_tag, *value;
443 char *dest = NULL, *next_hop = NULL;
444 gint64 prefix, metric;
445 gboolean success = FALSE;
447 g_return_val_if_fail (ifcfg != NULL, FALSE);
448 g_return_val_if_fail (network_file != NULL, FALSE);
449 g_return_val_if_fail (out_route != NULL, FALSE);
450 g_return_val_if_fail (*out_route == NULL, FALSE);
451 g_return_val_if_fail (!error || !*error, FALSE);
453 ip_tag = g_strdup_printf ("ADDRESS%u", which);
454 netmask_tag = g_strdup_printf ("NETMASK%u", which);
455 gw_tag = g_strdup_printf ("GATEWAY%u", which);
456 metric_tag = g_strdup_printf ("METRIC%u", which);
459 if (!read_ip4_address (ifcfg, ip_tag, &dest, error))
462 /* Check whether IP is missing or 0.0.0.0 */
464 val = svGetValue (ifcfg, ip_tag, FALSE);
467 success = TRUE; /* missing route = success */
474 if (!read_ip4_address (ifcfg, gw_tag, &next_hop, error))
476 /* We don't make distinction between missing GATEWAY IP and 0.0.0.0 */
479 if (!read_ip4_address (ifcfg, netmask_tag, &value, error))
484 inet_pton (AF_INET, value, &netmask);
485 prefix = nm_utils_ip4_netmask_to_prefix (netmask);
487 if (prefix == 0 || netmask != nm_utils_ip4_prefix_to_netmask (prefix)) {
488 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
489 "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, NULL));
493 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
494 "Missing IP4 route element '%s'", netmask_tag);
499 value = svGetValue (ifcfg, metric_tag, FALSE);
501 metric = nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1);
503 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
504 "Invalid IP4 route metric '%s'", value);
512 *out_route = nm_ip_route_new (AF_INET, dest, prefix, next_hop, metric, error);
520 g_free (netmask_tag);
527 read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error)
529 char *contents = NULL;
531 char **lines = NULL, **iter;
532 GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
533 GMatchInfo *match_info;
534 NMIPRoute *route = NULL;
535 char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
536 gint64 prefix_int, metric_int;
537 gboolean success = FALSE;
539 const char *pattern_empty = "^\\s*(\\#.*)?$";
540 const char *pattern_to1 = "^\\s*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */
541 "(?:/(\\d{1,2}))?"; /* optional prefix */
542 const char *pattern_to2 = "to\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */
543 "(?:/(\\d{1,2}))?"; /* optional prefix */
544 const char *pattern_via = "via\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})"; /* IP of gateway */
545 const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */
547 g_return_val_if_fail (filename != NULL, FALSE);
548 g_return_val_if_fail (s_ip4 != NULL, FALSE);
549 g_return_val_if_fail (!error || !*error, FALSE);
551 /* Read the route file */
552 if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) {
554 return TRUE; /* missing/empty = success */
557 /* Create regexes for pieces to be matched */
558 regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
559 regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
560 regex_via = g_regex_new (pattern_via, 0, 0, NULL);
561 regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
563 /* Iterate through file lines */
564 lines = g_strsplit_set (contents, "\n\r", -1);
565 for (iter = lines; iter && *iter; iter++) {
567 /* Skip empty lines */
568 if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
572 g_regex_match (regex_to1, *iter, 0, &match_info);
573 if (!g_match_info_matches (match_info)) {
574 g_match_info_free (match_info);
575 g_regex_match (regex_to2, *iter, 0, &match_info);
576 if (!g_match_info_matches (match_info)) {
577 g_match_info_free (match_info);
578 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
579 "Missing IP4 route destination address in record: '%s'", *iter);
583 dest = g_match_info_fetch (match_info, 1);
584 if (!strcmp (dest, "default"))
585 strcpy (dest, "0.0.0.0");
586 if (!nm_utils_ipaddr_valid (AF_INET, dest)) {
587 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
588 "Invalid IP4 route destination address '%s'", dest);
590 g_match_info_free (match_info);
594 /* Prefix - is optional; 32 if missing */
595 prefix = g_match_info_fetch (match_info, 2);
596 g_match_info_free (match_info);
600 prefix_int = strtol (prefix, NULL, 10);
601 if (errno || prefix_int <= 0 || prefix_int > 32) {
602 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
603 "Invalid IP4 route destination prefix '%s'", prefix);
612 g_regex_match (regex_via, *iter, 0, &match_info);
613 if (g_match_info_matches (match_info)) {
614 next_hop = g_match_info_fetch (match_info, 1);
615 if (!nm_utils_ipaddr_valid (AF_INET, next_hop)) {
616 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
617 "Invalid IP4 route gateway address '%s'",
619 g_match_info_free (match_info);
625 /* we don't make distinction between missing GATEWAY IP and 0.0.0.0 */
628 g_match_info_free (match_info);
631 g_regex_match (regex_metric, *iter, 0, &match_info);
633 if (g_match_info_matches (match_info)) {
634 metric = g_match_info_fetch (match_info, 1);
636 metric_int = strtol (metric, NULL, 10);
637 if (errno || metric_int < 0) {
638 g_match_info_free (match_info);
639 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
640 "Invalid IP4 route metric '%s'", metric);
648 g_match_info_free (match_info);
650 route = nm_ip_route_new (AF_INET, dest, prefix_int, next_hop, metric_int, error);
656 if (!nm_setting_ip_config_add_route (s_ip4, route))
657 PARSE_WARNING ("duplicate IP4 route");
666 nm_ip_route_unref (route);
667 g_regex_unref (regex_to1);
668 g_regex_unref (regex_to2);
669 g_regex_unref (regex_via);
670 g_regex_unref (regex_metric);
676 parse_full_ip6_address (shvarFile *ifcfg,
677 const char *network_file,
678 const char *addr_str,
680 NMIPAddress **out_address,
684 char *ip_val, *prefix_val;
686 gboolean success = FALSE;
688 g_return_val_if_fail (addr_str != NULL, FALSE);
689 g_return_val_if_fail (out_address != NULL, FALSE);
690 g_return_val_if_fail (*out_address == NULL, FALSE);
691 g_return_val_if_fail (!error || !*error, FALSE);
693 /* Split the address and prefix */
694 list = g_strsplit_set (addr_str, "/", 2);
695 if (g_strv_length (list) < 1) {
696 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
697 "Invalid IP6 address '%s'", addr_str);
703 prefix_val = list[1];
706 prefix = strtol (prefix_val, NULL, 10);
707 if (errno || prefix <= 0 || prefix > 128) {
708 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
709 "Invalid IP6 prefix '%s'", prefix_val);
713 /* Missing prefix is treated as prefix of 64 */
717 *out_address = nm_ip_address_new (AF_INET6, ip_val, prefix, error);
726 /* IPv6 address is very complex to describe completely by a regular expression,
727 * so don't try to, rather use looser syntax to comprise all possibilities
728 * NOTE: The regexes below don't describe all variants allowed by 'ip route add',
729 * namely destination IP without 'to' keyword is recognized just at line start.
731 #define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
734 read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error)
736 char *contents = NULL;
738 char **lines = NULL, **iter;
739 GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
740 GMatchInfo *match_info;
741 NMIPRoute *route = NULL;
742 char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
743 gint64 prefix_int, metric_int;
744 gboolean success = FALSE;
746 const char *pattern_empty = "^\\s*(\\#.*)?$";
747 const char *pattern_to1 = "^\\s*(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */
748 "(?:/(\\d{1,3}))?"; /* optional prefix */
749 const char *pattern_to2 = "to\\s+(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */
750 "(?:/(\\d{1,3}))?"; /* optional prefix */
751 const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")"; /* IPv6 of gateway */
752 const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */
754 g_return_val_if_fail (filename != NULL, FALSE);
755 g_return_val_if_fail (s_ip6 != NULL, FALSE);
756 g_return_val_if_fail (!error || !*error, FALSE);
758 /* Read the route file */
759 if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) {
761 return TRUE; /* missing/empty = success */
764 /* Create regexes for pieces to be matched */
765 regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
766 regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
767 regex_via = g_regex_new (pattern_via, 0, 0, NULL);
768 regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
770 /* Iterate through file lines */
771 lines = g_strsplit_set (contents, "\n\r", -1);
772 for (iter = lines; iter && *iter; iter++) {
774 /* Skip empty lines */
775 if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
779 g_regex_match (regex_to1, *iter, 0, &match_info);
780 if (!g_match_info_matches (match_info)) {
781 g_match_info_free (match_info);
782 g_regex_match (regex_to2, *iter, 0, &match_info);
783 if (!g_match_info_matches (match_info)) {
784 g_match_info_free (match_info);
785 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
786 "Missing IP6 route destination address in record: '%s'", *iter);
790 dest = g_match_info_fetch (match_info, 1);
791 if (!g_strcmp0 (dest, "default")) {
792 /* Ignore default route - NM handles it internally */
793 g_clear_pointer (&dest, g_free);
794 g_match_info_free (match_info);
795 PARSE_WARNING ("ignoring manual default route: '%s' (%s)", *iter, filename);
799 /* Prefix - is optional; 128 if missing */
800 prefix = g_match_info_fetch (match_info, 2);
801 g_match_info_free (match_info);
805 prefix_int = strtol (prefix, NULL, 10);
806 if (errno || prefix_int <= 0 || prefix_int > 128) {
807 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
808 "Invalid IP6 route destination prefix '%s'", prefix);
817 g_regex_match (regex_via, *iter, 0, &match_info);
818 if (g_match_info_matches (match_info)) {
819 next_hop = g_match_info_fetch (match_info, 1);
820 if (!nm_utils_ipaddr_valid (AF_INET6, next_hop)) {
821 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
822 "Invalid IPv6 route nexthop address '%s'",
824 g_match_info_free (match_info);
830 /* Missing "via" is taken as :: */
833 g_match_info_free (match_info);
836 g_regex_match (regex_metric, *iter, 0, &match_info);
838 if (g_match_info_matches (match_info)) {
839 metric = g_match_info_fetch (match_info, 1);
841 metric_int = strtol (metric, NULL, 10);
842 if (errno || metric_int < 0 || metric_int > G_MAXUINT32) {
843 g_match_info_free (match_info);
844 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
845 "Invalid IP6 route metric '%s'", metric);
853 g_match_info_free (match_info);
855 route = nm_ip_route_new (AF_INET6, dest, prefix_int, next_hop, metric_int, error);
860 if (!nm_setting_ip_config_add_route (s_ip6, route))
861 PARSE_WARNING ("duplicate IP6 route");
870 nm_ip_route_unref (route);
871 g_regex_unref (regex_to1);
872 g_regex_unref (regex_to2);
873 g_regex_unref (regex_via);
874 g_regex_unref (regex_metric);
881 make_ip4_setting (shvarFile *ifcfg,
882 const char *network_file,
885 NMSettingIPConfig *s_ip4 = NULL;
887 char *route_path = NULL;
889 char *gateway = NULL;
891 shvarFile *network_ifcfg;
892 shvarFile *route_ifcfg;
893 gboolean never_default = FALSE;
895 s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
897 /* First check if DEFROUTE is set for this device; DEFROUTE has the
898 * opposite meaning from never-default. The default if DEFROUTE is not
899 * specified is DEFROUTE=yes which means that this connection can be used
902 never_default = !svTrueValue (ifcfg, "DEFROUTE", TRUE);
904 /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */
905 network_ifcfg = svOpenFile (network_file, NULL);
909 /* Get the connection ifcfg device name and the global gateway device */
910 value = svGetValue (ifcfg, "DEVICE", FALSE);
911 gatewaydev = svGetValue (network_ifcfg, "GATEWAYDEV", FALSE);
913 /* If there was a global gateway device specified, then only connections
914 * for that device can be the default connection.
916 if (gatewaydev && value)
917 never_default = !!strcmp (value, gatewaydev);
921 svCloseFile (network_ifcfg);
924 value = svGetValue (ifcfg, "BOOTPROTO", FALSE);
926 if (!value || !*value || !g_ascii_strcasecmp (value, "none")) {
927 if (is_any_ip4_address_defined (ifcfg))
928 method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
930 method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
931 } else if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) {
932 method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
933 } else if (!g_ascii_strcasecmp (value, "static")) {
934 method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
935 } else if (!g_ascii_strcasecmp (value, "autoip")) {
938 NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
939 NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
941 return NM_SETTING (s_ip4);
942 } else if (!g_ascii_strcasecmp (value, "shared")) {
945 NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED,
946 NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
948 return NM_SETTING (s_ip4);
950 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
951 "Unknown BOOTPROTO '%s'", value);
958 NM_SETTING_IP_CONFIG_METHOD, method,
959 NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "PEERDNS", TRUE),
960 NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "PEERROUTES", TRUE),
961 NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
962 NM_SETTING_IP_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", FALSE),
963 NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV4_ROUTE_METRIC", 10,
964 -1, G_MAXUINT32, -1),
967 if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
968 return NM_SETTING (s_ip4);
970 /* Handle DHCP settings */
971 if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
972 value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
973 if (value && strlen (value))
974 g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL);
978 NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME,
979 svTrueValue (ifcfg, "DHCP_SEND_HOSTNAME", TRUE),
982 value = svGetValue (ifcfg, "DHCP_CLIENT_ID", FALSE);
983 if (value && strlen (value))
984 g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, value, NULL);
988 /* Read static IP addresses.
989 * Read them even for AUTO method - in this case the addresses are
990 * added to the automatic ones. Note that this is not currently supported by
991 * the legacy 'network' service (ifup-eth).
993 for (i = -1; i < 256; i++) {
994 NMIPAddress *addr = NULL;
996 if (!read_full_ip4_address (ifcfg, network_file, i, NULL, &addr, &gateway, error))
1000 /* The first mandatory variable is 2-indexed (IPADDR2)
1001 * Variables IPADDR, IPADDR0 and IPADDR1 are optional */
1007 if (!nm_setting_ip_config_add_address (s_ip4, addr))
1008 PARSE_WARNING ("duplicate IP4 address");
1009 nm_ip_address_unref (addr);
1014 network_ifcfg = svOpenFile (network_file, NULL);
1015 if (network_ifcfg) {
1016 gboolean read_success;
1018 read_success = read_ip4_address (network_ifcfg, "GATEWAY", &gateway, error);
1019 svCloseFile (network_ifcfg);
1024 g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
1027 * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
1029 for (i = 1; i <= 10; i++) {
1032 tag = g_strdup_printf ("DNS%u", i);
1033 value = svGetValue (ifcfg, tag, FALSE);
1035 if (nm_utils_ipaddr_valid (AF_INET, value)) {
1036 if (!nm_setting_ip_config_add_dns (s_ip4, value))
1037 PARSE_WARNING ("duplicate DNS server %s", tag);
1038 } else if (nm_utils_ipaddr_valid (AF_INET6, value)) {
1039 /* Ignore IPv6 addresses */
1041 PARSE_WARNING ("invalid DNS server address %s", value);
1054 value = svGetValue (ifcfg, "DOMAIN", FALSE);
1056 char **searches = NULL;
1058 searches = g_strsplit (value, " ", 0);
1061 for (item = searches; *item; item++) {
1062 if (strlen (*item)) {
1063 if (!nm_setting_ip_config_add_dns_search (s_ip4, *item))
1064 PARSE_WARNING ("duplicate DNS domain '%s'", *item);
1067 g_strfreev (searches);
1072 /* Static routes - route-<name> file */
1073 route_path = utils_get_route_path (ifcfg->fileName);
1075 if (utils_has_complex_routes (route_path)) {
1076 PARSE_WARNING ("'rule-' or 'rule6-' file is present; you will need to use a dispatcher script to apply these routes");
1077 } else if (utils_has_route_file_new_syntax (route_path)) {
1078 /* Parse route file in new syntax */
1079 route_ifcfg = utils_get_route_ifcfg (ifcfg->fileName, FALSE);
1081 for (i = 0; i < 256; i++) {
1082 NMIPRoute *route = NULL;
1084 if (!read_one_ip4_route (route_ifcfg, network_file, i, &route, error)) {
1085 svCloseFile (route_ifcfg);
1092 if (!nm_setting_ip_config_add_route (s_ip4, route))
1093 PARSE_WARNING ("duplicate IP4 route");
1094 nm_ip_route_unref (route);
1096 svCloseFile (route_ifcfg);
1099 if (!read_route_file_legacy (route_path, s_ip4, error))
1103 /* Legacy value NM used for a while but is incorrect (rh #459370) */
1104 if (!nm_setting_ip_config_get_num_dns_searches (s_ip4)) {
1105 value = svGetValue (ifcfg, "SEARCH", FALSE);
1107 char **searches = NULL;
1109 searches = g_strsplit (value, " ", 0);
1112 for (item = searches; *item; item++) {
1113 if (strlen (*item)) {
1114 if (!nm_setting_ip_config_add_dns_search (s_ip4, *item))
1115 PARSE_WARNING ("duplicate DNS search '%s'", *item);
1118 g_strfreev (searches);
1124 return NM_SETTING (s_ip4);
1128 g_free (route_path);
1129 g_object_unref (s_ip4);
1134 read_aliases (NMSettingIPConfig *s_ip4, const char *filename, const char *network_file)
1137 char *dirname, *base;
1139 NMIPAddress *base_addr;
1142 g_return_if_fail (s_ip4 != NULL);
1143 g_return_if_fail (filename != NULL);
1145 if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0)
1148 base_addr = nm_setting_ip_config_get_address (s_ip4, 0);
1150 dirname = g_path_get_dirname (filename);
1151 g_return_if_fail (dirname != NULL);
1152 base = g_path_get_basename (filename);
1153 g_return_if_fail (base != NULL);
1155 dir = g_dir_open (dirname, 0, &err);
1161 while ((item = g_dir_read_name (dir))) {
1162 char *full_path, *device;
1165 if (!utils_is_ifcfg_alias_file (item, base))
1168 full_path = g_build_filename (dirname, item, NULL);
1170 p = strchr (item, ':');
1171 g_assert (p != NULL); /* we know this is true from utils_is_ifcfg_alias_file() */
1172 for (p++; *p; p++) {
1173 if (!g_ascii_isalnum (*p) && *p != '_')
1177 PARSE_WARNING ("ignoring alias file '%s' with invalid name", full_path);
1182 parsed = svOpenFile (full_path, &err);
1184 PARSE_WARNING ("couldn't parse alias file '%s': %s", full_path, err->message);
1186 g_clear_error (&err);
1190 device = svGetValue (parsed, "DEVICE", FALSE);
1192 PARSE_WARNING ("alias file '%s' has no DEVICE", full_path);
1193 svCloseFile (parsed);
1197 /* We know that item starts with IFCFG_TAG from utils_is_ifcfg_alias_file() */
1198 if (strcmp (device, item + strlen (IFCFG_TAG)) != 0) {
1199 PARSE_WARNING ("alias file '%s' has invalid DEVICE (%s) for filename",
1202 svCloseFile (parsed);
1208 ok = read_full_ip4_address (parsed, network_file, -1, base_addr, &addr, NULL, &err);
1209 svCloseFile (parsed);
1211 nm_ip_address_set_attribute (addr, "label", g_variant_new_string (device));
1212 if (!nm_setting_ip_config_add_address (s_ip4, addr))
1213 PARSE_WARNING ("duplicate IP4 address in alias file %s", item);
1215 PARSE_WARNING ("error reading IP4 address from alias file '%s': %s",
1216 full_path, err ? err->message : "no address");
1217 g_clear_error (&err);
1219 nm_ip_address_unref (addr);
1227 PARSE_WARNING ("can not read directory '%s': %s", dirname, err->message);
1236 make_ip6_setting (shvarFile *ifcfg,
1237 const char *network_file,
1240 NMSettingIPConfig *s_ip6 = NULL;
1243 char *route6_path = NULL;
1244 gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE;
1245 char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
1246 char *ipv6addr, *ipv6addr_secondaries;
1247 char **list = NULL, **iter;
1249 shvarFile *network_ifcfg;
1250 gboolean never_default = FALSE;
1251 gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip;
1252 char *ip6_privacy_str;
1253 NMSettingIP6ConfigPrivacy ip6_privacy_val;
1255 s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
1257 /* First check if IPV6_DEFROUTE is set for this device; IPV6_DEFROUTE has the
1258 * opposite meaning from never-default. The default if IPV6_DEFROUTE is not
1259 * specified is IPV6_DEFROUTE=yes which means that this connection can be used
1260 * as a default route
1262 never_default = !svTrueValue (ifcfg, "IPV6_DEFROUTE", TRUE);
1264 /* Then check if IPV6_DEFAULTGW or IPV6_DEFAULTDEV is specified;
1265 * they are global and override IPV6_DEFROUTE
1266 * When both are set, the device specified in IPV6_DEFAULTGW takes preference.
1268 network_ifcfg = svOpenFile (network_file, NULL);
1269 if (network_ifcfg) {
1270 char *ipv6_defaultgw, *ipv6_defaultdev;
1271 char *default_dev = NULL;
1273 /* Get the connection ifcfg device name and the global default route device */
1274 value = svGetValue (ifcfg, "DEVICE", FALSE);
1275 ipv6_defaultgw = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
1276 ipv6_defaultdev = svGetValue (network_ifcfg, "IPV6_DEFAULTDEV", FALSE);
1278 if (ipv6_defaultgw) {
1279 default_dev = strchr (ipv6_defaultgw, '%');
1284 default_dev = ipv6_defaultdev;
1286 /* If there was a global default route device specified, then only connections
1287 * for that device can be the default connection.
1289 if (default_dev && value)
1290 never_default = !!strcmp (value, default_dev);
1292 g_free (ipv6_defaultgw);
1293 g_free (ipv6_defaultdev);
1295 svCloseFile (network_ifcfg);
1298 /* Find out method property */
1299 /* Is IPV6 enabled? Set method to "ignored", when not enabled */
1300 str_value = svGetValue (ifcfg, "IPV6INIT", FALSE);
1301 ipv6init = svTrueValue (ifcfg, "IPV6INIT", FALSE);
1303 network_ifcfg = svOpenFile (network_file, NULL);
1304 if (network_ifcfg) {
1305 ipv6init = svTrueValue (network_ifcfg, "IPV6INIT", FALSE);
1306 svCloseFile (network_ifcfg);
1312 method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */
1314 ipv6forwarding = svTrueValue (ifcfg, "IPV6FORWARDING", FALSE);
1315 ipv6_autoconf = svTrueValue (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding);
1316 dhcp6 = svTrueValue (ifcfg, "DHCPV6C", FALSE);
1319 method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
1321 method = NM_SETTING_IP6_CONFIG_METHOD_DHCP;
1323 /* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */
1324 str_value = svGetValue (ifcfg, "IPV6ADDR", FALSE);
1326 str_value = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
1329 method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
1333 /* TODO - handle other methods */
1335 /* Read IPv6 Privacy Extensions configuration */
1336 ip6_privacy_str = svGetValue (ifcfg, "IPV6_PRIVACY", FALSE);
1337 if (ip6_privacy_str) {
1338 ip6_privacy = svTrueValue (ifcfg, "IPV6_PRIVACY", FALSE);
1340 ip6_privacy = g_strcmp0 (ip6_privacy_str, "rfc4941") == 0 ||
1341 g_strcmp0 (ip6_privacy_str, "rfc3041") == 0;
1343 ip6_privacy_prefer_public_ip = svTrueValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE);
1344 ip6_privacy_val = ip6_privacy_str ?
1346 (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) :
1347 NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) :
1348 NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
1349 g_free (ip6_privacy_str);
1351 g_object_set (s_ip6,
1352 NM_SETTING_IP_CONFIG_METHOD, method,
1353 NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "IPV6_PEERDNS", TRUE),
1354 NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "IPV6_PEERROUTES", TRUE),
1355 NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
1356 NM_SETTING_IP_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE),
1357 NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV6_ROUTE_METRIC", 10,
1358 -1, G_MAXUINT32, -1),
1359 NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val,
1362 /* Don't bother to read IP, DNS and routes when IPv6 is disabled */
1363 if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0)
1364 return NM_SETTING (s_ip6);
1366 if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
1367 || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
1368 /* METHOD_AUTO may trigger DHCPv6, so save the hostname to send to DHCP */
1369 value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
1370 if (value && value[0])
1371 g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL);
1375 /* Read static IP addresses.
1376 * Read them even for AUTO and DHCP methods - in this case the addresses are
1377 * added to the automatic ones. Note that this is not currently supported by
1378 * the legacy 'network' service (ifup-eth).
1380 ipv6addr = svGetValue (ifcfg, "IPV6ADDR", FALSE);
1381 ipv6addr_secondaries = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
1383 value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL,
1384 ipv6addr ? ipv6addr : "",
1385 ipv6addr_secondaries ? ipv6addr_secondaries : "",
1388 g_free (ipv6addr_secondaries);
1390 list = g_strsplit_set (value, " ", 0);
1392 for (iter = list, i = 0; iter && *iter; iter++, i++) {
1393 NMIPAddress *addr = NULL;
1395 if (!parse_full_ip6_address (ifcfg, network_file, *iter, i, &addr, error)) {
1400 if (!nm_setting_ip_config_add_address (s_ip6, addr))
1401 PARSE_WARNING ("duplicate IP6 address");
1402 nm_ip_address_unref (addr);
1407 if (nm_setting_ip_config_get_num_addresses (s_ip6)) {
1408 value = svGetValue (ifcfg, "IPV6_DEFAULTGW", FALSE);
1410 /* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */
1411 network_ifcfg = svOpenFile (network_file, NULL);
1412 if (network_ifcfg) {
1413 value = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
1414 svCloseFile (network_ifcfg);
1419 if ((ptr = strchr (value, '%')) != NULL)
1420 *ptr = '\0'; /* remove %interface prefix if present */
1421 if (!nm_utils_ipaddr_valid (AF_INET6, value)) {
1422 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1423 "Invalid IP6 address '%s'", value);
1428 g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, value, NULL);
1434 * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting())
1436 for (i = 1; i <= 10; i++) {
1439 tag = g_strdup_printf ("DNS%u", i);
1440 value = svGetValue (ifcfg, tag, FALSE);
1443 break; /* all done */
1446 if (nm_utils_ipaddr_valid (AF_INET6, value)) {
1447 if (!nm_setting_ip_config_add_dns (s_ip6, value))
1448 PARSE_WARNING ("duplicate DNS server %s", tag);
1449 } else if (nm_utils_ipaddr_valid (AF_INET, value)) {
1450 /* Ignore IPv4 addresses */
1452 PARSE_WARNING ("invalid DNS server address %s", value);
1462 /* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */
1464 if (!utils_has_complex_routes (ifcfg->fileName)) {
1465 /* Read static routes from route6-<interface> file */
1466 route6_path = utils_get_route6_path (ifcfg->fileName);
1467 if (!read_route6_file (route6_path, s_ip6, error))
1470 g_free (route6_path);
1473 return NM_SETTING (s_ip6);
1476 g_free (route6_path);
1477 g_object_unref (s_ip6);
1482 check_if_bond_slave (shvarFile *ifcfg,
1483 NMSettingConnection *s_con)
1487 value = svGetValue (ifcfg, "MASTER", FALSE);
1489 g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
1490 g_object_set (s_con,
1491 NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
1496 /* We should be checking for SLAVE=yes as well, but NM used to not set that,
1497 * so for backward-compatibility, we don't check.
1502 check_if_team_slave (shvarFile *ifcfg,
1503 NMSettingConnection *s_con)
1507 value = svGetValue (ifcfg, "DEVICETYPE", FALSE);
1510 if (strcasecmp (value, TYPE_TEAM_PORT)) {
1515 value = svGetValue (ifcfg, "TEAM_MASTER", FALSE);
1518 g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
1519 g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL);
1524 const char *enable_key;
1525 const char *advertise_key;
1526 const char *willing_key;
1527 const char *flags_prop;
1531 DCB_APP_FCOE_FLAGS = 0,
1532 DCB_APP_ISCSI_FLAGS = 1,
1533 DCB_APP_FIP_FLAGS = 2,
1538 static DcbFlagsProperty dcb_flags_props[] = {
1539 { KEY_DCB_APP_FCOE_ENABLE, KEY_DCB_APP_FCOE_ADVERTISE, KEY_DCB_APP_FCOE_WILLING, NM_SETTING_DCB_APP_FCOE_FLAGS },
1540 { KEY_DCB_APP_ISCSI_ENABLE, KEY_DCB_APP_ISCSI_ADVERTISE, KEY_DCB_APP_ISCSI_WILLING, NM_SETTING_DCB_APP_ISCSI_FLAGS },
1541 { KEY_DCB_APP_FIP_ENABLE, KEY_DCB_APP_FIP_ADVERTISE, KEY_DCB_APP_FIP_WILLING, NM_SETTING_DCB_APP_FIP_FLAGS },
1542 { KEY_DCB_PFC_ENABLE, KEY_DCB_PFC_ADVERTISE, KEY_DCB_PFC_WILLING, NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS },
1543 { KEY_DCB_PG_ENABLE, KEY_DCB_PG_ADVERTISE, KEY_DCB_PG_WILLING, NM_SETTING_DCB_PRIORITY_GROUP_FLAGS },
1547 static NMSettingDcbFlags
1548 read_dcb_flags (shvarFile *ifcfg, DcbFlagsProperty *property)
1550 NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
1552 if (svTrueValue (ifcfg, property->enable_key, FALSE))
1553 flags |= NM_SETTING_DCB_FLAG_ENABLE;
1554 if (svTrueValue (ifcfg, property->advertise_key, FALSE))
1555 flags |= NM_SETTING_DCB_FLAG_ADVERTISE;
1556 if (svTrueValue (ifcfg, property->willing_key, FALSE))
1557 flags |= NM_SETTING_DCB_FLAG_WILLING;
1563 read_dcb_app (shvarFile *ifcfg,
1564 NMSettingDcb *s_dcb,
1566 DcbFlagsProperty *flags_prop,
1567 const char *priority_prop,
1570 NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
1572 gboolean success = TRUE;
1575 flags = read_dcb_flags (ifcfg, flags_prop);
1578 tmp = g_strdup_printf ("DCB_APP_%s_PRIORITY", app);
1579 val = svGetValue (ifcfg, tmp, FALSE);
1581 success = get_int (val, &priority);
1583 success = (priority >= 0 && priority <= 7);
1585 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1586 "Invalid %s value '%s' (expected 0 - 7)",
1591 if (!(flags & NM_SETTING_DCB_FLAG_ENABLE))
1592 PARSE_WARNING ("ignoring DCB %s priority; app not enabled", app);
1597 g_object_set (G_OBJECT (s_dcb),
1598 flags_prop->flags_prop, flags,
1599 priority_prop, (guint) priority,
1606 typedef void (*DcbSetBoolFunc) (NMSettingDcb *, guint, gboolean);
1609 read_dcb_bool_array (shvarFile *ifcfg,
1610 NMSettingDcb *s_dcb,
1611 NMSettingDcbFlags flags,
1614 DcbSetBoolFunc set_func,
1618 gboolean success = FALSE;
1621 val = svGetValue (ifcfg, prop, FALSE);
1625 if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
1626 PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
1631 val = g_strstrip (val);
1632 if (strlen (val) != 8) {
1633 PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val);
1634 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1635 "boolean array must be 8 characters");
1639 /* All characters must be either 0 or 1 */
1640 for (i = 0; i < 8; i++) {
1641 if (val[i] != '0' && val[i] != '1') {
1642 PARSE_WARNING ("invalid %s value '%s': not all 0s and 1s", prop, val);
1643 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1644 "invalid boolean digit");
1647 set_func (s_dcb, i, (val[i] == '1'));
1656 typedef void (*DcbSetUintFunc) (NMSettingDcb *, guint, guint);
1659 read_dcb_uint_array (shvarFile *ifcfg,
1660 NMSettingDcb *s_dcb,
1661 NMSettingDcbFlags flags,
1665 DcbSetUintFunc set_func,
1669 gboolean success = FALSE;
1672 val = svGetValue (ifcfg, prop, FALSE);
1676 if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
1677 PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
1682 val = g_strstrip (val);
1683 if (strlen (val) != 8) {
1684 PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val);
1685 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1686 "uint array must be 8 characters");
1690 /* All characters must be either 0 - 7 or (optionally) f */
1691 for (i = 0; i < 8; i++) {
1692 if (val[i] >= '0' && val[i] <= '7')
1693 set_func (s_dcb, i, val[i] - '0');
1694 else if (f_allowed && (val[i] == 'f' || val[i] == 'F'))
1695 set_func (s_dcb, i, 15);
1697 PARSE_WARNING ("invalid %s value '%s': not 0 - 7%s",
1698 prop, val, f_allowed ? " or 'f'" : "");
1699 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1700 "invalid uint digit");
1712 read_dcb_percent_array (shvarFile *ifcfg,
1713 NMSettingDcb *s_dcb,
1714 NMSettingDcbFlags flags,
1718 DcbSetUintFunc set_func,
1722 gboolean success = FALSE;
1723 char **split = NULL, **iter;
1727 val = svGetValue (ifcfg, prop, FALSE);
1731 if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) {
1732 PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc);
1737 val = g_strstrip (val);
1738 split = g_strsplit_set (val, ",", 0);
1739 if (!split || (g_strv_length (split) != 8)) {
1740 PARSE_WARNING ("invalid %s percentage list value '%s'", prop, val);
1741 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1742 "percent array must be 8 elements");
1746 for (iter = split, i = 0; iter && *iter; iter++, i++) {
1747 if (!get_int (*iter, &tmp) || tmp < 0 || tmp > 100) {
1748 PARSE_WARNING ("invalid %s percentage value '%s'", prop, *iter);
1749 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1750 "invalid percent element");
1753 set_func (s_dcb, i, (guint) tmp);
1757 if (sum_pct && (sum != 100)) {
1758 PARSE_WARNING ("%s percentages do not equal 100%%", prop);
1759 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1760 "invalid percentage sum");
1774 make_dcb_setting (shvarFile *ifcfg,
1775 const char *network_file,
1776 NMSetting **out_setting,
1779 NMSettingDcb *s_dcb = NULL;
1781 NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
1784 g_return_val_if_fail (out_setting != NULL, FALSE);
1786 dcb_on = !!svTrueValue (ifcfg, "DCB", FALSE);
1790 s_dcb = (NMSettingDcb *) nm_setting_dcb_new ();
1794 if (!read_dcb_app (ifcfg, s_dcb, "FCOE",
1795 &dcb_flags_props[DCB_APP_FCOE_FLAGS],
1796 NM_SETTING_DCB_APP_FCOE_PRIORITY,
1798 g_object_unref (s_dcb);
1801 if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) {
1802 val = svGetValue (ifcfg, KEY_DCB_APP_FCOE_MODE, FALSE);
1804 if (strcmp (val, NM_SETTING_DCB_FCOE_MODE_FABRIC) == 0 ||
1805 strcmp (val, NM_SETTING_DCB_FCOE_MODE_VN2VN) == 0)
1806 g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_FCOE_MODE, val, NULL);
1808 PARSE_WARNING ("invalid FCoE mode '%s'", val);
1809 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1810 "invalid FCoE mode");
1812 g_object_unref (s_dcb);
1820 if (!read_dcb_app (ifcfg, s_dcb, "ISCSI",
1821 &dcb_flags_props[DCB_APP_ISCSI_FLAGS],
1822 NM_SETTING_DCB_APP_ISCSI_PRIORITY,
1824 g_object_unref (s_dcb);
1829 if (!read_dcb_app (ifcfg, s_dcb, "FIP",
1830 &dcb_flags_props[DCB_APP_FIP_FLAGS],
1831 NM_SETTING_DCB_APP_FIP_PRIORITY,
1833 g_object_unref (s_dcb);
1837 /* Priority Flow Control */
1838 flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PFC_FLAGS]);
1839 g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, flags, NULL);
1841 if (!read_dcb_bool_array (ifcfg,
1846 nm_setting_dcb_set_priority_flow_control,
1848 g_object_unref (s_dcb);
1852 /* Priority Groups */
1853 flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PG_FLAGS]);
1854 g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, flags, NULL);
1856 if (!read_dcb_uint_array (ifcfg,
1862 nm_setting_dcb_set_priority_group_id,
1864 g_object_unref (s_dcb);
1868 /* Group bandwidth */
1869 if (!read_dcb_percent_array (ifcfg,
1875 nm_setting_dcb_set_priority_group_bandwidth,
1877 g_object_unref (s_dcb);
1881 /* Priority bandwidth */
1882 if (!read_dcb_percent_array (ifcfg,
1888 nm_setting_dcb_set_priority_bandwidth,
1890 g_object_unref (s_dcb);
1894 /* Strict Bandwidth */
1895 if (!read_dcb_bool_array (ifcfg,
1900 nm_setting_dcb_set_priority_strict_bandwidth,
1902 g_object_unref (s_dcb);
1906 if (!read_dcb_uint_array (ifcfg,
1912 nm_setting_dcb_set_priority_traffic_class,
1914 g_object_unref (s_dcb);
1918 *out_setting = NM_SETTING (s_dcb);
1923 add_one_wep_key (shvarFile *ifcfg,
1924 const char *shvar_key,
1926 gboolean passphrase,
1927 NMSettingWirelessSecurity *s_wsec,
1932 gboolean success = FALSE;
1934 g_return_val_if_fail (ifcfg != NULL, FALSE);
1935 g_return_val_if_fail (shvar_key != NULL, FALSE);
1936 g_return_val_if_fail (key_idx <= 3, FALSE);
1937 g_return_val_if_fail (s_wsec != NULL, FALSE);
1939 value = svGetValue (ifcfg, shvar_key, FALSE);
1940 if (!value || !strlen (value)) {
1947 if (strlen (value) && strlen (value) < 64) {
1948 key = g_strdup (value);
1949 g_object_set (G_OBJECT (s_wsec),
1950 NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
1951 NM_WEP_KEY_TYPE_PASSPHRASE,
1955 if (strlen (value) == 10 || strlen (value) == 26) {
1956 /* Hexadecimal WEP key */
1960 if (!g_ascii_isxdigit (*p)) {
1961 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1962 "Invalid hexadecimal WEP key.");
1967 key = g_strdup (value);
1968 } else if ( !strncmp (value, "s:", 2)
1969 && (strlen (value) == 7 || strlen (value) == 15)) {
1971 char *p = value + 2;
1974 if (!g_ascii_isprint ((int) (*p))) {
1975 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1976 "Invalid ASCII WEP key.");
1982 /* Remove 's:' prefix.
1983 * Don't convert to hex string. wpa_supplicant takes 'wep_key0' option over D-Bus as byte array
1984 * and converts it to hex string itself. Even though we convert hex string keys into a bin string
1985 * before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly,
1986 * ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users.
1988 key = g_strdup (value + 2);
1993 nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key);
1997 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
1998 "Invalid WEP key length.");
2006 read_wep_keys (shvarFile *ifcfg,
2008 NMSettingWirelessSecurity *s_wsec,
2011 /* Try hex/ascii keys first */
2012 if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error))
2014 if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error))
2016 if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error))
2018 if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error))
2020 if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error))
2023 /* And then passphrases */
2024 if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error))
2026 if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error))
2028 if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error))
2030 if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error))
2036 static NMSettingSecretFlags
2037 read_secret_flags (shvarFile *ifcfg, const char *flags_key)
2039 NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
2042 g_return_val_if_fail (flags_key != NULL, NM_SETTING_SECRET_FLAG_NONE);
2043 g_return_val_if_fail (flags_key[0] != '\0', NM_SETTING_SECRET_FLAG_NONE);
2044 g_return_val_if_fail (g_str_has_suffix (flags_key, "_FLAGS"), NM_SETTING_SECRET_FLAG_NONE);
2046 val = svGetValue (ifcfg, flags_key, FALSE);
2048 if (strstr (val, SECRET_FLAG_AGENT))
2049 flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
2050 if (strstr (val, SECRET_FLAG_NOT_SAVED))
2051 flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED;
2052 if (strstr (val, SECRET_FLAG_NOT_REQUIRED))
2053 flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED;
2061 make_wep_setting (shvarFile *ifcfg,
2065 NMSettingWirelessSecurity *s_wsec;
2067 shvarFile *keys_ifcfg = NULL;
2068 int default_key_idx = 0;
2069 gboolean has_default_key = FALSE, success;
2070 NMSettingSecretFlags key_flags;
2072 s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
2073 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL);
2075 value = svGetValue (ifcfg, "DEFAULTKEY", FALSE);
2077 success = get_int (value, &default_key_idx);
2078 if (success && (default_key_idx >= 1) && (default_key_idx <= 4)) {
2079 has_default_key = TRUE;
2080 default_key_idx--; /* convert to [0...3] */
2081 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, default_key_idx, NULL);
2083 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2084 "Invalid default WEP key '%s'", value);
2091 /* Read WEP key flags */
2092 key_flags = read_secret_flags (ifcfg, "WEP_KEY_FLAGS");
2093 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, key_flags, NULL);
2095 /* Read keys in the ifcfg file if they are system-owned */
2096 if (key_flags == NM_SETTING_SECRET_FLAG_NONE) {
2097 if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error))
2100 /* Try to get keys from the "shadow" key file */
2101 keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
2103 if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) {
2104 svCloseFile (keys_ifcfg);
2107 svCloseFile (keys_ifcfg);
2108 g_assert (error == NULL || *error == NULL);
2112 value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
2116 lcase = g_ascii_strdown (value, -1);
2119 if (!strcmp (lcase, "open")) {
2120 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL);
2121 } else if (!strcmp (lcase, "restricted")) {
2122 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL);
2124 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2125 "Invalid WEP authentication algorithm '%s'",
2133 /* If no WEP keys were given, and the keys are not agent-owned, and no
2134 * default WEP key index was given, then the connection is unencrypted.
2136 if ( !nm_setting_wireless_security_get_wep_key (s_wsec, 0)
2137 && !nm_setting_wireless_security_get_wep_key (s_wsec, 1)
2138 && !nm_setting_wireless_security_get_wep_key (s_wsec, 2)
2139 && !nm_setting_wireless_security_get_wep_key (s_wsec, 3)
2140 && (has_default_key == FALSE)
2141 && (key_flags == NM_SETTING_SECRET_FLAG_NONE)) {
2142 const char *auth_alg;
2144 auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
2145 if (auth_alg && !strcmp (auth_alg, "shared")) {
2146 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2147 "WEP Shared Key authentication is invalid for "
2148 "unencrypted connections.");
2153 g_object_unref (s_wsec);
2157 return (NMSetting *) s_wsec;
2161 g_object_unref (s_wsec);
2166 fill_wpa_ciphers (shvarFile *ifcfg,
2167 NMSettingWirelessSecurity *wsec,
2171 char *value = NULL, *p;
2172 char **list = NULL, **iter;
2175 p = value = svGetValue (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", TRUE);
2182 if (p[strlen (p) - 1] == '"')
2183 p[strlen (p) - 1] = '\0';
2185 list = g_strsplit_set (p, " ", 0);
2186 for (iter = list; iter && *iter; iter++, i++) {
2187 /* Ad-Hoc configurations cannot have pairwise ciphers, and can only
2188 * have one group cipher. Ignore any additional group ciphers and
2189 * any pairwise ciphers specified.
2192 if (group && (i > 0)) {
2193 PARSE_WARNING ("ignoring group cipher '%s' (only one group cipher allowed "
2194 "in Ad-Hoc mode)", *iter);
2196 } else if (!group) {
2197 PARSE_WARNING ("ignoring pairwise cipher '%s' (pairwise not used "
2198 "in Ad-Hoc mode)", *iter);
2203 if (!strcmp (*iter, "CCMP")) {
2205 nm_setting_wireless_security_add_group (wsec, "ccmp");
2207 nm_setting_wireless_security_add_pairwise (wsec, "ccmp");
2208 } else if (!strcmp (*iter, "TKIP")) {
2210 nm_setting_wireless_security_add_group (wsec, "tkip");
2212 nm_setting_wireless_security_add_pairwise (wsec, "tkip");
2213 } else if (group && !strcmp (*iter, "WEP104"))
2214 nm_setting_wireless_security_add_group (wsec, "wep104");
2215 else if (group && !strcmp (*iter, "WEP40"))
2216 nm_setting_wireless_security_add_group (wsec, "wep40");
2218 PARSE_WARNING ("ignoring invalid %s cipher '%s'",
2219 group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE",
2230 #define WPA_PMK_LEN 32
2233 parse_wpa_psk (shvarFile *ifcfg,
2238 shvarFile *keys_ifcfg;
2239 char *psk = NULL, *p, *hashed = NULL;
2241 gboolean quoted = FALSE;
2243 /* Passphrase must be between 10 and 66 characters in length because WPA
2244 * hex keys are exactly 64 characters (no quoting), and WPA passphrases
2245 * are between 8 and 63 characters (inclusive), plus optional quoting if
2246 * the passphrase contains spaces.
2249 /* Try to get keys from the "shadow" key file */
2250 keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
2252 psk = svGetValue (keys_ifcfg, "WPA_PSK", TRUE);
2253 svCloseFile (keys_ifcfg);
2256 /* Fall back to the original ifcfg */
2258 psk = svGetValue (ifcfg, "WPA_PSK", TRUE);
2266 if ( (plen >= 2 && (p[0] == '"' || p[0] == '\'') && p[0] == p[plen - 1])
2267 || (plen >= 3 && p[0] == '$' && p[1] == '\'' && p[1] == p[plen - 1]))
2270 if (!quoted && (strlen (psk) == 64)) {
2271 /* Verify the hex PSK; 64 digits */
2273 if (!g_ascii_isxdigit (*p++)) {
2274 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2275 "Invalid WPA_PSK (contains non-hexadecimal characters)");
2279 hashed = g_strdup (psk);
2281 /* Prior to 4f6eef9e77265484555663cf666cde4fa8323469 and
2282 * 28e2e446868b94b92edc4a82aa0bf1e3eda8ec54 the writer may not have
2283 * properly quoted passphrases, so just handle anything that's unquoted
2284 * and between 8 and 63 characters as a passphrase.
2287 /* Get rid of the quotes */
2288 hashed = utils_single_unquote_string (p);
2291 if (strlen (hashed) < 8 || strlen (hashed) > 63) {
2292 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2293 "Invalid WPA_PSK (passphrases must be between "
2294 "8 and 63 characters long (inclusive))");
2302 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2303 "Invalid WPA_PSK (doesn't look like a passphrase or hex key)");
2313 eap_simple_reader (const char *eap_method,
2316 NMSetting8021x *s_8021x,
2320 NMSettingSecretFlags flags;
2323 value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
2325 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2326 "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
2330 g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
2333 flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
2334 g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_FLAGS, flags, NULL);
2336 /* Only read the password if it's system-owned */
2337 if (flags == NM_SETTING_SECRET_FLAG_NONE) {
2338 value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
2339 if (!value && keys) {
2340 /* Try the lookaside keys file */
2341 value = svGetValue (keys, "IEEE_8021X_PASSWORD", FALSE);
2345 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2346 "Missing IEEE_8021X_PASSWORD for EAP method '%s'.",
2351 g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL);
2359 get_full_file_path (const char *ifcfg_path, const char *file_path)
2361 const char *base = file_path;
2362 char *p, *ret, *dirname;
2364 g_return_val_if_fail (ifcfg_path != NULL, NULL);
2365 g_return_val_if_fail (file_path != NULL, NULL);
2367 if (file_path[0] == '/')
2368 return g_strdup (file_path);
2370 p = strrchr (file_path, '/');
2374 dirname = g_path_get_dirname (ifcfg_path);
2375 ret = g_build_path ("/", dirname, base, NULL);
2381 eap_tls_reader (const char *eap_method,
2384 NMSetting8021x *s_8021x,
2389 char *ca_cert = NULL;
2390 char *real_path = NULL;
2391 char *client_cert = NULL;
2392 char *privkey = NULL;
2393 char *privkey_password = NULL;
2394 gboolean success = FALSE;
2395 NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
2396 const char *ca_cert_key = phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT";
2397 const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD";
2398 const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY";
2399 const char *cli_cert_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT";
2400 const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS": "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS";
2401 const char *pk_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS;
2402 NMSettingSecretFlags flags;
2404 value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
2406 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2407 "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
2411 g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
2414 ca_cert = svGetValue (ifcfg, ca_cert_key, FALSE);
2416 real_path = get_full_file_path (ifcfg->fileName, ca_cert);
2418 if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
2420 NM_SETTING_802_1X_CK_SCHEME_PATH,
2425 if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2427 NM_SETTING_802_1X_CK_SCHEME_PATH,
2435 PARSE_WARNING ("missing %s for EAP method '%s'; this is insecure!",
2436 ca_cert_key, eap_method);
2439 /* Read and set private key password flags */
2440 flags = read_secret_flags (ifcfg, pk_pw_flags_key);
2441 g_object_set (s_8021x, pk_pw_flags_prop, flags, NULL);
2443 /* Read the private key password if it's system-owned */
2444 if (flags == NM_SETTING_SECRET_FLAG_NONE) {
2445 /* Private key password */
2446 privkey_password = svGetValue (ifcfg, pk_pw_key, FALSE);
2447 if (!privkey_password && keys) {
2448 /* Try the lookaside keys file */
2449 privkey_password = svGetValue (keys, pk_pw_key, FALSE);
2452 if (!privkey_password) {
2453 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2454 "Missing %s for EAP method '%s'.",
2461 /* The private key itself */
2462 privkey = svGetValue (ifcfg, pk_key, FALSE);
2464 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2465 "Missing %s for EAP method '%s'.",
2471 real_path = get_full_file_path (ifcfg->fileName, privkey);
2473 if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
2476 NM_SETTING_802_1X_CK_SCHEME_PATH,
2481 if (!nm_setting_802_1x_set_private_key (s_8021x,
2484 NM_SETTING_802_1X_CK_SCHEME_PATH,
2492 /* Only set the client certificate if the private key is not PKCS#12 format,
2493 * as NM (due to supplicant restrictions) requires. If the key was PKCS#12,
2494 * then nm_setting_802_1x_set_private_key() already set the client certificate
2495 * to the same value as the private key.
2497 if ( privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY
2498 || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) {
2499 client_cert = svGetValue (ifcfg, cli_cert_key, FALSE);
2501 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2502 "Missing %s for EAP method '%s'.",
2508 real_path = get_full_file_path (ifcfg->fileName, client_cert);
2510 if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
2512 NM_SETTING_802_1X_CK_SCHEME_PATH,
2517 if (!nm_setting_802_1x_set_client_cert (s_8021x,
2519 NM_SETTING_802_1X_CK_SCHEME_PATH,
2533 g_free (client_cert);
2535 g_free (privkey_password);
2540 eap_peap_reader (const char *eap_method,
2543 NMSetting8021x *s_8021x,
2547 char *anon_ident = NULL;
2548 char *ca_cert = NULL;
2549 char *real_cert_path = NULL;
2550 char *inner_auth = NULL;
2551 char *peapver = NULL;
2553 char **list = NULL, **iter;
2554 gboolean success = FALSE;
2556 ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
2558 real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
2559 if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2561 NM_SETTING_802_1X_CK_SCHEME_PATH,
2566 PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
2570 peapver = svGetValue (ifcfg, "IEEE_8021X_PEAP_VERSION", FALSE);
2572 if (!strcmp (peapver, "0"))
2573 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
2574 else if (!strcmp (peapver, "1"))
2575 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL);
2577 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2578 "Unknown IEEE_8021X_PEAP_VERSION value '%s'",
2584 if (svTrueValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE))
2585 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL);
2587 anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2588 if (anon_ident && strlen (anon_ident))
2589 g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2591 inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2593 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2594 "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2598 /* Handle options for the inner auth method */
2599 list = g_strsplit (inner_auth, " ", 0);
2600 for (iter = list; iter && *iter; iter++) {
2601 if (!strlen (*iter))
2604 if ( !strcmp (*iter, "MSCHAPV2")
2605 || !strcmp (*iter, "MD5")
2606 || !strcmp (*iter, "GTC")) {
2607 if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2609 } else if (!strcmp (*iter, "TLS")) {
2610 if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2613 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2614 "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2619 lower = g_ascii_strdown (*iter, -1);
2620 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
2625 if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
2626 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2627 "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
2636 g_free (inner_auth);
2638 g_free (real_cert_path);
2640 g_free (anon_ident);
2645 eap_ttls_reader (const char *eap_method,
2648 NMSetting8021x *s_8021x,
2652 gboolean success = FALSE;
2653 char *anon_ident = NULL;
2654 char *ca_cert = NULL;
2655 char *real_cert_path = NULL;
2656 char *inner_auth = NULL;
2658 char **list = NULL, **iter;
2660 ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
2662 real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
2663 if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2665 NM_SETTING_802_1X_CK_SCHEME_PATH,
2670 PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
2674 anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2675 if (anon_ident && strlen (anon_ident))
2676 g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2678 tmp = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2680 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2681 "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2685 inner_auth = g_ascii_strdown (tmp, -1);
2688 /* Handle options for the inner auth method */
2689 list = g_strsplit (inner_auth, " ", 0);
2690 for (iter = list; iter && *iter; iter++) {
2691 if (!strlen (*iter))
2694 if ( !strcmp (*iter, "mschapv2")
2695 || !strcmp (*iter, "mschap")
2696 || !strcmp (*iter, "pap")
2697 || !strcmp (*iter, "chap")) {
2698 if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2700 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
2701 } else if (!strcmp (*iter, "eap-tls")) {
2702 if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2704 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
2705 } else if ( !strcmp (*iter, "eap-mschapv2")
2706 || !strcmp (*iter, "eap-md5")
2707 || !strcmp (*iter, "eap-gtc")) {
2708 if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2710 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + STRLEN ("eap-")), NULL);
2712 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2713 "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2725 g_free (inner_auth);
2726 g_free (real_cert_path);
2728 g_free (anon_ident);
2733 eap_fast_reader (const char *eap_method,
2736 NMSetting8021x *s_8021x,
2740 char *anon_ident = NULL;
2741 char *pac_file = NULL;
2742 char *real_pac_path = NULL;
2743 char *inner_auth = NULL;
2744 char *fast_provisioning = NULL;
2746 char **list = NULL, **iter;
2747 const char* pac_prov_str;
2748 gboolean allow_unauth = FALSE, allow_auth = FALSE;
2749 gboolean success = FALSE;
2751 pac_file = svGetValue (ifcfg, "IEEE_8021X_PAC_FILE", FALSE);
2753 real_pac_path = get_full_file_path (ifcfg->fileName, pac_file);
2754 g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL);
2757 fast_provisioning = svGetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", FALSE);
2758 if (fast_provisioning) {
2759 list = g_strsplit_set (fast_provisioning, " \t", 0);
2760 for (iter = list; iter && *iter; iter++) {
2763 if (strcmp (*iter, "allow-unauth") == 0)
2764 allow_unauth = TRUE;
2765 else if (strcmp (*iter, "allow-auth") == 0)
2768 PARSE_WARNING ("invalid IEEE_8021X_FAST_PROVISIONING '%s' "
2769 "(space-separated list of these values [allow-auth, allow-unauth] expected)",
2776 pac_prov_str = allow_unauth ? (allow_auth ? "3" : "1") : (allow_auth ? "2" : "0");
2777 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, pac_prov_str, NULL);
2779 if (!pac_file && !(allow_unauth || allow_auth)) {
2780 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2781 "IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled.");
2785 anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2786 if (anon_ident && strlen (anon_ident))
2787 g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2789 inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2791 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2792 "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2796 /* Handle options for the inner auth method */
2797 list = g_strsplit (inner_auth, " ", 0);
2798 for (iter = list; iter && *iter; iter++) {
2799 if (!strlen (*iter))
2802 if ( !strcmp (*iter, "MSCHAPV2")
2803 || !strcmp (*iter, "GTC")) {
2804 if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2807 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2808 "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2813 lower = g_ascii_strdown (*iter, -1);
2814 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
2819 if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
2820 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2821 "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
2829 g_free (inner_auth);
2830 g_free (fast_provisioning);
2831 g_free (real_pac_path);
2833 g_free (anon_ident);
2839 gboolean (*reader)(const char *eap_method,
2842 NMSetting8021x *s_8021x,
2845 gboolean wifi_phase2_only;
2848 static EAPReader eap_readers[] = {
2849 { "md5", eap_simple_reader, TRUE },
2850 { "pap", eap_simple_reader, TRUE },
2851 { "chap", eap_simple_reader, TRUE },
2852 { "mschap", eap_simple_reader, TRUE },
2853 { "mschapv2", eap_simple_reader, TRUE },
2854 { "leap", eap_simple_reader, FALSE },
2855 { "pwd", eap_simple_reader, FALSE },
2856 { "tls", eap_tls_reader, FALSE },
2857 { "peap", eap_peap_reader, FALSE },
2858 { "ttls", eap_ttls_reader, FALSE },
2859 { "fast", eap_fast_reader, FALSE },
2864 read_8021x_list_value (shvarFile *ifcfg,
2865 const char *ifcfg_var_name,
2866 NMSetting8021x *setting,
2867 const char *prop_name)
2872 g_return_if_fail (ifcfg != NULL);
2873 g_return_if_fail (ifcfg_var_name != NULL);
2874 g_return_if_fail (prop_name != NULL);
2876 value = svGetValue (ifcfg, ifcfg_var_name, FALSE);
2880 strv = g_strsplit_set (value, " \t", 0);
2881 if (strv && strv[0])
2882 g_object_set (setting, prop_name, strv, NULL);
2887 static NMSetting8021x *
2888 fill_8021x (shvarFile *ifcfg,
2890 const char *key_mgmt,
2894 NMSetting8021x *s_8021x;
2895 shvarFile *keys = NULL;
2897 char **list = NULL, **iter;
2899 value = svGetValue (ifcfg, "IEEE_8021X_EAP_METHODS", FALSE);
2901 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2902 "Missing IEEE_8021X_EAP_METHODS for key management '%s'",
2907 list = g_strsplit (value, " ", 0);
2910 s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
2912 /* Read in the lookaside keys file, if present */
2913 keys = utils_get_keys_ifcfg (file, FALSE);
2915 /* Validate and handle each EAP method */
2916 for (iter = list; iter && *iter; iter++) {
2917 EAPReader *eap = &eap_readers[0];
2918 gboolean found = FALSE;
2921 lower = g_ascii_strdown (*iter, -1);
2922 while (eap->method) {
2923 if (strcmp (eap->method, lower))
2926 /* Some EAP methods don't provide keying material, thus they
2927 * cannot be used with WiFi unless they are an inner method
2928 * used with TTLS or PEAP or whatever.
2930 if (wifi && eap->wifi_phase2_only) {
2931 PARSE_WARNING ("ignored invalid IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
2936 /* Parse EAP method specific options */
2937 if (!(*eap->reader)(lower, ifcfg, keys, s_8021x, FALSE, error)) {
2941 nm_setting_802_1x_add_eap_method (s_8021x, lower);
2950 PARSE_WARNING ("ignored unknown IEEE_8021X_EAP_METHOD '%s'.", lower);
2954 if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) {
2955 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
2956 "No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
2960 value = svGetValue (ifcfg, "IEEE_8021X_SUBJECT_MATCH", FALSE);
2961 g_object_set (s_8021x, NM_SETTING_802_1X_SUBJECT_MATCH, value, NULL);
2964 value = svGetValue (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH", FALSE);
2965 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, value, NULL);
2968 read_8021x_list_value (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES",
2969 s_8021x, NM_SETTING_802_1X_ALTSUBJECT_MATCHES);
2970 read_8021x_list_value (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES",
2971 s_8021x, NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES);
2984 g_object_unref (s_8021x);
2989 make_wpa_setting (shvarFile *ifcfg,
2993 NMSetting8021x **s_8021x,
2996 NMSettingWirelessSecurity *wsec;
2997 char *value, *psk, *lower;
2998 gboolean wpa_psk = FALSE, wpa_eap = FALSE, ieee8021x = FALSE;
3000 wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
3002 value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
3003 wpa_psk = !g_strcmp0 (value, "WPA-PSK");
3004 wpa_eap = !g_strcmp0 (value, "WPA-EAP");
3005 ieee8021x = !g_strcmp0 (value, "IEEE8021X");
3006 if (!wpa_psk && !wpa_eap && !ieee8021x)
3007 goto error; /* Not WPA or Dynamic WEP */
3009 /* Pairwise and Group ciphers (only relevant for WPA/RSN) */
3010 if (wpa_psk || wpa_eap) {
3011 fill_wpa_ciphers (ifcfg, wsec, FALSE, adhoc);
3012 fill_wpa_ciphers (ifcfg, wsec, TRUE, adhoc);
3015 /* WPA and/or RSN */
3017 /* Ad-Hoc mode only supports WPA proto for now */
3018 nm_setting_wireless_security_add_proto (wsec, "wpa");
3020 char *allow_wpa, *allow_rsn;
3022 allow_wpa = svGetValue (ifcfg, "WPA_ALLOW_WPA", FALSE);
3023 allow_rsn = svGetValue (ifcfg, "WPA_ALLOW_WPA2", FALSE);
3025 if (allow_wpa && svTrueValue (ifcfg, "WPA_ALLOW_WPA", TRUE))
3026 nm_setting_wireless_security_add_proto (wsec, "wpa");
3027 if (allow_rsn && svTrueValue (ifcfg, "WPA_ALLOW_WPA2", TRUE))
3028 nm_setting_wireless_security_add_proto (wsec, "rsn");
3030 /* If neither WPA_ALLOW_WPA or WPA_ALLOW_WPA2 were present, default
3031 * to both WPA and RSN allowed.
3033 if (!allow_wpa && !allow_rsn && !ieee8021x) {
3034 nm_setting_wireless_security_add_proto (wsec, "wpa");
3035 nm_setting_wireless_security_add_proto (wsec, "rsn");
3042 /* coverity[dereference] */
3043 if (!strcmp (value, "WPA-PSK")) {
3044 NMSettingSecretFlags psk_flags;
3046 psk_flags = read_secret_flags (ifcfg, "WPA_PSK_FLAGS");
3047 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, psk_flags, NULL);
3049 /* Read PSK if it's system-owned */
3050 if (psk_flags == NM_SETTING_SECRET_FLAG_NONE) {
3051 psk = parse_wpa_psk (ifcfg, file, ssid, error);
3053 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL);
3059 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
3061 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
3062 } else if (!strcmp (value, "WPA-EAP") || !strcmp (value, "IEEE8021X")) {
3063 /* Adhoc mode is mutually exclusive with any 802.1x-based authentication */
3065 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3066 "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'", value);
3070 *s_8021x = fill_8021x (ifcfg, file, value, TRUE, error);
3074 lower = g_ascii_strdown (value, -1);
3075 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL);
3078 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3079 "Unknown wireless KEY_MGMT type '%s'", value);
3084 return (NMSetting *) wsec;
3089 g_object_unref (wsec);
3094 make_leap_setting (shvarFile *ifcfg,
3098 NMSettingWirelessSecurity *wsec;
3099 shvarFile *keys_ifcfg;
3101 NMSettingSecretFlags flags;
3103 wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
3105 value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
3106 if (!value || strcmp (value, "IEEE8021X"))
3107 goto error; /* Not LEAP */
3110 value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
3111 if (!value || strcasecmp (value, "leap"))
3112 goto error; /* Not LEAP */
3116 flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
3117 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, flags, NULL);
3119 /* Read LEAP password if it's system-owned */
3120 if (flags == NM_SETTING_SECRET_FLAG_NONE) {
3121 value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
3123 /* Try to get keys from the "shadow" key file */
3124 keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
3126 value = svGetValue (keys_ifcfg, "IEEE_8021X_PASSWORD", FALSE);
3127 svCloseFile (keys_ifcfg);
3130 if (value && strlen (value))
3131 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, value, NULL);
3135 value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
3136 if (!value || !strlen (value)) {
3137 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3138 "Missing LEAP identity");
3141 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value, NULL);
3145 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
3146 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
3149 return (NMSetting *) wsec;
3154 g_object_unref (wsec);
3159 make_wireless_security_setting (shvarFile *ifcfg,
3163 NMSetting8021x **s_8021x,
3168 g_return_val_if_fail (error && !*error, NULL);
3171 wsec = make_leap_setting (ifcfg, file, error);
3178 wsec = make_wpa_setting (ifcfg, file, ssid, adhoc, s_8021x, error);
3184 wsec = make_wep_setting (ifcfg, file, error);
3190 return NULL; /* unencrypted */
3194 transform_hwaddr_blacklist (const char *blacklist)
3196 char **strv, **iter;
3199 strv = _nm_utils_strsplit_set (blacklist, " \t", 0);
3200 for (iter = strv; iter && *iter; iter++) {
3202 *(iter - shift) = *iter;
3205 if (!nm_utils_hwaddr_valid (*(iter - shift), ETH_ALEN)) {
3206 PARSE_WARNING ("invalid MAC in HWADDR_BLACKLIST '%s'", *(iter - shift));
3207 g_free (*(iter - shift));
3208 *(iter - shift) = NULL;
3216 make_wireless_setting (shvarFile *ifcfg,
3219 NMSettingWireless *s_wireless;
3223 s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
3225 value = svGetValue (ifcfg, "HWADDR", FALSE);
3227 value = g_strstrip (value);
3228 g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, value, NULL);
3232 value = svGetValue (ifcfg, "MACADDR", FALSE);
3234 value = g_strstrip (value);
3235 g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, value, NULL);
3239 value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
3243 strv = transform_hwaddr_blacklist (value);
3244 g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, strv, NULL);
3249 value = svGetValue (ifcfg, "ESSID", TRUE);
3251 GBytes *bytes = NULL;
3253 gsize value_len = strlen (value);
3255 if ( (value_len >= 2)
3256 && (value[0] == '"')
3257 && (value[value_len - 1] == '"')) {
3258 /* Strip the quotes and unescape */
3259 char *p = value + 1;
3261 value[value_len - 1] = '\0';
3263 bytes = g_bytes_new (p, strlen (p));
3264 } else if ((value_len > 2) && (strncmp (value, "0x", 2) == 0)) {
3265 /* Hex representation */
3266 if (value_len % 2) {
3267 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3268 "Invalid SSID '%s' size (looks like hex but length not multiple of 2)",
3274 bytes = nm_utils_hexstr2bin (value);
3276 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3277 "Invalid SSID '%s' (looks like hex SSID but isn't)",
3283 bytes = g_bytes_new (value, value_len);
3285 ssid_len = g_bytes_get_size (bytes);
3286 if (ssid_len > 32 || ssid_len == 0) {
3287 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3288 "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
3290 g_bytes_unref (bytes);
3295 g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, bytes, NULL);
3296 g_bytes_unref (bytes);
3300 value = svGetValue (ifcfg, "MODE", FALSE);
3303 const char *mode = NULL;
3305 lcase = g_ascii_strdown (value, -1);
3308 if (!strcmp (lcase, "ad-hoc")) {
3310 } else if (!strcmp (lcase, "ap")) {
3312 } else if (!strcmp (lcase, "managed") || !strcmp (lcase, "auto")) {
3313 mode = "infrastructure";
3315 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3316 "Invalid mode '%s' (not 'Ad-Hoc', 'Ap', 'Managed', or 'Auto')",
3323 g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, mode, NULL);
3326 value = svGetValue (ifcfg, "BSSID", FALSE);
3328 value = g_strstrip (value);
3329 g_object_set (s_wireless, NM_SETTING_WIRELESS_BSSID, value, NULL);
3333 value = svGetValue (ifcfg, "CHANNEL", FALSE);
3336 chan = nm_utils_ascii_str_to_int64 (value, 10, 1, 196, 0);
3337 if (errno || (chan == 0)) {
3338 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3339 "Invalid wireless channel '%s'", value);
3343 g_object_set (s_wireless, NM_SETTING_WIRELESS_CHANNEL, (guint32) chan, NULL);
3347 value = svGetValue (ifcfg, "BAND", FALSE);
3349 if (!strcmp (value, "a")) {
3350 if (chan && chan <= 14) {
3351 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3352 "Band '%s' invalid for channel %u", value, (guint32) chan);
3356 } else if (!strcmp (value, "bg")) {
3357 if (chan && chan > 14) {
3358 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3359 "Band '%s' invalid for channel %u", value, (guint32) chan);
3364 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3365 "Invalid wireless band '%s'", value);
3369 g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, value, NULL);
3371 } else if (chan > 0) {
3373 g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "a", NULL);
3375 g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "bg", NULL);
3378 value = svGetValue (ifcfg, "MTU", FALSE);
3383 mtu = strtol (value, NULL, 10);
3384 if (errno || mtu < 0 || mtu > 50000) {
3385 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3386 "Invalid wireless MTU '%s'", value);
3390 g_object_set (s_wireless, NM_SETTING_WIRELESS_MTU, (guint32) mtu, NULL);
3394 g_object_set (s_wireless,
3395 NM_SETTING_WIRELESS_HIDDEN,
3396 svTrueValue (ifcfg, "SSID_HIDDEN", FALSE),
3399 return NM_SETTING (s_wireless);
3403 g_object_unref (s_wireless);
3407 static NMConnection *
3408 wireless_connection_from_ifcfg (const char *file,
3412 NMConnection *connection = NULL;
3413 NMSetting *con_setting = NULL;
3414 NMSetting *wireless_setting = NULL;
3415 NMSetting8021x *s_8021x = NULL;
3417 NMSetting *security_setting = NULL;
3418 char *printable_ssid = NULL;
3420 gboolean adhoc = FALSE;
3421 GError *local = NULL;
3423 g_return_val_if_fail (file != NULL, NULL);
3424 g_return_val_if_fail (ifcfg != NULL, NULL);
3425 g_return_val_if_fail (!error || !*error, NULL);
3427 connection = nm_simple_connection_new ();
3430 wireless_setting = make_wireless_setting (ifcfg, error);
3431 if (!wireless_setting) {
3432 g_object_unref (connection);
3435 nm_connection_add_setting (connection, wireless_setting);
3437 ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (wireless_setting));
3439 printable_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL),
3440 g_bytes_get_size (ssid));
3442 printable_ssid = g_strdup_printf ("unmanaged");
3444 mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (wireless_setting));
3445 if (mode && !strcmp (mode, "adhoc"))
3448 /* Wireless security */
3449 security_setting = make_wireless_security_setting (ifcfg, file, ssid, adhoc, &s_8021x, &local);
3451 g_free (printable_ssid);
3452 g_object_unref (connection);
3453 g_propagate_error (error, local);
3456 if (security_setting) {
3457 nm_connection_add_setting (connection, security_setting);
3459 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3463 con_setting = make_connection_setting (file, ifcfg,
3464 NM_SETTING_WIRELESS_SETTING_NAME,
3465 printable_ssid, NULL);
3466 g_free (printable_ssid);
3468 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3469 "Failed to create connection setting.");
3470 g_object_unref (connection);
3473 nm_connection_add_setting (connection, con_setting);
3479 make_wired_setting (shvarFile *ifcfg,
3481 NMSetting8021x **s_8021x,
3484 NMSettingWired *s_wired;
3489 s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
3491 value = svGetValue (ifcfg, "MTU", FALSE);
3493 if (get_int (value, &mtu)) {
3494 if (mtu >= 0 && mtu < 65536)
3495 g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu, NULL);
3497 /* Shouldn't be fatal... */
3498 PARSE_WARNING ("invalid MTU '%s'", value);
3503 value = svGetValue (ifcfg, "HWADDR", FALSE);
3505 value = g_strstrip (value);
3506 g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, value, NULL);
3510 value = svGetValue (ifcfg, "SUBCHANNELS", FALSE);
3512 const char *p = value;
3513 gboolean success = TRUE;
3514 char **chans = NULL;
3516 /* basic sanity checks */
3518 if (!g_ascii_isxdigit (*p) && (*p != ',') && (*p != '.')) {
3519 PARSE_WARNING ("invalid SUBCHANNELS '%s'", value);
3529 chans = g_strsplit_set (value, ",", 0);
3530 num_chans = g_strv_length (chans);
3531 if (num_chans < 2 || num_chans > 3) {
3532 PARSE_WARNING ("invalid SUBCHANNELS '%s' (%d channels, 2 or 3 expected)",
3533 value, g_strv_length (chans));
3535 g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, chans, NULL);
3541 value = svGetValue (ifcfg, "PORTNAME", FALSE);
3542 if (value && strlen (value)) {
3543 nm_setting_wired_add_s390_option (s_wired, "portname", value);
3547 value = svGetValue (ifcfg, "CTCPROT", FALSE);
3548 if (value && strlen (value))
3549 nm_setting_wired_add_s390_option (s_wired, "ctcprot", value);
3552 nettype = svGetValue (ifcfg, "NETTYPE", FALSE);
3553 if (nettype && strlen (nettype)) {
3554 if (!strcmp (nettype, "qeth") || !strcmp (nettype, "lcs") || !strcmp (nettype, "ctc"))
3555 g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, nettype, NULL);
3557 PARSE_WARNING ("unknown s390 NETTYPE '%s'", nettype);
3561 value = svGetValue (ifcfg, "OPTIONS", FALSE);
3562 if (value && strlen (value)) {
3563 char **options, **iter;
3565 iter = options = g_strsplit_set (value, " ", 0);
3566 while (iter && *iter) {
3567 char *equals = strchr (*iter, '=');
3568 gboolean valid = FALSE;
3572 valid = nm_setting_wired_add_s390_option (s_wired, *iter, equals + 1);
3575 PARSE_WARNING ("invalid s390 OPTION '%s'", *iter);
3578 g_strfreev (options);
3582 value = svGetValue (ifcfg, "MACADDR", FALSE);
3584 value = g_strstrip (value);
3585 g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, value, NULL);
3589 value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
3593 strv = transform_hwaddr_blacklist (value);
3594 g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, strv, NULL);
3599 value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
3601 if (!strcmp (value, "IEEE8021X")) {
3602 *s_8021x = fill_8021x (ifcfg, file, value, FALSE, error);
3606 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3607 "Unknown wired KEY_MGMT type '%s'", value);
3613 return (NMSetting *) s_wired;
3617 g_object_unref (s_wired);
3621 static NMConnection *
3622 wired_connection_from_ifcfg (const char *file,
3626 NMConnection *connection = NULL;
3627 NMSetting *con_setting = NULL;
3628 NMSetting *wired_setting = NULL;
3629 NMSetting8021x *s_8021x = NULL;
3631 g_return_val_if_fail (file != NULL, NULL);
3632 g_return_val_if_fail (ifcfg != NULL, NULL);
3634 connection = nm_simple_connection_new ();
3636 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL, NULL);
3638 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3639 "Failed to create connection setting.");
3640 g_object_unref (connection);
3643 check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3644 check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3645 nm_connection_add_setting (connection, con_setting);
3647 wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
3648 if (!wired_setting) {
3649 g_object_unref (connection);
3652 nm_connection_add_setting (connection, wired_setting);
3655 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3661 parse_infiniband_p_key (shvarFile *ifcfg,
3666 char *device = NULL, *physdev = NULL, *pkey_id = NULL, *end;
3667 char *ifname = NULL;
3668 guint32 id = G_MAXUINT32;
3669 gboolean ret = FALSE;
3671 device = svGetValue (ifcfg, "DEVICE", FALSE);
3673 PARSE_WARNING ("InfiniBand connection specified PKEY but not DEVICE");
3677 physdev = svGetValue (ifcfg, "PHYSDEV", FALSE);
3679 PARSE_WARNING ("InfiniBand connection specified PKEY but not PHYSDEV");
3683 pkey_id = svGetValue (ifcfg, "PKEY_ID", FALSE);
3685 PARSE_WARNING ("InfiniBand connection specified PKEY but not PKEY_ID");
3689 if (g_str_has_prefix (pkey_id, "0x"))
3690 id = strtoul (pkey_id, &end, 16);
3691 else if (!g_str_has_prefix (pkey_id, "0"))
3692 id = strtoul (pkey_id, &end, 10);
3695 if (end == pkey_id || *end || id > 0xFFFF) {
3696 PARSE_WARNING ("invalid InfiniBand PKEY_ID '%s'", pkey_id);
3701 ifname = g_strdup_printf ("%s.%04x", physdev, id);
3702 if (strcmp (device, ifname) != 0) {
3703 PARSE_WARNING ("InfiniBand DEVICE (%s) does not match PHYSDEV+PKEY_ID (%s)",
3709 *out_parent = g_strdup (physdev);
3719 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3720 "Failed to create InfiniBand setting.");
3727 make_infiniband_setting (shvarFile *ifcfg,
3731 NMSettingInfiniband *s_infiniband;
3735 s_infiniband = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ());
3737 value = svGetValue (ifcfg, "MTU", FALSE);
3739 if (get_int (value, &mtu)) {
3740 if (mtu >= 0 && mtu < 65536)
3741 g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MTU, mtu, NULL);
3743 /* Shouldn't be fatal... */
3744 PARSE_WARNING ("invalid MTU '%s'", value);
3749 value = svGetValue (ifcfg, "HWADDR", FALSE);
3751 value = g_strstrip (value);
3752 g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, value, NULL);
3756 if (svTrueValue (ifcfg, "CONNECTED_MODE", FALSE))
3757 g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL);
3759 g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);
3761 if (svTrueValue (ifcfg, "PKEY", FALSE)) {
3765 if (!parse_infiniband_p_key (ifcfg, &p_key, &parent, error)) {
3766 g_object_unref (s_infiniband);
3770 g_object_set (s_infiniband,
3771 NM_SETTING_INFINIBAND_P_KEY, p_key,
3772 NM_SETTING_INFINIBAND_PARENT, parent,
3776 return (NMSetting *) s_infiniband;
3779 static NMConnection *
3780 infiniband_connection_from_ifcfg (const char *file,
3784 NMConnection *connection = NULL;
3785 NMSetting *con_setting = NULL;
3786 NMSetting *infiniband_setting = NULL;
3788 g_return_val_if_fail (file != NULL, NULL);
3789 g_return_val_if_fail (ifcfg != NULL, NULL);
3791 connection = nm_simple_connection_new ();
3793 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL);
3795 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3796 "Failed to create connection setting.");
3797 g_object_unref (connection);
3800 check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3801 check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3802 nm_connection_add_setting (connection, con_setting);
3804 infiniband_setting = make_infiniband_setting (ifcfg, file, error);
3805 if (!infiniband_setting) {
3806 g_object_unref (connection);
3809 nm_connection_add_setting (connection, infiniband_setting);
3815 handle_bond_option (NMSettingBond *s_bond,
3819 char *sanitized = NULL, *j;
3820 const char *p = value;
3822 /* Remove any quotes or +/- from arp_ip_target */
3823 if (!g_strcmp0 (key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET) && value && value[0]) {
3824 if (*p == '\'' || *p == '"')
3826 j = sanitized = g_malloc0 (strlen (p) + 1);
3828 if (*p != '+' && *p != '-' && *p != '\'' && *p != '"')
3834 if (!nm_setting_bond_add_option (s_bond, key, sanitized ? sanitized : value))
3835 PARSE_WARNING ("invalid bonding option '%s'", key);
3840 make_bond_setting (shvarFile *ifcfg,
3844 NMSettingBond *s_bond;
3847 s_bond = NM_SETTING_BOND (nm_setting_bond_new ());
3849 value = svGetValue (ifcfg, "DEVICE", FALSE);
3850 if (!value || !strlen (value)) {
3851 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3852 "mandatory DEVICE keyword missing");
3857 value = svGetValue (ifcfg, "BONDING_OPTS", FALSE);
3859 char **items, **iter;
3861 items = g_strsplit_set (value, " ", -1);
3862 for (iter = items; iter && *iter; iter++) {
3863 if (strlen (*iter)) {
3864 char **keys, *key, *val;
3866 keys = g_strsplit_set (*iter, "=", 2);
3867 if (keys && *keys) {
3870 if (val && strlen(key) && strlen(val))
3871 handle_bond_option (s_bond, key, val);
3881 return (NMSetting *) s_bond;
3884 g_object_unref (s_bond);
3888 static NMConnection *
3889 bond_connection_from_ifcfg (const char *file,
3893 NMConnection *connection = NULL;
3894 NMSetting *con_setting = NULL;
3895 NMSetting *bond_setting = NULL;
3896 NMSetting *wired_setting = NULL;
3897 NMSetting8021x *s_8021x = NULL;
3899 g_return_val_if_fail (file != NULL, NULL);
3900 g_return_val_if_fail (ifcfg != NULL, NULL);
3902 connection = nm_simple_connection_new ();
3904 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BOND_SETTING_NAME, NULL, _("Bond"));
3906 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3907 "Failed to create connection setting.");
3908 g_object_unref (connection);
3911 nm_connection_add_setting (connection, con_setting);
3913 bond_setting = make_bond_setting (ifcfg, file, error);
3914 if (!bond_setting) {
3915 g_object_unref (connection);
3918 nm_connection_add_setting (connection, bond_setting);
3920 wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
3921 if (!wired_setting) {
3922 g_object_unref (connection);
3925 nm_connection_add_setting (connection, wired_setting);
3928 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3933 /* Check 'error' for errors. Missing config (NULL return value) is a valid case. */
3935 read_team_config (shvarFile *ifcfg, const char *key, GError **error)
3940 /* FIXME: validate the JSON at some point */
3941 value = svGetValue (ifcfg, key, TRUE);
3945 /* No reason Team config should be over 20k. The config is read
3946 * verbatim, length-checked, then unescaped. svUnescape() does not
3947 * deal well with extremely long strings.
3951 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3952 "%s too long (size %zd)", key, l);
3961 make_team_setting (shvarFile *ifcfg,
3965 NMSettingTeam *s_team;
3967 GError *local_err = NULL;
3969 s_team = NM_SETTING_TEAM (nm_setting_team_new ());
3971 value = svGetValue (ifcfg, "DEVICE", FALSE);
3972 if (!value || !strlen (value)) {
3973 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
3974 "mandatory DEVICE keyword missing");
3979 value = read_team_config (ifcfg, "TEAM_CONFIG", &local_err);
3981 g_propagate_error (error, local_err);
3984 g_object_set (s_team, NM_SETTING_TEAM_CONFIG, value, NULL);
3987 return (NMSetting *) s_team;
3990 g_object_unref (s_team);
3994 static NMConnection *
3995 team_connection_from_ifcfg (const char *file,
3999 NMConnection *connection = NULL;
4000 NMSetting *con_setting = NULL;
4001 NMSetting *team_setting = NULL;
4002 NMSetting *wired_setting = NULL;
4003 NMSetting8021x *s_8021x = NULL;
4005 g_return_val_if_fail (file != NULL, NULL);
4006 g_return_val_if_fail (ifcfg != NULL, NULL);
4008 connection = nm_simple_connection_new ();
4010 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_TEAM_SETTING_NAME, NULL, _("Team"));
4012 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4013 "Failed to create connection setting.");
4014 g_object_unref (connection);
4017 nm_connection_add_setting (connection, con_setting);
4019 team_setting = make_team_setting (ifcfg, file, error);
4020 if (!team_setting) {
4021 g_object_unref (connection);
4024 nm_connection_add_setting (connection, team_setting);
4026 wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
4027 if (!wired_setting) {
4028 g_object_unref (connection);
4031 nm_connection_add_setting (connection, wired_setting);
4034 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
4039 typedef void (*BridgeOptFunc) (NMSetting *setting,
4045 handle_bridge_option (NMSetting *setting,
4052 if (!strcmp (key, "priority")) {
4054 PARSE_WARNING ("'priority' invalid when STP is disabled");
4055 } else if (get_uint (value, &u))
4056 g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL);
4058 PARSE_WARNING ("invalid priority value '%s'", value);
4059 } else if (!strcmp (key, "hello_time")) {
4061 PARSE_WARNING ("'hello_time' invalid when STP is disabled");
4062 } else if (get_uint (value, &u))
4063 g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL);
4065 PARSE_WARNING ("invalid hello_time value '%s'", value);
4066 } else if (!strcmp (key, "max_age")) {
4068 PARSE_WARNING ("'max_age' invalid when STP is disabled");
4069 } else if (get_uint (value, &u))
4070 g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL);
4072 PARSE_WARNING ("invalid max_age value '%s'", value);
4073 } else if (!strcmp (key, "ageing_time")) {
4074 if (get_uint (value, &u))
4075 g_object_set (setting, NM_SETTING_BRIDGE_AGEING_TIME, u, NULL);
4077 PARSE_WARNING ("invalid ageing_time value '%s'", value);
4079 PARSE_WARNING ("unhandled bridge option '%s'", key);
4083 handle_bridging_opts (NMSetting *setting,
4088 char **items, **iter;
4090 items = g_strsplit_set (value, " ", -1);
4091 for (iter = items; iter && *iter; iter++) {
4092 if (strlen (*iter)) {
4093 char **keys, *key, *val;
4095 keys = g_strsplit_set (*iter, "=", 2);
4096 if (keys && *keys) {
4099 if (val && strlen(key) && strlen(val))
4100 func (setting, stp, key, val);
4110 make_bridge_setting (shvarFile *ifcfg,
4114 NMSettingBridge *s_bridge;
4117 gboolean stp = FALSE;
4118 gboolean stp_set = FALSE;
4120 s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ());
4122 value = svGetValue (ifcfg, "DEVICE", FALSE);
4123 if (!value || !strlen (value)) {
4124 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4125 "mandatory DEVICE keyword missing");
4130 value = svGetValue (ifcfg, "MACADDR", FALSE);
4132 value = g_strstrip (value);
4133 g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, value, NULL);
4137 value = svGetValue (ifcfg, "STP", FALSE);
4139 if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) {
4140 g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL);
4143 } else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) {
4144 g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
4147 PARSE_WARNING ("invalid STP value '%s'", value);
4152 /* Missing or invalid STP property means "no" */
4153 g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
4156 value = svGetValue (ifcfg, "DELAY", FALSE);
4159 if (get_uint (value, &u))
4160 g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, u, NULL);
4162 PARSE_WARNING ("invalid forward delay value '%s'", value);
4164 PARSE_WARNING ("DELAY invalid when STP is disabled");
4168 value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE);
4170 handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option);
4174 return (NMSetting *) s_bridge;
4177 g_object_unref (s_bridge);
4181 static NMConnection *
4182 bridge_connection_from_ifcfg (const char *file,
4186 NMConnection *connection = NULL;
4187 NMSetting *con_setting = NULL;
4188 NMSetting *bridge_setting = NULL;
4190 g_return_val_if_fail (file != NULL, NULL);
4191 g_return_val_if_fail (ifcfg != NULL, NULL);
4193 connection = nm_simple_connection_new ();
4195 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BRIDGE_SETTING_NAME, NULL, _("Bridge"));
4197 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4198 "Failed to create connection setting.");
4199 g_object_unref (connection);
4202 nm_connection_add_setting (connection, con_setting);
4204 bridge_setting = make_bridge_setting (ifcfg, file, error);
4205 if (!bridge_setting) {
4206 g_object_unref (connection);
4209 nm_connection_add_setting (connection, bridge_setting);
4215 handle_bridge_port_option (NMSetting *setting,
4222 if (!strcmp (key, "priority")) {
4223 if (get_uint (value, &u))
4224 g_object_set (setting, NM_SETTING_BRIDGE_PORT_PRIORITY, u, NULL);
4226 PARSE_WARNING ("invalid priority value '%s'", value);
4227 } else if (!strcmp (key, "path_cost")) {
4228 if (get_uint (value, &u))
4229 g_object_set (setting, NM_SETTING_BRIDGE_PORT_PATH_COST, u, NULL);
4231 PARSE_WARNING ("invalid path_cost value '%s'", value);
4232 } else if (!strcmp (key, "hairpin_mode")) {
4233 if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1"))
4234 g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, TRUE, NULL);
4235 else if (!strcasecmp (value, "off") || !strcasecmp (value, "no"))
4236 g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, FALSE, NULL);
4238 PARSE_WARNING ("invalid hairpin_mode value '%s'", value);
4240 PARSE_WARNING ("unhandled bridge port option '%s'", key);
4244 make_bridge_port_setting (shvarFile *ifcfg)
4246 NMSetting *s_port = NULL;
4249 g_return_val_if_fail (ifcfg != NULL, FALSE);
4251 value = svGetValue (ifcfg, "BRIDGE", FALSE);
4255 s_port = nm_setting_bridge_port_new ();
4256 value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE);
4258 handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option);
4266 make_team_port_setting (shvarFile *ifcfg)
4268 NMSetting *s_port = NULL;
4270 GError *error = NULL;
4272 value = read_team_config (ifcfg, "TEAM_PORT_CONFIG", &error);
4274 s_port = nm_setting_team_port_new ();
4275 g_object_set (s_port, NM_SETTING_TEAM_PORT_CONFIG, value, NULL);
4278 PARSE_WARNING ("%s", error->message);
4279 g_error_free (error);
4286 is_bond_device (const char *name, shvarFile *parsed)
4288 g_return_val_if_fail (name != NULL, FALSE);
4289 g_return_val_if_fail (parsed != NULL, FALSE);
4291 if (svTrueValue (parsed, "BONDING_MASTER", FALSE))
4294 /* XXX: Check for "bond[\d]+"? */
4300 is_vlan_device (const char *name, shvarFile *parsed)
4302 g_return_val_if_fail (name != NULL, FALSE);
4303 g_return_val_if_fail (parsed != NULL, FALSE);
4305 if (svTrueValue (parsed, "VLAN", FALSE))
4312 is_wifi_device (const char *name, shvarFile *parsed)
4316 g_return_val_if_fail (name != NULL, FALSE);
4317 g_return_val_if_fail (parsed != NULL, FALSE);
4319 ifindex = nm_platform_link_get_ifindex (name);
4323 return nm_platform_link_get_type (ifindex) == NM_LINK_TYPE_WIFI;
4327 parse_prio_map_list (NMSettingVlan *s_vlan,
4330 NMVlanPriorityMap map)
4333 gchar **list = NULL, **iter;
4335 value = svGetValue (ifcfg, key, FALSE);
4339 list = g_strsplit_set (value, ",", -1);
4342 for (iter = list; iter && *iter; iter++) {
4343 if (!*iter || !strchr (*iter, ':'))
4346 if (!nm_setting_vlan_add_priority_str (s_vlan, map, *iter))
4347 PARSE_WARNING ("invalid %s priority map item '%s'", key, *iter);
4353 make_vlan_setting (shvarFile *ifcfg,
4357 NMSettingVlan *s_vlan = NULL;
4359 char *iface_name = NULL;
4360 char *parent = NULL;
4361 const char *p = NULL;
4364 guint32 vlan_flags = 0;
4366 value = svGetValue (ifcfg, "VLAN_ID", FALSE);
4369 vlan_id = (gint) g_ascii_strtoll (value, NULL, 10);
4370 if (vlan_id < 0 || vlan_id > 4096 || errno) {
4371 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4372 "Invalid VLAN_ID '%s'", value);
4379 /* Need DEVICE if we don't have a separate VLAN_ID property */
4380 iface_name = svGetValue (ifcfg, "DEVICE", FALSE);
4381 if (!iface_name && vlan_id < 0) {
4382 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4383 "Missing DEVICE property; cannot determine VLAN ID.");
4387 s_vlan = NM_SETTING_VLAN (nm_setting_vlan_new ());
4389 /* Parent interface from PHYSDEV takes precedence if it exists */
4390 parent = svGetValue (ifcfg, "PHYSDEV", FALSE);
4393 p = strchr (iface_name, '.');
4395 /* eth0.43; PHYSDEV is assumed from it if unknown */
4397 parent = g_strndup (iface_name, p - iface_name);
4398 if (g_str_has_prefix (parent, "vlan")) {
4399 /* Like initscripts, if no PHYSDEV and we get an obviously
4400 * invalid parent interface from DEVICE, fail.
4408 /* format like vlan43; PHYSDEV must be set */
4409 if (g_str_has_prefix (iface_name, "vlan"))
4414 /* Grab VLAN ID from interface name; this takes precedence over the
4415 * separate VLAN_ID property for backwards compat.
4417 vlan_id = (gint) g_ascii_strtoll (p, &end, 10);
4418 if (vlan_id < 0 || vlan_id > 4095 || end == p || *end) {
4419 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4420 "Failed to determine VLAN ID from DEVICE '%s'",
4428 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4429 "Failed to determine VLAN ID from DEVICE or VLAN_ID.");
4432 g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
4434 if (parent == NULL) {
4435 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4436 "Failed to determine VLAN parent from DEVICE or PHYSDEV");
4439 g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
4441 if (svTrueValue (ifcfg, "REORDER_HDR", FALSE))
4442 vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS;
4444 value = svGetValue (ifcfg, "VLAN_FLAGS", FALSE);
4446 if (g_strstr_len (value, -1, "GVRP"))
4447 vlan_flags |= NM_VLAN_FLAG_GVRP;
4448 if (g_strstr_len (value, -1, "LOOSE_BINDING"))
4449 vlan_flags |= NM_VLAN_FLAG_LOOSE_BINDING;
4452 g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, vlan_flags, NULL);
4455 parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP);
4456 parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP);
4458 return (NMSetting *) s_vlan;
4462 g_free (iface_name);
4463 g_object_unref (s_vlan);
4467 static NMConnection *
4468 vlan_connection_from_ifcfg (const char *file,
4472 NMConnection *connection = NULL;
4473 NMSetting *con_setting = NULL;
4474 NMSetting *wired_setting = NULL;
4475 NMSetting *vlan_setting = NULL;
4476 NMSetting8021x *s_8021x = NULL;
4478 g_return_val_if_fail (file != NULL, NULL);
4479 g_return_val_if_fail (ifcfg != NULL, NULL);
4481 connection = nm_simple_connection_new ();
4483 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_VLAN_SETTING_NAME, NULL, "Vlan");
4485 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4486 "Failed to create connection setting.");
4487 g_object_unref (connection);
4490 check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
4491 check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
4492 nm_connection_add_setting (connection, con_setting);
4494 vlan_setting = make_vlan_setting (ifcfg, file, error);
4495 if (!vlan_setting) {
4496 g_object_unref (connection);
4499 nm_connection_add_setting (connection, vlan_setting);
4501 wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
4502 if (!wired_setting) {
4503 g_object_unref (connection);
4506 nm_connection_add_setting (connection, wired_setting);
4509 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
4514 static NMConnection *
4515 create_unhandled_connection (const char *filename, shvarFile *ifcfg,
4516 const char *type, char **out_spec)
4518 NMConnection *connection;
4522 g_assert (out_spec != NULL);
4524 connection = nm_simple_connection_new ();
4526 /* Get NAME, UUID, etc. We need to set a connection type (generic) and add
4527 * an empty type-specific setting as well, to make sure it passes
4528 * nm_connection_verify() later.
4530 s_con = make_connection_setting (filename, ifcfg, NM_SETTING_GENERIC_SETTING_NAME,
4532 nm_connection_add_setting (connection, s_con);
4534 nm_connection_add_setting (connection, nm_setting_generic_new ());
4537 value = svGetValue (ifcfg, "HWADDR", FALSE);
4539 char *lower = g_ascii_strdown (value, -1);
4540 *out_spec = g_strdup_printf ("%s:mac:%s", type, lower);
4546 value = svGetValue (ifcfg, "SUBCHANNELS", FALSE);
4548 *out_spec = g_strdup_printf ("%s:s390-subchannels:%s", type, value);
4553 value = svGetValue (ifcfg, "DEVICE", FALSE);
4555 *out_spec = g_strdup_printf ("%s:interface-name:%s", type, value);
4560 g_object_unref (connection);
4565 uuid_from_file (const char *filename)
4567 const char *ifcfg_name = NULL;
4571 g_return_val_if_fail (filename != NULL, NULL);
4573 ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
4577 ifcfg = svOpenFile (filename, NULL);
4581 /* Try for a UUID key before falling back to hashing the file name */
4582 uuid = svGetValue (ifcfg, "UUID", FALSE);
4583 if (!uuid || !strlen (uuid)) {
4585 uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
4588 svCloseFile (ifcfg);
4593 check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6)
4598 /* If there is no IPv4 config or it doesn't contain DNS searches,
4599 * read DOMAIN and put the domains into IPv6.
4601 if (!s_ip4 || nm_setting_ip_config_get_num_dns_searches (NM_SETTING_IP_CONFIG (s_ip4)) == 0) {
4603 char *value = svGetValue (ifcfg, "DOMAIN", FALSE);
4605 char **searches = g_strsplit (value, " ", 0);
4608 for (item = searches; *item; item++) {
4609 if (strlen (*item)) {
4610 if (!nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (s_ip6), *item))
4611 PARSE_WARNING ("duplicate DNS domain '%s'", *item);
4614 g_strfreev (searches);
4621 static NMConnection *
4622 connection_from_file_full (const char *filename,
4623 const char *network_file, /* for unit tests only */
4624 const char *test_type, /* for unit tests only */
4625 char **out_unhandled,
4627 gboolean *out_ignore_error)
4629 NMConnection *connection = NULL;
4631 char *type, *devtype, *bootproto;
4632 NMSetting *s_ip4, *s_ip6, *s_port, *s_dcb = NULL;
4633 const char *ifcfg_name = NULL;
4635 g_return_val_if_fail (filename != NULL, NULL);
4637 g_return_val_if_fail (*out_unhandled == NULL, NULL);
4639 /* Non-NULL only for unit tests; normally use /etc/sysconfig/network */
4641 network_file = SYSCONFDIR "/sysconfig/network";
4643 ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
4645 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4646 "Ignoring connection '%s' because it's not an ifcfg file.", filename);
4650 parsed = svOpenFile (filename, error);
4654 if (!svTrueValue (parsed, "NM_CONTROLLED", TRUE)) {
4655 g_assert (out_unhandled != NULL);
4657 connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled);
4659 PARSE_WARNING ("NM_CONTROLLED was false but device was not uniquely identified; device will be managed");
4663 /* iBFT is handled by the iBFT settings plugin */
4664 bootproto = svGetValue (parsed, "BOOTPROTO", FALSE);
4665 if (bootproto && !g_ascii_strcasecmp (bootproto, "ibft")) {
4666 if (out_ignore_error)
4667 *out_ignore_error = TRUE;
4668 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4669 "Ignoring iBFT configuration");
4676 devtype = svGetValue (parsed, "DEVICETYPE", FALSE);
4678 if (!strcasecmp (devtype, TYPE_TEAM))
4679 type = g_strdup (TYPE_TEAM);
4680 else if (!strcasecmp (devtype, TYPE_TEAM_PORT))
4681 type = g_strdup (TYPE_ETHERNET);
4686 type = svGetValue (parsed, "TYPE", FALSE);
4691 device = svGetValue (parsed, "DEVICE", FALSE);
4693 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4694 "File '%s' had neither TYPE nor DEVICE keys.", filename);
4698 if (!strcmp (device, "lo")) {
4699 if (out_ignore_error)
4700 *out_ignore_error = TRUE;
4701 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4702 "Ignoring loopback device config.");
4708 if (is_bond_device (device, parsed))
4709 type = g_strdup (TYPE_BOND);
4710 else if (is_vlan_device (device, parsed))
4711 type = g_strdup (TYPE_VLAN);
4712 else if (is_wifi_device (device, parsed))
4713 type = g_strdup (TYPE_WIRELESS);
4715 type = g_strdup (TYPE_ETHERNET);
4717 /* For the unit tests, there won't necessarily be any
4718 * adapters of the connection's type in the system so the
4719 * type can't be tested with ioctls.
4721 type = g_strdup (test_type);
4726 /* Check for IBM s390 CTC devices and call them Ethernet */
4727 if (g_strcmp0 (type, "CTC") == 0) {
4729 type = g_strdup (TYPE_ETHERNET);
4733 if (svTrueValue (parsed, "BONDING_MASTER", FALSE) &&
4734 strcasecmp (type, TYPE_BOND)) {
4735 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
4736 "BONDING_MASTER=yes key only allowed in TYPE=bond connections");
4740 /* Construct the connection */
4741 if (!strcasecmp (type, TYPE_ETHERNET))
4742 connection = wired_connection_from_ifcfg (filename, parsed, error);
4743 else if (!strcasecmp (type, TYPE_WIRELESS))
4744 connection = wireless_connection_from_ifcfg (filename, parsed, error);
4745 else if (!strcasecmp (type, TYPE_INFINIBAND))
4746 connection = infiniband_connection_from_ifcfg (filename, parsed, error);
4747 else if (!strcasecmp (type, TYPE_BOND))
4748 connection = bond_connection_from_ifcfg (filename, parsed, error);
4749 else if (!strcasecmp (type, TYPE_TEAM))
4750 connection = team_connection_from_ifcfg (filename, parsed, error);
4751 else if (!strcasecmp (type, TYPE_VLAN))
4752 connection = vlan_connection_from_ifcfg (filename, parsed, error);
4753 else if (!strcasecmp (type, TYPE_BRIDGE))
4754 connection = bridge_connection_from_ifcfg (filename, parsed, error);
4756 g_assert (out_unhandled != NULL);
4758 connection = create_unhandled_connection (filename, parsed, "unrecognized", out_unhandled);
4760 PARSE_WARNING ("connection type was unrecognized but device was not uniquely identified; device may be managed");
4768 s_ip6 = make_ip6_setting (parsed, network_file, error);
4770 g_object_unref (connection);
4774 nm_connection_add_setting (connection, s_ip6);
4776 s_ip4 = make_ip4_setting (parsed, network_file, error);
4778 g_object_unref (connection);
4782 read_aliases (NM_SETTING_IP_CONFIG (s_ip4), filename, network_file);
4783 nm_connection_add_setting (connection, s_ip4);
4786 /* There is only one DOMAIN variable and it is read and put to IPv4 config
4787 * But if IPv4 is disabled or the config fails for some reason, we read
4788 * DOMAIN and put the values into IPv6 config instead.
4790 check_dns_search_domains (parsed, s_ip4, s_ip6);
4793 s_port = make_bridge_port_setting (parsed);
4795 nm_connection_add_setting (connection, s_port);
4798 s_port = make_team_port_setting (parsed);
4800 nm_connection_add_setting (connection, s_port);
4802 if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) {
4803 g_object_unref (connection);
4808 nm_connection_add_setting (connection, s_dcb);
4810 if (!nm_connection_normalize (connection, NULL, NULL, error)) {
4811 g_object_unref (connection);
4816 svCloseFile (parsed);
4821 connection_from_file (const char *filename,
4822 char **out_unhandled,
4825 gboolean ignore_error = FALSE;
4828 conn = connection_from_file_full (filename, NULL, NULL,
4832 if (error && *error && !ignore_error)
4833 PARSE_WARNING ("%s", (*error)->message);
4838 connection_from_file_test (const char *filename,
4839 const char *network_file,
4840 const char *test_type,
4841 char **out_unhandled,
4844 return connection_from_file_full (filename,
4853 devtimeout_from_file (const char *filename)
4856 char *devtimeout_str;
4859 g_return_val_if_fail (filename != NULL, 0);
4861 ifcfg = svOpenFile (filename, NULL);
4865 devtimeout_str = svGetValue (ifcfg, "DEVTIMEOUT", FALSE);
4866 if (devtimeout_str) {
4867 devtimeout = nm_utils_ascii_str_to_int64 (devtimeout_str, 10, 0, G_MAXUINT, 0);
4868 g_free (devtimeout_str);