shared: move _nm_utils_ascii_str_to_int64() to "shared/nm-shared-utils.h"
[NetworkManager.git] / libnm-core / nm-utils.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3 /*
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301 USA.
18  *
19  * Copyright 2005 - 2014 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include "nm-utils.h"
25
26 #include <string.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <netinet/ether.h>
30 #include <arpa/inet.h>
31 #include <uuid/uuid.h>
32 #include <libintl.h>
33 #include <gmodule.h>
34 #include <sys/stat.h>
35
36 #include "nm-utils-private.h"
37 #include "nm-setting-private.h"
38 #include "crypto.h"
39 #include "nm-setting-bond.h"
40 #include "nm-setting-bridge.h"
41 #include "nm-setting-infiniband.h"
42 #include "nm-setting-ip6-config.h"
43 #include "nm-setting-team.h"
44 #include "nm-setting-vlan.h"
45 #include "nm-setting-wired.h"
46 #include "nm-setting-wireless.h"
47
48 /* Embed the commit id in the build binary */
49 static const char *const __nm_git_sha = NM_STRLEN (NM_GIT_SHA) > 0 ? "NM_GIT_SHA:"NM_GIT_SHA : "";
50
51 /**
52  * SECTION:nm-utils
53  * @short_description: Utility functions
54  *
55  * A collection of utility functions for working with SSIDs, IP addresses, Wi-Fi
56  * access points and devices, among other things.
57  */
58
59 struct EncodingTriplet
60 {
61         const char *encoding1;
62         const char *encoding2;
63         const char *encoding3;
64 };
65
66 struct IsoLangToEncodings
67 {
68         const char *    lang;
69         struct EncodingTriplet encodings;
70 };
71
72 /* 5-letter language codes */
73 static const struct IsoLangToEncodings isoLangEntries5[] =
74 {
75         /* Simplified Chinese */
76         { "zh_cn",      {"euc-cn",      "gb2312",                       "gb18030"} },   /* PRC */
77         { "zh_sg",      {"euc-cn",      "gb2312",                       "gb18030"} },   /* Singapore */
78
79         /* Traditional Chinese */
80         { "zh_tw",      {"big5",                "euc-tw",                       NULL} },                /* Taiwan */
81         { "zh_hk",      {"big5",                "euc-tw",                       "big5-hkcs"} },/* Hong Kong */
82         { "zh_mo",      {"big5",                "euc-tw",                       NULL} },                /* Macau */
83
84         /* Table end */
85         { NULL, {NULL, NULL, NULL} }
86 };
87
88 /* 2-letter language codes; we don't care about the other 3 in this table */
89 static const struct IsoLangToEncodings isoLangEntries2[] =
90 {
91         /* Japanese */
92         { "ja",         {"euc-jp",      "shift_jis",            "iso-2022-jp"} },
93
94         /* Korean */
95         { "ko",         {"euc-kr",      "iso-2022-kr",          "johab"} },
96
97         /* Thai */
98         { "th",         {"iso-8859-11","windows-874",           NULL} },
99
100         /* Central European */
101         { "hu",         {"iso-8859-2",  "windows-1250", NULL} },        /* Hungarian */
102         { "cs",         {"iso-8859-2",  "windows-1250", NULL} },        /* Czech */
103         { "hr",         {"iso-8859-2",  "windows-1250", NULL} },        /* Croatian */
104         { "pl",         {"iso-8859-2",  "windows-1250", NULL} },        /* Polish */
105         { "ro",         {"iso-8859-2",  "windows-1250", NULL} },        /* Romanian */
106         { "sk",         {"iso-8859-2",  "windows-1250", NULL} },        /* Slovakian */
107         { "sl",         {"iso-8859-2",  "windows-1250", NULL} },        /* Slovenian */
108         { "sh",         {"iso-8859-2",  "windows-1250", NULL} },        /* Serbo-Croatian */
109
110         /* Cyrillic */
111         { "ru",         {"koi8-r",      "windows-1251", "iso-8859-5"} },        /* Russian */
112         { "be",         {"koi8-r",      "windows-1251", "iso-8859-5"} },        /* Belorussian */
113         { "bg",         {"windows-1251","koi8-r",               "iso-8859-5"} },        /* Bulgarian */
114         { "mk",         {"koi8-r",      "windows-1251", "iso-8859-5"} },        /* Macedonian */
115         { "sr",         {"koi8-r",      "windows-1251", "iso-8859-5"} },        /* Serbian */
116         { "uk",         {"koi8-u",      "koi8-r",                       "windows-1251"} },      /* Ukranian */
117
118         /* Arabic */
119         { "ar",         {"iso-8859-6",  "windows-1256", NULL} },
120
121         /* Baltic */
122         { "et",         {"iso-8859-4",  "windows-1257", NULL} },        /* Estonian */
123         { "lt",         {"iso-8859-4",  "windows-1257", NULL} },        /* Lithuanian */
124         { "lv",         {"iso-8859-4",  "windows-1257", NULL} },        /* Latvian */
125
126         /* Greek */
127         { "el",         {"iso-8859-7",  "windows-1253", NULL} },
128
129         /* Hebrew */
130         { "he",         {"iso-8859-8",  "windows-1255", NULL} },
131         { "iw",         {"iso-8859-8",  "windows-1255", NULL} },
132
133         /* Turkish */
134         { "tr",         {"iso-8859-9",  "windows-1254", NULL} },
135
136         /* Table end */
137         { NULL, {NULL, NULL, NULL} }
138 };
139
140
141 static GHashTable * langToEncodings5 = NULL;
142 static GHashTable * langToEncodings2 = NULL;
143
144 static void
145 init_lang_to_encodings_hash (void)
146 {
147         struct IsoLangToEncodings *enc;
148
149         if (G_UNLIKELY (langToEncodings5 == NULL)) {
150                 /* Five-letter codes */
151                 enc = (struct IsoLangToEncodings *) &isoLangEntries5[0];
152                 langToEncodings5 = g_hash_table_new (g_str_hash, g_str_equal);
153                 while (enc->lang) {
154                         g_hash_table_insert (langToEncodings5, (gpointer) enc->lang,
155                                              (gpointer) &enc->encodings);
156                         enc++;
157                 }
158         }
159
160         if (G_UNLIKELY (langToEncodings2 == NULL)) {
161                 /* Two-letter codes */
162                 enc = (struct IsoLangToEncodings *) &isoLangEntries2[0];
163                 langToEncodings2 = g_hash_table_new (g_str_hash, g_str_equal);
164                 while (enc->lang) {
165                         g_hash_table_insert (langToEncodings2, (gpointer) enc->lang,
166                                              (gpointer) &enc->encodings);
167                         enc++;
168                 }
169         }
170 }
171
172
173 static gboolean
174 get_encodings_for_lang (const char *lang,
175                         char **encoding1,
176                         char **encoding2,
177                         char **encoding3)
178 {
179         struct EncodingTriplet *        encodings;
180         gboolean                                success = FALSE;
181         char *                          tmp_lang;
182
183         g_return_val_if_fail (lang != NULL, FALSE);
184         g_return_val_if_fail (encoding1 != NULL, FALSE);
185         g_return_val_if_fail (encoding2 != NULL, FALSE);
186         g_return_val_if_fail (encoding3 != NULL, FALSE);
187
188         *encoding1 = "iso-8859-1";
189         *encoding2 = "windows-1251";
190         *encoding3 = NULL;
191
192         init_lang_to_encodings_hash ();
193
194         tmp_lang = g_strdup (lang);
195         if ((encodings = g_hash_table_lookup (langToEncodings5, tmp_lang))) {
196                 *encoding1 = (char *) encodings->encoding1;
197                 *encoding2 = (char *) encodings->encoding2;
198                 *encoding3 = (char *) encodings->encoding3;
199                 success = TRUE;
200         }
201
202         /* Truncate tmp_lang to length of 2 */
203         if (strlen (tmp_lang) > 2)
204                 tmp_lang[2] = '\0';
205         if (!success && (encodings = g_hash_table_lookup (langToEncodings2, tmp_lang))) {
206                 *encoding1 = (char *) encodings->encoding1;
207                 *encoding2 = (char *) encodings->encoding2;
208                 *encoding3 = (char *) encodings->encoding3;
209                 success = TRUE;
210         }
211
212         g_free (tmp_lang);
213         return success;
214 }
215
216 /* init libnm */
217
218 static gboolean initialized = FALSE;
219
220 static void __attribute__((constructor))
221 _nm_utils_init (void)
222 {
223         GModule *self;
224         gpointer func;
225
226         (void) __nm_git_sha;
227
228         if (initialized)
229                 return;
230         initialized = TRUE;
231
232         self = g_module_open (NULL, 0);
233         if (g_module_symbol (self, "nm_util_get_private", &func))
234                 g_error ("libnm-util symbols detected; Mixing libnm with libnm-util/libnm-glib is not supported");
235         g_module_close (self);
236
237         bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
238         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
239
240         nm_g_type_init ();
241
242         _nm_dbus_errors_init ();
243 }
244
245 gboolean _nm_utils_is_manager_process;
246
247 /* ssid helpers */
248
249 /**
250  * nm_utils_ssid_to_utf8:
251  * @ssid: (array length=len): pointer to a buffer containing the SSID data
252  * @len: length of the SSID data in @ssid
253  *
254  * Wi-Fi SSIDs are byte arrays, they are _not_ strings.  Thus, an SSID may
255  * contain embedded NULLs and other unprintable characters.  Often it is
256  * useful to print the SSID out for debugging purposes, but that should be the
257  * _only_ use of this function.  Do not use this function for any persistent
258  * storage of the SSID, since the printable SSID returned from this function
259  * cannot be converted back into the real SSID of the access point.
260  *
261  * This function does almost everything humanly possible to convert the input
262  * into a printable UTF-8 string, using roughly the following procedure:
263  *
264  * 1) if the input data is already UTF-8 safe, no conversion is performed
265  * 2) attempts to get the current system language from the LANG environment
266  *    variable, and depending on the language, uses a table of alternative
267  *    encodings to try.  For example, if LANG=hu_HU, the table may first try
268  *    the ISO-8859-2 encoding, and if that fails, try the Windows-1250 encoding.
269  *    If all fallback encodings fail, replaces non-UTF-8 characters with '?'.
270  * 3) If the system language was unable to be determined, falls back to the
271  *    ISO-8859-1 encoding, then to the Windows-1251 encoding.
272  * 4) If step 3 fails, replaces non-UTF-8 characters with '?'.
273  *
274  * Again, this function should be used for debugging and display purposes
275  * _only_.
276  *
277  * Returns: (transfer full): an allocated string containing a UTF-8
278  * representation of the SSID, which must be freed by the caller using g_free().
279  * Returns %NULL on errors.
280  **/
281 char *
282 nm_utils_ssid_to_utf8 (const guint8 *ssid, gsize len)
283 {
284         char *converted = NULL;
285         char *lang, *e1 = NULL, *e2 = NULL, *e3 = NULL;
286
287         g_return_val_if_fail (ssid != NULL, NULL);
288
289         if (g_utf8_validate ((const gchar *) ssid, len, NULL))
290                 return g_strndup ((const gchar *) ssid, len);
291
292         /* LANG may be a good encoding hint */
293         g_get_charset ((const char **)(&e1));
294         if ((lang = getenv ("LANG"))) {
295                 char * dot;
296
297                 lang = g_ascii_strdown (lang, -1);
298                 if ((dot = strchr (lang, '.')))
299                         *dot = '\0';
300
301                 get_encodings_for_lang (lang, &e1, &e2, &e3);
302                 g_free (lang);
303         }
304
305         converted = g_convert ((const gchar *) ssid, len, "UTF-8", e1, NULL, NULL, NULL);
306         if (!converted && e2)
307                 converted = g_convert ((const gchar *) ssid, len, "UTF-8", e2, NULL, NULL, NULL);
308
309         if (!converted && e3)
310                 converted = g_convert ((const gchar *) ssid, len, "UTF-8", e3, NULL, NULL, NULL);
311
312         if (!converted) {
313                 converted = g_convert_with_fallback ((const gchar *) ssid, len,
314                                                      "UTF-8", e1, "?", NULL, NULL, NULL);
315         }
316
317         if (!converted) {
318                 /* If there is still no converted string, the SSID probably
319                  * contains characters not valid in the current locale. Convert
320                  * the string to ASCII instead.
321                  */
322
323                 /* Use the printable range of 0x20-0x7E */
324                 gchar *valid_chars = " !\"#$%&'()*+,-./0123456789:;<=>?@"
325                                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
326                                      "abcdefghijklmnopqrstuvwxyz{|}~";
327
328                 converted = g_strndup ((const gchar *)ssid, len);
329                 g_strcanon (converted, valid_chars, '?');
330         }
331
332         return converted;
333 }
334
335 /* Shamelessly ripped from the Linux kernel ieee80211 stack */
336 /**
337  * nm_utils_is_empty_ssid:
338  * @ssid: (array length=len): pointer to a buffer containing the SSID data
339  * @len: length of the SSID data in @ssid
340  *
341  * Different manufacturers use different mechanisms for not broadcasting the
342  * AP's SSID.  This function attempts to detect blank/empty SSIDs using a
343  * number of known SSID-cloaking methods.
344  *
345  * Returns: %TRUE if the SSID is "empty", %FALSE if it is not
346  **/
347 gboolean
348 nm_utils_is_empty_ssid (const guint8 *ssid, gsize len)
349 {
350         /* Single white space is for Linksys APs */
351         if (len == 1 && ssid[0] == ' ')
352                 return TRUE;
353
354         /* Otherwise, if the entire ssid is 0, we assume it is hidden */
355         while (len--) {
356                 if (ssid[len] != '\0')
357                         return FALSE;
358         }
359         return TRUE;
360 }
361
362 #define ESSID_MAX_SIZE 32
363
364 /**
365  * nm_utils_escape_ssid:
366  * @ssid: (array length=len): pointer to a buffer containing the SSID data
367  * @len: length of the SSID data in @ssid
368  *
369  * This function does a quick printable character conversion of the SSID, simply
370  * replacing embedded NULLs and non-printable characters with the hexadecimal
371  * representation of that character.  Intended for debugging only, should not
372  * be used for display of SSIDs.
373  *
374  * Returns: pointer to the escaped SSID, which uses an internal static buffer
375  * and will be overwritten by subsequent calls to this function
376  **/
377 const char *
378 nm_utils_escape_ssid (const guint8 *ssid, gsize len)
379 {
380         static char escaped[ESSID_MAX_SIZE * 2 + 1];
381         const guint8 *s = ssid;
382         char *d = escaped;
383
384         if (nm_utils_is_empty_ssid (ssid, len)) {
385                 memcpy (escaped, "<hidden>", sizeof ("<hidden>"));
386                 return escaped;
387         }
388
389         len = MIN (len, (guint32) ESSID_MAX_SIZE);
390         while (len--) {
391                 if (*s == '\0') {
392                         *d++ = '\\';
393                         *d++ = '0';
394                         s++;
395                 } else {
396                         *d++ = *s++;
397                 }
398         }
399         *d = '\0';
400         return escaped;
401 }
402
403 /**
404  * nm_utils_same_ssid:
405  * @ssid1: (array length=len1): the first SSID to compare
406  * @len1: length of the SSID data in @ssid1
407  * @ssid2: (array length=len2): the second SSID to compare
408  * @len2: length of the SSID data in @ssid2
409  * @ignore_trailing_null: %TRUE to ignore one trailing NULL byte
410  *
411  * Earlier versions of the Linux kernel added a NULL byte to the end of the
412  * SSID to enable easy printing of the SSID on the console or in a terminal,
413  * but this behavior was problematic (SSIDs are simply byte arrays, not strings)
414  * and thus was changed.  This function compensates for that behavior at the
415  * cost of some compatibility with odd SSIDs that may legitimately have trailing
416  * NULLs, even though that is functionally pointless.
417  *
418  * Returns: %TRUE if the SSIDs are the same, %FALSE if they are not
419  **/
420 gboolean
421 nm_utils_same_ssid (const guint8 *ssid1, gsize len1,
422                     const guint8 *ssid2, gsize len2,
423                     gboolean ignore_trailing_null)
424 {
425         g_return_val_if_fail (ssid1 != NULL || len1 == 0, FALSE);
426         g_return_val_if_fail (ssid2 != NULL || len2 == 0, FALSE);
427
428         if (ssid1 == ssid2 && len1 == len2)
429                 return TRUE;
430         if (!ssid1 || !ssid2)
431                 return FALSE;
432
433         if (ignore_trailing_null) {
434                 if (len1 && ssid1[len1 - 1] == '\0')
435                         len1--;
436                 if (len2 && ssid2[len2 - 1] == '\0')
437                         len2--;
438         }
439
440         if (len1 != len2)
441                 return FALSE;
442
443         return memcmp (ssid1, ssid2, len1) == 0 ? TRUE : FALSE;
444 }
445
446 gboolean
447 _nm_utils_string_in_list (const char *str, const char **valid_strings)
448 {
449         return _nm_utils_strv_find_first ((char **) valid_strings, -1, str) >= 0;
450 }
451
452 /**
453  * _nm_utils_strv_find_first:
454  * @list: the strv list to search
455  * @len: the length of the list, or a negative value if @list is %NULL terminated.
456  * @needle: the value to search for. The search is done using strcmp().
457  *
458  * Searches @list for @needle and returns the index of the first match (based
459  * on strcmp()).
460  *
461  * For convenience, @list has type 'char**' instead of 'const char **'.
462  *
463  * Returns: index of first occurrence or -1 if @needle is not found in @list.
464  */
465 gssize
466 _nm_utils_strv_find_first (char **list, gssize len, const char *needle)
467 {
468         gssize i;
469
470         if (len > 0) {
471                 g_return_val_if_fail (list, -1);
472
473                 if (!needle) {
474                         /* if we search a list with known length, %NULL is a valid @needle. */
475                         for (i = 0; i < len; i++) {
476                                 if (!list[i])
477                                         return i;
478                         }
479                 } else {
480                         for (i = 0; i < len; i++) {
481                                 if (list[i] && !strcmp (needle, list[i]))
482                                         return i;
483                         }
484                 }
485         } else if (len < 0) {
486                 g_return_val_if_fail (needle, -1);
487
488                 if (list) {
489                         for (i = 0; list[i]; i++) {
490                                 if (strcmp (needle, list[i]) == 0)
491                                         return i;
492                         }
493                 }
494         }
495         return -1;
496 }
497
498 char **
499 _nm_utils_strv_cleanup (char **strv,
500                         gboolean strip_whitespace,
501                         gboolean skip_empty,
502                         gboolean skip_repeated)
503 {
504         guint i, j;
505
506         if (!strv || !*strv)
507                 return strv;
508
509         if (strip_whitespace) {
510                 for (i = 0; strv[i]; i++)
511                         g_strstrip (strv[i]);
512         }
513         if (!skip_empty && !skip_repeated)
514                 return strv;
515         j = 0;
516         for (i = 0; strv[i]; i++) {
517                 if (   (skip_empty && !*strv[i])
518                     || (skip_repeated && _nm_utils_strv_find_first (strv, j, strv[i]) >= 0))
519                         g_free (strv[i]);
520                 else
521                         strv[j++] = strv[i];
522         }
523         strv[j] = NULL;
524         return strv;
525 }
526
527
528 gboolean
529 _nm_utils_string_slist_validate (GSList *list, const char **valid_values)
530 {
531         GSList *iter;
532
533         for (iter = list; iter; iter = iter->next) {
534                 if (!_nm_utils_string_in_list ((char *) iter->data, valid_values))
535                         return FALSE;
536         }
537
538         return TRUE;
539 }
540
541 /**
542  * _nm_utils_hash_values_to_slist:
543  * @hash: a #GHashTable
544  *
545  * Utility function to iterate over a hash table and return
546  * it's values as a #GSList.
547  *
548  * Returns: (element-type gpointer) (transfer container): a newly allocated #GSList
549  * containing the values of the hash table. The caller must free the
550  * returned list with g_slist_free(). The hash values are not owned
551  * by the returned list.
552  **/
553 GSList *
554 _nm_utils_hash_values_to_slist (GHashTable *hash)
555 {
556         GSList *list = NULL;
557         GHashTableIter iter;
558         void *value;
559
560         g_return_val_if_fail (hash, NULL);
561
562         g_hash_table_iter_init (&iter, hash);
563         while (g_hash_table_iter_next (&iter, NULL, &value))
564                  list = g_slist_prepend (list, value);
565
566         return list;
567 }
568
569 GVariant *
570 _nm_utils_strdict_to_dbus (const GValue *prop_value)
571 {
572         GHashTable *hash;
573         GHashTableIter iter;
574         gpointer key, value;
575         GVariantBuilder builder;
576
577         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
578         hash = g_value_get_boxed (prop_value);
579         if (hash) {
580                 g_hash_table_iter_init (&iter, hash);
581                 while (g_hash_table_iter_next (&iter, &key, &value))
582                         g_variant_builder_add (&builder, "{ss}", key, value);
583         }
584
585         return g_variant_builder_end (&builder);
586 }
587
588 void
589 _nm_utils_strdict_from_dbus (GVariant *dbus_value,
590                              GValue *prop_value)
591 {
592         GVariantIter iter;
593         const char *key, *value;
594         GHashTable *hash;
595
596         hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
597         g_variant_iter_init (&iter, dbus_value);
598         while (g_variant_iter_next (&iter, "{&s&s}", &key, &value))
599                 g_hash_table_insert (hash, g_strdup (key), g_strdup (value));
600
601         g_value_take_boxed (prop_value, hash);
602 }
603
604 GHashTable *
605 _nm_utils_copy_strdict (GHashTable *strdict)
606 {
607         GHashTable *copy;
608         GHashTableIter iter;
609         gpointer key, value;
610
611         copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
612         if (strdict) {
613                 g_hash_table_iter_init (&iter, strdict);
614                 while (g_hash_table_iter_next (&iter, &key, &value))
615                         g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
616         }
617         return copy;
618 }
619
620 GPtrArray *
621 _nm_utils_copy_slist_to_array (const GSList *list,
622                                NMUtilsCopyFunc copy_func,
623                                GDestroyNotify unref_func)
624 {
625         const GSList *iter;
626         GPtrArray *array;
627
628         array = g_ptr_array_new_with_free_func (unref_func);
629         for (iter = list; iter; iter = iter->next)
630                 g_ptr_array_add (array, copy_func ? copy_func (iter->data) : iter->data);
631         return array;
632 }
633
634 GSList *
635 _nm_utils_copy_array_to_slist (const GPtrArray *array,
636                                NMUtilsCopyFunc copy_func)
637 {
638         GSList *slist = NULL;
639         gpointer item;
640         int i;
641
642         if (!array)
643                 return NULL;
644
645         for (i = 0; i < array->len; i++) {
646                 item = array->pdata[i];
647                 slist = g_slist_prepend (slist, copy_func (item));
648         }
649
650         return g_slist_reverse (slist);
651 }
652
653 GPtrArray *
654 _nm_utils_copy_array (const GPtrArray *array,
655                       NMUtilsCopyFunc copy_func,
656                       GDestroyNotify free_func)
657 {
658         GPtrArray *copy;
659         int i;
660
661         if (!array)
662                 return g_ptr_array_new_with_free_func (free_func);
663
664         copy = g_ptr_array_new_full (array->len, free_func);
665         for (i = 0; i < array->len; i++)
666                 g_ptr_array_add (copy, copy_func (array->pdata[i]));
667         return copy;
668 }
669
670 GPtrArray *
671 _nm_utils_copy_object_array (const GPtrArray *array)
672 {
673         return _nm_utils_copy_array (array, g_object_ref, g_object_unref);
674 }
675
676 /* have @list of type 'gpointer *' instead of 'gconstpointer *' to
677  * reduce the necessity for annoying const-casts. */
678 gssize
679 _nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle)
680 {
681         gssize i;
682
683         if (len == 0)
684                 return -1;
685
686         if (len > 0) {
687                 g_return_val_if_fail (list, -1);
688                 for (i = 0; i < len; i++) {
689                         if (list[i] == needle)
690                                 return i;
691                 }
692         } else {
693                 g_return_val_if_fail (needle, -1);
694                 for (i = 0; list && list[i]; i++) {
695                         if (list[i] == needle)
696                                 return i;
697                 }
698         }
699         return -1;
700 }
701
702 gssize
703 _nm_utils_ptrarray_find_binary_search (gpointer *list, gsize len, gpointer needle, GCompareDataFunc cmpfcn, gpointer user_data)
704 {
705         gssize imin, imax, imid;
706         int cmp;
707
708         g_return_val_if_fail (list || !len, ~((gssize) 0));
709         g_return_val_if_fail (cmpfcn, ~((gssize) 0));
710
711         imin = 0;
712         if (len == 0)
713                 return ~imin;
714
715         imax = len - 1;
716
717         while (imin <= imax) {
718                 imid = imin + (imax - imin) / 2;
719
720                 cmp = cmpfcn (list[imid], needle, user_data);
721                 if (cmp == 0)
722                         return imid;
723
724                 if (cmp < 0)
725                         imin = imid + 1;
726                 else
727                         imax = imid - 1;
728         }
729
730         /* return the inverse of @imin. This is a negative number, but
731          * also is ~imin the position where the value should be inserted. */
732         return ~imin;
733 }
734
735 GVariant *
736 _nm_utils_bytes_to_dbus (const GValue *prop_value)
737 {
738         GBytes *bytes = g_value_get_boxed (prop_value);
739
740         if (bytes) {
741                 return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
742                                                   g_bytes_get_data (bytes, NULL),
743                                                   g_bytes_get_size (bytes),
744                                                   1);
745         } else {
746                 return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
747                                                   NULL, 0,
748                                                   1);
749         }
750 }
751
752 void
753 _nm_utils_bytes_from_dbus (GVariant *dbus_value,
754                            GValue *prop_value)
755 {
756         GBytes *bytes;
757
758         if (g_variant_n_children (dbus_value)) {
759                 gconstpointer data;
760                 gsize length;
761
762                 data = g_variant_get_fixed_array (dbus_value, &length, 1);
763                 bytes = g_bytes_new (data, length);
764         } else
765                 bytes = NULL;
766         g_value_take_boxed (prop_value, bytes);
767 }
768
769 GSList *
770 _nm_utils_strv_to_slist (char **strv, gboolean deep_copy)
771 {
772         int i;
773         GSList *list = NULL;
774
775         if (strv) {
776                 if (deep_copy) {
777                         for (i = 0; strv[i]; i++)
778                                 list = g_slist_prepend (list, g_strdup (strv[i]));
779                 } else {
780                         for (i = 0; strv[i]; i++)
781                                 list = g_slist_prepend (list, strv[i]);
782                 }
783         }
784
785         return g_slist_reverse (list);
786 }
787
788 char **
789 _nm_utils_slist_to_strv (GSList *slist, gboolean deep_copy)
790 {
791         GSList *iter;
792         char **strv;
793         int len, i;
794
795         len = g_slist_length (slist);
796         strv = g_new (char *, len + 1);
797
798         if (deep_copy) {
799                 for (i = 0, iter = slist; iter; iter = iter->next, i++)
800                         strv[i] = g_strdup (iter->data);
801         } else {
802                 for (i = 0, iter = slist; iter; iter = iter->next, i++)
803                         strv[i] = iter->data;
804         }
805         strv[i] = NULL;
806
807         return strv;
808 }
809
810 GPtrArray *
811 _nm_utils_strv_to_ptrarray (char **strv)
812 {
813         GPtrArray *ptrarray;
814         int i;
815
816         ptrarray = g_ptr_array_new_with_free_func (g_free);
817
818         if (strv) {
819                 for (i = 0; strv[i]; i++)
820                         g_ptr_array_add (ptrarray, g_strdup (strv[i]));
821         }
822
823         return ptrarray;
824 }
825
826 char **
827 _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray)
828 {
829         char **strv;
830         int i;
831
832         if (!ptrarray)
833                 return g_new0 (char *, 1);
834
835         strv = g_new (char *, ptrarray->len + 1);
836
837         for (i = 0; i < ptrarray->len; i++)
838                 strv[i] = g_strdup (ptrarray->pdata[i]);
839         strv[i] = NULL;
840
841         return strv;
842 }
843
844 /**
845  * _nm_utils_strv_equal:
846  * @strv1: a string array
847  * @strv2: a string array
848  *
849  * Compare NULL-terminated string arrays for equality.
850  *
851  * Returns: %TRUE if the arrays are equal, %FALSE otherwise.
852  **/
853 gboolean
854 _nm_utils_strv_equal (char **strv1, char **strv2)
855 {
856         if (strv1 == strv2)
857                 return TRUE;
858
859         if (!strv1 || !strv2)
860                 return FALSE;
861
862         for ( ; *strv1 && *strv2 && !strcmp (*strv1, *strv2); strv1++, strv2++)
863                 ;
864
865         return !*strv1 && !*strv2;
866 }
867
868 /**
869  * _nm_utils_strsplit_set:
870  * @str: string to split
871  * @delimiters: string of delimiter characters
872  * @max_tokens: the maximum number of tokens to split string into. When it is
873  * less than 1, the @str is split completely.
874  *
875  * Utility function for splitting string into a string array. It is a wrapper
876  * for g_strsplit_set(), but it also removes empty strings from the vector as
877  * they are not useful in most cases.
878  *
879  * Returns: (transfer full): a newly allocated NULL-terminated array of strings.
880  * The caller must free the returned array with g_strfreev().
881  **/
882 char **
883 _nm_utils_strsplit_set (const char *str, const char *delimiters, int max_tokens)
884 {
885         char **result;
886         uint i;
887         uint j;
888
889         result = g_strsplit_set (str, delimiters, max_tokens);
890
891         /* remove empty strings */
892         for (i = 0; result && result[i]; i++) {
893                 if (*result[i] == '\0') {
894                         g_free (result[i]);
895                         for (j = i; result[j]; j++)
896                                 result[j] = result[j + 1];
897                         i--;
898                 }
899         }
900         return result;
901 }
902
903 static gboolean
904 device_supports_ap_ciphers (guint32 dev_caps,
905                             guint32 ap_flags,
906                             gboolean static_wep)
907 {
908         gboolean have_pair = FALSE;
909         gboolean have_group = FALSE;
910         /* Device needs to support at least one pairwise and one group cipher */
911
912         /* Pairwise */
913         if (static_wep) {
914                 /* Static WEP only uses group ciphers */
915                 have_pair = TRUE;
916         } else {
917                 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
918                         if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP40)
919                                 have_pair = TRUE;
920                 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
921                         if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP104)
922                                 have_pair = TRUE;
923                 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
924                         if (ap_flags & NM_802_11_AP_SEC_PAIR_TKIP)
925                                 have_pair = TRUE;
926                 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
927                         if (ap_flags & NM_802_11_AP_SEC_PAIR_CCMP)
928                                 have_pair = TRUE;
929         }
930
931         /* Group */
932         if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
933                 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP40)
934                         have_group = TRUE;
935         if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
936                 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP104)
937                         have_group = TRUE;
938         if (!static_wep) {
939                 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
940                         if (ap_flags & NM_802_11_AP_SEC_GROUP_TKIP)
941                                 have_group = TRUE;
942                 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
943                         if (ap_flags & NM_802_11_AP_SEC_GROUP_CCMP)
944                                 have_group = TRUE;
945         }
946
947         return (have_pair && have_group);
948 }
949
950 /**
951  * nm_utils_ap_mode_security_valid:
952  * @type: the security type to check device capabilties against,
953  * e.g. #NMU_SEC_STATIC_WEP
954  * @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
955  * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
956  *
957  * Given a set of device capabilities, and a desired security type to check
958  * against, determines whether the combination of device capabilities and
959  * desired security type are valid for AP/Hotspot connections.
960  *
961  * Returns: %TRUE if the device capabilities are compatible with the desired
962  * @type, %FALSE if they are not.
963  **/
964 gboolean
965 nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
966                                  NMDeviceWifiCapabilities wifi_caps)
967 {
968         if (!(wifi_caps & NM_WIFI_DEVICE_CAP_AP))
969                 return FALSE;
970
971         /* Return TRUE for any security that wpa_supplicant's lightweight AP
972          * mode can handle: which is open, WEP, and WPA/WPA2 PSK.
973          */
974         switch (type) {
975         case NMU_SEC_NONE:
976         case NMU_SEC_STATIC_WEP:
977         case NMU_SEC_WPA_PSK:
978         case NMU_SEC_WPA2_PSK:
979                 return TRUE;
980         default:
981                 break;
982         }
983         return FALSE;
984 }
985
986 /**
987  * nm_utils_security_valid:
988  * @type: the security type to check AP flags and device capabilties against,
989  * e.g. #NMU_SEC_STATIC_WEP
990  * @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
991  * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
992  * @have_ap: whether the @ap_flags, @ap_wpa, and @ap_rsn arguments are valid
993  * @adhoc: whether the capabilities being tested are from an Ad-Hoc AP (IBSS)
994  * @ap_flags: bitfield of AP capabilities, e.g. #NM_802_11_AP_FLAGS_PRIVACY
995  * @ap_wpa: bitfield of AP capabilties derived from the AP's WPA beacon,
996  * e.g. (#NM_802_11_AP_SEC_PAIR_TKIP | #NM_802_11_AP_SEC_KEY_MGMT_PSK)
997  * @ap_rsn: bitfield of AP capabilties derived from the AP's RSN/WPA2 beacon,
998  * e.g. (#NM_802_11_AP_SEC_PAIR_CCMP | #NM_802_11_AP_SEC_PAIR_TKIP)
999  *
1000  * Given a set of device capabilities, and a desired security type to check
1001  * against, determines whether the combination of device, desired security
1002  * type, and AP capabilities intersect.
1003  *
1004  * NOTE: this function cannot handle checking security for AP/Hotspot mode;
1005  * use nm_utils_ap_mode_security_valid() instead.
1006  *
1007  * Returns: %TRUE if the device capabilities and AP capabilties intersect and are
1008  * compatible with the desired @type, %FALSE if they are not
1009  **/
1010 gboolean
1011 nm_utils_security_valid (NMUtilsSecurityType type,
1012                          NMDeviceWifiCapabilities wifi_caps,
1013                          gboolean have_ap,
1014                          gboolean adhoc,
1015                          NM80211ApFlags ap_flags,
1016                          NM80211ApSecurityFlags ap_wpa,
1017                          NM80211ApSecurityFlags ap_rsn)
1018 {
1019         gboolean good = TRUE;
1020
1021         if (!have_ap) {
1022                 if (type == NMU_SEC_NONE)
1023                         return TRUE;
1024                 if (   (type == NMU_SEC_STATIC_WEP)
1025                     || ((type == NMU_SEC_DYNAMIC_WEP) && !adhoc)
1026                     || ((type == NMU_SEC_LEAP) && !adhoc)) {
1027                         if (wifi_caps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104))
1028                                 return TRUE;
1029                         else
1030                                 return FALSE;
1031                 }
1032         }
1033
1034         switch (type) {
1035         case NMU_SEC_NONE:
1036                 g_assert (have_ap);
1037                 if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
1038                         return FALSE;
1039                 if (ap_wpa || ap_rsn)
1040                         return FALSE;
1041                 break;
1042         case NMU_SEC_LEAP: /* require PRIVACY bit for LEAP? */
1043                 if (adhoc)
1044                         return FALSE;
1045                 /* Fall through */
1046         case NMU_SEC_STATIC_WEP:
1047                 g_assert (have_ap);
1048                 if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
1049                         return FALSE;
1050                 if (ap_wpa || ap_rsn) {
1051                         if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, TRUE))
1052                                 if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, TRUE))
1053                                         return FALSE;
1054                 }
1055                 break;
1056         case NMU_SEC_DYNAMIC_WEP:
1057                 if (adhoc)
1058                         return FALSE;
1059                 g_assert (have_ap);
1060                 if (ap_rsn || !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
1061                         return FALSE;
1062                 /* Some APs broadcast minimal WPA-enabled beacons that must be handled */
1063                 if (ap_wpa) {
1064                         if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1065                                 return FALSE;
1066                         if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
1067                                 return FALSE;
1068                 }
1069                 break;
1070         case NMU_SEC_WPA_PSK:
1071                 if (adhoc)
1072                         return FALSE;  /* FIXME: Kernel WPA Ad-Hoc support is buggy */
1073                 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
1074                         return FALSE;
1075                 if (have_ap) {
1076                         /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
1077                          * they don't have any pairwise ciphers. */
1078                         if (adhoc) {
1079                                 /* coverity[dead_error_line] */
1080                                 if (   (ap_wpa & NM_802_11_AP_SEC_GROUP_TKIP)
1081                                     && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
1082                                         return TRUE;
1083                                 if (   (ap_wpa & NM_802_11_AP_SEC_GROUP_CCMP)
1084                                     && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
1085                                         return TRUE;
1086                         } else {
1087                                 if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
1088                                         if (   (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
1089                                             && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
1090                                                 return TRUE;
1091                                         if (   (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
1092                                             && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
1093                                                 return TRUE;
1094                                 }
1095                         }
1096                         return FALSE;
1097                 }
1098                 break;
1099         case NMU_SEC_WPA2_PSK:
1100                 if (adhoc)
1101                         return FALSE;  /* FIXME: Kernel WPA Ad-Hoc support is buggy */
1102                 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
1103                         return FALSE;
1104                 if (have_ap) {
1105                         /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
1106                          * they don't have any pairwise ciphers, nor any RSA flags yet. */
1107                         if (adhoc) {
1108                                 /* coverity[dead_error_line] */
1109                                 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
1110                                         return TRUE;
1111                                 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
1112                                         return TRUE;
1113                         } else {
1114                                 if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
1115                                         if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_TKIP)
1116                                             && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
1117                                                 return TRUE;
1118                                         if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
1119                                             && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
1120                                                 return TRUE;
1121                                 }
1122                         }
1123                         return FALSE;
1124                 }
1125                 break;
1126         case NMU_SEC_WPA_ENTERPRISE:
1127                 if (adhoc)
1128                         return FALSE;
1129                 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
1130                         return FALSE;
1131                 if (have_ap) {
1132                         if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1133                                 return FALSE;
1134                         /* Ensure at least one WPA cipher is supported */
1135                         if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
1136                                 return FALSE;
1137                 }
1138                 break;
1139         case NMU_SEC_WPA2_ENTERPRISE:
1140                 if (adhoc)
1141                         return FALSE;
1142                 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
1143                         return FALSE;
1144                 if (have_ap) {
1145                         if (!(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1146                                 return FALSE;
1147                         /* Ensure at least one WPA cipher is supported */
1148                         if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, FALSE))
1149                                 return FALSE;
1150                 }
1151                 break;
1152         default:
1153                 good = FALSE;
1154                 break;
1155         }
1156
1157         return good;
1158 }
1159
1160 /**
1161  * nm_utils_wep_key_valid:
1162  * @key: a string that might be a WEP key
1163  * @wep_type: the #NMWepKeyType type of the WEP key
1164  *
1165  * Checks if @key is a valid WEP key
1166  *
1167  * Returns: %TRUE if @key is a WEP key, %FALSE if not
1168  */
1169 gboolean
1170 nm_utils_wep_key_valid (const char *key, NMWepKeyType wep_type)
1171 {
1172         int keylen, i;
1173
1174         if (!key)
1175                 return FALSE;
1176
1177         if (wep_type == NM_WEP_KEY_TYPE_UNKNOWN) {
1178                 return nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_KEY) ||
1179                        nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_PASSPHRASE);
1180         }
1181
1182         keylen = strlen (key);
1183         if (wep_type == NM_WEP_KEY_TYPE_KEY) {
1184                 if (keylen == 10 || keylen == 26) {
1185                         /* Hex key */
1186                         for (i = 0; i < keylen; i++) {
1187                                 if (!g_ascii_isxdigit (key[i]))
1188                                         return FALSE;
1189                         }
1190                 } else if (keylen == 5 || keylen == 13) {
1191                         /* ASCII key */
1192                         for (i = 0; i < keylen; i++) {
1193                                 if (!g_ascii_isprint (key[i]))
1194                                         return FALSE;
1195                         }
1196                 } else
1197                         return FALSE;
1198         } else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
1199                 if (!keylen || keylen > 64)
1200                         return FALSE;
1201         }
1202
1203         return TRUE;
1204 }
1205
1206 /**
1207  * nm_utils_wpa_psk_valid:
1208  * @psk: a string that might be a WPA PSK
1209  *
1210  * Checks if @psk is a valid WPA PSK
1211  *
1212  * Returns: %TRUE if @psk is a WPA PSK, %FALSE if not
1213  */
1214 gboolean
1215 nm_utils_wpa_psk_valid (const char *psk)
1216 {
1217         int psklen, i;
1218
1219         if (!psk)
1220                 return FALSE;
1221
1222         psklen = strlen (psk);
1223         if (psklen < 8 || psklen > 64)
1224                 return FALSE;
1225
1226         if (psklen == 64) {
1227                 /* Hex PSK */
1228                 for (i = 0; i < psklen; i++) {
1229                         if (!g_ascii_isxdigit (psk[i]))
1230                                 return FALSE;
1231                 }
1232         }
1233
1234         return TRUE;
1235 }
1236
1237 /**
1238  * nm_utils_ip4_dns_to_variant:
1239  * @dns: (type utf8): an array of IP address strings
1240  *
1241  * Utility function to convert an array of IP address strings int a #GVariant of
1242  * type 'au' representing an array of IPv4 addresses.
1243  *
1244  * Returns: (transfer none): a new floating #GVariant representing @dns.
1245  **/
1246 GVariant *
1247 nm_utils_ip4_dns_to_variant (char **dns)
1248 {
1249         GVariantBuilder builder;
1250         int i;
1251
1252         g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
1253
1254         if (dns) {
1255                 for (i = 0; dns[i]; i++) {
1256                         guint32 ip = 0;
1257
1258                         inet_pton (AF_INET, dns[i], &ip);
1259                         g_variant_builder_add (&builder, "u", ip);
1260                 }
1261         }
1262
1263         return g_variant_builder_end (&builder);
1264 }
1265
1266 /**
1267  * nm_utils_ip4_dns_from_variant:
1268  * @value: a #GVariant of type 'au'
1269  *
1270  * Utility function to convert a #GVariant of type 'au' representing a list of
1271  * IPv4 addresses into an array of IP address strings.
1272  *
1273  * Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
1274  **/
1275 char **
1276 nm_utils_ip4_dns_from_variant (GVariant *value)
1277 {
1278         const guint32 *array;
1279         gsize length;
1280         char **dns;
1281         int i;
1282
1283         g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("au")), NULL);
1284
1285         array = g_variant_get_fixed_array (value, &length, sizeof (guint32));
1286         dns = g_new (char *, length + 1);
1287
1288         for (i = 0; i < length; i++)
1289                 dns[i] = g_strdup (nm_utils_inet4_ntop (array[i], NULL));
1290         dns[i] = NULL;
1291
1292         return dns;
1293 }
1294
1295 /**
1296  * nm_utils_ip4_addresses_to_variant:
1297  * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
1298  * @gateway: (allow-none): the gateway IP address
1299  *
1300  * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
1301  * IPv4 addresses into a #GVariant of type 'aau' representing an array of
1302  * NetworkManager IPv4 addresses (which are tuples of address, prefix, and
1303  * gateway). The "gateway" field of the first address will get the value of
1304  * @gateway (if non-%NULL). In all of the other addresses, that field will be 0.
1305  *
1306  * Returns: (transfer none): a new floating #GVariant representing @addresses.
1307  **/
1308 GVariant *
1309 nm_utils_ip4_addresses_to_variant (GPtrArray *addresses, const char *gateway)
1310 {
1311         GVariantBuilder builder;
1312         int i;
1313
1314         g_variant_builder_init (&builder, G_VARIANT_TYPE ("aau"));
1315
1316         if (addresses) {
1317                 for (i = 0; i < addresses->len; i++) {
1318                         NMIPAddress *addr = addresses->pdata[i];
1319                         guint32 array[3];
1320
1321                         if (nm_ip_address_get_family (addr) != AF_INET)
1322                                 continue;
1323
1324                         nm_ip_address_get_address_binary (addr, &array[0]);
1325                         array[1] = nm_ip_address_get_prefix (addr);
1326                         if (i == 0 && gateway)
1327                                 inet_pton (AF_INET, gateway, &array[2]);
1328                         else
1329                                 array[2] = 0;
1330
1331                         g_variant_builder_add (&builder, "@au",
1332                                                g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
1333                                                                           array, 3, sizeof (guint32)));
1334                 }
1335         }
1336
1337         return g_variant_builder_end (&builder);
1338 }
1339
1340 /**
1341  * nm_utils_ip4_addresses_from_variant:
1342  * @value: a #GVariant of type 'aau'
1343  * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway
1344  *
1345  * Utility function to convert a #GVariant of type 'aau' representing a list of
1346  * NetworkManager IPv4 addresses (which are tuples of address, prefix, and
1347  * gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field of
1348  * the first address (if set) will be returned in @out_gateway; the "gateway" fields
1349  * of the other addresses are ignored.
1350  *
1351  * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1352  *   #GPtrArray of #NMIPAddress objects
1353  **/
1354 GPtrArray *
1355 nm_utils_ip4_addresses_from_variant (GVariant *value, char **out_gateway)
1356 {
1357         GPtrArray *addresses;
1358         GVariantIter iter;
1359         GVariant *addr_var;
1360
1361         g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aau")), NULL);
1362
1363         if (out_gateway)
1364                 *out_gateway = NULL;
1365
1366         g_variant_iter_init (&iter, value);
1367         addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
1368
1369         while (g_variant_iter_next (&iter, "@au", &addr_var)) {
1370                 const guint32 *addr_array;
1371                 gsize length;
1372                 NMIPAddress *addr;
1373                 GError *error = NULL;
1374
1375                 addr_array = g_variant_get_fixed_array (addr_var, &length, sizeof (guint32));
1376                 if (length < 3) {
1377                         g_warning ("Ignoring invalid IP4 address");
1378                         g_variant_unref (addr_var);
1379                         continue;
1380                 }
1381
1382                 addr = nm_ip_address_new_binary (AF_INET, &addr_array[0], addr_array[1], &error);
1383                 if (addr) {
1384                         g_ptr_array_add (addresses, addr);
1385
1386                         if (addr_array[2] && out_gateway && !*out_gateway)
1387                                 *out_gateway = g_strdup (nm_utils_inet4_ntop (addr_array[2], NULL));
1388                 } else {
1389                         g_warning ("Ignoring invalid IP4 address: %s", error->message);
1390                         g_clear_error (&error);
1391                 }
1392
1393                 g_variant_unref (addr_var);
1394         }
1395
1396         return addresses;
1397 }
1398
1399 /**
1400  * nm_utils_ip4_routes_to_variant:
1401  * @routes: (element-type NMIPRoute): an array of #NMIP4Route objects
1402  *
1403  * Utility function to convert a #GPtrArray of #NMIPRoute objects representing
1404  * IPv4 routes into a #GVariant of type 'aau' representing an array of
1405  * NetworkManager IPv4 routes (which are tuples of route, prefix, next hop, and
1406  * metric).
1407  *
1408  * Returns: (transfer none): a new floating #GVariant representing @routes.
1409  **/
1410 GVariant *
1411 nm_utils_ip4_routes_to_variant (GPtrArray *routes)
1412 {
1413         GVariantBuilder builder;
1414         int i;
1415
1416         g_variant_builder_init (&builder, G_VARIANT_TYPE ("aau"));
1417
1418         if (routes) {
1419                 for (i = 0; i < routes->len; i++) {
1420                         NMIPRoute *route = routes->pdata[i];
1421                         guint32 array[4];
1422
1423                         if (nm_ip_route_get_family (route) != AF_INET)
1424                                 continue;
1425
1426                         nm_ip_route_get_dest_binary (route, &array[0]);
1427                         array[1] = nm_ip_route_get_prefix (route);
1428                         nm_ip_route_get_next_hop_binary (route, &array[2]);
1429                         /* The old routes format uses "0" for default, not "-1" */
1430                         array[3] = MAX (0, nm_ip_route_get_metric (route));
1431
1432                         g_variant_builder_add (&builder, "@au",
1433                                                g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
1434                                                                           array, 4, sizeof (guint32)));
1435                 }
1436         }
1437
1438         return g_variant_builder_end (&builder);
1439 }
1440
1441 /**
1442  * nm_utils_ip4_routes_from_variant:
1443  * @value: #GVariant of type 'aau'
1444  *
1445  * Utility function to convert a #GVariant of type 'aau' representing an array
1446  * of NetworkManager IPv4 routes (which are tuples of route, prefix, next hop,
1447  * and metric) into a #GPtrArray of #NMIPRoute objects.
1448  *
1449  * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
1450  *   #GPtrArray of #NMIPRoute objects
1451  **/
1452 GPtrArray *
1453 nm_utils_ip4_routes_from_variant (GVariant *value)
1454 {
1455         GVariantIter iter;
1456         GVariant *route_var;
1457         GPtrArray *routes;
1458
1459         g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aau")), NULL);
1460
1461         g_variant_iter_init (&iter, value);
1462         routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
1463
1464         while (g_variant_iter_next (&iter, "@au", &route_var)) {
1465                 const guint32 *route_array;
1466                 gsize length;
1467                 NMIPRoute *route;
1468                 GError *error = NULL;
1469
1470                 route_array = g_variant_get_fixed_array (route_var, &length, sizeof (guint32));
1471                 if (length < 4) {
1472                         g_warning ("Ignoring invalid IP4 route");
1473                         g_variant_unref (route_var);
1474                         continue;
1475                 }
1476
1477                 route = nm_ip_route_new_binary (AF_INET,
1478                                                 &route_array[0],
1479                                                 route_array[1],
1480                                                 &route_array[2],
1481                                                 /* The old routes format uses "0" for default, not "-1" */
1482                                                 route_array[3] ? (gint64) route_array[3] : -1,
1483                                                 &error);
1484                 if (route)
1485                         g_ptr_array_add (routes, route);
1486                 else {
1487                         g_warning ("Ignoring invalid IP4 route: %s", error->message);
1488                         g_clear_error (&error);
1489                 }
1490                 g_variant_unref (route_var);
1491         }
1492
1493         return routes;
1494 }
1495
1496 /**
1497  * nm_utils_ip4_netmask_to_prefix:
1498  * @netmask: an IPv4 netmask in network byte order
1499  *
1500  * Returns: the CIDR prefix represented by the netmask
1501  **/
1502 guint32
1503 nm_utils_ip4_netmask_to_prefix (guint32 netmask)
1504 {
1505         guint32 prefix;
1506         guint8 v;
1507         const guint8 *p = (guint8 *) &netmask;
1508
1509         if (p[3]) {
1510                 prefix = 24;
1511                 v = p[3];
1512         } else if (p[2]) {
1513                 prefix = 16;
1514                 v = p[2];
1515         } else if (p[1]) {
1516                 prefix = 8;
1517                 v = p[1];
1518         } else {
1519                 prefix = 0;
1520                 v = p[0];
1521         }
1522
1523         while (v) {
1524                 prefix++;
1525                 v <<= 1;
1526         }
1527
1528         return prefix;
1529 }
1530
1531 /**
1532  * nm_utils_ip4_prefix_to_netmask:
1533  * @prefix: a CIDR prefix
1534  *
1535  * Returns: the netmask represented by the prefix, in network byte order
1536  **/
1537 guint32
1538 nm_utils_ip4_prefix_to_netmask (guint32 prefix)
1539 {
1540         return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
1541 }
1542
1543
1544 /**
1545  * nm_utils_ip4_get_default_prefix:
1546  * @ip: an IPv4 address (in network byte order)
1547  *
1548  * When the Internet was originally set up, various ranges of IP addresses were
1549  * segmented into three network classes: A, B, and C.  This function will return
1550  * a prefix that is associated with the IP address specified defining where it
1551  * falls in the predefined classes.
1552  *
1553  * Returns: the default class prefix for the given IP
1554  **/
1555 /* The function is originally from ipcalc.c of Red Hat's initscripts. */
1556 guint32
1557 nm_utils_ip4_get_default_prefix (guint32 ip)
1558 {
1559         if (((ntohl (ip) & 0xFF000000) >> 24) <= 127)
1560                 return 8;  /* Class A - 255.0.0.0 */
1561         else if (((ntohl (ip) & 0xFF000000) >> 24) <= 191)
1562                 return 16;  /* Class B - 255.255.0.0 */
1563
1564         return 24;  /* Class C - 255.255.255.0 */
1565 }
1566
1567 /**
1568  * nm_utils_ip6_dns_to_variant:
1569  * @dns: (type utf8): an array of IP address strings
1570  *
1571  * Utility function to convert an array of IP address strings int a #GVariant of
1572  * type 'aay' representing an array of IPv6 addresses.
1573  *
1574  * Returns: (transfer none): a new floating #GVariant representing @dns.
1575  **/
1576 GVariant *
1577 nm_utils_ip6_dns_to_variant (char **dns)
1578 {
1579         GVariantBuilder builder;
1580         int i;
1581
1582         g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
1583
1584         if (dns) {
1585                 for (i = 0; dns[i]; i++) {
1586                         struct in6_addr ip;
1587
1588                         inet_pton (AF_INET6, dns[i], &ip);
1589                         g_variant_builder_add (&builder, "@ay",
1590                                                g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
1591                                                                           &ip, sizeof (ip), 1));
1592                 }
1593         }
1594
1595         return g_variant_builder_end (&builder);
1596 }
1597
1598 /**
1599  * nm_utils_ip6_dns_from_variant:
1600  * @value: a #GVariant of type 'aay'
1601  *
1602  * Utility function to convert a #GVariant of type 'aay' representing a list of
1603  * IPv6 addresses into an array of IP address strings.
1604  *
1605  * Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
1606  **/
1607 char **
1608 nm_utils_ip6_dns_from_variant (GVariant *value)
1609 {
1610         GVariantIter iter;
1611         GVariant *ip_var;
1612         char **dns;
1613         int i;
1614
1615         g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aay")), NULL);
1616
1617         dns = g_new (char *, g_variant_n_children (value) + 1);
1618
1619         g_variant_iter_init (&iter, value);
1620         i = 0;
1621         while (g_variant_iter_next (&iter, "@ay", &ip_var)) {
1622                 gsize length;
1623                 const struct in6_addr *ip = g_variant_get_fixed_array (ip_var, &length, 1);
1624
1625                 if (length != sizeof (struct in6_addr)) {
1626                         g_warning ("%s: ignoring invalid IP6 address of length %d",
1627                                    __func__, (int) length);
1628                         g_variant_unref (ip_var);
1629                         continue;
1630                 }
1631
1632                 dns[i++] = g_strdup (nm_utils_inet6_ntop (ip, NULL));
1633                 g_variant_unref (ip_var);
1634         }
1635         dns[i] = NULL;
1636
1637         return dns;
1638 }
1639
1640 /**
1641  * nm_utils_ip6_addresses_to_variant:
1642  * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
1643  * @gateway: (allow-none): the gateway IP address
1644  *
1645  * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
1646  * IPv6 addresses into a #GVariant of type 'a(ayuay)' representing an array of
1647  * NetworkManager IPv6 addresses (which are tuples of address, prefix, and
1648  * gateway).  The "gateway" field of the first address will get the value of
1649  * @gateway (if non-%NULL). In all of the other addresses, that field will be
1650  * all 0s.
1651  *
1652  * Returns: (transfer none): a new floating #GVariant representing @addresses.
1653  **/
1654 GVariant *
1655 nm_utils_ip6_addresses_to_variant (GPtrArray *addresses, const char *gateway)
1656 {
1657         GVariantBuilder builder;
1658         int i;
1659
1660         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayuay)"));
1661
1662         if (addresses) {
1663                 for (i = 0; i < addresses->len; i++) {
1664                         NMIPAddress *addr = addresses->pdata[i];
1665                         struct in6_addr ip_bytes, gateway_bytes;
1666                         GVariant *ip_var, *gateway_var;
1667                         guint32 prefix;
1668
1669                         if (nm_ip_address_get_family (addr) != AF_INET6)
1670                                 continue;
1671
1672                         nm_ip_address_get_address_binary (addr, &ip_bytes);
1673                         ip_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &ip_bytes, 16, 1);
1674
1675                         prefix = nm_ip_address_get_prefix (addr);
1676
1677                         if (i == 0 && gateway)
1678                                 inet_pton (AF_INET6, gateway, &gateway_bytes);
1679                         else
1680                                 memset (&gateway_bytes, 0, sizeof (gateway_bytes));
1681                         gateway_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &gateway_bytes, 16, 1);
1682
1683                         g_variant_builder_add (&builder, "(@ayu@ay)", ip_var, prefix, gateway_var);
1684                 }
1685         }
1686
1687         return g_variant_builder_end (&builder);
1688 }
1689
1690 /**
1691  * nm_utils_ip6_addresses_from_variant:
1692  * @value: a #GVariant of type 'a(ayuay)'
1693  * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway
1694  *
1695  * Utility function to convert a #GVariant of type 'a(ayuay)' representing a
1696  * list of NetworkManager IPv6 addresses (which are tuples of address, prefix,
1697  * and gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field
1698  * of the first address (if set) will be returned in @out_gateway; the "gateway"
1699  * fields of the other addresses are ignored.
1700  *
1701  * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1702  *   #GPtrArray of #NMIPAddress objects
1703  **/
1704 GPtrArray *
1705 nm_utils_ip6_addresses_from_variant (GVariant *value, char **out_gateway)
1706 {
1707         GVariantIter iter;
1708         GVariant *addr_var, *gateway_var;
1709         guint32 prefix;
1710         GPtrArray *addresses;
1711
1712         g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(ayuay)")), NULL);
1713
1714         if (out_gateway)
1715                 *out_gateway = NULL;
1716
1717         g_variant_iter_init (&iter, value);
1718         addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
1719
1720         while (g_variant_iter_next (&iter, "(@ayu@ay)", &addr_var, &prefix, &gateway_var)) {
1721                 NMIPAddress *addr;
1722                 const struct in6_addr *addr_bytes, *gateway_bytes;
1723                 gsize addr_len, gateway_len;
1724                 GError *error = NULL;
1725
1726                 if (   !g_variant_is_of_type (addr_var, G_VARIANT_TYPE_BYTESTRING)
1727                     || !g_variant_is_of_type (gateway_var, G_VARIANT_TYPE_BYTESTRING)) {
1728                         g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1729                         goto next;
1730                 }
1731
1732                 addr_bytes = g_variant_get_fixed_array (addr_var, &addr_len, 1);
1733                 if (addr_len != 16) {
1734                         g_warning ("%s: ignoring invalid IP6 address of length %d",
1735                                    __func__, (int) addr_len);
1736                         goto next;
1737                 }
1738
1739                 addr = nm_ip_address_new_binary (AF_INET6, addr_bytes, prefix, &error);
1740                 if (addr) {
1741                         g_ptr_array_add (addresses, addr);
1742
1743                         if (out_gateway && !*out_gateway) {
1744                                 gateway_bytes = g_variant_get_fixed_array (gateway_var, &gateway_len, 1);
1745                                 if (gateway_len != 16) {
1746                                         g_warning ("%s: ignoring invalid IP6 address of length %d",
1747                                                    __func__, (int) gateway_len);
1748                                         goto next;
1749                                 }
1750                                 if (!IN6_IS_ADDR_UNSPECIFIED (gateway_bytes))
1751                                         *out_gateway = g_strdup (nm_utils_inet6_ntop (gateway_bytes, NULL));
1752                         }
1753                 } else {
1754                         g_warning ("Ignoring invalid IP6 address: %s", error->message);
1755                         g_clear_error (&error);
1756                 }
1757
1758         next:
1759                 g_variant_unref (addr_var);
1760                 g_variant_unref (gateway_var);
1761         }
1762
1763         return addresses;
1764 }
1765
1766 /**
1767  * nm_utils_ip6_routes_to_variant:
1768  * @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
1769  *
1770  * Utility function to convert a #GPtrArray of #NMIPRoute objects representing
1771  * IPv6 routes into a #GVariant of type 'a(ayuayu)' representing an array of
1772  * NetworkManager IPv6 routes (which are tuples of route, prefix, next hop, and
1773  * metric).
1774  *
1775  * Returns: (transfer none): a new floating #GVariant representing @routes.
1776  **/
1777 GVariant *
1778 nm_utils_ip6_routes_to_variant (GPtrArray *routes)
1779 {
1780         GVariantBuilder builder;
1781         int i;
1782
1783         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayuayu)"));
1784
1785         if (routes) {
1786                 for (i = 0; i < routes->len; i++) {
1787                         NMIPRoute *route = routes->pdata[i];
1788                         struct in6_addr dest_bytes, next_hop_bytes;
1789                         GVariant *dest, *next_hop;
1790                         guint32 prefix, metric;
1791
1792                         if (nm_ip_route_get_family (route) != AF_INET6)
1793                                 continue;
1794
1795                         nm_ip_route_get_dest_binary (route, &dest_bytes);
1796                         dest = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &dest_bytes, 16, 1);
1797                         prefix = nm_ip_route_get_prefix (route);
1798                         nm_ip_route_get_next_hop_binary (route, &next_hop_bytes);
1799                         next_hop = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &next_hop_bytes, 16, 1);
1800                         /* The old routes format uses "0" for default, not "-1" */
1801                         metric = MAX (0, nm_ip_route_get_metric (route));
1802
1803                         g_variant_builder_add (&builder, "(@ayu@ayu)", dest, prefix, next_hop, metric);
1804                 }
1805         }
1806
1807         return g_variant_builder_end (&builder);
1808 }
1809
1810 /**
1811  * nm_utils_ip6_routes_from_variant:
1812  * @value: #GVariant of type 'a(ayuayu)'
1813  *
1814  * Utility function to convert a #GVariant of type 'a(ayuayu)' representing an
1815  * array of NetworkManager IPv6 routes (which are tuples of route, prefix, next
1816  * hop, and metric) into a #GPtrArray of #NMIPRoute objects.
1817  *
1818  * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
1819  *   #GPtrArray of #NMIPRoute objects
1820  **/
1821 GPtrArray *
1822 nm_utils_ip6_routes_from_variant (GVariant *value)
1823 {
1824         GPtrArray *routes;
1825         GVariantIter iter;
1826         GVariant *dest_var, *next_hop_var;
1827         const struct in6_addr *dest, *next_hop;
1828         gsize dest_len, next_hop_len;
1829         guint32 prefix, metric;
1830
1831         g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(ayuayu)")), NULL);
1832
1833         routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
1834
1835         g_variant_iter_init (&iter, value);
1836         while (g_variant_iter_next (&iter, "(@ayu@ayu)", &dest_var, &prefix, &next_hop_var, &metric)) {
1837                 NMIPRoute *route;
1838                 GError *error = NULL;
1839
1840                 if (   !g_variant_is_of_type (dest_var, G_VARIANT_TYPE_BYTESTRING)
1841                     || !g_variant_is_of_type (next_hop_var, G_VARIANT_TYPE_BYTESTRING)) {
1842                         g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1843                         goto next;
1844                 }
1845
1846                 dest = g_variant_get_fixed_array (dest_var, &dest_len, 1);
1847                 if (dest_len != 16) {
1848                         g_warning ("%s: ignoring invalid IP6 address of length %d",
1849                                    __func__, (int) dest_len);
1850                         goto next;
1851                 }
1852
1853                 next_hop = g_variant_get_fixed_array (next_hop_var, &next_hop_len, 1);
1854                 if (next_hop_len != 16) {
1855                         g_warning ("%s: ignoring invalid IP6 address of length %d",
1856                                    __func__, (int) next_hop_len);
1857                         goto next;
1858                 }
1859
1860                 route = nm_ip_route_new_binary (AF_INET6, dest, prefix, next_hop,
1861                                                 metric ? (gint64) metric : -1,
1862                                                 &error);
1863                 if (route)
1864                         g_ptr_array_add (routes, route);
1865                 else {
1866                         g_warning ("Ignoring invalid IP6 route: %s", error->message);
1867                         g_clear_error (&error);
1868                 }
1869
1870         next:
1871                 g_variant_unref (dest_var);
1872                 g_variant_unref (next_hop_var);
1873         }
1874
1875         return routes;
1876 }
1877
1878 /**
1879  * nm_utils_ip_addresses_to_variant:
1880  * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
1881  *
1882  * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
1883  * IPv4 or IPv6 addresses into a #GVariant of type 'aa{sv}' representing an
1884  * array of new-style NetworkManager IP addresses. All addresses will include
1885  * "address" (an IP address string), and "prefix" (a uint). Some addresses may
1886  * include additional attributes.
1887  *
1888  * Returns: (transfer none): a new floating #GVariant representing @addresses.
1889  **/
1890 GVariant *
1891 nm_utils_ip_addresses_to_variant (GPtrArray *addresses)
1892 {
1893         GVariantBuilder builder;
1894         int i;
1895
1896         g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
1897
1898         if (addresses) {
1899                 for (i = 0; i < addresses->len; i++) {
1900                         NMIPAddress *addr = addresses->pdata[i];
1901                         GVariantBuilder addr_builder;
1902                         char **names;
1903                         int n;
1904
1905                         g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}"));
1906                         g_variant_builder_add (&addr_builder, "{sv}",
1907                                                "address",
1908                                                g_variant_new_string (nm_ip_address_get_address (addr)));
1909                         g_variant_builder_add (&addr_builder, "{sv}",
1910                                                "prefix",
1911                                                g_variant_new_uint32 (nm_ip_address_get_prefix (addr)));
1912
1913                         names = nm_ip_address_get_attribute_names (addr);
1914                         for (n = 0; names[n]; n++) {
1915                                 g_variant_builder_add (&addr_builder, "{sv}",
1916                                                        names[n],
1917                                                        nm_ip_address_get_attribute (addr, names[n]));
1918                         }
1919                         g_strfreev (names);
1920
1921                         g_variant_builder_add (&builder, "a{sv}", &addr_builder);
1922                 }
1923         }
1924
1925         return g_variant_builder_end (&builder);
1926 }
1927
1928 /**
1929  * nm_utils_ip_addresses_from_variant:
1930  * @value: a #GVariant of type 'aa{sv}'
1931  * @family: an IP address family
1932  *
1933  * Utility function to convert a #GVariant representing a list of new-style
1934  * NetworkManager IPv4 or IPv6 addresses (as described in the documentation for
1935  * nm_utils_ip_addresses_to_variant()) into a #GPtrArray of #NMIPAddress
1936  * objects.
1937  *
1938  * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1939  *   #GPtrArray of #NMIPAddress objects
1940  **/
1941 GPtrArray *
1942 nm_utils_ip_addresses_from_variant (GVariant *value,
1943                                     int family)
1944 {
1945         GPtrArray *addresses;
1946         GVariantIter iter, attrs_iter;
1947         GVariant *addr_var;
1948         const char *ip;
1949         guint32 prefix;
1950         const char *attr_name;
1951         GVariant *attr_val;
1952         NMIPAddress *addr;
1953         GError *error = NULL;
1954
1955         g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
1956
1957         g_variant_iter_init (&iter, value);
1958         addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
1959
1960         while (g_variant_iter_next (&iter, "@a{sv}", &addr_var)) {
1961                 if (   !g_variant_lookup (addr_var, "address", "&s", &ip)
1962                     || !g_variant_lookup (addr_var, "prefix", "u", &prefix)) {
1963                         g_warning ("Ignoring invalid address");
1964                         g_variant_unref (addr_var);
1965                         continue;
1966                 }
1967
1968                 addr = nm_ip_address_new (family, ip, prefix, &error);
1969                 if (!addr) {
1970                         g_warning ("Ignoring invalid address: %s", error->message);
1971                         g_clear_error (&error);
1972                         g_variant_unref (addr_var);
1973                         continue;
1974                 }
1975
1976                 g_variant_iter_init (&attrs_iter, addr_var);
1977                 while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) {
1978                         if (   strcmp (attr_name, "address") != 0
1979                             && strcmp (attr_name, "prefix") != 0)
1980                                 nm_ip_address_set_attribute (addr, attr_name, attr_val);
1981                         g_variant_unref (attr_val);
1982                 }
1983
1984                 g_variant_unref (addr_var);
1985                 g_ptr_array_add (addresses, addr);
1986         }
1987
1988         return addresses;
1989 }
1990
1991 /**
1992  * nm_utils_ip_routes_to_variant:
1993  * @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
1994  *
1995  * Utility function to convert a #GPtrArray of #NMIPRoute objects representing
1996  * IPv4 or IPv6 routes into a #GVariant of type 'aa{sv}' representing an array
1997  * of new-style NetworkManager IP routes (which are tuples of destination,
1998  * prefix, next hop, metric, and additional attributes).
1999  *
2000  * Returns: (transfer none): a new floating #GVariant representing @routes.
2001  **/
2002 GVariant *
2003 nm_utils_ip_routes_to_variant (GPtrArray *routes)
2004 {
2005         GVariantBuilder builder;
2006         int i;
2007
2008         g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
2009
2010         if (routes) {
2011                 for (i = 0; i < routes->len; i++) {
2012                         NMIPRoute *route = routes->pdata[i];
2013                         GVariantBuilder route_builder;
2014                         char **names;
2015                         int n;
2016
2017                         g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}"));
2018                         g_variant_builder_add (&route_builder, "{sv}",
2019                                                "dest",
2020                                                g_variant_new_string (nm_ip_route_get_dest (route)));
2021                         g_variant_builder_add (&route_builder, "{sv}",
2022                                                "prefix",
2023                                                g_variant_new_uint32 (nm_ip_route_get_prefix (route)));
2024                         if (nm_ip_route_get_next_hop (route)) {
2025                                 g_variant_builder_add (&route_builder, "{sv}",
2026                                                        "next-hop",
2027                                                        g_variant_new_string (nm_ip_route_get_next_hop (route)));
2028                         }
2029                         if (nm_ip_route_get_metric (route) != -1) {
2030                                 g_variant_builder_add (&route_builder, "{sv}",
2031                                                        "metric",
2032                                                        g_variant_new_uint32 ((guint32) nm_ip_route_get_metric (route)));
2033                         }
2034
2035                         names = nm_ip_route_get_attribute_names (route);
2036                         for (n = 0; names[n]; n++) {
2037                                 g_variant_builder_add (&route_builder, "{sv}",
2038                                                        names[n],
2039                                                        nm_ip_route_get_attribute (route, names[n]));
2040                         }
2041                         g_strfreev (names);
2042
2043                         g_variant_builder_add (&builder, "a{sv}", &route_builder);
2044                 }
2045         }
2046
2047         return g_variant_builder_end (&builder);
2048 }
2049
2050 /**
2051  * nm_utils_ip_routes_from_variant:
2052  * @value: a #GVariant of type 'aa{sv}'
2053  * @family: an IP address family
2054  *
2055  * Utility function to convert a #GVariant representing a list of new-style
2056  * NetworkManager IPv4 or IPv6 addresses (which are tuples of destination,
2057  * prefix, next hop, metric, and additional attributes) into a #GPtrArray of
2058  * #NMIPRoute objects.
2059  *
2060  * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
2061  *   #GPtrArray of #NMIPRoute objects
2062  **/
2063 GPtrArray *
2064 nm_utils_ip_routes_from_variant (GVariant *value,
2065                                  int family)
2066 {
2067         GPtrArray *routes;
2068         GVariantIter iter, attrs_iter;
2069         GVariant *route_var;
2070         const char *dest, *next_hop;
2071         guint32 prefix, metric32;
2072         gint64 metric;
2073         const char *attr_name;
2074         GVariant *attr_val;
2075         NMIPRoute *route;
2076         GError *error = NULL;
2077
2078         g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
2079
2080         g_variant_iter_init (&iter, value);
2081         routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
2082
2083         while (g_variant_iter_next (&iter, "@a{sv}", &route_var)) {
2084                 if (   !g_variant_lookup (route_var, "dest", "&s", &dest)
2085                     || !g_variant_lookup (route_var, "prefix", "u", &prefix)) {
2086                         g_warning ("Ignoring invalid address");
2087                         goto next;
2088                 }
2089                 if (!g_variant_lookup (route_var, "next-hop", "&s", &next_hop))
2090                         next_hop = NULL;
2091                 if (g_variant_lookup (route_var, "metric", "u", &metric32))
2092                         metric = metric32;
2093                 else
2094                         metric = -1;
2095
2096                 route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &error);
2097                 if (!route) {
2098                         g_warning ("Ignoring invalid route: %s", error->message);
2099                         g_clear_error (&error);
2100                         goto next;
2101                 }
2102
2103                 g_variant_iter_init (&attrs_iter, route_var);
2104                 while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) {
2105                         if (   strcmp (attr_name, "dest") != 0
2106                             && strcmp (attr_name, "prefix") != 0
2107                             && strcmp (attr_name, "next-hop") != 0
2108                             && strcmp (attr_name, "metric") != 0)
2109                                 nm_ip_route_set_attribute (route, attr_name, attr_val);
2110                         g_variant_unref (attr_val);
2111                 }
2112
2113                 g_ptr_array_add (routes, route);
2114 next:
2115                 g_variant_unref (route_var);
2116         }
2117
2118         return routes;
2119 }
2120
2121 /**********************************************************************************************/
2122
2123 /**
2124  * nm_utils_uuid_generate:
2125  *
2126  * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
2127  * object's #NMSettingConnection:id: property.  Should be freed with g_free()
2128  **/
2129 char *
2130 nm_utils_uuid_generate (void)
2131 {
2132         uuid_t uuid;
2133         char *buf;
2134
2135         buf = g_malloc0 (37);
2136         uuid_generate_random (uuid);
2137         uuid_unparse_lower (uuid, &buf[0]);
2138         return buf;
2139 }
2140
2141 /**
2142  * nm_utils_uuid_generate_from_string:
2143  * @s: a string to use as the seed for the UUID
2144  * @slen: if negative, treat @s as zero terminated C string.
2145  *   Otherwise, assume the length as given (and allow @s to be
2146  *   non-null terminated or contain '\0').
2147  * @uuid_type: a type identifier which UUID format to generate.
2148  * @type_args: additional arguments, depending on the uuid_type
2149  *
2150  * For a given @s, this function will always return the same UUID.
2151  *
2152  * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
2153  * object's #NMSettingConnection:id: property
2154  **/
2155 char *
2156 nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args)
2157 {
2158         uuid_t uuid;
2159         char *buf;
2160
2161         g_return_val_if_fail (slen == 0 || s, FALSE);
2162
2163         g_return_val_if_fail (uuid_type == NM_UTILS_UUID_TYPE_LEGACY || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
2164         g_return_val_if_fail (!type_args || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
2165
2166         switch (uuid_type) {
2167         case NM_UTILS_UUID_TYPE_LEGACY:
2168                 crypto_md5_hash (NULL, 0, s, slen, (char *) uuid, sizeof (uuid));
2169                 break;
2170         case NM_UTILS_UUID_TYPE_VARIANT3: {
2171                 uuid_t ns_uuid = { 0 };
2172
2173                 if (type_args) {
2174                         /* type_args can be a name space UUID. Interpret it as (char *) */
2175                         if (uuid_parse ((char *) type_args, ns_uuid) != 0)
2176                                 g_return_val_if_reached (NULL);
2177                 }
2178
2179                 crypto_md5_hash (s, slen, (char *) ns_uuid, sizeof (ns_uuid), (char *) uuid, sizeof (uuid));
2180
2181                 uuid[6] = (uuid[6] & 0x0F) | 0x30;
2182                 uuid[8] = (uuid[8] & 0x3F) | 0x80;
2183                 break;
2184         }
2185         default:
2186                 g_return_val_if_reached (NULL);
2187         }
2188
2189         buf = g_malloc0 (37);
2190         uuid_unparse_lower (uuid, &buf[0]);
2191
2192         return buf;
2193 }
2194
2195 /**
2196  * _nm_utils_uuid_generate_from_strings:
2197  * @string1: a variadic list of strings. Must be NULL terminated.
2198  *
2199  * Returns a variant3 UUID based on the concatenated C strings.
2200  * It does not simply concatenate them, but also includes the
2201  * terminating '\0' character. For example "a", "b", gives
2202  * "a\0b\0".
2203  *
2204  * This has the advantage, that the following invocations
2205  * all give different UUIDs: (NULL), (""), ("",""), ("","a"), ("a",""),
2206  * ("aa"), ("aa", ""), ("", "aa"), ...
2207  */
2208 char *
2209 _nm_utils_uuid_generate_from_strings (const char *string1, ...)
2210 {
2211         GString *str;
2212         va_list args;
2213         const char *s;
2214         char *uuid;
2215
2216         if (!string1)
2217                 return nm_utils_uuid_generate_from_string (NULL, 0, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
2218
2219         str = g_string_sized_new (120); /* effectively allocates power of 2 (128)*/
2220
2221         g_string_append_len (str, string1, strlen (string1) + 1);
2222
2223         va_start (args, string1);
2224         s = va_arg (args, const char *);
2225         while (s) {
2226                 g_string_append_len (str, s, strlen (s) + 1);
2227                 s = va_arg (args, const char *);
2228         }
2229         va_end (args);
2230
2231         uuid = nm_utils_uuid_generate_from_string (str->str, str->len, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
2232
2233         g_string_free (str, TRUE);
2234         return uuid;
2235 }
2236
2237 /**********************************************************************************************/
2238
2239 /**
2240  * nm_utils_rsa_key_encrypt:
2241  * @data: (array length=len): RSA private key data to be encrypted
2242  * @len: length of @data
2243  * @in_password: (allow-none): existing password to use, if any
2244  * @out_password: (out) (allow-none): if @in_password was %NULL, a random
2245  *  password will be generated and returned in this argument
2246  * @error: detailed error information on return, if an error occurred
2247  *
2248  * Encrypts the given RSA private key data with the given password (or generates
2249  * a password if no password was given) and converts the data to PEM format
2250  * suitable for writing to a file. It uses Triple DES cipher for the encryption.
2251  *
2252  * Returns: (transfer full): on success, PEM-formatted data suitable for writing
2253  * to a PEM-formatted certificate/private key file.
2254  **/
2255 GByteArray *
2256 nm_utils_rsa_key_encrypt (const guint8 *data,
2257                           gsize len,
2258                           const char *in_password,
2259                           char **out_password,
2260                           GError **error)
2261 {
2262         char salt[16];
2263         int salt_len;
2264         char *key = NULL, *enc = NULL, *pw_buf[32];
2265         gsize key_len = 0, enc_len = 0;
2266         GString *pem = NULL;
2267         char *tmp, *tmp_password = NULL;
2268         int left;
2269         const char *p;
2270         GByteArray *ret = NULL;
2271
2272         g_return_val_if_fail (data != NULL, NULL);
2273         g_return_val_if_fail (len > 0, NULL);
2274         if (out_password)
2275                 g_return_val_if_fail (*out_password == NULL, NULL);
2276
2277         /* Make the password if needed */
2278         if (!in_password) {
2279                 if (!crypto_randomize (pw_buf, sizeof (pw_buf), error))
2280                         return NULL;
2281                 in_password = tmp_password = nm_utils_bin2hexstr (pw_buf, sizeof (pw_buf), -1);
2282         }
2283
2284         salt_len = 8;
2285         if (!crypto_randomize (salt, salt_len, error))
2286                 goto out;
2287
2288         key = crypto_make_des_aes_key (CIPHER_DES_EDE3_CBC, &salt[0], salt_len, in_password, &key_len, NULL);
2289         if (!key)
2290                 g_return_val_if_reached (NULL);
2291
2292         enc = crypto_encrypt (CIPHER_DES_EDE3_CBC, data, len, salt, salt_len, key, key_len, &enc_len, error);
2293         if (!enc)
2294                 goto out;
2295
2296         pem = g_string_sized_new (enc_len * 2 + 100);
2297         g_string_append (pem, "-----BEGIN RSA PRIVATE KEY-----\n");
2298         g_string_append (pem, "Proc-Type: 4,ENCRYPTED\n");
2299
2300         /* Convert the salt to a hex string */
2301         tmp = nm_utils_bin2hexstr (salt, salt_len, salt_len * 2);
2302         g_string_append_printf (pem, "DEK-Info: %s,%s\n\n", CIPHER_DES_EDE3_CBC, tmp);
2303         g_free (tmp);
2304
2305         /* Convert the encrypted key to a base64 string */
2306         p = tmp = g_base64_encode ((const guchar *) enc, enc_len);
2307         left = strlen (tmp);
2308         while (left > 0) {
2309                 g_string_append_len (pem, p, (left < 64) ? left : 64);
2310                 g_string_append_c (pem, '\n');
2311                 left -= 64;
2312                 p += 64;
2313         }
2314         g_free (tmp);
2315
2316         g_string_append (pem, "-----END RSA PRIVATE KEY-----\n");
2317
2318         ret = g_byte_array_sized_new (pem->len);
2319         g_byte_array_append (ret, (const unsigned char *) pem->str, pem->len);
2320         if (tmp_password && out_password)
2321                 *out_password = g_strdup (tmp_password);
2322
2323 out:
2324         if (key) {
2325                 memset (key, 0, key_len);
2326                 g_free (key);
2327         }
2328         if (enc) {
2329                 memset (enc, 0, enc_len);
2330                 g_free (enc);
2331         }
2332         if (pem)
2333                 g_string_free (pem, TRUE);
2334
2335         if (tmp_password) {
2336                 memset (tmp_password, 0, strlen (tmp_password));
2337                 g_free (tmp_password);
2338         }
2339
2340         return ret;
2341 }
2342
2343 static gboolean
2344 file_has_extension (const char *filename, const char *extensions[])
2345 {
2346         const char *ext;
2347         int i;
2348
2349         ext = strrchr (filename, '.');
2350         if (!ext)
2351                 return FALSE;
2352
2353         for (i = 0; extensions[i]; i++) {
2354                 if (!g_ascii_strcasecmp (ext, extensions[i]))
2355                         return TRUE;
2356         }
2357
2358         return FALSE;
2359 }
2360
2361 /**
2362  * nm_utils_file_is_certificate:
2363  * @filename: name of the file to test
2364  *
2365  * Tests if @filename has a valid extension for an X.509 certificate file
2366  * (".cer", ".crt", ".der", or ".pem"), and contains a certificate in a format
2367  * recognized by NetworkManager.
2368  *
2369  * Returns: %TRUE if the file is a certificate, %FALSE if it is not
2370  **/
2371 gboolean
2372 nm_utils_file_is_certificate (const char *filename)
2373 {
2374         const char *extensions[] = { ".der", ".pem", ".crt", ".cer", NULL };
2375         NMCryptoFileFormat file_format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
2376         GByteArray *cert;
2377
2378         g_return_val_if_fail (filename != NULL, FALSE);
2379
2380         if (!file_has_extension (filename, extensions))
2381                 return FALSE;
2382
2383         cert = crypto_load_and_verify_certificate (filename, &file_format, NULL);
2384         if (cert)
2385                 g_byte_array_unref (cert);
2386
2387         return file_format = NM_CRYPTO_FILE_FORMAT_X509;
2388 }
2389
2390 /**
2391  * nm_utils_file_is_private_key:
2392  * @filename: name of the file to test
2393  * @out_encrypted: (out): on return, whether the file is encrypted
2394  *
2395  * Tests if @filename has a valid extension for an X.509 private key file
2396  * (".der", ".key", ".pem", or ".p12"), and contains a private key in a format
2397  * recognized by NetworkManager.
2398  *
2399  * Returns: %TRUE if the file is a private key, %FALSE if it is not
2400  **/
2401 gboolean
2402 nm_utils_file_is_private_key (const char *filename, gboolean *out_encrypted)
2403 {
2404         const char *extensions[] = { ".der", ".pem", ".p12", ".key", NULL };
2405
2406         g_return_val_if_fail (filename != NULL, FALSE);
2407         g_return_val_if_fail (out_encrypted == NULL || *out_encrypted == FALSE, FALSE);
2408
2409         if (!file_has_extension (filename, extensions))
2410                 return FALSE;
2411
2412         return crypto_verify_private_key (filename, NULL, out_encrypted, NULL) != NM_CRYPTO_FILE_FORMAT_UNKNOWN;
2413 }
2414
2415 /**
2416  * nm_utils_file_is_pkcs12:
2417  * @filename: name of the file to test
2418  *
2419  * Tests if @filename is a PKCS#<!-- -->12 file.
2420  *
2421  * Returns: %TRUE if the file is PKCS#<!-- -->12, %FALSE if it is not
2422  **/
2423 gboolean
2424 nm_utils_file_is_pkcs12 (const char *filename)
2425 {
2426         g_return_val_if_fail (filename != NULL, FALSE);
2427
2428         return crypto_is_pkcs12_file (filename, NULL);
2429 }
2430
2431 /**********************************************************************************************/
2432
2433 gboolean
2434 _nm_utils_check_file (const char *filename,
2435                       gint64 check_owner,
2436                       NMUtilsCheckFilePredicate check_file,
2437                       gpointer user_data,
2438                       struct stat *out_st,
2439                       GError **error)
2440 {
2441         struct stat st_backup;
2442
2443         if (!out_st)
2444                 out_st = &st_backup;
2445
2446         if (stat (filename, out_st) != 0) {
2447                 int errsv = errno;
2448
2449                 g_set_error (error,
2450                              NM_VPN_PLUGIN_ERROR,
2451                              NM_VPN_PLUGIN_ERROR_FAILED,
2452                              _("failed stat file %s: %s"), filename, strerror (errsv));
2453                 return FALSE;
2454         }
2455
2456         /* ignore non-files. */
2457         if (!S_ISREG (out_st->st_mode)) {
2458                 g_set_error (error,
2459                              NM_VPN_PLUGIN_ERROR,
2460                              NM_VPN_PLUGIN_ERROR_FAILED,
2461                              _("not a file (%s)"), filename);
2462                 return FALSE;
2463         }
2464
2465         /* with check_owner enabled, check that the file belongs to the
2466          * owner or root. */
2467         if (   check_owner >= 0
2468             && (out_st->st_uid != 0 && (gint64) out_st->st_uid != check_owner)) {
2469                 g_set_error (error,
2470                              NM_VPN_PLUGIN_ERROR,
2471                              NM_VPN_PLUGIN_ERROR_FAILED,
2472                              _("invalid file owner %d for %s"), out_st->st_uid, filename);
2473                 return FALSE;
2474         }
2475
2476         /* with check_owner enabled, check that the file cannot be modified
2477          * by other users (except root). */
2478         if (   check_owner >= 0
2479             && NM_FLAGS_ANY (out_st->st_mode, S_IWGRP | S_IWOTH | S_ISUID)) {
2480                 g_set_error (error,
2481                              NM_VPN_PLUGIN_ERROR,
2482                              NM_VPN_PLUGIN_ERROR_FAILED,
2483                              _("file permissions for %s"), filename);
2484                 return FALSE;
2485         }
2486
2487         if (    check_file
2488             && !check_file (filename, out_st, user_data, error)) {
2489                 if (error && !*error) {
2490                         g_set_error (error,
2491                                      NM_VPN_PLUGIN_ERROR,
2492                                      NM_VPN_PLUGIN_ERROR_FAILED,
2493                                      _("reject %s"), filename);
2494                 }
2495                 return FALSE;
2496         }
2497
2498         return TRUE;
2499 }
2500
2501
2502 gboolean
2503 _nm_utils_check_module_file (const char *name,
2504                              int check_owner,
2505                              NMUtilsCheckFilePredicate check_file,
2506                              gpointer user_data,
2507                              GError **error)
2508 {
2509         if (!g_path_is_absolute (name)) {
2510                 g_set_error (error,
2511                              NM_VPN_PLUGIN_ERROR,
2512                              NM_VPN_PLUGIN_ERROR_FAILED,
2513                              _("path is not absolute (%s)"), name);
2514                 return FALSE;
2515         }
2516
2517         /* Set special error code if the file doesn't exist.
2518          * The VPN package might be split into separate packages,
2519          * so it could be correct that the plugin file is missing.
2520          *
2521          * Note that nm-applet checks for this error code to fail
2522          * gracefully. */
2523         if (!g_file_test (name, G_FILE_TEST_EXISTS)) {
2524                 g_set_error (error,
2525                              G_FILE_ERROR,
2526                              G_FILE_ERROR_NOENT,
2527                              _("Plugin file does not exist (%s)"), name);
2528                 return FALSE;
2529         }
2530
2531         if (!g_file_test (name, G_FILE_TEST_IS_REGULAR)) {
2532                 g_set_error (error,
2533                              NM_VPN_PLUGIN_ERROR,
2534                              NM_VPN_PLUGIN_ERROR_FAILED,
2535                              _("Plugin is not a valid file (%s)"), name);
2536                 return FALSE;
2537         }
2538
2539         if (g_str_has_suffix (name, ".la")) {
2540                 /* g_module_open() treats files that end with .la special.
2541                  * We don't want to parse the libtool archive. Just error out. */
2542                 g_set_error (error,
2543                              NM_VPN_PLUGIN_ERROR,
2544                              NM_VPN_PLUGIN_ERROR_FAILED,
2545                              _("libtool archives are not supported (%s)"), name);
2546                 return FALSE;
2547         }
2548
2549         return _nm_utils_check_file (name,
2550                                      check_owner,
2551                                      check_file,
2552                                      user_data,
2553                                      NULL,
2554                                      error);
2555 }
2556
2557 /**********************************************************************************************/
2558
2559 /**
2560  * nm_utils_file_search_in_paths:
2561  * @progname: the helper program name, like "iptables"
2562  *   Must be a non-empty string, without path separator (/).
2563  * @try_first: (allow-none): a custom path to try first before searching.
2564  *   It is silently ignored if it is empty or not an absolute path.
2565  * @paths: (allow-none): a %NULL terminated list of search paths.
2566  *   Can be empty or %NULL, in which case only @try_first is checked.
2567  * @file_test_flags: the flags passed to g_file_test() when searching
2568  *   for @progname. Set it to 0 to skip the g_file_test().
2569  * @predicate: (scope call): if given, pass the file name to this function
2570  *   for additional checks. This check is performed after the check for
2571  *   @file_test_flags. You cannot omit both @file_test_flags and @predicate.
2572  * @user_data: (closure): (allow-none): user data for @predicate function.
2573  * @error: (allow-none): on failure, set a "not found" error %G_IO_ERROR %G_IO_ERROR_NOT_FOUND.
2574  *
2575  * Searches for a @progname file in a list of search @paths.
2576  *
2577  * Returns: (transfer none): the full path to the helper, if found, or %NULL if not found.
2578  *   The returned string is not owned by the caller, but later
2579  *   invocations of the function might overwrite it.
2580  */
2581 const char *
2582 nm_utils_file_search_in_paths (const char *progname,
2583                                const char *try_first,
2584                                const char *const *paths,
2585                                GFileTest file_test_flags,
2586                                NMUtilsFileSearchInPathsPredicate predicate,
2587                                gpointer user_data,
2588                                GError **error)
2589 {
2590         GString *tmp;
2591         const char *ret;
2592
2593         g_return_val_if_fail (!error || !*error, NULL);
2594         g_return_val_if_fail (progname && progname[0] && !strchr (progname, '/'), NULL);
2595         g_return_val_if_fail (file_test_flags || predicate, NULL);
2596
2597         /* Only consider @try_first if it is a valid, absolute path. This makes
2598          * it simpler to pass in a path from configure checks. */
2599         if (   try_first
2600             && try_first[0] == '/'
2601             && (file_test_flags == 0 || g_file_test (try_first, file_test_flags))
2602             && (!predicate || predicate (try_first, user_data)))
2603                 return g_intern_string (try_first);
2604
2605         if (!paths || !*paths)
2606                 goto NOT_FOUND;
2607
2608         tmp = g_string_sized_new (50);
2609         for (; *paths; paths++) {
2610                 if (!*paths)
2611                         continue;
2612                 g_string_append (tmp, *paths);
2613                 if (tmp->str[tmp->len - 1] != '/')
2614                         g_string_append_c (tmp, '/');
2615                 g_string_append (tmp, progname);
2616                 if (   (file_test_flags == 0 || g_file_test (tmp->str, file_test_flags))
2617                     && (!predicate || predicate (tmp->str, user_data))) {
2618                         ret = g_intern_string (tmp->str);
2619                         g_string_free (tmp, TRUE);
2620                         return ret;
2621                 }
2622                 g_string_set_size (tmp, 0);
2623         }
2624         g_string_free (tmp, TRUE);
2625
2626 NOT_FOUND:
2627         g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Could not find \"%s\" binary"), progname);
2628         return NULL;
2629 }
2630
2631 /**********************************************************************************************/
2632
2633 /* Band, channel/frequency stuff for wireless */
2634 struct cf_pair {
2635         guint32 chan;
2636         guint32 freq;
2637 };
2638
2639 static struct cf_pair a_table[] = {
2640         /* A band */
2641         {  7, 5035 },
2642         {  8, 5040 },
2643         {  9, 5045 },
2644         { 11, 5055 },
2645         { 12, 5060 },
2646         { 16, 5080 },
2647         { 34, 5170 },
2648         { 36, 5180 },
2649         { 38, 5190 },
2650         { 40, 5200 },
2651         { 42, 5210 },
2652         { 44, 5220 },
2653         { 46, 5230 },
2654         { 48, 5240 },
2655         { 50, 5250 },
2656         { 52, 5260 },
2657         { 56, 5280 },
2658         { 58, 5290 },
2659         { 60, 5300 },
2660         { 64, 5320 },
2661         { 100, 5500 },
2662         { 104, 5520 },
2663         { 108, 5540 },
2664         { 112, 5560 },
2665         { 116, 5580 },
2666         { 120, 5600 },
2667         { 124, 5620 },
2668         { 128, 5640 },
2669         { 132, 5660 },
2670         { 136, 5680 },
2671         { 140, 5700 },
2672         { 149, 5745 },
2673         { 152, 5760 },
2674         { 153, 5765 },
2675         { 157, 5785 },
2676         { 160, 5800 },
2677         { 161, 5805 },
2678         { 165, 5825 },
2679         { 183, 4915 },
2680         { 184, 4920 },
2681         { 185, 4925 },
2682         { 187, 4935 },
2683         { 188, 4945 },
2684         { 192, 4960 },
2685         { 196, 4980 },
2686         { 0, -1 }
2687 };
2688
2689 static struct cf_pair bg_table[] = {
2690         /* B/G band */
2691         { 1, 2412 },
2692         { 2, 2417 },
2693         { 3, 2422 },
2694         { 4, 2427 },
2695         { 5, 2432 },
2696         { 6, 2437 },
2697         { 7, 2442 },
2698         { 8, 2447 },
2699         { 9, 2452 },
2700         { 10, 2457 },
2701         { 11, 2462 },
2702         { 12, 2467 },
2703         { 13, 2472 },
2704         { 14, 2484 },
2705         { 0, -1 }
2706 };
2707
2708 /**
2709  * nm_utils_wifi_freq_to_channel:
2710  * @freq: frequency
2711  *
2712  * Utility function to translate a Wi-Fi frequency to its corresponding channel.
2713  *
2714  * Returns: the channel represented by the frequency or 0
2715  **/
2716 guint32
2717 nm_utils_wifi_freq_to_channel (guint32 freq)
2718 {
2719         int i = 0;
2720
2721         if (freq > 4900) {
2722                 while (a_table[i].chan && (a_table[i].freq != freq))
2723                         i++;
2724                 return a_table[i].chan;
2725         } else {
2726                 while (bg_table[i].chan && (bg_table[i].freq != freq))
2727                         i++;
2728                 return bg_table[i].chan;
2729         }
2730
2731         return 0;
2732 }
2733
2734 /**
2735  * nm_utils_wifi_channel_to_freq:
2736  * @channel: channel
2737  * @band: frequency band for wireless ("a" or "bg")
2738  *
2739  * Utility function to translate a Wi-Fi channel to its corresponding frequency.
2740  *
2741  * Returns: the frequency represented by the channel of the band,
2742  *          or -1 when the freq is invalid, or 0 when the band
2743  *          is invalid
2744  **/
2745 guint32
2746 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band)
2747 {
2748         int i = 0;
2749
2750         if (!strcmp (band, "a")) {
2751                 while (a_table[i].chan && (a_table[i].chan != channel))
2752                         i++;
2753                 return a_table[i].freq;
2754         } else if (!strcmp (band, "bg")) {
2755                 while (bg_table[i].chan && (bg_table[i].chan != channel))
2756                         i++;
2757                 return bg_table[i].freq;
2758         }
2759
2760         return 0;
2761 }
2762
2763 /**
2764  * nm_utils_wifi_find_next_channel:
2765  * @channel: current channel
2766  * @direction: whether going downward (0 or less) or upward (1 or more)
2767  * @band: frequency band for wireless ("a" or "bg")
2768  *
2769  * Utility function to find out next/previous Wi-Fi channel for a channel.
2770  *
2771  * Returns: the next channel in the specified direction or 0
2772  **/
2773 guint32
2774 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band)
2775 {
2776         size_t a_size = sizeof (a_table) / sizeof (struct cf_pair);
2777         size_t bg_size = sizeof (bg_table) / sizeof (struct cf_pair);
2778         struct cf_pair *pair = NULL;
2779
2780         if (!strcmp (band, "a")) {
2781                 if (channel < a_table[0].chan)
2782                         return a_table[0].chan;
2783                 if (channel > a_table[a_size - 2].chan)
2784                         return a_table[a_size - 2].chan;
2785                 pair = &a_table[0];
2786         } else if (!strcmp (band, "bg")) {
2787                 if (channel < bg_table[0].chan)
2788                         return bg_table[0].chan;
2789                 if (channel > bg_table[bg_size - 2].chan)
2790                         return bg_table[bg_size - 2].chan;
2791                 pair = &bg_table[0];
2792         } else {
2793                 g_assert_not_reached ();
2794                 return 0;
2795         }
2796
2797         while (pair->chan) {
2798                 if (channel == pair->chan)
2799                         return channel;
2800                 if ((channel < (pair+1)->chan) && (channel > pair->chan)) {
2801                         if (direction > 0)
2802                                 return (pair+1)->chan;
2803                         else
2804                                 return pair->chan;
2805                 }
2806                 pair++;
2807         }
2808         return 0;
2809 }
2810
2811 /**
2812  * nm_utils_wifi_is_channel_valid:
2813  * @channel: channel
2814  * @band: frequency band for wireless ("a" or "bg")
2815  *
2816  * Utility function to verify Wi-Fi channel validity.
2817  *
2818  * Returns: %TRUE or %FALSE
2819  **/
2820 gboolean
2821 nm_utils_wifi_is_channel_valid (guint32 channel, const char *band)
2822 {
2823         struct cf_pair *table = NULL;
2824         int i = 0;
2825
2826         if (!strcmp (band, "a"))
2827                 table = a_table;
2828         else if (!strcmp (band, "bg"))
2829                 table = bg_table;
2830         else
2831                 return FALSE;
2832
2833         while (table[i].chan && (table[i].chan != channel))
2834                 i++;
2835
2836         if (table[i].chan != 0)
2837                 return TRUE;
2838         else
2839                 return FALSE;
2840 }
2841
2842 static const guint *
2843 _wifi_freqs (gboolean bg_band)
2844 {
2845         static guint *freqs_2ghz = NULL;
2846         static guint *freqs_5ghz = NULL;
2847         guint *freqs;
2848
2849         freqs = bg_band ? freqs_2ghz : freqs_5ghz;
2850         if (G_UNLIKELY (freqs == NULL)) {
2851                 struct cf_pair *table;
2852                 int i;
2853
2854                 table = bg_band ? bg_table : a_table;
2855                 freqs = g_new0 (guint, bg_band ? G_N_ELEMENTS (bg_table) : G_N_ELEMENTS (a_table));
2856                 for (i = 0; table[i].chan; i++)
2857                         freqs[i] = table[i].freq;
2858                 freqs[i] = 0;
2859                 if (bg_band)
2860                         freqs_2ghz = freqs;
2861                 else
2862                         freqs_5ghz = freqs;
2863         }
2864         return freqs;
2865 }
2866
2867 /**
2868  * nm_utils_wifi_2ghz_freqs:
2869  *
2870  * Utility function to return 2.4 GHz Wi-Fi frequencies (802.11bg band).
2871  *
2872  * Returns: zero-terminated array of frequencies numbers (in MHz)
2873  *
2874  * Since: 1.2
2875  **/
2876 const guint *
2877 nm_utils_wifi_2ghz_freqs (void)
2878 {
2879         return _wifi_freqs (TRUE);
2880 }
2881 NM_BACKPORT_SYMBOL (libnm_1_0_6, const guint *, nm_utils_wifi_2ghz_freqs, (void), ());
2882
2883 /**
2884  * nm_utils_wifi_5ghz_freqs:
2885  *
2886  * Utility function to return 5 GHz Wi-Fi frequencies (802.11a band).
2887  *
2888  * Returns: zero-terminated array of frequencies numbers (in MHz)
2889  *
2890  * Since: 1.2
2891  **/
2892 const guint *
2893 nm_utils_wifi_5ghz_freqs (void)
2894 {
2895         return _wifi_freqs (FALSE);
2896 }
2897 NM_BACKPORT_SYMBOL (libnm_1_0_6, const guint *, nm_utils_wifi_5ghz_freqs, (void), ());
2898
2899 /**
2900  * nm_utils_wifi_strength_bars:
2901  * @strength: the access point strength, from 0 to 100
2902  *
2903  * Converts @strength into a 4-character-wide graphical representation of
2904  * strength suitable for printing to stdout. If the current locale and terminal
2905  * support it, this will use unicode graphics characters to represent
2906  * "bars". Otherwise it will use 0 to 4 asterisks.
2907  *
2908  * Returns: the graphical representation of the access point strength
2909  */
2910 const char *
2911 nm_utils_wifi_strength_bars (guint8 strength)
2912 {
2913         static const char *strength_full, *strength_high, *strength_med, *strength_low, *strength_none;
2914
2915         if (G_UNLIKELY (strength_full == NULL)) {
2916                 gboolean can_show_graphics = TRUE;
2917                 char *locale_str;
2918
2919                 if (!g_get_charset (NULL)) {
2920                         /* Non-UTF-8 locale */
2921                         locale_str = g_locale_from_utf8 ("\342\226\202\342\226\204\342\226\206\342\226\210", -1, NULL, NULL, NULL);
2922                         if (locale_str)
2923                                 g_free (locale_str);
2924                         else
2925                                 can_show_graphics = FALSE;
2926                 }
2927
2928                 /* The linux console font doesn't have these characters */
2929                 if (g_strcmp0 (g_getenv ("TERM"), "linux") == 0)
2930                         can_show_graphics = FALSE;
2931
2932                 if (can_show_graphics) {
2933                         strength_full = /* â–‚▄▆█ */ "\342\226\202\342\226\204\342\226\206\342\226\210";
2934                         strength_high = /* â–‚â–„â–†_ */ "\342\226\202\342\226\204\342\226\206_";
2935                         strength_med  = /* â–‚â–„__ */ "\342\226\202\342\226\204__";
2936                         strength_low  = /* â–‚___ */ "\342\226\202___";
2937                         strength_none = /* ____ */ "____";
2938                 } else {
2939                         strength_full = "****";
2940                         strength_high = "*** ";
2941                         strength_med  = "**  ";
2942                         strength_low  = "*   ";
2943                         strength_none = "    ";
2944                 }
2945         }
2946
2947         if (strength > 80)
2948                 return strength_full;
2949         else if (strength > 55)
2950                 return strength_high;
2951         else if (strength > 30)
2952                 return strength_med;
2953         else if (strength > 5)
2954                 return strength_low;
2955         else
2956                 return strength_none;
2957 }
2958
2959 /**
2960  * nm_utils_hwaddr_len:
2961  * @type: the type of address; either <literal>ARPHRD_ETHER</literal> or
2962  * <literal>ARPHRD_INFINIBAND</literal>
2963  *
2964  * Returns the length in octets of a hardware address of type @type.
2965  *
2966  * It is an error to call this function with any value other than
2967  * <literal>ARPHRD_ETHER</literal> or <literal>ARPHRD_INFINIBAND</literal>.
2968  *
2969  * Return value: the length.
2970  */
2971 gsize
2972 nm_utils_hwaddr_len (int type)
2973 {
2974         g_return_val_if_fail (type == ARPHRD_ETHER || type == ARPHRD_INFINIBAND, 0);
2975
2976         if (type == ARPHRD_ETHER)
2977                 return ETH_ALEN;
2978         else if (type == ARPHRD_INFINIBAND)
2979                 return INFINIBAND_ALEN;
2980
2981         g_assert_not_reached ();
2982 }
2983
2984 #define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
2985
2986 /**
2987  * nm_utils_hwaddr_atoba:
2988  * @asc: the ASCII representation of a hardware address
2989  * @length: the expected length in bytes of the result
2990  *
2991  * Parses @asc and converts it to binary form in a #GByteArray. See
2992  * nm_utils_hwaddr_aton() if you don't want a #GByteArray.
2993  *
2994  * Return value: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
2995  * be parsed
2996  */
2997 GByteArray *
2998 nm_utils_hwaddr_atoba (const char *asc, gsize length)
2999 {
3000         GByteArray *ba;
3001
3002         g_return_val_if_fail (asc != NULL, NULL);
3003         g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
3004
3005         ba = g_byte_array_sized_new (length);
3006         g_byte_array_set_size (ba, length);
3007         if (!nm_utils_hwaddr_aton (asc, ba->data, length)) {
3008                 g_byte_array_unref (ba);
3009                 return NULL;
3010         }
3011
3012         return ba;
3013 }
3014
3015 /**
3016  * nm_utils_hwaddr_aton:
3017  * @asc: the ASCII representation of a hardware address
3018  * @buffer: buffer to store the result into
3019  * @length: the expected length in bytes of the result and
3020  * the size of the buffer in bytes.
3021  *
3022  * Parses @asc and converts it to binary form in @buffer.
3023  * Bytes in @asc can be sepatared by colons (:), or hyphens (-), but not mixed.
3024  *
3025  * Return value: @buffer, or %NULL if @asc couldn't be parsed
3026  *   or would be shorter or longer than @length.
3027  */
3028 guint8 *
3029 nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize length)
3030 {
3031         const char *in = asc;
3032         guint8 *out = (guint8 *)buffer;
3033         char delimiter = '\0';
3034
3035         g_return_val_if_fail (asc != NULL, NULL);
3036         g_return_val_if_fail (buffer != NULL, NULL);
3037         g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
3038
3039         while (length && *in) {
3040                 guint8 d1 = in[0], d2 = in[1];
3041
3042                 if (!g_ascii_isxdigit (d1))
3043                         return NULL;
3044
3045                 /* If there's no leading zero (ie "aa:b:cc") then fake it */
3046                 if (d2 && g_ascii_isxdigit (d2)) {
3047                         *out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
3048                         in += 2;
3049                 } else {
3050                         /* Fake leading zero */
3051                         *out++ = (HEXVAL ('0') << 4) + HEXVAL (d1);
3052                         in += 1;
3053                 }
3054
3055                 length--;
3056                 if (*in) {
3057                         if (delimiter == '\0') {
3058                                 if (*in == ':' || *in == '-')
3059                                         delimiter = *in;
3060                                 else
3061                                         return NULL;
3062                         } else {
3063                                 if (*in != delimiter)
3064                                         return NULL;
3065                         }
3066                         in++;
3067                 }
3068         }
3069
3070         if (length == 0 && !*in)
3071                 return buffer;
3072         else
3073                 return NULL;
3074 }
3075
3076 /**
3077  * nm_utils_hwaddr_ntoa:
3078  * @addr: (type guint8) (array length=length): a binary hardware address
3079  * @length: the length of @addr
3080  *
3081  * Converts @addr to textual form.
3082  *
3083  * Return value: (transfer full): the textual form of @addr
3084  */
3085 char *
3086 nm_utils_hwaddr_ntoa (gconstpointer addr, gsize length)
3087 {
3088         const guint8 *in = addr;
3089         char *out, *result;
3090         const char *LOOKUP = "0123456789ABCDEF";
3091
3092         g_return_val_if_fail (addr != NULL, g_strdup (""));
3093         g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, g_strdup (""));
3094
3095         result = out = g_malloc (length * 3);
3096         while (length--) {
3097                 guint8 v = *in++;
3098
3099                 *out++ = LOOKUP[v >> 4];
3100                 *out++ = LOOKUP[v & 0x0F];
3101                 if (length)
3102                         *out++ = ':';
3103         }
3104
3105         *out = 0;
3106         return result;
3107 }
3108
3109 static int
3110 hwaddr_binary_len (const char *asc)
3111 {
3112         int octets = 1;
3113
3114         if (!*asc)
3115                 return 0;
3116
3117         for (; *asc; asc++) {
3118                 if (*asc == ':' || *asc == '-')
3119                         octets++;
3120         }
3121         return octets;
3122 }
3123
3124 /**
3125  * nm_utils_hwaddr_valid:
3126  * @asc: the ASCII representation of a hardware address
3127  * @length: the length of address that @asc is expected to convert to
3128  *   (or -1 to accept any length up to %NM_UTILS_HWADDR_LEN_MAX)
3129  *
3130  * Parses @asc to see if it is a valid hardware address of the given
3131  * length.
3132  *
3133  * Return value: %TRUE if @asc appears to be a valid hardware address
3134  *   of the indicated length, %FALSE if not.
3135  */
3136 gboolean
3137 nm_utils_hwaddr_valid (const char *asc, gssize length)
3138 {
3139         guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
3140
3141         g_return_val_if_fail (asc != NULL, FALSE);
3142         g_return_val_if_fail (length == -1 || (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX), FALSE);
3143
3144         if (length == -1) {
3145                 length = hwaddr_binary_len (asc);
3146                 if (length == 0 || length > NM_UTILS_HWADDR_LEN_MAX)
3147                         return FALSE;
3148         }
3149
3150         return nm_utils_hwaddr_aton (asc, buf, length) != NULL;
3151 }
3152
3153 /**
3154  * nm_utils_hwaddr_canonical:
3155  * @asc: the ASCII representation of a hardware address
3156  * @length: the length of address that @asc is expected to convert to
3157  *   (or -1 to accept any length up to %NM_UTILS_HWADDR_LEN_MAX)
3158  *
3159  * Parses @asc to see if it is a valid hardware address of the given
3160  * length, and if so, returns it in canonical form (uppercase, with
3161  * leading 0s as needed, and with colons rather than hyphens).
3162  *
3163  * Return value: (transfer full): the canonicalized address if @asc appears to
3164  *   be a valid hardware address of the indicated length, %NULL if not.
3165  */
3166 char *
3167 nm_utils_hwaddr_canonical (const char *asc, gssize length)
3168 {
3169         guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
3170
3171         g_return_val_if_fail (asc != NULL, NULL);
3172         g_return_val_if_fail (length == -1 || (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX), NULL);
3173
3174         if (length == -1) {
3175                 length = hwaddr_binary_len (asc);
3176                 if (length == 0 || length > NM_UTILS_HWADDR_LEN_MAX)
3177                         return NULL;
3178         }
3179
3180         if (nm_utils_hwaddr_aton (asc, buf, length) == NULL)
3181                 return NULL;
3182
3183         return nm_utils_hwaddr_ntoa (buf, length);
3184 }
3185
3186 /* This is used to possibly canonicalize values passed to MAC address property
3187  * setters. Unlike nm_utils_hwaddr_canonical(), it accepts %NULL, and if you
3188  * pass it an invalid MAC address, it just returns that string rather than
3189  * returning %NULL (so that we can return a proper error from verify() later).
3190  */
3191 char *
3192 _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize length)
3193 {
3194         char *canonical;
3195
3196         if (!mac)
3197                 return NULL;
3198
3199         canonical = nm_utils_hwaddr_canonical (mac, length);
3200         if (canonical)
3201                 return canonical;
3202         else
3203                 return g_strdup (mac);
3204 }
3205
3206 /**
3207  * nm_utils_hwaddr_matches:
3208  * @hwaddr1: pointer to a binary or ASCII hardware address, or %NULL
3209  * @hwaddr1_len: size of @hwaddr1, or -1 if @hwaddr1 is ASCII
3210  * @hwaddr2: pointer to a binary or ASCII hardware address, or %NULL
3211  * @hwaddr2_len: size of @hwaddr2, or -1 if @hwaddr2 is ASCII
3212  *
3213  * Generalized hardware address comparison function. Tests if @hwaddr1 and
3214  * @hwaddr2 "equal" (or more precisely, "equivalent"), with several advantages
3215  * over a simple memcmp():
3216  *
3217  *   1. If @hwaddr1_len or @hwaddr2_len is -1, then the corresponding address is
3218  *      assumed to be ASCII rather than binary, and will be converted to binary
3219  *      before being compared.
3220  *
3221  *   2. If @hwaddr1 or @hwaddr2 is %NULL, it is treated instead as though it was
3222  *      a zero-filled buffer @hwaddr1_len or @hwaddr2_len bytes long.
3223  *
3224  *   3. If @hwaddr1 and @hwaddr2 are InfiniBand hardware addresses (that is, if
3225  *      they are <literal>INFINIBAND_ALEN</literal> bytes long in binary form)
3226  *      then only the last 8 bytes are compared, since those are the only bytes
3227  *      that actually identify the hardware. (The other 12 bytes will change
3228  *      depending on the configuration of the InfiniBand fabric that the device
3229  *      is connected to.)
3230  *
3231  * If a passed-in ASCII hardware address cannot be parsed, or would parse to an
3232  * address larger than %NM_UTILS_HWADDR_LEN_MAX, then it will silently fail to
3233  * match. (This means that externally-provided address strings do not need to be
3234  * sanity-checked before comparing them against known good addresses; they are
3235  * guaranteed to not match if they are invalid.)
3236  *
3237  * Return value: %TRUE if @hwaddr1 and @hwaddr2 are equivalent, %FALSE if they are
3238  *   different (or either of them is invalid).
3239  */
3240 gboolean
3241 nm_utils_hwaddr_matches (gconstpointer hwaddr1,
3242                          gssize        hwaddr1_len,
3243                          gconstpointer hwaddr2,
3244                          gssize        hwaddr2_len)
3245 {
3246         guint8 buf1[NM_UTILS_HWADDR_LEN_MAX], buf2[NM_UTILS_HWADDR_LEN_MAX];
3247
3248         if (hwaddr1_len == -1) {
3249                 g_return_val_if_fail (hwaddr1 != NULL, FALSE);
3250
3251                 hwaddr1_len = hwaddr_binary_len (hwaddr1);
3252                 if (hwaddr1_len == 0 || hwaddr1_len > NM_UTILS_HWADDR_LEN_MAX)
3253                         return FALSE;
3254                 if (!nm_utils_hwaddr_aton (hwaddr1, buf1, hwaddr1_len))
3255                         return FALSE;
3256
3257                 hwaddr1 = buf1;
3258         } else {
3259                 g_return_val_if_fail (hwaddr1_len > 0 && hwaddr1_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
3260
3261                 if (!hwaddr1) {
3262                         memset (buf1, 0, hwaddr1_len);
3263                         hwaddr1 = buf1;
3264                 }
3265         }
3266
3267         if (hwaddr2_len == -1) {
3268                 g_return_val_if_fail (hwaddr2 != NULL, FALSE);
3269
3270                 if (!nm_utils_hwaddr_aton (hwaddr2, buf2, hwaddr1_len))
3271                         return FALSE;
3272
3273                 hwaddr2 = buf2;
3274                 hwaddr2_len = hwaddr1_len;
3275         } else {
3276                 g_return_val_if_fail (hwaddr2_len > 0 && hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
3277
3278                 if (!hwaddr2) {
3279                         memset (buf2, 0, hwaddr2_len);
3280                         hwaddr2 = buf2;
3281                 }
3282         }
3283
3284         if (hwaddr1_len != hwaddr2_len)
3285                 return FALSE;
3286
3287         if (hwaddr1_len == INFINIBAND_ALEN) {
3288                 hwaddr1 = (guint8 *)hwaddr1 + INFINIBAND_ALEN - 8;
3289                 hwaddr2 = (guint8 *)hwaddr2 + INFINIBAND_ALEN - 8;
3290                 hwaddr1_len = hwaddr2_len = 8;
3291         }
3292
3293         return !memcmp (hwaddr1, hwaddr2, hwaddr1_len);
3294 }
3295
3296 GVariant *
3297 _nm_utils_hwaddr_to_dbus (const GValue *prop_value)
3298 {
3299         const char *str = g_value_get_string (prop_value);
3300         guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
3301         int len;
3302
3303         if (str) {
3304                 len = hwaddr_binary_len (str);
3305                 g_return_val_if_fail (len > 0 && len <= NM_UTILS_HWADDR_LEN_MAX, NULL);
3306                 if (!nm_utils_hwaddr_aton (str, buf, len))
3307                         len = 0;
3308         } else
3309                 len = 0;
3310
3311         return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1);
3312 }
3313
3314 void
3315 _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
3316                             GValue *prop_value)
3317 {
3318         gsize length = 0;
3319         const guint8 *array = g_variant_get_fixed_array (dbus_value, &length, 1);
3320         char *str;
3321
3322         str = length ? nm_utils_hwaddr_ntoa (array, length) : NULL;
3323         g_value_take_string (prop_value, str);
3324 }
3325
3326 /**
3327  * nm_utils_bin2hexstr:
3328  * @src: (type guint8) (array length=len): an array of bytes
3329  * @len: the length of the @src array
3330  * @final_len: an index where to cut off the returned string, or -1
3331  *
3332  * Converts the byte array @src into a hexadecimal string. If @final_len is
3333  * greater than -1, the returned string is terminated at that index
3334  * (returned_string[final_len] == '\0'),
3335  *
3336  * Return value: (transfer full): the textual form of @bytes
3337  */
3338 /*
3339  * Code originally by Alex Larsson <alexl@redhat.com> and
3340  *  copyright Red Hat, Inc. under terms of the LGPL.
3341  */
3342 char *
3343 nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len)
3344 {
3345         static char hex_digits[] = "0123456789abcdef";
3346         const guint8 *bytes = src;
3347         char *result;
3348         int i;
3349         gsize buflen = (len * 2) + 1;
3350
3351         g_return_val_if_fail (bytes != NULL, NULL);
3352         g_return_val_if_fail (len > 0, NULL);
3353         g_return_val_if_fail (len < 4096, NULL);   /* Arbitrary limit */
3354         if (final_len > -1)
3355                 g_return_val_if_fail (final_len < buflen, NULL);
3356
3357         result = g_malloc0 (buflen);
3358         for (i = 0; i < len; i++) {
3359                 result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
3360                 result[2*i+1] = hex_digits[bytes[i] & 0xf];
3361         }
3362         /* Cut converted key off at the correct length for this cipher type */
3363         if (final_len > -1)
3364                 result[final_len] = '\0';
3365         else
3366                 result[buflen - 1] = '\0';
3367
3368         return result;
3369 }
3370
3371 /**
3372  * nm_utils_hexstr2bin:
3373  * @hex: a string of hexadecimal characters with optional ':' separators
3374  *
3375  * Converts a hexadecimal string @hex into an array of bytes.  The optional
3376  * separator ':' may be used between single or pairs of hexadecimal characters,
3377  * eg "00:11" or "0:1".  Any "0x" at the beginning of @hex is ignored.  @hex
3378  * may not start or end with ':'.
3379  *
3380  * Return value: (transfer full): the converted bytes, or %NULL on error
3381  */
3382 GBytes *
3383 nm_utils_hexstr2bin (const char *hex)
3384 {
3385         guint i = 0, x = 0;
3386         gs_free guint8 *c = NULL;
3387         int a, b;
3388         gboolean found_colon = FALSE;
3389
3390         g_return_val_if_fail (hex != NULL, NULL);
3391
3392         if (strncasecmp (hex, "0x", 2) == 0)
3393                 hex += 2;
3394         found_colon = !!strchr (hex, ':');
3395
3396         c = g_malloc (strlen (hex) / 2 + 1);
3397         for (;;) {
3398                 a = g_ascii_xdigit_value (hex[i++]);
3399                 if (a < 0)
3400                         return NULL;
3401
3402                 if (hex[i] && hex[i] != ':') {
3403                         b = g_ascii_xdigit_value (hex[i++]);
3404                         if (b < 0)
3405                                 return NULL;
3406                         c[x++] = ((guint) a << 4) | ((guint) b);
3407                 } else
3408                         c[x++] = (guint) a;
3409
3410                 if (!hex[i])
3411                         break;
3412                 if (hex[i] == ':') {
3413                         if (!hex[i + 1]) {
3414                                 /* trailing ':' is invalid */
3415                                 return NULL;
3416                         }
3417                         i++;
3418                 } else if (found_colon) {
3419                         /* If colons exist, they must delimit 1 or 2 hex chars */
3420                         return NULL;
3421                 }
3422         }
3423
3424         return g_bytes_new (c, x);
3425 }
3426
3427 /**
3428  * nm_utils_iface_valid_name:
3429  * @name: Name of interface
3430  *
3431  * This function is a 1:1 copy of the kernel's interface validation
3432  * function in net/core/dev.c.
3433  *
3434  * Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
3435  */
3436 gboolean
3437 nm_utils_iface_valid_name (const char *name)
3438 {
3439         g_return_val_if_fail (name != NULL, FALSE);
3440
3441         if (*name == '\0')
3442                 return FALSE;
3443
3444         if (strlen (name) >= 16)
3445                 return FALSE;
3446
3447         if (!strcmp (name, ".") || !strcmp (name, ".."))
3448                 return FALSE;
3449
3450         while (*name) {
3451                 if (*name == '/' || g_ascii_isspace (*name))
3452                         return FALSE;
3453                 name++;
3454         }
3455
3456         return TRUE;
3457 }
3458
3459 /**
3460  * nm_utils_is_uuid:
3461  * @str: a string that might be a UUID
3462  *
3463  * Checks if @str is a UUID
3464  *
3465  * Returns: %TRUE if @str is a UUID, %FALSE if not
3466  */
3467 gboolean
3468 nm_utils_is_uuid (const char *str)
3469 {
3470         const char *p = str;
3471         int num_dashes = 0;
3472
3473         while (*p) {
3474                 if (*p == '-')
3475                         num_dashes++;
3476                 else if (!g_ascii_isxdigit (*p))
3477                         return FALSE;
3478                 p++;
3479         }
3480
3481         if ((num_dashes == 4) && (p - str == 36))
3482                 return TRUE;
3483
3484         /* Backwards compat for older configurations */
3485         if ((num_dashes == 0) && (p - str == 40))
3486                 return TRUE;
3487
3488         return FALSE;
3489 }
3490
3491 static char _nm_utils_inet_ntop_buffer[NM_UTILS_INET_ADDRSTRLEN];
3492
3493 /**
3494  * nm_utils_inet4_ntop: (skip)
3495  * @inaddr: the address that should be converted to string.
3496  * @dst: the destination buffer, it must contain at least
3497  *  <literal>INET_ADDRSTRLEN</literal> or %NM_UTILS_INET_ADDRSTRLEN
3498  *  characters. If set to %NULL, it will return a pointer to an internal, static
3499  *  buffer (shared with nm_utils_inet6_ntop()).  Beware, that the internal
3500  *  buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
3501  *  nm_utils_inet6_ntop() that does not provied it's own @dst buffer. Also,
3502  *  using the internal buffer is not thread safe. When in doubt, pass your own
3503  *  @dst buffer to avoid these issues.
3504  *
3505  * Wrapper for inet_ntop.
3506  *
3507  * Returns: the input buffer @dst, or a pointer to an
3508  *  internal, static buffer. This function cannot fail.
3509  **/
3510 const char *
3511 nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
3512 {
3513         return inet_ntop (AF_INET, &inaddr, dst ? dst : _nm_utils_inet_ntop_buffer,
3514                           INET_ADDRSTRLEN);
3515 }
3516
3517 /**
3518  * nm_utils_inet6_ntop: (skip)
3519  * @in6addr: the address that should be converted to string.
3520  * @dst: the destination buffer, it must contain at least
3521  *  <literal>INET6_ADDRSTRLEN</literal> or %NM_UTILS_INET_ADDRSTRLEN
3522  *  characters. If set to %NULL, it will return a pointer to an internal, static
3523  *  buffer (shared with nm_utils_inet4_ntop()).  Beware, that the internal
3524  *  buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
3525  *  nm_utils_inet6_ntop() that does not provied it's own @dst buffer. Also,
3526  *  using the internal buffer is not thread safe. When in doubt, pass your own
3527  *  @dst buffer to avoid these issues.
3528  *
3529  * Wrapper for inet_ntop.
3530  *
3531  * Returns: the input buffer @dst, or a pointer to an
3532  *  internal, static buffer. %NULL is not allowed as @in6addr,
3533  *  otherwise, this function cannot fail.
3534  **/
3535 const char *
3536 nm_utils_inet6_ntop (const struct in6_addr *in6addr, char *dst)
3537 {
3538         g_return_val_if_fail (in6addr, NULL);
3539         return inet_ntop (AF_INET6, in6addr, dst ? dst : _nm_utils_inet_ntop_buffer,
3540                           INET6_ADDRSTRLEN);
3541 }
3542
3543 /**
3544  * nm_utils_ipaddr_valid:
3545  * @family: <literal>AF_INET</literal> or <literal>AF_INET6</literal>, or
3546  *   <literal>AF_UNSPEC</literal> to accept either
3547  * @ip: an IP address
3548  *
3549  * Checks if @ip contains a valid IP address of the given family.
3550  *
3551  * Return value: %TRUE or %FALSE
3552  */
3553 gboolean
3554 nm_utils_ipaddr_valid (int family, const char *ip)
3555 {
3556         guint8 buf[sizeof (struct in6_addr)];
3557
3558         g_return_val_if_fail (family == AF_INET || family == AF_INET6 || family == AF_UNSPEC, FALSE);
3559
3560         if (!ip)
3561                 return FALSE;
3562
3563         if (family == AF_UNSPEC)
3564                 family = strchr (ip, ':') ? AF_INET6 : AF_INET;
3565
3566         return inet_pton (family, ip, buf) == 1;
3567 }
3568
3569 /**
3570  * nm_utils_check_virtual_device_compatibility:
3571  * @virtual_type: a virtual connection type
3572  * @other_type: a connection type to test against @virtual_type
3573  *
3574  * Determines if a connection of type @virtual_type can (in the
3575  * general case) work with connections of type @other_type.
3576  *
3577  * If @virtual_type is %NM_TYPE_SETTING_VLAN, then this checks if
3578  * @other_type is a valid type for the parent of a VLAN.
3579  *
3580  * If @virtual_type is a "master" type (eg, %NM_TYPE_SETTING_BRIDGE),
3581  * then this checks if @other_type is a valid type for a slave of that
3582  * master.
3583  *
3584  * Note that even if this returns %TRUE it is not guaranteed that
3585  * <emphasis>every</emphasis> connection of type @other_type is
3586  * compatible with @virtual_type; it may depend on the exact
3587  * configuration of the two connections, or on the capabilities of an
3588  * underlying device driver.
3589  *
3590  * Returns: %TRUE or %FALSE
3591  */
3592 gboolean
3593 nm_utils_check_virtual_device_compatibility (GType virtual_type, GType other_type)
3594 {
3595         g_return_val_if_fail (_nm_setting_type_is_base_type (virtual_type), FALSE);
3596         g_return_val_if_fail (_nm_setting_type_is_base_type (other_type), FALSE);
3597
3598         if (virtual_type == NM_TYPE_SETTING_BOND) {
3599                 return (   other_type == NM_TYPE_SETTING_INFINIBAND
3600                         || other_type == NM_TYPE_SETTING_WIRED
3601                         || other_type == NM_TYPE_SETTING_BRIDGE
3602                         || other_type == NM_TYPE_SETTING_BOND
3603                         || other_type == NM_TYPE_SETTING_TEAM
3604                         || other_type == NM_TYPE_SETTING_VLAN);
3605         } else if (virtual_type == NM_TYPE_SETTING_BRIDGE) {
3606                 return (   other_type == NM_TYPE_SETTING_WIRED
3607                         || other_type == NM_TYPE_SETTING_BOND
3608                         || other_type == NM_TYPE_SETTING_TEAM
3609                         || other_type == NM_TYPE_SETTING_VLAN);
3610         } else if (virtual_type == NM_TYPE_SETTING_TEAM) {
3611                 return (   other_type == NM_TYPE_SETTING_WIRED
3612                         || other_type == NM_TYPE_SETTING_BRIDGE
3613                         || other_type == NM_TYPE_SETTING_BOND
3614                         || other_type == NM_TYPE_SETTING_TEAM
3615                         || other_type == NM_TYPE_SETTING_VLAN);
3616         } else if (virtual_type == NM_TYPE_SETTING_VLAN) {
3617                 return (   other_type == NM_TYPE_SETTING_WIRED
3618                         || other_type == NM_TYPE_SETTING_WIRELESS
3619                         || other_type == NM_TYPE_SETTING_BRIDGE
3620                         || other_type == NM_TYPE_SETTING_BOND
3621                         || other_type == NM_TYPE_SETTING_TEAM
3622                         || other_type == NM_TYPE_SETTING_VLAN);
3623         } else {
3624                 g_warn_if_reached ();
3625                 return FALSE;
3626         }
3627 }
3628
3629 typedef struct {
3630         const char *str;
3631         const char *num;
3632 } BondMode;
3633
3634 static BondMode bond_mode_table[] = {
3635         [0] = { "balance-rr",    "0" },
3636         [1] = { "active-backup", "1" },
3637         [2] = { "balance-xor",   "2" },
3638         [3] = { "broadcast",     "3" },
3639         [4] = { "802.3ad",       "4" },
3640         [5] = { "balance-tlb",   "5" },
3641         [6] = { "balance-alb",   "6" },
3642 };
3643
3644 /**
3645  * nm_utils_bond_mode_int_to_string:
3646  * @mode: bonding mode as a numeric value
3647  *
3648  * Convert bonding mode from integer value to descriptive name.
3649  * See https://www.kernel.org/doc/Documentation/networking/bonding.txt for
3650  * available modes.
3651  *
3652  * Returns: bonding mode string, or NULL on error
3653  *
3654  * Since: 1.2
3655  */
3656 const char *
3657 nm_utils_bond_mode_int_to_string (int mode)
3658 {
3659         if (mode >= 0 && mode < G_N_ELEMENTS (bond_mode_table))
3660                 return bond_mode_table[mode].str;
3661         return NULL;
3662 }
3663
3664 /**
3665  * nm_utils_bond_mode_string_to_int:
3666  * @mode: bonding mode as string
3667  *
3668  * Convert bonding mode from string representation to numeric value.
3669  * See https://www.kernel.org/doc/Documentation/networking/bonding.txt for
3670  * available modes.
3671  * The @mode string can be either a descriptive name or a number (as string).
3672  *
3673  * Returns: numeric bond mode, or -1 on error
3674  *
3675  * Since: 1.2
3676  */
3677 int
3678 nm_utils_bond_mode_string_to_int (const char *mode)
3679 {
3680         int i;
3681
3682         if (!mode || !*mode)
3683                 return -1;
3684
3685         for (i = 0; i < G_N_ELEMENTS (bond_mode_table); i++) {
3686                 if (   strcmp (mode, bond_mode_table[i].str) == 0
3687                     || strcmp (mode, bond_mode_table[i].num) == 0)
3688                         return i;
3689         }
3690         return -1;
3691 }
3692
3693 /**********************************************************************************************/
3694
3695 #define STRSTRDICTKEY_V1_SET  0x01
3696 #define STRSTRDICTKEY_V2_SET  0x02
3697 #define STRSTRDICTKEY_ALL_SET 0x03
3698
3699 struct _NMUtilsStrStrDictKey {
3700         char type;
3701         char data[1];
3702 };
3703
3704 guint
3705 _nm_utils_strstrdictkey_hash (gconstpointer a)
3706 {
3707         const NMUtilsStrStrDictKey *k = a;
3708         const signed char *p;
3709         guint32 h = 5381;
3710
3711         if (k) {
3712                 if (((int) k->type) & ~STRSTRDICTKEY_ALL_SET)
3713                         g_return_val_if_reached (0);
3714
3715                 h = (h << 5) + h + k->type;
3716                 if (k->type & STRSTRDICTKEY_ALL_SET) {
3717                         p = (void *) k->data;
3718                         for (; *p != '\0'; p++)
3719                                 h = (h << 5) + h + *p;
3720                         if (k->type == STRSTRDICTKEY_ALL_SET) {
3721                                 /* the key contains two strings. Continue... */
3722                                 h = (h << 5) + h + '\0';
3723                                 for (p++; *p != '\0'; p++)
3724                                         h = (h << 5) + h + *p;
3725                         }
3726                 }
3727         }
3728
3729         return h;
3730 }
3731
3732 gboolean
3733 _nm_utils_strstrdictkey_equal  (gconstpointer a, gconstpointer b)
3734 {
3735         const NMUtilsStrStrDictKey *k1 = a;
3736         const NMUtilsStrStrDictKey *k2 = b;
3737
3738         if (k1 == k2)
3739                 return TRUE;
3740         if (!k1 || !k2)
3741                 return FALSE;
3742
3743         if (k1->type != k2->type)
3744                 return FALSE;
3745
3746         if (k1->type & STRSTRDICTKEY_ALL_SET) {
3747                 if (strcmp (k1->data, k2->data) != 0)
3748                         return FALSE;
3749
3750                 if (k1->type == STRSTRDICTKEY_ALL_SET) {
3751                         gsize l = strlen (k1->data) + 1;
3752
3753                         return strcmp (&k1->data[l], &k2->data[l]) == 0;
3754                 }
3755         }
3756
3757         return TRUE;
3758 }
3759
3760 NMUtilsStrStrDictKey *
3761 _nm_utils_strstrdictkey_create (const char *v1, const char *v2)
3762 {
3763         char type = 0;
3764         gsize l1 = 0, l2 = 0;
3765         NMUtilsStrStrDictKey *k;
3766
3767         if (!v1 && !v2)
3768                 return g_malloc0 (1);
3769
3770         /* we need to distinguish between ("",NULL) and (NULL,"").
3771          * Thus, in @type we encode which strings we have present
3772          * as not-NULL. */
3773         if (v1) {
3774                 type |= STRSTRDICTKEY_V1_SET;
3775                 l1 = strlen (v1) + 1;
3776         }
3777         if (v2) {
3778                 type |= STRSTRDICTKEY_V2_SET;
3779                 l2 = strlen (v2) + 1;
3780         }
3781
3782         k = g_malloc (G_STRUCT_OFFSET (NMUtilsStrStrDictKey, data) + l1 + l2);
3783         k->type = type;
3784         if (v1)
3785                 memcpy (&k->data[0], v1, l1);
3786         if (v2)
3787                 memcpy (&k->data[l1], v2, l2);
3788
3789         return k;
3790 }
3791
3792 static gboolean
3793 validate_dns_option (const char *name, gboolean numeric, gboolean ipv6,
3794                      const NMUtilsDNSOptionDesc *option_descs)
3795 {
3796         const NMUtilsDNSOptionDesc *desc;
3797
3798         if (!option_descs)
3799                 return !!*name;
3800
3801         for (desc = option_descs; desc->name; desc++) {
3802                 if (!strcmp (name, desc->name) &&
3803                     numeric == desc->numeric &&
3804                     (!desc->ipv6_only || ipv6))
3805                         return TRUE;
3806         }
3807
3808         return FALSE;
3809 }
3810
3811 /**
3812  * _nm_utils_dns_option_validate:
3813  * @option: option string
3814  * @out_name: (out) (allow-none): the option name
3815  * @out_value: (out) (allow-none): the option value
3816  * @ipv6: whether the option refers to a IPv6 configuration
3817  * @option_descs: (allow-none): an array of NMUtilsDNSOptionDesc which describes the
3818  * valid options
3819  *
3820  * Parses a DNS option in the form "name" or "name:number" and, if
3821  * @option_descs is not NULL, checks that the option conforms to one
3822  * of the provided descriptors. If @option_descs is NULL @ipv6 is
3823  * not considered.
3824  *
3825  * Returns: %TRUE when the parsing was successful and the option is valid,
3826  * %FALSE otherwise
3827  */
3828 gboolean
3829 _nm_utils_dns_option_validate (const char *option, char **out_name,
3830                                long *out_value, gboolean ipv6,
3831                                const NMUtilsDNSOptionDesc *option_descs)
3832 {
3833         char **tokens, *ptr;
3834         gboolean ret = FALSE;
3835
3836         g_return_val_if_fail (option != NULL, FALSE);
3837
3838         if (out_name)
3839                 *out_name = NULL;
3840         if (out_value)
3841                 *out_value = -1;
3842
3843         if (!option[0])
3844                 return FALSE;
3845
3846         tokens = g_strsplit (option, ":", 2);
3847
3848         if (g_strv_length (tokens) == 1) {
3849                 ret = validate_dns_option (tokens[0], FALSE, ipv6, option_descs);
3850                 if (ret && out_name)
3851                         *out_name = g_strdup (tokens[0]);
3852                 goto out;
3853         }
3854
3855         if (!tokens[1][0]) {
3856                 ret = FALSE;
3857                 goto out;
3858         }
3859
3860         for (ptr = tokens[1]; *ptr; ptr++) {
3861                 if (!g_ascii_isdigit (*ptr)) {
3862                         ret = FALSE;
3863                         goto out;
3864                 }
3865         }
3866
3867         ret = FALSE;
3868         if (validate_dns_option (tokens[0], TRUE, ipv6, option_descs)) {
3869                 int value = _nm_utils_ascii_str_to_int64 (tokens[1], 10, 0, G_MAXINT32, -1);
3870                 if (value >= 0) {
3871                         if (out_name)
3872                                 *out_name = g_strdup (tokens[0]);
3873                         if (out_value)
3874                                 *out_value = value;
3875                         ret = TRUE;
3876                 }
3877         }
3878 out:
3879         g_strfreev (tokens);
3880         return ret;
3881 }
3882
3883 /**
3884  * _nm_utils_dns_option_find_idx:
3885  * @array: an array of strings
3886  * @option: a dns option string
3887  *
3888  * Searches for an option in an array of strings. The match is
3889  * performed only the option name; the option value is ignored.
3890  *
3891  * Returns: the index of the option in the array or -1 if was not
3892  * found.
3893  */
3894 int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option)
3895 {
3896         gboolean ret;
3897         char *option_name, *tmp_name;
3898         int i;
3899
3900         if (!_nm_utils_dns_option_validate (option, &option_name, NULL, FALSE, NULL))
3901                 return -1;
3902
3903         for (i = 0; i < array->len; i++) {
3904                 if (_nm_utils_dns_option_validate (array->pdata[i], &tmp_name, NULL, FALSE, NULL)) {
3905                         ret = strcmp (tmp_name, option_name);
3906                         g_free (tmp_name);
3907                         if (!ret) {
3908                                 g_free (option_name);
3909                                 return i;
3910                         }
3911                 }
3912
3913         }
3914
3915         g_free (option_name);
3916         return -1;
3917 }
3918
3919 /**
3920  * nm_utils_enum_to_str:
3921  * @type: the %GType of the enum
3922  * @value: the value to be translated
3923  *
3924  * Converts an enum value to its string representation. If the enum is a
3925  * %G_TYPE_FLAGS the function returns a comma-separated list of matching values.
3926  * If the enum is a %G_TYPE_ENUM and the given value is not valid the
3927  * function returns %NULL.
3928  *
3929  * Returns: a newly allocated string or %NULL
3930  *
3931  * Since: 1.2
3932  */
3933 char *nm_utils_enum_to_str (GType type, int value)
3934 {
3935         GTypeClass *class;
3936         char *ret;
3937
3938         class = g_type_class_ref (type);
3939
3940         if (G_IS_ENUM_CLASS (class)) {
3941                 GEnumValue *enum_value;
3942
3943                 enum_value = g_enum_get_value (G_ENUM_CLASS (class), value);
3944                 ret = enum_value ? strdup (enum_value->value_nick) : NULL;
3945         } else if (G_IS_FLAGS_CLASS (class)) {
3946                 GFlagsValue *flags_value;
3947                 GString *str = g_string_new ("");
3948                 gboolean first = TRUE;
3949
3950                 while (value) {
3951                         flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), value);
3952                         if (!flags_value)
3953                                 break;
3954
3955                         if (!first)
3956                                 g_string_append (str, ", ");
3957                         g_string_append (str, flags_value->value_nick);
3958
3959                         value &= ~flags_value->value;
3960                         first = FALSE;
3961                 }
3962                 ret = g_string_free (str, FALSE);
3963         } else
3964                 g_return_val_if_reached (NULL);
3965
3966         g_type_class_unref (class);
3967         return ret;
3968 }
3969 NM_BACKPORT_SYMBOL (libnm_1_0_6, char *, nm_utils_enum_to_str,
3970                     (GType type, int value), (type, value));
3971
3972 /**
3973  * nm_utils_enum_from_str:
3974  * @type: the %GType of the enum
3975  * @str: the input string
3976  * @out_value: (out) (allow-none): the output value
3977  * @err_token: (out) (allow-none): location to store the first unrecognized token
3978  *
3979  * Converts a string to the matching enum value.
3980  *
3981  * If the enum is a %G_TYPE_FLAGS the function returns the logical OR of values
3982  * matching the comma-separated tokens in the string; if an unknown token is found
3983  * the function returns %FALSE and stores a pointer to a newly allocated string
3984  * containing the unrecognized token in @err_token.
3985  *
3986  * Returns: %TRUE if the conversion was successful, %FALSE otherwise
3987  *
3988  * Since: 1.2
3989  */
3990 gboolean nm_utils_enum_from_str (GType type, const char *str,
3991                                  int *out_value, char **err_token)
3992 {
3993         GTypeClass *class;
3994         gboolean ret = FALSE;
3995         int value = 0;
3996         gs_free char *stripped = NULL;
3997
3998         g_return_val_if_fail (str, FALSE);
3999         stripped = g_strstrip (strdup (str));
4000         class = g_type_class_ref (type);
4001
4002         if (G_IS_ENUM_CLASS (class)) {
4003                 GEnumValue *enum_value;
4004
4005                 enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), stripped);
4006                 if (enum_value) {
4007                         value = enum_value->value;
4008                         ret = TRUE;
4009                 }
4010         } else if (G_IS_FLAGS_CLASS (class)) {
4011                 GFlagsValue *flags_value;
4012                 gs_strfreev char **strv = NULL;
4013                 int i;
4014
4015                 strv = g_strsplit_set (stripped, " \t,", 0);
4016                 for (i = 0; strv[i]; i++) {
4017                         if (!strv[i][0])
4018                                 continue;
4019
4020                         flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), strv[i]);
4021                         if (!flags_value)
4022                                 break;
4023
4024                         value |= flags_value->value;
4025                 }
4026
4027                 if (strv[i]) {
4028                         if (err_token)
4029                                 *err_token = strdup (strv[i]);
4030                         value = 0;
4031                 } else
4032                         ret = TRUE;
4033         } else
4034                 g_return_val_if_reached (FALSE);
4035
4036         if (out_value)
4037                 *out_value = value;
4038
4039         g_type_class_unref (class);
4040         return ret;
4041 }
4042 NM_BACKPORT_SYMBOL (libnm_1_0_6, gboolean, nm_utils_enum_from_str,
4043                     (GType type, const char *str, int *out_value, char **err_token),
4044                     (type, str, out_value, err_token));
4045
4046 /**
4047  * nm_utils_enum_get_values:
4048  * @type: the %GType of the enum
4049  * @from: the first element to be returned
4050  * @to: the last element to be returned
4051  *
4052  * Returns the list of possible values for a given enum.
4053  *
4054  * Returns: (transfer full): a NULL-terminated dynamically-allocated array of static strings
4055  * or %NULL on error
4056  *
4057  * Since: 1.2
4058  */
4059 const char **nm_utils_enum_get_values (GType type, gint from, gint to)
4060 {
4061         GTypeClass *class;
4062         GPtrArray *array;
4063         gint i;
4064
4065         class = g_type_class_ref (type);
4066         array = g_ptr_array_new ();
4067
4068         if (G_IS_ENUM_CLASS (class)) {
4069                 GEnumClass *enum_class = G_ENUM_CLASS (class);
4070                 GEnumValue *enum_value;
4071
4072                 for (i = 0; i < enum_class->n_values; i++) {
4073                         enum_value = &enum_class->values[i];
4074                         if (enum_value->value >= from && enum_value->value <= to)
4075                                 g_ptr_array_add (array, (gpointer) enum_value->value_nick);
4076                 }
4077         } else if (G_IS_FLAGS_CLASS (class)) {
4078                 GFlagsClass *flags_class = G_FLAGS_CLASS (class);
4079                 GFlagsValue *flags_value;
4080
4081                 for (i = 0; i < flags_class->n_values; i++) {
4082                         flags_value = &flags_class->values[i];
4083                         if (flags_value->value >= from && flags_value->value <= to)
4084                                 g_ptr_array_add (array, (gpointer) flags_value->value_nick);
4085                 }
4086         } else {
4087                 g_type_class_unref (class);
4088                 g_ptr_array_free (array, TRUE);
4089                 g_return_val_if_reached (NULL);
4090         }
4091
4092         g_type_class_unref (class);
4093         g_ptr_array_add (array, NULL);
4094
4095         return (const char **) g_ptr_array_free (array, FALSE);
4096 }
4097