1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager system settings service - keyfile plugin
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 (C) 2008 - 2009 Novell, Inc.
19 * Copyright (C) 2008 - 2015 Red Hat, Inc.
22 #include "nm-default.h"
24 #include "nm-keyfile-internal.h"
30 #include <sys/types.h>
31 #include <arpa/inet.h>
34 #include "nm-core-internal.h"
35 #include "nm-keyfile-utils.h"
38 NMConnection *connection;
41 NMKeyfileReadHandler handler;
50 _handle_warn (KeyfileReaderInfo *info,
51 const char *property_name,
52 NMKeyfileWarnSeverity severity,
55 NMKeyfileReadTypeDataWarn type_data = {
57 .setting = info->setting,
58 .property_name = property_name,
63 info->handler (info->keyfile,
65 NM_KEYFILE_READ_TYPE_WARN,
71 #define handle_warn(arg_info, arg_property_name, arg_severity, ...) \
73 KeyfileReaderInfo *_info = (arg_info); \
75 if (_info->handler) { \
76 _handle_warn (_info, (arg_property_name), (arg_severity), \
77 g_strdup_printf (__VA_ARGS__)); \
79 _info->error == NULL; \
82 /* Some setting properties also contain setting names, such as
83 * NMSettingConnection's 'type' property (which specifies the base type of the
84 * connection, e.g. ethernet or wifi) or 'slave-type' (specifies type of slave
85 * connection, e.g. bond or bridge). This function handles translating those
86 * properties' values to the real setting name if they are an alias.
89 setting_alias_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
91 const char *setting_name = nm_setting_get_name (setting);
93 const char *key_setting_name;
95 s = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
97 key_setting_name = nm_keyfile_plugin_get_setting_name_for_alias (s);
98 g_object_set (G_OBJECT (setting),
99 key, key_setting_name ? key_setting_name : s,
106 read_array_of_uint (GKeyFile *file,
110 GArray *array = NULL;
115 tmp = nm_keyfile_plugin_kf_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL);
116 array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length);
118 for (i = 0; i < length; i++)
119 g_array_append_val (array, tmp[i]);
121 g_object_set (setting, key, array, NULL);
122 g_array_unref (array);
126 get_one_int (KeyfileReaderInfo *info, const char *property_name, const char *str, guint32 max_val, guint32 *out)
131 g_return_val_if_fail (!info == !property_name, FALSE);
133 if (!str || !str[0]) {
135 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
136 _("ignoring missing number"));
141 tmp = strtol (str, &endptr, 10);
142 if (errno || (tmp < 0) || (tmp > max_val) || *endptr != 0) {
144 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
145 _("ignoring invalid number '%s'"),
150 *out = (guint32) tmp;
155 build_address (KeyfileReaderInfo *info, int family, const char *address_str, guint32 plen, const char *property_name)
158 GError *error = NULL;
160 g_return_val_if_fail (address_str, NULL);
162 addr = nm_ip_address_new (family, address_str, plen, &error);
164 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
165 _("ignoring invalid %s address: %s"),
166 family == AF_INET ? "IPv4" : "IPv6", error->message);
167 g_error_free (error);
174 build_route (KeyfileReaderInfo *info,
175 const char *property_name,
177 const char *dest_str, guint32 plen,
178 const char *gateway_str, const char *metric_str)
182 GError *error = NULL;
184 g_return_val_if_fail (plen, NULL);
185 g_return_val_if_fail (dest_str, NULL);
188 if (gateway_str && gateway_str[0]) {
189 if (!nm_utils_ipaddr_valid (family, gateway_str)) {
190 /* Try workaround for routes written by broken keyfile writer.
191 * Due to bug bgo#719851, an older version of writer would have
192 * written "a:b:c:d::/plen,metric" if the gateway was ::, instead
193 * of "a:b:c:d::/plen,,metric" or "a:b:c:d::/plen,::,metric"
194 * Try workaround by interpreting gateway_str as metric to accept such
195 * invalid routes. This broken syntax should not be not officially
198 if ( family == AF_INET6
200 && get_one_int (NULL, NULL, gateway_str, G_MAXUINT32, &metric))
204 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
205 _("ignoring invalid gateway '%s' for %s route"),
206 gateway_str, family == AF_INET ? "IPv4" : "IPv6");
214 /* parse metric, default to 0 */
216 if (!get_one_int (info, property_name, metric_str, G_MAXUINT32, &metric))
220 route = nm_ip_route_new (family, dest_str, plen, gateway_str,
221 metric ? (gint64) metric : -1,
224 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
225 _("ignoring invalid %s route: %s"),
226 family == AF_INET ? "IPv4" : "IPv6",
228 g_error_free (error);
234 /* On success, returns pointer to the zero-terminated field (original @current).
235 * The @current * pointer target is set to point to the rest of the input
236 * or %NULL if there is no more input. Sets error to %NULL for convenience.
238 * On failure, returns %NULL (unspecified). The @current pointer target is
239 * resets to its original value to allow skipping fields. The @error target
240 * is set to the character that breaks the parsing or %NULL if @current was %NULL.
242 * When @current target is %NULL, gracefully fail returning %NULL while
243 * leaving the @current target %NULL end setting @error to %NULL;
246 read_field (char **current, char **error, const char *characters, const char *delimiters)
250 g_return_val_if_fail (current, NULL);
251 g_return_val_if_fail (error, NULL);
252 g_return_val_if_fail (characters, NULL);
253 g_return_val_if_fail (delimiters, NULL);
258 /* graceful failure, leave '*current' NULL */
262 /* fail on empty input */
266 /* remember beginning of input */
269 while (**current && strchr (characters, **current))
272 if (strchr (delimiters, **current)) {
273 /* success, more data available */
274 *(*current)++ = '\0';
277 /* error, bad character */
283 /* success, end of input */
289 #define IP_ADDRESS_CHARS "0123456789abcdefABCDEF:.%"
290 #define DIGITS "0123456789"
291 #define DELIMITERS "/;,"
294 /* The following IPv4 and IPv6 address formats are supported:
296 * address (DEPRECATED)
298 * address/gateway (DEPRECATED)
299 * address/plen,gateway
301 * The following IPv4 and IPv6 route formats are supported:
303 * address/plen (NETWORK dev DEVICE)
304 * address/plen,gateway (NETWORK via GATEWAY dev DEVICE)
305 * address/plen,,metric (NETWORK dev DEVICE metric METRIC)
306 * address/plen,gateway,metric (NETWORK via GATEWAY dev DEVICE metric METRIC)
308 * For backward, forward and sideward compatibility, slash (/),
309 * semicolon (;) and comma (,) are interchangable. The choice of
310 * separator in the above examples is therefore not significant.
312 * Leaving out the prefix length is discouraged and DEPRECATED. The
313 * default value of IPv6 prefix length was 64 and has not been
314 * changed. The default for IPv4 is now 24, which is the closest
315 * IPv4 equivalent. These defaults may just as well be changed to
316 * match the iproute2 defaults (32 for IPv4 and 128 for IPv6).
319 read_one_ip_address_or_route (KeyfileReaderInfo *info,
320 const char *property_name,
321 const char *setting_name,
322 const char *key_name,
328 guint32 plen = G_MAXUINT32;
330 char *address_str, *plen_str, *gateway_str, *metric_str, *current, *error;
331 gs_free char *value = NULL, *value_orig = NULL;
333 #define VALUE_ORIG() (value_orig ? value_orig : (value_orig = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key_name, NULL)))
335 current = value = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key_name, NULL);
339 /* get address field */
340 address_str = read_field (¤t, &error, IP_ADDRESS_CHARS, DELIMITERS);
342 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
343 _("unexpected character '%c' for address %s: '%s' (position %td)"),
344 *error, key_name, VALUE_ORIG (), error - current);
347 /* get prefix length field (skippable) */
348 plen_str = read_field (¤t, &error, DIGITS, DELIMITERS);
349 /* get gateway field */
350 gateway_str = read_field (¤t, &error, IP_ADDRESS_CHARS, DELIMITERS);
352 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
353 _("unexpected character '%c' for %s: '%s' (position %td)"),
354 *error, key_name, VALUE_ORIG (), error - current);
357 /* for routes, get metric */
359 metric_str = read_field (¤t, &error, DIGITS, DELIMITERS);
361 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
362 _("unexpected character '%c' in prefix length for %s: '%s' (position %td)"),
363 *error, key_name, VALUE_ORIG (), error - current);
369 /* there is still some data */
371 /* another field follows */
372 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
373 _("garbage at the end of value %s: '%s'"),
374 key_name, VALUE_ORIG ());
377 /* semicolon at the end of input */
378 if (!handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_INFO,
379 _("deprecated semicolon at the end of value %s: '%s'"),
380 key_name, VALUE_ORIG ()))
385 #define DEFAULT_PREFIX(for_route, for_ipv6) ( (for_route) ? ( (for_ipv6) ? 128 : 24 ) : ( (for_ipv6) ? 64 : 24 ) )
387 /* parse plen, fallback to defaults */
389 if (!get_one_int (info, property_name, plen_str, ipv6 ? 128 : 32, &plen)
390 || (route && plen == 0)) {
391 plen = DEFAULT_PREFIX (route, ipv6);
393 || !handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
394 _("invalid prefix length for %s '%s', defaulting to %d"),
395 key_name, VALUE_ORIG (), plen))
399 plen = DEFAULT_PREFIX (route, ipv6);
400 if (!handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
401 _("missing prefix length for %s '%s', defaulting to %d"),
402 key_name, VALUE_ORIG (), plen))
406 /* build the appropriate data structure for NetworkManager settings */
408 result = build_route (info, property_name,
409 ipv6 ? AF_INET6 : AF_INET,
410 address_str, plen, gateway_str, metric_str);
412 result = build_address (info, ipv6 ? AF_INET6 : AF_INET,
413 address_str, plen, property_name);
416 if (out_gateway && gateway_str)
417 *out_gateway = g_strdup (gateway_str);
426 ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
428 const char *setting_name = nm_setting_get_name (setting);
429 gboolean ipv6 = !strcmp (setting_name, "ipv6");
430 gboolean routes = !strcmp (key, "routes");
431 static const char *key_names_routes[] = { "route", "routes", NULL };
432 static const char *key_names_addresses[] = { "address", "addresses", NULL };
433 const char **key_names = routes ? key_names_routes : key_names_addresses;
434 char *gateway = NULL;
436 GDestroyNotify free_func;
440 free_func = (GDestroyNotify) nm_ip_route_unref;
442 free_func = (GDestroyNotify) nm_ip_address_unref;
443 list = g_ptr_array_new_with_free_func (free_func);
445 for (i = -1; i < 1000; i++) {
446 const char **key_basename;
448 for (key_basename = key_names; *key_basename; key_basename++) {
452 /* -1 means no suffix */
454 key_name = g_strdup_printf ("%s%d", *key_basename, i);
456 key_name = g_strdup (*key_basename);
458 item = read_one_ip_address_or_route (info, key, setting_name, key_name, ipv6, routes,
459 gateway ? NULL : &gateway, setting);
463 g_ptr_array_unref (list);
468 g_ptr_array_add (list, item);
474 g_object_set (setting, key, list, NULL);
477 g_object_set (setting, "gateway", gateway, NULL);
481 g_ptr_array_unref (list);
485 ip4_dns_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
487 const char *setting_name = nm_setting_get_name (setting);
493 list = nm_keyfile_plugin_kf_get_string_list (info->keyfile, setting_name, key, &length, NULL);
494 if (!list || !g_strv_length (list))
497 array = g_ptr_array_sized_new (length + 1);
498 for (iter = list; *iter; iter++) {
501 ret = inet_pton (AF_INET, *iter, &addr);
503 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
504 _("ignoring invalid DNS server IPv4 address '%s'"),
506 g_ptr_array_unref (array);
513 g_ptr_array_add (array, *iter);
515 g_ptr_array_add (array, NULL);
517 g_object_set (setting, key, array->pdata, NULL);
518 g_ptr_array_unref (array);
523 ip6_dns_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
525 const char *setting_name = nm_setting_get_name (setting);
526 GPtrArray *array = NULL;
531 list = nm_keyfile_plugin_kf_get_string_list (info->keyfile, setting_name, key, &length, NULL);
532 if (!list || !g_strv_length (list))
535 array = g_ptr_array_sized_new (length + 1);
537 for (iter = list; *iter; iter++) {
538 struct in6_addr addr;
540 ret = inet_pton (AF_INET6, *iter, &addr);
542 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
543 _("ignoring invalid DNS server IPv6 address '%s'"),
545 g_ptr_array_unref (array);
552 g_ptr_array_add (array, *iter);
554 g_ptr_array_add (array, NULL);
556 g_object_set (setting, key, array->pdata, NULL);
557 g_ptr_array_unref (array);
562 ip6_addr_gen_mode_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
564 NMSettingIP6ConfigAddrGenMode addr_gen_mode;
565 const char *setting_name = nm_setting_get_name (setting);
566 gs_free char *s = NULL;
568 s = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
570 if (!nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), s,
571 (int *) &addr_gen_mode, NULL)) {
572 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
573 _("invalid option '%s', use one of [%s]"),
574 s, "eui64,stable-privacy");
578 addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64;
580 g_object_set (G_OBJECT (setting), key, (gint) addr_gen_mode, NULL);
584 mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize enforce_length)
586 const char *setting_name = nm_setting_get_name (setting);
587 char *tmp_string = NULL, *p, *mac_str;
589 GByteArray *array = NULL;
592 p = tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
593 if (tmp_string && tmp_string[0]) {
594 /* Look for enough ':' characters to signify a MAC address */
603 if (enforce_length == 0 || enforce_length == i+1) {
604 /* If we found enough it's probably a string-format MAC address */
605 array = g_byte_array_sized_new (i+1);
606 g_byte_array_set_size (array, i+1);
607 if (!nm_utils_hwaddr_aton (tmp_string, array->data, array->len)) {
608 g_byte_array_unref (array);
616 /* Old format; list of ints */
617 tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
618 if (length > 0 && (enforce_length == 0 || enforce_length == length)) {
621 array = g_byte_array_sized_new (length);
622 for (i = 0; i < length; i++) {
623 int val = tmp_list[i];
624 const guint8 v = (guint8) (val & 0xFF);
626 if (val < 0 || val > 255) {
627 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
628 _("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
630 g_byte_array_free (array, TRUE);
634 g_byte_array_append (array, &v, 1);
641 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
642 _("ignoring invalid MAC address"));
646 mac_str = nm_utils_hwaddr_ntoa (array->data, array->len);
647 g_object_set (setting, key, mac_str, NULL);
649 g_byte_array_free (array, TRUE);
653 mac_address_parser_ETHER (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
655 mac_address_parser (info, setting, key, ETH_ALEN);
659 mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
661 mac_address_parser (info, setting, key, INFINIBAND_ALEN);
665 read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
669 const char *setting_name = nm_setting_get_name (setting);
671 keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, NULL, NULL);
675 for (iter = keys; *iter; iter++) {
676 value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL);
680 if (NM_IS_SETTING_VPN (setting)) {
681 /* Add any item that's not a class property to the data hash */
682 if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), *iter))
683 nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), *iter, value);
685 if (NM_IS_SETTING_BOND (setting)) {
686 if (strcmp (*iter, "interface-name"))
687 nm_setting_bond_add_option (NM_SETTING_BOND (setting), *iter, value);
695 unescape_semicolons (char *str)
698 gsize len = strlen (str);
700 for (i = 0; i < len; i++) {
701 if (str[i] == '\\' && str[i+1] == ';') {
702 memmove(str + i, str + i + 1, len - (i + 1));
710 get_bytes (KeyfileReaderInfo *info,
711 const char *setting_name,
713 gboolean zero_terminate,
714 gboolean unescape_semicolon)
716 GByteArray *array = NULL;
722 if (!nm_keyfile_plugin_kf_has_key (info->keyfile, setting_name, key, NULL))
725 /* New format: just a string
726 * Old format: integer list; e.g. 11;25;38;
728 tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
731 GMatchInfo *match_info;
732 const char *pattern = "^[[:space:]]*[[:digit:]]{1,3}[[:space:]]*;([[:space:]]*[[:digit:]]{1,3}[[:space:]]*;)*([[:space:]]*)?$";
734 regex = g_regex_new (pattern, 0, 0, NULL);
735 g_regex_match (regex, tmp_string, 0, &match_info);
736 if (!g_match_info_matches (match_info)) {
737 /* Handle as a simple string (ie, new format) */
738 if (unescape_semicolon)
739 unescape_semicolons (tmp_string);
740 length = strlen (tmp_string);
743 array = g_byte_array_sized_new (length);
744 g_byte_array_append (array, (guint8 *) tmp_string, length);
746 g_match_info_free (match_info);
747 g_regex_unref (regex);
752 gboolean already_warned = FALSE;
754 /* Old format; list of ints */
755 tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
757 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
758 _("ignoring invalid binary property"));
761 array = g_byte_array_sized_new (length);
762 for (i = 0; i < length; i++) {
763 int val = tmp_list[i];
764 unsigned char v = (unsigned char) (val & 0xFF);
766 if (val < 0 || val > 255) {
768 && !handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
769 _("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
772 g_byte_array_free (array, TRUE);
775 already_warned = TRUE;
777 g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
782 if (array->len == 0) {
783 g_byte_array_free (array, TRUE);
786 return g_byte_array_free_to_bytes (array);
790 ssid_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
792 const char *setting_name = nm_setting_get_name (setting);
795 bytes = get_bytes (info, setting_name, key, FALSE, TRUE);
797 g_object_set (setting, key, bytes, NULL);
798 g_bytes_unref (bytes);
799 } else if (!info->error) {
800 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
801 _("ignoring invalid SSID"));
806 password_raw_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
808 const char *setting_name = nm_setting_get_name (setting);
811 bytes = get_bytes (info, setting_name, key, FALSE, TRUE);
813 g_object_set (setting, key, bytes, NULL);
814 g_bytes_unref (bytes);
815 } else if (!info->error) {
816 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
817 _("ignoring invalid raw password"));
822 get_cert_path (const char *base_dir, const guint8 *cert_path, gsize cert_path_len)
825 char *p = NULL, *path, *tmp;
827 g_return_val_if_fail (base_dir != NULL, NULL);
828 g_return_val_if_fail (cert_path != NULL, NULL);
830 base = path = g_malloc0 (cert_path_len + 1);
831 memcpy (path, cert_path, cert_path_len);
836 p = strrchr (path, '/');
840 tmp = g_build_path ("/", base_dir, base, NULL);
845 static const char *certext[] = { ".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key" };
848 has_cert_ext (const char *path)
852 for (i = 0; i < G_N_ELEMENTS (certext); i++) {
853 if (g_str_has_suffix (path, certext[i]))
860 handle_as_scheme (KeyfileReaderInfo *info, GBytes *bytes, NMSetting *setting, const char *key)
863 gsize data_len, bin_len;
865 data = g_bytes_get_data (bytes, &data_len);
867 g_return_val_if_fail (data && data_len > 0, FALSE);
869 /* to be a scheme, @data must be a zero terminated string, which is counted by @data_len */
870 if (data[data_len - 1] != '\0')
874 /* It's the PATH scheme, can just set plain data.
875 * In this case, @data_len includes */
876 if ( data_len >= NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)
877 && g_str_has_prefix (data, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)) {
878 if (nm_setting_802_1x_check_cert_scheme (data, data_len + 1, NULL) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
879 const char *path = &data[NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)];
880 gs_free char *path_free = NULL;
882 if (path[0] != '/') {
883 /* we want to read absolute paths because we use keyfile as exchange
884 * between different processes which might not have the same cwd. */
885 path = path_free = get_cert_path (info->base_dir, (const guint8 *) path,
886 data_len - NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH));
889 g_object_set (setting, key, bytes, NULL);
890 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
891 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE,
892 _("certificate or key file '%s' does not exist"),
896 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
897 _("invalid key/cert value path \"%s\""), data);
901 if ( data_len > NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB)
902 && g_str_has_prefix (data, NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB)) {
903 const char *cdata = data + NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB);
907 gboolean valid_base64;
909 data_len -= NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB);
911 /* Let's be strict here. We expect valid base64, no funny stuff!!
912 * We didn't write such invalid data ourselfes and refuse to read it as blob. */
913 if ((valid_base64 = (data_len % 4 == 0))) {
914 for (i = 0; i < data_len; i++) {
917 if (!( (c >= 'a' && c <= 'z')
918 || (c >= 'A' && c <= 'Z')
919 || (c >= '0' && c <= '9')
920 || (c == '+' || c == '/'))) {
921 if (c != '=' || i < data_len - 2)
922 valid_base64 = FALSE;
924 for (; i < data_len; i++) {
926 valid_base64 = FALSE;
934 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
935 _("invalid key/cert value data:;base64, is not base64"));
939 bin = g_base64_decode (cdata, &bin_len);
941 g_return_val_if_fail (bin_len > 0, FALSE);
942 if (nm_setting_802_1x_check_cert_scheme (bin, bin_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_BLOB) {
943 /* The blob probably starts with "file://". Setting the cert data will confuse NMSetting8021x.
944 * In fact this is a limitation of NMSetting8021x which does not support setting blobs that start
945 * with file://. Just warn and return TRUE to signal that we ~handled~ the setting. */
947 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
948 _("invalid key/cert value data:;base64,file://"));
950 bytes2 = g_bytes_new_take (bin, bin_len);
951 g_object_set (setting, key, bytes2, NULL);
952 g_bytes_unref (bytes2);
960 nm_keyfile_detect_unqualified_path_scheme (const char *base_dir,
963 gboolean consider_exists,
964 gboolean *out_exists)
966 const char *data = pdata;
967 gboolean exists = FALSE;
968 gboolean success = FALSE;
973 g_return_val_if_fail (base_dir && base_dir[0] == '/', NULL);
978 data_len = strlen (data);
979 if (data_len > 500 || data_len < 1)
982 /* If there's a trailing zero tell g_utf8_validate() to validate until the zero */
983 if (data[data_len - 1] == '\0') {
984 /* setting it to -1, would mean we accept data to contain NUL characters before the
985 * end. Don't accept any NUL in [0 .. data_len-1[ . */
986 validate_len = data_len - 1;
988 validate_len = data_len;
989 if ( validate_len == 0
990 || g_utf8_validate ((const char *) data, validate_len, NULL) == FALSE)
993 /* Might be a bare path without the file:// prefix; in that case
994 * if it's an absolute path, use that, otherwise treat it as a
995 * relative path to the current directory.
998 path = get_cert_path (base_dir, (const guint8 *) data, data_len);
999 if ( !memchr (data, '/', data_len)
1000 && !has_cert_ext (path)) {
1001 if (!consider_exists)
1003 exists = g_file_test (path, G_FILE_TEST_EXISTS);
1006 } else if (out_exists)
1007 exists = g_file_test (path, G_FILE_TEST_EXISTS);
1009 /* Construct the proper value as required for the PATH scheme */
1010 tmp = g_byte_array_sized_new (strlen (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) + strlen (path) + 1);
1011 g_byte_array_append (tmp, (const guint8 *) NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, strlen (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH));
1012 g_byte_array_append (tmp, (const guint8 *) path, strlen (path) + 1);
1013 if (nm_setting_802_1x_check_cert_scheme (tmp->data, tmp->len, NULL) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
1015 path = (char *) g_byte_array_free (tmp, FALSE);
1016 /* when returning TRUE, we must also be sure that @data_len does not look like
1017 * the deprecated format of list of integers. With this implementation that is the
1018 * case, as long as @consider_exists is FALSE. */
1021 g_byte_array_unref (tmp);
1029 *out_exists = exists;
1034 handle_as_path (KeyfileReaderInfo *info,
1042 gboolean exists = FALSE;
1045 data = g_bytes_get_data (bytes, &data_len);
1047 path = nm_keyfile_detect_unqualified_path_scheme (info->base_dir, data, data_len, TRUE, &exists);
1051 /* Construct the proper value as required for the PATH scheme */
1052 val = g_bytes_new_take (path, strlen (path) + 1);
1053 g_object_set (setting, key, val, NULL);
1055 /* Warn if the certificate didn't exist */
1057 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE,
1058 _("certificate or key file '%s' does not exist"),
1061 g_bytes_unref (val);
1067 cert_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
1069 const char *setting_name = nm_setting_get_name (setting);
1070 gs_unref_bytes GBytes *bytes = NULL;
1074 bytes = get_bytes (info, setting_name, key, TRUE, FALSE);
1076 /* Try as a path + scheme (ie, starts with "file://") */
1077 if (handle_as_scheme (info, bytes, setting, key))
1082 /* If not, it might be a plain path */
1083 if (handle_as_path (info, bytes, setting, key))
1088 bin = g_bytes_get_data (bytes, &bin_len);
1089 if (nm_setting_802_1x_check_cert_scheme (bin, bin_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_BLOB) {
1090 /* The blob probably starts with "file://" but contains invalid characters for a path.
1091 * Setting the cert data will confuse NMSetting8021x.
1092 * In fact, NMSetting8021x does not support setting such binary data, so just warn and
1094 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1095 _("invalid key/cert value is not a valid blob"));
1097 g_object_set (setting, key, bytes, NULL);
1098 } else if (!info->error) {
1099 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1100 _("invalid key/cert value"));
1105 parity_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
1107 const char *setting_name = nm_setting_get_name (setting);
1108 NMSettingSerialParity parity;
1110 gs_free char *str_val = NULL;
1112 /* Keyfile traditionally stored this as the ASCII value for 'E', 'o', or 'n'.
1113 * We now accept either that or the (case-insensitive) character itself (but
1114 * still always write it the old way, for backward compatibility).
1116 int_val = nm_keyfile_plugin_kf_get_integer (info->keyfile, setting_name, key, NULL);
1118 str_val = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
1120 if (str_val[0] && !str_val[1])
1121 int_val = str_val[0];
1123 /* This will hit the warning below */
1135 parity = NM_SETTING_SERIAL_PARITY_EVEN;
1139 parity = NM_SETTING_SERIAL_PARITY_ODD;
1143 parity = NM_SETTING_SERIAL_PARITY_NONE;
1146 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1147 _("invalid parity value '%s'"),
1148 str_val ? str_val : "");
1152 g_object_set (setting, key, parity, NULL);
1156 const char *setting_name;
1158 gboolean check_for_key;
1159 void (*parser) (KeyfileReaderInfo *info, NMSetting *setting, const char *key);
1162 /* A table of keys that require further parsing/conversion because they are
1163 * stored in a format that can't be automatically read using the key's type.
1164 * i.e. IPv4 addresses, which are stored in NetworkManager as guint32, but are
1165 * stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored
1166 * in struct in6_addr internally, but as string in keyfiles.
1168 static KeyParser key_parsers[] = {
1169 { NM_SETTING_CONNECTION_SETTING_NAME,
1170 NM_SETTING_CONNECTION_TYPE,
1172 setting_alias_parser },
1173 { NM_SETTING_BRIDGE_SETTING_NAME,
1174 NM_SETTING_BRIDGE_MAC_ADDRESS,
1176 mac_address_parser_ETHER },
1177 { NM_SETTING_IP4_CONFIG_SETTING_NAME,
1178 NM_SETTING_IP_CONFIG_ADDRESSES,
1180 ip_address_or_route_parser },
1181 { NM_SETTING_IP6_CONFIG_SETTING_NAME,
1182 NM_SETTING_IP_CONFIG_ADDRESSES,
1184 ip_address_or_route_parser },
1185 { NM_SETTING_IP4_CONFIG_SETTING_NAME,
1186 NM_SETTING_IP_CONFIG_ROUTES,
1188 ip_address_or_route_parser },
1189 { NM_SETTING_IP6_CONFIG_SETTING_NAME,
1190 NM_SETTING_IP_CONFIG_ROUTES,
1192 ip_address_or_route_parser },
1193 { NM_SETTING_IP4_CONFIG_SETTING_NAME,
1194 NM_SETTING_IP_CONFIG_DNS,
1197 { NM_SETTING_IP6_CONFIG_SETTING_NAME,
1198 NM_SETTING_IP_CONFIG_DNS,
1201 { NM_SETTING_IP6_CONFIG_SETTING_NAME,
1202 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
1204 ip6_addr_gen_mode_parser },
1205 { NM_SETTING_WIRED_SETTING_NAME,
1206 NM_SETTING_WIRED_MAC_ADDRESS,
1208 mac_address_parser_ETHER },
1209 { NM_SETTING_WIRED_SETTING_NAME,
1210 NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
1212 mac_address_parser_ETHER },
1213 { NM_SETTING_WIRELESS_SETTING_NAME,
1214 NM_SETTING_WIRELESS_MAC_ADDRESS,
1216 mac_address_parser_ETHER },
1217 { NM_SETTING_WIRELESS_SETTING_NAME,
1218 NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
1220 mac_address_parser_ETHER },
1221 { NM_SETTING_WIRELESS_SETTING_NAME,
1222 NM_SETTING_WIRELESS_BSSID,
1224 mac_address_parser_ETHER },
1225 { NM_SETTING_BLUETOOTH_SETTING_NAME,
1226 NM_SETTING_BLUETOOTH_BDADDR,
1228 mac_address_parser_ETHER },
1229 { NM_SETTING_INFINIBAND_SETTING_NAME,
1230 NM_SETTING_INFINIBAND_MAC_ADDRESS,
1232 mac_address_parser_INFINIBAND },
1233 { NM_SETTING_WIMAX_SETTING_NAME,
1234 NM_SETTING_WIMAX_MAC_ADDRESS,
1236 mac_address_parser_ETHER },
1237 { NM_SETTING_WIRELESS_SETTING_NAME,
1238 NM_SETTING_WIRELESS_SSID,
1241 { NM_SETTING_802_1X_SETTING_NAME,
1242 NM_SETTING_802_1X_PASSWORD_RAW,
1244 password_raw_parser },
1245 { NM_SETTING_802_1X_SETTING_NAME,
1246 NM_SETTING_802_1X_CA_CERT,
1249 { NM_SETTING_802_1X_SETTING_NAME,
1250 NM_SETTING_802_1X_CLIENT_CERT,
1253 { NM_SETTING_802_1X_SETTING_NAME,
1254 NM_SETTING_802_1X_PRIVATE_KEY,
1257 { NM_SETTING_802_1X_SETTING_NAME,
1258 NM_SETTING_802_1X_PHASE2_CA_CERT,
1261 { NM_SETTING_802_1X_SETTING_NAME,
1262 NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
1265 { NM_SETTING_802_1X_SETTING_NAME,
1266 NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
1269 { NM_SETTING_SERIAL_SETTING_NAME,
1270 NM_SETTING_SERIAL_PARITY,
1273 { NULL, NULL, FALSE }
1277 set_default_for_missing_key (NMSetting *setting, const char *property)
1279 /* Set a value different from the default value of the property's spec */
1281 if (NM_IS_SETTING_WIRELESS (setting)) {
1282 if (!strcmp (property, NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION))
1283 g_object_set (setting, property, (NMSettingMacRandomization) NM_SETTING_MAC_RANDOMIZATION_NEVER, NULL);
1288 read_one_setting_value (NMSetting *setting,
1290 const GValue *value,
1294 KeyfileReaderInfo *info = user_data;
1295 GKeyFile *keyfile = info->keyfile;
1296 const char *setting_name;
1299 gs_free_error GError *err = NULL;
1300 gboolean check_for_key = TRUE;
1301 KeyParser *parser = &key_parsers[0];
1306 /* Property is not writable */
1307 if (!(flags & G_PARAM_WRITABLE))
1310 /* Setting name gets picked up from the keyfile's section name instead */
1311 if (!strcmp (key, NM_SETTING_NAME))
1314 /* Don't read the NMSettingConnection object's 'read-only' property */
1315 if ( NM_IS_SETTING_CONNECTION (setting)
1316 && !strcmp (key, NM_SETTING_CONNECTION_READ_ONLY))
1319 setting_name = nm_setting_get_name (setting);
1321 /* Look through the list of handlers for non-standard format key values */
1322 while (parser->setting_name) {
1323 if (!strcmp (parser->setting_name, setting_name) && !strcmp (parser->key, key)) {
1324 check_for_key = parser->check_for_key;
1330 /* VPN properties don't have the exact key name */
1331 if (NM_IS_SETTING_VPN (setting))
1332 check_for_key = FALSE;
1334 /* Bonding 'options' don't have the exact key name. The options are right under [bond] group. */
1335 if (NM_IS_SETTING_BOND (setting))
1336 check_for_key = FALSE;
1338 /* Check for the exact key in the GKeyFile if required. Most setting
1339 * properties map 1:1 to a key in the GKeyFile, but for those properties
1340 * like IP addresses and routes where more than one value is actually
1341 * encoded by the setting property, this won't be true.
1343 if (check_for_key && !nm_keyfile_plugin_kf_has_key (keyfile, setting_name, key, &err)) {
1344 /* Key doesn't exist or an error ocurred, thus nothing to do. */
1346 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1347 _("error loading setting value: %s"),
1352 /* Allow default values different than in property spec */
1353 set_default_for_missing_key (setting, key);
1357 /* If there's a custom parser for this key, handle that before the generic
1360 if (parser->setting_name) {
1361 (*parser->parser) (info, setting, key);
1365 type = G_VALUE_TYPE (value);
1367 if (type == G_TYPE_STRING) {
1370 str_val = nm_keyfile_plugin_kf_get_string (keyfile, setting_name, key, NULL);
1371 g_object_set (setting, key, str_val, NULL);
1373 } else if (type == G_TYPE_UINT) {
1376 int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
1378 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1379 _("invalid negative value (%i)"),
1383 g_object_set (setting, key, int_val, NULL);
1384 } else if (type == G_TYPE_INT) {
1387 int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
1388 g_object_set (setting, key, int_val, NULL);
1389 } else if (type == G_TYPE_BOOLEAN) {
1392 bool_val = nm_keyfile_plugin_kf_get_boolean (keyfile, setting_name, key, NULL);
1393 g_object_set (setting, key, bool_val, NULL);
1394 } else if (type == G_TYPE_CHAR) {
1397 int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
1398 if (int_val < G_MININT8 || int_val > G_MAXINT8) {
1399 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1400 _("invalid char value (%i)"),
1405 g_object_set (setting, key, int_val, NULL);
1406 } else if (type == G_TYPE_UINT64) {
1410 tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, NULL);
1411 uint_val = g_ascii_strtoull (tmp_str, NULL, 10);
1413 g_object_set (setting, key, uint_val, NULL);
1414 } else if (type == G_TYPE_INT64) {
1415 gs_free char *tmp_str = NULL;
1418 tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, NULL);
1419 int_val = _nm_utils_ascii_str_to_int64 (tmp_str, 10, G_MININT64, G_MAXINT64, 0);
1422 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1423 _("invalid int64 value (%s)"),
1427 g_object_set (setting, key, int_val, NULL);
1428 } else if (type == G_TYPE_BYTES) {
1434 gboolean already_warned = FALSE;
1436 tmp = nm_keyfile_plugin_kf_get_integer_list (keyfile, setting_name, key, &length, NULL);
1438 array = g_byte_array_sized_new (length);
1439 for (i = 0; i < length; i++) {
1441 unsigned char v = (unsigned char) (val & 0xFF);
1443 if (val < 0 || val > 255) {
1444 if ( !already_warned
1445 && !handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1446 _("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
1448 g_byte_array_unref (array);
1452 already_warned = TRUE;
1454 g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
1457 bytes = g_byte_array_free_to_bytes (array);
1458 g_object_set (setting, key, bytes, NULL);
1459 g_bytes_unref (bytes);
1461 } else if (type == G_TYPE_STRV) {
1465 sa = nm_keyfile_plugin_kf_get_string_list (keyfile, setting_name, key, &length, NULL);
1466 g_object_set (setting, key, sa, NULL);
1468 } else if (type == G_TYPE_HASH_TABLE) {
1469 read_hash_of_string (keyfile, setting, key);
1470 } else if (type == G_TYPE_ARRAY) {
1471 read_array_of_uint (keyfile, setting, key);
1472 } else if (G_VALUE_HOLDS_FLAGS (value)) {
1475 /* Flags are guint but GKeyFile has no uint reader, just uint64 */
1476 uint_val = nm_keyfile_plugin_kf_get_uint64 (keyfile, setting_name, key, &err);
1478 if (uint_val <= G_MAXUINT)
1479 g_object_set (setting, key, (guint) uint_val, NULL);
1481 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1482 _("too large FLAGS property '%s' (%llu)"),
1483 G_VALUE_TYPE_NAME (value), (long long unsigned) uint_val))
1487 } else if (G_VALUE_HOLDS_ENUM (value)) {
1490 int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, &err);
1492 g_object_set (setting, key, (gint) int_val, NULL);
1494 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1495 _("unhandled setting property type '%s'"),
1496 G_VALUE_TYPE_NAME (value)))
1504 read_setting (KeyfileReaderInfo *info)
1509 alias = nm_keyfile_plugin_get_setting_name_for_alias (info->group);
1511 alias = info->group;
1513 type = nm_setting_lookup_type (alias);
1515 NMSetting *setting = g_object_new (type, NULL);
1517 info->setting = setting;
1518 nm_setting_enumerate_values (setting, read_one_setting_value, info);
1519 info->setting = NULL;
1523 g_object_unref (setting);
1525 handle_warn (info, NULL, NM_KEYFILE_WARN_SEVERITY_WARN,
1526 _("invalid setting name '%s'"), info->group);
1533 read_vpn_secrets (KeyfileReaderInfo *info, NMSettingVpn *s_vpn)
1535 char **keys, **iter;
1537 keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, NULL, NULL);
1538 for (iter = keys; *iter; iter++) {
1541 secret = nm_keyfile_plugin_kf_get_string (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, *iter, NULL);
1543 nm_setting_vpn_add_secret (s_vpn, *iter, secret);
1552 * @keyfile: the keyfile from which to create the connection
1553 * @keyfile_name: keyfile allows missing connection id and uuid
1554 * and NetworkManager will create those when reading a connection
1555 * from file. By providing a filename you can reproduce that behavior,
1556 * but of course, it can only recreate the same UUID if you provide the
1557 * same filename as NetworkManager core daemon would.
1558 * @keyfile_name has only a relevance for setting the id or uuid if it
1559 * is missing and as fallback for @base_dir.
1560 * @base_dir: when reading certificates from files with relative name,
1561 * the relative path is made absolute using @base_dir.
1562 * If @base_dir is missing, first try to get the pathname from @keyfile_name
1563 * (if it is given as absolute path). As last, fallback to the current path.
1564 * @handler: read handler
1565 * @user_data: user data for read handler
1568 * Tries to create a NMConnection from a keyfile. The resulting keyfile is
1569 * not normalized and might not even verify.
1571 * Returns: (transfer full): on success, returns the created connection.
1574 nm_keyfile_read (GKeyFile *keyfile,
1575 const char *keyfile_name,
1576 const char *base_dir,
1577 NMKeyfileReadHandler handler,
1581 NMConnection *connection = NULL;
1582 NMSettingConnection *s_con;
1587 gboolean vpn_secrets = FALSE;
1588 KeyfileReaderInfo info = { 0 };
1589 gs_free char *base_dir_free = NULL;
1591 g_return_val_if_fail (keyfile, NULL);
1592 g_return_val_if_fail (!error || !*error, NULL);
1595 /* basedir is not given. Prefer it from the keyfile_name */
1596 if (keyfile_name && keyfile_name[0] == '/') {
1597 base_dir = base_dir_free = g_path_get_dirname (keyfile_name);
1599 /* if keyfile is not given or not an absolute path, fallback
1600 * to current working directory. */
1601 base_dir = base_dir_free = g_get_current_dir ();
1604 g_return_val_if_fail ("/", NULL);
1606 connection = nm_simple_connection_new ();
1608 info.connection = connection;
1609 info.keyfile = (GKeyFile *) keyfile;
1610 info.base_dir = base_dir;
1611 info.handler = handler;
1612 info.user_data = user_data;
1614 groups = g_key_file_get_groups (keyfile, &length);
1617 for (i = 0; i < length; i++) {
1618 /* Only read out secrets when needed */
1619 if (!strcmp (groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) {
1624 info.group = groups[i];
1625 setting = read_setting (&info);
1630 nm_connection_add_setting (connection, setting);
1632 g_strfreev (groups);
1634 s_con = nm_connection_get_setting_connection (connection);
1636 s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
1637 nm_connection_add_setting (connection, NM_SETTING (s_con));
1640 /* Make sure that we have 'id' even if not explictly specified in the keyfile */
1642 && !nm_setting_connection_get_id (s_con)) {
1645 base_name = g_path_get_basename (keyfile_name);
1646 g_object_set (s_con, NM_SETTING_CONNECTION_ID, base_name, NULL);
1650 /* Make sure that we have 'uuid' even if not explictly specified in the keyfile */
1652 && !nm_setting_connection_get_uuid (s_con)) {
1655 hashed_uuid = _nm_utils_uuid_generate_from_strings ("keyfile", keyfile_name, NULL);
1656 g_object_set (s_con, NM_SETTING_CONNECTION_UUID, hashed_uuid, NULL);
1657 g_free (hashed_uuid);
1660 /* Make sure that we have 'interface-name' even if it was specified in the
1661 * "wrong" (ie, deprecated) group.
1663 if ( !nm_setting_connection_get_interface_name (s_con)
1664 && nm_setting_connection_get_connection_type (s_con)) {
1665 char *interface_name;
1667 interface_name = g_key_file_get_string (keyfile,
1668 nm_setting_connection_get_connection_type (s_con),
1671 if (interface_name) {
1672 g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL);
1673 g_free (interface_name);
1677 /* Handle vpn secrets after the 'vpn' setting was read */
1679 NMSettingVpn *s_vpn;
1681 s_vpn = nm_connection_get_setting_vpn (connection);
1683 read_vpn_secrets (&info, s_vpn);
1691 g_propagate_error (error, info.error);
1692 g_free (connection);