device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-core / nm-keyfile-reader.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager system settings service - keyfile plugin
3  *
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.
8  *
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.
13  *
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.
17  *
18  * Copyright (C) 2008 - 2009 Novell, Inc.
19  * Copyright (C) 2008 - 2015 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include "nm-keyfile-internal.h"
25
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <arpa/inet.h>
32 #include <string.h>
33
34 #include "nm-core-internal.h"
35 #include "nm-keyfile-utils.h"
36
37 typedef struct {
38         NMConnection *connection;
39         GKeyFile *keyfile;
40         const char *base_dir;
41         NMKeyfileReadHandler handler;
42         void *user_data;
43         GError *error;
44         const char *group;
45         NMSetting *setting;
46 } KeyfileReaderInfo;
47
48
49 static void
50 _handle_warn (KeyfileReaderInfo *info,
51               const char *property_name,
52               NMKeyfileWarnSeverity severity,
53               char *message)
54 {
55         NMKeyfileReadTypeDataWarn type_data = {
56                 .group = info->group,
57                 .setting = info->setting,
58                 .property_name = property_name,
59                 .severity = severity,
60                 .message = message,
61         };
62
63         info->handler (info->keyfile,
64                        info->connection,
65                        NM_KEYFILE_READ_TYPE_WARN,
66                        &type_data,
67                        info->user_data,
68                        &info->error);
69         g_free (message);
70 }
71 #define handle_warn(arg_info, arg_property_name, arg_severity, ...) \
72         ({ \
73                 KeyfileReaderInfo *_info = (arg_info); \
74                 \
75                 if (_info->handler) { \
76                         _handle_warn (_info, (arg_property_name), (arg_severity), \
77                                       g_strdup_printf (__VA_ARGS__)); \
78                 } \
79                 _info->error == NULL; \
80         })
81
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.
87  */
88 static void
89 setting_alias_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
90 {
91         const char *setting_name = nm_setting_get_name (setting);
92         char *s;
93         const char *key_setting_name;
94
95         s = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
96         if (s) {
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,
100                               NULL);
101                 g_free (s);
102         }
103 }
104
105 static void
106 read_array_of_uint (GKeyFile *file,
107                     NMSetting *setting,
108                     const char *key)
109 {
110         GArray *array = NULL;
111         gsize length;
112         int i;
113         gint *tmp;
114
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);
117
118         for (i = 0; i < length; i++)
119                 g_array_append_val (array, tmp[i]);
120
121         g_object_set (setting, key, array, NULL);
122         g_array_unref (array);
123 }
124
125 static gboolean
126 get_one_int (KeyfileReaderInfo *info, const char *property_name, const char *str, guint32 max_val, guint32 *out)
127 {
128         long tmp;
129         char *endptr;
130
131         g_return_val_if_fail (!info == !property_name, FALSE);
132
133         if (!str || !str[0]) {
134                 if (property_name)
135                         handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
136                                      _("ignoring missing number"));
137                 return FALSE;
138         }
139
140         errno = 0;
141         tmp = strtol (str, &endptr, 10);
142         if (errno || (tmp < 0) || (tmp > max_val) || *endptr != 0) {
143                 if (property_name)
144                         handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
145                                      _("ignoring invalid number '%s'"),
146                                     str);
147                 return FALSE;
148         }
149
150         *out = (guint32) tmp;
151         return TRUE;
152 }
153
154 static gpointer
155 build_address (KeyfileReaderInfo *info, int family, const char *address_str, guint32 plen, const char *property_name)
156 {
157         NMIPAddress *addr;
158         GError *error = NULL;
159
160         g_return_val_if_fail (address_str, NULL);
161
162         addr = nm_ip_address_new (family, address_str, plen, &error);
163         if (!addr) {
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);
168         }
169
170         return addr;
171 }
172
173 static gpointer
174 build_route (KeyfileReaderInfo *info,
175              const char *property_name,
176              int family,
177              const char *dest_str, guint32 plen,
178              const char *gateway_str, const char *metric_str)
179 {
180         NMIPRoute *route;
181         guint32 metric = 0;
182         GError *error = NULL;
183
184         g_return_val_if_fail (plen, NULL);
185         g_return_val_if_fail (dest_str, NULL);
186
187         /* Next hop */
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
196                          * supported.
197                          **/
198                         if (   family == AF_INET6
199                             && !metric_str
200                             && get_one_int (NULL, NULL, gateway_str, G_MAXUINT32, &metric))
201                                 gateway_str = NULL;
202                         else {
203                                 if (!info->error) {
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");
207                                 }
208                                 return NULL;
209                         }
210                 }
211         } else
212                 gateway_str = NULL;
213
214         /* parse metric, default to 0 */
215         if (metric_str) {
216                 if (!get_one_int (info, property_name, metric_str, G_MAXUINT32, &metric))
217                         return NULL;
218         }
219
220         route = nm_ip_route_new (family, dest_str, plen, gateway_str,
221                                  metric ? (gint64) metric : -1,
222                                  &error);
223         if (!route) {
224                 handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
225                              _("ignoring invalid %s route: %s"),
226                              family == AF_INET ? "IPv4" : "IPv6",
227                              error->message);
228                 g_error_free (error);
229         }
230
231         return route;
232 }
233
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.
237  *
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.
241  *
242  * When @current target is %NULL, gracefully fail returning %NULL while
243  * leaving the @current target %NULL end setting @error to %NULL;
244  */
245 static char *
246 read_field (char **current, char **error, const char *characters, const char *delimiters)
247 {
248         char *start;
249
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);
254
255         *error = NULL;
256
257         if (!*current) {
258                 /* graceful failure, leave '*current' NULL */
259                 return NULL;
260         }
261
262         /* fail on empty input */
263         if (!**current)
264                 return NULL;
265
266         /* remember beginning of input */
267         start = *current;
268
269         while (**current && strchr (characters, **current))
270                 (*current)++;
271         if (**current)
272                 if (strchr (delimiters, **current)) {
273                         /* success, more data available */
274                         *(*current)++ = '\0';
275                         return start;
276                 } else {
277                         /* error, bad character */
278                         *error = *current;
279                         *current = start;
280                         return NULL;
281                 }
282         else {
283                 /* success, end of input */
284                 *current = NULL;
285                 return start;
286         }
287 }
288
289 #define IP_ADDRESS_CHARS "0123456789abcdefABCDEF:.%"
290 #define DIGITS "0123456789"
291 #define DELIMITERS "/;,"
292
293
294 /* The following IPv4 and IPv6 address formats are supported:
295  *
296  * address (DEPRECATED)
297  * address/plen
298  * address/gateway (DEPRECATED)
299  * address/plen,gateway
300  *
301  * The following IPv4 and IPv6 route formats are supported:
302  *
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)
307  *
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.
311  *
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).
317  */
318 static gpointer
319 read_one_ip_address_or_route (KeyfileReaderInfo *info,
320                               const char *property_name,
321                               const char *setting_name,
322                               const char *key_name,
323                               gboolean ipv6,
324                               gboolean route,
325                               char **out_gateway,
326                               NMSetting *setting)
327 {
328         guint32 plen = G_MAXUINT32;
329         gpointer result;
330         char *address_str, *plen_str, *gateway_str, *metric_str, *current, *error;
331         gs_free char *value = NULL, *value_orig = NULL;
332
333 #define VALUE_ORIG()   (value_orig ? value_orig : (value_orig = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key_name, NULL)))
334
335         current = value = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key_name, NULL);
336         if (!value)
337                 return NULL;
338
339         /* get address field */
340         address_str = read_field (&current, &error, IP_ADDRESS_CHARS, DELIMITERS);
341         if (error) {
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);
345                 return NULL;
346         }
347         /* get prefix length field (skippable) */
348         plen_str = read_field (&current, &error, DIGITS, DELIMITERS);
349         /* get gateway field */
350         gateway_str = read_field (&current, &error, IP_ADDRESS_CHARS, DELIMITERS);
351         if (error) {
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);
355                 return NULL;
356         }
357         /* for routes, get metric */
358         if (route) {
359                 metric_str = read_field (&current, &error, DIGITS, DELIMITERS);
360                 if (error) {
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);
364                         return NULL;
365                 }
366         } else
367                 metric_str = NULL;
368         if (current) {
369                 /* there is still some data */
370                 if (*current) {
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 ());
375                         return NULL;
376                 } else {
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 ()))
381                                 return NULL;
382                 }
383         }
384
385 #define DEFAULT_PREFIX(for_route, for_ipv6) ( (for_route) ? ( (for_ipv6) ? 128 : 24 ) : ( (for_ipv6) ? 64 : 24 ) )
386
387         /* parse plen, fallback to defaults */
388         if (plen_str) {
389                 if (!get_one_int (info, property_name, plen_str, ipv6 ? 128 : 32, &plen)
390                     || (route && plen == 0)) {
391                         plen = DEFAULT_PREFIX (route, ipv6);
392                         if (   info->error
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))
396                                 return NULL;
397                 }
398         } else {
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))
403                         return NULL;
404         }
405
406         /* build the appropriate data structure for NetworkManager settings */
407         if (route) {
408                 result = build_route (info, property_name,
409                                       ipv6 ? AF_INET6 : AF_INET,
410                                       address_str, plen, gateway_str, metric_str);
411         } else {
412                 result = build_address (info, ipv6 ? AF_INET6 : AF_INET,
413                                         address_str, plen, property_name);
414                 if (!result)
415                         return NULL;
416                 if (out_gateway && gateway_str)
417                         *out_gateway = g_strdup (gateway_str);
418         }
419
420 #undef VALUE_ORIG
421
422         return result;
423 }
424
425 static void
426 ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
427 {
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;
435         GPtrArray *list;
436         GDestroyNotify free_func;
437         int i;
438
439         if (routes)
440                 free_func = (GDestroyNotify) nm_ip_route_unref;
441         else
442                 free_func = (GDestroyNotify) nm_ip_address_unref;
443         list = g_ptr_array_new_with_free_func (free_func);
444
445         for (i = -1; i < 1000; i++) {
446                 const char **key_basename;
447
448                 for (key_basename = key_names; *key_basename; key_basename++) {
449                         char *key_name;
450                         gpointer item;
451
452                         /* -1 means no suffix */
453                         if (i >= 0)
454                                 key_name = g_strdup_printf ("%s%d", *key_basename, i);
455                         else
456                                 key_name = g_strdup (*key_basename);
457
458                         item = read_one_ip_address_or_route (info, key, setting_name, key_name, ipv6, routes,
459                                                              gateway ? NULL : &gateway, setting);
460                         g_free (key_name);
461
462                         if (info->error) {
463                                 g_ptr_array_unref (list);
464                                 g_free (gateway);
465                                 return;
466                         }
467                         if (item)
468                                 g_ptr_array_add (list, item);
469
470                 }
471         }
472
473         if (list->len >= 1)
474                 g_object_set (setting, key, list, NULL);
475
476         if (gateway) {
477                 g_object_set (setting, "gateway", gateway, NULL);
478                 g_free (gateway);
479         }
480
481         g_ptr_array_unref (list);
482 }
483
484 static void
485 ip4_dns_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
486 {
487         const char *setting_name = nm_setting_get_name (setting);
488         GPtrArray *array;
489         gsize length;
490         char **list, **iter;
491         int ret;
492
493         list = nm_keyfile_plugin_kf_get_string_list (info->keyfile, setting_name, key, &length, NULL);
494         if (!list || !g_strv_length (list))
495                 return;
496
497         array = g_ptr_array_sized_new (length + 1);
498         for (iter = list; *iter; iter++) {
499                 guint32 addr;
500
501                 ret = inet_pton (AF_INET, *iter, &addr);
502                 if (ret <= 0) {
503                         if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
504                                           _("ignoring invalid DNS server IPv4 address '%s'"),
505                                           *iter)) {
506                                 g_ptr_array_unref (array);
507                                 g_strfreev (list);
508                                 return;
509                         }
510                         continue;
511                 }
512
513                 g_ptr_array_add (array, *iter);
514         }
515         g_ptr_array_add (array, NULL);
516
517         g_object_set (setting, key, array->pdata, NULL);
518         g_ptr_array_unref (array);
519         g_strfreev (list);
520 }
521
522 static void
523 ip6_dns_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
524 {
525         const char *setting_name = nm_setting_get_name (setting);
526         GPtrArray *array = NULL;
527         gsize length;
528         char **list, **iter;
529         int ret;
530
531         list = nm_keyfile_plugin_kf_get_string_list (info->keyfile, setting_name, key, &length, NULL);
532         if (!list || !g_strv_length (list))
533                 return;
534
535         array = g_ptr_array_sized_new (length + 1);
536
537         for (iter = list; *iter; iter++) {
538                 struct in6_addr addr;
539
540                 ret = inet_pton (AF_INET6, *iter, &addr);
541                 if (ret <= 0) {
542                         if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
543                                           _("ignoring invalid DNS server IPv6 address '%s'"),
544                                           *iter)) {
545                                 g_ptr_array_unref (array);
546                                 g_strfreev (list);
547                                 return;
548                         }
549                         continue;
550                 }
551
552                 g_ptr_array_add (array, *iter);
553         }
554         g_ptr_array_add (array, NULL);
555
556         g_object_set (setting, key, array->pdata, NULL);
557         g_ptr_array_unref (array);
558         g_strfreev (list);
559 }
560
561 static void
562 ip6_addr_gen_mode_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
563 {
564         NMSettingIP6ConfigAddrGenMode addr_gen_mode;
565         const char *setting_name = nm_setting_get_name (setting);
566         gs_free char *s = NULL;
567
568         s = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
569         if (s) {
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");
575                         return;
576                 }
577         } else
578                 addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64;
579
580         g_object_set (G_OBJECT (setting), key, (gint) addr_gen_mode, NULL);
581 }
582
583 static void
584 mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize enforce_length)
585 {
586         const char *setting_name = nm_setting_get_name (setting);
587         char *tmp_string = NULL, *p, *mac_str;
588         gint *tmp_list;
589         GByteArray *array = NULL;
590         gsize length;
591
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 */
595                 guint i = 0;
596
597                 while (*p) {
598                         if (*p == ':')
599                                 i++;
600                         p++;
601                 }
602
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);
609                                 array = NULL;
610                         }
611                 }
612         }
613         g_free (tmp_string);
614
615         if (array == NULL) {
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)) {
619                         gsize i;
620
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);
625
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)"),
629                                                      val);
630                                         g_byte_array_free (array, TRUE);
631                                         g_free (tmp_list);
632                                         return;
633                                 }
634                                 g_byte_array_append (array, &v, 1);
635                         }
636                 }
637                 g_free (tmp_list);
638         }
639
640         if (!array) {
641                 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
642                              _("ignoring invalid MAC address"));
643                 return;
644         }
645
646         mac_str = nm_utils_hwaddr_ntoa (array->data, array->len);
647         g_object_set (setting, key, mac_str, NULL);
648         g_free (mac_str);
649         g_byte_array_free (array, TRUE);
650 }
651
652 static void
653 mac_address_parser_ETHER (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
654 {
655         mac_address_parser (info, setting, key, ETH_ALEN);
656 }
657
658 static void
659 mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
660 {
661         mac_address_parser (info, setting, key, INFINIBAND_ALEN);
662 }
663
664 static void
665 read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
666 {
667         char **keys, **iter;
668         char *value;
669         const char *setting_name = nm_setting_get_name (setting);
670
671         keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, NULL, NULL);
672         if (!keys || !*keys)
673                 return;
674
675         for (iter = keys; *iter; iter++) {
676                 value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL);
677                 if (!value)
678                         continue;
679
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);
684                 }
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);
688                 }
689                 g_free (value);
690         }
691         g_strfreev (keys);
692 }
693
694 static void
695 unescape_semicolons (char *str)
696 {
697         int i;
698         gsize len = strlen (str);
699
700         for (i = 0; i < len; i++) {
701                 if (str[i] == '\\' && str[i+1] == ';') {
702                         memmove(str + i, str + i + 1, len - (i + 1));
703                         len--;
704                 }
705                 str[len] = '\0';
706         }
707 }
708
709 static GBytes *
710 get_bytes (KeyfileReaderInfo *info,
711            const char *setting_name,
712            const char *key,
713            gboolean zero_terminate,
714            gboolean unescape_semicolon)
715 {
716         GByteArray *array = NULL;
717         char *tmp_string;
718         gint *tmp_list;
719         gsize length;
720         int i;
721
722         if (!nm_keyfile_plugin_kf_has_key (info->keyfile, setting_name, key, NULL))
723                 return NULL;
724
725         /* New format: just a string
726          * Old format: integer list; e.g. 11;25;38;
727          */
728         tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
729         if (tmp_string) {
730                 GRegex *regex;
731                 GMatchInfo *match_info;
732                 const char *pattern = "^[[:space:]]*[[:digit:]]{1,3}[[:space:]]*;([[:space:]]*[[:digit:]]{1,3}[[:space:]]*;)*([[:space:]]*)?$";
733
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);
741                         if (zero_terminate)
742                                 length++;
743                         array = g_byte_array_sized_new (length);
744                         g_byte_array_append (array, (guint8 *) tmp_string, length);
745                 }
746                 g_match_info_free (match_info);
747                 g_regex_unref (regex);
748                 g_free (tmp_string);
749         }
750
751         if (!array) {
752                 gboolean already_warned = FALSE;
753
754                 /* Old format; list of ints */
755                 tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
756                 if (!tmp_list) {
757                         handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
758                                      _("ignoring invalid binary property"));
759                         return NULL;
760                 }
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);
765
766                         if (val < 0 || val > 255) {
767                                 if (   !already_warned
768                                     && !handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
769                                                      _("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
770                                                      val)) {
771                                         g_free (tmp_list);
772                                         g_byte_array_free (array, TRUE);
773                                         return NULL;
774                                 }
775                                 already_warned = TRUE;
776                         } else
777                                 g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
778                 }
779                 g_free (tmp_list);
780         }
781
782         if (array->len == 0) {
783                 g_byte_array_free (array, TRUE);
784                 return NULL;
785         } else
786                 return g_byte_array_free_to_bytes (array);
787 }
788
789 static void
790 ssid_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
791 {
792         const char *setting_name = nm_setting_get_name (setting);
793         GBytes *bytes;
794
795         bytes = get_bytes (info, setting_name, key, FALSE, TRUE);
796         if (bytes) {
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"));
802         }
803 }
804
805 static void
806 password_raw_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
807 {
808         const char *setting_name = nm_setting_get_name (setting);
809         GBytes *bytes;
810
811         bytes = get_bytes (info, setting_name, key, FALSE, TRUE);
812         if (bytes) {
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"));
818         }
819 }
820
821 static char *
822 get_cert_path (const char *base_dir, const guint8 *cert_path, gsize cert_path_len)
823 {
824         const char *base;
825         char *p = NULL, *path, *tmp;
826
827         g_return_val_if_fail (base_dir != NULL, NULL);
828         g_return_val_if_fail (cert_path != NULL, NULL);
829
830         base = path = g_malloc0 (cert_path_len + 1);
831         memcpy (path, cert_path, cert_path_len);
832
833         if (path[0] == '/')
834                 return path;
835
836         p = strrchr (path, '/');
837         if (p)
838                 base = p + 1;
839
840         tmp = g_build_path ("/", base_dir, base, NULL);
841         g_free (path);
842         return tmp;
843 }
844
845 static const char *certext[] = { ".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key" };
846
847 static gboolean
848 has_cert_ext (const char *path)
849 {
850         int i;
851
852         for (i = 0; i < G_N_ELEMENTS (certext); i++) {
853                 if (g_str_has_suffix (path, certext[i]))
854                         return TRUE;
855         }
856         return FALSE;
857 }
858
859 static gboolean
860 handle_as_scheme (KeyfileReaderInfo *info, GBytes *bytes, NMSetting *setting, const char *key)
861 {
862         const char *data;
863         gsize data_len, bin_len;
864
865         data = g_bytes_get_data (bytes, &data_len);
866
867         g_return_val_if_fail (data && data_len > 0, FALSE);
868
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')
871                 return FALSE;
872         data_len--;
873
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;
881
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));
887                         }
888
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"),
893                                              path);
894                         }
895                 } else {
896                         handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
897                                      _("invalid key/cert value path \"%s\""), data);
898                 }
899                 return TRUE;
900         }
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);
904                 guchar *bin;
905                 GBytes *bytes2;
906                 gsize i;
907                 gboolean valid_base64;
908
909                 data_len -= NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB);
910
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++) {
915                                 char c = cdata[i];
916
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;
923                                         else {
924                                                 for (; i < data_len; i++) {
925                                                         if (cdata[i] != '=')
926                                                                 valid_base64 = FALSE;
927                                                 }
928                                         }
929                                         break;
930                                 }
931                         }
932                 }
933                 if (!valid_base64) {
934                         handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
935                                      _("invalid key/cert value data:;base64, is not base64"));
936                         return TRUE;
937                 }
938
939                 bin = g_base64_decode (cdata, &bin_len);
940
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. */
946                         g_free (bin);
947                         handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
948                                      _("invalid key/cert value data:;base64,file://"));
949                 } else {
950                         bytes2 = g_bytes_new_take (bin, bin_len);
951                         g_object_set (setting, key, bytes2, NULL);
952                         g_bytes_unref (bytes2);
953                 }
954                 return TRUE;
955         }
956         return FALSE;
957 }
958
959 char *
960 nm_keyfile_detect_unqualified_path_scheme (const char *base_dir,
961                                            gconstpointer pdata,
962                                            gsize data_len,
963                                            gboolean consider_exists,
964                                            gboolean *out_exists)
965 {
966         const char *data = pdata;
967         gboolean exists = FALSE;
968         gboolean success = FALSE;
969         gsize validate_len;
970         char *path;
971         GByteArray *tmp;
972
973         g_return_val_if_fail (base_dir && base_dir[0] == '/', NULL);
974
975         if (!pdata)
976                 return NULL;
977         if (data_len == -1)
978                 data_len = strlen (data);
979         if (data_len > 500 || data_len < 1)
980                 return NULL;
981
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;
987         } else
988                 validate_len = data_len;
989         if (   validate_len == 0
990             || g_utf8_validate ((const char *) data, validate_len, NULL) == FALSE)
991                  return NULL;
992
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.
996          */
997
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)
1002                         goto out;
1003                 exists = g_file_test (path, G_FILE_TEST_EXISTS);
1004                 if (!exists)
1005                         goto out;
1006         } else if (out_exists)
1007                 exists = g_file_test (path, G_FILE_TEST_EXISTS);
1008
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) {
1014                 g_free (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. */
1019                 success = TRUE;
1020         } else
1021                 g_byte_array_unref (tmp);
1022
1023 out:
1024         if (!success) {
1025                 g_free (path);
1026                 return NULL;
1027         }
1028         if (out_exists)
1029                 *out_exists = exists;
1030         return path;
1031 }
1032
1033 static gboolean
1034 handle_as_path (KeyfileReaderInfo *info,
1035                 GBytes *bytes,
1036                 NMSetting *setting,
1037                 const char *key)
1038 {
1039         const guint8 *data;
1040         gsize data_len;
1041         char *path;
1042         gboolean exists = FALSE;
1043         GBytes *val;
1044
1045         data = g_bytes_get_data (bytes, &data_len);
1046
1047         path = nm_keyfile_detect_unqualified_path_scheme (info->base_dir, data, data_len, TRUE, &exists);
1048         if (!path)
1049                 return FALSE;
1050
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);
1054
1055         /* Warn if the certificate didn't exist */
1056         if (!exists) {
1057                 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE,
1058                              _("certificate or key file '%s' does not exist"),
1059                              path);
1060         }
1061         g_bytes_unref (val);
1062
1063         return TRUE;
1064 }
1065
1066 static void
1067 cert_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
1068 {
1069         const char *setting_name = nm_setting_get_name (setting);
1070         gs_unref_bytes GBytes *bytes = NULL;
1071         gsize bin_len;
1072         const char *bin;
1073
1074         bytes = get_bytes (info, setting_name, key, TRUE, FALSE);
1075         if (bytes) {
1076                 /* Try as a path + scheme (ie, starts with "file://") */
1077                 if (handle_as_scheme (info, bytes, setting, key))
1078                         return;
1079                 if (info->error)
1080                         return;
1081
1082                 /* If not, it might be a plain path */
1083                 if (handle_as_path (info, bytes, setting, key))
1084                         return;
1085                 if (info->error)
1086                         return;
1087
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
1093                          * continue. */
1094                         handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1095                                      _("invalid key/cert value is not a valid blob"));
1096                 } else
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"));
1101         }
1102 }
1103
1104 static void
1105 parity_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
1106 {
1107         const char *setting_name = nm_setting_get_name (setting);
1108         NMSettingSerialParity parity;
1109         int int_val;
1110         gs_free char *str_val = NULL;
1111
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).
1115          */
1116         int_val = nm_keyfile_plugin_kf_get_integer (info->keyfile, setting_name, key, NULL);
1117         if (!int_val) {
1118                 str_val = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
1119                 if (str_val) {
1120                         if (str_val[0] && !str_val[1])
1121                                 int_val = str_val[0];
1122                         else {
1123                                 /* This will hit the warning below */
1124                                 int_val = 'X';
1125                         }
1126                 }
1127         }
1128
1129         if (!int_val)
1130                 return;
1131
1132         switch (int_val) {
1133         case 'E':
1134         case 'e':
1135                 parity = NM_SETTING_SERIAL_PARITY_EVEN;
1136                 break;
1137         case 'O':
1138         case 'o':
1139                 parity = NM_SETTING_SERIAL_PARITY_ODD;
1140                 break;
1141         case 'N':
1142         case 'n':
1143                 parity = NM_SETTING_SERIAL_PARITY_NONE;
1144                 break;
1145         default:
1146                 handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1147                              _("invalid parity value '%s'"),
1148                              str_val ? str_val : "");
1149                 return;
1150         }
1151
1152         g_object_set (setting, key, parity, NULL);
1153 }
1154
1155 typedef struct {
1156         const char *setting_name;
1157         const char *key;
1158         gboolean check_for_key;
1159         void (*parser) (KeyfileReaderInfo *info, NMSetting *setting, const char *key);
1160 } KeyParser;
1161
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.
1167  */
1168 static KeyParser key_parsers[] = {
1169         { NM_SETTING_CONNECTION_SETTING_NAME,
1170           NM_SETTING_CONNECTION_TYPE,
1171           TRUE,
1172           setting_alias_parser },
1173         { NM_SETTING_BRIDGE_SETTING_NAME,
1174           NM_SETTING_BRIDGE_MAC_ADDRESS,
1175           TRUE,
1176           mac_address_parser_ETHER },
1177         { NM_SETTING_IP4_CONFIG_SETTING_NAME,
1178           NM_SETTING_IP_CONFIG_ADDRESSES,
1179           FALSE,
1180           ip_address_or_route_parser },
1181         { NM_SETTING_IP6_CONFIG_SETTING_NAME,
1182           NM_SETTING_IP_CONFIG_ADDRESSES,
1183           FALSE,
1184           ip_address_or_route_parser },
1185         { NM_SETTING_IP4_CONFIG_SETTING_NAME,
1186           NM_SETTING_IP_CONFIG_ROUTES,
1187           FALSE,
1188           ip_address_or_route_parser },
1189         { NM_SETTING_IP6_CONFIG_SETTING_NAME,
1190           NM_SETTING_IP_CONFIG_ROUTES,
1191           FALSE,
1192           ip_address_or_route_parser },
1193         { NM_SETTING_IP4_CONFIG_SETTING_NAME,
1194           NM_SETTING_IP_CONFIG_DNS,
1195           FALSE,
1196           ip4_dns_parser },
1197         { NM_SETTING_IP6_CONFIG_SETTING_NAME,
1198           NM_SETTING_IP_CONFIG_DNS,
1199           FALSE,
1200           ip6_dns_parser },
1201         { NM_SETTING_IP6_CONFIG_SETTING_NAME,
1202           NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
1203           FALSE,
1204           ip6_addr_gen_mode_parser },
1205         { NM_SETTING_WIRED_SETTING_NAME,
1206           NM_SETTING_WIRED_MAC_ADDRESS,
1207           TRUE,
1208           mac_address_parser_ETHER },
1209         { NM_SETTING_WIRED_SETTING_NAME,
1210           NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
1211           TRUE,
1212           mac_address_parser_ETHER },
1213         { NM_SETTING_WIRELESS_SETTING_NAME,
1214           NM_SETTING_WIRELESS_MAC_ADDRESS,
1215           TRUE,
1216           mac_address_parser_ETHER },
1217         { NM_SETTING_WIRELESS_SETTING_NAME,
1218           NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
1219           TRUE,
1220           mac_address_parser_ETHER },
1221         { NM_SETTING_WIRELESS_SETTING_NAME,
1222           NM_SETTING_WIRELESS_BSSID,
1223           TRUE,
1224           mac_address_parser_ETHER },
1225         { NM_SETTING_BLUETOOTH_SETTING_NAME,
1226           NM_SETTING_BLUETOOTH_BDADDR,
1227           TRUE,
1228           mac_address_parser_ETHER },
1229         { NM_SETTING_INFINIBAND_SETTING_NAME,
1230           NM_SETTING_INFINIBAND_MAC_ADDRESS,
1231           TRUE,
1232           mac_address_parser_INFINIBAND },
1233         { NM_SETTING_WIMAX_SETTING_NAME,
1234           NM_SETTING_WIMAX_MAC_ADDRESS,
1235           TRUE,
1236           mac_address_parser_ETHER },
1237         { NM_SETTING_WIRELESS_SETTING_NAME,
1238           NM_SETTING_WIRELESS_SSID,
1239           TRUE,
1240           ssid_parser },
1241         { NM_SETTING_802_1X_SETTING_NAME,
1242           NM_SETTING_802_1X_PASSWORD_RAW,
1243           TRUE,
1244           password_raw_parser },
1245         { NM_SETTING_802_1X_SETTING_NAME,
1246           NM_SETTING_802_1X_CA_CERT,
1247           TRUE,
1248           cert_parser },
1249         { NM_SETTING_802_1X_SETTING_NAME,
1250           NM_SETTING_802_1X_CLIENT_CERT,
1251           TRUE,
1252           cert_parser },
1253         { NM_SETTING_802_1X_SETTING_NAME,
1254           NM_SETTING_802_1X_PRIVATE_KEY,
1255           TRUE,
1256           cert_parser },
1257         { NM_SETTING_802_1X_SETTING_NAME,
1258           NM_SETTING_802_1X_PHASE2_CA_CERT,
1259           TRUE,
1260           cert_parser },
1261         { NM_SETTING_802_1X_SETTING_NAME,
1262           NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
1263           TRUE,
1264           cert_parser },
1265         { NM_SETTING_802_1X_SETTING_NAME,
1266           NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
1267           TRUE,
1268           cert_parser },
1269         { NM_SETTING_SERIAL_SETTING_NAME,
1270           NM_SETTING_SERIAL_PARITY,
1271           TRUE,
1272           parity_parser },
1273         { NULL, NULL, FALSE }
1274 };
1275
1276 static void
1277 set_default_for_missing_key (NMSetting *setting, const char *property)
1278 {
1279         /* Set a value different from the default value of the property's spec */
1280
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);
1284         }
1285 }
1286
1287 static void
1288 read_one_setting_value (NMSetting *setting,
1289                         const char *key,
1290                         const GValue *value,
1291                         GParamFlags flags,
1292                         gpointer user_data)
1293 {
1294         KeyfileReaderInfo *info = user_data;
1295         GKeyFile *keyfile = info->keyfile;
1296         const char *setting_name;
1297         int errsv;
1298         GType type;
1299         gs_free_error GError *err = NULL;
1300         gboolean check_for_key = TRUE;
1301         KeyParser *parser = &key_parsers[0];
1302
1303         if (info->error)
1304                 return;
1305
1306         /* Property is not writable */
1307         if (!(flags & G_PARAM_WRITABLE))
1308                 return;
1309
1310         /* Setting name gets picked up from the keyfile's section name instead */
1311         if (!strcmp (key, NM_SETTING_NAME))
1312                 return;
1313
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))
1317                 return;
1318
1319         setting_name = nm_setting_get_name (setting);
1320
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;
1325                         break;
1326                 }
1327                 parser++;
1328         }
1329
1330         /* VPN properties don't have the exact key name */
1331         if (NM_IS_SETTING_VPN (setting))
1332                 check_for_key = FALSE;
1333
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;
1337
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.
1342          */
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. */
1345                 if (err) {
1346                         if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1347                                           _("error loading setting value: %s"),
1348                                           err->message))
1349                                 goto out_error;
1350                 }
1351
1352                 /* Allow default values different than in property spec */
1353                 set_default_for_missing_key (setting, key);
1354                 return;
1355         }
1356
1357         /* If there's a custom parser for this key, handle that before the generic
1358          * parsers below.
1359          */
1360         if (parser->setting_name) {
1361                 (*parser->parser) (info, setting, key);
1362                 return;
1363         }
1364
1365         type = G_VALUE_TYPE (value);
1366
1367         if (type == G_TYPE_STRING) {
1368                 char *str_val;
1369
1370                 str_val = nm_keyfile_plugin_kf_get_string (keyfile, setting_name, key, NULL);
1371                 g_object_set (setting, key, str_val, NULL);
1372                 g_free (str_val);
1373         } else if (type == G_TYPE_UINT) {
1374                 int int_val;
1375
1376                 int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
1377                 if (int_val < 0) {
1378                         if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1379                                           _("invalid negative value (%i)"),
1380                                           int_val))
1381                                 goto out_error;
1382                 }
1383                 g_object_set (setting, key, int_val, NULL);
1384         } else if (type == G_TYPE_INT) {
1385                 int int_val;
1386
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) {
1390                 gboolean bool_val;
1391
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) {
1395                 int int_val;
1396
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)"),
1401                                           int_val))
1402                                 goto out_error;
1403                 }
1404
1405                 g_object_set (setting, key, int_val, NULL);
1406         } else if (type == G_TYPE_UINT64) {
1407                 char *tmp_str;
1408                 guint64 uint_val;
1409
1410                 tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, NULL);
1411                 uint_val = g_ascii_strtoull (tmp_str, NULL, 10);
1412                 g_free (tmp_str);
1413                 g_object_set (setting, key, uint_val, NULL);
1414         } else if (type == G_TYPE_INT64) {
1415                 gs_free char *tmp_str = NULL;
1416                 gint64 int_val;
1417
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);
1420                 errsv = errno;
1421                 if (errsv) {
1422                         if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1423                                           _("invalid int64 value (%s)"),
1424                                           tmp_str))
1425                                 goto out_error;
1426                 } else
1427                         g_object_set (setting, key, int_val, NULL);
1428         } else if (type == G_TYPE_BYTES) {
1429                 gint *tmp;
1430                 GByteArray *array;
1431                 GBytes *bytes;
1432                 gsize length;
1433                 int i;
1434                 gboolean already_warned = FALSE;
1435
1436                 tmp = nm_keyfile_plugin_kf_get_integer_list (keyfile, setting_name, key, &length, NULL);
1437
1438                 array = g_byte_array_sized_new (length);
1439                 for (i = 0; i < length; i++) {
1440                         int val = tmp[i];
1441                         unsigned char v = (unsigned char) (val & 0xFF);
1442
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)"),
1447                                                      val)) {
1448                                         g_byte_array_unref (array);
1449                                         g_free (tmp);
1450                                         goto out_error;
1451                                 }
1452                                 already_warned = TRUE;
1453                         } else
1454                                 g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
1455                 }
1456
1457                 bytes = g_byte_array_free_to_bytes (array);
1458                 g_object_set (setting, key, bytes, NULL);
1459                 g_bytes_unref (bytes);
1460                 g_free (tmp);
1461         } else if (type == G_TYPE_STRV) {
1462                 gchar **sa;
1463                 gsize length;
1464
1465                 sa = nm_keyfile_plugin_kf_get_string_list (keyfile, setting_name, key, &length, NULL);
1466                 g_object_set (setting, key, sa, NULL);
1467                 g_strfreev (sa);
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)) {
1473                 guint64 uint_val;
1474
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);
1477                 if (!err) {
1478                         if (uint_val <= G_MAXUINT)
1479                                 g_object_set (setting, key, (guint) uint_val, NULL);
1480                         else {
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))
1484                                         goto out_error;
1485                         }
1486                 }
1487         } else if (G_VALUE_HOLDS_ENUM (value)) {
1488                 gint int_val;
1489
1490                 int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, &err);
1491                 if (!err)
1492                         g_object_set (setting, key, (gint) int_val, NULL);
1493         } else {
1494                 if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
1495                                  _("unhandled setting property type '%s'"),
1496                                  G_VALUE_TYPE_NAME (value)))
1497                         goto out_error;
1498         }
1499 out_error:
1500         return;
1501 }
1502
1503 static NMSetting *
1504 read_setting (KeyfileReaderInfo *info)
1505 {
1506         const char *alias;
1507         GType type;
1508
1509         alias = nm_keyfile_plugin_get_setting_name_for_alias (info->group);
1510         if (!alias)
1511                 alias = info->group;
1512
1513         type = nm_setting_lookup_type (alias);
1514         if (type) {
1515                 NMSetting *setting = g_object_new (type, NULL);
1516
1517                 info->setting = setting;
1518                 nm_setting_enumerate_values (setting, read_one_setting_value, info);
1519                 info->setting = NULL;
1520                 if (!info->error)
1521                         return setting;
1522
1523                 g_object_unref (setting);
1524         } else {
1525                 handle_warn (info, NULL, NM_KEYFILE_WARN_SEVERITY_WARN,
1526                              _("invalid setting name '%s'"), info->group);
1527         }
1528
1529         return NULL;
1530 }
1531
1532 static void
1533 read_vpn_secrets (KeyfileReaderInfo *info, NMSettingVpn *s_vpn)
1534 {
1535         char **keys, **iter;
1536
1537         keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, NULL, NULL);
1538         for (iter = keys; *iter; iter++) {
1539                 char *secret;
1540
1541                 secret = nm_keyfile_plugin_kf_get_string (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, *iter, NULL);
1542                 if (secret) {
1543                         nm_setting_vpn_add_secret (s_vpn, *iter, secret);
1544                         g_free (secret);
1545                 }
1546         }
1547         g_strfreev (keys);
1548 }
1549
1550 /**
1551  * nm_keyfile_read:
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
1566  * @error: error
1567  *
1568  * Tries to create a NMConnection from a keyfile. The resulting keyfile is
1569  * not normalized and might not even verify.
1570  *
1571  * Returns: (transfer full): on success, returns the created connection.
1572  */
1573 NMConnection *
1574 nm_keyfile_read (GKeyFile *keyfile,
1575                  const char *keyfile_name,
1576                  const char *base_dir,
1577                  NMKeyfileReadHandler handler,
1578                  void *user_data,
1579                  GError **error)
1580 {
1581         NMConnection *connection = NULL;
1582         NMSettingConnection *s_con;
1583         NMSetting *setting;
1584         gchar **groups;
1585         gsize length;
1586         int i;
1587         gboolean vpn_secrets = FALSE;
1588         KeyfileReaderInfo info = { 0 };
1589         gs_free char *base_dir_free = NULL;
1590
1591         g_return_val_if_fail (keyfile, NULL);
1592         g_return_val_if_fail (!error || !*error, NULL);
1593
1594         if (!base_dir) {
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);
1598                 } else {
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 ();
1602                 }
1603         } else
1604                 g_return_val_if_fail ("/", NULL);
1605
1606         connection = nm_simple_connection_new ();
1607
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;
1613
1614         groups = g_key_file_get_groups (keyfile, &length);
1615         if (!groups)
1616                 length = 0;
1617         for (i = 0; i < length; i++) {
1618                 /* Only read out secrets when needed */
1619                 if (!strcmp (groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) {
1620                         vpn_secrets = TRUE;
1621                         continue;
1622                 }
1623
1624                 info.group = groups[i];
1625                 setting = read_setting (&info);
1626                 info.group = NULL;
1627                 if (info.error)
1628                         goto out_error;
1629                 if (setting)
1630                         nm_connection_add_setting (connection, setting);
1631         }
1632         g_strfreev (groups);
1633
1634         s_con = nm_connection_get_setting_connection (connection);
1635         if (!s_con) {
1636                 s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
1637                 nm_connection_add_setting (connection, NM_SETTING (s_con));
1638         }
1639
1640         /* Make sure that we have 'id' even if not explictly specified in the keyfile */
1641         if (   keyfile_name
1642             && !nm_setting_connection_get_id (s_con)) {
1643                 char *base_name;
1644
1645                 base_name = g_path_get_basename (keyfile_name);
1646                 g_object_set (s_con, NM_SETTING_CONNECTION_ID, base_name, NULL);
1647                 g_free (base_name);
1648         }
1649
1650         /* Make sure that we have 'uuid' even if not explictly specified in the keyfile */
1651         if (   keyfile_name
1652             && !nm_setting_connection_get_uuid (s_con)) {
1653                 char *hashed_uuid;
1654
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);
1658         }
1659
1660         /* Make sure that we have 'interface-name' even if it was specified in the
1661          * "wrong" (ie, deprecated) group.
1662          */
1663         if (   !nm_setting_connection_get_interface_name (s_con)
1664             && nm_setting_connection_get_connection_type (s_con)) {
1665                 char *interface_name;
1666
1667                 interface_name = g_key_file_get_string (keyfile,
1668                                                         nm_setting_connection_get_connection_type (s_con),
1669                                                         "interface-name",
1670                                                         NULL);
1671                 if (interface_name) {
1672                         g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL);
1673                         g_free (interface_name);
1674                 }
1675         }
1676
1677         /* Handle vpn secrets after the 'vpn' setting was read */
1678         if (vpn_secrets) {
1679                 NMSettingVpn *s_vpn;
1680
1681                 s_vpn = nm_connection_get_setting_vpn (connection);
1682                 if (s_vpn) {
1683                         read_vpn_secrets (&info, s_vpn);
1684                         if (info.error)
1685                                 goto out_error;
1686                 }
1687         }
1688
1689         return connection;
1690 out_error:
1691         g_propagate_error (error, info.error);
1692         g_free (connection);
1693         return NULL;
1694 }