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