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"
48 /* Embed the commit id in the build binary */
49 static const char *const __nm_git_sha = NM_STRLEN (NM_GIT_SHA) > 0 ? "NM_GIT_SHA:"NM_GIT_SHA : "";
53 * @short_description: Utility functions
55 * A collection of utility functions for working with SSIDs, IP addresses, Wi-Fi
56 * access points and devices, among other things.
59 struct EncodingTriplet
61 const char *encoding1;
62 const char *encoding2;
63 const char *encoding3;
66 struct IsoLangToEncodings
69 struct EncodingTriplet encodings;
72 /* 5-letter language codes */
73 static const struct IsoLangToEncodings isoLangEntries5[] =
75 /* Simplified Chinese */
76 { "zh_cn", {"euc-cn", "gb2312", "gb18030"} }, /* PRC */
77 { "zh_sg", {"euc-cn", "gb2312", "gb18030"} }, /* Singapore */
79 /* Traditional Chinese */
80 { "zh_tw", {"big5", "euc-tw", NULL} }, /* Taiwan */
81 { "zh_hk", {"big5", "euc-tw", "big5-hkcs"} },/* Hong Kong */
82 { "zh_mo", {"big5", "euc-tw", NULL} }, /* Macau */
85 { NULL, {NULL, NULL, NULL} }
88 /* 2-letter language codes; we don't care about the other 3 in this table */
89 static const struct IsoLangToEncodings isoLangEntries2[] =
92 { "ja", {"euc-jp", "shift_jis", "iso-2022-jp"} },
95 { "ko", {"euc-kr", "iso-2022-kr", "johab"} },
98 { "th", {"iso-8859-11","windows-874", NULL} },
100 /* Central European */
101 { "hu", {"iso-8859-2", "windows-1250", NULL} }, /* Hungarian */
102 { "cs", {"iso-8859-2", "windows-1250", NULL} }, /* Czech */
103 { "hr", {"iso-8859-2", "windows-1250", NULL} }, /* Croatian */
104 { "pl", {"iso-8859-2", "windows-1250", NULL} }, /* Polish */
105 { "ro", {"iso-8859-2", "windows-1250", NULL} }, /* Romanian */
106 { "sk", {"iso-8859-2", "windows-1250", NULL} }, /* Slovakian */
107 { "sl", {"iso-8859-2", "windows-1250", NULL} }, /* Slovenian */
108 { "sh", {"iso-8859-2", "windows-1250", NULL} }, /* Serbo-Croatian */
111 { "ru", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Russian */
112 { "be", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Belorussian */
113 { "bg", {"windows-1251","koi8-r", "iso-8859-5"} }, /* Bulgarian */
114 { "mk", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Macedonian */
115 { "sr", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Serbian */
116 { "uk", {"koi8-u", "koi8-r", "windows-1251"} }, /* Ukranian */
119 { "ar", {"iso-8859-6", "windows-1256", NULL} },
122 { "et", {"iso-8859-4", "windows-1257", NULL} }, /* Estonian */
123 { "lt", {"iso-8859-4", "windows-1257", NULL} }, /* Lithuanian */
124 { "lv", {"iso-8859-4", "windows-1257", NULL} }, /* Latvian */
127 { "el", {"iso-8859-7", "windows-1253", NULL} },
130 { "he", {"iso-8859-8", "windows-1255", NULL} },
131 { "iw", {"iso-8859-8", "windows-1255", NULL} },
134 { "tr", {"iso-8859-9", "windows-1254", NULL} },
137 { NULL, {NULL, NULL, NULL} }
141 static GHashTable * langToEncodings5 = NULL;
142 static GHashTable * langToEncodings2 = NULL;
145 init_lang_to_encodings_hash (void)
147 struct IsoLangToEncodings *enc;
149 if (G_UNLIKELY (langToEncodings5 == NULL)) {
150 /* Five-letter codes */
151 enc = (struct IsoLangToEncodings *) &isoLangEntries5[0];
152 langToEncodings5 = g_hash_table_new (g_str_hash, g_str_equal);
154 g_hash_table_insert (langToEncodings5, (gpointer) enc->lang,
155 (gpointer) &enc->encodings);
160 if (G_UNLIKELY (langToEncodings2 == NULL)) {
161 /* Two-letter codes */
162 enc = (struct IsoLangToEncodings *) &isoLangEntries2[0];
163 langToEncodings2 = g_hash_table_new (g_str_hash, g_str_equal);
165 g_hash_table_insert (langToEncodings2, (gpointer) enc->lang,
166 (gpointer) &enc->encodings);
174 get_encodings_for_lang (const char *lang,
179 struct EncodingTriplet * encodings;
180 gboolean success = FALSE;
183 g_return_val_if_fail (lang != NULL, FALSE);
184 g_return_val_if_fail (encoding1 != NULL, FALSE);
185 g_return_val_if_fail (encoding2 != NULL, FALSE);
186 g_return_val_if_fail (encoding3 != NULL, FALSE);
188 *encoding1 = "iso-8859-1";
189 *encoding2 = "windows-1251";
192 init_lang_to_encodings_hash ();
194 tmp_lang = g_strdup (lang);
195 if ((encodings = g_hash_table_lookup (langToEncodings5, tmp_lang))) {
196 *encoding1 = (char *) encodings->encoding1;
197 *encoding2 = (char *) encodings->encoding2;
198 *encoding3 = (char *) encodings->encoding3;
202 /* Truncate tmp_lang to length of 2 */
203 if (strlen (tmp_lang) > 2)
205 if (!success && (encodings = g_hash_table_lookup (langToEncodings2, tmp_lang))) {
206 *encoding1 = (char *) encodings->encoding1;
207 *encoding2 = (char *) encodings->encoding2;
208 *encoding3 = (char *) encodings->encoding3;
218 static gboolean initialized = FALSE;
220 static void __attribute__((constructor))
221 _nm_utils_init (void)
232 self = g_module_open (NULL, 0);
233 if (g_module_symbol (self, "nm_util_get_private", &func))
234 g_error ("libnm-util symbols detected; Mixing libnm with libnm-util/libnm-glib is not supported");
235 g_module_close (self);
237 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
238 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
242 _nm_dbus_errors_init ();
245 gboolean _nm_utils_is_manager_process;
250 * nm_utils_ssid_to_utf8:
251 * @ssid: (array length=len): pointer to a buffer containing the SSID data
252 * @len: length of the SSID data in @ssid
254 * Wi-Fi SSIDs are byte arrays, they are _not_ strings. Thus, an SSID may
255 * contain embedded NULLs and other unprintable characters. Often it is
256 * useful to print the SSID out for debugging purposes, but that should be the
257 * _only_ use of this function. Do not use this function for any persistent
258 * storage of the SSID, since the printable SSID returned from this function
259 * cannot be converted back into the real SSID of the access point.
261 * This function does almost everything humanly possible to convert the input
262 * into a printable UTF-8 string, using roughly the following procedure:
264 * 1) if the input data is already UTF-8 safe, no conversion is performed
265 * 2) attempts to get the current system language from the LANG environment
266 * variable, and depending on the language, uses a table of alternative
267 * encodings to try. For example, if LANG=hu_HU, the table may first try
268 * the ISO-8859-2 encoding, and if that fails, try the Windows-1250 encoding.
269 * If all fallback encodings fail, replaces non-UTF-8 characters with '?'.
270 * 3) If the system language was unable to be determined, falls back to the
271 * ISO-8859-1 encoding, then to the Windows-1251 encoding.
272 * 4) If step 3 fails, replaces non-UTF-8 characters with '?'.
274 * Again, this function should be used for debugging and display purposes
277 * Returns: (transfer full): an allocated string containing a UTF-8
278 * representation of the SSID, which must be freed by the caller using g_free().
279 * Returns %NULL on errors.
282 nm_utils_ssid_to_utf8 (const guint8 *ssid, gsize len)
284 char *converted = NULL;
285 char *lang, *e1 = NULL, *e2 = NULL, *e3 = NULL;
287 g_return_val_if_fail (ssid != NULL, NULL);
289 if (g_utf8_validate ((const gchar *) ssid, len, NULL))
290 return g_strndup ((const gchar *) ssid, len);
292 /* LANG may be a good encoding hint */
293 g_get_charset ((const char **)(&e1));
294 if ((lang = getenv ("LANG"))) {
297 lang = g_ascii_strdown (lang, -1);
298 if ((dot = strchr (lang, '.')))
301 get_encodings_for_lang (lang, &e1, &e2, &e3);
305 converted = g_convert ((const gchar *) ssid, len, "UTF-8", e1, NULL, NULL, NULL);
306 if (!converted && e2)
307 converted = g_convert ((const gchar *) ssid, len, "UTF-8", e2, NULL, NULL, NULL);
309 if (!converted && e3)
310 converted = g_convert ((const gchar *) ssid, len, "UTF-8", e3, NULL, NULL, NULL);
313 converted = g_convert_with_fallback ((const gchar *) ssid, len,
314 "UTF-8", e1, "?", NULL, NULL, NULL);
318 /* If there is still no converted string, the SSID probably
319 * contains characters not valid in the current locale. Convert
320 * the string to ASCII instead.
323 /* Use the printable range of 0x20-0x7E */
324 gchar *valid_chars = " !\"#$%&'()*+,-./0123456789:;<=>?@"
325 "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
326 "abcdefghijklmnopqrstuvwxyz{|}~";
328 converted = g_strndup ((const gchar *)ssid, len);
329 g_strcanon (converted, valid_chars, '?');
335 /* Shamelessly ripped from the Linux kernel ieee80211 stack */
337 * nm_utils_is_empty_ssid:
338 * @ssid: (array length=len): pointer to a buffer containing the SSID data
339 * @len: length of the SSID data in @ssid
341 * Different manufacturers use different mechanisms for not broadcasting the
342 * AP's SSID. This function attempts to detect blank/empty SSIDs using a
343 * number of known SSID-cloaking methods.
345 * Returns: %TRUE if the SSID is "empty", %FALSE if it is not
348 nm_utils_is_empty_ssid (const guint8 *ssid, gsize len)
350 /* Single white space is for Linksys APs */
351 if (len == 1 && ssid[0] == ' ')
354 /* Otherwise, if the entire ssid is 0, we assume it is hidden */
356 if (ssid[len] != '\0')
362 #define ESSID_MAX_SIZE 32
365 * nm_utils_escape_ssid:
366 * @ssid: (array length=len): pointer to a buffer containing the SSID data
367 * @len: length of the SSID data in @ssid
369 * This function does a quick printable character conversion of the SSID, simply
370 * replacing embedded NULLs and non-printable characters with the hexadecimal
371 * representation of that character. Intended for debugging only, should not
372 * be used for display of SSIDs.
374 * Returns: pointer to the escaped SSID, which uses an internal static buffer
375 * and will be overwritten by subsequent calls to this function
378 nm_utils_escape_ssid (const guint8 *ssid, gsize len)
380 static char escaped[ESSID_MAX_SIZE * 2 + 1];
381 const guint8 *s = ssid;
384 if (nm_utils_is_empty_ssid (ssid, len)) {
385 memcpy (escaped, "<hidden>", sizeof ("<hidden>"));
389 len = MIN (len, (guint32) ESSID_MAX_SIZE);
404 * nm_utils_same_ssid:
405 * @ssid1: (array length=len1): the first SSID to compare
406 * @len1: length of the SSID data in @ssid1
407 * @ssid2: (array length=len2): the second SSID to compare
408 * @len2: length of the SSID data in @ssid2
409 * @ignore_trailing_null: %TRUE to ignore one trailing NULL byte
411 * Earlier versions of the Linux kernel added a NULL byte to the end of the
412 * SSID to enable easy printing of the SSID on the console or in a terminal,
413 * but this behavior was problematic (SSIDs are simply byte arrays, not strings)
414 * and thus was changed. This function compensates for that behavior at the
415 * cost of some compatibility with odd SSIDs that may legitimately have trailing
416 * NULLs, even though that is functionally pointless.
418 * Returns: %TRUE if the SSIDs are the same, %FALSE if they are not
421 nm_utils_same_ssid (const guint8 *ssid1, gsize len1,
422 const guint8 *ssid2, gsize len2,
423 gboolean ignore_trailing_null)
425 g_return_val_if_fail (ssid1 != NULL || len1 == 0, FALSE);
426 g_return_val_if_fail (ssid2 != NULL || len2 == 0, FALSE);
428 if (ssid1 == ssid2 && len1 == len2)
430 if (!ssid1 || !ssid2)
433 if (ignore_trailing_null) {
434 if (len1 && ssid1[len1 - 1] == '\0')
436 if (len2 && ssid2[len2 - 1] == '\0')
443 return memcmp (ssid1, ssid2, len1) == 0 ? TRUE : FALSE;
447 _nm_utils_string_in_list (const char *str, const char **valid_strings)
449 return _nm_utils_strv_find_first ((char **) valid_strings, -1, str) >= 0;
453 * _nm_utils_strv_find_first:
454 * @list: the strv list to search
455 * @len: the length of the list, or a negative value if @list is %NULL terminated.
456 * @needle: the value to search for. The search is done using strcmp().
458 * Searches @list for @needle and returns the index of the first match (based
461 * For convenience, @list has type 'char**' instead of 'const char **'.
463 * Returns: index of first occurrence or -1 if @needle is not found in @list.
466 _nm_utils_strv_find_first (char **list, gssize len, const char *needle)
471 g_return_val_if_fail (list, -1);
474 /* if we search a list with known length, %NULL is a valid @needle. */
475 for (i = 0; i < len; i++) {
480 for (i = 0; i < len; i++) {
481 if (list[i] && !strcmp (needle, list[i]))
485 } else if (len < 0) {
486 g_return_val_if_fail (needle, -1);
489 for (i = 0; list[i]; i++) {
490 if (strcmp (needle, list[i]) == 0)
499 _nm_utils_strv_cleanup (char **strv,
500 gboolean strip_whitespace,
502 gboolean skip_repeated)
509 if (strip_whitespace) {
510 for (i = 0; strv[i]; i++)
511 g_strstrip (strv[i]);
513 if (!skip_empty && !skip_repeated)
516 for (i = 0; strv[i]; i++) {
517 if ( (skip_empty && !*strv[i])
518 || (skip_repeated && _nm_utils_strv_find_first (strv, j, strv[i]) >= 0))
529 _nm_utils_string_slist_validate (GSList *list, const char **valid_values)
533 for (iter = list; iter; iter = iter->next) {
534 if (!_nm_utils_string_in_list ((char *) iter->data, valid_values))
542 * _nm_utils_hash_values_to_slist:
543 * @hash: a #GHashTable
545 * Utility function to iterate over a hash table and return
546 * it's values as a #GSList.
548 * Returns: (element-type gpointer) (transfer container): a newly allocated #GSList
549 * containing the values of the hash table. The caller must free the
550 * returned list with g_slist_free(). The hash values are not owned
551 * by the returned list.
554 _nm_utils_hash_values_to_slist (GHashTable *hash)
560 g_return_val_if_fail (hash, NULL);
562 g_hash_table_iter_init (&iter, hash);
563 while (g_hash_table_iter_next (&iter, NULL, &value))
564 list = g_slist_prepend (list, value);
570 _nm_utils_strdict_to_dbus (const GValue *prop_value)
575 GVariantBuilder builder;
577 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
578 hash = g_value_get_boxed (prop_value);
580 g_hash_table_iter_init (&iter, hash);
581 while (g_hash_table_iter_next (&iter, &key, &value))
582 g_variant_builder_add (&builder, "{ss}", key, value);
585 return g_variant_builder_end (&builder);
589 _nm_utils_strdict_from_dbus (GVariant *dbus_value,
593 const char *key, *value;
596 hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
597 g_variant_iter_init (&iter, dbus_value);
598 while (g_variant_iter_next (&iter, "{&s&s}", &key, &value))
599 g_hash_table_insert (hash, g_strdup (key), g_strdup (value));
601 g_value_take_boxed (prop_value, hash);
605 _nm_utils_copy_strdict (GHashTable *strdict)
611 copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
613 g_hash_table_iter_init (&iter, strdict);
614 while (g_hash_table_iter_next (&iter, &key, &value))
615 g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
621 _nm_utils_copy_slist_to_array (const GSList *list,
622 NMUtilsCopyFunc copy_func,
623 GDestroyNotify unref_func)
628 array = g_ptr_array_new_with_free_func (unref_func);
629 for (iter = list; iter; iter = iter->next)
630 g_ptr_array_add (array, copy_func ? copy_func (iter->data) : iter->data);
635 _nm_utils_copy_array_to_slist (const GPtrArray *array,
636 NMUtilsCopyFunc copy_func)
638 GSList *slist = NULL;
645 for (i = 0; i < array->len; i++) {
646 item = array->pdata[i];
647 slist = g_slist_prepend (slist, copy_func (item));
650 return g_slist_reverse (slist);
654 _nm_utils_copy_array (const GPtrArray *array,
655 NMUtilsCopyFunc copy_func,
656 GDestroyNotify free_func)
662 return g_ptr_array_new_with_free_func (free_func);
664 copy = g_ptr_array_new_full (array->len, free_func);
665 for (i = 0; i < array->len; i++)
666 g_ptr_array_add (copy, copy_func (array->pdata[i]));
671 _nm_utils_copy_object_array (const GPtrArray *array)
673 return _nm_utils_copy_array (array, g_object_ref, g_object_unref);
676 /* have @list of type 'gpointer *' instead of 'gconstpointer *' to
677 * reduce the necessity for annoying const-casts. */
679 _nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle)
687 g_return_val_if_fail (list, -1);
688 for (i = 0; i < len; i++) {
689 if (list[i] == needle)
693 g_return_val_if_fail (needle, -1);
694 for (i = 0; list && list[i]; i++) {
695 if (list[i] == needle)
703 _nm_utils_ptrarray_find_binary_search (gpointer *list, gsize len, gpointer needle, GCompareDataFunc cmpfcn, gpointer user_data)
705 gssize imin, imax, imid;
708 g_return_val_if_fail (list || !len, ~((gssize) 0));
709 g_return_val_if_fail (cmpfcn, ~((gssize) 0));
717 while (imin <= imax) {
718 imid = imin + (imax - imin) / 2;
720 cmp = cmpfcn (list[imid], needle, user_data);
730 /* return the inverse of @imin. This is a negative number, but
731 * also is ~imin the position where the value should be inserted. */
736 _nm_utils_bytes_to_dbus (const GValue *prop_value)
738 GBytes *bytes = g_value_get_boxed (prop_value);
741 return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
742 g_bytes_get_data (bytes, NULL),
743 g_bytes_get_size (bytes),
746 return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
753 _nm_utils_bytes_from_dbus (GVariant *dbus_value,
758 if (g_variant_n_children (dbus_value)) {
762 data = g_variant_get_fixed_array (dbus_value, &length, 1);
763 bytes = g_bytes_new (data, length);
766 g_value_take_boxed (prop_value, bytes);
770 _nm_utils_strv_to_slist (char **strv, gboolean deep_copy)
777 for (i = 0; strv[i]; i++)
778 list = g_slist_prepend (list, g_strdup (strv[i]));
780 for (i = 0; strv[i]; i++)
781 list = g_slist_prepend (list, strv[i]);
785 return g_slist_reverse (list);
789 _nm_utils_slist_to_strv (GSList *slist, gboolean deep_copy)
795 len = g_slist_length (slist);
796 strv = g_new (char *, len + 1);
799 for (i = 0, iter = slist; iter; iter = iter->next, i++)
800 strv[i] = g_strdup (iter->data);
802 for (i = 0, iter = slist; iter; iter = iter->next, i++)
803 strv[i] = iter->data;
811 _nm_utils_strv_to_ptrarray (char **strv)
816 ptrarray = g_ptr_array_new_with_free_func (g_free);
819 for (i = 0; strv[i]; i++)
820 g_ptr_array_add (ptrarray, g_strdup (strv[i]));
827 _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray)
833 return g_new0 (char *, 1);
835 strv = g_new (char *, ptrarray->len + 1);
837 for (i = 0; i < ptrarray->len; i++)
838 strv[i] = g_strdup (ptrarray->pdata[i]);
845 * _nm_utils_strv_equal:
846 * @strv1: a string array
847 * @strv2: a string array
849 * Compare NULL-terminated string arrays for equality.
851 * Returns: %TRUE if the arrays are equal, %FALSE otherwise.
854 _nm_utils_strv_equal (char **strv1, char **strv2)
859 if (!strv1 || !strv2)
862 for ( ; *strv1 && *strv2 && !strcmp (*strv1, *strv2); strv1++, strv2++)
865 return !*strv1 && !*strv2;
869 * _nm_utils_strsplit_set:
870 * @str: string to split
871 * @delimiters: string of delimiter characters
872 * @max_tokens: the maximum number of tokens to split string into. When it is
873 * less than 1, the @str is split completely.
875 * Utility function for splitting string into a string array. It is a wrapper
876 * for g_strsplit_set(), but it also removes empty strings from the vector as
877 * they are not useful in most cases.
879 * Returns: (transfer full): a newly allocated NULL-terminated array of strings.
880 * The caller must free the returned array with g_strfreev().
883 _nm_utils_strsplit_set (const char *str, const char *delimiters, int max_tokens)
889 result = g_strsplit_set (str, delimiters, max_tokens);
891 /* remove empty strings */
892 for (i = 0; result && result[i]; i++) {
893 if (*result[i] == '\0') {
895 for (j = i; result[j]; j++)
896 result[j] = result[j + 1];
904 device_supports_ap_ciphers (guint32 dev_caps,
908 gboolean have_pair = FALSE;
909 gboolean have_group = FALSE;
910 /* Device needs to support at least one pairwise and one group cipher */
914 /* Static WEP only uses group ciphers */
917 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
918 if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP40)
920 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
921 if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP104)
923 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
924 if (ap_flags & NM_802_11_AP_SEC_PAIR_TKIP)
926 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
927 if (ap_flags & NM_802_11_AP_SEC_PAIR_CCMP)
932 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
933 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP40)
935 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
936 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP104)
939 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
940 if (ap_flags & NM_802_11_AP_SEC_GROUP_TKIP)
942 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
943 if (ap_flags & NM_802_11_AP_SEC_GROUP_CCMP)
947 return (have_pair && have_group);
951 * nm_utils_ap_mode_security_valid:
952 * @type: the security type to check device capabilties against,
953 * e.g. #NMU_SEC_STATIC_WEP
954 * @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
955 * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
957 * Given a set of device capabilities, and a desired security type to check
958 * against, determines whether the combination of device capabilities and
959 * desired security type are valid for AP/Hotspot connections.
961 * Returns: %TRUE if the device capabilities are compatible with the desired
962 * @type, %FALSE if they are not.
965 nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
966 NMDeviceWifiCapabilities wifi_caps)
968 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_AP))
971 /* Return TRUE for any security that wpa_supplicant's lightweight AP
972 * mode can handle: which is open, WEP, and WPA/WPA2 PSK.
976 case NMU_SEC_STATIC_WEP:
977 case NMU_SEC_WPA_PSK:
978 case NMU_SEC_WPA2_PSK:
987 * nm_utils_security_valid:
988 * @type: the security type to check AP flags and device capabilties against,
989 * e.g. #NMU_SEC_STATIC_WEP
990 * @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
991 * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
992 * @have_ap: whether the @ap_flags, @ap_wpa, and @ap_rsn arguments are valid
993 * @adhoc: whether the capabilities being tested are from an Ad-Hoc AP (IBSS)
994 * @ap_flags: bitfield of AP capabilities, e.g. #NM_802_11_AP_FLAGS_PRIVACY
995 * @ap_wpa: bitfield of AP capabilties derived from the AP's WPA beacon,
996 * e.g. (#NM_802_11_AP_SEC_PAIR_TKIP | #NM_802_11_AP_SEC_KEY_MGMT_PSK)
997 * @ap_rsn: bitfield of AP capabilties derived from the AP's RSN/WPA2 beacon,
998 * e.g. (#NM_802_11_AP_SEC_PAIR_CCMP | #NM_802_11_AP_SEC_PAIR_TKIP)
1000 * Given a set of device capabilities, and a desired security type to check
1001 * against, determines whether the combination of device, desired security
1002 * type, and AP capabilities intersect.
1004 * NOTE: this function cannot handle checking security for AP/Hotspot mode;
1005 * use nm_utils_ap_mode_security_valid() instead.
1007 * Returns: %TRUE if the device capabilities and AP capabilties intersect and are
1008 * compatible with the desired @type, %FALSE if they are not
1011 nm_utils_security_valid (NMUtilsSecurityType type,
1012 NMDeviceWifiCapabilities wifi_caps,
1015 NM80211ApFlags ap_flags,
1016 NM80211ApSecurityFlags ap_wpa,
1017 NM80211ApSecurityFlags ap_rsn)
1019 gboolean good = TRUE;
1022 if (type == NMU_SEC_NONE)
1024 if ( (type == NMU_SEC_STATIC_WEP)
1025 || ((type == NMU_SEC_DYNAMIC_WEP) && !adhoc)
1026 || ((type == NMU_SEC_LEAP) && !adhoc)) {
1027 if (wifi_caps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104))
1037 if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
1039 if (ap_wpa || ap_rsn)
1042 case NMU_SEC_LEAP: /* require PRIVACY bit for LEAP? */
1046 case NMU_SEC_STATIC_WEP:
1048 if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
1050 if (ap_wpa || ap_rsn) {
1051 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, TRUE))
1052 if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, TRUE))
1056 case NMU_SEC_DYNAMIC_WEP:
1060 if (ap_rsn || !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
1062 /* Some APs broadcast minimal WPA-enabled beacons that must be handled */
1064 if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1066 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
1070 case NMU_SEC_WPA_PSK:
1072 return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
1073 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
1076 /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
1077 * they don't have any pairwise ciphers. */
1079 /* coverity[dead_error_line] */
1080 if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_TKIP)
1081 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
1083 if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_CCMP)
1084 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
1087 if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
1088 if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
1089 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
1091 if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
1092 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
1099 case NMU_SEC_WPA2_PSK:
1101 return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
1102 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
1105 /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
1106 * they don't have any pairwise ciphers, nor any RSA flags yet. */
1108 /* coverity[dead_error_line] */
1109 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
1111 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
1114 if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
1115 if ( (ap_rsn & NM_802_11_AP_SEC_PAIR_TKIP)
1116 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
1118 if ( (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
1119 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
1126 case NMU_SEC_WPA_ENTERPRISE:
1129 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
1132 if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1134 /* Ensure at least one WPA cipher is supported */
1135 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
1139 case NMU_SEC_WPA2_ENTERPRISE:
1142 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
1145 if (!(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
1147 /* Ensure at least one WPA cipher is supported */
1148 if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, FALSE))
1161 * nm_utils_wep_key_valid:
1162 * @key: a string that might be a WEP key
1163 * @wep_type: the #NMWepKeyType type of the WEP key
1165 * Checks if @key is a valid WEP key
1167 * Returns: %TRUE if @key is a WEP key, %FALSE if not
1170 nm_utils_wep_key_valid (const char *key, NMWepKeyType wep_type)
1177 if (wep_type == NM_WEP_KEY_TYPE_UNKNOWN) {
1178 return nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_KEY) ||
1179 nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_PASSPHRASE);
1182 keylen = strlen (key);
1183 if (wep_type == NM_WEP_KEY_TYPE_KEY) {
1184 if (keylen == 10 || keylen == 26) {
1186 for (i = 0; i < keylen; i++) {
1187 if (!g_ascii_isxdigit (key[i]))
1190 } else if (keylen == 5 || keylen == 13) {
1192 for (i = 0; i < keylen; i++) {
1193 if (!g_ascii_isprint (key[i]))
1198 } else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
1199 if (!keylen || keylen > 64)
1207 * nm_utils_wpa_psk_valid:
1208 * @psk: a string that might be a WPA PSK
1210 * Checks if @psk is a valid WPA PSK
1212 * Returns: %TRUE if @psk is a WPA PSK, %FALSE if not
1215 nm_utils_wpa_psk_valid (const char *psk)
1222 psklen = strlen (psk);
1223 if (psklen < 8 || psklen > 64)
1228 for (i = 0; i < psklen; i++) {
1229 if (!g_ascii_isxdigit (psk[i]))
1238 * nm_utils_ip4_dns_to_variant:
1239 * @dns: (type utf8): an array of IP address strings
1241 * Utility function to convert an array of IP address strings int a #GVariant of
1242 * type 'au' representing an array of IPv4 addresses.
1244 * Returns: (transfer none): a new floating #GVariant representing @dns.
1247 nm_utils_ip4_dns_to_variant (char **dns)
1249 GVariantBuilder builder;
1252 g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
1255 for (i = 0; dns[i]; i++) {
1258 inet_pton (AF_INET, dns[i], &ip);
1259 g_variant_builder_add (&builder, "u", ip);
1263 return g_variant_builder_end (&builder);
1267 * nm_utils_ip4_dns_from_variant:
1268 * @value: a #GVariant of type 'au'
1270 * Utility function to convert a #GVariant of type 'au' representing a list of
1271 * IPv4 addresses into an array of IP address strings.
1273 * Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
1276 nm_utils_ip4_dns_from_variant (GVariant *value)
1278 const guint32 *array;
1283 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("au")), NULL);
1285 array = g_variant_get_fixed_array (value, &length, sizeof (guint32));
1286 dns = g_new (char *, length + 1);
1288 for (i = 0; i < length; i++)
1289 dns[i] = g_strdup (nm_utils_inet4_ntop (array[i], NULL));
1296 * nm_utils_ip4_addresses_to_variant:
1297 * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
1298 * @gateway: (allow-none): the gateway IP address
1300 * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
1301 * IPv4 addresses into a #GVariant of type 'aau' representing an array of
1302 * NetworkManager IPv4 addresses (which are tuples of address, prefix, and
1303 * gateway). The "gateway" field of the first address will get the value of
1304 * @gateway (if non-%NULL). In all of the other addresses, that field will be 0.
1306 * Returns: (transfer none): a new floating #GVariant representing @addresses.
1309 nm_utils_ip4_addresses_to_variant (GPtrArray *addresses, const char *gateway)
1311 GVariantBuilder builder;
1314 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aau"));
1317 for (i = 0; i < addresses->len; i++) {
1318 NMIPAddress *addr = addresses->pdata[i];
1321 if (nm_ip_address_get_family (addr) != AF_INET)
1324 nm_ip_address_get_address_binary (addr, &array[0]);
1325 array[1] = nm_ip_address_get_prefix (addr);
1326 if (i == 0 && gateway)
1327 inet_pton (AF_INET, gateway, &array[2]);
1331 g_variant_builder_add (&builder, "@au",
1332 g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
1333 array, 3, sizeof (guint32)));
1337 return g_variant_builder_end (&builder);
1341 * nm_utils_ip4_addresses_from_variant:
1342 * @value: a #GVariant of type 'aau'
1343 * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway
1345 * Utility function to convert a #GVariant of type 'aau' representing a list of
1346 * NetworkManager IPv4 addresses (which are tuples of address, prefix, and
1347 * gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field of
1348 * the first address (if set) will be returned in @out_gateway; the "gateway" fields
1349 * of the other addresses are ignored.
1351 * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1352 * #GPtrArray of #NMIPAddress objects
1355 nm_utils_ip4_addresses_from_variant (GVariant *value, char **out_gateway)
1357 GPtrArray *addresses;
1361 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aau")), NULL);
1364 *out_gateway = NULL;
1366 g_variant_iter_init (&iter, value);
1367 addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
1369 while (g_variant_iter_next (&iter, "@au", &addr_var)) {
1370 const guint32 *addr_array;
1373 GError *error = NULL;
1375 addr_array = g_variant_get_fixed_array (addr_var, &length, sizeof (guint32));
1377 g_warning ("Ignoring invalid IP4 address");
1378 g_variant_unref (addr_var);
1382 addr = nm_ip_address_new_binary (AF_INET, &addr_array[0], addr_array[1], &error);
1384 g_ptr_array_add (addresses, addr);
1386 if (addr_array[2] && out_gateway && !*out_gateway)
1387 *out_gateway = g_strdup (nm_utils_inet4_ntop (addr_array[2], NULL));
1389 g_warning ("Ignoring invalid IP4 address: %s", error->message);
1390 g_clear_error (&error);
1393 g_variant_unref (addr_var);
1400 * nm_utils_ip4_routes_to_variant:
1401 * @routes: (element-type NMIPRoute): an array of #NMIP4Route objects
1403 * Utility function to convert a #GPtrArray of #NMIPRoute objects representing
1404 * IPv4 routes into a #GVariant of type 'aau' representing an array of
1405 * NetworkManager IPv4 routes (which are tuples of route, prefix, next hop, and
1408 * Returns: (transfer none): a new floating #GVariant representing @routes.
1411 nm_utils_ip4_routes_to_variant (GPtrArray *routes)
1413 GVariantBuilder builder;
1416 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aau"));
1419 for (i = 0; i < routes->len; i++) {
1420 NMIPRoute *route = routes->pdata[i];
1423 if (nm_ip_route_get_family (route) != AF_INET)
1426 nm_ip_route_get_dest_binary (route, &array[0]);
1427 array[1] = nm_ip_route_get_prefix (route);
1428 nm_ip_route_get_next_hop_binary (route, &array[2]);
1429 /* The old routes format uses "0" for default, not "-1" */
1430 array[3] = MAX (0, nm_ip_route_get_metric (route));
1432 g_variant_builder_add (&builder, "@au",
1433 g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
1434 array, 4, sizeof (guint32)));
1438 return g_variant_builder_end (&builder);
1442 * nm_utils_ip4_routes_from_variant:
1443 * @value: #GVariant of type 'aau'
1445 * Utility function to convert a #GVariant of type 'aau' representing an array
1446 * of NetworkManager IPv4 routes (which are tuples of route, prefix, next hop,
1447 * and metric) into a #GPtrArray of #NMIPRoute objects.
1449 * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
1450 * #GPtrArray of #NMIPRoute objects
1453 nm_utils_ip4_routes_from_variant (GVariant *value)
1456 GVariant *route_var;
1459 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aau")), NULL);
1461 g_variant_iter_init (&iter, value);
1462 routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
1464 while (g_variant_iter_next (&iter, "@au", &route_var)) {
1465 const guint32 *route_array;
1468 GError *error = NULL;
1470 route_array = g_variant_get_fixed_array (route_var, &length, sizeof (guint32));
1472 g_warning ("Ignoring invalid IP4 route");
1473 g_variant_unref (route_var);
1477 route = nm_ip_route_new_binary (AF_INET,
1481 /* The old routes format uses "0" for default, not "-1" */
1482 route_array[3] ? (gint64) route_array[3] : -1,
1485 g_ptr_array_add (routes, route);
1487 g_warning ("Ignoring invalid IP4 route: %s", error->message);
1488 g_clear_error (&error);
1490 g_variant_unref (route_var);
1497 * nm_utils_ip4_netmask_to_prefix:
1498 * @netmask: an IPv4 netmask in network byte order
1500 * Returns: the CIDR prefix represented by the netmask
1503 nm_utils_ip4_netmask_to_prefix (guint32 netmask)
1507 const guint8 *p = (guint8 *) &netmask;
1532 * nm_utils_ip4_prefix_to_netmask:
1533 * @prefix: a CIDR prefix
1535 * Returns: the netmask represented by the prefix, in network byte order
1538 nm_utils_ip4_prefix_to_netmask (guint32 prefix)
1540 return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
1545 * nm_utils_ip4_get_default_prefix:
1546 * @ip: an IPv4 address (in network byte order)
1548 * When the Internet was originally set up, various ranges of IP addresses were
1549 * segmented into three network classes: A, B, and C. This function will return
1550 * a prefix that is associated with the IP address specified defining where it
1551 * falls in the predefined classes.
1553 * Returns: the default class prefix for the given IP
1555 /* The function is originally from ipcalc.c of Red Hat's initscripts. */
1557 nm_utils_ip4_get_default_prefix (guint32 ip)
1559 if (((ntohl (ip) & 0xFF000000) >> 24) <= 127)
1560 return 8; /* Class A - 255.0.0.0 */
1561 else if (((ntohl (ip) & 0xFF000000) >> 24) <= 191)
1562 return 16; /* Class B - 255.255.0.0 */
1564 return 24; /* Class C - 255.255.255.0 */
1568 * nm_utils_ip6_dns_to_variant:
1569 * @dns: (type utf8): an array of IP address strings
1571 * Utility function to convert an array of IP address strings int a #GVariant of
1572 * type 'aay' representing an array of IPv6 addresses.
1574 * Returns: (transfer none): a new floating #GVariant representing @dns.
1577 nm_utils_ip6_dns_to_variant (char **dns)
1579 GVariantBuilder builder;
1582 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
1585 for (i = 0; dns[i]; i++) {
1588 inet_pton (AF_INET6, dns[i], &ip);
1589 g_variant_builder_add (&builder, "@ay",
1590 g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
1591 &ip, sizeof (ip), 1));
1595 return g_variant_builder_end (&builder);
1599 * nm_utils_ip6_dns_from_variant:
1600 * @value: a #GVariant of type 'aay'
1602 * Utility function to convert a #GVariant of type 'aay' representing a list of
1603 * IPv6 addresses into an array of IP address strings.
1605 * Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
1608 nm_utils_ip6_dns_from_variant (GVariant *value)
1615 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aay")), NULL);
1617 dns = g_new (char *, g_variant_n_children (value) + 1);
1619 g_variant_iter_init (&iter, value);
1621 while (g_variant_iter_next (&iter, "@ay", &ip_var)) {
1623 const struct in6_addr *ip = g_variant_get_fixed_array (ip_var, &length, 1);
1625 if (length != sizeof (struct in6_addr)) {
1626 g_warning ("%s: ignoring invalid IP6 address of length %d",
1627 __func__, (int) length);
1628 g_variant_unref (ip_var);
1632 dns[i++] = g_strdup (nm_utils_inet6_ntop (ip, NULL));
1633 g_variant_unref (ip_var);
1641 * nm_utils_ip6_addresses_to_variant:
1642 * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
1643 * @gateway: (allow-none): the gateway IP address
1645 * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
1646 * IPv6 addresses into a #GVariant of type 'a(ayuay)' representing an array of
1647 * NetworkManager IPv6 addresses (which are tuples of address, prefix, and
1648 * gateway). The "gateway" field of the first address will get the value of
1649 * @gateway (if non-%NULL). In all of the other addresses, that field will be
1652 * Returns: (transfer none): a new floating #GVariant representing @addresses.
1655 nm_utils_ip6_addresses_to_variant (GPtrArray *addresses, const char *gateway)
1657 GVariantBuilder builder;
1660 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayuay)"));
1663 for (i = 0; i < addresses->len; i++) {
1664 NMIPAddress *addr = addresses->pdata[i];
1665 struct in6_addr ip_bytes, gateway_bytes;
1666 GVariant *ip_var, *gateway_var;
1669 if (nm_ip_address_get_family (addr) != AF_INET6)
1672 nm_ip_address_get_address_binary (addr, &ip_bytes);
1673 ip_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &ip_bytes, 16, 1);
1675 prefix = nm_ip_address_get_prefix (addr);
1677 if (i == 0 && gateway)
1678 inet_pton (AF_INET6, gateway, &gateway_bytes);
1680 memset (&gateway_bytes, 0, sizeof (gateway_bytes));
1681 gateway_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &gateway_bytes, 16, 1);
1683 g_variant_builder_add (&builder, "(@ayu@ay)", ip_var, prefix, gateway_var);
1687 return g_variant_builder_end (&builder);
1691 * nm_utils_ip6_addresses_from_variant:
1692 * @value: a #GVariant of type 'a(ayuay)'
1693 * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway
1695 * Utility function to convert a #GVariant of type 'a(ayuay)' representing a
1696 * list of NetworkManager IPv6 addresses (which are tuples of address, prefix,
1697 * and gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field
1698 * of the first address (if set) will be returned in @out_gateway; the "gateway"
1699 * fields of the other addresses are ignored.
1701 * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1702 * #GPtrArray of #NMIPAddress objects
1705 nm_utils_ip6_addresses_from_variant (GVariant *value, char **out_gateway)
1708 GVariant *addr_var, *gateway_var;
1710 GPtrArray *addresses;
1712 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(ayuay)")), NULL);
1715 *out_gateway = NULL;
1717 g_variant_iter_init (&iter, value);
1718 addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
1720 while (g_variant_iter_next (&iter, "(@ayu@ay)", &addr_var, &prefix, &gateway_var)) {
1722 const struct in6_addr *addr_bytes, *gateway_bytes;
1723 gsize addr_len, gateway_len;
1724 GError *error = NULL;
1726 if ( !g_variant_is_of_type (addr_var, G_VARIANT_TYPE_BYTESTRING)
1727 || !g_variant_is_of_type (gateway_var, G_VARIANT_TYPE_BYTESTRING)) {
1728 g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1732 addr_bytes = g_variant_get_fixed_array (addr_var, &addr_len, 1);
1733 if (addr_len != 16) {
1734 g_warning ("%s: ignoring invalid IP6 address of length %d",
1735 __func__, (int) addr_len);
1739 addr = nm_ip_address_new_binary (AF_INET6, addr_bytes, prefix, &error);
1741 g_ptr_array_add (addresses, addr);
1743 if (out_gateway && !*out_gateway) {
1744 gateway_bytes = g_variant_get_fixed_array (gateway_var, &gateway_len, 1);
1745 if (gateway_len != 16) {
1746 g_warning ("%s: ignoring invalid IP6 address of length %d",
1747 __func__, (int) gateway_len);
1750 if (!IN6_IS_ADDR_UNSPECIFIED (gateway_bytes))
1751 *out_gateway = g_strdup (nm_utils_inet6_ntop (gateway_bytes, NULL));
1754 g_warning ("Ignoring invalid IP6 address: %s", error->message);
1755 g_clear_error (&error);
1759 g_variant_unref (addr_var);
1760 g_variant_unref (gateway_var);
1767 * nm_utils_ip6_routes_to_variant:
1768 * @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
1770 * Utility function to convert a #GPtrArray of #NMIPRoute objects representing
1771 * IPv6 routes into a #GVariant of type 'a(ayuayu)' representing an array of
1772 * NetworkManager IPv6 routes (which are tuples of route, prefix, next hop, and
1775 * Returns: (transfer none): a new floating #GVariant representing @routes.
1778 nm_utils_ip6_routes_to_variant (GPtrArray *routes)
1780 GVariantBuilder builder;
1783 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayuayu)"));
1786 for (i = 0; i < routes->len; i++) {
1787 NMIPRoute *route = routes->pdata[i];
1788 struct in6_addr dest_bytes, next_hop_bytes;
1789 GVariant *dest, *next_hop;
1790 guint32 prefix, metric;
1792 if (nm_ip_route_get_family (route) != AF_INET6)
1795 nm_ip_route_get_dest_binary (route, &dest_bytes);
1796 dest = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &dest_bytes, 16, 1);
1797 prefix = nm_ip_route_get_prefix (route);
1798 nm_ip_route_get_next_hop_binary (route, &next_hop_bytes);
1799 next_hop = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &next_hop_bytes, 16, 1);
1800 /* The old routes format uses "0" for default, not "-1" */
1801 metric = MAX (0, nm_ip_route_get_metric (route));
1803 g_variant_builder_add (&builder, "(@ayu@ayu)", dest, prefix, next_hop, metric);
1807 return g_variant_builder_end (&builder);
1811 * nm_utils_ip6_routes_from_variant:
1812 * @value: #GVariant of type 'a(ayuayu)'
1814 * Utility function to convert a #GVariant of type 'a(ayuayu)' representing an
1815 * array of NetworkManager IPv6 routes (which are tuples of route, prefix, next
1816 * hop, and metric) into a #GPtrArray of #NMIPRoute objects.
1818 * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
1819 * #GPtrArray of #NMIPRoute objects
1822 nm_utils_ip6_routes_from_variant (GVariant *value)
1826 GVariant *dest_var, *next_hop_var;
1827 const struct in6_addr *dest, *next_hop;
1828 gsize dest_len, next_hop_len;
1829 guint32 prefix, metric;
1831 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(ayuayu)")), NULL);
1833 routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
1835 g_variant_iter_init (&iter, value);
1836 while (g_variant_iter_next (&iter, "(@ayu@ayu)", &dest_var, &prefix, &next_hop_var, &metric)) {
1838 GError *error = NULL;
1840 if ( !g_variant_is_of_type (dest_var, G_VARIANT_TYPE_BYTESTRING)
1841 || !g_variant_is_of_type (next_hop_var, G_VARIANT_TYPE_BYTESTRING)) {
1842 g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1846 dest = g_variant_get_fixed_array (dest_var, &dest_len, 1);
1847 if (dest_len != 16) {
1848 g_warning ("%s: ignoring invalid IP6 address of length %d",
1849 __func__, (int) dest_len);
1853 next_hop = g_variant_get_fixed_array (next_hop_var, &next_hop_len, 1);
1854 if (next_hop_len != 16) {
1855 g_warning ("%s: ignoring invalid IP6 address of length %d",
1856 __func__, (int) next_hop_len);
1860 route = nm_ip_route_new_binary (AF_INET6, dest, prefix, next_hop,
1861 metric ? (gint64) metric : -1,
1864 g_ptr_array_add (routes, route);
1866 g_warning ("Ignoring invalid IP6 route: %s", error->message);
1867 g_clear_error (&error);
1871 g_variant_unref (dest_var);
1872 g_variant_unref (next_hop_var);
1879 * nm_utils_ip_addresses_to_variant:
1880 * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
1882 * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
1883 * IPv4 or IPv6 addresses into a #GVariant of type 'aa{sv}' representing an
1884 * array of new-style NetworkManager IP addresses. All addresses will include
1885 * "address" (an IP address string), and "prefix" (a uint). Some addresses may
1886 * include additional attributes.
1888 * Returns: (transfer none): a new floating #GVariant representing @addresses.
1891 nm_utils_ip_addresses_to_variant (GPtrArray *addresses)
1893 GVariantBuilder builder;
1896 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
1899 for (i = 0; i < addresses->len; i++) {
1900 NMIPAddress *addr = addresses->pdata[i];
1901 GVariantBuilder addr_builder;
1905 g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}"));
1906 g_variant_builder_add (&addr_builder, "{sv}",
1908 g_variant_new_string (nm_ip_address_get_address (addr)));
1909 g_variant_builder_add (&addr_builder, "{sv}",
1911 g_variant_new_uint32 (nm_ip_address_get_prefix (addr)));
1913 names = nm_ip_address_get_attribute_names (addr);
1914 for (n = 0; names[n]; n++) {
1915 g_variant_builder_add (&addr_builder, "{sv}",
1917 nm_ip_address_get_attribute (addr, names[n]));
1921 g_variant_builder_add (&builder, "a{sv}", &addr_builder);
1925 return g_variant_builder_end (&builder);
1929 * nm_utils_ip_addresses_from_variant:
1930 * @value: a #GVariant of type 'aa{sv}'
1931 * @family: an IP address family
1933 * Utility function to convert a #GVariant representing a list of new-style
1934 * NetworkManager IPv4 or IPv6 addresses (as described in the documentation for
1935 * nm_utils_ip_addresses_to_variant()) into a #GPtrArray of #NMIPAddress
1938 * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
1939 * #GPtrArray of #NMIPAddress objects
1942 nm_utils_ip_addresses_from_variant (GVariant *value,
1945 GPtrArray *addresses;
1946 GVariantIter iter, attrs_iter;
1950 const char *attr_name;
1953 GError *error = NULL;
1955 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
1957 g_variant_iter_init (&iter, value);
1958 addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
1960 while (g_variant_iter_next (&iter, "@a{sv}", &addr_var)) {
1961 if ( !g_variant_lookup (addr_var, "address", "&s", &ip)
1962 || !g_variant_lookup (addr_var, "prefix", "u", &prefix)) {
1963 g_warning ("Ignoring invalid address");
1964 g_variant_unref (addr_var);
1968 addr = nm_ip_address_new (family, ip, prefix, &error);
1970 g_warning ("Ignoring invalid address: %s", error->message);
1971 g_clear_error (&error);
1972 g_variant_unref (addr_var);
1976 g_variant_iter_init (&attrs_iter, addr_var);
1977 while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) {
1978 if ( strcmp (attr_name, "address") != 0
1979 && strcmp (attr_name, "prefix") != 0)
1980 nm_ip_address_set_attribute (addr, attr_name, attr_val);
1981 g_variant_unref (attr_val);
1984 g_variant_unref (addr_var);
1985 g_ptr_array_add (addresses, addr);
1992 * nm_utils_ip_routes_to_variant:
1993 * @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
1995 * Utility function to convert a #GPtrArray of #NMIPRoute objects representing
1996 * IPv4 or IPv6 routes into a #GVariant of type 'aa{sv}' representing an array
1997 * of new-style NetworkManager IP routes (which are tuples of destination,
1998 * prefix, next hop, metric, and additional attributes).
2000 * Returns: (transfer none): a new floating #GVariant representing @routes.
2003 nm_utils_ip_routes_to_variant (GPtrArray *routes)
2005 GVariantBuilder builder;
2008 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
2011 for (i = 0; i < routes->len; i++) {
2012 NMIPRoute *route = routes->pdata[i];
2013 GVariantBuilder route_builder;
2017 g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}"));
2018 g_variant_builder_add (&route_builder, "{sv}",
2020 g_variant_new_string (nm_ip_route_get_dest (route)));
2021 g_variant_builder_add (&route_builder, "{sv}",
2023 g_variant_new_uint32 (nm_ip_route_get_prefix (route)));
2024 if (nm_ip_route_get_next_hop (route)) {
2025 g_variant_builder_add (&route_builder, "{sv}",
2027 g_variant_new_string (nm_ip_route_get_next_hop (route)));
2029 if (nm_ip_route_get_metric (route) != -1) {
2030 g_variant_builder_add (&route_builder, "{sv}",
2032 g_variant_new_uint32 ((guint32) nm_ip_route_get_metric (route)));
2035 names = nm_ip_route_get_attribute_names (route);
2036 for (n = 0; names[n]; n++) {
2037 g_variant_builder_add (&route_builder, "{sv}",
2039 nm_ip_route_get_attribute (route, names[n]));
2043 g_variant_builder_add (&builder, "a{sv}", &route_builder);
2047 return g_variant_builder_end (&builder);
2051 * nm_utils_ip_routes_from_variant:
2052 * @value: a #GVariant of type 'aa{sv}'
2053 * @family: an IP address family
2055 * Utility function to convert a #GVariant representing a list of new-style
2056 * NetworkManager IPv4 or IPv6 addresses (which are tuples of destination,
2057 * prefix, next hop, metric, and additional attributes) into a #GPtrArray of
2058 * #NMIPRoute objects.
2060 * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
2061 * #GPtrArray of #NMIPRoute objects
2064 nm_utils_ip_routes_from_variant (GVariant *value,
2068 GVariantIter iter, attrs_iter;
2069 GVariant *route_var;
2070 const char *dest, *next_hop;
2071 guint32 prefix, metric32;
2073 const char *attr_name;
2076 GError *error = NULL;
2078 g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
2080 g_variant_iter_init (&iter, value);
2081 routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
2083 while (g_variant_iter_next (&iter, "@a{sv}", &route_var)) {
2084 if ( !g_variant_lookup (route_var, "dest", "&s", &dest)
2085 || !g_variant_lookup (route_var, "prefix", "u", &prefix)) {
2086 g_warning ("Ignoring invalid address");
2089 if (!g_variant_lookup (route_var, "next-hop", "&s", &next_hop))
2091 if (g_variant_lookup (route_var, "metric", "u", &metric32))
2096 route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &error);
2098 g_warning ("Ignoring invalid route: %s", error->message);
2099 g_clear_error (&error);
2103 g_variant_iter_init (&attrs_iter, route_var);
2104 while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) {
2105 if ( strcmp (attr_name, "dest") != 0
2106 && strcmp (attr_name, "prefix") != 0
2107 && strcmp (attr_name, "next-hop") != 0
2108 && strcmp (attr_name, "metric") != 0)
2109 nm_ip_route_set_attribute (route, attr_name, attr_val);
2110 g_variant_unref (attr_val);
2113 g_ptr_array_add (routes, route);
2115 g_variant_unref (route_var);
2121 /**********************************************************************************************/
2124 * nm_utils_uuid_generate:
2126 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
2127 * object's #NMSettingConnection:id: property. Should be freed with g_free()
2130 nm_utils_uuid_generate (void)
2135 buf = g_malloc0 (37);
2136 uuid_generate_random (uuid);
2137 uuid_unparse_lower (uuid, &buf[0]);
2142 * nm_utils_uuid_generate_from_string:
2143 * @s: a string to use as the seed for the UUID
2144 * @slen: if negative, treat @s as zero terminated C string.
2145 * Otherwise, assume the length as given (and allow @s to be
2146 * non-null terminated or contain '\0').
2147 * @uuid_type: a type identifier which UUID format to generate.
2148 * @type_args: additional arguments, depending on the uuid_type
2150 * For a given @s, this function will always return the same UUID.
2152 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
2153 * object's #NMSettingConnection:id: property
2156 nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args)
2161 g_return_val_if_fail (slen == 0 || s, FALSE);
2163 g_return_val_if_fail (uuid_type == NM_UTILS_UUID_TYPE_LEGACY || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
2164 g_return_val_if_fail (!type_args || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
2166 switch (uuid_type) {
2167 case NM_UTILS_UUID_TYPE_LEGACY:
2168 crypto_md5_hash (NULL, 0, s, slen, (char *) uuid, sizeof (uuid));
2170 case NM_UTILS_UUID_TYPE_VARIANT3: {
2171 uuid_t ns_uuid = { 0 };
2174 /* type_args can be a name space UUID. Interpret it as (char *) */
2175 if (uuid_parse ((char *) type_args, ns_uuid) != 0)
2176 g_return_val_if_reached (NULL);
2179 crypto_md5_hash (s, slen, (char *) ns_uuid, sizeof (ns_uuid), (char *) uuid, sizeof (uuid));
2181 uuid[6] = (uuid[6] & 0x0F) | 0x30;
2182 uuid[8] = (uuid[8] & 0x3F) | 0x80;
2186 g_return_val_if_reached (NULL);
2189 buf = g_malloc0 (37);
2190 uuid_unparse_lower (uuid, &buf[0]);
2196 * _nm_utils_uuid_generate_from_strings:
2197 * @string1: a variadic list of strings. Must be NULL terminated.
2199 * Returns a variant3 UUID based on the concatenated C strings.
2200 * It does not simply concatenate them, but also includes the
2201 * terminating '\0' character. For example "a", "b", gives
2204 * This has the advantage, that the following invocations
2205 * all give different UUIDs: (NULL), (""), ("",""), ("","a"), ("a",""),
2206 * ("aa"), ("aa", ""), ("", "aa"), ...
2209 _nm_utils_uuid_generate_from_strings (const char *string1, ...)
2217 return nm_utils_uuid_generate_from_string (NULL, 0, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
2219 str = g_string_sized_new (120); /* effectively allocates power of 2 (128)*/
2221 g_string_append_len (str, string1, strlen (string1) + 1);
2223 va_start (args, string1);
2224 s = va_arg (args, const char *);
2226 g_string_append_len (str, s, strlen (s) + 1);
2227 s = va_arg (args, const char *);
2231 uuid = nm_utils_uuid_generate_from_string (str->str, str->len, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
2233 g_string_free (str, TRUE);
2237 /**********************************************************************************************/
2240 * nm_utils_rsa_key_encrypt:
2241 * @data: (array length=len): RSA private key data to be encrypted
2242 * @len: length of @data
2243 * @in_password: (allow-none): existing password to use, if any
2244 * @out_password: (out) (allow-none): if @in_password was %NULL, a random
2245 * password will be generated and returned in this argument
2246 * @error: detailed error information on return, if an error occurred
2248 * Encrypts the given RSA private key data with the given password (or generates
2249 * a password if no password was given) and converts the data to PEM format
2250 * suitable for writing to a file. It uses Triple DES cipher for the encryption.
2252 * Returns: (transfer full): on success, PEM-formatted data suitable for writing
2253 * to a PEM-formatted certificate/private key file.
2256 nm_utils_rsa_key_encrypt (const guint8 *data,
2258 const char *in_password,
2259 char **out_password,
2264 char *key = NULL, *enc = NULL, *pw_buf[32];
2265 gsize key_len = 0, enc_len = 0;
2266 GString *pem = NULL;
2267 char *tmp, *tmp_password = NULL;
2270 GByteArray *ret = NULL;
2272 g_return_val_if_fail (data != NULL, NULL);
2273 g_return_val_if_fail (len > 0, NULL);
2275 g_return_val_if_fail (*out_password == NULL, NULL);
2277 /* Make the password if needed */
2279 if (!crypto_randomize (pw_buf, sizeof (pw_buf), error))
2281 in_password = tmp_password = nm_utils_bin2hexstr (pw_buf, sizeof (pw_buf), -1);
2285 if (!crypto_randomize (salt, salt_len, error))
2288 key = crypto_make_des_aes_key (CIPHER_DES_EDE3_CBC, &salt[0], salt_len, in_password, &key_len, NULL);
2290 g_return_val_if_reached (NULL);
2292 enc = crypto_encrypt (CIPHER_DES_EDE3_CBC, data, len, salt, salt_len, key, key_len, &enc_len, error);
2296 pem = g_string_sized_new (enc_len * 2 + 100);
2297 g_string_append (pem, "-----BEGIN RSA PRIVATE KEY-----\n");
2298 g_string_append (pem, "Proc-Type: 4,ENCRYPTED\n");
2300 /* Convert the salt to a hex string */
2301 tmp = nm_utils_bin2hexstr (salt, salt_len, salt_len * 2);
2302 g_string_append_printf (pem, "DEK-Info: %s,%s\n\n", CIPHER_DES_EDE3_CBC, tmp);
2305 /* Convert the encrypted key to a base64 string */
2306 p = tmp = g_base64_encode ((const guchar *) enc, enc_len);
2307 left = strlen (tmp);
2309 g_string_append_len (pem, p, (left < 64) ? left : 64);
2310 g_string_append_c (pem, '\n');
2316 g_string_append (pem, "-----END RSA PRIVATE KEY-----\n");
2318 ret = g_byte_array_sized_new (pem->len);
2319 g_byte_array_append (ret, (const unsigned char *) pem->str, pem->len);
2320 if (tmp_password && out_password)
2321 *out_password = g_strdup (tmp_password);
2325 memset (key, 0, key_len);
2329 memset (enc, 0, enc_len);
2333 g_string_free (pem, TRUE);
2336 memset (tmp_password, 0, strlen (tmp_password));
2337 g_free (tmp_password);
2344 file_has_extension (const char *filename, const char *extensions[])
2349 ext = strrchr (filename, '.');
2353 for (i = 0; extensions[i]; i++) {
2354 if (!g_ascii_strcasecmp (ext, extensions[i]))
2362 * nm_utils_file_is_certificate:
2363 * @filename: name of the file to test
2365 * Tests if @filename has a valid extension for an X.509 certificate file
2366 * (".cer", ".crt", ".der", or ".pem"), and contains a certificate in a format
2367 * recognized by NetworkManager.
2369 * Returns: %TRUE if the file is a certificate, %FALSE if it is not
2372 nm_utils_file_is_certificate (const char *filename)
2374 const char *extensions[] = { ".der", ".pem", ".crt", ".cer", NULL };
2375 NMCryptoFileFormat file_format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
2378 g_return_val_if_fail (filename != NULL, FALSE);
2380 if (!file_has_extension (filename, extensions))
2383 cert = crypto_load_and_verify_certificate (filename, &file_format, NULL);
2385 g_byte_array_unref (cert);
2387 return file_format = NM_CRYPTO_FILE_FORMAT_X509;
2391 * nm_utils_file_is_private_key:
2392 * @filename: name of the file to test
2393 * @out_encrypted: (out): on return, whether the file is encrypted
2395 * Tests if @filename has a valid extension for an X.509 private key file
2396 * (".der", ".key", ".pem", or ".p12"), and contains a private key in a format
2397 * recognized by NetworkManager.
2399 * Returns: %TRUE if the file is a private key, %FALSE if it is not
2402 nm_utils_file_is_private_key (const char *filename, gboolean *out_encrypted)
2404 const char *extensions[] = { ".der", ".pem", ".p12", ".key", NULL };
2406 g_return_val_if_fail (filename != NULL, FALSE);
2407 g_return_val_if_fail (out_encrypted == NULL || *out_encrypted == FALSE, FALSE);
2409 if (!file_has_extension (filename, extensions))
2412 return crypto_verify_private_key (filename, NULL, out_encrypted, NULL) != NM_CRYPTO_FILE_FORMAT_UNKNOWN;
2416 * nm_utils_file_is_pkcs12:
2417 * @filename: name of the file to test
2419 * Tests if @filename is a PKCS#<!-- -->12 file.
2421 * Returns: %TRUE if the file is PKCS#<!-- -->12, %FALSE if it is not
2424 nm_utils_file_is_pkcs12 (const char *filename)
2426 g_return_val_if_fail (filename != NULL, FALSE);
2428 return crypto_is_pkcs12_file (filename, NULL);
2431 /**********************************************************************************************/
2434 _nm_utils_check_file (const char *filename,
2436 NMUtilsCheckFilePredicate check_file,
2438 struct stat *out_st,
2441 struct stat st_backup;
2444 out_st = &st_backup;
2446 if (stat (filename, out_st) != 0) {
2450 NM_VPN_PLUGIN_ERROR,
2451 NM_VPN_PLUGIN_ERROR_FAILED,
2452 _("failed stat file %s: %s"), filename, strerror (errsv));
2456 /* ignore non-files. */
2457 if (!S_ISREG (out_st->st_mode)) {
2459 NM_VPN_PLUGIN_ERROR,
2460 NM_VPN_PLUGIN_ERROR_FAILED,
2461 _("not a file (%s)"), filename);
2465 /* with check_owner enabled, check that the file belongs to the
2467 if ( check_owner >= 0
2468 && (out_st->st_uid != 0 && (gint64) out_st->st_uid != check_owner)) {
2470 NM_VPN_PLUGIN_ERROR,
2471 NM_VPN_PLUGIN_ERROR_FAILED,
2472 _("invalid file owner %d for %s"), out_st->st_uid, filename);
2476 /* with check_owner enabled, check that the file cannot be modified
2477 * by other users (except root). */
2478 if ( check_owner >= 0
2479 && NM_FLAGS_ANY (out_st->st_mode, S_IWGRP | S_IWOTH | S_ISUID)) {
2481 NM_VPN_PLUGIN_ERROR,
2482 NM_VPN_PLUGIN_ERROR_FAILED,
2483 _("file permissions for %s"), filename);
2488 && !check_file (filename, out_st, user_data, error)) {
2489 if (error && !*error) {
2491 NM_VPN_PLUGIN_ERROR,
2492 NM_VPN_PLUGIN_ERROR_FAILED,
2493 _("reject %s"), filename);
2503 _nm_utils_check_module_file (const char *name,
2505 NMUtilsCheckFilePredicate check_file,
2509 if (!g_path_is_absolute (name)) {
2511 NM_VPN_PLUGIN_ERROR,
2512 NM_VPN_PLUGIN_ERROR_FAILED,
2513 _("path is not absolute (%s)"), name);
2517 /* Set special error code if the file doesn't exist.
2518 * The VPN package might be split into separate packages,
2519 * so it could be correct that the plugin file is missing.
2521 * Note that nm-applet checks for this error code to fail
2523 if (!g_file_test (name, G_FILE_TEST_EXISTS)) {
2527 _("Plugin file does not exist (%s)"), name);
2531 if (!g_file_test (name, G_FILE_TEST_IS_REGULAR)) {
2533 NM_VPN_PLUGIN_ERROR,
2534 NM_VPN_PLUGIN_ERROR_FAILED,
2535 _("Plugin is not a valid file (%s)"), name);
2539 if (g_str_has_suffix (name, ".la")) {
2540 /* g_module_open() treats files that end with .la special.
2541 * We don't want to parse the libtool archive. Just error out. */
2543 NM_VPN_PLUGIN_ERROR,
2544 NM_VPN_PLUGIN_ERROR_FAILED,
2545 _("libtool archives are not supported (%s)"), name);
2549 return _nm_utils_check_file (name,
2557 /**********************************************************************************************/
2560 * nm_utils_file_search_in_paths:
2561 * @progname: the helper program name, like "iptables"
2562 * Must be a non-empty string, without path separator (/).
2563 * @try_first: (allow-none): a custom path to try first before searching.
2564 * It is silently ignored if it is empty or not an absolute path.
2565 * @paths: (allow-none): a %NULL terminated list of search paths.
2566 * Can be empty or %NULL, in which case only @try_first is checked.
2567 * @file_test_flags: the flags passed to g_file_test() when searching
2568 * for @progname. Set it to 0 to skip the g_file_test().
2569 * @predicate: (scope call): if given, pass the file name to this function
2570 * for additional checks. This check is performed after the check for
2571 * @file_test_flags. You cannot omit both @file_test_flags and @predicate.
2572 * @user_data: (closure): (allow-none): user data for @predicate function.
2573 * @error: (allow-none): on failure, set a "not found" error %G_IO_ERROR %G_IO_ERROR_NOT_FOUND.
2575 * Searches for a @progname file in a list of search @paths.
2577 * Returns: (transfer none): the full path to the helper, if found, or %NULL if not found.
2578 * The returned string is not owned by the caller, but later
2579 * invocations of the function might overwrite it.
2582 nm_utils_file_search_in_paths (const char *progname,
2583 const char *try_first,
2584 const char *const *paths,
2585 GFileTest file_test_flags,
2586 NMUtilsFileSearchInPathsPredicate predicate,
2593 g_return_val_if_fail (!error || !*error, NULL);
2594 g_return_val_if_fail (progname && progname[0] && !strchr (progname, '/'), NULL);
2595 g_return_val_if_fail (file_test_flags || predicate, NULL);
2597 /* Only consider @try_first if it is a valid, absolute path. This makes
2598 * it simpler to pass in a path from configure checks. */
2600 && try_first[0] == '/'
2601 && (file_test_flags == 0 || g_file_test (try_first, file_test_flags))
2602 && (!predicate || predicate (try_first, user_data)))
2603 return g_intern_string (try_first);
2605 if (!paths || !*paths)
2608 tmp = g_string_sized_new (50);
2609 for (; *paths; paths++) {
2612 g_string_append (tmp, *paths);
2613 if (tmp->str[tmp->len - 1] != '/')
2614 g_string_append_c (tmp, '/');
2615 g_string_append (tmp, progname);
2616 if ( (file_test_flags == 0 || g_file_test (tmp->str, file_test_flags))
2617 && (!predicate || predicate (tmp->str, user_data))) {
2618 ret = g_intern_string (tmp->str);
2619 g_string_free (tmp, TRUE);
2622 g_string_set_size (tmp, 0);
2624 g_string_free (tmp, TRUE);
2627 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Could not find \"%s\" binary"), progname);
2631 /**********************************************************************************************/
2633 /* Band, channel/frequency stuff for wireless */
2639 static struct cf_pair a_table[] = {
2689 static struct cf_pair bg_table[] = {
2709 * nm_utils_wifi_freq_to_channel:
2712 * Utility function to translate a Wi-Fi frequency to its corresponding channel.
2714 * Returns: the channel represented by the frequency or 0
2717 nm_utils_wifi_freq_to_channel (guint32 freq)
2722 while (a_table[i].chan && (a_table[i].freq != freq))
2724 return a_table[i].chan;
2726 while (bg_table[i].chan && (bg_table[i].freq != freq))
2728 return bg_table[i].chan;
2735 * nm_utils_wifi_channel_to_freq:
2737 * @band: frequency band for wireless ("a" or "bg")
2739 * Utility function to translate a Wi-Fi channel to its corresponding frequency.
2741 * Returns: the frequency represented by the channel of the band,
2742 * or -1 when the freq is invalid, or 0 when the band
2746 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band)
2750 if (!strcmp (band, "a")) {
2751 while (a_table[i].chan && (a_table[i].chan != channel))
2753 return a_table[i].freq;
2754 } else if (!strcmp (band, "bg")) {
2755 while (bg_table[i].chan && (bg_table[i].chan != channel))
2757 return bg_table[i].freq;
2764 * nm_utils_wifi_find_next_channel:
2765 * @channel: current channel
2766 * @direction: whether going downward (0 or less) or upward (1 or more)
2767 * @band: frequency band for wireless ("a" or "bg")
2769 * Utility function to find out next/previous Wi-Fi channel for a channel.
2771 * Returns: the next channel in the specified direction or 0
2774 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band)
2776 size_t a_size = sizeof (a_table) / sizeof (struct cf_pair);
2777 size_t bg_size = sizeof (bg_table) / sizeof (struct cf_pair);
2778 struct cf_pair *pair = NULL;
2780 if (!strcmp (band, "a")) {
2781 if (channel < a_table[0].chan)
2782 return a_table[0].chan;
2783 if (channel > a_table[a_size - 2].chan)
2784 return a_table[a_size - 2].chan;
2786 } else if (!strcmp (band, "bg")) {
2787 if (channel < bg_table[0].chan)
2788 return bg_table[0].chan;
2789 if (channel > bg_table[bg_size - 2].chan)
2790 return bg_table[bg_size - 2].chan;
2791 pair = &bg_table[0];
2793 g_assert_not_reached ();
2797 while (pair->chan) {
2798 if (channel == pair->chan)
2800 if ((channel < (pair+1)->chan) && (channel > pair->chan)) {
2802 return (pair+1)->chan;
2812 * nm_utils_wifi_is_channel_valid:
2814 * @band: frequency band for wireless ("a" or "bg")
2816 * Utility function to verify Wi-Fi channel validity.
2818 * Returns: %TRUE or %FALSE
2821 nm_utils_wifi_is_channel_valid (guint32 channel, const char *band)
2823 struct cf_pair *table = NULL;
2826 if (!strcmp (band, "a"))
2828 else if (!strcmp (band, "bg"))
2833 while (table[i].chan && (table[i].chan != channel))
2836 if (table[i].chan != 0)
2842 static const guint *
2843 _wifi_freqs (gboolean bg_band)
2845 static guint *freqs_2ghz = NULL;
2846 static guint *freqs_5ghz = NULL;
2849 freqs = bg_band ? freqs_2ghz : freqs_5ghz;
2850 if (G_UNLIKELY (freqs == NULL)) {
2851 struct cf_pair *table;
2854 table = bg_band ? bg_table : a_table;
2855 freqs = g_new0 (guint, bg_band ? G_N_ELEMENTS (bg_table) : G_N_ELEMENTS (a_table));
2856 for (i = 0; table[i].chan; i++)
2857 freqs[i] = table[i].freq;
2868 * nm_utils_wifi_2ghz_freqs:
2870 * Utility function to return 2.4 GHz Wi-Fi frequencies (802.11bg band).
2872 * Returns: zero-terminated array of frequencies numbers (in MHz)
2877 nm_utils_wifi_2ghz_freqs (void)
2879 return _wifi_freqs (TRUE);
2881 NM_BACKPORT_SYMBOL (libnm_1_0_6, const guint *, nm_utils_wifi_2ghz_freqs, (void), ());
2884 * nm_utils_wifi_5ghz_freqs:
2886 * Utility function to return 5 GHz Wi-Fi frequencies (802.11a band).
2888 * Returns: zero-terminated array of frequencies numbers (in MHz)
2893 nm_utils_wifi_5ghz_freqs (void)
2895 return _wifi_freqs (FALSE);
2897 NM_BACKPORT_SYMBOL (libnm_1_0_6, const guint *, nm_utils_wifi_5ghz_freqs, (void), ());
2900 * nm_utils_wifi_strength_bars:
2901 * @strength: the access point strength, from 0 to 100
2903 * Converts @strength into a 4-character-wide graphical representation of
2904 * strength suitable for printing to stdout. If the current locale and terminal
2905 * support it, this will use unicode graphics characters to represent
2906 * "bars". Otherwise it will use 0 to 4 asterisks.
2908 * Returns: the graphical representation of the access point strength
2911 nm_utils_wifi_strength_bars (guint8 strength)
2913 static const char *strength_full, *strength_high, *strength_med, *strength_low, *strength_none;
2915 if (G_UNLIKELY (strength_full == NULL)) {
2916 gboolean can_show_graphics = TRUE;
2919 if (!g_get_charset (NULL)) {
2920 /* Non-UTF-8 locale */
2921 locale_str = g_locale_from_utf8 ("\342\226\202\342\226\204\342\226\206\342\226\210", -1, NULL, NULL, NULL);
2923 g_free (locale_str);
2925 can_show_graphics = FALSE;
2928 /* The linux console font doesn't have these characters */
2929 if (g_strcmp0 (g_getenv ("TERM"), "linux") == 0)
2930 can_show_graphics = FALSE;
2932 if (can_show_graphics) {
2933 strength_full = /* ▂▄▆█ */ "\342\226\202\342\226\204\342\226\206\342\226\210";
2934 strength_high = /* â–‚â–„â–†_ */ "\342\226\202\342\226\204\342\226\206_";
2935 strength_med = /* â–‚â–„__ */ "\342\226\202\342\226\204__";
2936 strength_low = /* â–‚___ */ "\342\226\202___";
2937 strength_none = /* ____ */ "____";
2939 strength_full = "****";
2940 strength_high = "*** ";
2941 strength_med = "** ";
2942 strength_low = "* ";
2943 strength_none = " ";
2948 return strength_full;
2949 else if (strength > 55)
2950 return strength_high;
2951 else if (strength > 30)
2952 return strength_med;
2953 else if (strength > 5)
2954 return strength_low;
2956 return strength_none;
2960 * nm_utils_hwaddr_len:
2961 * @type: the type of address; either <literal>ARPHRD_ETHER</literal> or
2962 * <literal>ARPHRD_INFINIBAND</literal>
2964 * Returns the length in octets of a hardware address of type @type.
2966 * It is an error to call this function with any value other than
2967 * <literal>ARPHRD_ETHER</literal> or <literal>ARPHRD_INFINIBAND</literal>.
2969 * Return value: the length.
2972 nm_utils_hwaddr_len (int type)
2974 g_return_val_if_fail (type == ARPHRD_ETHER || type == ARPHRD_INFINIBAND, 0);
2976 if (type == ARPHRD_ETHER)
2978 else if (type == ARPHRD_INFINIBAND)
2979 return INFINIBAND_ALEN;
2981 g_assert_not_reached ();
2984 #define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
2987 * nm_utils_hwaddr_atoba:
2988 * @asc: the ASCII representation of a hardware address
2989 * @length: the expected length in bytes of the result
2991 * Parses @asc and converts it to binary form in a #GByteArray. See
2992 * nm_utils_hwaddr_aton() if you don't want a #GByteArray.
2994 * Return value: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
2998 nm_utils_hwaddr_atoba (const char *asc, gsize length)
3002 g_return_val_if_fail (asc != NULL, NULL);
3003 g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
3005 ba = g_byte_array_sized_new (length);
3006 g_byte_array_set_size (ba, length);
3007 if (!nm_utils_hwaddr_aton (asc, ba->data, length)) {
3008 g_byte_array_unref (ba);
3016 * nm_utils_hwaddr_aton:
3017 * @asc: the ASCII representation of a hardware address
3018 * @buffer: buffer to store the result into
3019 * @length: the expected length in bytes of the result and
3020 * the size of the buffer in bytes.
3022 * Parses @asc and converts it to binary form in @buffer.
3023 * Bytes in @asc can be sepatared by colons (:), or hyphens (-), but not mixed.
3025 * Return value: @buffer, or %NULL if @asc couldn't be parsed
3026 * or would be shorter or longer than @length.
3029 nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize length)
3031 const char *in = asc;
3032 guint8 *out = (guint8 *)buffer;
3033 char delimiter = '\0';
3035 g_return_val_if_fail (asc != NULL, NULL);
3036 g_return_val_if_fail (buffer != NULL, NULL);
3037 g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
3039 while (length && *in) {
3040 guint8 d1 = in[0], d2 = in[1];
3042 if (!g_ascii_isxdigit (d1))
3045 /* If there's no leading zero (ie "aa:b:cc") then fake it */
3046 if (d2 && g_ascii_isxdigit (d2)) {
3047 *out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
3050 /* Fake leading zero */
3051 *out++ = (HEXVAL ('0') << 4) + HEXVAL (d1);
3057 if (delimiter == '\0') {
3058 if (*in == ':' || *in == '-')
3063 if (*in != delimiter)
3070 if (length == 0 && !*in)
3077 * nm_utils_hwaddr_ntoa:
3078 * @addr: (type guint8) (array length=length): a binary hardware address
3079 * @length: the length of @addr
3081 * Converts @addr to textual form.
3083 * Return value: (transfer full): the textual form of @addr
3086 nm_utils_hwaddr_ntoa (gconstpointer addr, gsize length)
3088 const guint8 *in = addr;
3090 const char *LOOKUP = "0123456789ABCDEF";
3092 g_return_val_if_fail (addr != NULL, g_strdup (""));
3093 g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, g_strdup (""));
3095 result = out = g_malloc (length * 3);
3099 *out++ = LOOKUP[v >> 4];
3100 *out++ = LOOKUP[v & 0x0F];
3110 hwaddr_binary_len (const char *asc)
3117 for (; *asc; asc++) {
3118 if (*asc == ':' || *asc == '-')
3125 * nm_utils_hwaddr_valid:
3126 * @asc: the ASCII representation of a hardware address
3127 * @length: the length of address that @asc is expected to convert to
3128 * (or -1 to accept any length up to %NM_UTILS_HWADDR_LEN_MAX)
3130 * Parses @asc to see if it is a valid hardware address of the given
3133 * Return value: %TRUE if @asc appears to be a valid hardware address
3134 * of the indicated length, %FALSE if not.
3137 nm_utils_hwaddr_valid (const char *asc, gssize length)
3139 guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
3141 g_return_val_if_fail (asc != NULL, FALSE);
3142 g_return_val_if_fail (length == -1 || (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX), FALSE);
3145 length = hwaddr_binary_len (asc);
3146 if (length == 0 || length > NM_UTILS_HWADDR_LEN_MAX)
3150 return nm_utils_hwaddr_aton (asc, buf, length) != NULL;
3154 * nm_utils_hwaddr_canonical:
3155 * @asc: the ASCII representation of a hardware address
3156 * @length: the length of address that @asc is expected to convert to
3157 * (or -1 to accept any length up to %NM_UTILS_HWADDR_LEN_MAX)
3159 * Parses @asc to see if it is a valid hardware address of the given
3160 * length, and if so, returns it in canonical form (uppercase, with
3161 * leading 0s as needed, and with colons rather than hyphens).
3163 * Return value: (transfer full): the canonicalized address if @asc appears to
3164 * be a valid hardware address of the indicated length, %NULL if not.
3167 nm_utils_hwaddr_canonical (const char *asc, gssize length)
3169 guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
3171 g_return_val_if_fail (asc != NULL, NULL);
3172 g_return_val_if_fail (length == -1 || (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX), NULL);
3175 length = hwaddr_binary_len (asc);
3176 if (length == 0 || length > NM_UTILS_HWADDR_LEN_MAX)
3180 if (nm_utils_hwaddr_aton (asc, buf, length) == NULL)
3183 return nm_utils_hwaddr_ntoa (buf, length);
3186 /* This is used to possibly canonicalize values passed to MAC address property
3187 * setters. Unlike nm_utils_hwaddr_canonical(), it accepts %NULL, and if you
3188 * pass it an invalid MAC address, it just returns that string rather than
3189 * returning %NULL (so that we can return a proper error from verify() later).
3192 _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize length)
3199 canonical = nm_utils_hwaddr_canonical (mac, length);
3203 return g_strdup (mac);
3207 * nm_utils_hwaddr_matches:
3208 * @hwaddr1: pointer to a binary or ASCII hardware address, or %NULL
3209 * @hwaddr1_len: size of @hwaddr1, or -1 if @hwaddr1 is ASCII
3210 * @hwaddr2: pointer to a binary or ASCII hardware address, or %NULL
3211 * @hwaddr2_len: size of @hwaddr2, or -1 if @hwaddr2 is ASCII
3213 * Generalized hardware address comparison function. Tests if @hwaddr1 and
3214 * @hwaddr2 "equal" (or more precisely, "equivalent"), with several advantages
3215 * over a simple memcmp():
3217 * 1. If @hwaddr1_len or @hwaddr2_len is -1, then the corresponding address is
3218 * assumed to be ASCII rather than binary, and will be converted to binary
3219 * before being compared.
3221 * 2. If @hwaddr1 or @hwaddr2 is %NULL, it is treated instead as though it was
3222 * a zero-filled buffer @hwaddr1_len or @hwaddr2_len bytes long.
3224 * 3. If @hwaddr1 and @hwaddr2 are InfiniBand hardware addresses (that is, if
3225 * they are <literal>INFINIBAND_ALEN</literal> bytes long in binary form)
3226 * then only the last 8 bytes are compared, since those are the only bytes
3227 * that actually identify the hardware. (The other 12 bytes will change
3228 * depending on the configuration of the InfiniBand fabric that the device
3231 * If a passed-in ASCII hardware address cannot be parsed, or would parse to an
3232 * address larger than %NM_UTILS_HWADDR_LEN_MAX, then it will silently fail to
3233 * match. (This means that externally-provided address strings do not need to be
3234 * sanity-checked before comparing them against known good addresses; they are
3235 * guaranteed to not match if they are invalid.)
3237 * Return value: %TRUE if @hwaddr1 and @hwaddr2 are equivalent, %FALSE if they are
3238 * different (or either of them is invalid).
3241 nm_utils_hwaddr_matches (gconstpointer hwaddr1,
3243 gconstpointer hwaddr2,
3246 guint8 buf1[NM_UTILS_HWADDR_LEN_MAX], buf2[NM_UTILS_HWADDR_LEN_MAX];
3248 if (hwaddr1_len == -1) {
3249 g_return_val_if_fail (hwaddr1 != NULL, FALSE);
3251 hwaddr1_len = hwaddr_binary_len (hwaddr1);
3252 if (hwaddr1_len == 0 || hwaddr1_len > NM_UTILS_HWADDR_LEN_MAX)
3254 if (!nm_utils_hwaddr_aton (hwaddr1, buf1, hwaddr1_len))
3259 g_return_val_if_fail (hwaddr1_len > 0 && hwaddr1_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
3262 memset (buf1, 0, hwaddr1_len);
3267 if (hwaddr2_len == -1) {
3268 g_return_val_if_fail (hwaddr2 != NULL, FALSE);
3270 if (!nm_utils_hwaddr_aton (hwaddr2, buf2, hwaddr1_len))
3274 hwaddr2_len = hwaddr1_len;
3276 g_return_val_if_fail (hwaddr2_len > 0 && hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
3279 memset (buf2, 0, hwaddr2_len);
3284 if (hwaddr1_len != hwaddr2_len)
3287 if (hwaddr1_len == INFINIBAND_ALEN) {
3288 hwaddr1 = (guint8 *)hwaddr1 + INFINIBAND_ALEN - 8;
3289 hwaddr2 = (guint8 *)hwaddr2 + INFINIBAND_ALEN - 8;
3290 hwaddr1_len = hwaddr2_len = 8;
3293 return !memcmp (hwaddr1, hwaddr2, hwaddr1_len);
3297 _nm_utils_hwaddr_to_dbus (const GValue *prop_value)
3299 const char *str = g_value_get_string (prop_value);
3300 guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
3304 len = hwaddr_binary_len (str);
3305 g_return_val_if_fail (len > 0 && len <= NM_UTILS_HWADDR_LEN_MAX, NULL);
3306 if (!nm_utils_hwaddr_aton (str, buf, len))
3311 return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1);
3315 _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
3319 const guint8 *array = g_variant_get_fixed_array (dbus_value, &length, 1);
3322 str = length ? nm_utils_hwaddr_ntoa (array, length) : NULL;
3323 g_value_take_string (prop_value, str);
3327 * nm_utils_bin2hexstr:
3328 * @src: (type guint8) (array length=len): an array of bytes
3329 * @len: the length of the @src array
3330 * @final_len: an index where to cut off the returned string, or -1
3332 * Converts the byte array @src into a hexadecimal string. If @final_len is
3333 * greater than -1, the returned string is terminated at that index
3334 * (returned_string[final_len] == '\0'),
3336 * Return value: (transfer full): the textual form of @bytes
3339 * Code originally by Alex Larsson <alexl@redhat.com> and
3340 * copyright Red Hat, Inc. under terms of the LGPL.
3343 nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len)
3345 static char hex_digits[] = "0123456789abcdef";
3346 const guint8 *bytes = src;
3349 gsize buflen = (len * 2) + 1;
3351 g_return_val_if_fail (bytes != NULL, NULL);
3352 g_return_val_if_fail (len > 0, NULL);
3353 g_return_val_if_fail (len < 4096, NULL); /* Arbitrary limit */
3355 g_return_val_if_fail (final_len < buflen, NULL);
3357 result = g_malloc0 (buflen);
3358 for (i = 0; i < len; i++) {
3359 result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
3360 result[2*i+1] = hex_digits[bytes[i] & 0xf];
3362 /* Cut converted key off at the correct length for this cipher type */
3364 result[final_len] = '\0';
3366 result[buflen - 1] = '\0';
3372 * nm_utils_hexstr2bin:
3373 * @hex: a string of hexadecimal characters with optional ':' separators
3375 * Converts a hexadecimal string @hex into an array of bytes. The optional
3376 * separator ':' may be used between single or pairs of hexadecimal characters,
3377 * eg "00:11" or "0:1". Any "0x" at the beginning of @hex is ignored. @hex
3378 * may not start or end with ':'.
3380 * Return value: (transfer full): the converted bytes, or %NULL on error
3383 nm_utils_hexstr2bin (const char *hex)
3386 gs_free guint8 *c = NULL;
3388 gboolean found_colon = FALSE;
3390 g_return_val_if_fail (hex != NULL, NULL);
3392 if (strncasecmp (hex, "0x", 2) == 0)
3394 found_colon = !!strchr (hex, ':');
3396 c = g_malloc (strlen (hex) / 2 + 1);
3398 a = g_ascii_xdigit_value (hex[i++]);
3402 if (hex[i] && hex[i] != ':') {
3403 b = g_ascii_xdigit_value (hex[i++]);
3406 c[x++] = ((guint) a << 4) | ((guint) b);
3412 if (hex[i] == ':') {
3414 /* trailing ':' is invalid */
3418 } else if (found_colon) {
3419 /* If colons exist, they must delimit 1 or 2 hex chars */
3424 return g_bytes_new (c, x);
3428 * nm_utils_iface_valid_name:
3429 * @name: Name of interface
3431 * This function is a 1:1 copy of the kernel's interface validation
3432 * function in net/core/dev.c.
3434 * Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
3437 nm_utils_iface_valid_name (const char *name)
3439 g_return_val_if_fail (name != NULL, FALSE);
3444 if (strlen (name) >= 16)
3447 if (!strcmp (name, ".") || !strcmp (name, ".."))
3451 if (*name == '/' || g_ascii_isspace (*name))
3461 * @str: a string that might be a UUID
3463 * Checks if @str is a UUID
3465 * Returns: %TRUE if @str is a UUID, %FALSE if not
3468 nm_utils_is_uuid (const char *str)
3470 const char *p = str;
3476 else if (!g_ascii_isxdigit (*p))
3481 if ((num_dashes == 4) && (p - str == 36))
3484 /* Backwards compat for older configurations */
3485 if ((num_dashes == 0) && (p - str == 40))
3491 static char _nm_utils_inet_ntop_buffer[NM_UTILS_INET_ADDRSTRLEN];
3494 * nm_utils_inet4_ntop: (skip)
3495 * @inaddr: the address that should be converted to string.
3496 * @dst: the destination buffer, it must contain at least
3497 * <literal>INET_ADDRSTRLEN</literal> or %NM_UTILS_INET_ADDRSTRLEN
3498 * characters. If set to %NULL, it will return a pointer to an internal, static
3499 * buffer (shared with nm_utils_inet6_ntop()). Beware, that the internal
3500 * buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
3501 * nm_utils_inet6_ntop() that does not provied it's own @dst buffer. Also,
3502 * using the internal buffer is not thread safe. When in doubt, pass your own
3503 * @dst buffer to avoid these issues.
3505 * Wrapper for inet_ntop.
3507 * Returns: the input buffer @dst, or a pointer to an
3508 * internal, static buffer. This function cannot fail.
3511 nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
3513 return inet_ntop (AF_INET, &inaddr, dst ? dst : _nm_utils_inet_ntop_buffer,
3518 * nm_utils_inet6_ntop: (skip)
3519 * @in6addr: the address that should be converted to string.
3520 * @dst: the destination buffer, it must contain at least
3521 * <literal>INET6_ADDRSTRLEN</literal> or %NM_UTILS_INET_ADDRSTRLEN
3522 * characters. If set to %NULL, it will return a pointer to an internal, static
3523 * buffer (shared with nm_utils_inet4_ntop()). Beware, that the internal
3524 * buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
3525 * nm_utils_inet6_ntop() that does not provied it's own @dst buffer. Also,
3526 * using the internal buffer is not thread safe. When in doubt, pass your own
3527 * @dst buffer to avoid these issues.
3529 * Wrapper for inet_ntop.
3531 * Returns: the input buffer @dst, or a pointer to an
3532 * internal, static buffer. %NULL is not allowed as @in6addr,
3533 * otherwise, this function cannot fail.
3536 nm_utils_inet6_ntop (const struct in6_addr *in6addr, char *dst)
3538 g_return_val_if_fail (in6addr, NULL);
3539 return inet_ntop (AF_INET6, in6addr, dst ? dst : _nm_utils_inet_ntop_buffer,
3544 * nm_utils_ipaddr_valid:
3545 * @family: <literal>AF_INET</literal> or <literal>AF_INET6</literal>, or
3546 * <literal>AF_UNSPEC</literal> to accept either
3547 * @ip: an IP address
3549 * Checks if @ip contains a valid IP address of the given family.
3551 * Return value: %TRUE or %FALSE
3554 nm_utils_ipaddr_valid (int family, const char *ip)
3556 guint8 buf[sizeof (struct in6_addr)];
3558 g_return_val_if_fail (family == AF_INET || family == AF_INET6 || family == AF_UNSPEC, FALSE);
3563 if (family == AF_UNSPEC)
3564 family = strchr (ip, ':') ? AF_INET6 : AF_INET;
3566 return inet_pton (family, ip, buf) == 1;
3570 * nm_utils_check_virtual_device_compatibility:
3571 * @virtual_type: a virtual connection type
3572 * @other_type: a connection type to test against @virtual_type
3574 * Determines if a connection of type @virtual_type can (in the
3575 * general case) work with connections of type @other_type.
3577 * If @virtual_type is %NM_TYPE_SETTING_VLAN, then this checks if
3578 * @other_type is a valid type for the parent of a VLAN.
3580 * If @virtual_type is a "master" type (eg, %NM_TYPE_SETTING_BRIDGE),
3581 * then this checks if @other_type is a valid type for a slave of that
3584 * Note that even if this returns %TRUE it is not guaranteed that
3585 * <emphasis>every</emphasis> connection of type @other_type is
3586 * compatible with @virtual_type; it may depend on the exact
3587 * configuration of the two connections, or on the capabilities of an
3588 * underlying device driver.
3590 * Returns: %TRUE or %FALSE
3593 nm_utils_check_virtual_device_compatibility (GType virtual_type, GType other_type)
3595 g_return_val_if_fail (_nm_setting_type_is_base_type (virtual_type), FALSE);
3596 g_return_val_if_fail (_nm_setting_type_is_base_type (other_type), FALSE);
3598 if (virtual_type == NM_TYPE_SETTING_BOND) {
3599 return ( other_type == NM_TYPE_SETTING_INFINIBAND
3600 || other_type == NM_TYPE_SETTING_WIRED
3601 || other_type == NM_TYPE_SETTING_BRIDGE
3602 || other_type == NM_TYPE_SETTING_BOND
3603 || other_type == NM_TYPE_SETTING_TEAM
3604 || other_type == NM_TYPE_SETTING_VLAN);
3605 } else if (virtual_type == NM_TYPE_SETTING_BRIDGE) {
3606 return ( other_type == NM_TYPE_SETTING_WIRED
3607 || other_type == NM_TYPE_SETTING_BOND
3608 || other_type == NM_TYPE_SETTING_TEAM
3609 || other_type == NM_TYPE_SETTING_VLAN);
3610 } else if (virtual_type == NM_TYPE_SETTING_TEAM) {
3611 return ( other_type == NM_TYPE_SETTING_WIRED
3612 || other_type == NM_TYPE_SETTING_BRIDGE
3613 || other_type == NM_TYPE_SETTING_BOND
3614 || other_type == NM_TYPE_SETTING_TEAM
3615 || other_type == NM_TYPE_SETTING_VLAN);
3616 } else if (virtual_type == NM_TYPE_SETTING_VLAN) {
3617 return ( other_type == NM_TYPE_SETTING_WIRED
3618 || other_type == NM_TYPE_SETTING_WIRELESS
3619 || other_type == NM_TYPE_SETTING_BRIDGE
3620 || other_type == NM_TYPE_SETTING_BOND
3621 || other_type == NM_TYPE_SETTING_TEAM
3622 || other_type == NM_TYPE_SETTING_VLAN);
3624 g_warn_if_reached ();
3634 static BondMode bond_mode_table[] = {
3635 [0] = { "balance-rr", "0" },
3636 [1] = { "active-backup", "1" },
3637 [2] = { "balance-xor", "2" },
3638 [3] = { "broadcast", "3" },
3639 [4] = { "802.3ad", "4" },
3640 [5] = { "balance-tlb", "5" },
3641 [6] = { "balance-alb", "6" },
3645 * nm_utils_bond_mode_int_to_string:
3646 * @mode: bonding mode as a numeric value
3648 * Convert bonding mode from integer value to descriptive name.
3649 * See https://www.kernel.org/doc/Documentation/networking/bonding.txt for
3652 * Returns: bonding mode string, or NULL on error
3657 nm_utils_bond_mode_int_to_string (int mode)
3659 if (mode >= 0 && mode < G_N_ELEMENTS (bond_mode_table))
3660 return bond_mode_table[mode].str;
3665 * nm_utils_bond_mode_string_to_int:
3666 * @mode: bonding mode as string
3668 * Convert bonding mode from string representation to numeric value.
3669 * See https://www.kernel.org/doc/Documentation/networking/bonding.txt for
3671 * The @mode string can be either a descriptive name or a number (as string).
3673 * Returns: numeric bond mode, or -1 on error
3678 nm_utils_bond_mode_string_to_int (const char *mode)
3682 if (!mode || !*mode)
3685 for (i = 0; i < G_N_ELEMENTS (bond_mode_table); i++) {
3686 if ( strcmp (mode, bond_mode_table[i].str) == 0
3687 || strcmp (mode, bond_mode_table[i].num) == 0)
3693 /**********************************************************************************************/
3695 #define STRSTRDICTKEY_V1_SET 0x01
3696 #define STRSTRDICTKEY_V2_SET 0x02
3697 #define STRSTRDICTKEY_ALL_SET 0x03
3699 struct _NMUtilsStrStrDictKey {
3705 _nm_utils_strstrdictkey_hash (gconstpointer a)
3707 const NMUtilsStrStrDictKey *k = a;
3708 const signed char *p;
3712 if (((int) k->type) & ~STRSTRDICTKEY_ALL_SET)
3713 g_return_val_if_reached (0);
3715 h = (h << 5) + h + k->type;
3716 if (k->type & STRSTRDICTKEY_ALL_SET) {
3717 p = (void *) k->data;
3718 for (; *p != '\0'; p++)
3719 h = (h << 5) + h + *p;
3720 if (k->type == STRSTRDICTKEY_ALL_SET) {
3721 /* the key contains two strings. Continue... */
3722 h = (h << 5) + h + '\0';
3723 for (p++; *p != '\0'; p++)
3724 h = (h << 5) + h + *p;
3733 _nm_utils_strstrdictkey_equal (gconstpointer a, gconstpointer b)
3735 const NMUtilsStrStrDictKey *k1 = a;
3736 const NMUtilsStrStrDictKey *k2 = b;
3743 if (k1->type != k2->type)
3746 if (k1->type & STRSTRDICTKEY_ALL_SET) {
3747 if (strcmp (k1->data, k2->data) != 0)
3750 if (k1->type == STRSTRDICTKEY_ALL_SET) {
3751 gsize l = strlen (k1->data) + 1;
3753 return strcmp (&k1->data[l], &k2->data[l]) == 0;
3760 NMUtilsStrStrDictKey *
3761 _nm_utils_strstrdictkey_create (const char *v1, const char *v2)
3764 gsize l1 = 0, l2 = 0;
3765 NMUtilsStrStrDictKey *k;
3768 return g_malloc0 (1);
3770 /* we need to distinguish between ("",NULL) and (NULL,"").
3771 * Thus, in @type we encode which strings we have present
3774 type |= STRSTRDICTKEY_V1_SET;
3775 l1 = strlen (v1) + 1;
3778 type |= STRSTRDICTKEY_V2_SET;
3779 l2 = strlen (v2) + 1;
3782 k = g_malloc (G_STRUCT_OFFSET (NMUtilsStrStrDictKey, data) + l1 + l2);
3785 memcpy (&k->data[0], v1, l1);
3787 memcpy (&k->data[l1], v2, l2);
3793 validate_dns_option (const char *name, gboolean numeric, gboolean ipv6,
3794 const NMUtilsDNSOptionDesc *option_descs)
3796 const NMUtilsDNSOptionDesc *desc;
3801 for (desc = option_descs; desc->name; desc++) {
3802 if (!strcmp (name, desc->name) &&
3803 numeric == desc->numeric &&
3804 (!desc->ipv6_only || ipv6))
3812 * _nm_utils_dns_option_validate:
3813 * @option: option string
3814 * @out_name: (out) (allow-none): the option name
3815 * @out_value: (out) (allow-none): the option value
3816 * @ipv6: whether the option refers to a IPv6 configuration
3817 * @option_descs: (allow-none): an array of NMUtilsDNSOptionDesc which describes the
3820 * Parses a DNS option in the form "name" or "name:number" and, if
3821 * @option_descs is not NULL, checks that the option conforms to one
3822 * of the provided descriptors. If @option_descs is NULL @ipv6 is
3825 * Returns: %TRUE when the parsing was successful and the option is valid,
3829 _nm_utils_dns_option_validate (const char *option, char **out_name,
3830 long *out_value, gboolean ipv6,
3831 const NMUtilsDNSOptionDesc *option_descs)
3833 char **tokens, *ptr;
3834 gboolean ret = FALSE;
3836 g_return_val_if_fail (option != NULL, FALSE);
3846 tokens = g_strsplit (option, ":", 2);
3848 if (g_strv_length (tokens) == 1) {
3849 ret = validate_dns_option (tokens[0], FALSE, ipv6, option_descs);
3850 if (ret && out_name)
3851 *out_name = g_strdup (tokens[0]);
3855 if (!tokens[1][0]) {
3860 for (ptr = tokens[1]; *ptr; ptr++) {
3861 if (!g_ascii_isdigit (*ptr)) {
3868 if (validate_dns_option (tokens[0], TRUE, ipv6, option_descs)) {
3869 int value = _nm_utils_ascii_str_to_int64 (tokens[1], 10, 0, G_MAXINT32, -1);
3872 *out_name = g_strdup (tokens[0]);
3879 g_strfreev (tokens);
3884 * _nm_utils_dns_option_find_idx:
3885 * @array: an array of strings
3886 * @option: a dns option string
3888 * Searches for an option in an array of strings. The match is
3889 * performed only the option name; the option value is ignored.
3891 * Returns: the index of the option in the array or -1 if was not
3894 int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option)
3897 char *option_name, *tmp_name;
3900 if (!_nm_utils_dns_option_validate (option, &option_name, NULL, FALSE, NULL))
3903 for (i = 0; i < array->len; i++) {
3904 if (_nm_utils_dns_option_validate (array->pdata[i], &tmp_name, NULL, FALSE, NULL)) {
3905 ret = strcmp (tmp_name, option_name);
3908 g_free (option_name);
3915 g_free (option_name);
3920 * nm_utils_enum_to_str:
3921 * @type: the %GType of the enum
3922 * @value: the value to be translated
3924 * Converts an enum value to its string representation. If the enum is a
3925 * %G_TYPE_FLAGS the function returns a comma-separated list of matching values.
3926 * If the enum is a %G_TYPE_ENUM and the given value is not valid the
3927 * function returns %NULL.
3929 * Returns: a newly allocated string or %NULL
3933 char *nm_utils_enum_to_str (GType type, int value)
3938 class = g_type_class_ref (type);
3940 if (G_IS_ENUM_CLASS (class)) {
3941 GEnumValue *enum_value;
3943 enum_value = g_enum_get_value (G_ENUM_CLASS (class), value);
3944 ret = enum_value ? strdup (enum_value->value_nick) : NULL;
3945 } else if (G_IS_FLAGS_CLASS (class)) {
3946 GFlagsValue *flags_value;
3947 GString *str = g_string_new ("");
3948 gboolean first = TRUE;
3951 flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), value);
3956 g_string_append (str, ", ");
3957 g_string_append (str, flags_value->value_nick);
3959 value &= ~flags_value->value;
3962 ret = g_string_free (str, FALSE);
3964 g_return_val_if_reached (NULL);
3966 g_type_class_unref (class);
3969 NM_BACKPORT_SYMBOL (libnm_1_0_6, char *, nm_utils_enum_to_str,
3970 (GType type, int value), (type, value));
3973 * nm_utils_enum_from_str:
3974 * @type: the %GType of the enum
3975 * @str: the input string
3976 * @out_value: (out) (allow-none): the output value
3977 * @err_token: (out) (allow-none): location to store the first unrecognized token
3979 * Converts a string to the matching enum value.
3981 * If the enum is a %G_TYPE_FLAGS the function returns the logical OR of values
3982 * matching the comma-separated tokens in the string; if an unknown token is found
3983 * the function returns %FALSE and stores a pointer to a newly allocated string
3984 * containing the unrecognized token in @err_token.
3986 * Returns: %TRUE if the conversion was successful, %FALSE otherwise
3990 gboolean nm_utils_enum_from_str (GType type, const char *str,
3991 int *out_value, char **err_token)
3994 gboolean ret = FALSE;
3996 gs_free char *stripped = NULL;
3998 g_return_val_if_fail (str, FALSE);
3999 stripped = g_strstrip (strdup (str));
4000 class = g_type_class_ref (type);
4002 if (G_IS_ENUM_CLASS (class)) {
4003 GEnumValue *enum_value;
4005 enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), stripped);
4007 value = enum_value->value;
4010 } else if (G_IS_FLAGS_CLASS (class)) {
4011 GFlagsValue *flags_value;
4012 gs_strfreev char **strv = NULL;
4015 strv = g_strsplit_set (stripped, " \t,", 0);
4016 for (i = 0; strv[i]; i++) {
4020 flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), strv[i]);
4024 value |= flags_value->value;
4029 *err_token = strdup (strv[i]);
4034 g_return_val_if_reached (FALSE);
4039 g_type_class_unref (class);
4042 NM_BACKPORT_SYMBOL (libnm_1_0_6, gboolean, nm_utils_enum_from_str,
4043 (GType type, const char *str, int *out_value, char **err_token),
4044 (type, str, out_value, err_token));
4047 * nm_utils_enum_get_values:
4048 * @type: the %GType of the enum
4049 * @from: the first element to be returned
4050 * @to: the last element to be returned
4052 * Returns the list of possible values for a given enum.
4054 * Returns: (transfer full): a NULL-terminated dynamically-allocated array of static strings
4059 const char **nm_utils_enum_get_values (GType type, gint from, gint to)
4065 class = g_type_class_ref (type);
4066 array = g_ptr_array_new ();
4068 if (G_IS_ENUM_CLASS (class)) {
4069 GEnumClass *enum_class = G_ENUM_CLASS (class);
4070 GEnumValue *enum_value;
4072 for (i = 0; i < enum_class->n_values; i++) {
4073 enum_value = &enum_class->values[i];
4074 if (enum_value->value >= from && enum_value->value <= to)
4075 g_ptr_array_add (array, (gpointer) enum_value->value_nick);
4077 } else if (G_IS_FLAGS_CLASS (class)) {
4078 GFlagsClass *flags_class = G_FLAGS_CLASS (class);
4079 GFlagsValue *flags_value;
4081 for (i = 0; i < flags_class->n_values; i++) {
4082 flags_value = &flags_class->values[i];
4083 if (flags_value->value >= from && flags_value->value <= to)
4084 g_ptr_array_add (array, (gpointer) flags_value->value_nick);
4087 g_type_class_unref (class);
4088 g_ptr_array_free (array, TRUE);
4089 g_return_val_if_reached (NULL);
4092 g_type_class_unref (class);
4093 g_ptr_array_add (array, NULL);
4095 return (const char **) g_ptr_array_free (array, FALSE);