1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
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.
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.
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.
19 * Copyright 2005 - 2014 Red Hat, Inc.
22 #include "nm-default.h"
29 #include <netinet/ether.h>
30 #include <arpa/inet.h>
31 #include <uuid/uuid.h>
36 #include "nm-utils-private.h"
37 #include "nm-setting-private.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"
50 * @short_description: Utility functions
52 * A collection of utility functions for working with SSIDs, IP addresses, Wi-Fi
53 * access points and devices, among other things.
56 struct EncodingTriplet
58 const char *encoding1;
59 const char *encoding2;
60 const char *encoding3;
63 struct IsoLangToEncodings
66 struct EncodingTriplet encodings;
69 /* 5-letter language codes */
70 static const struct IsoLangToEncodings isoLangEntries5[] =
72 /* Simplified Chinese */
73 { "zh_cn", {"euc-cn", "gb2312", "gb18030"} }, /* PRC */
74 { "zh_sg", {"euc-cn", "gb2312", "gb18030"} }, /* Singapore */
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 */
82 { NULL, {NULL, NULL, NULL} }
85 /* 2-letter language codes; we don't care about the other 3 in this table */
86 static const struct IsoLangToEncodings isoLangEntries2[] =
89 { "ja", {"euc-jp", "shift_jis", "iso-2022-jp"} },
92 { "ko", {"euc-kr", "iso-2022-kr", "johab"} },
95 { "th", {"iso-8859-11","windows-874", NULL} },
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 */
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 */
116 { "ar", {"iso-8859-6", "windows-1256", NULL} },
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 */
124 { "el", {"iso-8859-7", "windows-1253", NULL} },
127 { "he", {"iso-8859-8", "windows-1255", NULL} },
128 { "iw", {"iso-8859-8", "windows-1255", NULL} },
131 { "tr", {"iso-8859-9", "windows-1254", NULL} },
134 { NULL, {NULL, NULL, NULL} }
138 static GHashTable * langToEncodings5 = NULL;
139 static GHashTable * langToEncodings2 = NULL;
142 init_lang_to_encodings_hash (void)
144 struct IsoLangToEncodings *enc;
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);
151 g_hash_table_insert (langToEncodings5, (gpointer) enc->lang,
152 (gpointer) &enc->encodings);
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);
162 g_hash_table_insert (langToEncodings2, (gpointer) enc->lang,
163 (gpointer) &enc->encodings);
171 get_encodings_for_lang (const char *lang,
176 struct EncodingTriplet * encodings;
177 gboolean success = FALSE;
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);
185 *encoding1 = "iso-8859-1";
186 *encoding2 = "windows-1251";
189 init_lang_to_encodings_hash ();
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;
199 /* Truncate tmp_lang to length of 2 */
200 if (strlen (tmp_lang) > 2)
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;
215 static gboolean initialized = FALSE;
217 static void __attribute__((constructor))
218 _nm_utils_init (void)
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);
232 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
233 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
237 _nm_dbus_errors_init ();
240 gboolean _nm_utils_is_manager_process;
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
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.
256 * This function does almost everything humanly possible to convert the input
257 * into a printable UTF-8 string, using roughly the following procedure:
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 '?'.
269 * Again, this function should be used for debugging and display purposes
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.
277 nm_utils_ssid_to_utf8 (const guint8 *ssid, gsize len)
279 char *converted = NULL;
280 char *lang, *e1 = NULL, *e2 = NULL, *e3 = NULL;
282 g_return_val_if_fail (ssid != NULL, NULL);
284 if (g_utf8_validate ((const gchar *) ssid, len, NULL))
285 return g_strndup ((const gchar *) ssid, len);
287 /* LANG may be a good encoding hint */
288 g_get_charset ((const char **)(&e1));
289 if ((lang = getenv ("LANG"))) {
292 lang = g_ascii_strdown (lang, -1);
293 if ((dot = strchr (lang, '.')))
296 get_encodings_for_lang (lang, &e1, &e2, &e3);
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);
304 if (!converted && e3)
305 converted = g_convert ((const gchar *) ssid, len, "UTF-8", e3, NULL, NULL, NULL);
308 converted = g_convert_with_fallback ((const gchar *) ssid, len,
309 "UTF-8", e1, "?", NULL, NULL, NULL);
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.
318 /* Use the printable range of 0x20-0x7E */
319 gchar *valid_chars = " !\"#$%&'()*+,-./0123456789:;<=>?@"
320 "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
321 "abcdefghijklmnopqrstuvwxyz{|}~";
323 converted = g_strndup ((const gchar *)ssid, len);
324 g_strcanon (converted, valid_chars, '?');
330 /* Shamelessly ripped from the Linux kernel ieee80211 stack */
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
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.
340 * Returns: %TRUE if the SSID is "empty", %FALSE if it is not
343 nm_utils_is_empty_ssid (const guint8 *ssid, gsize len)
345 /* Single white space is for Linksys APs */
346 if (len == 1 && ssid[0] == ' ')
349 /* Otherwise, if the entire ssid is 0, we assume it is hidden */
351 if (ssid[len] != '\0')
357 #define ESSID_MAX_SIZE 32
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
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.
369 * Returns: pointer to the escaped SSID, which uses an internal static buffer
370 * and will be overwritten by subsequent calls to this function
373 nm_utils_escape_ssid (const guint8 *ssid, gsize len)
375 static char escaped[ESSID_MAX_SIZE * 2 + 1];
376 const guint8 *s = ssid;
379 if (nm_utils_is_empty_ssid (ssid, len)) {
380 memcpy (escaped, "<hidden>", sizeof ("<hidden>"));
384 len = MIN (len, (guint32) ESSID_MAX_SIZE);
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
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.
413 * Returns: %TRUE if the SSIDs are the same, %FALSE if they are not
416 nm_utils_same_ssid (const guint8 *ssid1, gsize len1,
417 const guint8 *ssid2, gsize len2,
418 gboolean ignore_trailing_null)
420 g_return_val_if_fail (ssid1 != NULL || len1 == 0, FALSE);
421 g_return_val_if_fail (ssid2 != NULL || len2 == 0, FALSE);
423 if (ssid1 == ssid2 && len1 == len2)
425 if (!ssid1 || !ssid2)
428 if (ignore_trailing_null) {
429 if (len1 && ssid1[len1 - 1] == '\0')
431 if (len2 && ssid2[len2 - 1] == '\0')
438 return memcmp (ssid1, ssid2, len1) == 0 ? TRUE : FALSE;
442 _nm_utils_string_in_list (const char *str, const char **valid_strings)
444 return _nm_utils_strv_find_first ((char **) valid_strings, -1, str) >= 0;
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().
453 * Searches @list for @needle and returns the index of the first match (based
456 * For convenience, @list has type 'char**' instead of 'const char **'.
458 * Returns: index of first occurrence or -1 if @needle is not found in @list.
461 _nm_utils_strv_find_first (char **list, gssize len, const char *needle)
466 g_return_val_if_fail (list, -1);
469 /* if we search a list with known length, %NULL is a valid @needle. */
470 for (i = 0; i < len; i++) {
475 for (i = 0; i < len; i++) {
476 if (list[i] && !strcmp (needle, list[i]))
480 } else if (len < 0) {
481 g_return_val_if_fail (needle, -1);
484 for (i = 0; list[i]; i++) {
485 if (strcmp (needle, list[i]) == 0)
494 _nm_utils_strv_cleanup (char **strv,
495 gboolean strip_whitespace,
497 gboolean skip_repeated)
504 if (strip_whitespace) {
505 for (i = 0; strv[i]; i++)
506 g_strstrip (strv[i]);
508 if (!skip_empty && !skip_repeated)
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))
524 _nm_utils_string_slist_validate (GSList *list, const char **valid_values)
528 for (iter = list; iter; iter = iter->next) {
529 if (!_nm_utils_string_in_list ((char *) iter->data, valid_values))
537 * _nm_utils_hash_values_to_slist:
538 * @hash: a #GHashTable
540 * Utility function to iterate over a hash table and return
541 * it's values as a #GSList.
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.
549 _nm_utils_hash_values_to_slist (GHashTable *hash)
555 g_return_val_if_fail (hash, NULL);
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);
565 _nm_utils_strdict_to_dbus (const GValue *prop_value)
570 GVariantBuilder builder;
572 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
573 hash = g_value_get_boxed (prop_value);
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);
580 return g_variant_builder_end (&builder);
584 _nm_utils_strdict_from_dbus (GVariant *dbus_value,
588 const char *key, *value;
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));
596 g_value_take_boxed (prop_value, hash);
600 _nm_utils_copy_strdict (GHashTable *strdict)
606 copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
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));
616 _nm_utils_copy_slist_to_array (const GSList *list,
617 NMUtilsCopyFunc copy_func,
618 GDestroyNotify unref_func)
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);
630 _nm_utils_copy_array_to_slist (const GPtrArray *array,
631 NMUtilsCopyFunc copy_func)
633 GSList *slist = NULL;
640 for (i = 0; i < array->len; i++) {
641 item = array->pdata[i];
642 slist = g_slist_prepend (slist, copy_func (item));
645 return g_slist_reverse (slist);
649 _nm_utils_copy_array (const GPtrArray *array,
650 NMUtilsCopyFunc copy_func,
651 GDestroyNotify free_func)
657 return g_ptr_array_new_with_free_func (free_func);
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]));
666 _nm_utils_copy_object_array (const GPtrArray *array)
668 return _nm_utils_copy_array (array, g_object_ref, g_object_unref);
671 /* have @list of type 'gpointer *' instead of 'gconstpointer *' to
672 * reduce the necessity for annoying const-casts. */
674 _nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle)
682 g_return_val_if_fail (list, -1);
683 for (i = 0; i < len; i++) {
684 if (list[i] == needle)
688 g_return_val_if_fail (needle, -1);
689 for (i = 0; list && list[i]; i++) {
690 if (list[i] == needle)
698 _nm_utils_ptrarray_find_binary_search (gpointer *list, gsize len, gpointer needle, GCompareDataFunc cmpfcn, gpointer user_data)
700 gssize imin, imax, imid;
703 g_return_val_if_fail (list || !len, ~((gssize) 0));
704 g_return_val_if_fail (cmpfcn, ~((gssize) 0));
712 while (imin <= imax) {
713 imid = imin + (imax - imin) / 2;
715 cmp = cmpfcn (list[imid], needle, user_data);
725 /* return the inverse of @imin. This is a negative number, but
726 * also is ~imin the position where the value should be inserted. */
731 _nm_utils_bytes_to_dbus (const GValue *prop_value)
733 GBytes *bytes = g_value_get_boxed (prop_value);
736 return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
737 g_bytes_get_data (bytes, NULL),
738 g_bytes_get_size (bytes),
741 return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
748 _nm_utils_bytes_from_dbus (GVariant *dbus_value,
753 if (g_variant_n_children (dbus_value)) {
757 data = g_variant_get_fixed_array (dbus_value, &length, 1);
758 bytes = g_bytes_new (data, length);
761 g_value_take_boxed (prop_value, bytes);
765 _nm_utils_strv_to_slist (char **strv, gboolean deep_copy)
772 for (i = 0; strv[i]; i++)
773 list = g_slist_prepend (list, g_strdup (strv[i]));
775 for (i = 0; strv[i]; i++)
776 list = g_slist_prepend (list, strv[i]);
780 return g_slist_reverse (list);
784 _nm_utils_slist_to_strv (GSList *slist, gboolean deep_copy)
790 len = g_slist_length (slist);
791 strv = g_new (char *, len + 1);
794 for (i = 0, iter = slist; iter; iter = iter->next, i++)
795 strv[i] = g_strdup (iter->data);
797 for (i = 0, iter = slist; iter; iter = iter->next, i++)
798 strv[i] = iter->data;
806 _nm_utils_strv_to_ptrarray (char **strv)
811 ptrarray = g_ptr_array_new_with_free_func (g_free);
814 for (i = 0; strv[i]; i++)
815 g_ptr_array_add (ptrarray, g_strdup (strv[i]));
822 _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray)
828 return g_new0 (char *, 1);
830 strv = g_new (char *, ptrarray->len + 1);
832 for (i = 0; i < ptrarray->len; i++)
833 strv[i] = g_strdup (ptrarray->pdata[i]);
840 * _nm_utils_strv_equal:
841 * @strv1: a string array
842 * @strv2: a string array
844 * Compare NULL-terminated string arrays for equality.
846 * Returns: %TRUE if the arrays are equal, %FALSE otherwise.
849 _nm_utils_strv_equal (char **strv1, char **strv2)
854 if (!strv1 || !strv2)
857 for ( ; *strv1 && *strv2 && !strcmp (*strv1, *strv2); strv1++, strv2++)
860 return !*strv1 && !*strv2;
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.
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.
874 * Returns: (transfer full): a newly allocated NULL-terminated array of strings.
875 * The caller must free the returned array with g_strfreev().
878 _nm_utils_strsplit_set (const char *str, const char *delimiters, int max_tokens)
884 result = g_strsplit_set (str, delimiters, max_tokens);
886 /* remove empty strings */
887 for (i = 0; result && result[i]; i++) {
888 if (*result[i] == '\0') {
890 for (j = i; result[j]; j++)
891 result[j] = result[j + 1];
899 device_supports_ap_ciphers (guint32 dev_caps,
903 gboolean have_pair = FALSE;
904 gboolean have_group = FALSE;
905 /* Device needs to support at least one pairwise and one group cipher */
909 /* Static WEP only uses group ciphers */
912 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
913 if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP40)
915 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
916 if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP104)
918 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
919 if (ap_flags & NM_802_11_AP_SEC_PAIR_TKIP)
921 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
922 if (ap_flags & NM_802_11_AP_SEC_PAIR_CCMP)
927 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
928 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP40)
930 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
931 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP104)
934 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
935 if (ap_flags & NM_802_11_AP_SEC_GROUP_TKIP)
937 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
938 if (ap_flags & NM_802_11_AP_SEC_GROUP_CCMP)
942 return (have_pair && have_group);
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
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.
956 * Returns: %TRUE if the device capabilities are compatible with the desired
957 * @type, %FALSE if they are not.
960 nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
961 NMDeviceWifiCapabilities wifi_caps)
963 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_AP))
966 /* Return TRUE for any security that wpa_supplicant's lightweight AP
967 * mode can handle: which is open, WEP, and WPA/WPA2 PSK.
971 case NMU_SEC_STATIC_WEP:
972 case NMU_SEC_WPA_PSK:
973 case NMU_SEC_WPA2_PSK:
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)
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.
999 * NOTE: this function cannot handle checking security for AP/Hotspot mode;
1000 * use nm_utils_ap_mode_security_valid() instead.
1002 * Returns: %TRUE if the device capabilities and AP capabilties intersect and are
1003 * compatible with the desired @type, %FALSE if they are not
1006 nm_utils_security_valid (NMUtilsSecurityType type,
1007 NMDeviceWifiCapabilities wifi_caps,
1010 NM80211ApFlags ap_flags,
1011 NM80211ApSecurityFlags ap_wpa,
1012 NM80211ApSecurityFlags ap_rsn)
1014 gboolean good = TRUE;
1017 if (type == NMU_SEC_NONE)
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))
1032 if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
1034 if (ap_wpa || ap_rsn)
1037 case NMU_SEC_LEAP: /* require PRIVACY bit for LEAP? */
1041 case NMU_SEC_STATIC_WEP:
1043 if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
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))
1051 case NMU_SEC_DYNAMIC_WEP:
1055 if (ap_rsn || !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
1057 /* Some APs broadcast minimal WPA-enabled beacons that must be handled */
1059 if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1061 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
1065 case NMU_SEC_WPA_PSK:
1067 return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
1068 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
1071 /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
1072 * they don't have any pairwise ciphers. */
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))
1078 if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_CCMP)
1079 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
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))
1086 if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
1087 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
1094 case NMU_SEC_WPA2_PSK:
1096 return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
1097 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
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. */
1103 /* coverity[dead_error_line] */
1104 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
1106 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
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))
1113 if ( (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
1114 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
1121 case NMU_SEC_WPA_ENTERPRISE:
1124 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
1127 if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1129 /* Ensure at least one WPA cipher is supported */
1130 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
1134 case NMU_SEC_WPA2_ENTERPRISE:
1137 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
1140 if (!(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1142 /* Ensure at least one WPA cipher is supported */
1143 if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, FALSE))
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
1160 * Checks if @key is a valid WEP key
1162 * Returns: %TRUE if @key is a WEP key, %FALSE if not
1165 nm_utils_wep_key_valid (const char *key, NMWepKeyType wep_type)
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);
1177 keylen = strlen (key);
1178 if (wep_type == NM_WEP_KEY_TYPE_KEY) {
1179 if (keylen == 10 || keylen == 26) {
1181 for (i = 0; i < keylen; i++) {
1182 if (!g_ascii_isxdigit (key[i]))
1185 } else if (keylen == 5 || keylen == 13) {
1187 for (i = 0; i < keylen; i++) {
1188 if (!g_ascii_isprint (key[i]))
1193 } else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
1194 if (!keylen || keylen > 64)
1202 * nm_utils_wpa_psk_valid:
1203 * @psk: a string that might be a WPA PSK
1205 * Checks if @psk is a valid WPA PSK
1207 * Returns: %TRUE if @psk is a WPA PSK, %FALSE if not
1210 nm_utils_wpa_psk_valid (const char *psk)
1217 psklen = strlen (psk);
1218 if (psklen < 8 || psklen > 64)
1223 for (i = 0; i < psklen; i++) {
1224 if (!g_ascii_isxdigit (psk[i]))
1233 * nm_utils_ip4_dns_to_variant:
1234 * @dns: (type utf8): an array of IP address strings
1236 * Utility function to convert an array of IP address strings int a #GVariant of
1237 * type 'au' representing an array of IPv4 addresses.
1239 * Returns: (transfer none): a new floating #GVariant representing @dns.
1242 nm_utils_ip4_dns_to_variant (char **dns)
1244 GVariantBuilder builder;
1247 g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
1250 for (i = 0; dns[i]; i++) {
1253 inet_pton (AF_INET, dns[i], &ip);
1254 g_variant_builder_add (&builder, "u", ip);
1258 return g_variant_builder_end (&builder);
1262 * nm_utils_ip4_dns_from_variant:
1263 * @value: a #GVariant of type 'au'
1265 * Utility function to convert a #GVariant of type 'au' representing a list of
1266 * IPv4 addresses into an array of IP address strings.
1268 * Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
1271 nm_utils_ip4_dns_from_variant (GVariant *value)
1273 const guint32 *array;
1278 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("au")), NULL);
1280 array = g_variant_get_fixed_array (value, &length, sizeof (guint32));
1281 dns = g_new (char *, length + 1);
1283 for (i = 0; i < length; i++)
1284 dns[i] = g_strdup (nm_utils_inet4_ntop (array[i], NULL));
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
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.
1301 * Returns: (transfer none): a new floating #GVariant representing @addresses.
1304 nm_utils_ip4_addresses_to_variant (GPtrArray *addresses, const char *gateway)
1306 GVariantBuilder builder;
1309 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aau"));
1312 for (i = 0; i < addresses->len; i++) {
1313 NMIPAddress *addr = addresses->pdata[i];
1316 if (nm_ip_address_get_family (addr) != AF_INET)
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]);
1326 g_variant_builder_add (&builder, "@au",
1327 g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
1328 array, 3, sizeof (guint32)));
1332 return g_variant_builder_end (&builder);
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
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.
1346 * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1347 * #GPtrArray of #NMIPAddress objects
1350 nm_utils_ip4_addresses_from_variant (GVariant *value, char **out_gateway)
1352 GPtrArray *addresses;
1356 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aau")), NULL);
1359 *out_gateway = NULL;
1361 g_variant_iter_init (&iter, value);
1362 addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
1364 while (g_variant_iter_next (&iter, "@au", &addr_var)) {
1365 const guint32 *addr_array;
1368 GError *error = NULL;
1370 addr_array = g_variant_get_fixed_array (addr_var, &length, sizeof (guint32));
1372 g_warning ("Ignoring invalid IP4 address");
1373 g_variant_unref (addr_var);
1377 addr = nm_ip_address_new_binary (AF_INET, &addr_array[0], addr_array[1], &error);
1379 g_ptr_array_add (addresses, addr);
1381 if (addr_array[2] && out_gateway && !*out_gateway)
1382 *out_gateway = g_strdup (nm_utils_inet4_ntop (addr_array[2], NULL));
1384 g_warning ("Ignoring invalid IP4 address: %s", error->message);
1385 g_clear_error (&error);
1388 g_variant_unref (addr_var);
1395 * nm_utils_ip4_routes_to_variant:
1396 * @routes: (element-type NMIPRoute): an array of #NMIP4Route objects
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
1403 * Returns: (transfer none): a new floating #GVariant representing @routes.
1406 nm_utils_ip4_routes_to_variant (GPtrArray *routes)
1408 GVariantBuilder builder;
1411 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aau"));
1414 for (i = 0; i < routes->len; i++) {
1415 NMIPRoute *route = routes->pdata[i];
1418 if (nm_ip_route_get_family (route) != AF_INET)
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));
1427 g_variant_builder_add (&builder, "@au",
1428 g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
1429 array, 4, sizeof (guint32)));
1433 return g_variant_builder_end (&builder);
1437 * nm_utils_ip4_routes_from_variant:
1438 * @value: #GVariant of type 'aau'
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.
1444 * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
1445 * #GPtrArray of #NMIPRoute objects
1448 nm_utils_ip4_routes_from_variant (GVariant *value)
1451 GVariant *route_var;
1454 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aau")), NULL);
1456 g_variant_iter_init (&iter, value);
1457 routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
1459 while (g_variant_iter_next (&iter, "@au", &route_var)) {
1460 const guint32 *route_array;
1463 GError *error = NULL;
1465 route_array = g_variant_get_fixed_array (route_var, &length, sizeof (guint32));
1467 g_warning ("Ignoring invalid IP4 route");
1468 g_variant_unref (route_var);
1472 route = nm_ip_route_new_binary (AF_INET,
1476 /* The old routes format uses "0" for default, not "-1" */
1477 route_array[3] ? (gint64) route_array[3] : -1,
1480 g_ptr_array_add (routes, route);
1482 g_warning ("Ignoring invalid IP4 route: %s", error->message);
1483 g_clear_error (&error);
1485 g_variant_unref (route_var);
1492 * nm_utils_ip4_netmask_to_prefix:
1493 * @netmask: an IPv4 netmask in network byte order
1495 * Returns: the CIDR prefix represented by the netmask
1498 nm_utils_ip4_netmask_to_prefix (guint32 netmask)
1502 const guint8 *p = (guint8 *) &netmask;
1527 * nm_utils_ip4_prefix_to_netmask:
1528 * @prefix: a CIDR prefix
1530 * Returns: the netmask represented by the prefix, in network byte order
1533 nm_utils_ip4_prefix_to_netmask (guint32 prefix)
1535 return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
1540 * nm_utils_ip4_get_default_prefix:
1541 * @ip: an IPv4 address (in network byte order)
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.
1548 * Returns: the default class prefix for the given IP
1550 /* The function is originally from ipcalc.c of Red Hat's initscripts. */
1552 nm_utils_ip4_get_default_prefix (guint32 ip)
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 */
1559 return 24; /* Class C - 255.255.255.0 */
1563 * nm_utils_ip6_dns_to_variant:
1564 * @dns: (type utf8): an array of IP address strings
1566 * Utility function to convert an array of IP address strings int a #GVariant of
1567 * type 'aay' representing an array of IPv6 addresses.
1569 * Returns: (transfer none): a new floating #GVariant representing @dns.
1572 nm_utils_ip6_dns_to_variant (char **dns)
1574 GVariantBuilder builder;
1577 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
1580 for (i = 0; dns[i]; i++) {
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));
1590 return g_variant_builder_end (&builder);
1594 * nm_utils_ip6_dns_from_variant:
1595 * @value: a #GVariant of type 'aay'
1597 * Utility function to convert a #GVariant of type 'aay' representing a list of
1598 * IPv6 addresses into an array of IP address strings.
1600 * Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
1603 nm_utils_ip6_dns_from_variant (GVariant *value)
1610 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aay")), NULL);
1612 dns = g_new (char *, g_variant_n_children (value) + 1);
1614 g_variant_iter_init (&iter, value);
1616 while (g_variant_iter_next (&iter, "@ay", &ip_var)) {
1618 const struct in6_addr *ip = g_variant_get_fixed_array (ip_var, &length, 1);
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);
1627 dns[i++] = g_strdup (nm_utils_inet6_ntop (ip, NULL));
1628 g_variant_unref (ip_var);
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
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
1647 * Returns: (transfer none): a new floating #GVariant representing @addresses.
1650 nm_utils_ip6_addresses_to_variant (GPtrArray *addresses, const char *gateway)
1652 GVariantBuilder builder;
1655 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayuay)"));
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;
1664 if (nm_ip_address_get_family (addr) != AF_INET6)
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);
1670 prefix = nm_ip_address_get_prefix (addr);
1672 if (i == 0 && gateway)
1673 inet_pton (AF_INET6, gateway, &gateway_bytes);
1675 memset (&gateway_bytes, 0, sizeof (gateway_bytes));
1676 gateway_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &gateway_bytes, 16, 1);
1678 g_variant_builder_add (&builder, "(@ayu@ay)", ip_var, prefix, gateway_var);
1682 return g_variant_builder_end (&builder);
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
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.
1696 * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1697 * #GPtrArray of #NMIPAddress objects
1700 nm_utils_ip6_addresses_from_variant (GVariant *value, char **out_gateway)
1703 GVariant *addr_var, *gateway_var;
1705 GPtrArray *addresses;
1707 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(ayuay)")), NULL);
1710 *out_gateway = NULL;
1712 g_variant_iter_init (&iter, value);
1713 addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
1715 while (g_variant_iter_next (&iter, "(@ayu@ay)", &addr_var, &prefix, &gateway_var)) {
1717 const struct in6_addr *addr_bytes, *gateway_bytes;
1718 gsize addr_len, gateway_len;
1719 GError *error = NULL;
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__);
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);
1734 addr = nm_ip_address_new_binary (AF_INET6, addr_bytes, prefix, &error);
1736 g_ptr_array_add (addresses, addr);
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);
1745 if (!IN6_IS_ADDR_UNSPECIFIED (gateway_bytes))
1746 *out_gateway = g_strdup (nm_utils_inet6_ntop (gateway_bytes, NULL));
1749 g_warning ("Ignoring invalid IP6 address: %s", error->message);
1750 g_clear_error (&error);
1754 g_variant_unref (addr_var);
1755 g_variant_unref (gateway_var);
1762 * nm_utils_ip6_routes_to_variant:
1763 * @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
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
1770 * Returns: (transfer none): a new floating #GVariant representing @routes.
1773 nm_utils_ip6_routes_to_variant (GPtrArray *routes)
1775 GVariantBuilder builder;
1778 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayuayu)"));
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;
1787 if (nm_ip_route_get_family (route) != AF_INET6)
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));
1798 g_variant_builder_add (&builder, "(@ayu@ayu)", dest, prefix, next_hop, metric);
1802 return g_variant_builder_end (&builder);
1806 * nm_utils_ip6_routes_from_variant:
1807 * @value: #GVariant of type 'a(ayuayu)'
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.
1813 * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
1814 * #GPtrArray of #NMIPRoute objects
1817 nm_utils_ip6_routes_from_variant (GVariant *value)
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;
1826 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(ayuayu)")), NULL);
1828 routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
1830 g_variant_iter_init (&iter, value);
1831 while (g_variant_iter_next (&iter, "(@ayu@ayu)", &dest_var, &prefix, &next_hop_var, &metric)) {
1833 GError *error = NULL;
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__);
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);
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);
1855 route = nm_ip_route_new_binary (AF_INET6, dest, prefix, next_hop,
1856 metric ? (gint64) metric : -1,
1859 g_ptr_array_add (routes, route);
1861 g_warning ("Ignoring invalid IP6 route: %s", error->message);
1862 g_clear_error (&error);
1866 g_variant_unref (dest_var);
1867 g_variant_unref (next_hop_var);
1874 * nm_utils_ip_addresses_to_variant:
1875 * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
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.
1883 * Returns: (transfer none): a new floating #GVariant representing @addresses.
1886 nm_utils_ip_addresses_to_variant (GPtrArray *addresses)
1888 GVariantBuilder builder;
1891 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
1894 for (i = 0; i < addresses->len; i++) {
1895 NMIPAddress *addr = addresses->pdata[i];
1896 GVariantBuilder addr_builder;
1900 g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}"));
1901 g_variant_builder_add (&addr_builder, "{sv}",
1903 g_variant_new_string (nm_ip_address_get_address (addr)));
1904 g_variant_builder_add (&addr_builder, "{sv}",
1906 g_variant_new_uint32 (nm_ip_address_get_prefix (addr)));
1908 names = nm_ip_address_get_attribute_names (addr);
1909 for (n = 0; names[n]; n++) {
1910 g_variant_builder_add (&addr_builder, "{sv}",
1912 nm_ip_address_get_attribute (addr, names[n]));
1916 g_variant_builder_add (&builder, "a{sv}", &addr_builder);
1920 return g_variant_builder_end (&builder);
1924 * nm_utils_ip_addresses_from_variant:
1925 * @value: a #GVariant of type 'aa{sv}'
1926 * @family: an IP address family
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
1933 * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1934 * #GPtrArray of #NMIPAddress objects
1937 nm_utils_ip_addresses_from_variant (GVariant *value,
1940 GPtrArray *addresses;
1941 GVariantIter iter, attrs_iter;
1945 const char *attr_name;
1948 GError *error = NULL;
1950 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
1952 g_variant_iter_init (&iter, value);
1953 addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
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);
1963 addr = nm_ip_address_new (family, ip, prefix, &error);
1965 g_warning ("Ignoring invalid address: %s", error->message);
1966 g_clear_error (&error);
1967 g_variant_unref (addr_var);
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);
1979 g_variant_unref (addr_var);
1980 g_ptr_array_add (addresses, addr);
1987 * nm_utils_ip_routes_to_variant:
1988 * @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
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).
1995 * Returns: (transfer none): a new floating #GVariant representing @routes.
1998 nm_utils_ip_routes_to_variant (GPtrArray *routes)
2000 GVariantBuilder builder;
2003 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
2006 for (i = 0; i < routes->len; i++) {
2007 NMIPRoute *route = routes->pdata[i];
2008 GVariantBuilder route_builder;
2012 g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}"));
2013 g_variant_builder_add (&route_builder, "{sv}",
2015 g_variant_new_string (nm_ip_route_get_dest (route)));
2016 g_variant_builder_add (&route_builder, "{sv}",
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}",
2022 g_variant_new_string (nm_ip_route_get_next_hop (route)));
2024 if (nm_ip_route_get_metric (route) != -1) {
2025 g_variant_builder_add (&route_builder, "{sv}",
2027 g_variant_new_uint32 ((guint32) nm_ip_route_get_metric (route)));
2030 names = nm_ip_route_get_attribute_names (route);
2031 for (n = 0; names[n]; n++) {
2032 g_variant_builder_add (&route_builder, "{sv}",
2034 nm_ip_route_get_attribute (route, names[n]));
2038 g_variant_builder_add (&builder, "a{sv}", &route_builder);
2042 return g_variant_builder_end (&builder);
2046 * nm_utils_ip_routes_from_variant:
2047 * @value: a #GVariant of type 'aa{sv}'
2048 * @family: an IP address family
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.
2055 * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
2056 * #GPtrArray of #NMIPRoute objects
2059 nm_utils_ip_routes_from_variant (GVariant *value,
2063 GVariantIter iter, attrs_iter;
2064 GVariant *route_var;
2065 const char *dest, *next_hop;
2066 guint32 prefix, metric32;
2068 const char *attr_name;
2071 GError *error = NULL;
2073 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
2075 g_variant_iter_init (&iter, value);
2076 routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
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");
2084 if (!g_variant_lookup (route_var, "next-hop", "&s", &next_hop))
2086 if (g_variant_lookup (route_var, "metric", "u", &metric32))
2091 route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &error);
2093 g_warning ("Ignoring invalid route: %s", error->message);
2094 g_clear_error (&error);
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);
2108 g_ptr_array_add (routes, route);
2110 g_variant_unref (route_var);
2116 /**********************************************************************************************/
2119 * nm_utils_uuid_generate:
2121 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
2122 * object's #NMSettingConnection:id: property. Should be freed with g_free()
2125 nm_utils_uuid_generate (void)
2130 buf = g_malloc0 (37);
2131 uuid_generate_random (uuid);
2132 uuid_unparse_lower (uuid, &buf[0]);
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
2145 * For a given @s, this function will always return the same UUID.
2147 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
2148 * object's #NMSettingConnection:id: property
2151 nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args)
2156 g_return_val_if_fail (slen == 0 || s, FALSE);
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);
2161 switch (uuid_type) {
2162 case NM_UTILS_UUID_TYPE_LEGACY:
2163 crypto_md5_hash (NULL, 0, s, slen, (char *) uuid, sizeof (uuid));
2165 case NM_UTILS_UUID_TYPE_VARIANT3: {
2166 uuid_t ns_uuid = { 0 };
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);
2174 crypto_md5_hash (s, slen, (char *) ns_uuid, sizeof (ns_uuid), (char *) uuid, sizeof (uuid));
2176 uuid[6] = (uuid[6] & 0x0F) | 0x30;
2177 uuid[8] = (uuid[8] & 0x3F) | 0x80;
2181 g_return_val_if_reached (NULL);
2184 buf = g_malloc0 (37);
2185 uuid_unparse_lower (uuid, &buf[0]);
2191 * _nm_utils_uuid_generate_from_strings:
2192 * @string1: a variadic list of strings. Must be NULL terminated.
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
2199 * This has the advantage, that the following invocations
2200 * all give different UUIDs: (NULL), (""), ("",""), ("","a"), ("a",""),
2201 * ("aa"), ("aa", ""), ("", "aa"), ...
2204 _nm_utils_uuid_generate_from_strings (const char *string1, ...)
2212 return nm_utils_uuid_generate_from_string (NULL, 0, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
2214 str = g_string_sized_new (120); /* effectively allocates power of 2 (128)*/
2216 g_string_append_len (str, string1, strlen (string1) + 1);
2218 va_start (args, string1);
2219 s = va_arg (args, const char *);
2221 g_string_append_len (str, s, strlen (s) + 1);
2222 s = va_arg (args, const char *);
2226 uuid = nm_utils_uuid_generate_from_string (str->str, str->len, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
2228 g_string_free (str, TRUE);
2232 /**********************************************************************************************/
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
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.
2247 * Returns: (transfer full): on success, PEM-formatted data suitable for writing
2248 * to a PEM-formatted certificate/private key file.
2251 nm_utils_rsa_key_encrypt (const guint8 *data,
2253 const char *in_password,
2254 char **out_password,
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;
2265 GByteArray *ret = NULL;
2267 g_return_val_if_fail (data != NULL, NULL);
2268 g_return_val_if_fail (len > 0, NULL);
2270 g_return_val_if_fail (*out_password == NULL, NULL);
2272 /* Make the password if needed */
2274 if (!crypto_randomize (pw_buf, sizeof (pw_buf), error))
2276 in_password = tmp_password = nm_utils_bin2hexstr (pw_buf, sizeof (pw_buf), -1);
2280 if (!crypto_randomize (salt, salt_len, error))
2283 key = crypto_make_des_aes_key (CIPHER_DES_EDE3_CBC, &salt[0], salt_len, in_password, &key_len, NULL);
2285 g_return_val_if_reached (NULL);
2287 enc = crypto_encrypt (CIPHER_DES_EDE3_CBC, data, len, salt, salt_len, key, key_len, &enc_len, error);
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");
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);
2300 /* Convert the encrypted key to a base64 string */
2301 p = tmp = g_base64_encode ((const guchar *) enc, enc_len);
2302 left = strlen (tmp);
2304 g_string_append_len (pem, p, (left < 64) ? left : 64);
2305 g_string_append_c (pem, '\n');
2311 g_string_append (pem, "-----END RSA PRIVATE KEY-----\n");
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);
2320 memset (key, 0, key_len);
2324 memset (enc, 0, enc_len);
2328 g_string_free (pem, TRUE);
2331 memset (tmp_password, 0, strlen (tmp_password));
2332 g_free (tmp_password);
2339 file_has_extension (const char *filename, const char *extensions[])
2344 ext = strrchr (filename, '.');
2348 for (i = 0; extensions[i]; i++) {
2349 if (!g_ascii_strcasecmp (ext, extensions[i]))
2357 * nm_utils_file_is_certificate:
2358 * @filename: name of the file to test
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.
2364 * Returns: %TRUE if the file is a certificate, %FALSE if it is not
2367 nm_utils_file_is_certificate (const char *filename)
2369 const char *extensions[] = { ".der", ".pem", ".crt", ".cer", NULL };
2370 NMCryptoFileFormat file_format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
2373 g_return_val_if_fail (filename != NULL, FALSE);
2375 if (!file_has_extension (filename, extensions))
2378 cert = crypto_load_and_verify_certificate (filename, &file_format, NULL);
2380 g_byte_array_unref (cert);
2382 return file_format = NM_CRYPTO_FILE_FORMAT_X509;
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
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.
2394 * Returns: %TRUE if the file is a private key, %FALSE if it is not
2397 nm_utils_file_is_private_key (const char *filename, gboolean *out_encrypted)
2399 const char *extensions[] = { ".der", ".pem", ".p12", ".key", NULL };
2401 g_return_val_if_fail (filename != NULL, FALSE);
2402 g_return_val_if_fail (out_encrypted == NULL || *out_encrypted == FALSE, FALSE);
2404 if (!file_has_extension (filename, extensions))
2407 return crypto_verify_private_key (filename, NULL, out_encrypted, NULL) != NM_CRYPTO_FILE_FORMAT_UNKNOWN;
2411 * nm_utils_file_is_pkcs12:
2412 * @filename: name of the file to test
2414 * Tests if @filename is a PKCS#<!-- -->12 file.
2416 * Returns: %TRUE if the file is PKCS#<!-- -->12, %FALSE if it is not
2419 nm_utils_file_is_pkcs12 (const char *filename)
2421 g_return_val_if_fail (filename != NULL, FALSE);
2423 return crypto_is_pkcs12_file (filename, NULL);
2426 /**********************************************************************************************/
2429 _nm_utils_check_file (const char *filename,
2431 NMUtilsCheckFilePredicate check_file,
2433 struct stat *out_st,
2436 struct stat st_backup;
2439 out_st = &st_backup;
2441 if (stat (filename, out_st) != 0) {
2445 NM_VPN_PLUGIN_ERROR,
2446 NM_VPN_PLUGIN_ERROR_FAILED,
2447 _("failed stat file %s: %s"), filename, strerror (errsv));
2451 /* ignore non-files. */
2452 if (!S_ISREG (out_st->st_mode)) {
2454 NM_VPN_PLUGIN_ERROR,
2455 NM_VPN_PLUGIN_ERROR_FAILED,
2456 _("not a file (%s)"), filename);
2460 /* with check_owner enabled, check that the file belongs to the
2462 if ( check_owner >= 0
2463 && (out_st->st_uid != 0 && (gint64) out_st->st_uid != check_owner)) {
2465 NM_VPN_PLUGIN_ERROR,
2466 NM_VPN_PLUGIN_ERROR_FAILED,
2467 _("invalid file owner %d for %s"), out_st->st_uid, filename);
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)) {
2476 NM_VPN_PLUGIN_ERROR,
2477 NM_VPN_PLUGIN_ERROR_FAILED,
2478 _("file permissions for %s"), filename);
2483 && !check_file (filename, out_st, user_data, error)) {
2484 if (error && !*error) {
2486 NM_VPN_PLUGIN_ERROR,
2487 NM_VPN_PLUGIN_ERROR_FAILED,
2488 _("reject %s"), filename);
2498 _nm_utils_check_module_file (const char *name,
2500 NMUtilsCheckFilePredicate check_file,
2504 if (!g_path_is_absolute (name)) {
2506 NM_VPN_PLUGIN_ERROR,
2507 NM_VPN_PLUGIN_ERROR_FAILED,
2508 _("path is not absolute (%s)"), name);
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.
2516 * Note that nm-applet checks for this error code to fail
2518 if (!g_file_test (name, G_FILE_TEST_EXISTS)) {
2522 _("Plugin file does not exist (%s)"), name);
2526 if (!g_file_test (name, G_FILE_TEST_IS_REGULAR)) {
2528 NM_VPN_PLUGIN_ERROR,
2529 NM_VPN_PLUGIN_ERROR_FAILED,
2530 _("Plugin is not a valid file (%s)"), name);
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. */
2538 NM_VPN_PLUGIN_ERROR,
2539 NM_VPN_PLUGIN_ERROR_FAILED,
2540 _("libtool archives are not supported (%s)"), name);
2544 return _nm_utils_check_file (name,
2552 /**********************************************************************************************/
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.
2570 * Searches for a @progname file in a list of search @paths.
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.
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,
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);
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. */
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);
2600 if (!paths || !*paths)
2603 tmp = g_string_sized_new (50);
2604 for (; *paths; paths++) {
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);
2617 g_string_set_size (tmp, 0);
2619 g_string_free (tmp, TRUE);
2622 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Could not find \"%s\" binary"), progname);
2626 /**********************************************************************************************/
2628 /* Band, channel/frequency stuff for wireless */
2634 static struct cf_pair a_table[] = {
2684 static struct cf_pair bg_table[] = {
2704 * nm_utils_wifi_freq_to_channel:
2707 * Utility function to translate a Wi-Fi frequency to its corresponding channel.
2709 * Returns: the channel represented by the frequency or 0
2712 nm_utils_wifi_freq_to_channel (guint32 freq)
2717 while (a_table[i].chan && (a_table[i].freq != freq))
2719 return a_table[i].chan;
2721 while (bg_table[i].chan && (bg_table[i].freq != freq))
2723 return bg_table[i].chan;
2730 * nm_utils_wifi_channel_to_freq:
2732 * @band: frequency band for wireless ("a" or "bg")
2734 * Utility function to translate a Wi-Fi channel to its corresponding frequency.
2736 * Returns: the frequency represented by the channel of the band,
2737 * or -1 when the freq is invalid, or 0 when the band
2741 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band)
2745 if (!strcmp (band, "a")) {
2746 while (a_table[i].chan && (a_table[i].chan != channel))
2748 return a_table[i].freq;
2749 } else if (!strcmp (band, "bg")) {
2750 while (bg_table[i].chan && (bg_table[i].chan != channel))
2752 return bg_table[i].freq;
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")
2764 * Utility function to find out next/previous Wi-Fi channel for a channel.
2766 * Returns: the next channel in the specified direction or 0
2769 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band)
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;
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;
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];
2788 g_assert_not_reached ();
2792 while (pair->chan) {
2793 if (channel == pair->chan)
2795 if ((channel < (pair+1)->chan) && (channel > pair->chan)) {
2797 return (pair+1)->chan;
2807 * nm_utils_wifi_is_channel_valid:
2809 * @band: frequency band for wireless ("a" or "bg")
2811 * Utility function to verify Wi-Fi channel validity.
2813 * Returns: %TRUE or %FALSE
2816 nm_utils_wifi_is_channel_valid (guint32 channel, const char *band)
2818 struct cf_pair *table = NULL;
2821 if (!strcmp (band, "a"))
2823 else if (!strcmp (band, "bg"))
2828 while (table[i].chan && (table[i].chan != channel))
2831 if (table[i].chan != 0)
2837 static const guint *
2838 _wifi_freqs (gboolean bg_band)
2840 static guint *freqs_2ghz = NULL;
2841 static guint *freqs_5ghz = NULL;
2844 freqs = bg_band ? freqs_2ghz : freqs_5ghz;
2845 if (G_UNLIKELY (freqs == NULL)) {
2846 struct cf_pair *table;
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;
2863 * nm_utils_wifi_2ghz_freqs:
2865 * Utility function to return 2.4 GHz Wi-Fi frequencies (802.11bg band).
2867 * Returns: zero-terminated array of frequencies numbers (in MHz)
2872 nm_utils_wifi_2ghz_freqs (void)
2874 return _wifi_freqs (TRUE);
2876 NM_BACKPORT_SYMBOL (libnm_1_0_6, const guint *, nm_utils_wifi_2ghz_freqs, (void), ());
2879 * nm_utils_wifi_5ghz_freqs:
2881 * Utility function to return 5 GHz Wi-Fi frequencies (802.11a band).
2883 * Returns: zero-terminated array of frequencies numbers (in MHz)
2888 nm_utils_wifi_5ghz_freqs (void)
2890 return _wifi_freqs (FALSE);
2892 NM_BACKPORT_SYMBOL (libnm_1_0_6, const guint *, nm_utils_wifi_5ghz_freqs, (void), ());
2895 * nm_utils_wifi_strength_bars:
2896 * @strength: the access point strength, from 0 to 100
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.
2903 * Returns: the graphical representation of the access point strength
2906 nm_utils_wifi_strength_bars (guint8 strength)
2908 static const char *strength_full, *strength_high, *strength_med, *strength_low, *strength_none;
2910 if (G_UNLIKELY (strength_full == NULL)) {
2911 gboolean can_show_graphics = TRUE;
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);
2918 g_free (locale_str);
2920 can_show_graphics = FALSE;
2923 /* The linux console font doesn't have these characters */
2924 if (g_strcmp0 (g_getenv ("TERM"), "linux") == 0)
2925 can_show_graphics = FALSE;
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 = /* ____ */ "____";
2934 strength_full = "****";
2935 strength_high = "*** ";
2936 strength_med = "** ";
2937 strength_low = "* ";
2938 strength_none = " ";
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;
2951 return strength_none;
2955 * nm_utils_hwaddr_len:
2956 * @type: the type of address; either <literal>ARPHRD_ETHER</literal> or
2957 * <literal>ARPHRD_INFINIBAND</literal>
2959 * Returns the length in octets of a hardware address of type @type.
2961 * It is an error to call this function with any value other than
2962 * <literal>ARPHRD_ETHER</literal> or <literal>ARPHRD_INFINIBAND</literal>.
2964 * Return value: the length.
2967 nm_utils_hwaddr_len (int type)
2969 g_return_val_if_fail (type == ARPHRD_ETHER || type == ARPHRD_INFINIBAND, 0);
2971 if (type == ARPHRD_ETHER)
2973 else if (type == ARPHRD_INFINIBAND)
2974 return INFINIBAND_ALEN;
2976 g_assert_not_reached ();
2979 #define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
2982 * nm_utils_hwaddr_atoba:
2983 * @asc: the ASCII representation of a hardware address
2984 * @length: the expected length in bytes of the result
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.
2989 * Return value: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
2993 nm_utils_hwaddr_atoba (const char *asc, gsize length)
2997 g_return_val_if_fail (asc != NULL, NULL);
2998 g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
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);
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.
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.
3020 * Return value: @buffer, or %NULL if @asc couldn't be parsed
3021 * or would be shorter or longer than @length.
3024 nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize length)
3026 const char *in = asc;
3027 guint8 *out = (guint8 *)buffer;
3028 char delimiter = '\0';
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);
3034 while (length && *in) {
3035 guint8 d1 = in[0], d2 = in[1];
3037 if (!g_ascii_isxdigit (d1))
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);
3045 /* Fake leading zero */
3046 *out++ = (HEXVAL ('0') << 4) + HEXVAL (d1);
3052 if (delimiter == '\0') {
3053 if (*in == ':' || *in == '-')
3058 if (*in != delimiter)
3065 if (length == 0 && !*in)
3072 * nm_utils_hwaddr_ntoa:
3073 * @addr: (type guint8) (array length=length): a binary hardware address
3074 * @length: the length of @addr
3076 * Converts @addr to textual form.
3078 * Return value: (transfer full): the textual form of @addr
3081 nm_utils_hwaddr_ntoa (gconstpointer addr, gsize length)
3083 const guint8 *in = addr;
3085 const char *LOOKUP = "0123456789ABCDEF";
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 (""));
3090 result = out = g_malloc (length * 3);
3094 *out++ = LOOKUP[v >> 4];
3095 *out++ = LOOKUP[v & 0x0F];
3105 hwaddr_binary_len (const char *asc)
3112 for (; *asc; asc++) {
3113 if (*asc == ':' || *asc == '-')
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)
3125 * Parses @asc to see if it is a valid hardware address of the given
3128 * Return value: %TRUE if @asc appears to be a valid hardware address
3129 * of the indicated length, %FALSE if not.
3132 nm_utils_hwaddr_valid (const char *asc, gssize length)
3134 guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
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);
3140 length = hwaddr_binary_len (asc);
3141 if (length == 0 || length > NM_UTILS_HWADDR_LEN_MAX)
3145 return nm_utils_hwaddr_aton (asc, buf, length) != NULL;
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)
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).
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.
3162 nm_utils_hwaddr_canonical (const char *asc, gssize length)
3164 guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
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);
3170 length = hwaddr_binary_len (asc);
3171 if (length == 0 || length > NM_UTILS_HWADDR_LEN_MAX)
3175 if (nm_utils_hwaddr_aton (asc, buf, length) == NULL)
3178 return nm_utils_hwaddr_ntoa (buf, length);
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).
3187 _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize length)
3194 canonical = nm_utils_hwaddr_canonical (mac, length);
3198 return g_strdup (mac);
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
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():
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.
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.
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
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.)
3232 * Return value: %TRUE if @hwaddr1 and @hwaddr2 are equivalent, %FALSE if they are
3233 * different (or either of them is invalid).
3236 nm_utils_hwaddr_matches (gconstpointer hwaddr1,
3238 gconstpointer hwaddr2,
3241 guint8 buf1[NM_UTILS_HWADDR_LEN_MAX], buf2[NM_UTILS_HWADDR_LEN_MAX];
3243 if (hwaddr1_len == -1) {
3244 g_return_val_if_fail (hwaddr1 != NULL, FALSE);
3246 hwaddr1_len = hwaddr_binary_len (hwaddr1);
3247 if (hwaddr1_len == 0 || hwaddr1_len > NM_UTILS_HWADDR_LEN_MAX)
3249 if (!nm_utils_hwaddr_aton (hwaddr1, buf1, hwaddr1_len))
3254 g_return_val_if_fail (hwaddr1_len > 0 && hwaddr1_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
3257 memset (buf1, 0, hwaddr1_len);
3262 if (hwaddr2_len == -1) {
3263 g_return_val_if_fail (hwaddr2 != NULL, FALSE);
3265 if (!nm_utils_hwaddr_aton (hwaddr2, buf2, hwaddr1_len))
3269 hwaddr2_len = hwaddr1_len;
3271 g_return_val_if_fail (hwaddr2_len > 0 && hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
3274 memset (buf2, 0, hwaddr2_len);
3279 if (hwaddr1_len != hwaddr2_len)
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;
3288 return !memcmp (hwaddr1, hwaddr2, hwaddr1_len);
3292 _nm_utils_hwaddr_to_dbus (const GValue *prop_value)
3294 const char *str = g_value_get_string (prop_value);
3295 guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
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))
3306 return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1);
3310 _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
3314 const guint8 *array = g_variant_get_fixed_array (dbus_value, &length, 1);
3317 str = length ? nm_utils_hwaddr_ntoa (array, length) : NULL;
3318 g_value_take_string (prop_value, str);
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
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'),
3331 * Return value: (transfer full): the textual form of @bytes
3334 * Code originally by Alex Larsson <alexl@redhat.com> and
3335 * copyright Red Hat, Inc. under terms of the LGPL.
3338 nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len)
3340 static char hex_digits[] = "0123456789abcdef";
3341 const guint8 *bytes = src;
3344 gsize buflen = (len * 2) + 1;
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 */
3350 g_return_val_if_fail (final_len < buflen, NULL);
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];
3357 /* Cut converted key off at the correct length for this cipher type */
3359 result[final_len] = '\0';
3361 result[buflen - 1] = '\0';
3367 * nm_utils_hexstr2bin:
3368 * @hex: a string of hexadecimal characters with optional ':' separators
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 ':'.
3375 * Return value: (transfer full): the converted bytes, or %NULL on error
3378 nm_utils_hexstr2bin (const char *hex)
3381 gs_free guint8 *c = NULL;
3383 gboolean found_colon = FALSE;
3385 g_return_val_if_fail (hex != NULL, NULL);
3387 if (strncasecmp (hex, "0x", 2) == 0)
3389 found_colon = !!strchr (hex, ':');
3391 c = g_malloc (strlen (hex) / 2 + 1);
3393 a = g_ascii_xdigit_value (hex[i++]);
3397 if (hex[i] && hex[i] != ':') {
3398 b = g_ascii_xdigit_value (hex[i++]);
3401 c[x++] = ((guint) a << 4) | ((guint) b);
3407 if (hex[i] == ':') {
3409 /* trailing ':' is invalid */
3413 } else if (found_colon) {
3414 /* If colons exist, they must delimit 1 or 2 hex chars */
3419 return g_bytes_new (c, x);
3423 * nm_utils_iface_valid_name:
3424 * @name: Name of interface
3426 * This function is a 1:1 copy of the kernel's interface validation
3427 * function in net/core/dev.c.
3429 * Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
3432 nm_utils_iface_valid_name (const char *name)
3434 g_return_val_if_fail (name != NULL, FALSE);
3439 if (strlen (name) >= 16)
3442 if (!strcmp (name, ".") || !strcmp (name, ".."))
3446 if (*name == '/' || g_ascii_isspace (*name))
3456 * @str: a string that might be a UUID
3458 * Checks if @str is a UUID
3460 * Returns: %TRUE if @str is a UUID, %FALSE if not
3463 nm_utils_is_uuid (const char *str)
3465 const char *p = str;
3471 else if (!g_ascii_isxdigit (*p))
3476 if ((num_dashes == 4) && (p - str == 36))
3479 /* Backwards compat for older configurations */
3480 if ((num_dashes == 0) && (p - str == 40))
3486 static char _nm_utils_inet_ntop_buffer[NM_UTILS_INET_ADDRSTRLEN];
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.
3500 * Wrapper for inet_ntop.
3502 * Returns: the input buffer @dst, or a pointer to an
3503 * internal, static buffer. This function cannot fail.
3506 nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
3508 return inet_ntop (AF_INET, &inaddr, dst ? dst : _nm_utils_inet_ntop_buffer,
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.
3524 * Wrapper for inet_ntop.
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.
3531 nm_utils_inet6_ntop (const struct in6_addr *in6addr, char *dst)
3533 g_return_val_if_fail (in6addr, NULL);
3534 return inet_ntop (AF_INET6, in6addr, dst ? dst : _nm_utils_inet_ntop_buffer,
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
3544 * Checks if @ip contains a valid IP address of the given family.
3546 * Return value: %TRUE or %FALSE
3549 nm_utils_ipaddr_valid (int family, const char *ip)
3551 guint8 buf[sizeof (struct in6_addr)];
3553 g_return_val_if_fail (family == AF_INET || family == AF_INET6 || family == AF_UNSPEC, FALSE);
3558 if (family == AF_UNSPEC)
3559 family = strchr (ip, ':') ? AF_INET6 : AF_INET;
3561 return inet_pton (family, ip, buf) == 1;
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
3569 * Determines if a connection of type @virtual_type can (in the
3570 * general case) work with connections of type @other_type.
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.
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
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.
3585 * Returns: %TRUE or %FALSE
3588 nm_utils_check_virtual_device_compatibility (GType virtual_type, GType other_type)
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);
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);
3619 g_warn_if_reached ();
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" },
3640 * nm_utils_bond_mode_int_to_string:
3641 * @mode: bonding mode as a numeric value
3643 * Convert bonding mode from integer value to descriptive name.
3644 * See https://www.kernel.org/doc/Documentation/networking/bonding.txt for
3647 * Returns: bonding mode string, or NULL on error
3652 nm_utils_bond_mode_int_to_string (int mode)
3654 if (mode >= 0 && mode < G_N_ELEMENTS (bond_mode_table))
3655 return bond_mode_table[mode].str;
3660 * nm_utils_bond_mode_string_to_int:
3661 * @mode: bonding mode as string
3663 * Convert bonding mode from string representation to numeric value.
3664 * See https://www.kernel.org/doc/Documentation/networking/bonding.txt for
3666 * The @mode string can be either a descriptive name or a number (as string).
3668 * Returns: numeric bond mode, or -1 on error
3673 nm_utils_bond_mode_string_to_int (const char *mode)
3677 if (!mode || !*mode)
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)
3688 /**********************************************************************************************/
3690 #define STRSTRDICTKEY_V1_SET 0x01
3691 #define STRSTRDICTKEY_V2_SET 0x02
3692 #define STRSTRDICTKEY_ALL_SET 0x03
3694 struct _NMUtilsStrStrDictKey {
3700 _nm_utils_strstrdictkey_hash (gconstpointer a)
3702 const NMUtilsStrStrDictKey *k = a;
3703 const signed char *p;
3707 if (((int) k->type) & ~STRSTRDICTKEY_ALL_SET)
3708 g_return_val_if_reached (0);
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;
3728 _nm_utils_strstrdictkey_equal (gconstpointer a, gconstpointer b)
3730 const NMUtilsStrStrDictKey *k1 = a;
3731 const NMUtilsStrStrDictKey *k2 = b;
3738 if (k1->type != k2->type)
3741 if (k1->type & STRSTRDICTKEY_ALL_SET) {
3742 if (strcmp (k1->data, k2->data) != 0)
3745 if (k1->type == STRSTRDICTKEY_ALL_SET) {
3746 gsize l = strlen (k1->data) + 1;
3748 return strcmp (&k1->data[l], &k2->data[l]) == 0;
3755 NMUtilsStrStrDictKey *
3756 _nm_utils_strstrdictkey_create (const char *v1, const char *v2)
3759 gsize l1 = 0, l2 = 0;
3760 NMUtilsStrStrDictKey *k;
3763 return g_malloc0 (1);
3765 /* we need to distinguish between ("",NULL) and (NULL,"").
3766 * Thus, in @type we encode which strings we have present
3769 type |= STRSTRDICTKEY_V1_SET;
3770 l1 = strlen (v1) + 1;
3773 type |= STRSTRDICTKEY_V2_SET;
3774 l2 = strlen (v2) + 1;
3777 k = g_malloc (G_STRUCT_OFFSET (NMUtilsStrStrDictKey, data) + l1 + l2);
3780 memcpy (&k->data[0], v1, l1);
3782 memcpy (&k->data[l1], v2, l2);
3788 validate_dns_option (const char *name, gboolean numeric, gboolean ipv6,
3789 const NMUtilsDNSOptionDesc *option_descs)
3791 const NMUtilsDNSOptionDesc *desc;
3796 for (desc = option_descs; desc->name; desc++) {
3797 if (!strcmp (name, desc->name) &&
3798 numeric == desc->numeric &&
3799 (!desc->ipv6_only || ipv6))
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
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
3820 * Returns: %TRUE when the parsing was successful and the option is valid,
3824 _nm_utils_dns_option_validate (const char *option, char **out_name,
3825 long *out_value, gboolean ipv6,
3826 const NMUtilsDNSOptionDesc *option_descs)
3828 char **tokens, *ptr;
3829 gboolean ret = FALSE;
3831 g_return_val_if_fail (option != NULL, FALSE);
3841 tokens = g_strsplit (option, ":", 2);
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]);
3850 if (!tokens[1][0]) {
3855 for (ptr = tokens[1]; *ptr; ptr++) {
3856 if (!g_ascii_isdigit (*ptr)) {
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);
3867 *out_name = g_strdup (tokens[0]);
3874 g_strfreev (tokens);
3879 * _nm_utils_dns_option_find_idx:
3880 * @array: an array of strings
3881 * @option: a dns option string
3883 * Searches for an option in an array of strings. The match is
3884 * performed only the option name; the option value is ignored.
3886 * Returns: the index of the option in the array or -1 if was not
3889 int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option)
3892 char *option_name, *tmp_name;
3895 if (!_nm_utils_dns_option_validate (option, &option_name, NULL, FALSE, NULL))
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);
3903 g_free (option_name);
3910 g_free (option_name);
3915 * nm_utils_enum_to_str:
3916 * @type: the %GType of the enum
3917 * @value: the value to be translated
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.
3924 * Returns: a newly allocated string or %NULL
3928 char *nm_utils_enum_to_str (GType type, int value)
3933 class = g_type_class_ref (type);
3935 if (G_IS_ENUM_CLASS (class)) {
3936 GEnumValue *enum_value;
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;
3946 flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), value);
3951 g_string_append (str, ", ");
3952 g_string_append (str, flags_value->value_nick);
3954 value &= ~flags_value->value;
3957 ret = g_string_free (str, FALSE);
3959 g_return_val_if_reached (NULL);
3961 g_type_class_unref (class);
3964 NM_BACKPORT_SYMBOL (libnm_1_0_6, char *, nm_utils_enum_to_str,
3965 (GType type, int value), (type, value));
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
3974 * Converts a string to the matching enum value.
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.
3981 * Returns: %TRUE if the conversion was successful, %FALSE otherwise
3985 gboolean nm_utils_enum_from_str (GType type, const char *str,
3986 int *out_value, char **err_token)
3989 gboolean ret = FALSE;
3991 gs_free char *stripped = NULL;
3993 g_return_val_if_fail (str, FALSE);
3994 stripped = g_strstrip (strdup (str));
3995 class = g_type_class_ref (type);
3997 if (G_IS_ENUM_CLASS (class)) {
3998 GEnumValue *enum_value;
4000 enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), stripped);
4002 value = enum_value->value;
4005 } else if (G_IS_FLAGS_CLASS (class)) {
4006 GFlagsValue *flags_value;
4007 gs_strfreev char **strv = NULL;
4010 strv = g_strsplit_set (stripped, " \t,", 0);
4011 for (i = 0; strv[i]; i++) {
4015 flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), strv[i]);
4019 value |= flags_value->value;
4024 *err_token = strdup (strv[i]);
4029 g_return_val_if_reached (FALSE);
4034 g_type_class_unref (class);
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));
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
4047 * Returns the list of possible values for a given enum.
4049 * Returns: (transfer full): a NULL-terminated dynamically-allocated array of static strings
4054 const char **nm_utils_enum_get_values (GType type, gint from, gint to)
4060 class = g_type_class_ref (type);
4061 array = g_ptr_array_new ();
4063 if (G_IS_ENUM_CLASS (class)) {
4064 GEnumClass *enum_class = G_ENUM_CLASS (class);
4065 GEnumValue *enum_value;
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);
4072 } else if (G_IS_FLAGS_CLASS (class)) {
4073 GFlagsClass *flags_class = G_FLAGS_CLASS (class);
4074 GFlagsValue *flags_value;
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);
4082 g_type_class_unref (class);
4083 g_ptr_array_free (array, TRUE);
4084 g_return_val_if_reached (NULL);
4087 g_type_class_unref (class);
4088 g_ptr_array_add (array, NULL);
4090 return (const char **) g_ptr_array_free (array, FALSE);